]>
git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/PSOutputDev.cxx
1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
28 #include "FormWidget.h"
29 #include "PSOutputDev.h"
32 #include "Japan12ToRKSJ.h"
36 // needed for setting type/creator of MacOS files
37 #include "ICSupport.h"
40 //------------------------------------------------------------------------
42 //------------------------------------------------------------------------
44 // Generate Level 1 PostScript?
45 GBool psOutLevel1
= gFalse
;
47 // Generate Encapsulated PostScript?
48 GBool psOutEPS
= gFalse
;
51 // Generate OPI comments?
52 GBool psOutOPI
= gFalse
;
56 int paperHeight
= 792;
58 //------------------------------------------------------------------------
59 // PostScript prolog and setup
60 //------------------------------------------------------------------------
62 static const char *prolog
[] = {
63 "/xpdf 75 dict def xpdf begin",
64 "% PDF special state",
65 "/pdfDictSize 14 def",
66 #if 0 // Not used for CUPS - the pstops filter handles this...
69 " /setpagedevice where {",
70 " pop 3 dict dup begin",
71 " exch /PageSize exch def",
72 " /ImagingBBox null def",
73 " /Policies 1 dict dup begin /PageSize 3 def end def",
81 " pdfDictSize dict begin",
83 " /pdfStroke [0] def",
84 " /pdfLastFill false def",
85 " /pdfLastStroke false def",
86 " /pdfTextMat [1 0 0 1 0 0] def",
87 " /pdfFontSize 0 def",
88 " /pdfCharSpacing 0 def",
89 " /pdfTextRender 0 def",
90 " /pdfTextRise 0 def",
91 " /pdfWordSpacing 0 def",
92 " /pdfHorizScaling 1 def",
94 "/pdfEndPage { end } def",
95 "/sCol { pdfLastStroke not {",
96 " pdfStroke aload length",
97 " 1 eq { setgray } { setrgbcolor} ifelse",
98 " /pdfLastStroke true def /pdfLastFill false def",
100 "/fCol { pdfLastFill not {",
101 " pdfFill aload length",
102 " 1 eq { setgray } { setrgbcolor } ifelse",
103 " /pdfLastFill true def /pdfLastStroke false def",
107 " 4 3 roll findfont",
108 " 4 2 roll matrix scale makefont",
109 " dup length dict begin",
110 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
111 " /Encoding exch def",
116 "/pdfMakeFont16 { findfont definefont pop } def",
117 "% graphics state operators",
118 "/q { gsave pdfDictSize dict begin } def",
119 "/Q { end grestore } def",
120 "/cm { concat } def",
121 "/d { setdash } def",
122 "/i { setflat } def",
123 "/j { setlinejoin } def",
124 "/J { setlinecap } def",
125 "/M { setmiterlimit } def",
126 "/w { setlinewidth } def",
128 "/g { dup 1 array astore /pdfFill exch def setgray",
129 " /pdfLastFill true def /pdfLastStroke false def } def",
130 "/G { dup 1 array astore /pdfStroke exch def setgray",
131 " /pdfLastStroke true def /pdfLastFill false def } def",
132 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
133 " /pdfLastFill true def /pdfLastStroke false def } def",
134 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
135 " /pdfLastStroke true def /pdfLastFill false def } def",
136 "% path segment operators",
139 "/c { curveto } def",
140 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
141 " neg 0 rlineto closepath } def",
142 "/h { closepath } def",
143 "% path painting operators",
144 "/S { sCol stroke } def",
145 "/f { fCol fill } def",
146 "/f* { fCol eofill } def",
147 "% clipping operators",
148 "/W { clip newpath } def",
149 "/W* { eoclip newpath } def",
150 "% text state operators",
151 "/Tc { /pdfCharSpacing exch def } def",
152 "/Tf { dup /pdfFontSize exch def",
153 " dup pdfHorizScaling mul exch matrix scale",
154 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
155 " exch findfont exch makefont setfont } def",
156 "/Tr { /pdfTextRender exch def } def",
157 "/Ts { /pdfTextRise exch def } def",
158 "/Tw { /pdfWordSpacing exch def } def",
159 "/Tz { /pdfHorizScaling exch def } def",
160 "% text positioning operators",
161 "/Td { pdfTextMat transform moveto } def",
162 "/Tm { /pdfTextMat exch def } def",
163 "% text string operators",
164 "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
165 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
166 " pdfFontSize mul pdfHorizScaling mul",
167 " 1 index stringwidth pdfTextMat idtransform pop",
168 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
169 " pdfWordSpacing 0 pdfTextMat dtransform 32",
170 " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
171 " 6 5 roll awidthshow",
172 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
173 "/TJm { pdfFontSize 0.001 mul mul neg 0",
174 " pdfTextMat dtransform rmoveto } def",
175 "% Level 1 image operators",
177 " /pdfImBuf1 4 index string def",
178 " { currentfile pdfImBuf1 readhexstring pop } image",
181 " /pdfImBuf1 4 index 7 add 8 idiv string def",
182 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
184 "% Level 2 image operators",
185 "/pdfImBuf 100 string def",
188 " { currentfile pdfImBuf readline",
189 " not { pop exit } if",
190 " (%-EOD-) eq { exit } if } loop",
194 " { currentfile pdfImBuf readline",
195 " not { pop exit } if",
196 " (%-EOD-) eq { exit } if } loop",
202 //------------------------------------------------------------------------
204 //------------------------------------------------------------------------
207 const char *name
; // PDF name
208 const char *psName
; // PostScript name
212 const char *psName
; // PostScript name
213 double mWidth
; // width of 'm' character
216 static PSFont psFonts
[] = {
217 {"Courier", "Courier"},
218 {"Courier-Bold", "Courier-Bold"},
219 {"Courier-Oblique", "Courier-Bold"},
220 {"Courier-BoldOblique", "Courier-BoldOblique"},
221 {"Helvetica", "Helvetica"},
222 {"Helvetica-Bold", "Helvetica-Bold"},
223 {"Helvetica-Oblique", "Helvetica-Oblique"},
224 {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
225 {"Symbol", "Symbol"},
226 {"Times-Roman", "Times-Roman"},
227 {"Times-Bold", "Times-Bold"},
228 {"Times-Italic", "Times-Italic"},
229 {"Times-BoldItalic", "Times-BoldItalic"},
230 {"ZapfDingbats", "ZapfDingbats"},
234 static PSSubstFont psSubstFonts
[] = {
235 {"Helvetica", 0.833},
236 {"Helvetica-Oblique", 0.833},
237 {"Helvetica-Bold", 0.889},
238 {"Helvetica-BoldOblique", 0.889},
239 {"Times-Roman", 0.788},
240 {"Times-Italic", 0.722},
241 {"Times-Bold", 0.833},
242 {"Times-BoldItalic", 0.778},
244 {"Courier-Oblique", 0.600},
245 {"Courier-Bold", 0.600},
246 {"Courier-BoldOblique", 0.600}
249 //------------------------------------------------------------------------
251 //------------------------------------------------------------------------
253 PSOutputDev::PSOutputDev(const char *fileName
, Catalog
*catalog
,
254 int firstPage
, int lastPage
,
255 GBool embedType11
, GBool doForm1
) {
258 FormWidgets
*formWidgets
;
265 embedType1
= embedType11
;
269 fontFileNames
= NULL
;
273 lastPage
= firstPage
;
277 if (!strcmp(fileName
, "-")) {
280 } else if (fileName
[0] == '|') {
284 signal(SIGPIPE
, SIG_IGN
);
286 if (!(f
= popen(fileName
+ 1, "w"))) {
287 error(-1, "Couldn't run print command '%s'", fileName
);
292 error(-1, "Print commands are not supported ('%s')", fileName
);
298 if (!(f
= fopen(fileName
, "w"))) {
299 error(-1, "Couldn't open PostScript file '%s'", fileName
);
305 // initialize fontIDs, fontFileIDs, and fontFileNames lists
308 fontIDs
= (Ref
*)gmalloc(fontIDSize
* sizeof(Ref
));
311 fontFileIDs
= (Ref
*)gmalloc(fontFileIDSize
* sizeof(Ref
));
312 fontFileNameSize
= 64;
314 fontFileNames
= (GString
**)gmalloc(fontFileNameSize
* sizeof(GString
*));
316 // initialize embedded font resource comment list
317 embFontList
= new GString();
321 writePS("%%!PS-Adobe-3.0 Resource-Form\n");
322 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion
);
323 writePS("%%%%LanguageLevel: %d\n", psOutLevel1
? 1 : 2);
324 writePS("%%%%EndComments\n");
325 } else if (psOutEPS
) {
326 writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
327 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion
);
328 writePS("%%%%LanguageLevel: %d\n", psOutLevel1
? 1 : 2);
329 page
= catalog
->getPage(firstPage
);
330 writePS("%%%%BoundingBox: %d %d %d %d\n",
331 (int)floor(page
->getX1()), (int)floor(page
->getY1()),
332 (int)ceil(page
->getX2()), (int)ceil(page
->getY2()));
333 if (floor(page
->getX1()) != ceil(page
->getX1()) ||
334 floor(page
->getY1()) != ceil(page
->getY1()) ||
335 floor(page
->getX2()) != ceil(page
->getX2()) ||
336 floor(page
->getY2()) != ceil(page
->getY2())) {
337 writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
338 page
->getX1(), page
->getY1(),
339 page
->getX2(), page
->getY2());
341 writePS("%%%%DocumentSuppliedResources:\n");
342 writePS("%%%%+ font: (atend)\n");
343 writePS("%%%%EndComments\n");
345 writePS("%%!PS-Adobe-3.0\n");
346 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion
);
347 writePS("%%%%LanguageLevel: %d\n", psOutLevel1
? 1 : 2);
348 writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
349 paperWidth
, paperHeight
);
350 writePS("%%%%Pages: %d\n", lastPage
- firstPage
+ 1);
351 writePS("%%%%EndComments\n");
352 writePS("%%%%BeginDefaults\n");
353 writePS("%%%%PageMedia: plain\n");
354 writePS("%%%%EndDefaults\n");
359 writePS("%%%%BeginProlog\n");
360 writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion
);
361 for (p
= prolog
; *p
; ++p
)
363 writePS("%%%%EndResource\n");
365 writePS("%%%%EndProlog\n");
369 writePS("%%%%BeginSetup\n");
370 writePS("xpdf begin\n");
371 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
372 page
= catalog
->getPage(pg
);
373 if ((resDict
= page
->getResourceDict())) {
376 formWidgets
= new FormWidgets(page
->getAnnots(&obj1
));
378 for (i
= 0; i
< formWidgets
->getNumWidgets(); ++i
) {
379 if (formWidgets
->getWidget(i
)->getAppearance(&obj1
)->isStream()) {
380 obj1
.streamGetDict()->lookup("Resources", &obj2
);
382 setupFonts(obj2
.getDict());
395 writePS("/opiMatrix matrix currentmatrix def\n");
399 // pdfSetup not used for CUPS filter...
400 // writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
402 writePS("%%%%EndSetup\n");
407 page
= catalog
->getPage(firstPage
);
408 writePS("4 dict dup begin\n");
409 writePS("/BBox [%d %d %d %d] def\n",
410 (int)page
->getX1(), (int)page
->getY1(),
411 (int)page
->getX2(), (int)page
->getY2());
412 writePS("/FormType 1 def\n");
413 writePS("/Matrix [1 0 0 1 0 0] def\n");
416 // initialize sequential page number
420 // initialize OPI nesting levels
426 PSOutputDev::~PSOutputDev() {
432 writePS("/Foo exch /Form defineresource pop\n");
433 } else if (psOutEPS
) {
434 writePS("%%%%Trailer\n");
436 writePS("%%%%DocumentSuppliedResources:\n");
437 writePS("%s", embFontList
->getCString());
438 writePS("%%%%EOF\n");
440 writePS("%%%%Trailer\n");
442 writePS("%%%%EOF\n");
444 if (fileType
== psFile
) {
446 ICS_MapRefNumAndAssign((short)f
->handle
);
451 else if (fileType
== psPipe
) {
454 signal(SIGPIPE
, SIG_DFL
);
469 for (i
= 0; i
< fontFileNameLen
; ++i
) {
470 delete fontFileNames
[i
];
472 gfree(fontFileNames
);
476 void PSOutputDev::setupFonts(Dict
*resDict
) {
477 Object fontDict
, xObjDict
, xObj
, resObj
;
478 GfxFontDict
*gfxFontDict
;
482 resDict
->lookup("Font", &fontDict
);
483 if (fontDict
.isDict()) {
484 gfxFontDict
= new GfxFontDict(fontDict
.getDict());
485 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
486 font
= gfxFontDict
->getFont(i
);
493 resDict
->lookup("XObject", &xObjDict
);
494 if (xObjDict
.isDict()) {
495 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
496 xObjDict
.dictGetVal(i
, &xObj
);
497 if (xObj
.isStream()) {
498 xObj
.streamGetDict()->lookup("Resources", &resObj
);
500 setupFonts(resObj
.getDict());
509 void PSOutputDev::setupFont(GfxFont
*font
) {
513 const char *charName
;
521 // check if font is already set up
522 for (i
= 0; i
< fontIDLen
; ++i
) {
523 if (fontIDs
[i
].num
== font
->getID().num
&&
524 fontIDs
[i
].gen
== font
->getID().gen
)
528 // add entry to fontIDs list
529 if (fontIDLen
>= fontIDSize
) {
531 fontIDs
= (Ref
*)grealloc(fontIDs
, fontIDSize
* sizeof(Ref
));
533 fontIDs
[fontIDLen
++] = font
->getID();
538 // check for embedded Type 1 font
539 if (embedType1
&& font
->getType() == fontType1
&&
540 font
->getEmbeddedFontID(&fontFileID
)) {
541 psName
= font
->getEmbeddedFontName();
542 setupEmbeddedType1Font(&fontFileID
, psName
);
544 // check for external Type 1 font file
545 } else if (embedType1
&& font
->getType() == fontType1
&&
546 font
->getExtFontFile()) {
547 // this assumes that the PS font name matches the PDF font name
548 psName
= font
->getName()->getCString();
549 setupEmbeddedType1Font(font
->getExtFontFile(), psName
);
551 // check for embedded Type 1C font
552 } else if (embedType1
&& font
->getType() == fontType1C
&&
553 font
->getEmbeddedFontID(&fontFileID
)) {
554 psName
= font
->getEmbeddedFontName();
555 setupEmbeddedType1CFont(font
, &fontFileID
, psName
);
557 } else if (font
->is16Bit() && font
->getCharSet16() == font16AdobeJapan12
) {
558 psName
= "Ryumin-Light-RKSJ";
561 // do font substitution
563 name
= font
->getName();
566 for (i
= 0; psFonts
[i
].name
; ++i
) {
567 if (name
->cmp(psFonts
[i
].name
) == 0) {
568 psName
= psFonts
[i
].psName
;
574 if (font
->isFixedWidth())
576 else if (font
->isSerif())
582 if (font
->isItalic())
584 psName
= psSubstFonts
[i
].psName
;
585 if ((code
= font
->getCharCode("m")) >= 0) {
586 w1
= font
->getWidth(code
);
590 w2
= psSubstFonts
[i
].mWidth
;
595 if (font
->getType() == fontType3
) {
596 // This is a hack which makes it possible to substitute for some
597 // Type 3 fonts. The problem is that it's impossible to know what
598 // the base coordinate system used in the font is without actually
599 // rendering the font.
601 fm
= font
->getFontMatrix();
611 // generate PostScript code to set up the font
613 writePS("/F%d_%d /%s pdfMakeFont16\n",
614 font
->getID().num
, font
->getID().gen
, psName
);
616 writePS("/F%d_%d /%s %g %g\n",
617 font
->getID().num
, font
->getID().gen
, psName
, xs
, ys
);
618 for (i
= 0; i
< 256; i
+= 8) {
619 writePS((i
== 0) ? "[ " : " ");
620 for (j
= 0; j
< 8; ++j
) {
621 charName
= font
->getCharName(i
+j
);
622 writePS("/%s", charName
? charName
: ".notdef");
624 writePS((i
== 256-8) ? "]\n" : "\n");
626 writePS("pdfMakeFont\n");
630 void PSOutputDev::setupEmbeddedType1Font(Ref
*id
, const char *psName
) {
631 static char hexChar
[17] = "0123456789abcdef";
632 Object refObj
, strObj
, obj1
, obj2
;
634 int length1
, length2
;
640 // check if font is already embedded
641 for (i
= 0; i
< fontFileIDLen
; ++i
) {
642 if (fontFileIDs
[i
].num
== id
->num
&&
643 fontFileIDs
[i
].gen
== id
->gen
)
647 // add entry to fontFileIDs list
648 if (fontFileIDLen
>= fontFileIDSize
) {
649 fontFileIDSize
+= 64;
650 fontFileIDs
= (Ref
*)grealloc(fontFileIDs
, fontFileIDSize
* sizeof(Ref
));
652 fontFileIDs
[fontFileIDLen
++] = *id
;
654 // get the font stream and info
655 refObj
.initRef(id
->num
, id
->gen
);
656 refObj
.fetch(&strObj
);
658 if (!strObj
.isStream()) {
659 error(-1, "Embedded font file object is not a stream");
662 if (!(dict
= strObj
.streamGetDict())) {
663 error(-1, "Embedded font stream is missing its dictionary");
666 dict
->lookup("Length1", &obj1
);
667 dict
->lookup("Length2", &obj2
);
668 if (!obj1
.isInt() || !obj2
.isInt()) {
669 error(-1, "Missing length fields in embedded font stream dictionary");
674 length1
= obj1
.getInt();
675 length2
= obj2
.getInt();
681 writePS("%%%%BeginResource: font %s\n", psName
);
682 embFontList
->append("%%+ font ");
683 embFontList
->append(psName
);
684 embFontList
->append("\n");
687 // copy ASCII portion of font
688 strObj
.streamReset();
689 for (i
= 0; i
< length1
&& (c
= strObj
.streamGetChar()) != EOF
; ++i
)
692 // figure out if encrypted portion is binary or ASCII
694 for (i
= 0; i
< 4; ++i
) {
695 start
[i
] = strObj
.streamGetChar();
696 if (start
[i
] == EOF
) {
697 error(-1, "Unexpected end of file in embedded font stream");
700 if (!((start
[i
] >= '0' && start
[i
] <= '9') ||
701 (start
[i
] >= 'A' && start
[i
] <= 'F') ||
702 (start
[i
] >= 'a' && start
[i
] <= 'f')))
706 // convert binary data to ASCII
708 for (i
= 0; i
< 4; ++i
) {
709 fputc(hexChar
[(start
[i
] >> 4) & 0x0f], f
);
710 fputc(hexChar
[start
[i
] & 0x0f], f
);
712 while (i
< length2
) {
713 if ((c
= strObj
.streamGetChar()) == EOF
)
715 fputc(hexChar
[(c
>> 4) & 0x0f], f
);
716 fputc(hexChar
[c
& 0x0f], f
);
723 // already in ASCII format -- just copy it
725 for (i
= 0; i
< 4; ++i
)
727 for (i
= 4; i
< length2
; ++i
) {
728 if ((c
= strObj
.streamGetChar()) == EOF
)
734 // write padding and "cleartomark"
735 for (i
= 0; i
< 8; ++i
)
736 writePS("00000000000000000000000000000000"
737 "00000000000000000000000000000000\n");
738 writePS("cleartomark\n");
742 writePS("%%%%EndResource\n");
749 //~ This doesn't handle .pfb files or binary eexec data (which only
750 //~ happens in pfb files?).
751 void PSOutputDev::setupEmbeddedType1Font(GString
*fileName
, const char *psName
) {
756 // check if font is already embedded
757 for (i
= 0; i
< fontFileNameLen
; ++i
) {
758 if (!fontFileNames
[i
]->cmp(fileName
)) {
763 // add entry to fontFileNames list
764 if (fontFileNameLen
>= fontFileNameSize
) {
765 fontFileNameSize
+= 64;
766 fontFileNames
= (GString
**)grealloc(fontFileNames
,
767 fontFileNameSize
* sizeof(GString
*));
769 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
773 writePS("%%%%BeginResource: font %s\n", psName
);
774 embFontList
->append("%%+ font ");
775 embFontList
->append(psName
);
776 embFontList
->append("\n");
779 // copy the font file
780 if (!(fontFile
= fopen(fileName
->getCString(), "rb"))) {
781 error(-1, "Couldn't open external font file");
784 while ((c
= fgetc(fontFile
)) != EOF
)
790 writePS("%%%%EndResource\n");
794 void PSOutputDev::setupEmbeddedType1CFont(GfxFont
*font
, Ref
*id
,
795 const char *psName
) {
798 Type1CFontConverter
*cvt
;
801 // check if font is already embedded
802 for (i
= 0; i
< fontFileIDLen
; ++i
) {
803 if (fontFileIDs
[i
].num
== id
->num
&&
804 fontFileIDs
[i
].gen
== id
->gen
)
808 // add entry to fontFileIDs list
809 if (fontFileIDLen
>= fontFileIDSize
) {
810 fontFileIDSize
+= 64;
811 fontFileIDs
= (Ref
*)grealloc(fontFileIDs
, fontFileIDSize
* sizeof(Ref
));
813 fontFileIDs
[fontFileIDLen
++] = *id
;
817 writePS("%%%%BeginResource: font %s\n", psName
);
818 embFontList
->append("%%+ font ");
819 embFontList
->append(psName
);
820 embFontList
->append("\n");
823 // convert it to a Type 1 font
824 fontBuf
= font
->readEmbFontFile(&fontLen
);
825 cvt
= new Type1CFontConverter(fontBuf
, fontLen
, f
);
828 gfree((void *)fontBuf
);
832 writePS("%%%%EndResource\n");
836 void PSOutputDev::startPage(int pageNum
, GfxState
*state
) {
837 int x1
, y1
, x2
, y2
, width
, height
, t
;
841 writePS("/PaintProc {\n");
842 writePS("begin xpdf begin\n");
843 writePS("pdfStartPage\n");
848 } else if (psOutEPS
) {
850 writePS("pdfStartPage\n");
857 writePS("%%%%Page: %d %d\n", pageNum
, seqPage
);
858 writePS("%%%%BeginPageSetup\n");
860 // rotate, translate, and scale page
861 x1
= (int)(state
->getX1() + 0.5);
862 y1
= (int)(state
->getY1() + 0.5);
863 x2
= (int)(state
->getX2() + 0.5);
864 y2
= (int)(state
->getY2() + 0.5);
867 if (width
> height
&& width
> paperWidth
) {
869 writePS("%%%%PageOrientation: Landscape\n");
870 writePS("pdfStartPage\n");
871 writePS("90 rotate\n");
873 ty
= -(y1
+ paperWidth
);
879 writePS("%%%%PageOrientation: Portrait\n");
880 writePS("pdfStartPage\n");
884 if (width
< paperWidth
) {
885 tx
+= (paperWidth
- width
) / 2;
887 if (height
< paperHeight
) {
888 ty
+= (paperHeight
- height
) / 2;
890 if (tx
!= 0 || ty
!= 0) {
891 writePS("%g %g translate\n", tx
, ty
);
893 if (width
> paperWidth
|| height
> paperHeight
) {
894 xScale
= (double)paperWidth
/ (double)width
;
895 yScale
= (double)paperHeight
/ (double)height
;
896 if (yScale
< xScale
) {
899 writePS("%0.4f %0.4f scale\n", xScale
, xScale
);
904 writePS("%%%%EndPageSetup\n");
909 void PSOutputDev::endPage() {
911 writePS("pdfEndPage\n");
912 writePS("end end\n");
915 writePS("showpage\n");
916 writePS("%%%%PageTrailer\n");
917 writePS("pdfEndPage\n");
921 void PSOutputDev::saveState(GfxState
*state
) {
927 void PSOutputDev::restoreState(GfxState
*state
) {
933 void PSOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
934 double m21
, double m22
, double m31
, double m32
) {
937 writePS("[%g %g %g %g %g %g] cm\n", m11
, m12
, m21
, m22
, m31
, m32
);
940 void PSOutputDev::updateLineDash(GfxState
*state
) {
945 state
->getLineDash(&dash
, &length
, &start
);
947 for (i
= 0; i
< length
; ++i
)
948 writePS("%g%s", dash
[i
], (i
== length
-1) ? "" : " ");
949 writePS("] %g d\n", start
);
952 void PSOutputDev::updateFlatness(GfxState
*state
) {
953 writePS("%d i\n", state
->getFlatness());
956 void PSOutputDev::updateLineJoin(GfxState
*state
) {
957 writePS("%d j\n", state
->getLineJoin());
960 void PSOutputDev::updateLineCap(GfxState
*state
) {
961 writePS("%d J\n", state
->getLineCap());
964 void PSOutputDev::updateMiterLimit(GfxState
*state
) {
965 writePS("%g M\n", state
->getMiterLimit());
968 void PSOutputDev::updateLineWidth(GfxState
*state
) {
969 writePS("%g w\n", state
->getLineWidth());
972 void PSOutputDev::updateFillColor(GfxState
*state
) {
976 color
= state
->getFillColor();
980 if (r
== g
&& g
== b
)
981 writePS("%g g\n", r
);
983 writePS("%g %g %g rg\n", r
, g
, b
);
986 void PSOutputDev::updateStrokeColor(GfxState
*state
) {
990 color
= state
->getStrokeColor();
994 if (r
== g
&& g
== b
)
995 writePS("%g G\n", r
);
997 writePS("%g %g %g RG\n", r
, g
, b
);
1000 void PSOutputDev::updateFont(GfxState
*state
) {
1001 if (state
->getFont()) {
1002 writePS("/F%d_%d %g Tf\n",
1003 state
->getFont()->getID().num
, state
->getFont()->getID().gen
,
1004 state
->getFontSize());
1008 void PSOutputDev::updateTextMat(GfxState
*state
) {
1011 mat
= state
->getTextMat();
1012 writePS("[%g %g %g %g %g %g] Tm\n",
1013 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
1016 void PSOutputDev::updateCharSpace(GfxState
*state
) {
1017 writePS("%g Tc\n", state
->getCharSpace());
1020 void PSOutputDev::updateRender(GfxState
*state
) {
1021 writePS("%d Tr\n", state
->getRender());
1024 void PSOutputDev::updateRise(GfxState
*state
) {
1025 writePS("%g Ts\n", state
->getRise());
1028 void PSOutputDev::updateWordSpace(GfxState
*state
) {
1029 writePS("%g Tw\n", state
->getWordSpace());
1032 void PSOutputDev::updateHorizScaling(GfxState
*state
) {
1033 writePS("%g Tz\n", state
->getHorizScaling());
1036 void PSOutputDev::updateTextPos(GfxState
*state
) {
1037 writePS("%g %g Td\n", state
->getLineX(), state
->getLineY());
1040 void PSOutputDev::updateTextShift(GfxState
*state
, double shift
) {
1043 writePS("%g TJm\n", shift
);
1046 void PSOutputDev::stroke(GfxState
*state
) {
1047 doPath(state
->getPath());
1051 void PSOutputDev::fill(GfxState
*state
) {
1052 doPath(state
->getPath());
1056 void PSOutputDev::eoFill(GfxState
*state
) {
1057 doPath(state
->getPath());
1061 void PSOutputDev::clip(GfxState
*state
) {
1062 doPath(state
->getPath());
1066 void PSOutputDev::eoClip(GfxState
*state
) {
1067 doPath(state
->getPath());
1071 void PSOutputDev::doPath(GfxPath
*path
) {
1072 GfxSubpath
*subpath
;
1073 double x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1076 n
= path
->getNumSubpaths();
1078 if (n
== 1 && path
->getSubpath(0)->getNumPoints() == 5) {
1079 subpath
= path
->getSubpath(0);
1080 x0
= subpath
->getX(0);
1081 y0
= subpath
->getY(0);
1082 x4
= subpath
->getX(4);
1083 y4
= subpath
->getY(4);
1084 if (x4
== x0
&& y4
== y0
) {
1085 x1
= subpath
->getX(1);
1086 y1
= subpath
->getY(1);
1087 x2
= subpath
->getX(2);
1088 y2
= subpath
->getY(2);
1089 x3
= subpath
->getX(3);
1090 y3
= subpath
->getY(3);
1091 if (x0
== x1
&& x2
== x3
&& y0
== y3
&& y1
== y2
) {
1092 writePS("%g %g %g %g re\n",
1093 x0
< x2
? x0
: x2
, y0
< y1
? y0
: y1
,
1094 fabs(x2
- x0
), fabs(y1
- y0
));
1096 } else if (x0
== x3
&& x1
== x2
&& y0
== y1
&& y2
== y3
) {
1097 writePS("%g %g %g %g re\n",
1098 x0
< x1
? x0
: x1
, y0
< y2
? y0
: y2
,
1099 fabs(x1
- x0
), fabs(y2
- y0
));
1105 for (i
= 0; i
< n
; ++i
) {
1106 subpath
= path
->getSubpath(i
);
1107 m
= subpath
->getNumPoints();
1108 writePS("%g %g m\n", subpath
->getX(0), subpath
->getY(0));
1111 if (subpath
->getCurve(j
)) {
1112 writePS("%g %g %g %g %g %g c\n", subpath
->getX(j
), subpath
->getY(j
),
1113 subpath
->getX(j
+1), subpath
->getY(j
+1),
1114 subpath
->getX(j
+2), subpath
->getY(j
+2));
1117 writePS("%g %g l\n", subpath
->getX(j
), subpath
->getY(j
));
1121 if (subpath
->isClosed()) {
1127 void PSOutputDev::drawString(GfxState
*state
, GString
*s
) {
1128 // check for invisible text -- this is used by Acrobat Capture
1129 if ((state
->getRender() & 3) == 3)
1133 writePS(" %g Tj\n", state
->getFont()->getWidth(s
));
1136 void PSOutputDev::drawString16(GfxState
*state
, GString
*s
) {
1137 #if defined(JAPANESE_SUPPORT) || defined(CHINESE_SUPPORT)
1143 #endif /* JAPANESE_SUPPORT || CHINESE_SUPPORT */
1145 // check for invisible text -- this is used by Acrobat Capture
1146 if ((state
->getRender() & 3) == 3)
1149 switch (state
->getFont()->getCharSet16()) {
1151 case font16AdobeJapan12
:
1152 #if JAPANESE_SUPPORT
1155 for (i
= 0; i
< s
->getLength(); i
+= 2) {
1156 c1
= ((s
->getChar(i
) & 0xff) << 8) + (s
->getChar(i
+1) & 0xff);
1158 c2
= japan12ToRKSJ
[c1
];
1163 writePS("%02x", c2
);
1165 writePS("%02x%02x", c2
>> 8, c2
& 0xff);
1167 w
+= state
->getFont()->getWidth16(c1
);
1169 writePS("> %g Tj\n", w
);
1173 case font16AdobeGB12
:
1178 void PSOutputDev::drawImageMask(GfxState
*state
, Stream
*str
,
1179 int width
, int height
, GBool invert
,
1185 len
= height
* ((width
+ 7) / 8);
1187 doImageL1(NULL
, invert
, inlineImg
, str
, width
, height
, len
);
1189 doImage(NULL
, invert
, inlineImg
, str
, width
, height
, len
);
1192 void PSOutputDev::drawImage(GfxState
*state
, Stream
*str
, int width
,
1193 int height
, GfxImageColorMap
*colorMap
,
1199 len
= height
* ((width
* colorMap
->getNumPixelComps() *
1200 colorMap
->getBits() + 7) / 8);
1202 doImageL1(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
1204 doImage(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
1207 void PSOutputDev::doImageL1(GfxImageColorMap
*colorMap
,
1208 GBool invert
, GBool inlineImg
,
1209 Stream
*str
, int width
, int height
, int len
) {
1210 ImageStream
*imgStr
;
1218 // width, height, matrix, bits per component
1220 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
1222 width
, -height
, height
);
1224 writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
1225 width
, height
, invert
? "true" : "false",
1226 width
, -height
, height
);
1232 // set up to process the data stream
1233 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
1234 colorMap
->getBits());
1237 // process the data stream
1239 for (y
= 0; y
< height
; ++y
) {
1242 for (x
= 0; x
< width
; ++x
) {
1243 imgStr
->getPixel(pixBuf
);
1244 colorMap
->getColor(pixBuf
, &color
);
1245 fprintf(f
, "%02x", (int)(color
.getGray() * 255 + 0.5));
1260 for (y
= 0; y
< height
; ++y
) {
1261 for (x
= 0; x
< width
; x
+= 8) {
1262 fprintf(f
, "%02x", str
->getChar() & 0xff);
1274 void PSOutputDev::doImage(GfxImageColorMap
*colorMap
,
1275 GBool invert
, GBool inlineImg
,
1276 Stream
*str
, int width
, int height
, int len
) {
1277 GfxColorSpace
*colorSpace
;
1278 LabParams
*labParams
;
1284 GBool useRLE
, useA85
;
1290 colorSpace
= colorMap
->getColorSpace();
1291 if (colorSpace
->isSeparation()) {
1292 //~ this is a kludge -- the correct thing would be to output
1293 //~ a separation color space
1294 n
= (1 << colorMap
->getBits()) - 1;
1295 writePS("[/Indexed /DeviceRGB %d <", n
);
1296 for (i
= 0; i
<= n
; i
+= 8) {
1298 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
1300 colorMap
->getColor(x
, &rgb
);
1301 writePS("%02x%02x%02x",
1302 (int)(255 * rgb
.getR() + 0.5),
1303 (int)(255 * rgb
.getG() + 0.5),
1304 (int)(255 * rgb
.getB() + 0.5));
1308 writePS("> ] setcolorspace\n");
1310 if (colorSpace
->isIndexed()) {
1311 writePS("[/Indexed ");
1313 switch (colorSpace
->getMode()) {
1315 writePS("/DeviceGray ");
1318 writePS("/DeviceCMYK ");
1321 writePS("/DeviceRGB ");
1324 labParams
= colorSpace
->getLabParams();
1325 writePS("[/CIEBasedABC <<\n");
1326 writePS(" /RangeABC [0 100 %g %g %g %g]\n",
1327 labParams
->aMin
, labParams
->aMax
,
1328 labParams
->bMin
, labParams
->bMax
);
1329 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
1330 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
1331 writePS(" /DecodeLMN\n");
1332 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
1333 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
1335 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
1336 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
1338 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
1339 writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
1341 writePS(" /WhitePoint [%g %g %g]\n",
1342 labParams
->whiteX
, labParams
->whiteY
, labParams
->whiteZ
);
1346 if (colorSpace
->isIndexed()) {
1347 n
= colorSpace
->getIndexHigh();
1348 numComps
= colorSpace
->getNumColorComps();
1349 writePS("%d <\n", n
);
1350 for (i
= 0; i
<= n
; i
+= 8) {
1352 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
1353 color
= colorSpace
->getLookupVal(j
);
1354 for (k
= 0; k
< numComps
; ++k
) {
1355 writePS("%02x", color
[k
]);
1360 writePS("> ] setcolorspace\n");
1362 writePS("setcolorspace\n");
1368 writePS("<<\n /ImageType 1\n");
1370 // width, height, matrix, bits per component
1371 writePS(" /Width %d\n", width
);
1372 writePS(" /Height %d\n", height
);
1373 writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width
, -height
, height
);
1374 writePS(" /BitsPerComponent %d\n",
1375 colorMap
? colorMap
->getBits() : 1);
1379 writePS(" /Decode [");
1380 if (colorMap
->getColorSpace()->isSeparation()) {
1381 //~ this is a kludge -- the correct thing would be to output
1382 //~ a separation color space
1383 n
= (1 << colorMap
->getBits()) - 1;
1384 writePS("%g %g", colorMap
->getDecodeLow(0) * n
,
1385 colorMap
->getDecodeHigh(0) * n
);
1387 numComps
= colorMap
->getNumPixelComps();
1388 for (i
= 0; i
< numComps
; ++i
) {
1392 writePS("%g %g", colorMap
->getDecodeLow(i
),
1393 colorMap
->getDecodeHigh(i
));
1398 writePS(" /Decode [%d %d]\n", invert
? 1 : 0, invert
? 0 : 1);
1404 writePS(" /DataSource <~\n");
1406 // write image data stream, using ASCII85 encode filter
1408 str
= new FixedLengthEncoder(str
, len
);
1410 str
= new ASCII85Encoder(str
);
1412 while ((c
= str
->getChar()) != EOF
)
1417 // end of image dictionary
1418 writePS(">>\n%s\n", colorMap
? "image" : "imagemask");
1423 writePS(" /DataSource currentfile\n");
1424 s
= str
->getPSFilter(" ");
1425 if (inlineImg
|| !s
) {
1430 useA85
= str
->isBinary();
1433 writePS(" /ASCII85Decode filter\n");
1435 writePS(" /RunLengthDecode filter\n");
1437 writePS("%s", s
->getCString());
1441 // cut off inline image streams at appropriate length
1443 str
= new FixedLengthEncoder(str
, len
);
1445 str
= str
->getBaseStream();
1447 // add RunLengthEncode and ASCII85 encode filters
1449 str
= new RunLengthEncoder(str
);
1451 str
= new ASCII85Encoder(str
);
1453 // end of image dictionary
1458 // this can't happen -- OPI dictionaries are in XObjects
1459 error(-1, "Internal: OPI in inline image");
1462 // need to read the stream to count characters -- the length
1463 // is data-dependent (because of A85 and RLE filters)
1466 while ((c
= str
->getChar()) != EOF
) {
1470 // +6/7 for "pdfIm\n" / "pdfImM\n"
1471 // +8 for newline + trailer
1472 n
+= colorMap
? 14 : 15;
1473 writePS("%%%%BeginData: %d Hex Bytes\n", n
);
1476 writePS("%s\n", colorMap
? "pdfIm" : "pdfImM");
1478 // copy the stream data
1480 while ((c
= str
->getChar()) != EOF
)
1483 // add newline and trailer to the end
1485 fputs("%-EOD-\n", f
);
1488 writePS("%%%%EndData\n");
1493 if (useRLE
|| useA85
)
1499 void PSOutputDev::opiBegin(GfxState
*state
, Dict
*opiDict
) {
1503 opiDict
->lookup("2.0", &dict
);
1504 if (dict
.isDict()) {
1505 opiBegin20(state
, dict
.getDict());
1509 opiDict
->lookup("1.3", &dict
);
1510 if (dict
.isDict()) {
1511 opiBegin13(state
, dict
.getDict());
1518 void PSOutputDev::opiBegin20(GfxState
*state
, Dict
*dict
) {
1519 Object obj1
, obj2
, obj3
, obj4
;
1520 double width
, height
, left
, right
, top
, bottom
;
1524 writePS("%%%%BeginOPI: 2.0\n");
1525 writePS("%%%%Distilled\n");
1527 dict
->lookup("F", &obj1
);
1528 if (getFileSpec(&obj1
, &obj2
)) {
1529 writePS("%%%%ImageFileName: %s\n",
1530 obj2
.getString()->getCString());
1535 dict
->lookup("MainImage", &obj1
);
1536 if (obj1
.isString()) {
1537 writePS("%%%%MainImage: %s\n", obj1
.getString()->getCString());
1541 //~ ignoring 'Tags' entry
1542 //~ need to use writePSString() and deal with >255-char lines
1544 dict
->lookup("Size", &obj1
);
1545 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
1546 obj1
.arrayGet(0, &obj2
);
1547 width
= obj2
.getNum();
1549 obj1
.arrayGet(1, &obj2
);
1550 height
= obj2
.getNum();
1552 writePS("%%%%ImageDimensions: %g %g\n", width
, height
);
1556 dict
->lookup("CropRect", &obj1
);
1557 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
1558 obj1
.arrayGet(0, &obj2
);
1559 left
= obj2
.getNum();
1561 obj1
.arrayGet(1, &obj2
);
1562 top
= obj2
.getNum();
1564 obj1
.arrayGet(2, &obj2
);
1565 right
= obj2
.getNum();
1567 obj1
.arrayGet(3, &obj2
);
1568 bottom
= obj2
.getNum();
1570 writePS("%%%%ImageCropRect: %g %g %g %g\n", left
, top
, right
, bottom
);
1574 dict
->lookup("Overprint", &obj1
);
1575 if (obj1
.isBool()) {
1576 writePS("%%%%ImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
1580 dict
->lookup("Inks", &obj1
);
1581 if (obj1
.isName()) {
1582 writePS("%%%%ImageInks: %s\n", obj1
.getName());
1583 } else if (obj1
.isArray() && obj1
.arrayGetLength() >= 1) {
1584 obj1
.arrayGet(0, &obj2
);
1585 if (obj2
.isName()) {
1586 writePS("%%%%ImageInks: %s %d",
1587 obj2
.getName(), (obj1
.arrayGetLength() - 1) / 2);
1588 for (i
= 1; i
+1 < obj1
.arrayGetLength(); i
+= 2) {
1589 obj1
.arrayGet(i
, &obj3
);
1590 obj1
.arrayGet(i
+1, &obj4
);
1591 if (obj3
.isString() && obj4
.isNum()) {
1593 writePSString(obj3
.getString());
1594 writePS(" %g", obj4
.getNum());
1607 writePS("%%%%BeginIncludedImage\n");
1609 dict
->lookup("IncludedImageDimensions", &obj1
);
1610 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
1611 obj1
.arrayGet(0, &obj2
);
1614 obj1
.arrayGet(1, &obj2
);
1617 writePS("%%%%IncludedImageDimensions: %d %d\n", w
, h
);
1621 dict
->lookup("IncludedImageQuality", &obj1
);
1623 writePS("%%%%IncludedImageQuality: %g\n", obj1
.getNum());
1630 void PSOutputDev::opiBegin13(GfxState
*state
, Dict
*dict
) {
1632 int left
, right
, top
, bottom
, samples
, bits
, width
, height
;
1634 double llx
, lly
, ulx
, uly
, urx
, ury
, lrx
, lry
;
1635 double tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
;
1640 writePS("/opiMatrix2 matrix currentmatrix def\n");
1641 writePS("opiMatrix setmatrix\n");
1643 dict
->lookup("F", &obj1
);
1644 if (getFileSpec(&obj1
, &obj2
)) {
1645 writePS("%%ALDImageFileName: %s\n",
1646 obj2
.getString()->getCString());
1651 dict
->lookup("CropRect", &obj1
);
1652 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
1653 obj1
.arrayGet(0, &obj2
);
1654 left
= obj2
.getInt();
1656 obj1
.arrayGet(1, &obj2
);
1657 top
= obj2
.getInt();
1659 obj1
.arrayGet(2, &obj2
);
1660 right
= obj2
.getInt();
1662 obj1
.arrayGet(3, &obj2
);
1663 bottom
= obj2
.getInt();
1665 writePS("%%ALDImageCropRect: %d %d %d %d\n", left
, top
, right
, bottom
);
1669 dict
->lookup("Color", &obj1
);
1670 if (obj1
.isArray() && obj1
.arrayGetLength() == 5) {
1671 obj1
.arrayGet(0, &obj2
);
1674 obj1
.arrayGet(1, &obj2
);
1677 obj1
.arrayGet(2, &obj2
);
1680 obj1
.arrayGet(3, &obj2
);
1683 obj1
.arrayGet(4, &obj2
);
1684 if (obj2
.isString()) {
1685 writePS("%%ALDImageColor: %g %g %g %g ", c
, m
, y
, k
);
1686 writePSString(obj2
.getString());
1693 dict
->lookup("ColorType", &obj1
);
1694 if (obj1
.isName()) {
1695 writePS("%%ALDImageColorType: %s\n", obj1
.getName());
1699 //~ ignores 'Comments' entry
1700 //~ need to handle multiple lines
1702 dict
->lookup("CropFixed", &obj1
);
1703 if (obj1
.isArray()) {
1704 obj1
.arrayGet(0, &obj2
);
1705 ulx
= obj2
.getNum();
1707 obj1
.arrayGet(1, &obj2
);
1708 uly
= obj2
.getNum();
1710 obj1
.arrayGet(2, &obj2
);
1711 lrx
= obj2
.getNum();
1713 obj1
.arrayGet(3, &obj2
);
1714 lry
= obj2
.getNum();
1716 writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx
, uly
, lrx
, lry
);
1720 dict
->lookup("GrayMap", &obj1
);
1721 if (obj1
.isArray()) {
1722 writePS("%%ALDImageGrayMap:");
1723 for (i
= 0; i
< obj1
.arrayGetLength(); i
+= 16) {
1727 for (j
= 0; j
< 16 && i
+j
< obj1
.arrayGetLength(); ++j
) {
1728 obj1
.arrayGet(i
+j
, &obj2
);
1729 writePS(" %d", obj2
.getInt());
1737 dict
->lookup("ID", &obj1
);
1738 if (obj1
.isString()) {
1739 writePS("%%ALDImageID: %s\n", obj1
.getString()->getCString());
1743 dict
->lookup("ImageType", &obj1
);
1744 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
1745 obj1
.arrayGet(0, &obj2
);
1746 samples
= obj2
.getInt();
1748 obj1
.arrayGet(1, &obj2
);
1749 bits
= obj2
.getInt();
1751 writePS("%%ALDImageType: %d %d\n", samples
, bits
);
1755 dict
->lookup("Overprint", &obj1
);
1756 if (obj1
.isBool()) {
1757 writePS("%%ALDImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
1761 dict
->lookup("Position", &obj1
);
1762 if (obj1
.isArray() && obj1
.arrayGetLength() == 8) {
1763 obj1
.arrayGet(0, &obj2
);
1764 llx
= obj2
.getNum();
1766 obj1
.arrayGet(1, &obj2
);
1767 lly
= obj2
.getNum();
1769 obj1
.arrayGet(2, &obj2
);
1770 ulx
= obj2
.getNum();
1772 obj1
.arrayGet(3, &obj2
);
1773 uly
= obj2
.getNum();
1775 obj1
.arrayGet(4, &obj2
);
1776 urx
= obj2
.getNum();
1778 obj1
.arrayGet(5, &obj2
);
1779 ury
= obj2
.getNum();
1781 obj1
.arrayGet(6, &obj2
);
1782 lrx
= obj2
.getNum();
1784 obj1
.arrayGet(7, &obj2
);
1785 lry
= obj2
.getNum();
1787 opiTransform(state
, llx
, lly
, &tllx
, &tlly
);
1788 opiTransform(state
, ulx
, uly
, &tulx
, &tuly
);
1789 opiTransform(state
, urx
, ury
, &turx
, &tury
);
1790 opiTransform(state
, lrx
, lry
, &tlrx
, &tlry
);
1791 writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
1792 tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
);
1797 dict
->lookup("Resolution", &obj1
);
1798 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
1799 obj1
.arrayGet(0, &obj2
);
1800 horiz
= obj2
.getNum();
1802 obj1
.arrayGet(1, &obj2
);
1803 vert
= obj2
.getNum();
1805 writePS("%%ALDImageResoution: %g %g\n", horiz
, vert
);
1810 dict
->lookup("Size", &obj1
);
1811 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
1812 obj1
.arrayGet(0, &obj2
);
1813 width
= obj2
.getInt();
1815 obj1
.arrayGet(1, &obj2
);
1816 height
= obj2
.getInt();
1818 writePS("%%ALDImageSize: %d %d\n", width
, height
);
1822 //~ ignoring 'Tags' entry
1823 //~ need to use writePSString() and deal with >255-char lines
1825 dict
->lookup("Tint", &obj1
);
1827 writePS("%%ALDImageTint: %g\n", obj1
.getNum());
1831 dict
->lookup("Transparency", &obj1
);
1832 if (obj1
.isBool()) {
1833 writePS("%%ALDImageTransparency: %s\n", obj1
.getBool() ? "true" : "false");
1837 writePS("%%%%BeginObject: image\n");
1838 writePS("opiMatrix2 setmatrix\n");
1842 // Convert PDF user space coordinates to PostScript default user space
1843 // coordinates. This has to account for both the PDF CTM and the
1844 // PSOutputDev page-fitting transform.
1845 void PSOutputDev::opiTransform(GfxState
*state
, double x0
, double y0
,
1846 double *x1
, double *y1
) {
1849 state
->transform(x0
, y0
, x1
, y1
);
1861 void PSOutputDev::opiEnd(GfxState
*state
, Dict
*opiDict
) {
1865 opiDict
->lookup("2.0", &dict
);
1866 if (dict
.isDict()) {
1867 writePS("%%%%EndIncludedImage\n");
1868 writePS("%%%%EndOPI\n");
1869 writePS("grestore\n");
1874 opiDict
->lookup("1.3", &dict
);
1875 if (dict
.isDict()) {
1876 writePS("%%%%EndObject\n");
1877 writePS("restore\n");
1885 GBool
PSOutputDev::getFileSpec(Object
*fileSpec
, Object
*fileName
) {
1886 if (fileSpec
->isString()) {
1887 fileSpec
->copy(fileName
);
1890 if (fileSpec
->isDict()) {
1891 fileSpec
->dictLookup("DOS", fileName
);
1892 if (fileName
->isString()) {
1896 fileSpec
->dictLookup("Mac", fileName
);
1897 if (fileName
->isString()) {
1901 fileSpec
->dictLookup("Unix", fileName
);
1902 if (fileName
->isString()) {
1906 fileSpec
->dictLookup("F", fileName
);
1907 if (fileName
->isString()) {
1914 #endif // OPI_SUPPORT
1916 void PSOutputDev::writePS(const char *fmt
, ...) {
1919 va_start(args
, fmt
);
1920 vfprintf(f
, fmt
, args
);
1924 void PSOutputDev::writePSString(GString
*s
) {
1929 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
1930 if (*p
== '(' || *p
== ')' || *p
== '\\')
1931 fprintf(f
, "\\%c", *p
);
1932 else if (*p
< 0x20 || *p
>= 0x80)
1933 fprintf(f
, "\\%03o", *p
);