1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
22 #include "xpdfconfig.h"
23 #include "GlobalParams.h"
30 #include "UnicodeMap.h"
31 #include "FoFiType1C.h"
32 #include "FoFiTrueType.h"
37 #include "PSOutputDev.h"
40 // needed for setting type/creator of MacOS files
41 #include "ICSupport.h"
44 //------------------------------------------------------------------------
45 // PostScript prolog and setup
46 //------------------------------------------------------------------------
48 static char *prolog[] = {
49 "/xpdf 75 dict def xpdf begin",
50 "% PDF special state",
51 "/pdfDictSize 15 def",
53 "/pdfStates 64 array def",
55 " pdfStates exch pdfDictSize dict",
56 " dup /pdfStateIdx 3 index put",
61 " 3 1 roll 2 array astore",
62 " /setpagedevice where {",
64 " /PageSize exch def",
65 " /ImagingBBox null def",
66 " /Policies 1 dict dup begin /PageSize 3 def end def",
67 " { /Duplex true def } if",
68 " currentdict end setpagedevice",
75 " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
76 " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
77 " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
82 " pdfStates 0 get begin",
84 " pdfDictSize dict begin",
87 " /pdfStroke [0] def",
88 " /pdfLastFill false def",
89 " /pdfLastStroke false def",
90 " /pdfTextMat [1 0 0 1 0 0] def",
91 " /pdfFontSize 0 def",
92 " /pdfCharSpacing 0 def",
93 " /pdfTextRender 0 def",
94 " /pdfTextRise 0 def",
95 " /pdfWordSpacing 0 def",
96 " /pdfHorizScaling 1 def",
97 " /pdfTextClipPath [] def",
99 "/pdfEndPage { end } def",
100 "% separation convention operators",
101 "/findcmykcustomcolor where {",
104 " /findcmykcustomcolor { 5 array astore } def",
106 "/setcustomcolor where {",
109 " /setcustomcolor {",
111 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
112 " 0 4 getinterval cvx",
113 " [ exch /dup load exch { mul exch dup } /forall load",
114 " /pop load dup ] cvx",
115 " ] setcolorspace setcolor",
118 "/customcolorimage where {",
121 " /customcolorimage {",
123 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
125 " [ exch /dup load exch { mul exch dup } /forall load",
126 " /pop load dup ] cvx",
130 " /DataSource exch def",
131 " /ImageMatrix exch def",
132 " /BitsPerComponent exch def",
135 " /Decode [1 0] def",
143 " pdfLastStroke not {",
144 " pdfStroke aload length",
154 " findcmykcustomcolor exch setcustomcolor",
158 " /pdfLastStroke true def /pdfLastFill false def",
162 " pdfLastFill not {",
163 " pdfFill aload length",
173 " findcmykcustomcolor exch setcustomcolor",
177 " /pdfLastFill true def /pdfLastStroke false def",
182 " 4 3 roll findfont",
183 " 4 2 roll matrix scale makefont",
184 " dup length dict begin",
185 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
186 " /Encoding exch def",
193 " dup length dict begin",
194 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
200 "/pdfMakeFont16L3 {",
201 " 1 index /CIDFont resourcestatus {",
202 " pop pop 1 index /CIDFont findresource /CIDFontType known",
207 " 0 eq { /Identity-H } { /Identity-V } ifelse",
208 " exch 1 array astore composefont pop",
213 "% graphics state operators",
217 " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
218 " pdfStates pdfStateIdx 1 add get begin",
219 " pdfOpNames { exch def } forall",
222 "/q { gsave pdfDictSize dict begin } def",
224 "/Q { end grestore } def",
225 "/cm { concat } def",
226 "/d { setdash } def",
227 "/i { setflat } def",
228 "/j { setlinejoin } def",
229 "/J { setlinecap } def",
230 "/M { setmiterlimit } def",
231 "/w { setlinewidth } def",
233 "/g { dup 1 array astore /pdfFill exch def setgray",
234 " /pdfLastFill true def /pdfLastStroke false def } def",
235 "/G { dup 1 array astore /pdfStroke exch def setgray",
236 " /pdfLastStroke true def /pdfLastFill false def } def",
237 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
238 " /pdfLastFill true def /pdfLastStroke false def } def",
239 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
240 " /pdfLastStroke true def /pdfLastFill false def } def",
241 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
242 " /pdfLastFill true def /pdfLastStroke false def } def",
243 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
244 " /pdfLastStroke true def /pdfLastFill false def } def",
245 "/ck { 6 copy 6 array astore /pdfFill exch def",
246 " findcmykcustomcolor exch setcustomcolor",
247 " /pdfLastFill true def /pdfLastStroke false def } def",
248 "/CK { 6 copy 6 array astore /pdfStroke exch def",
249 " findcmykcustomcolor exch setcustomcolor",
250 " /pdfLastStroke true def /pdfLastFill false def } def",
251 "% path segment operators",
254 "/c { curveto } def",
255 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
256 " neg 0 rlineto closepath } def",
257 "/h { closepath } def",
258 "% path painting operators",
259 "/S { sCol stroke } def",
260 "/Sf { fCol stroke } def",
261 "/f { fCol fill } def",
262 "/f* { fCol eofill } def",
263 "% clipping operators",
264 "/W { clip newpath } def",
265 "/W* { eoclip newpath } def",
266 "% text state operators",
267 "/Tc { /pdfCharSpacing exch def } def",
268 "/Tf { dup /pdfFontSize exch def",
269 " dup pdfHorizScaling mul exch matrix scale",
270 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
271 " exch findfont exch makefont setfont } def",
272 "/Tr { /pdfTextRender exch def } def",
273 "/Ts { /pdfTextRise exch def } def",
274 "/Tw { /pdfWordSpacing exch def } def",
275 "/Tz { /pdfHorizScaling exch def } def",
276 "% text positioning operators",
277 "/Td { pdfTextMat transform moveto } def",
278 "/Tm { /pdfTextMat exch def } def",
279 "% text string operators",
285 " 1 string dup 0 3 index put 3 index exec",
291 " currentfont /FontType get 0 eq {",
292 " 0 2 2 index length 1 sub {",
293 " 2 copy get exch 1 add 2 index exch get",
294 " 2 copy exch 256 mul add",
295 " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
300 " 1 string dup 0 3 index put 3 index exec",
306 "/awcp {", // awidthcharpath
309 " 5 index 5 index rmoveto",
310 " 6 index eq { 7 index 7 index rmoveto } if",
315 " fCol", // because stringwidth has to draw Type 3 chars
316 " 1 index stringwidth pdfTextMat idtransform pop",
317 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
318 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
319 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
320 " pdfTextMat dtransform",
324 " fCol", // because stringwidth has to draw Type 3 chars
325 " 2 index stringwidth pdfTextMat idtransform pop",
327 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
328 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
329 " pdfTextMat dtransform",
333 " fCol", // because stringwidth has to draw Type 3 chars
334 " 2 index stringwidth pdfTextMat idtransform exch pop",
336 " 0 pdfWordSpacing pdfTextMat dtransform 32",
337 " 4 3 roll pdfCharSpacing add 0 exch",
338 " pdfTextMat dtransform",
342 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
343 " currentpoint 8 2 roll",
344 " pdfTextRender 1 and 0 eq {",
345 " 6 copy awidthshow",
347 " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
348 " 7 index 7 index moveto",
350 " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
351 " false awcp currentpoint stroke moveto",
353 " pdfTextRender 4 and 0 ne {",
356 " /pdfTextClipPath [ pdfTextClipPath aload pop",
362 " currentpoint newpath moveto",
366 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
368 "/TJm { pdfFontSize 0.001 mul mul neg 0",
369 " pdfTextMat dtransform rmoveto } def",
370 "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
371 " pdfTextMat dtransform rmoveto } def",
372 "/Tclip { pdfTextClipPath cvx exec clip newpath",
373 " /pdfTextClipPath [] def } def",
375 "% Level 1 image operators",
377 " /pdfImBuf1 4 index string def",
378 " { currentfile pdfImBuf1 readhexstring pop } image",
381 " /pdfImBuf1 4 index string def",
382 " /pdfImBuf2 4 index string def",
383 " /pdfImBuf3 4 index string def",
384 " /pdfImBuf4 4 index string def",
385 " { currentfile pdfImBuf1 readhexstring pop }",
386 " { currentfile pdfImBuf2 readhexstring pop }",
387 " { currentfile pdfImBuf3 readhexstring pop }",
388 " { currentfile pdfImBuf4 readhexstring pop }",
389 " true 4 colorimage",
392 " /pdfImBuf1 4 index 7 add 8 idiv string def",
393 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
396 " { 2 copy get exch 1 add exch } imagemask",
400 "% Level 2 image operators",
401 "/pdfImBuf 100 string def",
404 " { currentfile pdfImBuf readline",
405 " not { pop exit } if",
406 " (%-EOD-) eq { exit } if } loop",
409 " findcmykcustomcolor exch",
410 " dup /Width get /pdfImBuf1 exch string def",
411 " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
412 " /pdfImDecodeLow exch def",
413 " begin Width Height BitsPerComponent ImageMatrix DataSource end",
414 " /pdfImData exch def",
415 " { pdfImData pdfImBuf1 readstring pop",
416 " 0 1 2 index length 1 sub {",
417 " 1 index exch 2 copy get",
418 " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
421 " 6 5 roll customcolorimage",
422 " { currentfile pdfImBuf readline",
423 " not { pop exit } if",
424 " (%-EOD-) eq { exit } if } loop",
428 " { currentfile pdfImBuf readline",
429 " not { pop exit } if",
430 " (%-EOD-) eq { exit } if } loop",
437 static char *cmapProlog[] = {
438 "/CIDInit /ProcSet findresource begin",
442 " /CMapName /Identity-H def",
443 " /CIDSystemInfo 3 dict dup begin",
444 " /Registry (Adobe) def",
445 " /Ordering (Identity) def",
446 " /Supplement 0 def",
448 " 1 begincodespacerange",
450 " endcodespacerange",
456 " currentdict CMapName exch /CMap defineresource pop",
461 " /CMapName /Identity-V def",
462 " /CIDSystemInfo 3 dict dup begin",
463 " /Registry (Adobe) def",
464 " /Ordering (Identity) def",
465 " /Supplement 0 def",
468 " 1 begincodespacerange",
470 " endcodespacerange",
476 " currentdict CMapName exch /CMap defineresource pop",
482 //------------------------------------------------------------------------
484 //------------------------------------------------------------------------
487 char *psName; // PostScript name
488 double mWidth; // width of 'm' character
491 static char *psFonts[] = {
495 "Courier-BoldOblique",
499 "Helvetica-BoldOblique",
509 static PSSubstFont psSubstFonts[] = {
510 {"Helvetica", 0.833},
511 {"Helvetica-Oblique", 0.833},
512 {"Helvetica-Bold", 0.889},
513 {"Helvetica-BoldOblique", 0.889},
514 {"Times-Roman", 0.788},
515 {"Times-Italic", 0.722},
516 {"Times-Bold", 0.833},
517 {"Times-BoldItalic", 0.778},
519 {"Courier-Oblique", 0.600},
520 {"Courier-Bold", 0.600},
521 {"Courier-BoldOblique", 0.600}
524 // Encoding info for substitute 16-bit font
530 //------------------------------------------------------------------------
532 //------------------------------------------------------------------------
534 #define psProcessCyan 1
535 #define psProcessMagenta 2
536 #define psProcessYellow 4
537 #define psProcessBlack 8
538 #define psProcessCMYK 15
540 //------------------------------------------------------------------------
542 //------------------------------------------------------------------------
544 class PSOutCustomColor {
547 PSOutCustomColor(double cA, double mA,
548 double yA, double kA, GString *nameA);
553 PSOutCustomColor *next;
556 PSOutCustomColor::PSOutCustomColor(double cA, double mA,
557 double yA, double kA, GString *nameA) {
566 PSOutCustomColor::~PSOutCustomColor() {
570 //------------------------------------------------------------------------
572 //------------------------------------------------------------------------
574 class DeviceNRecoder: public FilterStream {
577 DeviceNRecoder(Stream *strA, int widthA, int heightA,
578 GfxImageColorMap *colorMapA);
579 virtual ~DeviceNRecoder();
580 virtual StreamKind getKind() { return strWeird; }
581 virtual void reset();
582 virtual int getChar()
583 { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
584 virtual int lookChar()
585 { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
586 virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
587 virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
588 virtual GBool isEncoder() { return gTrue; }
595 GfxImageColorMap *colorMap;
598 int buf[gfxColorMaxComps];
604 DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
605 GfxImageColorMap *colorMapA):
609 colorMap = colorMapA;
612 bufIdx = gfxColorMaxComps;
613 bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
614 getAlt()->getNComps();
615 func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
616 getTintTransformFunc();
619 DeviceNRecoder::~DeviceNRecoder() {
625 void DeviceNRecoder::reset() {
626 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
627 colorMap->getBits());
631 GBool DeviceNRecoder::fillBuf() {
632 Guchar pixBuf[gfxColorMaxComps];
634 double y[gfxColorMaxComps];
637 if (pixelIdx >= width * height) {
640 imgStr->getPixel(pixBuf);
641 colorMap->getColor(pixBuf, &color);
642 func->transform(color.c, y);
643 for (i = 0; i < bufSize; ++i) {
644 buf[i] = (int)(y[i] * 255 + 0.5);
651 //------------------------------------------------------------------------
653 //------------------------------------------------------------------------
656 typedef void (*SignalFunc)(int);
659 static void outputToFile(void *stream, char *data, int len) {
660 fwrite(data, 1, len, (FILE *)stream);
663 PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
664 int firstPage, int lastPage, PSOutMode modeA,
665 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
668 PSFileType fileTypeA;
671 underlayCbkData = NULL;
673 overlayCbkData = NULL;
677 fontFileNames = NULL;
682 haveTextClip = gFalse;
686 if (!strcmp(fileName, "-")) {
687 fileTypeA = psStdout;
689 } else if (fileName[0] == '|') {
693 signal(SIGPIPE, (SignalFunc)SIG_IGN);
695 if (!(f = popen(fileName + 1, "w"))) {
696 error(-1, "Couldn't run print command '%s'", fileName);
701 error(-1, "Print commands are not supported ('%s')", fileName);
707 if (!(f = fopen(fileName, "w"))) {
708 error(-1, "Couldn't open PostScript file '%s'", fileName);
714 init(outputToFile, f, fileTypeA,
715 xrefA, catalog, firstPage, lastPage, modeA,
716 imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
719 PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
720 XRef *xrefA, Catalog *catalog,
721 int firstPage, int lastPage, PSOutMode modeA,
722 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
725 underlayCbkData = NULL;
727 overlayCbkData = NULL;
731 fontFileNames = NULL;
736 haveTextClip = gFalse;
739 init(outputFuncA, outputStreamA, psGeneric,
740 xrefA, catalog, firstPage, lastPage, modeA,
741 imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
744 void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
745 PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
746 int firstPage, int lastPage, PSOutMode modeA,
747 int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
754 outputFunc = outputFuncA;
755 outputStream = outputStreamA;
756 fileType = fileTypeA;
758 level = globalParams->getPSLevel();
760 paperWidth = globalParams->getPSPaperWidth();
761 paperHeight = globalParams->getPSPaperHeight();
766 if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
767 globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY);
769 if (paperWidth < 0 || paperHeight < 0) {
770 // this check is needed in case the document has zero pages
771 if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
772 page = catalog->getPage(firstPage);
773 paperWidth = (int)(page->getWidth() + 0.5);
774 paperHeight = (int)(page->getHeight() + 0.5);
781 imgURY = paperHeight;
783 manualCtrl = manualCtrlA;
784 if (mode == psModeForm) {
785 lastPage = firstPage;
788 inType3Char = gFalse;
791 // initialize OPI nesting levels
797 xScale0 = yScale0 = 1;
799 clipLLX0 = clipLLY0 = 0;
800 clipURX0 = clipURY0 = -1;
802 // initialize fontIDs, fontFileIDs, and fontFileNames lists
805 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
808 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
809 fontFileNameSize = 64;
811 fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
816 xobjStack = new GList();
819 // initialize embedded font resource comment list
820 embFontList = new GString();
823 // this check is needed in case the document has zero pages
824 if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
825 writeHeader(firstPage, lastPage,
826 catalog->getPage(firstPage)->getBox(),
827 catalog->getPage(firstPage)->getCropBox());
829 box = new PDFRectangle(0, 0, 1, 1);
830 writeHeader(firstPage, lastPage, box, box);
833 if (mode != psModeForm) {
834 writePS("%%BeginProlog\n");
837 if (mode != psModeForm) {
838 writePS("%%EndProlog\n");
839 writePS("%%BeginSetup\n");
841 writeDocSetup(catalog, firstPage, lastPage);
842 if (mode != psModeForm) {
843 writePS("%%EndSetup\n");
847 // initialize sequential page number
851 PSOutputDev::~PSOutputDev() {
852 PSOutCustomColor *cc;
857 writePS("%%Trailer\n");
859 if (mode != psModeForm) {
863 if (fileType == psFile) {
865 ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
867 fclose((FILE *)outputStream);
870 else if (fileType == psPipe) {
871 pclose((FILE *)outputStream);
873 signal(SIGPIPE, (SignalFunc)SIG_DFL);
888 for (i = 0; i < fontFileNameLen; ++i) {
889 delete fontFileNames[i];
891 gfree(fontFileNames);
894 for (i = 0; i < font16EncLen; ++i) {
895 delete font16Enc[i].enc;
902 while (customColors) {
904 customColors = cc->next;
909 void PSOutputDev::writeHeader(int firstPage, int lastPage,
910 PDFRectangle *mediaBox, PDFRectangle *cropBox) {
913 writePS("%!PS-Adobe-3.0\n");
914 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
915 writePSFmt("%%%%LanguageLevel: %d\n",
916 (level == psLevel1 || level == psLevel1Sep) ? 1 :
917 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
918 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
919 writePS("%%DocumentProcessColors: (atend)\n");
920 writePS("%%DocumentCustomColors: (atend)\n");
922 writePS("%%DocumentSuppliedResources: (atend)\n");
923 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
924 paperWidth, paperHeight);
925 writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth, paperHeight);
926 writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1);
927 writePS("%%EndComments\n");
928 writePS("%%BeginDefaults\n");
929 writePS("%%PageMedia: plain\n");
930 writePS("%%EndDefaults\n");
933 writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
934 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
935 writePSFmt("%%%%LanguageLevel: %d\n",
936 (level == psLevel1 || level == psLevel1Sep) ? 1 :
937 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
938 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
939 writePS("%%DocumentProcessColors: (atend)\n");
940 writePS("%%DocumentCustomColors: (atend)\n");
942 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
943 (int)floor(cropBox->x1), (int)floor(cropBox->y1),
944 (int)ceil(cropBox->x2), (int)ceil(cropBox->y2));
945 if (floor(cropBox->x1) != ceil(cropBox->x1) ||
946 floor(cropBox->y1) != ceil(cropBox->y1) ||
947 floor(cropBox->x2) != ceil(cropBox->x2) ||
948 floor(cropBox->y2) != ceil(cropBox->y2)) {
949 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n",
950 cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
952 writePS("%%DocumentSuppliedResources: (atend)\n");
953 writePS("%%EndComments\n");
956 writePS("%!PS-Adobe-3.0 Resource-Form\n");
957 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
958 writePSFmt("%%%%LanguageLevel: %d\n",
959 (level == psLevel1 || level == psLevel1Sep) ? 1 :
960 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
961 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
962 writePS("%%DocumentProcessColors: (atend)\n");
963 writePS("%%DocumentCustomColors: (atend)\n");
965 writePS("%%DocumentSuppliedResources: (atend)\n");
966 writePS("%%EndComments\n");
967 writePS("32 dict dup begin\n");
968 writePSFmt("/BBox [%d %d %d %d] def\n",
969 (int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
970 (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
971 writePS("/FormType 1 def\n");
972 writePS("/Matrix [1 0 0 1 0 0] def\n");
977 void PSOutputDev::writeXpdfProcset() {
981 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
983 for (p = prolog; *p; ++p) {
984 if ((*p)[0] == '~' && (*p)[1] == '1') {
986 } else if ((*p)[0] == '~' && (*p)[1] == '2') {
988 } else if ((*p)[0] == '~' && (*p)[1] == 'a') {
990 } else if (prologLevel == 'a' ||
991 (prologLevel == '1' && level < psLevel2) ||
992 (prologLevel == '2' && level >= psLevel2)) {
993 writePSFmt("%s\n", *p);
996 writePS("%%EndResource\n");
998 if (level >= psLevel3) {
999 for (p = cmapProlog; *p; ++p) {
1000 writePSFmt("%s\n", *p);
1005 void PSOutputDev::writeDocSetup(Catalog *catalog,
1006 int firstPage, int lastPage) {
1013 if (mode == psModeForm) {
1014 // swap the form and xpdf dicts
1015 writePS("xpdf end begin dup begin\n");
1017 writePS("xpdf begin\n");
1019 for (pg = firstPage; pg <= lastPage; ++pg) {
1020 page = catalog->getPage(pg);
1021 if ((resDict = page->getResourceDict())) {
1022 setupResources(resDict);
1024 annots = new Annots(xref, page->getAnnots(&obj1));
1026 for (i = 0; i < annots->getNumAnnots(); ++i) {
1027 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
1028 obj1.streamGetDict()->lookup("Resources", &obj2);
1029 if (obj2.isDict()) {
1030 setupResources(obj2.getDict());
1038 if (mode != psModeForm) {
1039 if (mode != psModeEPS && !manualCtrl) {
1040 writePSFmt("%d %d %s pdfSetup\n",
1041 paperWidth, paperHeight,
1042 globalParams->getPSDuplex() ? "true" : "false");
1045 if (globalParams->getPSOPI()) {
1046 writePS("/opiMatrix matrix currentmatrix def\n");
1052 void PSOutputDev::writePageTrailer() {
1053 if (mode != psModeForm) {
1054 writePS("pdfEndPage\n");
1058 void PSOutputDev::writeTrailer() {
1059 PSOutCustomColor *cc;
1061 if (mode == psModeForm) {
1062 writePS("/Foo exch /Form defineresource pop\n");
1065 writePS("%%DocumentSuppliedResources:\n");
1066 writePS(embFontList->getCString());
1067 if (level == psLevel1Sep || level == psLevel2Sep ||
1068 level == psLevel3Sep) {
1069 writePS("%%DocumentProcessColors:");
1070 if (processColors & psProcessCyan) {
1073 if (processColors & psProcessMagenta) {
1074 writePS(" Magenta");
1076 if (processColors & psProcessYellow) {
1079 if (processColors & psProcessBlack) {
1083 writePS("%%DocumentCustomColors:");
1084 for (cc = customColors; cc; cc = cc->next) {
1085 writePSFmt(" (%s)", cc->name->getCString());
1088 writePS("%%CMYKCustomColor:\n");
1089 for (cc = customColors; cc; cc = cc->next) {
1090 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
1091 cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
1097 void PSOutputDev::setupResources(Dict *resDict) {
1098 Object xObjDict, xObjRef, xObj, resObj;
1103 setupFonts(resDict);
1104 setupImages(resDict);
1106 resDict->lookup("XObject", &xObjDict);
1107 if (xObjDict.isDict()) {
1108 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
1110 // avoid infinite recursion on XObjects
1112 if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
1113 ref0 = xObjRef.getRef();
1114 for (j = 0; j < xobjStack->getLength(); ++j) {
1115 ref1 = *(Ref *)xobjStack->get(j);
1116 if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
1122 xobjStack->append(&ref0);
1127 // process the XObject's resource dictionary
1128 xObjDict.dictGetVal(i, &xObj);
1129 if (xObj.isStream()) {
1130 xObj.streamGetDict()->lookup("Resources", &resObj);
1131 if (resObj.isDict()) {
1132 setupResources(resObj.getDict());
1139 if (xObjRef.isRef() && !skip) {
1140 xobjStack->del(xobjStack->getLength() - 1);
1148 void PSOutputDev::setupFonts(Dict *resDict) {
1151 GfxFontDict *gfxFontDict;
1156 resDict->lookupNF("Font", &obj1);
1158 obj1.fetch(xref, &obj2);
1159 if (obj2.isDict()) {
1161 gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
1164 } else if (obj1.isDict()) {
1165 gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
1168 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
1169 if ((font = gfxFontDict->getFont(i))) {
1170 setupFont(font, resDict);
1178 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
1181 PSFontParam *fontParam;
1183 char type3Name[64], buf[16];
1193 // check if font is already set up
1194 for (i = 0; i < fontIDLen; ++i) {
1195 if (fontIDs[i].num == font->getID()->num &&
1196 fontIDs[i].gen == font->getID()->gen) {
1201 // add entry to fontIDs list
1202 if (fontIDLen >= fontIDSize) {
1204 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
1206 fontIDs[fontIDLen++] = *font->getID();
1211 // check for resident 8-bit font
1212 if (font->getName() &&
1213 (fontParam = globalParams->getPSFont(font->getName()))) {
1214 psName = new GString(fontParam->psFontName->getCString());
1216 // check for embedded Type 1 font
1217 } else if (globalParams->getPSEmbedType1() &&
1218 font->getType() == fontType1 &&
1219 font->getEmbeddedFontID(&fontFileID)) {
1220 psName = filterPSName(font->getEmbeddedFontName());
1221 setupEmbeddedType1Font(&fontFileID, psName);
1223 // check for embedded Type 1C font
1224 } else if (globalParams->getPSEmbedType1() &&
1225 font->getType() == fontType1C &&
1226 font->getEmbeddedFontID(&fontFileID)) {
1227 psName = filterPSName(font->getEmbeddedFontName());
1228 setupEmbeddedType1CFont(font, &fontFileID, psName);
1230 // check for external Type 1 font file
1231 } else if (globalParams->getPSEmbedType1() &&
1232 font->getType() == fontType1 &&
1233 font->getExtFontFile()) {
1234 // this assumes that the PS font name matches the PDF font name
1235 psName = font->getName()->copy();
1236 setupExternalType1Font(font->getExtFontFile(), psName);
1238 // check for embedded TrueType font
1239 } else if (globalParams->getPSEmbedTrueType() &&
1240 font->getType() == fontTrueType &&
1241 font->getEmbeddedFontID(&fontFileID)) {
1242 psName = filterPSName(font->getEmbeddedFontName());
1243 setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
1245 // check for external TrueType font file
1246 } else if (globalParams->getPSEmbedTrueType() &&
1247 font->getType() == fontTrueType &&
1248 font->getExtFontFile()) {
1249 psName = filterPSName(font->getName());
1250 setupExternalTrueTypeFont(font, psName);
1252 // check for embedded CID PostScript font
1253 } else if (globalParams->getPSEmbedCIDPostScript() &&
1254 font->getType() == fontCIDType0C &&
1255 font->getEmbeddedFontID(&fontFileID)) {
1256 psName = filterPSName(font->getEmbeddedFontName());
1257 setupEmbeddedCIDType0Font(font, &fontFileID, psName);
1259 // check for embedded CID TrueType font
1260 } else if (globalParams->getPSEmbedCIDTrueType() &&
1261 font->getType() == fontCIDType2 &&
1262 font->getEmbeddedFontID(&fontFileID)) {
1263 psName = filterPSName(font->getEmbeddedFontName());
1264 setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName);
1266 } else if (font->getType() == fontType3) {
1267 sprintf(type3Name, "T3_%d_%d",
1268 font->getID()->num, font->getID()->gen);
1269 psName = new GString(type3Name);
1270 setupType3Font(font, psName, parentResDict);
1272 // do 8-bit font substitution
1273 } else if (!font->isCIDFont()) {
1275 name = font->getName();
1278 for (i = 0; psFonts[i]; ++i) {
1279 if (name->cmp(psFonts[i]) == 0) {
1280 psName = new GString(psFonts[i]);
1286 if (font->isFixedWidth()) {
1288 } else if (font->isSerif()) {
1293 if (font->isBold()) {
1296 if (font->isItalic()) {
1299 psName = new GString(psSubstFonts[i].psName);
1300 for (code = 0; code < 256; ++code) {
1301 if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
1302 charName[0] == 'm' && charName[1] == '\0') {
1307 w1 = ((Gfx8BitFont *)font)->getWidth(code);
1311 w2 = psSubstFonts[i].mWidth;
1316 if (font->getType() == fontType3) {
1317 // This is a hack which makes it possible to substitute for some
1318 // Type 3 fonts. The problem is that it's impossible to know what
1319 // the base coordinate system used in the font is without actually
1320 // rendering the font.
1322 fm = font->getFontMatrix();
1324 ys *= fm[3] / fm[0];
1331 // do 16-bit font substitution
1332 } else if ((fontParam = globalParams->
1333 getPSFont16(font->getName(),
1334 ((GfxCIDFont *)font)->getCollection(),
1335 font->getWMode()))) {
1337 psName = fontParam->psFontName->copy();
1338 if (font16EncLen >= font16EncSize) {
1339 font16EncSize += 16;
1340 font16Enc = (PSFont16Enc *)grealloc(font16Enc,
1341 font16EncSize * sizeof(PSFont16Enc));
1343 font16Enc[font16EncLen].fontID = *font->getID();
1344 font16Enc[font16EncLen].enc = fontParam->encoding->copy();
1345 if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
1349 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1350 font16Enc[font16EncLen].enc->getCString());
1353 // give up - can't do anything with this font
1355 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1356 font->getName() ? font->getName()->getCString() : "(unnamed)",
1357 ((GfxCIDFont *)font)->getCollection()
1358 ? ((GfxCIDFont *)font)->getCollection()->getCString()
1363 // generate PostScript code to set up the font
1364 if (font->isCIDFont()) {
1365 if (level == psLevel3 || level == psLevel3Sep) {
1366 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
1367 font->getID()->num, font->getID()->gen, psName->getCString(),
1370 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
1371 font->getID()->num, font->getID()->gen, psName->getCString(),
1375 writePSFmt("/F%d_%d /%s %g %g\n",
1376 font->getID()->num, font->getID()->gen, psName->getCString(),
1378 for (i = 0; i < 256; i += 8) {
1379 writePSFmt((i == 0) ? "[ " : " ");
1380 for (j = 0; j < 8; ++j) {
1381 if (font->getType() == fontTrueType &&
1383 !((Gfx8BitFont *)font)->getHasEncoding()) {
1384 sprintf(buf, "c%02x", i+j);
1387 charName = ((Gfx8BitFont *)font)->getCharName(i+j);
1388 // this is a kludge for broken PDF files that encode char 32
1390 if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
1395 writePSName(charName ? charName : (char *)".notdef");
1397 writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
1399 writePS("pdfMakeFont\n");
1405 void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) {
1406 static char hexChar[17] = "0123456789abcdef";
1407 Object refObj, strObj, obj1, obj2, obj3;
1409 int length1, length2, length3;
1415 // check if font is already embedded
1416 for (i = 0; i < fontFileIDLen; ++i) {
1417 if (fontFileIDs[i].num == id->num &&
1418 fontFileIDs[i].gen == id->gen)
1422 // add entry to fontFileIDs list
1423 if (fontFileIDLen >= fontFileIDSize) {
1424 fontFileIDSize += 64;
1425 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1427 fontFileIDs[fontFileIDLen++] = *id;
1429 // get the font stream and info
1430 refObj.initRef(id->num, id->gen);
1431 refObj.fetch(xref, &strObj);
1433 if (!strObj.isStream()) {
1434 error(-1, "Embedded font file object is not a stream");
1437 if (!(dict = strObj.streamGetDict())) {
1438 error(-1, "Embedded font stream is missing its dictionary");
1441 dict->lookup("Length1", &obj1);
1442 dict->lookup("Length2", &obj2);
1443 dict->lookup("Length3", &obj3);
1444 if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
1445 error(-1, "Missing length fields in embedded font stream dictionary");
1451 length1 = obj1.getInt();
1452 length2 = obj2.getInt();
1453 length3 = obj3.getInt();
1458 // beginning comment
1459 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1460 embFontList->append("%%+ font ");
1461 embFontList->append(psName->getCString());
1462 embFontList->append("\n");
1464 // copy ASCII portion of font
1465 strObj.streamReset();
1466 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
1470 // figure out if encrypted portion is binary or ASCII
1472 for (i = 0; i < 4; ++i) {
1473 start[i] = strObj.streamGetChar();
1474 if (start[i] == EOF) {
1475 error(-1, "Unexpected end of file in embedded font stream");
1478 if (!((start[i] >= '0' && start[i] <= '9') ||
1479 (start[i] >= 'A' && start[i] <= 'F') ||
1480 (start[i] >= 'a' && start[i] <= 'f')))
1484 // convert binary data to ASCII
1486 for (i = 0; i < 4; ++i) {
1487 writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
1488 writePSChar(hexChar[start[i] & 0x0f]);
1490 // if Length2 is incorrect (too small), font data gets chopped, so
1491 // we take a few extra characters from the trailer just in case
1492 length2 += length3 >= 8 ? 8 : length3;
1493 while (i < length2) {
1494 if ((c = strObj.streamGetChar()) == EOF) {
1497 writePSChar(hexChar[(c >> 4) & 0x0f]);
1498 writePSChar(hexChar[c & 0x0f]);
1499 if (++i % 32 == 0) {
1507 // already in ASCII format -- just copy it
1509 for (i = 0; i < 4; ++i) {
1510 writePSChar(start[i]);
1512 for (i = 4; i < length2; ++i) {
1513 if ((c = strObj.streamGetChar()) == EOF) {
1520 // write padding and "cleartomark"
1521 for (i = 0; i < 8; ++i) {
1522 writePS("00000000000000000000000000000000"
1523 "00000000000000000000000000000000\n");
1525 writePS("cleartomark\n");
1528 writePS("%%EndResource\n");
1531 strObj.streamClose();
1535 //~ This doesn't handle .pfb files or binary eexec data (which only
1536 //~ happens in pfb files?).
1537 void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
1542 // check if font is already embedded
1543 for (i = 0; i < fontFileNameLen; ++i) {
1544 if (!fontFileNames[i]->cmp(fileName)) {
1549 // add entry to fontFileNames list
1550 if (fontFileNameLen >= fontFileNameSize) {
1551 fontFileNameSize += 64;
1552 fontFileNames = (GString **)grealloc(fontFileNames,
1553 fontFileNameSize * sizeof(GString *));
1555 fontFileNames[fontFileNameLen++] = fileName->copy();
1557 // beginning comment
1558 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1559 embFontList->append("%%+ font ");
1560 embFontList->append(psName->getCString());
1561 embFontList->append("\n");
1563 // copy the font file
1564 if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
1565 error(-1, "Couldn't open external font file");
1568 while ((c = fgetc(fontFile)) != EOF) {
1574 writePS("%%EndResource\n");
1577 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
1584 // check if font is already embedded
1585 for (i = 0; i < fontFileIDLen; ++i) {
1586 if (fontFileIDs[i].num == id->num &&
1587 fontFileIDs[i].gen == id->gen)
1591 // add entry to fontFileIDs list
1592 if (fontFileIDLen >= fontFileIDSize) {
1593 fontFileIDSize += 64;
1594 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1596 fontFileIDs[fontFileIDLen++] = *id;
1598 // beginning comment
1599 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1600 embFontList->append("%%+ font ");
1601 embFontList->append(psName->getCString());
1602 embFontList->append("\n");
1604 // convert it to a Type 1 font
1605 fontBuf = font->readEmbFontFile(xref, &fontLen);
1606 if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
1607 ffT1C->convertToType1(NULL, gTrue, outputFunc, outputStream);
1613 writePS("%%EndResource\n");
1616 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
1625 // check if font is already embedded
1626 for (i = 0; i < fontFileIDLen; ++i) {
1627 if (fontFileIDs[i].num == id->num &&
1628 fontFileIDs[i].gen == id->gen) {
1629 sprintf(unique, "_%d", nextTrueTypeNum++);
1630 psName->append(unique);
1635 // add entry to fontFileIDs list
1636 if (i == fontFileIDLen) {
1637 if (fontFileIDLen >= fontFileIDSize) {
1638 fontFileIDSize += 64;
1639 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1641 fontFileIDs[fontFileIDLen++] = *id;
1644 // beginning comment
1645 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1646 embFontList->append("%%+ font ");
1647 embFontList->append(psName->getCString());
1648 embFontList->append("\n");
1650 // convert it to a Type 42 font
1651 fontBuf = font->readEmbFontFile(xref, &fontLen);
1652 if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
1653 codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
1654 ffTT->convertToType42(psName->getCString(),
1655 ((Gfx8BitFont *)font)->getHasEncoding()
1656 ? ((Gfx8BitFont *)font)->getEncoding()
1658 codeToGID, outputFunc, outputStream);
1665 writePS("%%EndResource\n");
1668 void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) {
1677 // check if font is already embedded
1678 fileName = font->getExtFontFile();
1679 for (i = 0; i < fontFileNameLen; ++i) {
1680 if (!fontFileNames[i]->cmp(fileName)) {
1681 sprintf(unique, "_%d", nextTrueTypeNum++);
1682 psName->append(unique);
1687 // add entry to fontFileNames list
1688 if (i == fontFileNameLen) {
1689 if (fontFileNameLen >= fontFileNameSize) {
1690 fontFileNameSize += 64;
1692 (GString **)grealloc(fontFileNames,
1693 fontFileNameSize * sizeof(GString *));
1696 fontFileNames[fontFileNameLen++] = fileName->copy();
1698 // beginning comment
1699 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1700 embFontList->append("%%+ font ");
1701 embFontList->append(psName->getCString());
1702 embFontList->append("\n");
1704 // convert it to a Type 42 font
1705 fontBuf = font->readExtFontFile(&fontLen);
1706 if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
1707 codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
1708 ffTT->convertToType42(psName->getCString(),
1709 ((Gfx8BitFont *)font)->getHasEncoding()
1710 ? ((Gfx8BitFont *)font)->getEncoding()
1712 codeToGID, outputFunc, outputStream);
1718 writePS("%%EndResource\n");
1721 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
1728 // check if font is already embedded
1729 for (i = 0; i < fontFileIDLen; ++i) {
1730 if (fontFileIDs[i].num == id->num &&
1731 fontFileIDs[i].gen == id->gen)
1735 // add entry to fontFileIDs list
1736 if (fontFileIDLen >= fontFileIDSize) {
1737 fontFileIDSize += 64;
1738 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1740 fontFileIDs[fontFileIDLen++] = *id;
1742 // beginning comment
1743 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1744 embFontList->append("%%+ font ");
1745 embFontList->append(psName->getCString());
1746 embFontList->append("\n");
1748 // convert it to a Type 0 font
1749 fontBuf = font->readEmbFontFile(xref, &fontLen);
1750 if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
1751 if (globalParams->getPSLevel() >= psLevel3) {
1752 // Level 3: use a CID font
1753 ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
1755 // otherwise: use a non-CID composite font
1756 ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
1763 writePS("%%EndResource\n");
1766 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
1773 // check if font is already embedded
1774 for (i = 0; i < fontFileIDLen; ++i) {
1775 if (fontFileIDs[i].num == id->num &&
1776 fontFileIDs[i].gen == id->gen)
1780 // add entry to fontFileIDs list
1781 if (fontFileIDLen >= fontFileIDSize) {
1782 fontFileIDSize += 64;
1783 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
1785 fontFileIDs[fontFileIDLen++] = *id;
1787 // beginning comment
1788 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1789 embFontList->append("%%+ font ");
1790 embFontList->append(psName->getCString());
1791 embFontList->append("\n");
1793 // convert it to a Type 0 font
1794 fontBuf = font->readEmbFontFile(xref, &fontLen);
1795 if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
1796 if (globalParams->getPSLevel() >= psLevel3) {
1797 // Level 3: use a CID font
1798 ffTT->convertToCIDType2(psName->getCString(),
1799 ((GfxCIDFont *)font)->getCIDToGID(),
1800 ((GfxCIDFont *)font)->getCIDToGIDLen(),
1801 outputFunc, outputStream);
1803 // otherwise: use a non-CID composite font
1804 ffTT->convertToType0(psName->getCString(),
1805 ((GfxCIDFont *)font)->getCIDToGID(),
1806 ((GfxCIDFont *)font)->getCIDToGIDLen(),
1807 outputFunc, outputStream);
1814 writePS("%%EndResource\n");
1817 void PSOutputDev::setupType3Font(GfxFont *font, GString *psName,
1818 Dict *parentResDict) {
1828 // set up resources used by font
1829 if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
1830 inType3Char = gTrue;
1831 setupResources(resDict);
1832 inType3Char = gFalse;
1834 resDict = parentResDict;
1837 // beginning comment
1838 writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
1839 embFontList->append("%%+ font ");
1840 embFontList->append(psName->getCString());
1841 embFontList->append("\n");
1844 writePS("8 dict begin\n");
1845 writePS("/FontType 3 def\n");
1846 m = font->getFontMatrix();
1847 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
1848 m[0], m[1], m[2], m[3], m[4], m[5]);
1849 m = font->getFontBBox();
1850 writePSFmt("/FontBBox [%g %g %g %g] def\n",
1851 m[0], m[1], m[2], m[3]);
1852 writePS("/Encoding 256 array def\n");
1853 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
1854 writePS("/BuildGlyph {\n");
1855 writePS(" exch /CharProcs get exch\n");
1856 writePS(" 2 copy known not { pop /.notdef } if\n");
1857 writePS(" get exec\n");
1858 writePS("} bind def\n");
1859 writePS("/BuildChar {\n");
1860 writePS(" 1 index /Encoding get exch get\n");
1861 writePS(" 1 index /BuildGlyph get exec\n");
1862 writePS("} bind def\n");
1863 if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
1864 writePSFmt("/CharProcs %d dict def\n", charProcs->getLength());
1865 writePS("CharProcs begin\n");
1870 gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL);
1871 inType3Char = gTrue;
1872 t3Cacheable = gFalse;
1873 for (i = 0; i < charProcs->getLength(); ++i) {
1875 writePSName(charProcs->getKey(i));
1877 gfx->display(charProcs->getVal(i, &charProc));
1881 sprintf(buf, "%g %g %g %g %g %g setcachedevice\n",
1882 t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
1884 sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY);
1886 (*outputFunc)(outputStream, buf, strlen(buf));
1887 (*outputFunc)(outputStream, t3String->getCString(),
1888 t3String->getLength());
1892 (*outputFunc)(outputStream, "Q\n", 2);
1895 inType3Char = gFalse;
1899 writePS("currentdict end\n");
1900 writePSFmt("/%s exch definefont pop\n", psName->getCString());
1903 writePS("%%EndResource\n");
1906 void PSOutputDev::setupImages(Dict *resDict) {
1907 Object xObjDict, xObj, xObjRef, subtypeObj;
1910 if (!(mode == psModeForm || inType3Char)) {
1914 resDict->lookup("XObject", &xObjDict);
1915 if (xObjDict.isDict()) {
1916 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
1917 xObjDict.dictGetValNF(i, &xObjRef);
1918 xObjDict.dictGetVal(i, &xObj);
1919 if (xObj.isStream()) {
1920 xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
1921 if (subtypeObj.isName("Image")) {
1922 if (xObjRef.isRef()) {
1923 setupImage(xObjRef.getRef(), xObj.getStream());
1925 error(-1, "Image in resource dict is not an indirect reference");
1937 void PSOutputDev::setupImage(Ref id, Stream *str) {
1940 int size, line, col, i;
1942 // construct an encoder stream
1943 useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
1944 globalParams->getPSASCIIHex();
1946 str = new ASCIIHexEncoder(str);
1948 str = new ASCII85Encoder(str);
1951 // compute image data size
1957 } while (c == '\n' || c == '\r');
1958 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
1965 for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
1968 } while (c == '\n' || c == '\r');
1969 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
1979 } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
1981 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
1984 // write the data into the array
1987 writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
1991 } while (c == '\n' || c == '\r');
1992 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2001 for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2004 } while (c == '\n' || c == '\r');
2005 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2012 // each line is: "dup nnnnn <~...data...~> put<eol>"
2013 // so max data length = 255 - 20 = 235
2014 // chunks are 1 or 4 bytes each, so we have to stop at 232
2015 // but make it 225 just to be safe
2017 writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2019 writePSFmt((char *)(useASCIIHex ? "dup %d <" : "dup %d <~"), line);
2022 } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
2023 writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2030 void PSOutputDev::startPage(int pageNum, GfxState *state) {
2031 int x1, y1, x2, y2, width, height;
2032 int imgWidth, imgHeight, imgWidth2, imgHeight2;
2038 writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage);
2039 writePS("%%BeginPageSetup\n");
2041 // rotate, translate, and scale page
2042 imgWidth = imgURX - imgLLX;
2043 imgHeight = imgURY - imgLLY;
2044 x1 = (int)(state->getX1() + 0.5);
2045 y1 = (int)(state->getY1() + 0.5);
2046 x2 = (int)(state->getX2() + 0.5);
2047 y2 = (int)(state->getY2() + 0.5);
2051 // portrait or landscape
2052 if (width > height && width > imgWidth) {
2054 writePSFmt("%%%%PageOrientation: %s\n",
2055 state->getCTM()[0] ? "Landscape" : "Portrait");
2056 writePS("pdfStartPage\n");
2057 writePS("90 rotate\n");
2059 imgWidth2 = imgHeight;
2060 imgHeight2 = imgWidth;
2063 writePSFmt("%%%%PageOrientation: %s\n",
2064 state->getCTM()[0] ? "Portrait" : "Landscape");
2065 writePS("pdfStartPage\n");
2066 imgWidth2 = imgWidth;
2067 imgHeight2 = imgHeight;
2070 if ((globalParams->getPSShrinkLarger() &&
2071 (width > imgWidth2 || height > imgHeight2)) ||
2072 (globalParams->getPSExpandSmaller() &&
2073 (width < imgWidth2 && height < imgHeight2))) {
2074 xScale = (double)imgWidth2 / (double)width;
2075 yScale = (double)imgHeight2 / (double)height;
2076 if (yScale < xScale) {
2082 xScale = yScale = 1;
2084 // deal with odd bounding boxes
2088 if (globalParams->getPSCenter()) {
2089 tx += (imgWidth2 - xScale * width) / 2;
2090 ty += (imgHeight2 - yScale * height) / 2;
2096 if (tx != 0 || ty != 0) {
2097 writePSFmt("%g %g translate\n", tx, ty);
2099 if (xScale != 1 || yScale != 1) {
2100 writePSFmt("%0.4f %0.4f scale\n", xScale, xScale);
2102 if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
2103 writePSFmt("%g %g %g %g re W\n",
2104 clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
2107 writePS("%%EndPageSetup\n");
2112 writePS("pdfStartPage\n");
2114 xScale = yScale = 1;
2119 writePS("/PaintProc {\n");
2120 writePS("begin xpdf begin\n");
2121 writePS("pdfStartPage\n");
2123 xScale = yScale = 1;
2129 (*underlayCbk)(this, underlayCbkData);
2133 void PSOutputDev::endPage() {
2135 (*overlayCbk)(this, overlayCbkData);
2139 if (mode == psModeForm) {
2140 writePS("pdfEndPage\n");
2141 writePS("end end\n");
2143 writePS("end end\n");
2146 writePS("showpage\n");
2147 writePS("%%PageTrailer\n");
2153 void PSOutputDev::saveState(GfxState *state) {
2158 void PSOutputDev::restoreState(GfxState *state) {
2163 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
2164 double m21, double m22, double m31, double m32) {
2165 writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
2168 void PSOutputDev::updateLineDash(GfxState *state) {
2173 state->getLineDash(&dash, &length, &start);
2175 for (i = 0; i < length; ++i)
2176 writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " ");
2177 writePSFmt("] %g d\n", start);
2180 void PSOutputDev::updateFlatness(GfxState *state) {
2181 writePSFmt("%d i\n", state->getFlatness());
2184 void PSOutputDev::updateLineJoin(GfxState *state) {
2185 writePSFmt("%d j\n", state->getLineJoin());
2188 void PSOutputDev::updateLineCap(GfxState *state) {
2189 writePSFmt("%d J\n", state->getLineCap());
2192 void PSOutputDev::updateMiterLimit(GfxState *state) {
2193 writePSFmt("%g M\n", state->getMiterLimit());
2196 void PSOutputDev::updateLineWidth(GfxState *state) {
2197 writePSFmt("%g w\n", state->getLineWidth());
2200 void PSOutputDev::updateFillColor(GfxState *state) {
2205 GfxSeparationColorSpace *sepCS;
2209 state->getFillGray(&gray);
2210 writePSFmt("%g g\n", gray);
2213 state->getFillCMYK(&cmyk);
2214 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2215 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2219 if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
2220 state->getFillCMYK(&cmyk);
2221 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2223 state->getFillRGB(&rgb);
2224 if (rgb.r == rgb.g && rgb.g == rgb.b) {
2225 writePSFmt("%g g\n", rgb.r);
2227 writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
2233 if (state->getFillColorSpace()->getMode() == csSeparation) {
2234 sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
2236 sepCS->getCMYK(&color, &cmyk);
2237 writePSFmt("%g %g %g %g %g (%s) ck\n",
2238 state->getFillColor()->c[0],
2239 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
2240 sepCS->getName()->getCString());
2241 addCustomColor(sepCS);
2243 state->getFillCMYK(&cmyk);
2244 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2245 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2249 t3Cacheable = gFalse;
2252 void PSOutputDev::updateStrokeColor(GfxState *state) {
2257 GfxSeparationColorSpace *sepCS;
2261 state->getStrokeGray(&gray);
2262 writePSFmt("%g G\n", gray);
2265 state->getStrokeCMYK(&cmyk);
2266 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2267 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2271 if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
2272 state->getStrokeCMYK(&cmyk);
2273 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2275 state->getStrokeRGB(&rgb);
2276 if (rgb.r == rgb.g && rgb.g == rgb.b) {
2277 writePSFmt("%g G\n", rgb.r);
2279 writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
2285 if (state->getStrokeColorSpace()->getMode() == csSeparation) {
2286 sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
2288 sepCS->getCMYK(&color, &cmyk);
2289 writePSFmt("%g %g %g %g %g (%s) CK\n",
2290 state->getStrokeColor()->c[0],
2291 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
2292 sepCS->getName()->getCString());
2293 addCustomColor(sepCS);
2295 state->getStrokeCMYK(&cmyk);
2296 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2297 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2301 t3Cacheable = gFalse;
2304 void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
2306 processColors |= psProcessCyan;
2309 processColors |= psProcessMagenta;
2312 processColors |= psProcessYellow;
2315 processColors |= psProcessBlack;
2319 void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
2320 PSOutCustomColor *cc;
2324 for (cc = customColors; cc; cc = cc->next) {
2325 if (!cc->name->cmp(sepCS->getName())) {
2330 sepCS->getCMYK(&color, &cmyk);
2331 cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
2332 sepCS->getName()->copy());
2333 cc->next = customColors;
2337 void PSOutputDev::updateFont(GfxState *state) {
2338 if (state->getFont()) {
2339 writePSFmt("/F%d_%d %g Tf\n",
2340 state->getFont()->getID()->num, state->getFont()->getID()->gen,
2341 state->getFontSize());
2345 void PSOutputDev::updateTextMat(GfxState *state) {
2348 mat = state->getTextMat();
2349 writePSFmt("[%g %g %g %g %g %g] Tm\n",
2350 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
2353 void PSOutputDev::updateCharSpace(GfxState *state) {
2354 writePSFmt("%g Tc\n", state->getCharSpace());
2357 void PSOutputDev::updateRender(GfxState *state) {
2360 rm = state->getRender();
2361 writePSFmt("%d Tr\n", rm);
2363 if (rm != 0 && rm != 3) {
2364 t3Cacheable = gFalse;
2368 void PSOutputDev::updateRise(GfxState *state) {
2369 writePSFmt("%g Ts\n", state->getRise());
2372 void PSOutputDev::updateWordSpace(GfxState *state) {
2373 writePSFmt("%g Tw\n", state->getWordSpace());
2376 void PSOutputDev::updateHorizScaling(GfxState *state) {
2379 if ((h = state->getHorizScaling()) < 0.01) {
2382 writePSFmt("%g Tz\n", h);
2385 void PSOutputDev::updateTextPos(GfxState *state) {
2386 writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY());
2389 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
2390 if (state->getFont()->getWMode()) {
2391 writePSFmt("%g TJmV\n", shift);
2393 writePSFmt("%g TJm\n", shift);
2397 void PSOutputDev::stroke(GfxState *state) {
2398 doPath(state->getPath());
2400 // if we're construct a cacheable Type 3 glyph, we need to do
2401 // everything in the fill color
2408 void PSOutputDev::fill(GfxState *state) {
2409 doPath(state->getPath());
2413 void PSOutputDev::eoFill(GfxState *state) {
2414 doPath(state->getPath());
2418 void PSOutputDev::clip(GfxState *state) {
2419 doPath(state->getPath());
2423 void PSOutputDev::eoClip(GfxState *state) {
2424 doPath(state->getPath());
2428 void PSOutputDev::doPath(GfxPath *path) {
2429 GfxSubpath *subpath;
2430 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
2433 n = path->getNumSubpaths();
2435 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
2436 subpath = path->getSubpath(0);
2437 x0 = subpath->getX(0);
2438 y0 = subpath->getY(0);
2439 x4 = subpath->getX(4);
2440 y4 = subpath->getY(4);
2441 if (x4 == x0 && y4 == y0) {
2442 x1 = subpath->getX(1);
2443 y1 = subpath->getY(1);
2444 x2 = subpath->getX(2);
2445 y2 = subpath->getY(2);
2446 x3 = subpath->getX(3);
2447 y3 = subpath->getY(3);
2448 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
2449 writePSFmt("%g %g %g %g re\n",
2450 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
2451 fabs(x2 - x0), fabs(y1 - y0));
2453 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
2454 writePSFmt("%g %g %g %g re\n",
2455 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
2456 fabs(x1 - x0), fabs(y2 - y0));
2462 for (i = 0; i < n; ++i) {
2463 subpath = path->getSubpath(i);
2464 m = subpath->getNumPoints();
2465 writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0));
2468 if (subpath->getCurve(j)) {
2469 writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
2470 subpath->getX(j+1), subpath->getY(j+1),
2471 subpath->getX(j+2), subpath->getY(j+2));
2474 writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j));
2478 if (subpath->isClosed()) {
2484 void PSOutputDev::drawString(GfxState *state, GString *s) {
2488 double dx, dy, dx2, dy2, originX, originY;
2494 int len, nChars, uLen, n, m, i, j;
2496 // check for invisible text -- this is used by Acrobat Capture
2497 if (state->getRender() == 3) {
2501 // ignore empty strings
2502 if (s->getLength() == 0) {
2507 if (!(font = state->getFont())) {
2510 wMode = font->getWMode();
2512 // check for a subtitute 16-bit font
2514 if (font->isCIDFont()) {
2515 for (i = 0; i < font16EncLen; ++i) {
2516 if (font->getID()->num == font16Enc[i].fontID.num &&
2517 font->getID()->gen == font16Enc[i].fontID.gen) {
2518 uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
2524 // compute width of chars in string, ignoring char spacing and word
2525 // spacing -- the Tj operator will adjust for the metrics of the
2526 // font that's actually used
2529 p = s->getCString();
2530 len = s->getLength();
2531 if (font->isCIDFont()) {
2537 n = font->getNextChar(p, len, &code,
2538 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2539 &dx2, &dy2, &originX, &originY);
2540 if (font->isCIDFont()) {
2542 for (i = 0; i < uLen; ++i) {
2543 m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
2544 for (j = 0; j < m; ++j) {
2548 //~ this really needs to get the number of chars in the target
2549 //~ encoding - which may be more than the number of Unicode
2553 s2->append((char)((code >> 8) & 0xff));
2554 s2->append((char)(code & 0xff));
2563 dx *= state->getFontSize() * state->getHorizScaling();
2564 dy *= state->getFontSize();
2569 if (s2->getLength() > 0) {
2571 if (font->isCIDFont()) {
2573 writePSFmt(" %d %g Tj16V\n", nChars, dy);
2575 writePSFmt(" %d %g Tj16\n", nChars, dx);
2578 writePSFmt(" %g Tj\n", dx);
2581 if (font->isCIDFont()) {
2585 if (state->getRender() & 4) {
2586 haveTextClip = gTrue;
2590 void PSOutputDev::endTextObject(GfxState *state) {
2593 haveTextClip = gFalse;
2597 void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2598 int width, int height, GBool invert,
2602 len = height * ((width + 7) / 8);
2603 if (level == psLevel1 || level == psLevel1Sep) {
2604 doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
2606 doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
2610 void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2611 int width, int height, GfxImageColorMap *colorMap,
2612 int *maskColors, GBool inlineImg) {
2615 len = height * ((width * colorMap->getNumPixelComps() *
2616 colorMap->getBits() + 7) / 8);
2619 doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len);
2622 //~ handle indexed, separation, ... color spaces
2623 doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
2629 doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
2632 t3Cacheable = gFalse;
2635 void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
2636 GBool invert, GBool inlineImg,
2637 Stream *str, int width, int height, int len) {
2638 ImageStream *imgStr;
2639 Guchar pixBuf[gfxColorMaxComps];
2641 int col, x, y, c, i;
2643 if (inType3Char && !colorMap) {
2646 str = new FixedLengthEncoder(str, len);
2647 str = new ASCIIHexEncoder(str);
2654 } while (c == '\n' || c == '\r');
2655 if (c == '>' || c == EOF) {
2660 // each line is: "<...data...><eol>"
2661 // so max data length = 255 - 4 = 251
2662 // but make it 240 just to be safe
2663 // chunks are 2 bytes each, so we need to stop on an even col number
2668 } while (c != '>' && c != EOF);
2674 // set up to use the array already created by setupImages()
2675 writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
2679 // image/imagemask command
2680 if (inType3Char && !colorMap) {
2681 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
2682 width, height, invert ? "true" : "false",
2683 width, -height, height);
2684 } else if (colorMap) {
2685 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
2687 width, -height, height);
2689 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
2690 width, height, invert ? "true" : "false",
2691 width, -height, height);
2695 if (!(inType3Char && !colorMap)) {
2699 // set up to process the data stream
2700 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
2701 colorMap->getBits());
2704 // process the data stream
2706 for (y = 0; y < height; ++y) {
2709 for (x = 0; x < width; ++x) {
2710 imgStr->getPixel(pixBuf);
2711 colorMap->getGray(pixBuf, &gray);
2712 writePSFmt("%02x", (int)(gray * 255 + 0.5));
2728 for (y = 0; y < height; ++y) {
2729 for (x = 0; x < width; x += 8) {
2730 writePSFmt("%02x", str->getChar() & 0xff);
2745 void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
2746 GBool invert, GBool inlineImg,
2747 Stream *str, int width, int height, int len) {
2748 ImageStream *imgStr;
2750 Guchar pixBuf[gfxColorMaxComps];
2754 // width, height, matrix, bits per component
2755 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
2757 width, -height, height);
2759 // allocate a line buffer
2760 lineBuf = (Guchar *)gmalloc(4 * width);
2762 // set up to process the data stream
2763 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
2764 colorMap->getBits());
2767 // process the data stream
2769 for (y = 0; y < height; ++y) {
2772 for (x = 0; x < width; ++x) {
2773 imgStr->getPixel(pixBuf);
2774 colorMap->getCMYK(pixBuf, &cmyk);
2775 lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5);
2776 lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
2777 lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
2778 lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
2779 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
2782 // write one line of each color component
2783 for (comp = 0; comp < 4; ++comp) {
2784 for (x = 0; x < width; ++x) {
2785 writePSFmt("%02x", lineBuf[4*x + comp]);
2802 void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
2803 GBool invert, GBool inlineImg,
2804 Stream *str, int width, int height, int len) {
2807 GBool useRLE, useASCII, useASCIIHex, useCompressed;
2808 GfxSeparationColorSpace *sepCS;
2816 dumpColorSpaceL2(colorMap->getColorSpace());
2817 writePS(" setcolorspace\n");
2820 useASCIIHex = globalParams->getPSASCIIHex();
2822 // set up the image data
2823 if (mode == psModeForm || inType3Char) {
2826 str = new FixedLengthEncoder(str, len);
2828 str = new ASCIIHexEncoder(str);
2830 str = new ASCII85Encoder(str);
2834 writePS((char *)(useASCIIHex ? "[<" : "[<~"));
2838 } while (c == '\n' || c == '\r');
2839 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2848 for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2851 } while (c == '\n' || c == '\r');
2852 if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2859 // each line is: "<~...data...~><eol>"
2860 // so max data length = 255 - 6 = 249
2861 // chunks are 1 or 5 bytes each, so we have to stop at 245
2862 // but make it 240 just to be safe
2864 writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
2867 } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
2868 writePS((char *)(useASCIIHex ? ">]\n" : "~>]\n"));
2873 // set up to use the array already created by setupImages()
2874 writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
2879 writePS("<<\n /ImageType 1\n");
2881 // width, height, matrix, bits per component
2882 writePSFmt(" /Width %d\n", width);
2883 writePSFmt(" /Height %d\n", height);
2884 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
2885 if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
2886 writePSFmt(" /BitsPerComponent 8\n");
2888 writePSFmt(" /BitsPerComponent %d\n",
2889 colorMap ? colorMap->getBits() : 1);
2894 writePS(" /Decode [");
2895 if (colorMap->getColorSpace()->getMode() == csSeparation) {
2896 //~ this is a kludge -- see comment in dumpColorSpaceL2
2897 n = (1 << colorMap->getBits()) - 1;
2898 writePSFmt("%g %g", colorMap->getDecodeLow(0) * n,
2899 colorMap->getDecodeHigh(0) * n);
2900 } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
2901 numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
2902 getAlt()->getNComps();
2903 for (i = 0; i < numComps; ++i) {
2907 writePSFmt("0 1", colorMap->getDecodeLow(i),
2908 colorMap->getDecodeHigh(i));
2911 numComps = colorMap->getNumPixelComps();
2912 for (i = 0; i < numComps; ++i) {
2916 writePSFmt("%g %g", colorMap->getDecodeLow(i),
2917 colorMap->getDecodeHigh(i));
2922 writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
2925 if (mode == psModeForm || inType3Char) {
2928 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
2930 // end of image dictionary
2931 writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask");
2933 // get rid of the array and index
2934 writePS("pop pop\n");
2939 writePS(" /DataSource currentfile\n");
2940 s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
2942 if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
2946 useCompressed = gFalse;
2949 useASCII = str->isBinary();
2950 useCompressed = gTrue;
2953 writePSFmt(" /ASCII%sDecode filter\n",
2954 useASCIIHex ? "Hex" : "85");
2957 writePS(" /RunLengthDecode filter\n");
2959 if (useCompressed) {
2960 writePS(s->getCString());
2966 // cut off inline image streams at appropriate length
2968 str = new FixedLengthEncoder(str, len);
2969 } else if (useCompressed) {
2970 str = str->getBaseStream();
2973 // recode DeviceN data
2974 if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
2975 str = new DeviceNRecoder(str, width, height, colorMap);
2978 // add RunLengthEncode and ASCIIHex/85 encode filters
2980 str = new RunLengthEncoder(str);
2984 str = new ASCIIHexEncoder(str);
2986 str = new ASCII85Encoder(str);
2990 // end of image dictionary
2995 // this can't happen -- OPI dictionaries are in XObjects
2996 error(-1, "Internal: OPI in inline image");
2999 // need to read the stream to count characters -- the length
3000 // is data-dependent (because of ASCII and RLE filters)
3003 while ((c = str->getChar()) != EOF) {
3008 // +6/7 for "pdfIm\n" / "pdfImM\n"
3009 // +8 for newline + trailer
3010 n += colorMap ? 14 : 15;
3011 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n);
3014 if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
3015 colorMap->getColorSpace()->getMode() == csSeparation) {
3017 sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
3018 sepCS->getCMYK(&color, &cmyk);
3019 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
3020 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
3021 sepCS->getName()->getCString());
3023 writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM");
3026 // copy the stream data
3028 while ((c = str->getChar()) != EOF) {
3033 // add newline and trailer to the end
3035 writePS("%-EOD-\n");
3038 writePS("%%EndData\n");
3043 if (useRLE || useASCII || inlineImg) {
3049 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
3050 GfxCalGrayColorSpace *calGrayCS;
3051 GfxCalRGBColorSpace *calRGBCS;
3052 GfxLabColorSpace *labCS;
3053 GfxIndexedColorSpace *indexedCS;
3054 GfxSeparationColorSpace *separationCS;
3055 GfxColorSpace *baseCS;
3057 double x[gfxColorMaxComps], y[gfxColorMaxComps];
3061 int n, numComps, numAltComps;
3065 switch (colorSpace->getMode()) {
3068 writePS("/DeviceGray");
3069 processColors |= psProcessBlack;
3073 calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
3074 writePS("[/CIEBasedA <<\n");
3075 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
3076 writePSFmt(" /MatrixA [%g %g %g]\n",
3077 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
3078 calGrayCS->getWhiteZ());
3079 writePSFmt(" /WhitePoint [%g %g %g]\n",
3080 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
3081 calGrayCS->getWhiteZ());
3082 writePSFmt(" /BlackPoint [%g %g %g]\n",
3083 calGrayCS->getBlackX(), calGrayCS->getBlackY(),
3084 calGrayCS->getBlackZ());
3086 processColors |= psProcessBlack;
3090 writePS("/DeviceRGB");
3091 processColors |= psProcessCMYK;
3095 calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
3096 writePS("[/CIEBasedABC <<\n");
3097 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
3098 calRGBCS->getGammaR(), calRGBCS->getGammaG(),
3099 calRGBCS->getGammaB());
3100 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
3101 calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
3102 calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
3103 calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
3104 calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
3105 calRGBCS->getMatrix()[8]);
3106 writePSFmt(" /WhitePoint [%g %g %g]\n",
3107 calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
3108 calRGBCS->getWhiteZ());
3109 writePSFmt(" /BlackPoint [%g %g %g]\n",
3110 calRGBCS->getBlackX(), calRGBCS->getBlackY(),
3111 calRGBCS->getBlackZ());
3113 processColors |= psProcessCMYK;
3117 writePS("/DeviceCMYK");
3118 processColors |= psProcessCMYK;
3122 labCS = (GfxLabColorSpace *)colorSpace;
3123 writePS("[/CIEBasedABC <<\n");
3124 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
3125 labCS->getAMin(), labCS->getAMax(),
3126 labCS->getBMin(), labCS->getBMax());
3127 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
3128 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
3129 writePS(" /DecodeLMN\n");
3130 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
3131 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
3132 labCS->getWhiteX());
3133 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
3134 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
3135 labCS->getWhiteY());
3136 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
3137 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
3138 labCS->getWhiteZ());
3139 writePSFmt(" /WhitePoint [%g %g %g]\n",
3140 labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
3141 writePSFmt(" /BlackPoint [%g %g %g]\n",
3142 labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
3144 processColors |= psProcessCMYK;
3148 // there is no transform function to the alternate color space, so
3149 // we can use it directly
3150 dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
3154 indexedCS = (GfxIndexedColorSpace *)colorSpace;
3155 baseCS = indexedCS->getBase();
3156 writePS("[/Indexed ");
3157 dumpColorSpaceL2(baseCS);
3158 n = indexedCS->getIndexHigh();
3159 numComps = baseCS->getNComps();
3160 lookup = indexedCS->getLookup();
3161 writePSFmt(" %d <\n", n);
3162 if (baseCS->getMode() == csDeviceN) {
3163 func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
3164 numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
3166 for (i = 0; i <= n; i += 8) {
3168 for (j = i; j < i+8 && j <= n; ++j) {
3169 for (k = 0; k < numComps; ++k) {
3170 x[k] = *p++ / 255.0;
3172 func->transform(x, y);
3173 for (k = 0; k < numAltComps; ++k) {
3174 byte = (int)(y[k] * 255 + 0.5);
3177 } else if (byte > 255) {
3180 writePSFmt("%02x", byte);
3183 indexedCS->getCMYK(&color, &cmyk);
3184 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
3189 for (i = 0; i <= n; i += 8) {
3191 for (j = i; j < i+8 && j <= n; ++j) {
3192 for (k = 0; k < numComps; ++k) {
3193 writePSFmt("%02x", lookup[j * numComps + k]);
3196 indexedCS->getCMYK(&color, &cmyk);
3197 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
3206 //~ this is a kludge -- the correct thing would to ouput a
3207 //~ separation color space, with the specified alternate color
3208 //~ space and tint transform
3209 separationCS = (GfxSeparationColorSpace *)colorSpace;
3210 writePS("[/Indexed ");
3211 dumpColorSpaceL2(separationCS->getAlt());
3212 writePS(" 255 <\n");
3213 numComps = separationCS->getAlt()->getNComps();
3214 for (i = 0; i <= 255; i += 8) {
3216 for (j = i; j < i+8 && j <= 255; ++j) {
3217 x[0] = (double)j / 255.0;
3218 separationCS->getFunc()->transform(x, y);
3219 for (k = 0; k < numComps; ++k) {
3220 writePSFmt("%02x", (int)(255 * y[k] + 0.5));
3226 #if 0 //~ this shouldn't be here since the PS file doesn't actually refer
3227 //~ to this colorant (it's converted to CMYK instead)
3228 addCustomColor(separationCS);
3233 // DeviceN color spaces are a Level 3 PostScript feature.
3234 dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt());
3245 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
3248 if (globalParams->getPSOPI()) {
3249 opiDict->lookup("2.0", &dict);
3250 if (dict.isDict()) {
3251 opiBegin20(state, dict.getDict());
3255 opiDict->lookup("1.3", &dict);
3256 if (dict.isDict()) {
3257 opiBegin13(state, dict.getDict());
3264 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
3265 Object obj1, obj2, obj3, obj4;
3266 double width, height, left, right, top, bottom;
3270 writePS("%%BeginOPI: 2.0\n");
3271 writePS("%%Distilled\n");
3273 dict->lookup("F", &obj1);
3274 if (getFileSpec(&obj1, &obj2)) {
3275 writePSFmt("%%%%ImageFileName: %s\n",
3276 obj2.getString()->getCString());
3281 dict->lookup("MainImage", &obj1);
3282 if (obj1.isString()) {
3283 writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString());
3287 //~ ignoring 'Tags' entry
3288 //~ need to use writePSString() and deal with >255-char lines
3290 dict->lookup("Size", &obj1);
3291 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3292 obj1.arrayGet(0, &obj2);
3293 width = obj2.getNum();
3295 obj1.arrayGet(1, &obj2);
3296 height = obj2.getNum();
3298 writePSFmt("%%%%ImageDimensions: %g %g\n", width, height);
3302 dict->lookup("CropRect", &obj1);
3303 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
3304 obj1.arrayGet(0, &obj2);
3305 left = obj2.getNum();
3307 obj1.arrayGet(1, &obj2);
3308 top = obj2.getNum();
3310 obj1.arrayGet(2, &obj2);
3311 right = obj2.getNum();
3313 obj1.arrayGet(3, &obj2);
3314 bottom = obj2.getNum();
3316 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
3320 dict->lookup("Overprint", &obj1);
3321 if (obj1.isBool()) {
3322 writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
3326 dict->lookup("Inks", &obj1);
3327 if (obj1.isName()) {
3328 writePSFmt("%%%%ImageInks: %s\n", obj1.getName());
3329 } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
3330 obj1.arrayGet(0, &obj2);
3331 if (obj2.isName()) {
3332 writePSFmt("%%%%ImageInks: %s %d",
3333 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
3334 for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
3335 obj1.arrayGet(i, &obj3);
3336 obj1.arrayGet(i+1, &obj4);
3337 if (obj3.isString() && obj4.isNum()) {
3339 writePSString(obj3.getString());
3340 writePSFmt(" %g", obj4.getNum());
3353 writePS("%%BeginIncludedImage\n");
3355 dict->lookup("IncludedImageDimensions", &obj1);
3356 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3357 obj1.arrayGet(0, &obj2);
3360 obj1.arrayGet(1, &obj2);
3363 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h);
3367 dict->lookup("IncludedImageQuality", &obj1);
3369 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum());
3376 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
3378 int left, right, top, bottom, samples, bits, width, height;
3380 double llx, lly, ulx, uly, urx, ury, lrx, lry;
3381 double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
3386 writePS("/opiMatrix2 matrix currentmatrix def\n");
3387 writePS("opiMatrix setmatrix\n");
3389 dict->lookup("F", &obj1);
3390 if (getFileSpec(&obj1, &obj2)) {
3391 writePSFmt("%%ALDImageFileName: %s\n",
3392 obj2.getString()->getCString());
3397 dict->lookup("CropRect", &obj1);
3398 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
3399 obj1.arrayGet(0, &obj2);
3400 left = obj2.getInt();
3402 obj1.arrayGet(1, &obj2);
3403 top = obj2.getInt();
3405 obj1.arrayGet(2, &obj2);
3406 right = obj2.getInt();
3408 obj1.arrayGet(3, &obj2);
3409 bottom = obj2.getInt();
3411 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
3415 dict->lookup("Color", &obj1);
3416 if (obj1.isArray() && obj1.arrayGetLength() == 5) {
3417 obj1.arrayGet(0, &obj2);
3420 obj1.arrayGet(1, &obj2);
3423 obj1.arrayGet(2, &obj2);
3426 obj1.arrayGet(3, &obj2);
3429 obj1.arrayGet(4, &obj2);
3430 if (obj2.isString()) {
3431 writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
3432 writePSString(obj2.getString());
3439 dict->lookup("ColorType", &obj1);
3440 if (obj1.isName()) {
3441 writePSFmt("%%ALDImageColorType: %s\n", obj1.getName());
3445 //~ ignores 'Comments' entry
3446 //~ need to handle multiple lines
3448 dict->lookup("CropFixed", &obj1);
3449 if (obj1.isArray()) {
3450 obj1.arrayGet(0, &obj2);
3451 ulx = obj2.getNum();
3453 obj1.arrayGet(1, &obj2);
3454 uly = obj2.getNum();
3456 obj1.arrayGet(2, &obj2);
3457 lrx = obj2.getNum();
3459 obj1.arrayGet(3, &obj2);
3460 lry = obj2.getNum();
3462 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
3466 dict->lookup("GrayMap", &obj1);
3467 if (obj1.isArray()) {
3468 writePS("%ALDImageGrayMap:");
3469 for (i = 0; i < obj1.arrayGetLength(); i += 16) {
3473 for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
3474 obj1.arrayGet(i+j, &obj2);
3475 writePSFmt(" %d", obj2.getInt());
3483 dict->lookup("ID", &obj1);
3484 if (obj1.isString()) {
3485 writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString());
3489 dict->lookup("ImageType", &obj1);
3490 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3491 obj1.arrayGet(0, &obj2);
3492 samples = obj2.getInt();
3494 obj1.arrayGet(1, &obj2);
3495 bits = obj2.getInt();
3497 writePSFmt("%%ALDImageType: %d %d\n", samples, bits);
3501 dict->lookup("Overprint", &obj1);
3502 if (obj1.isBool()) {
3503 writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
3507 dict->lookup("Position", &obj1);
3508 if (obj1.isArray() && obj1.arrayGetLength() == 8) {
3509 obj1.arrayGet(0, &obj2);
3510 llx = obj2.getNum();
3512 obj1.arrayGet(1, &obj2);
3513 lly = obj2.getNum();
3515 obj1.arrayGet(2, &obj2);
3516 ulx = obj2.getNum();
3518 obj1.arrayGet(3, &obj2);
3519 uly = obj2.getNum();
3521 obj1.arrayGet(4, &obj2);
3522 urx = obj2.getNum();
3524 obj1.arrayGet(5, &obj2);
3525 ury = obj2.getNum();
3527 obj1.arrayGet(6, &obj2);
3528 lrx = obj2.getNum();
3530 obj1.arrayGet(7, &obj2);
3531 lry = obj2.getNum();
3533 opiTransform(state, llx, lly, &tllx, &tlly);
3534 opiTransform(state, ulx, uly, &tulx, &tuly);
3535 opiTransform(state, urx, ury, &turx, &tury);
3536 opiTransform(state, lrx, lry, &tlrx, &tlry);
3537 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
3538 tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
3543 dict->lookup("Resolution", &obj1);
3544 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3545 obj1.arrayGet(0, &obj2);
3546 horiz = obj2.getNum();
3548 obj1.arrayGet(1, &obj2);
3549 vert = obj2.getNum();
3551 writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert);
3556 dict->lookup("Size", &obj1);
3557 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
3558 obj1.arrayGet(0, &obj2);
3559 width = obj2.getInt();
3561 obj1.arrayGet(1, &obj2);
3562 height = obj2.getInt();
3564 writePSFmt("%%ALDImageDimensions: %d %d\n", width, height);
3568 //~ ignoring 'Tags' entry
3569 //~ need to use writePSString() and deal with >255-char lines
3571 dict->lookup("Tint", &obj1);
3573 writePSFmt("%%ALDImageTint: %g\n", obj1.getNum());
3577 dict->lookup("Transparency", &obj1);
3578 if (obj1.isBool()) {
3579 writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
3583 writePS("%%BeginObject: image\n");
3584 writePS("opiMatrix2 setmatrix\n");
3588 // Convert PDF user space coordinates to PostScript default user space
3589 // coordinates. This has to account for both the PDF CTM and the
3590 // PSOutputDev page-fitting transform.
3591 void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
3592 double *x1, double *y1) {
3595 state->transform(x0, y0, x1, y1);
3602 } else if (rotate == 180) {
3605 } else if (rotate == 270) {
3614 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
3617 if (globalParams->getPSOPI()) {
3618 opiDict->lookup("2.0", &dict);
3619 if (dict.isDict()) {
3620 writePS("%%EndIncludedImage\n");
3621 writePS("%%EndOPI\n");
3622 writePS("grestore\n");
3627 opiDict->lookup("1.3", &dict);
3628 if (dict.isDict()) {
3629 writePS("%%EndObject\n");
3630 writePS("restore\n");
3638 GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
3639 if (fileSpec->isString()) {
3640 fileSpec->copy(fileName);
3643 if (fileSpec->isDict()) {
3644 fileSpec->dictLookup("DOS", fileName);
3645 if (fileName->isString()) {
3649 fileSpec->dictLookup("Mac", fileName);
3650 if (fileName->isString()) {
3654 fileSpec->dictLookup("Unix", fileName);
3655 if (fileName->isString()) {
3659 fileSpec->dictLookup("F", fileName);
3660 if (fileName->isString()) {
3667 #endif // OPI_SUPPORT
3669 void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
3670 writePSFmt("%g %g setcharwidth\n", wx, wy);
3674 void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
3675 double llx, double lly, double urx, double ury) {
3682 t3String = new GString();
3684 t3Cacheable = gTrue;
3687 void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
3691 if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
3697 while ((c = str->getChar()) != EOF) {
3703 void PSOutputDev::writePSChar(char c) {
3705 t3String->append(c);
3707 (*outputFunc)(outputStream, &c, 1);
3711 void PSOutputDev::writePS(char *s) {
3713 t3String->append(s);
3715 (*outputFunc)(outputStream, s, strlen(s));
3719 void PSOutputDev::writePSFmt(const char *fmt, ...) {
3723 va_start(args, fmt);
3724 vsprintf(buf, fmt, args);
3727 t3String->append(buf);
3729 (*outputFunc)(outputStream, buf, strlen(buf));
3733 void PSOutputDev::writePSString(GString *s) {
3739 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
3740 if (*p == '(' || *p == ')' || *p == '\\') {
3742 writePSChar((char)*p);
3743 } else if (*p < 0x20 || *p >= 0x80) {
3744 sprintf(buf, "\\%03o", *p);
3746 t3String->append(buf);
3748 (*outputFunc)(outputStream, buf, strlen(buf));
3751 writePSChar((char)*p);
3757 void PSOutputDev::writePSName(char *s) {
3762 while ((c = *p++)) {
3763 if (c <= (char)0x20 || c >= (char)0x7f ||
3764 c == '(' || c == ')' || c == '<' || c == '>' ||
3765 c == '[' || c == ']' || c == '{' || c == '}' ||
3766 c == '/' || c == '%') {
3767 writePSFmt("#%02x", c & 0xff);
3774 GString *PSOutputDev::filterPSName(GString *name) {
3780 name2 = new GString();
3782 // ghostscript chokes on names that begin with out-of-limits
3783 // numbers, e.g., 1e4foo is handled correctly (as a name), but
3784 // 1e999foo generates a limitcheck error
3785 c = name->getChar(0);
3786 if (c >= '0' && c <= '9') {
3790 for (i = 0; i < name->getLength(); ++i) {
3791 c = name->getChar(i);
3792 if (c <= (char)0x20 || c >= (char)0x7f ||
3793 c == '(' || c == ')' || c == '<' || c == '>' ||
3794 c == '[' || c == ']' || c == '{' || c == '}' ||
3795 c == '/' || c == '%') {
3796 sprintf(buf, "#%02x", c & 0xff);