Imported from antiword-0.33.tar.gz.
[antiword.git] / postscript.c
blob5f4d0ff2660078ccde1c60b7925dbaec232bd6c6
1 /*
2 * postscript.c
3 * Copyright (C) 1999-2002 A.J. van Os; Released under GPL
5 * Description:
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.
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <time.h>
21 #include "version.h"
22 #include "antiword.h"
24 /* The output must be in PostScript */
25 static BOOL bUsePostScript = FALSE;
26 /* The character set */
27 static encoding_type eEncoding = encoding_neutral;
28 /* The image level */
29 static image_level_enum eImageLevel = level_default;
30 /* The output must use landscape orientation */
31 static BOOL bUseLandscape = FALSE;
32 /* The height of a PostScript page (in DrawUnits) */
33 static long lPageHeight = LONG_MAX;
34 /* Current time for a PS header */
35 static const char *szCreationDate = NULL;
36 /* Current creator for a PS header */
37 static const char *szCreator = NULL;
38 /* Current font information */
39 static draw_fontref tFontRefCurr = (draw_fontref)-1;
40 static short sFontsizeCurr = -1;
41 static int iColorCurr = -1;
42 /* Current vertical position information */
43 static long lYtopCurr = -1;
44 /* PostScript page counter */
45 static int iPageCount = 0;
46 /* Image counter */
47 static int iImageCount = 0;
48 /* Local representation of the non-breaking space */
49 static UCHAR ucNbsp = 0;
51 static char iso_8859_1_data[] = { "\
52 /newcodes % ISO-8859-1 character encodings\n\
53 [\n\
54 160/space 161/exclamdown 162/cent 163/sterling 164/currency\n\
55 165/yen 166/brokenbar 167/section 168/dieresis 169/copyright\n\
56 170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered\n\
57 175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior\n\
58 180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla\n\
59 185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter\n\
60 189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute\n\
61 194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla\n\
62 200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute\n\
63 206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute\n\
64 212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash\n\
65 217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn\n\
66 223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde\n\
67 228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute\n\
68 234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex\n\
69 239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex\n\
70 245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute\n\
71 251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis\n\
72 ] bind def\n\
73 \n\
74 /reencdict 12 dict def\n\
75 \n\
76 " };
78 static char iso_8859_2_data[] = { "\
79 /newcodes % ISO-8859-2 character encodings\n\
80 [\n\
81 160/space 161/Aogonek 162/breve 163/Lslash 164/currency 165/Lcaron\n\
82 166/Sacute 167/section 168/dieresis 169/Scaron 170/Scommaaccent\n\
83 171/Tcaron 172/Zacute 173/hyphen 174/Zcaron 175/Zdotaccent 176/degree\n\
84 177/aogonek 178/ogonek 179/lslash 180/acute 181/lcaron 182/sacute\n\
85 183/caron 184/cedilla 185/scaron 186/scommaaccent 187/tcaron\n\
86 188/zacute 189/hungarumlaut 190/zcaron 191/zdotaccent 192/Racute\n\
87 193/Aacute 194/Acircumflex 195/Abreve 196/Adieresis 197/Lacute\n\
88 198/Cacute 199/Ccedilla 200/Ccaron 201/Eacute 202/Eogonek\n\
89 203/Edieresis 204/Ecaron 205/Iacute 206/Icircumflex 207/Dcaron\n\
90 208/Dcroat 209/Nacute 210/Ncaron 211/Oacute 212/Ocircumflex\n\
91 213/Ohungarumlaut 214/Odieresis 215/multiply 216/Rcaron 217/Uring\n\
92 218/Uacute 219/Uhungarumlaut 220/Udieresis 221/Yacute 222/Tcommaaccent\n\
93 223/germandbls 224/racute 225/aacute 226/acircumflex 227/abreve\n\
94 228/adieresis 229/lacute 230/cacute 231/ccedilla 232/ccaron 233/eacute\n\
95 234/eogonek 235/edieresis 236/ecaron 237/iacute 238/icircumflex\n\
96 239/dcaron 240/dcroat 241/nacute 242/ncaron 243/oacute 244/ocircumflex\n\
97 245/ohungarumlaut 246/odieresis 247/divide 248/rcaron 249/uring\n\
98 250/uacute 251/uhungarumlaut 252/udieresis 253/yacute 254/tcommaaccent\n\
99 255/dotaccent\n\
100 ] bind def\n\
102 /reencdict 12 dict def\n\
104 " };
106 static char iso_8859_x_func[] = { "\
107 % change fonts using ISO-8859-x characters\n\
108 /ChgFnt % size psname natname => font\n\
109 {\n\
110 dup FontDirectory exch known % is re-encoded name known?\n\
111 { exch pop } % yes, get rid of long name\n\
112 { dup 3 1 roll ReEncode } ifelse % no, re-encode it\n\
113 findfont exch scalefont setfont\n\
114 } bind def\n\
116 /ReEncode\n\
117 {\n\
118 reencdict begin\n\
119 /newname exch def\n\
120 /basename exch def\n\
121 /basedict basename findfont def\n\
122 /newfont basedict maxlength dict def\n\
123 basedict\n\
124 { exch dup /FID ne\n\
125 { dup /Encoding eq\n\
126 { exch dup length array copy newfont 3 1 roll put }\n\
127 { exch newfont 3 1 roll put } ifelse\n\
128 }\n\
129 { pop pop } ifelse\n\
130 } forall\n\
131 newfont /FontName newname put\n\
132 newcodes aload pop newcodes length 2 idiv\n\
133 { newfont /Encoding get 3 1 roll put } repeat\n\
134 newname newfont definefont pop\n\
135 end\n\
136 } bind def\n\
138 " };
140 static char misc_func[] = { "\
141 % draw a line and show the string\n\
142 /LineShow % string linewidth movement\n\
143 {\n\
144 gsave\n\
145 0 exch rmoveto\n\
146 setlinewidth\n\
147 dup\n\
148 stringwidth pop\n\
149 0 rlineto stroke\n\
150 grestore\n\
151 show\n\
152 } bind def\n\
154 % begin an EPS file (level 2 and up)\n\
155 /BeginEPSF\n\
156 {\n\
157 /b4_Inc_state save def\n\
158 /dict_count countdictstack def\n\
159 /op_count count 1 sub def\n\
160 userdict begin\n\
161 /showpage { } def\n\
162 0 setgray 0 setlinecap\n\
163 1 setlinewidth 0 setlinejoin\n\
164 10 setmiterlimit [ ] 0 setdash newpath\n\
165 false setstrokeadjust false setoverprint\n\
166 } bind def\n\
168 % end an EPS file\n\
169 /EndEPSF {\n\
170 count op_count sub { pop } repeat\n\
171 countdictstack dict_count sub { end } repeat\n\
172 b4_Inc_state restore\n\
173 } bind def\n\
175 " };
179 * vAddPageSetup - add the page setup
181 static void
182 vAddPageSetup(FILE *pOutFile)
184 if (bUseLandscape) {
185 fprintf(pOutFile, "%%%%BeginPageSetup\n");
186 fprintf(pOutFile, "90 rotate\n");
187 fprintf(pOutFile, "0.00 %.2f translate\n",
188 -dDrawUnits2Points(lPageHeight));
189 fprintf(pOutFile, "%%%%EndPageSetup\n");
191 } /* end of vAddPageSetup */
194 * vMove2NextPage - move to the start of the next page
196 static void
197 vMove2NextPage(diagram_type *pDiag)
199 fail(pDiag == NULL);
200 fail(!bUsePostScript);
202 fprintf(pDiag->pOutFile, "showpage\n");
203 iPageCount++;
204 fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
205 vAddPageSetup(pDiag->pOutFile);
206 pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
207 lYtopCurr = -1;
208 } /* end of vMove2NextPage */
211 * vMoveToPS - move to the given X,Y coordinates (Postscript)
213 * Move the current position of the given diagram to its X,Y coordinates,
214 * start on a new page if needed
216 static void
217 vMoveToPS(diagram_type *pDiag, long lLastVerticalMovement)
219 fail(pDiag == NULL);
220 fail(pDiag->pOutFile == NULL);
222 if (pDiag->lYtop < PS_BOTTOM_MARGIN) {
223 vMove2NextPage(pDiag);
224 /* Repeat the last vertical movement on the new page */
225 pDiag->lYtop -= lLastVerticalMovement;
227 fail(pDiag->lYtop < PS_BOTTOM_MARGIN);
229 if (pDiag->lYtop != lYtopCurr) {
230 fprintf(pDiag->pOutFile, "%.2f %.2f moveto\n",
231 dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
232 dDrawUnits2Points(pDiag->lYtop));
233 lYtopCurr = pDiag->lYtop;
235 } /* end of vMoveToPS */
238 * vPrologue - set options and perform the PostScript initialization
240 static void
241 vPrologue(FILE *pOutFile, const char *szTask, const char *szFilename)
243 options_type tOptions;
244 const char *szTmp;
245 time_t tTime;
247 fail(pOutFile == NULL);
248 fail(szTask == NULL || szTask[0] == '\0');
250 vGetOptions(&tOptions);
251 if (tOptions.iPageHeight == INT_MAX) {
252 lPageHeight = LONG_MAX;
253 } else {
254 lPageHeight = lPoints2DrawUnits(tOptions.iPageHeight);
256 DBG_DEC(lPageHeight);
257 bUsePostScript = tOptions.bUseOutlineFonts;
258 bUseLandscape = tOptions.bUseLandscape;
259 eEncoding = tOptions.eEncoding;
260 eImageLevel = tOptions.eImageLevel;
261 tFontRefCurr = (draw_fontref)-1;
262 sFontsizeCurr = -1;
263 iColorCurr = -1;
264 lYtopCurr = -1;
265 iImageCount = 0;
267 if (!bUsePostScript) {
268 return;
271 szCreator = szTask;
273 fprintf(pOutFile, "%%!PS-Adobe-2.0\n");
274 fprintf(pOutFile, "%%%%Title: %s\n", szBasename(szFilename));
275 fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
276 szTmp = getenv("LOGNAME");
277 if (szTmp == NULL || szTmp[0] == '\0') {
278 szTmp = getenv("USER");
279 if (szTmp == NULL || szTmp[0] == '\0') {
280 szTmp = "unknown";
283 fprintf(pOutFile, "%%%%For: %.50s\n", szTmp);
284 errno = 0;
285 tTime = time(NULL);
286 if (tTime == (time_t)-1 && errno != 0) {
287 szCreationDate = NULL;
288 } else {
289 szCreationDate = ctime(&tTime);
291 if (szCreationDate == NULL || szCreationDate[0] == '\0') {
292 szCreationDate = "unknown\n";
294 fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
295 if (bUseLandscape) {
296 fprintf(pOutFile, "%%%%Orientation: Landscape\n");
297 fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
298 tOptions.iPageHeight, tOptions.iPageWidth);
299 } else {
300 fprintf(pOutFile, "%%%%Orientation: Portrait\n");
301 fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
302 tOptions.iPageWidth, tOptions.iPageHeight);
304 } /* end of vPrologue */
307 * vEpilogue - clean up after everything is done
309 static void
310 vEpilogue(FILE *pFile)
312 if (!bUsePostScript) {
313 fprintf(pFile, "\n");
314 return;
317 fprintf(pFile, "%%%%Trailer\n");
318 fprintf(pFile, "%%%%Pages: %d\n", iPageCount);
319 fprintf(pFile, "%%%%EOF\n");
320 szCreationDate = NULL;
321 szCreator = NULL;
322 } /* end of vEpilogue */
325 * vPrintPalette - print a postscript palette
327 static void
328 vPrintPalette(FILE *pOutFile, const imagedata_type *pImg)
330 int iIndex;
332 fail(pOutFile == NULL);
333 fail(pImg == NULL);
334 fail(pImg->iColorsUsed < 2);
335 fail(pImg->iColorsUsed > 256);
337 fprintf(pOutFile, "[ /Indexed\n");
338 fprintf(pOutFile, "\t/Device%s %d\n",
339 pImg->bColorImage ? "RGB" : "Gray", pImg->iColorsUsed - 1);
340 fprintf(pOutFile, "<");
341 for (iIndex = 0; iIndex < pImg->iColorsUsed; iIndex++) {
342 fprintf(pOutFile, "%02x",
343 (unsigned int)pImg->aucPalette[iIndex][0]);
344 if (pImg->bColorImage) {
345 fprintf(pOutFile, "%02x%02x",
346 (unsigned int)pImg->aucPalette[iIndex][1],
347 (unsigned int)pImg->aucPalette[iIndex][2]);
349 if (iIndex % 8 == 7) {
350 fprintf(pOutFile, "\n");
351 } else {
352 fprintf(pOutFile, " ");
355 fprintf(pOutFile, ">\n");
356 fprintf(pOutFile, "] setcolorspace\n");
357 } /* end of vPrintPalette */
360 * vImagePrologue - perform the Encapsulated PostScript initialization
362 void
363 vImagePrologue(diagram_type *pDiag, const imagedata_type *pImg)
365 FILE *pOutFile;
367 fail(pDiag == NULL);
368 fail(pDiag->pOutFile == NULL);
369 fail(pImg == NULL);
371 if (!bUsePostScript) {
372 return;
375 if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
376 return;
379 fail(szCreationDate == NULL);
380 fail(szCreator == NULL);
381 fail(eImageLevel == level_no_images);
383 iImageCount++;
385 DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
387 pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
388 vMoveToPS(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
390 pOutFile = pDiag->pOutFile;
392 fprintf(pOutFile, "BeginEPSF\n");
393 fprintf(pOutFile, "%%%%BeginDocument: image%03d.eps\n", iImageCount);
394 fprintf(pOutFile, "%%!PS-Adobe-2.0 EPSF-2.0\n");
395 fprintf(pOutFile, "%%%%Creator: %s %s\n", szCreator, VERSIONSTRING);
396 fprintf(pOutFile, "%%%%Title: Image %03d\n", iImageCount);
397 fprintf(pOutFile, "%%%%CreationDate: %s", szCreationDate);
398 fprintf(pOutFile, "%%%%BoundingBox: 0 0 %d %d\n",
399 pImg->iHorSizeScaled, pImg->iVerSizeScaled);
400 fprintf(pOutFile, "%%%%DocumentData: Clean7Bit\n");
401 fprintf(pOutFile, "%%%%LanguageLevel: 2\n");
402 fprintf(pOutFile, "%%%%EndComments\n");
403 fprintf(pOutFile, "%%%%BeginProlog\n");
404 fprintf(pOutFile, "%%%%EndProlog\n");
405 fprintf(pOutFile, "%%%%Page: 1 1\n");
407 fprintf(pOutFile, "save\n");
409 switch (pImg->eImageType) {
410 case imagetype_is_jpeg:
411 fprintf(pOutFile, "/Data1 currentfile ");
412 fprintf(pOutFile, "/ASCII85Decode filter def\n");
413 fprintf(pOutFile, "/Data Data1 << ");
414 fprintf(pOutFile, ">> /DCTDecode filter def\n");
415 switch (pImg->iComponents) {
416 case 1:
417 fprintf(pOutFile, "/DeviceGray setcolorspace\n");
418 break;
419 case 3:
420 fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
421 break;
422 case 4:
423 fprintf(pOutFile, "/DeviceCMYK setcolorspace\n");
424 break;
425 default:
426 DBG_DEC(pImg->iComponents);
427 break;
429 break;
430 case imagetype_is_png:
431 if (eImageLevel == level_gs_special) {
432 fprintf(pOutFile,
433 "/Data2 currentfile /ASCII85Decode filter def\n");
434 fprintf(pOutFile,
435 "/Data1 Data2 << >> /FlateDecode filter def\n");
436 fprintf(pOutFile, "/Data Data1 <<\n");
437 fprintf(pOutFile, "\t/Colors %d\n", pImg->iComponents);
438 fprintf(pOutFile, "\t/BitsPerComponent %d\n",
439 pImg->iBitsPerComponent);
440 fprintf(pOutFile, "\t/Columns %d\n", pImg->iWidth);
441 fprintf(pOutFile,
442 ">> /PNGPredictorDecode filter def\n");
443 } else {
444 fprintf(pOutFile,
445 "/Data1 currentfile /ASCII85Decode filter def\n");
446 fprintf(pOutFile,
447 "/Data Data1 << >> /FlateDecode filter def\n");
449 if (pImg->iComponents == 3) {
450 fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
451 } else if (pImg->iColorsUsed > 0) {
452 vPrintPalette(pOutFile, pImg);
453 } else {
454 fprintf(pOutFile, "/DeviceGray setcolorspace\n");
456 break;
457 case imagetype_is_dib:
458 fprintf(pOutFile, "/Data currentfile ");
459 fprintf(pOutFile, "/ASCII85Decode filter def\n");
460 if (pImg->iBitsPerComponent <= 8) {
461 vPrintPalette(pOutFile, pImg);
462 } else {
463 fprintf(pOutFile, "/DeviceRGB setcolorspace\n");
465 break;
466 default:
467 fprintf(pOutFile, "/Data currentfile ");
468 fprintf(pOutFile, "/ASCIIHexDecode filter def\n");
469 fprintf(pOutFile, "/Device%s setcolorspace\n",
470 pImg->bColorImage ? "RGB" : "Gray");
471 break;
474 /* Translate to lower left corner of image */
475 fprintf(pOutFile, "%.2f %.2f translate\n",
476 dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
477 dDrawUnits2Points(pDiag->lYtop));
479 fprintf(pOutFile, "%d %d scale\n",
480 pImg->iHorSizeScaled, pImg->iVerSizeScaled);
482 fprintf(pOutFile, "{ <<\n");
483 fprintf(pOutFile, "\t/ImageType 1\n");
484 fprintf(pOutFile, "\t/Width %d\n", pImg->iWidth);
485 fprintf(pOutFile, "\t/Height %d\n", pImg->iHeight);
486 if (pImg->eImageType == imagetype_is_dib) {
487 /* Scanning from left to right and bottom to top */
488 fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 0 ]\n",
489 pImg->iWidth, pImg->iHeight);
490 } else {
491 /* Scanning from left to right and top to bottom */
492 fprintf(pOutFile, "\t/ImageMatrix [ %d 0 0 %d 0 %d ]\n",
493 pImg->iWidth, -pImg->iHeight, pImg->iHeight);
495 fprintf(pOutFile, "\t/DataSource Data\n");
497 switch (pImg->eImageType) {
498 case imagetype_is_jpeg:
499 fprintf(pOutFile, "\t/BitsPerComponent 8\n");
500 switch (pImg->iComponents) {
501 case 1:
502 fprintf(pOutFile, "\t/Decode [0 1]\n");
503 break;
504 case 3:
505 fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
506 break;
507 case 4:
508 if (pImg->bAdobe) {
510 * Adobe-conforming CMYK file
511 * applying workaround for color inversion
513 fprintf(pOutFile,
514 "\t/Decode [1 0 1 0 1 0 1 0]\n");
515 } else {
516 fprintf(pOutFile,
517 "\t/Decode [0 1 0 1 0 1 0 1]\n");
519 break;
520 default:
521 DBG_DEC(pImg->iComponents);
522 break;
524 break;
525 case imagetype_is_png:
526 if (pImg->iComponents == 3) {
527 fprintf(pOutFile, "\t/BitsPerComponent 8\n");
528 fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
529 } else if (pImg->iColorsUsed > 0) {
530 fail(pImg->iBitsPerComponent > 8);
531 fprintf(pOutFile, "\t/BitsPerComponent %d\n",
532 pImg->iBitsPerComponent);
533 fprintf(pOutFile, "\t/Decode [0 %d]\n",
534 (1 << pImg->iBitsPerComponent) - 1);
535 } else {
536 fprintf(pOutFile, "\t/BitsPerComponent 8\n");
537 fprintf(pOutFile, "\t/Decode [0 1]\n");
539 break;
540 case imagetype_is_dib:
541 fprintf(pOutFile, "\t/BitsPerComponent 8\n");
542 if (pImg->iBitsPerComponent <= 8) {
543 fprintf(pOutFile, "\t/Decode [0 255]\n");
544 } else {
545 fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
547 break;
548 default:
549 fprintf(pOutFile, "\t/BitsPerComponent 8\n");
550 if (pImg->bColorImage) {
551 fprintf(pOutFile, "\t/Decode [0 1 0 1 0 1]\n");
552 } else {
553 fprintf(pOutFile, "\t/Decode [0 1]\n");
555 break;
558 fprintf(pOutFile, " >> image\n");
559 fprintf(pOutFile, " Data closefile\n");
560 fprintf(pOutFile, " showpage\n");
561 fprintf(pOutFile, " restore\n");
562 fprintf(pOutFile, "} exec\n");
563 } /* end of vImagePrologue */
566 * vImageEpilogue - clean up after Encapsulated PostScript
568 void
569 vImageEpilogue(diagram_type *pDiag)
571 FILE *pOutFile;
573 if (!bUsePostScript) {
574 return;
577 fail(pDiag == NULL);
578 fail(pDiag->pOutFile == NULL);
580 pOutFile = pDiag->pOutFile;
582 fprintf(pOutFile, "%%%%EOF\n");
583 fprintf(pOutFile, "%%%%EndDocument\n");
584 fprintf(pOutFile, "EndEPSF\n");
586 pDiag->lXleft = 0;
587 } /* end of vImageEpilogue */
590 * bAddDummyImage - add a dummy image
592 * return TRUE when successful, otherwise FALSE
594 BOOL
595 bAddDummyImage(diagram_type *pDiag, const imagedata_type *pImg)
597 FILE *pOutFile;
599 fail(pDiag == NULL);
600 fail(pDiag->pOutFile == NULL);
601 fail(pImg == NULL);
603 if (!bUsePostScript) {
604 return FALSE;
607 if (pImg->iVerSizeScaled <= 0 || pImg->iHorSizeScaled <= 0) {
608 return FALSE;
611 iImageCount++;
613 DBG_DEC_C(pDiag->lXleft != 0, pDiag->lXleft);
615 pDiag->lYtop -= lPoints2DrawUnits(pImg->iVerSizeScaled);
616 vMoveToPS(pDiag, lPoints2DrawUnits(pImg->iVerSizeScaled));
618 pOutFile = pDiag->pOutFile;
620 fprintf(pOutFile, "gsave %% Image %03d\n", iImageCount);
621 fprintf(pOutFile, "\tnewpath\n");
622 fprintf(pOutFile, "\t%.2f %.2f moveto\n",
623 dDrawUnits2Points(pDiag->lXleft + PS_LEFT_MARGIN),
624 dDrawUnits2Points(pDiag->lYtop));
625 fprintf(pOutFile, "\t1.0 setlinewidth\n");
626 fprintf(pOutFile, "\t0.3 setgray\n");
627 fprintf(pOutFile, "\t0 %d rlineto\n", pImg->iVerSizeScaled);
628 fprintf(pOutFile, "\t%d 0 rlineto\n", pImg->iHorSizeScaled);
629 fprintf(pOutFile, "\t0 %d rlineto\n", -pImg->iVerSizeScaled);
630 fprintf(pOutFile, "\tclosepath\n");
631 fprintf(pOutFile, "\tstroke\n");
632 fprintf(pOutFile, "grestore\n");
634 pDiag->lXleft = 0;
636 return TRUE;
637 } /* end of bAddDummyImage */
640 * pCreateDiagram - create and initialize a diagram
642 * remark: does not return if the diagram can't be created
644 diagram_type *
645 pCreateDiagram(const char *szTask, const char *szFilename)
647 diagram_type *pDiag;
649 fail(szTask == NULL || szTask[0] == '\0');
650 DBG_MSG("pCreateDiagram");
652 /* Get the necessary memory */
653 pDiag = xmalloc(sizeof(diagram_type));
654 /* Initialization */
655 pDiag->pOutFile = stdout;
656 vPrologue(pDiag->pOutFile, szTask, szFilename);
657 iPageCount = 0;
658 pDiag->lXleft = 0;
659 if (bUsePostScript) {
660 pDiag->lYtop = lPageHeight - PS_TOP_MARGIN;
661 } else {
662 pDiag->lYtop = 0;
664 /* Return success */
665 return pDiag;
666 } /* end of pCreateDiagram */
669 * vDestroyDiagram - remove a diagram by freeing the memory it uses
671 void
672 vDestroyDiagram(diagram_type *pDiag)
674 DBG_MSG("vDestroyDiagram");
676 fail(pDiag == NULL);
678 if (pDiag == NULL) {
679 return;
681 if (bUsePostScript && pDiag->lYtop < lPageHeight - PS_TOP_MARGIN) {
682 fprintf(pDiag->pOutFile, "showpage\n");
684 vEpilogue(pDiag->pOutFile);
685 pDiag = xfree(pDiag);
686 } /* end of vDestroyDiagram */
689 * vAddFonts2Diagram - add the list of fonts and complete the prologue
691 void
692 vAddFonts2Diagram(diagram_type *pDiag)
694 FILE *pOutFile;
695 const font_table_type *pTmp, *pTmp2;
696 int iLineLen;
697 BOOL bFound;
699 fail(pDiag == NULL);
700 fail(pDiag->pOutFile == NULL);
702 if (!bUsePostScript) {
703 return;
706 pOutFile = pDiag->pOutFile;
707 iLineLen = fprintf(pOutFile, "%%%%DocumentFonts:");
709 if (tGetFontTableLength() == 0) {
710 iLineLen += fprintf(pOutFile, " Courier");
711 } else {
712 pTmp = NULL;
713 while ((pTmp = pGetNextFontTableRecord(pTmp)) != NULL) {
714 /* Print the document fonts */
715 bFound = FALSE;
716 pTmp2 = NULL;
717 while ((pTmp2 = pGetNextFontTableRecord(pTmp2))
718 != NULL && pTmp2 < pTmp) {
719 bFound = STREQ(pTmp2->szOurFontname,
720 pTmp->szOurFontname);
721 if (bFound) {
722 break;
725 if (bFound) {
726 continue;
728 if (iLineLen + (int)strlen(pTmp->szOurFontname) > 78) {
729 fprintf(pOutFile, "\n%%%%+");
730 iLineLen = 3;
732 iLineLen += fprintf(pOutFile,
733 " %s", pTmp->szOurFontname);
736 fprintf(pOutFile, "\n");
737 fprintf(pOutFile, "%%%%Pages: (atend)\n");
738 fprintf(pOutFile, "%%%%EndComments\n");
739 fprintf(pOutFile, "%%%%BeginProlog\n");
741 switch (eEncoding) {
742 case encoding_iso_8859_1:
743 fprintf(pOutFile, "%s\n%s", iso_8859_1_data, iso_8859_x_func);
744 break;
745 case encoding_iso_8859_2:
746 fprintf(pOutFile, "%s\n%s", iso_8859_2_data, iso_8859_x_func);
747 break;
748 default:
749 DBG_DEC(eEncoding);
750 break;
753 /* The rest of the functions */
754 fprintf(pOutFile, "%s", misc_func);
755 fprintf(pOutFile, "%%%%EndProlog\n");
756 iPageCount = 1;
757 fprintf(pDiag->pOutFile, "%%%%Page: %d %d\n", iPageCount, iPageCount);
758 vAddPageSetup(pDiag->pOutFile);
759 } /* end of vAddFonts2Diagram */
762 * vPrintPS - print a PostScript string
764 static void
765 vPrintPS(FILE *pFile, const char *szString, int iStringLength,
766 UCHAR ucFontstyle)
768 const UCHAR *ucBytes;
769 int iCount;
771 fail(szString == NULL || iStringLength < 0);
773 if (szString == NULL || szString[0] == '\0' || iStringLength <= 0) {
774 return;
777 ucBytes = (UCHAR *)szString;
778 (void)putc('(', pFile);
779 for (iCount = 0; iCount < iStringLength ; iCount++) {
780 switch (ucBytes[iCount]) {
781 case '(':
782 case ')':
783 case '\\':
784 (void)putc('\\', pFile);
785 (void)putc(szString[iCount], pFile);
786 break;
787 default:
788 if ((int)ucBytes[iCount] < 0x20 ||
789 ((int)ucBytes[iCount] >= 0x7f &&
790 (int)ucBytes[iCount] < 0xa0)) {
791 DBG_HEX(ucBytes[iCount]);
792 (void)putc(' ', pFile);
793 } else if ((int)ucBytes[iCount] >= 0x80) {
794 fprintf(pFile, "\\%03o",
795 (unsigned int)ucBytes[iCount]);
796 } else {
797 (void)putc(szString[iCount], pFile);
799 break;
802 fprintf(pFile, ") ");
803 if ((bIsStrike(ucFontstyle) || bIsMarkDel(ucFontstyle)) &&
804 sFontsizeCurr > 0) {
805 fprintf(pFile, "%.2f %.2f LineShow\n",
806 sFontsizeCurr * 0.02, sFontsizeCurr * 0.12);
807 } else if (bIsUnderline(ucFontstyle) && sFontsizeCurr > 0) {
808 fprintf(pFile, "%.2f %.2f LineShow\n",
809 sFontsizeCurr * 0.02, sFontsizeCurr * -0.06);
810 } else {
811 fprintf(pFile, "show\n");
813 } /* end of vPrintPS */
816 * vPrintTXT - print a Text string
818 static void
819 vPrintTXT(FILE *pFile, const char *szString, int iStringLength)
821 const UCHAR *ucBytes;
822 int iCount;
824 fail(szString == NULL || iStringLength < 0);
826 if (szString == NULL || szString[0] == '\0' || iStringLength <= 0) {
827 return;
830 if (eEncoding == encoding_utf8) {
831 fprintf(pFile, "%.*s", iStringLength, szString);
832 return;
835 if (ucNbsp == 0) {
836 ucNbsp = ucGetNbspValue();
837 DBG_HEX_C(ucNbsp != 0xa0, ucNbsp);
840 ucBytes = (UCHAR *)szString;
841 for (iCount = 0; iCount < iStringLength ; iCount++) {
842 if (ucBytes[iCount] == ucNbsp) {
843 (void)putc(' ', pFile);
844 } else {
845 (void)putc(szString[iCount], pFile);
848 } /* end of vPrintTXT */
851 * vSetColor - move to the given color
853 static void
854 vSetColor(FILE *pFile, int iColor)
856 ULONG ulTmp, ulRed, ulGreen, ulBlue;
858 ulTmp = ulColor2Color(iColor);
859 ulRed = (ulTmp & 0x0000ff00) >> 8;
860 ulGreen = (ulTmp & 0x00ff0000) >> 16;
861 ulBlue = (ulTmp & 0xff000000) >> 24;
862 fprintf(pFile, "%.3f %.3f %.3f setrgbcolor\n",
863 ulRed / 255.0, ulGreen / 255.0, ulBlue / 255.0);
864 } /* end of vSetColor */
867 * vMoveToTXT - move to the given X,Y coordinates (Text)
869 * Move the current position of the given diagram to its X,Y coordinates,
870 * start on a new page if needed
872 static void
873 vMoveToTXT(diagram_type *pDiag)
875 int iCount, iNbr;
877 fail(pDiag == NULL);
878 fail(pDiag->pOutFile == NULL);
880 if (pDiag->lYtop != lYtopCurr) {
881 iNbr = iDrawUnits2Char(pDiag->lXleft);
882 for (iCount = 0; iCount < iNbr; iCount++) {
883 (void)putc(FILLER_CHAR, pDiag->pOutFile);
885 lYtopCurr = pDiag->lYtop;
887 } /* end of vMoveToTXT */
890 * vMove2NextLine - move to the next line
892 void
893 vMove2NextLine(diagram_type *pDiag, draw_fontref tFontRef, short sFontsize)
895 fail(pDiag == NULL);
896 fail(pDiag->pOutFile == NULL);
897 fail(sFontsize < MIN_FONT_SIZE || sFontsize > MAX_FONT_SIZE);
899 pDiag->lYtop -= lComputeLeading(sFontsize);
900 if (!bUsePostScript) {
901 (void)fprintf(pDiag->pOutFile, "\n");
903 } /* end of vMove2NextLine */
906 * vSubstring2Diagram - put a sub string into a diagram
908 void
909 vSubstring2Diagram(diagram_type *pDiag,
910 char *szString, int iStringLength, long lStringWidth,
911 int iColor, UCHAR ucFontstyle, draw_fontref tFontRef,
912 short sFontsize, short sMaxFontsize)
914 const char *szOurFontname;
916 fail(pDiag == NULL || szString == NULL);
917 fail(pDiag->pOutFile == NULL);
918 fail(pDiag->lXleft < 0);
919 fail(iStringLength < 0);
920 fail((size_t)iStringLength != strlen(szString));
921 fail(sFontsize < MIN_FONT_SIZE || sFontsize > MAX_FONT_SIZE);
922 fail(sMaxFontsize < MIN_FONT_SIZE || sMaxFontsize > MAX_FONT_SIZE);
923 fail(sFontsize > sMaxFontsize);
925 if (szString[0] == '\0' || iStringLength <= 0) {
926 return;
929 if (bUsePostScript) {
930 if (tFontRef != tFontRefCurr || sFontsize != sFontsizeCurr) {
931 szOurFontname = szGetFontname(tFontRef);
932 fail(szOurFontname == NULL);
933 fprintf(pDiag->pOutFile,
934 "%.1f /%s /%s-ISO-8859-x ChgFnt\n",
935 (double)sFontsize / 2.0,
936 szOurFontname, szOurFontname);
937 tFontRefCurr = tFontRef;
938 sFontsizeCurr = sFontsize;
940 if (iColor != iColorCurr) {
941 vSetColor(pDiag->pOutFile, iColor);
942 iColorCurr = iColor;
944 vMoveToPS(pDiag, lComputeLeading(sMaxFontsize));
945 vPrintPS(pDiag->pOutFile, szString, iStringLength, ucFontstyle);
946 } else {
947 vMoveToTXT(pDiag);
948 vPrintTXT(pDiag->pOutFile, szString, iStringLength);
950 pDiag->lXleft += lStringWidth;
951 } /* end of vSubstring2Diagram */
954 * Create an start of paragraph by moving the y-top mark
956 void
957 vStartOfParagraph2Diagram(diagram_type *pDiag,
958 draw_fontref tFontRef, short sFontsize, long lBeforeIndentation)
960 fail(pDiag == NULL);
961 fail(pDiag->pOutFile == NULL);
962 fail(sFontsize < MIN_FONT_SIZE || sFontsize > MAX_FONT_SIZE);
963 fail(lBeforeIndentation < 0);
965 if (bUsePostScript) {
966 pDiag->lXleft = 0;
967 pDiag->lYtop -= lMilliPoints2DrawUnits(lBeforeIndentation);
968 } else {
969 if (lBeforeIndentation >= lTwips2MilliPoints(HEADING_GAP)) {
970 /* A large gap is replaced by an empty line */
971 vMove2NextLine(pDiag, tFontRef, sFontsize);
974 } /* end of vStartOfParagraph2Diagram */
977 * Create an end of paragraph by moving the y-top mark
979 void
980 vEndOfParagraph2Diagram(diagram_type *pDiag,
981 draw_fontref tFontRef, short sFontsize, long lAfterIndentation)
983 fail(pDiag == NULL);
984 fail(pDiag->pOutFile == NULL);
985 fail(sFontsize < MIN_FONT_SIZE || sFontsize > MAX_FONT_SIZE);
986 fail(lAfterIndentation < 0);
988 if (pDiag->lXleft > 0) {
989 /* To the start of the line */
990 vMove2NextLine(pDiag, tFontRef, sFontsize);
993 if (bUsePostScript) {
994 pDiag->lXleft = 0;
995 pDiag->lYtop -= lMilliPoints2DrawUnits(lAfterIndentation);
996 } else {
997 if (lAfterIndentation >= lTwips2MilliPoints(HEADING_GAP)) {
998 /* A large gap is replaced by an empty line */
999 vMove2NextLine(pDiag, tFontRef, sFontsize);
1002 } /* end of vEndOfParagraph2Diagram */
1005 * Create an end of page
1007 void
1008 vEndOfPage2Diagram(diagram_type *pDiag,
1009 draw_fontref tFontRef, short sFontsize, long lAfterIndentation)
1011 if (bUsePostScript) {
1012 vMove2NextPage(pDiag);
1013 } else {
1014 vEndOfParagraph2Diagram(pDiag,
1015 tFontRef,
1016 sFontsize,
1017 lAfterIndentation);
1019 } /* end of vEndOfPage2Diagram */