1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 #include "GlobalParams.h"
32 #include "UnicodeMap.h"
33 #include "FoFiType1C.h"
34 #include "FoFiTrueType.h"
40 #include "PSOutputDev.h"
43 // needed for setting type/creator of MacOS files
44 #include "ICSupport.h"
47 //------------------------------------------------------------------------
48 // PostScript prolog and setup
49 //------------------------------------------------------------------------
51 // The '~' escapes mark prolog code that is emitted only in certain
55 // ^ ^----- s=psLevel*Sep, n=psLevel*
56 // +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
58 static char *prolog
[] = {
59 "/xpdf 75 dict def xpdf begin",
60 "% PDF special state",
61 "/pdfDictSize 15 def",
63 "/pdfStates 64 array def",
65 " pdfStates exch pdfDictSize dict",
66 " dup /pdfStateIdx 3 index put",
71 " 3 1 roll 2 array astore",
72 " /setpagedevice where {",
74 " /PageSize exch def",
75 " /ImagingBBox null def",
76 " /Policies 1 dict dup begin /PageSize 3 def end def",
77 " { /Duplex true def } if",
78 " currentdict end setpagedevice",
85 " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
86 " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
87 " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
92 " pdfStates 0 get begin",
94 " pdfDictSize dict begin",
97 " /pdfFillXform {} def",
98 " /pdfStrokeCS [] def",
99 " /pdfStrokeXform {} def",
104 " /pdfFill [0 0 0 1] def",
105 " /pdfStroke [0 0 0 1] def",
108 " /pdfStroke [0] def",
109 " /pdfFillOP false def",
110 " /pdfStrokeOP false def",
112 " /pdfLastFill false def",
113 " /pdfLastStroke false def",
114 " /pdfTextMat [1 0 0 1 0 0] def",
115 " /pdfFontSize 0 def",
116 " /pdfCharSpacing 0 def",
117 " /pdfTextRender 0 def",
118 " /pdfTextRise 0 def",
119 " /pdfWordSpacing 0 def",
120 " /pdfHorizScaling 1 def",
121 " /pdfTextClipPath [] def",
123 "/pdfEndPage { end } def",
125 "% separation convention operators",
126 "/findcmykcustomcolor where {",
129 " /findcmykcustomcolor { 5 array astore } def",
131 "/setcustomcolor where {",
134 " /setcustomcolor {",
136 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
137 " 0 4 getinterval cvx",
138 " [ exch /dup load exch { mul exch dup } /forall load",
139 " /pop load dup ] cvx",
140 " ] setcolorspace setcolor",
143 "/customcolorimage where {",
146 " /customcolorimage {",
148 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
150 " [ exch /dup load exch { mul exch dup } /forall load",
151 " /pop load dup ] cvx",
155 " /DataSource exch def",
156 " /ImageMatrix exch def",
157 " /BitsPerComponent exch def",
160 " /Decode [1 0] def",
169 "/g { dup /pdfFill exch def setgray",
170 " /pdfLastFill true def /pdfLastStroke false def } def",
171 "/G { dup /pdfStroke exch def setgray",
172 " /pdfLastStroke true def /pdfLastFill false def } def",
174 " pdfLastFill not {",
176 " /pdfLastFill true def /pdfLastStroke false def",
180 " pdfLastStroke not {",
181 " pdfStroke setgray",
182 " /pdfLastStroke true def /pdfLastFill false def",
186 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
187 " /pdfLastFill true def /pdfLastStroke false def } def",
188 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
189 " /pdfLastStroke true def /pdfLastFill false def } def",
191 " pdfLastFill not {",
192 " pdfFill aload pop setcmykcolor",
193 " /pdfLastFill true def /pdfLastStroke false def",
197 " pdfLastStroke not {",
198 " pdfStroke aload pop setcmykcolor",
199 " /pdfLastStroke true def /pdfLastFill false def",
203 "/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
204 " setcolorspace } def",
205 "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
206 " setcolorspace } def",
207 "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
208 " dup /pdfFill exch def aload pop pdfFillXform setcolor",
209 " /pdfLastFill true def /pdfLastStroke false def } def",
210 "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
211 " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
212 " /pdfLastStroke true def /pdfLastFill false def } def",
213 "/op { /pdfFillOP exch def",
214 " pdfLastFill { pdfFillOP setoverprint } if } def",
215 "/OP { /pdfStrokeOP exch def",
216 " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
218 " pdfLastFill not {",
219 " pdfFillCS setcolorspace",
220 " pdfFill aload pop pdfFillXform setcolor",
221 " pdfFillOP setoverprint",
222 " /pdfLastFill true def /pdfLastStroke false def",
226 " pdfLastStroke not {",
227 " pdfStrokeCS setcolorspace",
228 " pdfStroke aload pop pdfStrokeXform setcolor",
229 " pdfStrokeOP setoverprint",
230 " /pdfLastStroke true def /pdfLastFill false def",
234 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
235 " /pdfLastFill true def /pdfLastStroke false def } def",
236 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
237 " /pdfLastStroke true def /pdfLastFill false def } def",
238 "/ck { 6 copy 6 array astore /pdfFill exch def",
239 " findcmykcustomcolor exch setcustomcolor",
240 " /pdfLastFill true def /pdfLastStroke false def } def",
241 "/CK { 6 copy 6 array astore /pdfStroke exch def",
242 " findcmykcustomcolor exch setcustomcolor",
243 " /pdfLastStroke true def /pdfLastFill false def } def",
244 "/op { /pdfFillOP exch def",
245 " pdfLastFill { pdfFillOP setoverprint } if } def",
246 "/OP { /pdfStrokeOP exch def",
247 " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
249 " pdfLastFill not {",
250 " pdfFill aload length 4 eq {",
253 " findcmykcustomcolor exch setcustomcolor",
255 " pdfFillOP setoverprint",
256 " /pdfLastFill true def /pdfLastStroke false def",
260 " pdfLastStroke not {",
261 " pdfStroke aload length 4 eq {",
264 " findcmykcustomcolor exch setcustomcolor",
266 " pdfStrokeOP setoverprint",
267 " /pdfLastStroke true def /pdfLastFill false def",
273 " 4 3 roll findfont",
274 " 4 2 roll matrix scale makefont",
275 " dup length dict begin",
276 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
277 " /Encoding exch def",
284 " dup length dict begin",
285 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
292 "/pdfMakeFont16L3 {",
293 " 1 index /CIDFont resourcestatus {",
294 " pop pop 1 index /CIDFont findresource /CIDFontType known",
299 " 0 eq { /Identity-H } { /Identity-V } ifelse",
300 " exch 1 array astore composefont pop",
306 "% graphics state operators",
310 " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
311 " pdfStates pdfStateIdx 1 add get begin",
312 " pdfOpNames { exch def } forall",
314 "/Q { end grestore } def",
316 "/q { gsave pdfDictSize dict begin } def",
319 " /pdfLastFill where {",
322 " pdfFillOP setoverprint",
324 " pdfStrokeOP setoverprint",
329 "/cm { concat } def",
330 "/d { setdash } def",
331 "/i { setflat } def",
332 "/j { setlinejoin } def",
333 "/J { setlinecap } def",
334 "/M { setmiterlimit } def",
335 "/w { setlinewidth } def",
336 "% path segment operators",
339 "/c { curveto } def",
340 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
341 " neg 0 rlineto closepath } def",
342 "/h { closepath } def",
343 "% path painting operators",
344 "/S { sCol stroke } def",
345 "/Sf { fCol stroke } def",
346 "/f { fCol fill } def",
347 "/f* { fCol eofill } def",
348 "% clipping operators",
349 "/W { clip newpath } def",
350 "/W* { eoclip newpath } def",
351 "% text state operators",
352 "/Tc { /pdfCharSpacing exch def } def",
353 "/Tf { dup /pdfFontSize exch def",
354 " dup pdfHorizScaling mul exch matrix scale",
355 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
356 " exch findfont exch makefont setfont } def",
357 "/Tr { /pdfTextRender exch def } def",
358 "/Ts { /pdfTextRise exch def } def",
359 "/Tw { /pdfWordSpacing exch def } def",
360 "/Tz { /pdfHorizScaling exch def } def",
361 "% text positioning operators",
362 "/Td { pdfTextMat transform moveto } def",
363 "/Tm { /pdfTextMat exch def } def",
364 "% text string operators",
370 " 1 string dup 0 3 index put 3 index exec",
376 " currentfont /FontType get 0 eq {",
377 " 0 2 2 index length 1 sub {",
378 " 2 copy get exch 1 add 2 index exch get",
379 " 2 copy exch 256 mul add",
380 " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
385 " 1 string dup 0 3 index put 3 index exec",
391 "/awcp {", // awidthcharpath
394 " 5 index 5 index rmoveto",
395 " 6 index eq { 7 index 7 index rmoveto } if",
400 " fCol", // because stringwidth has to draw Type 3 chars
401 " 1 index stringwidth pdfTextMat idtransform pop",
402 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
403 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
404 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
405 " pdfTextMat dtransform",
409 " fCol", // because stringwidth has to draw Type 3 chars
410 " 2 index stringwidth pdfTextMat idtransform pop",
412 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
413 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
414 " pdfTextMat dtransform",
418 " fCol", // because stringwidth has to draw Type 3 chars
419 " 2 index stringwidth pdfTextMat idtransform exch pop",
421 " 0 pdfWordSpacing pdfTextMat dtransform 32",
422 " 4 3 roll pdfCharSpacing add 0 exch",
423 " pdfTextMat dtransform",
427 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
428 " currentpoint 8 2 roll",
429 " pdfTextRender 1 and 0 eq {",
430 " 6 copy awidthshow",
432 " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
433 " 7 index 7 index moveto",
435 " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
436 " false awcp currentpoint stroke moveto",
438 " pdfTextRender 4 and 0 ne {",
441 " /pdfTextClipPath [ pdfTextClipPath aload pop",
447 " currentpoint newpath moveto",
451 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
453 "/TJm { pdfFontSize 0.001 mul mul neg 0",
454 " pdfTextMat dtransform rmoveto } def",
455 "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
456 " pdfTextMat dtransform rmoveto } def",
457 "/Tclip { pdfTextClipPath cvx exec clip newpath",
458 " /pdfTextClipPath [] def } def",
460 "% Level 1 image operators",
463 " /pdfImBuf1 4 index string def",
464 " { currentfile pdfImBuf1 readhexstring pop } image",
468 " /pdfImBuf1 4 index string def",
469 " /pdfImBuf2 4 index string def",
470 " /pdfImBuf3 4 index string def",
471 " /pdfImBuf4 4 index string def",
472 " { currentfile pdfImBuf1 readhexstring pop }",
473 " { currentfile pdfImBuf2 readhexstring pop }",
474 " { currentfile pdfImBuf3 readhexstring pop }",
475 " { currentfile pdfImBuf4 readhexstring pop }",
476 " true 4 colorimage",
480 " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
481 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
484 " { 2 copy get exch 1 add exch } imagemask",
488 "% Level 2 image operators",
489 "/pdfImBuf 100 string def",
492 " { currentfile pdfImBuf readline",
493 " not { pop exit } if",
494 " (%-EOD-) eq { exit } if } loop",
498 " findcmykcustomcolor exch",
499 " dup /Width get /pdfImBuf1 exch string def",
500 " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
501 " /pdfImDecodeLow exch def",
502 " begin Width Height BitsPerComponent ImageMatrix DataSource end",
503 " /pdfImData exch def",
504 " { pdfImData pdfImBuf1 readstring pop",
505 " 0 1 2 index length 1 sub {",
506 " 1 index exch 2 copy get",
507 " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
510 " 6 5 roll customcolorimage",
511 " { currentfile pdfImBuf readline",
512 " not { pop exit } if",
513 " (%-EOD-) eq { exit } if } loop",
518 " { currentfile pdfImBuf readline",
519 " not { pop exit } if",
520 " (%-EOD-) eq { exit } if } loop",
524 " 0 2 4 index length 1 sub {",
525 " dup 4 index exch 2 copy",
526 " get 5 index div put",
527 " 1 add 3 index exch 2 copy",
528 " get 3 index div put",
532 "/pdfImClipEnd { grestore } def",
534 "% shading operators",
536 " false 0 1 3 index length 1 sub {",
537 " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
541 " exch pop exch pop",
543 "/funcCol { func n array astore } def",
551 " 4 index 4 index funcCol dup",
552 " 6 index 4 index funcCol dup",
553 " 3 1 roll colordelta 3 1 roll",
554 " 5 index 5 index funcCol dup",
555 " 3 1 roll colordelta 3 1 roll",
556 " 6 index 8 index funcCol dup",
557 " 3 1 roll colordelta 3 1 roll",
558 " colordelta or or or",
563 " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
564 " 6 index 6 index 4 index 4 index 4 index funcSH",
565 " 2 index 6 index 6 index 4 index 4 index funcSH",
566 " 6 index 2 index 4 index 6 index 4 index funcSH",
567 " 5 3 roll 3 2 roll funcSH pop pop",
569 " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
571 " dup 4 index exch mat transform m",
572 " 3 index 3 index mat transform l",
573 " 1 index 3 index mat transform l",
574 " mat transform l pop pop h f*",
587 " func n array astore",
596 " 2 index axialCol 2 index axialCol colordelta",
600 " 1 add 3 1 roll 2 copy add 0.5 mul",
601 " dup 4 3 roll exch 4 index axialSH",
602 " exch 3 2 roll axialSH",
604 " pop 2 copy add 0.5 mul axialCol sc",
605 " exch dup dx mul x0 add exch dy mul y0 add",
606 " 3 2 roll dup dx mul x0 add exch dy mul y0 add",
607 " dx abs dy abs ge {",
608 " 2 copy yMin sub dy mul dx div add yMin m",
609 " yMax sub dy mul dx div add yMax l",
610 " 2 copy yMax sub dy mul dx div add yMax l",
611 " yMin sub dy mul dx div add yMin l",
614 " exch 2 copy xMin sub dx mul dy div add xMin exch m",
615 " xMax sub dx mul dy div add xMax exch l",
616 " exch 2 copy xMax sub dx mul dy div add xMax exch l",
617 " xMin sub dx mul dy div add xMin exch l",
630 " func n array astore",
639 " 2 index dt mul t0 add radialCol",
640 " 2 index dt mul t0 add radialCol colordelta",
644 " 1 add 3 1 roll 2 copy add 0.5 mul",
645 " dup 4 3 roll exch 4 index radialSH",
646 " exch 3 2 roll radialSH",
648 " pop 2 copy add 0.5 mul dt mul t0 add axialCol sc",
649 " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
651 " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
660 static char *cmapProlog
[] = {
661 "/CIDInit /ProcSet findresource begin",
665 " /CMapName /Identity-H def",
666 " /CIDSystemInfo 3 dict dup begin",
667 " /Registry (Adobe) def",
668 " /Ordering (Identity) def",
669 " /Supplement 0 def",
671 " 1 begincodespacerange",
673 " endcodespacerange",
679 " currentdict CMapName exch /CMap defineresource pop",
684 " /CMapName /Identity-V def",
685 " /CIDSystemInfo 3 dict dup begin",
686 " /Registry (Adobe) def",
687 " /Ordering (Identity) def",
688 " /Supplement 0 def",
691 " 1 begincodespacerange",
693 " endcodespacerange",
699 " currentdict CMapName exch /CMap defineresource pop",
705 //------------------------------------------------------------------------
707 //------------------------------------------------------------------------
710 char *psName
; // PostScript name
711 double mWidth
; // width of 'm' character
714 static char *psFonts
[] = {
718 "Courier-BoldOblique",
722 "Helvetica-BoldOblique",
732 static PSSubstFont psSubstFonts
[] = {
733 {"Helvetica", 0.833},
734 {"Helvetica-Oblique", 0.833},
735 {"Helvetica-Bold", 0.889},
736 {"Helvetica-BoldOblique", 0.889},
737 {"Times-Roman", 0.788},
738 {"Times-Italic", 0.722},
739 {"Times-Bold", 0.833},
740 {"Times-BoldItalic", 0.778},
742 {"Courier-Oblique", 0.600},
743 {"Courier-Bold", 0.600},
744 {"Courier-BoldOblique", 0.600}
747 // Encoding info for substitute 16-bit font
753 //------------------------------------------------------------------------
755 //------------------------------------------------------------------------
757 #define psProcessCyan 1
758 #define psProcessMagenta 2
759 #define psProcessYellow 4
760 #define psProcessBlack 8
761 #define psProcessCMYK 15
763 //------------------------------------------------------------------------
765 //------------------------------------------------------------------------
767 class PSOutCustomColor
{
770 PSOutCustomColor(double cA
, double mA
,
771 double yA
, double kA
, GString
*nameA
);
776 PSOutCustomColor
*next
;
779 PSOutCustomColor::PSOutCustomColor(double cA
, double mA
,
780 double yA
, double kA
, GString
*nameA
) {
789 PSOutCustomColor::~PSOutCustomColor() {
793 //------------------------------------------------------------------------
795 //------------------------------------------------------------------------
797 class DeviceNRecoder
: public FilterStream
{
800 DeviceNRecoder(Stream
*strA
, int widthA
, int heightA
,
801 GfxImageColorMap
*colorMapA
);
802 virtual ~DeviceNRecoder();
803 virtual StreamKind
getKind() { return strWeird
; }
804 virtual void reset();
805 virtual int getChar()
806 { return (bufIdx
>= bufSize
&& !fillBuf()) ? EOF
: buf
[bufIdx
++]; }
807 virtual int lookChar()
808 { return (bufIdx
>= bufSize
&& !fillBuf()) ? EOF
: buf
[bufIdx
]; }
809 virtual GString
*getPSFilter(int psLevel
, char *indent
) { return NULL
; }
810 virtual GBool
isBinary(GBool last
= gTrue
) { return gTrue
; }
811 virtual GBool
isEncoder() { return gTrue
; }
818 GfxImageColorMap
*colorMap
;
821 int buf
[gfxColorMaxComps
];
827 DeviceNRecoder::DeviceNRecoder(Stream
*strA
, int widthA
, int heightA
,
828 GfxImageColorMap
*colorMapA
):
832 colorMap
= colorMapA
;
835 bufIdx
= gfxColorMaxComps
;
836 bufSize
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
837 getAlt()->getNComps();
838 func
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
839 getTintTransformFunc();
842 DeviceNRecoder::~DeviceNRecoder() {
848 void DeviceNRecoder::reset() {
849 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
850 colorMap
->getBits());
854 GBool
DeviceNRecoder::fillBuf() {
855 Guchar pixBuf
[gfxColorMaxComps
];
857 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
860 if (pixelIdx
>= width
* height
) {
863 imgStr
->getPixel(pixBuf
);
864 colorMap
->getColor(pixBuf
, &color
);
866 i
< ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->getNComps();
868 x
[i
] = colToDbl(color
.c
[i
]);
870 func
->transform(x
, y
);
871 for (i
= 0; i
< bufSize
; ++i
) {
872 buf
[i
] = (int)(y
[i
] * 255 + 0.5);
879 //------------------------------------------------------------------------
881 //------------------------------------------------------------------------
884 typedef void (*SignalFunc
)(int);
887 static void outputToFile(void *stream
, char *data
, int len
) {
888 fwrite(data
, 1, len
, (FILE *)stream
);
891 PSOutputDev::PSOutputDev(char *fileName
, XRef
*xrefA
, Catalog
*catalog
,
892 int firstPage
, int lastPage
, PSOutMode modeA
,
893 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
894 GBool manualCtrlA
, const char *pageRangesA
) {
896 PSFileType fileTypeA
;
899 underlayCbkData
= NULL
;
901 overlayCbkData
= NULL
;
905 fontFileNames
= NULL
;
910 haveTextClip
= gFalse
;
914 if (!strcmp(fileName
, "-")) {
915 fileTypeA
= psStdout
;
917 } else if (fileName
[0] == '|') {
921 signal(SIGPIPE
, (SignalFunc
)SIG_IGN
);
923 if (!(f
= popen(fileName
+ 1, "w"))) {
924 error(-1, "Couldn't run print command '%s'", fileName
);
929 error(-1, "Print commands are not supported ('%s')", fileName
);
935 if (!(f
= fopen(fileName
, "w"))) {
936 error(-1, "Couldn't open PostScript file '%s'", fileName
);
942 init(outputToFile
, f
, fileTypeA
,
943 xrefA
, catalog
, firstPage
, lastPage
, modeA
,
944 imgLLXA
, imgLLYA
, imgURXA
, imgURYA
, manualCtrlA
, pageRangesA
);
947 PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA
, void *outputStreamA
,
948 XRef
*xrefA
, Catalog
*catalog
,
949 int firstPage
, int lastPage
, PSOutMode modeA
,
950 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
951 GBool manualCtrlA
, const char *pageRangesA
) {
953 underlayCbkData
= NULL
;
955 overlayCbkData
= NULL
;
959 fontFileNames
= NULL
;
964 haveTextClip
= gFalse
;
967 init(outputFuncA
, outputStreamA
, psGeneric
,
968 xrefA
, catalog
, firstPage
, lastPage
, modeA
,
969 imgLLXA
, imgLLYA
, imgURXA
, imgURYA
, manualCtrlA
, pageRangesA
);
972 void PSOutputDev::init(PSOutputFunc outputFuncA
, void *outputStreamA
,
973 PSFileType fileTypeA
, XRef
*xrefA
, Catalog
*catalog
,
974 int firstPage
, int lastPage
, PSOutMode modeA
,
975 int imgLLXA
, int imgLLYA
, int imgURXA
, int imgURYA
,
976 GBool manualCtrlA
, const char *pageRangesA
) {
982 outputFunc
= outputFuncA
;
983 outputStream
= outputStreamA
;
984 fileType
= fileTypeA
;
986 level
= globalParams
->getPSLevel();
988 paperWidth
= globalParams
->getPSPaperWidth();
989 paperHeight
= globalParams
->getPSPaperHeight();
994 pageRanges
= pageRangesA
;
995 if (imgLLX
== 0 && imgURX
== 0 && imgLLY
== 0 && imgURY
== 0) {
996 globalParams
->getPSImageableArea(&imgLLX
, &imgLLY
, &imgURX
, &imgURY
);
998 if (paperWidth
< 0 || paperHeight
< 0) {
999 // this check is needed in case the document has zero pages
1000 if (firstPage
> 0 && firstPage
<= catalog
->getNumPages()) {
1001 page
= catalog
->getPage(firstPage
);
1002 paperWidth
= (int)ceil(page
->getMediaWidth());
1003 paperHeight
= (int)ceil(page
->getMediaHeight());
1008 imgLLX
= imgLLY
= 0;
1009 imgURX
= paperWidth
;
1010 imgURY
= paperHeight
;
1012 manualCtrl
= manualCtrlA
;
1013 if (mode
== psModeForm
) {
1014 lastPage
= firstPage
;
1017 inType3Char
= gFalse
;
1020 // initialize OPI nesting levels
1026 xScale0
= yScale0
= 0;
1028 clipLLX0
= clipLLY0
= 0;
1029 clipURX0
= clipURY0
= -1;
1031 // initialize fontIDs, fontFileIDs, and fontFileNames lists
1034 fontIDs
= (Ref
*)gmallocn(fontIDSize
, sizeof(Ref
));
1035 fontFileIDSize
= 64;
1037 fontFileIDs
= (Ref
*)gmallocn(fontFileIDSize
, sizeof(Ref
));
1038 fontFileNameSize
= 64;
1039 fontFileNameLen
= 0;
1040 fontFileNames
= (GString
**)gmallocn(fontFileNameSize
, sizeof(GString
*));
1041 nextTrueTypeNum
= 0;
1045 xobjStack
= new GList();
1047 numTilingPatterns
= 0;
1050 // initialize embedded font resource comment list
1051 embFontList
= new GString();
1054 // this check is needed in case the document has zero pages
1055 if (firstPage
> 0 && firstPage
<= catalog
->getNumPages()) {
1056 writeHeader(firstPage
, lastPage
,
1057 catalog
->getPage(firstPage
)->getMediaBox(),
1058 catalog
->getPage(firstPage
)->getCropBox(),
1059 catalog
->getPage(firstPage
)->getRotate());
1061 box
= new PDFRectangle(0, 0, 1, 1);
1062 writeHeader(firstPage
, lastPage
, box
, box
, 0);
1065 if (mode
!= psModeForm
) {
1066 writePS("%%BeginProlog\n");
1069 if (mode
!= psModeForm
) {
1070 writePS("%%EndProlog\n");
1071 writePS("%%BeginSetup\n");
1073 writeDocSetup(catalog
, firstPage
, lastPage
);
1074 if (mode
!= psModeForm
) {
1075 writePS("%%EndSetup\n");
1079 // initialize sequential page number
1083 PSOutputDev::~PSOutputDev() {
1084 PSOutCustomColor
*cc
;
1089 writePS("%%Trailer\n");
1091 if (mode
!= psModeForm
) {
1095 if (fileType
== psFile
) {
1097 ICS_MapRefNumAndAssign((short)((FILE *)outputStream
)->handle
);
1099 fclose((FILE *)outputStream
);
1102 else if (fileType
== psPipe
) {
1103 pclose((FILE *)outputStream
);
1105 signal(SIGPIPE
, (SignalFunc
)SIG_DFL
);
1119 if (fontFileNames
) {
1120 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1121 delete fontFileNames
[i
];
1123 gfree(fontFileNames
);
1126 for (i
= 0; i
< font16EncLen
; ++i
) {
1127 delete font16Enc
[i
].enc
;
1134 while (customColors
) {
1136 customColors
= cc
->next
;
1141 void PSOutputDev::writeHeader(int firstPage
, int lastPage
,
1142 PDFRectangle
*mediaBox
, PDFRectangle
*cropBox
,
1145 double x1
, y1
, x2
, y2
;
1151 writePS("%!PS-Adobe-3.0\n");
1154 writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
1157 writePS("%!PS-Adobe-3.0 Resource-Form\n");
1161 // Tell CUPS pstops filter not to do its own rotation...
1162 writePSFmt("%%cupsRotation: %d\n", pageRotate
);
1164 writePSFmt("%%Producer: xpdf/pdftops %s\n", xpdfVersion
);
1165 xref
->getDocInfo(&info
);
1166 if (info
.isDict() && info
.dictLookup("Creator", &obj1
)->isString()) {
1167 writePS("%%Creator: ");
1168 s
= obj1
.getString();
1169 if ((s
->getChar(0) & 0xff) == 0xfe &&
1170 (s
->getChar(1) & 0xff) == 0xff) {
1171 // Convert UTF-16 to UTF-8...
1172 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1173 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1175 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1176 // Multi-word UTF-16 char...
1178 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1180 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1182 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1188 * Single byte ASCII...
1193 else if (ch
< 0x800)
1199 writePSChar(0xc0 | (ch
>> 6));
1200 writePSChar(0x80 | (ch
& 0x3f));
1202 else if (ch
< 0x10000)
1205 * Three-byte UTF-8...
1208 writePSChar(0xe0 | (ch
>> 12));
1209 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1210 writePSChar(0x80 | (ch
& 0x3f));
1215 * Four-byte UTF-8...
1218 writePSChar(0xf0 | (ch
>> 18));
1219 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1220 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1221 writePSChar(0x80 | (ch
& 0x3f));
1225 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1226 writePSChar(s
->getChar(i
));
1232 if (info
.isDict() && info
.dictLookup("Title", &obj1
)->isString()) {
1233 writePS("%%Title: ");
1234 s
= obj1
.getString();
1235 if ((s
->getChar(0) & 0xff) == 0xfe &&
1236 (s
->getChar(1) & 0xff) == 0xff) {
1237 // Convert UTF-16 to UTF-8...
1238 for (i
= 2; i
< s
->getLength() && i
< 400; i
+= 2) {
1239 int ch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1241 if (ch
>= 0xd800 && ch
<= 0xdbff) {
1242 // Multi-word UTF-16 char...
1244 int lch
= ((s
->getChar(i
) & 255) << 8) | (s
->getChar(i
+ 1) & 255);
1246 if (lch
< 0xdc00 || lch
>= 0xdfff) continue;
1248 ch
= (((ch
& 0x3ff) << 10) | (lch
& 0x3ff)) + 0x10000;
1254 * Single byte ASCII...
1259 else if (ch
< 0x800)
1265 writePSChar(0xc0 | (ch
>> 6));
1266 writePSChar(0x80 | (ch
& 0x3f));
1268 else if (ch
< 0x10000)
1271 * Three-byte UTF-8...
1274 writePSChar(0xe0 | (ch
>> 12));
1275 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1276 writePSChar(0x80 | (ch
& 0x3f));
1281 * Four-byte UTF-8...
1284 writePSChar(0xf0 | (ch
>> 18));
1285 writePSChar(0x80 | ((ch
>> 12) & 0x3f));
1286 writePSChar(0x80 | ((ch
>> 6) & 0x3f));
1287 writePSChar(0x80 | (ch
& 0x3f));
1291 for (i
= 0; i
< s
->getLength() && i
< 200; ++i
) {
1292 writePSChar(s
->getChar(i
));
1299 writePSFmt("%%%%LanguageLevel: %d\n",
1300 (level
== psLevel1
|| level
== psLevel1Sep
) ? 1 :
1301 (level
== psLevel2
|| level
== psLevel2Sep
) ? 2 : 3);
1302 if (level
== psLevel1Sep
|| level
== psLevel2Sep
|| level
== psLevel3Sep
) {
1303 writePS("%%DocumentProcessColors: (atend)\n");
1304 writePS("%%DocumentCustomColors: (atend)\n");
1306 writePS("%%DocumentSuppliedResources: (atend)\n");
1310 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
1311 paperWidth
, paperHeight
);
1312 writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth
, paperHeight
);
1313 writePSFmt("%%%%Pages: %d\n", lastPage
- firstPage
+ 1);
1314 writePS("%%EndComments\n");
1315 writePS("%%BeginDefaults\n");
1316 writePS("%%PageMedia: plain\n");
1317 writePS("%%EndDefaults\n");
1320 epsX1
= cropBox
->x1
;
1321 epsY1
= cropBox
->y1
;
1322 epsX2
= cropBox
->x2
;
1323 epsY2
= cropBox
->y2
;
1324 if (pageRotate
== 0 || pageRotate
== 180) {
1329 } else { // pageRotate == 90 || pageRotate == 270
1335 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
1336 (int)floor(x1
), (int)floor(y1
), (int)ceil(x2
), (int)ceil(y2
));
1337 if (floor(x1
) != ceil(x1
) || floor(y1
) != ceil(y1
) ||
1338 floor(x2
) != ceil(x2
) || floor(y2
) != ceil(y2
)) {
1339 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1
, y1
, x2
, y2
);
1341 writePS("%%EndComments\n");
1344 writePS("%%EndComments\n");
1345 writePS("32 dict dup begin\n");
1346 writePSFmt("/BBox [%d %d %d %d] def\n",
1347 (int)floor(mediaBox
->x1
), (int)floor(mediaBox
->y1
),
1348 (int)ceil(mediaBox
->x2
), (int)ceil(mediaBox
->y2
));
1349 writePS("/FormType 1 def\n");
1350 writePS("/Matrix [1 0 0 1 0 0] def\n");
1355 void PSOutputDev::writeXpdfProcset() {
1356 GBool lev1
, lev2
, lev3
, sep
, nonSep
;
1360 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion
);
1361 lev1
= lev2
= lev3
= sep
= nonSep
= gTrue
;
1362 for (p
= prolog
; *p
; ++p
) {
1363 if ((*p
)[0] == '~') {
1364 lev1
= lev2
= lev3
= sep
= nonSep
= gFalse
;
1365 for (q
= *p
+ 1; *q
; ++q
) {
1367 case '1': lev1
= gTrue
; break;
1368 case '2': lev2
= gTrue
; break;
1369 case '3': lev3
= gTrue
; break;
1370 case 's': sep
= gTrue
; break;
1371 case 'n': nonSep
= gTrue
; break;
1374 } else if ((level
== psLevel1
&& lev1
&& nonSep
) ||
1375 (level
== psLevel1Sep
&& lev1
&& sep
) ||
1376 (level
== psLevel2
&& lev2
&& nonSep
) ||
1377 (level
== psLevel2Sep
&& lev2
&& sep
) ||
1378 (level
== psLevel3
&& lev3
&& nonSep
) ||
1379 (level
== psLevel3Sep
&& lev3
&& sep
)) {
1380 writePSFmt("%s\n", *p
);
1383 writePS("%%EndResource\n");
1385 if (level
>= psLevel3
) {
1386 for (p
= cmapProlog
; *p
; ++p
) {
1387 writePSFmt("%s\n", *p
);
1392 void PSOutputDev::writeDocSetup(Catalog
*catalog
,
1393 int firstPage
, int lastPage
) {
1400 if (mode
== psModeForm
) {
1401 // swap the form and xpdf dicts
1402 writePS("xpdf end begin dup begin\n");
1404 writePS("xpdf begin\n");
1406 for (pg
= firstPage
; pg
<= lastPage
; ++pg
) {
1407 page
= catalog
->getPage(pg
);
1408 if ((resDict
= page
->getResourceDict())) {
1409 setupResources(resDict
);
1411 annots
= new Annots(xref
, catalog
, page
->getAnnots(&obj1
));
1413 for (i
= 0; i
< annots
->getNumAnnots(); ++i
) {
1414 if (annots
->getAnnot(i
)->getAppearance(&obj1
)->isStream()) {
1415 obj1
.streamGetDict()->lookup("Resources", &obj2
);
1416 if (obj2
.isDict()) {
1417 setupResources(obj2
.getDict());
1425 if (mode
!= psModeForm
) {
1426 if (mode
!= psModeEPS
&& !manualCtrl
) {
1427 writePSFmt("%d %d %s pdfSetup\n",
1428 paperWidth
, paperHeight
,
1429 globalParams
->getPSDuplex() ? "true" : "false");
1432 if (globalParams
->getPSOPI()) {
1433 writePS("/opiMatrix matrix currentmatrix def\n");
1439 void PSOutputDev::writePageTrailer() {
1440 if (mode
!= psModeForm
) {
1441 writePS("pdfEndPage\n");
1445 void PSOutputDev::writeTrailer() {
1446 PSOutCustomColor
*cc
;
1448 if (mode
== psModeForm
) {
1449 writePS("/Foo exch /Form defineresource pop\n");
1452 writePS("%%DocumentSuppliedResources:\n");
1453 writePS(embFontList
->getCString());
1454 if (level
== psLevel1Sep
|| level
== psLevel2Sep
||
1455 level
== psLevel3Sep
) {
1456 writePS("%%DocumentProcessColors:");
1457 if (processColors
& psProcessCyan
) {
1460 if (processColors
& psProcessMagenta
) {
1461 writePS(" Magenta");
1463 if (processColors
& psProcessYellow
) {
1466 if (processColors
& psProcessBlack
) {
1470 writePS("%%DocumentCustomColors:");
1471 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1472 writePSFmt(" (%s)", cc
->name
->getCString());
1475 writePS("%%CMYKCustomColor:\n");
1476 for (cc
= customColors
; cc
; cc
= cc
->next
) {
1477 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
1478 cc
->c
, cc
->m
, cc
->y
, cc
->k
, cc
->name
->getCString());
1484 void PSOutputDev::setupResources(Dict
*resDict
) {
1485 Object xObjDict
, xObjRef
, xObj
, patDict
, patRef
, pat
, resObj
;
1490 setupFonts(resDict
);
1491 setupImages(resDict
);
1493 //----- recursively scan XObjects
1494 resDict
->lookup("XObject", &xObjDict
);
1495 if (xObjDict
.isDict()) {
1496 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
1498 // avoid infinite recursion on XObjects
1500 if ((xObjDict
.dictGetValNF(i
, &xObjRef
)->isRef())) {
1501 ref0
= xObjRef
.getRef();
1502 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1503 ref1
= *(Ref
*)xobjStack
->get(j
);
1504 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1510 xobjStack
->append(&ref0
);
1515 // process the XObject's resource dictionary
1516 xObjDict
.dictGetVal(i
, &xObj
);
1517 if (xObj
.isStream()) {
1518 xObj
.streamGetDict()->lookup("Resources", &resObj
);
1519 if (resObj
.isDict()) {
1520 setupResources(resObj
.getDict());
1527 if (xObjRef
.isRef() && !skip
) {
1528 xobjStack
->del(xobjStack
->getLength() - 1);
1535 //----- recursively scan Patterns
1536 resDict
->lookup("Pattern", &patDict
);
1537 if (patDict
.isDict()) {
1538 inType3Char
= gTrue
;
1539 for (i
= 0; i
< patDict
.dictGetLength(); ++i
) {
1541 // avoid infinite recursion on Patterns
1543 if ((patDict
.dictGetValNF(i
, &patRef
)->isRef())) {
1544 ref0
= patRef
.getRef();
1545 for (j
= 0; j
< xobjStack
->getLength(); ++j
) {
1546 ref1
= *(Ref
*)xobjStack
->get(j
);
1547 if (ref1
.num
== ref0
.num
&& ref1
.gen
== ref0
.gen
) {
1553 xobjStack
->append(&ref0
);
1558 // process the Pattern's resource dictionary
1559 patDict
.dictGetVal(i
, &pat
);
1560 if (pat
.isStream()) {
1561 pat
.streamGetDict()->lookup("Resources", &resObj
);
1562 if (resObj
.isDict()) {
1563 setupResources(resObj
.getDict());
1570 if (patRef
.isRef() && !skip
) {
1571 xobjStack
->del(xobjStack
->getLength() - 1);
1575 inType3Char
= gFalse
;
1580 void PSOutputDev::setupFonts(Dict
*resDict
) {
1583 GfxFontDict
*gfxFontDict
;
1588 resDict
->lookupNF("Font", &obj1
);
1590 obj1
.fetch(xref
, &obj2
);
1591 if (obj2
.isDict()) {
1593 gfxFontDict
= new GfxFontDict(xref
, &r
, obj2
.getDict());
1596 } else if (obj1
.isDict()) {
1597 gfxFontDict
= new GfxFontDict(xref
, NULL
, obj1
.getDict());
1600 for (i
= 0; i
< gfxFontDict
->getNumFonts(); ++i
) {
1601 if ((font
= gfxFontDict
->getFont(i
))) {
1602 setupFont(font
, resDict
);
1610 void PSOutputDev::setupFont(GfxFont
*font
, Dict
*parentResDict
) {
1613 PSFontParam
*fontParam
;
1615 char type3Name
[64], buf
[16];
1625 // check if font is already set up
1626 for (i
= 0; i
< fontIDLen
; ++i
) {
1627 if (fontIDs
[i
].num
== font
->getID()->num
&&
1628 fontIDs
[i
].gen
== font
->getID()->gen
) {
1633 // add entry to fontIDs list
1634 if (fontIDLen
>= fontIDSize
) {
1636 fontIDs
= (Ref
*)greallocn(fontIDs
, fontIDSize
, sizeof(Ref
));
1638 fontIDs
[fontIDLen
++] = *font
->getID();
1643 // check for resident 8-bit font
1644 if (font
->getName() &&
1645 (fontParam
= globalParams
->getPSFont(font
->getName()))) {
1646 psName
= new GString(fontParam
->psFontName
->getCString());
1648 // check for embedded Type 1 font
1649 } else if (globalParams
->getPSEmbedType1() &&
1650 font
->getType() == fontType1
&&
1651 font
->getEmbeddedFontID(&fontFileID
)) {
1652 psName
= filterPSName(font
->getEmbeddedFontName());
1653 setupEmbeddedType1Font(&fontFileID
, psName
);
1655 // check for embedded Type 1C font
1656 } else if (globalParams
->getPSEmbedType1() &&
1657 font
->getType() == fontType1C
&&
1658 font
->getEmbeddedFontID(&fontFileID
)) {
1659 psName
= filterPSName(font
->getEmbeddedFontName());
1660 setupEmbeddedType1CFont(font
, &fontFileID
, psName
);
1662 // check for external Type 1 font file
1663 } else if (globalParams
->getPSEmbedType1() &&
1664 font
->getType() == fontType1
&&
1665 font
->getExtFontFile()) {
1666 // this assumes that the PS font name matches the PDF font name
1667 psName
= font
->getName()->copy();
1668 setupExternalType1Font(font
->getExtFontFile(), psName
);
1670 // check for embedded TrueType font
1671 } else if (globalParams
->getPSEmbedTrueType() &&
1672 font
->getType() == fontTrueType
&&
1673 font
->getEmbeddedFontID(&fontFileID
)) {
1674 psName
= filterPSName(font
->getEmbeddedFontName());
1675 setupEmbeddedTrueTypeFont(font
, &fontFileID
, psName
);
1677 // check for external TrueType font file
1678 } else if (globalParams
->getPSEmbedTrueType() &&
1679 font
->getType() == fontTrueType
&&
1680 font
->getExtFontFile()) {
1681 psName
= filterPSName(font
->getName());
1682 setupExternalTrueTypeFont(font
, psName
);
1684 // check for embedded CID PostScript font
1685 } else if (globalParams
->getPSEmbedCIDPostScript() &&
1686 font
->getType() == fontCIDType0C
&&
1687 font
->getEmbeddedFontID(&fontFileID
)) {
1688 psName
= filterPSName(font
->getEmbeddedFontName());
1689 setupEmbeddedCIDType0Font(font
, &fontFileID
, psName
);
1691 // check for embedded CID TrueType font
1692 } else if (globalParams
->getPSEmbedCIDTrueType() &&
1693 font
->getType() == fontCIDType2
&&
1694 font
->getEmbeddedFontID(&fontFileID
)) {
1695 psName
= filterPSName(font
->getEmbeddedFontName());
1696 //~ should check to see if font actually uses vertical mode
1697 setupEmbeddedCIDTrueTypeFont(font
, &fontFileID
, psName
, gTrue
);
1699 } else if (font
->getType() == fontType3
) {
1700 sprintf(type3Name
, "T3_%d_%d",
1701 font
->getID()->num
, font
->getID()->gen
);
1702 psName
= new GString(type3Name
);
1703 setupType3Font(font
, psName
, parentResDict
);
1705 // do 8-bit font substitution
1706 } else if (!font
->isCIDFont()) {
1708 name
= font
->getName();
1711 for (i
= 0; psFonts
[i
]; ++i
) {
1712 if (name
->cmp(psFonts
[i
]) == 0) {
1713 psName
= new GString(psFonts
[i
]);
1719 if (font
->isFixedWidth()) {
1721 } else if (font
->isSerif()) {
1726 if (font
->isBold()) {
1729 if (font
->isItalic()) {
1732 psName
= new GString(psSubstFonts
[i
].psName
);
1733 for (code
= 0; code
< 256; ++code
) {
1734 if ((charName
= ((Gfx8BitFont
*)font
)->getCharName(code
)) &&
1735 charName
[0] == 'm' && charName
[1] == '\0') {
1740 w1
= ((Gfx8BitFont
*)font
)->getWidth(code
);
1744 w2
= psSubstFonts
[i
].mWidth
;
1749 if (font
->getType() == fontType3
) {
1750 // This is a hack which makes it possible to substitute for some
1751 // Type 3 fonts. The problem is that it's impossible to know what
1752 // the base coordinate system used in the font is without actually
1753 // rendering the font.
1755 fm
= font
->getFontMatrix();
1757 ys
*= fm
[3] / fm
[0];
1764 // do 16-bit font substitution
1765 } else if ((fontParam
= globalParams
->
1766 getPSFont16(font
->getName(),
1767 ((GfxCIDFont
*)font
)->getCollection(),
1768 font
->getWMode()))) {
1770 psName
= fontParam
->psFontName
->copy();
1771 if (font16EncLen
>= font16EncSize
) {
1772 font16EncSize
+= 16;
1773 font16Enc
= (PSFont16Enc
*)greallocn(font16Enc
,
1774 font16EncSize
, sizeof(PSFont16Enc
));
1776 font16Enc
[font16EncLen
].fontID
= *font
->getID();
1777 font16Enc
[font16EncLen
].enc
= fontParam
->encoding
->copy();
1778 if ((uMap
= globalParams
->getUnicodeMap(font16Enc
[font16EncLen
].enc
))) {
1782 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1783 font16Enc
[font16EncLen
].enc
->getCString());
1786 // give up - can't do anything with this font
1788 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1789 font
->getName() ? font
->getName()->getCString() : "(unnamed)",
1790 ((GfxCIDFont
*)font
)->getCollection()
1791 ? ((GfxCIDFont
*)font
)->getCollection()->getCString()
1796 // generate PostScript code to set up the font
1797 if (font
->isCIDFont()) {
1798 if (level
== psLevel3
|| level
== psLevel3Sep
) {
1799 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
1800 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1803 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
1804 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1808 writePSFmt("/F%d_%d /%s %g %g\n",
1809 font
->getID()->num
, font
->getID()->gen
, psName
->getCString(),
1811 for (i
= 0; i
< 256; i
+= 8) {
1812 writePSFmt((i
== 0) ? "[ " : " ");
1813 for (j
= 0; j
< 8; ++j
) {
1814 if (font
->getType() == fontTrueType
&&
1816 !((Gfx8BitFont
*)font
)->getHasEncoding()) {
1817 sprintf(buf
, "c%02x", i
+j
);
1820 charName
= ((Gfx8BitFont
*)font
)->getCharName(i
+j
);
1821 // this is a kludge for broken PDF files that encode char 32
1823 if (i
+j
== 32 && charName
&& !strcmp(charName
, ".notdef")) {
1828 writePSName(charName
? charName
: (char *)".notdef");
1829 // the empty name is legal in PDF and PostScript, but PostScript
1830 // uses a double-slash (//...) for "immediately evaluated names",
1831 // so we need to add a space character here
1832 if (charName
&& !charName
[0]) {
1836 writePS((i
== 256-8) ? (char *)"]\n" : (char *)"\n");
1838 writePS("pdfMakeFont\n");
1844 void PSOutputDev::setupEmbeddedType1Font(Ref
*id
, GString
*psName
) {
1845 static char hexChar
[17] = "0123456789abcdef";
1846 Object refObj
, strObj
, obj1
, obj2
, obj3
;
1848 int length1
, length2
, length3
;
1854 // check if font is already embedded
1855 for (i
= 0; i
< fontFileIDLen
; ++i
) {
1856 if (fontFileIDs
[i
].num
== id
->num
&&
1857 fontFileIDs
[i
].gen
== id
->gen
)
1861 // add entry to fontFileIDs list
1862 if (fontFileIDLen
>= fontFileIDSize
) {
1863 fontFileIDSize
+= 64;
1864 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
1866 fontFileIDs
[fontFileIDLen
++] = *id
;
1868 // get the font stream and info
1869 refObj
.initRef(id
->num
, id
->gen
);
1870 refObj
.fetch(xref
, &strObj
);
1872 if (!strObj
.isStream()) {
1873 error(-1, "Embedded font file object is not a stream");
1876 if (!(dict
= strObj
.streamGetDict())) {
1877 error(-1, "Embedded font stream is missing its dictionary");
1880 dict
->lookup("Length1", &obj1
);
1881 dict
->lookup("Length2", &obj2
);
1882 dict
->lookup("Length3", &obj3
);
1883 if (!obj1
.isInt() || !obj2
.isInt() || !obj3
.isInt()) {
1884 error(-1, "Missing length fields in embedded font stream dictionary");
1890 length1
= obj1
.getInt();
1891 length2
= obj2
.getInt();
1892 length3
= obj3
.getInt();
1897 // beginning comment
1898 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1899 embFontList
->append("%%+ font ");
1900 embFontList
->append(psName
->getCString());
1901 embFontList
->append("\n");
1903 // copy ASCII portion of font
1904 strObj
.streamReset();
1905 for (i
= 0; i
< length1
&& (c
= strObj
.streamGetChar()) != EOF
; ++i
) {
1909 // figure out if encrypted portion is binary or ASCII
1911 for (i
= 0; i
< 4; ++i
) {
1912 start
[i
] = strObj
.streamGetChar();
1913 if (start
[i
] == EOF
) {
1914 error(-1, "Unexpected end of file in embedded font stream");
1917 if (!((start
[i
] >= '0' && start
[i
] <= '9') ||
1918 (start
[i
] >= 'A' && start
[i
] <= 'F') ||
1919 (start
[i
] >= 'a' && start
[i
] <= 'f')))
1923 // convert binary data to ASCII
1925 for (i
= 0; i
< 4; ++i
) {
1926 writePSChar(hexChar
[(start
[i
] >> 4) & 0x0f]);
1927 writePSChar(hexChar
[start
[i
] & 0x0f]);
1929 // if Length2 is incorrect (too small), font data gets chopped, so
1930 // we take a few extra characters from the trailer just in case
1931 // length2 += length3 >= 8 ? 8 : length3;
1932 while (i
< length2
) {
1933 if ((c
= strObj
.streamGetChar()) == EOF
) {
1936 writePSChar(hexChar
[(c
>> 4) & 0x0f]);
1937 writePSChar(hexChar
[c
& 0x0f]);
1938 if (++i
% 32 == 0) {
1946 // already in ASCII format -- just copy it
1948 for (i
= 0; i
< 4; ++i
) {
1949 writePSChar(start
[i
]);
1951 for (i
= 4; i
< length2
; ++i
) {
1952 if ((c
= strObj
.streamGetChar()) == EOF
) {
1959 // write padding and "cleartomark"
1960 for (i
= 0; i
< 8; ++i
) {
1961 writePS("00000000000000000000000000000000"
1962 "00000000000000000000000000000000\n");
1964 writePS("cleartomark\n");
1967 writePS("%%EndResource\n");
1970 strObj
.streamClose();
1974 //~ This doesn't handle .pfb files or binary eexec data (which only
1975 //~ happens in pfb files?).
1976 void PSOutputDev::setupExternalType1Font(GString
*fileName
, GString
*psName
) {
1981 // check if font is already embedded
1982 for (i
= 0; i
< fontFileNameLen
; ++i
) {
1983 if (!fontFileNames
[i
]->cmp(fileName
)) {
1988 // add entry to fontFileNames list
1989 if (fontFileNameLen
>= fontFileNameSize
) {
1990 fontFileNameSize
+= 64;
1991 fontFileNames
= (GString
**)greallocn(fontFileNames
,
1992 fontFileNameSize
, sizeof(GString
*));
1994 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
1996 // beginning comment
1997 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
1998 embFontList
->append("%%+ font ");
1999 embFontList
->append(psName
->getCString());
2000 embFontList
->append("\n");
2002 // copy the font file
2003 if (!(fontFile
= fopen(fileName
->getCString(), "rb"))) {
2004 error(-1, "Couldn't open external font file");
2007 while ((c
= fgetc(fontFile
)) != EOF
) {
2013 writePS("%%EndResource\n");
2016 void PSOutputDev::setupEmbeddedType1CFont(GfxFont
*font
, Ref
*id
,
2023 // check if font is already embedded
2024 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2025 if (fontFileIDs
[i
].num
== id
->num
&&
2026 fontFileIDs
[i
].gen
== id
->gen
)
2030 // add entry to fontFileIDs list
2031 if (fontFileIDLen
>= fontFileIDSize
) {
2032 fontFileIDSize
+= 64;
2033 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2035 fontFileIDs
[fontFileIDLen
++] = *id
;
2037 // beginning comment
2038 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2039 embFontList
->append("%%+ font ");
2040 embFontList
->append(psName
->getCString());
2041 embFontList
->append("\n");
2043 // convert it to a Type 1 font
2044 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2045 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2046 ffT1C
->convertToType1(NULL
, gTrue
, outputFunc
, outputStream
);
2052 writePS("%%EndResource\n");
2055 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont
*font
, Ref
*id
,
2064 // check if font is already embedded
2065 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2066 if (fontFileIDs
[i
].num
== id
->num
&&
2067 fontFileIDs
[i
].gen
== id
->gen
) {
2068 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2069 psName
->append(unique
);
2074 // add entry to fontFileIDs list
2075 if (i
== fontFileIDLen
) {
2076 if (fontFileIDLen
>= fontFileIDSize
) {
2077 fontFileIDSize
+= 64;
2078 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2080 fontFileIDs
[fontFileIDLen
++] = *id
;
2083 // beginning comment
2084 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2085 embFontList
->append("%%+ font ");
2086 embFontList
->append(psName
->getCString());
2087 embFontList
->append("\n");
2089 // convert it to a Type 42 font
2090 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2091 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2092 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2093 ffTT
->convertToType42(psName
->getCString(),
2094 ((Gfx8BitFont
*)font
)->getHasEncoding()
2095 ? ((Gfx8BitFont
*)font
)->getEncoding()
2097 codeToGID
, outputFunc
, outputStream
);
2104 writePS("%%EndResource\n");
2107 void PSOutputDev::setupExternalTrueTypeFont(GfxFont
*font
, GString
*psName
) {
2116 // check if font is already embedded
2117 fileName
= font
->getExtFontFile();
2118 for (i
= 0; i
< fontFileNameLen
; ++i
) {
2119 if (!fontFileNames
[i
]->cmp(fileName
)) {
2120 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2121 psName
->append(unique
);
2126 // add entry to fontFileNames list
2127 if (i
== fontFileNameLen
) {
2128 if (fontFileNameLen
>= fontFileNameSize
) {
2129 fontFileNameSize
+= 64;
2131 (GString
**)greallocn(fontFileNames
,
2132 fontFileNameSize
, sizeof(GString
*));
2134 fontFileNames
[fontFileNameLen
++] = fileName
->copy();
2137 // beginning comment
2138 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2139 embFontList
->append("%%+ font ");
2140 embFontList
->append(psName
->getCString());
2141 embFontList
->append("\n");
2143 // convert it to a Type 42 font
2144 fontBuf
= font
->readExtFontFile(&fontLen
);
2145 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2146 codeToGID
= ((Gfx8BitFont
*)font
)->getCodeToGIDMap(ffTT
);
2147 ffTT
->convertToType42(psName
->getCString(),
2148 ((Gfx8BitFont
*)font
)->getHasEncoding()
2149 ? ((Gfx8BitFont
*)font
)->getEncoding()
2151 codeToGID
, outputFunc
, outputStream
);
2157 writePS("%%EndResource\n");
2160 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont
*font
, Ref
*id
,
2167 // check if font is already embedded
2168 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2169 if (fontFileIDs
[i
].num
== id
->num
&&
2170 fontFileIDs
[i
].gen
== id
->gen
)
2174 // add entry to fontFileIDs list
2175 if (fontFileIDLen
>= fontFileIDSize
) {
2176 fontFileIDSize
+= 64;
2177 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2179 fontFileIDs
[fontFileIDLen
++] = *id
;
2181 // beginning comment
2182 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2183 embFontList
->append("%%+ font ");
2184 embFontList
->append(psName
->getCString());
2185 embFontList
->append("\n");
2187 // convert it to a Type 0 font
2188 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2189 if ((ffT1C
= FoFiType1C::make(fontBuf
, fontLen
))) {
2190 if (globalParams
->getPSLevel() >= psLevel3
) {
2191 // Level 3: use a CID font
2192 ffT1C
->convertToCIDType0(psName
->getCString(), outputFunc
, outputStream
);
2194 // otherwise: use a non-CID composite font
2195 ffT1C
->convertToType0(psName
->getCString(), outputFunc
, outputStream
);
2202 writePS("%%EndResource\n");
2205 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont
*font
, Ref
*id
,
2207 GBool needVerticalMetrics
) {
2214 // check if font is already embedded
2215 for (i
= 0; i
< fontFileIDLen
; ++i
) {
2216 if (fontFileIDs
[i
].num
== id
->num
&&
2217 fontFileIDs
[i
].gen
== id
->gen
) {
2218 sprintf(unique
, "_%d", nextTrueTypeNum
++);
2219 psName
->append(unique
);
2224 // add entry to fontFileIDs list
2225 if (fontFileIDLen
>= fontFileIDSize
) {
2226 fontFileIDSize
+= 64;
2227 fontFileIDs
= (Ref
*)greallocn(fontFileIDs
, fontFileIDSize
, sizeof(Ref
));
2229 fontFileIDs
[fontFileIDLen
++] = *id
;
2231 // beginning comment
2232 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2233 embFontList
->append("%%+ font ");
2234 embFontList
->append(psName
->getCString());
2235 embFontList
->append("\n");
2237 // convert it to a Type 0 font
2238 fontBuf
= font
->readEmbFontFile(xref
, &fontLen
);
2239 if ((ffTT
= FoFiTrueType::make(fontBuf
, fontLen
))) {
2240 if (globalParams
->getPSLevel() >= psLevel3
) {
2241 // Level 3: use a CID font
2242 ffTT
->convertToCIDType2(psName
->getCString(),
2243 ((GfxCIDFont
*)font
)->getCIDToGID(),
2244 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2245 needVerticalMetrics
,
2246 outputFunc
, outputStream
);
2248 // otherwise: use a non-CID composite font
2249 ffTT
->convertToType0(psName
->getCString(),
2250 ((GfxCIDFont
*)font
)->getCIDToGID(),
2251 ((GfxCIDFont
*)font
)->getCIDToGIDLen(),
2252 needVerticalMetrics
,
2253 outputFunc
, outputStream
);
2260 writePS("%%EndResource\n");
2263 void PSOutputDev::setupType3Font(GfxFont
*font
, GString
*psName
,
2264 Dict
*parentResDict
) {
2274 // set up resources used by font
2275 if ((resDict
= ((Gfx8BitFont
*)font
)->getResources())) {
2276 inType3Char
= gTrue
;
2277 setupResources(resDict
);
2278 inType3Char
= gFalse
;
2280 resDict
= parentResDict
;
2283 // beginning comment
2284 writePSFmt("%%%%BeginResource: font %s\n", psName
->getCString());
2285 embFontList
->append("%%+ font ");
2286 embFontList
->append(psName
->getCString());
2287 embFontList
->append("\n");
2290 writePS("8 dict begin\n");
2291 writePS("/FontType 3 def\n");
2292 m
= font
->getFontMatrix();
2293 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
2294 m
[0], m
[1], m
[2], m
[3], m
[4], m
[5]);
2295 m
= font
->getFontBBox();
2296 writePSFmt("/FontBBox [%g %g %g %g] def\n",
2297 m
[0], m
[1], m
[2], m
[3]);
2298 writePS("/Encoding 256 array def\n");
2299 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2300 writePS("/BuildGlyph {\n");
2301 writePS(" exch /CharProcs get exch\n");
2302 writePS(" 2 copy known not { pop /.notdef } if\n");
2303 writePS(" get exec\n");
2304 writePS("} bind def\n");
2305 writePS("/BuildChar {\n");
2306 writePS(" 1 index /Encoding get exch get\n");
2307 writePS(" 1 index /BuildGlyph get exec\n");
2308 writePS("} bind def\n");
2309 if ((charProcs
= ((Gfx8BitFont
*)font
)->getCharProcs())) {
2310 writePSFmt("/CharProcs %d dict def\n", charProcs
->getLength());
2311 writePS("CharProcs begin\n");
2316 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
2317 inType3Char
= gTrue
;
2318 t3Cacheable
= gFalse
;
2319 for (i
= 0; i
< charProcs
->getLength(); ++i
) {
2321 writePSName(charProcs
->getKey(i
));
2323 gfx
->display(charProcs
->getVal(i
, &charProc
));
2327 sprintf(buf
, "%g %g %g %g %g %g setcachedevice\n",
2328 t3WX
, t3WY
, t3LLX
, t3LLY
, t3URX
, t3URY
);
2330 sprintf(buf
, "%g %g setcharwidth\n", t3WX
, t3WY
);
2332 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
2333 (*outputFunc
)(outputStream
, t3String
->getCString(),
2334 t3String
->getLength());
2338 (*outputFunc
)(outputStream
, "Q\n", 2);
2341 inType3Char
= gFalse
;
2345 writePS("currentdict end\n");
2346 writePSFmt("/%s exch definefont pop\n", psName
->getCString());
2349 writePS("%%EndResource\n");
2352 void PSOutputDev::setupImages(Dict
*resDict
) {
2353 Object xObjDict
, xObj
, xObjRef
, subtypeObj
;
2356 if (!(mode
== psModeForm
|| inType3Char
)) {
2360 resDict
->lookup("XObject", &xObjDict
);
2361 if (xObjDict
.isDict()) {
2362 for (i
= 0; i
< xObjDict
.dictGetLength(); ++i
) {
2363 xObjDict
.dictGetValNF(i
, &xObjRef
);
2364 xObjDict
.dictGetVal(i
, &xObj
);
2365 if (xObj
.isStream()) {
2366 xObj
.streamGetDict()->lookup("Subtype", &subtypeObj
);
2367 if (subtypeObj
.isName("Image")) {
2368 if (xObjRef
.isRef()) {
2369 setupImage(xObjRef
.getRef(), xObj
.getStream());
2371 error(-1, "Image in resource dict is not an indirect reference");
2383 void PSOutputDev::setupImage(Ref id
, Stream
*str
) {
2386 int size
, line
, col
, i
;
2388 // construct an encoder stream
2389 useASCIIHex
= level
== psLevel1
|| level
== psLevel1Sep
||
2390 globalParams
->getPSASCIIHex();
2392 str
= new ASCIIHexEncoder(str
);
2394 str
= new ASCII85Encoder(str
);
2397 // compute image data size
2403 } while (c
== '\n' || c
== '\r');
2404 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2411 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2414 } while (c
== '\n' || c
== '\r');
2415 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2425 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2427 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size
, id
.num
, id
.gen
);
2430 // write the data into the array
2433 writePS((char *)(useASCIIHex
? "dup 0 <" : "dup 0 <~"));
2437 } while (c
== '\n' || c
== '\r');
2438 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2447 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
2450 } while (c
== '\n' || c
== '\r');
2451 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
2458 // each line is: "dup nnnnn <~...data...~> put<eol>"
2459 // so max data length = 255 - 20 = 235
2460 // chunks are 1 or 4 bytes each, so we have to stop at 232
2461 // but make it 225 just to be safe
2463 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2465 writePSFmt((char *)(useASCIIHex
? "dup %d <" : "dup %d <~"), line
);
2468 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
2469 writePS((char *)(useASCIIHex
? "> put\n" : "~> put\n"));
2476 GBool
PSOutputDev::startPage(int pageNum
, GfxState
*state
) {
2477 int x1
, y1
, x2
, y2
, width
, height
;
2478 int imgWidth
, imgHeight
, imgWidth2
, imgHeight2
;
2482 if (mode
== psModePS
) {
2483 writePSFmt("%%%%Page: %d %d\n", pageNum
, seqPage
);
2484 writePS("%%BeginPageSetup\n");
2489 (*underlayCbk
)(this, underlayCbkData
);
2498 // rotate, translate, and scale page
2499 imgWidth
= imgURX
- imgLLX
;
2500 imgHeight
= imgURY
- imgLLY
;
2501 x1
= (int)floor(state
->getX1());
2502 y1
= (int)floor(state
->getY1());
2503 x2
= (int)ceil(state
->getX2());
2504 y2
= (int)ceil(state
->getY2());
2508 // rotation and portrait/landscape mode
2510 rotate
= (360 - rotate0
) % 360;
2513 rotate
= (360 - state
->getRotate()) % 360;
2515 fprintf(stderr
, "DEBUG: Page rotate=%d, width=%d, height=%d, imgWidth=%d, imgHeight=%d\n",
2516 state
->getRotate(), width
, height
, imgWidth
, imgHeight
);
2518 rotate
= (360 - state
->getRotate()) % 360;
2519 if (rotate
== 0 || rotate
== 180) {
2520 if (width
> height
&& width
> imgWidth
) {
2526 } else { // rotate == 90 || rotate == 270
2527 if (height
> width
&& height
> imgWidth
) {
2528 rotate
= 270 - rotate
;
2536 writePSFmt("%%%%PageOrientation: %s\n",
2537 landscape
? "Landscape" : "Portrait");
2538 writePS("pdfStartPage\n");
2540 imgWidth2
= imgWidth
;
2541 imgHeight2
= imgHeight
;
2542 } else if (rotate
== 90) {
2543 writePS("90 rotate\n");
2545 imgWidth2
= imgHeight
;
2546 imgHeight2
= imgWidth
;
2547 } else if (rotate
== 180) {
2548 writePS("180 rotate\n");
2549 imgWidth2
= imgWidth
;
2550 imgHeight2
= imgHeight
;
2553 } else { // rotate == 270
2554 writePS("270 rotate\n");
2556 imgWidth2
= imgHeight
;
2557 imgHeight2
= imgWidth
;
2560 if (xScale0
> 0 && yScale0
> 0) {
2563 } else if ((globalParams
->getPSShrinkLarger() &&
2564 (width
> imgWidth2
|| height
> imgHeight2
)) ||
2565 (globalParams
->getPSExpandSmaller() &&
2566 (width
< imgWidth2
&& height
< imgHeight2
))) {
2567 xScale
= (double)imgWidth2
/ (double)width
;
2568 yScale
= (double)imgHeight2
/ (double)height
;
2569 if (yScale
< xScale
) {
2575 xScale
= yScale
= 1;
2577 paperHeight
= height
;
2580 // deal with odd bounding boxes or clipping
2581 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2582 tx
-= xScale
* clipLLX0
;
2583 ty
-= yScale
* clipLLY0
;
2589 if (globalParams
->getPSCenter()) {
2590 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2591 tx
+= (imgWidth2
- xScale
* (clipURX0
- clipLLX0
)) / 2;
2592 ty
+= (imgHeight2
- yScale
* (clipURY0
- clipLLY0
)) / 2;
2594 tx
+= (imgWidth2
- xScale
* width
) / 2;
2595 ty
+= (imgHeight2
- yScale
* height
) / 2;
2598 tx
+= rotate
== 0 ? imgLLX
+ tx0
: imgLLY
+ ty0
;
2599 ty
+= rotate
== 0 ? imgLLY
+ ty0
: -(imgLLX
+ tx0
);
2600 if (tx
!= 0 || ty
!= 0) {
2601 writePSFmt("%g %g translate\n", tx
, ty
);
2603 if (xScale
!= 1 || yScale
!= 1) {
2604 writePSFmt("%0.4f %0.4f scale\n", xScale
, xScale
);
2606 if (clipLLX0
< clipURX0
&& clipLLY0
< clipURY0
) {
2607 writePSFmt("%g %g %g %g re W\n",
2608 clipLLX0
, clipLLY0
, clipURX0
- clipLLX0
, clipURY0
- clipLLY0
);
2610 writePSFmt("%d %d %d %d re W\n", x1
, y1
, x2
- x1
, y2
- y1
);
2613 writePS("%%EndPageSetup\n");
2618 writePS("pdfStartPage\n");
2620 rotate
= (360 - state
->getRotate()) % 360;
2622 } else if (rotate
== 90) {
2623 writePS("90 rotate\n");
2626 } else if (rotate
== 180) {
2627 writePS("180 rotate\n");
2628 tx
= -(epsX1
+ epsX2
);
2629 ty
= -(epsY1
+ epsY2
);
2630 } else { // rotate == 270
2631 writePS("270 rotate\n");
2635 if (tx
!= 0 || ty
!= 0) {
2636 writePSFmt("%g %g translate\n", tx
, ty
);
2638 xScale
= yScale
= 1;
2642 writePS("/PaintProc {\n");
2643 writePS("begin xpdf begin\n");
2644 writePS("pdfStartPage\n");
2646 xScale
= yScale
= 1;
2651 if (!checkRange(pageNum
))
2657 void PSOutputDev::endPage() {
2660 (*overlayCbk
)(this, overlayCbkData
);
2663 if (mode
== psModeForm
) {
2664 writePS("pdfEndPage\n");
2665 writePS("end end\n");
2667 writePS("end end\n");
2670 writePS("showpage\n");
2672 writePS("%%PageTrailer\n");
2677 void PSOutputDev::saveState(GfxState
*state
) {
2682 void PSOutputDev::restoreState(GfxState
*state
) {
2687 void PSOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
2688 double m21
, double m22
, double m31
, double m32
) {
2689 writePSFmt("[%g %g %g %g %g %g] cm\n", m11
, m12
, m21
, m22
, m31
, m32
);
2692 void PSOutputDev::updateLineDash(GfxState
*state
) {
2697 state
->getLineDash(&dash
, &length
, &start
);
2699 for (i
= 0; i
< length
; ++i
) {
2701 dash
[i
] == 0 ? 1 : dash
[i
],
2702 (i
== length
-1) ? "" : " ");
2704 writePSFmt("] %g d\n", start
);
2707 void PSOutputDev::updateFlatness(GfxState
*state
) {
2708 writePSFmt("%d i\n", state
->getFlatness());
2711 void PSOutputDev::updateLineJoin(GfxState
*state
) {
2712 writePSFmt("%d j\n", state
->getLineJoin());
2715 void PSOutputDev::updateLineCap(GfxState
*state
) {
2716 writePSFmt("%d J\n", state
->getLineCap());
2719 void PSOutputDev::updateMiterLimit(GfxState
*state
) {
2720 writePSFmt("%g M\n", state
->getMiterLimit());
2723 void PSOutputDev::updateLineWidth(GfxState
*state
) {
2724 writePSFmt("%g w\n", state
->getLineWidth());
2727 void PSOutputDev::updateFillColorSpace(GfxState
*state
) {
2734 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2735 dumpColorSpaceL2(state
->getFillColorSpace(), gTrue
, gFalse
);
2745 void PSOutputDev::updateStrokeColorSpace(GfxState
*state
) {
2752 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2753 dumpColorSpaceL2(state
->getStrokeColorSpace(), gTrue
, gFalse
);
2763 void PSOutputDev::updateFillColor(GfxState
*state
) {
2768 GfxSeparationColorSpace
*sepCS
;
2774 state
->getFillGray(&gray
);
2775 writePSFmt("%g g\n", colToDbl(gray
));
2778 state
->getFillCMYK(&cmyk
);
2779 c
= colToDbl(cmyk
.c
);
2780 m
= colToDbl(cmyk
.m
);
2781 y
= colToDbl(cmyk
.y
);
2782 k
= colToDbl(cmyk
.k
);
2783 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2784 addProcessColor(c
, m
, y
, k
);
2788 if (state
->getFillColorSpace()->getMode() != csPattern
) {
2789 colorPtr
= state
->getFillColor();
2791 for (i
= 0; i
< state
->getFillColorSpace()->getNComps(); ++i
) {
2795 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2802 if (state
->getFillColorSpace()->getMode() == csSeparation
) {
2803 sepCS
= (GfxSeparationColorSpace
*)state
->getFillColorSpace();
2804 color
.c
[0] = gfxColorComp1
;
2805 sepCS
->getCMYK(&color
, &cmyk
);
2806 writePSFmt("%g %g %g %g %g (%s) ck\n",
2807 colToDbl(state
->getFillColor()->c
[0]),
2808 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2809 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2810 sepCS
->getName()->getCString());
2811 addCustomColor(sepCS
);
2813 state
->getFillCMYK(&cmyk
);
2814 c
= colToDbl(cmyk
.c
);
2815 m
= colToDbl(cmyk
.m
);
2816 y
= colToDbl(cmyk
.y
);
2817 k
= colToDbl(cmyk
.k
);
2818 writePSFmt("%g %g %g %g k\n", c
, m
, y
, k
);
2819 addProcessColor(c
, m
, y
, k
);
2823 t3Cacheable
= gFalse
;
2826 void PSOutputDev::updateStrokeColor(GfxState
*state
) {
2831 GfxSeparationColorSpace
*sepCS
;
2837 state
->getStrokeGray(&gray
);
2838 writePSFmt("%g G\n", colToDbl(gray
));
2841 state
->getStrokeCMYK(&cmyk
);
2842 c
= colToDbl(cmyk
.c
);
2843 m
= colToDbl(cmyk
.m
);
2844 y
= colToDbl(cmyk
.y
);
2845 k
= colToDbl(cmyk
.k
);
2846 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2847 addProcessColor(c
, m
, y
, k
);
2851 if (state
->getStrokeColorSpace()->getMode() != csPattern
) {
2852 colorPtr
= state
->getStrokeColor();
2854 for (i
= 0; i
< state
->getStrokeColorSpace()->getNComps(); ++i
) {
2858 writePSFmt("%g", colToDbl(colorPtr
->c
[i
]));
2865 if (state
->getStrokeColorSpace()->getMode() == csSeparation
) {
2866 sepCS
= (GfxSeparationColorSpace
*)state
->getStrokeColorSpace();
2867 color
.c
[0] = gfxColorComp1
;
2868 sepCS
->getCMYK(&color
, &cmyk
);
2869 writePSFmt("%g %g %g %g %g (%s) CK\n",
2870 colToDbl(state
->getStrokeColor()->c
[0]),
2871 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2872 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2873 sepCS
->getName()->getCString());
2874 addCustomColor(sepCS
);
2876 state
->getStrokeCMYK(&cmyk
);
2877 c
= colToDbl(cmyk
.c
);
2878 m
= colToDbl(cmyk
.m
);
2879 y
= colToDbl(cmyk
.y
);
2880 k
= colToDbl(cmyk
.k
);
2881 writePSFmt("%g %g %g %g K\n", c
, m
, y
, k
);
2882 addProcessColor(c
, m
, y
, k
);
2886 t3Cacheable
= gFalse
;
2889 void PSOutputDev::addProcessColor(double c
, double m
, double y
, double k
) {
2891 processColors
|= psProcessCyan
;
2894 processColors
|= psProcessMagenta
;
2897 processColors
|= psProcessYellow
;
2900 processColors
|= psProcessBlack
;
2904 void PSOutputDev::addCustomColor(GfxSeparationColorSpace
*sepCS
) {
2905 PSOutCustomColor
*cc
;
2909 for (cc
= customColors
; cc
; cc
= cc
->next
) {
2910 if (!cc
->name
->cmp(sepCS
->getName())) {
2914 color
.c
[0] = gfxColorComp1
;
2915 sepCS
->getCMYK(&color
, &cmyk
);
2916 cc
= new PSOutCustomColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
2917 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
2918 sepCS
->getName()->copy());
2919 cc
->next
= customColors
;
2923 void PSOutputDev::updateFillOverprint(GfxState
*state
) {
2924 if (level
>= psLevel2
) {
2925 writePSFmt("%s op\n", state
->getFillOverprint() ? "true" : "false");
2929 void PSOutputDev::updateStrokeOverprint(GfxState
*state
) {
2930 if (level
>= psLevel2
) {
2931 writePSFmt("%s OP\n", state
->getStrokeOverprint() ? "true" : "false");
2935 void PSOutputDev::updateFont(GfxState
*state
) {
2936 if (state
->getFont()) {
2937 writePSFmt("/F%d_%d %g Tf\n",
2938 state
->getFont()->getID()->num
, state
->getFont()->getID()->gen
,
2939 fabs(state
->getFontSize()) < 0.00001 ? 0.00001
2940 : state
->getFontSize());
2944 void PSOutputDev::updateTextMat(GfxState
*state
) {
2947 mat
= state
->getTextMat();
2948 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.00001) {
2949 // avoid a singular (or close-to-singular) matrix
2950 writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat
[4], mat
[5]);
2952 writePSFmt("[%g %g %g %g %g %g] Tm\n",
2953 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
2957 void PSOutputDev::updateCharSpace(GfxState
*state
) {
2958 writePSFmt("%g Tc\n", state
->getCharSpace());
2961 void PSOutputDev::updateRender(GfxState
*state
) {
2964 rm
= state
->getRender();
2965 writePSFmt("%d Tr\n", rm
);
2967 if (rm
!= 0 && rm
!= 3) {
2968 t3Cacheable
= gFalse
;
2972 void PSOutputDev::updateRise(GfxState
*state
) {
2973 writePSFmt("%g Ts\n", state
->getRise());
2976 void PSOutputDev::updateWordSpace(GfxState
*state
) {
2977 writePSFmt("%g Tw\n", state
->getWordSpace());
2980 void PSOutputDev::updateHorizScaling(GfxState
*state
) {
2983 h
= state
->getHorizScaling();
2984 if (fabs(h
) < 0.01) {
2987 writePSFmt("%g Tz\n", h
);
2990 void PSOutputDev::updateTextPos(GfxState
*state
) {
2991 writePSFmt("%g %g Td\n", state
->getLineX(), state
->getLineY());
2994 void PSOutputDev::updateTextShift(GfxState
*state
, double shift
) {
2995 if (state
->getFont()->getWMode()) {
2996 writePSFmt("%g TJmV\n", shift
);
2998 writePSFmt("%g TJm\n", shift
);
3002 void PSOutputDev::stroke(GfxState
*state
) {
3003 doPath(state
->getPath());
3005 // if we're construct a cacheable Type 3 glyph, we need to do
3006 // everything in the fill color
3013 void PSOutputDev::fill(GfxState
*state
) {
3014 doPath(state
->getPath());
3018 void PSOutputDev::eoFill(GfxState
*state
) {
3019 doPath(state
->getPath());
3023 void PSOutputDev::tilingPatternFill(GfxState
*state
, Object
*str
,
3024 int paintType
, Dict
*resDict
,
3025 double *mat
, double *bbox
,
3026 int x0
, int y0
, int x1
, int y1
,
3027 double xStep
, double yStep
) {
3031 // define a Type 3 font
3032 writePS("8 dict begin\n");
3033 writePS("/FontType 3 def\n");
3034 writePS("/FontMatrix [1 0 0 1 0 0] def\n");
3035 writePSFmt("/FontBBox [%g %g %g %g] def\n",
3036 bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3037 writePS("/Encoding 256 array def\n");
3038 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
3039 writePS(" Encoding 120 /x put\n");
3040 writePS("/BuildGlyph {\n");
3041 writePS(" exch /CharProcs get exch\n");
3042 writePS(" 2 copy known not { pop /.notdef } if\n");
3043 writePS(" get exec\n");
3044 writePS("} bind def\n");
3045 writePS("/BuildChar {\n");
3046 writePS(" 1 index /Encoding get exch get\n");
3047 writePS(" 1 index /BuildGlyph get exec\n");
3048 writePS("} bind def\n");
3049 writePS("/CharProcs 1 dict def\n");
3050 writePS("CharProcs begin\n");
3055 gfx
= new Gfx(xref
, this, resDict
, &box
, NULL
);
3057 if (paintType
== 2) {
3058 writePSFmt("%g 0 %g %g %g %g setcachedevice\n",
3059 xStep
, bbox
[0], bbox
[1], bbox
[2], bbox
[3]);
3061 writePSFmt("%g 0 setcharwidth\n", xStep
);
3063 inType3Char
= gTrue
;
3064 ++numTilingPatterns
;
3066 --numTilingPatterns
;
3067 inType3Char
= gFalse
;
3071 writePS("currentdict end\n");
3072 writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns
);
3075 writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns
);
3076 writePSFmt("gsave [%g %g %g %g %g %g] concat\n",
3077 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3078 writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n",
3079 y0
, y1
- 1, x0
* xStep
, yStep
, x0
, x1
- 1);
3080 writePS("grestore\n");
3083 void PSOutputDev::functionShadedFill(GfxState
*state
,
3084 GfxFunctionShading
*shading
) {
3085 double x0
, y0
, x1
, y1
;
3089 shading
->getDomain(&x0
, &y0
, &x1
, &y1
);
3090 mat
= shading
->getMatrix();
3091 writePSFmt("/mat [%g %g %g %g %g %g] def\n",
3092 mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
3093 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3094 if (shading
->getNFuncs() == 1) {
3096 cvtFunction(shading
->getFunc(0));
3099 writePS("/func {\n");
3100 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3101 if (i
< shading
->getNFuncs() - 1) {
3102 writePS("2 copy\n");
3104 cvtFunction(shading
->getFunc(i
));
3106 if (i
< shading
->getNFuncs() - 1) {
3107 writePS("3 1 roll\n");
3112 writePSFmt("%g %g %g %g 0 funcSH\n", x0
, y0
, x1
, y1
);
3115 void PSOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
) {
3116 double xMin
, yMin
, xMax
, yMax
;
3117 double x0
, y0
, x1
, y1
, dx
, dy
, mul
;
3118 double tMin
, tMax
, t
, t0
, t1
;
3121 // get the clip region bbox
3122 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3124 // compute min and max t values, based on the four corners of the
3126 shading
->getCoords(&x0
, &y0
, &x1
, &y1
);
3129 mul
= 1 / (dx
* dx
+ dy
* dy
);
3130 tMin
= tMax
= ((xMin
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3131 t
= ((xMin
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3134 } else if (t
> tMax
) {
3137 t
= ((xMax
- x0
) * dx
+ (yMin
- y0
) * dy
) * mul
;
3140 } else if (t
> tMax
) {
3143 t
= ((xMax
- x0
) * dx
+ (yMax
- y0
) * dy
) * mul
;
3146 } else if (t
> tMax
) {
3149 if (tMin
< 0 && !shading
->getExtend0()) {
3152 if (tMax
> 1 && !shading
->getExtend1()) {
3156 // get the function domain
3157 t0
= shading
->getDomain0();
3158 t1
= shading
->getDomain1();
3160 // generate the PS code
3161 writePSFmt("/t0 %g def\n", t0
);
3162 writePSFmt("/t1 %g def\n", t1
);
3163 writePSFmt("/dt %g def\n", t1
- t0
);
3164 writePSFmt("/x0 %g def\n", x0
);
3165 writePSFmt("/y0 %g def\n", y0
);
3166 writePSFmt("/dx %g def\n", x1
- x0
);
3167 writePSFmt("/x1 %g def\n", x1
);
3168 writePSFmt("/y1 %g def\n", y1
);
3169 writePSFmt("/dy %g def\n", y1
- y0
);
3170 writePSFmt("/xMin %g def\n", xMin
);
3171 writePSFmt("/yMin %g def\n", yMin
);
3172 writePSFmt("/xMax %g def\n", xMax
);
3173 writePSFmt("/yMax %g def\n", yMax
);
3174 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3175 if (shading
->getNFuncs() == 1) {
3177 cvtFunction(shading
->getFunc(0));
3180 writePS("/func {\n");
3181 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3182 if (i
< shading
->getNFuncs() - 1) {
3185 cvtFunction(shading
->getFunc(i
));
3187 if (i
< shading
->getNFuncs() - 1) {
3193 writePSFmt("%g %g 0 axialSH\n", tMin
, tMax
);
3196 void PSOutputDev::radialShadedFill(GfxState
*state
,
3197 GfxRadialShading
*shading
) {
3198 double x0
, y0
, r0
, x1
, y1
, r1
, t0
, t1
, sMin
, sMax
;
3199 double xMin
, yMin
, xMax
, yMax
;
3203 // get the shading info
3204 shading
->getCoords(&x0
, &y0
, &r0
, &x1
, &y1
, &r1
);
3205 t0
= shading
->getDomain0();
3206 t1
= shading
->getDomain1();
3208 // compute the (possibly extended) s range
3211 if (shading
->getExtend0()) {
3213 // extend the smaller end
3214 sMin
= -r0
/ (r1
- r0
);
3216 // extend the larger end
3217 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3218 d0
= (x0
- xMin
) * (x0
- xMin
);
3219 d1
= (x0
- xMax
) * (x0
- xMax
);
3220 sMin
= d0
> d1
? d0
: d1
;
3221 d0
= (y0
- yMin
) * (y0
- yMin
);
3222 d1
= (y0
- yMax
) * (y0
- yMax
);
3223 sMin
+= d0
> d1
? d0
: d1
;
3224 sMin
= (sqrt(sMin
) - r0
) / (r1
- r0
);
3227 } else if (sMin
< -20) {
3233 if (shading
->getExtend1()) {
3235 // extend the smaller end
3236 sMax
= -r0
/ (r1
- r0
);
3237 } else if (r1
> r0
) {
3238 // extend the larger end
3239 state
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
3240 d0
= (x1
- xMin
) * (x1
- xMin
);
3241 d1
= (x1
- xMax
) * (x1
- xMax
);
3242 sMax
= d0
> d1
? d0
: d1
;
3243 d0
= (y1
- yMin
) * (y1
- yMin
);
3244 d1
= (y1
- yMax
) * (y1
- yMax
);
3245 sMax
+= d0
> d1
? d0
: d1
;
3246 sMax
= (sqrt(sMax
) - r0
) / (r1
- r0
);
3249 } else if (sMax
> 20) {
3256 // generate the PS code
3257 writePSFmt("/x0 %g def\n", x0
);
3258 writePSFmt("/x1 %g def\n", x1
);
3259 writePSFmt("/dx %g def\n", x1
- x0
);
3260 writePSFmt("/y0 %g def\n", y0
);
3261 writePSFmt("/y1 %g def\n", y1
);
3262 writePSFmt("/dy %g def\n", y1
- y0
);
3263 writePSFmt("/r0 %g def\n", r0
);
3264 writePSFmt("/r1 %g def\n", r1
);
3265 writePSFmt("/dr %g def\n", r1
- r0
);
3266 writePSFmt("/t0 %g def\n", t0
);
3267 writePSFmt("/t1 %g def\n", t1
);
3268 writePSFmt("/dt %g def\n", t1
- t0
);
3269 writePSFmt("/n %d def\n", shading
->getColorSpace()->getNComps());
3270 if (shading
->getNFuncs() == 1) {
3272 cvtFunction(shading
->getFunc(0));
3275 writePS("/func {\n");
3276 for (i
= 0; i
< shading
->getNFuncs(); ++i
) {
3277 if (i
< shading
->getNFuncs() - 1) {
3280 cvtFunction(shading
->getFunc(i
));
3282 if (i
< shading
->getNFuncs() - 1) {
3288 writePSFmt("%g %g 0 radialSH\n", sMin
, sMax
);
3291 void PSOutputDev::clip(GfxState
*state
) {
3292 doPath(state
->getPath());
3296 void PSOutputDev::eoClip(GfxState
*state
) {
3297 doPath(state
->getPath());
3301 void PSOutputDev::doPath(GfxPath
*path
) {
3302 GfxSubpath
*subpath
;
3303 double x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
3306 n
= path
->getNumSubpaths();
3308 if (n
== 1 && path
->getSubpath(0)->getNumPoints() == 5) {
3309 subpath
= path
->getSubpath(0);
3310 x0
= subpath
->getX(0);
3311 y0
= subpath
->getY(0);
3312 x4
= subpath
->getX(4);
3313 y4
= subpath
->getY(4);
3314 if (x4
== x0
&& y4
== y0
) {
3315 x1
= subpath
->getX(1);
3316 y1
= subpath
->getY(1);
3317 x2
= subpath
->getX(2);
3318 y2
= subpath
->getY(2);
3319 x3
= subpath
->getX(3);
3320 y3
= subpath
->getY(3);
3321 if (x0
== x1
&& x2
== x3
&& y0
== y3
&& y1
== y2
) {
3322 writePSFmt("%g %g %g %g re\n",
3323 x0
< x2
? x0
: x2
, y0
< y1
? y0
: y1
,
3324 fabs(x2
- x0
), fabs(y1
- y0
));
3326 } else if (x0
== x3
&& x1
== x2
&& y0
== y1
&& y2
== y3
) {
3327 writePSFmt("%g %g %g %g re\n",
3328 x0
< x1
? x0
: x1
, y0
< y2
? y0
: y2
,
3329 fabs(x1
- x0
), fabs(y2
- y0
));
3335 for (i
= 0; i
< n
; ++i
) {
3336 subpath
= path
->getSubpath(i
);
3337 m
= subpath
->getNumPoints();
3338 writePSFmt("%g %g m\n", subpath
->getX(0), subpath
->getY(0));
3341 if (subpath
->getCurve(j
)) {
3342 writePSFmt("%g %g %g %g %g %g c\n", subpath
->getX(j
), subpath
->getY(j
),
3343 subpath
->getX(j
+1), subpath
->getY(j
+1),
3344 subpath
->getX(j
+2), subpath
->getY(j
+2));
3347 writePSFmt("%g %g l\n", subpath
->getX(j
), subpath
->getY(j
));
3351 if (subpath
->isClosed()) {
3357 void PSOutputDev::drawString(GfxState
*state
, GString
*s
) {
3361 double dx
, dy
, dx2
, dy2
, originX
, originY
;
3367 int len
, nChars
, uLen
, n
, m
, i
, j
;
3369 // check for invisible text -- this is used by Acrobat Capture
3370 if (state
->getRender() == 3) {
3374 // ignore empty strings
3375 if (s
->getLength() == 0) {
3380 if (!(font
= state
->getFont())) {
3383 wMode
= font
->getWMode();
3385 // check for a subtitute 16-bit font
3387 if (font
->isCIDFont()) {
3388 for (i
= 0; i
< font16EncLen
; ++i
) {
3389 if (font
->getID()->num
== font16Enc
[i
].fontID
.num
&&
3390 font
->getID()->gen
== font16Enc
[i
].fontID
.gen
) {
3391 uMap
= globalParams
->getUnicodeMap(font16Enc
[i
].enc
);
3397 // compute width of chars in string, ignoring char spacing and word
3398 // spacing -- the Tj operator will adjust for the metrics of the
3399 // font that's actually used
3402 p
= s
->getCString();
3403 len
= s
->getLength();
3404 if (font
->isCIDFont()) {
3410 n
= font
->getNextChar(p
, len
, &code
,
3411 u
, (int)(sizeof(u
) / sizeof(Unicode
)), &uLen
,
3412 &dx2
, &dy2
, &originX
, &originY
);
3413 if (font
->isCIDFont()) {
3415 for (i
= 0; i
< uLen
; ++i
) {
3416 m
= uMap
->mapUnicode(u
[i
], buf
, (int)sizeof(buf
));
3417 for (j
= 0; j
< m
; ++j
) {
3421 //~ this really needs to get the number of chars in the target
3422 //~ encoding - which may be more than the number of Unicode
3426 s2
->append((char)((code
>> 8) & 0xff));
3427 s2
->append((char)(code
& 0xff));
3436 dx
*= state
->getFontSize() * state
->getHorizScaling();
3437 dy
*= state
->getFontSize();
3442 if (s2
->getLength() > 0) {
3444 if (font
->isCIDFont()) {
3446 writePSFmt(" %d %g Tj16V\n", nChars
, dy
);
3448 writePSFmt(" %d %g Tj16\n", nChars
, dx
);
3451 writePSFmt(" %g Tj\n", dx
);
3454 if (font
->isCIDFont()) {
3458 if (state
->getRender() & 4) {
3459 haveTextClip
= gTrue
;
3463 void PSOutputDev::endTextObject(GfxState
*state
) {
3466 haveTextClip
= gFalse
;
3470 void PSOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
3471 int width
, int height
, GBool invert
,
3475 len
= height
* ((width
+ 7) / 8);
3476 if (level
== psLevel1
|| level
== psLevel1Sep
) {
3477 doImageL1(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
);
3479 doImageL2(ref
, NULL
, invert
, inlineImg
, str
, width
, height
, len
,
3480 NULL
, NULL
, 0, 0, gFalse
);
3484 void PSOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3485 int width
, int height
, GfxImageColorMap
*colorMap
,
3486 int *maskColors
, GBool inlineImg
) {
3489 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3490 colorMap
->getBits() + 7) / 8);
3493 doImageL1(ref
, colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3496 //~ handle indexed, separation, ... color spaces
3497 doImageL1Sep(colorMap
, gFalse
, inlineImg
, str
, width
, height
, len
);
3503 doImageL2(ref
, colorMap
, gFalse
, inlineImg
, str
,
3504 width
, height
, len
, maskColors
, NULL
, 0, 0, gFalse
);
3507 t3Cacheable
= gFalse
;
3510 void PSOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3511 int width
, int height
,
3512 GfxImageColorMap
*colorMap
,
3514 int maskWidth
, int maskHeight
,
3518 len
= height
* ((width
* colorMap
->getNumPixelComps() *
3519 colorMap
->getBits() + 7) / 8);
3522 doImageL1(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3525 //~ handle indexed, separation, ... color spaces
3526 doImageL1Sep(colorMap
, gFalse
, gFalse
, str
, width
, height
, len
);
3532 doImageL2(ref
, colorMap
, gFalse
, gFalse
, str
, width
, height
, len
,
3533 NULL
, maskStr
, maskWidth
, maskHeight
, maskInvert
);
3536 t3Cacheable
= gFalse
;
3539 void PSOutputDev::doImageL1(Object
*ref
, GfxImageColorMap
*colorMap
,
3540 GBool invert
, GBool inlineImg
,
3541 Stream
*str
, int width
, int height
, int len
) {
3542 ImageStream
*imgStr
;
3543 Guchar pixBuf
[gfxColorMaxComps
];
3545 int col
, x
, y
, c
, i
;
3547 if (inType3Char
&& !colorMap
) {
3550 str
= new FixedLengthEncoder(str
, len
);
3551 str
= new ASCIIHexEncoder(str
);
3558 } while (c
== '\n' || c
== '\r');
3559 if (c
== '>' || c
== EOF
) {
3564 // each line is: "<...data...><eol>"
3565 // so max data length = 255 - 4 = 251
3566 // but make it 240 just to be safe
3567 // chunks are 2 bytes each, so we need to stop on an even col number
3572 } while (c
!= '>' && c
!= EOF
);
3578 // set up to use the array already created by setupImages()
3579 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3583 // image/imagemask command
3584 if (inType3Char
&& !colorMap
) {
3585 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
3586 width
, height
, invert
? "true" : "false",
3587 width
, -height
, height
);
3588 } else if (colorMap
) {
3589 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
3591 width
, -height
, height
);
3593 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
3594 width
, height
, invert
? "true" : "false",
3595 width
, -height
, height
);
3599 if (!(inType3Char
&& !colorMap
)) {
3603 // set up to process the data stream
3604 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3605 colorMap
->getBits());
3608 // process the data stream
3610 for (y
= 0; y
< height
; ++y
) {
3613 for (x
= 0; x
< width
; ++x
) {
3614 imgStr
->getPixel(pixBuf
);
3615 colorMap
->getGray(pixBuf
, &gray
);
3616 writePSFmt("%02x", colToByte(gray
));
3632 for (y
= 0; y
< height
; ++y
) {
3633 for (x
= 0; x
< width
; x
+= 8) {
3634 writePSFmt("%02x", str
->getChar() & 0xff);
3649 void PSOutputDev::doImageL1Sep(GfxImageColorMap
*colorMap
,
3650 GBool invert
, GBool inlineImg
,
3651 Stream
*str
, int width
, int height
, int len
) {
3652 ImageStream
*imgStr
;
3654 Guchar pixBuf
[gfxColorMaxComps
];
3658 // width, height, matrix, bits per component
3659 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
3661 width
, -height
, height
);
3663 // allocate a line buffer
3664 lineBuf
= (Guchar
*)gmalloc(4 * width
);
3666 // set up to process the data stream
3667 imgStr
= new ImageStream(str
, width
, colorMap
->getNumPixelComps(),
3668 colorMap
->getBits());
3671 // process the data stream
3673 for (y
= 0; y
< height
; ++y
) {
3676 for (x
= 0; x
< width
; ++x
) {
3677 imgStr
->getPixel(pixBuf
);
3678 colorMap
->getCMYK(pixBuf
, &cmyk
);
3679 lineBuf
[4*x
+0] = colToByte(cmyk
.c
);
3680 lineBuf
[4*x
+1] = colToByte(cmyk
.m
);
3681 lineBuf
[4*x
+2] = colToByte(cmyk
.y
);
3682 lineBuf
[4*x
+3] = colToByte(cmyk
.k
);
3683 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
3684 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
3687 // write one line of each color component
3688 for (comp
= 0; comp
< 4; ++comp
) {
3689 for (x
= 0; x
< width
; ++x
) {
3690 writePSFmt("%02x", lineBuf
[4*x
+ comp
]);
3707 void PSOutputDev::doImageL2(Object
*ref
, GfxImageColorMap
*colorMap
,
3708 GBool invert
, GBool inlineImg
,
3709 Stream
*str
, int width
, int height
, int len
,
3710 int *maskColors
, Stream
*maskStr
,
3711 int maskWidth
, int maskHeight
, GBool maskInvert
) {
3712 ImageStream
*imgStr
;
3716 GBool useRLE
, useASCII
, useASCIIHex
, useCompressed
;
3717 GfxSeparationColorSpace
*sepCS
;
3721 int col
, i
, x
, x0
, y
, y0
, maskXor
;
3723 // color key masking
3724 if (maskColors
&& colorMap
&& !inlineImg
) {
3725 // can't read the stream twice for inline images -- but masking
3726 // isn't allowed with inline images anyway
3728 numComps
= colorMap
->getNumPixelComps();
3729 imgStr
= new ImageStream(str
, width
, numComps
, colorMap
->getBits());
3731 for (y
= 0, y0
= 0; y
< height
; ++y
) {
3732 if (!(line
= imgStr
->getLine())) {
3735 for (x
= 0, x0
= 0, pix
= line
; x
< width
; ++x
, pix
+= numComps
) {
3736 for (i
= 0; i
< numComps
; ++i
) {
3737 if (pix
[i
] < maskColors
[2*i
] ||
3738 pix
[i
] > maskColors
[2*i
+1]) {
3742 if (i
== numComps
) {
3744 writePSFmt("0 %d %d %d\n", height
- y
, width
, y
- y0
);
3747 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, x
- x0
);
3753 if (x0
> 0 && x0
< width
) {
3754 writePSFmt("%d %d %d 1\n", x0
, height
- y
- 1, width
- x0
);
3758 writePSFmt("0 0 %d %d\n", width
, height
- y0
);
3762 writePSFmt("] %d %d pdfImClip\n", width
, height
);
3765 } else if (maskStr
) {
3767 imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3769 maskXor
= maskInvert
? 1 : 0;
3770 for (y
= 0, y0
= 0; y
< maskHeight
; ++y
) {
3771 if (!(line
= imgStr
->getLine())) {
3774 for (x
= 0, x0
= 0, pix
= line
; x
< maskWidth
; ++x
, ++pix
) {
3775 if (*pix
^ maskXor
) {
3777 writePSFmt("0 %d %d %d\n", maskHeight
- y
, maskWidth
, y
- y0
);
3780 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, x
- x0
);
3786 if (x0
> 0 && x0
< maskWidth
) {
3787 writePSFmt("%d %d %d 1\n", x0
, maskHeight
- y
- 1, maskWidth
- x0
);
3790 if (y0
< maskHeight
) {
3791 writePSFmt("0 0 %d %d\n", maskWidth
, maskHeight
- y0
);
3795 writePSFmt("] %d %d pdfImClip\n", maskWidth
, maskHeight
);
3800 dumpColorSpaceL2(colorMap
->getColorSpace(), gFalse
, gTrue
);
3801 writePS(" setcolorspace\n");
3804 useASCIIHex
= globalParams
->getPSASCIIHex();
3806 // set up the image data
3807 if (mode
== psModeForm
|| inType3Char
) {
3810 str
= new FixedLengthEncoder(str
, len
);
3812 str
= new ASCIIHexEncoder(str
);
3814 str
= new ASCII85Encoder(str
);
3818 writePS((char *)(useASCIIHex
? "[<" : "[<~"));
3822 } while (c
== '\n' || c
== '\r');
3823 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3832 for (i
= 1; i
<= (useASCIIHex
? 1 : 4); ++i
) {
3835 } while (c
== '\n' || c
== '\r');
3836 if (c
== (useASCIIHex
? '>' : '~') || c
== EOF
) {
3843 // each line is: "<~...data...~><eol>"
3844 // so max data length = 255 - 6 = 249
3845 // chunks are 1 or 5 bytes each, so we have to stop at 245
3846 // but make it 240 just to be safe
3848 writePS((char *)(useASCIIHex
? ">\n<" : "~>\n<~"));
3851 } while (c
!= (useASCIIHex
? '>' : '~') && c
!= EOF
);
3852 writePS((char *)(useASCIIHex
? ">]\n" : "~>]\n"));
3857 // set up to use the array already created by setupImages()
3858 writePSFmt("ImData_%d_%d 0\n", ref
->getRefNum(), ref
->getRefGen());
3863 writePS("<<\n /ImageType 1\n");
3865 // width, height, matrix, bits per component
3866 writePSFmt(" /Width %d\n", width
);
3867 writePSFmt(" /Height %d\n", height
);
3868 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width
, -height
, height
);
3869 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3870 writePSFmt(" /BitsPerComponent 8\n");
3872 writePSFmt(" /BitsPerComponent %d\n",
3873 colorMap
? colorMap
->getBits() : 1);
3878 writePS(" /Decode [");
3879 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) &&
3880 colorMap
->getColorSpace()->getMode() == csSeparation
) {
3881 // this matches up with the code in the pdfImSep operator
3882 n
= (1 << colorMap
->getBits()) - 1;
3883 writePSFmt("%g %g", colorMap
->getDecodeLow(0) * n
,
3884 colorMap
->getDecodeHigh(0) * n
);
3885 } else if (colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3886 numComps
= ((GfxDeviceNColorSpace
*)colorMap
->getColorSpace())->
3887 getAlt()->getNComps();
3888 for (i
= 0; i
< numComps
; ++i
) {
3895 numComps
= colorMap
->getNumPixelComps();
3896 for (i
= 0; i
< numComps
; ++i
) {
3900 writePSFmt("%g %g", colorMap
->getDecodeLow(i
),
3901 colorMap
->getDecodeHigh(i
));
3906 writePSFmt(" /Decode [%d %d]\n", invert
? 1 : 0, invert
? 0 : 1);
3909 if (mode
== psModeForm
|| inType3Char
) {
3912 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
3914 // end of image dictionary
3915 writePSFmt(">>\n%s\n", colorMap
? "image" : "imagemask");
3917 // get rid of the array and index
3918 writePS("pop pop\n");
3923 writePS(" /DataSource currentfile\n");
3924 s
= str
->getPSFilter(level
< psLevel2
? 1 : level
< psLevel3
? 2 : 3,
3926 if ((colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) ||
3930 useCompressed
= gFalse
;
3933 useASCII
= str
->isBinary();
3934 useCompressed
= gTrue
;
3937 writePSFmt(" /ASCII%sDecode filter\n",
3938 useASCIIHex
? "Hex" : "85");
3941 writePS(" /RunLengthDecode filter\n");
3943 if (useCompressed
) {
3944 writePS(s
->getCString());
3950 // cut off inline image streams at appropriate length
3952 str
= new FixedLengthEncoder(str
, len
);
3953 } else if (useCompressed
) {
3954 str
= str
->getBaseStream();
3957 // recode DeviceN data
3958 if (colorMap
&& colorMap
->getColorSpace()->getMode() == csDeviceN
) {
3959 str
= new DeviceNRecoder(str
, width
, height
, colorMap
);
3962 // add RunLengthEncode and ASCIIHex/85 encode filters
3964 str
= new RunLengthEncoder(str
);
3968 str
= new ASCIIHexEncoder(str
);
3970 str
= new ASCII85Encoder(str
);
3974 // end of image dictionary
3979 // this can't happen -- OPI dictionaries are in XObjects
3980 error(-1, "Internal: OPI in inline image");
3983 // need to read the stream to count characters -- the length
3984 // is data-dependent (because of ASCII and RLE filters)
3987 while ((c
= str
->getChar()) != EOF
) {
3992 // +6/7 for "pdfIm\n" / "pdfImM\n"
3993 // +8 for newline + trailer
3994 n
+= colorMap
? 14 : 15;
3995 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n
);
3998 if ((level
== psLevel2Sep
|| level
== psLevel3Sep
) && colorMap
&&
3999 colorMap
->getColorSpace()->getMode() == csSeparation
) {
4000 color
.c
[0] = gfxColorComp1
;
4001 sepCS
= (GfxSeparationColorSpace
*)colorMap
->getColorSpace();
4002 sepCS
->getCMYK(&color
, &cmyk
);
4003 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
4004 colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4005 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
),
4006 sepCS
->getName()->getCString());
4008 writePSFmt("%s\n", colorMap
? "pdfIm" : "pdfImM");
4011 // copy the stream data
4013 while ((c
= str
->getChar()) != EOF
) {
4018 // add newline and trailer to the end
4020 writePS("%-EOD-\n");
4023 writePS("%%EndData\n");
4028 if (useRLE
|| useASCII
|| inlineImg
) {
4033 if ((maskColors
&& colorMap
&& !inlineImg
) || maskStr
) {
4034 writePS("pdfImClipEnd\n");
4038 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace
*colorSpace
,
4039 GBool genXform
, GBool updateColors
) {
4040 GfxCalGrayColorSpace
*calGrayCS
;
4041 GfxCalRGBColorSpace
*calRGBCS
;
4042 GfxLabColorSpace
*labCS
;
4043 GfxIndexedColorSpace
*indexedCS
;
4044 GfxSeparationColorSpace
*separationCS
;
4045 GfxDeviceNColorSpace
*deviceNCS
;
4046 GfxColorSpace
*baseCS
;
4048 double x
[gfxColorMaxComps
], y
[gfxColorMaxComps
];
4052 int n
, numComps
, numAltComps
;
4056 switch (colorSpace
->getMode()) {
4059 writePS("/DeviceGray");
4064 processColors
|= psProcessBlack
;
4069 calGrayCS
= (GfxCalGrayColorSpace
*)colorSpace
;
4070 writePS("[/CIEBasedA <<\n");
4071 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS
->getGamma());
4072 writePSFmt(" /MatrixA [%g %g %g]\n",
4073 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4074 calGrayCS
->getWhiteZ());
4075 writePSFmt(" /WhitePoint [%g %g %g]\n",
4076 calGrayCS
->getWhiteX(), calGrayCS
->getWhiteY(),
4077 calGrayCS
->getWhiteZ());
4078 writePSFmt(" /BlackPoint [%g %g %g]\n",
4079 calGrayCS
->getBlackX(), calGrayCS
->getBlackY(),
4080 calGrayCS
->getBlackZ());
4086 processColors
|= psProcessBlack
;
4091 writePS("/DeviceRGB");
4096 processColors
|= psProcessCMYK
;
4101 calRGBCS
= (GfxCalRGBColorSpace
*)colorSpace
;
4102 writePS("[/CIEBasedABC <<\n");
4103 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
4104 calRGBCS
->getGammaR(), calRGBCS
->getGammaG(),
4105 calRGBCS
->getGammaB());
4106 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
4107 calRGBCS
->getMatrix()[0], calRGBCS
->getMatrix()[1],
4108 calRGBCS
->getMatrix()[2], calRGBCS
->getMatrix()[3],
4109 calRGBCS
->getMatrix()[4], calRGBCS
->getMatrix()[5],
4110 calRGBCS
->getMatrix()[6], calRGBCS
->getMatrix()[7],
4111 calRGBCS
->getMatrix()[8]);
4112 writePSFmt(" /WhitePoint [%g %g %g]\n",
4113 calRGBCS
->getWhiteX(), calRGBCS
->getWhiteY(),
4114 calRGBCS
->getWhiteZ());
4115 writePSFmt(" /BlackPoint [%g %g %g]\n",
4116 calRGBCS
->getBlackX(), calRGBCS
->getBlackY(),
4117 calRGBCS
->getBlackZ());
4123 processColors
|= psProcessCMYK
;
4128 writePS("/DeviceCMYK");
4133 processColors
|= psProcessCMYK
;
4138 labCS
= (GfxLabColorSpace
*)colorSpace
;
4139 writePS("[/CIEBasedABC <<\n");
4140 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
4141 labCS
->getAMin(), labCS
->getAMax(),
4142 labCS
->getBMin(), labCS
->getBMax());
4143 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
4144 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
4145 writePS(" /DecodeLMN\n");
4146 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
4147 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4148 labCS
->getWhiteX());
4149 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4150 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
4151 labCS
->getWhiteY());
4152 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
4153 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
4154 labCS
->getWhiteZ());
4155 writePSFmt(" /WhitePoint [%g %g %g]\n",
4156 labCS
->getWhiteX(), labCS
->getWhiteY(), labCS
->getWhiteZ());
4157 writePSFmt(" /BlackPoint [%g %g %g]\n",
4158 labCS
->getBlackX(), labCS
->getBlackY(), labCS
->getBlackZ());
4164 processColors
|= psProcessCMYK
;
4169 // there is no transform function to the alternate color space, so
4170 // we can use it directly
4171 dumpColorSpaceL2(((GfxICCBasedColorSpace
*)colorSpace
)->getAlt(),
4172 genXform
, updateColors
);
4176 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
4177 baseCS
= indexedCS
->getBase();
4178 writePS("[/Indexed ");
4179 dumpColorSpaceL2(baseCS
, gFalse
, gFalse
);
4180 n
= indexedCS
->getIndexHigh();
4181 numComps
= baseCS
->getNComps();
4182 lookup
= indexedCS
->getLookup();
4183 writePSFmt(" %d <\n", n
);
4184 if (baseCS
->getMode() == csDeviceN
) {
4185 func
= ((GfxDeviceNColorSpace
*)baseCS
)->getTintTransformFunc();
4186 numAltComps
= ((GfxDeviceNColorSpace
*)baseCS
)->getAlt()->getNComps();
4188 for (i
= 0; i
<= n
; i
+= 8) {
4190 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4191 for (k
= 0; k
< numComps
; ++k
) {
4192 x
[k
] = *p
++ / 255.0;
4194 func
->transform(x
, y
);
4195 for (k
= 0; k
< numAltComps
; ++k
) {
4196 byte
= (int)(y
[k
] * 255 + 0.5);
4199 } else if (byte
> 255) {
4202 writePSFmt("%02x", byte
);
4205 color
.c
[0] = dblToCol(j
);
4206 indexedCS
->getCMYK(&color
, &cmyk
);
4207 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4208 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4214 for (i
= 0; i
<= n
; i
+= 8) {
4216 for (j
= i
; j
< i
+8 && j
<= n
; ++j
) {
4217 for (k
= 0; k
< numComps
; ++k
) {
4218 writePSFmt("%02x", lookup
[j
* numComps
+ k
]);
4221 color
.c
[0] = dblToCol(j
);
4222 indexedCS
->getCMYK(&color
, &cmyk
);
4223 addProcessColor(colToDbl(cmyk
.c
), colToDbl(cmyk
.m
),
4224 colToDbl(cmyk
.y
), colToDbl(cmyk
.k
));
4237 separationCS
= (GfxSeparationColorSpace
*)colorSpace
;
4238 writePS("[/Separation /");
4239 writePSName(separationCS
->getName()->getCString());
4241 dumpColorSpaceL2(separationCS
->getAlt(), gFalse
, gFalse
);
4243 cvtFunction(separationCS
->getFunc());
4249 addCustomColor(separationCS
);
4254 // DeviceN color spaces are a Level 3 PostScript feature.
4255 deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
4256 dumpColorSpaceL2(deviceNCS
->getAlt(), gFalse
, updateColors
);
4259 cvtFunction(deviceNCS
->getTintTransformFunc());
4270 void PSOutputDev::opiBegin(GfxState
*state
, Dict
*opiDict
) {
4273 if (globalParams
->getPSOPI()) {
4274 opiDict
->lookup("2.0", &dict
);
4275 if (dict
.isDict()) {
4276 opiBegin20(state
, dict
.getDict());
4280 opiDict
->lookup("1.3", &dict
);
4281 if (dict
.isDict()) {
4282 opiBegin13(state
, dict
.getDict());
4289 void PSOutputDev::opiBegin20(GfxState
*state
, Dict
*dict
) {
4290 Object obj1
, obj2
, obj3
, obj4
;
4291 double width
, height
, left
, right
, top
, bottom
;
4295 writePS("%%BeginOPI: 2.0\n");
4296 writePS("%%Distilled\n");
4298 dict
->lookup("F", &obj1
);
4299 if (getFileSpec(&obj1
, &obj2
)) {
4300 writePSFmt("%%%%ImageFileName: %s\n",
4301 obj2
.getString()->getCString());
4306 dict
->lookup("MainImage", &obj1
);
4307 if (obj1
.isString()) {
4308 writePSFmt("%%%%MainImage: %s\n", obj1
.getString()->getCString());
4312 //~ ignoring 'Tags' entry
4313 //~ need to use writePSString() and deal with >255-char lines
4315 dict
->lookup("Size", &obj1
);
4316 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4317 obj1
.arrayGet(0, &obj2
);
4318 width
= obj2
.getNum();
4320 obj1
.arrayGet(1, &obj2
);
4321 height
= obj2
.getNum();
4323 writePSFmt("%%%%ImageDimensions: %g %g\n", width
, height
);
4327 dict
->lookup("CropRect", &obj1
);
4328 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4329 obj1
.arrayGet(0, &obj2
);
4330 left
= obj2
.getNum();
4332 obj1
.arrayGet(1, &obj2
);
4333 top
= obj2
.getNum();
4335 obj1
.arrayGet(2, &obj2
);
4336 right
= obj2
.getNum();
4338 obj1
.arrayGet(3, &obj2
);
4339 bottom
= obj2
.getNum();
4341 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left
, top
, right
, bottom
);
4345 dict
->lookup("Overprint", &obj1
);
4346 if (obj1
.isBool()) {
4347 writePSFmt("%%%%ImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4351 dict
->lookup("Inks", &obj1
);
4352 if (obj1
.isName()) {
4353 writePSFmt("%%%%ImageInks: %s\n", obj1
.getName());
4354 } else if (obj1
.isArray() && obj1
.arrayGetLength() >= 1) {
4355 obj1
.arrayGet(0, &obj2
);
4356 if (obj2
.isName()) {
4357 writePSFmt("%%%%ImageInks: %s %d",
4358 obj2
.getName(), (obj1
.arrayGetLength() - 1) / 2);
4359 for (i
= 1; i
+1 < obj1
.arrayGetLength(); i
+= 2) {
4360 obj1
.arrayGet(i
, &obj3
);
4361 obj1
.arrayGet(i
+1, &obj4
);
4362 if (obj3
.isString() && obj4
.isNum()) {
4364 writePSString(obj3
.getString());
4365 writePSFmt(" %g", obj4
.getNum());
4378 writePS("%%BeginIncludedImage\n");
4380 dict
->lookup("IncludedImageDimensions", &obj1
);
4381 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4382 obj1
.arrayGet(0, &obj2
);
4385 obj1
.arrayGet(1, &obj2
);
4388 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w
, h
);
4392 dict
->lookup("IncludedImageQuality", &obj1
);
4394 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1
.getNum());
4401 void PSOutputDev::opiBegin13(GfxState
*state
, Dict
*dict
) {
4403 int left
, right
, top
, bottom
, samples
, bits
, width
, height
;
4405 double llx
, lly
, ulx
, uly
, urx
, ury
, lrx
, lry
;
4406 double tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
;
4411 writePS("/opiMatrix2 matrix currentmatrix def\n");
4412 writePS("opiMatrix setmatrix\n");
4414 dict
->lookup("F", &obj1
);
4415 if (getFileSpec(&obj1
, &obj2
)) {
4416 writePSFmt("%%ALDImageFileName: %s\n",
4417 obj2
.getString()->getCString());
4422 dict
->lookup("CropRect", &obj1
);
4423 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
4424 obj1
.arrayGet(0, &obj2
);
4425 left
= obj2
.getInt();
4427 obj1
.arrayGet(1, &obj2
);
4428 top
= obj2
.getInt();
4430 obj1
.arrayGet(2, &obj2
);
4431 right
= obj2
.getInt();
4433 obj1
.arrayGet(3, &obj2
);
4434 bottom
= obj2
.getInt();
4436 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left
, top
, right
, bottom
);
4440 dict
->lookup("Color", &obj1
);
4441 if (obj1
.isArray() && obj1
.arrayGetLength() == 5) {
4442 obj1
.arrayGet(0, &obj2
);
4445 obj1
.arrayGet(1, &obj2
);
4448 obj1
.arrayGet(2, &obj2
);
4451 obj1
.arrayGet(3, &obj2
);
4454 obj1
.arrayGet(4, &obj2
);
4455 if (obj2
.isString()) {
4456 writePSFmt("%%ALDImageColor: %g %g %g %g ", c
, m
, y
, k
);
4457 writePSString(obj2
.getString());
4464 dict
->lookup("ColorType", &obj1
);
4465 if (obj1
.isName()) {
4466 writePSFmt("%%ALDImageColorType: %s\n", obj1
.getName());
4470 //~ ignores 'Comments' entry
4471 //~ need to handle multiple lines
4473 dict
->lookup("CropFixed", &obj1
);
4474 if (obj1
.isArray()) {
4475 obj1
.arrayGet(0, &obj2
);
4476 ulx
= obj2
.getNum();
4478 obj1
.arrayGet(1, &obj2
);
4479 uly
= obj2
.getNum();
4481 obj1
.arrayGet(2, &obj2
);
4482 lrx
= obj2
.getNum();
4484 obj1
.arrayGet(3, &obj2
);
4485 lry
= obj2
.getNum();
4487 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx
, uly
, lrx
, lry
);
4491 dict
->lookup("GrayMap", &obj1
);
4492 if (obj1
.isArray()) {
4493 writePS("%ALDImageGrayMap:");
4494 for (i
= 0; i
< obj1
.arrayGetLength(); i
+= 16) {
4498 for (j
= 0; j
< 16 && i
+j
< obj1
.arrayGetLength(); ++j
) {
4499 obj1
.arrayGet(i
+j
, &obj2
);
4500 writePSFmt(" %d", obj2
.getInt());
4508 dict
->lookup("ID", &obj1
);
4509 if (obj1
.isString()) {
4510 writePSFmt("%%ALDImageID: %s\n", obj1
.getString()->getCString());
4514 dict
->lookup("ImageType", &obj1
);
4515 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4516 obj1
.arrayGet(0, &obj2
);
4517 samples
= obj2
.getInt();
4519 obj1
.arrayGet(1, &obj2
);
4520 bits
= obj2
.getInt();
4522 writePSFmt("%%ALDImageType: %d %d\n", samples
, bits
);
4526 dict
->lookup("Overprint", &obj1
);
4527 if (obj1
.isBool()) {
4528 writePSFmt("%%ALDImageOverprint: %s\n", obj1
.getBool() ? "true" : "false");
4532 dict
->lookup("Position", &obj1
);
4533 if (obj1
.isArray() && obj1
.arrayGetLength() == 8) {
4534 obj1
.arrayGet(0, &obj2
);
4535 llx
= obj2
.getNum();
4537 obj1
.arrayGet(1, &obj2
);
4538 lly
= obj2
.getNum();
4540 obj1
.arrayGet(2, &obj2
);
4541 ulx
= obj2
.getNum();
4543 obj1
.arrayGet(3, &obj2
);
4544 uly
= obj2
.getNum();
4546 obj1
.arrayGet(4, &obj2
);
4547 urx
= obj2
.getNum();
4549 obj1
.arrayGet(5, &obj2
);
4550 ury
= obj2
.getNum();
4552 obj1
.arrayGet(6, &obj2
);
4553 lrx
= obj2
.getNum();
4555 obj1
.arrayGet(7, &obj2
);
4556 lry
= obj2
.getNum();
4558 opiTransform(state
, llx
, lly
, &tllx
, &tlly
);
4559 opiTransform(state
, ulx
, uly
, &tulx
, &tuly
);
4560 opiTransform(state
, urx
, ury
, &turx
, &tury
);
4561 opiTransform(state
, lrx
, lry
, &tlrx
, &tlry
);
4562 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
4563 tllx
, tlly
, tulx
, tuly
, turx
, tury
, tlrx
, tlry
);
4568 dict
->lookup("Resolution", &obj1
);
4569 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4570 obj1
.arrayGet(0, &obj2
);
4571 horiz
= obj2
.getNum();
4573 obj1
.arrayGet(1, &obj2
);
4574 vert
= obj2
.getNum();
4576 writePSFmt("%%ALDImageResoution: %g %g\n", horiz
, vert
);
4581 dict
->lookup("Size", &obj1
);
4582 if (obj1
.isArray() && obj1
.arrayGetLength() == 2) {
4583 obj1
.arrayGet(0, &obj2
);
4584 width
= obj2
.getInt();
4586 obj1
.arrayGet(1, &obj2
);
4587 height
= obj2
.getInt();
4589 writePSFmt("%%ALDImageDimensions: %d %d\n", width
, height
);
4593 //~ ignoring 'Tags' entry
4594 //~ need to use writePSString() and deal with >255-char lines
4596 dict
->lookup("Tint", &obj1
);
4598 writePSFmt("%%ALDImageTint: %g\n", obj1
.getNum());
4602 dict
->lookup("Transparency", &obj1
);
4603 if (obj1
.isBool()) {
4604 writePSFmt("%%ALDImageTransparency: %s\n", obj1
.getBool() ? "true" : "false");
4608 writePS("%%BeginObject: image\n");
4609 writePS("opiMatrix2 setmatrix\n");
4613 // Convert PDF user space coordinates to PostScript default user space
4614 // coordinates. This has to account for both the PDF CTM and the
4615 // PSOutputDev page-fitting transform.
4616 void PSOutputDev::opiTransform(GfxState
*state
, double x0
, double y0
,
4617 double *x1
, double *y1
) {
4620 state
->transform(x0
, y0
, x1
, y1
);
4627 } else if (rotate
== 180) {
4630 } else if (rotate
== 270) {
4639 void PSOutputDev::opiEnd(GfxState
*state
, Dict
*opiDict
) {
4642 if (globalParams
->getPSOPI()) {
4643 opiDict
->lookup("2.0", &dict
);
4644 if (dict
.isDict()) {
4645 writePS("%%EndIncludedImage\n");
4646 writePS("%%EndOPI\n");
4647 writePS("grestore\n");
4652 opiDict
->lookup("1.3", &dict
);
4653 if (dict
.isDict()) {
4654 writePS("%%EndObject\n");
4655 writePS("restore\n");
4663 GBool
PSOutputDev::getFileSpec(Object
*fileSpec
, Object
*fileName
) {
4664 if (fileSpec
->isString()) {
4665 fileSpec
->copy(fileName
);
4668 if (fileSpec
->isDict()) {
4669 fileSpec
->dictLookup("DOS", fileName
);
4670 if (fileName
->isString()) {
4674 fileSpec
->dictLookup("Mac", fileName
);
4675 if (fileName
->isString()) {
4679 fileSpec
->dictLookup("Unix", fileName
);
4680 if (fileName
->isString()) {
4684 fileSpec
->dictLookup("F", fileName
);
4685 if (fileName
->isString()) {
4692 #endif // OPI_SUPPORT
4694 void PSOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
4695 writePSFmt("%g %g setcharwidth\n", wx
, wy
);
4699 void PSOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
4700 double llx
, double lly
, double urx
, double ury
) {
4707 t3String
= new GString();
4709 t3Cacheable
= gTrue
;
4712 void PSOutputDev::psXObject(Stream
*psStream
, Stream
*level1Stream
) {
4716 if ((level
== psLevel1
|| level
== psLevel1Sep
) && level1Stream
) {
4722 while ((c
= str
->getChar()) != EOF
) {
4728 //~ can nextFunc be reset to 0 -- maybe at the start of each page?
4729 //~ or maybe at the start of each color space / pattern?
4730 void PSOutputDev::cvtFunction(Function
*func
) {
4731 SampledFunction
*func0
;
4732 ExponentialFunction
*func2
;
4733 StitchingFunction
*func3
;
4734 PostScriptFunction
*func4
;
4735 int thisFunc
, m
, n
, nSamples
, i
, j
, k
;
4737 switch (func
->getType()) {
4739 case -1: // identity
4744 func0
= (SampledFunction
*)func
;
4745 thisFunc
= nextFunc
++;
4746 m
= func0
->getInputSize();
4747 n
= func0
->getOutputSize();
4749 for (i
= 0; i
< m
; ++i
) {
4750 nSamples
*= func0
->getSampleSize(i
);
4752 writePSFmt("/xpdfSamples%d [\n", thisFunc
);
4753 for (i
= 0; i
< nSamples
; ++i
) {
4754 writePSFmt("%g\n", func0
->getSamples()[i
]);
4757 writePSFmt("{ %d array %d array %d 2 roll\n", 2*m
, m
, m
+2);
4758 // [e01] [efrac] x0 x1 ... xm-1
4759 for (i
= m
-1; i
>= 0; --i
) {
4760 // [e01] [efrac] x0 x1 ... xi
4761 writePSFmt("%g sub %g mul %g add\n",
4762 func0
->getDomainMin(i
),
4763 (func0
->getEncodeMax(i
) - func0
->getEncodeMin(i
)) /
4764 (func0
->getDomainMax(i
) - func0
->getDomainMin(i
)),
4765 func0
->getEncodeMin(i
));
4766 // [e01] [efrac] x0 x1 ... xi-1 xi'
4767 writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n",
4768 func0
->getSampleSize(i
) - 1, func0
->getSampleSize(i
) - 1);
4769 // [e01] [efrac] x0 x1 ... xi-1 xi'
4770 writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
4771 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
4772 writePSFmt("%d index %d 3 2 roll put\n", i
+3, i
);
4773 // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
4774 writePSFmt("%d index %d 3 2 roll put\n", i
+3, 2*i
+1);
4775 // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
4776 writePSFmt("%d index %d 3 2 roll put\n", i
+2, 2*i
);
4777 // [e01] [efrac] x0 x1 ... xi-1
4780 for (i
= 0; i
< n
; ++i
) {
4781 // [e01] [efrac] y(0) ... y(i-1)
4782 for (j
= 0; j
< (1<<m
); ++j
) {
4783 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
4784 writePSFmt("xpdfSamples%d\n", thisFunc
);
4786 writePSFmt("%d index %d get\n", i
+j
+2, 2 * k
+ ((j
>> k
) & 1));
4787 for (k
= m
- 2; k
>= 0; --k
) {
4788 writePSFmt("%d mul %d index %d get add\n",
4789 func0
->getSampleSize(k
),
4791 2 * k
+ ((j
>> k
) & 1));
4794 writePSFmt("%d mul %d add ", n
, i
);
4798 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
4799 for (j
= 0; j
< m
; ++j
) {
4800 // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
4801 for (k
= 0; k
< (1 << (m
- j
)); k
+= 2) {
4802 // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
4803 writePSFmt("%d index %d get dup\n", i
+ k
/2 + (1 << (m
-j
)) - k
, j
);
4804 writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
4805 writePSFmt("%d 1 roll\n", k
/2 + (1 << m
-j
) - k
- 1);
4807 // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
4809 // [e01] [efrac] y(0) ... y(i-1) s
4810 writePSFmt("%g mul %g add\n",
4811 func0
->getDecodeMax(i
) - func0
->getDecodeMin(i
),
4812 func0
->getDecodeMin(i
));
4813 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4814 func0
->getRangeMin(i
), func0
->getRangeMin(i
),
4815 func0
->getRangeMax(i
), func0
->getRangeMax(i
));
4816 // [e01] [efrac] y(0) ... y(i-1) y(i)
4818 // [e01] [efrac] y(0) ... y(n-1)
4819 writePSFmt("%d %d roll pop pop }\n", n
+2, n
);
4822 case 2: // exponential
4823 func2
= (ExponentialFunction
*)func
;
4824 n
= func2
->getOutputSize();
4825 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4826 func2
->getDomainMin(0), func2
->getDomainMin(0),
4827 func2
->getDomainMax(0), func2
->getDomainMax(0));
4829 for (i
= 0; i
< n
; ++i
) {
4831 writePSFmt("%d index %g exp %g mul %g add\n",
4832 i
, func2
->getE(), func2
->getC1()[i
] - func2
->getC0()[i
],
4834 if (func2
->getHasRange()) {
4835 writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4836 func2
->getRangeMin(i
), func2
->getRangeMin(i
),
4837 func2
->getRangeMax(i
), func2
->getRangeMax(i
));
4841 writePSFmt("%d %d roll pop }\n", n
+1, n
);
4844 case 3: // stitching
4845 func3
= (StitchingFunction
*)func
;
4846 thisFunc
= nextFunc
++;
4847 for (i
= 0; i
< func3
->getNumFuncs(); ++i
) {
4848 cvtFunction(func3
->getFunc(i
));
4849 writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc
, i
);
4851 writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n",
4852 func3
->getDomainMin(0), func3
->getDomainMin(0),
4853 func3
->getDomainMax(0), func3
->getDomainMax(0));
4854 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4855 writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n",
4856 func3
->getBounds()[i
+1],
4857 func3
->getBounds()[i
],
4858 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4859 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4860 func3
->getEncode()[2*i
],
4863 writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n",
4864 func3
->getBounds()[i
],
4865 (func3
->getEncode()[2*i
+1] - func3
->getEncode()[2*i
]) /
4866 (func3
->getBounds()[i
+1] - func3
->getBounds()[i
]),
4867 func3
->getEncode()[2*i
],
4869 for (i
= 0; i
< func3
->getNumFuncs() - 1; ++i
) {
4870 writePS("} ifelse\n");
4875 case 4: // PostScript
4876 func4
= (PostScriptFunction
*)func
;
4877 writePS(func4
->getCodeString()->getCString());
4883 void PSOutputDev::writePSChar(char c
) {
4885 t3String
->append(c
);
4887 (*outputFunc
)(outputStream
, &c
, 1);
4891 void PSOutputDev::writePS(char *s
) {
4893 t3String
->append(s
);
4895 (*outputFunc
)(outputStream
, s
, strlen(s
));
4899 void PSOutputDev::writePSFmt(const char *fmt
, ...) {
4903 va_start(args
, fmt
);
4904 vsprintf(buf
, fmt
, args
);
4907 t3String
->append(buf
);
4909 (*outputFunc
)(outputStream
, buf
, strlen(buf
));
4913 void PSOutputDev::writePSString(GString
*s
) {
4920 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
4926 if (*p
== '(' || *p
== ')' || *p
== '\\') {
4928 writePSChar((char)*p
);
4930 } else if (*p
< 0x20 || *p
>= 0x80) {
4931 sprintf(buf
, "\\%03o", *p
);
4935 writePSChar((char)*p
);
4942 void PSOutputDev::writePSName(char *s
) {
4947 while ((c
= *p
++)) {
4948 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4949 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4950 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4951 c
== '/' || c
== '%') {
4952 writePSFmt("#%02x", c
& 0xff);
4959 GString
*PSOutputDev::filterPSName(GString
*name
) {
4965 name2
= new GString();
4967 // ghostscript chokes on names that begin with out-of-limits
4968 // numbers, e.g., 1e4foo is handled correctly (as a name), but
4969 // 1e999foo generates a limitcheck error
4970 c
= name
->getChar(0);
4971 if (c
>= '0' && c
<= '9') {
4975 for (i
= 0; i
< name
->getLength(); ++i
) {
4976 c
= name
->getChar(i
);
4977 if (c
<= (char)0x20 || c
>= (char)0x7f ||
4978 c
== '(' || c
== ')' || c
== '<' || c
== '>' ||
4979 c
== '[' || c
== ']' || c
== '{' || c
== '}' ||
4980 c
== '/' || c
== '%') {
4981 sprintf(buf
, "#%02x", c
& 0xff);
4990 GBool
/* O - gTrue if selected, gFalse otherwise */
4991 PSOutputDev::checkRange(int page
) /* I - Page number */
4993 const char *range
; /* Pointer into range string */
4994 int lower
, upper
; /* Lower and upper page numbers */
4997 if (pageRanges
== NULL
)
4998 return (gTrue
); /* No range, print all pages... */
5000 for (range
= pageRanges
; *range
!= '\0';)
5006 upper
= strtol(range
, (char **)&range
, 10);
5010 lower
= strtol(range
, (char **)&range
, 10);
5015 if (!isdigit(*range
& 255))
5018 upper
= strtol(range
, (char **)&range
, 10);
5024 if (page
>= lower
&& page
<= upper
)