1
//========================================================================
5
// Copyright 1996-2003 Glyph & Cog, LLC
7
//========================================================================
9
//========================================================================
11
// Modified under the Poppler project - http://poppler.freedesktop.org
13
// All changes made under the Poppler project to this file are licensed
14
// under GPL version 2 or later
16
// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
17
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
18
// Copyright (C) 2006-2009 Albert Astals Cid <aacid@kde.org>
19
// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
20
// Copyright (C) 2007, 2008 Brad Hards <bradh@kde.org>
21
// Copyright (C) 2008, 2009 Koji Otani <sho@bbr.jp>
22
// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
23
// Copyright (C) 2009, 2010 Thomas Freitag <Thomas.Freitag@alfa.de>
24
// Copyright (C) 2009 Till Kamppeter <till.kamppeter@gmail.com>
25
// Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
26
// Copyright (C) 2009, 2011 William Bader <williambader@hotmail.com>
27
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
28
// Copyright (C) 2009, 2010 Adrian Johnson <ajohnson@redneon.com>
30
// To see a description of the changes please see the Changelog file that
31
// came with your tarball or type make ChangeLog if you are building from git
33
//========================================================================
37
#ifdef USE_GCC_PRAGMAS
38
#pragma implementation
47
#include "goo/GooString.h"
48
#include "goo/GooList.h"
49
#include "poppler-config.h"
50
#include "GlobalParams.h"
57
#include "UnicodeMap.h"
58
#include <fofi/FoFiType1C.h>
59
#include <fofi/FoFiTrueType.h>
65
#include "PreScanOutputDev.h"
68
# include "splash/Splash.h"
69
# include "splash/SplashBitmap.h"
70
# include "SplashOutputDev.h"
72
#include "PSOutputDev.h"
76
// needed for setting type/creator of MacOS files
77
#include "ICSupport.h"
80
// the MSVC math.h doesn't define this
82
#define M_PI 3.14159265358979323846
85
//------------------------------------------------------------------------
87
// Resolution at which pages with transparency will be rasterized.
90
//------------------------------------------------------------------------
91
// PostScript prolog and setup
92
//------------------------------------------------------------------------
94
// The '~' escapes mark prolog code that is emitted only in certain
98
// ^ ^----- s=psLevel*Sep, n=psLevel*
99
// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
101
static char *prolog[] = {
102
"/xpdf 75 dict def xpdf begin",
103
"% PDF special state",
104
"/pdfDictSize 15 def",
106
"/pdfStates 64 array def",
108
" pdfStates exch pdfDictSize dict",
109
" dup /pdfStateIdx 3 index put",
114
" 3 1 roll 2 array astore",
115
" /setpagedevice where {",
117
" /PageSize exch def",
118
" /ImagingBBox null def",
119
" { /Duplex true def } if",
120
" currentdict end setpagedevice",
127
" /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
128
" /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender /pdfPatternCS",
129
" /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
134
" pdfStates 0 get begin",
136
" pdfDictSize dict begin",
138
" /pdfFillCS [] def",
139
" /pdfFillXform {} def",
140
" /pdfStrokeCS [] def",
141
" /pdfStrokeXform {} def",
146
" /pdfFill [0 0 0 1] def",
147
" /pdfStroke [0 0 0 1] def",
150
" /pdfStroke [0] def",
151
" /pdfFillOP false def",
152
" /pdfStrokeOP false def",
154
" /pdfLastFill false def",
155
" /pdfLastStroke false def",
156
" /pdfTextMat [1 0 0 1 0 0] def",
157
" /pdfFontSize 0 def",
158
" /pdfCharSpacing 0 def",
159
" /pdfTextRender 0 def",
160
" /pdfPatternCS false def",
161
" /pdfTextRise 0 def",
162
" /pdfWordSpacing 0 def",
163
" /pdfHorizScaling 1 def",
164
" /pdfTextClipPath [] def",
166
"/pdfEndPage { end } def",
168
"% separation convention operators",
169
"/findcmykcustomcolor where {",
172
" /findcmykcustomcolor { 5 array astore } def",
174
"/setcustomcolor where {",
177
" /setcustomcolor {",
179
" [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
180
" 0 4 getinterval cvx",
181
" [ exch /dup load exch { mul exch dup } /forall load",
182
" /pop load dup ] cvx",
183
" ] setcolorspace setcolor",
186
"/customcolorimage where {",
189
" /customcolorimage {",
191
" [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
193
" [ exch /dup load exch { mul exch dup } /forall load",
194
" /pop load dup ] cvx",
198
" /DataSource exch def",
199
" /ImageMatrix exch def",
200
" /BitsPerComponent exch def",
203
" /Decode [1 0] def",
212
"/g { dup /pdfFill exch def setgray",
213
" /pdfLastFill true def /pdfLastStroke false def } def",
214
"/G { dup /pdfStroke exch def setgray",
215
" /pdfLastStroke true def /pdfLastFill false def } def",
217
" pdfLastFill not {",
219
" /pdfLastFill true def /pdfLastStroke false def",
223
" pdfLastStroke not {",
224
" pdfStroke setgray",
225
" /pdfLastStroke true def /pdfLastFill false def",
229
"/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
230
" /pdfLastFill true def /pdfLastStroke false def } def",
231
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
232
" /pdfLastStroke true def /pdfLastFill false def } def",
234
" pdfLastFill not {",
235
" pdfFill aload pop setcmykcolor",
236
" /pdfLastFill true def /pdfLastStroke false def",
240
" pdfLastStroke not {",
241
" pdfStroke aload pop setcmykcolor",
242
" /pdfLastStroke true def /pdfLastFill false def",
246
"/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
247
" setcolorspace } def",
248
"/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
249
" setcolorspace } def",
250
"/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
251
" dup /pdfFill exch def aload pop pdfFillXform setcolor",
252
" /pdfLastFill true def /pdfLastStroke false def } def",
253
"/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
254
" dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
255
" /pdfLastStroke true def /pdfLastFill false def } def",
256
"/op { /pdfFillOP exch def",
257
" pdfLastFill { pdfFillOP setoverprint } if } def",
258
"/OP { /pdfStrokeOP exch def",
259
" pdfLastStroke { pdfStrokeOP setoverprint } if } def",
261
" pdfLastFill not {",
262
" pdfFillCS setcolorspace",
263
" pdfFill aload pop pdfFillXform setcolor",
264
" pdfFillOP setoverprint",
265
" /pdfLastFill true def /pdfLastStroke false def",
269
" pdfLastStroke not {",
270
" pdfStrokeCS setcolorspace",
271
" pdfStroke aload pop pdfStrokeXform setcolor",
272
" pdfStrokeOP setoverprint",
273
" /pdfLastStroke true def /pdfLastFill false def",
277
"/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
278
" /pdfLastFill true def /pdfLastStroke false def } def",
279
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
280
" /pdfLastStroke true def /pdfLastFill false def } def",
281
"/ck { 6 copy 6 array astore /pdfFill exch def",
282
" findcmykcustomcolor exch setcustomcolor",
283
" /pdfLastFill true def /pdfLastStroke false def } def",
284
"/CK { 6 copy 6 array astore /pdfStroke exch def",
285
" findcmykcustomcolor exch setcustomcolor",
286
" /pdfLastStroke true def /pdfLastFill false def } def",
287
"/op { /pdfFillOP exch def",
288
" pdfLastFill { pdfFillOP setoverprint } if } def",
289
"/OP { /pdfStrokeOP exch def",
290
" pdfLastStroke { pdfStrokeOP setoverprint } if } def",
292
" pdfLastFill not {",
293
" pdfFill aload length 4 eq {",
296
" findcmykcustomcolor exch setcustomcolor",
298
" pdfFillOP setoverprint",
299
" /pdfLastFill true def /pdfLastStroke false def",
303
" pdfLastStroke not {",
304
" pdfStroke aload length 4 eq {",
307
" findcmykcustomcolor exch setcustomcolor",
309
" pdfStrokeOP setoverprint",
310
" /pdfLastStroke true def /pdfLastFill false def",
316
" 4 3 roll findfont",
317
" 4 2 roll matrix scale makefont",
318
" dup length dict begin",
319
" { 1 index /FID ne { def } { pop pop } ifelse } forall",
320
" /Encoding exch def",
327
" dup length dict begin",
328
" { 1 index /FID ne { def } { pop pop } ifelse } forall",
335
"/pdfMakeFont16L3 {",
336
" 1 index /CIDFont resourcestatus {",
337
" pop pop 1 index /CIDFont findresource /CIDFontType known",
342
" 0 eq { /Identity-H } { /Identity-V } ifelse",
343
" exch 1 array astore composefont pop",
349
"% graphics state operators",
353
" pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
354
" pdfStates pdfStateIdx 1 add get begin",
355
" pdfOpNames { exch def } forall",
357
"/Q { end grestore } def",
359
"/q { gsave pdfDictSize dict begin } def",
362
" /pdfLastFill where {",
365
" pdfFillOP setoverprint",
367
" pdfStrokeOP setoverprint",
372
"/cm { concat } def",
373
"/d { setdash } def",
374
"/i { setflat } def",
375
"/j { setlinejoin } def",
376
"/J { setlinecap } def",
377
"/M { setmiterlimit } def",
378
"/w { setlinewidth } def",
379
"% path segment operators",
382
"/c { curveto } def",
383
"/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
384
" neg 0 rlineto closepath } def",
385
"/h { closepath } def",
386
"% path painting operators",
387
"/S { sCol stroke } def",
388
"/Sf { fCol stroke } def",
389
"/f { fCol fill } def",
390
"/f* { fCol eofill } def",
391
"% clipping operators",
392
"/W { clip newpath } def",
393
"/W* { eoclip newpath } def",
394
"/Ws { strokepath clip newpath } def",
395
"% text state operators",
396
"/Tc { /pdfCharSpacing exch def } def",
397
"/Tf { dup /pdfFontSize exch def",
398
" dup pdfHorizScaling mul exch matrix scale",
399
" pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
400
" exch findfont exch makefont setfont } def",
401
"/Tr { /pdfTextRender exch def } def",
402
"/Tp { /pdfPatternCS exch def } def",
403
"/Ts { /pdfTextRise exch def } def",
404
"/Tw { /pdfWordSpacing exch def } def",
405
"/Tz { /pdfHorizScaling exch def } def",
406
"% text positioning operators",
407
"/Td { pdfTextMat transform moveto } def",
408
"/Tm { /pdfTextMat exch def } def",
409
"% text string operators",
415
" 1 string dup 0 3 index put 3 index exec",
421
" currentfont /FontType get 0 eq {",
422
" 0 2 2 index length 1 sub {",
423
" 2 copy get exch 1 add 2 index exch get",
424
" 2 copy exch 256 mul add",
425
" 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
430
" 1 string dup 0 3 index put 3 index exec",
436
"/awcp {", // awidthcharpath
439
" 5 index 5 index rmoveto",
440
" 6 index eq { 7 index 7 index rmoveto } if",
445
" fCol", // because stringwidth has to draw Type 3 chars
446
" 1 index stringwidth pdfTextMat idtransform pop",
447
" sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
448
" pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
449
" 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
450
" pdfTextMat dtransform",
454
" fCol", // because stringwidth has to draw Type 3 chars
455
" 2 index stringwidth pdfTextMat idtransform pop",
457
" pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
458
" 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
459
" pdfTextMat dtransform",
463
" fCol", // because stringwidth has to draw Type 3 chars
464
" 2 index stringwidth pdfTextMat idtransform exch pop",
466
" 0 pdfWordSpacing pdfTextMat dtransform 32",
467
" 4 3 roll pdfCharSpacing add 0 exch",
468
" pdfTextMat dtransform",
472
" 0 pdfTextRise pdfTextMat dtransform rmoveto",
473
" currentpoint 8 2 roll",
474
" pdfTextRender 1 and 0 eq pdfPatternCS not and {",
475
" 6 copy awidthshow",
477
" pdfTextRender 3 and dup 1 eq exch 2 eq or {",
478
" 7 index 7 index moveto",
480
" currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
481
" false awcp currentpoint stroke moveto",
483
" pdfTextRender 4 and 0 ne pdfPatternCS or {",
486
" /pdfTextClipPath [ pdfTextClipPath aload pop",
492
" currentpoint newpath moveto",
496
" 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
498
"/TJm { pdfFontSize 0.001 mul mul neg 0",
499
" pdfTextMat dtransform rmoveto } def",
500
"/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
501
" pdfTextMat dtransform rmoveto } def",
502
"/Tclip { pdfTextClipPath cvx exec clip newpath",
503
" /pdfTextClipPath [] def } def",
504
"/Tclip* { pdfTextClipPath cvx exec eoclip newpath",
505
" /pdfTextClipPath [] def } def",
507
"% Level 1 image operators",
510
" /pdfImBuf1 4 index string def",
511
" { currentfile pdfImBuf1 readhexstring pop } image",
515
" /pdfImBuf1 4 index string def",
516
" /pdfImBuf2 4 index string def",
517
" /pdfImBuf3 4 index string def",
518
" /pdfImBuf4 4 index string def",
519
" { currentfile pdfImBuf1 readhexstring pop }",
520
" { currentfile pdfImBuf2 readhexstring pop }",
521
" { currentfile pdfImBuf3 readhexstring pop }",
522
" { currentfile pdfImBuf4 readhexstring pop }",
523
" true 4 colorimage",
527
" fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
528
" { currentfile pdfImBuf1 readhexstring pop } imagemask",
531
" { 2 copy get exch 1 add exch } imagemask",
535
"% Level 2 image operators",
536
"/pdfImBuf 100 string def",
539
" { currentfile pdfImBuf readline",
540
" not { pop exit } if",
541
" (%-EOD-) eq { exit } if } loop",
545
" findcmykcustomcolor exch",
546
" dup /Width get /pdfImBuf1 exch string def",
547
" dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
548
" /pdfImDecodeLow exch def",
549
" begin Width Height BitsPerComponent ImageMatrix DataSource end",
550
" /pdfImData exch def",
551
" { pdfImData pdfImBuf1 readstring pop",
552
" 0 1 2 index length 1 sub {",
553
" 1 index exch 2 copy get",
554
" pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
557
" 6 5 roll customcolorimage",
558
" { currentfile pdfImBuf readline",
559
" not { pop exit } if",
560
" (%-EOD-) eq { exit } if } loop",
565
" { currentfile pdfImBuf readline",
566
" not { pop exit } if",
567
" (%-EOD-) eq { exit } if } loop",
570
"/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
573
" 0 2 4 index length 1 sub {",
574
" dup 4 index exch 2 copy",
575
" get 5 index div put",
576
" 1 add 3 index exch 2 copy",
577
" get 3 index div put",
581
"/pdfImClipEnd { grestore } def",
583
"% shading operators",
585
" false 0 1 3 index length 1 sub {",
586
" dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
590
" exch pop exch pop",
592
"/funcCol { func n array astore } def",
600
" 4 index 4 index funcCol dup",
601
" 6 index 4 index funcCol dup",
602
" 3 1 roll colordelta 3 1 roll",
603
" 5 index 5 index funcCol dup",
604
" 3 1 roll colordelta 3 1 roll",
605
" 6 index 8 index funcCol dup",
606
" 3 1 roll colordelta 3 1 roll",
607
" colordelta or or or",
612
" 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
613
" 6 index 6 index 4 index 4 index 4 index funcSH",
614
" 2 index 6 index 6 index 4 index 4 index funcSH",
615
" 6 index 2 index 4 index 6 index 4 index funcSH",
616
" 5 3 roll 3 2 roll funcSH pop pop",
618
" pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
622
" funcCol aload pop k",
624
" dup 4 index exch mat transform m",
625
" 3 index 3 index mat transform l",
626
" 1 index 3 index mat transform l",
627
" mat transform l pop pop h f*",
640
" func n array astore",
649
" 2 index axialCol 2 index axialCol colordelta",
653
" 1 add 3 1 roll 2 copy add 0.5 mul",
654
" dup 4 3 roll exch 4 index axialSH",
655
" exch 3 2 roll axialSH",
657
" pop 2 copy add 0.5 mul",
661
" axialCol aload pop k",
663
" exch dup dx mul x0 add exch dy mul y0 add",
664
" 3 2 roll dup dx mul x0 add exch dy mul y0 add",
665
" dx abs dy abs ge {",
666
" 2 copy yMin sub dy mul dx div add yMin m",
667
" yMax sub dy mul dx div add yMax l",
668
" 2 copy yMax sub dy mul dx div add yMax l",
669
" yMin sub dy mul dx div add yMin l",
672
" exch 2 copy xMin sub dx mul dy div add xMin exch m",
673
" xMax sub dx mul dy div add xMax exch l",
674
" exch 2 copy xMax sub dx mul dy div add xMax exch l",
675
" xMin sub dx mul dy div add xMin exch l",
688
" func n array astore",
697
" 2 index dt mul t0 add radialCol",
698
" 2 index dt mul t0 add radialCol colordelta",
702
" 1 add 3 1 roll 2 copy add 0.5 mul",
703
" dup 4 3 roll exch 4 index radialSH",
704
" exch 3 2 roll radialSH",
706
" pop 2 copy add 0.5 mul dt mul t0 add",
710
" radialCol aload pop k",
713
" exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
715
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
719
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
721
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
723
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
725
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
735
static char *cmapProlog[] = {
736
"/CIDInit /ProcSet findresource begin",
740
" /CMapName /Identity-H def",
741
" /CIDSystemInfo 3 dict dup begin",
742
" /Registry (Adobe) def",
743
" /Ordering (Identity) def",
744
" /Supplement 0 def",
746
" 1 begincodespacerange",
748
" endcodespacerange",
754
" currentdict CMapName exch /CMap defineresource pop",
759
" /CMapName /Identity-V def",
760
" /CIDSystemInfo 3 dict dup begin",
761
" /Registry (Adobe) def",
762
" /Ordering (Identity) def",
763
" /Supplement 0 def",
766
" 1 begincodespacerange",
768
" endcodespacerange",
774
" currentdict CMapName exch /CMap defineresource pop",
780
//------------------------------------------------------------------------
782
//------------------------------------------------------------------------
785
char *psName; // PostScript name
786
double mWidth; // width of 'm' character
789
static const char *psFonts[] = {
793
"Courier-BoldOblique",
797
"Helvetica-BoldOblique",
807
static const PSSubstFont psSubstFonts[] = {
808
{"Helvetica", 0.833},
809
{"Helvetica-Oblique", 0.833},
810
{"Helvetica-Bold", 0.889},
811
{"Helvetica-BoldOblique", 0.889},
812
{"Times-Roman", 0.788},
813
{"Times-Italic", 0.722},
814
{"Times-Bold", 0.833},
815
{"Times-BoldItalic", 0.778},
817
{"Courier-Oblique", 0.600},
818
{"Courier-Bold", 0.600},
819
{"Courier-BoldOblique", 0.600}
822
// Info for 8-bit fonts
825
Gushort *codeToGID; // code-to-GID mapping for TrueType fonts
828
// Encoding info for substitute 16-bit font
834
//------------------------------------------------------------------------
836
//------------------------------------------------------------------------
838
#define psProcessCyan 1
839
#define psProcessMagenta 2
840
#define psProcessYellow 4
841
#define psProcessBlack 8
842
#define psProcessCMYK 15
844
//------------------------------------------------------------------------
846
//------------------------------------------------------------------------
848
class PSOutCustomColor {
851
PSOutCustomColor(double cA, double mA,
852
double yA, double kA, GooString *nameA);
857
PSOutCustomColor *next;
860
PSOutCustomColor::PSOutCustomColor(double cA, double mA,
861
double yA, double kA, GooString *nameA) {
870
PSOutCustomColor::~PSOutCustomColor() {
874
//------------------------------------------------------------------------
876
struct PSOutImgClipRect {
880
//------------------------------------------------------------------------
882
//------------------------------------------------------------------------
884
class DeviceNRecoder: public FilterStream {
887
DeviceNRecoder(Stream *strA, int widthA, int heightA,
888
GfxImageColorMap *colorMapA);
889
virtual ~DeviceNRecoder();
890
virtual StreamKind getKind() { return strWeird; }
891
virtual void reset();
892
virtual int getChar()
893
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
894
virtual int lookChar()
895
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
896
virtual GooString *getPSFilter(int psLevel, char *indent) { return NULL; }
897
virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
898
virtual GBool isEncoder() { return gTrue; }
905
GfxImageColorMap *colorMap;
908
int buf[gfxColorMaxComps];
914
DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
915
GfxImageColorMap *colorMapA):
919
colorMap = colorMapA;
922
bufIdx = gfxColorMaxComps;
923
bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
924
getAlt()->getNComps();
925
func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
926
getTintTransformFunc();
929
DeviceNRecoder::~DeviceNRecoder() {
935
void DeviceNRecoder::reset() {
936
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
937
colorMap->getBits());
941
GBool DeviceNRecoder::fillBuf() {
942
Guchar pixBuf[gfxColorMaxComps];
944
double x[gfxColorMaxComps], y[gfxColorMaxComps];
947
if (pixelIdx >= width * height) {
950
imgStr->getPixel(pixBuf);
951
colorMap->getColor(pixBuf, &color);
953
i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps();
955
x[i] = colToDbl(color.c[i]);
957
func->transform(x, y);
958
for (i = 0; i < bufSize; ++i) {
959
buf[i] = (int)(y[i] * 255 + 0.5);
966
//------------------------------------------------------------------------
968
//------------------------------------------------------------------------
971
typedef void (*SignalFunc)(int);
974
static void outputToFile(void *stream, char *data, int len) {
975
fwrite(data, 1, len, (FILE *)stream);
978
PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
980
int firstPage, int lastPage, PSOutMode modeA,
981
int paperWidthA, int paperHeightA, GBool duplexA,
982
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
983
GBool forceRasterizeA,
986
PSFileType fileTypeA;
989
underlayCbkData = NULL;
991
overlayCbkData = NULL;
995
fontFileNames = NULL;
1002
customColors = NULL;
1003
haveTextClip = gFalse;
1004
haveCSPattern = gFalse;
1007
forceRasterize = forceRasterizeA;
1009
// open file or pipe
1010
if (!strcmp(fileName, "-")) {
1011
fileTypeA = psStdout;
1013
} else if (fileName[0] == '|') {
1017
signal(SIGPIPE, (SignalFunc)SIG_IGN);
1019
if (!(f = popen(fileName + 1, "w"))) {
1020
error(-1, "Couldn't run print command '%s'", fileName);
1025
error(-1, "Print commands are not supported ('%s')", fileName);
1031
if (!(f = fopen(fileName, "w"))) {
1032
error(-1, "Couldn't open PostScript file '%s'", fileName);
1038
init(outputToFile, f, fileTypeA, psTitle,
1039
doc, xrefA, catalog, firstPage, lastPage, modeA,
1040
imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
1041
paperWidthA, paperHeightA, duplexA);
1044
PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
1047
XRef *xrefA, Catalog *catalog,
1048
int firstPage, int lastPage, PSOutMode modeA,
1049
int paperWidthA, int paperHeightA, GBool duplexA,
1050
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
1051
GBool forceRasterizeA,
1052
GBool manualCtrlA) {
1054
underlayCbkData = NULL;
1056
overlayCbkData = NULL;
1060
fontFileNames = NULL;
1067
customColors = NULL;
1068
haveTextClip = gFalse;
1069
haveCSPattern = gFalse;
1072
forceRasterize = forceRasterizeA;
1074
init(outputFuncA, outputStreamA, psGeneric, psTitle,
1075
doc, xrefA, catalog, firstPage, lastPage, modeA,
1076
imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
1077
paperWidthA, paperHeightA, duplexA);
1080
void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
1081
PSFileType fileTypeA, char *pstitle, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
1082
int firstPage, int lastPage, PSOutMode modeA,
1083
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
1084
GBool manualCtrlA, int paperWidthA, int paperHeightA,
1089
displayText = gTrue;
1091
outputFunc = outputFuncA;
1092
outputStream = outputStreamA;
1093
fileType = fileTypeA;
1094
m_catalog = catalog;
1096
level = globalParams->getPSLevel();
1098
paperWidth = paperWidthA;
1099
paperHeight = paperHeightA;
1104
if (paperWidth < 0 || paperHeight < 0) {
1106
if ((page = doc->getPage(firstPage))) {
1107
paperWidth = (int)ceil(page->getMediaWidth());
1108
paperHeight = (int)ceil(page->getMediaHeight());
1110
error(-1, "Invalid page %d", firstPage);
1115
substFonts = globalParams->getPSSubstFonts();
1116
preload = globalParams->getPSPreload();
1117
if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
1118
imgLLX = imgLLY = 0;
1119
imgURX = paperWidth;
1120
imgURY = paperHeight;
1122
if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
1123
imgLLX = imgLLY = 0;
1124
imgURX = paperWidth;
1125
imgURY = paperHeight;
1127
manualCtrl = manualCtrlA;
1128
if (mode == psModeForm) {
1129
lastPage = firstPage;
1132
inType3Char = gFalse;
1135
// initialize OPI nesting levels
1141
xScale0 = yScale0 = 0;
1143
clipLLX0 = clipLLY0 = 0;
1144
clipURX0 = clipURY0 = -1;
1146
// initialize fontIDs, fontFileIDs, and fontFileNames lists
1149
fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
1150
fontFileIDSize = 64;
1152
fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
1153
fontFileNameSize = 64;
1154
fontFileNameLen = 0;
1155
fontFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
1156
psFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
1157
nextTrueTypeNum = 0;
1167
xobjStack = new GooList();
1169
numTilingPatterns = 0;
1172
// initialize embedded font resource comment list
1173
embFontList = new GooString();
1177
// this check is needed in case the document has zero pages
1178
if ((page = doc->getPage(firstPage))) {
1179
writeHeader(firstPage, lastPage,
1180
page->getMediaBox(),
1185
error(-1, "Invalid page %d", firstPage);
1186
box = new PDFRectangle(0, 0, 1, 1);
1187
writeHeader(firstPage, lastPage, box, box, 0, pstitle);
1190
if (mode != psModeForm) {
1191
writePS("%%BeginProlog\n");
1194
if (mode != psModeForm) {
1195
writePS("%%EndProlog\n");
1196
writePS("%%BeginSetup\n");
1198
writeDocSetup(doc, catalog, firstPage, lastPage, duplexA);
1199
if (mode != psModeForm) {
1200
writePS("%%EndSetup\n");
1204
// initialize sequential page number
1208
PSOutputDev::~PSOutputDev() {
1209
PSOutCustomColor *cc;
1214
writePS("%%Trailer\n");
1216
if (mode != psModeForm) {
1220
if (fileType == psFile) {
1222
ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
1224
fclose((FILE *)outputStream);
1227
else if (fileType == psPipe) {
1228
pclose((FILE *)outputStream);
1230
signal(SIGPIPE, (SignalFunc)SIG_DFL);
1244
if (fontFileNames) {
1245
for (i = 0; i < fontFileNameLen; ++i) {
1246
delete fontFileNames[i];
1248
gfree(fontFileNames);
1251
for (i = 0; i < font8InfoLen; ++i) {
1252
gfree(font8Info[i].codeToGID);
1257
for (i = 0; i < fontFileNameLen; ++i) {
1259
delete psFileNames[i];
1264
for (i = 0; i < font16EncLen; ++i) {
1265
delete font16Enc[i].enc;
1274
while (customColors) {
1276
customColors = cc->next;
1281
void PSOutputDev::writeHeader(int firstPage, int lastPage,
1282
PDFRectangle *mediaBox, PDFRectangle *cropBox,
1283
int pageRotate, char *psTitle) {
1284
double x1, y1, x2, y2;
1288
case psModePSOrigPageSizes:
1290
writePS("%!PS-Adobe-3.0\n");
1293
writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
1296
writePS("%!PS-Adobe-3.0 Resource-Form\n");
1299
xref->getDocInfo(&info);
1300
if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
1301
writePS("%%Creator: ");
1302
writePSTextLine(obj1.getString());
1307
writePSFmt("%%Title: {0:s}\n", psTitle);
1309
writePSFmt("%%LanguageLevel: {0:d}\n",
1310
(level == psLevel1 || level == psLevel1Sep) ? 1 :
1311
(level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
1312
if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
1313
writePS("%%DocumentProcessColors: (atend)\n");
1314
writePS("%%DocumentCustomColors: (atend)\n");
1316
writePS("%%DocumentSuppliedResources: (atend)\n");
1319
case psModePSOrigPageSizes:
1323
writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
1324
paperWidth, paperHeight);
1325
writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
1326
writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
1327
writePS("%%EndComments\n");
1328
writePS("%%BeginDefaults\n");
1329
writePS("%%PageMedia: plain\n");
1330
writePS("%%EndDefaults\n");
1333
epsX1 = cropBox->x1;
1334
epsY1 = cropBox->y1;
1335
epsX2 = cropBox->x2;
1336
epsY2 = cropBox->y2;
1337
if (pageRotate == 0 || pageRotate == 180) {
1342
} else { // pageRotate == 90 || pageRotate == 270
1348
writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
1349
(int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
1350
if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) ||
1351
floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) {
1352
writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
1355
writePS("%%DocumentSuppliedResources: (atend)\n");
1356
writePS("%%EndComments\n");
1359
writePS("%%EndComments\n");
1360
writePS("32 dict dup begin\n");
1361
writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n",
1362
(int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
1363
(int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
1364
writePS("/FormType 1 def\n");
1365
writePS("/Matrix [1 0 0 1 0 0] def\n");
1370
void PSOutputDev::writeXpdfProcset() {
1371
GBool lev1, lev2, lev3, sep, nonSep;
1375
writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", "3.00");
1376
writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
1377
lev1 = lev2 = lev3 = sep = nonSep = gTrue;
1378
for (p = prolog; *p; ++p) {
1379
if ((*p)[0] == '~') {
1380
lev1 = lev2 = lev3 = sep = nonSep = gFalse;
1381
for (q = *p + 1; *q; ++q) {
1383
case '1': lev1 = gTrue; break;
1384
case '2': lev2 = gTrue; break;
1385
case '3': lev3 = gTrue; break;
1386
case 's': sep = gTrue; break;
1387
case 'n': nonSep = gTrue; break;
1390
} else if ((level == psLevel1 && lev1 && nonSep) ||
1391
(level == psLevel1Sep && lev1 && sep) ||
1392
(level == psLevel2 && lev2 && nonSep) ||
1393
(level == psLevel2Sep && lev2 && sep) ||
1394
(level == psLevel3 && lev3 && nonSep) ||
1395
(level == psLevel3Sep && lev3 && sep)) {
1396
writePSFmt("{0:s}\n", *p);
1399
writePS("%%EndResource\n");
1401
if (level >= psLevel3) {
1402
for (p = cmapProlog; *p; ++p) {
1403
writePSFmt("{0:s}\n", *p);
1408
void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
1409
int firstPage, int lastPage,
1417
if (mode == psModeForm) {
1418
// swap the form and xpdf dicts
1419
writePS("xpdf end begin dup begin\n");
1421
writePS("xpdf begin\n");
1423
for (pg = firstPage; pg <= lastPage; ++pg) {
1424
page = doc->getPage(pg);
1426
error(-1, "Failed writing resources for page %d", pg);
1429
if ((resDict = page->getResourceDict())) {
1430
setupResources(resDict);
1432
annots = new Annots(xref, catalog, page->getAnnots(&obj1));
1434
for (i = 0; i < annots->getNumAnnots(); ++i) {
1435
if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
1436
obj1.streamGetDict()->lookup("Resources", &obj2);
1437
if (obj2.isDict()) {
1438
setupResources(obj2.getDict());
1446
if (mode != psModeForm) {
1447
if (mode != psModeEPS && !manualCtrl) {
1448
writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
1449
paperWidth, paperHeight, duplexA ? "true" : "false");
1452
if (globalParams->getPSOPI()) {
1453
writePS("/opiMatrix matrix currentmatrix def\n");
1459
void PSOutputDev::writePageTrailer() {
1460
if (mode != psModeForm) {
1461
writePS("pdfEndPage\n");
1465
void PSOutputDev::writeTrailer() {
1466
PSOutCustomColor *cc;
1468
if (mode == psModeForm) {
1469
writePS("/Foo exch /Form defineresource pop\n");
1472
writePS("%%DocumentSuppliedResources:\n");
1473
writePS(embFontList->getCString());
1474
if (level == psLevel1Sep || level == psLevel2Sep ||
1475
level == psLevel3Sep) {
1476
writePS("%%DocumentProcessColors:");
1477
if (processColors & psProcessCyan) {
1480
if (processColors & psProcessMagenta) {
1481
writePS(" Magenta");
1483
if (processColors & psProcessYellow) {
1486
if (processColors & psProcessBlack) {
1490
writePS("%%DocumentCustomColors:");
1491
for (cc = customColors; cc; cc = cc->next) {
1492
writePSFmt(" ({0:s})", cc->name->getCString());
1495
writePS("%%CMYKCustomColor:\n");
1496
for (cc = customColors; cc; cc = cc->next) {
1497
writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t})\n",
1498
cc->c, cc->m, cc->y, cc->k, cc->name);
1504
void PSOutputDev::setupResources(Dict *resDict) {
1505
Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
1510
setupFonts(resDict);
1511
setupImages(resDict);
1512
setupForms(resDict);
1514
//----- recursively scan XObjects
1515
resDict->lookup("XObject", &xObjDict);
1516
if (xObjDict.isDict()) {
1517
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
1519
// avoid infinite recursion on XObjects
1521
if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
1522
ref0 = xObjRef.getRef();
1523
for (j = 0; j < xobjStack->getLength(); ++j) {
1524
ref1 = *(Ref *)xobjStack->get(j);
1525
if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
1531
xobjStack->append(&ref0);
1536
// process the XObject's resource dictionary
1537
xObjDict.dictGetVal(i, &xObj);
1538
if (xObj.isStream()) {
1539
xObj.streamGetDict()->lookup("Resources", &resObj);
1540
if (resObj.isDict()) {
1541
setupResources(resObj.getDict());
1548
if (xObjRef.isRef() && !skip) {
1549
xobjStack->del(xobjStack->getLength() - 1);
1556
//----- recursively scan Patterns
1557
resDict->lookup("Pattern", &patDict);
1558
if (patDict.isDict()) {
1559
inType3Char = gTrue;
1560
for (i = 0; i < patDict.dictGetLength(); ++i) {
1562
// avoid infinite recursion on Patterns
1564
if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
1565
ref0 = patRef.getRef();
1566
for (j = 0; j < xobjStack->getLength(); ++j) {
1567
ref1 = *(Ref *)xobjStack->get(j);
1568
if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
1574
xobjStack->append(&ref0);
1579
// process the Pattern's resource dictionary
1580
patDict.dictGetVal(i, &pat);
1581
if (pat.isStream()) {
1582
pat.streamGetDict()->lookup("Resources", &resObj);
1583
if (resObj.isDict()) {
1584
setupResources(resObj.getDict());
1591
if (patRef.isRef() && !skip) {
1592
xobjStack->del(xobjStack->getLength() - 1);
1596
inType3Char = gFalse;
1601
void PSOutputDev::setupFonts(Dict *resDict) {
1604
GfxFontDict *gfxFontDict;
1608
if (forceRasterize) return;
1611
resDict->lookupNF("Font", &obj1);
1613
obj1.fetch(xref, &obj2);
1614
if (obj2.isDict()) {
1616
gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
1619
} else if (obj1.isDict()) {
1620
gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
1623
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
1624
if ((font = gfxFontDict->getFont(i))) {
1625
setupFont(font, resDict);
1633
void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
1636
PSFontParam *fontParam;
1647
DisplayFontParam *dfp;
1649
// check if font is already set up
1650
for (i = 0; i < fontIDLen; ++i) {
1651
if (fontIDs[i].num == font->getID()->num &&
1652
fontIDs[i].gen == font->getID()->gen) {
1657
// add entry to fontIDs list
1658
if (fontIDLen >= fontIDSize) {
1660
fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref));
1662
fontIDs[fontIDLen++] = *font->getID();
1667
// check for resident 8-bit font
1668
if (font->getName() &&
1669
(fontParam = globalParams->getPSFont(font->getName()))) {
1670
psName = new GooString(fontParam->psFontName->getCString());
1672
// check for embedded Type 1 font
1673
} else if (globalParams->getPSEmbedType1() &&
1674
font->getType() == fontType1 &&
1675
font->getEmbeddedFontID(&fontFileID) &&
1676
font->getEmbeddedFontName()) {
1677
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1678
setupEmbeddedType1Font(&fontFileID, psName);
1680
// check for embedded Type 1C font
1681
} else if (globalParams->getPSEmbedType1() &&
1682
font->getType() == fontType1C &&
1683
font->getEmbeddedFontID(&fontFileID) &&
1684
font->getOrigName()) {
1685
// use the PDF font name because the embedded font name might
1686
// not include the subset prefix
1687
psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
1688
setupEmbeddedType1CFont(font, &fontFileID, psName);
1690
// check for embedded OpenType - Type 1C font
1691
} else if (globalParams->getPSEmbedType1() &&
1692
font->getType() == fontType1COT &&
1693
font->getEmbeddedFontID(&fontFileID) &&
1694
font->getOrigName()) {
1695
// use the PDF font name because the embedded font name might
1696
// not include the subset prefix
1697
psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
1698
setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
1700
// check for external Type 1 font file
1701
} else if (globalParams->getPSEmbedType1() &&
1702
font->getType() == fontType1 &&
1703
font->getExtFontFile() &&
1705
// this assumes that the PS font name matches the PDF font name
1706
psName = font->getName()->copy();
1707
setupExternalType1Font(font->getExtFontFile(), psName);
1709
// check for embedded TrueType font
1710
} else if (globalParams->getPSEmbedTrueType() &&
1711
(font->getType() == fontTrueType ||
1712
font->getType() == fontTrueTypeOT) &&
1713
font->getEmbeddedFontID(&fontFileID) &&
1714
font->getEmbeddedFontName()) {
1715
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1716
setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
1718
// check for external TrueType font file
1719
} else if (globalParams->getPSEmbedTrueType() &&
1720
font->getType() == fontTrueType &&
1721
font->getExtFontFile()) {
1722
psName = setupExternalTrueTypeFont(font);
1724
// check for embedded CID PostScript font
1725
} else if (globalParams->getPSEmbedCIDPostScript() &&
1726
font->getType() == fontCIDType0C &&
1727
font->getEmbeddedFontID(&fontFileID) &&
1728
font->getEmbeddedFontName()) {
1729
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1730
setupEmbeddedCIDType0Font(font, &fontFileID, psName);
1732
// check for embedded CID TrueType font
1733
} else if (globalParams->getPSEmbedCIDTrueType() &&
1734
(font->getType() == fontCIDType2 ||
1735
font->getType() == fontCIDType2OT) &&
1736
font->getEmbeddedFontID(&fontFileID) &&
1737
font->getEmbeddedFontName()) {
1738
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1739
setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
1741
// check for embedded OpenType - CID CFF font
1742
} else if (globalParams->getPSEmbedCIDPostScript() &&
1743
font->getType() == fontCIDType0COT &&
1744
font->getEmbeddedFontID(&fontFileID) &&
1745
font->getEmbeddedFontName()) {
1746
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1747
setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
1749
// check for Type 3 font
1750
} else if (font->getType() == fontType3) {
1751
psName = GooString::format("T3_{0:d}_{1:d}",
1752
font->getID()->num, font->getID()->gen);
1753
setupType3Font(font, psName, parentResDict);
1755
// check for external CID TrueType font file
1756
} else if (globalParams->getPSEmbedCIDTrueType() &&
1757
font->getType() == fontCIDType2 &&
1758
font->getExtFontFile()) {
1759
psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile());
1761
// do 8-bit font substitution
1762
} else if (!font->isCIDFont()) {
1764
name = font->getName();
1767
for (i = 0; psFonts[i]; ++i) {
1768
if (name->cmp(psFonts[i]) == 0) {
1769
psName = new GooString(psFonts[i]);
1776
if (font->isFixedWidth()) {
1778
} else if (font->isSerif()) {
1783
if (font->isBold()) {
1786
if (font->isItalic()) {
1789
psName = new GooString(psSubstFonts[i].psName);
1790
for (code = 0; code < 256; ++code) {
1791
if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
1792
charName[0] == 'm' && charName[1] == '\0') {
1797
w1 = ((Gfx8BitFont *)font)->getWidth(code);
1801
w2 = psSubstFonts[i].mWidth;
1807
psName = new GooString(name);
1810
if (font->getType() == fontType3) {
1811
// This is a hack which makes it possible to substitute for some
1812
// Type 3 fonts. The problem is that it's impossible to know what
1813
// the base coordinate system used in the font is without actually
1814
// rendering the font.
1816
fm = font->getFontMatrix();
1818
ys *= fm[3] / fm[0];
1825
// do 16-bit font substitution
1826
} else if ((fontParam = globalParams->
1827
getPSFont16(font->getName(),
1828
((GfxCIDFont *)font)->getCollection(),
1829
font->getWMode()))) {
1831
psName = fontParam->psFontName->copy();
1832
if (font16EncLen >= font16EncSize) {
1833
font16EncSize += 16;
1834
font16Enc = (PSFont16Enc *)greallocn(font16Enc,
1835
font16EncSize, sizeof(PSFont16Enc));
1837
font16Enc[font16EncLen].fontID = *font->getID();
1838
font16Enc[font16EncLen].enc = fontParam->encoding->copy();
1839
if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
1843
error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1844
font16Enc[font16EncLen].enc->getCString());
1847
// try the display font for embedding
1848
} else if (globalParams->getPSEmbedCIDTrueType() &&
1849
((GfxCIDFont *)font)->getCollection() &&
1850
(dfp = globalParams->
1851
getDisplayFont(font)) &&
1852
dfp->kind == displayFontTT) {
1853
psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex);
1855
// give up - can't do anything with this font
1857
error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1858
font->getName() ? font->getName()->getCString() : "(unnamed)",
1859
((GfxCIDFont *)font)->getCollection()
1860
? ((GfxCIDFont *)font)->getCollection()->getCString()
1865
// generate PostScript code to set up the font
1866
if (font->isCIDFont()) {
1867
if (level == psLevel3 || level == psLevel3Sep) {
1868
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
1869
font->getID()->num, font->getID()->gen, psName,
1872
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n",
1873
font->getID()->num, font->getID()->gen, psName,
1877
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.6g} {4:.6g}\n",
1878
font->getID()->num, font->getID()->gen, psName, xs, ys);
1879
for (i = 0; i < 256; i += 8) {
1880
writePS((char *)((i == 0) ? "[ " : " "));
1881
for (j = 0; j < 8; ++j) {
1882
if (font->getType() == fontTrueType &&
1884
!((Gfx8BitFont *)font)->getHasEncoding()) {
1885
sprintf(buf, "c%02x", i+j);
1888
charName = ((Gfx8BitFont *)font)->getCharName(i+j);
1889
// this is a kludge for broken PDF files that encode char 32
1891
if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
1896
writePSName(charName ? charName : (char *)".notdef");
1897
// the empty name is legal in PDF and PostScript, but PostScript
1898
// uses a double-slash (//...) for "immediately evaluated names",
1899
// so we need to add a space character here
1900
if (charName && !charName[0]) {
1904
writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
1906
writePS("pdfMakeFont\n");
1912
void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
1913
static const char hexChar[17] = "0123456789abcdef";
1914
Object refObj, strObj, obj1, obj2, obj3;
1916
int length1, length2, length3;
1920
GBool writePadding = gTrue;
1923
// check if font is already embedded
1924
for (i = 0; i < fontFileIDLen; ++i) {
1925
if (fontFileIDs[i].num == id->num &&
1926
fontFileIDs[i].gen == id->gen)
1930
// add entry to fontFileIDs list
1931
if (fontFileIDLen >= fontFileIDSize) {
1932
fontFileIDSize += 64;
1933
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
1935
fontFileIDs[fontFileIDLen++] = *id;
1937
// get the font stream and info
1938
refObj.initRef(id->num, id->gen);
1939
refObj.fetch(xref, &strObj);
1941
if (!strObj.isStream()) {
1942
error(-1, "Embedded font file object is not a stream");
1945
if (!(dict = strObj.streamGetDict())) {
1946
error(-1, "Embedded font stream is missing its dictionary");
1949
dict->lookup("Length1", &obj1);
1950
dict->lookup("Length2", &obj2);
1951
dict->lookup("Length3", &obj3);
1952
if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
1953
error(-1, "Missing length fields in embedded font stream dictionary");
1959
length1 = obj1.getInt();
1960
length2 = obj2.getInt();
1961
length3 = obj3.getInt();
1966
// beginning comment
1967
writePSFmt("%%BeginResource: font {0:t}\n", psName);
1968
embFontList->append("%%+ font ");
1969
embFontList->append(psName->getCString());
1970
embFontList->append("\n");
1972
// copy ASCII portion of font
1973
strObj.streamReset();
1974
for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
1978
// figure out if encrypted portion is binary or ASCII
1980
for (i = 0; i < 4; ++i) {
1981
start[i] = strObj.streamGetChar();
1982
if (start[i] == EOF) {
1983
error(-1, "Unexpected end of file in embedded font stream");
1986
if (!((start[i] >= '0' && start[i] <= '9') ||
1987
(start[i] >= 'A' && start[i] <= 'F') ||
1988
(start[i] >= 'a' && start[i] <= 'f')))
1994
// length2 == 0 is an error
1995
// trying to solve it by just piping all
1997
error(-1, "Font has length2 as 0, trying to overcome the problem reading the stream until the end");
1999
writePadding = gFalse;
2003
// convert binary data to ASCII
2005
for (i = 0; i < 4; ++i) {
2006
writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
2007
writePSChar(hexChar[start[i] & 0x0f]);
2009
#if 0 // this causes trouble for various PostScript printers
2010
// if Length2 is incorrect (too small), font data gets chopped, so
2011
// we take a few extra characters from the trailer just in case
2012
length2 += length3 >= 8 ? 8 : length3;
2014
while (i < length2) {
2015
if ((c = strObj.streamGetChar()) == EOF) {
2018
writePSChar(hexChar[(c >> 4) & 0x0f]);
2019
writePSChar(hexChar[c & 0x0f]);
2020
if (++i % 32 == 0) {
2028
// already in ASCII format -- just copy it
2030
for (i = 0; i < 4; ++i) {
2031
writePSChar(start[i]);
2033
for (i = 4; i < length2; ++i) {
2034
if ((c = strObj.streamGetChar()) == EOF) {
2044
// write fixed-content portion
2045
while ((c = strObj.streamGetChar()) != EOF) {
2049
// write padding and "cleartomark"
2050
for (i = 0; i < 8; ++i) {
2051
writePS("00000000000000000000000000000000"
2052
"00000000000000000000000000000000\n");
2054
writePS("cleartomark\n");
2059
writePS("%%EndResource\n");
2062
strObj.streamClose();
2066
//~ This doesn't handle .pfb files or binary eexec data (which only
2067
//~ happens in pfb files?).
2068
void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
2073
// check if font is already embedded
2074
for (i = 0; i < fontFileNameLen; ++i) {
2075
if (!fontFileNames[i]->cmp(fileName)) {
2080
// add entry to fontFileNames list
2081
if (fontFileNameLen >= fontFileNameSize) {
2082
fontFileNameSize += 64;
2083
fontFileNames = (GooString **)greallocn(fontFileNames,
2084
fontFileNameSize, sizeof(GooString *));
2085
psFileNames = (GooString **)greallocn(psFileNames,
2086
fontFileNameSize, sizeof(GooString *));
2088
fontFileNames[fontFileNameLen] = fileName->copy();
2089
psFileNames[fontFileNameLen] = psName->copy();
2092
// beginning comment
2093
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2094
embFontList->append("%%+ font ");
2095
embFontList->append(psName->getCString());
2096
embFontList->append("\n");
2098
// copy the font file
2099
if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
2100
error(-1, "Couldn't open external font file");
2103
while ((c = fgetc(fontFile)) != EOF) {
2109
writePS("%%EndResource\n");
2112
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
2113
GooString *psName) {
2119
// check if font is already embedded
2120
for (i = 0; i < fontFileIDLen; ++i) {
2121
if (fontFileIDs[i].num == id->num &&
2122
fontFileIDs[i].gen == id->gen)
2126
// add entry to fontFileIDs list
2127
if (fontFileIDLen >= fontFileIDSize) {
2128
fontFileIDSize += 64;
2129
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2131
fontFileIDs[fontFileIDLen++] = *id;
2133
// beginning comment
2134
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2135
embFontList->append("%%+ font ");
2136
embFontList->append(psName->getCString());
2137
embFontList->append("\n");
2139
// convert it to a Type 1 font
2140
fontBuf = font->readEmbFontFile(xref, &fontLen);
2141
if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
2142
ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
2143
outputFunc, outputStream);
2149
writePS("%%EndResource\n");
2152
void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
2153
GooString *psName) {
2159
// check if font is already embedded
2160
for (i = 0; i < fontFileIDLen; ++i) {
2161
if (fontFileIDs[i].num == id->num &&
2162
fontFileIDs[i].gen == id->gen)
2166
// add entry to fontFileIDs list
2167
if (fontFileIDLen >= fontFileIDSize) {
2168
fontFileIDSize += 64;
2169
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2171
fontFileIDs[fontFileIDLen++] = *id;
2173
// beginning comment
2174
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2175
embFontList->append("%%+ font ");
2176
embFontList->append(psName->getCString());
2177
embFontList->append("\n");
2179
// convert it to a Type 1 font
2180
fontBuf = font->readEmbFontFile(xref, &fontLen);
2181
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2182
if (ffTT->isOpenTypeCFF()) {
2183
ffTT->convertToType1(psName->getCString(), NULL, gTrue,
2184
outputFunc, outputStream);
2191
writePS("%%EndResource\n");
2194
void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
2195
GooString *psName) {
2202
// check if font is already embedded
2203
for (i = 0; i < fontFileIDLen; ++i) {
2204
if (fontFileIDs[i].num == id->num &&
2205
fontFileIDs[i].gen == id->gen) {
2206
psName->appendf("_{0:d}", nextTrueTypeNum++);
2211
// add entry to fontFileIDs list
2212
if (i == fontFileIDLen) {
2213
if (fontFileIDLen >= fontFileIDSize) {
2214
fontFileIDSize += 64;
2215
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2217
fontFileIDs[fontFileIDLen++] = *id;
2220
// beginning comment
2221
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2222
embFontList->append("%%+ font ");
2223
embFontList->append(psName->getCString());
2224
embFontList->append("\n");
2226
// convert it to a Type 42 font
2227
fontBuf = font->readEmbFontFile(xref, &fontLen);
2228
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2229
codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
2230
ffTT->convertToType42(psName->getCString(),
2231
((Gfx8BitFont *)font)->getHasEncoding()
2232
? ((Gfx8BitFont *)font)->getEncoding()
2234
codeToGID, outputFunc, outputStream);
2236
if (font8InfoLen >= font8InfoSize) {
2237
font8InfoSize += 16;
2238
font8Info = (PSFont8Info *)greallocn(font8Info,
2240
sizeof(PSFont8Info));
2242
font8Info[font8InfoLen].fontID = *font->getID();
2243
font8Info[font8InfoLen].codeToGID = codeToGID;
2251
writePS("%%EndResource\n");
2254
GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
2255
GooString *fileName;
2263
// check if font is already embedded
2264
fileName = font->getExtFontFile();
2265
for (i = 0; i < fontFileNameLen; ++i) {
2266
if (!fontFileNames[i]->cmp(fileName)) {
2267
return psFileNames[i]->copy();
2271
psName = font->getName()->sanitizedName(gTrue /* ps mode */);
2272
// add entry to fontFileNames list
2273
if (i == fontFileNameLen) {
2274
if (fontFileNameLen >= fontFileNameSize) {
2275
fontFileNameSize += 64;
2277
(GooString **)greallocn(fontFileNames,
2278
fontFileNameSize, sizeof(GooString *));
2280
(GooString **)greallocn(psFileNames,
2281
fontFileNameSize, sizeof(GooString *));
2283
fontFileNames[fontFileNameLen] = fileName->copy();
2284
psFileNames[fontFileNameLen] = psName->copy();
2288
// beginning comment
2289
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2290
embFontList->append("%%+ font ");
2291
embFontList->append(psName->getCString());
2292
embFontList->append("\n");
2294
// convert it to a Type 42 font
2295
fontBuf = font->readExtFontFile(&fontLen);
2296
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2297
codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
2298
ffTT->convertToType42(psName->getCString(),
2299
((Gfx8BitFont *)font)->getHasEncoding()
2300
? ((Gfx8BitFont *)font)->getEncoding()
2302
codeToGID, outputFunc, outputStream);
2304
if (font8InfoLen >= font8InfoSize) {
2305
font8InfoSize += 16;
2306
font8Info = (PSFont8Info *)greallocn(font8Info,
2308
sizeof(PSFont8Info));
2310
font8Info[font8InfoLen].fontID = *font->getID();
2311
font8Info[font8InfoLen].codeToGID = codeToGID;
2319
writePS("%%EndResource\n");
2323
GooString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex) {
2328
GooString *myFileName;
2330
myFileName = fileName->copy();
2331
if (faceIndex > 0) {
2333
sprintf(tmp, ",%d", faceIndex);
2334
myFileName->append(tmp);
2336
// check if font is already embedded
2337
for (i = 0; i < fontFileNameLen; ++i) {
2338
if (!fontFileNames[i]->cmp(myFileName)) {
2340
return psFileNames[i]->copy();
2344
psName = font->getName()->sanitizedName(gTrue /* ps mode */);
2345
// add entry to fontFileNames list
2346
if (i == fontFileNameLen) {
2347
if (fontFileNameLen >= fontFileNameSize) {
2348
fontFileNameSize += 64;
2350
(GooString **)grealloc(fontFileNames,
2351
fontFileNameSize * sizeof(GooString *));
2353
(GooString **)grealloc(psFileNames,
2354
fontFileNameSize * sizeof(GooString *));
2357
fontFileNames[fontFileNameLen] = myFileName;
2358
psFileNames[fontFileNameLen] = psName->copy();
2361
// beginning comment
2362
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2363
embFontList->append("%%+ font ");
2364
embFontList->append(psName->getCString());
2365
embFontList->append("\n");
2367
// convert it to a CID type2 font
2368
if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) {
2369
int n = ((GfxCIDFont *)font)->getCIDToGIDLen();
2371
codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
2372
memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort));
2374
codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n);
2376
if (globalParams->getPSLevel() >= psLevel3) {
2377
// Level 3: use a CID font
2378
ffTT->convertToCIDType2(psName->getCString(),
2379
codeToGID, n, gTrue,
2380
outputFunc, outputStream);
2382
// otherwise: use a non-CID composite font
2383
ffTT->convertToType0(psName->getCString(),
2384
codeToGID, n, gTrue,
2385
outputFunc, outputStream);
2392
writePS("%%EndResource\n");
2396
void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
2397
GooString *psName) {
2403
// check if font is already embedded
2404
for (i = 0; i < fontFileIDLen; ++i) {
2405
if (fontFileIDs[i].num == id->num &&
2406
fontFileIDs[i].gen == id->gen)
2410
// add entry to fontFileIDs list
2411
if (fontFileIDLen >= fontFileIDSize) {
2412
fontFileIDSize += 64;
2413
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2415
fontFileIDs[fontFileIDLen++] = *id;
2417
// beginning comment
2418
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2419
embFontList->append("%%+ font ");
2420
embFontList->append(psName->getCString());
2421
embFontList->append("\n");
2423
// convert it to a Type 0 font
2424
fontBuf = font->readEmbFontFile(xref, &fontLen);
2425
if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
2426
if (globalParams->getPSLevel() >= psLevel3) {
2427
// Level 3: use a CID font
2428
ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
2430
// otherwise: use a non-CID composite font
2431
ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
2438
writePS("%%EndResource\n");
2441
void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
2443
GBool needVerticalMetrics) {
2449
// check if font is already embedded
2450
for (i = 0; i < fontFileIDLen; ++i) {
2451
if (fontFileIDs[i].num == id->num &&
2452
fontFileIDs[i].gen == id->gen) {
2453
psName->appendf("_{0:d}", nextTrueTypeNum++);
2458
// add entry to fontFileIDs list
2459
if (fontFileIDLen >= fontFileIDSize) {
2460
fontFileIDSize += 64;
2461
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2463
fontFileIDs[fontFileIDLen++] = *id;
2465
// beginning comment
2466
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2467
embFontList->append("%%+ font ");
2468
embFontList->append(psName->getCString());
2469
embFontList->append("\n");
2471
// convert it to a Type 0 font
2472
fontBuf = font->readEmbFontFile(xref, &fontLen);
2473
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2474
if (globalParams->getPSLevel() >= psLevel3) {
2475
// Level 3: use a CID font
2476
ffTT->convertToCIDType2(psName->getCString(),
2477
((GfxCIDFont *)font)->getCIDToGID(),
2478
((GfxCIDFont *)font)->getCIDToGIDLen(),
2479
needVerticalMetrics,
2480
outputFunc, outputStream);
2482
// otherwise: use a non-CID composite font
2483
ffTT->convertToType0(psName->getCString(),
2484
((GfxCIDFont *)font)->getCIDToGID(),
2485
((GfxCIDFont *)font)->getCIDToGIDLen(),
2486
needVerticalMetrics,
2487
outputFunc, outputStream);
2494
writePS("%%EndResource\n");
2497
void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
2498
GooString *psName) {
2504
// check if font is already embedded
2505
for (i = 0; i < fontFileIDLen; ++i) {
2506
if (fontFileIDs[i].num == id->num &&
2507
fontFileIDs[i].gen == id->gen)
2511
// add entry to fontFileIDs list
2512
if (fontFileIDLen >= fontFileIDSize) {
2513
fontFileIDSize += 64;
2514
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2516
fontFileIDs[fontFileIDLen++] = *id;
2518
// beginning comment
2519
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2520
embFontList->append("%%+ font ");
2521
embFontList->append(psName->getCString());
2522
embFontList->append("\n");
2524
// convert it to a Type 0 font
2525
fontBuf = font->readEmbFontFile(xref, &fontLen);
2526
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2527
if (ffTT->isOpenTypeCFF()) {
2528
if (globalParams->getPSLevel() >= psLevel3) {
2529
// Level 3: use a CID font
2530
ffTT->convertToCIDType0(psName->getCString(),
2531
outputFunc, outputStream);
2533
// otherwise: use a non-CID composite font
2534
ffTT->convertToType0(psName->getCString(), outputFunc, outputStream);
2542
writePS("%%EndResource\n");
2545
void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
2546
Dict *parentResDict) {
2556
// set up resources used by font
2557
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
2558
inType3Char = gTrue;
2559
setupResources(resDict);
2560
inType3Char = gFalse;
2562
resDict = parentResDict;
2565
// beginning comment
2566
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2567
embFontList->append("%%+ font ");
2568
embFontList->append(psName->getCString());
2569
embFontList->append("\n");
2572
writePS("8 dict begin\n");
2573
writePS("/FontType 3 def\n");
2574
m = font->getFontMatrix();
2575
writePSFmt("/FontMatrix [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
2576
m[0], m[1], m[2], m[3], m[4], m[5]);
2577
m = font->getFontBBox();
2578
writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
2579
m[0], m[1], m[2], m[3]);
2580
writePS("/Encoding 256 array def\n");
2581
writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2582
writePS("/BuildGlyph {\n");
2583
writePS(" exch /CharProcs get exch\n");
2584
writePS(" 2 copy known not { pop /.notdef } if\n");
2585
writePS(" get exec\n");
2586
writePS("} bind def\n");
2587
writePS("/BuildChar {\n");
2588
writePS(" 1 index /Encoding get exch get\n");
2589
writePS(" 1 index /BuildGlyph get exec\n");
2590
writePS("} bind def\n");
2591
if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
2592
writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength());
2593
writePS("CharProcs begin\n");
2598
gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
2599
inType3Char = gTrue;
2600
for (i = 0; i < charProcs->getLength(); ++i) {
2601
t3Cacheable = gFalse;
2602
t3NeedsRestore = gFalse;
2604
writePSName(charProcs->getKey(i));
2606
gfx->display(charProcs->getVal(i, &charProc));
2610
buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
2611
t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
2613
buf = GooString::format("{0:.6g} {1:.6g} setcharwidth\n", t3WX, t3WY);
2615
(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
2617
(*outputFunc)(outputStream, t3String->getCString(),
2618
t3String->getLength());
2622
if (t3NeedsRestore) {
2623
(*outputFunc)(outputStream, "Q\n", 2);
2627
inType3Char = gFalse;
2631
writePS("currentdict end\n");
2632
writePSFmt("/{0:t} exch definefont pop\n", psName);
2635
writePS("%%EndResource\n");
2638
void PSOutputDev::setupImages(Dict *resDict) {
2639
Object xObjDict, xObj, xObjRef, subtypeObj;
2642
if (!(mode == psModeForm || inType3Char || preload)) {
2646
//----- recursively scan XObjects
2647
resDict->lookup("XObject", &xObjDict);
2648
if (xObjDict.isDict()) {
2649
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
2650
xObjDict.dictGetValNF(i, &xObjRef);
2651
xObjDict.dictGetVal(i, &xObj);
2652
if (xObj.isStream()) {
2653
xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
2654
if (subtypeObj.isName("Image")) {
2655
if (xObjRef.isRef()) {
2656
setupImage(xObjRef.getRef(), xObj.getStream());
2658
error(-1, "Image in resource dict is not an indirect reference");
2670
void PSOutputDev::setupImage(Ref id, Stream *str) {
2671
GBool useRLE, useCompressed, useASCIIHex;
2674
int size, line, col, i;
2675
int outerSize, outer;
2677
// check if image is already setup
2678
for (i = 0; i < imgIDLen; ++i) {
2679
if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
2684
// add entry to imgIDs list
2685
if (imgIDLen >= imgIDSize) {
2686
if (imgIDSize == 0) {
2691
imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
2693
imgIDs[imgIDLen++] = id;
2696
//~ this does not correctly handle the DeviceN color space
2697
//~ -- need to use DeviceNRecoder
2698
if (level < psLevel2) {
2700
useCompressed = gFalse;
2701
useASCIIHex = gTrue;
2703
s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
2706
useCompressed = gTrue;
2710
useCompressed = gFalse;
2712
useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
2713
globalParams->getPSASCIIHex();
2715
if (useCompressed) {
2716
str = str->getUndecodedStream();
2719
str = new RunLengthEncoder(str);
2722
str = new ASCIIHexEncoder(str);
2724
str = new ASCII85Encoder(str);
2727
// compute image data size
2733
} while (c == '\n' || c == '\r');
2734
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2741
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2744
} while (c == '\n' || c == '\r');
2745
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2750
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2758
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
2759
// add one entry for the final line of data; add another entry
2760
// because the RunLengthDecode filter may read past the end
2765
outerSize = size/65535 + 1;
2767
writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
2768
outerSize, id.num, id.gen);
2771
// write the data into the array
2773
for (outer = 0;outer < outerSize;outer++) {
2774
int innerSize = size > 65535 ? 65535 : size;
2776
// put the inner array into the outer array
2777
writePSFmt("{0:d} array 1 index {1:d} 2 index put\n",
2780
writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
2784
} while (c == '\n' || c == '\r');
2785
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2794
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2797
} while (c == '\n' || c == '\r');
2798
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2805
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2808
// each line is: "dup nnnnn <~...data...~> put<eol>"
2809
// so max data length = 255 - 20 = 235
2810
// chunks are 1 or 4 bytes each, so we have to stop at 232
2811
// but make it 225 just to be safe
2813
writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2815
if (line >= innerSize) break;
2816
writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line);
2820
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2821
writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2824
writePSFmt("{0:d} <> put\n", line);
2839
void PSOutputDev::setupForms(Dict *resDict) {
2840
Object xObjDict, xObj, xObjRef, subtypeObj;
2847
resDict->lookup("XObject", &xObjDict);
2848
if (xObjDict.isDict()) {
2849
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
2850
xObjDict.dictGetValNF(i, &xObjRef);
2851
xObjDict.dictGetVal(i, &xObj);
2852
if (xObj.isStream()) {
2853
xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
2854
if (subtypeObj.isName("Form")) {
2855
if (xObjRef.isRef()) {
2856
setupForm(xObjRef.getRef(), &xObj);
2858
error(-1, "Form in resource dict is not an indirect reference");
2870
void PSOutputDev::setupForm(Ref id, Object *strObj) {
2871
Dict *dict, *resDict;
2872
Object matrixObj, bboxObj, resObj, obj1;
2873
double m[6], bbox[4];
2878
// check if form is already defined
2879
for (i = 0; i < formIDLen; ++i) {
2880
if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
2885
// add entry to formIDs list
2886
if (formIDLen >= formIDSize) {
2887
if (formIDSize == 0) {
2892
formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref));
2894
formIDs[formIDLen++] = id;
2896
dict = strObj->streamGetDict();
2899
dict->lookup("BBox", &bboxObj);
2900
if (!bboxObj.isArray()) {
2902
error(-1, "Bad form bounding box");
2905
for (i = 0; i < 4; ++i) {
2906
bboxObj.arrayGet(i, &obj1);
2907
bbox[i] = obj1.getNum();
2913
dict->lookup("Matrix", &matrixObj);
2914
if (matrixObj.isArray()) {
2915
for (i = 0; i < 6; ++i) {
2916
matrixObj.arrayGet(i, &obj1);
2917
m[i] = obj1.getNum();
2928
dict->lookup("Resources", &resObj);
2929
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
2931
writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
2933
writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
2934
m[0], m[1], m[2], m[3], m[4], m[5]);
2940
gfx = new Gfx(xref, this, resDict, m_catalog, &box, &box);
2941
gfx->display(strObj);
2950
GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
2951
int rotateA, GBool useMediaBox, GBool crop,
2952
int sliceX, int sliceY,
2953
int sliceW, int sliceH,
2954
GBool printing, Catalog *catalog,
2955
GBool (*abortCheckCbk)(void *data),
2956
void *abortCheckCbkData) {
2958
PreScanOutputDev *scan;
2960
SplashOutputDev *splashOut;
2961
SplashColor paperColor;
2964
SplashBitmap *bitmap;
2969
double m0, m1, m2, m3, m4, m5;
2970
int c, w, h, x, y, comp, i;
2971
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
2974
if (!forceRasterize) {
2975
scan = new PreScanOutputDev();
2976
page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
2977
sliceX, sliceY, sliceW, sliceH,
2978
printing, catalog, abortCheckCbk, abortCheckCbkData);
2979
rasterize = scan->usesTransparency() || scan->hasLevel1PSBug();
2988
// rasterize the page
2989
if (level == psLevel1) {
2990
paperColor[0] = 0xff;
2991
splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
2992
paperColor, gTrue, gFalse);
2994
} else if (level == psLevel1Sep) {
2995
paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
2996
splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
2997
paperColor, gTrue, gFalse);
2999
} else if (level == psLevel1Sep) {
3000
error(-1, "pdftops was built without CMYK support, level1sep needs it to work in this file");
3004
paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
3005
splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
3006
paperColor, gTrue, gFalse);
3008
splashOut->startDoc(xref);
3009
page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
3011
sliceX, sliceY, sliceW, sliceH,
3012
printing, catalog, abortCheckCbk, abortCheckCbkData);
3014
// start the PS page
3015
page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
3016
sliceX, sliceY, sliceW, sliceH, &box, &crop);
3017
rotateA += page->getRotate();
3018
if (rotateA >= 360) {
3020
} else if (rotateA < 0) {
3023
state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
3024
startPage(page->getNum(), state);
3028
default: // this should never happen
3029
m0 = box.x2 - box.x1;
3032
m3 = box.y2 - box.y1;
3038
m1 = box.y2 - box.y1;
3039
m2 = -(box.x2 - box.x1);
3045
m0 = -(box.x2 - box.x1);
3048
m3 = -(box.y2 - box.y1);
3054
m1 = -(box.y2 - box.y1);
3055
m2 = box.x2 - box.x1;
3062
//~ need to add the process colors
3064
// draw the rasterized image
3065
bitmap = splashOut->getBitmap();
3066
w = bitmap->getWidth();
3067
h = bitmap->getHeight();
3069
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
3070
m0, m1, m2, m3, m4, m5);
3073
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
3075
p = bitmap->getDataPtr();
3077
for (y = 0; y < h; ++y) {
3078
for (x = 0; x < w; ++x) {
3080
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3082
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3085
writePSBuf(hexBuf, i);
3092
writePSBuf(hexBuf, i);
3096
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
3098
p = bitmap->getDataPtr();
3100
col[0] = col[1] = col[2] = col[3] = 0;
3101
if (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0) {
3102
for (y = 0; y < h; ++y) {
3103
for (comp = 0; comp < 4; ++comp) {
3104
for (x = 0; x < w; ++x) {
3105
col[comp] |= p[4*x + comp];
3106
digit = p[4*x + comp] / 16;
3107
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3108
digit = p[4*x + comp] % 16;
3109
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3112
writePSBuf(hexBuf, i);
3117
p += bitmap->getRowSize();
3120
for (y = 0; y < h; ++y) {
3121
for (comp = 0; comp < 4; ++comp) {
3122
for (x = 0; x < w; ++x) {
3123
digit = p[4*x + comp] / 16;
3124
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3125
digit = p[4*x + comp] % 16;
3126
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3129
writePSBuf(hexBuf, i);
3134
p += bitmap->getRowSize();
3139
writePSBuf(hexBuf, i);
3142
processColors |= psProcessCyan;
3145
processColors |= psProcessMagenta;
3148
processColors |= psProcessYellow;
3151
processColors |= psProcessBlack;
3158
writePS("/DeviceRGB setcolorspace\n");
3159
writePS("<<\n /ImageType 1\n");
3160
writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
3161
writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
3162
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
3163
writePS(" /BitsPerComponent 8\n");
3164
writePS(" /Decode [0 1 0 1 0 1]\n");
3165
writePS(" /DataSource currentfile\n");
3166
if (globalParams->getPSASCIIHex()) {
3167
writePS(" /ASCIIHexDecode filter\n");
3169
writePS(" /ASCII85Decode filter\n");
3171
writePS(" /RunLengthDecode filter\n");
3175
str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
3176
str = new RunLengthEncoder(str0);
3177
if (globalParams->getPSASCIIHex()) {
3178
str = new ASCIIHexEncoder(str);
3180
str = new ASCII85Encoder(str);
3183
while ((c = str->getChar()) != EOF) {
3189
processColors |= psProcessCMYK;
3193
writePS("grestore\n");
3195
// finish the PS page
3204
void PSOutputDev::startPage(int pageNum, GfxState *state) {
3205
int x1, y1, x2, y2, width, height;
3206
int imgWidth, imgHeight, imgWidth2, imgHeight2;
3210
if (mode == psModePS || mode == psModePSOrigPageSizes) {
3211
GooString pageLabel;
3212
const GBool gotLabel = m_catalog->indexToLabel(pageNum -1, &pageLabel);
3214
// See bug13338 for why we try to avoid parentheses...
3216
GooString *filteredString = filterPSLabel(&pageLabel, &needParens);
3218
writePSFmt("%%Page: ({0:t}) {1:d}\n", filteredString, seqPage);
3220
writePSFmt("%%Page: {0:t} {1:d}\n", filteredString, seqPage);
3222
delete filteredString;
3224
writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
3226
if (mode != psModePSOrigPageSizes)
3227
writePS("%%BeginPageSetup\n");
3232
(*underlayCbk)(this, underlayCbkData);
3240
case psModePSOrigPageSizes:
3241
x1 = (int)floor(state->getX1());
3242
y1 = (int)floor(state->getY1());
3243
x2 = (int)ceil(state->getX2());
3244
y2 = (int)ceil(state->getY2());
3247
if (width > height) {
3252
writePSFmt("%%PageBoundingBox: {0:d} {1:d} {2:d} {3:d}\n", x1, y1, x2 - x1, y2 - y1);
3253
writePS("%%BeginPageSetup\n");
3254
writePSFmt("%%PageOrientation: {0:s}\n",
3255
landscape ? "Landscape" : "Portrait");
3256
if ((width != prevWidth) || (height != prevHeight)) {
3257
// Set page size only when it actually changes, as otherwise Duplex
3258
// printing does not work
3259
writePSFmt("<</PageSize [{0:d} {1:d}]>> setpagedevice\n", width, height);
3261
prevHeight = height;
3263
writePS("pdfStartPage\n");
3264
writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
3265
writePS("%%EndPageSetup\n");
3270
// rotate, translate, and scale page
3271
imgWidth = imgURX - imgLLX;
3272
imgHeight = imgURY - imgLLY;
3273
x1 = (int)floor(state->getX1());
3274
y1 = (int)floor(state->getY1());
3275
x2 = (int)ceil(state->getX2());
3276
y2 = (int)ceil(state->getY2());
3280
// rotation and portrait/landscape mode
3282
rotate = (360 - rotate0) % 360;
3285
rotate = (360 - state->getRotate()) % 360;
3286
if (rotate == 0 || rotate == 180) {
3287
if (width > height && width > imgWidth) {
3293
} else { // rotate == 90 || rotate == 270
3294
if (height > width && height > imgWidth) {
3295
rotate = 270 - rotate;
3302
writePSFmt("%%PageOrientation: {0:s}\n",
3303
landscape ? "Landscape" : "Portrait");
3304
writePS("pdfStartPage\n");
3306
imgWidth2 = imgWidth;
3307
imgHeight2 = imgHeight;
3308
} else if (rotate == 90) {
3309
writePS("90 rotate\n");
3311
imgWidth2 = imgHeight;
3312
imgHeight2 = imgWidth;
3313
} else if (rotate == 180) {
3314
writePS("180 rotate\n");
3315
imgWidth2 = imgWidth;
3316
imgHeight2 = imgHeight;
3319
} else { // rotate == 270
3320
writePS("270 rotate\n");
3322
imgWidth2 = imgHeight;
3323
imgHeight2 = imgWidth;
3326
if (xScale0 > 0 && yScale0 > 0) {
3329
} else if ((globalParams->getPSShrinkLarger() &&
3330
(width > imgWidth2 || height > imgHeight2)) ||
3331
(globalParams->getPSExpandSmaller() &&
3332
(width < imgWidth2 && height < imgHeight2))) {
3333
xScale = (double)imgWidth2 / (double)width;
3334
yScale = (double)imgHeight2 / (double)height;
3335
if (yScale < xScale) {
3341
xScale = yScale = 1;
3343
// deal with odd bounding boxes or clipping
3344
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3345
tx -= xScale * clipLLX0;
3346
ty -= yScale * clipLLY0;
3352
if (tx0 >= 0 && ty0 >= 0) {
3353
tx += rotate == 0 ? tx0 : ty0;
3354
ty += rotate == 0 ? ty0 : -tx0;
3355
} else if (globalParams->getPSCenter()) {
3356
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3357
tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
3358
ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2;
3360
tx += (imgWidth2 - xScale * width) / 2;
3361
ty += (imgHeight2 - yScale * height) / 2;
3364
tx += rotate == 0 ? imgLLX : imgLLY;
3365
ty += rotate == 0 ? imgLLY : -imgLLX;
3366
if (tx != 0 || ty != 0) {
3367
writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
3369
if (xScale != 1 || yScale != 1) {
3370
writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
3372
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3373
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
3374
clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
3376
writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
3379
writePS("%%EndPageSetup\n");
3384
writePS("pdfStartPage\n");
3386
rotate = (360 - state->getRotate()) % 360;
3388
} else if (rotate == 90) {
3389
writePS("90 rotate\n");
3392
} else if (rotate == 180) {
3393
writePS("180 rotate\n");
3394
tx = -(epsX1 + epsX2);
3395
ty = -(epsY1 + epsY2);
3396
} else { // rotate == 270
3397
writePS("270 rotate\n");
3401
if (tx != 0 || ty != 0) {
3402
writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
3404
xScale = yScale = 1;
3408
writePS("/PaintProc {\n");
3409
writePS("begin xpdf begin\n");
3410
writePS("pdfStartPage\n");
3412
xScale = yScale = 1;
3418
void PSOutputDev::endPage() {
3421
(*overlayCbk)(this, overlayCbkData);
3425
if (mode == psModeForm) {
3426
writePS("pdfEndPage\n");
3427
writePS("end end\n");
3429
writePS("end end\n");
3432
writePS("showpage\n");
3434
writePS("%%PageTrailer\n");
3439
void PSOutputDev::saveState(GfxState *state) {
3444
void PSOutputDev::restoreState(GfxState *state) {
3449
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
3450
double m21, double m22, double m31, double m32) {
3451
writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
3452
m11, m12, m21, m22, m31, m32);
3455
void PSOutputDev::updateLineDash(GfxState *state) {
3460
state->getLineDash(&dash, &length, &start);
3462
for (i = 0; i < length; ++i) {
3463
writePSFmt("{0:.6g}{1:w}",
3464
dash[i] < 0 ? 0 : dash[i],
3465
(i == length-1) ? 0 : 1);
3467
writePSFmt("] {0:.6g} d\n", start);
3470
void PSOutputDev::updateFlatness(GfxState *state) {
3471
writePSFmt("{0:d} i\n", state->getFlatness());
3474
void PSOutputDev::updateLineJoin(GfxState *state) {
3475
writePSFmt("{0:d} j\n", state->getLineJoin());
3478
void PSOutputDev::updateLineCap(GfxState *state) {
3479
writePSFmt("{0:d} J\n", state->getLineCap());
3482
void PSOutputDev::updateMiterLimit(GfxState *state) {
3483
writePSFmt("{0:.6g} M\n", state->getMiterLimit());
3486
void PSOutputDev::updateLineWidth(GfxState *state) {
3487
writePSFmt("{0:.6g} w\n", state->getLineWidth());
3490
void PSOutputDev::updateFillColorSpace(GfxState *state) {
3497
if (state->getFillColorSpace()->getMode() != csPattern) {
3498
dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
3508
void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
3515
if (state->getStrokeColorSpace()->getMode() != csPattern) {
3516
dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
3526
void PSOutputDev::updateFillColor(GfxState *state) {
3531
GfxSeparationColorSpace *sepCS;
3537
state->getFillGray(&gray);
3538
writePSFmt("{0:.4g} g\n", colToDbl(gray));
3541
state->getFillCMYK(&cmyk);
3542
c = colToDbl(cmyk.c);
3543
m = colToDbl(cmyk.m);
3544
y = colToDbl(cmyk.y);
3545
k = colToDbl(cmyk.k);
3546
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
3547
addProcessColor(c, m, y, k);
3551
if (state->getFillColorSpace()->getMode() != csPattern) {
3552
colorPtr = state->getFillColor();
3554
for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) {
3558
writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
3565
if (state->getFillColorSpace()->getMode() == csSeparation) {
3566
sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
3567
color.c[0] = gfxColorComp1;
3568
sepCS->getCMYK(&color, &cmyk);
3569
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
3570
colToDbl(state->getFillColor()->c[0]),
3571
colToDbl(cmyk.c), colToDbl(cmyk.m),
3572
colToDbl(cmyk.y), colToDbl(cmyk.k),
3574
addCustomColor(sepCS);
3576
state->getFillCMYK(&cmyk);
3577
c = colToDbl(cmyk.c);
3578
m = colToDbl(cmyk.m);
3579
y = colToDbl(cmyk.y);
3580
k = colToDbl(cmyk.k);
3581
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
3582
addProcessColor(c, m, y, k);
3586
t3Cacheable = gFalse;
3589
void PSOutputDev::updateStrokeColor(GfxState *state) {
3594
GfxSeparationColorSpace *sepCS;
3600
state->getStrokeGray(&gray);
3601
writePSFmt("{0:.4g} G\n", colToDbl(gray));
3604
state->getStrokeCMYK(&cmyk);
3605
c = colToDbl(cmyk.c);
3606
m = colToDbl(cmyk.m);
3607
y = colToDbl(cmyk.y);
3608
k = colToDbl(cmyk.k);
3609
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
3610
addProcessColor(c, m, y, k);
3614
if (state->getStrokeColorSpace()->getMode() != csPattern) {
3615
colorPtr = state->getStrokeColor();
3617
for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) {
3621
writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
3628
if (state->getStrokeColorSpace()->getMode() == csSeparation) {
3629
sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
3630
color.c[0] = gfxColorComp1;
3631
sepCS->getCMYK(&color, &cmyk);
3632
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
3633
colToDbl(state->getStrokeColor()->c[0]),
3634
colToDbl(cmyk.c), colToDbl(cmyk.m),
3635
colToDbl(cmyk.y), colToDbl(cmyk.k),
3637
addCustomColor(sepCS);
3639
state->getStrokeCMYK(&cmyk);
3640
c = colToDbl(cmyk.c);
3641
m = colToDbl(cmyk.m);
3642
y = colToDbl(cmyk.y);
3643
k = colToDbl(cmyk.k);
3644
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
3645
addProcessColor(c, m, y, k);
3649
t3Cacheable = gFalse;
3652
void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
3654
processColors |= psProcessCyan;
3657
processColors |= psProcessMagenta;
3660
processColors |= psProcessYellow;
3663
processColors |= psProcessBlack;
3667
void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
3668
PSOutCustomColor *cc;
3672
for (cc = customColors; cc; cc = cc->next) {
3673
if (!cc->name->cmp(sepCS->getName())) {
3677
color.c[0] = gfxColorComp1;
3678
sepCS->getCMYK(&color, &cmyk);
3679
cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
3680
colToDbl(cmyk.y), colToDbl(cmyk.k),
3681
sepCS->getName()->copy());
3682
cc->next = customColors;
3686
void PSOutputDev::updateFillOverprint(GfxState *state) {
3687
if (level >= psLevel2) {
3688
writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
3692
void PSOutputDev::updateStrokeOverprint(GfxState *state) {
3693
if (level >= psLevel2) {
3694
writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
3698
void PSOutputDev::updateTransfer(GfxState *state) {
3702
funcs = state->getTransfer();
3703
if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
3704
if (level >= psLevel2) {
3705
for (i = 0; i < 4; ++i) {
3706
cvtFunction(funcs[i]);
3708
writePS("setcolortransfer\n");
3710
cvtFunction(funcs[3]);
3711
writePS("settransfer\n");
3713
} else if (funcs[0]) {
3714
cvtFunction(funcs[0]);
3715
writePS("settransfer\n");
3717
writePS("{} settransfer\n");
3721
void PSOutputDev::updateFont(GfxState *state) {
3722
if (state->getFont()) {
3723
writePSFmt("/F{0:d}_{1:d} {2:.6g} Tf\n",
3724
state->getFont()->getID()->num, state->getFont()->getID()->gen,
3725
fabs(state->getFontSize()) < 0.00001 ? 0.00001
3726
: state->getFontSize());
3730
void PSOutputDev::updateTextMat(GfxState *state) {
3733
mat = state->getTextMat();
3734
if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
3735
// avoid a singular (or close-to-singular) matrix
3736
writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]);
3738
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n",
3739
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3743
void PSOutputDev::updateCharSpace(GfxState *state) {
3744
writePSFmt("{0:.6g} Tc\n", state->getCharSpace());
3747
void PSOutputDev::updateRender(GfxState *state) {
3750
rm = state->getRender();
3751
writePSFmt("{0:d} Tr\n", rm);
3753
if (rm != 0 && rm != 3) {
3754
t3Cacheable = gFalse;
3758
void PSOutputDev::updateRise(GfxState *state) {
3759
writePSFmt("{0:.6g} Ts\n", state->getRise());
3762
void PSOutputDev::updateWordSpace(GfxState *state) {
3763
writePSFmt("{0:.6g} Tw\n", state->getWordSpace());
3766
void PSOutputDev::updateHorizScaling(GfxState *state) {
3769
h = state->getHorizScaling();
3770
if (fabs(h) < 0.01) {
3773
writePSFmt("{0:.6g} Tz\n", h);
3776
void PSOutputDev::updateTextPos(GfxState *state) {
3777
writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY());
3780
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
3781
if (state->getFont()->getWMode()) {
3782
writePSFmt("{0:.6g} TJmV\n", shift);
3784
writePSFmt("{0:.6g} TJm\n", shift);
3788
void PSOutputDev::stroke(GfxState *state) {
3789
doPath(state->getPath());
3791
// if we're construct a cacheable Type 3 glyph, we need to do
3792
// everything in the fill color
3799
void PSOutputDev::fill(GfxState *state) {
3800
doPath(state->getPath());
3804
void PSOutputDev::eoFill(GfxState *state) {
3805
doPath(state->getPath());
3809
GBool PSOutputDev::tilingPatternFill(GfxState *state, Object *str,
3810
int paintType, Dict *resDict,
3811
double *mat, double *bbox,
3812
int x0, int y0, int x1, int y1,
3813
double xStep, double yStep) {
3817
// define a Type 3 font
3818
writePS("8 dict begin\n");
3819
writePS("/FontType 3 def\n");
3820
writePS("/FontMatrix [1 0 0 1 0 0] def\n");
3821
writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
3822
bbox[0], bbox[1], bbox[2], bbox[3]);
3823
writePS("/Encoding 256 array def\n");
3824
writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
3825
writePS(" Encoding 120 /x put\n");
3826
writePS("/BuildGlyph {\n");
3827
writePS(" exch /CharProcs get exch\n");
3828
writePS(" 2 copy known not { pop /.notdef } if\n");
3829
writePS(" get exec\n");
3830
writePS("} bind def\n");
3831
writePS("/BuildChar {\n");
3832
writePS(" 1 index /Encoding get exch get\n");
3833
writePS(" 1 index /BuildGlyph get exec\n");
3834
writePS("} bind def\n");
3835
writePS("/CharProcs 1 dict def\n");
3836
writePS("CharProcs begin\n");
3841
gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
3843
if (paintType == 2) {
3844
writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
3845
xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
3849
writePS("1 0 setcharwidth\n");
3851
writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
3854
inType3Char = gTrue;
3855
++numTilingPatterns;
3857
--numTilingPatterns;
3858
inType3Char = gFalse;
3862
writePS("currentdict end\n");
3863
writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
3866
writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
3867
writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
3868
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3869
writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
3870
y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
3871
writePS("grestore\n");
3876
GBool PSOutputDev::functionShadedFill(GfxState *state,
3877
GfxFunctionShading *shading) {
3878
double x0, y0, x1, y1;
3882
if (level == psLevel2Sep || level == psLevel3Sep) {
3883
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
3886
processColors |= psProcessCMYK;
3889
shading->getDomain(&x0, &y0, &x1, &y1);
3890
mat = shading->getMatrix();
3891
writePSFmt("/mat [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
3892
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3893
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
3894
if (shading->getNFuncs() == 1) {
3896
cvtFunction(shading->getFunc(0));
3899
writePS("/func {\n");
3900
for (i = 0; i < shading->getNFuncs(); ++i) {
3901
if (i < shading->getNFuncs() - 1) {
3902
writePS("2 copy\n");
3904
cvtFunction(shading->getFunc(i));
3906
if (i < shading->getNFuncs() - 1) {
3907
writePS("3 1 roll\n");
3912
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1);
3917
GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
3918
double xMin, yMin, xMax, yMax;
3919
double x0, y0, x1, y1, dx, dy, mul;
3920
double tMin, tMax, t, t0, t1;
3923
if (level == psLevel2Sep || level == psLevel3Sep) {
3924
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
3927
processColors |= psProcessCMYK;
3930
// get the clip region bbox
3931
state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
3933
// compute min and max t values, based on the four corners of the
3935
shading->getCoords(&x0, &y0, &x1, &y1);
3938
if (fabs(dx) < 0.01 && fabs(dy) < 0.01) {
3941
mul = 1 / (dx * dx + dy * dy);
3942
tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
3943
t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
3946
} else if (t > tMax) {
3949
t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
3952
} else if (t > tMax) {
3955
t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
3958
} else if (t > tMax) {
3961
if (tMin < 0 && !shading->getExtend0()) {
3964
if (tMax > 1 && !shading->getExtend1()) {
3969
// get the function domain
3970
t0 = shading->getDomain0();
3971
t1 = shading->getDomain1();
3973
// generate the PS code
3974
writePSFmt("/t0 {0:.6g} def\n", t0);
3975
writePSFmt("/t1 {0:.6g} def\n", t1);
3976
writePSFmt("/dt {0:.6g} def\n", t1 - t0);
3977
writePSFmt("/x0 {0:.6g} def\n", x0);
3978
writePSFmt("/y0 {0:.6g} def\n", y0);
3979
writePSFmt("/dx {0:.6g} def\n", x1 - x0);
3980
writePSFmt("/x1 {0:.6g} def\n", x1);
3981
writePSFmt("/y1 {0:.6g} def\n", y1);
3982
writePSFmt("/dy {0:.6g} def\n", y1 - y0);
3983
writePSFmt("/xMin {0:.6g} def\n", xMin);
3984
writePSFmt("/yMin {0:.6g} def\n", yMin);
3985
writePSFmt("/xMax {0:.6g} def\n", xMax);
3986
writePSFmt("/yMax {0:.6g} def\n", yMax);
3987
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
3988
if (shading->getNFuncs() == 1) {
3990
cvtFunction(shading->getFunc(0));
3993
writePS("/func {\n");
3994
for (i = 0; i < shading->getNFuncs(); ++i) {
3995
if (i < shading->getNFuncs() - 1) {
3998
cvtFunction(shading->getFunc(i));
4000
if (i < shading->getNFuncs() - 1) {
4006
writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax);
4011
GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
4012
double xMin, yMin, xMax, yMax;
4013
double x0, y0, r0, x1, y1, r1, t0, t1;
4015
double sz, xz, yz, sMin, sMax, sa, ta;
4016
double theta, alpha, a1, a2;
4020
if (level == psLevel2Sep || level == psLevel3Sep) {
4021
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
4024
processColors |= psProcessCMYK;
4027
// get the shading info
4028
shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
4029
t0 = shading->getDomain0();
4030
t1 = shading->getDomain1();
4032
// Compute the point at which r(s) = 0; check for the enclosed
4033
// circles case; and compute the angles for the tangent lines.
4035
enclosed = x0 == x1 && y0 == y1;
4037
sz = 0; // make gcc happy
4039
sz = -r0 / (r1 - r0);
4040
xz = x0 + sz * (x1 - x0);
4041
yz = y0 + sz * (y1 - y0);
4042
enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
4043
theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
4052
alpha = atan2(y1 - y0, x1 - x0);
4053
a1 = (180 / M_PI) * (alpha + theta) + 90;
4054
a2 = (180 / M_PI) * (alpha - theta) - 90;
4060
// compute the (possibly extended) s range
4061
state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
4068
// solve for x(s) + r(s) = xMin
4069
if ((x1 + r1) - (x0 + r0) != 0) {
4070
sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
4073
} else if (sa > sMax) {
4077
// solve for x(s) - r(s) = xMax
4078
if ((x1 - r1) - (x0 - r0) != 0) {
4079
sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
4082
} else if (sa > sMax) {
4086
// solve for y(s) + r(s) = yMin
4087
if ((y1 + r1) - (y0 + r0) != 0) {
4088
sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
4091
} else if (sa > sMax) {
4095
// solve for y(s) - r(s) = yMax
4096
if ((y1 - r1) - (y0 - r0) != 0) {
4097
sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
4100
} else if (sa > sMax) {
4109
} else if (r0 > r1) {
4114
// check the 'extend' flags
4115
if (!shading->getExtend0() && sMin < 0) {
4118
if (!shading->getExtend1() && sMax > 1) {
4123
// generate the PS code
4124
writePSFmt("/x0 {0:.6g} def\n", x0);
4125
writePSFmt("/x1 {0:.6g} def\n", x1);
4126
writePSFmt("/dx {0:.6g} def\n", x1 - x0);
4127
writePSFmt("/y0 {0:.6g} def\n", y0);
4128
writePSFmt("/y1 {0:.6g} def\n", y1);
4129
writePSFmt("/dy {0:.6g} def\n", y1 - y0);
4130
writePSFmt("/r0 {0:.6g} def\n", r0);
4131
writePSFmt("/r1 {0:.6g} def\n", r1);
4132
writePSFmt("/dr {0:.6g} def\n", r1 - r0);
4133
writePSFmt("/t0 {0:.6g} def\n", t0);
4134
writePSFmt("/t1 {0:.6g} def\n", t1);
4135
writePSFmt("/dt {0:.6g} def\n", t1 - t0);
4136
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
4137
writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false");
4138
writePSFmt("/a1 {0:.6g} def\n", a1);
4139
writePSFmt("/a2 {0:.6g} def\n", a2);
4140
if (shading->getNFuncs() == 1) {
4142
cvtFunction(shading->getFunc(0));
4145
writePS("/func {\n");
4146
for (i = 0; i < shading->getNFuncs(); ++i) {
4147
if (i < shading->getNFuncs() - 1) {
4150
cvtFunction(shading->getFunc(i));
4152
if (i < shading->getNFuncs() - 1) {
4158
writePSFmt("{0:.6g} {1:.6g} 0 radialSH\n", sMin, sMax);
4160
// extend the 'enclosed' case
4162
// extend the smaller circle
4163
if ((shading->getExtend0() && r0 <= r1) ||
4164
(shading->getExtend1() && r1 < r0)) {
4176
if (level == psLevel2Sep || level == psLevel3Sep) {
4177
writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
4179
writePSFmt("{0:.6g} radialCol sc\n", ta);
4181
writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h f*\n", xa, ya, ra);
4184
// extend the larger circle
4185
if ((shading->getExtend0() && r0 > r1) ||
4186
(shading->getExtend1() && r1 >= r0)) {
4198
if (level == psLevel2Sep || level == psLevel3Sep) {
4199
writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
4201
writePSFmt("{0:.6g} radialCol sc\n", ta);
4203
writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h\n", xa, ya, ra);
4204
writePSFmt("{0:.6g} {1:.6g} m {2:.6g} {3:.6g} l {4:.6g} {5:.6g} l {6:.6g} {7:.6g} l h f*\n",
4205
xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin);
4212
void PSOutputDev::clip(GfxState *state) {
4213
doPath(state->getPath());
4217
void PSOutputDev::eoClip(GfxState *state) {
4218
doPath(state->getPath());
4222
void PSOutputDev::clipToStrokePath(GfxState *state) {
4223
doPath(state->getPath());
4227
void PSOutputDev::doPath(GfxPath *path) {
4228
GfxSubpath *subpath;
4229
double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
4232
n = path->getNumSubpaths();
4234
if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
4235
subpath = path->getSubpath(0);
4236
x0 = subpath->getX(0);
4237
y0 = subpath->getY(0);
4238
x4 = subpath->getX(4);
4239
y4 = subpath->getY(4);
4240
if (x4 == x0 && y4 == y0) {
4241
x1 = subpath->getX(1);
4242
y1 = subpath->getY(1);
4243
x2 = subpath->getX(2);
4244
y2 = subpath->getY(2);
4245
x3 = subpath->getX(3);
4246
y3 = subpath->getY(3);
4247
if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
4248
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4249
x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
4250
fabs(x2 - x0), fabs(y1 - y0));
4252
} else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
4253
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4254
x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
4255
fabs(x1 - x0), fabs(y2 - y0));
4261
for (i = 0; i < n; ++i) {
4262
subpath = path->getSubpath(i);
4263
m = subpath->getNumPoints();
4264
writePSFmt("{0:.6g} {1:.6g} m\n", subpath->getX(0), subpath->getY(0));
4267
if (subpath->getCurve(j)) {
4268
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} c\n",
4269
subpath->getX(j), subpath->getY(j),
4270
subpath->getX(j+1), subpath->getY(j+1),
4271
subpath->getX(j+2), subpath->getY(j+2));
4274
writePSFmt("{0:.6g} {1:.6g} l\n", subpath->getX(j), subpath->getY(j));
4278
if (subpath->isClosed()) {
4284
void PSOutputDev::drawString(GfxState *state, GooString *s) {
4289
double dx, dy, dx2, dy2, originX, originY;
4295
int len, nChars, uLen, n, m, i, j;
4297
// for pdftohtml, output PS without text
4298
if( displayText == gFalse )
4301
// check for invisible text -- this is used by Acrobat Capture
4302
if (state->getRender() == 3) {
4306
// ignore empty strings
4307
if (s->getLength() == 0) {
4312
if (!(font = state->getFont())) {
4315
wMode = font->getWMode();
4317
// check for a subtitute 16-bit font
4320
if (font->isCIDFont()) {
4321
for (i = 0; i < font16EncLen; ++i) {
4322
if (font->getID()->num == font16Enc[i].fontID.num &&
4323
font->getID()->gen == font16Enc[i].fontID.gen) {
4324
uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
4329
// check for a code-to-GID map
4331
for (i = 0; i < font8InfoLen; ++i) {
4332
if (font->getID()->num == font8Info[i].fontID.num &&
4333
font->getID()->gen == font8Info[i].fontID.gen) {
4334
codeToGID = font8Info[i].codeToGID;
4340
// compute width of chars in string, ignoring char spacing and word
4341
// spacing -- the Tj operator will adjust for the metrics of the
4342
// font that's actually used
4345
p = s->getCString();
4346
len = s->getLength();
4347
s2 = new GooString();
4349
n = font->getNextChar(p, len, &code,
4351
&dx2, &dy2, &originX, &originY);
4352
if (font->isCIDFont()) {
4354
for (i = 0; i < uLen; ++i) {
4355
m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
4356
for (j = 0; j < m; ++j) {
4360
//~ this really needs to get the number of chars in the target
4361
//~ encoding - which may be more than the number of Unicode
4365
s2->append((char)((code >> 8) & 0xff));
4366
s2->append((char)(code & 0xff));
4370
if (!codeToGID || codeToGID[code]) {
4371
s2->append((char)code);
4379
dx *= state->getFontSize() * state->getHorizScaling();
4380
dy *= state->getFontSize();
4385
if (s2->getLength() > 0) {
4387
if (font->isCIDFont()) {
4389
writePSFmt(" {0:d} {1:.6g} Tj16V\n", nChars, dy);
4391
writePSFmt(" {0:d} {1:.6g} Tj16\n", nChars, dx);
4394
writePSFmt(" {0:.6g} Tj\n", dx);
4399
if (state->getRender() & 4 || haveCSPattern) {
4400
haveTextClip = gTrue;
4404
void PSOutputDev::beginTextObject(GfxState *state) {
4405
if (state->getFillColorSpace()->getMode() == csPattern) {
4407
haveCSPattern = gTrue;
4408
writePS("true Tp\n");
4412
void PSOutputDev::endTextObject(GfxState *state) {
4413
if (haveCSPattern) {
4415
writePS("Tclip*\n");
4416
haveTextClip = gFalse;
4417
if (state->getFillColorSpace()->getMode() != csPattern) {
4418
double cxMin, cyMin, cxMax, cyMax;
4419
state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
4420
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4424
restoreState(state);
4425
updateFillColor(state);
4428
haveCSPattern = gFalse;
4429
} else if (haveTextClip) {
4431
haveTextClip = gFalse;
4435
void PSOutputDev::endMaskClip(GfxState * state) {
4436
writePS("pdfImClipEnd\n");
4439
void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
4440
int width, int height, GBool invert,
4441
GBool interpolate, GBool inlineImg) {
4444
len = height * ((width + 7) / 8);
4445
if (state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep)) {
4446
maskToClippingPath(str, width, height, invert);
4451
doImageL1(ref, NULL, invert, inlineImg, str, width, height, len,
4452
NULL, NULL, 0, 0, gFalse);
4456
doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
4457
NULL, NULL, 0, 0, gFalse);
4461
doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
4462
NULL, NULL, 0, 0, gFalse);
4468
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
4469
int width, int height, GfxImageColorMap *colorMap,
4470
GBool interpolate, int *maskColors, GBool inlineImg) {
4473
len = height * ((width * colorMap->getNumPixelComps() *
4474
colorMap->getBits() + 7) / 8);
4477
doImageL1(ref, colorMap, gFalse, inlineImg, str,
4478
width, height, len, maskColors, NULL, 0, 0, gFalse);
4481
//~ handle indexed, separation, ... color spaces
4482
doImageL1Sep(ref, colorMap, gFalse, inlineImg, str,
4483
width, height, len, maskColors, NULL, 0, 0, gFalse);
4487
doImageL2(ref, colorMap, gFalse, inlineImg, str,
4488
width, height, len, maskColors, NULL, 0, 0, gFalse);
4492
doImageL3(ref, colorMap, gFalse, inlineImg, str,
4493
width, height, len, maskColors, NULL, 0, 0, gFalse);
4496
t3Cacheable = gFalse;
4499
void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
4500
int width, int height,
4501
GfxImageColorMap *colorMap,
4504
int maskWidth, int maskHeight,
4505
GBool maskInvert, GBool maskInterpolate) {
4508
len = height * ((width * colorMap->getNumPixelComps() *
4509
colorMap->getBits() + 7) / 8);
4512
doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len,
4513
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4516
//~ handle indexed, separation, ... color spaces
4517
doImageL1Sep(ref, colorMap, gFalse, gFalse, str, width, height, len,
4518
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4522
doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
4523
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4527
doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
4528
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4531
t3Cacheable = gFalse;
4534
void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
4535
GBool invert, GBool inlineImg,
4536
Stream *str, int width, int height, int len,
4537
int *maskColors, Stream *maskStr,
4538
int maskWidth, int maskHeight, GBool maskInvert) {
4539
ImageStream *imgStr;
4540
Guchar pixBuf[gfxColorMaxComps];
4542
int col, x, y, c, i;
4543
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
4544
Guchar digit, grayValue;
4547
if (maskStr && !(maskColors && colorMap)) {
4548
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
4551
if ((inType3Char || preload) && !colorMap) {
4554
str = new FixedLengthEncoder(str, len);
4555
str = new ASCIIHexEncoder(str);
4562
} while (c == '\n' || c == '\r');
4563
if (c == '>' || c == EOF) {
4568
// each line is: "<...data...><eol>"
4569
// so max data length = 255 - 4 = 251
4570
// but make it 240 just to be safe
4571
// chunks are 2 bytes each, so we need to stop on an even col number
4576
} while (c != '>' && c != EOF);
4582
// make sure the image is setup, it sometimes is not like on bug #17645
4583
setupImage(ref->getRef(), str);
4584
// set up to use the array already created by setupImages()
4585
writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
4589
// image/imagemask command
4590
if ((inType3Char || preload) && !colorMap) {
4591
writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n",
4592
width, height, invert ? "true" : "false",
4593
width, -height, height);
4594
} else if (colorMap) {
4595
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
4597
width, -height, height);
4599
writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n",
4600
width, height, invert ? "true" : "false",
4601
width, -height, height);
4605
if (!((inType3Char || preload) && !colorMap)) {
4609
// set up to process the data stream
4610
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
4611
colorMap->getBits());
4614
// process the data stream
4616
for (y = 0; y < height; ++y) {
4619
for (x = 0; x < width; ++x) {
4620
imgStr->getPixel(pixBuf);
4621
colorMap->getGray(pixBuf, &gray);
4622
grayValue = colToByte(gray);
4623
digit = grayValue / 16;
4624
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4625
digit = grayValue % 16;
4626
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4629
writePSBuf(hexBuf, i);
4636
writePSBuf(hexBuf, i);
4645
for (y = 0; y < height; ++y) {
4646
for (x = 0; x < width; x += 8) {
4647
grayValue = str->getChar();
4648
digit = grayValue / 16;
4649
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4650
digit = grayValue % 16;
4651
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4654
writePSBuf(hexBuf, i);
4661
writePSBuf(hexBuf, i);
4667
if (maskStr && !(maskColors && colorMap)) {
4668
writePS("pdfImClipEnd\n");
4672
void PSOutputDev::doImageL1Sep(Object *ref, GfxImageColorMap *colorMap,
4673
GBool invert, GBool inlineImg,
4674
Stream *str, int width, int height, int len,
4675
int *maskColors, Stream *maskStr,
4676
int maskWidth, int maskHeight, GBool maskInvert) {
4677
ImageStream *imgStr;
4679
Guchar pixBuf[gfxColorMaxComps];
4682
GBool checkProcessColor;
4683
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
4687
if (maskStr && !(maskColors && colorMap)) {
4688
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
4691
// width, height, matrix, bits per component
4692
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
4694
width, -height, height);
4696
// allocate a line buffer
4697
lineBuf = (Guchar *)gmallocn(width, 4);
4699
// set up to process the data stream
4700
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
4701
colorMap->getBits());
4704
// process the data stream
4705
checkProcessColor = gTrue;
4707
for (y = 0; y < height; ++y) {
4710
if (checkProcessColor) {
4711
checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0);
4713
if (checkProcessColor) {
4714
for (x = 0; x < width; ++x) {
4715
imgStr->getPixel(pixBuf);
4716
colorMap->getCMYK(pixBuf, &cmyk);
4717
lineBuf[4*x+0] = colToByte(cmyk.c);
4718
lineBuf[4*x+1] = colToByte(cmyk.m);
4719
lineBuf[4*x+2] = colToByte(cmyk.y);
4720
lineBuf[4*x+3] = colToByte(cmyk.k);
4721
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
4722
colToDbl(cmyk.y), colToDbl(cmyk.k));
4725
for (x = 0; x < width; ++x) {
4726
imgStr->getPixel(pixBuf);
4727
colorMap->getCMYK(pixBuf, &cmyk);
4728
lineBuf[4*x+0] = colToByte(cmyk.c);
4729
lineBuf[4*x+1] = colToByte(cmyk.m);
4730
lineBuf[4*x+2] = colToByte(cmyk.y);
4731
lineBuf[4*x+3] = colToByte(cmyk.k);
4735
// write one line of each color component
4736
for (comp = 0; comp < 4; ++comp) {
4737
for (x = 0; x < width; ++x) {
4738
digit = lineBuf[4*x + comp] / 16;
4739
hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
4740
digit = lineBuf[4*x + comp] % 16;
4741
hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
4744
writePSBuf(hexBuf, i);
4753
writePSBuf(hexBuf, i);
4760
if (maskStr && !(maskColors && colorMap)) {
4761
writePS("pdfImClipEnd\n");
4765
void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) {
4766
ImageStream *imgStr;
4768
PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
4769
int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
4770
GBool emitRect, addRect, extendRect;
4771
int i, x0, x1, y, maskXor;
4773
imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
4775
rects0Len = rects1Len = rectsOutLen = 0;
4776
rectsSize = rectsOutSize = 64;
4777
rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4778
rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4779
rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect));
4780
maskXor = maskInvert ? 1 : 0;
4781
for (y = 0; y < maskHeight; ++y) {
4782
if (!(line = imgStr->getLine())) {
4787
for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
4788
for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
4789
while (x0 < maskWidth || i < rects0Len) {
4790
emitRect = addRect = extendRect = gFalse;
4791
if (x0 >= maskWidth) {
4793
} else if (i >= rects0Len) {
4795
} else if (rects0[i].x0 < x0) {
4797
} else if (x0 < rects0[i].x0) {
4799
} else if (rects0[i].x1 == x1) {
4802
emitRect = addRect = gTrue;
4805
if (rectsOutLen == rectsOutSize) {
4807
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
4809
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4810
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4811
rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
4812
rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
4816
if (addRect || extendRect) {
4817
if (rects1Len == rectsSize) {
4819
rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect));
4820
rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect));
4822
rects1[rects1Len].x0 = x0;
4823
rects1[rects1Len].x1 = x1;
4825
rects1[rects1Len].y0 = y;
4828
rects1[rects1Len].y0 = rects0[i].y0;
4832
for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
4833
for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
4840
rects0Len = rects1Len;
4843
for (i = 0; i < rects0Len; ++i) {
4844
if (rectsOutLen == rectsOutSize) {
4846
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
4848
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4849
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4850
rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
4851
rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
4854
if (rectsOutLen < 65536/4) {
4855
writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
4856
for (i = 0; i < rectsOutLen; ++i) {
4857
writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
4858
rectsOut[i].x0, rectsOut[i].y0,
4859
rectsOut[i].x1 - rectsOut[i].x0,
4860
rectsOut[i].y1 - rectsOut[i].y0);
4862
writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
4864
// would be over the limit of array size.
4865
// make each rectangle path and clip.
4866
writePS("gsave newpath\n");
4867
for (i = 0; i < rectsOutLen; ++i) {
4868
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4869
((double)rectsOut[i].x0)/maskWidth,
4870
((double)rectsOut[i].y0)/maskHeight,
4871
((double)(rectsOut[i].x1 - rectsOut[i].x0))/maskWidth,
4872
((double)(rectsOut[i].y1 - rectsOut[i].y0))/maskHeight);
4883
void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
4884
GBool invert, GBool inlineImg,
4885
Stream *str, int width, int height, int len,
4886
int *maskColors, Stream *maskStr,
4887
int maskWidth, int maskHeight, GBool maskInvert) {
4889
ImageStream *imgStr;
4891
PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
4892
int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
4893
GBool emitRect, addRect, extendRect;
4896
GBool useRLE, useASCII, useASCIIHex, useCompressed;
4897
GfxSeparationColorSpace *sepCS;
4901
int col, i, j, x0, x1, y;
4906
// color key masking
4907
if (maskColors && colorMap && !inlineImg) {
4908
// can't read the stream twice for inline images -- but masking
4909
// isn't allowed with inline images anyway
4910
numComps = colorMap->getNumPixelComps();
4911
imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
4913
rects0Len = rects1Len = 0;
4914
rectsSize = rectsOutSize = 64;
4915
rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4916
rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4917
rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
4918
sizeof(PSOutImgClipRect));
4919
for (y = 0; y < height; ++y) {
4920
if (!(line = imgStr->getLine())) {
4925
for (x0 = 0; x0 < width; ++x0) {
4926
for (j = 0; j < numComps; ++j) {
4927
if (line[x0*numComps+j] < maskColors[2*j] ||
4928
line[x0*numComps+j] > maskColors[2*j+1]) {
4936
for (x1 = x0; x1 < width; ++x1) {
4937
for (j = 0; j < numComps; ++j) {
4938
if (line[x1*numComps+j] < maskColors[2*j] ||
4939
line[x1*numComps+j] > maskColors[2*j+1]) {
4943
if (j == numComps) {
4947
while (x0 < width || i < rects0Len) {
4948
emitRect = addRect = extendRect = gFalse;
4951
} else if (i >= rects0Len) {
4953
} else if (rects0[i].x0 < x0) {
4955
} else if (x0 < rects0[i].x0) {
4957
} else if (rects0[i].x1 == x1) {
4960
emitRect = addRect = gTrue;
4963
if (rectsOutLen == rectsOutSize) {
4965
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
4966
sizeof(PSOutImgClipRect));
4968
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4969
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4970
rectsOut[rectsOutLen].y0 = height - y - 1;
4971
rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
4975
if (addRect || extendRect) {
4976
if (rects1Len == rectsSize) {
4978
rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
4979
sizeof(PSOutImgClipRect));
4980
rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
4981
sizeof(PSOutImgClipRect));
4983
rects1[rects1Len].x0 = x0;
4984
rects1[rects1Len].x1 = x1;
4986
rects1[rects1Len].y0 = y;
4989
rects1[rects1Len].y0 = rects0[i].y0;
4993
for (x0 = x1; x0 < width; ++x0) {
4994
for (j = 0; j < numComps; ++j) {
4995
if (line[x0*numComps+j] < maskColors[2*j] ||
4996
line[x0*numComps+j] > maskColors[2*j+1]) {
5004
for (x1 = x0; x1 < width; ++x1) {
5005
for (j = 0; j < numComps; ++j) {
5006
if (line[x1*numComps+j] < maskColors[2*j] ||
5007
line[x1*numComps+j] > maskColors[2*j+1]) {
5011
if (j == numComps) {
5021
rects0Len = rects1Len;
5024
for (i = 0; i < rects0Len; ++i) {
5025
if (rectsOutLen == rectsOutSize) {
5027
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
5028
sizeof(PSOutImgClipRect));
5030
rectsOut[rectsOutLen].x0 = rects0[i].x0;
5031
rectsOut[rectsOutLen].x1 = rects0[i].x1;
5032
rectsOut[rectsOutLen].y0 = height - y - 1;
5033
rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
5036
if (rectsOutLen < 65536/4) {
5037
writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
5038
for (i = 0; i < rectsOutLen; ++i) {
5039
writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
5040
rectsOut[i].x0, rectsOut[i].y0,
5041
rectsOut[i].x1 - rectsOut[i].x0,
5042
rectsOut[i].y1 - rectsOut[i].y0);
5044
writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height);
5046
// would be over the limit of array size.
5047
// make each rectangle path and clip.
5048
writePS("gsave newpath\n");
5049
for (i = 0; i < rectsOutLen; ++i) {
5050
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
5051
((double)rectsOut[i].x0)/width,
5052
((double)rectsOut[i].y0)/height,
5053
((double)(rectsOut[i].x1 - rectsOut[i].x0))/width,
5054
((double)(rectsOut[i].y1 - rectsOut[i].y0))/height);
5065
} else if (maskStr) {
5066
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
5071
dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
5072
writePS(" setcolorspace\n");
5075
useASCIIHex = globalParams->getPSASCIIHex();
5077
// set up the image data
5078
if (mode == psModeForm || inType3Char || preload) {
5081
str2 = new FixedLengthEncoder(str, len);
5082
str2 = new RunLengthEncoder(str2);
5084
str2 = new ASCIIHexEncoder(str2);
5086
str2 = new ASCII85Encoder(str2);
5090
writePS((char *)(useASCIIHex ? "[<" : "[<~"));
5093
c = str2->getChar();
5094
} while (c == '\n' || c == '\r');
5095
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5104
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
5106
c = str2->getChar();
5107
} while (c == '\n' || c == '\r');
5108
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5115
// each line is: "<~...data...~><eol>"
5116
// so max data length = 255 - 6 = 249
5117
// chunks are 1 or 5 bytes each, so we have to stop at 245
5118
// but make it 240 just to be safe
5120
writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
5123
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
5124
writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
5125
// add an extra entry because the RunLengthDecode filter may
5126
// read past the end
5132
// make sure the image is setup, it sometimes is not like on bug #17645
5133
setupImage(ref->getRef(), str);
5134
// set up to use the array already created by setupImages()
5135
writePSFmt("ImData_{0:d}_{1:d} 0 0\n",ref->getRefNum(), ref->getRefGen());
5140
writePS("<<\n /ImageType 1\n");
5142
// width, height, matrix, bits per component
5143
writePSFmt(" /Width {0:d}\n", width);
5144
writePSFmt(" /Height {0:d}\n", height);
5145
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5146
width, -height, height);
5147
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5148
writePS(" /BitsPerComponent 8\n");
5150
writePSFmt(" /BitsPerComponent {0:d}\n",
5151
colorMap ? colorMap->getBits() : 1);
5156
writePS(" /Decode [");
5157
if ((level == psLevel2Sep || level == psLevel3Sep) &&
5158
colorMap->getColorSpace()->getMode() == csSeparation) {
5159
// this matches up with the code in the pdfImSep operator
5160
n = (1 << colorMap->getBits()) - 1;
5161
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
5162
colorMap->getDecodeHigh(0) * n);
5163
} else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
5164
numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
5165
getAlt()->getNComps();
5166
for (i = 0; i < numComps; ++i) {
5173
numComps = colorMap->getNumPixelComps();
5174
for (i = 0; i < numComps; ++i) {
5178
writePSFmt("{0:.4g} {1:.4g}",
5179
colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
5184
writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
5188
if (mode == psModeForm || inType3Char || preload) {
5190
writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
5192
writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
5193
" index get 1 index get exch 1 add exch }\n");
5196
writePS(" /DataSource currentfile\n");
5200
s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
5202
if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
5205
useASCII = !(mode == psModeForm || inType3Char || preload);
5206
useCompressed = gFalse;
5209
useASCII = str->isBinary() &&
5210
!(mode == psModeForm || inType3Char || preload);
5211
useCompressed = gTrue;
5214
writePSFmt(" /ASCII{0:s}Decode filter\n",
5215
useASCIIHex ? "Hex" : "85");
5218
writePS(" /RunLengthDecode filter\n");
5220
if (useCompressed) {
5221
writePS(s->getCString());
5227
if (mode == psModeForm || inType3Char || preload) {
5229
// end of image dictionary
5230
writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask");
5232
// get rid of the array and index
5233
if (!inlineImg) writePS("pop ");
5234
writePS("pop pop\n");
5238
// cut off inline image streams at appropriate length
5240
str = new FixedLengthEncoder(str, len);
5241
} else if (useCompressed) {
5242
str = str->getUndecodedStream();
5245
// recode DeviceN data
5246
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5247
str = new DeviceNRecoder(str, width, height, colorMap);
5250
// add RunLengthEncode and ASCIIHex/85 encode filters
5252
str = new RunLengthEncoder(str);
5256
str = new ASCIIHexEncoder(str);
5258
str = new ASCII85Encoder(str);
5262
// end of image dictionary
5267
// this can't happen -- OPI dictionaries are in XObjects
5268
error(-1, "Internal: OPI in inline image");
5271
// need to read the stream to count characters -- the length
5272
// is data-dependent (because of ASCII and RLE filters)
5275
while ((c = str->getChar()) != EOF) {
5280
// +6/7 for "pdfIm\n" / "pdfImM\n"
5281
// +8 for newline + trailer
5282
n += colorMap ? 14 : 15;
5283
writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n);
5286
if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
5287
colorMap->getColorSpace()->getMode() == csSeparation) {
5288
color.c[0] = gfxColorComp1;
5289
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
5290
sepCS->getCMYK(&color, &cmyk);
5291
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
5292
colToDbl(cmyk.c), colToDbl(cmyk.m),
5293
colToDbl(cmyk.y), colToDbl(cmyk.k),
5296
writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
5299
// copy the stream data
5302
while ((c = str->getChar()) != EOF) {
5304
if (i >= (int)sizeof(dataBuf)) {
5305
writePSBuf(dataBuf, i);
5310
writePSBuf(dataBuf, i);
5314
// add newline and trailer to the end
5316
writePS("%-EOD-\n");
5319
writePS("%%EndData\n");
5324
if (useRLE || useASCII || inlineImg) {
5329
if ((maskColors && colorMap && !inlineImg) || maskStr) {
5330
if (rectsOutLen < 65536/4) {
5331
writePS("pdfImClipEnd\n");
5333
writePS("grestore\n");
5338
//~ this doesn't currently support OPI
5339
void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
5340
GBool invert, GBool inlineImg,
5341
Stream *str, int width, int height, int len,
5342
int *maskColors, Stream *maskStr,
5343
int maskWidth, int maskHeight, GBool maskInvert) {
5347
GBool useRLE, useASCII, useASCIIHex, useCompressed;
5348
GBool maskUseRLE, maskUseASCII, maskUseCompressed;
5349
GfxSeparationColorSpace *sepCS;
5355
useASCIIHex = globalParams->getPSASCIIHex();
5356
useRLE = useASCII = useCompressed = gFalse; // make gcc happy
5357
maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
5361
dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
5362
writePS(" setcolorspace\n");
5365
// set up the image data
5366
if (mode == psModeForm || inType3Char || preload) {
5369
str2 = new FixedLengthEncoder(str, len);
5370
str2 = new RunLengthEncoder(str2);
5372
str2 = new ASCIIHexEncoder(str2);
5374
str2 = new ASCII85Encoder(str2);
5378
writePS((char *)(useASCIIHex ? "[<" : "[<~"));
5381
c = str2->getChar();
5382
} while (c == '\n' || c == '\r');
5383
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5392
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
5394
c = str2->getChar();
5395
} while (c == '\n' || c == '\r');
5396
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5403
// each line is: "<~...data...~><eol>"
5404
// so max data length = 255 - 6 = 249
5405
// chunks are 1 or 5 bytes each, so we have to stop at 245
5406
// but make it 240 just to be safe
5408
writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
5411
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
5412
writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
5413
// add an extra entry because the RunLengthDecode filter may
5414
// read past the end
5420
// make sure the image is setup, it sometimes is not like on bug #17645
5421
setupImage(ref->getRef(), str);
5422
// set up to use the array already created by setupImages()
5423
writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
5429
writePS("<<\n /ImageType 3\n");
5430
writePS(" /InterleaveType 3\n");
5431
writePS(" /DataDict\n");
5434
// image (data) dictionary
5435
writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
5437
// color key masking
5438
if (maskColors && colorMap) {
5439
writePS(" /MaskColor [\n");
5440
numComps = colorMap->getNumPixelComps();
5441
for (i = 0; i < 2 * numComps; i += 2) {
5442
writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]);
5447
// width, height, matrix, bits per component
5448
writePSFmt(" /Width {0:d}\n", width);
5449
writePSFmt(" /Height {0:d}\n", height);
5450
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5451
width, -height, height);
5452
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5453
writePS(" /BitsPerComponent 8\n");
5455
writePSFmt(" /BitsPerComponent {0:d}\n",
5456
colorMap ? colorMap->getBits() : 1);
5461
writePS(" /Decode [");
5462
if ((level == psLevel2Sep || level == psLevel3Sep) &&
5463
colorMap->getColorSpace()->getMode() == csSeparation) {
5464
// this matches up with the code in the pdfImSep operator
5465
n = (1 << colorMap->getBits()) - 1;
5466
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
5467
colorMap->getDecodeHigh(0) * n);
5468
} else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
5469
numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
5470
getAlt()->getNComps();
5471
for (i = 0; i < numComps; ++i) {
5478
numComps = colorMap->getNumPixelComps();
5479
for (i = 0; i < numComps; ++i) {
5483
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i),
5484
colorMap->getDecodeHigh(i));
5489
writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
5493
if (mode == psModeForm || inType3Char || preload) {
5495
writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
5497
writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
5498
" index get 1 index get exch 1 add exch }\n");
5501
writePS(" /DataSource currentfile\n");
5505
s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
5507
if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
5510
useASCII = !(mode == psModeForm || inType3Char || preload);
5511
useCompressed = gFalse;
5514
useASCII = str->isBinary() &&
5515
!(mode == psModeForm || inType3Char || preload);
5516
useCompressed = gTrue;
5519
writePSFmt(" /ASCII{0:s}Decode filter\n",
5520
useASCIIHex ? "Hex" : "85");
5523
writePS(" /RunLengthDecode filter\n");
5525
if (useCompressed) {
5526
writePS(s->getCString());
5532
// end of image (data) dictionary
5537
writePS(" /MaskDict\n");
5539
writePS(" /ImageType 1\n");
5540
writePSFmt(" /Width {0:d}\n", maskWidth);
5541
writePSFmt(" /Height {0:d}\n", maskHeight);
5542
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5543
maskWidth, -maskHeight, maskHeight);
5544
writePS(" /BitsPerComponent 1\n");
5545
writePSFmt(" /Decode [{0:d} {1:d}]\n",
5546
maskInvert ? 1 : 0, maskInvert ? 0 : 1);
5549
writePS(" /DataSource currentfile\n");
5550
s = maskStr->getPSFilter(3, " ");
5553
maskUseASCII = gTrue;
5554
maskUseCompressed = gFalse;
5556
maskUseRLE = gFalse;
5557
maskUseASCII = maskStr->isBinary();
5558
maskUseCompressed = gTrue;
5561
writePSFmt(" /ASCII{0:s}Decode filter\n",
5562
useASCIIHex ? "Hex" : "85");
5565
writePS(" /RunLengthDecode filter\n");
5567
if (maskUseCompressed) {
5568
writePS(s->getCString());
5578
if (mode == psModeForm || inType3Char || preload) {
5581
writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask");
5585
if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
5586
colorMap->getColorSpace()->getMode() == csSeparation) {
5587
color.c[0] = gfxColorComp1;
5588
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
5589
sepCS->getCMYK(&color, &cmyk);
5590
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
5591
colToDbl(cmyk.c), colToDbl(cmyk.m),
5592
colToDbl(cmyk.y), colToDbl(cmyk.k),
5595
writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
5603
if (maskUseCompressed) {
5604
maskStr = maskStr->getUndecodedStream();
5607
// add RunLengthEncode and ASCIIHex/85 encode filters
5609
maskStr = new RunLengthEncoder(maskStr);
5613
maskStr = new ASCIIHexEncoder(maskStr);
5615
maskStr = new ASCII85Encoder(maskStr);
5619
// copy the stream data
5621
while ((c = maskStr->getChar()) != EOF) {
5628
if (maskUseRLE || maskUseASCII) {
5633
// get rid of the array and index
5634
if (mode == psModeForm || inType3Char || preload) {
5635
if (!inlineImg) writePS("pop ");
5636
writePS("pop pop\n");
5641
// cut off inline image streams at appropriate length
5643
str = new FixedLengthEncoder(str, len);
5644
} else if (useCompressed) {
5645
str = str->getUndecodedStream();
5648
// recode DeviceN data
5649
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5650
str = new DeviceNRecoder(str, width, height, colorMap);
5653
// add RunLengthEncode and ASCIIHex/85 encode filters
5655
str = new RunLengthEncoder(str);
5659
str = new ASCIIHexEncoder(str);
5661
str = new ASCII85Encoder(str);
5665
// copy the stream data
5667
while ((c = str->getChar()) != EOF) {
5672
// add newline and trailer to the end
5674
writePS("%-EOD-\n");
5677
if (useRLE || useASCII || inlineImg) {
5683
void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
5684
GBool genXform, GBool updateColors,
5686
GfxCalGrayColorSpace *calGrayCS;
5687
GfxCalRGBColorSpace *calRGBCS;
5688
GfxLabColorSpace *labCS;
5689
GfxIndexedColorSpace *indexedCS;
5690
GfxSeparationColorSpace *separationCS;
5691
GfxDeviceNColorSpace *deviceNCS;
5692
GfxColorSpace *baseCS;
5694
double x[gfxColorMaxComps], y[gfxColorMaxComps];
5695
double low[gfxColorMaxComps], range[gfxColorMaxComps];
5699
int n, numComps, numAltComps;
5703
switch (colorSpace->getMode()) {
5706
writePS("/DeviceGray");
5711
processColors |= psProcessBlack;
5716
calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
5717
writePS("[/CIEBasedA <<\n");
5718
writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
5719
writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
5720
calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
5721
calGrayCS->getWhiteZ());
5722
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5723
calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
5724
calGrayCS->getWhiteZ());
5725
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5726
calGrayCS->getBlackX(), calGrayCS->getBlackY(),
5727
calGrayCS->getBlackZ());
5733
processColors |= psProcessBlack;
5738
writePS("/DeviceRGB");
5743
processColors |= psProcessCMYK;
5748
calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
5749
writePS("[/CIEBasedABC <<\n");
5750
writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
5751
calRGBCS->getGammaR(), calRGBCS->getGammaG(),
5752
calRGBCS->getGammaB());
5753
writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
5754
calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
5755
calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
5756
calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
5757
calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
5758
calRGBCS->getMatrix()[8]);
5759
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5760
calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
5761
calRGBCS->getWhiteZ());
5762
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5763
calRGBCS->getBlackX(), calRGBCS->getBlackY(),
5764
calRGBCS->getBlackZ());
5770
processColors |= psProcessCMYK;
5775
writePS("/DeviceCMYK");
5780
processColors |= psProcessCMYK;
5785
labCS = (GfxLabColorSpace *)colorSpace;
5786
writePS("[/CIEBasedABC <<\n");
5788
writePS(" /RangeABC [0 1 0 1 0 1]\n");
5789
writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
5790
(labCS->getAMax() - labCS->getAMin()) / 500.0,
5791
labCS->getAMin() / 500.0,
5792
(labCS->getBMax() - labCS->getBMin()) / 200.0,
5793
labCS->getBMin() / 200.0);
5795
writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
5796
labCS->getAMin(), labCS->getAMax(),
5797
labCS->getBMin(), labCS->getBMax());
5798
writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
5800
writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
5801
writePS(" /DecodeLMN\n");
5802
writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
5803
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
5804
labCS->getWhiteX());
5805
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
5806
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
5807
labCS->getWhiteY());
5808
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
5809
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
5810
labCS->getWhiteZ());
5811
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5812
labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
5813
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5814
labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
5820
processColors |= psProcessCMYK;
5825
// there is no transform function to the alternate color space, so
5826
// we can use it directly
5827
dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
5828
genXform, updateColors, gFalse);
5832
indexedCS = (GfxIndexedColorSpace *)colorSpace;
5833
baseCS = indexedCS->getBase();
5834
writePS("[/Indexed ");
5835
dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
5836
n = indexedCS->getIndexHigh();
5837
numComps = baseCS->getNComps();
5838
lookup = indexedCS->getLookup();
5839
writePSFmt(" {0:d} <\n", n);
5840
if (baseCS->getMode() == csDeviceN) {
5841
func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
5842
baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
5843
if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
5844
labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
5848
numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
5850
for (i = 0; i <= n; i += 8) {
5852
for (j = i; j < i+8 && j <= n; ++j) {
5853
for (k = 0; k < numComps; ++k) {
5854
x[k] = low[k] + (*p++ / 255.0) * range[k];
5856
func->transform(x, y);
5859
y[1] = (y[1] - labCS->getAMin()) /
5860
(labCS->getAMax() - labCS->getAMin());
5861
y[2] = (y[2] - labCS->getBMin()) /
5862
(labCS->getBMax() - labCS->getBMin());
5864
for (k = 0; k < numAltComps; ++k) {
5865
byte = (int)(y[k] * 255 + 0.5);
5868
} else if (byte > 255) {
5871
writePSFmt("{0:02x}", byte);
5874
color.c[0] = dblToCol(j);
5875
indexedCS->getCMYK(&color, &cmyk);
5876
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
5877
colToDbl(cmyk.y), colToDbl(cmyk.k));
5883
for (i = 0; i <= n; i += 8) {
5885
for (j = i; j < i+8 && j <= n; ++j) {
5886
for (k = 0; k < numComps; ++k) {
5887
writePSFmt("{0:02x}", lookup[j * numComps + k]);
5890
color.c[0] = dblToCol(j);
5891
indexedCS->getCMYK(&color, &cmyk);
5892
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
5893
colToDbl(cmyk.y), colToDbl(cmyk.k));
5906
separationCS = (GfxSeparationColorSpace *)colorSpace;
5907
writePS("[/Separation ");
5908
writePSString(separationCS->getName());
5910
dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
5912
cvtFunction(separationCS->getFunc());
5918
addCustomColor(separationCS);
5923
// DeviceN color spaces are a Level 3 PostScript feature.
5924
deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
5925
dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
5928
cvtFunction(deviceNCS->getTintTransformFunc());
5939
void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
5942
if (globalParams->getPSOPI()) {
5943
opiDict->lookup("2.0", &dict);
5944
if (dict.isDict()) {
5945
opiBegin20(state, dict.getDict());
5949
opiDict->lookup("1.3", &dict);
5950
if (dict.isDict()) {
5951
opiBegin13(state, dict.getDict());
5958
void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
5959
Object obj1, obj2, obj3, obj4;
5960
double width, height, left, right, top, bottom;
5964
writePS("%%BeginOPI: 2.0\n");
5965
writePS("%%Distilled\n");
5967
dict->lookup("F", &obj1);
5968
if (getFileSpecName(&obj1, &obj2)) {
5969
writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
5974
dict->lookup("MainImage", &obj1);
5975
if (obj1.isString()) {
5976
writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
5980
//~ ignoring 'Tags' entry
5981
//~ need to use writePSString() and deal with >255-char lines
5983
dict->lookup("Size", &obj1);
5984
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
5985
obj1.arrayGet(0, &obj2);
5986
width = obj2.getNum();
5988
obj1.arrayGet(1, &obj2);
5989
height = obj2.getNum();
5991
writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
5995
dict->lookup("CropRect", &obj1);
5996
if (obj1.isArray() && obj1.arrayGetLength() == 4) {
5997
obj1.arrayGet(0, &obj2);
5998
left = obj2.getNum();
6000
obj1.arrayGet(1, &obj2);
6001
top = obj2.getNum();
6003
obj1.arrayGet(2, &obj2);
6004
right = obj2.getNum();
6006
obj1.arrayGet(3, &obj2);
6007
bottom = obj2.getNum();
6009
writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
6010
left, top, right, bottom);
6014
dict->lookup("Overprint", &obj1);
6015
if (obj1.isBool()) {
6016
writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
6020
dict->lookup("Inks", &obj1);
6021
if (obj1.isName()) {
6022
writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
6023
} else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
6024
obj1.arrayGet(0, &obj2);
6025
if (obj2.isName()) {
6026
writePSFmt("%%ImageInks: {0:s} {1:d}",
6027
obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
6028
for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
6029
obj1.arrayGet(i, &obj3);
6030
obj1.arrayGet(i+1, &obj4);
6031
if (obj3.isString() && obj4.isNum()) {
6033
writePSString(obj3.getString());
6034
writePSFmt(" {0:.6g}", obj4.getNum());
6047
writePS("%%BeginIncludedImage\n");
6049
dict->lookup("IncludedImageDimensions", &obj1);
6050
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6051
obj1.arrayGet(0, &obj2);
6054
obj1.arrayGet(1, &obj2);
6057
writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
6061
dict->lookup("IncludedImageQuality", &obj1);
6063
writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
6070
void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
6072
int left, right, top, bottom, samples, bits, width, height;
6074
double llx, lly, ulx, uly, urx, ury, lrx, lry;
6075
double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
6080
writePS("/opiMatrix2 matrix currentmatrix def\n");
6081
writePS("opiMatrix setmatrix\n");
6083
dict->lookup("F", &obj1);
6084
if (getFileSpecName(&obj1, &obj2)) {
6085
writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
6090
dict->lookup("CropRect", &obj1);
6091
if (obj1.isArray() && obj1.arrayGetLength() == 4) {
6092
obj1.arrayGet(0, &obj2);
6093
left = obj2.getInt();
6095
obj1.arrayGet(1, &obj2);
6096
top = obj2.getInt();
6098
obj1.arrayGet(2, &obj2);
6099
right = obj2.getInt();
6101
obj1.arrayGet(3, &obj2);
6102
bottom = obj2.getInt();
6104
writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
6105
left, top, right, bottom);
6109
dict->lookup("Color", &obj1);
6110
if (obj1.isArray() && obj1.arrayGetLength() == 5) {
6111
obj1.arrayGet(0, &obj2);
6114
obj1.arrayGet(1, &obj2);
6117
obj1.arrayGet(2, &obj2);
6120
obj1.arrayGet(3, &obj2);
6123
obj1.arrayGet(4, &obj2);
6124
if (obj2.isString()) {
6125
writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
6127
writePSString(obj2.getString());
6134
dict->lookup("ColorType", &obj1);
6135
if (obj1.isName()) {
6136
writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
6140
//~ ignores 'Comments' entry
6141
//~ need to handle multiple lines
6143
dict->lookup("CropFixed", &obj1);
6144
if (obj1.isArray()) {
6145
obj1.arrayGet(0, &obj2);
6146
ulx = obj2.getNum();
6148
obj1.arrayGet(1, &obj2);
6149
uly = obj2.getNum();
6151
obj1.arrayGet(2, &obj2);
6152
lrx = obj2.getNum();
6154
obj1.arrayGet(3, &obj2);
6155
lry = obj2.getNum();
6157
writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
6158
ulx, uly, lrx, lry);
6162
dict->lookup("GrayMap", &obj1);
6163
if (obj1.isArray()) {
6164
writePS("%ALDImageGrayMap:");
6165
for (i = 0; i < obj1.arrayGetLength(); i += 16) {
6169
for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
6170
obj1.arrayGet(i+j, &obj2);
6171
writePSFmt(" {0:d}", obj2.getInt());
6179
dict->lookup("ID", &obj1);
6180
if (obj1.isString()) {
6181
writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
6185
dict->lookup("ImageType", &obj1);
6186
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6187
obj1.arrayGet(0, &obj2);
6188
samples = obj2.getInt();
6190
obj1.arrayGet(1, &obj2);
6191
bits = obj2.getInt();
6193
writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
6197
dict->lookup("Overprint", &obj1);
6198
if (obj1.isBool()) {
6199
writePSFmt("%ALDImageOverprint: {0:s}\n",
6200
obj1.getBool() ? "true" : "false");
6204
dict->lookup("Position", &obj1);
6205
if (obj1.isArray() && obj1.arrayGetLength() == 8) {
6206
obj1.arrayGet(0, &obj2);
6207
llx = obj2.getNum();
6209
obj1.arrayGet(1, &obj2);
6210
lly = obj2.getNum();
6212
obj1.arrayGet(2, &obj2);
6213
ulx = obj2.getNum();
6215
obj1.arrayGet(3, &obj2);
6216
uly = obj2.getNum();
6218
obj1.arrayGet(4, &obj2);
6219
urx = obj2.getNum();
6221
obj1.arrayGet(5, &obj2);
6222
ury = obj2.getNum();
6224
obj1.arrayGet(6, &obj2);
6225
lrx = obj2.getNum();
6227
obj1.arrayGet(7, &obj2);
6228
lry = obj2.getNum();
6230
opiTransform(state, llx, lly, &tllx, &tlly);
6231
opiTransform(state, ulx, uly, &tulx, &tuly);
6232
opiTransform(state, urx, ury, &turx, &tury);
6233
opiTransform(state, lrx, lry, &tlrx, &tlry);
6234
writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
6235
tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
6240
dict->lookup("Resolution", &obj1);
6241
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6242
obj1.arrayGet(0, &obj2);
6243
horiz = obj2.getNum();
6245
obj1.arrayGet(1, &obj2);
6246
vert = obj2.getNum();
6248
writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
6253
dict->lookup("Size", &obj1);
6254
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6255
obj1.arrayGet(0, &obj2);
6256
width = obj2.getInt();
6258
obj1.arrayGet(1, &obj2);
6259
height = obj2.getInt();
6261
writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
6265
//~ ignoring 'Tags' entry
6266
//~ need to use writePSString() and deal with >255-char lines
6268
dict->lookup("Tint", &obj1);
6270
writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
6274
dict->lookup("Transparency", &obj1);
6275
if (obj1.isBool()) {
6276
writePSFmt("%ALDImageTransparency: {0:s}\n",
6277
obj1.getBool() ? "true" : "false");
6281
writePS("%%BeginObject: image\n");
6282
writePS("opiMatrix2 setmatrix\n");
6286
// Convert PDF user space coordinates to PostScript default user space
6287
// coordinates. This has to account for both the PDF CTM and the
6288
// PSOutputDev page-fitting transform.
6289
void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
6290
double *x1, double *y1) {
6293
state->transform(x0, y0, x1, y1);
6300
} else if (rotate == 180) {
6303
} else if (rotate == 270) {
6312
void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
6315
if (globalParams->getPSOPI()) {
6316
opiDict->lookup("2.0", &dict);
6317
if (dict.isDict()) {
6318
writePS("%%EndIncludedImage\n");
6319
writePS("%%EndOPI\n");
6320
writePS("grestore\n");
6325
opiDict->lookup("1.3", &dict);
6326
if (dict.isDict()) {
6327
writePS("%%EndObject\n");
6328
writePS("restore\n");
6335
#endif // OPI_SUPPORT
6337
void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
6338
writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy);
6340
t3NeedsRestore = gTrue;
6343
void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
6344
double llx, double lly, double urx, double ury) {
6351
t3String = new GooString();
6353
t3Cacheable = gTrue;
6354
t3NeedsRestore = gTrue;
6357
void PSOutputDev::drawForm(Ref id) {
6358
writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
6361
void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
6365
if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
6371
while ((c = str->getChar()) != EOF) {
6377
//~ can nextFunc be reset to 0 -- maybe at the start of each page?
6378
//~ or maybe at the start of each color space / pattern?
6379
void PSOutputDev::cvtFunction(Function *func) {
6380
SampledFunction *func0;
6381
ExponentialFunction *func2;
6382
StitchingFunction *func3;
6383
PostScriptFunction *func4;
6384
int thisFunc, m, n, nSamples, i, j, k;
6386
switch (func->getType()) {
6388
case -1: // identity
6393
func0 = (SampledFunction *)func;
6394
thisFunc = nextFunc++;
6395
m = func0->getInputSize();
6396
n = func0->getOutputSize();
6398
for (i = 0; i < m; ++i) {
6399
nSamples *= func0->getSampleSize(i);
6401
writePSFmt("/xpdfSamples{0:d} [\n", thisFunc);
6402
for (i = 0; i < nSamples; ++i) {
6403
writePSFmt("{0:.6g}\n", func0->getSamples()[i]);
6406
writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2);
6407
// [e01] [efrac] x0 x1 ... xm-1
6408
for (i = m-1; i >= 0; --i) {
6409
// [e01] [efrac] x0 x1 ... xi
6410
writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add\n",
6411
func0->getDomainMin(i),
6412
(func0->getEncodeMax(i) - func0->getEncodeMin(i)) /
6413
(func0->getDomainMax(i) - func0->getDomainMin(i)),
6414
func0->getEncodeMin(i));
6415
// [e01] [efrac] x0 x1 ... xi-1 xi'
6416
writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n",
6417
func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1);
6418
// [e01] [efrac] x0 x1 ... xi-1 xi'
6419
writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
6420
// [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
6421
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i);
6422
// [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
6423
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1);
6424
// [e01] [efrac] x0 x1 ... xi-1 floor(xi')
6425
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i);
6426
// [e01] [efrac] x0 x1 ... xi-1
6429
for (i = 0; i < n; ++i) {
6430
// [e01] [efrac] y(0) ... y(i-1)
6431
for (j = 0; j < (1<<m); ++j) {
6432
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
6433
writePSFmt("xpdfSamples{0:d}\n", thisFunc);
6435
writePSFmt("{0:d} index {1:d} get\n", i+j+2, 2 * k + ((j >> k) & 1));
6436
for (k = m - 2; k >= 0; --k) {
6437
writePSFmt("{0:d} mul {1:d} index {2:d} get add\n",
6438
func0->getSampleSize(k),
6440
2 * k + ((j >> k) & 1));
6443
writePSFmt("{0:d} mul {1:d} add ", n, i);
6447
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
6448
for (j = 0; j < m; ++j) {
6449
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
6450
for (k = 0; k < (1 << (m - j)); k += 2) {
6451
// [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
6452
writePSFmt("{0:d} index {1:d} get dup\n",
6453
i + k/2 + (1 << (m-j)) - k, j);
6454
writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
6455
writePSFmt("{0:d} 1 roll\n", k/2 + (1 << (m-j)) - k - 1);
6457
// [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
6459
// [e01] [efrac] y(0) ... y(i-1) s
6460
writePSFmt("{0:.6g} mul {1:.6g} add\n",
6461
func0->getDecodeMax(i) - func0->getDecodeMin(i),
6462
func0->getDecodeMin(i));
6463
writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6464
func0->getRangeMin(i), func0->getRangeMin(i),
6465
func0->getRangeMax(i), func0->getRangeMax(i));
6466
// [e01] [efrac] y(0) ... y(i-1) y(i)
6468
// [e01] [efrac] y(0) ... y(n-1)
6469
writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n);
6472
case 2: // exponential
6473
func2 = (ExponentialFunction *)func;
6474
n = func2->getOutputSize();
6475
writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6476
func2->getDomainMin(0), func2->getDomainMin(0),
6477
func2->getDomainMax(0), func2->getDomainMax(0));
6479
for (i = 0; i < n; ++i) {
6481
writePSFmt("{0:d} index {1:.6g} exp {2:.6g} mul {3:.6g} add\n",
6482
i, func2->getE(), func2->getC1()[i] - func2->getC0()[i],
6484
if (func2->getHasRange()) {
6485
writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6486
func2->getRangeMin(i), func2->getRangeMin(i),
6487
func2->getRangeMax(i), func2->getRangeMax(i));
6491
writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n);
6494
case 3: // stitching
6495
func3 = (StitchingFunction *)func;
6496
thisFunc = nextFunc++;
6497
for (i = 0; i < func3->getNumFuncs(); ++i) {
6498
cvtFunction(func3->getFunc(i));
6499
writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i);
6501
writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6502
func3->getDomainMin(0), func3->getDomainMin(0),
6503
func3->getDomainMax(0), func3->getDomainMax(0));
6504
for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
6505
writePSFmt("dup {0:.6g} lt {{ {1:.6g} sub {2:.6g} mul {3:.6g} add xpdfFunc{4:d}_{5:d} }} {{\n",
6506
func3->getBounds()[i+1],
6507
func3->getBounds()[i],
6508
func3->getScale()[i],
6509
func3->getEncode()[2*i],
6512
writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add xpdfFunc{3:d}_{4:d}\n",
6513
func3->getBounds()[i],
6514
func3->getScale()[i],
6515
func3->getEncode()[2*i],
6517
for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
6518
writePS("} ifelse\n");
6523
case 4: // PostScript
6524
func4 = (PostScriptFunction *)func;
6525
writePS(func4->getCodeString()->getCString());
6531
void PSOutputDev::writePSChar(char c) {
6533
t3String->append(c);
6535
(*outputFunc)(outputStream, &c, 1);
6539
void PSOutputDev::writePS(char *s) {
6541
t3String->append(s);
6543
(*outputFunc)(outputStream, s, strlen(s));
6547
void PSOutputDev::writePSBuf(char *s, int len) {
6549
for (int i = 0; i < len; i++) {
6550
t3String->append(s[i]);
6553
(*outputFunc)(outputStream, s, len);
6557
void PSOutputDev::writePSFmt(const char *fmt, ...) {
6561
va_start(args, fmt);
6563
t3String->appendfv((char *)fmt, args);
6565
buf = GooString::formatv((char *)fmt, args);
6566
(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
6572
void PSOutputDev::writePSString(GooString *s) {
6579
for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
6585
if (*p == '(' || *p == ')' || *p == '\\') {
6587
writePSChar((char)*p);
6589
} else if (*p < 0x20 || *p >= 0x80) {
6590
sprintf(buf, "\\%03o", *p);
6594
writePSChar((char)*p);
6601
void PSOutputDev::writePSName(char *s) {
6606
while ((c = *p++)) {
6607
if (c <= (char)0x20 || c >= (char)0x7f ||
6608
c == '(' || c == ')' || c == '<' || c == '>' ||
6609
c == '[' || c == ']' || c == '{' || c == '}' ||
6610
c == '/' || c == '%' || c == '\\') {
6611
writePSFmt("#{0:02x}", c & 0xff);
6618
// Convert GooString to GooString, with appropriate escaping
6619
// of things that can't appear in a label
6620
// This is heavily based on the writePSTextLine() method
6621
GooString* PSOutputDev::filterPSLabel(GooString *label, GBool *needParens) {
6625
// - DSC comments must be printable ASCII; control chars and
6626
// backslashes have to be escaped (we do cheap UCS2-to-ASCII
6627
// conversion by simply ignoring the high byte)
6628
// - parentheses are escaped. this isn't strictly necessary for matched
6629
// parentheses, but shouldn't be a problem
6630
// - lines are limited to 255 chars (we limit to 200 here to allow
6631
// for the keyword, which was emitted by the caller)
6633
GooString *label2 = new GooString();
6634
int labelLength = label->getLength();
6636
if (labelLength == 0) {
6639
// this gets changed later if we find a non-numeric character
6643
if ( (labelLength >= 2) &&
6644
( (label->getChar(0) & 0xff) == 0xfe) &&
6645
( (label->getChar(1) & 0xff) == 0xff) ) {
6649
if ( (label->getChar(labelLength-1) == 0) ) {
6650
// prune the trailing null (0x000 for UCS2)
6657
for (int j = 0; i < labelLength && j < 200; i += step) {
6658
char c = label->getChar(i);
6659
if ( (c < '0') || (c > '9') ) {
6663
label2->append("\\\\");
6665
} else if (c == ')') {
6666
label2->append("\\)");
6667
} else if (c == '(') {
6668
label2->append("\\(");
6669
} else if (c < 0x20 || c > 0x7e) {
6670
label2->append(GooString::format("\\{0:03o}", c));
6678
*needParens = !(isNumeric);
6683
// Write a DSC-compliant <textline>.
6684
void PSOutputDev::writePSTextLine(GooString *s) {
6688
// - DSC comments must be printable ASCII; control chars and
6689
// backslashes have to be escaped (we do cheap Unicode-to-ASCII
6690
// conversion by simply ignoring the high byte)
6691
// - lines are limited to 255 chars (we limit to 200 here to allow
6692
// for the keyword, which was emitted by the caller)
6693
// - lines that start with a left paren are treated as <text>
6694
// instead of <textline>, so we escape a leading paren
6695
if (s->getLength() >= 2 &&
6696
(s->getChar(0) & 0xff) == 0xfe &&
6697
(s->getChar(1) & 0xff) == 0xff) {
6704
for (j = 0; i < s->getLength() && j < 200; i += step) {
6705
c = s->getChar(i) & 0xff;
6709
} else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
6710
writePSFmt("\\{0:03o}", c);