PLplot  5.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plmeta.c
Go to the documentation of this file.
1 // Copyright (C) 1991, 1992, 1993, 1994, 1995 Geoffrey Furnish
2 // Copyright (C) 1991, 1992, 1993, 1994, 1995 Maurice LeBrun
3 //
4 // PLplot is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU Library General Public License as published
6 // by the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // PLplot is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Library General Public License for more details.
13 //
14 // You should have received a copy of the GNU Library General Public License
15 // along with PLplot; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 //
18 //--------------------------------------------------------------------------
19 //
20 // This is a metafile writer for PLplot.
21 //
22 //
23 #include "plDevs.h"
24 
25 //#define DEBUG
26 
27 #ifdef PLD_plmeta
28 
29 #define NEED_PLDEBUG
30 #include "plplotP.h"
31 #include "drivers.h"
32 #include "metadefs.h"
33 #include <string.h>
34 
35 // Device info
36 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_plmeta = "plmeta:PLplot Native Meta-File:0:plmeta:26:plm\n";
37 
38 
40 
41 void plD_init_plm( PLStream * );
42 void plD_line_plm( PLStream *, short, short, short, short );
43 void plD_polyline_plm( PLStream *, short *, short *, PLINT );
44 void plD_eop_plm( PLStream * );
45 void plD_bop_plm( PLStream * );
46 void plD_tidy_plm( PLStream * );
47 void plD_state_plm( PLStream *, PLINT );
48 void plD_esc_plm( PLStream *, PLINT, void * );
49 
50 // Struct to hold device-specific info.
51 
52 // Used for constructing error messages
53 
54 #define BUFFER_LEN 256
55 
56 // Function prototypes
57 
58 static void WriteFileHeader( PLStream *pls );
59 static void UpdatePrevPagehdr( PLStream *pls );
60 static void WritePageInfo( PLStream *pls, FPOS_T pp_offset );
61 static void UpdateIndex( PLStream *pls, FPOS_T cp_offset );
62 static void plm_fill( PLStream *pls );
63 static void plm_swin( PLStream *pls );
64 static void plm_text( PLStream *pls, EscText *args );
65 
66 // A little function to help with debugging
67 
68 #ifdef DEBUG
69 #define DEBUG_PRINT_LOCATION( a ) PrintLocation( pls, a )
70 
71 static void PrintLocation( PLStream *pls, char *tag )
72 {
73  int isfile = ( pls->output_type == 0 );
74  if ( isfile )
75  {
76  FILE *file = pls->OutFile;
77  FPOS_T current_offset;
78 
79  if ( pl_fgetpos( file, &current_offset ) )
80  plexit( "PrintLocation (plmeta.c): fgetpos call failed" );
81 
82  pldebug( tag, "at offset %d in file %s\n",
83  (int) current_offset, pls->FileName );
84  }
85 }
86 #else
87 #define DEBUG_PRINT_LOCATION( a )
88 #endif
89 
91 {
92 #ifndef ENABLE_DYNDRIVERS
93  pdt->pl_MenuStr = "PLplot Native Meta-File";
94  pdt->pl_DevName = "plmeta";
95 #endif
97  pdt->pl_seq = 26;
98  pdt->pl_init = (plD_init_fp) plD_init_plm;
99  pdt->pl_line = (plD_line_fp) plD_line_plm;
100  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_plm;
101  pdt->pl_eop = (plD_eop_fp) plD_eop_plm;
102  pdt->pl_bop = (plD_bop_fp) plD_bop_plm;
103  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_plm;
104  pdt->pl_state = (plD_state_fp) plD_state_plm;
105  pdt->pl_esc = (plD_esc_fp) plD_esc_plm;
106 }
107 
108 //--------------------------------------------------------------------------
109 // plD_init_plm()
110 //
111 // Initialize device.
112 //--------------------------------------------------------------------------
113 
114 void
115 plD_init_plm( PLStream *pls )
116 {
117  PLmDev *dev;
118 
119  dbug_enter( "plD_init_plm" );
120 
121  pls->color = 1; // Is a color device
122  pls->dev_fill0 = 1; // Handle solid fills
123  pls->dev_fill1 = 1; // Driver handles pattern fills
124 
125  if ( strncmp( PLMETA_VERSION, "2005", 4 ) == 0 )
126  {
127  pls->dev_text = 0; // Disable text handling by the driver
128  pls->dev_unicode = 0; // Disable unicode support
129  pls->dev_hrshsym = 0;
130  }
131  else
132  {
133  // NOTE: This breaks compatibility with the 2005 version of
134  // the plot metafile format
135  // Unicode support is not needed because the plmeta driver
136  // stores the unprocessed string data that was passed to PLplot.
137  // However, we turn it on to force unicode representation of the
138  // plot symbols in plsym.c rather than vectorization.
139  pls->dev_text = 1; // Enable text handling by the driver
140  pls->dev_unicode = 1; // Enable unicode support
141  pls->dev_hrshsym = 0; // Disable vectorizaton of Hershey symbols
142  }
143 
144 // Initialize family file info
145 
146  plFamInit( pls );
147 
148 // Prompt for a file name if not already set
149 
150  plOpenFile( pls );
151  pls->pdfs = pdf_finit( pls->OutFile );
152 
153 // Allocate and initialize device-specific data
154 
155  pls->dev = calloc( 1, (size_t) sizeof ( PLmDev ) );
156  if ( pls->dev == NULL )
157  plexit( "plD_init_plm: Out of memory." );
158 
159  dev = (PLmDev *) pls->dev;
160 
161  dev->xold = PL_UNDEFINED;
162  dev->yold = PL_UNDEFINED;
163 
164  dev->xmin = 0;
165  dev->xmax = PIXELS_X - 1;
166  dev->ymin = 0;
167  dev->ymax = PIXELS_Y - 1;
168 
169  dev->pxlx = (double) PIXELS_X / (double) LPAGE_X;
170  dev->pxly = (double) PIXELS_Y / (double) LPAGE_Y;
171 
172  plP_setpxl( dev->pxlx, dev->pxly );
173  plP_setphy( dev->xmin, dev->xmax, dev->ymin, dev->ymax );
174 
175 // Write Metafile header.
176 
177  WriteFileHeader( pls );
178 
179 // Write color map state info
180 
181  plD_state_plm( pls, PLSTATE_CMAP0 );
182  plD_state_plm( pls, PLSTATE_CMAP1 );
183 
184 // Write initialization command.
185 
186  DEBUG_PRINT_LOCATION( "before init" );
187  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) INITIALIZE ) );
188 }
189 
190 //--------------------------------------------------------------------------
191 // plD_line_plm()
192 //
193 // Draw a line in the current color from (x1,y1) to (x2,y2).
194 //--------------------------------------------------------------------------
195 
196 void
197 plD_line_plm( PLStream *pls, short x1, short y1, short x2, short y2 )
198 {
199  PLmDev *dev = (PLmDev *) pls->dev;
200  U_SHORT xy[4];
201 
202  // dbug_enter("plD_line_plm");
203 
204  // Failsafe check
205 
206 #ifdef DEBUG
207  if ( x1 < dev->xmin || x1 > dev->xmax ||
208  x2 < dev->xmin || x2 > dev->xmax ||
209  y1 < dev->ymin || y1 > dev->ymax ||
210  y2 < dev->ymin || y2 > dev->ymax )
211  {
212  pldebug( "plD_line_plm",
213  "coordinates out of bounds -- \nActual: (%i,%i), (%i,%i) Bounds: (%i,%i,%i,%i)\n",
214  x1, y1, x2, y2, dev->xmin, dev->xmax, dev->ymin, dev->ymax );
215  }
216 #endif
217 
218 // If continuation of previous line send the LINETO command, which uses
219 // the previous (x,y) point as it's starting location. This results in a
220 // storage reduction of not quite 50%, since the instruction length for
221 // a LINETO is 5/9 of that for the LINE command, and given that most
222 // graphics applications use this command heavily.
223 //
224 // Still not quite as efficient as tektronix format since we also send the
225 // command each time (so shortest command is 25% larger), but a lot easier
226 // to implement than the tek method.
227 //
228  if ( x1 == dev->xold && y1 == dev->yold )
229  {
230  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) LINETO ) );
231 
232  xy[0] = x2;
233  xy[1] = y2;
234  plm_wr( pdf_wr_2nbytes( pls->pdfs, xy, 2 ) );
235  }
236  else
237  {
238  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) LINE ) );
239 
240  xy[0] = x1;
241  xy[1] = y1;
242  xy[2] = x2;
243  xy[3] = y2;
244  plm_wr( pdf_wr_2nbytes( pls->pdfs, xy, 4 ) );
245  }
246  dev->xold = x2;
247  dev->yold = y2;
248 }
249 
250 //--------------------------------------------------------------------------
251 // plD_polyline_plm()
252 //
253 // Draw a polyline in the current color.
254 //--------------------------------------------------------------------------
255 
256 void
257 plD_polyline_plm( PLStream *pls, short *xa, short *ya, PLINT npts )
258 {
259  PLmDev *dev = (PLmDev *) pls->dev;
260 
261  dbug_enter( "plD_polyline_plm" );
262 
263  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) POLYLINE ) );
264 
265  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) npts ) );
266 
267  plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) xa, npts ) );
268  plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) ya, npts ) );
269 
270  dev->xold = xa[npts - 1];
271  dev->yold = ya[npts - 1];
272 }
273 
274 //--------------------------------------------------------------------------
275 // plD_eop_plm()
276 //
277 // End of page.
278 //--------------------------------------------------------------------------
279 
280 void
281 plD_eop_plm( PLStream *pls )
282 {
283  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) EOP ) );
284 }
285 
286 //--------------------------------------------------------------------------
287 // plD_bop_plm()
288 //
289 // Set up for the next page.
290 //
291 // Page header layout as follows:
292 //
293 // BOP (U_CHAR)
294 // page number (U_SHORT)
295 // prev page offset (U_LONG)
296 // next page offset (U_LONG)
297 //
298 // Each call after the first is responsible for updating the table of
299 // contents and the next page offset from the previous page.
300 //--------------------------------------------------------------------------
301 
302 void
303 plD_bop_plm( PLStream *pls )
304 {
305  PLmDev *dev = (PLmDev *) pls->dev;
306  int isfile = ( pls->output_type == 0 );
307  FPOS_T pp_offset = dev->lp_offset;
308 
309  dbug_enter( "plD_bop_plm" );
310 
311  dev->xold = PL_UNDEFINED;
312  dev->yold = PL_UNDEFINED;
313 
314 // Update previous page header
315 
316  if ( isfile )
317  UpdatePrevPagehdr( pls );
318 
319 // Start next family file if necessary.
320 
321  pls->bytecnt = pls->pdfs->bp;
322  plGetFam( pls );
323 
324 // Update page counter
325 
326  pls->page++;
327 
328 // Update table of contents info & write new page header.
329 
330  WritePageInfo( pls, pp_offset );
331 }
332 
333 //--------------------------------------------------------------------------
334 // plD_tidy_plm()
335 //
336 // Close graphics file
337 //--------------------------------------------------------------------------
338 
339 void
340 plD_tidy_plm( PLStream *pls )
341 {
342  dbug_enter( "plD_tidy_plm" );
343 
344  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) CLOSE ) );
345  pdf_close( pls->pdfs );
346  free_mem( pls->dev );
347 }
348 
349 //--------------------------------------------------------------------------
350 // plD_state_plm()
351 //
352 // Handle change in PLStream state (color, pen width, fill attribute, etc).
353 //--------------------------------------------------------------------------
354 
355 void
356 plD_state_plm( PLStream *pls, PLINT op )
357 {
358  int i;
359 
360  dbug_enter( "plD_state_plm" );
361 
363  plm_wr( pdf_wr_1byte( pls->pdfs, op ) );
364 
365  switch ( op )
366  {
367  case PLSTATE_WIDTH:
368  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) ( pls->width ) ) );
369  break;
370 
371  case PLSTATE_COLOR0:
372  plm_wr( pdf_wr_2bytes( pls->pdfs, (short) pls->icol0 ) );
373 
374  if ( pls->icol0 == PL_RGB_COLOR )
375  {
376  plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.r ) );
377  plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.g ) );
378  plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.b ) );
379  }
380  break;
381 
382  case PLSTATE_COLOR1:
383  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->icol1 ) );
384  break;
385 
386  case PLSTATE_FILL:
387  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) pls->patt ) );
388  break;
389 
390  case PLSTATE_CMAP0:
391  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ncol0 ) );
392  for ( i = 0; i < pls->ncol0; i++ )
393  {
394  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].r ) );
395  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].g ) );
396  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].b ) );
397  }
398  break;
399 
400  case PLSTATE_CMAP1:
401  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ncol1 ) );
402  for ( i = 0; i < pls->ncol1; i++ )
403  {
404  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].r ) );
405  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].g ) );
406  plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].b ) );
407  }
408  break;
409 
410  case PLSTATE_CHR:
411  // save the chrdef and chrht parameters
412  if ( strncmp( PLMETA_VERSION, "2005", 4 ) != 0 )
413  {
414  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->chrdef ) );
415  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->chrht ) );
416  }
417  break;
418 
419  case PLSTATE_SYM:
420  // save the symdef and symht parameters
421  if ( strncmp( PLMETA_VERSION, "2005", 4 ) != 0 )
422  {
423  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->symdef ) );
424  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->symht ) );
425  }
426  break;
427  }
428 }
429 
430 //--------------------------------------------------------------------------
431 // plD_esc_plm()
432 //
433 // Escape function. Note that any data written must be in device
434 // independent form to maintain the transportability of the metafile.
435 //
436 // Functions:
437 //
438 // PLESC_FILL Fill polygon
439 // PLESC_SWIN Set window parameters
440 //
441 //--------------------------------------------------------------------------
442 
443 void
444 plD_esc_plm( PLStream *pls, PLINT op, void *ptr )
445 {
446  dbug_enter( "plD_esc_plm" );
447 
448  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) ESCAPE ) );
449  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) op ) );
450 
451  switch ( op )
452  {
453  case PLESC_FILL:
454  plm_fill( pls );
455  break;
456 
457  case PLESC_SWIN:
458  plm_swin( pls );
459  break;
460 
461  // Unicode and non-Unicode text handling
462  case PLESC_HAS_TEXT:
463  plm_text( pls, (EscText *) ptr );
464  break;
465 
466  // Alternate unicode text handling
467  case PLESC_BEGIN_TEXT:
468  case PLESC_TEXT_CHAR:
469  case PLESC_CONTROL_CHAR:
470  case PLESC_END_TEXT:
471  // NOP these for now until a decision is made
472  // which method should be implemented for metafiles
473  plwarn( "plmeta: Alternate Unicode text handling is not implemented" );
474  break;
475  }
476 }
477 
478 //--------------------------------------------------------------------------
479 // Private functions
480 //--------------------------------------------------------------------------
481 
482 //--------------------------------------------------------------------------
483 // plm_fill()
484 //
485 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
486 //--------------------------------------------------------------------------
487 
488 static void
489 plm_fill( PLStream *pls )
490 {
491  PLmDev *dev = (PLmDev *) pls->dev;
492 
493  dbug_enter( "plm_fill" );
494 
495  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->dev_npts ) );
496 
497  plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) pls->dev_x, pls->dev_npts ) );
498  plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) pls->dev_y, pls->dev_npts ) );
499 
500  dev->xold = PL_UNDEFINED;
501  dev->yold = PL_UNDEFINED;
502 }
503 
504 //--------------------------------------------------------------------------
505 // plm_swin()
506 //
507 // Set window parameters.
508 // Each parameter or group of parameters is tagged to make backward
509 // compatibility easier.
510 //--------------------------------------------------------------------------
511 
512 static void
513 plm_swin( PLStream *pls )
514 {
515  dbug_enter( "plm_swin" );
516 }
517 
518 //--------------------------------------------------------------------------
519 // plm_text()
520 //
521 // Stores the text into the metafile.
522 //--------------------------------------------------------------------------
523 
524 static void
525 plm_text( PLStream *pls, EscText *args )
526 {
527  PLmDev *dev = (PLmDev *) pls->dev;
528  size_t len;
529 
530  // Write state information needed to render the text
531 
532  plm_wr( pdf_wr_ieeef( pls->pdfs, pls->chrht ) );
533  plm_wr( pdf_wr_ieeef( pls->pdfs, pls->diorot ) );
534  plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpxmi ) );
535  plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpxma ) );
536  plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpymi ) );
537  plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpyma ) );
538 
539  // Write the text layout information
540 
541  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->base ) );
542  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->just ) );
543 
544  // Do we have a rotation shear that needs to be saved
545  if ( args->xform != NULL )
546  {
547  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[0] ) );
548  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[1] ) );
549  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[2] ) );
550  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[3] ) );
551  }
552  else
553  {
554  plwarn( "plmeta: transformation matrix undefined, using a guess" );
555  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 1.0 ) );
556  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 0.0 ) );
557  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 0.0 ) );
558  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 1.0 ) );
559  }
560 
561  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->x ) );
562  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->y ) );
563  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->refx ) );
564  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->refy ) );
565  plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) args->font_face ) );
566  plm_wr( pdf_wr_4bytes( pls->pdfs, (int) args->text_type ) );
567 
568  // Was a text string passed or a plot symbol?
569  if ( args->text_type == PL_STRING_TEXT )
570  {
571  // Text string
572  len = strlen( args->string );
573  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) len ) );
574  if ( len > 0 )
575  plm_wr( pdf_wr_string( pls->pdfs, args->string ) );
576  }
577  else
578  {
579  // Plot symbol
580  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->symbol ) );
581  }
582 
583  // Clear the last known position
584  dev->xold = PL_UNDEFINED;
585  dev->yold = PL_UNDEFINED;
586 }
587 
588 //--------------------------------------------------------------------------
589 // Provide a consistent method for handling a failed fsetpos.
590 //--------------------------------------------------------------------------
591 static void
592 handle_fsetpos_failed( const char *where, const char *which, FPOS_T position )
593 {
594  char buffer[BUFFER_LEN];
595 
596  // Format a standard message detailing the failure location
597  snprintf( buffer, BUFFER_LEN,
598  "%s: fsetpos to %s (%lu) failed",
599  where,
600  which,
601  (unsigned long) position );
602 
603  plexit( buffer );
604 }
605 
606 //--------------------------------------------------------------------------
607 // WriteFileHeader()
608 //
609 // Writes Metafile header.
610 //--------------------------------------------------------------------------
611 
612 static void
613 WriteFileHeader( PLStream *pls )
614 {
615  PLmDev *dev = (PLmDev *) pls->dev;
616  FILE *file = pls->OutFile;
617  int isfile = ( pls->output_type == 0 );
618 
619  dbug_enter( "WriteFileHeader(PLStream *pls" );
620 
623 
624  // Write file index info. Right now only number of pages.
625  // The order here is critical
626 
627  if ( isfile )
628  {
629  // Save the position of the pages field so that it can
630  // be updated when a new page is created
631  if ( pl_fgetpos( file, &dev->index_offset ) )
632  plexit( "WriteFileHeader: fgetpos call failed" );
633  }
634 
635  plm_wr( pdf_wr_header( pls->pdfs, "pages" ) );
636  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) 0 ) );
637 
638  // Write initialization info. Tag via strings to make backward
639  // compatibility with old metafiles as easy as possible.
640 
641  plm_wr( pdf_wr_header( pls->pdfs, "xmin" ) );
642  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->xmin ) );
643 
644  plm_wr( pdf_wr_header( pls->pdfs, "xmax" ) );
645  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->xmax ) );
646 
647  plm_wr( pdf_wr_header( pls->pdfs, "ymin" ) );
648  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->ymin ) );
649 
650  plm_wr( pdf_wr_header( pls->pdfs, "ymax" ) );
651  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->ymax ) );
652 
653  plm_wr( pdf_wr_header( pls->pdfs, "pxlx" ) );
654  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) dev->pxlx ) );
655 
656  plm_wr( pdf_wr_header( pls->pdfs, "pxly" ) );
657  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) dev->pxly ) );
658 
659  // Geometry info, needed to properly transmit e.g. aspect ratio, via the
660  // length params. Not sure if the others are useful, but they're included
661  // for completeness.
662 
663  plm_wr( pdf_wr_header( pls->pdfs, "xdpi" ) );
664  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->xdpi ) );
665 
666  plm_wr( pdf_wr_header( pls->pdfs, "ydpi" ) );
667  plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->ydpi ) );
668 
669  plm_wr( pdf_wr_header( pls->pdfs, "xlength" ) );
670  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->xlength ) );
671 
672  plm_wr( pdf_wr_header( pls->pdfs, "ylength" ) );
673  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ylength ) );
674 
675  plm_wr( pdf_wr_header( pls->pdfs, "xoffset" ) );
676  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->xoffset ) );
677 
678  plm_wr( pdf_wr_header( pls->pdfs, "yoffset" ) );
679  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->yoffset ) );
680 
681  plm_wr( pdf_wr_header( pls->pdfs, "" ) );
682 }
683 
684 //--------------------------------------------------------------------------
685 // WritePageInfo()
686 //
687 // Update table of contents info & write new page header.
688 //--------------------------------------------------------------------------
689 
690 static void
691 WritePageInfo( PLStream *pls, FPOS_T pp_offset )
692 {
693  PLmDev *dev = (PLmDev *) pls->dev;
694  FILE *file = pls->OutFile;
695  int isfile = ( pls->output_type == 0 );
696  U_CHAR c;
697  FPOS_T cp_offset = 0;
698 
699  // Update table of contents.
700 
701  if ( isfile )
702  {
703  // Get the position of this page in order to update the index
704  if ( pl_fgetpos( file, &cp_offset ) )
705  plexit( "WritePageInfo (plmeta.c): fgetpos call failed" );
706 
707  UpdateIndex( pls, cp_offset );
708  }
709 
710  // Write new page header
711 
712  if ( dev->notfirst )
713  c = BOP;
714  else
715  {
716  c = BOP0;
717  dev->notfirst = 1;
718  }
719  plm_wr( pdf_wr_1byte( pls->pdfs, c ) );
720  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->page ) );
721  plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) pp_offset ) );
722  plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) 0 ) );
723 
724  // Update last page offset with current page value
725 
726  dev->lp_offset = cp_offset;
727 
728  // Write some page state information just to make things nice later on
729  // Eventually there will be more
730 
731  plD_state_plm( pls, PLSTATE_COLOR0 );
732 }
733 
734 //--------------------------------------------------------------------------
735 // UpdatePrevPagehdr()
736 //
737 // Update previous page header.
738 //--------------------------------------------------------------------------
739 
740 static void
741 UpdatePrevPagehdr( PLStream *pls )
742 {
743  PLmDev *dev = (PLmDev *) pls->dev;
744  FILE *file = pls->OutFile;
745  FPOS_T cp_offset = 0;
746 
747  fflush( file );
748 
749  // Determine where we are
750 
751  if ( pl_fgetpos( file, &cp_offset ) )
752  plexit( "plD_bop_plm: fgetpos call failed" );
753 
754  // Seek back to previous page header.
755 
756  if ( dev->lp_offset > 0 )
757  {
758  FPOS_T fwbyte_offset = 0;
759 
760  pldebug( "UpdatePrevPagehdr 1 (plmeta.c)",
761  "Location: %d, seeking to: %d\n",
762  (int) cp_offset, (int) dev->lp_offset );
763 
764  // The forward byte offset is located exactly 7 bytes after the BOP
765  fwbyte_offset = dev->lp_offset + 7;
766  if ( pl_fsetpos( file, &fwbyte_offset ) )
767  {
768  handle_fsetpos_failed( "UpdatePrevPagehdr",
769  "fwbyte_offset", fwbyte_offset );
770  }
771 
772  // DEBUG: verify current location
773 
774 #ifdef DEBUG
775  if ( pl_fgetpos( file, &fwbyte_offset ) )
776  plexit( "UpdatePrevPagehdr (plmeta.c): fgetpos call failed" );
777 
778  pldebug( "UpdatePrevPagehdr 2 (plmeta.c)",
779  "Now at: %d, to write: %d\n",
780  (int) fwbyte_offset, (int) cp_offset );
781 #endif
782 
783  // Write forward byte offset into previous page header.
784 
785  plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) cp_offset ) );
786  fflush( file );
787 
788  // DEBUG: move back to before the write & read it to verify
789 
790 #ifdef DEBUG
791  if ( pl_fsetpos( file, &fwbyte_offset ) )
792  {
793  handle_fsetpos_failed( "UpdatePrevPagehdr",
794  "fwbyte_offset", fwbyte_offset );
795  }
796  {
797  U_LONG read_offset;
798  plm_rd( pdf_rd_4bytes( pls->pdfs, &read_offset ) );
799  pldebug( "UpdatePrevPagehdr 3 (plmeta.c)",
800  "Value read as: %d\n", read_offset );
801  }
802 #endif
803 
804  // Return to current page offset
805 
806  if ( pl_fsetpos( file, &cp_offset ) )
807  {
808  handle_fsetpos_failed( "UpdatePrevPagehdr",
809  "cp_offset", cp_offset );
810  }
811  }
812 }
813 
814 //--------------------------------------------------------------------------
815 // UpdateIndex()
816 //
817 // Update file index.
818 //--------------------------------------------------------------------------
819 
820 static void
821 UpdateIndex( PLStream *pls, FPOS_T cp_offset )
822 {
823  PLmDev *dev = (PLmDev *) pls->dev;
824  FILE *file = pls->OutFile;
825 
826  // Update file index. Right now only number of pages.
827  // The ordering here is critical
828 
829  if ( dev->index_offset > 0 )
830  {
831  pldebug( "UpdateIndex (plmeta.c)",
832  "Location: %d, seeking to: %d\n",
833  (int) cp_offset, (int) dev->lp_offset );
834 
835  if ( pl_fsetpos( file, &dev->index_offset ) )
836  {
837  handle_fsetpos_failed( "UpdateIndex",
838  "index_offset", dev->index_offset );
839  }
840  plm_wr( pdf_wr_header( pls->pdfs, "pages" ) );
841  plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->page ) );
842 
843  pldebug( "UpdateIndex (plmeta.c)",
844  "Location: %d, seeking to: %d\n",
845  (int) dev->lp_offset, (int) cp_offset );
846 
847  if ( pl_fsetpos( file, &cp_offset ) )
848  {
849  handle_fsetpos_failed( "UpdateIndex",
850  "cp_offset", cp_offset );
851  }
852  }
853 }
854 
855 #else
856 int
858 {
859  return 0;
860 }
861 
862 #endif // PLD_plmeta