1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
28 #include "FormWidget.h"
29 #include "PSOutputDev.h"
32 #include "Japan12ToRKSJ.h"
36 // needed for setting type/creator of MacOS files
37 #include "ICSupport.h"
40 //------------------------------------------------------------------------
42 //------------------------------------------------------------------------
44 // Generate Level 1 PostScript?
45 GBool psOutLevel1 = gFalse;
47 // Generate Level 1 separable PostScript?
48 GBool psOutLevel1Sep = gFalse;
50 // Generate Encapsulated PostScript?
51 GBool psOutEPS = gFalse;
54 // Generate OPI comments?
55 GBool psOutOPI = gFalse;
58 int paperWidth = defPaperWidth;
59 int paperHeight = defPaperHeight;
61 //------------------------------------------------------------------------
62 // PostScript prolog and setup
63 //------------------------------------------------------------------------
65 static char *prolog[] = {
66 "/xpdf 75 dict def xpdf begin",
67 "% PDF special state",
68 "/pdfDictSize 14 def",
71 " /setpagedevice where {",
72 " pop 3 dict dup begin",
73 " exch /PageSize exch def",
74 " /ImagingBBox null def",
75 " /Policies 1 dict dup begin /PageSize 3 def end def",
82 " pdfDictSize dict begin",
84 " /pdfStroke [0] def",
85 " /pdfLastFill false def",
86 " /pdfLastStroke false def",
87 " /pdfTextMat [1 0 0 1 0 0] def",
88 " /pdfFontSize 0 def",
89 " /pdfCharSpacing 0 def",
90 " /pdfTextRender 0 def",
91 " /pdfTextRise 0 def",
92 " /pdfWordSpacing 0 def",
93 " /pdfHorizScaling 1 def",
95 "/pdfEndPage { end } def",
97 " pdfLastStroke not {",
98 " pdfStroke aload length",
99 " dup 1 eq { pop setgray }",
100 " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
101 " /pdfLastStroke true def /pdfLastFill false def",
105 " pdfLastFill not {",
106 " pdfFill aload length",
107 " dup 1 eq { pop setgray }",
108 " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
109 " /pdfLastFill true def /pdfLastStroke false def",
114 " 4 3 roll findfont",
115 " 4 2 roll matrix scale makefont",
116 " dup length dict begin",
117 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
118 " /Encoding exch def",
123 "/pdfMakeFont16 { findfont definefont pop } def",
124 "% graphics state operators",
125 "/q { gsave pdfDictSize dict begin } def",
126 "/Q { end grestore } def",
127 "/cm { concat } def",
128 "/d { setdash } def",
129 "/i { setflat } def",
130 "/j { setlinejoin } def",
131 "/J { setlinecap } def",
132 "/M { setmiterlimit } def",
133 "/w { setlinewidth } def",
135 "/g { dup 1 array astore /pdfFill exch def setgray",
136 " /pdfLastFill true def /pdfLastStroke false def } def",
137 "/G { dup 1 array astore /pdfStroke exch def setgray",
138 " /pdfLastStroke true def /pdfLastFill false def } def",
139 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
140 " /pdfLastFill true def /pdfLastStroke false def } def",
141 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
142 " /pdfLastStroke true def /pdfLastFill false def } def",
143 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
144 " /pdfLastFill true def /pdfLastStroke false def } def",
145 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
146 " /pdfLastStroke true def /pdfLastFill false def } def",
147 "% path segment operators",
150 "/c { curveto } def",
151 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
152 " neg 0 rlineto closepath } def",
153 "/h { closepath } def",
154 "% path painting operators",
155 "/S { sCol stroke } def",
156 "/f { fCol fill } def",
157 "/f* { fCol eofill } def",
158 "% clipping operators",
159 "/W { clip newpath } def",
160 "/W* { eoclip newpath } def",
161 "% text state operators",
162 "/Tc { /pdfCharSpacing exch def } def",
163 "/Tf { dup /pdfFontSize exch def",
164 " dup pdfHorizScaling mul exch matrix scale",
165 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
166 " exch findfont exch makefont setfont } def",
167 "/Tr { /pdfTextRender exch def } def",
168 "/Ts { /pdfTextRise exch def } def",
169 "/Tw { /pdfWordSpacing exch def } def",
170 "/Tz { /pdfHorizScaling exch def } def",
171 "% text positioning operators",
172 "/Td { pdfTextMat transform moveto } def",
173 "/Tm { /pdfTextMat exch def } def",
174 "% text string operators",
175 "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
176 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
177 " pdfFontSize mul pdfHorizScaling mul",
178 " 1 index stringwidth pdfTextMat idtransform pop",
179 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
180 " pdfWordSpacing 0 pdfTextMat dtransform 32",
181 " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
182 " 6 5 roll awidthshow",
183 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
184 "/TJm { pdfFontSize 0.001 mul mul neg 0",
185 " pdfTextMat dtransform rmoveto } def",
186 "% Level 1 image operators",
188 " /pdfImBuf1 4 index string def",
189 " { currentfile pdfImBuf1 readhexstring pop } image",
192 " /pdfImBuf1 4 index string def",
193 " /pdfImBuf2 4 index string def",
194 " /pdfImBuf3 4 index string def",
195 " /pdfImBuf4 4 index string def",
196 " { currentfile pdfImBuf1 readhexstring pop }",
197 " { currentfile pdfImBuf2 readhexstring pop }",
198 " { currentfile pdfImBuf3 readhexstring pop }",
199 " { currentfile pdfImBuf4 readhexstring pop }",
200 " true 4 colorimage",
203 " /pdfImBuf1 4 index 7 add 8 idiv string def",
204 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
206 "% Level 2 image operators",
207 "/pdfImBuf 100 string def",
210 " { currentfile pdfImBuf readline",
211 " not { pop exit } if",
212 " (%-EOD-) eq { exit } if } loop",
216 " { currentfile pdfImBuf readline",
217 " not { pop exit } if",
218 " (%-EOD-) eq { exit } if } loop",
224 //------------------------------------------------------------------------
226 //------------------------------------------------------------------------
229 char *name; // PDF name
230 char *psName; // PostScript name
234 char *psName; // PostScript name
235 double mWidth; // width of 'm' character
238 static PSFont psFonts[] = {
239 {"Courier", "Courier"},
240 {"Courier-Bold", "Courier-Bold"},
241 {"Courier-Oblique", "Courier-Bold"},
242 {"Courier-BoldOblique", "Courier-BoldOblique"},
243 {"Helvetica", "Helvetica"},
244 {"Helvetica-Bold", "Helvetica-Bold"},
245 {"Helvetica-Oblique", "Helvetica-Oblique"},
246 {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
247 {"Symbol", "Symbol"},
248 {"Times-Roman", "Times-Roman"},
249 {"Times-Bold", "Times-Bold"},
250 {"Times-Italic", "Times-Italic"},
251 {"Times-BoldItalic", "Times-BoldItalic"},
252 {"ZapfDingbats", "ZapfDingbats"},
256 static PSSubstFont psSubstFonts[] = {
257 {"Helvetica", 0.833},
258 {"Helvetica-Oblique", 0.833},
259 {"Helvetica-Bold", 0.889},
260 {"Helvetica-BoldOblique", 0.889},
261 {"Times-Roman", 0.788},
262 {"Times-Italic", 0.722},
263 {"Times-Bold", 0.833},
264 {"Times-BoldItalic", 0.778},
266 {"Courier-Oblique", 0.600},
267 {"Courier-Bold", 0.600},
268 {"Courier-BoldOblique", 0.600}
271 //------------------------------------------------------------------------
273 //------------------------------------------------------------------------
275 PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
276 int firstPage, int lastPage,
277 GBool embedType11, GBool doForm1) {
280 FormWidgets *formWidgets;
287 embedType1 = embedType11;
291 fontFileNames = NULL;
295 lastPage = firstPage;
299 if (!strcmp(fileName, "-")) {
302 } else if (fileName[0] == '|') {
306 signal(SIGPIPE, (void (*)(int))SIG_IGN);
308 if (!(f = popen(fileName + 1, "w"))) {
309 error(-1, "Couldn't run print command '%s'", fileName);
314 error(-1, "Print commands are not supported ('%s')", fileName);
320 if (!(f = fopen(fileName, "w"))) {
321 error(-1, "Couldn't open PostScript file '%s'", fileName);
327 // initialize fontIDs, fontFileIDs, and fontFileNames lists
330 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
333 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
334 fontFileNameSize = 64;
336 fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
338 // initialize embedded font resource comment list
339 embFontList = new GString();
343 writePS("%%!PS-Adobe-3.0 Resource-Form\n");
344 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
345 writePS("%%%%LanguageLevel: %d\n",
346 (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
347 if (psOutLevel1Sep) {
348 writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
350 writePS("%%%%EndComments\n");
351 page = catalog->getPage(firstPage);
352 writePS("32 dict dup begin\n");
353 writePS("/BBox [%d %d %d %d] def\n",
354 (int)page->getX1(), (int)page->getY1(),
355 (int)page->getX2(), (int)page->getY2());
356 writePS("/FormType 1 def\n");
357 writePS("/Matrix [1 0 0 1 0 0] def\n");
358 } else if (psOutEPS) {
359 writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
360 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
361 writePS("%%%%LanguageLevel: %d\n",
362 (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
363 if (psOutLevel1Sep) {
364 writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
366 page = catalog->getPage(firstPage);
367 writePS("%%%%BoundingBox: %d %d %d %d\n",
368 (int)floor(page->getX1()), (int)floor(page->getY1()),
369 (int)ceil(page->getX2()), (int)ceil(page->getY2()));
370 if (floor(page->getX1()) != ceil(page->getX1()) ||
371 floor(page->getY1()) != ceil(page->getY1()) ||
372 floor(page->getX2()) != ceil(page->getX2()) ||
373 floor(page->getY2()) != ceil(page->getY2())) {
374 writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
375 page->getX1(), page->getY1(),
376 page->getX2(), page->getY2());
378 writePS("%%%%DocumentSuppliedResources: (atend)\n");
379 writePS("%%%%EndComments\n");
381 writePS("%%!PS-Adobe-3.0\n");
382 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
383 writePS("%%%%LanguageLevel: %d\n",
384 (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
385 if (psOutLevel1Sep) {
386 writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
388 writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
389 paperWidth, paperHeight);
390 writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
391 writePS("%%%%EndComments\n");
392 writePS("%%%%BeginDefaults\n");
393 writePS("%%%%PageMedia: plain\n");
394 writePS("%%%%EndDefaults\n");
399 writePS("%%%%BeginProlog\n");
401 writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
402 for (p = prolog; *p; ++p) {
405 writePS("%%%%EndResource\n");
407 writePS("%%%%EndProlog\n");
410 // set up fonts and images
411 type3Warning = gFalse;
413 // swap the form and xpdf dicts
414 writePS("xpdf end begin dup begin\n");
416 writePS("%%%%BeginSetup\n");
417 writePS("xpdf begin\n");
419 for (pg = firstPage; pg <= lastPage; ++pg) {
420 page = catalog->getPage(pg);
421 if ((resDict = page->getResourceDict())) {
422 setupResources(resDict);
424 formWidgets = new FormWidgets(page->getAnnots(&obj1));
426 for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
427 if (formWidgets->getWidget(i)->getAppearance(&obj1)->isStream()) {
428 obj1.streamGetDict()->lookup("Resources", &obj2);
430 setupResources(obj2.getDict());
441 writePS("/opiMatrix matrix currentmatrix def\n");
445 writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
447 writePS("%%%%EndSetup\n");
450 // initialize sequential page number
454 // initialize OPI nesting levels
460 PSOutputDev::~PSOutputDev() {
465 writePS("/Foo exch /Form defineresource pop\n");
466 } else if (psOutEPS) {
467 writePS("%%%%Trailer\n");
469 writePS("%%%%DocumentSuppliedResources:\n");
470 writePS("%s", embFontList->getCString());
471 writePS("%%%%EOF\n");
473 writePS("%%%%Trailer\n");
475 writePS("%%%%EOF\n");
477 if (fileType == psFile) {
479 ICS_MapRefNumAndAssign((short)f->handle);
484 else if (fileType == psPipe) {
487 signal(SIGPIPE, (void (*)(int))SIG_DFL);
502 for (i = 0; i < fontFileNameLen; ++i) {
503 delete fontFileNames[i];
505 gfree(fontFileNames);
509 void PSOutputDev::setupResources(Dict *resDict) {
510 Object xObjDict, xObj, resObj;
514 setupImages(resDict);
516 resDict->lookup("XObject", &xObjDict);
517 if (xObjDict.isDict()) {
518 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
519 xObjDict.dictGetVal(i, &xObj);
520 if (xObj.isStream()) {
521 xObj.streamGetDict()->lookup("Resources", &resObj);
522 if (resObj.isDict()) {
523 setupResources(resObj.getDict());
533 void PSOutputDev::setupFonts(Dict *resDict) {
535 GfxFontDict *gfxFontDict;
539 resDict->lookup("Font", &fontDict);
540 if (fontDict.isDict()) {
541 gfxFontDict = new GfxFontDict(fontDict.getDict());
542 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
543 font = gfxFontDict->getFont(i);
551 void PSOutputDev::setupFont(GfxFont *font) {
563 // check if font is already set up
564 for (i = 0; i < fontIDLen; ++i) {
565 if (fontIDs[i].num == font->getID().num &&
566 fontIDs[i].gen == font->getID().gen)
570 // add entry to fontIDs list
571 if (fontIDLen >= fontIDSize) {
573 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
575 fontIDs[fontIDLen++] = font->getID();
580 // check for embedded Type 1 font
581 if (embedType1 && font->getType() == fontType1 &&
582 font->getEmbeddedFontID(&fontFileID)) {
583 psName = font->getEmbeddedFontName();
584 setupEmbeddedType1Font(&fontFileID, psName);
586 // check for external Type 1 font file
587 } else if (embedType1 && font->getType() == fontType1 &&
588 font->getExtFontFile()) {
589 // this assumes that the PS font name matches the PDF font name
590 psName = font->getName()->getCString();
591 setupEmbeddedType1Font(font->getExtFontFile(), psName);
593 // check for embedded Type 1C font
594 } else if (embedType1 && font->getType() == fontType1C &&
595 font->getEmbeddedFontID(&fontFileID)) {
596 psName = font->getEmbeddedFontName();
597 setupEmbeddedType1CFont(font, &fontFileID, psName);
599 } else if (font->is16Bit() && font->getCharSet16() == font16AdobeJapan12) {
600 psName = "Ryumin-Light-RKSJ";
603 // do font substitution
605 if (!type3Warning && font->getType() == fontType3) {
606 error(-1, "This document uses Type 3 fonts - some text may not be correctly printed");
607 type3Warning = gTrue;
609 name = font->getName();
612 for (i = 0; psFonts[i].name; ++i) {
613 if (name->cmp(psFonts[i].name) == 0) {
614 psName = psFonts[i].psName;
620 if (font->isFixedWidth())
622 else if (font->isSerif())
628 if (font->isItalic())
630 psName = psSubstFonts[i].psName;
631 if ((code = font->getCharCode("m")) >= 0) {
632 w1 = font->getWidth(code);
636 w2 = psSubstFonts[i].mWidth;
641 if (font->getType() == fontType3) {
642 // This is a hack which makes it possible to substitute for some
643 // Type 3 fonts. The problem is that it's impossible to know what
644 // the base coordinate system used in the font is without actually
645 // rendering the font.
647 fm = font->getFontMatrix();
657 // generate PostScript code to set up the font
659 writePS("/F%d_%d /%s pdfMakeFont16\n",
660 font->getID().num, font->getID().gen, psName);
662 writePS("/F%d_%d /%s %g %g\n",
663 font->getID().num, font->getID().gen, psName, xs, ys);
664 for (i = 0; i < 256; i += 8) {
665 writePS((i == 0) ? "[ " : " ");
666 for (j = 0; j < 8; ++j) {
667 charName = font->getCharName(i+j);
668 writePS("/%s", charName ? charName : ".notdef");
670 writePS((i == 256-8) ? "]\n" : "\n");
672 writePS("pdfMakeFont\n");
676 void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
677 static char hexChar[17] = "0123456789abcdef";
678 Object refObj, strObj, obj1, obj2;
680 int length1, length2;
686 // check if font is already embedded
687 for (i = 0; i < fontFileIDLen; ++i) {
688 if (fontFileIDs[i].num == id->num &&
689 fontFileIDs[i].gen == id->gen)
693 // add entry to fontFileIDs list
694 if (fontFileIDLen >= fontFileIDSize) {
695 fontFileIDSize += 64;
696 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
698 fontFileIDs[fontFileIDLen++] = *id;
700 // get the font stream and info
701 refObj.initRef(id->num, id->gen);
702 refObj.fetch(&strObj);
704 if (!strObj.isStream()) {
705 error(-1, "Embedded font file object is not a stream");
708 if (!(dict = strObj.streamGetDict())) {
709 error(-1, "Embedded font stream is missing its dictionary");
712 dict->lookup("Length1", &obj1);
713 dict->lookup("Length2", &obj2);
714 if (!obj1.isInt() || !obj2.isInt()) {
715 error(-1, "Missing length fields in embedded font stream dictionary");
720 length1 = obj1.getInt();
721 length2 = obj2.getInt();
727 writePS("%%%%BeginResource: font %s\n", psName);
728 embFontList->append("%%+ font ");
729 embFontList->append(psName);
730 embFontList->append("\n");
733 // copy ASCII portion of font
734 strObj.streamReset();
735 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
738 // figure out if encrypted portion is binary or ASCII
740 for (i = 0; i < 4; ++i) {
741 start[i] = strObj.streamGetChar();
742 if (start[i] == EOF) {
743 error(-1, "Unexpected end of file in embedded font stream");
746 if (!((start[i] >= '0' && start[i] <= '9') ||
747 (start[i] >= 'A' && start[i] <= 'F') ||
748 (start[i] >= 'a' && start[i] <= 'f')))
752 // convert binary data to ASCII
754 for (i = 0; i < 4; ++i) {
755 fputc(hexChar[(start[i] >> 4) & 0x0f], f);
756 fputc(hexChar[start[i] & 0x0f], f);
758 while (i < length2) {
759 if ((c = strObj.streamGetChar()) == EOF)
761 fputc(hexChar[(c >> 4) & 0x0f], f);
762 fputc(hexChar[c & 0x0f], f);
769 // already in ASCII format -- just copy it
771 for (i = 0; i < 4; ++i)
773 for (i = 4; i < length2; ++i) {
774 if ((c = strObj.streamGetChar()) == EOF)
780 // write padding and "cleartomark"
781 for (i = 0; i < 8; ++i)
782 writePS("00000000000000000000000000000000"
783 "00000000000000000000000000000000\n");
784 writePS("cleartomark\n");
788 writePS("%%%%EndResource\n");
792 strObj.streamClose();
796 //~ This doesn't handle .pfb files or binary eexec data (which only
797 //~ happens in pfb files?).
798 void PSOutputDev::setupEmbeddedType1Font(GString *fileName, char *psName) {
803 // check if font is already embedded
804 for (i = 0; i < fontFileNameLen; ++i) {
805 if (!fontFileNames[i]->cmp(fileName)) {
810 // add entry to fontFileNames list
811 if (fontFileNameLen >= fontFileNameSize) {
812 fontFileNameSize += 64;
813 fontFileNames = (GString **)grealloc(fontFileNames,
814 fontFileNameSize * sizeof(GString *));
816 fontFileNames[fontFileNameLen++] = fileName->copy();
820 writePS("%%%%BeginResource: font %s\n", psName);
821 embFontList->append("%%+ font ");
822 embFontList->append(psName);
823 embFontList->append("\n");
826 // copy the font file
827 if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
828 error(-1, "Couldn't open external font file");
831 while ((c = fgetc(fontFile)) != EOF)
837 writePS("%%%%EndResource\n");
841 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
845 Type1CFontConverter *cvt;
848 // check if font is already embedded
849 for (i = 0; i < fontFileIDLen; ++i) {
850 if (fontFileIDs[i].num == id->num &&
851 fontFileIDs[i].gen == id->gen)
855 // add entry to fontFileIDs list
856 if (fontFileIDLen >= fontFileIDSize) {
857 fontFileIDSize += 64;
858 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
860 fontFileIDs[fontFileIDLen++] = *id;
864 writePS("%%%%BeginResource: font %s\n", psName);
865 embFontList->append("%%+ font ");
866 embFontList->append(psName);
867 embFontList->append("\n");
870 // convert it to a Type 1 font
871 fontBuf = font->readEmbFontFile(&fontLen);
872 cvt = new Type1CFontConverter(fontBuf, fontLen, f);
879 writePS("%%%%EndResource\n");
883 void PSOutputDev::setupImages(Dict *resDict) {
884 Object xObjDict, xObj, xObjRef, subtypeObj;
891 resDict->lookup("XObject", &xObjDict);
892 if (xObjDict.isDict()) {
893 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
894 xObjDict.dictGetValNF(i, &xObjRef);
895 xObjDict.dictGetVal(i, &xObj);
896 if (xObj.isStream()) {
897 xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
898 if (subtypeObj.isName("Image")) {
899 if (xObjRef.isRef()) {
900 setupImage(xObjRef.getRef(), xObj.getStream());
902 error(-1, "Image in resource dict is not an indirect reference");
914 void PSOutputDev::setupImage(Ref id, Stream *str) {
916 int size, line, col, i;
918 // construct an encoder stream
919 str = new ASCII85Encoder(str);
921 // compute image data size
927 } while (c == '\n' || c == '\r');
928 if (c == '~' || c == EOF) {
935 for (i = 1; i <= 4; ++i) {
938 } while (c == '\n' || c == '\r');
939 if (c == '~' || c == EOF) {
949 } while (c != '~' && c != EOF);
951 writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
953 // write the data into the array
960 } while (c == '\n' || c == '\r');
961 if (c == '~' || c == EOF) {
970 for (i = 1; i <= 4; ++i) {
973 } while (c == '\n' || c == '\r');
974 if (c == '~' || c == EOF) {
981 // each line is: "dup nnnnn <~...data...~> put<eol>"
982 // so max data length = 255 - 20 = 235
983 // chunks are 1 or 4 bytes each, so we have to stop at 232
984 // but make it 225 just to be safe
988 writePS("dup %d <~", line);
991 } while (c != '~' && c != EOF);
998 void PSOutputDev::startPage(int pageNum, GfxState *state) {
999 int x1, y1, x2, y2, width, height, t;
1003 writePS("/PaintProc {\n");
1004 writePS("begin xpdf begin\n");
1005 writePS("pdfStartPage\n");
1007 xScale = yScale = 1;
1010 } else if (psOutEPS) {
1012 writePS("pdfStartPage\n");
1014 xScale = yScale = 1;
1019 writePS("%%%%Page: %d %d\n", pageNum, seqPage);
1020 writePS("%%%%BeginPageSetup\n");
1022 // rotate, translate, and scale page
1023 x1 = (int)(state->getX1() + 0.5);
1024 y1 = (int)(state->getY1() + 0.5);
1025 x2 = (int)(state->getX2() + 0.5);
1026 y2 = (int)(state->getY2() + 0.5);
1029 if (width > height && width > paperWidth) {
1031 writePS("%%%%PageOrientation: Landscape\n");
1032 writePS("pdfStartPage\n");
1033 writePS("90 rotate\n");
1035 ty = -(y1 + paperWidth);
1041 writePS("%%%%PageOrientation: Portrait\n");
1042 writePS("pdfStartPage\n");
1046 if (width < paperWidth) {
1047 tx += (paperWidth - width) / 2;
1049 if (height < paperHeight) {
1050 ty += (paperHeight - height) / 2;
1052 if (tx != 0 || ty != 0) {
1053 writePS("%g %g translate\n", tx, ty);
1055 if (width > paperWidth || height > paperHeight) {
1056 xScale = (double)paperWidth / (double)width;
1057 yScale = (double)paperHeight / (double)height;
1058 if (yScale < xScale) {
1061 writePS("%0.4f %0.4f scale\n", xScale, xScale);
1063 xScale = yScale = 1;
1066 writePS("%%%%EndPageSetup\n");
1071 void PSOutputDev::endPage() {
1073 writePS("pdfEndPage\n");
1074 writePS("end end\n");
1076 writePS("end end\n");
1078 writePS("showpage\n");
1079 writePS("%%%%PageTrailer\n");
1080 writePS("pdfEndPage\n");
1084 void PSOutputDev::saveState(GfxState *state) {
1088 void PSOutputDev::restoreState(GfxState *state) {
1092 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
1093 double m21, double m22, double m31, double m32) {
1094 writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
1097 void PSOutputDev::updateLineDash(GfxState *state) {
1102 state->getLineDash(&dash, &length, &start);
1104 for (i = 0; i < length; ++i)
1105 writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
1106 writePS("] %g d\n", start);
1109 void PSOutputDev::updateFlatness(GfxState *state) {
1110 writePS("%d i\n", state->getFlatness());
1113 void PSOutputDev::updateLineJoin(GfxState *state) {
1114 writePS("%d j\n", state->getLineJoin());
1117 void PSOutputDev::updateLineCap(GfxState *state) {
1118 writePS("%d J\n", state->getLineCap());
1121 void PSOutputDev::updateMiterLimit(GfxState *state) {
1122 writePS("%g M\n", state->getMiterLimit());
1125 void PSOutputDev::updateLineWidth(GfxState *state) {
1126 writePS("%g w\n", state->getLineWidth());
1129 void PSOutputDev::updateFillColor(GfxState *state) {
1133 if (psOutLevel1Sep) {
1134 state->getFillCMYK(&cmyk);
1135 writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1137 state->getFillRGB(&rgb);
1138 if (rgb.r == rgb.g && rgb.g == rgb.b) {
1139 writePS("%g g\n", rgb.r);
1141 writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
1146 void PSOutputDev::updateStrokeColor(GfxState *state) {
1150 if (psOutLevel1Sep) {
1151 state->getStrokeCMYK(&cmyk);
1152 writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1154 state->getStrokeRGB(&rgb);
1155 if (rgb.r == rgb.g && rgb.g == rgb.b) {
1156 writePS("%g G\n", rgb.r);
1158 writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
1163 void PSOutputDev::updateFont(GfxState *state) {
1164 if (state->getFont()) {
1165 writePS("/F%d_%d %g Tf\n",
1166 state->getFont()->getID().num, state->getFont()->getID().gen,
1167 state->getFontSize());
1171 void PSOutputDev::updateTextMat(GfxState *state) {
1174 mat = state->getTextMat();
1175 writePS("[%g %g %g %g %g %g] Tm\n",
1176 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
1179 void PSOutputDev::updateCharSpace(GfxState *state) {
1180 writePS("%g Tc\n", state->getCharSpace());
1183 void PSOutputDev::updateRender(GfxState *state) {
1184 writePS("%d Tr\n", state->getRender());
1187 void PSOutputDev::updateRise(GfxState *state) {
1188 writePS("%g Ts\n", state->getRise());
1191 void PSOutputDev::updateWordSpace(GfxState *state) {
1192 writePS("%g Tw\n", state->getWordSpace());
1195 void PSOutputDev::updateHorizScaling(GfxState *state) {
1196 writePS("%g Tz\n", state->getHorizScaling());
1199 void PSOutputDev::updateTextPos(GfxState *state) {
1200 writePS("%g %g Td\n", state->getLineX(), state->getLineY());
1203 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
1204 writePS("%g TJm\n", shift);
1207 void PSOutputDev::stroke(GfxState *state) {
1208 doPath(state->getPath());
1212 void PSOutputDev::fill(GfxState *state) {
1213 doPath(state->getPath());
1217 void PSOutputDev::eoFill(GfxState *state) {
1218 doPath(state->getPath());
1222 void PSOutputDev::clip(GfxState *state) {
1223 doPath(state->getPath());
1227 void PSOutputDev::eoClip(GfxState *state) {
1228 doPath(state->getPath());
1232 void PSOutputDev::doPath(GfxPath *path) {
1233 GfxSubpath *subpath;
1234 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
1237 n = path->getNumSubpaths();
1239 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
1240 subpath = path->getSubpath(0);
1241 x0 = subpath->getX(0);
1242 y0 = subpath->getY(0);
1243 x4 = subpath->getX(4);
1244 y4 = subpath->getY(4);
1245 if (x4 == x0 && y4 == y0) {
1246 x1 = subpath->getX(1);
1247 y1 = subpath->getY(1);
1248 x2 = subpath->getX(2);
1249 y2 = subpath->getY(2);
1250 x3 = subpath->getX(3);
1251 y3 = subpath->getY(3);
1252 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
1253 writePS("%g %g %g %g re\n",
1254 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
1255 fabs(x2 - x0), fabs(y1 - y0));
1257 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
1258 writePS("%g %g %g %g re\n",
1259 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
1260 fabs(x1 - x0), fabs(y2 - y0));
1266 for (i = 0; i < n; ++i) {
1267 subpath = path->getSubpath(i);
1268 m = subpath->getNumPoints();
1269 writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
1272 if (subpath->getCurve(j)) {
1273 writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
1274 subpath->getX(j+1), subpath->getY(j+1),
1275 subpath->getX(j+2), subpath->getY(j+2));
1278 writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
1282 if (subpath->isClosed()) {
1288 void PSOutputDev::drawString(GfxState *state, GString *s) {
1289 // check for invisible text -- this is used by Acrobat Capture
1290 if ((state->getRender() & 3) == 3)
1294 writePS(" %g Tj\n", state->getFont()->getWidth(s));
1297 void PSOutputDev::drawString16(GfxState *state, GString *s) {
1302 // check for invisible text -- this is used by Acrobat Capture
1303 if ((state->getRender() & 3) == 3)
1306 switch (state->getFont()->getCharSet16()) {
1308 case font16AdobeJapan12:
1309 #if JAPANESE_SUPPORT
1312 for (i = 0; i < s->getLength(); i += 2) {
1313 c1 = ((s->getChar(i) & 0xff) << 8) + (s->getChar(i+1) & 0xff);
1315 c2 = japan12ToRKSJ[c1];
1320 writePS("%02x", c2);
1322 writePS("%02x%02x", c2 >> 8, c2 & 0xff);
1324 w += state->getFont()->getWidth16(c1);
1326 writePS("> %g Tj\n", w);
1330 case font16AdobeGB12:
1333 case font16AdobeCNS13:
1338 void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1339 int width, int height, GBool invert,
1343 len = height * ((width + 7) / 8);
1344 if (psOutLevel1 || psOutLevel1Sep) {
1345 doImageL1(NULL, invert, inlineImg, str, width, height, len);
1347 doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
1351 void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1352 int width, int height, GfxImageColorMap *colorMap,
1356 len = height * ((width * colorMap->getNumPixelComps() *
1357 colorMap->getBits() + 7) / 8);
1359 doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
1360 } else if (psOutLevel1Sep) {
1361 //~ handle indexed, separation, ... color spaces
1362 doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
1364 doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
1368 void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
1369 GBool invert, GBool inlineImg,
1370 Stream *str, int width, int height, int len) {
1371 ImageStream *imgStr;
1372 Guchar pixBuf[gfxColorMaxComps];
1376 // width, height, matrix, bits per component
1378 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
1380 width, -height, height);
1382 writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
1383 width, height, invert ? "true" : "false",
1384 width, -height, height);
1390 // set up to process the data stream
1391 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
1392 colorMap->getBits());
1395 // process the data stream
1397 for (y = 0; y < height; ++y) {
1400 for (x = 0; x < width; ++x) {
1401 imgStr->getPixel(pixBuf);
1402 colorMap->getGray(pixBuf, &gray);
1403 fprintf(f, "%02x", (int)(gray * 255 + 0.5));
1418 for (y = 0; y < height; ++y) {
1419 for (x = 0; x < width; x += 8) {
1420 fprintf(f, "%02x", str->getChar() & 0xff);
1432 void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
1433 GBool invert, GBool inlineImg,
1434 Stream *str, int width, int height, int len) {
1435 ImageStream *imgStr;
1437 Guchar pixBuf[gfxColorMaxComps];
1441 // width, height, matrix, bits per component
1442 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
1444 width, -height, height);
1446 // allocate a line buffer
1447 lineBuf = (Guchar *)gmalloc(4 * width);
1449 // set up to process the data stream
1450 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
1451 colorMap->getBits());
1454 // process the data stream
1456 for (y = 0; y < height; ++y) {
1459 for (x = 0; x < width; ++x) {
1460 imgStr->getPixel(pixBuf);
1461 colorMap->getCMYK(pixBuf, &cmyk);
1462 lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5);
1463 lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
1464 lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
1465 lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
1468 // write one line of each color component
1469 for (comp = 0; comp < 4; ++comp) {
1470 for (x = 0; x < width; ++x) {
1471 fprintf(f, "%02x", lineBuf[4*x + comp]);
1488 void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
1489 GBool invert, GBool inlineImg,
1490 Stream *str, int width, int height, int len) {
1493 GBool useRLE, useA85;
1499 dumpColorSpaceL2(colorMap->getColorSpace());
1500 writePS(" setcolorspace\n");
1503 // set up to use the array created by setupImages()
1504 if (doForm && !inlineImg) {
1505 writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
1509 writePS("<<\n /ImageType 1\n");
1511 // width, height, matrix, bits per component
1512 writePS(" /Width %d\n", width);
1513 writePS(" /Height %d\n", height);
1514 writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
1515 writePS(" /BitsPerComponent %d\n",
1516 colorMap ? colorMap->getBits() : 1);
1520 writePS(" /Decode [");
1521 if (colorMap->getColorSpace()->getMode() == csSeparation) {
1522 //~ this is a kludge -- see comment in dumpColorSpaceL2
1523 n = (1 << colorMap->getBits()) - 1;
1524 writePS("%g %g", colorMap->getDecodeLow(0) * n,
1525 colorMap->getDecodeHigh(0) * n);
1527 numComps = colorMap->getNumPixelComps();
1528 for (i = 0; i < numComps; ++i) {
1532 writePS("%g %g", colorMap->getDecodeLow(i),
1533 colorMap->getDecodeHigh(i));
1538 writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
1546 writePS(" /DataSource <~\n");
1548 // write image data stream, using ASCII85 encode filter
1549 str = new FixedLengthEncoder(str, len);
1550 str = new ASCII85Encoder(str);
1552 while ((c = str->getChar()) != EOF) {
1559 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
1562 // end of image dictionary
1563 writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
1565 // get rid of the array and index
1567 writePS("pop pop\n");
1573 writePS(" /DataSource currentfile\n");
1574 s = str->getPSFilter(" ");
1575 if (inlineImg || !s) {
1580 useA85 = str->isBinary();
1583 writePS(" /ASCII85Decode filter\n");
1585 writePS(" /RunLengthDecode filter\n");
1587 writePS("%s", s->getCString());
1591 // cut off inline image streams at appropriate length
1593 str = new FixedLengthEncoder(str, len);
1595 str = str->getBaseStream();
1597 // add RunLengthEncode and ASCII85 encode filters
1599 str = new RunLengthEncoder(str);
1601 str = new ASCII85Encoder(str);
1603 // end of image dictionary
1608 // this can't happen -- OPI dictionaries are in XObjects
1609 error(-1, "Internal: OPI in inline image");
1612 // need to read the stream to count characters -- the length
1613 // is data-dependent (because of A85 and RLE filters)
1616 while ((c = str->getChar()) != EOF) {
1620 // +6/7 for "pdfIm\n" / "pdfImM\n"
1621 // +8 for newline + trailer
1622 n += colorMap ? 14 : 15;
1623 writePS("%%%%BeginData: %d Hex Bytes\n", n);
1626 writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
1628 // copy the stream data
1630 while ((c = str->getChar()) != EOF)
1633 // add newline and trailer to the end
1635 fputs("%-EOD-\n", f);
1638 writePS("%%%%EndData\n");
1643 if (useRLE || useA85)
1648 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
1649 GfxCalGrayColorSpace *calGrayCS;
1650 GfxCalRGBColorSpace *calRGBCS;
1651 GfxLabColorSpace *labCS;
1652 GfxIndexedColorSpace *indexedCS;
1653 GfxSeparationColorSpace *separationCS;
1655 double x[1], y[gfxColorMaxComps];
1659 switch (colorSpace->getMode()) {
1662 writePS("/DeviceGray");
1666 calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
1667 writePS("[/CIEBasedA <<\n");
1668 writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
1669 writePS(" /MatrixA [%g %g %g]\n",
1670 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
1671 calGrayCS->getWhiteZ());
1672 writePS(" /WhitePoint [%g %g %g]\n",
1673 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
1674 calGrayCS->getWhiteZ());
1675 writePS(" /BlackPoint [%g %g %g]\n",
1676 calGrayCS->getBlackX(), calGrayCS->getBlackY(),
1677 calGrayCS->getBlackZ());
1682 writePS("/DeviceRGB");
1686 calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
1687 writePS("[/CIEBasedABC <<\n");
1688 writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
1689 calRGBCS->getGammaR(), calRGBCS->getGammaG(),
1690 calRGBCS->getGammaB());
1691 writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
1692 calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
1693 calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
1694 calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
1695 calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
1696 calRGBCS->getMatrix()[8]);
1697 writePS(" /WhitePoint [%g %g %g]\n",
1698 calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
1699 calRGBCS->getWhiteZ());
1700 writePS(" /BlackPoint [%g %g %g]\n",
1701 calRGBCS->getBlackX(), calRGBCS->getBlackY(),
1702 calRGBCS->getBlackZ());
1707 writePS("/DeviceCMYK");
1711 labCS = (GfxLabColorSpace *)colorSpace;
1712 writePS("[/CIEBasedABC <<\n");
1713 writePS(" /RangeABC [0 100 %g %g %g %g]\n",
1714 labCS->getAMin(), labCS->getAMax(),
1715 labCS->getBMin(), labCS->getBMax());
1716 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
1717 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
1718 writePS(" /DecodeLMN\n");
1719 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
1720 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
1721 labCS->getWhiteX());
1722 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
1723 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
1724 labCS->getWhiteY());
1725 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
1726 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
1727 labCS->getWhiteZ());
1728 writePS(" /WhitePoint [%g %g %g]\n",
1729 labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
1730 writePS(" /BlackPoint [%g %g %g]\n",
1731 labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
1736 dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
1740 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1741 writePS("[/Indexed ");
1742 dumpColorSpaceL2(indexedCS->getBase());
1743 n = indexedCS->getIndexHigh();
1744 numComps = indexedCS->getBase()->getNComps();
1745 lookup = indexedCS->getLookup();
1746 writePS(" %d <\n", n);
1747 for (i = 0; i <= n; i += 8) {
1749 for (j = i; j < i+8 && j <= n; ++j) {
1750 for (k = 0; k < numComps; ++k) {
1751 writePS("%02x", lookup[j * numComps + k]);
1760 //~ this is a kludge -- the correct thing would to ouput a
1761 //~ separation color space, with the specified alternate color
1762 //~ space and tint transform
1763 separationCS = (GfxSeparationColorSpace *)colorSpace;
1764 writePS(" [/Indexed ");
1765 dumpColorSpaceL2(separationCS->getAlt());
1766 writePS(" 255 <\n");
1767 numComps = separationCS->getAlt()->getNComps();
1768 for (i = 0; i <= 255; i += 8) {
1770 for (j = i; j < i+8 && j <= 255; ++j) {
1771 x[0] = (double)j / 255.0;
1772 separationCS->getFunc()->transform(x, y);
1773 for (k = 0; k < numComps; ++k) {
1774 writePS("%02x", (int)(255 * y[k] + 0.5));
1783 // DeviceN color spaces are a Level 3 PostScript feature.
1784 dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt());
1795 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
1799 opiDict->lookup("2.0", &dict);
1800 if (dict.isDict()) {
1801 opiBegin20(state, dict.getDict());
1805 opiDict->lookup("1.3", &dict);
1806 if (dict.isDict()) {
1807 opiBegin13(state, dict.getDict());
1814 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
1815 Object obj1, obj2, obj3, obj4;
1816 double width, height, left, right, top, bottom;
1820 writePS("%%%%BeginOPI: 2.0\n");
1821 writePS("%%%%Distilled\n");
1823 dict->lookup("F", &obj1);
1824 if (getFileSpec(&obj1, &obj2)) {
1825 writePS("%%%%ImageFileName: %s\n",
1826 obj2.getString()->getCString());
1831 dict->lookup("MainImage", &obj1);
1832 if (obj1.isString()) {
1833 writePS("%%%%MainImage: %s\n", obj1.getString()->getCString());
1837 //~ ignoring 'Tags' entry
1838 //~ need to use writePSString() and deal with >255-char lines
1840 dict->lookup("Size", &obj1);
1841 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
1842 obj1.arrayGet(0, &obj2);
1843 width = obj2.getNum();
1845 obj1.arrayGet(1, &obj2);
1846 height = obj2.getNum();
1848 writePS("%%%%ImageDimensions: %g %g\n", width, height);
1852 dict->lookup("CropRect", &obj1);
1853 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
1854 obj1.arrayGet(0, &obj2);
1855 left = obj2.getNum();
1857 obj1.arrayGet(1, &obj2);
1858 top = obj2.getNum();
1860 obj1.arrayGet(2, &obj2);
1861 right = obj2.getNum();
1863 obj1.arrayGet(3, &obj2);
1864 bottom = obj2.getNum();
1866 writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
1870 dict->lookup("Overprint", &obj1);
1871 if (obj1.isBool()) {
1872 writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
1876 dict->lookup("Inks", &obj1);
1877 if (obj1.isName()) {
1878 writePS("%%%%ImageInks: %s\n", obj1.getName());
1879 } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
1880 obj1.arrayGet(0, &obj2);
1881 if (obj2.isName()) {
1882 writePS("%%%%ImageInks: %s %d",
1883 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
1884 for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
1885 obj1.arrayGet(i, &obj3);
1886 obj1.arrayGet(i+1, &obj4);
1887 if (obj3.isString() && obj4.isNum()) {
1889 writePSString(obj3.getString());
1890 writePS(" %g", obj4.getNum());
1903 writePS("%%%%BeginIncludedImage\n");
1905 dict->lookup("IncludedImageDimensions", &obj1);
1906 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
1907 obj1.arrayGet(0, &obj2);
1910 obj1.arrayGet(1, &obj2);
1913 writePS("%%%%IncludedImageDimensions: %d %d\n", w, h);
1917 dict->lookup("IncludedImageQuality", &obj1);
1919 writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum());
1926 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
1928 int left, right, top, bottom, samples, bits, width, height;
1930 double llx, lly, ulx, uly, urx, ury, lrx, lry;
1931 double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
1936 writePS("/opiMatrix2 matrix currentmatrix def\n");
1937 writePS("opiMatrix setmatrix\n");
1939 dict->lookup("F", &obj1);
1940 if (getFileSpec(&obj1, &obj2)) {
1941 writePS("%%ALDImageFileName: %s\n",
1942 obj2.getString()->getCString());
1947 dict->lookup("CropRect", &obj1);
1948 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
1949 obj1.arrayGet(0, &obj2);
1950 left = obj2.getInt();
1952 obj1.arrayGet(1, &obj2);
1953 top = obj2.getInt();
1955 obj1.arrayGet(2, &obj2);
1956 right = obj2.getInt();
1958 obj1.arrayGet(3, &obj2);
1959 bottom = obj2.getInt();
1961 writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
1965 dict->lookup("Color", &obj1);
1966 if (obj1.isArray() && obj1.arrayGetLength() == 5) {
1967 obj1.arrayGet(0, &obj2);
1970 obj1.arrayGet(1, &obj2);
1973 obj1.arrayGet(2, &obj2);
1976 obj1.arrayGet(3, &obj2);
1979 obj1.arrayGet(4, &obj2);
1980 if (obj2.isString()) {
1981 writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
1982 writePSString(obj2.getString());
1989 dict->lookup("ColorType", &obj1);
1990 if (obj1.isName()) {
1991 writePS("%%ALDImageColorType: %s\n", obj1.getName());
1995 //~ ignores 'Comments' entry
1996 //~ need to handle multiple lines
1998 dict->lookup("CropFixed", &obj1);
1999 if (obj1.isArray()) {
2000 obj1.arrayGet(0, &obj2);
2001 ulx = obj2.getNum();
2003 obj1.arrayGet(1, &obj2);
2004 uly = obj2.getNum();
2006 obj1.arrayGet(2, &obj2);
2007 lrx = obj2.getNum();
2009 obj1.arrayGet(3, &obj2);
2010 lry = obj2.getNum();
2012 writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
2016 dict->lookup("GrayMap", &obj1);
2017 if (obj1.isArray()) {
2018 writePS("%%ALDImageGrayMap:");
2019 for (i = 0; i < obj1.arrayGetLength(); i += 16) {
2023 for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
2024 obj1.arrayGet(i+j, &obj2);
2025 writePS(" %d", obj2.getInt());
2033 dict->lookup("ID", &obj1);
2034 if (obj1.isString()) {
2035 writePS("%%ALDImageID: %s\n", obj1.getString()->getCString());
2039 dict->lookup("ImageType", &obj1);
2040 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2041 obj1.arrayGet(0, &obj2);
2042 samples = obj2.getInt();
2044 obj1.arrayGet(1, &obj2);
2045 bits = obj2.getInt();
2047 writePS("%%ALDImageType: %d %d\n", samples, bits);
2051 dict->lookup("Overprint", &obj1);
2052 if (obj1.isBool()) {
2053 writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
2057 dict->lookup("Position", &obj1);
2058 if (obj1.isArray() && obj1.arrayGetLength() == 8) {
2059 obj1.arrayGet(0, &obj2);
2060 llx = obj2.getNum();
2062 obj1.arrayGet(1, &obj2);
2063 lly = obj2.getNum();
2065 obj1.arrayGet(2, &obj2);
2066 ulx = obj2.getNum();
2068 obj1.arrayGet(3, &obj2);
2069 uly = obj2.getNum();
2071 obj1.arrayGet(4, &obj2);
2072 urx = obj2.getNum();
2074 obj1.arrayGet(5, &obj2);
2075 ury = obj2.getNum();
2077 obj1.arrayGet(6, &obj2);
2078 lrx = obj2.getNum();
2080 obj1.arrayGet(7, &obj2);
2081 lry = obj2.getNum();
2083 opiTransform(state, llx, lly, &tllx, &tlly);
2084 opiTransform(state, ulx, uly, &tulx, &tuly);
2085 opiTransform(state, urx, ury, &turx, &tury);
2086 opiTransform(state, lrx, lry, &tlrx, &tlry);
2087 writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
2088 tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
2093 dict->lookup("Resolution", &obj1);
2094 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2095 obj1.arrayGet(0, &obj2);
2096 horiz = obj2.getNum();
2098 obj1.arrayGet(1, &obj2);
2099 vert = obj2.getNum();
2101 writePS("%%ALDImageResoution: %g %g\n", horiz, vert);
2106 dict->lookup("Size", &obj1);
2107 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2108 obj1.arrayGet(0, &obj2);
2109 width = obj2.getInt();
2111 obj1.arrayGet(1, &obj2);
2112 height = obj2.getInt();
2114 writePS("%%ALDImageDimensions: %d %d\n", width, height);
2118 //~ ignoring 'Tags' entry
2119 //~ need to use writePSString() and deal with >255-char lines
2121 dict->lookup("Tint", &obj1);
2123 writePS("%%ALDImageTint: %g\n", obj1.getNum());
2127 dict->lookup("Transparency", &obj1);
2128 if (obj1.isBool()) {
2129 writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
2133 writePS("%%%%BeginObject: image\n");
2134 writePS("opiMatrix2 setmatrix\n");
2138 // Convert PDF user space coordinates to PostScript default user space
2139 // coordinates. This has to account for both the PDF CTM and the
2140 // PSOutputDev page-fitting transform.
2141 void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
2142 double *x1, double *y1) {
2145 state->transform(x0, y0, x1, y1);
2157 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
2161 opiDict->lookup("2.0", &dict);
2162 if (dict.isDict()) {
2163 writePS("%%%%EndIncludedImage\n");
2164 writePS("%%%%EndOPI\n");
2165 writePS("grestore\n");
2170 opiDict->lookup("1.3", &dict);
2171 if (dict.isDict()) {
2172 writePS("%%%%EndObject\n");
2173 writePS("restore\n");
2181 GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
2182 if (fileSpec->isString()) {
2183 fileSpec->copy(fileName);
2186 if (fileSpec->isDict()) {
2187 fileSpec->dictLookup("DOS", fileName);
2188 if (fileName->isString()) {
2192 fileSpec->dictLookup("Mac", fileName);
2193 if (fileName->isString()) {
2197 fileSpec->dictLookup("Unix", fileName);
2198 if (fileName->isString()) {
2202 fileSpec->dictLookup("F", fileName);
2203 if (fileName->isString()) {
2210 #endif // OPI_SUPPORT
2212 void PSOutputDev::writePS(const char *fmt, ...) {
2215 va_start(args, fmt);
2216 vfprintf(f, fmt, args);
2220 void PSOutputDev::writePSString(GString *s) {
2225 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
2226 if (*p == '(' || *p == ')' || *p == '\\')
2227 fprintf(f, "\\%c", *p);
2228 else if (*p < 0x20 || *p >= 0x80)
2229 fprintf(f, "\\%03o", *p);