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
39 void plD_dispatch_init_plm( PLDispatchTable *pdt );
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
PrintLocation(PLStream * pls,char * tag)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, ¤t_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
plD_dispatch_init_plm(PLDispatchTable * pdt)90 void plD_dispatch_init_plm( PLDispatchTable *pdt )
91 {
92 #ifndef ENABLE_DYNDRIVERS
93 pdt->pl_MenuStr = "PLplot Native Meta-File";
94 pdt->pl_DevName = "plmeta";
95 #endif
96 pdt->pl_type = plDevType_FileOriented;
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
plD_init_plm(PLStream * pls)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
plD_line_plm(PLStream * pls,short x1,short y1,short x2,short y2)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
plD_polyline_plm(PLStream * pls,short * xa,short * ya,PLINT npts)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
plD_eop_plm(PLStream * pls)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
plD_bop_plm(PLStream * pls)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
plD_tidy_plm(PLStream * pls)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
plD_state_plm(PLStream * pls,PLINT op)356 plD_state_plm( PLStream *pls, PLINT op )
357 {
358 int i;
359
360 dbug_enter( "plD_state_plm" );
361
362 plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) CHANGE_STATE ) );
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
plD_esc_plm(PLStream * pls,PLINT op,void * ptr)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
plm_fill(PLStream * pls)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
plm_swin(PLStream * pls)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
plm_text(PLStream * pls,EscText * args)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
handle_fsetpos_failed(const char * where,const char * which,FPOS_T position)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
WriteFileHeader(PLStream * pls)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
621 plm_wr( pdf_wr_header( pls->pdfs, PLMETA_HEADER ) );
622 plm_wr( pdf_wr_header( pls->pdfs, PLMETA_VERSION ) );
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
WritePageInfo(PLStream * pls,FPOS_T pp_offset)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
UpdatePrevPagehdr(PLStream * pls)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
UpdateIndex(PLStream * pls,FPOS_T cp_offset)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
pldummy_plmeta()857 pldummy_plmeta()
858 {
859 return 0;
860 }
861
862 #endif // PLD_plmeta
863