3 * Copyright (C) 1999-2005 A.J. van Os; Released under GNU GPL
6 * Functions to deal with the PostScript format
8 *================================================================
9 * The function vImagePrologue is based on:
10 * jpeg2ps - convert JPEG compressed images to PostScript Level 2
11 * Copyright (C) 1994-99 Thomas Merz (tm@muc.de)
12 *================================================================
13 * The credit should go to him, but all the bugs are mine.
23 /* The character set */
24 static encoding_type eEncoding
= encoding_neutral
;
26 static image_level_enum eImageLevel
= level_default
;
27 /* The output must use landscape orientation */
28 static BOOL bUseLandscape
= FALSE
;
29 /* The height and width of a PostScript page (in DrawUnits) */
30 static long lPageHeight
= LONG_MAX
;
31 static long lPageWidth
= LONG_MAX
;
32 /* The height of the footer on the current page (in DrawUnits) */
33 static long lFooterHeight
= 0;
34 /* Inside a footer (to prevent an infinite loop when the footer is too big) */
35 static BOOL bInFtrSpace
= FALSE
;
36 /* Current time for a PS header */
37 static const char *szCreationDate
= NULL
;
38 /* Current creator for a PS header */
39 static const char *szCreator
= NULL
;
40 /* Current font information */
41 static drawfile_fontref tFontRefCurr
= (drawfile_fontref
)-1;
42 static USHORT usFontSizeCurr
= 0;
43 static int iFontColorCurr
= -1;
44 /* Current vertical position information */
45 static long lYtopCurr
= -1;
46 /* PostScript page counter */
47 static int iPageCount
= 0;
49 static int iImageCount
= 0;
51 static int iSectionIndex
= 0;
52 /* Are we on the first page of the section? */
53 static BOOL bFirstInSection
= TRUE
;
55 static void vMoveTo(diagram_type
*, long);
57 static const char *iso_8859_1_data
[] = {
58 "/newcodes % ISO-8859-1 character encodings",
60 "140/ellipsis 141/trademark 142/perthousand 143/bullet",
61 "144/quoteleft 145/quoteright 146/guilsinglleft 147/guilsinglright",
62 "148/quotedblleft 149/quotedblright 150/quotedblbase 151/endash 152/emdash",
63 "153/minus 154/OE 155/oe 156/dagger 157/daggerdbl 158/fi 159/fl",
64 "160/space 161/exclamdown 162/cent 163/sterling 164/currency",
65 "165/yen 166/brokenbar 167/section 168/dieresis 169/copyright",
66 "170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered",
67 "175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior",
68 "180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla",
69 "185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter",
70 "189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute",
71 "194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla",
72 "200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute",
73 "206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute",
74 "212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash",
75 "217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn",
76 "223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde",
77 "228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute",
78 "234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex",
79 "239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex",
80 "245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute",
81 "251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis",
84 "/reencdict 12 dict def",
88 static const char *iso_8859_2_data
[] = {
89 "/newcodes % ISO-8859-2 character encodings",
91 "160/space 161/Aogonek 162/breve 163/Lslash 164/currency 165/Lcaron",
92 "166/Sacute 167/section 168/dieresis 169/Scaron 170/Scommaaccent",
93 "171/Tcaron 172/Zacute 173/hyphen 174/Zcaron 175/Zdotaccent 176/degree",
94 "177/aogonek 178/ogonek 179/lslash 180/acute 181/lcaron 182/sacute",
95 "183/caron 184/cedilla 185/scaron 186/scommaaccent 187/tcaron",
96 "188/zacute 189/hungarumlaut 190/zcaron 191/zdotaccent 192/Racute",
97 "193/Aacute 194/Acircumflex 195/Abreve 196/Adieresis 197/Lacute",
98 "198/Cacute 199/Ccedilla 200/Ccaron 201/Eacute 202/Eogonek",
99 "203/Edieresis 204/Ecaron 205/Iacute 206/Icircumflex 207/Dcaron",
100 "208/Dcroat 209/Nacute 210/Ncaron 211/Oacute 212/Ocircumflex",
101 "213/Ohungarumlaut 214/Odieresis 215/multiply 216/Rcaron 217/Uring",
102 "218/Uacute 219/Uhungarumlaut 220/Udieresis 221/Yacute 222/Tcommaaccent",
103 "223/germandbls 224/racute 225/aacute 226/acircumflex 227/abreve",
104 "228/adieresis 229/lacute 230/cacute 231/ccedilla 232/ccaron 233/eacute",
105 "234/eogonek 235/edieresis 236/ecaron 237/iacute 238/icircumflex",
106 "239/dcaron 240/dcroat 241/nacute 242/ncaron 243/oacute 244/ocircumflex",
107 "245/ohungarumlaut 246/odieresis 247/divide 248/rcaron 249/uring",
108 "250/uacute 251/uhungarumlaut 252/udieresis 253/yacute 254/tcommaaccent",
112 "/reencdict 12 dict def",
116 static const char *iso_8859_5_data
[] = {
117 "/newcodes % ISO-8859-5 character encodings",
119 "160/space 161/afii10023 162/afii10051 163/afii10052 164/afii10053",
120 "165/afii10054 166/afii10055 167/afii10056 168/afii10057 169/afii10058",
121 "170/afii10059 171/afii10060 172/afii10061 173/hyphen 174/afii10062",
122 "175/afii10145 176/afii10017 177/afii10018 178/afii10019 179/afii10020",
123 "180/afii10021 181/afii10022 182/afii10024 183/afii10025 184/afii10026",
124 "185/afii10027 186/afii10028 187/afii10029 188/afii10030 189/afii10031",
125 "190/afii10032 191/afii10033 192/afii10034 193/afii10035 194/afii10036",
126 "195/afii10037 196/afii10038 197/afii10039 198/afii10040 199/afii10041",
127 "200/afii10042 201/afii10043 202/afii10044 203/afii10045 204/afii10046",
128 "205/afii10047 206/afii10048 207/afii10049 208/afii10065 209/afii10066",
129 "210/afii10067 211/afii10068 212/afii10069 213/afii10070 214/afii10072",
130 "215/afii10073 216/afii10074 217/afii10075 218/afii10076 219/afii10077",
131 "220/afii10078 221/afii10079 222/afii10080 223/afii10081 224/afii10082",
132 "225/afii10083 226/afii10084 227/afii10085 228/afii10086 229/afii10087",
133 "230/afii10088 231/afii10089 232/afii10090 233/afii10091 234/afii10092",
134 "235/afii10093 236/afii10094 237/afii10095 238/afii10096 239/afii10097",
135 "240/afii61352 241/afii10071 242/afii10099 243/afii10100 244/afii10101",
136 "245/afii10102 246/afii10103 247/afii10104 248/afii10105 249/afii10106",
137 "250/afii10107 251/afii10108 252/afii10109 253/section 254/afii10110",
141 "/reencdict 12 dict def",
145 static const char *iso_8859_x_func
[] = {
146 "% change fonts using ISO-8859-x characters",
147 "/ChgFnt % size psname natname => font",
149 " dup FontDirectory exch known % is re-encoded name known?",
150 " { exch pop } % yes, get rid of long name",
151 " { dup 3 1 roll ReEncode } ifelse % no, re-encode it",
152 " findfont exch scalefont setfont",
158 " /newname exch def",
159 " /basename exch def",
160 " /basedict basename findfont def",
161 " /newfont basedict maxlength dict def",
163 " { exch dup /FID ne",
164 " { dup /Encoding eq",
165 " { exch dup length array copy newfont 3 1 roll put }",
166 " { exch newfont 3 1 roll put } ifelse",
168 " { pop pop } ifelse",
170 " newfont /FontName newname put",
171 " newcodes aload pop newcodes length 2 idiv",
172 " { newfont /Encoding get 3 1 roll put } repeat",
173 " newname newfont definefont pop",
179 static const char *misc_func
[] = {
180 "% draw a line and show the string",
181 "/LineShow % string linewidth movement",
193 "% begin an EPS file (level 2 and up)",
196 " /b4_Inc_state save def",
197 " /dict_count countdictstack def",
198 " /op_count count 1 sub def",
200 " /showpage { } def",
201 " 0 setgray 0 setlinecap",
202 " 1 setlinewidth 0 setlinejoin",
203 " 10 setmiterlimit [ ] 0 setdash newpath",
204 " false setstrokeadjust false setoverprint",
209 " count op_count sub { pop } repeat",
210 " countdictstack dict_count sub { end } repeat",
211 " b4_Inc_state restore",
218 * vAddPageSetup - add the page setup
221 vAddPageSetup(FILE *pOutFile
)
224 fprintf(pOutFile
, "%%%%BeginPageSetup\n");
225 fprintf(pOutFile
, "90 rotate\n");
226 fprintf(pOutFile
, "0.00 %.2f translate\n",
227 -dDrawUnits2Points(lPageHeight
));
228 fprintf(pOutFile
, "%%%%EndPageSetup\n");
230 } /* end of vAddPageSetup */
233 * vAddHdrFtr - add a header or footer
236 vAddHdrFtr(diagram_type
*pDiag
, const hdrftr_block_type
*pHdrFtrInfo
)
238 output_type
*pStart
, *pPrev
, *pNext
;
241 fail(pHdrFtrInfo
== NULL
);
243 vStartOfParagraphPS(pDiag
, 0);
244 pStart
= pHdrFtrInfo
->pText
;
245 while (pStart
!= NULL
) {
247 while (pNext
!= NULL
&&
248 (pNext
->tNextFree
!= 1 ||
249 (pNext
->szStorage
[0] != PAR_END
&&
250 pNext
->szStorage
[0] != HARD_RETURN
))) {
251 pNext
= pNext
->pNext
;
254 if (bOutputContainsText(pStart
)) {
255 vAlign2Window(pDiag
, pStart
,
256 lChar2MilliPoints(DEFAULT_SCREEN_WIDTH
),
259 vMove2NextLinePS(pDiag
, pStart
->usFontSize
);
263 fail(pNext
->tNextFree
!= 1);
264 fail(pNext
->szStorage
[0] != PAR_END
&&
265 pNext
->szStorage
[0] != HARD_RETURN
);
267 if (pStart
!= pNext
) {
268 /* There is something to print */
269 pPrev
= pNext
->pPrev
;
270 fail(pPrev
->pNext
!= pNext
);
273 if (bOutputContainsText(pStart
)) {
275 vAlign2Window(pDiag
, pStart
,
276 lChar2MilliPoints(DEFAULT_SCREEN_WIDTH
),
279 /* Just an empty line */
280 vMove2NextLinePS(pDiag
, pStart
->usFontSize
);
282 /* Repair the chain */
283 pPrev
->pNext
= pNext
;
285 if (pNext
->szStorage
[0] == PAR_END
) {
286 vEndOfParagraphPS(pDiag
, pNext
->usFontSize
,
287 (long)pNext
->usFontSize
* 200);
289 pStart
= pNext
->pNext
;
291 } /* end of vAddHdrFtr */
294 * vAddHeader - add a page header
297 vAddHeader(diagram_type
*pDiag
)
299 const hdrftr_block_type
*pHdrInfo
;
300 const hdrftr_block_type
*pFtrInfo
;
304 NO_DBG_MSG("vAddHeader");
306 pHdrInfo
= pGetHdrFtrInfo(iSectionIndex
, TRUE
,
307 odd(iPageCount
), bFirstInSection
);
308 pFtrInfo
= pGetHdrFtrInfo(iSectionIndex
, FALSE
,
309 odd(iPageCount
), bFirstInSection
);
310 /* Set the height of the footer of this page */
311 lFooterHeight
= pFtrInfo
== NULL
? 0 : pFtrInfo
->lHeight
;
312 fail(lFooterHeight
< 0);
314 if (pHdrInfo
== NULL
||
315 pHdrInfo
->pText
== NULL
||
316 pHdrInfo
->lHeight
<= 0) {
317 fail(pHdrInfo
!= NULL
&& pHdrInfo
->lHeight
< 0);
318 fail(pHdrInfo
!= NULL
&&
319 pHdrInfo
->pText
!= NULL
&&
320 pHdrInfo
->lHeight
== 0);
324 vAddHdrFtr(pDiag
, pHdrInfo
);
326 DBG_DEC_C(pHdrInfo
->lHeight
!=
327 lPageHeight
- PS_TOP_MARGIN
- pDiag
->lYtop
,
329 DBG_DEC_C(pHdrInfo
->lHeight
!=
330 lPageHeight
- PS_TOP_MARGIN
- pDiag
->lYtop
,
331 lPageHeight
- PS_TOP_MARGIN
- pDiag
->lYtop
);
333 #if 0 /* defined(DEBUG) */
334 fprintf(pDiag
->pOutFile
,
335 "(HEADER: FileOffset 0x%04lx-0x%04lx; Height %ld-%ld) show\n",
336 ulCharPos2FileOffset(pHdrInfo
->ulCharPosStart
),
337 ulCharPos2FileOffset(pHdrInfo
->ulCharPosNext
),
339 lPageHeight
- PS_TOP_MARGIN
- pDiag
->lYtop
);
341 } /* end of vAddHeader */
344 * vAddFooter - add a page footer
347 vAddFooter(diagram_type
*pDiag
)
349 const hdrftr_block_type
*pFtrInfo
;
353 NO_DBG_MSG("vAddFooter");
354 pFtrInfo
= pGetHdrFtrInfo(iSectionIndex
, FALSE
,
355 odd(iPageCount
), bFirstInSection
);
356 bFirstInSection
= FALSE
;
357 if (pFtrInfo
== NULL
||
358 pFtrInfo
->pText
== NULL
||
359 pFtrInfo
->lHeight
<= 0) {
360 fail(pFtrInfo
!= NULL
&& pFtrInfo
->lHeight
< 0);
361 fail(pFtrInfo
!= NULL
&&
362 pFtrInfo
->pText
!= NULL
&&
363 pFtrInfo
->lHeight
== 0);
369 DBG_DEC_C(pFtrInfo
->lHeight
!= lFooterHeight
, pFtrInfo
->lHeight
);
370 DBG_DEC_C(pFtrInfo
->lHeight
!= lFooterHeight
, lFooterHeight
);
371 DBG_DEC_C(pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
,
373 DBG_DEC_C(pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
,
374 lFooterHeight
+ PS_BOTTOM_MARGIN
);
376 if (pDiag
->lYtop
> lFooterHeight
+ PS_BOTTOM_MARGIN
) {
377 /* Move down to the start of the footer */
378 pDiag
->lYtop
= lFooterHeight
+ PS_BOTTOM_MARGIN
;
380 } else if (pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
/ 2) {
383 * Move up to the start of the footer, to prevent moving
384 * of the bottom edge of the paper
386 pDiag
->lYtop
= lFooterHeight
+ PS_BOTTOM_MARGIN
;
390 DBG_FLT_C(pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
,
391 dDrawUnits2Points(lFooterHeight
+ PS_BOTTOM_MARGIN
- pDiag
->lYtop
));
393 #if 0 /* defined(DEBUG) */
394 fprintf(pDiag
->pOutFile
,
395 "(FOOTER: FileOffset 0x%04lx-0x%04lx; Bottom %ld-%ld) show\n",
396 ulCharPos2FileOffset(pFtrInfo
->ulCharPosStart
),
397 ulCharPos2FileOffset(pFtrInfo
->ulCharPosNext
),
399 pFtrInfo
->lHeight
+ PS_BOTTOM_MARGIN
);
401 vAddHdrFtr(pDiag
, pFtrInfo
);
403 } /* end of vAddFooter */
406 * vMove2NextPage - move to the start of the next page
409 vMove2NextPage(diagram_type
*pDiag
, BOOL bNewSection
)
414 fprintf(pDiag
->pOutFile
, "showpage\n");
416 fprintf(pDiag
->pOutFile
, "%%%%Page: %d %d\n", iPageCount
, iPageCount
);
419 bFirstInSection
= TRUE
;
421 vAddPageSetup(pDiag
->pOutFile
);
422 pDiag
->lYtop
= lPageHeight
- PS_TOP_MARGIN
;
425 } /* end of vMove2NextPage */
428 * vMoveTo - move to the specified X,Y coordinates
430 * Move the current position of the specified diagram to its X,Y coordinates,
431 * start on a new page if needed
434 vMoveTo(diagram_type
*pDiag
, long lLastVerticalMovement
)
437 fail(pDiag
->pOutFile
== NULL
);
439 if (pDiag
->lYtop
<= lFooterHeight
+ PS_BOTTOM_MARGIN
&& !bInFtrSpace
) {
440 vMove2NextPage(pDiag
, FALSE
);
441 /* Repeat the last vertical movement on the new page */
442 pDiag
->lYtop
-= lLastVerticalMovement
;
445 fail(pDiag
->lYtop
< lFooterHeight
+ PS_BOTTOM_MARGIN
&& !bInFtrSpace
);
446 DBG_DEC_C(pDiag
->lYtop
< PS_BOTTOM_MARGIN
, pDiag
->lYtop
);
447 fail(pDiag
->lYtop
< PS_BOTTOM_MARGIN
/ 3);
449 if (pDiag
->lYtop
!= lYtopCurr
) {
450 fprintf(pDiag
->pOutFile
, "%.2f %.2f moveto\n",
451 dDrawUnits2Points(pDiag
->lXleft
+ PS_LEFT_MARGIN
),
452 dDrawUnits2Points(pDiag
->lYtop
));
453 lYtopCurr
= pDiag
->lYtop
;
455 } /* end of vMoveTo */
458 * vProloguePS - set options and perform the PostScript initialization
461 vProloguePS(diagram_type
*pDiag
,
462 const char *szTask
, const char *szFilename
,
463 const options_type
*pOptions
)
470 fail(pDiag
->pOutFile
== NULL
);
471 fail(szTask
== NULL
|| szTask
[0] == '\0');
472 fail(pOptions
== NULL
);
474 pOutFile
= pDiag
->pOutFile
;
476 bUseLandscape
= pOptions
->bUseLandscape
;
477 eEncoding
= pOptions
->eEncoding
;
478 eImageLevel
= pOptions
->eImageLevel
;
480 if (pOptions
->iPageHeight
== INT_MAX
) {
481 lPageHeight
= LONG_MAX
;
483 lPageHeight
= lPoints2DrawUnits(pOptions
->iPageHeight
);
485 DBG_DEC(lPageHeight
);
486 if (pOptions
->iPageWidth
== INT_MAX
) {
487 lPageWidth
= LONG_MAX
;
489 lPageWidth
= lPoints2DrawUnits(pOptions
->iPageWidth
);
495 tFontRefCurr
= (drawfile_fontref
)-1;
502 bFirstInSection
= TRUE
;
504 pDiag
->lYtop
= lPageHeight
- PS_TOP_MARGIN
;
508 fprintf(pOutFile
, "%%!PS-Adobe-2.0\n");
509 fprintf(pOutFile
, "%%%%Title: %s\n", szBasename(szFilename
));
510 fprintf(pOutFile
, "%%%%Creator: %s %s\n", szCreator
, VERSIONSTRING
);
511 szTmp
= getenv("LOGNAME");
512 if (szTmp
== NULL
|| szTmp
[0] == '\0') {
513 szTmp
= getenv("USER");
514 if (szTmp
== NULL
|| szTmp
[0] == '\0') {
518 fprintf(pOutFile
, "%%%%For: %.50s\n", szTmp
);
521 if (tTime
== (time_t)-1 && errno
!= 0) {
522 szCreationDate
= NULL
;
524 szCreationDate
= ctime(&tTime
);
526 if (szCreationDate
== NULL
|| szCreationDate
[0] == '\0') {
527 szCreationDate
= "unknown\n";
529 fprintf(pOutFile
, "%%%%CreationDate: %s", szCreationDate
);
531 fprintf(pOutFile
, "%%%%Orientation: Landscape\n");
532 fprintf(pOutFile
, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
533 dDrawUnits2Points(lPageHeight
),
534 dDrawUnits2Points(lPageWidth
));
536 fprintf(pOutFile
, "%%%%Orientation: Portrait\n");
537 fprintf(pOutFile
, "%%%%BoundingBox: 0 0 %.0f %.0f\n",
538 dDrawUnits2Points(lPageWidth
),
539 dDrawUnits2Points(lPageHeight
));
541 } /* end of vProloguePS */
544 * vEpiloguePS - clean up after everything is done
547 vEpiloguePS(diagram_type
*pDiag
)
550 fail(pDiag
->pOutFile
== NULL
);
552 if (pDiag
->lYtop
< lPageHeight
- PS_TOP_MARGIN
) {
554 fprintf(pDiag
->pOutFile
, "showpage\n");
556 fprintf(pDiag
->pOutFile
, "%%%%Trailer\n");
557 fprintf(pDiag
->pOutFile
, "%%%%Pages: %d\n", iPageCount
);
558 fprintf(pDiag
->pOutFile
, "%%%%EOF\n");
559 szCreationDate
= NULL
;
561 } /* end of vEpiloguePS */
564 * vPrintPalette - print a postscript palette
567 vPrintPalette(FILE *pOutFile
, const imagedata_type
*pImg
)
571 fail(pOutFile
== NULL
);
573 fail(pImg
->iColorsUsed
< 2);
574 fail(pImg
->iColorsUsed
> 256);
576 fprintf(pOutFile
, "[ /Indexed\n");
577 fprintf(pOutFile
, "\t/Device%s %d\n",
578 pImg
->bColorImage
? "RGB" : "Gray", pImg
->iColorsUsed
- 1);
579 fprintf(pOutFile
, "<");
580 for (iIndex
= 0; iIndex
< pImg
->iColorsUsed
; iIndex
++) {
581 fprintf(pOutFile
, "%02x",
582 (unsigned int)pImg
->aucPalette
[iIndex
][0]);
583 if (pImg
->bColorImage
) {
584 fprintf(pOutFile
, "%02x%02x",
585 (unsigned int)pImg
->aucPalette
[iIndex
][1],
586 (unsigned int)pImg
->aucPalette
[iIndex
][2]);
588 if (iIndex
% 8 == 7) {
589 fprintf(pOutFile
, "\n");
591 fprintf(pOutFile
, " ");
594 fprintf(pOutFile
, ">\n");
595 fprintf(pOutFile
, "] setcolorspace\n");
596 } /* end of vPrintPalette */
599 * vImageProloguePS - perform the Encapsulated PostScript initialization
602 vImageProloguePS(diagram_type
*pDiag
, const imagedata_type
*pImg
)
607 fail(pDiag
->pOutFile
== NULL
);
610 if (pImg
->iVerSizeScaled
<= 0 || pImg
->iHorSizeScaled
<= 0) {
614 fail(szCreationDate
== NULL
);
615 fail(szCreator
== NULL
);
616 fail(eImageLevel
== level_no_images
);
620 DBG_DEC_C(pDiag
->lXleft
!= 0, pDiag
->lXleft
);
622 pDiag
->lYtop
-= lPoints2DrawUnits(pImg
->iVerSizeScaled
);
623 vMoveTo(pDiag
, lPoints2DrawUnits(pImg
->iVerSizeScaled
));
625 pOutFile
= pDiag
->pOutFile
;
627 fprintf(pOutFile
, "BeginEPSF\n");
628 fprintf(pOutFile
, "%%%%BeginDocument: image%03d.eps\n", iImageCount
);
629 fprintf(pOutFile
, "%%!PS-Adobe-2.0 EPSF-2.0\n");
630 fprintf(pOutFile
, "%%%%Creator: %s %s\n", szCreator
, VERSIONSTRING
);
631 fprintf(pOutFile
, "%%%%Title: Image %03d\n", iImageCount
);
632 fprintf(pOutFile
, "%%%%CreationDate: %s", szCreationDate
);
633 fprintf(pOutFile
, "%%%%BoundingBox: 0 0 %d %d\n",
634 pImg
->iHorSizeScaled
, pImg
->iVerSizeScaled
);
635 fprintf(pOutFile
, "%%%%DocumentData: Clean7Bit\n");
636 fprintf(pOutFile
, "%%%%LanguageLevel: 2\n");
637 fprintf(pOutFile
, "%%%%EndComments\n");
638 fprintf(pOutFile
, "%%%%BeginProlog\n");
639 fprintf(pOutFile
, "%%%%EndProlog\n");
640 fprintf(pOutFile
, "%%%%Page: 1 1\n");
642 fprintf(pOutFile
, "save\n");
644 switch (pImg
->eImageType
) {
645 case imagetype_is_jpeg
:
646 fprintf(pOutFile
, "/Data1 currentfile ");
647 fprintf(pOutFile
, "/ASCII85Decode filter def\n");
648 fprintf(pOutFile
, "/Data Data1 << ");
649 fprintf(pOutFile
, ">> /DCTDecode filter def\n");
650 switch (pImg
->iComponents
) {
652 fprintf(pOutFile
, "/DeviceGray setcolorspace\n");
655 fprintf(pOutFile
, "/DeviceRGB setcolorspace\n");
658 fprintf(pOutFile
, "/DeviceCMYK setcolorspace\n");
661 DBG_DEC(pImg
->iComponents
);
665 case imagetype_is_png
:
666 if (eImageLevel
== level_gs_special
) {
668 "/Data2 currentfile /ASCII85Decode filter def\n");
670 "/Data1 Data2 << >> /FlateDecode filter def\n");
671 fprintf(pOutFile
, "/Data Data1 <<\n");
672 fprintf(pOutFile
, "\t/Colors %d\n", pImg
->iComponents
);
673 fprintf(pOutFile
, "\t/BitsPerComponent %u\n",
674 pImg
->uiBitsPerComponent
);
675 fprintf(pOutFile
, "\t/Columns %d\n", pImg
->iWidth
);
677 ">> /PNGPredictorDecode filter def\n");
680 "/Data1 currentfile /ASCII85Decode filter def\n");
682 "/Data Data1 << >> /FlateDecode filter def\n");
684 if (pImg
->iComponents
== 3 || pImg
->iComponents
== 4) {
685 fprintf(pOutFile
, "/DeviceRGB setcolorspace\n");
686 } else if (pImg
->iColorsUsed
> 0) {
687 vPrintPalette(pOutFile
, pImg
);
689 fprintf(pOutFile
, "/DeviceGray setcolorspace\n");
692 case imagetype_is_dib
:
693 fprintf(pOutFile
, "/Data currentfile ");
694 fprintf(pOutFile
, "/ASCII85Decode filter def\n");
695 if (pImg
->uiBitsPerComponent
<= 8) {
696 vPrintPalette(pOutFile
, pImg
);
698 fprintf(pOutFile
, "/DeviceRGB setcolorspace\n");
702 fprintf(pOutFile
, "/Data currentfile ");
703 fprintf(pOutFile
, "/ASCIIHexDecode filter def\n");
704 fprintf(pOutFile
, "/Device%s setcolorspace\n",
705 pImg
->bColorImage
? "RGB" : "Gray");
709 /* Translate to lower left corner of image */
710 fprintf(pOutFile
, "%.2f %.2f translate\n",
711 dDrawUnits2Points(pDiag
->lXleft
+ PS_LEFT_MARGIN
),
712 dDrawUnits2Points(pDiag
->lYtop
));
714 fprintf(pOutFile
, "%d %d scale\n",
715 pImg
->iHorSizeScaled
, pImg
->iVerSizeScaled
);
717 fprintf(pOutFile
, "{ <<\n");
718 fprintf(pOutFile
, "\t/ImageType 1\n");
719 fprintf(pOutFile
, "\t/Width %d\n", pImg
->iWidth
);
720 fprintf(pOutFile
, "\t/Height %d\n", pImg
->iHeight
);
721 if (pImg
->eImageType
== imagetype_is_dib
) {
722 /* Scanning from left to right and bottom to top */
723 fprintf(pOutFile
, "\t/ImageMatrix [ %d 0 0 %d 0 0 ]\n",
724 pImg
->iWidth
, pImg
->iHeight
);
726 /* Scanning from left to right and top to bottom */
727 fprintf(pOutFile
, "\t/ImageMatrix [ %d 0 0 %d 0 %d ]\n",
728 pImg
->iWidth
, -pImg
->iHeight
, pImg
->iHeight
);
730 fprintf(pOutFile
, "\t/DataSource Data\n");
732 switch (pImg
->eImageType
) {
733 case imagetype_is_jpeg
:
734 fprintf(pOutFile
, "\t/BitsPerComponent 8\n");
735 switch (pImg
->iComponents
) {
737 fprintf(pOutFile
, "\t/Decode [0 1]\n");
740 fprintf(pOutFile
, "\t/Decode [0 1 0 1 0 1]\n");
745 * Adobe-conforming CMYK file
746 * applying workaround for color inversion
749 "\t/Decode [1 0 1 0 1 0 1 0]\n");
752 "\t/Decode [0 1 0 1 0 1 0 1]\n");
756 DBG_DEC(pImg
->iComponents
);
760 case imagetype_is_png
:
761 if (pImg
->iComponents
== 3) {
762 fprintf(pOutFile
, "\t/BitsPerComponent 8\n");
763 fprintf(pOutFile
, "\t/Decode [0 1 0 1 0 1]\n");
764 } else if (pImg
->iColorsUsed
> 0) {
765 fail(pImg
->uiBitsPerComponent
> 8);
766 fprintf(pOutFile
, "\t/BitsPerComponent %u\n",
767 pImg
->uiBitsPerComponent
);
768 fprintf(pOutFile
, "\t/Decode [0 %d]\n",
769 (1 << pImg
->uiBitsPerComponent
) - 1);
771 fprintf(pOutFile
, "\t/BitsPerComponent 8\n");
772 fprintf(pOutFile
, "\t/Decode [0 1]\n");
775 case imagetype_is_dib
:
776 fprintf(pOutFile
, "\t/BitsPerComponent 8\n");
777 if (pImg
->uiBitsPerComponent
<= 8) {
778 fprintf(pOutFile
, "\t/Decode [0 255]\n");
780 fprintf(pOutFile
, "\t/Decode [0 1 0 1 0 1]\n");
784 fprintf(pOutFile
, "\t/BitsPerComponent 8\n");
785 if (pImg
->bColorImage
) {
786 fprintf(pOutFile
, "\t/Decode [0 1 0 1 0 1]\n");
788 fprintf(pOutFile
, "\t/Decode [0 1]\n");
793 fprintf(pOutFile
, " >> image\n");
794 fprintf(pOutFile
, " Data closefile\n");
795 fprintf(pOutFile
, " showpage\n");
796 fprintf(pOutFile
, " restore\n");
797 fprintf(pOutFile
, "} exec\n");
798 } /* end of vImageProloguePS */
801 * vImageEpiloguePS - clean up after Encapsulated PostScript
804 vImageEpiloguePS(diagram_type
*pDiag
)
809 fail(pDiag
->pOutFile
== NULL
);
811 pOutFile
= pDiag
->pOutFile
;
813 fprintf(pOutFile
, "%%%%EOF\n");
814 fprintf(pOutFile
, "%%%%EndDocument\n");
815 fprintf(pOutFile
, "EndEPSF\n");
818 } /* end of vImageEpiloguePS */
821 * bAddDummyImagePS - add a dummy image
823 * return TRUE when successful, otherwise FALSE
826 bAddDummyImagePS(diagram_type
*pDiag
, const imagedata_type
*pImg
)
831 fail(pDiag
->pOutFile
== NULL
);
834 if (pImg
->iVerSizeScaled
<= 0 || pImg
->iHorSizeScaled
<= 0) {
840 DBG_DEC_C(pDiag
->lXleft
!= 0, pDiag
->lXleft
);
842 pDiag
->lYtop
-= lPoints2DrawUnits(pImg
->iVerSizeScaled
);
843 vMoveTo(pDiag
, lPoints2DrawUnits(pImg
->iVerSizeScaled
));
845 pOutFile
= pDiag
->pOutFile
;
847 fprintf(pOutFile
, "gsave %% Image %03d\n", iImageCount
);
848 fprintf(pOutFile
, "\tnewpath\n");
849 fprintf(pOutFile
, "\t%.2f %.2f moveto\n",
850 dDrawUnits2Points(pDiag
->lXleft
+ PS_LEFT_MARGIN
),
851 dDrawUnits2Points(pDiag
->lYtop
));
852 fprintf(pOutFile
, "\t1.0 setlinewidth\n");
853 fprintf(pOutFile
, "\t0.3 setgray\n");
854 fprintf(pOutFile
, "\t0 %d rlineto\n", pImg
->iVerSizeScaled
);
855 fprintf(pOutFile
, "\t%d 0 rlineto\n", pImg
->iHorSizeScaled
);
856 fprintf(pOutFile
, "\t0 %d rlineto\n", -pImg
->iVerSizeScaled
);
857 fprintf(pOutFile
, "\tclosepath\n");
858 fprintf(pOutFile
, "\tstroke\n");
859 fprintf(pOutFile
, "grestore\n");
864 } /* end of bAddDummyImagePS */
867 * vAddFontsPS - add the list of fonts and complete the prologue
870 vAddFontsPS(diagram_type
*pDiag
)
873 const font_table_type
*pTmp
, *pTmp2
;
875 int iLineLen
, iOurFontnameLen
;
879 fail(pDiag
->pOutFile
== NULL
);
881 pOutFile
= pDiag
->pOutFile
;
882 iLineLen
= fprintf(pOutFile
, "%%%%DocumentFonts:");
884 if (tGetFontTableLength() == 0) {
885 iLineLen
+= fprintf(pOutFile
, " Courier");
888 while ((pTmp
= pGetNextFontTableRecord(pTmp
)) != NULL
) {
889 /* Print the document fonts */
892 while ((pTmp2
= pGetNextFontTableRecord(pTmp2
))
893 != NULL
&& pTmp2
< pTmp
) {
894 bFound
= STREQ(pTmp2
->szOurFontname
,
895 pTmp
->szOurFontname
);
900 iOurFontnameLen
= (int)strlen(pTmp
->szOurFontname
);
901 if (bFound
|| iOurFontnameLen
<= 0) {
904 if (iLineLen
+ iOurFontnameLen
> 76) {
905 fprintf(pOutFile
, "\n%%%%+");
908 iLineLen
+= fprintf(pOutFile
,
909 " %s", pTmp
->szOurFontname
);
912 fprintf(pOutFile
, "\n");
913 fprintf(pOutFile
, "%%%%Pages: (atend)\n");
914 fprintf(pOutFile
, "%%%%EndComments\n");
915 fprintf(pOutFile
, "%%%%BeginProlog\n");
918 case encoding_latin_1
:
920 tIndex
< elementsof(iso_8859_1_data
);
922 fprintf(pOutFile
, "%s\n", iso_8859_1_data
[tIndex
]);
924 fprintf(pOutFile
, "\n");
926 tIndex
< elementsof(iso_8859_x_func
);
928 fprintf(pOutFile
, "%s\n", iso_8859_x_func
[tIndex
]);
931 case encoding_latin_2
:
933 tIndex
< elementsof(iso_8859_2_data
);
935 fprintf(pOutFile
, "%s\n", iso_8859_2_data
[tIndex
]);
937 fprintf(pOutFile
, "\n");
939 tIndex
< elementsof(iso_8859_x_func
);
941 fprintf(pOutFile
, "%s\n", iso_8859_x_func
[tIndex
]);
944 case encoding_cyrillic
:
946 tIndex
< elementsof(iso_8859_5_data
);
948 fprintf(pOutFile
, "%s\n", iso_8859_5_data
[tIndex
]);
950 fprintf(pOutFile
, "\n");
952 tIndex
< elementsof(iso_8859_x_func
);
954 fprintf(pOutFile
, "%s\n", iso_8859_x_func
[tIndex
]);
959 "The combination PostScript and UTF-8 is not supported");
966 /* The rest of the functions */
967 for (tIndex
= 0; tIndex
< elementsof(misc_func
); tIndex
++) {
968 fprintf(pOutFile
, "%s\n", misc_func
[tIndex
]);
970 fprintf(pOutFile
, "%%%%EndProlog\n");
972 fprintf(pDiag
->pOutFile
, "%%%%Page: %d %d\n", iPageCount
, iPageCount
);
973 vAddPageSetup(pDiag
->pOutFile
);
975 } /* end of vAddFontsPS */
978 * vPrintPS - print a PostScript string
981 vPrintPS(FILE *pFile
, const char *szString
, size_t tStringLength
,
984 double dSuperscriptMove
, dSubscriptMove
;
985 const UCHAR
*ucBytes
;
988 fail(szString
== NULL
);
990 if (szString
== NULL
|| szString
[0] == '\0' || tStringLength
== 0) {
993 DBG_DEC_C(usFontSizeCurr
< MIN_FONT_SIZE
, usFontSizeCurr
);
995 dSuperscriptMove
= 0.0;
996 dSubscriptMove
= 0.0;
998 /* Up for superscript */
999 if (bIsSuperscript(usFontstyle
) && usFontSizeCurr
!= 0) {
1000 dSuperscriptMove
= (double)((usFontSizeCurr
+ 1) / 2) * 0.375;
1001 fprintf(pFile
, "0 %.2f rmoveto\n", dSuperscriptMove
);
1004 /* Down for subscript */
1005 if (bIsSubscript(usFontstyle
) && usFontSizeCurr
!= 0) {
1006 dSubscriptMove
= (double)usFontSizeCurr
* 0.125;
1007 fprintf(pFile
, "0 %.2f rmoveto\n", -dSubscriptMove
);
1010 /* Generate and print the PostScript output */
1011 ucBytes
= (UCHAR
*)szString
;
1012 (void)putc('(', pFile
);
1013 for (tCount
= 0; tCount
< tStringLength
; tCount
++) {
1014 switch (ucBytes
[tCount
]) {
1018 (void)putc('\\', pFile
);
1019 (void)putc(szString
[tCount
], pFile
);
1022 if (ucBytes
[tCount
] < 0x20 ||
1023 (ucBytes
[tCount
] >= 0x7f &&
1024 ucBytes
[tCount
] < 0x8c)) {
1025 DBG_HEX(ucBytes
[tCount
]);
1026 (void)putc(' ', pFile
);
1027 } else if (ucBytes
[tCount
] >= 0x80) {
1028 fprintf(pFile
, "\\%03o", (UINT
)ucBytes
[tCount
]);
1030 (void)putc(szString
[tCount
], pFile
);
1035 fprintf(pFile
, ") ");
1036 if ((bIsStrike(usFontstyle
) || bIsMarkDel(usFontstyle
)) &&
1037 usFontSizeCurr
!= 0) {
1038 fprintf(pFile
, "%.2f %.2f LineShow\n",
1039 (double)usFontSizeCurr
* 0.02,
1040 (double)usFontSizeCurr
* 0.12);
1041 } else if (bIsUnderline(usFontstyle
) && usFontSizeCurr
!= 0) {
1042 fprintf(pFile
, "%.2f %.2f LineShow\n",
1043 (double)usFontSizeCurr
* 0.02,
1044 (double)usFontSizeCurr
* -0.06);
1046 fprintf(pFile
, "show\n");
1049 /* Undo the superscript move */
1050 if (bIsSuperscript(usFontstyle
) && usFontSizeCurr
!= 0) {
1051 fprintf(pFile
, "0 %.2f rmoveto\n", -dSuperscriptMove
);
1054 /* Undo the subscript move */
1055 if (bIsSubscript(usFontstyle
) && usFontSizeCurr
!= 0) {
1056 fprintf(pFile
, "0 %.2f rmoveto\n", dSubscriptMove
);
1058 } /* end of vPrintPS */
1061 * vSetColor - move to the specified color
1064 vSetColor(FILE *pFile
, UCHAR ucFontColor
)
1066 ULONG ulTmp
, ulRed
, ulGreen
, ulBlue
;
1068 ulTmp
= ulColor2Color(ucFontColor
);
1069 ulRed
= (ulTmp
& 0x0000ff00) >> 8;
1070 ulGreen
= (ulTmp
& 0x00ff0000) >> 16;
1071 ulBlue
= (ulTmp
& 0xff000000) >> 24;
1072 fprintf(pFile
, "%.3f %.3f %.3f setrgbcolor\n",
1073 ulRed
/ 255.0, ulGreen
/ 255.0, ulBlue
/ 255.0);
1074 } /* end of vSetColor */
1077 * vMove2NextLinePS - move to the next line
1080 vMove2NextLinePS(diagram_type
*pDiag
, USHORT usFontSize
)
1082 fail(pDiag
== NULL
);
1083 fail(usFontSize
< MIN_FONT_SIZE
|| usFontSize
> MAX_FONT_SIZE
);
1085 pDiag
->lYtop
-= lComputeLeading(usFontSize
);
1086 } /* end of vMove2NextLinePS */
1089 * vSubstringPS - print a sub string
1092 vSubstringPS(diagram_type
*pDiag
,
1093 char *szString
, size_t tStringLength
, long lStringWidth
,
1094 UCHAR ucFontColor
, USHORT usFontstyle
, drawfile_fontref tFontRef
,
1095 USHORT usFontSize
, USHORT usMaxFontSize
)
1097 const char *szOurFontname
;
1099 fail(pDiag
== NULL
|| szString
== NULL
);
1100 fail(pDiag
->pOutFile
== NULL
);
1101 fail(pDiag
->lXleft
< 0);
1102 fail(tStringLength
!= strlen(szString
));
1103 fail(usFontSize
< MIN_FONT_SIZE
|| usFontSize
> MAX_FONT_SIZE
);
1104 fail(usMaxFontSize
< MIN_FONT_SIZE
|| usMaxFontSize
> MAX_FONT_SIZE
);
1105 fail(usFontSize
> usMaxFontSize
);
1107 if (szString
[0] == '\0' || tStringLength
== 0) {
1111 if (tFontRef
!= tFontRefCurr
|| usFontSize
!= usFontSizeCurr
) {
1112 szOurFontname
= szGetFontname(tFontRef
);
1113 fail(szOurFontname
== NULL
);
1114 fprintf(pDiag
->pOutFile
,
1115 "%.1f /%s /%s-ISO-8859-x ChgFnt\n",
1116 (double)usFontSize
/ 2.0,
1117 szOurFontname
, szOurFontname
);
1118 tFontRefCurr
= tFontRef
;
1119 usFontSizeCurr
= usFontSize
;
1121 if ((int)ucFontColor
!= iFontColorCurr
) {
1122 vSetColor(pDiag
->pOutFile
, ucFontColor
);
1123 iFontColorCurr
= (int)ucFontColor
;
1125 vMoveTo(pDiag
, lComputeLeading(usMaxFontSize
));
1126 vPrintPS(pDiag
->pOutFile
, szString
, tStringLength
, usFontstyle
);
1127 pDiag
->lXleft
+= lStringWidth
;
1128 } /* end of vSubstringPS */
1131 * Create an start of paragraph by moving the y-top mark
1134 vStartOfParagraphPS(diagram_type
*pDiag
, long lBeforeIndentation
)
1136 fail(pDiag
== NULL
);
1137 fail(lBeforeIndentation
< 0);
1140 pDiag
->lYtop
-= lMilliPoints2DrawUnits(lBeforeIndentation
);
1141 } /* end of vStartOfParagraphPS */
1144 * Create an end of paragraph by moving the y-top mark
1147 vEndOfParagraphPS(diagram_type
*pDiag
,
1148 USHORT usFontSize
, long lAfterIndentation
)
1150 fail(pDiag
== NULL
);
1151 fail(pDiag
->pOutFile
== NULL
);
1152 fail(usFontSize
< MIN_FONT_SIZE
|| usFontSize
> MAX_FONT_SIZE
);
1153 fail(lAfterIndentation
< 0);
1155 if (pDiag
->lXleft
> 0) {
1156 /* To the start of the line */
1157 vMove2NextLinePS(pDiag
, usFontSize
);
1161 pDiag
->lYtop
-= lMilliPoints2DrawUnits(lAfterIndentation
);
1162 } /* end of vEndOfParagraphPS */
1165 * Create an end of page
1168 vEndOfPagePS(diagram_type
*pDiag
, BOOL bNewSection
)
1170 vMove2NextPage(pDiag
, bNewSection
);
1171 } /* end of vEndOfPagePS */