1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
21 #include "GlobalParams.h"
28 #include "CharCodeToUnicode.h"
29 #include "UnicodeMap.h"
35 #include "PSOutputDev.h"
38 // needed for setting type/creator of MacOS files
39 #include "ICSupport.h"
42 //------------------------------------------------------------------------
43 // PostScript prolog and setup
44 //------------------------------------------------------------------------
46 static char *prolog[] = {
47 "/xpdf 75 dict def xpdf begin",
48 "% PDF special state",
49 "/pdfDictSize 14 def",
51 " 3 1 roll 2 array astore",
52 " /setpagedevice where {",
54 " /PageSize exch def",
55 " /ImagingBBox null def",
56 " /Policies 1 dict dup begin /PageSize 3 def end def",
58 " currentdict end setpagedevice",
64 " pdfDictSize dict begin",
66 " /pdfStroke [0] def",
67 " /pdfLastFill false def",
68 " /pdfLastStroke false def",
69 " /pdfTextMat [1 0 0 1 0 0] def",
70 " /pdfFontSize 0 def",
71 " /pdfCharSpacing 0 def",
72 " /pdfTextRender 0 def",
73 " /pdfTextRise 0 def",
74 " /pdfWordSpacing 0 def",
75 " /pdfHorizScaling 1 def",
77 "/pdfEndPage { end } def",
78 "% separation convention operators",
79 "/findcmykcustomcolor where {",
82 " /findcmykcustomcolor { 5 array astore } def",
84 "/setcustomcolor where {",
89 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
90 " 0 4 getinterval cvx",
91 " [ exch /dup load exch { mul exch dup } /forall load",
92 " /pop load dup ] cvx",
93 " ] setcolorspace setcolor",
96 "/customcolorimage where {",
99 " /customcolorimage {",
101 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
102 " 0 4 getinterval cvx",
103 " [ exch /dup load exch { mul exch dup } /forall load",
104 " /pop load dup ] cvx",
108 " /DataSource exch def",
109 " /ImageMatrix exch def",
110 " /BitsPerComponent exch def",
113 " /Decode [1 0] def",
121 " pdfLastStroke not {",
122 " pdfStroke aload length",
132 " findcmykcustomcolor exch setcustomcolor",
136 " /pdfLastStroke true def /pdfLastFill false def",
140 " pdfLastFill not {",
141 " pdfFill aload length",
151 " findcmykcustomcolor exch setcustomcolor",
155 " /pdfLastFill true def /pdfLastStroke false def",
160 " 4 3 roll findfont",
161 " 4 2 roll matrix scale makefont",
162 " dup length dict begin",
163 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
164 " /Encoding exch def",
171 " dup length dict begin",
172 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
178 "/pdfMakeFont16L3 {",
179 " 1 index /CIDFont resourcestatus {",
180 " pop pop 1 index /CIDFont findresource /CIDFontType known",
185 " 0 eq { /Identity-H } { /Identity-V } ifelse",
186 " exch 1 array astore composefont pop",
191 "% graphics state operators",
192 "/q { gsave pdfDictSize dict begin } def",
193 "/Q { end grestore } def",
194 "/cm { concat } def",
195 "/d { setdash } def",
196 "/i { setflat } def",
197 "/j { setlinejoin } def",
198 "/J { setlinecap } def",
199 "/M { setmiterlimit } def",
200 "/w { setlinewidth } def",
202 "/g { dup 1 array astore /pdfFill exch def setgray",
203 " /pdfLastFill true def /pdfLastStroke false def } def",
204 "/G { dup 1 array astore /pdfStroke exch def setgray",
205 " /pdfLastStroke true def /pdfLastFill false def } def",
206 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
207 " /pdfLastFill true def /pdfLastStroke false def } def",
208 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
209 " /pdfLastStroke true def /pdfLastFill false def } def",
210 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
211 " /pdfLastFill true def /pdfLastStroke false def } def",
212 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
213 " /pdfLastStroke true def /pdfLastFill false def } def",
214 "/ck { 6 copy 6 array astore /pdfFill exch def",
215 " findcmykcustomcolor exch setcustomcolor",
216 " /pdfLastFill true def /pdfLastStroke false def } def",
217 "/CK { 6 copy 6 array astore /pdfStroke exch def",
218 " findcmykcustomcolor exch setcustomcolor",
219 " /pdfLastStroke true def /pdfLastFill false def } def",
220 "% path segment operators",
223 "/c { curveto } def",
224 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
225 " neg 0 rlineto closepath } def",
226 "/h { closepath } def",
227 "% path painting operators",
228 "/S { sCol stroke } def",
229 "/Sf { fCol stroke } def",
230 "/f { fCol fill } def",
231 "/f* { fCol eofill } def",
232 "% clipping operators",
233 "/W { clip newpath } def",
234 "/W* { eoclip newpath } def",
235 "% text state operators",
236 "/Tc { /pdfCharSpacing exch def } def",
237 "/Tf { dup /pdfFontSize exch def",
238 " dup pdfHorizScaling mul exch matrix scale",
239 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
240 " exch findfont exch makefont setfont } def",
241 "/Tr { /pdfTextRender exch def } def",
242 "/Ts { /pdfTextRise exch def } def",
243 "/Tw { /pdfWordSpacing exch def } def",
244 "/Tz { /pdfHorizScaling exch def } def",
245 "% text positioning operators",
246 "/Td { pdfTextMat transform moveto } def",
247 "/Tm { /pdfTextMat exch def } def",
248 "% text string operators",
249 "/awcp { % awidthcharpath",
251 " 1 string dup 0 3 index put 2 index charpath",
252 " 3 index 3 index rmoveto",
253 " 4 index eq { 5 index 5 index rmoveto } if",
257 "/Tj { fCol", // because stringwidth has to draw Type 3 chars
258 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
259 " 1 index stringwidth pdfTextMat idtransform pop",
260 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
261 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
262 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
263 " pdfTextMat dtransform",
265 " currentpoint 8 2 roll",
266 " pdfTextRender 1 and 0 eq {",
267 " 6 copy awidthshow",
269 " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
271 " sCol false awcp currentpoint stroke moveto",
275 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
276 "/Tj16 { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
277 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
278 " 2 index stringwidth pdfTextMat idtransform pop",
280 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
281 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
282 " pdfTextMat dtransform",
283 " 6 5 roll awidthshow",
284 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
285 "/Tj16V { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
286 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
287 " 2 index stringwidth pdfTextMat idtransform exch pop",
289 " 0 pdfWordSpacing pdfTextMat dtransform 32",
290 " 4 3 roll pdfCharSpacing add 0 exch",
291 " pdfTextMat dtransform",
292 " 6 5 roll awidthshow",
293 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
294 "/TJm { pdfFontSize 0.001 mul mul neg 0",
295 " pdfTextMat dtransform rmoveto } def",
296 "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
297 " pdfTextMat dtransform rmoveto } def",
298 "% Level 1 image operators",
300 " /pdfImBuf1 4 index string def",
301 " { currentfile pdfImBuf1 readhexstring pop } image",
304 " /pdfImBuf1 4 index string def",
305 " /pdfImBuf2 4 index string def",
306 " /pdfImBuf3 4 index string def",
307 " /pdfImBuf4 4 index string def",
308 " { currentfile pdfImBuf1 readhexstring pop }",
309 " { currentfile pdfImBuf2 readhexstring pop }",
310 " { currentfile pdfImBuf3 readhexstring pop }",
311 " { currentfile pdfImBuf4 readhexstring pop }",
312 " true 4 colorimage",
315 " /pdfImBuf1 4 index 7 add 8 idiv string def",
316 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
318 "% Level 2 image operators",
319 "/pdfImBuf 100 string def",
322 " { currentfile pdfImBuf readline",
323 " not { pop exit } if",
324 " (%-EOD-) eq { exit } if } loop",
327 " findcmykcustomcolor exch",
328 " dup /Width get /pdfImBuf1 exch string def",
329 " begin Width Height BitsPerComponent ImageMatrix DataSource end",
330 " /pdfImData exch def",
331 " { pdfImData pdfImBuf1 readstring pop",
332 " 0 1 2 index length 1 sub {",
333 " 1 index exch 2 copy get 255 exch sub put",
335 " 6 5 roll customcolorimage",
336 " { currentfile pdfImBuf readline",
337 " not { pop exit } if",
338 " (%-EOD-) eq { exit } if } loop",
342 " { currentfile pdfImBuf readline",
343 " not { pop exit } if",
344 " (%-EOD-) eq { exit } if } loop",
350 static char *cmapProlog[] = {
351 "/CIDInit /ProcSet findresource begin",
355 " /CMapName /Identity-H def",
356 " /CIDSystemInfo 3 dict dup begin",
357 " /Registry (Adobe) def",
358 " /Ordering (Identity) def",
359 " /Supplement 0 def",
361 " 1 begincodespacerange",
363 " endcodespacerange",
369 " currentdict CMapName exch /CMap defineresource pop",
374 " /CMapName /Identity-V def",
375 " /CIDSystemInfo 3 dict dup begin",
376 " /Registry (Adobe) def",
377 " /Ordering (Identity) def",
378 " /Supplement 0 def",
381 " 1 begincodespacerange",
383 " endcodespacerange",
389 " currentdict CMapName exch /CMap defineresource pop",
395 //------------------------------------------------------------------------
397 //------------------------------------------------------------------------
400 char *psName; // PostScript name
401 double mWidth; // width of 'm' character
404 static char *psFonts[] = {
408 "Courier-BoldOblique",
412 "Helvetica-BoldOblique",
422 static PSSubstFont psSubstFonts[] = {
423 {"Helvetica", 0.833},
424 {"Helvetica-Oblique", 0.833},
425 {"Helvetica-Bold", 0.889},
426 {"Helvetica-BoldOblique", 0.889},
427 {"Times-Roman", 0.788},
428 {"Times-Italic", 0.722},
429 {"Times-Bold", 0.833},
430 {"Times-BoldItalic", 0.778},
432 {"Courier-Oblique", 0.600},
433 {"Courier-Bold", 0.600},
434 {"Courier-BoldOblique", 0.600}
437 // Encoding info for substitute 16-bit font
443 //------------------------------------------------------------------------
445 //------------------------------------------------------------------------
447 #define psProcessCyan 1
448 #define psProcessMagenta 2
449 #define psProcessYellow 4
450 #define psProcessBlack 8
451 #define psProcessCMYK 15
453 //------------------------------------------------------------------------
455 //------------------------------------------------------------------------
457 class PSOutCustomColor {
460 PSOutCustomColor(double cA, double mA,
461 double yA, double kA, GString *nameA);
466 PSOutCustomColor *next;
469 PSOutCustomColor::PSOutCustomColor(double cA, double mA,
470 double yA, double kA, GString *nameA) {
479 PSOutCustomColor::~PSOutCustomColor() {
483 //------------------------------------------------------------------------
485 //------------------------------------------------------------------------
488 typedef void (*SignalFunc)(int);
491 PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
492 int firstPage, int lastPage, PSOutMode modeA) {
504 level = globalParams->getPSLevel();
506 paperWidth = globalParams->getPSPaperWidth();
507 paperHeight = globalParams->getPSPaperHeight();
510 fontFileNames = NULL;
514 if (mode == psModeForm) {
515 lastPage = firstPage;
519 inType3Char = gFalse;
523 // initialize OPI nesting levels
530 if (!strcmp(fileName, "-")) {
533 } else if (fileName[0] == '|') {
537 signal(SIGPIPE, (SignalFunc)SIG_IGN);
539 if (!(f = popen(fileName + 1, "w"))) {
540 error(-1, "Couldn't run print command '%s'", fileName);
545 error(-1, "Print commands are not supported ('%s')", fileName);
551 if (!(f = fopen(fileName, "w"))) {
552 error(-1, "Couldn't open PostScript file '%s'", fileName);
558 // initialize fontIDs, fontFileIDs, and fontFileNames lists
561 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
564 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
565 fontFileNameSize = 64;
567 fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
571 // initialize embedded font resource comment list
572 embFontList = new GString();
577 writePS("%%!PS-Adobe-3.0\n");
578 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
579 writePS("%%%%LanguageLevel: %d\n",
580 (level == psLevel1 || level == psLevel1Sep) ? 1 :
581 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
582 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
583 writePS("%%%%DocumentProcessColors: (atend)\n");
584 writePS("%%%%DocumentCustomColors: (atend)\n");
586 writePS("%%%%DocumentSuppliedResources: (atend)\n");
587 writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
588 paperWidth, paperHeight);
589 writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
590 writePS("%%%%EndComments\n");
591 writePS("%%%%BeginDefaults\n");
592 writePS("%%%%PageMedia: plain\n");
593 writePS("%%%%EndDefaults\n");
596 writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
597 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
598 writePS("%%%%LanguageLevel: %d\n",
599 (level == psLevel1 || level == psLevel1Sep) ? 1 :
600 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
601 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
602 writePS("%%%%DocumentProcessColors: (atend)\n");
603 writePS("%%%%DocumentCustomColors: (atend)\n");
605 page = catalog->getPage(firstPage);
606 box = page->getBox();
607 writePS("%%%%BoundingBox: %d %d %d %d\n",
608 (int)floor(box->x1), (int)floor(box->y1),
609 (int)ceil(box->x2), (int)ceil(box->y2));
610 if (floor(box->x1) != ceil(box->x1) ||
611 floor(box->y1) != ceil(box->y1) ||
612 floor(box->x2) != ceil(box->x2) ||
613 floor(box->y2) != ceil(box->y2)) {
614 writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
615 box->x1, box->y1, box->x2, box->y2);
617 writePS("%%%%DocumentSuppliedResources: (atend)\n");
618 writePS("%%%%EndComments\n");
621 writePS("%%!PS-Adobe-3.0 Resource-Form\n");
622 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
623 writePS("%%%%LanguageLevel: %d\n",
624 (level == psLevel1 || level == psLevel1Sep) ? 1 :
625 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
626 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
627 writePS("%%%%DocumentProcessColors: (atend)\n");
628 writePS("%%%%DocumentCustomColors: (atend)\n");
630 writePS("%%%%DocumentSuppliedResources: (atend)\n");
631 writePS("%%%%EndComments\n");
632 page = catalog->getPage(firstPage);
633 box = page->getBox();
634 writePS("32 dict dup begin\n");
635 writePS("/BBox [%d %d %d %d] def\n",
636 (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
637 writePS("/FormType 1 def\n");
638 writePS("/Matrix [1 0 0 1 0 0] def\n");
643 if (mode != psModeForm) {
644 writePS("%%%%BeginProlog\n");
646 writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
647 for (p = prolog; *p; ++p) {
650 writePS("%%%%EndResource\n");
651 if (level >= psLevel3) {
652 for (p = cmapProlog; *p; ++p) {
656 if (mode != psModeForm) {
657 writePS("%%%%EndProlog\n");
660 // set up fonts and images
661 if (mode == psModeForm) {
662 // swap the form and xpdf dicts
663 writePS("xpdf end begin dup begin\n");
665 writePS("%%%%BeginSetup\n");
666 writePS("xpdf begin\n");
668 for (pg = firstPage; pg <= lastPage; ++pg) {
669 page = catalog->getPage(pg);
670 if ((resDict = page->getResourceDict())) {
671 setupResources(resDict);
673 annots = new Annots(xref, page->getAnnots(&obj1));
675 for (i = 0; i < annots->getNumAnnots(); ++i) {
676 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
677 obj1.streamGetDict()->lookup("Resources", &obj2);
679 setupResources(obj2.getDict());
687 if (mode != psModeForm) {
688 if (mode != psModeEPS) {
689 writePS("%d %d %s pdfSetup\n",
690 paperWidth, paperHeight,
691 globalParams->getPSDuplex() ? "true" : "false");
694 if (globalParams->getPSOPI()) {
695 writePS("/opiMatrix matrix currentmatrix def\n");
698 writePS("%%%%EndSetup\n");
701 // initialize sequential page number
705 PSOutputDev::~PSOutputDev() {
706 PSOutCustomColor *cc;
710 if (mode == psModeForm) {
711 writePS("/Foo exch /Form defineresource pop\n");
713 writePS("%%%%Trailer\n");
715 writePS("%%%%DocumentSuppliedResources:\n");
716 writePS("%s", embFontList->getCString());
717 if (level == psLevel1Sep || level == psLevel2Sep ||
718 level == psLevel3Sep) {
719 writePS("%%%%DocumentProcessColors:");
720 if (processColors & psProcessCyan) {
723 if (processColors & psProcessMagenta) {
726 if (processColors & psProcessYellow) {
729 if (processColors & psProcessBlack) {
733 writePS("%%%%DocumentCustomColors:");
734 for (cc = customColors; cc; cc = cc->next) {
735 writePS(" (%s)", cc->name->getCString());
738 writePS("%%%%CMYKCustomColor:\n");
739 for (cc = customColors; cc; cc = cc->next) {
740 writePS("%%%%+ %g %g %g %g (%s)\n",
741 cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
744 writePS("%%%%EOF\n");
746 if (fileType == psFile) {
748 ICS_MapRefNumAndAssign((short)f->handle);
753 else if (fileType == psPipe) {
756 signal(SIGPIPE, (SignalFunc)SIG_DFL);
771 for (i = 0; i < fontFileNameLen; ++i) {
772 delete fontFileNames[i];
774 gfree(fontFileNames);
777 for (i = 0; i < font16EncLen; ++i) {
778 delete font16Enc[i].enc;
782 while (customColors) {
784 customColors = cc->next;
789 void PSOutputDev::setupResources(Dict *resDict) {
790 Object xObjDict, xObj, resObj;
794 setupImages(resDict);
796 resDict->lookup("XObject", &xObjDict);
797 if (xObjDict.isDict()) {
798 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
799 xObjDict.dictGetVal(i, &xObj);
800 if (xObj.isStream()) {
801 xObj.streamGetDict()->lookup("Resources", &resObj);
802 if (resObj.isDict()) {
803 setupResources(resObj.getDict());
813 void PSOutputDev::setupFonts(Dict *resDict) {
815 GfxFontDict *gfxFontDict;
819 resDict->lookup("Font", &fontDict);
820 if (fontDict.isDict()) {
821 gfxFontDict = new GfxFontDict(xref, fontDict.getDict());
822 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
823 font = gfxFontDict->getFont(i);
824 setupFont(font, resDict);
831 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
834 PSFontParam *fontParam;
846 // check if font is already set up
847 for (i = 0; i < fontIDLen; ++i) {
848 if (fontIDs[i].num == font->getID()->num &&
849 fontIDs[i].gen == font->getID()->gen) {
854 // add entry to fontIDs list
855 if (fontIDLen >= fontIDSize) {
857 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
859 fontIDs[fontIDLen++] = *font->getID();
864 // check for resident 8-bit font
865 if (font->getName() &&
866 (fontParam = globalParams->getPSFont(font->getName()))) {
867 psName = fontParam->psFontName->getCString();
869 // check for embedded Type 1 font
870 } else if (globalParams->getPSEmbedType1() &&
871 font->getType() == fontType1 &&
872 font->getEmbeddedFontID(&fontFileID)) {
873 psNameStr = filterPSName(font->getEmbeddedFontName());
874 psName = psNameStr->getCString();
875 setupEmbeddedType1Font(&fontFileID, psName);
877 // check for embedded Type 1C font
878 } else if (globalParams->getPSEmbedType1() &&
879 font->getType() == fontType1C &&
880 font->getEmbeddedFontID(&fontFileID)) {
881 psNameStr = filterPSName(font->getEmbeddedFontName());
882 psName = psNameStr->getCString();
883 setupEmbeddedType1CFont(font, &fontFileID, psName);
885 // check for external Type 1 font file
886 } else if (globalParams->getPSEmbedType1() &&
887 font->getType() == fontType1 &&
888 font->getExtFontFile()) {
889 // this assumes that the PS font name matches the PDF font name
890 psName = font->getName()->getCString();
891 setupExternalType1Font(font->getExtFontFile(), psName);
893 // check for embedded TrueType font
894 } else if (globalParams->getPSEmbedTrueType() &&
895 font->getType() == fontTrueType &&
896 font->getEmbeddedFontID(&fontFileID)) {
897 psNameStr = filterPSName(font->getEmbeddedFontName());
898 psName = psNameStr->getCString();
899 setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
901 // check for external TrueType font file
902 } else if (globalParams->getPSEmbedTrueType() &&
903 font->getType() == fontTrueType &&
904 font->getExtFontFile()) {
905 psNameStr = filterPSName(font->getName());
906 psName = psNameStr->getCString();
907 setupExternalTrueTypeFont(font, psName);
909 // check for embedded CID PostScript font
910 } else if (globalParams->getPSEmbedCIDPostScript() &&
911 font->getType() == fontCIDType0C &&
912 font->getEmbeddedFontID(&fontFileID)) {
913 psNameStr = filterPSName(font->getEmbeddedFontName());
914 psName = psNameStr->getCString();
915 setupEmbeddedCIDType0Font(font, &fontFileID, psName);
917 // check for embedded CID TrueType font
918 } else if (globalParams->getPSEmbedCIDTrueType() &&
919 font->getType() == fontCIDType2 &&
920 font->getEmbeddedFontID(&fontFileID)) {
921 psNameStr = filterPSName(font->getEmbeddedFontName());
922 psName = psNameStr->getCString();
923 setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName);
925 } else if (font->getType() == fontType3) {
926 sprintf(type3Name, "T3_%d_%d",
927 font->getID()->num, font->getID()->gen);
929 setupType3Font(font, psName, parentResDict);
931 // do 8-bit font substitution
932 } else if (!font->isCIDFont()) {
933 name = font->getName();
936 for (i = 0; psFonts[i]; ++i) {
937 if (name->cmp(psFonts[i]) == 0) {
944 if (font->isFixedWidth()) {
946 } else if (font->isSerif()) {
951 if (font->isBold()) {
954 if (font->isItalic()) {
957 psName = psSubstFonts[i].psName;
958 for (code = 0; code < 256; ++code) {
959 if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
960 charName[0] == 'm' && charName[1] == '\0') {
965 w1 = ((Gfx8BitFont *)font)->getWidth(code);
969 w2 = psSubstFonts[i].mWidth;
974 if (font->getType() == fontType3) {
975 // This is a hack which makes it possible to substitute for some
976 // Type 3 fonts. The problem is that it's impossible to know what
977 // the base coordinate system used in the font is without actually
978 // rendering the font.
980 fm = font->getFontMatrix();
989 // do 16-bit font substitution
990 } else if ((fontParam = globalParams->
991 getPSFont16(font->getName(),
992 ((GfxCIDFont *)font)->getCollection(),
993 font->getWMode()))) {
994 psName = fontParam->psFontName->getCString();
995 if (font16EncLen >= font16EncSize) {
997 font16Enc = (PSFont16Enc *)grealloc(font16Enc,
998 font16EncSize * sizeof(PSFont16Enc));
1000 font16Enc[font16EncLen].fontID = *font->getID();
1001 font16Enc[font16EncLen].enc = fontParam->encoding->copy();
1002 if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
1006 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1007 font16Enc[font16EncLen].enc->getCString());
1010 // give up - can't do anything with this font
1012 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1013 font->getName() ? font->getName()->getCString() : "(unnamed)",
1014 ((GfxCIDFont *)font)->getCollection()
1015 ? ((GfxCIDFont *)font)->getCollection()->getCString()
1020 // generate PostScript code to set up the font
1021 if (font->isCIDFont()) {
1022 if (level == psLevel3 || level == psLevel3Sep) {
1023 writePS("/F%d_%d /%s %d pdfMakeFont16L3\n",
1024 font->getID()->num, font->getID()->gen, psName,
1027 writePS("/F%d_%d /%s %d pdfMakeFont16\n",
1028 font->getID()->num, font->getID()->gen, psName,
1032 writePS("/F%d_%d /%s %g %g\n",
1033 font->getID()->num, font->getID()->gen, psName, xs, ys);
1034 for (i = 0; i < 256; i += 8) {
1035 writePS((i == 0) ? "[ " : " ");
1036 for (j = 0; j < 8; ++j) {
1037 charName = ((Gfx8BitFont *)font)->getCharName(i+j);
1038 // this is a kludge for broken PDF files that encode char 32
1040 if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
1043 writePS("/%s", charName ? charName : ".notdef");
1045 writePS((i == 256-8) ? "]\n" : "\n");
1047 writePS("pdfMakeFont\n");
1055 void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
1056 static char hexChar[17] = "0123456789abcdef";
1057 Object refObj, strObj, obj1, obj2;
1059 int length1, length2;
1065 // check if font is already embedded
1066 for (i = 0; i < fontFileIDLen; ++i) {
1067 if (fontFileIDs[i].num == id->num &&
1068 fontFileIDs[i].gen == id->gen)
1072 // add entry to fontFileIDs list
1073 if (fontFileIDLen >= fontFileIDSize) {
1074 fontFileIDSize += 64;
1075 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1077 fontFileIDs[fontFileIDLen++] = *id;
1079 // get the font stream and info
1080 refObj.initRef(id->num, id->gen);
1081 refObj.fetch(xref, &strObj);
1083 if (!strObj.isStream()) {
1084 error(-1, "Embedded font file object is not a stream");
1087 if (!(dict = strObj.streamGetDict())) {
1088 error(-1, "Embedded font stream is missing its dictionary");
1091 dict->lookup("Length1", &obj1);
1092 dict->lookup("Length2", &obj2);
1093 if (!obj1.isInt() || !obj2.isInt()) {
1094 error(-1, "Missing length fields in embedded font stream dictionary");
1099 length1 = obj1.getInt();
1100 length2 = obj2.getInt();
1104 // beginning comment
1105 writePS("%%%%BeginResource: font %s\n", psName);
1106 embFontList->append("%%+ font ");
1107 embFontList->append(psName);
1108 embFontList->append("\n");
1110 // copy ASCII portion of font
1111 strObj.streamReset();
1112 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
1116 // figure out if encrypted portion is binary or ASCII
1118 for (i = 0; i < 4; ++i) {
1119 start[i] = strObj.streamGetChar();
1120 if (start[i] == EOF) {
1121 error(-1, "Unexpected end of file in embedded font stream");
1124 if (!((start[i] >= '0' && start[i] <= '9') ||
1125 (start[i] >= 'A' && start[i] <= 'F') ||
1126 (start[i] >= 'a' && start[i] <= 'f')))
1130 // convert binary data to ASCII
1132 for (i = 0; i < 4; ++i) {
1133 writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
1134 writePSChar(hexChar[start[i] & 0x0f]);
1136 while (i < length2) {
1137 if ((c = strObj.streamGetChar()) == EOF) {
1140 writePSChar(hexChar[(c >> 4) & 0x0f]);
1141 writePSChar(hexChar[c & 0x0f]);
1142 if (++i % 32 == 0) {
1150 // already in ASCII format -- just copy it
1152 for (i = 0; i < 4; ++i) {
1153 writePSChar(start[i]);
1155 for (i = 4; i < length2; ++i) {
1156 if ((c = strObj.streamGetChar()) == EOF) {
1163 // write padding and "cleartomark"
1164 for (i = 0; i < 8; ++i) {
1165 writePS("00000000000000000000000000000000"
1166 "00000000000000000000000000000000\n");
1168 writePS("cleartomark\n");
1171 writePS("%%%%EndResource\n");
1174 strObj.streamClose();
1178 //~ This doesn't handle .pfb files or binary eexec data (which only
1179 //~ happens in pfb files?).
1180 void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
1185 // check if font is already embedded
1186 for (i = 0; i < fontFileNameLen; ++i) {
1187 if (!fontFileNames[i]->cmp(fileName)) {
1192 // add entry to fontFileNames list
1193 if (fontFileNameLen >= fontFileNameSize) {
1194 fontFileNameSize += 64;
1195 fontFileNames = (GString **)grealloc(fontFileNames,
1196 fontFileNameSize * sizeof(GString *));
1198 fontFileNames[fontFileNameLen++] = fileName->copy();
1200 // beginning comment
1201 writePS("%%%%BeginResource: font %s\n", psName);
1202 embFontList->append("%%+ font ");
1203 embFontList->append(psName);
1204 embFontList->append("\n");
1206 // copy the font file
1207 if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
1208 error(-1, "Couldn't open external font file");
1211 while ((c = fgetc(fontFile)) != EOF) {
1217 writePS("%%%%EndResource\n");
1220 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
1224 Type1CFontFile *t1cFile;
1227 // check if font is already embedded
1228 for (i = 0; i < fontFileIDLen; ++i) {
1229 if (fontFileIDs[i].num == id->num &&
1230 fontFileIDs[i].gen == id->gen)
1234 // add entry to fontFileIDs list
1235 if (fontFileIDLen >= fontFileIDSize) {
1236 fontFileIDSize += 64;
1237 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1239 fontFileIDs[fontFileIDLen++] = *id;
1241 // beginning comment
1242 writePS("%%%%BeginResource: font %s\n", psName);
1243 embFontList->append("%%+ font ");
1244 embFontList->append(psName);
1245 embFontList->append("\n");
1247 // convert it to a Type 1 font
1248 fontBuf = font->readEmbFontFile(xref, &fontLen);
1249 t1cFile = new Type1CFontFile(fontBuf, fontLen);
1250 t1cFile->convertToType1(f);
1255 writePS("%%%%EndResource\n");
1258 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
1262 TrueTypeFontFile *ttFile;
1263 CharCodeToUnicode *ctu;
1266 // check if font is already embedded
1267 for (i = 0; i < fontFileIDLen; ++i) {
1268 if (fontFileIDs[i].num == id->num &&
1269 fontFileIDs[i].gen == id->gen)
1273 // add entry to fontFileIDs list
1274 if (fontFileIDLen >= fontFileIDSize) {
1275 fontFileIDSize += 64;
1276 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1278 fontFileIDs[fontFileIDLen++] = *id;
1280 // beginning comment
1281 writePS("%%%%BeginResource: font %s\n", psName);
1282 embFontList->append("%%+ font ");
1283 embFontList->append(psName);
1284 embFontList->append("\n");
1286 // convert it to a Type 42 font
1287 fontBuf = font->readEmbFontFile(xref, &fontLen);
1288 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
1289 ctu = ((Gfx8BitFont *)font)->getToUnicode();
1290 ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
1291 ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f);
1297 writePS("%%%%EndResource\n");
1300 void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
1304 TrueTypeFontFile *ttFile;
1305 CharCodeToUnicode *ctu;
1308 // check if font is already embedded
1309 fileName = font->getExtFontFile();
1310 for (i = 0; i < fontFileNameLen; ++i) {
1311 if (!fontFileNames[i]->cmp(fileName)) {
1316 // add entry to fontFileNames list
1317 if (fontFileNameLen >= fontFileNameSize) {
1318 fontFileNameSize += 64;
1319 fontFileNames = (GString **)grealloc(fontFileNames,
1320 fontFileNameSize * sizeof(GString *));
1322 fontFileNames[fontFileNameLen++] = fileName->copy();
1324 // beginning comment
1325 writePS("%%%%BeginResource: font %s\n", psName);
1326 embFontList->append("%%+ font ");
1327 embFontList->append(psName);
1328 embFontList->append("\n");
1330 // convert it to a Type 42 font
1331 fontBuf = font->readExtFontFile(&fontLen);
1332 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
1333 ctu = ((Gfx8BitFont *)font)->getToUnicode();
1334 ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
1335 ctu, ((Gfx8BitFont *)font)->getHasEncoding(), f);
1341 writePS("%%%%EndResource\n");
1344 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
1348 Type1CFontFile *t1cFile;
1351 // check if font is already embedded
1352 for (i = 0; i < fontFileIDLen; ++i) {
1353 if (fontFileIDs[i].num == id->num &&
1354 fontFileIDs[i].gen == id->gen)
1358 // add entry to fontFileIDs list
1359 if (fontFileIDLen >= fontFileIDSize) {
1360 fontFileIDSize += 64;
1361 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1363 fontFileIDs[fontFileIDLen++] = *id;
1365 // beginning comment
1366 writePS("%%%%BeginResource: font %s\n", psName);
1367 embFontList->append("%%+ font ");
1368 embFontList->append(psName);
1369 embFontList->append("\n");
1371 // convert it to a Type 0 font
1372 fontBuf = font->readEmbFontFile(xref, &fontLen);
1373 t1cFile = new Type1CFontFile(fontBuf, fontLen);
1374 if (globalParams->getPSLevel() >= psLevel3) {
1375 // Level 3: use a CID font
1376 t1cFile->convertToCIDType0(psName, f);
1378 // otherwise: use a non-CID composite font
1379 t1cFile->convertToType0(psName, f);
1385 writePS("%%%%EndResource\n");
1388 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
1392 TrueTypeFontFile *ttFile;
1395 // check if font is already embedded
1396 for (i = 0; i < fontFileIDLen; ++i) {
1397 if (fontFileIDs[i].num == id->num &&
1398 fontFileIDs[i].gen == id->gen)
1402 // add entry to fontFileIDs list
1403 if (fontFileIDLen >= fontFileIDSize) {
1404 fontFileIDSize += 64;
1405 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1407 fontFileIDs[fontFileIDLen++] = *id;
1409 // beginning comment
1410 writePS("%%%%BeginResource: font %s\n", psName);
1411 embFontList->append("%%+ font ");
1412 embFontList->append(psName);
1413 embFontList->append("\n");
1415 // convert it to a Type 0 font
1416 fontBuf = font->readEmbFontFile(xref, &fontLen);
1417 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
1418 if (globalParams->getPSLevel() >= psLevel3) {
1419 ttFile->convertToCIDType2(psName,
1420 ((GfxCIDFont *)font)->getCIDToGID(),
1421 ((GfxCIDFont *)font)->getCIDToGIDLen(), f);
1423 // otherwise: use a non-CID composite font
1424 ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(),
1425 ((GfxCIDFont *)font)->getCIDToGIDLen(), f);
1431 writePS("%%%%EndResource\n");
1434 void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
1435 Dict *parentResDict) {
1444 // set up resources used by font
1445 if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
1446 setupResources(resDict);
1448 resDict = parentResDict;
1451 // beginning comment
1452 writePS("%%%%BeginResource: font %s\n", psName);
1453 embFontList->append("%%+ font ");
1454 embFontList->append(psName);
1455 embFontList->append("\n");
1458 writePS("7 dict begin\n");
1459 writePS("/FontType 3 def\n");
1460 m = font->getFontMatrix();
1461 writePS("/FontMatrix [%g %g %g %g %g %g] def\n",
1462 m[0], m[1], m[2], m[3], m[4], m[5]);
1463 m = font->getFontBBox();
1464 writePS("/FontBBox [%g %g %g %g] def\n",
1465 m[0], m[1], m[2], m[3]);
1466 writePS("/Encoding 256 array def\n");
1467 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
1468 writePS("/BuildGlyph {\n");
1469 writePS(" exch /CharProcs get exch\n");
1470 writePS(" 2 copy known not { pop /.notdef } if\n");
1471 writePS(" get exec\n");
1472 writePS("} bind def\n");
1473 writePS("/BuildChar {\n");
1474 writePS(" 1 index /Encoding get exch get\n");
1475 writePS(" 1 index /BuildGlyph get exec\n");
1476 writePS("} bind def\n");
1477 if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
1478 writePS("/CharProcs %d dict def\n", charProcs->getLength());
1479 writePS("CharProcs begin\n");
1484 gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL);
1485 inType3Char = gTrue;
1486 for (i = 0; i < charProcs->getLength(); ++i) {
1487 writePS("/%s {\n", charProcs->getKey(i));
1488 gfx->display(charProcs->getVal(i, &charProc));
1492 fprintf(f, "%g %g %g %g %g %g setcachedevice\n",
1493 t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
1495 fprintf(f, "%g %g setcharwidth\n", t3WX, t3WY);
1497 fputs(t3String->getCString(), f);
1504 inType3Char = gFalse;
1508 writePS("currentdict end\n");
1509 writePS("/%s exch definefont pop\n", psName);
1512 writePS("%%%%EndResource\n");
1515 void PSOutputDev::setupImages(Dict *resDict) {
1516 Object xObjDict, xObj, xObjRef, subtypeObj;
1519 if (mode != psModeForm) {
1523 resDict->lookup("XObject", &xObjDict);
1524 if (xObjDict.isDict()) {
1525 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
1526 xObjDict.dictGetValNF(i, &xObjRef);
1527 xObjDict.dictGetVal(i, &xObj);
1528 if (xObj.isStream()) {
1529 xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
1530 if (subtypeObj.isName("Image")) {
1531 if (xObjRef.isRef()) {
1532 setupImage(xObjRef.getRef(), xObj.getStream());
1534 error(-1, "Image in resource dict is not an indirect reference");
1546 void PSOutputDev::setupImage(Ref id, Stream *str) {
1548 int size, line, col, i;
1550 // construct an encoder stream
1551 if (globalParams->getPSASCIIHex()) {
1552 str = new ASCIIHexEncoder(str);
1554 str = new ASCII85Encoder(str);
1557 // compute image data size
1563 } while (c == '\n' || c == '\r');
1564 if (c == '~' || c == EOF) {
1571 for (i = 1; i <= 4; ++i) {
1574 } while (c == '\n' || c == '\r');
1575 if (c == '~' || c == EOF) {
1585 } while (c != '~' && c != EOF);
1587 writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
1589 // write the data into the array
1592 writePS("dup 0 <~");
1596 } while (c == '\n' || c == '\r');
1597 if (c == '~' || c == EOF) {
1606 for (i = 1; i <= 4; ++i) {
1609 } while (c == '\n' || c == '\r');
1610 if (c == '~' || c == EOF) {
1617 // each line is: "dup nnnnn <~...data...~> put<eol>"
1618 // so max data length = 255 - 20 = 235
1619 // chunks are 1 or 4 bytes each, so we have to stop at 232
1620 // but make it 225 just to be safe
1622 writePS("~> put\n");
1624 writePS("dup %d <~", line);
1627 } while (c != '~' && c != EOF);
1628 writePS("~> put\n");
1634 void PSOutputDev::startPage(int pageNum, GfxState *state) {
1635 int x1, y1, x2, y2, width, height, t;
1640 writePS("%%%%Page: %d %d\n", pageNum, seqPage);
1641 writePS("%%%%BeginPageSetup\n");
1643 // rotate, translate, and scale page
1644 x1 = (int)(state->getX1() + 0.5);
1645 y1 = (int)(state->getY1() + 0.5);
1646 x2 = (int)(state->getX2() + 0.5);
1647 y2 = (int)(state->getY2() + 0.5);
1650 if (width > height && width > paperWidth) {
1652 writePS("%%%%PageOrientation: %s\n",
1653 state->getCTM()[0] ? "Landscape" : "Portrait");
1654 writePS("pdfStartPage\n");
1655 writePS("90 rotate\n");
1657 ty = -(y1 + paperWidth);
1663 writePS("%%%%PageOrientation: %s\n",
1664 state->getCTM()[0] ? "Portrait" : "Landscape");
1665 writePS("pdfStartPage\n");
1669 if (width < paperWidth) {
1670 tx += (paperWidth - width) / 2;
1672 if (height < paperHeight) {
1673 ty += (paperHeight - height) / 2;
1675 if (tx != 0 || ty != 0) {
1676 writePS("%g %g translate\n", tx, ty);
1678 if (width > paperWidth || height > paperHeight) {
1679 xScale = (double)paperWidth / (double)width;
1680 yScale = (double)paperHeight / (double)height;
1681 if (yScale < xScale) {
1686 writePS("%0.4f %0.4f scale\n", xScale, xScale);
1688 xScale = yScale = 1;
1691 writePS("%%%%EndPageSetup\n");
1696 writePS("pdfStartPage\n");
1698 xScale = yScale = 1;
1703 writePS("/PaintProc {\n");
1704 writePS("begin xpdf begin\n");
1705 writePS("pdfStartPage\n");
1707 xScale = yScale = 1;
1713 void PSOutputDev::endPage() {
1714 if (mode == psModeForm) {
1715 writePS("pdfEndPage\n");
1716 writePS("end end\n");
1718 writePS("end end\n");
1720 writePS("showpage\n");
1721 writePS("%%%%PageTrailer\n");
1722 writePS("pdfEndPage\n");
1726 void PSOutputDev::saveState(GfxState *state) {
1730 void PSOutputDev::restoreState(GfxState *state) {
1734 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
1735 double m21, double m22, double m31, double m32) {
1736 writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
1739 void PSOutputDev::updateLineDash(GfxState *state) {
1744 state->getLineDash(&dash, &length, &start);
1746 for (i = 0; i < length; ++i)
1747 writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
1748 writePS("] %g d\n", start);
1751 void PSOutputDev::updateFlatness(GfxState *state) {
1752 writePS("%d i\n", state->getFlatness());
1755 void PSOutputDev::updateLineJoin(GfxState *state) {
1756 writePS("%d j\n", state->getLineJoin());
1759 void PSOutputDev::updateLineCap(GfxState *state) {
1760 writePS("%d J\n", state->getLineCap());
1763 void PSOutputDev::updateMiterLimit(GfxState *state) {
1764 writePS("%g M\n", state->getMiterLimit());
1767 void PSOutputDev::updateLineWidth(GfxState *state) {
1768 writePS("%g w\n", state->getLineWidth());
1771 void PSOutputDev::updateFillColor(GfxState *state) {
1776 GfxSeparationColorSpace *sepCS;
1780 state->getFillGray(&gray);
1781 writePS("%g g\n", gray);
1784 state->getFillCMYK(&cmyk);
1785 writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1789 if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
1790 state->getFillCMYK(&cmyk);
1791 writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1793 state->getFillRGB(&rgb);
1794 if (rgb.r == rgb.g && rgb.g == rgb.b) {
1795 writePS("%g g\n", rgb.r);
1797 writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
1803 if (state->getFillColorSpace()->getMode() == csSeparation) {
1804 sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
1806 sepCS->getCMYK(&color, &cmyk);
1807 writePS("%g %g %g %g %g (%s) ck\n",
1808 state->getFillColor()->c[0],
1809 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
1810 sepCS->getName()->getCString());
1811 addCustomColor(sepCS);
1813 state->getFillCMYK(&cmyk);
1814 writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1815 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1819 t3Cacheable = gFalse;
1822 void PSOutputDev::updateStrokeColor(GfxState *state) {
1827 GfxSeparationColorSpace *sepCS;
1831 state->getStrokeGray(&gray);
1832 writePS("%g G\n", gray);
1835 state->getStrokeCMYK(&cmyk);
1836 writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1840 if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
1841 state->getStrokeCMYK(&cmyk);
1842 writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1844 state->getStrokeRGB(&rgb);
1845 if (rgb.r == rgb.g && rgb.g == rgb.b) {
1846 writePS("%g G\n", rgb.r);
1848 writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
1854 if (state->getStrokeColorSpace()->getMode() == csSeparation) {
1855 sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
1857 sepCS->getCMYK(&color, &cmyk);
1858 writePS("%g %g %g %g %g (%s) CK\n",
1859 state->getStrokeColor()->c[0],
1860 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
1861 sepCS->getName()->getCString());
1862 addCustomColor(sepCS);
1864 state->getStrokeCMYK(&cmyk);
1865 writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1866 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
1870 t3Cacheable = gFalse;
1873 void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
1875 processColors |= psProcessCyan;
1878 processColors |= psProcessMagenta;
1881 processColors |= psProcessYellow;
1884 processColors |= psProcessBlack;
1888 void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
1889 PSOutCustomColor *cc;
1893 for (cc = customColors; cc; cc = cc->next) {
1894 if (!cc->name->cmp(sepCS->getName())) {
1899 sepCS->getCMYK(&color, &cmyk);
1900 cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
1901 sepCS->getName()->copy());
1902 cc->next = customColors;
1906 void PSOutputDev::updateFont(GfxState *state) {
1907 if (state->getFont()) {
1908 writePS("/F%d_%d %g Tf\n",
1909 state->getFont()->getID()->num, state->getFont()->getID()->gen,
1910 state->getFontSize());
1914 void PSOutputDev::updateTextMat(GfxState *state) {
1917 mat = state->getTextMat();
1918 writePS("[%g %g %g %g %g %g] Tm\n",
1919 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
1922 void PSOutputDev::updateCharSpace(GfxState *state) {
1923 writePS("%g Tc\n", state->getCharSpace());
1926 void PSOutputDev::updateRender(GfxState *state) {
1929 rm = state->getRender();
1930 writePS("%d Tr\n", rm);
1932 if (rm != 0 && rm != 3) {
1933 t3Cacheable = gFalse;
1937 void PSOutputDev::updateRise(GfxState *state) {
1938 writePS("%g Ts\n", state->getRise());
1941 void PSOutputDev::updateWordSpace(GfxState *state) {
1942 writePS("%g Tw\n", state->getWordSpace());
1945 void PSOutputDev::updateHorizScaling(GfxState *state) {
1946 writePS("%g Tz\n", state->getHorizScaling());
1949 void PSOutputDev::updateTextPos(GfxState *state) {
1950 writePS("%g %g Td\n", state->getLineX(), state->getLineY());
1953 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
1954 if (state->getFont()->getWMode()) {
1955 writePS("%g TJmV\n", shift);
1957 writePS("%g TJm\n", shift);
1961 void PSOutputDev::stroke(GfxState *state) {
1962 doPath(state->getPath());
1964 // if we're construct a cacheable Type 3 glyph, we need to do
1965 // everything in the fill color
1972 void PSOutputDev::fill(GfxState *state) {
1973 doPath(state->getPath());
1977 void PSOutputDev::eoFill(GfxState *state) {
1978 doPath(state->getPath());
1982 void PSOutputDev::clip(GfxState *state) {
1983 doPath(state->getPath());
1987 void PSOutputDev::eoClip(GfxState *state) {
1988 doPath(state->getPath());
1992 void PSOutputDev::doPath(GfxPath *path) {
1993 GfxSubpath *subpath;
1994 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
1997 n = path->getNumSubpaths();
1999 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
2000 subpath = path->getSubpath(0);
2001 x0 = subpath->getX(0);
2002 y0 = subpath->getY(0);
2003 x4 = subpath->getX(4);
2004 y4 = subpath->getY(4);
2005 if (x4 == x0 && y4 == y0) {
2006 x1 = subpath->getX(1);
2007 y1 = subpath->getY(1);
2008 x2 = subpath->getX(2);
2009 y2 = subpath->getY(2);
2010 x3 = subpath->getX(3);
2011 y3 = subpath->getY(3);
2012 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
2013 writePS("%g %g %g %g re\n",
2014 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
2015 fabs(x2 - x0), fabs(y1 - y0));
2017 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
2018 writePS("%g %g %g %g re\n",
2019 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
2020 fabs(x1 - x0), fabs(y2 - y0));
2026 for (i = 0; i < n; ++i) {
2027 subpath = path->getSubpath(i);
2028 m = subpath->getNumPoints();
2029 writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
2032 if (subpath->getCurve(j)) {
2033 writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
2034 subpath->getX(j+1), subpath->getY(j+1),
2035 subpath->getX(j+2), subpath->getY(j+2));
2038 writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
2042 if (subpath->isClosed()) {
2048 void PSOutputDev::drawString(GfxState *state, GString *s) {
2052 double dx, dy, dx2, dy2, originX, originY;
2058 int len, nChars, uLen, n, m, i, j;
2060 // check for invisible text -- this is used by Acrobat Capture
2061 if ((state->getRender() & 3) == 3) {
2065 // ignore empty strings
2066 if (s->getLength() == 0) {
2071 if (!(font = state->getFont())) {
2074 wMode = font->getWMode();
2076 // check for a subtitute 16-bit font
2078 if (font->isCIDFont()) {
2079 for (i = 0; i < font16EncLen; ++i) {
2080 if (font->getID()->num == font16Enc[i].fontID.num &&
2081 font->getID()->gen == font16Enc[i].fontID.gen) {
2082 uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
2088 // compute width of chars in string, ignoring char spacing and word
2089 // spacing -- the Tj operator will adjust for the metrics of the
2090 // font that's actually used
2093 p = s->getCString();
2094 len = s->getLength();
2095 if (font->isCIDFont()) {
2101 n = font->getNextChar(p, len, &code,
2102 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2103 &dx2, &dy2, &originX, &originY);
2104 if (font->isCIDFont()) {
2106 for (i = 0; i < uLen; ++i) {
2107 m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
2108 for (j = 0; j < m; ++j) {
2112 //~ this really needs to get the number of chars in the target
2113 //~ encoding - which may be more than the number of Unicode
2117 s2->append((char)((code >> 8) & 0xff));
2118 s2->append((char)(code & 0xff));
2127 dx *= state->getFontSize() * state->getHorizScaling();
2128 dy *= state->getFontSize();
2133 if (s2->getLength() > 0) {
2135 if (font->isCIDFont()) {
2137 writePS(" %d %g Tj16V\n", nChars, dy);
2139 writePS(" %d %g Tj16\n", nChars, dx);
2142 writePS(" %g Tj\n", dx);
2145 if (font->isCIDFont()) {
2150 void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2151 int width, int height, GBool invert,
2155 len = height * ((width + 7) / 8);
2156 if (level == psLevel1 || level == psLevel1Sep) {
2157 doImageL1(NULL, invert, inlineImg, str, width, height, len);
2159 doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
2163 void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2164 int width, int height, GfxImageColorMap *colorMap,
2165 int *maskColors, GBool inlineImg) {
2168 len = height * ((width * colorMap->getNumPixelComps() *
2169 colorMap->getBits() + 7) / 8);
2172 doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
2175 //~ handle indexed, separation, ... color spaces
2176 doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
2182 doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
2185 t3Cacheable = gFalse;
2188 void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
2189 GBool invert, GBool inlineImg,
2190 Stream *str, int width, int height, int len) {
2191 ImageStream *imgStr;
2192 Guchar pixBuf[gfxColorMaxComps];
2196 // width, height, matrix, bits per component
2198 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
2200 width, -height, height);
2202 writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
2203 width, height, invert ? "true" : "false",
2204 width, -height, height);
2210 // set up to process the data stream
2211 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
2212 colorMap->getBits());
2215 // process the data stream
2217 for (y = 0; y < height; ++y) {
2220 for (x = 0; x < width; ++x) {
2221 imgStr->getPixel(pixBuf);
2222 colorMap->getGray(pixBuf, &gray);
2223 writePS("%02x", (int)(gray * 255 + 0.5));
2239 for (y = 0; y < height; ++y) {
2240 for (x = 0; x < width; x += 8) {
2241 writePS("%02x", str->getChar() & 0xff);
2255 void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
2256 GBool invert, GBool inlineImg,
2257 Stream *str, int width, int height, int len) {
2258 ImageStream *imgStr;
2260 Guchar pixBuf[gfxColorMaxComps];
2264 // width, height, matrix, bits per component
2265 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
2267 width, -height, height);
2269 // allocate a line buffer
2270 lineBuf = (Guchar *)gmalloc(4 * width);
2272 // set up to process the data stream
2273 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
2274 colorMap->getBits());
2277 // process the data stream
2279 for (y = 0; y < height; ++y) {
2282 for (x = 0; x < width; ++x) {
2283 imgStr->getPixel(pixBuf);
2284 colorMap->getCMYK(pixBuf, &cmyk);
2285 lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5);
2286 lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
2287 lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
2288 lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
2291 // write one line of each color component
2292 for (comp = 0; comp < 4; ++comp) {
2293 for (x = 0; x < width; ++x) {
2294 writePS("%02x", lineBuf[4*x + comp]);
2311 void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
2312 GBool invert, GBool inlineImg,
2313 Stream *str, int width, int height, int len) {
2316 GBool useRLE, useASCII, useCompressed;
2317 GfxSeparationColorSpace *sepCS;
2325 dumpColorSpaceL2(colorMap->getColorSpace());
2326 writePS(" setcolorspace\n");
2329 // set up to use the array created by setupImages()
2330 if ((mode == psModeForm || inType3Char) && !inlineImg) {
2331 writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
2335 writePS("<<\n /ImageType 1\n");
2337 // width, height, matrix, bits per component
2338 writePS(" /Width %d\n", width);
2339 writePS(" /Height %d\n", height);
2340 writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
2341 writePS(" /BitsPerComponent %d\n",
2342 colorMap ? colorMap->getBits() : 1);
2346 writePS(" /Decode [");
2347 if (colorMap->getColorSpace()->getMode() == csSeparation) {
2348 //~ this is a kludge -- see comment in dumpColorSpaceL2
2349 n = (1 << colorMap->getBits()) - 1;
2350 writePS("%g %g", colorMap->getDecodeLow(0) * n,
2351 colorMap->getDecodeHigh(0) * n);
2353 numComps = colorMap->getNumPixelComps();
2354 for (i = 0; i < numComps; ++i) {
2358 writePS("%g %g", colorMap->getDecodeLow(i),
2359 colorMap->getDecodeHigh(i));
2364 writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
2367 if (mode == psModeForm || inType3Char) {
2372 writePS(" /DataSource <~\n");
2374 // write image data stream, using ASCII85 encode filter
2375 str = new FixedLengthEncoder(str, len);
2376 if (globalParams->getPSASCIIHex()) {
2377 str = new ASCIIHexEncoder(str);
2379 str = new ASCII85Encoder(str);
2382 while ((c = str->getChar()) != EOF) {
2389 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
2392 // end of image dictionary
2393 writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
2395 // get rid of the array and index
2397 writePS("pop pop\n");
2403 writePS(" /DataSource currentfile\n");
2404 s = str->getPSFilter(" ");
2405 if (inlineImg || !s) {
2408 useCompressed = gFalse;
2411 useASCII = str->isBinary();
2412 useCompressed = gTrue;
2415 writePS(" /ASCII%sDecode filter\n",
2416 globalParams->getPSASCIIHex() ? "Hex" : "85");
2419 writePS(" /RunLengthDecode filter\n");
2421 if (useCompressed) {
2422 writePS("%s", s->getCString());
2428 // cut off inline image streams at appropriate length
2430 str = new FixedLengthEncoder(str, len);
2431 } else if (useCompressed) {
2432 str = str->getBaseStream();
2435 // add RunLengthEncode and ASCIIHex/85 encode filters
2437 str = new RunLengthEncoder(str);
2440 if (globalParams->getPSASCIIHex()) {
2441 str = new ASCIIHexEncoder(str);
2443 str = new ASCII85Encoder(str);
2447 // end of image dictionary
2452 // this can't happen -- OPI dictionaries are in XObjects
2453 error(-1, "Internal: OPI in inline image");
2456 // need to read the stream to count characters -- the length
2457 // is data-dependent (because of ASCII and RLE filters)
2460 while ((c = str->getChar()) != EOF) {
2465 // +6/7 for "pdfIm\n" / "pdfImM\n"
2466 // +8 for newline + trailer
2467 n += colorMap ? 14 : 15;
2468 writePS("%%%%BeginData: %d Hex Bytes\n", n);
2471 if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
2472 colorMap->getColorSpace()->getMode() == csSeparation) {
2474 sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
2475 sepCS->getCMYK(&color, &cmyk);
2476 writePS("%g %g %g %g (%s) pdfImSep\n",
2477 cmyk.c, cmyk.m, cmyk.y, cmyk.k, sepCS->getName()->getCString());
2479 writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
2482 // copy the stream data
2484 while ((c = str->getChar()) != EOF) {
2489 // add newline and trailer to the end
2491 writePS("%%-EOD-\n");
2494 writePS("%%%%EndData\n");
2499 if (useRLE || useASCII || inlineImg) {
2505 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
2506 GfxCalGrayColorSpace *calGrayCS;
2507 GfxCalRGBColorSpace *calRGBCS;
2508 GfxLabColorSpace *labCS;
2509 GfxIndexedColorSpace *indexedCS;
2510 GfxSeparationColorSpace *separationCS;
2512 double x[gfxColorMaxComps], y[gfxColorMaxComps];
2518 switch (colorSpace->getMode()) {
2521 writePS("/DeviceGray");
2522 processColors |= psProcessBlack;
2526 calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
2527 writePS("[/CIEBasedA <<\n");
2528 writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
2529 writePS(" /MatrixA [%g %g %g]\n",
2530 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
2531 calGrayCS->getWhiteZ());
2532 writePS(" /WhitePoint [%g %g %g]\n",
2533 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
2534 calGrayCS->getWhiteZ());
2535 writePS(" /BlackPoint [%g %g %g]\n",
2536 calGrayCS->getBlackX(), calGrayCS->getBlackY(),
2537 calGrayCS->getBlackZ());
2539 processColors |= psProcessBlack;
2543 writePS("/DeviceRGB");
2544 processColors |= psProcessCMYK;
2548 calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
2549 writePS("[/CIEBasedABC <<\n");
2550 writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
2551 calRGBCS->getGammaR(), calRGBCS->getGammaG(),
2552 calRGBCS->getGammaB());
2553 writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
2554 calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
2555 calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
2556 calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
2557 calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
2558 calRGBCS->getMatrix()[8]);
2559 writePS(" /WhitePoint [%g %g %g]\n",
2560 calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
2561 calRGBCS->getWhiteZ());
2562 writePS(" /BlackPoint [%g %g %g]\n",
2563 calRGBCS->getBlackX(), calRGBCS->getBlackY(),
2564 calRGBCS->getBlackZ());
2566 processColors |= psProcessCMYK;
2570 writePS("/DeviceCMYK");
2571 processColors |= psProcessCMYK;
2575 labCS = (GfxLabColorSpace *)colorSpace;
2576 writePS("[/CIEBasedABC <<\n");
2577 writePS(" /RangeABC [0 100 %g %g %g %g]\n",
2578 labCS->getAMin(), labCS->getAMax(),
2579 labCS->getBMin(), labCS->getBMax());
2580 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
2581 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
2582 writePS(" /DecodeLMN\n");
2583 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
2584 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
2585 labCS->getWhiteX());
2586 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
2587 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
2588 labCS->getWhiteY());
2589 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
2590 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
2591 labCS->getWhiteZ());
2592 writePS(" /WhitePoint [%g %g %g]\n",
2593 labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
2594 writePS(" /BlackPoint [%g %g %g]\n",
2595 labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
2597 processColors |= psProcessCMYK;
2601 dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
2605 indexedCS = (GfxIndexedColorSpace *)colorSpace;
2606 writePS("[/Indexed ");
2607 dumpColorSpaceL2(indexedCS->getBase());
2608 n = indexedCS->getIndexHigh();
2609 numComps = indexedCS->getBase()->getNComps();
2610 lookup = indexedCS->getLookup();
2611 writePS(" %d <\n", n);
2612 for (i = 0; i <= n; i += 8) {
2614 for (j = i; j < i+8 && j <= n; ++j) {
2615 for (k = 0; k < numComps; ++k) {
2616 writePS("%02x", lookup[j * numComps + k]);
2619 indexedCS->getCMYK(&color, &cmyk);
2620 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2628 //~ this is a kludge -- the correct thing would to ouput a
2629 //~ separation color space, with the specified alternate color
2630 //~ space and tint transform
2631 separationCS = (GfxSeparationColorSpace *)colorSpace;
2632 writePS("[/Indexed ");
2633 dumpColorSpaceL2(separationCS->getAlt());
2634 writePS(" 255 <\n");
2635 numComps = separationCS->getAlt()->getNComps();
2636 for (i = 0; i <= 255; i += 8) {
2638 for (j = i; j < i+8 && j <= 255; ++j) {
2639 x[0] = (double)j / 255.0;
2640 separationCS->getFunc()->transform(x, y);
2641 for (k = 0; k < numComps; ++k) {
2642 writePS("%02x", (int)(255 * y[k] + 0.5));
2648 addCustomColor(separationCS);
2652 // DeviceN color spaces are a Level 3 PostScript feature.
2653 dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt());
2664 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
2667 if (globalParams->getPSOPI()) {
2668 opiDict->lookup("2.0", &dict);
2669 if (dict.isDict()) {
2670 opiBegin20(state, dict.getDict());
2674 opiDict->lookup("1.3", &dict);
2675 if (dict.isDict()) {
2676 opiBegin13(state, dict.getDict());
2683 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
2684 Object obj1, obj2, obj3, obj4;
2685 double width, height, left, right, top, bottom;
2689 writePS("%%%%BeginOPI: 2.0\n");
2690 writePS("%%%%Distilled\n");
2692 dict->lookup("F", &obj1);
2693 if (getFileSpec(&obj1, &obj2)) {
2694 writePS("%%%%ImageFileName: %s\n",
2695 obj2.getString()->getCString());
2700 dict->lookup("MainImage", &obj1);
2701 if (obj1.isString()) {
2702 writePS("%%%%MainImage: %s\n", obj1.getString()->getCString());
2706 //~ ignoring 'Tags' entry
2707 //~ need to use writePSString() and deal with >255-char lines
2709 dict->lookup("Size", &obj1);
2710 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2711 obj1.arrayGet(0, &obj2);
2712 width = obj2.getNum();
2714 obj1.arrayGet(1, &obj2);
2715 height = obj2.getNum();
2717 writePS("%%%%ImageDimensions: %g %g\n", width, height);
2721 dict->lookup("CropRect", &obj1);
2722 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
2723 obj1.arrayGet(0, &obj2);
2724 left = obj2.getNum();
2726 obj1.arrayGet(1, &obj2);
2727 top = obj2.getNum();
2729 obj1.arrayGet(2, &obj2);
2730 right = obj2.getNum();
2732 obj1.arrayGet(3, &obj2);
2733 bottom = obj2.getNum();
2735 writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
2739 dict->lookup("Overprint", &obj1);
2740 if (obj1.isBool()) {
2741 writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
2745 dict->lookup("Inks", &obj1);
2746 if (obj1.isName()) {
2747 writePS("%%%%ImageInks: %s\n", obj1.getName());
2748 } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
2749 obj1.arrayGet(0, &obj2);
2750 if (obj2.isName()) {
2751 writePS("%%%%ImageInks: %s %d",
2752 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
2753 for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
2754 obj1.arrayGet(i, &obj3);
2755 obj1.arrayGet(i+1, &obj4);
2756 if (obj3.isString() && obj4.isNum()) {
2758 writePSString(obj3.getString());
2759 writePS(" %g", obj4.getNum());
2772 writePS("%%%%BeginIncludedImage\n");
2774 dict->lookup("IncludedImageDimensions", &obj1);
2775 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2776 obj1.arrayGet(0, &obj2);
2779 obj1.arrayGet(1, &obj2);
2782 writePS("%%%%IncludedImageDimensions: %d %d\n", w, h);
2786 dict->lookup("IncludedImageQuality", &obj1);
2788 writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum());
2795 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
2797 int left, right, top, bottom, samples, bits, width, height;
2799 double llx, lly, ulx, uly, urx, ury, lrx, lry;
2800 double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
2805 writePS("/opiMatrix2 matrix currentmatrix def\n");
2806 writePS("opiMatrix setmatrix\n");
2808 dict->lookup("F", &obj1);
2809 if (getFileSpec(&obj1, &obj2)) {
2810 writePS("%%ALDImageFileName: %s\n",
2811 obj2.getString()->getCString());
2816 dict->lookup("CropRect", &obj1);
2817 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
2818 obj1.arrayGet(0, &obj2);
2819 left = obj2.getInt();
2821 obj1.arrayGet(1, &obj2);
2822 top = obj2.getInt();
2824 obj1.arrayGet(2, &obj2);
2825 right = obj2.getInt();
2827 obj1.arrayGet(3, &obj2);
2828 bottom = obj2.getInt();
2830 writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
2834 dict->lookup("Color", &obj1);
2835 if (obj1.isArray() && obj1.arrayGetLength() == 5) {
2836 obj1.arrayGet(0, &obj2);
2839 obj1.arrayGet(1, &obj2);
2842 obj1.arrayGet(2, &obj2);
2845 obj1.arrayGet(3, &obj2);
2848 obj1.arrayGet(4, &obj2);
2849 if (obj2.isString()) {
2850 writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
2851 writePSString(obj2.getString());
2858 dict->lookup("ColorType", &obj1);
2859 if (obj1.isName()) {
2860 writePS("%%ALDImageColorType: %s\n", obj1.getName());
2864 //~ ignores 'Comments' entry
2865 //~ need to handle multiple lines
2867 dict->lookup("CropFixed", &obj1);
2868 if (obj1.isArray()) {
2869 obj1.arrayGet(0, &obj2);
2870 ulx = obj2.getNum();
2872 obj1.arrayGet(1, &obj2);
2873 uly = obj2.getNum();
2875 obj1.arrayGet(2, &obj2);
2876 lrx = obj2.getNum();
2878 obj1.arrayGet(3, &obj2);
2879 lry = obj2.getNum();
2881 writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
2885 dict->lookup("GrayMap", &obj1);
2886 if (obj1.isArray()) {
2887 writePS("%%ALDImageGrayMap:");
2888 for (i = 0; i < obj1.arrayGetLength(); i += 16) {
2892 for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
2893 obj1.arrayGet(i+j, &obj2);
2894 writePS(" %d", obj2.getInt());
2902 dict->lookup("ID", &obj1);
2903 if (obj1.isString()) {
2904 writePS("%%ALDImageID: %s\n", obj1.getString()->getCString());
2908 dict->lookup("ImageType", &obj1);
2909 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2910 obj1.arrayGet(0, &obj2);
2911 samples = obj2.getInt();
2913 obj1.arrayGet(1, &obj2);
2914 bits = obj2.getInt();
2916 writePS("%%ALDImageType: %d %d\n", samples, bits);
2920 dict->lookup("Overprint", &obj1);
2921 if (obj1.isBool()) {
2922 writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
2926 dict->lookup("Position", &obj1);
2927 if (obj1.isArray() && obj1.arrayGetLength() == 8) {
2928 obj1.arrayGet(0, &obj2);
2929 llx = obj2.getNum();
2931 obj1.arrayGet(1, &obj2);
2932 lly = obj2.getNum();
2934 obj1.arrayGet(2, &obj2);
2935 ulx = obj2.getNum();
2937 obj1.arrayGet(3, &obj2);
2938 uly = obj2.getNum();
2940 obj1.arrayGet(4, &obj2);
2941 urx = obj2.getNum();
2943 obj1.arrayGet(5, &obj2);
2944 ury = obj2.getNum();
2946 obj1.arrayGet(6, &obj2);
2947 lrx = obj2.getNum();
2949 obj1.arrayGet(7, &obj2);
2950 lry = obj2.getNum();
2952 opiTransform(state, llx, lly, &tllx, &tlly);
2953 opiTransform(state, ulx, uly, &tulx, &tuly);
2954 opiTransform(state, urx, ury, &turx, &tury);
2955 opiTransform(state, lrx, lry, &tlrx, &tlry);
2956 writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
2957 tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
2962 dict->lookup("Resolution", &obj1);
2963 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2964 obj1.arrayGet(0, &obj2);
2965 horiz = obj2.getNum();
2967 obj1.arrayGet(1, &obj2);
2968 vert = obj2.getNum();
2970 writePS("%%ALDImageResoution: %g %g\n", horiz, vert);
2975 dict->lookup("Size", &obj1);
2976 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
2977 obj1.arrayGet(0, &obj2);
2978 width = obj2.getInt();
2980 obj1.arrayGet(1, &obj2);
2981 height = obj2.getInt();
2983 writePS("%%ALDImageDimensions: %d %d\n", width, height);
2987 //~ ignoring 'Tags' entry
2988 //~ need to use writePSString() and deal with >255-char lines
2990 dict->lookup("Tint", &obj1);
2992 writePS("%%ALDImageTint: %g\n", obj1.getNum());
2996 dict->lookup("Transparency", &obj1);
2997 if (obj1.isBool()) {
2998 writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
3002 writePS("%%%%BeginObject: image\n");
3003 writePS("opiMatrix2 setmatrix\n");
3007 // Convert PDF user space coordinates to PostScript default user space
3008 // coordinates. This has to account for both the PDF CTM and the
3009 // PSOutputDev page-fitting transform.
3010 void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
3011 double *x1, double *y1) {
3014 state->transform(x0, y0, x1, y1);
3026 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
3029 if (globalParams->getPSOPI()) {
3030 opiDict->lookup("2.0", &dict);
3031 if (dict.isDict()) {
3032 writePS("%%%%EndIncludedImage\n");
3033 writePS("%%%%EndOPI\n");
3034 writePS("grestore\n");
3039 opiDict->lookup("1.3", &dict);
3040 if (dict.isDict()) {
3041 writePS("%%%%EndObject\n");
3042 writePS("restore\n");
3050 GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
3051 if (fileSpec->isString()) {
3052 fileSpec->copy(fileName);
3055 if (fileSpec->isDict()) {
3056 fileSpec->dictLookup("DOS", fileName);
3057 if (fileName->isString()) {
3061 fileSpec->dictLookup("Mac", fileName);
3062 if (fileName->isString()) {
3066 fileSpec->dictLookup("Unix", fileName);
3067 if (fileName->isString()) {
3071 fileSpec->dictLookup("F", fileName);
3072 if (fileName->isString()) {
3079 #endif // OPI_SUPPORT
3081 void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
3082 writePS("%g %g setcharwidth\n", wx, wy);
3086 void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
3087 double llx, double lly, double urx, double ury) {
3094 t3String = new GString();
3096 t3Cacheable = gTrue;
3099 void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
3103 if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
3109 while ((c = str->getChar()) != EOF) {
3115 void PSOutputDev::writePS(const char *fmt, ...) {
3119 va_start(args, fmt);
3121 vsprintf(buf, fmt, args);
3122 t3String->append(buf);
3124 vfprintf(f, fmt, args);
3129 void PSOutputDev::writePSString(GString *s) {
3135 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
3136 if (*p == '(' || *p == ')' || *p == '\\') {
3138 writePSChar((char)*p);
3139 } else if (*p < 0x20 || *p >= 0x80) {
3141 sprintf(buf, "\\%03o", *p);
3142 t3String->append(buf);
3144 fprintf(f, "\\%03o", *p);
3147 writePSChar((char)*p);
3153 void PSOutputDev::writePSChar(char c) {
3155 t3String->append(c);
3161 GString *PSOutputDev::filterPSName(GString *name) {
3167 name2 = new GString();
3168 for (i = 0; i < name->getLength(); ++i) {
3169 c = name->getChar(i);
3170 if (c <= (char)0x20 || c >= (char)0x7f ||
3171 c == '(' || c == ')' || c == '<' || c == '>' ||
3172 c == '[' || c == ']' || c == '{' || c == '}' ||
3173 c == '/' || c == '%') {
3174 sprintf(buf, "#%02x", c & 0xff);