1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 #include "GlobalParams.h"
32 #include "UnicodeMap.h"
33 #include "FoFiType1C.h"
34 #include "FoFiTrueType.h"
40 #include "PSOutputDev.h"
43 // needed for setting type/creator of MacOS files
44 #include "ICSupport.h"
47 //------------------------------------------------------------------------
48 // PostScript prolog and setup
49 //------------------------------------------------------------------------
51 // The '~' escapes mark prolog code that is emitted only in certain
55 // ^ ^----- s=psLevel*Sep, n=psLevel*
56 // +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
58 static char *prolog
[] = {
59 "/xpdf 75 dict def xpdf begin",
60 "% PDF special state",
61 "/pdfDictSize 15 def",
63 "/pdfStates 64 array def",
65 " pdfStates exch pdfDictSize dict",
66 " dup /pdfStateIdx 3 index put",
71 " 3 1 roll 2 array astore",
72 " /setpagedevice where {",
74 " /PageSize exch def",
75 " /ImagingBBox null def",
76 " /Policies 1 dict dup begin /PageSize 3 def end def",
77 " { /Duplex true def } if",
78 " currentdict end setpagedevice",
85 " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
86 " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
87 " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
92 " pdfStates 0 get begin",
94 " pdfDictSize dict begin",
97 " /pdfFillXform {} def",
98 " /pdfStrokeCS [] def",
99 " /pdfStrokeXform {} def",
104 " /pdfFill [0 0 0 1] def",
105 " /pdfStroke [0 0 0 1] def",
108 " /pdfStroke [0] def",
109 " /pdfFillOP false def",
110 " /pdfStrokeOP false def",
112 " /pdfLastFill false def",
113 " /pdfLastStroke false def",
114 " /pdfTextMat [1 0 0 1 0 0] def",
115 " /pdfFontSize 0 def",
116 " /pdfCharSpacing 0 def",
117 " /pdfTextRender 0 def",
118 " /pdfTextRise 0 def",
119 " /pdfWordSpacing 0 def",
120 " /pdfHorizScaling 1 def",
121 " /pdfTextClipPath [] def",
123 "/pdfEndPage { end } def",
125 "% separation convention operators",
126 "/findcmykcustomcolor where {",
129 " /findcmykcustomcolor { 5 array astore } def",
131 "/setcustomcolor where {",
134 " /setcustomcolor {",
136 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
137 " 0 4 getinterval cvx",
138 " [ exch /dup load exch { mul exch dup } /forall load",
139 " /pop load dup ] cvx",
140 " ] setcolorspace setcolor",
143 "/customcolorimage where {",
146 " /customcolorimage {",
148 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
150 " [ exch /dup load exch { mul exch dup } /forall load",
151 " /pop load dup ] cvx",
155 " /DataSource exch def",
156 " /ImageMatrix exch def",
157 " /BitsPerComponent exch def",
160 " /Decode [1 0] def",
169 "/g { dup /pdfFill exch def setgray",
170 " /pdfLastFill true def /pdfLastStroke false def } def",
171 "/G { dup /pdfStroke exch def setgray",
172 " /pdfLastStroke true def /pdfLastFill false def } def",
174 " pdfLastFill not {",
176 " /pdfLastFill true def /pdfLastStroke false def",
180 " pdfLastStroke not {",
181 " pdfStroke setgray",
182 " /pdfLastStroke true def /pdfLastFill false def",
186 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
187 " /pdfLastFill true def /pdfLastStroke false def } def",
188 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
189 " /pdfLastStroke true def /pdfLastFill false def } def",
191 " pdfLastFill not {",
192 " pdfFill aload pop setcmykcolor",
193 " /pdfLastFill true def /pdfLastStroke false def",
197 " pdfLastStroke not {",
198 " pdfStroke aload pop setcmykcolor",
199 " /pdfLastStroke true def /pdfLastFill false def",
203 "/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
204 " setcolorspace } def",
205 "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
206 " setcolorspace } def",
207 "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
208 " dup /pdfFill exch def aload pop pdfFillXform setcolor",
209 " /pdfLastFill true def /pdfLastStroke false def } def",
210 "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
211 " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
212 " /pdfLastStroke true def /pdfLastFill false def } def",
213 "/op { /pdfFillOP exch def",
214 " pdfLastFill { pdfFillOP setoverprint } if } def",
215 "/OP { /pdfStrokeOP exch def",
216 " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
218 " pdfLastFill not {",
219 " pdfFillCS setcolorspace",
220 " pdfFill aload pop pdfFillXform setcolor",
221 " pdfFillOP setoverprint",
222 " /pdfLastFill true def /pdfLastStroke false def",
226 " pdfLastStroke not {",
227 " pdfStrokeCS setcolorspace",
228 " pdfStroke aload pop pdfStrokeXform setcolor",
229 " pdfStrokeOP setoverprint",
230 " /pdfLastStroke true def /pdfLastFill false def",
234 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
235 " /pdfLastFill true def /pdfLastStroke false def } def",
236 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
237 " /pdfLastStroke true def /pdfLastFill false def } def",
238 "/ck { 6 copy 6 array astore /pdfFill exch def",
239 " findcmykcustomcolor exch setcustomcolor",
240 " /pdfLastFill true def /pdfLastStroke false def } def",
241 "/CK { 6 copy 6 array astore /pdfStroke exch def",
242 " findcmykcustomcolor exch setcustomcolor",
243 " /pdfLastStroke true def /pdfLastFill false def } def",
244 "/op { /pdfFillOP exch def",
245 " pdfLastFill { pdfFillOP setoverprint } if } def",
246 "/OP { /pdfStrokeOP exch def",
247 " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
249 " pdfLastFill not {",
250 " pdfFill aload length 4 eq {",
253 " findcmykcustomcolor exch setcustomcolor",
255 " pdfFillOP setoverprint",
256 " /pdfLastFill true def /pdfLastStroke false def",
260 " pdfLastStroke not {",
261 " pdfStroke aload length 4 eq {",
264 " findcmykcustomcolor exch setcustomcolor",
266 " pdfStrokeOP setoverprint",
267 " /pdfLastStroke true def /pdfLastFill false def",
273 " 4 3 roll findfont",
274 " 4 2 roll matrix scale makefont",
275 " dup length dict begin",
276 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
277 " /Encoding exch def",
284 " dup length dict begin",
285 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
292 "/pdfMakeFont16L3 {",
293 " 1 index /CIDFont resourcestatus {",
294 " pop pop 1 index /CIDFont findresource /CIDFontType known",
299 " 0 eq { /Identity-H } { /Identity-V } ifelse",
300 " exch 1 array astore composefont pop",
306 "% graphics state operators",
310 " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
311 " pdfStates pdfStateIdx 1 add get begin",
312 " pdfOpNames { exch def } forall",
314 "/Q { end grestore } def",
316 "/q { gsave pdfDictSize dict begin } def",
319 " /pdfLastFill where {",
322 " pdfFillOP setoverprint",
324 " pdfStrokeOP setoverprint",
329 "/cm { concat } def",
330 "/d { setdash } def",
331 "/i { setflat } def",
332 "/j { setlinejoin } def",
333 "/J { setlinecap } def",
334 "/M { setmiterlimit } def",
335 "/w { setlinewidth } def",
336 "% path segment operators",
339 "/c { curveto } def",
340 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
341 " neg 0 rlineto closepath } def",
342 "/h { closepath } def",
343 "% path painting operators",
344 "/S { sCol stroke } def",
345 "/Sf { fCol stroke } def",
346 "/f { fCol fill } def",
347 "/f* { fCol eofill } def",
348 "% clipping operators",
349 "/W { clip newpath } def",
350 "/W* { eoclip newpath } def",
351 "% text state operators",
352 "/Tc { /pdfCharSpacing exch def } def",
353 "/Tf { dup /pdfFontSize exch def",
354 " dup pdfHorizScaling mul exch matrix scale",
355 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
356 " exch findfont exch makefont setfont } def",
357 "/Tr { /pdfTextRender exch def } def",
358 "/Ts { /pdfTextRise exch def } def",
359 "/Tw { /pdfWordSpacing exch def } def",
360 "/Tz { /pdfHorizScaling exch def } def",
361 "% text positioning operators",
362 "/Td { pdfTextMat transform moveto } def",
363 "/Tm { /pdfTextMat exch def } def",
364 "% text string operators",
370 " 1 string dup 0 3 index put 3 index exec",
376 " currentfont /FontType get 0 eq {",
377 " 0 2 2 index length 1 sub {",
378 " 2 copy get exch 1 add 2 index exch get",
379 " 2 copy exch 256 mul add",
380 " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
385 " 1 string dup 0 3 index put 3 index exec",
391 "/awcp {", // awidthcharpath
394 " 5 index 5 index rmoveto",
395 " 6 index eq { 7 index 7 index rmoveto } if",
400 " fCol", // because stringwidth has to draw Type 3 chars
401 " 1 index stringwidth pdfTextMat idtransform pop",
402 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
403 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
404 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
405 " pdfTextMat dtransform",
409 " fCol", // because stringwidth has to draw Type 3 chars
410 " 2 index stringwidth pdfTextMat idtransform pop",
412 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
413 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
414 " pdfTextMat dtransform",
418 " fCol", // because stringwidth has to draw Type 3 chars
419 " 2 index stringwidth pdfTextMat idtransform exch pop",
421 " 0 pdfWordSpacing pdfTextMat dtransform 32",
422 " 4 3 roll pdfCharSpacing add 0 exch",
423 " pdfTextMat dtransform",
427 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
428 " currentpoint 8 2 roll",
429 " pdfTextRender 1 and 0 eq {",
430 " 6 copy awidthshow",
432 " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
433 " 7 index 7 index moveto",
435 " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
436 " false awcp currentpoint stroke moveto",
438 " pdfTextRender 4 and 0 ne {",
441 " /pdfTextClipPath [ pdfTextClipPath aload pop",
447 " currentpoint newpath moveto",
451 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
453 "/TJm { pdfFontSize 0.001 mul mul neg 0",
454 " pdfTextMat dtransform rmoveto } def",
455 "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
456 " pdfTextMat dtransform rmoveto } def",
457 "/Tclip { pdfTextClipPath cvx exec clip newpath",
458 " /pdfTextClipPath [] def } def",
460 "% Level 1 image operators",
463 " /pdfImBuf1 4 index string def",
464 " { currentfile pdfImBuf1 readhexstring pop } image",
468 " /pdfImBuf1 4 index string def",
469 " /pdfImBuf2 4 index string def",
470 " /pdfImBuf3 4 index string def",
471 " /pdfImBuf4 4 index string def",
472 " { currentfile pdfImBuf1 readhexstring pop }",
473 " { currentfile pdfImBuf2 readhexstring pop }",
474 " { currentfile pdfImBuf3 readhexstring pop }",
475 " { currentfile pdfImBuf4 readhexstring pop }",
476 " true 4 colorimage",
480 " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
481 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
484 " { 2 copy get exch 1 add exch } imagemask",
488 "% Level 2 image operators",
489 "/pdfImBuf 100 string def",
492 " { currentfile pdfImBuf readline",
493 " not { pop exit } if",
494 " (%-EOD-) eq { exit } if } loop",
498 " findcmykcustomcolor exch",
499 " dup /Width get /pdfImBuf1 exch string def",
500 " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
501 " /pdfImDecodeLow exch def",
502 " begin Width Height BitsPerComponent ImageMatrix DataSource end",
503 " /pdfImData exch def",
504 " { pdfImData pdfImBuf1 readstring pop",
505 " 0 1 2 index length 1 sub {",
506 " 1 index exch 2 copy get",
507 " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
510 " 6 5 roll customcolorimage",
511 " { currentfile pdfImBuf readline",
512 " not { pop exit } if",
513 " (%-EOD-) eq { exit } if } loop",
518 " { currentfile pdfImBuf readline",
519 " not { pop exit } if",
520 " (%-EOD-) eq { exit } if } loop",
524 " 0 2 4 index length 1 sub {",
525 " dup 4 index exch 2 copy",
526 " get 5 index div put",
527 " 1 add 3 index exch 2 copy",
528 " get 3 index div put",
532 "/pdfImClipEnd { grestore } def",
534 "% shading operators",
536 " false 0 1 3 index length 1 sub {",
537 " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
541 " exch pop exch pop",
543 "/funcCol { func n array astore } def",
551 " 4 index 4 index funcCol dup",
552 " 6 index 4 index funcCol dup",
553 " 3 1 roll colordelta 3 1 roll",
554 " 5 index 5 index funcCol dup",
555 " 3 1 roll colordelta 3 1 roll",
556 " 6 index 8 index funcCol dup",
557 " 3 1 roll colordelta 3 1 roll",
558 " colordelta or or or",
563 " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
564 " 6 index 6 index 4 index 4 index 4 index funcSH",
565 " 2 index 6 index 6 index 4 index 4 index funcSH",
566 " 6 index 2 index 4 index 6 index 4 index funcSH",
567 " 5 3 roll 3 2 roll funcSH pop pop",
569 " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
571 " dup 4 index exch mat transform m",
572 " 3 index 3 index mat transform l",
573 " 1 index 3 index mat transform l",
574 " mat transform l pop pop h f*",
587 " func n array astore",
596 " 2 index axialCol 2 index axialCol colordelta",
600 " 1 add 3 1 roll 2 copy add 0.5 mul",
601 " dup 4 3 roll exch 4 index axialSH",
602 " exch 3 2 roll axialSH",
604 " pop 2 copy add 0.5 mul axialCol sc",
605 " exch dup dx mul x0 add exch dy mul y0 add",
606 " 3 2 roll dup dx mul x0 add exch dy mul y0 add",
607 " dx abs dy abs ge {",
608 " 2 copy yMin sub dy mul dx div add yMin m",
609 " yMax sub dy mul dx div add yMax l",
610 " 2 copy yMax sub dy mul dx div add yMax l",
611 " yMin sub dy mul dx div add yMin l",
614 " exch 2 copy xMin sub dx mul dy div add xMin exch m",
615 " xMax sub dx mul dy div add xMax exch l",
616 " exch 2 copy xMax sub dx mul dy div add xMax exch l",
617 " xMin sub dx mul dy div add xMin exch l",
630 " func n array astore",
639 " 2 index dt mul t0 add radialCol",
640 " 2 index dt mul t0 add radialCol colordelta",
644 " 1 add 3 1 roll 2 copy add 0.5 mul",
645 " dup 4 3 roll exch 4 index radialSH",
646 " exch 3 2 roll radialSH",
648 " pop 2 copy add 0.5 mul dt mul t0 add axialCol sc",
649 " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
651 " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
660 static char *cmapProlog
[] = {
661 "/CIDInit /ProcSet findresource begin",
665 " /CMapName /Identity-H def",
666 " /CIDSystemInfo 3 dict dup begin",
667 " /Registry (Adobe) def",
668 " /Ordering (Identity) def",
669 " /Supplement 0 def",
671 " 1 begincodespacerange",
673 " endcodespacerange",
679 " currentdict CMapName exch /CMap defineresource pop",
684 " /CMapName /Identity-V def",
685 " /CIDSystemInfo 3 dict dup begin",
686 " /Registry (Adobe) def",
687 " /Ordering (Identity) def",
688 " /Supplement 0 def",
691 " 1 begincodespacerange",
693 " endcodespacerange",
699 " currentdict CMapName exch /CMap defineresource pop",
705 //------------------------------------------------------------------------
707 //------------------------------------------------------------------------
710 char *psName
; // PostScript name
711 double mWidth
; // width of 'm' character
714 static char *psFonts
[] = {
718 "Courier-BoldOblique",
722 "Helvetica-BoldOblique",
732 static PSSubstFont psSubstFonts
[] = {
733 {"Helvetica", 0.833},
734 {"Helvetica-Oblique", 0.833},
735 {"Helvetica-Bold", 0.889},
736 {"Helvetica-BoldOblique", 0.889},
737 {"Times-Roman", 0.788},
738 {"Times-Italic", 0.722},
739 {"Times-Bold", 0.833},
740 {"Times-BoldItalic", 0.778},
742 {"Courier-Oblique", 0.600},
743 {"Courier-Bold", 0.600},
744 {"Courier-BoldOblique", 0.600}
747 // Encoding info for substitute 16-bit font
753 //------------------------------------------------------------------------
755 //------------------------------------------------------------------------
757 #define psProcessCyan 1
758 #define psProcessMagenta 2
759 #define psProcessYellow 4
760 #define psProcessBlack 8
761 #define psProcessCMYK 15
763 //------------------------------------------------------------------------
765 //------------------------------------------------------------------------
767 class PSOutCustomColor
{
770 PSOutCustomColor(double cA
, double mA
,
771 double yA
, double kA
, GString
*nameA
);
776 PSOutCustomColor
*next
;
779 PSOutCustomColor::PSOutCustomColor(double cA
, double mA
,
780 double yA
, double kA
, GString
*nameA
) {
789 PSOutCustomColor::~PSOutCustomColor() {
793 //------------------------------------------------------------------------
795 //------------------------------------------------------------------------
797 class DeviceNRecoder
: public FilterStream
{
800 DeviceNRecoder(Stream
*strA
, int widthA
, int heightA
,
801 GfxImageColorMap
*colorMapA
);
802 virtual ~DeviceNRecoder();
803 virtual StreamKind
getKind() { return strWeird
; }
804 virtual void reset();
805 virtual int getChar()
806 { return (bufIdx
>= bufSize
&& !fillBuf()) ? EOF
: buf
[bufIdx
++]; }
807 virtual int lookChar()
808 { return (bufIdx
>= bufSize
&& !fillBuf()) ? EOF
: buf
[bufIdx
]; }
809 virtual GString
*getPSFilter(int psLevel
, char *indent
) { return NULL
; }
810 virtual GBool
isBinary(GBool last
= gTrue
) { return gTrue
; }
811 virtual GBool
isEncoder() { return gTrue
; }
818 GfxImageColorMap
*colorMap
;
821 int buf
[gfxColorMaxComps
];
827 DeviceNRecoder::DeviceNRecoder(Stream
*strA
, int widthA
, int heightA
,
828 GfxImageColorMap
*colorMapA
):
832 colorMap
= colorMapA
;
835 bufIdx
= gfxColorMaxComps
;
836 bufSize
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
837 getAlt()->getNComps();
838 func
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
839 getTintTransformFunc();
842 DeviceNRecoder::~DeviceNRecoder() {
848 void DeviceNRecoder::reset() {
849 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
850 colorMap
->getBits());
854 GBool
DeviceNRecoder::fillBuf() {
855 Guchar pixBuf
[gfxColorMaxComps
];
857 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
860 if (pixelIdx
>= width
* height
) {
863 imgStr
->getPixel(pixBuf
);
864 colorMap
->getColor(pixBuf
, &color
);
866 i
< ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->getNComps();
868 x
[i
] = colToDbl(color
.c
[i
]);
870 func
->transform(x
, y
);
871 for (i
= 0; i
< bufSize
; ++i
) {
872 buf
[i
] = (int)(y
[i
] * 255 + 0.5);
879 //------------------------------------------------------------------------
881 //------------------------------------------------------------------------
884 typedef void (*SignalFunc
)(int);
887 static void outputToFile(void *stream
, char *data
, int len
) {
888 fwrite(data
, 1, len
, (FILE *)stream
);
891 PSOutputDev::PSOutputDev(char *fileName
, XRef
*xrefA
, Catalog
*catalog
,
892 int firstPage
, int lastPage
, PSOutMode modeA
,
893 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
894 GBool manualCtrlA
, const char *pageRangesA
) {
896 PSFileType fileTypeA
;
899 underlayCbkData
= NULL
;
901 overlayCbkData
= NULL
;
905 fontFileNames
= NULL
;
910 haveTextClip
= gFalse
;
914 if (!strcmp(fileName
, "-")) {
915 fileTypeA
= psStdout
;
917 } else if (fileName
[0] == '|') {
921 signal(SIGPIPE
, (SignalFunc
)SIG_IGN
);
923 if (!(f
= popen(fileName
+ 1, "w"))) {
924 error(-1, "Couldn't run print command '%s'", fileName
);
929 error(-1, "Print commands are not supported ('%s')", fileName
);
935 if (!(f
= fopen(fileName
, "w"))) {
936 error(-1, "Couldn't open PostScript file '%s'", fileName
);
942 init(outputToFile
, f
, fileTypeA
,
943 xrefA
, catalog
, firstPage
, lastPage
, modeA
,
944 imgLLXA
, imgLLYA
, imgURXA
, imgURYA
, manualCtrlA
, pageRangesA
);
947 PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA
, void *outputStreamA
,
948 XRef
*xrefA
, Catalog
*catalog
,
949 int firstPage
, int lastPage
, PSOutMode modeA
,
950 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
951 GBool manualCtrlA
, const char *pageRangesA
) {
953 underlayCbkData
= NULL
;
955 overlayCbkData
= NULL
;
959 fontFileNames
= NULL
;
964 haveTextClip
= gFalse
;
967 init(outputFuncA
, outputStreamA
, psGeneric
,
968 xrefA
, catalog
, firstPage
, lastPage
, modeA
,
969 imgLLXA
, imgLLYA
, imgURXA
, imgURYA
, manualCtrlA
, pageRangesA
);
972 void PSOutputDev::init(PSOutputFunc outputFuncA
, void *outputStreamA
,
973 PSFileType fileTypeA
, XRef
*xrefA
, Catalog
*catalog
,
974 int firstPage
, int lastPage
, PSOutMode modeA
,
975 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
976 GBool manualCtrlA
, const char *pageRangesA
) {
982 outputFunc
= outputFuncA
;
983 outputStream
= outputStreamA
;
984 fileType
= fileTypeA
;
986 level
= globalParams
->getPSLevel();
988 paperWidth
= globalParams
->getPSPaperWidth();
989 paperHeight
= globalParams
->getPSPaperHeight();
994 pageRanges
= pageRangesA
;
995 if (imgLLX
== 0 && imgURX
== 0 && imgLLY
== 0 && imgURY
== 0) {
996 globalParams
->getPSImageableArea(&imgLLX
, &imgLLY
, &imgURX
, &imgURY
);
998 if (paperWidth
< 0 || paperHeight
< 0) {
999 // this check is needed in case the document has zero pages
1000 if (firstPage
> 0 && firstPage
<= catalog
->getNumPages()) {
1001 page
= catalog
->getPage(firstPage
);
1002 paperWidth
= (int)ceil(page
->getMediaWidth());
1003 paperHeight
= (int)ceil(page
->getMediaHeight());
1008 imgLLX
= imgLLY
= 0;
1009 imgURX
= paperWidth
;
1010 imgURY
= paperHeight
;
1012 manualCtrl
= manualCtrlA
;
1013 if (mode
== psModeForm
) {
1014 lastPage
= firstPage
;
1017 inType3Char
= gFalse
;
1020 // initialize OPI nesting levels
1026 xScale0
= yScale0
= 0;
1028 clipLLX0
= clipLLY0
= 0;
1029 clipURX0
= clipURY0
= -1;
1031 // initialize fontIDs, fontFileIDs, and fontFileNames lists
1034 fontIDs
= (Ref
*)gmallocn(fontIDSize
, sizeof(Ref
));
1035 fontFileIDSize
= 64;
1037 fontFileIDs
= (Ref
*)gmallocn(fontFileIDSize
, sizeof(Ref
));
1038 fontFileNameSize
= 64;
1039 fontFileNameLen
= 0;
1040 fontFileNames
= (GString
**)gmallocn(fontFileNameSize
, sizeof(GString
*));
1041 nextTrueTypeNum
= 0;
1045 xobjStack
= new GList();
1047 numTilingPatterns
= 0;
1050 // initialize embedded font resource comment list
1051 embFontList
= new GString();
1054 // this check is needed in case the document has zero pages
1055 if (firstPage
> 0 && firstPage
<= catalog
->getNumPages()) {
1056 writeHeader(firstPage
, lastPage
,
1057 catalog
->getPage(firstPage
)->getMediaBox(),
1058 catalog
->getPage(firstPage
)->getCropBox(),
1059 catalog
->getPage(firstPage
)->getRotate());
1061 box
= new PDFRectangle(0, 0, 1, 1);
1062 writeHeader(firstPage
, lastPage
, box
, box
, 0);
1065 if (mode
!= psModeForm
) {
1066 writePS("%%BeginProlog\n");
1069 if (mode
!= psModeForm
) {
1070 writePS("%%EndProlog\n");
1071 writePS("%%BeginSetup\n");
1073 writeDocSetup(catalog
, firstPage
, lastPage
);
1074 if (mode
!= psModeForm
) {
1075 writePS("%%EndSetup\n");
1079 // initialize sequential page number
1083 PSOutputDev::~PSOutputDev() {
1084 PSOutCustomColor
*cc
;
1089 writePS("%%Trailer\n");
1091 if (mode
!= psModeForm
) {
1095 if (fileType
== psFile
) {
1097 ICS_MapRefNumAndAssign((short)((FILE *)outputStream
)->handle
);
1099 fclose((FILE *)outputStream
);
1102 else if (fileType
== psPipe
) {
1103 pclose((FILE *)outputStream
);
1105 signal(SIGPIPE
, (SignalFunc
)SIG_DFL
);
1119 if (fontFileNames
) {
1120 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1121 delete fontFileNames
[i
];
1123 gfree(fontFileNames
);
1126 for (i
= 0; i
< font16EncLen
; ++i
) {
1127 delete font16Enc
[i
].enc
;
1134 while (customColors
) {
1136 customColors
= cc
->next
;
1141 void PSOutputDev::writeHeader(int firstPage
, int lastPage
,
1142 PDFRectangle
*mediaBox
, PDFRectangle
*cropBox
,
1145 double x1
, y1
, x2
, y2
;
1151 writePS("%!PS-Adobe-3.0\n");
1154 writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
1157 writePS("%!PS-Adobe-3.0 Resource-Form\n");
1161 // Tell CUPS pstops filter not to do its own rotation...
1162 int cups_rotate
= 0;
1163 int width
= (int)ceil(mediaBox
->x2
- mediaBox
->x1
);
1164 int height
= (int)ceil(mediaBox
->y2
- mediaBox
->y1
);
1165 int imgWidth
= (int)ceil(cropBox
->x2
- cropBox
->x1
);
1167 if (width
> height
&& width
> imgWidth
) cups_rotate
= 90;
1169 writePSFmt("%%cupsRotation: %d\n", cups_rotate
);
1171 writePSFmt("%%Producer: xpdf/pdftops %s\n", xpdfVersion
);
1172 xref
->getDocInfo(&info
);
1173 if (info
.isDict() && info
.dictLookup("Creator", &obj1
)->isString()) {
1174 writePS("%%Creator: ");
1175 s
= obj1
.getString();
1176 if ((s
->getChar(0) & 0xff) == 0xfe &&
1177 (s
->getChar(1) & 0xff) == 0xff) {
1178 // Convert UTF-16 to UTF-8...
1179 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1180 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1182 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1183 // Multi-word UTF-16 char...
1185 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1187 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1189 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1195 * Single byte ASCII...
1200 else if (ch
< 0x800)
1206 writePSChar(0xc0 | (ch
>> 6));
1207 writePSChar(0x80 | (ch
& 0x3f));
1209 else if (ch
< 0x10000)
1212 * Three-byte UTF-8...
1215 writePSChar(0xe0 | (ch
>> 12));
1216 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1217 writePSChar(0x80 | (ch
& 0x3f));
1222 * Four-byte UTF-8...
1225 writePSChar(0xf0 | (ch
>> 18));
1226 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1227 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1228 writePSChar(0x80 | (ch
& 0x3f));
1232 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1233 writePSChar(s
->getChar(i
));
1239 if (info
.isDict() && info
.dictLookup("Title", &obj1
)->isString()) {
1240 writePS("%%Title: ");
1241 s
= obj1
.getString();
1242 if ((s
->getChar(0) & 0xff) == 0xfe &&
1243 (s
->getChar(1) & 0xff) == 0xff) {
1244 // Convert UTF-16 to UTF-8...
1245 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1246 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1248 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1249 // Multi-word UTF-16 char...
1251 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1253 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1255 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1261 * Single byte ASCII...
1266 else if (ch
< 0x800)
1272 writePSChar(0xc0 | (ch
>> 6));
1273 writePSChar(0x80 | (ch
& 0x3f));
1275 else if (ch
< 0x10000)
1278 * Three-byte UTF-8...
1281 writePSChar(0xe0 | (ch
>> 12));
1282 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1283 writePSChar(0x80 | (ch
& 0x3f));
1288 * Four-byte UTF-8...
1291 writePSChar(0xf0 | (ch
>> 18));
1292 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1293 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1294 writePSChar(0x80 | (ch
& 0x3f));
1298 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1299 writePSChar(s
->getChar(i
));
1306 writePSFmt("%%%%LanguageLevel: %d\n",
1307 (level
== psLevel1
|| level
== psLevel1Sep
) ? 1 :
1308 (level
== psLevel2
|| level
== psLevel2Sep
) ? 2 : 3);
1309 if (level
== psLevel1Sep
|| level
== psLevel2Sep
|| level
== psLevel3Sep
) {
1310 writePS("%%DocumentProcessColors: (atend)\n");
1311 writePS("%%DocumentCustomColors: (atend)\n");
1313 writePS("%%DocumentSuppliedResources: (atend)\n");
1317 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
1318 paperWidth
, paperHeight
);
1319 writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth
, paperHeight
);
1320 writePSFmt("%%%%Pages: %d\n", lastPage
- firstPage
+ 1);
1321 writePS("%%EndComments\n");
1322 writePS("%%BeginDefaults\n");
1323 writePS("%%PageMedia: plain\n");
1324 writePS("%%EndDefaults\n");
1327 epsX1
= cropBox
->x1
;
1328 epsY1
= cropBox
->y1
;
1329 epsX2
= cropBox
->x2
;
1330 epsY2
= cropBox
->y2
;
1331 if (pageRotate
== 0 || pageRotate
== 180) {
1336 } else { // pageRotate == 90 || pageRotate == 270
1342 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
1343 (int)floor(x1
), (int)floor(y1
), (int)ceil(x2
), (int)ceil(y2
));
1344 if (floor(x1
) != ceil(x1
) || floor(y1
) != ceil(y1
) ||
1345 floor(x2
) != ceil(x2
) || floor(y2
) != ceil(y2
)) {
1346 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1
, y1
, x2
, y2
);
1348 writePS("%%EndComments\n");
1351 writePS("%%EndComments\n");
1352 writePS("32 dict dup begin\n");
1353 writePSFmt("/BBox [%d %d %d %d] def\n",
1354 (int)floor(mediaBox
->x1
), (int)floor(mediaBox
->y1
),
1355 (int)ceil(mediaBox
->x2
), (int)ceil(mediaBox
->y2
));
1356 writePS("/FormType 1 def\n");
1357 writePS("/Matrix [1 0 0 1 0 0] def\n");
1362 void PSOutputDev::writeXpdfProcset() {
1363 GBool lev1
, lev2
, lev3
, sep
, nonSep
;
1367 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion
);
1368 lev1
= lev2
= lev3
= sep
= nonSep
= gTrue
;
1369 for (p
= prolog
; *p
; ++p
) {
1370 if ((*p
)[0] == '~') {
1371 lev1
= lev2
= lev3
= sep
= nonSep
= gFalse
;
1372 for (q
= *p
+ 1; *q
; ++q
) {
1374 case '1': lev1
= gTrue
; break;
1375 case '2': lev2
= gTrue
; break;
1376 case '3': lev3
= gTrue
; break;
1377 case 's': sep
= gTrue
; break;
1378 case 'n': nonSep
= gTrue
; break;
1381 } else if ((level
== psLevel1
&& lev1
&& nonSep
) ||
1382 (level
== psLevel1Sep
&& lev1
&& sep
) ||
1383 (level
== psLevel2
&& lev2
&& nonSep
) ||
1384 (level
== psLevel2Sep
&& lev2
&& sep
) ||
1385 (level
== psLevel3
&& lev3
&& nonSep
) ||
1386 (level
== psLevel3Sep
&& lev3
&& sep
)) {
1387 writePSFmt("%s\n", *p
);
1390 writePS("%%EndResource\n");
1392 if (level
>= psLevel3
) {
1393 for (p
= cmapProlog
; *p
; ++p
) {
1394 writePSFmt("%s\n", *p
);
1399 void PSOutputDev::writeDocSetup(Catalog
*catalog
,
1400 int firstPage
, int lastPage
) {
1407 if (mode
== psModeForm
) {
1408 // swap the form and xpdf dicts
1409 writePS("xpdf end begin dup begin\n");
1411 writePS("xpdf begin\n");
1413 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
1414 page
= catalog
->getPage(pg
);
1415 if ((resDict
= page
->getResourceDict())) {
1416 setupResources(resDict
);
1418 annots
= new Annots(xref
, catalog
, page
->getAnnots(&obj1
));
1420 for (i
= 0; i
< annots
->getNumAnnots(); ++i
) {
1421 if (annots
->getAnnot(i
)->getAppearance(&obj1
)->isStream()) {
1422 obj1
.streamGetDict()->lookup("Resources", &obj2
);
1423 if (obj2
.isDict()) {
1424 setupResources(obj2
.getDict());
1432 if (mode
!= psModeForm
) {
1433 if (mode
!= psModeEPS
&& !manualCtrl
) {
1434 writePSFmt("%d %d %s pdfSetup\n",
1435 paperWidth
, paperHeight
,
1436 globalParams
->getPSDuplex() ? "true" : "false");
1439 if (globalParams
->getPSOPI()) {
1440 writePS("/opiMatrix matrix currentmatrix def\n");
1446 void PSOutputDev::writePageTrailer() {
1447 if (mode
!= psModeForm
) {
1448 writePS("pdfEndPage\n");
1452 void PSOutputDev::writeTrailer() {
1453 PSOutCustomColor
*cc
;
1455 if (mode
== psModeForm
) {
1456 writePS("/Foo exch /Form defineresource pop\n");
1459 writePS("%%DocumentSuppliedResources:\n");
1460 writePS(embFontList
->getCString());
1461 if (level
== psLevel1Sep
|| level
== psLevel2Sep
||
1462 level
== psLevel3Sep
) {
1463 writePS("%%DocumentProcessColors:");
1464 if (processColors
& psProcessCyan
) {
1467 if (processColors
& psProcessMagenta
) {
1468 writePS(" Magenta");
1470 if (processColors
& psProcessYellow
) {
1473 if (processColors
& psProcessBlack
) {
1477 writePS("%%DocumentCustomColors:");
1478 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1479 writePSFmt(" (%s)", cc
->name
->getCString());
1482 writePS("%%CMYKCustomColor:\n");
1483 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1484 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
1485 cc
->c
, cc
->m
, cc
->y
, cc
->k
, cc
->name
->getCString());
1491 void PSOutputDev::setupResources(Dict
*resDict
) {
1492 Object xObjDict
, xObjRef
, xObj
, patDict
, patRef
, pat
, resObj
;
1497 setupFonts(resDict
);
1498 setupImages(resDict
);
1500 //----- recursively scan XObjects
1501 resDict
->lookup("XObject", &xObjDict
);
1502 if (xObjDict
.isDict()) {
1503 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
1505 // avoid infinite recursion on XObjects
1507 if ((xObjDict
.dictGetValNF(i
, &xObjRef
)->isRef())) {
1508 ref0
= xObjRef
.getRef();
1509 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1510 ref1
= *(Ref
*)xobjStack
->get(j
);
1511 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1517 xobjStack
->append(&ref0
);
1522 // process the XObject's resource dictionary
1523 xObjDict
.dictGetVal(i
, &xObj
);
1524 if (xObj
.isStream()) {
1525 xObj
.streamGetDict()->lookup("Resources", &resObj
);
1526 if (resObj
.isDict()) {
1527 setupResources(resObj
.getDict());
1534 if (xObjRef
.isRef() && !skip
) {
1535 xobjStack
->del(xobjStack
->getLength() - 1);
1542 //----- recursively scan Patterns
1543 resDict
->lookup("Pattern", &patDict
);
1544 if (patDict
.isDict()) {
1545 inType3Char
= gTrue
;
1546 for (i
= 0; i
< patDict
.dictGetLength(); ++i
) {
1548 // avoid infinite recursion on Patterns
1550 if ((patDict
.dictGetValNF(i
, &patRef
)->isRef())) {
1551 ref0
= patRef
.getRef();
1552 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1553 ref1
= *(Ref
*)xobjStack
->get(j
);
1554 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1560 xobjStack
->append(&ref0
);
1565 // process the Pattern's resource dictionary
1566 patDict
.dictGetVal(i
, &pat
);
1567 if (pat
.isStream()) {
1568 pat
.streamGetDict()->lookup("Resources", &resObj
);
1569 if (resObj
.isDict()) {
1570 setupResources(resObj
.getDict());
1577 if (patRef
.isRef() && !skip
) {
1578 xobjStack
->del(xobjStack
->getLength() - 1);
1582 inType3Char
= gFalse
;
1587 void PSOutputDev::setupFonts(Dict
*resDict
) {
1590 GfxFontDict
*gfxFontDict
;
1595 resDict
->lookupNF("Font", &obj1
);
1597 obj1
.fetch(xref
, &obj2
);
1598 if (obj2
.isDict()) {
1600 gfxFontDict
= new GfxFontDict(xref
, &r
, obj2
.getDict());
1603 } else if (obj1
.isDict()) {
1604 gfxFontDict
= new GfxFontDict(xref
, NULL
, obj1
.getDict());
1607 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
1608 if ((font
= gfxFontDict
->getFont(i
))) {
1609 setupFont(font
, resDict
);
1617 void PSOutputDev::setupFont(GfxFont
*font
, Dict
*parentResDict
) {
1620 PSFontParam
*fontParam
;
1622 char type3Name
[64], buf
[16];
1632 // check if font is already set up
1633 for (i
= 0; i
< fontIDLen
; ++i
) {
1634 if (fontIDs
[i
].num
== font
->getID()->num
&&
1635 fontIDs
[i
].gen
== font
->getID()->gen
) {
1640 // add entry to fontIDs list
1641 if (fontIDLen
>= fontIDSize
) {
1643 fontIDs
= (Ref
*)greallocn(fontIDs
, fontIDSize
, sizeof(Ref
));
1645 fontIDs
[fontIDLen
++] = *font
->getID();
1650 // check for resident 8-bit font
1651 if (font
->getName() &&
1652 (fontParam
= globalParams
->getPSFont(font
->getName()))) {
1653 psName
= new GString(fontParam
->psFontName
->getCString());
1655 // check for embedded Type 1 font
1656 } else if (globalParams
->getPSEmbedType1() &&
1657 font
->getType() == fontType1
&&
1658 font
->getEmbeddedFontID(&fontFileID
)) {
1659 psName
= filterPSName(font
->getEmbeddedFontName());
1660 setupEmbeddedType1Font(&fontFileID
, psName
);
1662 // check for embedded Type 1C font
1663 } else if (globalParams
->getPSEmbedType1() &&
1664 font
->getType() == fontType1C
&&
1665 font
->getEmbeddedFontID(&fontFileID
)) {
1666 psName
= filterPSName(font
->getEmbeddedFontName());
1667 setupEmbeddedType1CFont(font
, &fontFileID
, psName
);
1669 // check for external Type 1 font file
1670 } else if (globalParams
->getPSEmbedType1() &&
1671 font
->getType() == fontType1
&&
1672 font
->getExtFontFile()) {
1673 // this assumes that the PS font name matches the PDF font name
1674 psName
= font
->getName()->copy();
1675 setupExternalType1Font(font
->getExtFontFile(), psName
);
1677 // check for embedded TrueType font
1678 } else if (globalParams
->getPSEmbedTrueType() &&
1679 font
->getType() == fontTrueType
&&
1680 font
->getEmbeddedFontID(&fontFileID
)) {
1681 psName
= filterPSName(font
->getEmbeddedFontName());
1682 setupEmbeddedTrueTypeFont(font
, &fontFileID
, psName
);
1684 // check for external TrueType font file
1685 } else if (globalParams
->getPSEmbedTrueType() &&
1686 font
->getType() == fontTrueType
&&
1687 font
->getExtFontFile()) {
1688 psName
= filterPSName(font
->getName());
1689 setupExternalTrueTypeFont(font
, psName
);
1691 // check for embedded CID PostScript font
1692 } else if (globalParams
->getPSEmbedCIDPostScript() &&
1693 font
->getType() == fontCIDType0C
&&
1694 font
->getEmbeddedFontID(&fontFileID
)) {
1695 psName
= filterPSName(font
->getEmbeddedFontName());
1696 setupEmbeddedCIDType0Font(font
, &fontFileID
, psName
);
1698 // check for embedded CID TrueType font
1699 } else if (globalParams
->getPSEmbedCIDTrueType() &&
1700 font
->getType() == fontCIDType2
&&
1701 font
->getEmbeddedFontID(&fontFileID
)) {
1702 psName
= filterPSName(font
->getEmbeddedFontName());
1703 //~ should check to see if font actually uses vertical mode
1704 setupEmbeddedCIDTrueTypeFont(font
, &fontFileID
, psName
, gTrue
);
1706 } else if (font
->getType() == fontType3
) {
1707 sprintf(type3Name
, "T3_%d_%d",
1708 font
->getID()->num
, font
->getID()->gen
);
1709 psName
= new GString(type3Name
);
1710 setupType3Font(font
, psName
, parentResDict
);
1712 // do 8-bit font substitution
1713 } else if (!font
->isCIDFont()) {
1715 name
= font
->getName();
1718 for (i
= 0; psFonts
[i
]; ++i
) {
1719 if (name
->cmp(psFonts
[i
]) == 0) {
1720 psName
= new GString(psFonts
[i
]);
1726 if (font
->isFixedWidth()) {
1728 } else if (font
->isSerif()) {
1733 if (font
->isBold()) {
1736 if (font
->isItalic()) {
1739 psName
= new GString(psSubstFonts
[i
].psName
);
1740 for (code
= 0; code
< 256; ++code
) {
1741 if ((charName
= ((Gfx8BitFont
*)font
)->getCharName(code
)) &&
1742 charName
[0] == 'm' && charName
[1] == '\0') {
1747 w1
= ((Gfx8BitFont
*)font
)->getWidth(code
);
1751 w2
= psSubstFonts
[i
].mWidth
;
1756 if (font
->getType() == fontType3
) {
1757 // This is a hack which makes it possible to substitute for some
1758 // Type 3 fonts. The problem is that it's impossible to know what
1759 // the base coordinate system used in the font is without actually
1760 // rendering the font.
1762 fm
= font
->getFontMatrix();
1764 ys
*= fm
[3] / fm
[0];
1771 // do 16-bit font substitution
1772 } else if ((fontParam
= globalParams
->
1773 getPSFont16(font
->getName(),
1774 ((GfxCIDFont
*)font
)->getCollection(),
1775 font
->getWMode()))) {
1777 psName
= fontParam
->psFontName
->copy();
1778 if (font16EncLen
>= font16EncSize
) {
1779 font16EncSize
+= 16;
1780 font16Enc
= (PSFont16Enc
*)greallocn(font16Enc
,
1781 font16EncSize
, sizeof(PSFont16Enc
));
1783 font16Enc
[font16EncLen
].fontID
= *font
->getID();
1784 font16Enc
[font16EncLen
].enc
= fontParam
->encoding
->copy();
1785 if ((uMap
= globalParams
->getUnicodeMap(font16Enc
[font16EncLen
].enc
))) {
1789 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1790 font16Enc
[font16EncLen
].enc
->getCString());
1793 // give up - can't do anything with this font
1795 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1796 font
->getName() ? font
->getName()->getCString() : "(unnamed)",
1797 ((GfxCIDFont
*)font
)->getCollection()
1798 ? ((GfxCIDFont
*)font
)->getCollection()->getCString()
1803 // generate PostScript code to set up the font
1804 if (font
->isCIDFont()) {
1805 if (level
== psLevel3
|| level
== psLevel3Sep
) {
1806 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
1807 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1810 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
1811 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1815 writePSFmt("/F%d_%d /%s %g %g\n",
1816 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1818 for (i
= 0; i
< 256; i
+= 8) {
1819 writePSFmt((i
== 0) ? "[ " : " ");
1820 for (j
= 0; j
< 8; ++j
) {
1821 if (font
->getType() == fontTrueType
&&
1823 !((Gfx8BitFont
*)font
)->getHasEncoding()) {
1824 sprintf(buf
, "c%02x", i
+j
);
1827 charName
= ((Gfx8BitFont
*)font
)->getCharName(i
+j
);
1828 // this is a kludge for broken PDF files that encode char 32
1830 if (i
+j
== 32 && charName
&& !strcmp(charName
, ".notdef")) {
1835 writePSName(charName
? charName
: (char *)".notdef");
1836 // the empty name is legal in PDF and PostScript, but PostScript
1837 // uses a double-slash (//...) for "immediately evaluated names",
1838 // so we need to add a space character here
1839 if (charName
&& !charName
[0]) {
1843 writePS((i
== 256-8) ? (char *)"]\n" : (char *)"\n");
1845 writePS("pdfMakeFont\n");
1851 void PSOutputDev::setupEmbeddedType1Font(Ref
*id
, GString
*psName
) {
1852 static char hexChar
[17] = "0123456789abcdef";
1853 Object refObj
, strObj
, obj1
, obj2
, obj3
;
1855 int length1
, length2
, length3
;
1861 // check if font is already embedded
1862 for (i
= 0; i
< fontFileIDLen
; ++i
) {
1863 if (fontFileIDs
[i
].num
== id
->num
&&
1864 fontFileIDs
[i
].gen
== id
->gen
)
1868 // add entry to fontFileIDs list
1869 if (fontFileIDLen
>= fontFileIDSize
) {
1870 fontFileIDSize
+= 64;
1871 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
1873 fontFileIDs
[fontFileIDLen
++] = *id
;
1875 // get the font stream and info
1876 refObj
.initRef(id
->num
, id
->gen
);
1877 refObj
.fetch(xref
, &strObj
);
1879 if (!strObj
.isStream()) {
1880 error(-1, "Embedded font file object is not a stream");
1883 if (!(dict
= strObj
.streamGetDict())) {
1884 error(-1, "Embedded font stream is missing its dictionary");
1887 dict
->lookup("Length1", &obj1
);
1888 dict
->lookup("Length2", &obj2
);
1889 dict
->lookup("Length3", &obj3
);
1890 if (!obj1
.isInt() || !obj2
.isInt() || !obj3
.isInt()) {
1891 error(-1, "Missing length fields in embedded font stream dictionary");
1897 length1
= obj1
.getInt();
1898 length2
= obj2
.getInt();
1899 length3
= obj3
.getInt();
1904 // beginning comment
1905 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1906 embFontList
->append("%%+ font ");
1907 embFontList
->append(psName
->getCString());
1908 embFontList
->append("\n");
1910 // copy ASCII portion of font
1911 strObj
.streamReset();
1912 for (i
= 0; i
< length1
&& (c
= strObj
.streamGetChar()) != EOF
; ++i
) {
1916 // figure out if encrypted portion is binary or ASCII
1918 for (i
= 0; i
< 4; ++i
) {
1919 start
[i
] = strObj
.streamGetChar();
1920 if (start
[i
] == EOF
) {
1921 error(-1, "Unexpected end of file in embedded font stream");
1924 if (!((start
[i
] >= '0' && start
[i
] <= '9') ||
1925 (start
[i
] >= 'A' && start
[i
] <= 'F') ||
1926 (start
[i
] >= 'a' && start
[i
] <= 'f')))
1930 // convert binary data to ASCII
1932 for (i
= 0; i
< 4; ++i
) {
1933 writePSChar(hexChar
[(start
[i
] >> 4) & 0x0f]);
1934 writePSChar(hexChar
[start
[i
] & 0x0f]);
1936 // if Length2 is incorrect (too small), font data gets chopped, so
1937 // we take a few extra characters from the trailer just in case
1938 // length2 += length3 >= 8 ? 8 : length3;
1939 while (i
< length2
) {
1940 if ((c
= strObj
.streamGetChar()) == EOF
) {
1943 writePSChar(hexChar
[(c
>> 4) & 0x0f]);
1944 writePSChar(hexChar
[c
& 0x0f]);
1945 if (++i
% 32 == 0) {
1953 // already in ASCII format -- just copy it
1955 for (i
= 0; i
< 4; ++i
) {
1956 writePSChar(start
[i
]);
1958 for (i
= 4; i
< length2
; ++i
) {
1959 if ((c
= strObj
.streamGetChar()) == EOF
) {
1966 // write padding and "cleartomark"
1967 for (i
= 0; i
< 8; ++i
) {
1968 writePS("00000000000000000000000000000000"
1969 "00000000000000000000000000000000\n");
1971 writePS("cleartomark\n");
1974 writePS("%%EndResource\n");
1977 strObj
.streamClose();
1981 //~ This doesn't handle .pfb files or binary eexec data (which only
1982 //~ happens in pfb files?).
1983 void PSOutputDev::setupExternalType1Font(GString
*fileName
, GString
*psName
) {
1988 // check if font is already embedded
1989 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1990 if (!fontFileNames
[i
]->cmp(fileName
)) {
1995 // add entry to fontFileNames list
1996 if (fontFileNameLen
>= fontFileNameSize
) {
1997 fontFileNameSize
+= 64;
1998 fontFileNames
= (GString
**)greallocn(fontFileNames
,
1999 fontFileNameSize
, sizeof(GString
*));
2001 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
2003 // beginning comment
2004 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2005 embFontList
->append("%%+ font ");
2006 embFontList
->append(psName
->getCString());
2007 embFontList
->append("\n");
2009 // copy the font file
2010 if (!(fontFile
= fopen(fileName
->getCString(), "rb"))) {
2011 error(-1, "Couldn't open external font file");
2014 while ((c
= fgetc(fontFile
)) != EOF
) {
2020 writePS("%%EndResource\n");
2023 void PSOutputDev::setupEmbeddedType1CFont(GfxFont
*font
, Ref
*id
,
2030 // check if font is already embedded
2031 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2032 if (fontFileIDs
[i
].num
== id
->num
&&
2033 fontFileIDs
[i
].gen
== id
->gen
)
2037 // add entry to fontFileIDs list
2038 if (fontFileIDLen
>= fontFileIDSize
) {
2039 fontFileIDSize
+= 64;
2040 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2042 fontFileIDs
[fontFileIDLen
++] = *id
;
2044 // beginning comment
2045 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2046 embFontList
->append("%%+ font ");
2047 embFontList
->append(psName
->getCString());
2048 embFontList
->append("\n");
2050 // convert it to a Type 1 font
2051 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2052 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2053 ffT1C
->convertToType1(NULL
, gTrue
, outputFunc
, outputStream
);
2059 writePS("%%EndResource\n");
2062 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont
*font
, Ref
*id
,
2071 // check if font is already embedded
2072 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2073 if (fontFileIDs
[i
].num
== id
->num
&&
2074 fontFileIDs
[i
].gen
== id
->gen
) {
2075 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2076 psName
->append(unique
);
2081 // add entry to fontFileIDs list
2082 if (i
== fontFileIDLen
) {
2083 if (fontFileIDLen
>= fontFileIDSize
) {
2084 fontFileIDSize
+= 64;
2085 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2087 fontFileIDs
[fontFileIDLen
++] = *id
;
2090 // beginning comment
2091 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2092 embFontList
->append("%%+ font ");
2093 embFontList
->append(psName
->getCString());
2094 embFontList
->append("\n");
2096 // convert it to a Type 42 font
2097 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2098 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2099 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2100 ffTT
->convertToType42(psName
->getCString(),
2101 ((Gfx8BitFont
*)font
)->getHasEncoding()
2102 ? ((Gfx8BitFont
*)font
)->getEncoding()
2104 codeToGID
, outputFunc
, outputStream
);
2111 writePS("%%EndResource\n");
2114 void PSOutputDev::setupExternalTrueTypeFont(GfxFont
*font
, GString
*psName
) {
2123 // check if font is already embedded
2124 fileName
= font
->getExtFontFile();
2125 for (i
= 0; i
< fontFileNameLen
; ++i
) {
2126 if (!fontFileNames
[i
]->cmp(fileName
)) {
2127 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2128 psName
->append(unique
);
2133 // add entry to fontFileNames list
2134 if (i
== fontFileNameLen
) {
2135 if (fontFileNameLen
>= fontFileNameSize
) {
2136 fontFileNameSize
+= 64;
2138 (GString
**)greallocn(fontFileNames
,
2139 fontFileNameSize
, sizeof(GString
*));
2141 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
2144 // beginning comment
2145 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2146 embFontList
->append("%%+ font ");
2147 embFontList
->append(psName
->getCString());
2148 embFontList
->append("\n");
2150 // convert it to a Type 42 font
2151 fontBuf
= font
->readExtFontFile(&fontLen
);
2152 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2153 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2154 ffTT
->convertToType42(psName
->getCString(),
2155 ((Gfx8BitFont
*)font
)->getHasEncoding()
2156 ? ((Gfx8BitFont
*)font
)->getEncoding()
2158 codeToGID
, outputFunc
, outputStream
);
2164 writePS("%%EndResource\n");
2167 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont
*font
, Ref
*id
,
2174 // check if font is already embedded
2175 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2176 if (fontFileIDs
[i
].num
== id
->num
&&
2177 fontFileIDs
[i
].gen
== id
->gen
)
2181 // add entry to fontFileIDs list
2182 if (fontFileIDLen
>= fontFileIDSize
) {
2183 fontFileIDSize
+= 64;
2184 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2186 fontFileIDs
[fontFileIDLen
++] = *id
;
2188 // beginning comment
2189 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2190 embFontList
->append("%%+ font ");
2191 embFontList
->append(psName
->getCString());
2192 embFontList
->append("\n");
2194 // convert it to a Type 0 font
2195 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2196 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2197 if (globalParams
->getPSLevel() >= psLevel3
) {
2198 // Level 3: use a CID font
2199 ffT1C
->convertToCIDType0(psName
->getCString(), outputFunc
, outputStream
);
2201 // otherwise: use a non-CID composite font
2202 ffT1C
->convertToType0(psName
->getCString(), outputFunc
, outputStream
);
2209 writePS("%%EndResource\n");
2212 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont
*font
, Ref
*id
,
2214 GBool needVerticalMetrics
) {
2221 // check if font is already embedded
2222 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2223 if (fontFileIDs
[i
].num
== id
->num
&&
2224 fontFileIDs
[i
].gen
== id
->gen
) {
2225 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2226 psName
->append(unique
);
2231 // add entry to fontFileIDs list
2232 if (fontFileIDLen
>= fontFileIDSize
) {
2233 fontFileIDSize
+= 64;
2234 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2236 fontFileIDs
[fontFileIDLen
++] = *id
;
2238 // beginning comment
2239 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2240 embFontList
->append("%%+ font ");
2241 embFontList
->append(psName
->getCString());
2242 embFontList
->append("\n");
2244 // convert it to a Type 0 font
2245 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2246 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2247 if (globalParams
->getPSLevel() >= psLevel3
) {
2248 // Level 3: use a CID font
2249 ffTT
->convertToCIDType2(psName
->getCString(),
2250 ((GfxCIDFont
*)font
)->getCIDToGID(),
2251 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2252 needVerticalMetrics
,
2253 outputFunc
, outputStream
);
2255 // otherwise: use a non-CID composite font
2256 ffTT
->convertToType0(psName
->getCString(),
2257 ((GfxCIDFont
*)font
)->getCIDToGID(),
2258 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2259 needVerticalMetrics
,
2260 outputFunc
, outputStream
);
2267 writePS("%%EndResource\n");
2270 void PSOutputDev::setupType3Font(GfxFont
*font
, GString
*psName
,
2271 Dict
*parentResDict
) {
2281 // set up resources used by font
2282 if ((resDict
= ((Gfx8BitFont
*)font
)->getResources())) {
2283 inType3Char
= gTrue
;
2284 setupResources(resDict
);
2285 inType3Char
= gFalse
;
2287 resDict
= parentResDict
;
2290 // beginning comment
2291 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2292 embFontList
->append("%%+ font ");
2293 embFontList
->append(psName
->getCString());
2294 embFontList
->append("\n");
2297 writePS("8 dict begin\n");
2298 writePS("/FontType 3 def\n");
2299 m
= font
->getFontMatrix();
2300 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
2301 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
2302 m
= font
->getFontBBox();
2303 writePSFmt("/FontBBox [%g %g %g %g] def\n",
2304 m
[0], m
[1], m
[2], m
[3]);
2305 writePS("/Encoding 256 array def\n");
2306 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2307 writePS("/BuildGlyph {\n");
2308 writePS(" exch /CharProcs get exch\n");
2309 writePS(" 2 copy known not { pop /.notdef } if\n");
2310 writePS(" get exec\n");
2311 writePS("} bind def\n");
2312 writePS("/BuildChar {\n");
2313 writePS(" 1 index /Encoding get exch get\n");
2314 writePS(" 1 index /BuildGlyph get exec\n");
2315 writePS("} bind def\n");
2316 if ((charProcs
= ((Gfx8BitFont
*)font
)->getCharProcs())) {
2317 writePSFmt("/CharProcs %d dict def\n", charProcs
->getLength());
2318 writePS("CharProcs begin\n");
2323 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
2324 inType3Char
= gTrue
;
2325 t3Cacheable
= gFalse
;
2326 for (i
= 0; i
< charProcs
->getLength(); ++i
) {
2328 writePSName(charProcs
->getKey(i
));
2330 gfx
->display(charProcs
->getVal(i
, &charProc
));
2334 sprintf(buf
, "%g %g %g %g %g %g setcachedevice\n",
2335 t3WX
, t3WY
, t3LLX
, t3LLY
, t3URX
, t3URY
);
2337 sprintf(buf
, "%g %g setcharwidth\n", t3WX
, t3WY
);
2339 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
2340 (*outputFunc
)(outputStream
, t3String
->getCString(),
2341 t3String
->getLength());
2345 (*outputFunc
)(outputStream
, "Q\n", 2);
2348 inType3Char
= gFalse
;
2352 writePS("currentdict end\n");
2353 writePSFmt("/%s exch definefont pop\n", psName
->getCString());
2356 writePS("%%EndResource\n");
2359 void PSOutputDev::setupImages(Dict
*resDict
) {
2360 Object xObjDict
, xObj
, xObjRef
, subtypeObj
;
2363 if (!(mode
== psModeForm
|| inType3Char
)) {
2367 resDict
->lookup("XObject", &xObjDict
);
2368 if (xObjDict
.isDict()) {
2369 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
2370 xObjDict
.dictGetValNF(i
, &xObjRef
);
2371 xObjDict
.dictGetVal(i
, &xObj
);
2372 if (xObj
.isStream()) {
2373 xObj
.streamGetDict()->lookup("Subtype", &subtypeObj
);
2374 if (subtypeObj
.isName("Image")) {
2375 if (xObjRef
.isRef()) {
2376 setupImage(xObjRef
.getRef(), xObj
.getStream());
2378 error(-1, "Image in resource dict is not an indirect reference");
2390 void PSOutputDev::setupImage(Ref id
, Stream
*str
) {
2393 int size
, line
, col
, i
;
2395 // construct an encoder stream
2396 useASCIIHex
= level
== psLevel1
|| level
== psLevel1Sep
||
2397 globalParams
->getPSASCIIHex();
2399 str
= new ASCIIHexEncoder(str
);
2401 str
= new ASCII85Encoder(str
);
2404 // compute image data size
2410 } while (c
== '\n' || c
== '\r');
2411 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2418 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2421 } while (c
== '\n' || c
== '\r');
2422 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2432 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2434 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size
, id
.num
, id
.gen
);
2437 // write the data into the array
2440 writePS((char *)(useASCIIHex
? "dup 0 <" : "dup 0 <~"));
2444 } while (c
== '\n' || c
== '\r');
2445 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2454 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2457 } while (c
== '\n' || c
== '\r');
2458 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2465 // each line is: "dup nnnnn <~...data...~> put<eol>"
2466 // so max data length = 255 - 20 = 235
2467 // chunks are 1 or 4 bytes each, so we have to stop at 232
2468 // but make it 225 just to be safe
2470 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2472 writePSFmt((char *)(useASCIIHex
? "dup %d <" : "dup %d <~"), line
);
2475 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2476 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2483 GBool
PSOutputDev::startPage(int pageNum
, GfxState
*state
) {
2484 int x1
, y1
, x2
, y2
, width
, height
;
2485 int imgWidth
, imgHeight
, imgWidth2
, imgHeight2
;
2489 if (mode
== psModePS
) {
2490 writePSFmt("%%%%Page: %d %d\n", pageNum
, seqPage
);
2491 writePS("%%BeginPageSetup\n");
2496 (*underlayCbk
)(this, underlayCbkData
);
2505 // rotate, translate, and scale page
2506 imgWidth
= imgURX
- imgLLX
;
2507 imgHeight
= imgURY
- imgLLY
;
2508 x1
= (int)floor(state
->getX1());
2509 y1
= (int)floor(state
->getY1());
2510 x2
= (int)ceil(state
->getX2());
2511 y2
= (int)ceil(state
->getY2());
2515 // rotation and portrait/landscape mode
2517 rotate
= (360 - rotate0
) % 360;
2520 rotate
= (360 - state
->getRotate()) % 360;
2522 fprintf(stderr
, "DEBUG: Page rotate=%d, width=%d, height=%d, imgWidth=%d, imgHeight=%d\n",
2523 state
->getRotate(), width
, height
, imgWidth
, imgHeight
);
2525 if (rotate
== 0 || rotate
== 180) {
2526 if (width
> height
&& width
> imgWidth
) {
2532 } else { // rotate == 90 || rotate == 270
2533 if (height
> width
&& height
> imgWidth
) {
2534 rotate
= 270 - rotate
;
2542 writePSFmt("%%%%PageOrientation: %s\n",
2543 landscape
? "Landscape" : "Portrait");
2544 writePS("pdfStartPage\n");
2546 imgWidth2
= imgWidth
;
2547 imgHeight2
= imgHeight
;
2548 } else if (rotate
== 90) {
2549 writePS("90 rotate\n");
2551 imgWidth2
= imgHeight
;
2552 imgHeight2
= imgWidth
;
2553 } else if (rotate
== 180) {
2554 writePS("180 rotate\n");
2555 imgWidth2
= imgWidth
;
2556 imgHeight2
= imgHeight
;
2559 } else { // rotate == 270
2560 writePS("270 rotate\n");
2562 imgWidth2
= imgHeight
;
2563 imgHeight2
= imgWidth
;
2566 if (xScale0
> 0 && yScale0
> 0) {
2569 } else if ((globalParams
->getPSShrinkLarger() &&
2570 (width
> imgWidth2
|| height
> imgHeight2
)) ||
2571 (globalParams
->getPSExpandSmaller() &&
2572 (width
< imgWidth2
&& height
< imgHeight2
))) {
2573 xScale
= (double)imgWidth2
/ (double)width
;
2574 yScale
= (double)imgHeight2
/ (double)height
;
2575 if (yScale
< xScale
) {
2581 xScale
= yScale
= 1;
2583 paperHeight
= height
;
2586 // deal with odd bounding boxes or clipping
2587 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2588 tx
-= xScale
* clipLLX0
;
2589 ty
-= yScale
* clipLLY0
;
2595 if (globalParams
->getPSCenter()) {
2596 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2597 tx
+= (imgWidth2
- xScale
* (clipURX0
- clipLLX0
)) / 2;
2598 ty
+= (imgHeight2
- yScale
* (clipURY0
- clipLLY0
)) / 2;
2600 tx
+= (imgWidth2
- xScale
* width
) / 2;
2601 ty
+= (imgHeight2
- yScale
* height
) / 2;
2604 tx
+= rotate
== 0 ? imgLLX
+ tx0
: imgLLY
+ ty0
;
2605 ty
+= rotate
== 0 ? imgLLY
+ ty0
: -(imgLLX
+ tx0
);
2606 if (tx
!= 0 || ty
!= 0) {
2607 writePSFmt("%g %g translate\n", tx
, ty
);
2609 if (xScale
!= 1 || yScale
!= 1) {
2610 writePSFmt("%0.4f %0.4f scale\n", xScale
, xScale
);
2612 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2613 writePSFmt("%g %g %g %g re W\n",
2614 clipLLX0
, clipLLY0
, clipURX0
- clipLLX0
, clipURY0
- clipLLY0
);
2616 writePSFmt("%d %d %d %d re W\n", x1
, y1
, x2
- x1
, y2
- y1
);
2619 writePS("%%EndPageSetup\n");
2624 writePS("pdfStartPage\n");
2626 rotate
= (360 - state
->getRotate()) % 360;
2628 } else if (rotate
== 90) {
2629 writePS("90 rotate\n");
2632 } else if (rotate
== 180) {
2633 writePS("180 rotate\n");
2634 tx
= -(epsX1
+ epsX2
);
2635 ty
= -(epsY1
+ epsY2
);
2636 } else { // rotate == 270
2637 writePS("270 rotate\n");
2641 if (tx
!= 0 || ty
!= 0) {
2642 writePSFmt("%g %g translate\n", tx
, ty
);
2644 xScale
= yScale
= 1;
2648 writePS("/PaintProc {\n");
2649 writePS("begin xpdf begin\n");
2650 writePS("pdfStartPage\n");
2652 xScale
= yScale
= 1;
2657 if (!checkRange(pageNum
))
2663 void PSOutputDev::endPage() {
2666 (*overlayCbk
)(this, overlayCbkData
);
2669 if (mode
== psModeForm
) {
2670 writePS("pdfEndPage\n");
2671 writePS("end end\n");
2673 writePS("end end\n");
2676 writePS("showpage\n");
2678 writePS("%%PageTrailer\n");
2683 void PSOutputDev::saveState(GfxState
*state
) {
2688 void PSOutputDev::restoreState(GfxState
*state
) {
2693 void PSOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
2694 double m21
, double m22
, double m31
, double m32
) {
2695 writePSFmt("[%g %g %g %g %g %g] cm\n", m11
, m12
, m21
, m22
, m31
, m32
);
2698 void PSOutputDev::updateLineDash(GfxState
*state
) {
2703 state
->getLineDash(&dash
, &length
, &start
);
2705 for (i
= 0; i
< length
; ++i
) {
2707 dash
[i
] == 0 ? 1 : dash
[i
],
2708 (i
== length
-1) ? "" : " ");
2710 writePSFmt("] %g d\n", start
);
2713 void PSOutputDev::updateFlatness(GfxState
*state
) {
2714 writePSFmt("%d i\n", state
->getFlatness());
2717 void PSOutputDev::updateLineJoin(GfxState
*state
) {
2718 writePSFmt("%d j\n", state
->getLineJoin());
2721 void PSOutputDev::updateLineCap(GfxState
*state
) {
2722 writePSFmt("%d J\n", state
->getLineCap());
2725 void PSOutputDev::updateMiterLimit(GfxState
*state
) {
2726 writePSFmt("%g M\n", state
->getMiterLimit());
2729 void PSOutputDev::updateLineWidth(GfxState
*state
) {
2730 writePSFmt("%g w\n", state
->getLineWidth());
2733 void PSOutputDev::updateFillColorSpace(GfxState
*state
) {
2740 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2741 dumpColorSpaceL2(state
->getFillColorSpace(), gTrue
, gFalse
);
2751 void PSOutputDev::updateStrokeColorSpace(GfxState
*state
) {
2758 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2759 dumpColorSpaceL2(state
->getStrokeColorSpace(), gTrue
, gFalse
);
2769 void PSOutputDev::updateFillColor(GfxState
*state
) {
2774 GfxSeparationColorSpace
*sepCS
;
2780 state
->getFillGray(&gray
);
2781 writePSFmt("%g g\n", colToDbl(gray
));
2784 state
->getFillCMYK(&cmyk
);
2785 c
= colToDbl(cmyk
.c
);
2786 m
= colToDbl(cmyk
.m
);
2787 y
= colToDbl(cmyk
.y
);
2788 k
= colToDbl(cmyk
.k
);
2789 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2790 addProcessColor(c
, m
, y
, k
);
2794 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2795 colorPtr
= state
->getFillColor();
2797 for (i
= 0; i
< state
->getFillColorSpace()->getNComps(); ++i
) {
2801 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2808 if (state
->getFillColorSpace()->getMode() == csSeparation
) {
2809 sepCS
= (GfxSeparationColorSpace
*)state
->getFillColorSpace();
2810 color
.c
[0] = gfxColorComp1
;
2811 sepCS
->getCMYK(&color
, &cmyk
);
2812 writePSFmt("%g %g %g %g %g (%s) ck\n",
2813 colToDbl(state
->getFillColor()->c
[0]),
2814 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2815 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2816 sepCS
->getName()->getCString());
2817 addCustomColor(sepCS
);
2819 state
->getFillCMYK(&cmyk
);
2820 c
= colToDbl(cmyk
.c
);
2821 m
= colToDbl(cmyk
.m
);
2822 y
= colToDbl(cmyk
.y
);
2823 k
= colToDbl(cmyk
.k
);
2824 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2825 addProcessColor(c
, m
, y
, k
);
2829 t3Cacheable
= gFalse
;
2832 void PSOutputDev::updateStrokeColor(GfxState
*state
) {
2837 GfxSeparationColorSpace
*sepCS
;
2843 state
->getStrokeGray(&gray
);
2844 writePSFmt("%g G\n", colToDbl(gray
));
2847 state
->getStrokeCMYK(&cmyk
);
2848 c
= colToDbl(cmyk
.c
);
2849 m
= colToDbl(cmyk
.m
);
2850 y
= colToDbl(cmyk
.y
);
2851 k
= colToDbl(cmyk
.k
);
2852 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2853 addProcessColor(c
, m
, y
, k
);
2857 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2858 colorPtr
= state
->getStrokeColor();
2860 for (i
= 0; i
< state
->getStrokeColorSpace()->getNComps(); ++i
) {
2864 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2871 if (state
->getStrokeColorSpace()->getMode() == csSeparation
) {
2872 sepCS
= (GfxSeparationColorSpace
*)state
->getStrokeColorSpace();
2873 color
.c
[0] = gfxColorComp1
;
2874 sepCS
->getCMYK(&color
, &cmyk
);
2875 writePSFmt("%g %g %g %g %g (%s) CK\n",
2876 colToDbl(state
->getStrokeColor()->c
[0]),
2877 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2878 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2879 sepCS
->getName()->getCString());
2880 addCustomColor(sepCS
);
2882 state
->getStrokeCMYK(&cmyk
);
2883 c
= colToDbl(cmyk
.c
);
2884 m
= colToDbl(cmyk
.m
);
2885 y
= colToDbl(cmyk
.y
);
2886 k
= colToDbl(cmyk
.k
);
2887 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2888 addProcessColor(c
, m
, y
, k
);
2892 t3Cacheable
= gFalse
;
2895 void PSOutputDev::addProcessColor(double c
, double m
, double y
, double k
) {
2897 processColors
|= psProcessCyan
;
2900 processColors
|= psProcessMagenta
;
2903 processColors
|= psProcessYellow
;
2906 processColors
|= psProcessBlack
;
2910 void PSOutputDev::addCustomColor(GfxSeparationColorSpace
*sepCS
) {
2911 PSOutCustomColor
*cc
;
2915 for (cc
= customColors
; cc
; cc
= cc
->next
) {
2916 if (!cc
->name
->cmp(sepCS
->getName())) {
2920 color
.c
[0] = gfxColorComp1
;
2921 sepCS
->getCMYK(&color
, &cmyk
);
2922 cc
= new PSOutCustomColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2923 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2924 sepCS
->getName()->copy());
2925 cc
->next
= customColors
;
2929 void PSOutputDev::updateFillOverprint(GfxState
*state
) {
2930 if (level
>= psLevel2
) {
2931 writePSFmt("%s op\n", state
->getFillOverprint() ? "true" : "false");
2935 void PSOutputDev::updateStrokeOverprint(GfxState
*state
) {
2936 if (level
>= psLevel2
) {
2937 writePSFmt("%s OP\n", state
->getStrokeOverprint() ? "true" : "false");
2941 void PSOutputDev::updateFont(GfxState
*state
) {
2942 if (state
->getFont()) {
2943 writePSFmt("/F%d_%d %g Tf\n",
2944 state
->getFont()->getID()->num
, state
->getFont()->getID()->gen
,
2945 fabs(state
->getFontSize()) < 0.00001 ? 0.00001
2946 : state
->getFontSize());
2950 void PSOutputDev::updateTextMat(GfxState
*state
) {
2953 mat
= state
->getTextMat();
2954 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.00001) {
2955 // avoid a singular (or close-to-singular) matrix
2956 writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat
[4], mat
[5]);
2958 writePSFmt("[%g %g %g %g %g %g] Tm\n",
2959 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
2963 void PSOutputDev::updateCharSpace(GfxState
*state
) {
2964 writePSFmt("%g Tc\n", state
->getCharSpace());
2967 void PSOutputDev::updateRender(GfxState
*state
) {
2970 rm
= state
->getRender();
2971 writePSFmt("%d Tr\n", rm
);
2973 if (rm
!= 0 && rm
!= 3) {
2974 t3Cacheable
= gFalse
;
2978 void PSOutputDev::updateRise(GfxState
*state
) {
2979 writePSFmt("%g Ts\n", state
->getRise());
2982 void PSOutputDev::updateWordSpace(GfxState
*state
) {
2983 writePSFmt("%g Tw\n", state
->getWordSpace());
2986 void PSOutputDev::updateHorizScaling(GfxState
*state
) {
2989 h
= state
->getHorizScaling();
2990 if (fabs(h
) < 0.01) {
2993 writePSFmt("%g Tz\n", h
);
2996 void PSOutputDev::updateTextPos(GfxState
*state
) {
2997 writePSFmt("%g %g Td\n", state
->getLineX(), state
->getLineY());
3000 void PSOutputDev::updateTextShift(GfxState
*state
, double shift
) {
3001 if (state
->getFont()->getWMode()) {
3002 writePSFmt("%g TJmV\n", shift
);
3004 writePSFmt("%g TJm\n", shift
);
3008 void PSOutputDev::stroke(GfxState
*state
) {
3009 doPath(state
->getPath());
3011 // if we're construct a cacheable Type 3 glyph, we need to do
3012 // everything in the fill color
3019 void PSOutputDev::fill(GfxState
*state
) {
3020 doPath(state
->getPath());
3024 void PSOutputDev::eoFill(GfxState
*state
) {
3025 doPath(state
->getPath());
3029 void PSOutputDev::tilingPatternFill(GfxState
*state
, Object
*str
,
3030 int paintType
, Dict
*resDict
,
3031 double *mat
, double *bbox
,
3032 int x0
, int y0
, int x1
, int y1
,
3033 double xStep
, double yStep
) {
3037 // define a Type 3 font
3038 writePS("8 dict begin\n");
3039 writePS("/FontType 3 def\n");
3040 writePS("/FontMatrix [1 0 0 1 0 0] def\n");
3041 writePSFmt("/FontBBox [%g %g %g %g] def\n",
3042 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3043 writePS("/Encoding 256 array def\n");
3044 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
3045 writePS(" Encoding 120 /x put\n");
3046 writePS("/BuildGlyph {\n");
3047 writePS(" exch /CharProcs get exch\n");
3048 writePS(" 2 copy known not { pop /.notdef } if\n");
3049 writePS(" get exec\n");
3050 writePS("} bind def\n");
3051 writePS("/BuildChar {\n");
3052 writePS(" 1 index /Encoding get exch get\n");
3053 writePS(" 1 index /BuildGlyph get exec\n");
3054 writePS("} bind def\n");
3055 writePS("/CharProcs 1 dict def\n");
3056 writePS("CharProcs begin\n");
3061 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
3063 if (paintType
== 2) {
3064 writePSFmt("%g 0 %g %g %g %g setcachedevice\n",
3065 xStep
, bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3067 writePSFmt("%g 0 setcharwidth\n", xStep
);
3069 inType3Char
= gTrue
;
3070 ++numTilingPatterns
;
3072 --numTilingPatterns
;
3073 inType3Char
= gFalse
;
3077 writePS("currentdict end\n");
3078 writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns
);
3081 writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns
);
3082 writePSFmt("gsave [%g %g %g %g %g %g] concat\n",
3083 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3084 writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n",
3085 y0
, y1
- 1, x0
* xStep
, yStep
, x0
, x1
- 1);
3086 writePS("grestore\n");
3089 void PSOutputDev::functionShadedFill(GfxState
*state
,
3090 GfxFunctionShading
*shading
) {
3091 double x0
, y0
, x1
, y1
;
3095 shading
->getDomain(&x0
, &y0
, &x1
, &y1
);
3096 mat
= shading
->getMatrix();
3097 writePSFmt("/mat [%g %g %g %g %g %g] def\n",
3098 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3099 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3100 if (shading
->getNFuncs() == 1) {
3102 cvtFunction(shading
->getFunc(0));
3105 writePS("/func {\n");
3106 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3107 if (i
< shading
->getNFuncs() - 1) {
3108 writePS("2 copy\n");
3110 cvtFunction(shading
->getFunc(i
));
3112 if (i
< shading
->getNFuncs() - 1) {
3113 writePS("3 1 roll\n");
3118 writePSFmt("%g %g %g %g 0 funcSH\n", x0
, y0
, x1
, y1
);
3121 void PSOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
) {
3122 double xMin
, yMin
, xMax
, yMax
;
3123 double x0
, y0
, x1
, y1
, dx
, dy
, mul
;
3124 double tMin
, tMax
, t
, t0
, t1
;
3127 // get the clip region bbox
3128 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3130 // compute min and max t values, based on the four corners of the
3132 shading
->getCoords(&x0
, &y0
, &x1
, &y1
);
3135 mul
= 1 / (dx
* dx
+ dy
* dy
);
3136 tMin
= tMax
= ((xMin
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3137 t
= ((xMin
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3140 } else if (t
> tMax
) {
3143 t
= ((xMax
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3146 } else if (t
> tMax
) {
3149 t
= ((xMax
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3152 } else if (t
> tMax
) {
3155 if (tMin
< 0 && !shading
->getExtend0()) {
3158 if (tMax
> 1 && !shading
->getExtend1()) {
3162 // get the function domain
3163 t0
= shading
->getDomain0();
3164 t1
= shading
->getDomain1();
3166 // generate the PS code
3167 writePSFmt("/t0 %g def\n", t0
);
3168 writePSFmt("/t1 %g def\n", t1
);
3169 writePSFmt("/dt %g def\n", t1
- t0
);
3170 writePSFmt("/x0 %g def\n", x0
);
3171 writePSFmt("/y0 %g def\n", y0
);
3172 writePSFmt("/dx %g def\n", x1
- x0
);
3173 writePSFmt("/x1 %g def\n", x1
);
3174 writePSFmt("/y1 %g def\n", y1
);
3175 writePSFmt("/dy %g def\n", y1
- y0
);
3176 writePSFmt("/xMin %g def\n", xMin
);
3177 writePSFmt("/yMin %g def\n", yMin
);
3178 writePSFmt("/xMax %g def\n", xMax
);
3179 writePSFmt("/yMax %g def\n", yMax
);
3180 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3181 if (shading
->getNFuncs() == 1) {
3183 cvtFunction(shading
->getFunc(0));
3186 writePS("/func {\n");
3187 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3188 if (i
< shading
->getNFuncs() - 1) {
3191 cvtFunction(shading
->getFunc(i
));
3193 if (i
< shading
->getNFuncs() - 1) {
3199 writePSFmt("%g %g 0 axialSH\n", tMin
, tMax
);
3202 void PSOutputDev::radialShadedFill(GfxState
*state
,
3203 GfxRadialShading
*shading
) {
3204 double x0
, y0
, r0
, x1
, y1
, r1
, t0
, t1
, sMin
, sMax
;
3205 double xMin
, yMin
, xMax
, yMax
;
3209 // get the shading info
3210 shading
->getCoords(&x0
, &y0
, &r0
, &x1
, &y1
, &r1
);
3211 t0
= shading
->getDomain0();
3212 t1
= shading
->getDomain1();
3214 // compute the (possibly extended) s range
3217 if (shading
->getExtend0()) {
3219 // extend the smaller end
3220 sMin
= -r0
/ (r1
- r0
);
3222 // extend the larger end
3223 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3224 d0
= (x0
- xMin
) * (x0
- xMin
);
3225 d1
= (x0
- xMax
) * (x0
- xMax
);
3226 sMin
= d0
> d1
? d0
: d1
;
3227 d0
= (y0
- yMin
) * (y0
- yMin
);
3228 d1
= (y0
- yMax
) * (y0
- yMax
);
3229 sMin
+= d0
> d1
? d0
: d1
;
3230 sMin
= (sqrt(sMin
) - r0
) / (r1
- r0
);
3233 } else if (sMin
< -20) {
3239 if (shading
->getExtend1()) {
3241 // extend the smaller end
3242 sMax
= -r0
/ (r1
- r0
);
3243 } else if (r1
> r0
) {
3244 // extend the larger end
3245 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3246 d0
= (x1
- xMin
) * (x1
- xMin
);
3247 d1
= (x1
- xMax
) * (x1
- xMax
);
3248 sMax
= d0
> d1
? d0
: d1
;
3249 d0
= (y1
- yMin
) * (y1
- yMin
);
3250 d1
= (y1
- yMax
) * (y1
- yMax
);
3251 sMax
+= d0
> d1
? d0
: d1
;
3252 sMax
= (sqrt(sMax
) - r0
) / (r1
- r0
);
3255 } else if (sMax
> 20) {
3262 // generate the PS code
3263 writePSFmt("/x0 %g def\n", x0
);
3264 writePSFmt("/x1 %g def\n", x1
);
3265 writePSFmt("/dx %g def\n", x1
- x0
);
3266 writePSFmt("/y0 %g def\n", y0
);
3267 writePSFmt("/y1 %g def\n", y1
);
3268 writePSFmt("/dy %g def\n", y1
- y0
);
3269 writePSFmt("/r0 %g def\n", r0
);
3270 writePSFmt("/r1 %g def\n", r1
);
3271 writePSFmt("/dr %g def\n", r1
- r0
);
3272 writePSFmt("/t0 %g def\n", t0
);
3273 writePSFmt("/t1 %g def\n", t1
);
3274 writePSFmt("/dt %g def\n", t1
- t0
);
3275 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3276 if (shading
->getNFuncs() == 1) {
3278 cvtFunction(shading
->getFunc(0));
3281 writePS("/func {\n");
3282 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3283 if (i
< shading
->getNFuncs() - 1) {
3286 cvtFunction(shading
->getFunc(i
));
3288 if (i
< shading
->getNFuncs() - 1) {
3294 writePSFmt("%g %g 0 radialSH\n", sMin
, sMax
);
3297 void PSOutputDev::clip(GfxState
*state
) {
3298 doPath(state
->getPath());
3302 void PSOutputDev::eoClip(GfxState
*state
) {
3303 doPath(state
->getPath());
3307 void PSOutputDev::doPath(GfxPath
*path
) {
3308 GfxSubpath
*subpath
;
3309 double x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
3312 n
= path
->getNumSubpaths();
3314 if (n
== 1 && path
->getSubpath(0)->getNumPoints() == 5) {
3315 subpath
= path
->getSubpath(0);
3316 x0
= subpath
->getX(0);
3317 y0
= subpath
->getY(0);
3318 x4
= subpath
->getX(4);
3319 y4
= subpath
->getY(4);
3320 if (x4
== x0
&& y4
== y0
) {
3321 x1
= subpath
->getX(1);
3322 y1
= subpath
->getY(1);
3323 x2
= subpath
->getX(2);
3324 y2
= subpath
->getY(2);
3325 x3
= subpath
->getX(3);
3326 y3
= subpath
->getY(3);
3327 if (x0
== x1
&& x2
== x3
&& y0
== y3
&& y1
== y2
) {
3328 writePSFmt("%g %g %g %g re\n",
3329 x0
< x2
? x0
: x2
, y0
< y1
? y0
: y1
,
3330 fabs(x2
- x0
), fabs(y1
- y0
));
3332 } else if (x0
== x3
&& x1
== x2
&& y0
== y1
&& y2
== y3
) {
3333 writePSFmt("%g %g %g %g re\n",
3334 x0
< x1
? x0
: x1
, y0
< y2
? y0
: y2
,
3335 fabs(x1
- x0
), fabs(y2
- y0
));
3341 for (i
= 0; i
< n
; ++i
) {
3342 subpath
= path
->getSubpath(i
);
3343 m
= subpath
->getNumPoints();
3344 writePSFmt("%g %g m\n", subpath
->getX(0), subpath
->getY(0));
3347 if (subpath
->getCurve(j
)) {
3348 writePSFmt("%g %g %g %g %g %g c\n", subpath
->getX(j
), subpath
->getY(j
),
3349 subpath
->getX(j
+1), subpath
->getY(j
+1),
3350 subpath
->getX(j
+2), subpath
->getY(j
+2));
3353 writePSFmt("%g %g l\n", subpath
->getX(j
), subpath
->getY(j
));
3357 if (subpath
->isClosed()) {
3363 void PSOutputDev::drawString(GfxState
*state
, GString
*s
) {
3367 double dx
, dy
, dx2
, dy2
, originX
, originY
;
3373 int len
, nChars
, uLen
, n
, m
, i
, j
;
3375 // check for invisible text -- this is used by Acrobat Capture
3376 if (state
->getRender() == 3) {
3380 // ignore empty strings
3381 if (s
->getLength() == 0) {
3386 if (!(font
= state
->getFont())) {
3389 wMode
= font
->getWMode();
3391 // check for a subtitute 16-bit font
3393 if (font
->isCIDFont()) {
3394 for (i
= 0; i
< font16EncLen
; ++i
) {
3395 if (font
->getID()->num
== font16Enc
[i
].fontID
.num
&&
3396 font
->getID()->gen
== font16Enc
[i
].fontID
.gen
) {
3397 uMap
= globalParams
->getUnicodeMap(font16Enc
[i
].enc
);
3403 // compute width of chars in string, ignoring char spacing and word
3404 // spacing -- the Tj operator will adjust for the metrics of the
3405 // font that's actually used
3408 p
= s
->getCString();
3409 len
= s
->getLength();
3410 if (font
->isCIDFont()) {
3416 n
= font
->getNextChar(p
, len
, &code
,
3417 u
, (int)(sizeof(u
) / sizeof(Unicode
)), &uLen
,
3418 &dx2
, &dy2
, &originX
, &originY
);
3419 if (font
->isCIDFont()) {
3421 for (i
= 0; i
< uLen
; ++i
) {
3422 m
= uMap
->mapUnicode(u
[i
], buf
, (int)sizeof(buf
));
3423 for (j
= 0; j
< m
; ++j
) {
3427 //~ this really needs to get the number of chars in the target
3428 //~ encoding - which may be more than the number of Unicode
3432 s2
->append((char)((code
>> 8) & 0xff));
3433 s2
->append((char)(code
& 0xff));
3442 dx
*= state
->getFontSize() * state
->getHorizScaling();
3443 dy
*= state
->getFontSize();
3448 if (s2
->getLength() > 0) {
3450 if (font
->isCIDFont()) {
3452 writePSFmt(" %d %g Tj16V\n", nChars
, dy
);
3454 writePSFmt(" %d %g Tj16\n", nChars
, dx
);
3457 writePSFmt(" %g Tj\n", dx
);
3460 if (font
->isCIDFont()) {
3464 if (state
->getRender() & 4) {
3465 haveTextClip
= gTrue
;
3469 void PSOutputDev::endTextObject(GfxState
*state
) {
3472 haveTextClip
= gFalse
;
3476 void PSOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
3477 int width
, int height
, GBool invert
,
3481 len
= height
* ((width
+ 7) / 8);
3482 if (level
== psLevel1
|| level
== psLevel1Sep
) {
3483 doImageL1(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
);
3485 doImageL2(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
,
3486 NULL
, NULL
, 0, 0, gFalse
);
3490 void PSOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3491 int width
, int height
, GfxImageColorMap
*colorMap
,
3492 int *maskColors
, GBool inlineImg
) {
3495 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3496 colorMap
->getBits() + 7) / 8);
3499 doImageL1(ref
, colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3502 //~ handle indexed, separation, ... color spaces
3503 doImageL1Sep(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3509 doImageL2(ref
, colorMap
, gFalse
, inlineImg
, str
,
3510 width
, height
, len
, maskColors
, NULL
, 0, 0, gFalse
);
3513 t3Cacheable
= gFalse
;
3516 void PSOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3517 int width
, int height
,
3518 GfxImageColorMap
*colorMap
,
3520 int maskWidth
, int maskHeight
,
3524 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3525 colorMap
->getBits() + 7) / 8);
3528 doImageL1(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3531 //~ handle indexed, separation, ... color spaces
3532 doImageL1Sep(colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3538 doImageL2(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
,
3539 NULL
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
3542 t3Cacheable
= gFalse
;
3545 void PSOutputDev::doImageL1(Object
*ref
, GfxImageColorMap
*colorMap
,
3546 GBool invert
, GBool inlineImg
,
3547 Stream
*str
, int width
, int height
, int len
) {
3548 ImageStream
*imgStr
;
3549 Guchar pixBuf
[gfxColorMaxComps
];
3551 int col
, x
, y
, c
, i
;
3553 if (inType3Char
&& !colorMap
) {
3556 str
= new FixedLengthEncoder(str
, len
);
3557 str
= new ASCIIHexEncoder(str
);
3564 } while (c
== '\n' || c
== '\r');
3565 if (c
== '>' || c
== EOF
) {
3570 // each line is: "<...data...><eol>"
3571 // so max data length = 255 - 4 = 251
3572 // but make it 240 just to be safe
3573 // chunks are 2 bytes each, so we need to stop on an even col number
3578 } while (c
!= '>' && c
!= EOF
);
3584 // set up to use the array already created by setupImages()
3585 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3589 // image/imagemask command
3590 if (inType3Char
&& !colorMap
) {
3591 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
3592 width
, height
, invert
? "true" : "false",
3593 width
, -height
, height
);
3594 } else if (colorMap
) {
3595 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
3597 width
, -height
, height
);
3599 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
3600 width
, height
, invert
? "true" : "false",
3601 width
, -height
, height
);
3605 if (!(inType3Char
&& !colorMap
)) {
3609 // set up to process the data stream
3610 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3611 colorMap
->getBits());
3614 // process the data stream
3616 for (y
= 0; y
< height
; ++y
) {
3619 for (x
= 0; x
< width
; ++x
) {
3620 imgStr
->getPixel(pixBuf
);
3621 colorMap
->getGray(pixBuf
, &gray
);
3622 writePSFmt("%02x", colToByte(gray
));
3638 for (y
= 0; y
< height
; ++y
) {
3639 for (x
= 0; x
< width
; x
+= 8) {
3640 writePSFmt("%02x", str
->getChar() & 0xff);
3655 void PSOutputDev::doImageL1Sep(GfxImageColorMap
*colorMap
,
3656 GBool invert
, GBool inlineImg
,
3657 Stream
*str
, int width
, int height
, int len
) {
3658 ImageStream
*imgStr
;
3660 Guchar pixBuf
[gfxColorMaxComps
];
3664 // width, height, matrix, bits per component
3665 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
3667 width
, -height
, height
);
3669 // allocate a line buffer
3670 lineBuf
= (Guchar
*)gmalloc(4 * width
);
3672 // set up to process the data stream
3673 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3674 colorMap
->getBits());
3677 // process the data stream
3679 for (y
= 0; y
< height
; ++y
) {
3682 for (x
= 0; x
< width
; ++x
) {
3683 imgStr
->getPixel(pixBuf
);
3684 colorMap
->getCMYK(pixBuf
, &cmyk
);
3685 lineBuf
[4*x
+0] = colToByte(cmyk
.c
);
3686 lineBuf
[4*x
+1] = colToByte(cmyk
.m
);
3687 lineBuf
[4*x
+2] = colToByte(cmyk
.y
);
3688 lineBuf
[4*x
+3] = colToByte(cmyk
.k
);
3689 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3690 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
3693 // write one line of each color component
3694 for (comp
= 0; comp
< 4; ++comp
) {
3695 for (x
= 0; x
< width
; ++x
) {
3696 writePSFmt("%02x", lineBuf
[4*x
+ comp
]);
3713 void PSOutputDev::doImageL2(Object
*ref
, GfxImageColorMap
*colorMap
,
3714 GBool invert
, GBool inlineImg
,
3715 Stream
*str
, int width
, int height
, int len
,
3716 int *maskColors
, Stream
*maskStr
,
3717 int maskWidth
, int maskHeight
, GBool maskInvert
) {
3718 ImageStream
*imgStr
;
3722 GBool useRLE
, useASCII
, useASCIIHex
, useCompressed
;
3723 GfxSeparationColorSpace
*sepCS
;
3727 int col
, i
, x
, x0
, y
, y0
, maskXor
;
3729 // color key masking
3730 if (maskColors
&& colorMap
&& !inlineImg
) {
3731 // can't read the stream twice for inline images -- but masking
3732 // isn't allowed with inline images anyway
3734 numComps
= colorMap
->getNumPixelComps();
3735 imgStr
= new ImageStream(str
, width
, numComps
, colorMap
->getBits());
3737 for (y
= 0, y0
= 0; y
< height
; ++y
) {
3738 if (!(line
= imgStr
->getLine())) {
3741 for (x
= 0, x0
= 0, pix
= line
; x
< width
; ++x
, pix
+= numComps
) {
3742 for (i
= 0; i
< numComps
; ++i
) {
3743 if (pix
[i
] < maskColors
[2*i
] ||
3744 pix
[i
] > maskColors
[2*i
+1]) {
3748 if (i
== numComps
) {
3750 writePSFmt("0 %d %d %d\n", height
- y
, width
, y
- y0
);
3753 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, x
- x0
);
3759 if (x0
> 0 && x0
< width
) {
3760 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, width
- x0
);
3764 writePSFmt("0 0 %d %d\n", width
, height
- y0
);
3768 writePSFmt("] %d %d pdfImClip\n", width
, height
);
3771 } else if (maskStr
) {
3773 imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3775 maskXor
= maskInvert
? 1 : 0;
3776 for (y
= 0, y0
= 0; y
< maskHeight
; ++y
) {
3777 if (!(line
= imgStr
->getLine())) {
3780 for (x
= 0, x0
= 0, pix
= line
; x
< maskWidth
; ++x
, ++pix
) {
3781 if (*pix
^ maskXor
) {
3783 writePSFmt("0 %d %d %d\n", maskHeight
- y
, maskWidth
, y
- y0
);
3786 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, x
- x0
);
3792 if (x0
> 0 && x0
< maskWidth
) {
3793 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, maskWidth
- x0
);
3796 if (y0
< maskHeight
) {
3797 writePSFmt("0 0 %d %d\n", maskWidth
, maskHeight
- y0
);
3801 writePSFmt("] %d %d pdfImClip\n", maskWidth
, maskHeight
);
3806 dumpColorSpaceL2(colorMap
->getColorSpace(), gFalse
, gTrue
);
3807 writePS(" setcolorspace\n");
3810 useASCIIHex
= globalParams
->getPSASCIIHex();
3812 // set up the image data
3813 if (mode
== psModeForm
|| inType3Char
) {
3816 str
= new FixedLengthEncoder(str
, len
);
3818 str
= new ASCIIHexEncoder(str
);
3820 str
= new ASCII85Encoder(str
);
3824 writePS((char *)(useASCIIHex
? "[<" : "[<~"));
3828 } while (c
== '\n' || c
== '\r');
3829 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3838 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
3841 } while (c
== '\n' || c
== '\r');
3842 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3849 // each line is: "<~...data...~><eol>"
3850 // so max data length = 255 - 6 = 249
3851 // chunks are 1 or 5 bytes each, so we have to stop at 245
3852 // but make it 240 just to be safe
3854 writePS((char *)(useASCIIHex
? ">\n<" : "~>\n<~"));
3857 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
3858 writePS((char *)(useASCIIHex
? ">]\n" : "~>]\n"));
3863 // set up to use the array already created by setupImages()
3864 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3869 writePS("<<\n /ImageType 1\n");
3871 // width, height, matrix, bits per component
3872 writePSFmt(" /Width %d\n", width
);
3873 writePSFmt(" /Height %d\n", height
);
3874 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width
, -height
, height
);
3875 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3876 writePSFmt(" /BitsPerComponent 8\n");
3878 writePSFmt(" /BitsPerComponent %d\n",
3879 colorMap
? colorMap
->getBits() : 1);
3884 writePS(" /Decode [");
3885 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) &&
3886 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3887 // this matches up with the code in the pdfImSep operator
3888 n
= (1 << colorMap
->getBits()) - 1;
3889 writePSFmt("%g %g", colorMap
->getDecodeLow(0) * n
,
3890 colorMap
->getDecodeHigh(0) * n
);
3891 } else if (colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3892 numComps
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
3893 getAlt()->getNComps();
3894 for (i
= 0; i
< numComps
; ++i
) {
3901 numComps
= colorMap
->getNumPixelComps();
3902 for (i
= 0; i
< numComps
; ++i
) {
3906 writePSFmt("%g %g", colorMap
->getDecodeLow(i
),
3907 colorMap
->getDecodeHigh(i
));
3912 writePSFmt(" /Decode [%d %d]\n", invert
? 1 : 0, invert
? 0 : 1);
3915 if (mode
== psModeForm
|| inType3Char
) {
3918 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
3920 // end of image dictionary
3921 writePSFmt(">>\n%s\n", colorMap
? "image" : "imagemask");
3923 // get rid of the array and index
3924 writePS("pop pop\n");
3929 writePS(" /DataSource currentfile\n");
3930 s
= str
->getPSFilter(level
< psLevel2
? 1 : level
< psLevel3
? 2 : 3,
3932 if ((colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) ||
3936 useCompressed
= gFalse
;
3939 useASCII
= str
->isBinary();
3940 useCompressed
= gTrue
;
3943 writePSFmt(" /ASCII%sDecode filter\n",
3944 useASCIIHex
? "Hex" : "85");
3947 writePS(" /RunLengthDecode filter\n");
3949 if (useCompressed
) {
3950 writePS(s
->getCString());
3956 // cut off inline image streams at appropriate length
3958 str
= new FixedLengthEncoder(str
, len
);
3959 } else if (useCompressed
) {
3960 str
= str
->getBaseStream();
3963 // recode DeviceN data
3964 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3965 str
= new DeviceNRecoder(str
, width
, height
, colorMap
);
3968 // add RunLengthEncode and ASCIIHex/85 encode filters
3970 str
= new RunLengthEncoder(str
);
3974 str
= new ASCIIHexEncoder(str
);
3976 str
= new ASCII85Encoder(str
);
3980 // end of image dictionary
3985 // this can't happen -- OPI dictionaries are in XObjects
3986 error(-1, "Internal: OPI in inline image");
3989 // need to read the stream to count characters -- the length
3990 // is data-dependent (because of ASCII and RLE filters)
3993 while ((c
= str
->getChar()) != EOF
) {
3998 // +6/7 for "pdfIm\n" / "pdfImM\n"
3999 // +8 for newline + trailer
4000 n
+= colorMap
? 14 : 15;
4001 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n
);
4004 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) && colorMap
&&
4005 colorMap
->getColorSpace()->getMode() == csSeparation
) {
4006 color
.c
[0] = gfxColorComp1
;
4007 sepCS
= (GfxSeparationColorSpace
*)colorMap
->getColorSpace();
4008 sepCS
->getCMYK(&color
, &cmyk
);
4009 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
4010 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4011 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
4012 sepCS
->getName()->getCString());
4014 writePSFmt("%s\n", colorMap
? "pdfIm" : "pdfImM");
4017 // copy the stream data
4019 while ((c
= str
->getChar()) != EOF
) {
4024 // add newline and trailer to the end
4026 writePS("%-EOD-\n");
4029 writePS("%%EndData\n");
4034 if (useRLE
|| useASCII
|| inlineImg
) {
4039 if ((maskColors
&& colorMap
&& !inlineImg
) || maskStr
) {
4040 writePS("pdfImClipEnd\n");
4044 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace
*colorSpace
,
4045 GBool genXform
, GBool updateColors
) {
4046 GfxCalGrayColorSpace
*calGrayCS
;
4047 GfxCalRGBColorSpace
*calRGBCS
;
4048 GfxLabColorSpace
*labCS
;
4049 GfxIndexedColorSpace
*indexedCS
;
4050 GfxSeparationColorSpace
*separationCS
;
4051 GfxDeviceNColorSpace
*deviceNCS
;
4052 GfxColorSpace
*baseCS
;
4054 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
4058 int n
, numComps
, numAltComps
;
4062 switch (colorSpace
->getMode()) {
4065 writePS("/DeviceGray");
4070 processColors
|= psProcessBlack
;
4075 calGrayCS
= (GfxCalGrayColorSpace
*)colorSpace
;
4076 writePS("[/CIEBasedA <<\n");
4077 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS
->getGamma());
4078 writePSFmt(" /MatrixA [%g %g %g]\n",
4079 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4080 calGrayCS
->getWhiteZ());
4081 writePSFmt(" /WhitePoint [%g %g %g]\n",
4082 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4083 calGrayCS
->getWhiteZ());
4084 writePSFmt(" /BlackPoint [%g %g %g]\n",
4085 calGrayCS
->getBlackX(), calGrayCS
->getBlackY(),
4086 calGrayCS
->getBlackZ());
4092 processColors
|= psProcessBlack
;
4097 writePS("/DeviceRGB");
4102 processColors
|= psProcessCMYK
;
4107 calRGBCS
= (GfxCalRGBColorSpace
*)colorSpace
;
4108 writePS("[/CIEBasedABC <<\n");
4109 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
4110 calRGBCS
->getGammaR(), calRGBCS
->getGammaG(),
4111 calRGBCS
->getGammaB());
4112 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
4113 calRGBCS
->getMatrix()[0], calRGBCS
->getMatrix()[1],
4114 calRGBCS
->getMatrix()[2], calRGBCS
->getMatrix()[3],
4115 calRGBCS
->getMatrix()[4], calRGBCS
->getMatrix()[5],
4116 calRGBCS
->getMatrix()[6], calRGBCS
->getMatrix()[7],
4117 calRGBCS
->getMatrix()[8]);
4118 writePSFmt(" /WhitePoint [%g %g %g]\n",
4119 calRGBCS
->getWhiteX(), calRGBCS
->getWhiteY(),
4120 calRGBCS
->getWhiteZ());
4121 writePSFmt(" /BlackPoint [%g %g %g]\n",
4122 calRGBCS
->getBlackX(), calRGBCS
->getBlackY(),
4123 calRGBCS
->getBlackZ());
4129 processColors
|= psProcessCMYK
;
4134 writePS("/DeviceCMYK");
4139 processColors
|= psProcessCMYK
;
4144 labCS
= (GfxLabColorSpace
*)colorSpace
;
4145 writePS("[/CIEBasedABC <<\n");
4146 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
4147 labCS
->getAMin(), labCS
->getAMax(),
4148 labCS
->getBMin(), labCS
->getBMax());
4149 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
4150 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
4151 writePS(" /DecodeLMN\n");
4152 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
4153 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4154 labCS
->getWhiteX());
4155 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4156 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4157 labCS
->getWhiteY());
4158 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4159 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
4160 labCS
->getWhiteZ());
4161 writePSFmt(" /WhitePoint [%g %g %g]\n",
4162 labCS
->getWhiteX(), labCS
->getWhiteY(), labCS
->getWhiteZ());
4163 writePSFmt(" /BlackPoint [%g %g %g]\n",
4164 labCS
->getBlackX(), labCS
->getBlackY(), labCS
->getBlackZ());
4170 processColors
|= psProcessCMYK
;
4175 // there is no transform function to the alternate color space, so
4176 // we can use it directly
4177 dumpColorSpaceL2(((GfxICCBasedColorSpace
*)colorSpace
)->getAlt(),
4178 genXform
, updateColors
);
4182 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
4183 baseCS
= indexedCS
->getBase();
4184 writePS("[/Indexed ");
4185 dumpColorSpaceL2(baseCS
, gFalse
, gFalse
);
4186 n
= indexedCS
->getIndexHigh();
4187 numComps
= baseCS
->getNComps();
4188 lookup
= indexedCS
->getLookup();
4189 writePSFmt(" %d <\n", n
);
4190 if (baseCS
->getMode() == csDeviceN
) {
4191 func
= ((GfxDeviceNColorSpace
*)baseCS
)->getTintTransformFunc();
4192 numAltComps
= ((GfxDeviceNColorSpace
*)baseCS
)->getAlt()->getNComps();
4194 for (i
= 0; i
<= n
; i
+= 8) {
4196 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4197 for (k
= 0; k
< numComps
; ++k
) {
4198 x
[k
] = *p
++ / 255.0;
4200 func
->transform(x
, y
);
4201 for (k
= 0; k
< numAltComps
; ++k
) {
4202 byte
= (int)(y
[k
] * 255 + 0.5);
4205 } else if (byte
> 255) {
4208 writePSFmt("%02x", byte
);
4211 color
.c
[0] = dblToCol(j
);
4212 indexedCS
->getCMYK(&color
, &cmyk
);
4213 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4214 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4220 for (i
= 0; i
<= n
; i
+= 8) {
4222 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4223 for (k
= 0; k
< numComps
; ++k
) {
4224 writePSFmt("%02x", lookup
[j
* numComps
+ k
]);
4227 color
.c
[0] = dblToCol(j
);
4228 indexedCS
->getCMYK(&color
, &cmyk
);
4229 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4230 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4243 separationCS
= (GfxSeparationColorSpace
*)colorSpace
;
4244 writePS("[/Separation /");
4245 writePSName(separationCS
->getName()->getCString());
4247 dumpColorSpaceL2(separationCS
->getAlt(), gFalse
, gFalse
);
4249 cvtFunction(separationCS
->getFunc());
4255 addCustomColor(separationCS
);
4260 // DeviceN color spaces are a Level 3 PostScript feature.
4261 deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
4262 dumpColorSpaceL2(deviceNCS
->getAlt(), gFalse
, updateColors
);
4265 cvtFunction(deviceNCS
->getTintTransformFunc());
4276 void PSOutputDev::opiBegin(GfxState
*state
, Dict
*opiDict
) {
4279 if (globalParams
->getPSOPI()) {
4280 opiDict
->lookup("2.0", &dict
);
4281 if (dict
.isDict()) {
4282 opiBegin20(state
, dict
.getDict());
4286 opiDict
->lookup("1.3", &dict
);
4287 if (dict
.isDict()) {
4288 opiBegin13(state
, dict
.getDict());
4295 void PSOutputDev::opiBegin20(GfxState
*state
, Dict
*dict
) {
4296 Object obj1
, obj2
, obj3
, obj4
;
4297 double width
, height
, left
, right
, top
, bottom
;
4301 writePS("%%BeginOPI: 2.0\n");
4302 writePS("%%Distilled\n");
4304 dict
->lookup("F", &obj1
);
4305 if (getFileSpec(&obj1
, &obj2
)) {
4306 writePSFmt("%%%%ImageFileName: %s\n",
4307 obj2
.getString()->getCString());
4312 dict
->lookup("MainImage", &obj1
);
4313 if (obj1
.isString()) {
4314 writePSFmt("%%%%MainImage: %s\n", obj1
.getString()->getCString());
4318 //~ ignoring 'Tags' entry
4319 //~ need to use writePSString() and deal with >255-char lines
4321 dict
->lookup("Size", &obj1
);
4322 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4323 obj1
.arrayGet(0, &obj2
);
4324 width
= obj2
.getNum();
4326 obj1
.arrayGet(1, &obj2
);
4327 height
= obj2
.getNum();
4329 writePSFmt("%%%%ImageDimensions: %g %g\n", width
, height
);
4333 dict
->lookup("CropRect", &obj1
);
4334 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4335 obj1
.arrayGet(0, &obj2
);
4336 left
= obj2
.getNum();
4338 obj1
.arrayGet(1, &obj2
);
4339 top
= obj2
.getNum();
4341 obj1
.arrayGet(2, &obj2
);
4342 right
= obj2
.getNum();
4344 obj1
.arrayGet(3, &obj2
);
4345 bottom
= obj2
.getNum();
4347 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left
, top
, right
, bottom
);
4351 dict
->lookup("Overprint", &obj1
);
4352 if (obj1
.isBool()) {
4353 writePSFmt("%%%%ImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4357 dict
->lookup("Inks", &obj1
);
4358 if (obj1
.isName()) {
4359 writePSFmt("%%%%ImageInks: %s\n", obj1
.getName());
4360 } else if (obj1
.isArray() && obj1
.arrayGetLength() >= 1) {
4361 obj1
.arrayGet(0, &obj2
);
4362 if (obj2
.isName()) {
4363 writePSFmt("%%%%ImageInks: %s %d",
4364 obj2
.getName(), (obj1
.arrayGetLength() - 1) / 2);
4365 for (i
= 1; i
+1 < obj1
.arrayGetLength(); i
+= 2) {
4366 obj1
.arrayGet(i
, &obj3
);
4367 obj1
.arrayGet(i
+1, &obj4
);
4368 if (obj3
.isString() && obj4
.isNum()) {
4370 writePSString(obj3
.getString());
4371 writePSFmt(" %g", obj4
.getNum());
4384 writePS("%%BeginIncludedImage\n");
4386 dict
->lookup("IncludedImageDimensions", &obj1
);
4387 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4388 obj1
.arrayGet(0, &obj2
);
4391 obj1
.arrayGet(1, &obj2
);
4394 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w
, h
);
4398 dict
->lookup("IncludedImageQuality", &obj1
);
4400 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1
.getNum());
4407 void PSOutputDev::opiBegin13(GfxState
*state
, Dict
*dict
) {
4409 int left
, right
, top
, bottom
, samples
, bits
, width
, height
;
4411 double llx
, lly
, ulx
, uly
, urx
, ury
, lrx
, lry
;
4412 double tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
;
4417 writePS("/opiMatrix2 matrix currentmatrix def\n");
4418 writePS("opiMatrix setmatrix\n");
4420 dict
->lookup("F", &obj1
);
4421 if (getFileSpec(&obj1
, &obj2
)) {
4422 writePSFmt("%%ALDImageFileName: %s\n",
4423 obj2
.getString()->getCString());
4428 dict
->lookup("CropRect", &obj1
);
4429 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4430 obj1
.arrayGet(0, &obj2
);
4431 left
= obj2
.getInt();
4433 obj1
.arrayGet(1, &obj2
);
4434 top
= obj2
.getInt();
4436 obj1
.arrayGet(2, &obj2
);
4437 right
= obj2
.getInt();
4439 obj1
.arrayGet(3, &obj2
);
4440 bottom
= obj2
.getInt();
4442 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left
, top
, right
, bottom
);
4446 dict
->lookup("Color", &obj1
);
4447 if (obj1
.isArray() && obj1
.arrayGetLength() == 5) {
4448 obj1
.arrayGet(0, &obj2
);
4451 obj1
.arrayGet(1, &obj2
);
4454 obj1
.arrayGet(2, &obj2
);
4457 obj1
.arrayGet(3, &obj2
);
4460 obj1
.arrayGet(4, &obj2
);
4461 if (obj2
.isString()) {
4462 writePSFmt("%%ALDImageColor: %g %g %g %g ", c
, m
, y
, k
);
4463 writePSString(obj2
.getString());
4470 dict
->lookup("ColorType", &obj1
);
4471 if (obj1
.isName()) {
4472 writePSFmt("%%ALDImageColorType: %s\n", obj1
.getName());
4476 //~ ignores 'Comments' entry
4477 //~ need to handle multiple lines
4479 dict
->lookup("CropFixed", &obj1
);
4480 if (obj1
.isArray()) {
4481 obj1
.arrayGet(0, &obj2
);
4482 ulx
= obj2
.getNum();
4484 obj1
.arrayGet(1, &obj2
);
4485 uly
= obj2
.getNum();
4487 obj1
.arrayGet(2, &obj2
);
4488 lrx
= obj2
.getNum();
4490 obj1
.arrayGet(3, &obj2
);
4491 lry
= obj2
.getNum();
4493 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx
, uly
, lrx
, lry
);
4497 dict
->lookup("GrayMap", &obj1
);
4498 if (obj1
.isArray()) {
4499 writePS("%ALDImageGrayMap:");
4500 for (i
= 0; i
< obj1
.arrayGetLength(); i
+= 16) {
4504 for (j
= 0; j
< 16 && i
+j
< obj1
.arrayGetLength(); ++j
) {
4505 obj1
.arrayGet(i
+j
, &obj2
);
4506 writePSFmt(" %d", obj2
.getInt());
4514 dict
->lookup("ID", &obj1
);
4515 if (obj1
.isString()) {
4516 writePSFmt("%%ALDImageID: %s\n", obj1
.getString()->getCString());
4520 dict
->lookup("ImageType", &obj1
);
4521 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4522 obj1
.arrayGet(0, &obj2
);
4523 samples
= obj2
.getInt();
4525 obj1
.arrayGet(1, &obj2
);
4526 bits
= obj2
.getInt();
4528 writePSFmt("%%ALDImageType: %d %d\n", samples
, bits
);
4532 dict
->lookup("Overprint", &obj1
);
4533 if (obj1
.isBool()) {
4534 writePSFmt("%%ALDImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4538 dict
->lookup("Position", &obj1
);
4539 if (obj1
.isArray() && obj1
.arrayGetLength() == 8) {
4540 obj1
.arrayGet(0, &obj2
);
4541 llx
= obj2
.getNum();
4543 obj1
.arrayGet(1, &obj2
);
4544 lly
= obj2
.getNum();
4546 obj1
.arrayGet(2, &obj2
);
4547 ulx
= obj2
.getNum();
4549 obj1
.arrayGet(3, &obj2
);
4550 uly
= obj2
.getNum();
4552 obj1
.arrayGet(4, &obj2
);
4553 urx
= obj2
.getNum();
4555 obj1
.arrayGet(5, &obj2
);
4556 ury
= obj2
.getNum();
4558 obj1
.arrayGet(6, &obj2
);
4559 lrx
= obj2
.getNum();
4561 obj1
.arrayGet(7, &obj2
);
4562 lry
= obj2
.getNum();
4564 opiTransform(state
, llx
, lly
, &tllx
, &tlly
);
4565 opiTransform(state
, ulx
, uly
, &tulx
, &tuly
);
4566 opiTransform(state
, urx
, ury
, &turx
, &tury
);
4567 opiTransform(state
, lrx
, lry
, &tlrx
, &tlry
);
4568 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
4569 tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
);
4574 dict
->lookup("Resolution", &obj1
);
4575 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4576 obj1
.arrayGet(0, &obj2
);
4577 horiz
= obj2
.getNum();
4579 obj1
.arrayGet(1, &obj2
);
4580 vert
= obj2
.getNum();
4582 writePSFmt("%%ALDImageResoution: %g %g\n", horiz
, vert
);
4587 dict
->lookup("Size", &obj1
);
4588 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4589 obj1
.arrayGet(0, &obj2
);
4590 width
= obj2
.getInt();
4592 obj1
.arrayGet(1, &obj2
);
4593 height
= obj2
.getInt();
4595 writePSFmt("%%ALDImageDimensions: %d %d\n", width
, height
);
4599 //~ ignoring 'Tags' entry
4600 //~ need to use writePSString() and deal with >255-char lines
4602 dict
->lookup("Tint", &obj1
);
4604 writePSFmt("%%ALDImageTint: %g\n", obj1
.getNum());
4608 dict
->lookup("Transparency", &obj1
);
4609 if (obj1
.isBool()) {
4610 writePSFmt("%%ALDImageTransparency: %s\n", obj1
.getBool() ? "true" : "false");
4614 writePS("%%BeginObject: image\n");
4615 writePS("opiMatrix2 setmatrix\n");
4619 // Convert PDF user space coordinates to PostScript default user space
4620 // coordinates. This has to account for both the PDF CTM and the
4621 // PSOutputDev page-fitting transform.
4622 void PSOutputDev::opiTransform(GfxState
*state
, double x0
, double y0
,
4623 double *x1
, double *y1
) {
4626 state
->transform(x0
, y0
, x1
, y1
);
4633 } else if (rotate
== 180) {
4636 } else if (rotate
== 270) {
4645 void PSOutputDev::opiEnd(GfxState
*state
, Dict
*opiDict
) {
4648 if (globalParams
->getPSOPI()) {
4649 opiDict
->lookup("2.0", &dict
);
4650 if (dict
.isDict()) {
4651 writePS("%%EndIncludedImage\n");
4652 writePS("%%EndOPI\n");
4653 writePS("grestore\n");
4658 opiDict
->lookup("1.3", &dict
);
4659 if (dict
.isDict()) {
4660 writePS("%%EndObject\n");
4661 writePS("restore\n");
4669 GBool
PSOutputDev::getFileSpec(Object
*fileSpec
, Object
*fileName
) {
4670 if (fileSpec
->isString()) {
4671 fileSpec
->copy(fileName
);
4674 if (fileSpec
->isDict()) {
4675 fileSpec
->dictLookup("DOS", fileName
);
4676 if (fileName
->isString()) {
4680 fileSpec
->dictLookup("Mac", fileName
);
4681 if (fileName
->isString()) {
4685 fileSpec
->dictLookup("Unix", fileName
);
4686 if (fileName
->isString()) {
4690 fileSpec
->dictLookup("F", fileName
);
4691 if (fileName
->isString()) {
4698 #endif // OPI_SUPPORT
4700 void PSOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
4701 writePSFmt("%g %g setcharwidth\n", wx
, wy
);
4705 void PSOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
4706 double llx
, double lly
, double urx
, double ury
) {
4713 t3String
= new GString();
4715 t3Cacheable
= gTrue
;
4718 void PSOutputDev::psXObject(Stream
*psStream
, Stream
*level1Stream
) {
4722 if ((level
== psLevel1
|| level
== psLevel1Sep
) && level1Stream
) {
4728 while ((c
= str
->getChar()) != EOF
) {
4734 //~ can nextFunc be reset to 0 -- maybe at the start of each page?
4735 //~ or maybe at the start of each color space / pattern?
4736 void PSOutputDev::cvtFunction(Function
*func
) {
4737 SampledFunction
*func0
;
4738 ExponentialFunction
*func2
;
4739 StitchingFunction
*func3
;
4740 PostScriptFunction
*func4
;
4741 int thisFunc
, m
, n
, nSamples
, i
, j
, k
;
4743 switch (func
->getType()) {
4745 case -1: // identity
4750 func0
= (SampledFunction
*)func
;
4751 thisFunc
= nextFunc
++;
4752 m
= func0
->getInputSize();
4753 n
= func0
->getOutputSize();
4755 for (i
= 0; i
< m
; ++i
) {
4756 nSamples
*= func0
->getSampleSize(i
);
4758 writePSFmt("/xpdfSamples%d [\n", thisFunc
);
4759 for (i
= 0; i
< nSamples
; ++i
) {
4760 writePSFmt("%g\n", func0
->getSamples()[i
]);
4763 writePSFmt("{ %d array %d array %d 2 roll\n", 2*m
, m
, m
+2);
4764 // [e01] [efrac] x0 x1 ... xm-1
4765 for (i
= m
-1; i
>= 0; --i
) {
4766 // [e01] [efrac] x0 x1 ... xi
4767 writePSFmt("%g sub %g mul %g add\n",
4768 func0
->getDomainMin(i
),
4769 (func0
->getEncodeMax(i
) - func0
->getEncodeMin(i
)) /
4770 (func0
->getDomainMax(i
) - func0
->getDomainMin(i
)),
4771 func0
->getEncodeMin(i
));
4772 // [e01] [efrac] x0 x1 ... xi-1 xi'
4773 writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n",
4774 func0
->getSampleSize(i
) - 1, func0
->getSampleSize(i
) - 1);
4775 // [e01] [efrac] x0 x1 ... xi-1 xi'
4776 writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
4777 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
4778 writePSFmt("%d index %d 3 2 roll put\n", i
+3, i
);
4779 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
4780 writePSFmt("%d index %d 3 2 roll put\n", i
+3, 2*i
+1);
4781 // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
4782 writePSFmt("%d index %d 3 2 roll put\n", i
+2, 2*i
);
4783 // [e01] [efrac] x0 x1 ... xi-1
4786 for (i
= 0; i
< n
; ++i
) {
4787 // [e01] [efrac] y(0) ... y(i-1)
4788 for (j
= 0; j
< (1<<m
); ++j
) {
4789 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
4790 writePSFmt("xpdfSamples%d\n", thisFunc
);
4792 writePSFmt("%d index %d get\n", i
+j
+2, 2 * k
+ ((j
>> k
) & 1));
4793 for (k
= m
- 2; k
>= 0; --k
) {
4794 writePSFmt("%d mul %d index %d get add\n",
4795 func0
->getSampleSize(k
),
4797 2 * k
+ ((j
>> k
) & 1));
4800 writePSFmt("%d mul %d add ", n
, i
);
4804 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
4805 for (j
= 0; j
< m
; ++j
) {
4806 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
4807 for (k
= 0; k
< (1 << (m
- j
)); k
+= 2) {
4808 // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
4809 writePSFmt("%d index %d get dup\n", i
+ k
/2 + (1 << (m
-j
)) - k
, j
);
4810 writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
4811 writePSFmt("%d 1 roll\n", k
/2 + (1 << m
-j
) - k
- 1);
4813 // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
4815 // [e01] [efrac] y(0) ... y(i-1) s
4816 writePSFmt("%g mul %g add\n",
4817 func0
->getDecodeMax(i
) - func0
->getDecodeMin(i
),
4818 func0
->getDecodeMin(i
));
4819 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4820 func0
->getRangeMin(i
), func0
->getRangeMin(i
),
4821 func0
->getRangeMax(i
), func0
->getRangeMax(i
));
4822 // [e01] [efrac] y(0) ... y(i-1) y(i)
4824 // [e01] [efrac] y(0) ... y(n-1)
4825 writePSFmt("%d %d roll pop pop }\n", n
+2, n
);
4828 case 2: // exponential
4829 func2
= (ExponentialFunction
*)func
;
4830 n
= func2
->getOutputSize();
4831 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4832 func2
->getDomainMin(0), func2
->getDomainMin(0),
4833 func2
->getDomainMax(0), func2
->getDomainMax(0));
4835 for (i
= 0; i
< n
; ++i
) {
4837 writePSFmt("%d index %g exp %g mul %g add\n",
4838 i
, func2
->getE(), func2
->getC1()[i
] - func2
->getC0()[i
],
4840 if (func2
->getHasRange()) {
4841 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4842 func2
->getRangeMin(i
), func2
->getRangeMin(i
),
4843 func2
->getRangeMax(i
), func2
->getRangeMax(i
));
4847 writePSFmt("%d %d roll pop }\n", n
+1, n
);
4850 case 3: // stitching
4851 func3
= (StitchingFunction
*)func
;
4852 thisFunc
= nextFunc
++;
4853 for (i
= 0; i
< func3
->getNumFuncs(); ++i
) {
4854 cvtFunction(func3
->getFunc(i
));
4855 writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc
, i
);
4857 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4858 func3
->getDomainMin(0), func3
->getDomainMin(0),
4859 func3
->getDomainMax(0), func3
->getDomainMax(0));
4860 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4861 writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n",
4862 func3
->getBounds()[i
+1],
4863 func3
->getBounds()[i
],
4864 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4865 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4866 func3
->getEncode()[2*i
],
4869 writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n",
4870 func3
->getBounds()[i
],
4871 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4872 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4873 func3
->getEncode()[2*i
],
4875 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4876 writePS("} ifelse\n");
4881 case 4: // PostScript
4882 func4
= (PostScriptFunction
*)func
;
4883 writePS(func4
->getCodeString()->getCString());
4889 void PSOutputDev::writePSChar(char c
) {
4891 t3String
->append(c
);
4893 (*outputFunc
)(outputStream
, &c
, 1);
4897 void PSOutputDev::writePS(char *s
) {
4899 t3String
->append(s
);
4901 (*outputFunc
)(outputStream
, s
, strlen(s
));
4905 void PSOutputDev::writePSFmt(const char *fmt
, ...) {
4909 va_start(args
, fmt
);
4910 vsprintf(buf
, fmt
, args
);
4913 t3String
->append(buf
);
4915 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
4919 void PSOutputDev::writePSString(GString
*s
) {
4926 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
4932 if (*p
== '(' || *p
== ')' || *p
== '\\') {
4934 writePSChar((char)*p
);
4936 } else if (*p
< 0x20 || *p
>= 0x80) {
4937 sprintf(buf
, "\\%03o", *p
);
4941 writePSChar((char)*p
);
4948 void PSOutputDev::writePSName(char *s
) {
4953 while ((c
= *p
++)) {
4954 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4955 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4956 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4957 c
== '/' || c
== '%') {
4958 writePSFmt("#%02x", c
& 0xff);
4965 GString
*PSOutputDev::filterPSName(GString
*name
) {
4971 name2
= new GString();
4973 // ghostscript chokes on names that begin with out-of-limits
4974 // numbers, e.g., 1e4foo is handled correctly (as a name), but
4975 // 1e999foo generates a limitcheck error
4976 c
= name
->getChar(0);
4977 if (c
>= '0' && c
<= '9') {
4981 for (i
= 0; i
< name
->getLength(); ++i
) {
4982 c
= name
->getChar(i
);
4983 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4984 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4985 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4986 c
== '/' || c
== '%') {
4987 sprintf(buf
, "#%02x", c
& 0xff);
4996 GBool
/* O - gTrue if selected, gFalse otherwise */
4997 PSOutputDev::checkRange(int page
) /* I - Page number */
4999 const char *range
; /* Pointer into range string */
5000 int lower
, upper
; /* Lower and upper page numbers */
5003 if (pageRanges
== NULL
)
5004 return (gTrue
); /* No range, print all pages... */
5006 for (range
= pageRanges
; *range
!= '\0';)
5012 upper
= strtol(range
, (char **)&range
, 10);
5016 lower
= strtol(range
, (char **)&range
, 10);
5021 if (!isdigit(*range
& 255))
5024 upper
= strtol(range
, (char **)&range
, 10);
5030 if (page
>= lower
&& page
<= upper
)