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 writePSFmt("% Produced by xpdf/pdftops %s\n", xpdfVersion
);
1162 xref
->getDocInfo(&info
);
1163 if (info
.dictLookup("Creator", &obj1
)->isString()) {
1164 writePS("%%Creator: ");
1165 s
= obj1
.getString();
1166 if ((s
->getChar(0) & 0xff) == 0xfe &&
1167 (s
->getChar(1) & 0xff) == 0xff) {
1168 // Convert UTF-16 to UTF-8...
1169 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1170 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1172 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1173 // Multi-word UTF-16 char...
1175 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1177 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1179 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1185 * Single byte ASCII...
1190 else if (ch
< 0x800)
1196 writePSChar(0xc0 | (ch
>> 6));
1197 writePSChar(0x80 | (ch
& 0x3f));
1199 else if (ch
< 0x10000)
1202 * Three-byte UTF-8...
1205 writePSChar(0xe0 | (ch
>> 12));
1206 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1207 writePSChar(0x80 | (ch
& 0x3f));
1212 * Four-byte UTF-8...
1215 writePSChar(0xf0 | (ch
>> 18));
1216 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1217 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1218 writePSChar(0x80 | (ch
& 0x3f));
1222 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1223 writePSChar(s
->getChar(i
));
1229 if (info
.dictLookup("Title", &obj1
)->isString()) {
1230 writePS("%%Title: ");
1231 s
= obj1
.getString();
1232 if ((s
->getChar(0) & 0xff) == 0xfe &&
1233 (s
->getChar(1) & 0xff) == 0xff) {
1234 // cheap Unicode-to-ASCII conversion
1235 for (i
= 3; i
< s
->getLength() && i
< 400; i
+= 2) {
1236 writePSChar(s
->getChar(i
));
1239 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1240 writePSChar(s
->getChar(i
));
1247 writePSFmt("%%%%LanguageLevel: %d\n",
1248 (level
== psLevel1
|| level
== psLevel1Sep
) ? 1 :
1249 (level
== psLevel2
|| level
== psLevel2Sep
) ? 2 : 3);
1250 if (level
== psLevel1Sep
|| level
== psLevel2Sep
|| level
== psLevel3Sep
) {
1251 writePS("%%DocumentProcessColors: (atend)\n");
1252 writePS("%%DocumentCustomColors: (atend)\n");
1254 writePS("%%DocumentSuppliedResources: (atend)\n");
1258 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
1259 paperWidth
, paperHeight
);
1260 writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth
, paperHeight
);
1261 writePSFmt("%%%%Pages: %d\n", lastPage
- firstPage
+ 1);
1262 writePS("%%EndComments\n");
1263 writePS("%%BeginDefaults\n");
1264 writePS("%%PageMedia: plain\n");
1265 writePS("%%EndDefaults\n");
1268 epsX1
= cropBox
->x1
;
1269 epsY1
= cropBox
->y1
;
1270 epsX2
= cropBox
->x2
;
1271 epsY2
= cropBox
->y2
;
1272 if (pageRotate
== 0 || pageRotate
== 180) {
1277 } else { // pageRotate == 90 || pageRotate == 270
1283 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
1284 (int)floor(x1
), (int)floor(y1
), (int)ceil(x2
), (int)ceil(y2
));
1285 if (floor(x1
) != ceil(x1
) || floor(y1
) != ceil(y1
) ||
1286 floor(x2
) != ceil(x2
) || floor(y2
) != ceil(y2
)) {
1287 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1
, y1
, x2
, y2
);
1289 writePS("%%EndComments\n");
1292 writePS("%%EndComments\n");
1293 writePS("32 dict dup begin\n");
1294 writePSFmt("/BBox [%d %d %d %d] def\n",
1295 (int)floor(mediaBox
->x1
), (int)floor(mediaBox
->y1
),
1296 (int)ceil(mediaBox
->x2
), (int)ceil(mediaBox
->y2
));
1297 writePS("/FormType 1 def\n");
1298 writePS("/Matrix [1 0 0 1 0 0] def\n");
1303 void PSOutputDev::writeXpdfProcset() {
1304 GBool lev1
, lev2
, lev3
, sep
, nonSep
;
1308 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion
);
1309 lev1
= lev2
= lev3
= sep
= nonSep
= gTrue
;
1310 for (p
= prolog
; *p
; ++p
) {
1311 if ((*p
)[0] == '~') {
1312 lev1
= lev2
= lev3
= sep
= nonSep
= gFalse
;
1313 for (q
= *p
+ 1; *q
; ++q
) {
1315 case '1': lev1
= gTrue
; break;
1316 case '2': lev2
= gTrue
; break;
1317 case '3': lev3
= gTrue
; break;
1318 case 's': sep
= gTrue
; break;
1319 case 'n': nonSep
= gTrue
; break;
1322 } else if ((level
== psLevel1
&& lev1
&& nonSep
) ||
1323 (level
== psLevel1Sep
&& lev1
&& sep
) ||
1324 (level
== psLevel2
&& lev2
&& nonSep
) ||
1325 (level
== psLevel2Sep
&& lev2
&& sep
) ||
1326 (level
== psLevel3
&& lev3
&& nonSep
) ||
1327 (level
== psLevel3Sep
&& lev3
&& sep
)) {
1328 writePSFmt("%s\n", *p
);
1331 writePS("%%EndResource\n");
1333 if (level
>= psLevel3
) {
1334 for (p
= cmapProlog
; *p
; ++p
) {
1335 writePSFmt("%s\n", *p
);
1340 void PSOutputDev::writeDocSetup(Catalog
*catalog
,
1341 int firstPage
, int lastPage
) {
1348 if (mode
== psModeForm
) {
1349 // swap the form and xpdf dicts
1350 writePS("xpdf end begin dup begin\n");
1352 writePS("xpdf begin\n");
1354 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
1355 page
= catalog
->getPage(pg
);
1356 if ((resDict
= page
->getResourceDict())) {
1357 setupResources(resDict
);
1359 annots
= new Annots(xref
, catalog
, page
->getAnnots(&obj1
));
1361 for (i
= 0; i
< annots
->getNumAnnots(); ++i
) {
1362 if (annots
->getAnnot(i
)->getAppearance(&obj1
)->isStream()) {
1363 obj1
.streamGetDict()->lookup("Resources", &obj2
);
1364 if (obj2
.isDict()) {
1365 setupResources(obj2
.getDict());
1373 if (mode
!= psModeForm
) {
1374 if (mode
!= psModeEPS
&& !manualCtrl
) {
1375 writePSFmt("%d %d %s pdfSetup\n",
1376 paperWidth
, paperHeight
,
1377 globalParams
->getPSDuplex() ? "true" : "false");
1380 if (globalParams
->getPSOPI()) {
1381 writePS("/opiMatrix matrix currentmatrix def\n");
1387 void PSOutputDev::writePageTrailer() {
1388 if (mode
!= psModeForm
) {
1389 writePS("pdfEndPage\n");
1393 void PSOutputDev::writeTrailer() {
1394 PSOutCustomColor
*cc
;
1396 if (mode
== psModeForm
) {
1397 writePS("/Foo exch /Form defineresource pop\n");
1400 writePS("%%DocumentSuppliedResources:\n");
1401 writePS(embFontList
->getCString());
1402 if (level
== psLevel1Sep
|| level
== psLevel2Sep
||
1403 level
== psLevel3Sep
) {
1404 writePS("%%DocumentProcessColors:");
1405 if (processColors
& psProcessCyan
) {
1408 if (processColors
& psProcessMagenta
) {
1409 writePS(" Magenta");
1411 if (processColors
& psProcessYellow
) {
1414 if (processColors
& psProcessBlack
) {
1418 writePS("%%DocumentCustomColors:");
1419 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1420 writePSFmt(" (%s)", cc
->name
->getCString());
1423 writePS("%%CMYKCustomColor:\n");
1424 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1425 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
1426 cc
->c
, cc
->m
, cc
->y
, cc
->k
, cc
->name
->getCString());
1432 void PSOutputDev::setupResources(Dict
*resDict
) {
1433 Object xObjDict
, xObjRef
, xObj
, patDict
, patRef
, pat
, resObj
;
1438 setupFonts(resDict
);
1439 setupImages(resDict
);
1441 //----- recursively scan XObjects
1442 resDict
->lookup("XObject", &xObjDict
);
1443 if (xObjDict
.isDict()) {
1444 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
1446 // avoid infinite recursion on XObjects
1448 if ((xObjDict
.dictGetValNF(i
, &xObjRef
)->isRef())) {
1449 ref0
= xObjRef
.getRef();
1450 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1451 ref1
= *(Ref
*)xobjStack
->get(j
);
1452 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1458 xobjStack
->append(&ref0
);
1463 // process the XObject's resource dictionary
1464 xObjDict
.dictGetVal(i
, &xObj
);
1465 if (xObj
.isStream()) {
1466 xObj
.streamGetDict()->lookup("Resources", &resObj
);
1467 if (resObj
.isDict()) {
1468 setupResources(resObj
.getDict());
1475 if (xObjRef
.isRef() && !skip
) {
1476 xobjStack
->del(xobjStack
->getLength() - 1);
1483 //----- recursively scan Patterns
1484 resDict
->lookup("Pattern", &patDict
);
1485 if (patDict
.isDict()) {
1486 inType3Char
= gTrue
;
1487 for (i
= 0; i
< patDict
.dictGetLength(); ++i
) {
1489 // avoid infinite recursion on Patterns
1491 if ((patDict
.dictGetValNF(i
, &patRef
)->isRef())) {
1492 ref0
= patRef
.getRef();
1493 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1494 ref1
= *(Ref
*)xobjStack
->get(j
);
1495 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1501 xobjStack
->append(&ref0
);
1506 // process the Pattern's resource dictionary
1507 patDict
.dictGetVal(i
, &pat
);
1508 if (pat
.isStream()) {
1509 pat
.streamGetDict()->lookup("Resources", &resObj
);
1510 if (resObj
.isDict()) {
1511 setupResources(resObj
.getDict());
1518 if (patRef
.isRef() && !skip
) {
1519 xobjStack
->del(xobjStack
->getLength() - 1);
1523 inType3Char
= gFalse
;
1528 void PSOutputDev::setupFonts(Dict
*resDict
) {
1531 GfxFontDict
*gfxFontDict
;
1536 resDict
->lookupNF("Font", &obj1
);
1538 obj1
.fetch(xref
, &obj2
);
1539 if (obj2
.isDict()) {
1541 gfxFontDict
= new GfxFontDict(xref
, &r
, obj2
.getDict());
1544 } else if (obj1
.isDict()) {
1545 gfxFontDict
= new GfxFontDict(xref
, NULL
, obj1
.getDict());
1548 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
1549 if ((font
= gfxFontDict
->getFont(i
))) {
1550 setupFont(font
, resDict
);
1558 void PSOutputDev::setupFont(GfxFont
*font
, Dict
*parentResDict
) {
1561 PSFontParam
*fontParam
;
1563 char type3Name
[64], buf
[16];
1573 // check if font is already set up
1574 for (i
= 0; i
< fontIDLen
; ++i
) {
1575 if (fontIDs
[i
].num
== font
->getID()->num
&&
1576 fontIDs
[i
].gen
== font
->getID()->gen
) {
1581 // add entry to fontIDs list
1582 if (fontIDLen
>= fontIDSize
) {
1584 fontIDs
= (Ref
*)greallocn(fontIDs
, fontIDSize
, sizeof(Ref
));
1586 fontIDs
[fontIDLen
++] = *font
->getID();
1591 // check for resident 8-bit font
1592 if (font
->getName() &&
1593 (fontParam
= globalParams
->getPSFont(font
->getName()))) {
1594 psName
= new GString(fontParam
->psFontName
->getCString());
1596 // check for embedded Type 1 font
1597 } else if (globalParams
->getPSEmbedType1() &&
1598 font
->getType() == fontType1
&&
1599 font
->getEmbeddedFontID(&fontFileID
)) {
1600 psName
= filterPSName(font
->getEmbeddedFontName());
1601 setupEmbeddedType1Font(&fontFileID
, psName
);
1603 // check for embedded Type 1C font
1604 } else if (globalParams
->getPSEmbedType1() &&
1605 font
->getType() == fontType1C
&&
1606 font
->getEmbeddedFontID(&fontFileID
)) {
1607 psName
= filterPSName(font
->getEmbeddedFontName());
1608 setupEmbeddedType1CFont(font
, &fontFileID
, psName
);
1610 // check for external Type 1 font file
1611 } else if (globalParams
->getPSEmbedType1() &&
1612 font
->getType() == fontType1
&&
1613 font
->getExtFontFile()) {
1614 // this assumes that the PS font name matches the PDF font name
1615 psName
= font
->getName()->copy();
1616 setupExternalType1Font(font
->getExtFontFile(), psName
);
1618 // check for embedded TrueType font
1619 } else if (globalParams
->getPSEmbedTrueType() &&
1620 font
->getType() == fontTrueType
&&
1621 font
->getEmbeddedFontID(&fontFileID
)) {
1622 psName
= filterPSName(font
->getEmbeddedFontName());
1623 setupEmbeddedTrueTypeFont(font
, &fontFileID
, psName
);
1625 // check for external TrueType font file
1626 } else if (globalParams
->getPSEmbedTrueType() &&
1627 font
->getType() == fontTrueType
&&
1628 font
->getExtFontFile()) {
1629 psName
= filterPSName(font
->getName());
1630 setupExternalTrueTypeFont(font
, psName
);
1632 // check for embedded CID PostScript font
1633 } else if (globalParams
->getPSEmbedCIDPostScript() &&
1634 font
->getType() == fontCIDType0C
&&
1635 font
->getEmbeddedFontID(&fontFileID
)) {
1636 psName
= filterPSName(font
->getEmbeddedFontName());
1637 setupEmbeddedCIDType0Font(font
, &fontFileID
, psName
);
1639 // check for embedded CID TrueType font
1640 } else if (globalParams
->getPSEmbedCIDTrueType() &&
1641 font
->getType() == fontCIDType2
&&
1642 font
->getEmbeddedFontID(&fontFileID
)) {
1643 psName
= filterPSName(font
->getEmbeddedFontName());
1644 //~ should check to see if font actually uses vertical mode
1645 setupEmbeddedCIDTrueTypeFont(font
, &fontFileID
, psName
, gTrue
);
1647 } else if (font
->getType() == fontType3
) {
1648 sprintf(type3Name
, "T3_%d_%d",
1649 font
->getID()->num
, font
->getID()->gen
);
1650 psName
= new GString(type3Name
);
1651 setupType3Font(font
, psName
, parentResDict
);
1653 // do 8-bit font substitution
1654 } else if (!font
->isCIDFont()) {
1656 name
= font
->getName();
1659 for (i
= 0; psFonts
[i
]; ++i
) {
1660 if (name
->cmp(psFonts
[i
]) == 0) {
1661 psName
= new GString(psFonts
[i
]);
1667 if (font
->isFixedWidth()) {
1669 } else if (font
->isSerif()) {
1674 if (font
->isBold()) {
1677 if (font
->isItalic()) {
1680 psName
= new GString(psSubstFonts
[i
].psName
);
1681 for (code
= 0; code
< 256; ++code
) {
1682 if ((charName
= ((Gfx8BitFont
*)font
)->getCharName(code
)) &&
1683 charName
[0] == 'm' && charName
[1] == '\0') {
1688 w1
= ((Gfx8BitFont
*)font
)->getWidth(code
);
1692 w2
= psSubstFonts
[i
].mWidth
;
1697 if (font
->getType() == fontType3
) {
1698 // This is a hack which makes it possible to substitute for some
1699 // Type 3 fonts. The problem is that it's impossible to know what
1700 // the base coordinate system used in the font is without actually
1701 // rendering the font.
1703 fm
= font
->getFontMatrix();
1705 ys
*= fm
[3] / fm
[0];
1712 // do 16-bit font substitution
1713 } else if ((fontParam
= globalParams
->
1714 getPSFont16(font
->getName(),
1715 ((GfxCIDFont
*)font
)->getCollection(),
1716 font
->getWMode()))) {
1718 psName
= fontParam
->psFontName
->copy();
1719 if (font16EncLen
>= font16EncSize
) {
1720 font16EncSize
+= 16;
1721 font16Enc
= (PSFont16Enc
*)greallocn(font16Enc
,
1722 font16EncSize
, sizeof(PSFont16Enc
));
1724 font16Enc
[font16EncLen
].fontID
= *font
->getID();
1725 font16Enc
[font16EncLen
].enc
= fontParam
->encoding
->copy();
1726 if ((uMap
= globalParams
->getUnicodeMap(font16Enc
[font16EncLen
].enc
))) {
1730 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1731 font16Enc
[font16EncLen
].enc
->getCString());
1734 // give up - can't do anything with this font
1736 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1737 font
->getName() ? font
->getName()->getCString() : "(unnamed)",
1738 ((GfxCIDFont
*)font
)->getCollection()
1739 ? ((GfxCIDFont
*)font
)->getCollection()->getCString()
1744 // generate PostScript code to set up the font
1745 if (font
->isCIDFont()) {
1746 if (level
== psLevel3
|| level
== psLevel3Sep
) {
1747 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
1748 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1751 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
1752 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1756 writePSFmt("/F%d_%d /%s %g %g\n",
1757 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1759 for (i
= 0; i
< 256; i
+= 8) {
1760 writePSFmt((i
== 0) ? "[ " : " ");
1761 for (j
= 0; j
< 8; ++j
) {
1762 if (font
->getType() == fontTrueType
&&
1764 !((Gfx8BitFont
*)font
)->getHasEncoding()) {
1765 sprintf(buf
, "c%02x", i
+j
);
1768 charName
= ((Gfx8BitFont
*)font
)->getCharName(i
+j
);
1769 // this is a kludge for broken PDF files that encode char 32
1771 if (i
+j
== 32 && charName
&& !strcmp(charName
, ".notdef")) {
1776 writePSName(charName
? charName
: (char *)".notdef");
1777 // the empty name is legal in PDF and PostScript, but PostScript
1778 // uses a double-slash (//...) for "immediately evaluated names",
1779 // so we need to add a space character here
1780 if (charName
&& !charName
[0]) {
1784 writePS((i
== 256-8) ? (char *)"]\n" : (char *)"\n");
1786 writePS("pdfMakeFont\n");
1792 void PSOutputDev::setupEmbeddedType1Font(Ref
*id
, GString
*psName
) {
1793 static char hexChar
[17] = "0123456789abcdef";
1794 Object refObj
, strObj
, obj1
, obj2
, obj3
;
1796 int length1
, length2
, length3
;
1802 // check if font is already embedded
1803 for (i
= 0; i
< fontFileIDLen
; ++i
) {
1804 if (fontFileIDs
[i
].num
== id
->num
&&
1805 fontFileIDs
[i
].gen
== id
->gen
)
1809 // add entry to fontFileIDs list
1810 if (fontFileIDLen
>= fontFileIDSize
) {
1811 fontFileIDSize
+= 64;
1812 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
1814 fontFileIDs
[fontFileIDLen
++] = *id
;
1816 // get the font stream and info
1817 refObj
.initRef(id
->num
, id
->gen
);
1818 refObj
.fetch(xref
, &strObj
);
1820 if (!strObj
.isStream()) {
1821 error(-1, "Embedded font file object is not a stream");
1824 if (!(dict
= strObj
.streamGetDict())) {
1825 error(-1, "Embedded font stream is missing its dictionary");
1828 dict
->lookup("Length1", &obj1
);
1829 dict
->lookup("Length2", &obj2
);
1830 dict
->lookup("Length3", &obj3
);
1831 if (!obj1
.isInt() || !obj2
.isInt() || !obj3
.isInt()) {
1832 error(-1, "Missing length fields in embedded font stream dictionary");
1838 length1
= obj1
.getInt();
1839 length2
= obj2
.getInt();
1840 length3
= obj3
.getInt();
1845 // beginning comment
1846 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1847 embFontList
->append("%%+ font ");
1848 embFontList
->append(psName
->getCString());
1849 embFontList
->append("\n");
1851 // copy ASCII portion of font
1852 strObj
.streamReset();
1853 for (i
= 0; i
< length1
&& (c
= strObj
.streamGetChar()) != EOF
; ++i
) {
1857 // figure out if encrypted portion is binary or ASCII
1859 for (i
= 0; i
< 4; ++i
) {
1860 start
[i
] = strObj
.streamGetChar();
1861 if (start
[i
] == EOF
) {
1862 error(-1, "Unexpected end of file in embedded font stream");
1865 if (!((start
[i
] >= '0' && start
[i
] <= '9') ||
1866 (start
[i
] >= 'A' && start
[i
] <= 'F') ||
1867 (start
[i
] >= 'a' && start
[i
] <= 'f')))
1871 // convert binary data to ASCII
1873 for (i
= 0; i
< 4; ++i
) {
1874 writePSChar(hexChar
[(start
[i
] >> 4) & 0x0f]);
1875 writePSChar(hexChar
[start
[i
] & 0x0f]);
1877 // if Length2 is incorrect (too small), font data gets chopped, so
1878 // we take a few extra characters from the trailer just in case
1879 // length2 += length3 >= 8 ? 8 : length3;
1880 while (i
< length2
) {
1881 if ((c
= strObj
.streamGetChar()) == EOF
) {
1884 writePSChar(hexChar
[(c
>> 4) & 0x0f]);
1885 writePSChar(hexChar
[c
& 0x0f]);
1886 if (++i
% 32 == 0) {
1894 // already in ASCII format -- just copy it
1896 for (i
= 0; i
< 4; ++i
) {
1897 writePSChar(start
[i
]);
1899 for (i
= 4; i
< length2
; ++i
) {
1900 if ((c
= strObj
.streamGetChar()) == EOF
) {
1907 // write padding and "cleartomark"
1908 for (i
= 0; i
< 8; ++i
) {
1909 writePS("00000000000000000000000000000000"
1910 "00000000000000000000000000000000\n");
1912 writePS("cleartomark\n");
1915 writePS("%%EndResource\n");
1918 strObj
.streamClose();
1922 //~ This doesn't handle .pfb files or binary eexec data (which only
1923 //~ happens in pfb files?).
1924 void PSOutputDev::setupExternalType1Font(GString
*fileName
, GString
*psName
) {
1929 // check if font is already embedded
1930 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1931 if (!fontFileNames
[i
]->cmp(fileName
)) {
1936 // add entry to fontFileNames list
1937 if (fontFileNameLen
>= fontFileNameSize
) {
1938 fontFileNameSize
+= 64;
1939 fontFileNames
= (GString
**)greallocn(fontFileNames
,
1940 fontFileNameSize
, sizeof(GString
*));
1942 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
1944 // beginning comment
1945 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1946 embFontList
->append("%%+ font ");
1947 embFontList
->append(psName
->getCString());
1948 embFontList
->append("\n");
1950 // copy the font file
1951 if (!(fontFile
= fopen(fileName
->getCString(), "rb"))) {
1952 error(-1, "Couldn't open external font file");
1955 while ((c
= fgetc(fontFile
)) != EOF
) {
1961 writePS("%%EndResource\n");
1964 void PSOutputDev::setupEmbeddedType1CFont(GfxFont
*font
, Ref
*id
,
1971 // check if font is already embedded
1972 for (i
= 0; i
< fontFileIDLen
; ++i
) {
1973 if (fontFileIDs
[i
].num
== id
->num
&&
1974 fontFileIDs
[i
].gen
== id
->gen
)
1978 // add entry to fontFileIDs list
1979 if (fontFileIDLen
>= fontFileIDSize
) {
1980 fontFileIDSize
+= 64;
1981 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
1983 fontFileIDs
[fontFileIDLen
++] = *id
;
1985 // beginning comment
1986 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1987 embFontList
->append("%%+ font ");
1988 embFontList
->append(psName
->getCString());
1989 embFontList
->append("\n");
1991 // convert it to a Type 1 font
1992 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
1993 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
1994 ffT1C
->convertToType1(NULL
, gTrue
, outputFunc
, outputStream
);
2000 writePS("%%EndResource\n");
2003 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont
*font
, Ref
*id
,
2012 // check if font is already embedded
2013 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2014 if (fontFileIDs
[i
].num
== id
->num
&&
2015 fontFileIDs
[i
].gen
== id
->gen
) {
2016 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2017 psName
->append(unique
);
2022 // add entry to fontFileIDs list
2023 if (i
== fontFileIDLen
) {
2024 if (fontFileIDLen
>= fontFileIDSize
) {
2025 fontFileIDSize
+= 64;
2026 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2028 fontFileIDs
[fontFileIDLen
++] = *id
;
2031 // beginning comment
2032 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2033 embFontList
->append("%%+ font ");
2034 embFontList
->append(psName
->getCString());
2035 embFontList
->append("\n");
2037 // convert it to a Type 42 font
2038 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2039 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2040 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2041 ffTT
->convertToType42(psName
->getCString(),
2042 ((Gfx8BitFont
*)font
)->getHasEncoding()
2043 ? ((Gfx8BitFont
*)font
)->getEncoding()
2045 codeToGID
, outputFunc
, outputStream
);
2052 writePS("%%EndResource\n");
2055 void PSOutputDev::setupExternalTrueTypeFont(GfxFont
*font
, GString
*psName
) {
2064 // check if font is already embedded
2065 fileName
= font
->getExtFontFile();
2066 for (i
= 0; i
< fontFileNameLen
; ++i
) {
2067 if (!fontFileNames
[i
]->cmp(fileName
)) {
2068 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2069 psName
->append(unique
);
2074 // add entry to fontFileNames list
2075 if (i
== fontFileNameLen
) {
2076 if (fontFileNameLen
>= fontFileNameSize
) {
2077 fontFileNameSize
+= 64;
2079 (GString
**)greallocn(fontFileNames
,
2080 fontFileNameSize
, sizeof(GString
*));
2082 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
2085 // beginning comment
2086 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2087 embFontList
->append("%%+ font ");
2088 embFontList
->append(psName
->getCString());
2089 embFontList
->append("\n");
2091 // convert it to a Type 42 font
2092 fontBuf
= font
->readExtFontFile(&fontLen
);
2093 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2094 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2095 ffTT
->convertToType42(psName
->getCString(),
2096 ((Gfx8BitFont
*)font
)->getHasEncoding()
2097 ? ((Gfx8BitFont
*)font
)->getEncoding()
2099 codeToGID
, outputFunc
, outputStream
);
2105 writePS("%%EndResource\n");
2108 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont
*font
, Ref
*id
,
2115 // check if font is already embedded
2116 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2117 if (fontFileIDs
[i
].num
== id
->num
&&
2118 fontFileIDs
[i
].gen
== id
->gen
)
2122 // add entry to fontFileIDs list
2123 if (fontFileIDLen
>= fontFileIDSize
) {
2124 fontFileIDSize
+= 64;
2125 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2127 fontFileIDs
[fontFileIDLen
++] = *id
;
2129 // beginning comment
2130 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2131 embFontList
->append("%%+ font ");
2132 embFontList
->append(psName
->getCString());
2133 embFontList
->append("\n");
2135 // convert it to a Type 0 font
2136 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2137 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2138 if (globalParams
->getPSLevel() >= psLevel3
) {
2139 // Level 3: use a CID font
2140 ffT1C
->convertToCIDType0(psName
->getCString(), outputFunc
, outputStream
);
2142 // otherwise: use a non-CID composite font
2143 ffT1C
->convertToType0(psName
->getCString(), outputFunc
, outputStream
);
2150 writePS("%%EndResource\n");
2153 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont
*font
, Ref
*id
,
2155 GBool needVerticalMetrics
) {
2162 // check if font is already embedded
2163 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2164 if (fontFileIDs
[i
].num
== id
->num
&&
2165 fontFileIDs
[i
].gen
== id
->gen
) {
2166 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2167 psName
->append(unique
);
2172 // add entry to fontFileIDs list
2173 if (fontFileIDLen
>= fontFileIDSize
) {
2174 fontFileIDSize
+= 64;
2175 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2177 fontFileIDs
[fontFileIDLen
++] = *id
;
2179 // beginning comment
2180 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2181 embFontList
->append("%%+ font ");
2182 embFontList
->append(psName
->getCString());
2183 embFontList
->append("\n");
2185 // convert it to a Type 0 font
2186 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2187 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2188 if (globalParams
->getPSLevel() >= psLevel3
) {
2189 // Level 3: use a CID font
2190 ffTT
->convertToCIDType2(psName
->getCString(),
2191 ((GfxCIDFont
*)font
)->getCIDToGID(),
2192 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2193 needVerticalMetrics
,
2194 outputFunc
, outputStream
);
2196 // otherwise: use a non-CID composite font
2197 ffTT
->convertToType0(psName
->getCString(),
2198 ((GfxCIDFont
*)font
)->getCIDToGID(),
2199 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2200 needVerticalMetrics
,
2201 outputFunc
, outputStream
);
2208 writePS("%%EndResource\n");
2211 void PSOutputDev::setupType3Font(GfxFont
*font
, GString
*psName
,
2212 Dict
*parentResDict
) {
2222 // set up resources used by font
2223 if ((resDict
= ((Gfx8BitFont
*)font
)->getResources())) {
2224 inType3Char
= gTrue
;
2225 setupResources(resDict
);
2226 inType3Char
= gFalse
;
2228 resDict
= parentResDict
;
2231 // beginning comment
2232 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2233 embFontList
->append("%%+ font ");
2234 embFontList
->append(psName
->getCString());
2235 embFontList
->append("\n");
2238 writePS("8 dict begin\n");
2239 writePS("/FontType 3 def\n");
2240 m
= font
->getFontMatrix();
2241 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
2242 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
2243 m
= font
->getFontBBox();
2244 writePSFmt("/FontBBox [%g %g %g %g] def\n",
2245 m
[0], m
[1], m
[2], m
[3]);
2246 writePS("/Encoding 256 array def\n");
2247 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2248 writePS("/BuildGlyph {\n");
2249 writePS(" exch /CharProcs get exch\n");
2250 writePS(" 2 copy known not { pop /.notdef } if\n");
2251 writePS(" get exec\n");
2252 writePS("} bind def\n");
2253 writePS("/BuildChar {\n");
2254 writePS(" 1 index /Encoding get exch get\n");
2255 writePS(" 1 index /BuildGlyph get exec\n");
2256 writePS("} bind def\n");
2257 if ((charProcs
= ((Gfx8BitFont
*)font
)->getCharProcs())) {
2258 writePSFmt("/CharProcs %d dict def\n", charProcs
->getLength());
2259 writePS("CharProcs begin\n");
2264 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
2265 inType3Char
= gTrue
;
2266 t3Cacheable
= gFalse
;
2267 for (i
= 0; i
< charProcs
->getLength(); ++i
) {
2269 writePSName(charProcs
->getKey(i
));
2271 gfx
->display(charProcs
->getVal(i
, &charProc
));
2275 sprintf(buf
, "%g %g %g %g %g %g setcachedevice\n",
2276 t3WX
, t3WY
, t3LLX
, t3LLY
, t3URX
, t3URY
);
2278 sprintf(buf
, "%g %g setcharwidth\n", t3WX
, t3WY
);
2280 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
2281 (*outputFunc
)(outputStream
, t3String
->getCString(),
2282 t3String
->getLength());
2286 (*outputFunc
)(outputStream
, "Q\n", 2);
2289 inType3Char
= gFalse
;
2293 writePS("currentdict end\n");
2294 writePSFmt("/%s exch definefont pop\n", psName
->getCString());
2297 writePS("%%EndResource\n");
2300 void PSOutputDev::setupImages(Dict
*resDict
) {
2301 Object xObjDict
, xObj
, xObjRef
, subtypeObj
;
2304 if (!(mode
== psModeForm
|| inType3Char
)) {
2308 resDict
->lookup("XObject", &xObjDict
);
2309 if (xObjDict
.isDict()) {
2310 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
2311 xObjDict
.dictGetValNF(i
, &xObjRef
);
2312 xObjDict
.dictGetVal(i
, &xObj
);
2313 if (xObj
.isStream()) {
2314 xObj
.streamGetDict()->lookup("Subtype", &subtypeObj
);
2315 if (subtypeObj
.isName("Image")) {
2316 if (xObjRef
.isRef()) {
2317 setupImage(xObjRef
.getRef(), xObj
.getStream());
2319 error(-1, "Image in resource dict is not an indirect reference");
2331 void PSOutputDev::setupImage(Ref id
, Stream
*str
) {
2334 int size
, line
, col
, i
;
2336 // construct an encoder stream
2337 useASCIIHex
= level
== psLevel1
|| level
== psLevel1Sep
||
2338 globalParams
->getPSASCIIHex();
2340 str
= new ASCIIHexEncoder(str
);
2342 str
= new ASCII85Encoder(str
);
2345 // compute image data size
2351 } while (c
== '\n' || c
== '\r');
2352 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2359 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2362 } while (c
== '\n' || c
== '\r');
2363 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2373 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2375 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size
, id
.num
, id
.gen
);
2378 // write the data into the array
2381 writePS((char *)(useASCIIHex
? "dup 0 <" : "dup 0 <~"));
2385 } while (c
== '\n' || c
== '\r');
2386 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2395 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2398 } while (c
== '\n' || c
== '\r');
2399 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2406 // each line is: "dup nnnnn <~...data...~> put<eol>"
2407 // so max data length = 255 - 20 = 235
2408 // chunks are 1 or 4 bytes each, so we have to stop at 232
2409 // but make it 225 just to be safe
2411 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2413 writePSFmt((char *)(useASCIIHex
? "dup %d <" : "dup %d <~"), line
);
2416 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2417 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2424 GBool
PSOutputDev::startPage(int pageNum
, GfxState
*state
) {
2425 int x1
, y1
, x2
, y2
, width
, height
;
2426 int imgWidth
, imgHeight
, imgWidth2
, imgHeight2
;
2430 if (mode
== psModePS
) {
2431 writePSFmt("%%%%Page: %d %d\n", pageNum
, seqPage
);
2432 writePS("%%BeginPageSetup\n");
2437 (*underlayCbk
)(this, underlayCbkData
);
2446 // rotate, translate, and scale page
2447 imgWidth
= imgURX
- imgLLX
;
2448 imgHeight
= imgURY
- imgLLY
;
2449 x1
= (int)floor(state
->getX1());
2450 y1
= (int)floor(state
->getY1());
2451 x2
= (int)ceil(state
->getX2());
2452 y2
= (int)ceil(state
->getY2());
2456 // rotation and portrait/landscape mode
2458 rotate
= (360 - rotate0
) % 360;
2461 rotate
= (360 - state
->getRotate()) % 360;
2462 if (rotate
== 0 || rotate
== 180) {
2463 if (width
> height
&& width
> imgWidth
) {
2469 } else { // rotate == 90 || rotate == 270
2470 if (height
> width
&& height
> imgWidth
) {
2471 rotate
= 270 - rotate
;
2478 writePSFmt("%%%%PageOrientation: %s\n",
2479 landscape
? "Landscape" : "Portrait");
2480 writePS("pdfStartPage\n");
2482 imgWidth2
= imgWidth
;
2483 imgHeight2
= imgHeight
;
2484 } else if (rotate
== 90) {
2485 writePS("90 rotate\n");
2487 imgWidth2
= imgHeight
;
2488 imgHeight2
= imgWidth
;
2489 } else if (rotate
== 180) {
2490 writePS("180 rotate\n");
2491 imgWidth2
= imgWidth
;
2492 imgHeight2
= imgHeight
;
2495 } else { // rotate == 270
2496 writePS("270 rotate\n");
2498 imgWidth2
= imgHeight
;
2499 imgHeight2
= imgWidth
;
2502 if (xScale0
> 0 && yScale0
> 0) {
2505 } else if ((globalParams
->getPSShrinkLarger() &&
2506 (width
> imgWidth2
|| height
> imgHeight2
)) ||
2507 (globalParams
->getPSExpandSmaller() &&
2508 (width
< imgWidth2
&& height
< imgHeight2
))) {
2509 xScale
= (double)imgWidth2
/ (double)width
;
2510 yScale
= (double)imgHeight2
/ (double)height
;
2511 if (yScale
< xScale
) {
2517 xScale
= yScale
= 1;
2519 paperHeight
= height
;
2522 // deal with odd bounding boxes or clipping
2523 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2524 tx
-= xScale
* clipLLX0
;
2525 ty
-= yScale
* clipLLY0
;
2531 if (globalParams
->getPSCenter()) {
2532 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2533 tx
+= (imgWidth2
- xScale
* (clipURX0
- clipLLX0
)) / 2;
2534 ty
+= (imgHeight2
- yScale
* (clipURY0
- clipLLY0
)) / 2;
2536 tx
+= (imgWidth2
- xScale
* width
) / 2;
2537 ty
+= (imgHeight2
- yScale
* height
) / 2;
2540 tx
+= rotate
== 0 ? imgLLX
+ tx0
: imgLLY
+ ty0
;
2541 ty
+= rotate
== 0 ? imgLLY
+ ty0
: -(imgLLX
+ tx0
);
2542 if (tx
!= 0 || ty
!= 0) {
2543 writePSFmt("%g %g translate\n", tx
, ty
);
2545 if (xScale
!= 1 || yScale
!= 1) {
2546 writePSFmt("%0.4f %0.4f scale\n", xScale
, xScale
);
2548 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2549 writePSFmt("%g %g %g %g re W\n",
2550 clipLLX0
, clipLLY0
, clipURX0
- clipLLX0
, clipURY0
- clipLLY0
);
2552 writePSFmt("%d %d %d %d re W\n", x1
, y1
, x2
- x1
, y2
- y1
);
2555 writePS("%%EndPageSetup\n");
2560 writePS("pdfStartPage\n");
2562 rotate
= (360 - state
->getRotate()) % 360;
2564 } else if (rotate
== 90) {
2565 writePS("90 rotate\n");
2568 } else if (rotate
== 180) {
2569 writePS("180 rotate\n");
2570 tx
= -(epsX1
+ epsX2
);
2571 ty
= -(epsY1
+ epsY2
);
2572 } else { // rotate == 270
2573 writePS("270 rotate\n");
2577 if (tx
!= 0 || ty
!= 0) {
2578 writePSFmt("%g %g translate\n", tx
, ty
);
2580 xScale
= yScale
= 1;
2584 writePS("/PaintProc {\n");
2585 writePS("begin xpdf begin\n");
2586 writePS("pdfStartPage\n");
2588 xScale
= yScale
= 1;
2593 if (!checkRange(pageNum
))
2599 void PSOutputDev::endPage() {
2602 (*overlayCbk
)(this, overlayCbkData
);
2605 if (mode
== psModeForm
) {
2606 writePS("pdfEndPage\n");
2607 writePS("end end\n");
2609 writePS("end end\n");
2612 writePS("showpage\n");
2614 writePS("%%PageTrailer\n");
2619 void PSOutputDev::saveState(GfxState
*state
) {
2624 void PSOutputDev::restoreState(GfxState
*state
) {
2629 void PSOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
2630 double m21
, double m22
, double m31
, double m32
) {
2631 writePSFmt("[%g %g %g %g %g %g] cm\n", m11
, m12
, m21
, m22
, m31
, m32
);
2634 void PSOutputDev::updateLineDash(GfxState
*state
) {
2639 state
->getLineDash(&dash
, &length
, &start
);
2641 for (i
= 0; i
< length
; ++i
) {
2643 dash
[i
] == 0 ? 1 : dash
[i
],
2644 (i
== length
-1) ? "" : " ");
2646 writePSFmt("] %g d\n", start
);
2649 void PSOutputDev::updateFlatness(GfxState
*state
) {
2650 writePSFmt("%d i\n", state
->getFlatness());
2653 void PSOutputDev::updateLineJoin(GfxState
*state
) {
2654 writePSFmt("%d j\n", state
->getLineJoin());
2657 void PSOutputDev::updateLineCap(GfxState
*state
) {
2658 writePSFmt("%d J\n", state
->getLineCap());
2661 void PSOutputDev::updateMiterLimit(GfxState
*state
) {
2662 writePSFmt("%g M\n", state
->getMiterLimit());
2665 void PSOutputDev::updateLineWidth(GfxState
*state
) {
2666 writePSFmt("%g w\n", state
->getLineWidth());
2669 void PSOutputDev::updateFillColorSpace(GfxState
*state
) {
2676 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2677 dumpColorSpaceL2(state
->getFillColorSpace(), gTrue
, gFalse
);
2687 void PSOutputDev::updateStrokeColorSpace(GfxState
*state
) {
2694 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2695 dumpColorSpaceL2(state
->getStrokeColorSpace(), gTrue
, gFalse
);
2705 void PSOutputDev::updateFillColor(GfxState
*state
) {
2710 GfxSeparationColorSpace
*sepCS
;
2716 state
->getFillGray(&gray
);
2717 writePSFmt("%g g\n", colToDbl(gray
));
2720 state
->getFillCMYK(&cmyk
);
2721 c
= colToDbl(cmyk
.c
);
2722 m
= colToDbl(cmyk
.m
);
2723 y
= colToDbl(cmyk
.y
);
2724 k
= colToDbl(cmyk
.k
);
2725 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2726 addProcessColor(c
, m
, y
, k
);
2730 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2731 colorPtr
= state
->getFillColor();
2733 for (i
= 0; i
< state
->getFillColorSpace()->getNComps(); ++i
) {
2737 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2744 if (state
->getFillColorSpace()->getMode() == csSeparation
) {
2745 sepCS
= (GfxSeparationColorSpace
*)state
->getFillColorSpace();
2746 color
.c
[0] = gfxColorComp1
;
2747 sepCS
->getCMYK(&color
, &cmyk
);
2748 writePSFmt("%g %g %g %g %g (%s) ck\n",
2749 colToDbl(state
->getFillColor()->c
[0]),
2750 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2751 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2752 sepCS
->getName()->getCString());
2753 addCustomColor(sepCS
);
2755 state
->getFillCMYK(&cmyk
);
2756 c
= colToDbl(cmyk
.c
);
2757 m
= colToDbl(cmyk
.m
);
2758 y
= colToDbl(cmyk
.y
);
2759 k
= colToDbl(cmyk
.k
);
2760 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2761 addProcessColor(c
, m
, y
, k
);
2765 t3Cacheable
= gFalse
;
2768 void PSOutputDev::updateStrokeColor(GfxState
*state
) {
2773 GfxSeparationColorSpace
*sepCS
;
2779 state
->getStrokeGray(&gray
);
2780 writePSFmt("%g G\n", colToDbl(gray
));
2783 state
->getStrokeCMYK(&cmyk
);
2784 c
= colToDbl(cmyk
.c
);
2785 m
= colToDbl(cmyk
.m
);
2786 y
= colToDbl(cmyk
.y
);
2787 k
= colToDbl(cmyk
.k
);
2788 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2789 addProcessColor(c
, m
, y
, k
);
2793 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2794 colorPtr
= state
->getStrokeColor();
2796 for (i
= 0; i
< state
->getStrokeColorSpace()->getNComps(); ++i
) {
2800 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2807 if (state
->getStrokeColorSpace()->getMode() == csSeparation
) {
2808 sepCS
= (GfxSeparationColorSpace
*)state
->getStrokeColorSpace();
2809 color
.c
[0] = gfxColorComp1
;
2810 sepCS
->getCMYK(&color
, &cmyk
);
2811 writePSFmt("%g %g %g %g %g (%s) CK\n",
2812 colToDbl(state
->getStrokeColor()->c
[0]),
2813 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2814 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2815 sepCS
->getName()->getCString());
2816 addCustomColor(sepCS
);
2818 state
->getStrokeCMYK(&cmyk
);
2819 c
= colToDbl(cmyk
.c
);
2820 m
= colToDbl(cmyk
.m
);
2821 y
= colToDbl(cmyk
.y
);
2822 k
= colToDbl(cmyk
.k
);
2823 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2824 addProcessColor(c
, m
, y
, k
);
2828 t3Cacheable
= gFalse
;
2831 void PSOutputDev::addProcessColor(double c
, double m
, double y
, double k
) {
2833 processColors
|= psProcessCyan
;
2836 processColors
|= psProcessMagenta
;
2839 processColors
|= psProcessYellow
;
2842 processColors
|= psProcessBlack
;
2846 void PSOutputDev::addCustomColor(GfxSeparationColorSpace
*sepCS
) {
2847 PSOutCustomColor
*cc
;
2851 for (cc
= customColors
; cc
; cc
= cc
->next
) {
2852 if (!cc
->name
->cmp(sepCS
->getName())) {
2856 color
.c
[0] = gfxColorComp1
;
2857 sepCS
->getCMYK(&color
, &cmyk
);
2858 cc
= new PSOutCustomColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2859 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2860 sepCS
->getName()->copy());
2861 cc
->next
= customColors
;
2865 void PSOutputDev::updateFillOverprint(GfxState
*state
) {
2866 if (level
>= psLevel2
) {
2867 writePSFmt("%s op\n", state
->getFillOverprint() ? "true" : "false");
2871 void PSOutputDev::updateStrokeOverprint(GfxState
*state
) {
2872 if (level
>= psLevel2
) {
2873 writePSFmt("%s OP\n", state
->getStrokeOverprint() ? "true" : "false");
2877 void PSOutputDev::updateFont(GfxState
*state
) {
2878 if (state
->getFont()) {
2879 writePSFmt("/F%d_%d %g Tf\n",
2880 state
->getFont()->getID()->num
, state
->getFont()->getID()->gen
,
2881 fabs(state
->getFontSize()) < 0.00001 ? 0.00001
2882 : state
->getFontSize());
2886 void PSOutputDev::updateTextMat(GfxState
*state
) {
2889 mat
= state
->getTextMat();
2890 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.00001) {
2891 // avoid a singular (or close-to-singular) matrix
2892 writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat
[4], mat
[5]);
2894 writePSFmt("[%g %g %g %g %g %g] Tm\n",
2895 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
2899 void PSOutputDev::updateCharSpace(GfxState
*state
) {
2900 writePSFmt("%g Tc\n", state
->getCharSpace());
2903 void PSOutputDev::updateRender(GfxState
*state
) {
2906 rm
= state
->getRender();
2907 writePSFmt("%d Tr\n", rm
);
2909 if (rm
!= 0 && rm
!= 3) {
2910 t3Cacheable
= gFalse
;
2914 void PSOutputDev::updateRise(GfxState
*state
) {
2915 writePSFmt("%g Ts\n", state
->getRise());
2918 void PSOutputDev::updateWordSpace(GfxState
*state
) {
2919 writePSFmt("%g Tw\n", state
->getWordSpace());
2922 void PSOutputDev::updateHorizScaling(GfxState
*state
) {
2925 h
= state
->getHorizScaling();
2926 if (fabs(h
) < 0.01) {
2929 writePSFmt("%g Tz\n", h
);
2932 void PSOutputDev::updateTextPos(GfxState
*state
) {
2933 writePSFmt("%g %g Td\n", state
->getLineX(), state
->getLineY());
2936 void PSOutputDev::updateTextShift(GfxState
*state
, double shift
) {
2937 if (state
->getFont()->getWMode()) {
2938 writePSFmt("%g TJmV\n", shift
);
2940 writePSFmt("%g TJm\n", shift
);
2944 void PSOutputDev::stroke(GfxState
*state
) {
2945 doPath(state
->getPath());
2947 // if we're construct a cacheable Type 3 glyph, we need to do
2948 // everything in the fill color
2955 void PSOutputDev::fill(GfxState
*state
) {
2956 doPath(state
->getPath());
2960 void PSOutputDev::eoFill(GfxState
*state
) {
2961 doPath(state
->getPath());
2965 void PSOutputDev::tilingPatternFill(GfxState
*state
, Object
*str
,
2966 int paintType
, Dict
*resDict
,
2967 double *mat
, double *bbox
,
2968 int x0
, int y0
, int x1
, int y1
,
2969 double xStep
, double yStep
) {
2973 // define a Type 3 font
2974 writePS("8 dict begin\n");
2975 writePS("/FontType 3 def\n");
2976 writePS("/FontMatrix [1 0 0 1 0 0] def\n");
2977 writePSFmt("/FontBBox [%g %g %g %g] def\n",
2978 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
2979 writePS("/Encoding 256 array def\n");
2980 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2981 writePS(" Encoding 120 /x put\n");
2982 writePS("/BuildGlyph {\n");
2983 writePS(" exch /CharProcs get exch\n");
2984 writePS(" 2 copy known not { pop /.notdef } if\n");
2985 writePS(" get exec\n");
2986 writePS("} bind def\n");
2987 writePS("/BuildChar {\n");
2988 writePS(" 1 index /Encoding get exch get\n");
2989 writePS(" 1 index /BuildGlyph get exec\n");
2990 writePS("} bind def\n");
2991 writePS("/CharProcs 1 dict def\n");
2992 writePS("CharProcs begin\n");
2997 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
2999 if (paintType
== 2) {
3000 writePSFmt("%g 0 %g %g %g %g setcachedevice\n",
3001 xStep
, bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3003 writePSFmt("%g 0 setcharwidth\n", xStep
);
3005 inType3Char
= gTrue
;
3006 ++numTilingPatterns
;
3008 --numTilingPatterns
;
3009 inType3Char
= gFalse
;
3013 writePS("currentdict end\n");
3014 writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns
);
3017 writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns
);
3018 writePSFmt("gsave [%g %g %g %g %g %g] concat\n",
3019 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3020 writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n",
3021 y0
, y1
- 1, x0
* xStep
, yStep
, x0
, x1
- 1);
3022 writePS("grestore\n");
3025 void PSOutputDev::functionShadedFill(GfxState
*state
,
3026 GfxFunctionShading
*shading
) {
3027 double x0
, y0
, x1
, y1
;
3031 shading
->getDomain(&x0
, &y0
, &x1
, &y1
);
3032 mat
= shading
->getMatrix();
3033 writePSFmt("/mat [%g %g %g %g %g %g] def\n",
3034 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3035 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3036 if (shading
->getNFuncs() == 1) {
3038 cvtFunction(shading
->getFunc(0));
3041 writePS("/func {\n");
3042 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3043 if (i
< shading
->getNFuncs() - 1) {
3044 writePS("2 copy\n");
3046 cvtFunction(shading
->getFunc(i
));
3048 if (i
< shading
->getNFuncs() - 1) {
3049 writePS("3 1 roll\n");
3054 writePSFmt("%g %g %g %g 0 funcSH\n", x0
, y0
, x1
, y1
);
3057 void PSOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
) {
3058 double xMin
, yMin
, xMax
, yMax
;
3059 double x0
, y0
, x1
, y1
, dx
, dy
, mul
;
3060 double tMin
, tMax
, t
, t0
, t1
;
3063 // get the clip region bbox
3064 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3066 // compute min and max t values, based on the four corners of the
3068 shading
->getCoords(&x0
, &y0
, &x1
, &y1
);
3071 mul
= 1 / (dx
* dx
+ dy
* dy
);
3072 tMin
= tMax
= ((xMin
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3073 t
= ((xMin
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3076 } else if (t
> tMax
) {
3079 t
= ((xMax
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3082 } else if (t
> tMax
) {
3085 t
= ((xMax
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3088 } else if (t
> tMax
) {
3091 if (tMin
< 0 && !shading
->getExtend0()) {
3094 if (tMax
> 1 && !shading
->getExtend1()) {
3098 // get the function domain
3099 t0
= shading
->getDomain0();
3100 t1
= shading
->getDomain1();
3102 // generate the PS code
3103 writePSFmt("/t0 %g def\n", t0
);
3104 writePSFmt("/t1 %g def\n", t1
);
3105 writePSFmt("/dt %g def\n", t1
- t0
);
3106 writePSFmt("/x0 %g def\n", x0
);
3107 writePSFmt("/y0 %g def\n", y0
);
3108 writePSFmt("/dx %g def\n", x1
- x0
);
3109 writePSFmt("/x1 %g def\n", x1
);
3110 writePSFmt("/y1 %g def\n", y1
);
3111 writePSFmt("/dy %g def\n", y1
- y0
);
3112 writePSFmt("/xMin %g def\n", xMin
);
3113 writePSFmt("/yMin %g def\n", yMin
);
3114 writePSFmt("/xMax %g def\n", xMax
);
3115 writePSFmt("/yMax %g def\n", yMax
);
3116 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3117 if (shading
->getNFuncs() == 1) {
3119 cvtFunction(shading
->getFunc(0));
3122 writePS("/func {\n");
3123 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3124 if (i
< shading
->getNFuncs() - 1) {
3127 cvtFunction(shading
->getFunc(i
));
3129 if (i
< shading
->getNFuncs() - 1) {
3135 writePSFmt("%g %g 0 axialSH\n", tMin
, tMax
);
3138 void PSOutputDev::radialShadedFill(GfxState
*state
,
3139 GfxRadialShading
*shading
) {
3140 double x0
, y0
, r0
, x1
, y1
, r1
, t0
, t1
, sMin
, sMax
;
3141 double xMin
, yMin
, xMax
, yMax
;
3145 // get the shading info
3146 shading
->getCoords(&x0
, &y0
, &r0
, &x1
, &y1
, &r1
);
3147 t0
= shading
->getDomain0();
3148 t1
= shading
->getDomain1();
3150 // compute the (possibly extended) s range
3153 if (shading
->getExtend0()) {
3155 // extend the smaller end
3156 sMin
= -r0
/ (r1
- r0
);
3158 // extend the larger end
3159 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3160 d0
= (x0
- xMin
) * (x0
- xMin
);
3161 d1
= (x0
- xMax
) * (x0
- xMax
);
3162 sMin
= d0
> d1
? d0
: d1
;
3163 d0
= (y0
- yMin
) * (y0
- yMin
);
3164 d1
= (y0
- yMax
) * (y0
- yMax
);
3165 sMin
+= d0
> d1
? d0
: d1
;
3166 sMin
= (sqrt(sMin
) - r0
) / (r1
- r0
);
3169 } else if (sMin
< -20) {
3175 if (shading
->getExtend1()) {
3177 // extend the smaller end
3178 sMax
= -r0
/ (r1
- r0
);
3179 } else if (r1
> r0
) {
3180 // extend the larger end
3181 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3182 d0
= (x1
- xMin
) * (x1
- xMin
);
3183 d1
= (x1
- xMax
) * (x1
- xMax
);
3184 sMax
= d0
> d1
? d0
: d1
;
3185 d0
= (y1
- yMin
) * (y1
- yMin
);
3186 d1
= (y1
- yMax
) * (y1
- yMax
);
3187 sMax
+= d0
> d1
? d0
: d1
;
3188 sMax
= (sqrt(sMax
) - r0
) / (r1
- r0
);
3191 } else if (sMax
> 20) {
3198 // generate the PS code
3199 writePSFmt("/x0 %g def\n", x0
);
3200 writePSFmt("/x1 %g def\n", x1
);
3201 writePSFmt("/dx %g def\n", x1
- x0
);
3202 writePSFmt("/y0 %g def\n", y0
);
3203 writePSFmt("/y1 %g def\n", y1
);
3204 writePSFmt("/dy %g def\n", y1
- y0
);
3205 writePSFmt("/r0 %g def\n", r0
);
3206 writePSFmt("/r1 %g def\n", r1
);
3207 writePSFmt("/dr %g def\n", r1
- r0
);
3208 writePSFmt("/t0 %g def\n", t0
);
3209 writePSFmt("/t1 %g def\n", t1
);
3210 writePSFmt("/dt %g def\n", t1
- t0
);
3211 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3212 if (shading
->getNFuncs() == 1) {
3214 cvtFunction(shading
->getFunc(0));
3217 writePS("/func {\n");
3218 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3219 if (i
< shading
->getNFuncs() - 1) {
3222 cvtFunction(shading
->getFunc(i
));
3224 if (i
< shading
->getNFuncs() - 1) {
3230 writePSFmt("%g %g 0 radialSH\n", sMin
, sMax
);
3233 void PSOutputDev::clip(GfxState
*state
) {
3234 doPath(state
->getPath());
3238 void PSOutputDev::eoClip(GfxState
*state
) {
3239 doPath(state
->getPath());
3243 void PSOutputDev::doPath(GfxPath
*path
) {
3244 GfxSubpath
*subpath
;
3245 double x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
3248 n
= path
->getNumSubpaths();
3250 if (n
== 1 && path
->getSubpath(0)->getNumPoints() == 5) {
3251 subpath
= path
->getSubpath(0);
3252 x0
= subpath
->getX(0);
3253 y0
= subpath
->getY(0);
3254 x4
= subpath
->getX(4);
3255 y4
= subpath
->getY(4);
3256 if (x4
== x0
&& y4
== y0
) {
3257 x1
= subpath
->getX(1);
3258 y1
= subpath
->getY(1);
3259 x2
= subpath
->getX(2);
3260 y2
= subpath
->getY(2);
3261 x3
= subpath
->getX(3);
3262 y3
= subpath
->getY(3);
3263 if (x0
== x1
&& x2
== x3
&& y0
== y3
&& y1
== y2
) {
3264 writePSFmt("%g %g %g %g re\n",
3265 x0
< x2
? x0
: x2
, y0
< y1
? y0
: y1
,
3266 fabs(x2
- x0
), fabs(y1
- y0
));
3268 } else if (x0
== x3
&& x1
== x2
&& y0
== y1
&& y2
== y3
) {
3269 writePSFmt("%g %g %g %g re\n",
3270 x0
< x1
? x0
: x1
, y0
< y2
? y0
: y2
,
3271 fabs(x1
- x0
), fabs(y2
- y0
));
3277 for (i
= 0; i
< n
; ++i
) {
3278 subpath
= path
->getSubpath(i
);
3279 m
= subpath
->getNumPoints();
3280 writePSFmt("%g %g m\n", subpath
->getX(0), subpath
->getY(0));
3283 if (subpath
->getCurve(j
)) {
3284 writePSFmt("%g %g %g %g %g %g c\n", subpath
->getX(j
), subpath
->getY(j
),
3285 subpath
->getX(j
+1), subpath
->getY(j
+1),
3286 subpath
->getX(j
+2), subpath
->getY(j
+2));
3289 writePSFmt("%g %g l\n", subpath
->getX(j
), subpath
->getY(j
));
3293 if (subpath
->isClosed()) {
3299 void PSOutputDev::drawString(GfxState
*state
, GString
*s
) {
3303 double dx
, dy
, dx2
, dy2
, originX
, originY
;
3309 int len
, nChars
, uLen
, n
, m
, i
, j
;
3311 // check for invisible text -- this is used by Acrobat Capture
3312 if (state
->getRender() == 3) {
3316 // ignore empty strings
3317 if (s
->getLength() == 0) {
3322 if (!(font
= state
->getFont())) {
3325 wMode
= font
->getWMode();
3327 // check for a subtitute 16-bit font
3329 if (font
->isCIDFont()) {
3330 for (i
= 0; i
< font16EncLen
; ++i
) {
3331 if (font
->getID()->num
== font16Enc
[i
].fontID
.num
&&
3332 font
->getID()->gen
== font16Enc
[i
].fontID
.gen
) {
3333 uMap
= globalParams
->getUnicodeMap(font16Enc
[i
].enc
);
3339 // compute width of chars in string, ignoring char spacing and word
3340 // spacing -- the Tj operator will adjust for the metrics of the
3341 // font that's actually used
3344 p
= s
->getCString();
3345 len
= s
->getLength();
3346 if (font
->isCIDFont()) {
3352 n
= font
->getNextChar(p
, len
, &code
,
3353 u
, (int)(sizeof(u
) / sizeof(Unicode
)), &uLen
,
3354 &dx2
, &dy2
, &originX
, &originY
);
3355 if (font
->isCIDFont()) {
3357 for (i
= 0; i
< uLen
; ++i
) {
3358 m
= uMap
->mapUnicode(u
[i
], buf
, (int)sizeof(buf
));
3359 for (j
= 0; j
< m
; ++j
) {
3363 //~ this really needs to get the number of chars in the target
3364 //~ encoding - which may be more than the number of Unicode
3368 s2
->append((char)((code
>> 8) & 0xff));
3369 s2
->append((char)(code
& 0xff));
3378 dx
*= state
->getFontSize() * state
->getHorizScaling();
3379 dy
*= state
->getFontSize();
3384 if (s2
->getLength() > 0) {
3386 if (font
->isCIDFont()) {
3388 writePSFmt(" %d %g Tj16V\n", nChars
, dy
);
3390 writePSFmt(" %d %g Tj16\n", nChars
, dx
);
3393 writePSFmt(" %g Tj\n", dx
);
3396 if (font
->isCIDFont()) {
3400 if (state
->getRender() & 4) {
3401 haveTextClip
= gTrue
;
3405 void PSOutputDev::endTextObject(GfxState
*state
) {
3408 haveTextClip
= gFalse
;
3412 void PSOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
3413 int width
, int height
, GBool invert
,
3417 len
= height
* ((width
+ 7) / 8);
3418 if (level
== psLevel1
|| level
== psLevel1Sep
) {
3419 doImageL1(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
);
3421 doImageL2(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
,
3422 NULL
, NULL
, 0, 0, gFalse
);
3426 void PSOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3427 int width
, int height
, GfxImageColorMap
*colorMap
,
3428 int *maskColors
, GBool inlineImg
) {
3431 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3432 colorMap
->getBits() + 7) / 8);
3435 doImageL1(ref
, colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3438 //~ handle indexed, separation, ... color spaces
3439 doImageL1Sep(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3445 doImageL2(ref
, colorMap
, gFalse
, inlineImg
, str
,
3446 width
, height
, len
, maskColors
, NULL
, 0, 0, gFalse
);
3449 t3Cacheable
= gFalse
;
3452 void PSOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3453 int width
, int height
,
3454 GfxImageColorMap
*colorMap
,
3456 int maskWidth
, int maskHeight
,
3460 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3461 colorMap
->getBits() + 7) / 8);
3464 doImageL1(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3467 //~ handle indexed, separation, ... color spaces
3468 doImageL1Sep(colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3474 doImageL2(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
,
3475 NULL
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
3478 t3Cacheable
= gFalse
;
3481 void PSOutputDev::doImageL1(Object
*ref
, GfxImageColorMap
*colorMap
,
3482 GBool invert
, GBool inlineImg
,
3483 Stream
*str
, int width
, int height
, int len
) {
3484 ImageStream
*imgStr
;
3485 Guchar pixBuf
[gfxColorMaxComps
];
3487 int col
, x
, y
, c
, i
;
3489 if (inType3Char
&& !colorMap
) {
3492 str
= new FixedLengthEncoder(str
, len
);
3493 str
= new ASCIIHexEncoder(str
);
3500 } while (c
== '\n' || c
== '\r');
3501 if (c
== '>' || c
== EOF
) {
3506 // each line is: "<...data...><eol>"
3507 // so max data length = 255 - 4 = 251
3508 // but make it 240 just to be safe
3509 // chunks are 2 bytes each, so we need to stop on an even col number
3514 } while (c
!= '>' && c
!= EOF
);
3520 // set up to use the array already created by setupImages()
3521 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3525 // image/imagemask command
3526 if (inType3Char
&& !colorMap
) {
3527 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
3528 width
, height
, invert
? "true" : "false",
3529 width
, -height
, height
);
3530 } else if (colorMap
) {
3531 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
3533 width
, -height
, height
);
3535 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
3536 width
, height
, invert
? "true" : "false",
3537 width
, -height
, height
);
3541 if (!(inType3Char
&& !colorMap
)) {
3545 // set up to process the data stream
3546 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3547 colorMap
->getBits());
3550 // process the data stream
3552 for (y
= 0; y
< height
; ++y
) {
3555 for (x
= 0; x
< width
; ++x
) {
3556 imgStr
->getPixel(pixBuf
);
3557 colorMap
->getGray(pixBuf
, &gray
);
3558 writePSFmt("%02x", colToByte(gray
));
3574 for (y
= 0; y
< height
; ++y
) {
3575 for (x
= 0; x
< width
; x
+= 8) {
3576 writePSFmt("%02x", str
->getChar() & 0xff);
3591 void PSOutputDev::doImageL1Sep(GfxImageColorMap
*colorMap
,
3592 GBool invert
, GBool inlineImg
,
3593 Stream
*str
, int width
, int height
, int len
) {
3594 ImageStream
*imgStr
;
3596 Guchar pixBuf
[gfxColorMaxComps
];
3600 // width, height, matrix, bits per component
3601 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
3603 width
, -height
, height
);
3605 // allocate a line buffer
3606 lineBuf
= (Guchar
*)gmalloc(4 * width
);
3608 // set up to process the data stream
3609 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3610 colorMap
->getBits());
3613 // process the data stream
3615 for (y
= 0; y
< height
; ++y
) {
3618 for (x
= 0; x
< width
; ++x
) {
3619 imgStr
->getPixel(pixBuf
);
3620 colorMap
->getCMYK(pixBuf
, &cmyk
);
3621 lineBuf
[4*x
+0] = colToByte(cmyk
.c
);
3622 lineBuf
[4*x
+1] = colToByte(cmyk
.m
);
3623 lineBuf
[4*x
+2] = colToByte(cmyk
.y
);
3624 lineBuf
[4*x
+3] = colToByte(cmyk
.k
);
3625 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3626 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
3629 // write one line of each color component
3630 for (comp
= 0; comp
< 4; ++comp
) {
3631 for (x
= 0; x
< width
; ++x
) {
3632 writePSFmt("%02x", lineBuf
[4*x
+ comp
]);
3649 void PSOutputDev::doImageL2(Object
*ref
, GfxImageColorMap
*colorMap
,
3650 GBool invert
, GBool inlineImg
,
3651 Stream
*str
, int width
, int height
, int len
,
3652 int *maskColors
, Stream
*maskStr
,
3653 int maskWidth
, int maskHeight
, GBool maskInvert
) {
3654 ImageStream
*imgStr
;
3658 GBool useRLE
, useASCII
, useASCIIHex
, useCompressed
;
3659 GfxSeparationColorSpace
*sepCS
;
3663 int col
, i
, x
, x0
, y
, y0
, maskXor
;
3665 // color key masking
3666 if (maskColors
&& colorMap
&& !inlineImg
) {
3667 // can't read the stream twice for inline images -- but masking
3668 // isn't allowed with inline images anyway
3670 numComps
= colorMap
->getNumPixelComps();
3671 imgStr
= new ImageStream(str
, width
, numComps
, colorMap
->getBits());
3673 for (y
= 0, y0
= 0; y
< height
; ++y
) {
3674 if (!(line
= imgStr
->getLine())) {
3677 for (x
= 0, x0
= 0, pix
= line
; x
< width
; ++x
, pix
+= numComps
) {
3678 for (i
= 0; i
< numComps
; ++i
) {
3679 if (pix
[i
] < maskColors
[2*i
] ||
3680 pix
[i
] > maskColors
[2*i
+1]) {
3684 if (i
== numComps
) {
3686 writePSFmt("0 %d %d %d\n", height
- y
, width
, y
- y0
);
3689 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, x
- x0
);
3695 if (x0
> 0 && x0
< width
) {
3696 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, width
- x0
);
3700 writePSFmt("0 0 %d %d\n", width
, height
- y0
);
3704 writePSFmt("] %d %d pdfImClip\n", width
, height
);
3707 } else if (maskStr
) {
3709 imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3711 maskXor
= maskInvert
? 1 : 0;
3712 for (y
= 0, y0
= 0; y
< maskHeight
; ++y
) {
3713 if (!(line
= imgStr
->getLine())) {
3716 for (x
= 0, x0
= 0, pix
= line
; x
< maskWidth
; ++x
, ++pix
) {
3717 if (*pix
^ maskXor
) {
3719 writePSFmt("0 %d %d %d\n", maskHeight
- y
, maskWidth
, y
- y0
);
3722 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, x
- x0
);
3728 if (x0
> 0 && x0
< maskWidth
) {
3729 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, maskWidth
- x0
);
3732 if (y0
< maskHeight
) {
3733 writePSFmt("0 0 %d %d\n", maskWidth
, maskHeight
- y0
);
3737 writePSFmt("] %d %d pdfImClip\n", maskWidth
, maskHeight
);
3742 dumpColorSpaceL2(colorMap
->getColorSpace(), gFalse
, gTrue
);
3743 writePS(" setcolorspace\n");
3746 useASCIIHex
= globalParams
->getPSASCIIHex();
3748 // set up the image data
3749 if (mode
== psModeForm
|| inType3Char
) {
3752 str
= new FixedLengthEncoder(str
, len
);
3754 str
= new ASCIIHexEncoder(str
);
3756 str
= new ASCII85Encoder(str
);
3760 writePS((char *)(useASCIIHex
? "[<" : "[<~"));
3764 } while (c
== '\n' || c
== '\r');
3765 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3774 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
3777 } while (c
== '\n' || c
== '\r');
3778 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3785 // each line is: "<~...data...~><eol>"
3786 // so max data length = 255 - 6 = 249
3787 // chunks are 1 or 5 bytes each, so we have to stop at 245
3788 // but make it 240 just to be safe
3790 writePS((char *)(useASCIIHex
? ">\n<" : "~>\n<~"));
3793 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
3794 writePS((char *)(useASCIIHex
? ">]\n" : "~>]\n"));
3799 // set up to use the array already created by setupImages()
3800 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3805 writePS("<<\n /ImageType 1\n");
3807 // width, height, matrix, bits per component
3808 writePSFmt(" /Width %d\n", width
);
3809 writePSFmt(" /Height %d\n", height
);
3810 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width
, -height
, height
);
3811 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3812 writePSFmt(" /BitsPerComponent 8\n");
3814 writePSFmt(" /BitsPerComponent %d\n",
3815 colorMap
? colorMap
->getBits() : 1);
3820 writePS(" /Decode [");
3821 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) &&
3822 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3823 // this matches up with the code in the pdfImSep operator
3824 n
= (1 << colorMap
->getBits()) - 1;
3825 writePSFmt("%g %g", colorMap
->getDecodeLow(0) * n
,
3826 colorMap
->getDecodeHigh(0) * n
);
3827 } else if (colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3828 numComps
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
3829 getAlt()->getNComps();
3830 for (i
= 0; i
< numComps
; ++i
) {
3837 numComps
= colorMap
->getNumPixelComps();
3838 for (i
= 0; i
< numComps
; ++i
) {
3842 writePSFmt("%g %g", colorMap
->getDecodeLow(i
),
3843 colorMap
->getDecodeHigh(i
));
3848 writePSFmt(" /Decode [%d %d]\n", invert
? 1 : 0, invert
? 0 : 1);
3851 if (mode
== psModeForm
|| inType3Char
) {
3854 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
3856 // end of image dictionary
3857 writePSFmt(">>\n%s\n", colorMap
? "image" : "imagemask");
3859 // get rid of the array and index
3860 writePS("pop pop\n");
3865 writePS(" /DataSource currentfile\n");
3866 s
= str
->getPSFilter(level
< psLevel2
? 1 : level
< psLevel3
? 2 : 3,
3868 if ((colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) ||
3872 useCompressed
= gFalse
;
3875 useASCII
= str
->isBinary();
3876 useCompressed
= gTrue
;
3879 writePSFmt(" /ASCII%sDecode filter\n",
3880 useASCIIHex
? "Hex" : "85");
3883 writePS(" /RunLengthDecode filter\n");
3885 if (useCompressed
) {
3886 writePS(s
->getCString());
3892 // cut off inline image streams at appropriate length
3894 str
= new FixedLengthEncoder(str
, len
);
3895 } else if (useCompressed
) {
3896 str
= str
->getBaseStream();
3899 // recode DeviceN data
3900 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3901 str
= new DeviceNRecoder(str
, width
, height
, colorMap
);
3904 // add RunLengthEncode and ASCIIHex/85 encode filters
3906 str
= new RunLengthEncoder(str
);
3910 str
= new ASCIIHexEncoder(str
);
3912 str
= new ASCII85Encoder(str
);
3916 // end of image dictionary
3921 // this can't happen -- OPI dictionaries are in XObjects
3922 error(-1, "Internal: OPI in inline image");
3925 // need to read the stream to count characters -- the length
3926 // is data-dependent (because of ASCII and RLE filters)
3929 while ((c
= str
->getChar()) != EOF
) {
3934 // +6/7 for "pdfIm\n" / "pdfImM\n"
3935 // +8 for newline + trailer
3936 n
+= colorMap
? 14 : 15;
3937 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n
);
3940 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) && colorMap
&&
3941 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3942 color
.c
[0] = gfxColorComp1
;
3943 sepCS
= (GfxSeparationColorSpace
*)colorMap
->getColorSpace();
3944 sepCS
->getCMYK(&color
, &cmyk
);
3945 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
3946 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3947 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
3948 sepCS
->getName()->getCString());
3950 writePSFmt("%s\n", colorMap
? "pdfIm" : "pdfImM");
3953 // copy the stream data
3955 while ((c
= str
->getChar()) != EOF
) {
3960 // add newline and trailer to the end
3962 writePS("%-EOD-\n");
3965 writePS("%%EndData\n");
3970 if (useRLE
|| useASCII
|| inlineImg
) {
3975 if ((maskColors
&& colorMap
&& !inlineImg
) || maskStr
) {
3976 writePS("pdfImClipEnd\n");
3980 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace
*colorSpace
,
3981 GBool genXform
, GBool updateColors
) {
3982 GfxCalGrayColorSpace
*calGrayCS
;
3983 GfxCalRGBColorSpace
*calRGBCS
;
3984 GfxLabColorSpace
*labCS
;
3985 GfxIndexedColorSpace
*indexedCS
;
3986 GfxSeparationColorSpace
*separationCS
;
3987 GfxDeviceNColorSpace
*deviceNCS
;
3988 GfxColorSpace
*baseCS
;
3990 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
3994 int n
, numComps
, numAltComps
;
3998 switch (colorSpace
->getMode()) {
4001 writePS("/DeviceGray");
4006 processColors
|= psProcessBlack
;
4011 calGrayCS
= (GfxCalGrayColorSpace
*)colorSpace
;
4012 writePS("[/CIEBasedA <<\n");
4013 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS
->getGamma());
4014 writePSFmt(" /MatrixA [%g %g %g]\n",
4015 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4016 calGrayCS
->getWhiteZ());
4017 writePSFmt(" /WhitePoint [%g %g %g]\n",
4018 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4019 calGrayCS
->getWhiteZ());
4020 writePSFmt(" /BlackPoint [%g %g %g]\n",
4021 calGrayCS
->getBlackX(), calGrayCS
->getBlackY(),
4022 calGrayCS
->getBlackZ());
4028 processColors
|= psProcessBlack
;
4033 writePS("/DeviceRGB");
4038 processColors
|= psProcessCMYK
;
4043 calRGBCS
= (GfxCalRGBColorSpace
*)colorSpace
;
4044 writePS("[/CIEBasedABC <<\n");
4045 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
4046 calRGBCS
->getGammaR(), calRGBCS
->getGammaG(),
4047 calRGBCS
->getGammaB());
4048 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
4049 calRGBCS
->getMatrix()[0], calRGBCS
->getMatrix()[1],
4050 calRGBCS
->getMatrix()[2], calRGBCS
->getMatrix()[3],
4051 calRGBCS
->getMatrix()[4], calRGBCS
->getMatrix()[5],
4052 calRGBCS
->getMatrix()[6], calRGBCS
->getMatrix()[7],
4053 calRGBCS
->getMatrix()[8]);
4054 writePSFmt(" /WhitePoint [%g %g %g]\n",
4055 calRGBCS
->getWhiteX(), calRGBCS
->getWhiteY(),
4056 calRGBCS
->getWhiteZ());
4057 writePSFmt(" /BlackPoint [%g %g %g]\n",
4058 calRGBCS
->getBlackX(), calRGBCS
->getBlackY(),
4059 calRGBCS
->getBlackZ());
4065 processColors
|= psProcessCMYK
;
4070 writePS("/DeviceCMYK");
4075 processColors
|= psProcessCMYK
;
4080 labCS
= (GfxLabColorSpace
*)colorSpace
;
4081 writePS("[/CIEBasedABC <<\n");
4082 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
4083 labCS
->getAMin(), labCS
->getAMax(),
4084 labCS
->getBMin(), labCS
->getBMax());
4085 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
4086 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
4087 writePS(" /DecodeLMN\n");
4088 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
4089 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4090 labCS
->getWhiteX());
4091 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4092 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4093 labCS
->getWhiteY());
4094 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4095 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
4096 labCS
->getWhiteZ());
4097 writePSFmt(" /WhitePoint [%g %g %g]\n",
4098 labCS
->getWhiteX(), labCS
->getWhiteY(), labCS
->getWhiteZ());
4099 writePSFmt(" /BlackPoint [%g %g %g]\n",
4100 labCS
->getBlackX(), labCS
->getBlackY(), labCS
->getBlackZ());
4106 processColors
|= psProcessCMYK
;
4111 // there is no transform function to the alternate color space, so
4112 // we can use it directly
4113 dumpColorSpaceL2(((GfxICCBasedColorSpace
*)colorSpace
)->getAlt(),
4114 genXform
, updateColors
);
4118 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
4119 baseCS
= indexedCS
->getBase();
4120 writePS("[/Indexed ");
4121 dumpColorSpaceL2(baseCS
, gFalse
, gFalse
);
4122 n
= indexedCS
->getIndexHigh();
4123 numComps
= baseCS
->getNComps();
4124 lookup
= indexedCS
->getLookup();
4125 writePSFmt(" %d <\n", n
);
4126 if (baseCS
->getMode() == csDeviceN
) {
4127 func
= ((GfxDeviceNColorSpace
*)baseCS
)->getTintTransformFunc();
4128 numAltComps
= ((GfxDeviceNColorSpace
*)baseCS
)->getAlt()->getNComps();
4130 for (i
= 0; i
<= n
; i
+= 8) {
4132 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4133 for (k
= 0; k
< numComps
; ++k
) {
4134 x
[k
] = *p
++ / 255.0;
4136 func
->transform(x
, y
);
4137 for (k
= 0; k
< numAltComps
; ++k
) {
4138 byte
= (int)(y
[k
] * 255 + 0.5);
4141 } else if (byte
> 255) {
4144 writePSFmt("%02x", byte
);
4147 color
.c
[0] = dblToCol(j
);
4148 indexedCS
->getCMYK(&color
, &cmyk
);
4149 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4150 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4156 for (i
= 0; i
<= n
; i
+= 8) {
4158 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4159 for (k
= 0; k
< numComps
; ++k
) {
4160 writePSFmt("%02x", lookup
[j
* numComps
+ k
]);
4163 color
.c
[0] = dblToCol(j
);
4164 indexedCS
->getCMYK(&color
, &cmyk
);
4165 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4166 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4179 separationCS
= (GfxSeparationColorSpace
*)colorSpace
;
4180 writePS("[/Separation /");
4181 writePSName(separationCS
->getName()->getCString());
4183 dumpColorSpaceL2(separationCS
->getAlt(), gFalse
, gFalse
);
4185 cvtFunction(separationCS
->getFunc());
4191 addCustomColor(separationCS
);
4196 // DeviceN color spaces are a Level 3 PostScript feature.
4197 deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
4198 dumpColorSpaceL2(deviceNCS
->getAlt(), gFalse
, updateColors
);
4201 cvtFunction(deviceNCS
->getTintTransformFunc());
4212 void PSOutputDev::opiBegin(GfxState
*state
, Dict
*opiDict
) {
4215 if (globalParams
->getPSOPI()) {
4216 opiDict
->lookup("2.0", &dict
);
4217 if (dict
.isDict()) {
4218 opiBegin20(state
, dict
.getDict());
4222 opiDict
->lookup("1.3", &dict
);
4223 if (dict
.isDict()) {
4224 opiBegin13(state
, dict
.getDict());
4231 void PSOutputDev::opiBegin20(GfxState
*state
, Dict
*dict
) {
4232 Object obj1
, obj2
, obj3
, obj4
;
4233 double width
, height
, left
, right
, top
, bottom
;
4237 writePS("%%BeginOPI: 2.0\n");
4238 writePS("%%Distilled\n");
4240 dict
->lookup("F", &obj1
);
4241 if (getFileSpec(&obj1
, &obj2
)) {
4242 writePSFmt("%%%%ImageFileName: %s\n",
4243 obj2
.getString()->getCString());
4248 dict
->lookup("MainImage", &obj1
);
4249 if (obj1
.isString()) {
4250 writePSFmt("%%%%MainImage: %s\n", obj1
.getString()->getCString());
4254 //~ ignoring 'Tags' entry
4255 //~ need to use writePSString() and deal with >255-char lines
4257 dict
->lookup("Size", &obj1
);
4258 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4259 obj1
.arrayGet(0, &obj2
);
4260 width
= obj2
.getNum();
4262 obj1
.arrayGet(1, &obj2
);
4263 height
= obj2
.getNum();
4265 writePSFmt("%%%%ImageDimensions: %g %g\n", width
, height
);
4269 dict
->lookup("CropRect", &obj1
);
4270 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4271 obj1
.arrayGet(0, &obj2
);
4272 left
= obj2
.getNum();
4274 obj1
.arrayGet(1, &obj2
);
4275 top
= obj2
.getNum();
4277 obj1
.arrayGet(2, &obj2
);
4278 right
= obj2
.getNum();
4280 obj1
.arrayGet(3, &obj2
);
4281 bottom
= obj2
.getNum();
4283 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left
, top
, right
, bottom
);
4287 dict
->lookup("Overprint", &obj1
);
4288 if (obj1
.isBool()) {
4289 writePSFmt("%%%%ImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4293 dict
->lookup("Inks", &obj1
);
4294 if (obj1
.isName()) {
4295 writePSFmt("%%%%ImageInks: %s\n", obj1
.getName());
4296 } else if (obj1
.isArray() && obj1
.arrayGetLength() >= 1) {
4297 obj1
.arrayGet(0, &obj2
);
4298 if (obj2
.isName()) {
4299 writePSFmt("%%%%ImageInks: %s %d",
4300 obj2
.getName(), (obj1
.arrayGetLength() - 1) / 2);
4301 for (i
= 1; i
+1 < obj1
.arrayGetLength(); i
+= 2) {
4302 obj1
.arrayGet(i
, &obj3
);
4303 obj1
.arrayGet(i
+1, &obj4
);
4304 if (obj3
.isString() && obj4
.isNum()) {
4306 writePSString(obj3
.getString());
4307 writePSFmt(" %g", obj4
.getNum());
4320 writePS("%%BeginIncludedImage\n");
4322 dict
->lookup("IncludedImageDimensions", &obj1
);
4323 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4324 obj1
.arrayGet(0, &obj2
);
4327 obj1
.arrayGet(1, &obj2
);
4330 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w
, h
);
4334 dict
->lookup("IncludedImageQuality", &obj1
);
4336 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1
.getNum());
4343 void PSOutputDev::opiBegin13(GfxState
*state
, Dict
*dict
) {
4345 int left
, right
, top
, bottom
, samples
, bits
, width
, height
;
4347 double llx
, lly
, ulx
, uly
, urx
, ury
, lrx
, lry
;
4348 double tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
;
4353 writePS("/opiMatrix2 matrix currentmatrix def\n");
4354 writePS("opiMatrix setmatrix\n");
4356 dict
->lookup("F", &obj1
);
4357 if (getFileSpec(&obj1
, &obj2
)) {
4358 writePSFmt("%%ALDImageFileName: %s\n",
4359 obj2
.getString()->getCString());
4364 dict
->lookup("CropRect", &obj1
);
4365 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4366 obj1
.arrayGet(0, &obj2
);
4367 left
= obj2
.getInt();
4369 obj1
.arrayGet(1, &obj2
);
4370 top
= obj2
.getInt();
4372 obj1
.arrayGet(2, &obj2
);
4373 right
= obj2
.getInt();
4375 obj1
.arrayGet(3, &obj2
);
4376 bottom
= obj2
.getInt();
4378 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left
, top
, right
, bottom
);
4382 dict
->lookup("Color", &obj1
);
4383 if (obj1
.isArray() && obj1
.arrayGetLength() == 5) {
4384 obj1
.arrayGet(0, &obj2
);
4387 obj1
.arrayGet(1, &obj2
);
4390 obj1
.arrayGet(2, &obj2
);
4393 obj1
.arrayGet(3, &obj2
);
4396 obj1
.arrayGet(4, &obj2
);
4397 if (obj2
.isString()) {
4398 writePSFmt("%%ALDImageColor: %g %g %g %g ", c
, m
, y
, k
);
4399 writePSString(obj2
.getString());
4406 dict
->lookup("ColorType", &obj1
);
4407 if (obj1
.isName()) {
4408 writePSFmt("%%ALDImageColorType: %s\n", obj1
.getName());
4412 //~ ignores 'Comments' entry
4413 //~ need to handle multiple lines
4415 dict
->lookup("CropFixed", &obj1
);
4416 if (obj1
.isArray()) {
4417 obj1
.arrayGet(0, &obj2
);
4418 ulx
= obj2
.getNum();
4420 obj1
.arrayGet(1, &obj2
);
4421 uly
= obj2
.getNum();
4423 obj1
.arrayGet(2, &obj2
);
4424 lrx
= obj2
.getNum();
4426 obj1
.arrayGet(3, &obj2
);
4427 lry
= obj2
.getNum();
4429 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx
, uly
, lrx
, lry
);
4433 dict
->lookup("GrayMap", &obj1
);
4434 if (obj1
.isArray()) {
4435 writePS("%ALDImageGrayMap:");
4436 for (i
= 0; i
< obj1
.arrayGetLength(); i
+= 16) {
4440 for (j
= 0; j
< 16 && i
+j
< obj1
.arrayGetLength(); ++j
) {
4441 obj1
.arrayGet(i
+j
, &obj2
);
4442 writePSFmt(" %d", obj2
.getInt());
4450 dict
->lookup("ID", &obj1
);
4451 if (obj1
.isString()) {
4452 writePSFmt("%%ALDImageID: %s\n", obj1
.getString()->getCString());
4456 dict
->lookup("ImageType", &obj1
);
4457 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4458 obj1
.arrayGet(0, &obj2
);
4459 samples
= obj2
.getInt();
4461 obj1
.arrayGet(1, &obj2
);
4462 bits
= obj2
.getInt();
4464 writePSFmt("%%ALDImageType: %d %d\n", samples
, bits
);
4468 dict
->lookup("Overprint", &obj1
);
4469 if (obj1
.isBool()) {
4470 writePSFmt("%%ALDImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4474 dict
->lookup("Position", &obj1
);
4475 if (obj1
.isArray() && obj1
.arrayGetLength() == 8) {
4476 obj1
.arrayGet(0, &obj2
);
4477 llx
= obj2
.getNum();
4479 obj1
.arrayGet(1, &obj2
);
4480 lly
= obj2
.getNum();
4482 obj1
.arrayGet(2, &obj2
);
4483 ulx
= obj2
.getNum();
4485 obj1
.arrayGet(3, &obj2
);
4486 uly
= obj2
.getNum();
4488 obj1
.arrayGet(4, &obj2
);
4489 urx
= obj2
.getNum();
4491 obj1
.arrayGet(5, &obj2
);
4492 ury
= obj2
.getNum();
4494 obj1
.arrayGet(6, &obj2
);
4495 lrx
= obj2
.getNum();
4497 obj1
.arrayGet(7, &obj2
);
4498 lry
= obj2
.getNum();
4500 opiTransform(state
, llx
, lly
, &tllx
, &tlly
);
4501 opiTransform(state
, ulx
, uly
, &tulx
, &tuly
);
4502 opiTransform(state
, urx
, ury
, &turx
, &tury
);
4503 opiTransform(state
, lrx
, lry
, &tlrx
, &tlry
);
4504 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
4505 tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
);
4510 dict
->lookup("Resolution", &obj1
);
4511 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4512 obj1
.arrayGet(0, &obj2
);
4513 horiz
= obj2
.getNum();
4515 obj1
.arrayGet(1, &obj2
);
4516 vert
= obj2
.getNum();
4518 writePSFmt("%%ALDImageResoution: %g %g\n", horiz
, vert
);
4523 dict
->lookup("Size", &obj1
);
4524 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4525 obj1
.arrayGet(0, &obj2
);
4526 width
= obj2
.getInt();
4528 obj1
.arrayGet(1, &obj2
);
4529 height
= obj2
.getInt();
4531 writePSFmt("%%ALDImageDimensions: %d %d\n", width
, height
);
4535 //~ ignoring 'Tags' entry
4536 //~ need to use writePSString() and deal with >255-char lines
4538 dict
->lookup("Tint", &obj1
);
4540 writePSFmt("%%ALDImageTint: %g\n", obj1
.getNum());
4544 dict
->lookup("Transparency", &obj1
);
4545 if (obj1
.isBool()) {
4546 writePSFmt("%%ALDImageTransparency: %s\n", obj1
.getBool() ? "true" : "false");
4550 writePS("%%BeginObject: image\n");
4551 writePS("opiMatrix2 setmatrix\n");
4555 // Convert PDF user space coordinates to PostScript default user space
4556 // coordinates. This has to account for both the PDF CTM and the
4557 // PSOutputDev page-fitting transform.
4558 void PSOutputDev::opiTransform(GfxState
*state
, double x0
, double y0
,
4559 double *x1
, double *y1
) {
4562 state
->transform(x0
, y0
, x1
, y1
);
4569 } else if (rotate
== 180) {
4572 } else if (rotate
== 270) {
4581 void PSOutputDev::opiEnd(GfxState
*state
, Dict
*opiDict
) {
4584 if (globalParams
->getPSOPI()) {
4585 opiDict
->lookup("2.0", &dict
);
4586 if (dict
.isDict()) {
4587 writePS("%%EndIncludedImage\n");
4588 writePS("%%EndOPI\n");
4589 writePS("grestore\n");
4594 opiDict
->lookup("1.3", &dict
);
4595 if (dict
.isDict()) {
4596 writePS("%%EndObject\n");
4597 writePS("restore\n");
4605 GBool
PSOutputDev::getFileSpec(Object
*fileSpec
, Object
*fileName
) {
4606 if (fileSpec
->isString()) {
4607 fileSpec
->copy(fileName
);
4610 if (fileSpec
->isDict()) {
4611 fileSpec
->dictLookup("DOS", fileName
);
4612 if (fileName
->isString()) {
4616 fileSpec
->dictLookup("Mac", fileName
);
4617 if (fileName
->isString()) {
4621 fileSpec
->dictLookup("Unix", fileName
);
4622 if (fileName
->isString()) {
4626 fileSpec
->dictLookup("F", fileName
);
4627 if (fileName
->isString()) {
4634 #endif // OPI_SUPPORT
4636 void PSOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
4637 writePSFmt("%g %g setcharwidth\n", wx
, wy
);
4641 void PSOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
4642 double llx
, double lly
, double urx
, double ury
) {
4649 t3String
= new GString();
4651 t3Cacheable
= gTrue
;
4654 void PSOutputDev::psXObject(Stream
*psStream
, Stream
*level1Stream
) {
4658 if ((level
== psLevel1
|| level
== psLevel1Sep
) && level1Stream
) {
4664 while ((c
= str
->getChar()) != EOF
) {
4670 //~ can nextFunc be reset to 0 -- maybe at the start of each page?
4671 //~ or maybe at the start of each color space / pattern?
4672 void PSOutputDev::cvtFunction(Function
*func
) {
4673 SampledFunction
*func0
;
4674 ExponentialFunction
*func2
;
4675 StitchingFunction
*func3
;
4676 PostScriptFunction
*func4
;
4677 int thisFunc
, m
, n
, nSamples
, i
, j
, k
;
4679 switch (func
->getType()) {
4681 case -1: // identity
4686 func0
= (SampledFunction
*)func
;
4687 thisFunc
= nextFunc
++;
4688 m
= func0
->getInputSize();
4689 n
= func0
->getOutputSize();
4691 for (i
= 0; i
< m
; ++i
) {
4692 nSamples
*= func0
->getSampleSize(i
);
4694 writePSFmt("/xpdfSamples%d [\n", thisFunc
);
4695 for (i
= 0; i
< nSamples
; ++i
) {
4696 writePSFmt("%g\n", func0
->getSamples()[i
]);
4699 writePSFmt("{ %d array %d array %d 2 roll\n", 2*m
, m
, m
+2);
4700 // [e01] [efrac] x0 x1 ... xm-1
4701 for (i
= m
-1; i
>= 0; --i
) {
4702 // [e01] [efrac] x0 x1 ... xi
4703 writePSFmt("%g sub %g mul %g add\n",
4704 func0
->getDomainMin(i
),
4705 (func0
->getEncodeMax(i
) - func0
->getEncodeMin(i
)) /
4706 (func0
->getDomainMax(i
) - func0
->getDomainMin(i
)),
4707 func0
->getEncodeMin(i
));
4708 // [e01] [efrac] x0 x1 ... xi-1 xi'
4709 writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n",
4710 func0
->getSampleSize(i
) - 1, func0
->getSampleSize(i
) - 1);
4711 // [e01] [efrac] x0 x1 ... xi-1 xi'
4712 writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
4713 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
4714 writePSFmt("%d index %d 3 2 roll put\n", i
+3, i
);
4715 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
4716 writePSFmt("%d index %d 3 2 roll put\n", i
+3, 2*i
+1);
4717 // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
4718 writePSFmt("%d index %d 3 2 roll put\n", i
+2, 2*i
);
4719 // [e01] [efrac] x0 x1 ... xi-1
4722 for (i
= 0; i
< n
; ++i
) {
4723 // [e01] [efrac] y(0) ... y(i-1)
4724 for (j
= 0; j
< (1<<m
); ++j
) {
4725 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
4726 writePSFmt("xpdfSamples%d\n", thisFunc
);
4728 writePSFmt("%d index %d get\n", i
+j
+2, 2 * k
+ ((j
>> k
) & 1));
4729 for (k
= m
- 2; k
>= 0; --k
) {
4730 writePSFmt("%d mul %d index %d get add\n",
4731 func0
->getSampleSize(k
),
4733 2 * k
+ ((j
>> k
) & 1));
4736 writePSFmt("%d mul %d add ", n
, i
);
4740 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
4741 for (j
= 0; j
< m
; ++j
) {
4742 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
4743 for (k
= 0; k
< (1 << (m
- j
)); k
+= 2) {
4744 // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
4745 writePSFmt("%d index %d get dup\n", i
+ k
/2 + (1 << (m
-j
)) - k
, j
);
4746 writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
4747 writePSFmt("%d 1 roll\n", k
/2 + (1 << m
-j
) - k
- 1);
4749 // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
4751 // [e01] [efrac] y(0) ... y(i-1) s
4752 writePSFmt("%g mul %g add\n",
4753 func0
->getDecodeMax(i
) - func0
->getDecodeMin(i
),
4754 func0
->getDecodeMin(i
));
4755 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4756 func0
->getRangeMin(i
), func0
->getRangeMin(i
),
4757 func0
->getRangeMax(i
), func0
->getRangeMax(i
));
4758 // [e01] [efrac] y(0) ... y(i-1) y(i)
4760 // [e01] [efrac] y(0) ... y(n-1)
4761 writePSFmt("%d %d roll pop pop }\n", n
+2, n
);
4764 case 2: // exponential
4765 func2
= (ExponentialFunction
*)func
;
4766 n
= func2
->getOutputSize();
4767 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4768 func2
->getDomainMin(0), func2
->getDomainMin(0),
4769 func2
->getDomainMax(0), func2
->getDomainMax(0));
4771 for (i
= 0; i
< n
; ++i
) {
4773 writePSFmt("%d index %g exp %g mul %g add\n",
4774 i
, func2
->getE(), func2
->getC1()[i
] - func2
->getC0()[i
],
4776 if (func2
->getHasRange()) {
4777 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4778 func2
->getRangeMin(i
), func2
->getRangeMin(i
),
4779 func2
->getRangeMax(i
), func2
->getRangeMax(i
));
4783 writePSFmt("%d %d roll pop }\n", n
+1, n
);
4786 case 3: // stitching
4787 func3
= (StitchingFunction
*)func
;
4788 thisFunc
= nextFunc
++;
4789 for (i
= 0; i
< func3
->getNumFuncs(); ++i
) {
4790 cvtFunction(func3
->getFunc(i
));
4791 writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc
, i
);
4793 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4794 func3
->getDomainMin(0), func3
->getDomainMin(0),
4795 func3
->getDomainMax(0), func3
->getDomainMax(0));
4796 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4797 writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n",
4798 func3
->getBounds()[i
+1],
4799 func3
->getBounds()[i
],
4800 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4801 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4802 func3
->getEncode()[2*i
],
4805 writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n",
4806 func3
->getBounds()[i
],
4807 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4808 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4809 func3
->getEncode()[2*i
],
4811 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4812 writePS("} ifelse\n");
4817 case 4: // PostScript
4818 func4
= (PostScriptFunction
*)func
;
4819 writePS(func4
->getCodeString()->getCString());
4825 void PSOutputDev::writePSChar(char c
) {
4827 t3String
->append(c
);
4829 (*outputFunc
)(outputStream
, &c
, 1);
4833 void PSOutputDev::writePS(char *s
) {
4835 t3String
->append(s
);
4837 (*outputFunc
)(outputStream
, s
, strlen(s
));
4841 void PSOutputDev::writePSFmt(const char *fmt
, ...) {
4845 va_start(args
, fmt
);
4846 vsprintf(buf
, fmt
, args
);
4849 t3String
->append(buf
);
4851 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
4855 void PSOutputDev::writePSString(GString
*s
) {
4862 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
4868 if (*p
== '(' || *p
== ')' || *p
== '\\') {
4870 writePSChar((char)*p
);
4872 } else if (*p
< 0x20 || *p
>= 0x80) {
4873 sprintf(buf
, "\\%03o", *p
);
4877 writePSChar((char)*p
);
4884 void PSOutputDev::writePSName(char *s
) {
4889 while ((c
= *p
++)) {
4890 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4891 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4892 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4893 c
== '/' || c
== '%') {
4894 writePSFmt("#%02x", c
& 0xff);
4901 GString
*PSOutputDev::filterPSName(GString
*name
) {
4907 name2
= new GString();
4909 // ghostscript chokes on names that begin with out-of-limits
4910 // numbers, e.g., 1e4foo is handled correctly (as a name), but
4911 // 1e999foo generates a limitcheck error
4912 c
= name
->getChar(0);
4913 if (c
>= '0' && c
<= '9') {
4917 for (i
= 0; i
< name
->getLength(); ++i
) {
4918 c
= name
->getChar(i
);
4919 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4920 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4921 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4922 c
== '/' || c
== '%') {
4923 sprintf(buf
, "#%02x", c
& 0xff);
4932 GBool
/* O - gTrue if selected, gFalse otherwise */
4933 PSOutputDev::checkRange(int page
) /* I - Page number */
4935 const char *range
; /* Pointer into range string */
4936 int lower
, upper
; /* Lower and upper page numbers */
4939 if (pageRanges
== NULL
)
4940 return (gTrue
); /* No range, print all pages... */
4942 for (range
= pageRanges
; *range
!= '\0';)
4948 upper
= strtol(range
, (char **)&range
, 10);
4952 lower
= strtol(range
, (char **)&range
, 10);
4957 if (!isdigit(*range
& 255))
4960 upper
= strtol(range
, (char **)&range
, 10);
4966 if (page
>= lower
&& page
<= upper
)