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("%%Producer: 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 // Convert UTF-16 to UTF-8...
1235 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1236 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1238 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1239 // Multi-word UTF-16 char...
1241 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1243 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1245 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1251 * Single byte ASCII...
1256 else if (ch
< 0x800)
1262 writePSChar(0xc0 | (ch
>> 6));
1263 writePSChar(0x80 | (ch
& 0x3f));
1265 else if (ch
< 0x10000)
1268 * Three-byte UTF-8...
1271 writePSChar(0xe0 | (ch
>> 12));
1272 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1273 writePSChar(0x80 | (ch
& 0x3f));
1278 * Four-byte UTF-8...
1281 writePSChar(0xf0 | (ch
>> 18));
1282 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1283 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1284 writePSChar(0x80 | (ch
& 0x3f));
1288 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1289 writePSChar(s
->getChar(i
));
1296 writePSFmt("%%%%LanguageLevel: %d\n",
1297 (level
== psLevel1
|| level
== psLevel1Sep
) ? 1 :
1298 (level
== psLevel2
|| level
== psLevel2Sep
) ? 2 : 3);
1299 if (level
== psLevel1Sep
|| level
== psLevel2Sep
|| level
== psLevel3Sep
) {
1300 writePS("%%DocumentProcessColors: (atend)\n");
1301 writePS("%%DocumentCustomColors: (atend)\n");
1303 writePS("%%DocumentSuppliedResources: (atend)\n");
1307 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
1308 paperWidth
, paperHeight
);
1309 writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth
, paperHeight
);
1310 writePSFmt("%%%%Pages: %d\n", lastPage
- firstPage
+ 1);
1311 writePS("%%EndComments\n");
1312 writePS("%%BeginDefaults\n");
1313 writePS("%%PageMedia: plain\n");
1314 writePS("%%EndDefaults\n");
1317 epsX1
= cropBox
->x1
;
1318 epsY1
= cropBox
->y1
;
1319 epsX2
= cropBox
->x2
;
1320 epsY2
= cropBox
->y2
;
1321 if (pageRotate
== 0 || pageRotate
== 180) {
1326 } else { // pageRotate == 90 || pageRotate == 270
1332 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
1333 (int)floor(x1
), (int)floor(y1
), (int)ceil(x2
), (int)ceil(y2
));
1334 if (floor(x1
) != ceil(x1
) || floor(y1
) != ceil(y1
) ||
1335 floor(x2
) != ceil(x2
) || floor(y2
) != ceil(y2
)) {
1336 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1
, y1
, x2
, y2
);
1338 writePS("%%EndComments\n");
1341 writePS("%%EndComments\n");
1342 writePS("32 dict dup begin\n");
1343 writePSFmt("/BBox [%d %d %d %d] def\n",
1344 (int)floor(mediaBox
->x1
), (int)floor(mediaBox
->y1
),
1345 (int)ceil(mediaBox
->x2
), (int)ceil(mediaBox
->y2
));
1346 writePS("/FormType 1 def\n");
1347 writePS("/Matrix [1 0 0 1 0 0] def\n");
1352 void PSOutputDev::writeXpdfProcset() {
1353 GBool lev1
, lev2
, lev3
, sep
, nonSep
;
1357 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion
);
1358 lev1
= lev2
= lev3
= sep
= nonSep
= gTrue
;
1359 for (p
= prolog
; *p
; ++p
) {
1360 if ((*p
)[0] == '~') {
1361 lev1
= lev2
= lev3
= sep
= nonSep
= gFalse
;
1362 for (q
= *p
+ 1; *q
; ++q
) {
1364 case '1': lev1
= gTrue
; break;
1365 case '2': lev2
= gTrue
; break;
1366 case '3': lev3
= gTrue
; break;
1367 case 's': sep
= gTrue
; break;
1368 case 'n': nonSep
= gTrue
; break;
1371 } else if ((level
== psLevel1
&& lev1
&& nonSep
) ||
1372 (level
== psLevel1Sep
&& lev1
&& sep
) ||
1373 (level
== psLevel2
&& lev2
&& nonSep
) ||
1374 (level
== psLevel2Sep
&& lev2
&& sep
) ||
1375 (level
== psLevel3
&& lev3
&& nonSep
) ||
1376 (level
== psLevel3Sep
&& lev3
&& sep
)) {
1377 writePSFmt("%s\n", *p
);
1380 writePS("%%EndResource\n");
1382 if (level
>= psLevel3
) {
1383 for (p
= cmapProlog
; *p
; ++p
) {
1384 writePSFmt("%s\n", *p
);
1389 void PSOutputDev::writeDocSetup(Catalog
*catalog
,
1390 int firstPage
, int lastPage
) {
1397 if (mode
== psModeForm
) {
1398 // swap the form and xpdf dicts
1399 writePS("xpdf end begin dup begin\n");
1401 writePS("xpdf begin\n");
1403 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
1404 page
= catalog
->getPage(pg
);
1405 if ((resDict
= page
->getResourceDict())) {
1406 setupResources(resDict
);
1408 annots
= new Annots(xref
, catalog
, page
->getAnnots(&obj1
));
1410 for (i
= 0; i
< annots
->getNumAnnots(); ++i
) {
1411 if (annots
->getAnnot(i
)->getAppearance(&obj1
)->isStream()) {
1412 obj1
.streamGetDict()->lookup("Resources", &obj2
);
1413 if (obj2
.isDict()) {
1414 setupResources(obj2
.getDict());
1422 if (mode
!= psModeForm
) {
1423 if (mode
!= psModeEPS
&& !manualCtrl
) {
1424 writePSFmt("%d %d %s pdfSetup\n",
1425 paperWidth
, paperHeight
,
1426 globalParams
->getPSDuplex() ? "true" : "false");
1429 if (globalParams
->getPSOPI()) {
1430 writePS("/opiMatrix matrix currentmatrix def\n");
1436 void PSOutputDev::writePageTrailer() {
1437 if (mode
!= psModeForm
) {
1438 writePS("pdfEndPage\n");
1442 void PSOutputDev::writeTrailer() {
1443 PSOutCustomColor
*cc
;
1445 if (mode
== psModeForm
) {
1446 writePS("/Foo exch /Form defineresource pop\n");
1449 writePS("%%DocumentSuppliedResources:\n");
1450 writePS(embFontList
->getCString());
1451 if (level
== psLevel1Sep
|| level
== psLevel2Sep
||
1452 level
== psLevel3Sep
) {
1453 writePS("%%DocumentProcessColors:");
1454 if (processColors
& psProcessCyan
) {
1457 if (processColors
& psProcessMagenta
) {
1458 writePS(" Magenta");
1460 if (processColors
& psProcessYellow
) {
1463 if (processColors
& psProcessBlack
) {
1467 writePS("%%DocumentCustomColors:");
1468 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1469 writePSFmt(" (%s)", cc
->name
->getCString());
1472 writePS("%%CMYKCustomColor:\n");
1473 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1474 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
1475 cc
->c
, cc
->m
, cc
->y
, cc
->k
, cc
->name
->getCString());
1481 void PSOutputDev::setupResources(Dict
*resDict
) {
1482 Object xObjDict
, xObjRef
, xObj
, patDict
, patRef
, pat
, resObj
;
1487 setupFonts(resDict
);
1488 setupImages(resDict
);
1490 //----- recursively scan XObjects
1491 resDict
->lookup("XObject", &xObjDict
);
1492 if (xObjDict
.isDict()) {
1493 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
1495 // avoid infinite recursion on XObjects
1497 if ((xObjDict
.dictGetValNF(i
, &xObjRef
)->isRef())) {
1498 ref0
= xObjRef
.getRef();
1499 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1500 ref1
= *(Ref
*)xobjStack
->get(j
);
1501 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1507 xobjStack
->append(&ref0
);
1512 // process the XObject's resource dictionary
1513 xObjDict
.dictGetVal(i
, &xObj
);
1514 if (xObj
.isStream()) {
1515 xObj
.streamGetDict()->lookup("Resources", &resObj
);
1516 if (resObj
.isDict()) {
1517 setupResources(resObj
.getDict());
1524 if (xObjRef
.isRef() && !skip
) {
1525 xobjStack
->del(xobjStack
->getLength() - 1);
1532 //----- recursively scan Patterns
1533 resDict
->lookup("Pattern", &patDict
);
1534 if (patDict
.isDict()) {
1535 inType3Char
= gTrue
;
1536 for (i
= 0; i
< patDict
.dictGetLength(); ++i
) {
1538 // avoid infinite recursion on Patterns
1540 if ((patDict
.dictGetValNF(i
, &patRef
)->isRef())) {
1541 ref0
= patRef
.getRef();
1542 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1543 ref1
= *(Ref
*)xobjStack
->get(j
);
1544 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1550 xobjStack
->append(&ref0
);
1555 // process the Pattern's resource dictionary
1556 patDict
.dictGetVal(i
, &pat
);
1557 if (pat
.isStream()) {
1558 pat
.streamGetDict()->lookup("Resources", &resObj
);
1559 if (resObj
.isDict()) {
1560 setupResources(resObj
.getDict());
1567 if (patRef
.isRef() && !skip
) {
1568 xobjStack
->del(xobjStack
->getLength() - 1);
1572 inType3Char
= gFalse
;
1577 void PSOutputDev::setupFonts(Dict
*resDict
) {
1580 GfxFontDict
*gfxFontDict
;
1585 resDict
->lookupNF("Font", &obj1
);
1587 obj1
.fetch(xref
, &obj2
);
1588 if (obj2
.isDict()) {
1590 gfxFontDict
= new GfxFontDict(xref
, &r
, obj2
.getDict());
1593 } else if (obj1
.isDict()) {
1594 gfxFontDict
= new GfxFontDict(xref
, NULL
, obj1
.getDict());
1597 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
1598 if ((font
= gfxFontDict
->getFont(i
))) {
1599 setupFont(font
, resDict
);
1607 void PSOutputDev::setupFont(GfxFont
*font
, Dict
*parentResDict
) {
1610 PSFontParam
*fontParam
;
1612 char type3Name
[64], buf
[16];
1622 // check if font is already set up
1623 for (i
= 0; i
< fontIDLen
; ++i
) {
1624 if (fontIDs
[i
].num
== font
->getID()->num
&&
1625 fontIDs
[i
].gen
== font
->getID()->gen
) {
1630 // add entry to fontIDs list
1631 if (fontIDLen
>= fontIDSize
) {
1633 fontIDs
= (Ref
*)greallocn(fontIDs
, fontIDSize
, sizeof(Ref
));
1635 fontIDs
[fontIDLen
++] = *font
->getID();
1640 // check for resident 8-bit font
1641 if (font
->getName() &&
1642 (fontParam
= globalParams
->getPSFont(font
->getName()))) {
1643 psName
= new GString(fontParam
->psFontName
->getCString());
1645 // check for embedded Type 1 font
1646 } else if (globalParams
->getPSEmbedType1() &&
1647 font
->getType() == fontType1
&&
1648 font
->getEmbeddedFontID(&fontFileID
)) {
1649 psName
= filterPSName(font
->getEmbeddedFontName());
1650 setupEmbeddedType1Font(&fontFileID
, psName
);
1652 // check for embedded Type 1C font
1653 } else if (globalParams
->getPSEmbedType1() &&
1654 font
->getType() == fontType1C
&&
1655 font
->getEmbeddedFontID(&fontFileID
)) {
1656 psName
= filterPSName(font
->getEmbeddedFontName());
1657 setupEmbeddedType1CFont(font
, &fontFileID
, psName
);
1659 // check for external Type 1 font file
1660 } else if (globalParams
->getPSEmbedType1() &&
1661 font
->getType() == fontType1
&&
1662 font
->getExtFontFile()) {
1663 // this assumes that the PS font name matches the PDF font name
1664 psName
= font
->getName()->copy();
1665 setupExternalType1Font(font
->getExtFontFile(), psName
);
1667 // check for embedded TrueType font
1668 } else if (globalParams
->getPSEmbedTrueType() &&
1669 font
->getType() == fontTrueType
&&
1670 font
->getEmbeddedFontID(&fontFileID
)) {
1671 psName
= filterPSName(font
->getEmbeddedFontName());
1672 setupEmbeddedTrueTypeFont(font
, &fontFileID
, psName
);
1674 // check for external TrueType font file
1675 } else if (globalParams
->getPSEmbedTrueType() &&
1676 font
->getType() == fontTrueType
&&
1677 font
->getExtFontFile()) {
1678 psName
= filterPSName(font
->getName());
1679 setupExternalTrueTypeFont(font
, psName
);
1681 // check for embedded CID PostScript font
1682 } else if (globalParams
->getPSEmbedCIDPostScript() &&
1683 font
->getType() == fontCIDType0C
&&
1684 font
->getEmbeddedFontID(&fontFileID
)) {
1685 psName
= filterPSName(font
->getEmbeddedFontName());
1686 setupEmbeddedCIDType0Font(font
, &fontFileID
, psName
);
1688 // check for embedded CID TrueType font
1689 } else if (globalParams
->getPSEmbedCIDTrueType() &&
1690 font
->getType() == fontCIDType2
&&
1691 font
->getEmbeddedFontID(&fontFileID
)) {
1692 psName
= filterPSName(font
->getEmbeddedFontName());
1693 //~ should check to see if font actually uses vertical mode
1694 setupEmbeddedCIDTrueTypeFont(font
, &fontFileID
, psName
, gTrue
);
1696 } else if (font
->getType() == fontType3
) {
1697 sprintf(type3Name
, "T3_%d_%d",
1698 font
->getID()->num
, font
->getID()->gen
);
1699 psName
= new GString(type3Name
);
1700 setupType3Font(font
, psName
, parentResDict
);
1702 // do 8-bit font substitution
1703 } else if (!font
->isCIDFont()) {
1705 name
= font
->getName();
1708 for (i
= 0; psFonts
[i
]; ++i
) {
1709 if (name
->cmp(psFonts
[i
]) == 0) {
1710 psName
= new GString(psFonts
[i
]);
1716 if (font
->isFixedWidth()) {
1718 } else if (font
->isSerif()) {
1723 if (font
->isBold()) {
1726 if (font
->isItalic()) {
1729 psName
= new GString(psSubstFonts
[i
].psName
);
1730 for (code
= 0; code
< 256; ++code
) {
1731 if ((charName
= ((Gfx8BitFont
*)font
)->getCharName(code
)) &&
1732 charName
[0] == 'm' && charName
[1] == '\0') {
1737 w1
= ((Gfx8BitFont
*)font
)->getWidth(code
);
1741 w2
= psSubstFonts
[i
].mWidth
;
1746 if (font
->getType() == fontType3
) {
1747 // This is a hack which makes it possible to substitute for some
1748 // Type 3 fonts. The problem is that it's impossible to know what
1749 // the base coordinate system used in the font is without actually
1750 // rendering the font.
1752 fm
= font
->getFontMatrix();
1754 ys
*= fm
[3] / fm
[0];
1761 // do 16-bit font substitution
1762 } else if ((fontParam
= globalParams
->
1763 getPSFont16(font
->getName(),
1764 ((GfxCIDFont
*)font
)->getCollection(),
1765 font
->getWMode()))) {
1767 psName
= fontParam
->psFontName
->copy();
1768 if (font16EncLen
>= font16EncSize
) {
1769 font16EncSize
+= 16;
1770 font16Enc
= (PSFont16Enc
*)greallocn(font16Enc
,
1771 font16EncSize
, sizeof(PSFont16Enc
));
1773 font16Enc
[font16EncLen
].fontID
= *font
->getID();
1774 font16Enc
[font16EncLen
].enc
= fontParam
->encoding
->copy();
1775 if ((uMap
= globalParams
->getUnicodeMap(font16Enc
[font16EncLen
].enc
))) {
1779 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1780 font16Enc
[font16EncLen
].enc
->getCString());
1783 // give up - can't do anything with this font
1785 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1786 font
->getName() ? font
->getName()->getCString() : "(unnamed)",
1787 ((GfxCIDFont
*)font
)->getCollection()
1788 ? ((GfxCIDFont
*)font
)->getCollection()->getCString()
1793 // generate PostScript code to set up the font
1794 if (font
->isCIDFont()) {
1795 if (level
== psLevel3
|| level
== psLevel3Sep
) {
1796 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
1797 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1800 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
1801 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1805 writePSFmt("/F%d_%d /%s %g %g\n",
1806 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1808 for (i
= 0; i
< 256; i
+= 8) {
1809 writePSFmt((i
== 0) ? "[ " : " ");
1810 for (j
= 0; j
< 8; ++j
) {
1811 if (font
->getType() == fontTrueType
&&
1813 !((Gfx8BitFont
*)font
)->getHasEncoding()) {
1814 sprintf(buf
, "c%02x", i
+j
);
1817 charName
= ((Gfx8BitFont
*)font
)->getCharName(i
+j
);
1818 // this is a kludge for broken PDF files that encode char 32
1820 if (i
+j
== 32 && charName
&& !strcmp(charName
, ".notdef")) {
1825 writePSName(charName
? charName
: (char *)".notdef");
1826 // the empty name is legal in PDF and PostScript, but PostScript
1827 // uses a double-slash (//...) for "immediately evaluated names",
1828 // so we need to add a space character here
1829 if (charName
&& !charName
[0]) {
1833 writePS((i
== 256-8) ? (char *)"]\n" : (char *)"\n");
1835 writePS("pdfMakeFont\n");
1841 void PSOutputDev::setupEmbeddedType1Font(Ref
*id
, GString
*psName
) {
1842 static char hexChar
[17] = "0123456789abcdef";
1843 Object refObj
, strObj
, obj1
, obj2
, obj3
;
1845 int length1
, length2
, length3
;
1851 // check if font is already embedded
1852 for (i
= 0; i
< fontFileIDLen
; ++i
) {
1853 if (fontFileIDs
[i
].num
== id
->num
&&
1854 fontFileIDs
[i
].gen
== id
->gen
)
1858 // add entry to fontFileIDs list
1859 if (fontFileIDLen
>= fontFileIDSize
) {
1860 fontFileIDSize
+= 64;
1861 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
1863 fontFileIDs
[fontFileIDLen
++] = *id
;
1865 // get the font stream and info
1866 refObj
.initRef(id
->num
, id
->gen
);
1867 refObj
.fetch(xref
, &strObj
);
1869 if (!strObj
.isStream()) {
1870 error(-1, "Embedded font file object is not a stream");
1873 if (!(dict
= strObj
.streamGetDict())) {
1874 error(-1, "Embedded font stream is missing its dictionary");
1877 dict
->lookup("Length1", &obj1
);
1878 dict
->lookup("Length2", &obj2
);
1879 dict
->lookup("Length3", &obj3
);
1880 if (!obj1
.isInt() || !obj2
.isInt() || !obj3
.isInt()) {
1881 error(-1, "Missing length fields in embedded font stream dictionary");
1887 length1
= obj1
.getInt();
1888 length2
= obj2
.getInt();
1889 length3
= obj3
.getInt();
1894 // beginning comment
1895 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1896 embFontList
->append("%%+ font ");
1897 embFontList
->append(psName
->getCString());
1898 embFontList
->append("\n");
1900 // copy ASCII portion of font
1901 strObj
.streamReset();
1902 for (i
= 0; i
< length1
&& (c
= strObj
.streamGetChar()) != EOF
; ++i
) {
1906 // figure out if encrypted portion is binary or ASCII
1908 for (i
= 0; i
< 4; ++i
) {
1909 start
[i
] = strObj
.streamGetChar();
1910 if (start
[i
] == EOF
) {
1911 error(-1, "Unexpected end of file in embedded font stream");
1914 if (!((start
[i
] >= '0' && start
[i
] <= '9') ||
1915 (start
[i
] >= 'A' && start
[i
] <= 'F') ||
1916 (start
[i
] >= 'a' && start
[i
] <= 'f')))
1920 // convert binary data to ASCII
1922 for (i
= 0; i
< 4; ++i
) {
1923 writePSChar(hexChar
[(start
[i
] >> 4) & 0x0f]);
1924 writePSChar(hexChar
[start
[i
] & 0x0f]);
1926 // if Length2 is incorrect (too small), font data gets chopped, so
1927 // we take a few extra characters from the trailer just in case
1928 // length2 += length3 >= 8 ? 8 : length3;
1929 while (i
< length2
) {
1930 if ((c
= strObj
.streamGetChar()) == EOF
) {
1933 writePSChar(hexChar
[(c
>> 4) & 0x0f]);
1934 writePSChar(hexChar
[c
& 0x0f]);
1935 if (++i
% 32 == 0) {
1943 // already in ASCII format -- just copy it
1945 for (i
= 0; i
< 4; ++i
) {
1946 writePSChar(start
[i
]);
1948 for (i
= 4; i
< length2
; ++i
) {
1949 if ((c
= strObj
.streamGetChar()) == EOF
) {
1956 // write padding and "cleartomark"
1957 for (i
= 0; i
< 8; ++i
) {
1958 writePS("00000000000000000000000000000000"
1959 "00000000000000000000000000000000\n");
1961 writePS("cleartomark\n");
1964 writePS("%%EndResource\n");
1967 strObj
.streamClose();
1971 //~ This doesn't handle .pfb files or binary eexec data (which only
1972 //~ happens in pfb files?).
1973 void PSOutputDev::setupExternalType1Font(GString
*fileName
, GString
*psName
) {
1978 // check if font is already embedded
1979 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1980 if (!fontFileNames
[i
]->cmp(fileName
)) {
1985 // add entry to fontFileNames list
1986 if (fontFileNameLen
>= fontFileNameSize
) {
1987 fontFileNameSize
+= 64;
1988 fontFileNames
= (GString
**)greallocn(fontFileNames
,
1989 fontFileNameSize
, sizeof(GString
*));
1991 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
1993 // beginning comment
1994 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1995 embFontList
->append("%%+ font ");
1996 embFontList
->append(psName
->getCString());
1997 embFontList
->append("\n");
1999 // copy the font file
2000 if (!(fontFile
= fopen(fileName
->getCString(), "rb"))) {
2001 error(-1, "Couldn't open external font file");
2004 while ((c
= fgetc(fontFile
)) != EOF
) {
2010 writePS("%%EndResource\n");
2013 void PSOutputDev::setupEmbeddedType1CFont(GfxFont
*font
, Ref
*id
,
2020 // check if font is already embedded
2021 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2022 if (fontFileIDs
[i
].num
== id
->num
&&
2023 fontFileIDs
[i
].gen
== id
->gen
)
2027 // add entry to fontFileIDs list
2028 if (fontFileIDLen
>= fontFileIDSize
) {
2029 fontFileIDSize
+= 64;
2030 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2032 fontFileIDs
[fontFileIDLen
++] = *id
;
2034 // beginning comment
2035 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2036 embFontList
->append("%%+ font ");
2037 embFontList
->append(psName
->getCString());
2038 embFontList
->append("\n");
2040 // convert it to a Type 1 font
2041 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2042 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2043 ffT1C
->convertToType1(NULL
, gTrue
, outputFunc
, outputStream
);
2049 writePS("%%EndResource\n");
2052 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont
*font
, Ref
*id
,
2061 // check if font is already embedded
2062 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2063 if (fontFileIDs
[i
].num
== id
->num
&&
2064 fontFileIDs
[i
].gen
== id
->gen
) {
2065 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2066 psName
->append(unique
);
2071 // add entry to fontFileIDs list
2072 if (i
== fontFileIDLen
) {
2073 if (fontFileIDLen
>= fontFileIDSize
) {
2074 fontFileIDSize
+= 64;
2075 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2077 fontFileIDs
[fontFileIDLen
++] = *id
;
2080 // beginning comment
2081 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2082 embFontList
->append("%%+ font ");
2083 embFontList
->append(psName
->getCString());
2084 embFontList
->append("\n");
2086 // convert it to a Type 42 font
2087 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2088 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2089 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2090 ffTT
->convertToType42(psName
->getCString(),
2091 ((Gfx8BitFont
*)font
)->getHasEncoding()
2092 ? ((Gfx8BitFont
*)font
)->getEncoding()
2094 codeToGID
, outputFunc
, outputStream
);
2101 writePS("%%EndResource\n");
2104 void PSOutputDev::setupExternalTrueTypeFont(GfxFont
*font
, GString
*psName
) {
2113 // check if font is already embedded
2114 fileName
= font
->getExtFontFile();
2115 for (i
= 0; i
< fontFileNameLen
; ++i
) {
2116 if (!fontFileNames
[i
]->cmp(fileName
)) {
2117 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2118 psName
->append(unique
);
2123 // add entry to fontFileNames list
2124 if (i
== fontFileNameLen
) {
2125 if (fontFileNameLen
>= fontFileNameSize
) {
2126 fontFileNameSize
+= 64;
2128 (GString
**)greallocn(fontFileNames
,
2129 fontFileNameSize
, sizeof(GString
*));
2131 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
2134 // beginning comment
2135 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2136 embFontList
->append("%%+ font ");
2137 embFontList
->append(psName
->getCString());
2138 embFontList
->append("\n");
2140 // convert it to a Type 42 font
2141 fontBuf
= font
->readExtFontFile(&fontLen
);
2142 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2143 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2144 ffTT
->convertToType42(psName
->getCString(),
2145 ((Gfx8BitFont
*)font
)->getHasEncoding()
2146 ? ((Gfx8BitFont
*)font
)->getEncoding()
2148 codeToGID
, outputFunc
, outputStream
);
2154 writePS("%%EndResource\n");
2157 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont
*font
, Ref
*id
,
2164 // check if font is already embedded
2165 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2166 if (fontFileIDs
[i
].num
== id
->num
&&
2167 fontFileIDs
[i
].gen
== id
->gen
)
2171 // add entry to fontFileIDs list
2172 if (fontFileIDLen
>= fontFileIDSize
) {
2173 fontFileIDSize
+= 64;
2174 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2176 fontFileIDs
[fontFileIDLen
++] = *id
;
2178 // beginning comment
2179 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2180 embFontList
->append("%%+ font ");
2181 embFontList
->append(psName
->getCString());
2182 embFontList
->append("\n");
2184 // convert it to a Type 0 font
2185 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2186 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2187 if (globalParams
->getPSLevel() >= psLevel3
) {
2188 // Level 3: use a CID font
2189 ffT1C
->convertToCIDType0(psName
->getCString(), outputFunc
, outputStream
);
2191 // otherwise: use a non-CID composite font
2192 ffT1C
->convertToType0(psName
->getCString(), outputFunc
, outputStream
);
2199 writePS("%%EndResource\n");
2202 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont
*font
, Ref
*id
,
2204 GBool needVerticalMetrics
) {
2211 // check if font is already embedded
2212 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2213 if (fontFileIDs
[i
].num
== id
->num
&&
2214 fontFileIDs
[i
].gen
== id
->gen
) {
2215 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2216 psName
->append(unique
);
2221 // add entry to fontFileIDs list
2222 if (fontFileIDLen
>= fontFileIDSize
) {
2223 fontFileIDSize
+= 64;
2224 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2226 fontFileIDs
[fontFileIDLen
++] = *id
;
2228 // beginning comment
2229 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2230 embFontList
->append("%%+ font ");
2231 embFontList
->append(psName
->getCString());
2232 embFontList
->append("\n");
2234 // convert it to a Type 0 font
2235 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2236 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2237 if (globalParams
->getPSLevel() >= psLevel3
) {
2238 // Level 3: use a CID font
2239 ffTT
->convertToCIDType2(psName
->getCString(),
2240 ((GfxCIDFont
*)font
)->getCIDToGID(),
2241 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2242 needVerticalMetrics
,
2243 outputFunc
, outputStream
);
2245 // otherwise: use a non-CID composite font
2246 ffTT
->convertToType0(psName
->getCString(),
2247 ((GfxCIDFont
*)font
)->getCIDToGID(),
2248 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2249 needVerticalMetrics
,
2250 outputFunc
, outputStream
);
2257 writePS("%%EndResource\n");
2260 void PSOutputDev::setupType3Font(GfxFont
*font
, GString
*psName
,
2261 Dict
*parentResDict
) {
2271 // set up resources used by font
2272 if ((resDict
= ((Gfx8BitFont
*)font
)->getResources())) {
2273 inType3Char
= gTrue
;
2274 setupResources(resDict
);
2275 inType3Char
= gFalse
;
2277 resDict
= parentResDict
;
2280 // beginning comment
2281 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2282 embFontList
->append("%%+ font ");
2283 embFontList
->append(psName
->getCString());
2284 embFontList
->append("\n");
2287 writePS("8 dict begin\n");
2288 writePS("/FontType 3 def\n");
2289 m
= font
->getFontMatrix();
2290 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
2291 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
2292 m
= font
->getFontBBox();
2293 writePSFmt("/FontBBox [%g %g %g %g] def\n",
2294 m
[0], m
[1], m
[2], m
[3]);
2295 writePS("/Encoding 256 array def\n");
2296 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2297 writePS("/BuildGlyph {\n");
2298 writePS(" exch /CharProcs get exch\n");
2299 writePS(" 2 copy known not { pop /.notdef } if\n");
2300 writePS(" get exec\n");
2301 writePS("} bind def\n");
2302 writePS("/BuildChar {\n");
2303 writePS(" 1 index /Encoding get exch get\n");
2304 writePS(" 1 index /BuildGlyph get exec\n");
2305 writePS("} bind def\n");
2306 if ((charProcs
= ((Gfx8BitFont
*)font
)->getCharProcs())) {
2307 writePSFmt("/CharProcs %d dict def\n", charProcs
->getLength());
2308 writePS("CharProcs begin\n");
2313 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
2314 inType3Char
= gTrue
;
2315 t3Cacheable
= gFalse
;
2316 for (i
= 0; i
< charProcs
->getLength(); ++i
) {
2318 writePSName(charProcs
->getKey(i
));
2320 gfx
->display(charProcs
->getVal(i
, &charProc
));
2324 sprintf(buf
, "%g %g %g %g %g %g setcachedevice\n",
2325 t3WX
, t3WY
, t3LLX
, t3LLY
, t3URX
, t3URY
);
2327 sprintf(buf
, "%g %g setcharwidth\n", t3WX
, t3WY
);
2329 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
2330 (*outputFunc
)(outputStream
, t3String
->getCString(),
2331 t3String
->getLength());
2335 (*outputFunc
)(outputStream
, "Q\n", 2);
2338 inType3Char
= gFalse
;
2342 writePS("currentdict end\n");
2343 writePSFmt("/%s exch definefont pop\n", psName
->getCString());
2346 writePS("%%EndResource\n");
2349 void PSOutputDev::setupImages(Dict
*resDict
) {
2350 Object xObjDict
, xObj
, xObjRef
, subtypeObj
;
2353 if (!(mode
== psModeForm
|| inType3Char
)) {
2357 resDict
->lookup("XObject", &xObjDict
);
2358 if (xObjDict
.isDict()) {
2359 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
2360 xObjDict
.dictGetValNF(i
, &xObjRef
);
2361 xObjDict
.dictGetVal(i
, &xObj
);
2362 if (xObj
.isStream()) {
2363 xObj
.streamGetDict()->lookup("Subtype", &subtypeObj
);
2364 if (subtypeObj
.isName("Image")) {
2365 if (xObjRef
.isRef()) {
2366 setupImage(xObjRef
.getRef(), xObj
.getStream());
2368 error(-1, "Image in resource dict is not an indirect reference");
2380 void PSOutputDev::setupImage(Ref id
, Stream
*str
) {
2383 int size
, line
, col
, i
;
2385 // construct an encoder stream
2386 useASCIIHex
= level
== psLevel1
|| level
== psLevel1Sep
||
2387 globalParams
->getPSASCIIHex();
2389 str
= new ASCIIHexEncoder(str
);
2391 str
= new ASCII85Encoder(str
);
2394 // compute image data size
2400 } while (c
== '\n' || c
== '\r');
2401 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2408 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2411 } while (c
== '\n' || c
== '\r');
2412 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2422 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2424 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size
, id
.num
, id
.gen
);
2427 // write the data into the array
2430 writePS((char *)(useASCIIHex
? "dup 0 <" : "dup 0 <~"));
2434 } while (c
== '\n' || c
== '\r');
2435 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2444 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2447 } while (c
== '\n' || c
== '\r');
2448 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2455 // each line is: "dup nnnnn <~...data...~> put<eol>"
2456 // so max data length = 255 - 20 = 235
2457 // chunks are 1 or 4 bytes each, so we have to stop at 232
2458 // but make it 225 just to be safe
2460 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2462 writePSFmt((char *)(useASCIIHex
? "dup %d <" : "dup %d <~"), line
);
2465 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2466 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2473 GBool
PSOutputDev::startPage(int pageNum
, GfxState
*state
) {
2474 int x1
, y1
, x2
, y2
, width
, height
;
2475 int imgWidth
, imgHeight
, imgWidth2
, imgHeight2
;
2479 if (mode
== psModePS
) {
2480 writePSFmt("%%%%Page: %d %d\n", pageNum
, seqPage
);
2481 writePS("%%BeginPageSetup\n");
2486 (*underlayCbk
)(this, underlayCbkData
);
2495 // rotate, translate, and scale page
2496 imgWidth
= imgURX
- imgLLX
;
2497 imgHeight
= imgURY
- imgLLY
;
2498 x1
= (int)floor(state
->getX1());
2499 y1
= (int)floor(state
->getY1());
2500 x2
= (int)ceil(state
->getX2());
2501 y2
= (int)ceil(state
->getY2());
2505 // rotation and portrait/landscape mode
2507 rotate
= (360 - rotate0
) % 360;
2510 rotate
= (360 - state
->getRotate()) % 360;
2511 if (rotate
== 0 || rotate
== 180) {
2512 if (width
> height
&& width
> imgWidth
) {
2518 } else { // rotate == 90 || rotate == 270
2519 if (height
> width
&& height
> imgWidth
) {
2520 rotate
= 270 - rotate
;
2527 writePSFmt("%%%%PageOrientation: %s\n",
2528 landscape
? "Landscape" : "Portrait");
2529 writePS("pdfStartPage\n");
2531 imgWidth2
= imgWidth
;
2532 imgHeight2
= imgHeight
;
2533 } else if (rotate
== 90) {
2534 writePS("90 rotate\n");
2536 imgWidth2
= imgHeight
;
2537 imgHeight2
= imgWidth
;
2538 } else if (rotate
== 180) {
2539 writePS("180 rotate\n");
2540 imgWidth2
= imgWidth
;
2541 imgHeight2
= imgHeight
;
2544 } else { // rotate == 270
2545 writePS("270 rotate\n");
2547 imgWidth2
= imgHeight
;
2548 imgHeight2
= imgWidth
;
2551 if (xScale0
> 0 && yScale0
> 0) {
2554 } else if ((globalParams
->getPSShrinkLarger() &&
2555 (width
> imgWidth2
|| height
> imgHeight2
)) ||
2556 (globalParams
->getPSExpandSmaller() &&
2557 (width
< imgWidth2
&& height
< imgHeight2
))) {
2558 xScale
= (double)imgWidth2
/ (double)width
;
2559 yScale
= (double)imgHeight2
/ (double)height
;
2560 if (yScale
< xScale
) {
2566 xScale
= yScale
= 1;
2568 paperHeight
= height
;
2571 // deal with odd bounding boxes or clipping
2572 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2573 tx
-= xScale
* clipLLX0
;
2574 ty
-= yScale
* clipLLY0
;
2580 if (globalParams
->getPSCenter()) {
2581 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2582 tx
+= (imgWidth2
- xScale
* (clipURX0
- clipLLX0
)) / 2;
2583 ty
+= (imgHeight2
- yScale
* (clipURY0
- clipLLY0
)) / 2;
2585 tx
+= (imgWidth2
- xScale
* width
) / 2;
2586 ty
+= (imgHeight2
- yScale
* height
) / 2;
2589 tx
+= rotate
== 0 ? imgLLX
+ tx0
: imgLLY
+ ty0
;
2590 ty
+= rotate
== 0 ? imgLLY
+ ty0
: -(imgLLX
+ tx0
);
2591 if (tx
!= 0 || ty
!= 0) {
2592 writePSFmt("%g %g translate\n", tx
, ty
);
2594 if (xScale
!= 1 || yScale
!= 1) {
2595 writePSFmt("%0.4f %0.4f scale\n", xScale
, xScale
);
2597 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2598 writePSFmt("%g %g %g %g re W\n",
2599 clipLLX0
, clipLLY0
, clipURX0
- clipLLX0
, clipURY0
- clipLLY0
);
2601 writePSFmt("%d %d %d %d re W\n", x1
, y1
, x2
- x1
, y2
- y1
);
2604 writePS("%%EndPageSetup\n");
2609 writePS("pdfStartPage\n");
2611 rotate
= (360 - state
->getRotate()) % 360;
2613 } else if (rotate
== 90) {
2614 writePS("90 rotate\n");
2617 } else if (rotate
== 180) {
2618 writePS("180 rotate\n");
2619 tx
= -(epsX1
+ epsX2
);
2620 ty
= -(epsY1
+ epsY2
);
2621 } else { // rotate == 270
2622 writePS("270 rotate\n");
2626 if (tx
!= 0 || ty
!= 0) {
2627 writePSFmt("%g %g translate\n", tx
, ty
);
2629 xScale
= yScale
= 1;
2633 writePS("/PaintProc {\n");
2634 writePS("begin xpdf begin\n");
2635 writePS("pdfStartPage\n");
2637 xScale
= yScale
= 1;
2642 if (!checkRange(pageNum
))
2648 void PSOutputDev::endPage() {
2651 (*overlayCbk
)(this, overlayCbkData
);
2654 if (mode
== psModeForm
) {
2655 writePS("pdfEndPage\n");
2656 writePS("end end\n");
2658 writePS("end end\n");
2661 writePS("showpage\n");
2663 writePS("%%PageTrailer\n");
2668 void PSOutputDev::saveState(GfxState
*state
) {
2673 void PSOutputDev::restoreState(GfxState
*state
) {
2678 void PSOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
2679 double m21
, double m22
, double m31
, double m32
) {
2680 writePSFmt("[%g %g %g %g %g %g] cm\n", m11
, m12
, m21
, m22
, m31
, m32
);
2683 void PSOutputDev::updateLineDash(GfxState
*state
) {
2688 state
->getLineDash(&dash
, &length
, &start
);
2690 for (i
= 0; i
< length
; ++i
) {
2692 dash
[i
] == 0 ? 1 : dash
[i
],
2693 (i
== length
-1) ? "" : " ");
2695 writePSFmt("] %g d\n", start
);
2698 void PSOutputDev::updateFlatness(GfxState
*state
) {
2699 writePSFmt("%d i\n", state
->getFlatness());
2702 void PSOutputDev::updateLineJoin(GfxState
*state
) {
2703 writePSFmt("%d j\n", state
->getLineJoin());
2706 void PSOutputDev::updateLineCap(GfxState
*state
) {
2707 writePSFmt("%d J\n", state
->getLineCap());
2710 void PSOutputDev::updateMiterLimit(GfxState
*state
) {
2711 writePSFmt("%g M\n", state
->getMiterLimit());
2714 void PSOutputDev::updateLineWidth(GfxState
*state
) {
2715 writePSFmt("%g w\n", state
->getLineWidth());
2718 void PSOutputDev::updateFillColorSpace(GfxState
*state
) {
2725 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2726 dumpColorSpaceL2(state
->getFillColorSpace(), gTrue
, gFalse
);
2736 void PSOutputDev::updateStrokeColorSpace(GfxState
*state
) {
2743 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2744 dumpColorSpaceL2(state
->getStrokeColorSpace(), gTrue
, gFalse
);
2754 void PSOutputDev::updateFillColor(GfxState
*state
) {
2759 GfxSeparationColorSpace
*sepCS
;
2765 state
->getFillGray(&gray
);
2766 writePSFmt("%g g\n", colToDbl(gray
));
2769 state
->getFillCMYK(&cmyk
);
2770 c
= colToDbl(cmyk
.c
);
2771 m
= colToDbl(cmyk
.m
);
2772 y
= colToDbl(cmyk
.y
);
2773 k
= colToDbl(cmyk
.k
);
2774 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2775 addProcessColor(c
, m
, y
, k
);
2779 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2780 colorPtr
= state
->getFillColor();
2782 for (i
= 0; i
< state
->getFillColorSpace()->getNComps(); ++i
) {
2786 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2793 if (state
->getFillColorSpace()->getMode() == csSeparation
) {
2794 sepCS
= (GfxSeparationColorSpace
*)state
->getFillColorSpace();
2795 color
.c
[0] = gfxColorComp1
;
2796 sepCS
->getCMYK(&color
, &cmyk
);
2797 writePSFmt("%g %g %g %g %g (%s) ck\n",
2798 colToDbl(state
->getFillColor()->c
[0]),
2799 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2800 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2801 sepCS
->getName()->getCString());
2802 addCustomColor(sepCS
);
2804 state
->getFillCMYK(&cmyk
);
2805 c
= colToDbl(cmyk
.c
);
2806 m
= colToDbl(cmyk
.m
);
2807 y
= colToDbl(cmyk
.y
);
2808 k
= colToDbl(cmyk
.k
);
2809 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2810 addProcessColor(c
, m
, y
, k
);
2814 t3Cacheable
= gFalse
;
2817 void PSOutputDev::updateStrokeColor(GfxState
*state
) {
2822 GfxSeparationColorSpace
*sepCS
;
2828 state
->getStrokeGray(&gray
);
2829 writePSFmt("%g G\n", colToDbl(gray
));
2832 state
->getStrokeCMYK(&cmyk
);
2833 c
= colToDbl(cmyk
.c
);
2834 m
= colToDbl(cmyk
.m
);
2835 y
= colToDbl(cmyk
.y
);
2836 k
= colToDbl(cmyk
.k
);
2837 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2838 addProcessColor(c
, m
, y
, k
);
2842 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2843 colorPtr
= state
->getStrokeColor();
2845 for (i
= 0; i
< state
->getStrokeColorSpace()->getNComps(); ++i
) {
2849 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2856 if (state
->getStrokeColorSpace()->getMode() == csSeparation
) {
2857 sepCS
= (GfxSeparationColorSpace
*)state
->getStrokeColorSpace();
2858 color
.c
[0] = gfxColorComp1
;
2859 sepCS
->getCMYK(&color
, &cmyk
);
2860 writePSFmt("%g %g %g %g %g (%s) CK\n",
2861 colToDbl(state
->getStrokeColor()->c
[0]),
2862 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2863 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2864 sepCS
->getName()->getCString());
2865 addCustomColor(sepCS
);
2867 state
->getStrokeCMYK(&cmyk
);
2868 c
= colToDbl(cmyk
.c
);
2869 m
= colToDbl(cmyk
.m
);
2870 y
= colToDbl(cmyk
.y
);
2871 k
= colToDbl(cmyk
.k
);
2872 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2873 addProcessColor(c
, m
, y
, k
);
2877 t3Cacheable
= gFalse
;
2880 void PSOutputDev::addProcessColor(double c
, double m
, double y
, double k
) {
2882 processColors
|= psProcessCyan
;
2885 processColors
|= psProcessMagenta
;
2888 processColors
|= psProcessYellow
;
2891 processColors
|= psProcessBlack
;
2895 void PSOutputDev::addCustomColor(GfxSeparationColorSpace
*sepCS
) {
2896 PSOutCustomColor
*cc
;
2900 for (cc
= customColors
; cc
; cc
= cc
->next
) {
2901 if (!cc
->name
->cmp(sepCS
->getName())) {
2905 color
.c
[0] = gfxColorComp1
;
2906 sepCS
->getCMYK(&color
, &cmyk
);
2907 cc
= new PSOutCustomColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2908 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2909 sepCS
->getName()->copy());
2910 cc
->next
= customColors
;
2914 void PSOutputDev::updateFillOverprint(GfxState
*state
) {
2915 if (level
>= psLevel2
) {
2916 writePSFmt("%s op\n", state
->getFillOverprint() ? "true" : "false");
2920 void PSOutputDev::updateStrokeOverprint(GfxState
*state
) {
2921 if (level
>= psLevel2
) {
2922 writePSFmt("%s OP\n", state
->getStrokeOverprint() ? "true" : "false");
2926 void PSOutputDev::updateFont(GfxState
*state
) {
2927 if (state
->getFont()) {
2928 writePSFmt("/F%d_%d %g Tf\n",
2929 state
->getFont()->getID()->num
, state
->getFont()->getID()->gen
,
2930 fabs(state
->getFontSize()) < 0.00001 ? 0.00001
2931 : state
->getFontSize());
2935 void PSOutputDev::updateTextMat(GfxState
*state
) {
2938 mat
= state
->getTextMat();
2939 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.00001) {
2940 // avoid a singular (or close-to-singular) matrix
2941 writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat
[4], mat
[5]);
2943 writePSFmt("[%g %g %g %g %g %g] Tm\n",
2944 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
2948 void PSOutputDev::updateCharSpace(GfxState
*state
) {
2949 writePSFmt("%g Tc\n", state
->getCharSpace());
2952 void PSOutputDev::updateRender(GfxState
*state
) {
2955 rm
= state
->getRender();
2956 writePSFmt("%d Tr\n", rm
);
2958 if (rm
!= 0 && rm
!= 3) {
2959 t3Cacheable
= gFalse
;
2963 void PSOutputDev::updateRise(GfxState
*state
) {
2964 writePSFmt("%g Ts\n", state
->getRise());
2967 void PSOutputDev::updateWordSpace(GfxState
*state
) {
2968 writePSFmt("%g Tw\n", state
->getWordSpace());
2971 void PSOutputDev::updateHorizScaling(GfxState
*state
) {
2974 h
= state
->getHorizScaling();
2975 if (fabs(h
) < 0.01) {
2978 writePSFmt("%g Tz\n", h
);
2981 void PSOutputDev::updateTextPos(GfxState
*state
) {
2982 writePSFmt("%g %g Td\n", state
->getLineX(), state
->getLineY());
2985 void PSOutputDev::updateTextShift(GfxState
*state
, double shift
) {
2986 if (state
->getFont()->getWMode()) {
2987 writePSFmt("%g TJmV\n", shift
);
2989 writePSFmt("%g TJm\n", shift
);
2993 void PSOutputDev::stroke(GfxState
*state
) {
2994 doPath(state
->getPath());
2996 // if we're construct a cacheable Type 3 glyph, we need to do
2997 // everything in the fill color
3004 void PSOutputDev::fill(GfxState
*state
) {
3005 doPath(state
->getPath());
3009 void PSOutputDev::eoFill(GfxState
*state
) {
3010 doPath(state
->getPath());
3014 void PSOutputDev::tilingPatternFill(GfxState
*state
, Object
*str
,
3015 int paintType
, Dict
*resDict
,
3016 double *mat
, double *bbox
,
3017 int x0
, int y0
, int x1
, int y1
,
3018 double xStep
, double yStep
) {
3022 // define a Type 3 font
3023 writePS("8 dict begin\n");
3024 writePS("/FontType 3 def\n");
3025 writePS("/FontMatrix [1 0 0 1 0 0] def\n");
3026 writePSFmt("/FontBBox [%g %g %g %g] def\n",
3027 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3028 writePS("/Encoding 256 array def\n");
3029 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
3030 writePS(" Encoding 120 /x put\n");
3031 writePS("/BuildGlyph {\n");
3032 writePS(" exch /CharProcs get exch\n");
3033 writePS(" 2 copy known not { pop /.notdef } if\n");
3034 writePS(" get exec\n");
3035 writePS("} bind def\n");
3036 writePS("/BuildChar {\n");
3037 writePS(" 1 index /Encoding get exch get\n");
3038 writePS(" 1 index /BuildGlyph get exec\n");
3039 writePS("} bind def\n");
3040 writePS("/CharProcs 1 dict def\n");
3041 writePS("CharProcs begin\n");
3046 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
3048 if (paintType
== 2) {
3049 writePSFmt("%g 0 %g %g %g %g setcachedevice\n",
3050 xStep
, bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3052 writePSFmt("%g 0 setcharwidth\n", xStep
);
3054 inType3Char
= gTrue
;
3055 ++numTilingPatterns
;
3057 --numTilingPatterns
;
3058 inType3Char
= gFalse
;
3062 writePS("currentdict end\n");
3063 writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns
);
3066 writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns
);
3067 writePSFmt("gsave [%g %g %g %g %g %g] concat\n",
3068 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3069 writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n",
3070 y0
, y1
- 1, x0
* xStep
, yStep
, x0
, x1
- 1);
3071 writePS("grestore\n");
3074 void PSOutputDev::functionShadedFill(GfxState
*state
,
3075 GfxFunctionShading
*shading
) {
3076 double x0
, y0
, x1
, y1
;
3080 shading
->getDomain(&x0
, &y0
, &x1
, &y1
);
3081 mat
= shading
->getMatrix();
3082 writePSFmt("/mat [%g %g %g %g %g %g] def\n",
3083 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3084 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3085 if (shading
->getNFuncs() == 1) {
3087 cvtFunction(shading
->getFunc(0));
3090 writePS("/func {\n");
3091 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3092 if (i
< shading
->getNFuncs() - 1) {
3093 writePS("2 copy\n");
3095 cvtFunction(shading
->getFunc(i
));
3097 if (i
< shading
->getNFuncs() - 1) {
3098 writePS("3 1 roll\n");
3103 writePSFmt("%g %g %g %g 0 funcSH\n", x0
, y0
, x1
, y1
);
3106 void PSOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
) {
3107 double xMin
, yMin
, xMax
, yMax
;
3108 double x0
, y0
, x1
, y1
, dx
, dy
, mul
;
3109 double tMin
, tMax
, t
, t0
, t1
;
3112 // get the clip region bbox
3113 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3115 // compute min and max t values, based on the four corners of the
3117 shading
->getCoords(&x0
, &y0
, &x1
, &y1
);
3120 mul
= 1 / (dx
* dx
+ dy
* dy
);
3121 tMin
= tMax
= ((xMin
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3122 t
= ((xMin
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3125 } else if (t
> tMax
) {
3128 t
= ((xMax
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3131 } else if (t
> tMax
) {
3134 t
= ((xMax
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3137 } else if (t
> tMax
) {
3140 if (tMin
< 0 && !shading
->getExtend0()) {
3143 if (tMax
> 1 && !shading
->getExtend1()) {
3147 // get the function domain
3148 t0
= shading
->getDomain0();
3149 t1
= shading
->getDomain1();
3151 // generate the PS code
3152 writePSFmt("/t0 %g def\n", t0
);
3153 writePSFmt("/t1 %g def\n", t1
);
3154 writePSFmt("/dt %g def\n", t1
- t0
);
3155 writePSFmt("/x0 %g def\n", x0
);
3156 writePSFmt("/y0 %g def\n", y0
);
3157 writePSFmt("/dx %g def\n", x1
- x0
);
3158 writePSFmt("/x1 %g def\n", x1
);
3159 writePSFmt("/y1 %g def\n", y1
);
3160 writePSFmt("/dy %g def\n", y1
- y0
);
3161 writePSFmt("/xMin %g def\n", xMin
);
3162 writePSFmt("/yMin %g def\n", yMin
);
3163 writePSFmt("/xMax %g def\n", xMax
);
3164 writePSFmt("/yMax %g def\n", yMax
);
3165 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3166 if (shading
->getNFuncs() == 1) {
3168 cvtFunction(shading
->getFunc(0));
3171 writePS("/func {\n");
3172 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3173 if (i
< shading
->getNFuncs() - 1) {
3176 cvtFunction(shading
->getFunc(i
));
3178 if (i
< shading
->getNFuncs() - 1) {
3184 writePSFmt("%g %g 0 axialSH\n", tMin
, tMax
);
3187 void PSOutputDev::radialShadedFill(GfxState
*state
,
3188 GfxRadialShading
*shading
) {
3189 double x0
, y0
, r0
, x1
, y1
, r1
, t0
, t1
, sMin
, sMax
;
3190 double xMin
, yMin
, xMax
, yMax
;
3194 // get the shading info
3195 shading
->getCoords(&x0
, &y0
, &r0
, &x1
, &y1
, &r1
);
3196 t0
= shading
->getDomain0();
3197 t1
= shading
->getDomain1();
3199 // compute the (possibly extended) s range
3202 if (shading
->getExtend0()) {
3204 // extend the smaller end
3205 sMin
= -r0
/ (r1
- r0
);
3207 // extend the larger end
3208 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3209 d0
= (x0
- xMin
) * (x0
- xMin
);
3210 d1
= (x0
- xMax
) * (x0
- xMax
);
3211 sMin
= d0
> d1
? d0
: d1
;
3212 d0
= (y0
- yMin
) * (y0
- yMin
);
3213 d1
= (y0
- yMax
) * (y0
- yMax
);
3214 sMin
+= d0
> d1
? d0
: d1
;
3215 sMin
= (sqrt(sMin
) - r0
) / (r1
- r0
);
3218 } else if (sMin
< -20) {
3224 if (shading
->getExtend1()) {
3226 // extend the smaller end
3227 sMax
= -r0
/ (r1
- r0
);
3228 } else if (r1
> r0
) {
3229 // extend the larger end
3230 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3231 d0
= (x1
- xMin
) * (x1
- xMin
);
3232 d1
= (x1
- xMax
) * (x1
- xMax
);
3233 sMax
= d0
> d1
? d0
: d1
;
3234 d0
= (y1
- yMin
) * (y1
- yMin
);
3235 d1
= (y1
- yMax
) * (y1
- yMax
);
3236 sMax
+= d0
> d1
? d0
: d1
;
3237 sMax
= (sqrt(sMax
) - r0
) / (r1
- r0
);
3240 } else if (sMax
> 20) {
3247 // generate the PS code
3248 writePSFmt("/x0 %g def\n", x0
);
3249 writePSFmt("/x1 %g def\n", x1
);
3250 writePSFmt("/dx %g def\n", x1
- x0
);
3251 writePSFmt("/y0 %g def\n", y0
);
3252 writePSFmt("/y1 %g def\n", y1
);
3253 writePSFmt("/dy %g def\n", y1
- y0
);
3254 writePSFmt("/r0 %g def\n", r0
);
3255 writePSFmt("/r1 %g def\n", r1
);
3256 writePSFmt("/dr %g def\n", r1
- r0
);
3257 writePSFmt("/t0 %g def\n", t0
);
3258 writePSFmt("/t1 %g def\n", t1
);
3259 writePSFmt("/dt %g def\n", t1
- t0
);
3260 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3261 if (shading
->getNFuncs() == 1) {
3263 cvtFunction(shading
->getFunc(0));
3266 writePS("/func {\n");
3267 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3268 if (i
< shading
->getNFuncs() - 1) {
3271 cvtFunction(shading
->getFunc(i
));
3273 if (i
< shading
->getNFuncs() - 1) {
3279 writePSFmt("%g %g 0 radialSH\n", sMin
, sMax
);
3282 void PSOutputDev::clip(GfxState
*state
) {
3283 doPath(state
->getPath());
3287 void PSOutputDev::eoClip(GfxState
*state
) {
3288 doPath(state
->getPath());
3292 void PSOutputDev::doPath(GfxPath
*path
) {
3293 GfxSubpath
*subpath
;
3294 double x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
3297 n
= path
->getNumSubpaths();
3299 if (n
== 1 && path
->getSubpath(0)->getNumPoints() == 5) {
3300 subpath
= path
->getSubpath(0);
3301 x0
= subpath
->getX(0);
3302 y0
= subpath
->getY(0);
3303 x4
= subpath
->getX(4);
3304 y4
= subpath
->getY(4);
3305 if (x4
== x0
&& y4
== y0
) {
3306 x1
= subpath
->getX(1);
3307 y1
= subpath
->getY(1);
3308 x2
= subpath
->getX(2);
3309 y2
= subpath
->getY(2);
3310 x3
= subpath
->getX(3);
3311 y3
= subpath
->getY(3);
3312 if (x0
== x1
&& x2
== x3
&& y0
== y3
&& y1
== y2
) {
3313 writePSFmt("%g %g %g %g re\n",
3314 x0
< x2
? x0
: x2
, y0
< y1
? y0
: y1
,
3315 fabs(x2
- x0
), fabs(y1
- y0
));
3317 } else if (x0
== x3
&& x1
== x2
&& y0
== y1
&& y2
== y3
) {
3318 writePSFmt("%g %g %g %g re\n",
3319 x0
< x1
? x0
: x1
, y0
< y2
? y0
: y2
,
3320 fabs(x1
- x0
), fabs(y2
- y0
));
3326 for (i
= 0; i
< n
; ++i
) {
3327 subpath
= path
->getSubpath(i
);
3328 m
= subpath
->getNumPoints();
3329 writePSFmt("%g %g m\n", subpath
->getX(0), subpath
->getY(0));
3332 if (subpath
->getCurve(j
)) {
3333 writePSFmt("%g %g %g %g %g %g c\n", subpath
->getX(j
), subpath
->getY(j
),
3334 subpath
->getX(j
+1), subpath
->getY(j
+1),
3335 subpath
->getX(j
+2), subpath
->getY(j
+2));
3338 writePSFmt("%g %g l\n", subpath
->getX(j
), subpath
->getY(j
));
3342 if (subpath
->isClosed()) {
3348 void PSOutputDev::drawString(GfxState
*state
, GString
*s
) {
3352 double dx
, dy
, dx2
, dy2
, originX
, originY
;
3358 int len
, nChars
, uLen
, n
, m
, i
, j
;
3360 // check for invisible text -- this is used by Acrobat Capture
3361 if (state
->getRender() == 3) {
3365 // ignore empty strings
3366 if (s
->getLength() == 0) {
3371 if (!(font
= state
->getFont())) {
3374 wMode
= font
->getWMode();
3376 // check for a subtitute 16-bit font
3378 if (font
->isCIDFont()) {
3379 for (i
= 0; i
< font16EncLen
; ++i
) {
3380 if (font
->getID()->num
== font16Enc
[i
].fontID
.num
&&
3381 font
->getID()->gen
== font16Enc
[i
].fontID
.gen
) {
3382 uMap
= globalParams
->getUnicodeMap(font16Enc
[i
].enc
);
3388 // compute width of chars in string, ignoring char spacing and word
3389 // spacing -- the Tj operator will adjust for the metrics of the
3390 // font that's actually used
3393 p
= s
->getCString();
3394 len
= s
->getLength();
3395 if (font
->isCIDFont()) {
3401 n
= font
->getNextChar(p
, len
, &code
,
3402 u
, (int)(sizeof(u
) / sizeof(Unicode
)), &uLen
,
3403 &dx2
, &dy2
, &originX
, &originY
);
3404 if (font
->isCIDFont()) {
3406 for (i
= 0; i
< uLen
; ++i
) {
3407 m
= uMap
->mapUnicode(u
[i
], buf
, (int)sizeof(buf
));
3408 for (j
= 0; j
< m
; ++j
) {
3412 //~ this really needs to get the number of chars in the target
3413 //~ encoding - which may be more than the number of Unicode
3417 s2
->append((char)((code
>> 8) & 0xff));
3418 s2
->append((char)(code
& 0xff));
3427 dx
*= state
->getFontSize() * state
->getHorizScaling();
3428 dy
*= state
->getFontSize();
3433 if (s2
->getLength() > 0) {
3435 if (font
->isCIDFont()) {
3437 writePSFmt(" %d %g Tj16V\n", nChars
, dy
);
3439 writePSFmt(" %d %g Tj16\n", nChars
, dx
);
3442 writePSFmt(" %g Tj\n", dx
);
3445 if (font
->isCIDFont()) {
3449 if (state
->getRender() & 4) {
3450 haveTextClip
= gTrue
;
3454 void PSOutputDev::endTextObject(GfxState
*state
) {
3457 haveTextClip
= gFalse
;
3461 void PSOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
3462 int width
, int height
, GBool invert
,
3466 len
= height
* ((width
+ 7) / 8);
3467 if (level
== psLevel1
|| level
== psLevel1Sep
) {
3468 doImageL1(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
);
3470 doImageL2(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
,
3471 NULL
, NULL
, 0, 0, gFalse
);
3475 void PSOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3476 int width
, int height
, GfxImageColorMap
*colorMap
,
3477 int *maskColors
, GBool inlineImg
) {
3480 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3481 colorMap
->getBits() + 7) / 8);
3484 doImageL1(ref
, colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3487 //~ handle indexed, separation, ... color spaces
3488 doImageL1Sep(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3494 doImageL2(ref
, colorMap
, gFalse
, inlineImg
, str
,
3495 width
, height
, len
, maskColors
, NULL
, 0, 0, gFalse
);
3498 t3Cacheable
= gFalse
;
3501 void PSOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3502 int width
, int height
,
3503 GfxImageColorMap
*colorMap
,
3505 int maskWidth
, int maskHeight
,
3509 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3510 colorMap
->getBits() + 7) / 8);
3513 doImageL1(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3516 //~ handle indexed, separation, ... color spaces
3517 doImageL1Sep(colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3523 doImageL2(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
,
3524 NULL
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
3527 t3Cacheable
= gFalse
;
3530 void PSOutputDev::doImageL1(Object
*ref
, GfxImageColorMap
*colorMap
,
3531 GBool invert
, GBool inlineImg
,
3532 Stream
*str
, int width
, int height
, int len
) {
3533 ImageStream
*imgStr
;
3534 Guchar pixBuf
[gfxColorMaxComps
];
3536 int col
, x
, y
, c
, i
;
3538 if (inType3Char
&& !colorMap
) {
3541 str
= new FixedLengthEncoder(str
, len
);
3542 str
= new ASCIIHexEncoder(str
);
3549 } while (c
== '\n' || c
== '\r');
3550 if (c
== '>' || c
== EOF
) {
3555 // each line is: "<...data...><eol>"
3556 // so max data length = 255 - 4 = 251
3557 // but make it 240 just to be safe
3558 // chunks are 2 bytes each, so we need to stop on an even col number
3563 } while (c
!= '>' && c
!= EOF
);
3569 // set up to use the array already created by setupImages()
3570 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3574 // image/imagemask command
3575 if (inType3Char
&& !colorMap
) {
3576 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
3577 width
, height
, invert
? "true" : "false",
3578 width
, -height
, height
);
3579 } else if (colorMap
) {
3580 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
3582 width
, -height
, height
);
3584 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
3585 width
, height
, invert
? "true" : "false",
3586 width
, -height
, height
);
3590 if (!(inType3Char
&& !colorMap
)) {
3594 // set up to process the data stream
3595 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3596 colorMap
->getBits());
3599 // process the data stream
3601 for (y
= 0; y
< height
; ++y
) {
3604 for (x
= 0; x
< width
; ++x
) {
3605 imgStr
->getPixel(pixBuf
);
3606 colorMap
->getGray(pixBuf
, &gray
);
3607 writePSFmt("%02x", colToByte(gray
));
3623 for (y
= 0; y
< height
; ++y
) {
3624 for (x
= 0; x
< width
; x
+= 8) {
3625 writePSFmt("%02x", str
->getChar() & 0xff);
3640 void PSOutputDev::doImageL1Sep(GfxImageColorMap
*colorMap
,
3641 GBool invert
, GBool inlineImg
,
3642 Stream
*str
, int width
, int height
, int len
) {
3643 ImageStream
*imgStr
;
3645 Guchar pixBuf
[gfxColorMaxComps
];
3649 // width, height, matrix, bits per component
3650 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
3652 width
, -height
, height
);
3654 // allocate a line buffer
3655 lineBuf
= (Guchar
*)gmalloc(4 * width
);
3657 // set up to process the data stream
3658 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3659 colorMap
->getBits());
3662 // process the data stream
3664 for (y
= 0; y
< height
; ++y
) {
3667 for (x
= 0; x
< width
; ++x
) {
3668 imgStr
->getPixel(pixBuf
);
3669 colorMap
->getCMYK(pixBuf
, &cmyk
);
3670 lineBuf
[4*x
+0] = colToByte(cmyk
.c
);
3671 lineBuf
[4*x
+1] = colToByte(cmyk
.m
);
3672 lineBuf
[4*x
+2] = colToByte(cmyk
.y
);
3673 lineBuf
[4*x
+3] = colToByte(cmyk
.k
);
3674 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3675 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
3678 // write one line of each color component
3679 for (comp
= 0; comp
< 4; ++comp
) {
3680 for (x
= 0; x
< width
; ++x
) {
3681 writePSFmt("%02x", lineBuf
[4*x
+ comp
]);
3698 void PSOutputDev::doImageL2(Object
*ref
, GfxImageColorMap
*colorMap
,
3699 GBool invert
, GBool inlineImg
,
3700 Stream
*str
, int width
, int height
, int len
,
3701 int *maskColors
, Stream
*maskStr
,
3702 int maskWidth
, int maskHeight
, GBool maskInvert
) {
3703 ImageStream
*imgStr
;
3707 GBool useRLE
, useASCII
, useASCIIHex
, useCompressed
;
3708 GfxSeparationColorSpace
*sepCS
;
3712 int col
, i
, x
, x0
, y
, y0
, maskXor
;
3714 // color key masking
3715 if (maskColors
&& colorMap
&& !inlineImg
) {
3716 // can't read the stream twice for inline images -- but masking
3717 // isn't allowed with inline images anyway
3719 numComps
= colorMap
->getNumPixelComps();
3720 imgStr
= new ImageStream(str
, width
, numComps
, colorMap
->getBits());
3722 for (y
= 0, y0
= 0; y
< height
; ++y
) {
3723 if (!(line
= imgStr
->getLine())) {
3726 for (x
= 0, x0
= 0, pix
= line
; x
< width
; ++x
, pix
+= numComps
) {
3727 for (i
= 0; i
< numComps
; ++i
) {
3728 if (pix
[i
] < maskColors
[2*i
] ||
3729 pix
[i
] > maskColors
[2*i
+1]) {
3733 if (i
== numComps
) {
3735 writePSFmt("0 %d %d %d\n", height
- y
, width
, y
- y0
);
3738 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, x
- x0
);
3744 if (x0
> 0 && x0
< width
) {
3745 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, width
- x0
);
3749 writePSFmt("0 0 %d %d\n", width
, height
- y0
);
3753 writePSFmt("] %d %d pdfImClip\n", width
, height
);
3756 } else if (maskStr
) {
3758 imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3760 maskXor
= maskInvert
? 1 : 0;
3761 for (y
= 0, y0
= 0; y
< maskHeight
; ++y
) {
3762 if (!(line
= imgStr
->getLine())) {
3765 for (x
= 0, x0
= 0, pix
= line
; x
< maskWidth
; ++x
, ++pix
) {
3766 if (*pix
^ maskXor
) {
3768 writePSFmt("0 %d %d %d\n", maskHeight
- y
, maskWidth
, y
- y0
);
3771 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, x
- x0
);
3777 if (x0
> 0 && x0
< maskWidth
) {
3778 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, maskWidth
- x0
);
3781 if (y0
< maskHeight
) {
3782 writePSFmt("0 0 %d %d\n", maskWidth
, maskHeight
- y0
);
3786 writePSFmt("] %d %d pdfImClip\n", maskWidth
, maskHeight
);
3791 dumpColorSpaceL2(colorMap
->getColorSpace(), gFalse
, gTrue
);
3792 writePS(" setcolorspace\n");
3795 useASCIIHex
= globalParams
->getPSASCIIHex();
3797 // set up the image data
3798 if (mode
== psModeForm
|| inType3Char
) {
3801 str
= new FixedLengthEncoder(str
, len
);
3803 str
= new ASCIIHexEncoder(str
);
3805 str
= new ASCII85Encoder(str
);
3809 writePS((char *)(useASCIIHex
? "[<" : "[<~"));
3813 } while (c
== '\n' || c
== '\r');
3814 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3823 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
3826 } while (c
== '\n' || c
== '\r');
3827 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3834 // each line is: "<~...data...~><eol>"
3835 // so max data length = 255 - 6 = 249
3836 // chunks are 1 or 5 bytes each, so we have to stop at 245
3837 // but make it 240 just to be safe
3839 writePS((char *)(useASCIIHex
? ">\n<" : "~>\n<~"));
3842 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
3843 writePS((char *)(useASCIIHex
? ">]\n" : "~>]\n"));
3848 // set up to use the array already created by setupImages()
3849 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3854 writePS("<<\n /ImageType 1\n");
3856 // width, height, matrix, bits per component
3857 writePSFmt(" /Width %d\n", width
);
3858 writePSFmt(" /Height %d\n", height
);
3859 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width
, -height
, height
);
3860 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3861 writePSFmt(" /BitsPerComponent 8\n");
3863 writePSFmt(" /BitsPerComponent %d\n",
3864 colorMap
? colorMap
->getBits() : 1);
3869 writePS(" /Decode [");
3870 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) &&
3871 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3872 // this matches up with the code in the pdfImSep operator
3873 n
= (1 << colorMap
->getBits()) - 1;
3874 writePSFmt("%g %g", colorMap
->getDecodeLow(0) * n
,
3875 colorMap
->getDecodeHigh(0) * n
);
3876 } else if (colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3877 numComps
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
3878 getAlt()->getNComps();
3879 for (i
= 0; i
< numComps
; ++i
) {
3886 numComps
= colorMap
->getNumPixelComps();
3887 for (i
= 0; i
< numComps
; ++i
) {
3891 writePSFmt("%g %g", colorMap
->getDecodeLow(i
),
3892 colorMap
->getDecodeHigh(i
));
3897 writePSFmt(" /Decode [%d %d]\n", invert
? 1 : 0, invert
? 0 : 1);
3900 if (mode
== psModeForm
|| inType3Char
) {
3903 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
3905 // end of image dictionary
3906 writePSFmt(">>\n%s\n", colorMap
? "image" : "imagemask");
3908 // get rid of the array and index
3909 writePS("pop pop\n");
3914 writePS(" /DataSource currentfile\n");
3915 s
= str
->getPSFilter(level
< psLevel2
? 1 : level
< psLevel3
? 2 : 3,
3917 if ((colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) ||
3921 useCompressed
= gFalse
;
3924 useASCII
= str
->isBinary();
3925 useCompressed
= gTrue
;
3928 writePSFmt(" /ASCII%sDecode filter\n",
3929 useASCIIHex
? "Hex" : "85");
3932 writePS(" /RunLengthDecode filter\n");
3934 if (useCompressed
) {
3935 writePS(s
->getCString());
3941 // cut off inline image streams at appropriate length
3943 str
= new FixedLengthEncoder(str
, len
);
3944 } else if (useCompressed
) {
3945 str
= str
->getBaseStream();
3948 // recode DeviceN data
3949 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3950 str
= new DeviceNRecoder(str
, width
, height
, colorMap
);
3953 // add RunLengthEncode and ASCIIHex/85 encode filters
3955 str
= new RunLengthEncoder(str
);
3959 str
= new ASCIIHexEncoder(str
);
3961 str
= new ASCII85Encoder(str
);
3965 // end of image dictionary
3970 // this can't happen -- OPI dictionaries are in XObjects
3971 error(-1, "Internal: OPI in inline image");
3974 // need to read the stream to count characters -- the length
3975 // is data-dependent (because of ASCII and RLE filters)
3978 while ((c
= str
->getChar()) != EOF
) {
3983 // +6/7 for "pdfIm\n" / "pdfImM\n"
3984 // +8 for newline + trailer
3985 n
+= colorMap
? 14 : 15;
3986 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n
);
3989 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) && colorMap
&&
3990 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3991 color
.c
[0] = gfxColorComp1
;
3992 sepCS
= (GfxSeparationColorSpace
*)colorMap
->getColorSpace();
3993 sepCS
->getCMYK(&color
, &cmyk
);
3994 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
3995 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3996 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
3997 sepCS
->getName()->getCString());
3999 writePSFmt("%s\n", colorMap
? "pdfIm" : "pdfImM");
4002 // copy the stream data
4004 while ((c
= str
->getChar()) != EOF
) {
4009 // add newline and trailer to the end
4011 writePS("%-EOD-\n");
4014 writePS("%%EndData\n");
4019 if (useRLE
|| useASCII
|| inlineImg
) {
4024 if ((maskColors
&& colorMap
&& !inlineImg
) || maskStr
) {
4025 writePS("pdfImClipEnd\n");
4029 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace
*colorSpace
,
4030 GBool genXform
, GBool updateColors
) {
4031 GfxCalGrayColorSpace
*calGrayCS
;
4032 GfxCalRGBColorSpace
*calRGBCS
;
4033 GfxLabColorSpace
*labCS
;
4034 GfxIndexedColorSpace
*indexedCS
;
4035 GfxSeparationColorSpace
*separationCS
;
4036 GfxDeviceNColorSpace
*deviceNCS
;
4037 GfxColorSpace
*baseCS
;
4039 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
4043 int n
, numComps
, numAltComps
;
4047 switch (colorSpace
->getMode()) {
4050 writePS("/DeviceGray");
4055 processColors
|= psProcessBlack
;
4060 calGrayCS
= (GfxCalGrayColorSpace
*)colorSpace
;
4061 writePS("[/CIEBasedA <<\n");
4062 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS
->getGamma());
4063 writePSFmt(" /MatrixA [%g %g %g]\n",
4064 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4065 calGrayCS
->getWhiteZ());
4066 writePSFmt(" /WhitePoint [%g %g %g]\n",
4067 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4068 calGrayCS
->getWhiteZ());
4069 writePSFmt(" /BlackPoint [%g %g %g]\n",
4070 calGrayCS
->getBlackX(), calGrayCS
->getBlackY(),
4071 calGrayCS
->getBlackZ());
4077 processColors
|= psProcessBlack
;
4082 writePS("/DeviceRGB");
4087 processColors
|= psProcessCMYK
;
4092 calRGBCS
= (GfxCalRGBColorSpace
*)colorSpace
;
4093 writePS("[/CIEBasedABC <<\n");
4094 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
4095 calRGBCS
->getGammaR(), calRGBCS
->getGammaG(),
4096 calRGBCS
->getGammaB());
4097 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
4098 calRGBCS
->getMatrix()[0], calRGBCS
->getMatrix()[1],
4099 calRGBCS
->getMatrix()[2], calRGBCS
->getMatrix()[3],
4100 calRGBCS
->getMatrix()[4], calRGBCS
->getMatrix()[5],
4101 calRGBCS
->getMatrix()[6], calRGBCS
->getMatrix()[7],
4102 calRGBCS
->getMatrix()[8]);
4103 writePSFmt(" /WhitePoint [%g %g %g]\n",
4104 calRGBCS
->getWhiteX(), calRGBCS
->getWhiteY(),
4105 calRGBCS
->getWhiteZ());
4106 writePSFmt(" /BlackPoint [%g %g %g]\n",
4107 calRGBCS
->getBlackX(), calRGBCS
->getBlackY(),
4108 calRGBCS
->getBlackZ());
4114 processColors
|= psProcessCMYK
;
4119 writePS("/DeviceCMYK");
4124 processColors
|= psProcessCMYK
;
4129 labCS
= (GfxLabColorSpace
*)colorSpace
;
4130 writePS("[/CIEBasedABC <<\n");
4131 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
4132 labCS
->getAMin(), labCS
->getAMax(),
4133 labCS
->getBMin(), labCS
->getBMax());
4134 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
4135 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
4136 writePS(" /DecodeLMN\n");
4137 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
4138 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4139 labCS
->getWhiteX());
4140 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4141 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4142 labCS
->getWhiteY());
4143 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4144 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
4145 labCS
->getWhiteZ());
4146 writePSFmt(" /WhitePoint [%g %g %g]\n",
4147 labCS
->getWhiteX(), labCS
->getWhiteY(), labCS
->getWhiteZ());
4148 writePSFmt(" /BlackPoint [%g %g %g]\n",
4149 labCS
->getBlackX(), labCS
->getBlackY(), labCS
->getBlackZ());
4155 processColors
|= psProcessCMYK
;
4160 // there is no transform function to the alternate color space, so
4161 // we can use it directly
4162 dumpColorSpaceL2(((GfxICCBasedColorSpace
*)colorSpace
)->getAlt(),
4163 genXform
, updateColors
);
4167 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
4168 baseCS
= indexedCS
->getBase();
4169 writePS("[/Indexed ");
4170 dumpColorSpaceL2(baseCS
, gFalse
, gFalse
);
4171 n
= indexedCS
->getIndexHigh();
4172 numComps
= baseCS
->getNComps();
4173 lookup
= indexedCS
->getLookup();
4174 writePSFmt(" %d <\n", n
);
4175 if (baseCS
->getMode() == csDeviceN
) {
4176 func
= ((GfxDeviceNColorSpace
*)baseCS
)->getTintTransformFunc();
4177 numAltComps
= ((GfxDeviceNColorSpace
*)baseCS
)->getAlt()->getNComps();
4179 for (i
= 0; i
<= n
; i
+= 8) {
4181 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4182 for (k
= 0; k
< numComps
; ++k
) {
4183 x
[k
] = *p
++ / 255.0;
4185 func
->transform(x
, y
);
4186 for (k
= 0; k
< numAltComps
; ++k
) {
4187 byte
= (int)(y
[k
] * 255 + 0.5);
4190 } else if (byte
> 255) {
4193 writePSFmt("%02x", byte
);
4196 color
.c
[0] = dblToCol(j
);
4197 indexedCS
->getCMYK(&color
, &cmyk
);
4198 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4199 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4205 for (i
= 0; i
<= n
; i
+= 8) {
4207 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4208 for (k
= 0; k
< numComps
; ++k
) {
4209 writePSFmt("%02x", lookup
[j
* numComps
+ k
]);
4212 color
.c
[0] = dblToCol(j
);
4213 indexedCS
->getCMYK(&color
, &cmyk
);
4214 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4215 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4228 separationCS
= (GfxSeparationColorSpace
*)colorSpace
;
4229 writePS("[/Separation /");
4230 writePSName(separationCS
->getName()->getCString());
4232 dumpColorSpaceL2(separationCS
->getAlt(), gFalse
, gFalse
);
4234 cvtFunction(separationCS
->getFunc());
4240 addCustomColor(separationCS
);
4245 // DeviceN color spaces are a Level 3 PostScript feature.
4246 deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
4247 dumpColorSpaceL2(deviceNCS
->getAlt(), gFalse
, updateColors
);
4250 cvtFunction(deviceNCS
->getTintTransformFunc());
4261 void PSOutputDev::opiBegin(GfxState
*state
, Dict
*opiDict
) {
4264 if (globalParams
->getPSOPI()) {
4265 opiDict
->lookup("2.0", &dict
);
4266 if (dict
.isDict()) {
4267 opiBegin20(state
, dict
.getDict());
4271 opiDict
->lookup("1.3", &dict
);
4272 if (dict
.isDict()) {
4273 opiBegin13(state
, dict
.getDict());
4280 void PSOutputDev::opiBegin20(GfxState
*state
, Dict
*dict
) {
4281 Object obj1
, obj2
, obj3
, obj4
;
4282 double width
, height
, left
, right
, top
, bottom
;
4286 writePS("%%BeginOPI: 2.0\n");
4287 writePS("%%Distilled\n");
4289 dict
->lookup("F", &obj1
);
4290 if (getFileSpec(&obj1
, &obj2
)) {
4291 writePSFmt("%%%%ImageFileName: %s\n",
4292 obj2
.getString()->getCString());
4297 dict
->lookup("MainImage", &obj1
);
4298 if (obj1
.isString()) {
4299 writePSFmt("%%%%MainImage: %s\n", obj1
.getString()->getCString());
4303 //~ ignoring 'Tags' entry
4304 //~ need to use writePSString() and deal with >255-char lines
4306 dict
->lookup("Size", &obj1
);
4307 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4308 obj1
.arrayGet(0, &obj2
);
4309 width
= obj2
.getNum();
4311 obj1
.arrayGet(1, &obj2
);
4312 height
= obj2
.getNum();
4314 writePSFmt("%%%%ImageDimensions: %g %g\n", width
, height
);
4318 dict
->lookup("CropRect", &obj1
);
4319 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4320 obj1
.arrayGet(0, &obj2
);
4321 left
= obj2
.getNum();
4323 obj1
.arrayGet(1, &obj2
);
4324 top
= obj2
.getNum();
4326 obj1
.arrayGet(2, &obj2
);
4327 right
= obj2
.getNum();
4329 obj1
.arrayGet(3, &obj2
);
4330 bottom
= obj2
.getNum();
4332 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left
, top
, right
, bottom
);
4336 dict
->lookup("Overprint", &obj1
);
4337 if (obj1
.isBool()) {
4338 writePSFmt("%%%%ImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4342 dict
->lookup("Inks", &obj1
);
4343 if (obj1
.isName()) {
4344 writePSFmt("%%%%ImageInks: %s\n", obj1
.getName());
4345 } else if (obj1
.isArray() && obj1
.arrayGetLength() >= 1) {
4346 obj1
.arrayGet(0, &obj2
);
4347 if (obj2
.isName()) {
4348 writePSFmt("%%%%ImageInks: %s %d",
4349 obj2
.getName(), (obj1
.arrayGetLength() - 1) / 2);
4350 for (i
= 1; i
+1 < obj1
.arrayGetLength(); i
+= 2) {
4351 obj1
.arrayGet(i
, &obj3
);
4352 obj1
.arrayGet(i
+1, &obj4
);
4353 if (obj3
.isString() && obj4
.isNum()) {
4355 writePSString(obj3
.getString());
4356 writePSFmt(" %g", obj4
.getNum());
4369 writePS("%%BeginIncludedImage\n");
4371 dict
->lookup("IncludedImageDimensions", &obj1
);
4372 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4373 obj1
.arrayGet(0, &obj2
);
4376 obj1
.arrayGet(1, &obj2
);
4379 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w
, h
);
4383 dict
->lookup("IncludedImageQuality", &obj1
);
4385 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1
.getNum());
4392 void PSOutputDev::opiBegin13(GfxState
*state
, Dict
*dict
) {
4394 int left
, right
, top
, bottom
, samples
, bits
, width
, height
;
4396 double llx
, lly
, ulx
, uly
, urx
, ury
, lrx
, lry
;
4397 double tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
;
4402 writePS("/opiMatrix2 matrix currentmatrix def\n");
4403 writePS("opiMatrix setmatrix\n");
4405 dict
->lookup("F", &obj1
);
4406 if (getFileSpec(&obj1
, &obj2
)) {
4407 writePSFmt("%%ALDImageFileName: %s\n",
4408 obj2
.getString()->getCString());
4413 dict
->lookup("CropRect", &obj1
);
4414 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4415 obj1
.arrayGet(0, &obj2
);
4416 left
= obj2
.getInt();
4418 obj1
.arrayGet(1, &obj2
);
4419 top
= obj2
.getInt();
4421 obj1
.arrayGet(2, &obj2
);
4422 right
= obj2
.getInt();
4424 obj1
.arrayGet(3, &obj2
);
4425 bottom
= obj2
.getInt();
4427 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left
, top
, right
, bottom
);
4431 dict
->lookup("Color", &obj1
);
4432 if (obj1
.isArray() && obj1
.arrayGetLength() == 5) {
4433 obj1
.arrayGet(0, &obj2
);
4436 obj1
.arrayGet(1, &obj2
);
4439 obj1
.arrayGet(2, &obj2
);
4442 obj1
.arrayGet(3, &obj2
);
4445 obj1
.arrayGet(4, &obj2
);
4446 if (obj2
.isString()) {
4447 writePSFmt("%%ALDImageColor: %g %g %g %g ", c
, m
, y
, k
);
4448 writePSString(obj2
.getString());
4455 dict
->lookup("ColorType", &obj1
);
4456 if (obj1
.isName()) {
4457 writePSFmt("%%ALDImageColorType: %s\n", obj1
.getName());
4461 //~ ignores 'Comments' entry
4462 //~ need to handle multiple lines
4464 dict
->lookup("CropFixed", &obj1
);
4465 if (obj1
.isArray()) {
4466 obj1
.arrayGet(0, &obj2
);
4467 ulx
= obj2
.getNum();
4469 obj1
.arrayGet(1, &obj2
);
4470 uly
= obj2
.getNum();
4472 obj1
.arrayGet(2, &obj2
);
4473 lrx
= obj2
.getNum();
4475 obj1
.arrayGet(3, &obj2
);
4476 lry
= obj2
.getNum();
4478 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx
, uly
, lrx
, lry
);
4482 dict
->lookup("GrayMap", &obj1
);
4483 if (obj1
.isArray()) {
4484 writePS("%ALDImageGrayMap:");
4485 for (i
= 0; i
< obj1
.arrayGetLength(); i
+= 16) {
4489 for (j
= 0; j
< 16 && i
+j
< obj1
.arrayGetLength(); ++j
) {
4490 obj1
.arrayGet(i
+j
, &obj2
);
4491 writePSFmt(" %d", obj2
.getInt());
4499 dict
->lookup("ID", &obj1
);
4500 if (obj1
.isString()) {
4501 writePSFmt("%%ALDImageID: %s\n", obj1
.getString()->getCString());
4505 dict
->lookup("ImageType", &obj1
);
4506 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4507 obj1
.arrayGet(0, &obj2
);
4508 samples
= obj2
.getInt();
4510 obj1
.arrayGet(1, &obj2
);
4511 bits
= obj2
.getInt();
4513 writePSFmt("%%ALDImageType: %d %d\n", samples
, bits
);
4517 dict
->lookup("Overprint", &obj1
);
4518 if (obj1
.isBool()) {
4519 writePSFmt("%%ALDImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4523 dict
->lookup("Position", &obj1
);
4524 if (obj1
.isArray() && obj1
.arrayGetLength() == 8) {
4525 obj1
.arrayGet(0, &obj2
);
4526 llx
= obj2
.getNum();
4528 obj1
.arrayGet(1, &obj2
);
4529 lly
= obj2
.getNum();
4531 obj1
.arrayGet(2, &obj2
);
4532 ulx
= obj2
.getNum();
4534 obj1
.arrayGet(3, &obj2
);
4535 uly
= obj2
.getNum();
4537 obj1
.arrayGet(4, &obj2
);
4538 urx
= obj2
.getNum();
4540 obj1
.arrayGet(5, &obj2
);
4541 ury
= obj2
.getNum();
4543 obj1
.arrayGet(6, &obj2
);
4544 lrx
= obj2
.getNum();
4546 obj1
.arrayGet(7, &obj2
);
4547 lry
= obj2
.getNum();
4549 opiTransform(state
, llx
, lly
, &tllx
, &tlly
);
4550 opiTransform(state
, ulx
, uly
, &tulx
, &tuly
);
4551 opiTransform(state
, urx
, ury
, &turx
, &tury
);
4552 opiTransform(state
, lrx
, lry
, &tlrx
, &tlry
);
4553 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
4554 tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
);
4559 dict
->lookup("Resolution", &obj1
);
4560 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4561 obj1
.arrayGet(0, &obj2
);
4562 horiz
= obj2
.getNum();
4564 obj1
.arrayGet(1, &obj2
);
4565 vert
= obj2
.getNum();
4567 writePSFmt("%%ALDImageResoution: %g %g\n", horiz
, vert
);
4572 dict
->lookup("Size", &obj1
);
4573 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4574 obj1
.arrayGet(0, &obj2
);
4575 width
= obj2
.getInt();
4577 obj1
.arrayGet(1, &obj2
);
4578 height
= obj2
.getInt();
4580 writePSFmt("%%ALDImageDimensions: %d %d\n", width
, height
);
4584 //~ ignoring 'Tags' entry
4585 //~ need to use writePSString() and deal with >255-char lines
4587 dict
->lookup("Tint", &obj1
);
4589 writePSFmt("%%ALDImageTint: %g\n", obj1
.getNum());
4593 dict
->lookup("Transparency", &obj1
);
4594 if (obj1
.isBool()) {
4595 writePSFmt("%%ALDImageTransparency: %s\n", obj1
.getBool() ? "true" : "false");
4599 writePS("%%BeginObject: image\n");
4600 writePS("opiMatrix2 setmatrix\n");
4604 // Convert PDF user space coordinates to PostScript default user space
4605 // coordinates. This has to account for both the PDF CTM and the
4606 // PSOutputDev page-fitting transform.
4607 void PSOutputDev::opiTransform(GfxState
*state
, double x0
, double y0
,
4608 double *x1
, double *y1
) {
4611 state
->transform(x0
, y0
, x1
, y1
);
4618 } else if (rotate
== 180) {
4621 } else if (rotate
== 270) {
4630 void PSOutputDev::opiEnd(GfxState
*state
, Dict
*opiDict
) {
4633 if (globalParams
->getPSOPI()) {
4634 opiDict
->lookup("2.0", &dict
);
4635 if (dict
.isDict()) {
4636 writePS("%%EndIncludedImage\n");
4637 writePS("%%EndOPI\n");
4638 writePS("grestore\n");
4643 opiDict
->lookup("1.3", &dict
);
4644 if (dict
.isDict()) {
4645 writePS("%%EndObject\n");
4646 writePS("restore\n");
4654 GBool
PSOutputDev::getFileSpec(Object
*fileSpec
, Object
*fileName
) {
4655 if (fileSpec
->isString()) {
4656 fileSpec
->copy(fileName
);
4659 if (fileSpec
->isDict()) {
4660 fileSpec
->dictLookup("DOS", fileName
);
4661 if (fileName
->isString()) {
4665 fileSpec
->dictLookup("Mac", fileName
);
4666 if (fileName
->isString()) {
4670 fileSpec
->dictLookup("Unix", fileName
);
4671 if (fileName
->isString()) {
4675 fileSpec
->dictLookup("F", fileName
);
4676 if (fileName
->isString()) {
4683 #endif // OPI_SUPPORT
4685 void PSOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
4686 writePSFmt("%g %g setcharwidth\n", wx
, wy
);
4690 void PSOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
4691 double llx
, double lly
, double urx
, double ury
) {
4698 t3String
= new GString();
4700 t3Cacheable
= gTrue
;
4703 void PSOutputDev::psXObject(Stream
*psStream
, Stream
*level1Stream
) {
4707 if ((level
== psLevel1
|| level
== psLevel1Sep
) && level1Stream
) {
4713 while ((c
= str
->getChar()) != EOF
) {
4719 //~ can nextFunc be reset to 0 -- maybe at the start of each page?
4720 //~ or maybe at the start of each color space / pattern?
4721 void PSOutputDev::cvtFunction(Function
*func
) {
4722 SampledFunction
*func0
;
4723 ExponentialFunction
*func2
;
4724 StitchingFunction
*func3
;
4725 PostScriptFunction
*func4
;
4726 int thisFunc
, m
, n
, nSamples
, i
, j
, k
;
4728 switch (func
->getType()) {
4730 case -1: // identity
4735 func0
= (SampledFunction
*)func
;
4736 thisFunc
= nextFunc
++;
4737 m
= func0
->getInputSize();
4738 n
= func0
->getOutputSize();
4740 for (i
= 0; i
< m
; ++i
) {
4741 nSamples
*= func0
->getSampleSize(i
);
4743 writePSFmt("/xpdfSamples%d [\n", thisFunc
);
4744 for (i
= 0; i
< nSamples
; ++i
) {
4745 writePSFmt("%g\n", func0
->getSamples()[i
]);
4748 writePSFmt("{ %d array %d array %d 2 roll\n", 2*m
, m
, m
+2);
4749 // [e01] [efrac] x0 x1 ... xm-1
4750 for (i
= m
-1; i
>= 0; --i
) {
4751 // [e01] [efrac] x0 x1 ... xi
4752 writePSFmt("%g sub %g mul %g add\n",
4753 func0
->getDomainMin(i
),
4754 (func0
->getEncodeMax(i
) - func0
->getEncodeMin(i
)) /
4755 (func0
->getDomainMax(i
) - func0
->getDomainMin(i
)),
4756 func0
->getEncodeMin(i
));
4757 // [e01] [efrac] x0 x1 ... xi-1 xi'
4758 writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n",
4759 func0
->getSampleSize(i
) - 1, func0
->getSampleSize(i
) - 1);
4760 // [e01] [efrac] x0 x1 ... xi-1 xi'
4761 writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
4762 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
4763 writePSFmt("%d index %d 3 2 roll put\n", i
+3, i
);
4764 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
4765 writePSFmt("%d index %d 3 2 roll put\n", i
+3, 2*i
+1);
4766 // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
4767 writePSFmt("%d index %d 3 2 roll put\n", i
+2, 2*i
);
4768 // [e01] [efrac] x0 x1 ... xi-1
4771 for (i
= 0; i
< n
; ++i
) {
4772 // [e01] [efrac] y(0) ... y(i-1)
4773 for (j
= 0; j
< (1<<m
); ++j
) {
4774 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
4775 writePSFmt("xpdfSamples%d\n", thisFunc
);
4777 writePSFmt("%d index %d get\n", i
+j
+2, 2 * k
+ ((j
>> k
) & 1));
4778 for (k
= m
- 2; k
>= 0; --k
) {
4779 writePSFmt("%d mul %d index %d get add\n",
4780 func0
->getSampleSize(k
),
4782 2 * k
+ ((j
>> k
) & 1));
4785 writePSFmt("%d mul %d add ", n
, i
);
4789 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
4790 for (j
= 0; j
< m
; ++j
) {
4791 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
4792 for (k
= 0; k
< (1 << (m
- j
)); k
+= 2) {
4793 // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
4794 writePSFmt("%d index %d get dup\n", i
+ k
/2 + (1 << (m
-j
)) - k
, j
);
4795 writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
4796 writePSFmt("%d 1 roll\n", k
/2 + (1 << m
-j
) - k
- 1);
4798 // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
4800 // [e01] [efrac] y(0) ... y(i-1) s
4801 writePSFmt("%g mul %g add\n",
4802 func0
->getDecodeMax(i
) - func0
->getDecodeMin(i
),
4803 func0
->getDecodeMin(i
));
4804 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4805 func0
->getRangeMin(i
), func0
->getRangeMin(i
),
4806 func0
->getRangeMax(i
), func0
->getRangeMax(i
));
4807 // [e01] [efrac] y(0) ... y(i-1) y(i)
4809 // [e01] [efrac] y(0) ... y(n-1)
4810 writePSFmt("%d %d roll pop pop }\n", n
+2, n
);
4813 case 2: // exponential
4814 func2
= (ExponentialFunction
*)func
;
4815 n
= func2
->getOutputSize();
4816 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4817 func2
->getDomainMin(0), func2
->getDomainMin(0),
4818 func2
->getDomainMax(0), func2
->getDomainMax(0));
4820 for (i
= 0; i
< n
; ++i
) {
4822 writePSFmt("%d index %g exp %g mul %g add\n",
4823 i
, func2
->getE(), func2
->getC1()[i
] - func2
->getC0()[i
],
4825 if (func2
->getHasRange()) {
4826 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4827 func2
->getRangeMin(i
), func2
->getRangeMin(i
),
4828 func2
->getRangeMax(i
), func2
->getRangeMax(i
));
4832 writePSFmt("%d %d roll pop }\n", n
+1, n
);
4835 case 3: // stitching
4836 func3
= (StitchingFunction
*)func
;
4837 thisFunc
= nextFunc
++;
4838 for (i
= 0; i
< func3
->getNumFuncs(); ++i
) {
4839 cvtFunction(func3
->getFunc(i
));
4840 writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc
, i
);
4842 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4843 func3
->getDomainMin(0), func3
->getDomainMin(0),
4844 func3
->getDomainMax(0), func3
->getDomainMax(0));
4845 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4846 writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n",
4847 func3
->getBounds()[i
+1],
4848 func3
->getBounds()[i
],
4849 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4850 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4851 func3
->getEncode()[2*i
],
4854 writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n",
4855 func3
->getBounds()[i
],
4856 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4857 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4858 func3
->getEncode()[2*i
],
4860 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4861 writePS("} ifelse\n");
4866 case 4: // PostScript
4867 func4
= (PostScriptFunction
*)func
;
4868 writePS(func4
->getCodeString()->getCString());
4874 void PSOutputDev::writePSChar(char c
) {
4876 t3String
->append(c
);
4878 (*outputFunc
)(outputStream
, &c
, 1);
4882 void PSOutputDev::writePS(char *s
) {
4884 t3String
->append(s
);
4886 (*outputFunc
)(outputStream
, s
, strlen(s
));
4890 void PSOutputDev::writePSFmt(const char *fmt
, ...) {
4894 va_start(args
, fmt
);
4895 vsprintf(buf
, fmt
, args
);
4898 t3String
->append(buf
);
4900 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
4904 void PSOutputDev::writePSString(GString
*s
) {
4911 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
4917 if (*p
== '(' || *p
== ')' || *p
== '\\') {
4919 writePSChar((char)*p
);
4921 } else if (*p
< 0x20 || *p
>= 0x80) {
4922 sprintf(buf
, "\\%03o", *p
);
4926 writePSChar((char)*p
);
4933 void PSOutputDev::writePSName(char *s
) {
4938 while ((c
= *p
++)) {
4939 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4940 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4941 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4942 c
== '/' || c
== '%') {
4943 writePSFmt("#%02x", c
& 0xff);
4950 GString
*PSOutputDev::filterPSName(GString
*name
) {
4956 name2
= new GString();
4958 // ghostscript chokes on names that begin with out-of-limits
4959 // numbers, e.g., 1e4foo is handled correctly (as a name), but
4960 // 1e999foo generates a limitcheck error
4961 c
= name
->getChar(0);
4962 if (c
>= '0' && c
<= '9') {
4966 for (i
= 0; i
< name
->getLength(); ++i
) {
4967 c
= name
->getChar(i
);
4968 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4969 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4970 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4971 c
== '/' || c
== '%') {
4972 sprintf(buf
, "#%02x", c
& 0xff);
4981 GBool
/* O - gTrue if selected, gFalse otherwise */
4982 PSOutputDev::checkRange(int page
) /* I - Page number */
4984 const char *range
; /* Pointer into range string */
4985 int lower
, upper
; /* Lower and upper page numbers */
4988 if (pageRanges
== NULL
)
4989 return (gTrue
); /* No range, print all pages... */
4991 for (range
= pageRanges
; *range
!= '\0';)
4997 upper
= strtol(range
, (char **)&range
, 10);
5001 lower
= strtol(range
, (char **)&range
, 10);
5006 if (!isdigit(*range
& 255))
5009 upper
= strtol(range
, (char **)&range
, 10);
5015 if (page
>= lower
&& page
<= upper
)