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
" /Policies 1 dict dup begin /PageSize 3 def end def",
120
" { /Duplex true def } if",
121
" currentdict end setpagedevice",
128
" /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
129
" /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender /pdfPatternCS",
130
" /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
135
" pdfStates 0 get begin",
137
" pdfDictSize dict begin",
139
" /pdfFillCS [] def",
140
" /pdfFillXform {} def",
141
" /pdfStrokeCS [] def",
142
" /pdfStrokeXform {} def",
147
" /pdfFill [0 0 0 1] def",
148
" /pdfStroke [0 0 0 1] def",
151
" /pdfStroke [0] def",
152
" /pdfFillOP false def",
153
" /pdfStrokeOP false def",
155
" /pdfLastFill false def",
156
" /pdfLastStroke false def",
157
" /pdfTextMat [1 0 0 1 0 0] def",
158
" /pdfFontSize 0 def",
159
" /pdfCharSpacing 0 def",
160
" /pdfTextRender 0 def",
161
" /pdfPatternCS false def",
162
" /pdfTextRise 0 def",
163
" /pdfWordSpacing 0 def",
164
" /pdfHorizScaling 1 def",
165
" /pdfTextClipPath [] def",
167
"/pdfEndPage { end } def",
169
"% separation convention operators",
170
"/findcmykcustomcolor where {",
173
" /findcmykcustomcolor { 5 array astore } def",
175
"/setcustomcolor where {",
178
" /setcustomcolor {",
180
" [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
181
" 0 4 getinterval cvx",
182
" [ exch /dup load exch { mul exch dup } /forall load",
183
" /pop load dup ] cvx",
184
" ] setcolorspace setcolor",
187
"/customcolorimage where {",
190
" /customcolorimage {",
192
" [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
194
" [ exch /dup load exch { mul exch dup } /forall load",
195
" /pop load dup ] cvx",
199
" /DataSource exch def",
200
" /ImageMatrix exch def",
201
" /BitsPerComponent exch def",
204
" /Decode [1 0] def",
213
"/g { dup /pdfFill exch def setgray",
214
" /pdfLastFill true def /pdfLastStroke false def } def",
215
"/G { dup /pdfStroke exch def setgray",
216
" /pdfLastStroke true def /pdfLastFill false def } def",
218
" pdfLastFill not {",
220
" /pdfLastFill true def /pdfLastStroke false def",
224
" pdfLastStroke not {",
225
" pdfStroke setgray",
226
" /pdfLastStroke true def /pdfLastFill false def",
230
"/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
231
" /pdfLastFill true def /pdfLastStroke false def } def",
232
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
233
" /pdfLastStroke true def /pdfLastFill false def } def",
235
" pdfLastFill not {",
236
" pdfFill aload pop setcmykcolor",
237
" /pdfLastFill true def /pdfLastStroke false def",
241
" pdfLastStroke not {",
242
" pdfStroke aload pop setcmykcolor",
243
" /pdfLastStroke true def /pdfLastFill false def",
247
"/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
248
" setcolorspace } def",
249
"/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
250
" setcolorspace } def",
251
"/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
252
" dup /pdfFill exch def aload pop pdfFillXform setcolor",
253
" /pdfLastFill true def /pdfLastStroke false def } def",
254
"/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
255
" dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
256
" /pdfLastStroke true def /pdfLastFill false def } def",
257
"/op { /pdfFillOP exch def",
258
" pdfLastFill { pdfFillOP setoverprint } if } def",
259
"/OP { /pdfStrokeOP exch def",
260
" pdfLastStroke { pdfStrokeOP setoverprint } if } def",
262
" pdfLastFill not {",
263
" pdfFillCS setcolorspace",
264
" pdfFill aload pop pdfFillXform setcolor",
265
" pdfFillOP setoverprint",
266
" /pdfLastFill true def /pdfLastStroke false def",
270
" pdfLastStroke not {",
271
" pdfStrokeCS setcolorspace",
272
" pdfStroke aload pop pdfStrokeXform setcolor",
273
" pdfStrokeOP setoverprint",
274
" /pdfLastStroke true def /pdfLastFill false def",
278
"/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
279
" /pdfLastFill true def /pdfLastStroke false def } def",
280
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
281
" /pdfLastStroke true def /pdfLastFill false def } def",
282
"/ck { 6 copy 6 array astore /pdfFill exch def",
283
" findcmykcustomcolor exch setcustomcolor",
284
" /pdfLastFill true def /pdfLastStroke false def } def",
285
"/CK { 6 copy 6 array astore /pdfStroke exch def",
286
" findcmykcustomcolor exch setcustomcolor",
287
" /pdfLastStroke true def /pdfLastFill false def } def",
288
"/op { /pdfFillOP exch def",
289
" pdfLastFill { pdfFillOP setoverprint } if } def",
290
"/OP { /pdfStrokeOP exch def",
291
" pdfLastStroke { pdfStrokeOP setoverprint } if } def",
293
" pdfLastFill not {",
294
" pdfFill aload length 4 eq {",
297
" findcmykcustomcolor exch setcustomcolor",
299
" pdfFillOP setoverprint",
300
" /pdfLastFill true def /pdfLastStroke false def",
304
" pdfLastStroke not {",
305
" pdfStroke aload length 4 eq {",
308
" findcmykcustomcolor exch setcustomcolor",
310
" pdfStrokeOP setoverprint",
311
" /pdfLastStroke true def /pdfLastFill false def",
317
" 4 3 roll findfont",
318
" 4 2 roll matrix scale makefont",
319
" dup length dict begin",
320
" { 1 index /FID ne { def } { pop pop } ifelse } forall",
321
" /Encoding exch def",
328
" dup length dict begin",
329
" { 1 index /FID ne { def } { pop pop } ifelse } forall",
336
"/pdfMakeFont16L3 {",
337
" 1 index /CIDFont resourcestatus {",
338
" pop pop 1 index /CIDFont findresource /CIDFontType known",
343
" 0 eq { /Identity-H } { /Identity-V } ifelse",
344
" exch 1 array astore composefont pop",
350
"% graphics state operators",
354
" pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
355
" pdfStates pdfStateIdx 1 add get begin",
356
" pdfOpNames { exch def } forall",
358
"/Q { end grestore } def",
360
"/q { gsave pdfDictSize dict begin } def",
363
" /pdfLastFill where {",
366
" pdfFillOP setoverprint",
368
" pdfStrokeOP setoverprint",
373
"/cm { concat } def",
374
"/d { setdash } def",
375
"/i { setflat } def",
376
"/j { setlinejoin } def",
377
"/J { setlinecap } def",
378
"/M { setmiterlimit } def",
379
"/w { setlinewidth } def",
380
"% path segment operators",
383
"/c { curveto } def",
384
"/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
385
" neg 0 rlineto closepath } def",
386
"/h { closepath } def",
387
"% path painting operators",
388
"/S { sCol stroke } def",
389
"/Sf { fCol stroke } def",
390
"/f { fCol fill } def",
391
"/f* { fCol eofill } def",
392
"% clipping operators",
393
"/W { clip newpath } def",
394
"/W* { eoclip newpath } def",
395
"/Ws { strokepath clip newpath } def",
396
"% text state operators",
397
"/Tc { /pdfCharSpacing exch def } def",
398
"/Tf { dup /pdfFontSize exch def",
399
" dup pdfHorizScaling mul exch matrix scale",
400
" pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
401
" exch findfont exch makefont setfont } def",
402
"/Tr { /pdfTextRender exch def } def",
403
"/Tp { /pdfPatternCS exch def } def",
404
"/Ts { /pdfTextRise exch def } def",
405
"/Tw { /pdfWordSpacing exch def } def",
406
"/Tz { /pdfHorizScaling exch def } def",
407
"% text positioning operators",
408
"/Td { pdfTextMat transform moveto } def",
409
"/Tm { /pdfTextMat exch def } def",
410
"% text string operators",
416
" 1 string dup 0 3 index put 3 index exec",
422
" currentfont /FontType get 0 eq {",
423
" 0 2 2 index length 1 sub {",
424
" 2 copy get exch 1 add 2 index exch get",
425
" 2 copy exch 256 mul add",
426
" 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
431
" 1 string dup 0 3 index put 3 index exec",
437
"/awcp {", // awidthcharpath
440
" 5 index 5 index rmoveto",
441
" 6 index eq { 7 index 7 index rmoveto } if",
446
" fCol", // because stringwidth has to draw Type 3 chars
447
" 1 index stringwidth pdfTextMat idtransform pop",
448
" sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
449
" pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
450
" 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
451
" pdfTextMat dtransform",
455
" fCol", // because stringwidth has to draw Type 3 chars
456
" 2 index stringwidth pdfTextMat idtransform pop",
458
" pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
459
" 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
460
" pdfTextMat dtransform",
464
" fCol", // because stringwidth has to draw Type 3 chars
465
" 2 index stringwidth pdfTextMat idtransform exch pop",
467
" 0 pdfWordSpacing pdfTextMat dtransform 32",
468
" 4 3 roll pdfCharSpacing add 0 exch",
469
" pdfTextMat dtransform",
473
" 0 pdfTextRise pdfTextMat dtransform rmoveto",
474
" currentpoint 8 2 roll",
475
" pdfTextRender 1 and 0 eq pdfPatternCS not and {",
476
" 6 copy awidthshow",
478
" pdfTextRender 3 and dup 1 eq exch 2 eq or {",
479
" 7 index 7 index moveto",
481
" currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
482
" false awcp currentpoint stroke moveto",
484
" pdfTextRender 4 and 0 ne pdfPatternCS or {",
487
" /pdfTextClipPath [ pdfTextClipPath aload pop",
493
" currentpoint newpath moveto",
497
" 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
499
"/TJm { pdfFontSize 0.001 mul mul neg 0",
500
" pdfTextMat dtransform rmoveto } def",
501
"/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
502
" pdfTextMat dtransform rmoveto } def",
503
"/Tclip { pdfTextClipPath cvx exec clip newpath",
504
" /pdfTextClipPath [] def } def",
505
"/Tclip* { pdfTextClipPath cvx exec eoclip newpath",
506
" /pdfTextClipPath [] def } def",
508
"% Level 1 image operators",
511
" /pdfImBuf1 4 index string def",
512
" { currentfile pdfImBuf1 readhexstring pop } image",
516
" /pdfImBuf1 4 index string def",
517
" /pdfImBuf2 4 index string def",
518
" /pdfImBuf3 4 index string def",
519
" /pdfImBuf4 4 index string def",
520
" { currentfile pdfImBuf1 readhexstring pop }",
521
" { currentfile pdfImBuf2 readhexstring pop }",
522
" { currentfile pdfImBuf3 readhexstring pop }",
523
" { currentfile pdfImBuf4 readhexstring pop }",
524
" true 4 colorimage",
528
" fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
529
" { currentfile pdfImBuf1 readhexstring pop } imagemask",
532
" { 2 copy get exch 1 add exch } imagemask",
536
"% Level 2 image operators",
537
"/pdfImBuf 100 string def",
540
" { currentfile pdfImBuf readline",
541
" not { pop exit } if",
542
" (%-EOD-) eq { exit } if } loop",
546
" findcmykcustomcolor exch",
547
" dup /Width get /pdfImBuf1 exch string def",
548
" dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
549
" /pdfImDecodeLow exch def",
550
" begin Width Height BitsPerComponent ImageMatrix DataSource end",
551
" /pdfImData exch def",
552
" { pdfImData pdfImBuf1 readstring pop",
553
" 0 1 2 index length 1 sub {",
554
" 1 index exch 2 copy get",
555
" pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
558
" 6 5 roll customcolorimage",
559
" { currentfile pdfImBuf readline",
560
" not { pop exit } if",
561
" (%-EOD-) eq { exit } if } loop",
566
" { currentfile pdfImBuf readline",
567
" not { pop exit } if",
568
" (%-EOD-) eq { exit } if } loop",
571
"/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
574
" 0 2 4 index length 1 sub {",
575
" dup 4 index exch 2 copy",
576
" get 5 index div put",
577
" 1 add 3 index exch 2 copy",
578
" get 3 index div put",
582
"/pdfImClipEnd { grestore } def",
584
"% shading operators",
586
" false 0 1 3 index length 1 sub {",
587
" dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
591
" exch pop exch pop",
593
"/funcCol { func n array astore } def",
601
" 4 index 4 index funcCol dup",
602
" 6 index 4 index funcCol dup",
603
" 3 1 roll colordelta 3 1 roll",
604
" 5 index 5 index funcCol dup",
605
" 3 1 roll colordelta 3 1 roll",
606
" 6 index 8 index funcCol dup",
607
" 3 1 roll colordelta 3 1 roll",
608
" colordelta or or or",
613
" 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
614
" 6 index 6 index 4 index 4 index 4 index funcSH",
615
" 2 index 6 index 6 index 4 index 4 index funcSH",
616
" 6 index 2 index 4 index 6 index 4 index funcSH",
617
" 5 3 roll 3 2 roll funcSH pop pop",
619
" pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
623
" funcCol aload pop k",
625
" dup 4 index exch mat transform m",
626
" 3 index 3 index mat transform l",
627
" 1 index 3 index mat transform l",
628
" mat transform l pop pop h f*",
641
" func n array astore",
650
" 2 index axialCol 2 index axialCol colordelta",
654
" 1 add 3 1 roll 2 copy add 0.5 mul",
655
" dup 4 3 roll exch 4 index axialSH",
656
" exch 3 2 roll axialSH",
658
" pop 2 copy add 0.5 mul",
662
" axialCol aload pop k",
664
" exch dup dx mul x0 add exch dy mul y0 add",
665
" 3 2 roll dup dx mul x0 add exch dy mul y0 add",
666
" dx abs dy abs ge {",
667
" 2 copy yMin sub dy mul dx div add yMin m",
668
" yMax sub dy mul dx div add yMax l",
669
" 2 copy yMax sub dy mul dx div add yMax l",
670
" yMin sub dy mul dx div add yMin l",
673
" exch 2 copy xMin sub dx mul dy div add xMin exch m",
674
" xMax sub dx mul dy div add xMax exch l",
675
" exch 2 copy xMax sub dx mul dy div add xMax exch l",
676
" xMin sub dx mul dy div add xMin exch l",
689
" func n array astore",
698
" 2 index dt mul t0 add radialCol",
699
" 2 index dt mul t0 add radialCol colordelta",
703
" 1 add 3 1 roll 2 copy add 0.5 mul",
704
" dup 4 3 roll exch 4 index radialSH",
705
" exch 3 2 roll radialSH",
707
" pop 2 copy add 0.5 mul dt mul t0 add",
711
" radialCol aload pop k",
714
" exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
716
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
720
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
722
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
724
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
726
" dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
736
static char *cmapProlog[] = {
737
"/CIDInit /ProcSet findresource begin",
741
" /CMapName /Identity-H def",
742
" /CIDSystemInfo 3 dict dup begin",
743
" /Registry (Adobe) def",
744
" /Ordering (Identity) def",
745
" /Supplement 0 def",
747
" 1 begincodespacerange",
749
" endcodespacerange",
755
" currentdict CMapName exch /CMap defineresource pop",
760
" /CMapName /Identity-V def",
761
" /CIDSystemInfo 3 dict dup begin",
762
" /Registry (Adobe) def",
763
" /Ordering (Identity) def",
764
" /Supplement 0 def",
767
" 1 begincodespacerange",
769
" endcodespacerange",
775
" currentdict CMapName exch /CMap defineresource pop",
781
//------------------------------------------------------------------------
783
//------------------------------------------------------------------------
786
char *psName; // PostScript name
787
double mWidth; // width of 'm' character
790
static const char *psFonts[] = {
794
"Courier-BoldOblique",
798
"Helvetica-BoldOblique",
808
static const PSSubstFont psSubstFonts[] = {
809
{"Helvetica", 0.833},
810
{"Helvetica-Oblique", 0.833},
811
{"Helvetica-Bold", 0.889},
812
{"Helvetica-BoldOblique", 0.889},
813
{"Times-Roman", 0.788},
814
{"Times-Italic", 0.722},
815
{"Times-Bold", 0.833},
816
{"Times-BoldItalic", 0.778},
818
{"Courier-Oblique", 0.600},
819
{"Courier-Bold", 0.600},
820
{"Courier-BoldOblique", 0.600}
823
// Info for 8-bit fonts
826
Gushort *codeToGID; // code-to-GID mapping for TrueType fonts
829
// Encoding info for substitute 16-bit font
835
//------------------------------------------------------------------------
837
//------------------------------------------------------------------------
839
#define psProcessCyan 1
840
#define psProcessMagenta 2
841
#define psProcessYellow 4
842
#define psProcessBlack 8
843
#define psProcessCMYK 15
845
//------------------------------------------------------------------------
847
//------------------------------------------------------------------------
849
class PSOutCustomColor {
852
PSOutCustomColor(double cA, double mA,
853
double yA, double kA, GooString *nameA);
858
PSOutCustomColor *next;
861
PSOutCustomColor::PSOutCustomColor(double cA, double mA,
862
double yA, double kA, GooString *nameA) {
871
PSOutCustomColor::~PSOutCustomColor() {
875
//------------------------------------------------------------------------
877
struct PSOutImgClipRect {
881
//------------------------------------------------------------------------
883
//------------------------------------------------------------------------
885
class DeviceNRecoder: public FilterStream {
888
DeviceNRecoder(Stream *strA, int widthA, int heightA,
889
GfxImageColorMap *colorMapA);
890
virtual ~DeviceNRecoder();
891
virtual StreamKind getKind() { return strWeird; }
892
virtual void reset();
893
virtual int getChar()
894
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
895
virtual int lookChar()
896
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
897
virtual GooString *getPSFilter(int psLevel, char *indent) { return NULL; }
898
virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
899
virtual GBool isEncoder() { return gTrue; }
906
GfxImageColorMap *colorMap;
909
int buf[gfxColorMaxComps];
915
DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
916
GfxImageColorMap *colorMapA):
920
colorMap = colorMapA;
923
bufIdx = gfxColorMaxComps;
924
bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
925
getAlt()->getNComps();
926
func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
927
getTintTransformFunc();
930
DeviceNRecoder::~DeviceNRecoder() {
936
void DeviceNRecoder::reset() {
937
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
938
colorMap->getBits());
942
GBool DeviceNRecoder::fillBuf() {
943
Guchar pixBuf[gfxColorMaxComps];
945
double x[gfxColorMaxComps], y[gfxColorMaxComps];
948
if (pixelIdx >= width * height) {
951
imgStr->getPixel(pixBuf);
952
colorMap->getColor(pixBuf, &color);
954
i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps();
956
x[i] = colToDbl(color.c[i]);
958
func->transform(x, y);
959
for (i = 0; i < bufSize; ++i) {
960
buf[i] = (int)(y[i] * 255 + 0.5);
967
//------------------------------------------------------------------------
969
//------------------------------------------------------------------------
972
typedef void (*SignalFunc)(int);
975
static void outputToFile(void *stream, char *data, int len) {
976
fwrite(data, 1, len, (FILE *)stream);
979
PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
981
int firstPage, int lastPage, PSOutMode modeA,
982
int paperWidthA, int paperHeightA, GBool duplexA,
983
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
984
GBool forceRasterizeA,
987
PSFileType fileTypeA;
990
underlayCbkData = NULL;
992
overlayCbkData = NULL;
996
fontFileNames = NULL;
1003
customColors = NULL;
1004
haveTextClip = gFalse;
1005
haveCSPattern = gFalse;
1008
forceRasterize = forceRasterizeA;
1010
// open file or pipe
1011
if (!strcmp(fileName, "-")) {
1012
fileTypeA = psStdout;
1014
} else if (fileName[0] == '|') {
1018
signal(SIGPIPE, (SignalFunc)SIG_IGN);
1020
if (!(f = popen(fileName + 1, "w"))) {
1021
error(-1, "Couldn't run print command '%s'", fileName);
1026
error(-1, "Print commands are not supported ('%s')", fileName);
1032
if (!(f = fopen(fileName, "w"))) {
1033
error(-1, "Couldn't open PostScript file '%s'", fileName);
1039
init(outputToFile, f, fileTypeA, psTitle,
1040
doc, xrefA, catalog, firstPage, lastPage, modeA,
1041
imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
1042
paperWidthA, paperHeightA, duplexA);
1045
PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
1048
XRef *xrefA, Catalog *catalog,
1049
int firstPage, int lastPage, PSOutMode modeA,
1050
int paperWidthA, int paperHeightA, GBool duplexA,
1051
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
1052
GBool forceRasterizeA,
1053
GBool manualCtrlA) {
1055
underlayCbkData = NULL;
1057
overlayCbkData = NULL;
1061
fontFileNames = NULL;
1068
customColors = NULL;
1069
haveTextClip = gFalse;
1070
haveCSPattern = gFalse;
1073
forceRasterize = forceRasterizeA;
1075
init(outputFuncA, outputStreamA, psGeneric, psTitle,
1076
doc, xrefA, catalog, firstPage, lastPage, modeA,
1077
imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
1078
paperWidthA, paperHeightA, duplexA);
1081
void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
1082
PSFileType fileTypeA, char *pstitle, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
1083
int firstPage, int lastPage, PSOutMode modeA,
1084
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
1085
GBool manualCtrlA, int paperWidthA, int paperHeightA,
1090
displayText = gTrue;
1092
outputFunc = outputFuncA;
1093
outputStream = outputStreamA;
1094
fileType = fileTypeA;
1095
m_catalog = catalog;
1097
level = globalParams->getPSLevel();
1099
paperWidth = paperWidthA;
1100
paperHeight = paperHeightA;
1105
if (paperWidth < 0 || paperHeight < 0) {
1107
if ((page = doc->getPage(firstPage))) {
1108
paperWidth = (int)ceil(page->getMediaWidth());
1109
paperHeight = (int)ceil(page->getMediaHeight());
1111
error(-1, "Invalid page %d", firstPage);
1116
substFonts = globalParams->getPSSubstFonts();
1117
preload = globalParams->getPSPreload();
1118
if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
1119
imgLLX = imgLLY = 0;
1120
imgURX = paperWidth;
1121
imgURY = paperHeight;
1123
if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
1124
imgLLX = imgLLY = 0;
1125
imgURX = paperWidth;
1126
imgURY = paperHeight;
1128
manualCtrl = manualCtrlA;
1129
if (mode == psModeForm) {
1130
lastPage = firstPage;
1133
inType3Char = gFalse;
1136
// initialize OPI nesting levels
1142
xScale0 = yScale0 = 0;
1144
clipLLX0 = clipLLY0 = 0;
1145
clipURX0 = clipURY0 = -1;
1147
// initialize fontIDs, fontFileIDs, and fontFileNames lists
1150
fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
1151
fontFileIDSize = 64;
1153
fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
1154
fontFileNameSize = 64;
1155
fontFileNameLen = 0;
1156
fontFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
1157
psFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
1158
nextTrueTypeNum = 0;
1168
xobjStack = new GooList();
1170
numTilingPatterns = 0;
1173
// initialize embedded font resource comment list
1174
embFontList = new GooString();
1178
// this check is needed in case the document has zero pages
1179
if ((page = doc->getPage(firstPage))) {
1180
writeHeader(firstPage, lastPage,
1181
page->getMediaBox(),
1186
error(-1, "Invalid page %d", firstPage);
1187
box = new PDFRectangle(0, 0, 1, 1);
1188
writeHeader(firstPage, lastPage, box, box, 0, pstitle);
1191
if (mode != psModeForm) {
1192
writePS("%%BeginProlog\n");
1195
if (mode != psModeForm) {
1196
writePS("%%EndProlog\n");
1197
writePS("%%BeginSetup\n");
1199
writeDocSetup(doc, catalog, firstPage, lastPage, duplexA);
1200
if (mode != psModeForm) {
1201
writePS("%%EndSetup\n");
1205
// initialize sequential page number
1209
PSOutputDev::~PSOutputDev() {
1210
PSOutCustomColor *cc;
1215
writePS("%%Trailer\n");
1217
if (mode != psModeForm) {
1221
if (fileType == psFile) {
1223
ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
1225
fclose((FILE *)outputStream);
1228
else if (fileType == psPipe) {
1229
pclose((FILE *)outputStream);
1231
signal(SIGPIPE, (SignalFunc)SIG_DFL);
1245
if (fontFileNames) {
1246
for (i = 0; i < fontFileNameLen; ++i) {
1247
delete fontFileNames[i];
1249
gfree(fontFileNames);
1252
for (i = 0; i < font8InfoLen; ++i) {
1253
gfree(font8Info[i].codeToGID);
1258
for (i = 0; i < fontFileNameLen; ++i) {
1260
delete psFileNames[i];
1265
for (i = 0; i < font16EncLen; ++i) {
1266
delete font16Enc[i].enc;
1275
while (customColors) {
1277
customColors = cc->next;
1282
void PSOutputDev::writeHeader(int firstPage, int lastPage,
1283
PDFRectangle *mediaBox, PDFRectangle *cropBox,
1284
int pageRotate, char *psTitle) {
1285
double x1, y1, x2, y2;
1289
case psModePSOrigPageSizes:
1291
writePS("%!PS-Adobe-3.0\n");
1294
writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
1297
writePS("%!PS-Adobe-3.0 Resource-Form\n");
1300
xref->getDocInfo(&info);
1301
if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
1302
writePS("%%Creator: ");
1303
writePSTextLine(obj1.getString());
1308
writePSFmt("%%Title: {0:s}\n", psTitle);
1310
writePSFmt("%%LanguageLevel: {0:d}\n",
1311
(level == psLevel1 || level == psLevel1Sep) ? 1 :
1312
(level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
1313
if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
1314
writePS("%%DocumentProcessColors: (atend)\n");
1315
writePS("%%DocumentCustomColors: (atend)\n");
1317
writePS("%%DocumentSuppliedResources: (atend)\n");
1320
case psModePSOrigPageSizes:
1324
writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
1325
paperWidth, paperHeight);
1326
writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
1327
writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
1328
writePS("%%EndComments\n");
1329
writePS("%%BeginDefaults\n");
1330
writePS("%%PageMedia: plain\n");
1331
writePS("%%EndDefaults\n");
1334
epsX1 = cropBox->x1;
1335
epsY1 = cropBox->y1;
1336
epsX2 = cropBox->x2;
1337
epsY2 = cropBox->y2;
1338
if (pageRotate == 0 || pageRotate == 180) {
1343
} else { // pageRotate == 90 || pageRotate == 270
1349
writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
1350
(int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
1351
if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) ||
1352
floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) {
1353
writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
1356
writePS("%%DocumentSuppliedResources: (atend)\n");
1357
writePS("%%EndComments\n");
1360
writePS("%%EndComments\n");
1361
writePS("32 dict dup begin\n");
1362
writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n",
1363
(int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
1364
(int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
1365
writePS("/FormType 1 def\n");
1366
writePS("/Matrix [1 0 0 1 0 0] def\n");
1371
void PSOutputDev::writeXpdfProcset() {
1372
GBool lev1, lev2, lev3, sep, nonSep;
1376
writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", "3.00");
1377
writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
1378
lev1 = lev2 = lev3 = sep = nonSep = gTrue;
1379
for (p = prolog; *p; ++p) {
1380
if ((*p)[0] == '~') {
1381
lev1 = lev2 = lev3 = sep = nonSep = gFalse;
1382
for (q = *p + 1; *q; ++q) {
1384
case '1': lev1 = gTrue; break;
1385
case '2': lev2 = gTrue; break;
1386
case '3': lev3 = gTrue; break;
1387
case 's': sep = gTrue; break;
1388
case 'n': nonSep = gTrue; break;
1391
} else if ((level == psLevel1 && lev1 && nonSep) ||
1392
(level == psLevel1Sep && lev1 && sep) ||
1393
(level == psLevel2 && lev2 && nonSep) ||
1394
(level == psLevel2Sep && lev2 && sep) ||
1395
(level == psLevel3 && lev3 && nonSep) ||
1396
(level == psLevel3Sep && lev3 && sep)) {
1397
writePSFmt("{0:s}\n", *p);
1400
writePS("%%EndResource\n");
1402
if (level >= psLevel3) {
1403
for (p = cmapProlog; *p; ++p) {
1404
writePSFmt("{0:s}\n", *p);
1409
void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
1410
int firstPage, int lastPage,
1418
if (mode == psModeForm) {
1419
// swap the form and xpdf dicts
1420
writePS("xpdf end begin dup begin\n");
1422
writePS("xpdf begin\n");
1424
for (pg = firstPage; pg <= lastPage; ++pg) {
1425
page = doc->getPage(pg);
1427
error(-1, "Failed writing resources for page %d", pg);
1430
if ((resDict = page->getResourceDict())) {
1431
setupResources(resDict);
1433
annots = new Annots(xref, catalog, page->getAnnots(&obj1));
1435
for (i = 0; i < annots->getNumAnnots(); ++i) {
1436
if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
1437
obj1.streamGetDict()->lookup("Resources", &obj2);
1438
if (obj2.isDict()) {
1439
setupResources(obj2.getDict());
1447
if (mode != psModeForm) {
1448
if (mode != psModeEPS && !manualCtrl) {
1449
writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
1450
paperWidth, paperHeight, duplexA ? "true" : "false");
1453
if (globalParams->getPSOPI()) {
1454
writePS("/opiMatrix matrix currentmatrix def\n");
1460
void PSOutputDev::writePageTrailer() {
1461
if (mode != psModeForm) {
1462
writePS("pdfEndPage\n");
1466
void PSOutputDev::writeTrailer() {
1467
PSOutCustomColor *cc;
1469
if (mode == psModeForm) {
1470
writePS("/Foo exch /Form defineresource pop\n");
1473
writePS("%%DocumentSuppliedResources:\n");
1474
writePS(embFontList->getCString());
1475
if (level == psLevel1Sep || level == psLevel2Sep ||
1476
level == psLevel3Sep) {
1477
writePS("%%DocumentProcessColors:");
1478
if (processColors & psProcessCyan) {
1481
if (processColors & psProcessMagenta) {
1482
writePS(" Magenta");
1484
if (processColors & psProcessYellow) {
1487
if (processColors & psProcessBlack) {
1491
writePS("%%DocumentCustomColors:");
1492
for (cc = customColors; cc; cc = cc->next) {
1493
writePSFmt(" ({0:s})", cc->name->getCString());
1496
writePS("%%CMYKCustomColor:\n");
1497
for (cc = customColors; cc; cc = cc->next) {
1498
writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t})\n",
1499
cc->c, cc->m, cc->y, cc->k, cc->name);
1505
void PSOutputDev::setupResources(Dict *resDict) {
1506
Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
1511
setupFonts(resDict);
1512
setupImages(resDict);
1513
setupForms(resDict);
1515
//----- recursively scan XObjects
1516
resDict->lookup("XObject", &xObjDict);
1517
if (xObjDict.isDict()) {
1518
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
1520
// avoid infinite recursion on XObjects
1522
if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
1523
ref0 = xObjRef.getRef();
1524
for (j = 0; j < xobjStack->getLength(); ++j) {
1525
ref1 = *(Ref *)xobjStack->get(j);
1526
if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
1532
xobjStack->append(&ref0);
1537
// process the XObject's resource dictionary
1538
xObjDict.dictGetVal(i, &xObj);
1539
if (xObj.isStream()) {
1540
xObj.streamGetDict()->lookup("Resources", &resObj);
1541
if (resObj.isDict()) {
1542
setupResources(resObj.getDict());
1549
if (xObjRef.isRef() && !skip) {
1550
xobjStack->del(xobjStack->getLength() - 1);
1557
//----- recursively scan Patterns
1558
resDict->lookup("Pattern", &patDict);
1559
if (patDict.isDict()) {
1560
inType3Char = gTrue;
1561
for (i = 0; i < patDict.dictGetLength(); ++i) {
1563
// avoid infinite recursion on Patterns
1565
if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
1566
ref0 = patRef.getRef();
1567
for (j = 0; j < xobjStack->getLength(); ++j) {
1568
ref1 = *(Ref *)xobjStack->get(j);
1569
if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
1575
xobjStack->append(&ref0);
1580
// process the Pattern's resource dictionary
1581
patDict.dictGetVal(i, &pat);
1582
if (pat.isStream()) {
1583
pat.streamGetDict()->lookup("Resources", &resObj);
1584
if (resObj.isDict()) {
1585
setupResources(resObj.getDict());
1592
if (patRef.isRef() && !skip) {
1593
xobjStack->del(xobjStack->getLength() - 1);
1597
inType3Char = gFalse;
1602
void PSOutputDev::setupFonts(Dict *resDict) {
1605
GfxFontDict *gfxFontDict;
1609
if (forceRasterize) return;
1612
resDict->lookupNF("Font", &obj1);
1614
obj1.fetch(xref, &obj2);
1615
if (obj2.isDict()) {
1617
gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
1620
} else if (obj1.isDict()) {
1621
gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
1624
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
1625
if ((font = gfxFontDict->getFont(i))) {
1626
setupFont(font, resDict);
1634
void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
1637
PSFontParam *fontParam;
1648
DisplayFontParam *dfp;
1650
// check if font is already set up
1651
for (i = 0; i < fontIDLen; ++i) {
1652
if (fontIDs[i].num == font->getID()->num &&
1653
fontIDs[i].gen == font->getID()->gen) {
1658
// add entry to fontIDs list
1659
if (fontIDLen >= fontIDSize) {
1661
fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref));
1663
fontIDs[fontIDLen++] = *font->getID();
1668
// check for resident 8-bit font
1669
if (font->getName() &&
1670
(fontParam = globalParams->getPSFont(font->getName()))) {
1671
psName = new GooString(fontParam->psFontName->getCString());
1673
// check for embedded Type 1 font
1674
} else if (globalParams->getPSEmbedType1() &&
1675
font->getType() == fontType1 &&
1676
font->getEmbeddedFontID(&fontFileID) &&
1677
font->getEmbeddedFontName()) {
1678
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1679
setupEmbeddedType1Font(&fontFileID, psName);
1681
// check for embedded Type 1C font
1682
} else if (globalParams->getPSEmbedType1() &&
1683
font->getType() == fontType1C &&
1684
font->getEmbeddedFontID(&fontFileID) &&
1685
font->getOrigName()) {
1686
// use the PDF font name because the embedded font name might
1687
// not include the subset prefix
1688
psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
1689
setupEmbeddedType1CFont(font, &fontFileID, psName);
1691
// check for embedded OpenType - Type 1C font
1692
} else if (globalParams->getPSEmbedType1() &&
1693
font->getType() == fontType1COT &&
1694
font->getEmbeddedFontID(&fontFileID) &&
1695
font->getOrigName()) {
1696
// use the PDF font name because the embedded font name might
1697
// not include the subset prefix
1698
psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
1699
setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
1701
// check for external Type 1 font file
1702
} else if (globalParams->getPSEmbedType1() &&
1703
font->getType() == fontType1 &&
1704
font->getExtFontFile() &&
1706
// this assumes that the PS font name matches the PDF font name
1707
psName = font->getName()->copy();
1708
setupExternalType1Font(font->getExtFontFile(), psName);
1710
// check for embedded TrueType font
1711
} else if (globalParams->getPSEmbedTrueType() &&
1712
(font->getType() == fontTrueType ||
1713
font->getType() == fontTrueTypeOT) &&
1714
font->getEmbeddedFontID(&fontFileID) &&
1715
font->getEmbeddedFontName()) {
1716
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1717
setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
1719
// check for external TrueType font file
1720
} else if (globalParams->getPSEmbedTrueType() &&
1721
font->getType() == fontTrueType &&
1722
font->getExtFontFile()) {
1723
psName = setupExternalTrueTypeFont(font);
1725
// check for embedded CID PostScript font
1726
} else if (globalParams->getPSEmbedCIDPostScript() &&
1727
font->getType() == fontCIDType0C &&
1728
font->getEmbeddedFontID(&fontFileID) &&
1729
font->getEmbeddedFontName()) {
1730
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1731
setupEmbeddedCIDType0Font(font, &fontFileID, psName);
1733
// check for embedded CID TrueType font
1734
} else if (globalParams->getPSEmbedCIDTrueType() &&
1735
(font->getType() == fontCIDType2 ||
1736
font->getType() == fontCIDType2OT) &&
1737
font->getEmbeddedFontID(&fontFileID) &&
1738
font->getEmbeddedFontName()) {
1739
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1740
setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
1742
// check for embedded OpenType - CID CFF font
1743
} else if (globalParams->getPSEmbedCIDPostScript() &&
1744
font->getType() == fontCIDType0COT &&
1745
font->getEmbeddedFontID(&fontFileID) &&
1746
font->getEmbeddedFontName()) {
1747
psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
1748
setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
1750
// check for Type 3 font
1751
} else if (font->getType() == fontType3) {
1752
psName = GooString::format("T3_{0:d}_{1:d}",
1753
font->getID()->num, font->getID()->gen);
1754
setupType3Font(font, psName, parentResDict);
1756
// check for external CID TrueType font file
1757
} else if (globalParams->getPSEmbedCIDTrueType() &&
1758
font->getType() == fontCIDType2 &&
1759
font->getExtFontFile()) {
1760
psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile());
1762
// do 8-bit font substitution
1763
} else if (!font->isCIDFont()) {
1765
name = font->getName();
1768
for (i = 0; psFonts[i]; ++i) {
1769
if (name->cmp(psFonts[i]) == 0) {
1770
psName = new GooString(psFonts[i]);
1777
if (font->isFixedWidth()) {
1779
} else if (font->isSerif()) {
1784
if (font->isBold()) {
1787
if (font->isItalic()) {
1790
psName = new GooString(psSubstFonts[i].psName);
1791
for (code = 0; code < 256; ++code) {
1792
if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
1793
charName[0] == 'm' && charName[1] == '\0') {
1798
w1 = ((Gfx8BitFont *)font)->getWidth(code);
1802
w2 = psSubstFonts[i].mWidth;
1808
psName = new GooString(name);
1811
if (font->getType() == fontType3) {
1812
// This is a hack which makes it possible to substitute for some
1813
// Type 3 fonts. The problem is that it's impossible to know what
1814
// the base coordinate system used in the font is without actually
1815
// rendering the font.
1817
fm = font->getFontMatrix();
1819
ys *= fm[3] / fm[0];
1826
// do 16-bit font substitution
1827
} else if ((fontParam = globalParams->
1828
getPSFont16(font->getName(),
1829
((GfxCIDFont *)font)->getCollection(),
1830
font->getWMode()))) {
1832
psName = fontParam->psFontName->copy();
1833
if (font16EncLen >= font16EncSize) {
1834
font16EncSize += 16;
1835
font16Enc = (PSFont16Enc *)greallocn(font16Enc,
1836
font16EncSize, sizeof(PSFont16Enc));
1838
font16Enc[font16EncLen].fontID = *font->getID();
1839
font16Enc[font16EncLen].enc = fontParam->encoding->copy();
1840
if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
1844
error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
1845
font16Enc[font16EncLen].enc->getCString());
1848
// try the display font for embedding
1849
} else if (globalParams->getPSEmbedCIDTrueType() &&
1850
((GfxCIDFont *)font)->getCollection() &&
1851
(dfp = globalParams->
1852
getDisplayFont(font)) &&
1853
dfp->kind == displayFontTT) {
1854
psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex);
1856
// give up - can't do anything with this font
1858
error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
1859
font->getName() ? font->getName()->getCString() : "(unnamed)",
1860
((GfxCIDFont *)font)->getCollection()
1861
? ((GfxCIDFont *)font)->getCollection()->getCString()
1866
// generate PostScript code to set up the font
1867
if (font->isCIDFont()) {
1868
if (level == psLevel3 || level == psLevel3Sep) {
1869
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
1870
font->getID()->num, font->getID()->gen, psName,
1873
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n",
1874
font->getID()->num, font->getID()->gen, psName,
1878
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.6g} {4:.6g}\n",
1879
font->getID()->num, font->getID()->gen, psName, xs, ys);
1880
for (i = 0; i < 256; i += 8) {
1881
writePS((char *)((i == 0) ? "[ " : " "));
1882
for (j = 0; j < 8; ++j) {
1883
if (font->getType() == fontTrueType &&
1885
!((Gfx8BitFont *)font)->getHasEncoding()) {
1886
sprintf(buf, "c%02x", i+j);
1889
charName = ((Gfx8BitFont *)font)->getCharName(i+j);
1890
// this is a kludge for broken PDF files that encode char 32
1892
if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
1897
writePSName(charName ? charName : (char *)".notdef");
1898
// the empty name is legal in PDF and PostScript, but PostScript
1899
// uses a double-slash (//...) for "immediately evaluated names",
1900
// so we need to add a space character here
1901
if (charName && !charName[0]) {
1905
writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
1907
writePS("pdfMakeFont\n");
1913
void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
1914
static const char hexChar[17] = "0123456789abcdef";
1915
Object refObj, strObj, obj1, obj2, obj3;
1917
int length1, length2, length3;
1921
GBool writePadding = gTrue;
1924
// check if font is already embedded
1925
for (i = 0; i < fontFileIDLen; ++i) {
1926
if (fontFileIDs[i].num == id->num &&
1927
fontFileIDs[i].gen == id->gen)
1931
// add entry to fontFileIDs list
1932
if (fontFileIDLen >= fontFileIDSize) {
1933
fontFileIDSize += 64;
1934
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
1936
fontFileIDs[fontFileIDLen++] = *id;
1938
// get the font stream and info
1939
refObj.initRef(id->num, id->gen);
1940
refObj.fetch(xref, &strObj);
1942
if (!strObj.isStream()) {
1943
error(-1, "Embedded font file object is not a stream");
1946
if (!(dict = strObj.streamGetDict())) {
1947
error(-1, "Embedded font stream is missing its dictionary");
1950
dict->lookup("Length1", &obj1);
1951
dict->lookup("Length2", &obj2);
1952
dict->lookup("Length3", &obj3);
1953
if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
1954
error(-1, "Missing length fields in embedded font stream dictionary");
1960
length1 = obj1.getInt();
1961
length2 = obj2.getInt();
1962
length3 = obj3.getInt();
1967
// beginning comment
1968
writePSFmt("%%BeginResource: font {0:t}\n", psName);
1969
embFontList->append("%%+ font ");
1970
embFontList->append(psName->getCString());
1971
embFontList->append("\n");
1973
// copy ASCII portion of font
1974
strObj.streamReset();
1975
for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
1979
// figure out if encrypted portion is binary or ASCII
1981
for (i = 0; i < 4; ++i) {
1982
start[i] = strObj.streamGetChar();
1983
if (start[i] == EOF) {
1984
error(-1, "Unexpected end of file in embedded font stream");
1987
if (!((start[i] >= '0' && start[i] <= '9') ||
1988
(start[i] >= 'A' && start[i] <= 'F') ||
1989
(start[i] >= 'a' && start[i] <= 'f')))
1995
// length2 == 0 is an error
1996
// trying to solve it by just piping all
1998
error(-1, "Font has length2 as 0, trying to overcome the problem reading the stream until the end");
2000
writePadding = gFalse;
2004
// convert binary data to ASCII
2006
for (i = 0; i < 4; ++i) {
2007
writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
2008
writePSChar(hexChar[start[i] & 0x0f]);
2010
#if 0 // this causes trouble for various PostScript printers
2011
// if Length2 is incorrect (too small), font data gets chopped, so
2012
// we take a few extra characters from the trailer just in case
2013
length2 += length3 >= 8 ? 8 : length3;
2015
while (i < length2) {
2016
if ((c = strObj.streamGetChar()) == EOF) {
2019
writePSChar(hexChar[(c >> 4) & 0x0f]);
2020
writePSChar(hexChar[c & 0x0f]);
2021
if (++i % 32 == 0) {
2029
// already in ASCII format -- just copy it
2031
for (i = 0; i < 4; ++i) {
2032
writePSChar(start[i]);
2034
for (i = 4; i < length2; ++i) {
2035
if ((c = strObj.streamGetChar()) == EOF) {
2045
// write fixed-content portion
2046
while ((c = strObj.streamGetChar()) != EOF) {
2050
// write padding and "cleartomark"
2051
for (i = 0; i < 8; ++i) {
2052
writePS("00000000000000000000000000000000"
2053
"00000000000000000000000000000000\n");
2055
writePS("cleartomark\n");
2060
writePS("%%EndResource\n");
2063
strObj.streamClose();
2067
//~ This doesn't handle .pfb files or binary eexec data (which only
2068
//~ happens in pfb files?).
2069
void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
2074
// check if font is already embedded
2075
for (i = 0; i < fontFileNameLen; ++i) {
2076
if (!fontFileNames[i]->cmp(fileName)) {
2081
// add entry to fontFileNames list
2082
if (fontFileNameLen >= fontFileNameSize) {
2083
fontFileNameSize += 64;
2084
fontFileNames = (GooString **)greallocn(fontFileNames,
2085
fontFileNameSize, sizeof(GooString *));
2086
psFileNames = (GooString **)greallocn(psFileNames,
2087
fontFileNameSize, sizeof(GooString *));
2089
fontFileNames[fontFileNameLen] = fileName->copy();
2090
psFileNames[fontFileNameLen] = psName->copy();
2093
// beginning comment
2094
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2095
embFontList->append("%%+ font ");
2096
embFontList->append(psName->getCString());
2097
embFontList->append("\n");
2099
// copy the font file
2100
if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
2101
error(-1, "Couldn't open external font file");
2104
while ((c = fgetc(fontFile)) != EOF) {
2110
writePS("%%EndResource\n");
2113
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
2114
GooString *psName) {
2120
// check if font is already embedded
2121
for (i = 0; i < fontFileIDLen; ++i) {
2122
if (fontFileIDs[i].num == id->num &&
2123
fontFileIDs[i].gen == id->gen)
2127
// add entry to fontFileIDs list
2128
if (fontFileIDLen >= fontFileIDSize) {
2129
fontFileIDSize += 64;
2130
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2132
fontFileIDs[fontFileIDLen++] = *id;
2134
// beginning comment
2135
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2136
embFontList->append("%%+ font ");
2137
embFontList->append(psName->getCString());
2138
embFontList->append("\n");
2140
// convert it to a Type 1 font
2141
fontBuf = font->readEmbFontFile(xref, &fontLen);
2142
if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
2143
ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
2144
outputFunc, outputStream);
2150
writePS("%%EndResource\n");
2153
void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
2154
GooString *psName) {
2160
// check if font is already embedded
2161
for (i = 0; i < fontFileIDLen; ++i) {
2162
if (fontFileIDs[i].num == id->num &&
2163
fontFileIDs[i].gen == id->gen)
2167
// add entry to fontFileIDs list
2168
if (fontFileIDLen >= fontFileIDSize) {
2169
fontFileIDSize += 64;
2170
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2172
fontFileIDs[fontFileIDLen++] = *id;
2174
// beginning comment
2175
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2176
embFontList->append("%%+ font ");
2177
embFontList->append(psName->getCString());
2178
embFontList->append("\n");
2180
// convert it to a Type 1 font
2181
fontBuf = font->readEmbFontFile(xref, &fontLen);
2182
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2183
if (ffTT->isOpenTypeCFF()) {
2184
ffTT->convertToType1(psName->getCString(), NULL, gTrue,
2185
outputFunc, outputStream);
2192
writePS("%%EndResource\n");
2195
void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
2196
GooString *psName) {
2203
// check if font is already embedded
2204
for (i = 0; i < fontFileIDLen; ++i) {
2205
if (fontFileIDs[i].num == id->num &&
2206
fontFileIDs[i].gen == id->gen) {
2207
psName->appendf("_{0:d}", nextTrueTypeNum++);
2212
// add entry to fontFileIDs list
2213
if (i == fontFileIDLen) {
2214
if (fontFileIDLen >= fontFileIDSize) {
2215
fontFileIDSize += 64;
2216
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2218
fontFileIDs[fontFileIDLen++] = *id;
2221
// beginning comment
2222
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2223
embFontList->append("%%+ font ");
2224
embFontList->append(psName->getCString());
2225
embFontList->append("\n");
2227
// convert it to a Type 42 font
2228
fontBuf = font->readEmbFontFile(xref, &fontLen);
2229
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2230
codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
2231
ffTT->convertToType42(psName->getCString(),
2232
((Gfx8BitFont *)font)->getHasEncoding()
2233
? ((Gfx8BitFont *)font)->getEncoding()
2235
codeToGID, outputFunc, outputStream);
2237
if (font8InfoLen >= font8InfoSize) {
2238
font8InfoSize += 16;
2239
font8Info = (PSFont8Info *)greallocn(font8Info,
2241
sizeof(PSFont8Info));
2243
font8Info[font8InfoLen].fontID = *font->getID();
2244
font8Info[font8InfoLen].codeToGID = codeToGID;
2252
writePS("%%EndResource\n");
2255
GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
2256
GooString *fileName;
2264
// check if font is already embedded
2265
fileName = font->getExtFontFile();
2266
for (i = 0; i < fontFileNameLen; ++i) {
2267
if (!fontFileNames[i]->cmp(fileName)) {
2268
return psFileNames[i]->copy();
2272
psName = font->getName()->sanitizedName(gTrue /* ps mode */);
2273
// add entry to fontFileNames list
2274
if (i == fontFileNameLen) {
2275
if (fontFileNameLen >= fontFileNameSize) {
2276
fontFileNameSize += 64;
2278
(GooString **)greallocn(fontFileNames,
2279
fontFileNameSize, sizeof(GooString *));
2281
(GooString **)greallocn(psFileNames,
2282
fontFileNameSize, sizeof(GooString *));
2284
fontFileNames[fontFileNameLen] = fileName->copy();
2285
psFileNames[fontFileNameLen] = psName->copy();
2289
// beginning comment
2290
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2291
embFontList->append("%%+ font ");
2292
embFontList->append(psName->getCString());
2293
embFontList->append("\n");
2295
// convert it to a Type 42 font
2296
fontBuf = font->readExtFontFile(&fontLen);
2297
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2298
codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
2299
ffTT->convertToType42(psName->getCString(),
2300
((Gfx8BitFont *)font)->getHasEncoding()
2301
? ((Gfx8BitFont *)font)->getEncoding()
2303
codeToGID, outputFunc, outputStream);
2305
if (font8InfoLen >= font8InfoSize) {
2306
font8InfoSize += 16;
2307
font8Info = (PSFont8Info *)greallocn(font8Info,
2309
sizeof(PSFont8Info));
2311
font8Info[font8InfoLen].fontID = *font->getID();
2312
font8Info[font8InfoLen].codeToGID = codeToGID;
2320
writePS("%%EndResource\n");
2324
GooString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex) {
2329
GooString *myFileName;
2331
myFileName = fileName->copy();
2332
if (faceIndex > 0) {
2334
sprintf(tmp, ",%d", faceIndex);
2335
myFileName->append(tmp);
2337
// check if font is already embedded
2338
for (i = 0; i < fontFileNameLen; ++i) {
2339
if (!fontFileNames[i]->cmp(myFileName)) {
2341
return psFileNames[i]->copy();
2345
psName = font->getName()->sanitizedName(gTrue /* ps mode */);
2346
// add entry to fontFileNames list
2347
if (i == fontFileNameLen) {
2348
if (fontFileNameLen >= fontFileNameSize) {
2349
fontFileNameSize += 64;
2351
(GooString **)grealloc(fontFileNames,
2352
fontFileNameSize * sizeof(GooString *));
2354
(GooString **)grealloc(psFileNames,
2355
fontFileNameSize * sizeof(GooString *));
2358
fontFileNames[fontFileNameLen] = myFileName;
2359
psFileNames[fontFileNameLen] = psName->copy();
2362
// beginning comment
2363
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2364
embFontList->append("%%+ font ");
2365
embFontList->append(psName->getCString());
2366
embFontList->append("\n");
2368
// convert it to a CID type2 font
2369
if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) {
2370
int n = ((GfxCIDFont *)font)->getCIDToGIDLen();
2372
codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
2373
memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort));
2375
codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n);
2377
if (globalParams->getPSLevel() >= psLevel3) {
2378
// Level 3: use a CID font
2379
ffTT->convertToCIDType2(psName->getCString(),
2380
codeToGID, n, gTrue,
2381
outputFunc, outputStream);
2383
// otherwise: use a non-CID composite font
2384
ffTT->convertToType0(psName->getCString(),
2385
codeToGID, n, gTrue,
2386
outputFunc, outputStream);
2393
writePS("%%EndResource\n");
2397
void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
2398
GooString *psName) {
2404
// check if font is already embedded
2405
for (i = 0; i < fontFileIDLen; ++i) {
2406
if (fontFileIDs[i].num == id->num &&
2407
fontFileIDs[i].gen == id->gen)
2411
// add entry to fontFileIDs list
2412
if (fontFileIDLen >= fontFileIDSize) {
2413
fontFileIDSize += 64;
2414
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2416
fontFileIDs[fontFileIDLen++] = *id;
2418
// beginning comment
2419
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2420
embFontList->append("%%+ font ");
2421
embFontList->append(psName->getCString());
2422
embFontList->append("\n");
2424
// convert it to a Type 0 font
2425
fontBuf = font->readEmbFontFile(xref, &fontLen);
2426
if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
2427
if (globalParams->getPSLevel() >= psLevel3) {
2428
// Level 3: use a CID font
2429
ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
2431
// otherwise: use a non-CID composite font
2432
ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
2439
writePS("%%EndResource\n");
2442
void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
2444
GBool needVerticalMetrics) {
2450
// check if font is already embedded
2451
for (i = 0; i < fontFileIDLen; ++i) {
2452
if (fontFileIDs[i].num == id->num &&
2453
fontFileIDs[i].gen == id->gen) {
2454
psName->appendf("_{0:d}", nextTrueTypeNum++);
2459
// add entry to fontFileIDs list
2460
if (fontFileIDLen >= fontFileIDSize) {
2461
fontFileIDSize += 64;
2462
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2464
fontFileIDs[fontFileIDLen++] = *id;
2466
// beginning comment
2467
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2468
embFontList->append("%%+ font ");
2469
embFontList->append(psName->getCString());
2470
embFontList->append("\n");
2472
// convert it to a Type 0 font
2473
fontBuf = font->readEmbFontFile(xref, &fontLen);
2474
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2475
if (globalParams->getPSLevel() >= psLevel3) {
2476
// Level 3: use a CID font
2477
ffTT->convertToCIDType2(psName->getCString(),
2478
((GfxCIDFont *)font)->getCIDToGID(),
2479
((GfxCIDFont *)font)->getCIDToGIDLen(),
2480
needVerticalMetrics,
2481
outputFunc, outputStream);
2483
// otherwise: use a non-CID composite font
2484
ffTT->convertToType0(psName->getCString(),
2485
((GfxCIDFont *)font)->getCIDToGID(),
2486
((GfxCIDFont *)font)->getCIDToGIDLen(),
2487
needVerticalMetrics,
2488
outputFunc, outputStream);
2495
writePS("%%EndResource\n");
2498
void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
2499
GooString *psName) {
2505
// check if font is already embedded
2506
for (i = 0; i < fontFileIDLen; ++i) {
2507
if (fontFileIDs[i].num == id->num &&
2508
fontFileIDs[i].gen == id->gen)
2512
// add entry to fontFileIDs list
2513
if (fontFileIDLen >= fontFileIDSize) {
2514
fontFileIDSize += 64;
2515
fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
2517
fontFileIDs[fontFileIDLen++] = *id;
2519
// beginning comment
2520
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2521
embFontList->append("%%+ font ");
2522
embFontList->append(psName->getCString());
2523
embFontList->append("\n");
2525
// convert it to a Type 0 font
2526
fontBuf = font->readEmbFontFile(xref, &fontLen);
2527
if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
2528
if (ffTT->isOpenTypeCFF()) {
2529
if (globalParams->getPSLevel() >= psLevel3) {
2530
// Level 3: use a CID font
2531
ffTT->convertToCIDType0(psName->getCString(),
2532
outputFunc, outputStream);
2534
// otherwise: use a non-CID composite font
2535
ffTT->convertToType0(psName->getCString(), outputFunc, outputStream);
2543
writePS("%%EndResource\n");
2546
void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
2547
Dict *parentResDict) {
2557
// set up resources used by font
2558
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
2559
inType3Char = gTrue;
2560
setupResources(resDict);
2561
inType3Char = gFalse;
2563
resDict = parentResDict;
2566
// beginning comment
2567
writePSFmt("%%BeginResource: font {0:t}\n", psName);
2568
embFontList->append("%%+ font ");
2569
embFontList->append(psName->getCString());
2570
embFontList->append("\n");
2573
writePS("8 dict begin\n");
2574
writePS("/FontType 3 def\n");
2575
m = font->getFontMatrix();
2576
writePSFmt("/FontMatrix [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
2577
m[0], m[1], m[2], m[3], m[4], m[5]);
2578
m = font->getFontBBox();
2579
writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
2580
m[0], m[1], m[2], m[3]);
2581
writePS("/Encoding 256 array def\n");
2582
writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
2583
writePS("/BuildGlyph {\n");
2584
writePS(" exch /CharProcs get exch\n");
2585
writePS(" 2 copy known not { pop /.notdef } if\n");
2586
writePS(" get exec\n");
2587
writePS("} bind def\n");
2588
writePS("/BuildChar {\n");
2589
writePS(" 1 index /Encoding get exch get\n");
2590
writePS(" 1 index /BuildGlyph get exec\n");
2591
writePS("} bind def\n");
2592
if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
2593
writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength());
2594
writePS("CharProcs begin\n");
2599
gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
2600
inType3Char = gTrue;
2601
for (i = 0; i < charProcs->getLength(); ++i) {
2602
t3Cacheable = gFalse;
2603
t3NeedsRestore = gFalse;
2605
writePSName(charProcs->getKey(i));
2607
gfx->display(charProcs->getVal(i, &charProc));
2611
buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
2612
t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
2614
buf = GooString::format("{0:.6g} {1:.6g} setcharwidth\n", t3WX, t3WY);
2616
(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
2618
(*outputFunc)(outputStream, t3String->getCString(),
2619
t3String->getLength());
2623
if (t3NeedsRestore) {
2624
(*outputFunc)(outputStream, "Q\n", 2);
2628
inType3Char = gFalse;
2632
writePS("currentdict end\n");
2633
writePSFmt("/{0:t} exch definefont pop\n", psName);
2636
writePS("%%EndResource\n");
2639
void PSOutputDev::setupImages(Dict *resDict) {
2640
Object xObjDict, xObj, xObjRef, subtypeObj;
2643
if (!(mode == psModeForm || inType3Char || preload)) {
2647
//----- recursively scan XObjects
2648
resDict->lookup("XObject", &xObjDict);
2649
if (xObjDict.isDict()) {
2650
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
2651
xObjDict.dictGetValNF(i, &xObjRef);
2652
xObjDict.dictGetVal(i, &xObj);
2653
if (xObj.isStream()) {
2654
xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
2655
if (subtypeObj.isName("Image")) {
2656
if (xObjRef.isRef()) {
2657
setupImage(xObjRef.getRef(), xObj.getStream());
2659
error(-1, "Image in resource dict is not an indirect reference");
2671
void PSOutputDev::setupImage(Ref id, Stream *str) {
2672
GBool useRLE, useCompressed, useASCIIHex;
2675
int size, line, col, i;
2676
int outerSize, outer;
2678
// check if image is already setup
2679
for (i = 0; i < imgIDLen; ++i) {
2680
if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
2685
// add entry to imgIDs list
2686
if (imgIDLen >= imgIDSize) {
2687
if (imgIDSize == 0) {
2692
imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
2694
imgIDs[imgIDLen++] = id;
2697
//~ this does not correctly handle the DeviceN color space
2698
//~ -- need to use DeviceNRecoder
2699
if (level < psLevel2) {
2701
useCompressed = gFalse;
2702
useASCIIHex = gTrue;
2704
s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
2707
useCompressed = gTrue;
2711
useCompressed = gFalse;
2713
useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
2714
globalParams->getPSASCIIHex();
2716
if (useCompressed) {
2717
str = str->getUndecodedStream();
2720
str = new RunLengthEncoder(str);
2723
str = new ASCIIHexEncoder(str);
2725
str = new ASCII85Encoder(str);
2728
// compute image data size
2734
} while (c == '\n' || c == '\r');
2735
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2742
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2745
} while (c == '\n' || c == '\r');
2746
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2751
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2759
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
2760
// add one entry for the final line of data; add another entry
2761
// because the RunLengthDecode filter may read past the end
2766
outerSize = size/65535 + 1;
2768
writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
2769
outerSize, id.num, id.gen);
2772
// write the data into the array
2774
for (outer = 0;outer < outerSize;outer++) {
2775
int innerSize = size > 65535 ? 65535 : size;
2777
// put the inner array into the outer array
2778
writePSFmt("{0:d} array 1 index {1:d} 2 index put\n",
2781
writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
2785
} while (c == '\n' || c == '\r');
2786
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2795
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
2798
} while (c == '\n' || c == '\r');
2799
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2806
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2809
// each line is: "dup nnnnn <~...data...~> put<eol>"
2810
// so max data length = 255 - 20 = 235
2811
// chunks are 1 or 4 bytes each, so we have to stop at 232
2812
// but make it 225 just to be safe
2814
writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2816
if (line >= innerSize) break;
2817
writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line);
2821
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
2822
writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
2825
writePSFmt("{0:d} <> put\n", line);
2840
void PSOutputDev::setupForms(Dict *resDict) {
2841
Object xObjDict, xObj, xObjRef, subtypeObj;
2848
resDict->lookup("XObject", &xObjDict);
2849
if (xObjDict.isDict()) {
2850
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
2851
xObjDict.dictGetValNF(i, &xObjRef);
2852
xObjDict.dictGetVal(i, &xObj);
2853
if (xObj.isStream()) {
2854
xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
2855
if (subtypeObj.isName("Form")) {
2856
if (xObjRef.isRef()) {
2857
setupForm(xObjRef.getRef(), &xObj);
2859
error(-1, "Form in resource dict is not an indirect reference");
2871
void PSOutputDev::setupForm(Ref id, Object *strObj) {
2872
Dict *dict, *resDict;
2873
Object matrixObj, bboxObj, resObj, obj1;
2874
double m[6], bbox[4];
2879
// check if form is already defined
2880
for (i = 0; i < formIDLen; ++i) {
2881
if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
2886
// add entry to formIDs list
2887
if (formIDLen >= formIDSize) {
2888
if (formIDSize == 0) {
2893
formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref));
2895
formIDs[formIDLen++] = id;
2897
dict = strObj->streamGetDict();
2900
dict->lookup("BBox", &bboxObj);
2901
if (!bboxObj.isArray()) {
2903
error(-1, "Bad form bounding box");
2906
for (i = 0; i < 4; ++i) {
2907
bboxObj.arrayGet(i, &obj1);
2908
bbox[i] = obj1.getNum();
2914
dict->lookup("Matrix", &matrixObj);
2915
if (matrixObj.isArray()) {
2916
for (i = 0; i < 6; ++i) {
2917
matrixObj.arrayGet(i, &obj1);
2918
m[i] = obj1.getNum();
2929
dict->lookup("Resources", &resObj);
2930
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
2932
writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
2934
writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
2935
m[0], m[1], m[2], m[3], m[4], m[5]);
2941
gfx = new Gfx(xref, this, resDict, m_catalog, &box, &box);
2942
gfx->display(strObj);
2951
GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
2952
int rotateA, GBool useMediaBox, GBool crop,
2953
int sliceX, int sliceY,
2954
int sliceW, int sliceH,
2955
GBool printing, Catalog *catalog,
2956
GBool (*abortCheckCbk)(void *data),
2957
void *abortCheckCbkData) {
2959
PreScanOutputDev *scan;
2961
SplashOutputDev *splashOut;
2962
SplashColor paperColor;
2965
SplashBitmap *bitmap;
2970
double m0, m1, m2, m3, m4, m5;
2971
int c, w, h, x, y, comp, i;
2972
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
2975
if (!forceRasterize) {
2976
scan = new PreScanOutputDev();
2977
page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
2978
sliceX, sliceY, sliceW, sliceH,
2979
printing, catalog, abortCheckCbk, abortCheckCbkData);
2980
rasterize = scan->usesTransparency() || scan->hasLevel1PSBug();
2989
// rasterize the page
2990
if (level == psLevel1) {
2991
paperColor[0] = 0xff;
2992
splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
2993
paperColor, gTrue, gFalse);
2995
} else if (level == psLevel1Sep) {
2996
paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
2997
splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
2998
paperColor, gTrue, gFalse);
3000
} else if (level == psLevel1Sep) {
3001
error(-1, "pdftops was built without CMYK support, level1sep needs it to work in this file");
3005
paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
3006
splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
3007
paperColor, gTrue, gFalse);
3009
splashOut->startDoc(xref);
3010
page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
3012
sliceX, sliceY, sliceW, sliceH,
3013
printing, catalog, abortCheckCbk, abortCheckCbkData);
3015
// start the PS page
3016
page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
3017
sliceX, sliceY, sliceW, sliceH, &box, &crop);
3018
rotateA += page->getRotate();
3019
if (rotateA >= 360) {
3021
} else if (rotateA < 0) {
3024
state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
3025
startPage(page->getNum(), state);
3029
default: // this should never happen
3030
m0 = box.x2 - box.x1;
3033
m3 = box.y2 - box.y1;
3039
m1 = box.y2 - box.y1;
3040
m2 = -(box.x2 - box.x1);
3046
m0 = -(box.x2 - box.x1);
3049
m3 = -(box.y2 - box.y1);
3055
m1 = -(box.y2 - box.y1);
3056
m2 = box.x2 - box.x1;
3063
//~ need to add the process colors
3065
// draw the rasterized image
3066
bitmap = splashOut->getBitmap();
3067
w = bitmap->getWidth();
3068
h = bitmap->getHeight();
3070
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
3071
m0, m1, m2, m3, m4, m5);
3074
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
3076
p = bitmap->getDataPtr();
3078
for (y = 0; y < h; ++y) {
3079
for (x = 0; x < w; ++x) {
3081
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3083
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3086
writePSBuf(hexBuf, i);
3093
writePSBuf(hexBuf, i);
3097
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
3099
p = bitmap->getDataPtr();
3101
col[0] = col[1] = col[2] = col[3] = 0;
3102
if (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0) {
3103
for (y = 0; y < h; ++y) {
3104
for (comp = 0; comp < 4; ++comp) {
3105
for (x = 0; x < w; ++x) {
3106
col[comp] |= p[4*x + comp];
3107
digit = p[4*x + comp] / 16;
3108
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3109
digit = p[4*x + comp] % 16;
3110
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3113
writePSBuf(hexBuf, i);
3118
p += bitmap->getRowSize();
3121
for (y = 0; y < h; ++y) {
3122
for (comp = 0; comp < 4; ++comp) {
3123
for (x = 0; x < w; ++x) {
3124
digit = p[4*x + comp] / 16;
3125
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3126
digit = p[4*x + comp] % 16;
3127
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
3130
writePSBuf(hexBuf, i);
3135
p += bitmap->getRowSize();
3140
writePSBuf(hexBuf, i);
3143
processColors |= psProcessCyan;
3146
processColors |= psProcessMagenta;
3149
processColors |= psProcessYellow;
3152
processColors |= psProcessBlack;
3159
writePS("/DeviceRGB setcolorspace\n");
3160
writePS("<<\n /ImageType 1\n");
3161
writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
3162
writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
3163
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
3164
writePS(" /BitsPerComponent 8\n");
3165
writePS(" /Decode [0 1 0 1 0 1]\n");
3166
writePS(" /DataSource currentfile\n");
3167
if (globalParams->getPSASCIIHex()) {
3168
writePS(" /ASCIIHexDecode filter\n");
3170
writePS(" /ASCII85Decode filter\n");
3172
writePS(" /RunLengthDecode filter\n");
3176
str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
3177
str = new RunLengthEncoder(str0);
3178
if (globalParams->getPSASCIIHex()) {
3179
str = new ASCIIHexEncoder(str);
3181
str = new ASCII85Encoder(str);
3184
while ((c = str->getChar()) != EOF) {
3190
processColors |= psProcessCMYK;
3194
writePS("grestore\n");
3196
// finish the PS page
3205
void PSOutputDev::startPage(int pageNum, GfxState *state) {
3206
int x1, y1, x2, y2, width, height;
3207
int imgWidth, imgHeight, imgWidth2, imgHeight2;
3211
if (mode == psModePS || mode == psModePSOrigPageSizes) {
3212
GooString pageLabel;
3213
const GBool gotLabel = m_catalog->indexToLabel(pageNum -1, &pageLabel);
3215
// See bug13338 for why we try to avoid parentheses...
3217
GooString *filteredString = filterPSLabel(&pageLabel, &needParens);
3219
writePSFmt("%%Page: ({0:t}) {1:d}\n", filteredString, seqPage);
3221
writePSFmt("%%Page: {0:t} {1:d}\n", filteredString, seqPage);
3223
delete filteredString;
3225
writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
3227
if (mode != psModePSOrigPageSizes)
3228
writePS("%%BeginPageSetup\n");
3233
(*underlayCbk)(this, underlayCbkData);
3241
case psModePSOrigPageSizes:
3242
x1 = (int)floor(state->getX1());
3243
y1 = (int)floor(state->getY1());
3244
x2 = (int)ceil(state->getX2());
3245
y2 = (int)ceil(state->getY2());
3248
if (width > height) {
3253
writePSFmt("%%PageBoundingBox: {0:d} {1:d} {2:d} {3:d}\n", x1, y1, x2 - x1, y2 - y1);
3254
writePS("%%BeginPageSetup\n");
3255
writePSFmt("%%PageOrientation: {0:s}\n",
3256
landscape ? "Landscape" : "Portrait");
3257
if ((width != prevWidth) || (height != prevHeight)) {
3258
// Set page size only when it actually changes, as otherwise Duplex
3259
// printing does not work
3260
writePSFmt("<</PageSize [{0:d} {1:d}]>> setpagedevice\n", width, height);
3262
prevHeight = height;
3264
writePS("pdfStartPage\n");
3265
writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
3266
writePS("%%EndPageSetup\n");
3271
// rotate, translate, and scale page
3272
imgWidth = imgURX - imgLLX;
3273
imgHeight = imgURY - imgLLY;
3274
x1 = (int)floor(state->getX1());
3275
y1 = (int)floor(state->getY1());
3276
x2 = (int)ceil(state->getX2());
3277
y2 = (int)ceil(state->getY2());
3281
// rotation and portrait/landscape mode
3283
rotate = (360 - rotate0) % 360;
3286
rotate = (360 - state->getRotate()) % 360;
3287
if (rotate == 0 || rotate == 180) {
3288
if (width > height && width > imgWidth) {
3294
} else { // rotate == 90 || rotate == 270
3295
if (height > width && height > imgWidth) {
3296
rotate = 270 - rotate;
3303
writePSFmt("%%PageOrientation: {0:s}\n",
3304
landscape ? "Landscape" : "Portrait");
3305
writePS("pdfStartPage\n");
3307
imgWidth2 = imgWidth;
3308
imgHeight2 = imgHeight;
3309
} else if (rotate == 90) {
3310
writePS("90 rotate\n");
3312
imgWidth2 = imgHeight;
3313
imgHeight2 = imgWidth;
3314
} else if (rotate == 180) {
3315
writePS("180 rotate\n");
3316
imgWidth2 = imgWidth;
3317
imgHeight2 = imgHeight;
3320
} else { // rotate == 270
3321
writePS("270 rotate\n");
3323
imgWidth2 = imgHeight;
3324
imgHeight2 = imgWidth;
3327
if (xScale0 > 0 && yScale0 > 0) {
3330
} else if ((globalParams->getPSShrinkLarger() &&
3331
(width > imgWidth2 || height > imgHeight2)) ||
3332
(globalParams->getPSExpandSmaller() &&
3333
(width < imgWidth2 && height < imgHeight2))) {
3334
xScale = (double)imgWidth2 / (double)width;
3335
yScale = (double)imgHeight2 / (double)height;
3336
if (yScale < xScale) {
3342
xScale = yScale = 1;
3344
// deal with odd bounding boxes or clipping
3345
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3346
tx -= xScale * clipLLX0;
3347
ty -= yScale * clipLLY0;
3353
if (tx0 >= 0 && ty0 >= 0) {
3354
tx += rotate == 0 ? tx0 : ty0;
3355
ty += rotate == 0 ? ty0 : -tx0;
3356
} else if (globalParams->getPSCenter()) {
3357
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3358
tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
3359
ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2;
3361
tx += (imgWidth2 - xScale * width) / 2;
3362
ty += (imgHeight2 - yScale * height) / 2;
3365
tx += rotate == 0 ? imgLLX : imgLLY;
3366
ty += rotate == 0 ? imgLLY : -imgLLX;
3367
if (tx != 0 || ty != 0) {
3368
writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
3370
if (xScale != 1 || yScale != 1) {
3371
writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
3373
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
3374
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
3375
clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
3377
writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
3380
writePS("%%EndPageSetup\n");
3385
writePS("pdfStartPage\n");
3387
rotate = (360 - state->getRotate()) % 360;
3389
} else if (rotate == 90) {
3390
writePS("90 rotate\n");
3393
} else if (rotate == 180) {
3394
writePS("180 rotate\n");
3395
tx = -(epsX1 + epsX2);
3396
ty = -(epsY1 + epsY2);
3397
} else { // rotate == 270
3398
writePS("270 rotate\n");
3402
if (tx != 0 || ty != 0) {
3403
writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
3405
xScale = yScale = 1;
3409
writePS("/PaintProc {\n");
3410
writePS("begin xpdf begin\n");
3411
writePS("pdfStartPage\n");
3413
xScale = yScale = 1;
3419
void PSOutputDev::endPage() {
3422
(*overlayCbk)(this, overlayCbkData);
3426
if (mode == psModeForm) {
3427
writePS("pdfEndPage\n");
3428
writePS("end end\n");
3430
writePS("end end\n");
3433
writePS("showpage\n");
3435
writePS("%%PageTrailer\n");
3440
void PSOutputDev::saveState(GfxState *state) {
3445
void PSOutputDev::restoreState(GfxState *state) {
3450
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
3451
double m21, double m22, double m31, double m32) {
3452
writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
3453
m11, m12, m21, m22, m31, m32);
3456
void PSOutputDev::updateLineDash(GfxState *state) {
3461
state->getLineDash(&dash, &length, &start);
3463
for (i = 0; i < length; ++i) {
3464
writePSFmt("{0:.6g}{1:w}",
3465
dash[i] < 0 ? 0 : dash[i],
3466
(i == length-1) ? 0 : 1);
3468
writePSFmt("] {0:.6g} d\n", start);
3471
void PSOutputDev::updateFlatness(GfxState *state) {
3472
writePSFmt("{0:d} i\n", state->getFlatness());
3475
void PSOutputDev::updateLineJoin(GfxState *state) {
3476
writePSFmt("{0:d} j\n", state->getLineJoin());
3479
void PSOutputDev::updateLineCap(GfxState *state) {
3480
writePSFmt("{0:d} J\n", state->getLineCap());
3483
void PSOutputDev::updateMiterLimit(GfxState *state) {
3484
writePSFmt("{0:.6g} M\n", state->getMiterLimit());
3487
void PSOutputDev::updateLineWidth(GfxState *state) {
3488
writePSFmt("{0:.6g} w\n", state->getLineWidth());
3491
void PSOutputDev::updateFillColorSpace(GfxState *state) {
3498
if (state->getFillColorSpace()->getMode() != csPattern) {
3499
dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
3509
void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
3516
if (state->getStrokeColorSpace()->getMode() != csPattern) {
3517
dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
3527
void PSOutputDev::updateFillColor(GfxState *state) {
3532
GfxSeparationColorSpace *sepCS;
3538
state->getFillGray(&gray);
3539
writePSFmt("{0:.4g} g\n", colToDbl(gray));
3542
state->getFillCMYK(&cmyk);
3543
c = colToDbl(cmyk.c);
3544
m = colToDbl(cmyk.m);
3545
y = colToDbl(cmyk.y);
3546
k = colToDbl(cmyk.k);
3547
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
3548
addProcessColor(c, m, y, k);
3552
if (state->getFillColorSpace()->getMode() != csPattern) {
3553
colorPtr = state->getFillColor();
3555
for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) {
3559
writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
3566
if (state->getFillColorSpace()->getMode() == csSeparation) {
3567
sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
3568
color.c[0] = gfxColorComp1;
3569
sepCS->getCMYK(&color, &cmyk);
3570
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
3571
colToDbl(state->getFillColor()->c[0]),
3572
colToDbl(cmyk.c), colToDbl(cmyk.m),
3573
colToDbl(cmyk.y), colToDbl(cmyk.k),
3575
addCustomColor(sepCS);
3577
state->getFillCMYK(&cmyk);
3578
c = colToDbl(cmyk.c);
3579
m = colToDbl(cmyk.m);
3580
y = colToDbl(cmyk.y);
3581
k = colToDbl(cmyk.k);
3582
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
3583
addProcessColor(c, m, y, k);
3587
t3Cacheable = gFalse;
3590
void PSOutputDev::updateStrokeColor(GfxState *state) {
3595
GfxSeparationColorSpace *sepCS;
3601
state->getStrokeGray(&gray);
3602
writePSFmt("{0:.4g} G\n", colToDbl(gray));
3605
state->getStrokeCMYK(&cmyk);
3606
c = colToDbl(cmyk.c);
3607
m = colToDbl(cmyk.m);
3608
y = colToDbl(cmyk.y);
3609
k = colToDbl(cmyk.k);
3610
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
3611
addProcessColor(c, m, y, k);
3615
if (state->getStrokeColorSpace()->getMode() != csPattern) {
3616
colorPtr = state->getStrokeColor();
3618
for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) {
3622
writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
3629
if (state->getStrokeColorSpace()->getMode() == csSeparation) {
3630
sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
3631
color.c[0] = gfxColorComp1;
3632
sepCS->getCMYK(&color, &cmyk);
3633
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
3634
colToDbl(state->getStrokeColor()->c[0]),
3635
colToDbl(cmyk.c), colToDbl(cmyk.m),
3636
colToDbl(cmyk.y), colToDbl(cmyk.k),
3638
addCustomColor(sepCS);
3640
state->getStrokeCMYK(&cmyk);
3641
c = colToDbl(cmyk.c);
3642
m = colToDbl(cmyk.m);
3643
y = colToDbl(cmyk.y);
3644
k = colToDbl(cmyk.k);
3645
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
3646
addProcessColor(c, m, y, k);
3650
t3Cacheable = gFalse;
3653
void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
3655
processColors |= psProcessCyan;
3658
processColors |= psProcessMagenta;
3661
processColors |= psProcessYellow;
3664
processColors |= psProcessBlack;
3668
void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
3669
PSOutCustomColor *cc;
3673
for (cc = customColors; cc; cc = cc->next) {
3674
if (!cc->name->cmp(sepCS->getName())) {
3678
color.c[0] = gfxColorComp1;
3679
sepCS->getCMYK(&color, &cmyk);
3680
cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
3681
colToDbl(cmyk.y), colToDbl(cmyk.k),
3682
sepCS->getName()->copy());
3683
cc->next = customColors;
3687
void PSOutputDev::updateFillOverprint(GfxState *state) {
3688
if (level >= psLevel2) {
3689
writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
3693
void PSOutputDev::updateStrokeOverprint(GfxState *state) {
3694
if (level >= psLevel2) {
3695
writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
3699
void PSOutputDev::updateTransfer(GfxState *state) {
3703
funcs = state->getTransfer();
3704
if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
3705
if (level >= psLevel2) {
3706
for (i = 0; i < 4; ++i) {
3707
cvtFunction(funcs[i]);
3709
writePS("setcolortransfer\n");
3711
cvtFunction(funcs[3]);
3712
writePS("settransfer\n");
3714
} else if (funcs[0]) {
3715
cvtFunction(funcs[0]);
3716
writePS("settransfer\n");
3718
writePS("{} settransfer\n");
3722
void PSOutputDev::updateFont(GfxState *state) {
3723
if (state->getFont()) {
3724
writePSFmt("/F{0:d}_{1:d} {2:.6g} Tf\n",
3725
state->getFont()->getID()->num, state->getFont()->getID()->gen,
3726
fabs(state->getFontSize()) < 0.00001 ? 0.00001
3727
: state->getFontSize());
3731
void PSOutputDev::updateTextMat(GfxState *state) {
3734
mat = state->getTextMat();
3735
if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
3736
// avoid a singular (or close-to-singular) matrix
3737
writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]);
3739
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n",
3740
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3744
void PSOutputDev::updateCharSpace(GfxState *state) {
3745
writePSFmt("{0:.6g} Tc\n", state->getCharSpace());
3748
void PSOutputDev::updateRender(GfxState *state) {
3751
rm = state->getRender();
3752
writePSFmt("{0:d} Tr\n", rm);
3754
if (rm != 0 && rm != 3) {
3755
t3Cacheable = gFalse;
3759
void PSOutputDev::updateRise(GfxState *state) {
3760
writePSFmt("{0:.6g} Ts\n", state->getRise());
3763
void PSOutputDev::updateWordSpace(GfxState *state) {
3764
writePSFmt("{0:.6g} Tw\n", state->getWordSpace());
3767
void PSOutputDev::updateHorizScaling(GfxState *state) {
3770
h = state->getHorizScaling();
3771
if (fabs(h) < 0.01) {
3774
writePSFmt("{0:.6g} Tz\n", h);
3777
void PSOutputDev::updateTextPos(GfxState *state) {
3778
writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY());
3781
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
3782
if (state->getFont()->getWMode()) {
3783
writePSFmt("{0:.6g} TJmV\n", shift);
3785
writePSFmt("{0:.6g} TJm\n", shift);
3789
void PSOutputDev::stroke(GfxState *state) {
3790
doPath(state->getPath());
3792
// if we're construct a cacheable Type 3 glyph, we need to do
3793
// everything in the fill color
3800
void PSOutputDev::fill(GfxState *state) {
3801
doPath(state->getPath());
3805
void PSOutputDev::eoFill(GfxState *state) {
3806
doPath(state->getPath());
3810
GBool PSOutputDev::tilingPatternFill(GfxState *state, Object *str,
3811
int paintType, Dict *resDict,
3812
double *mat, double *bbox,
3813
int x0, int y0, int x1, int y1,
3814
double xStep, double yStep) {
3818
// define a Type 3 font
3819
writePS("8 dict begin\n");
3820
writePS("/FontType 3 def\n");
3821
writePS("/FontMatrix [1 0 0 1 0 0] def\n");
3822
writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
3823
bbox[0], bbox[1], bbox[2], bbox[3]);
3824
writePS("/Encoding 256 array def\n");
3825
writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
3826
writePS(" Encoding 120 /x put\n");
3827
writePS("/BuildGlyph {\n");
3828
writePS(" exch /CharProcs get exch\n");
3829
writePS(" 2 copy known not { pop /.notdef } if\n");
3830
writePS(" get exec\n");
3831
writePS("} bind def\n");
3832
writePS("/BuildChar {\n");
3833
writePS(" 1 index /Encoding get exch get\n");
3834
writePS(" 1 index /BuildGlyph get exec\n");
3835
writePS("} bind def\n");
3836
writePS("/CharProcs 1 dict def\n");
3837
writePS("CharProcs begin\n");
3842
gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
3844
if (paintType == 2) {
3845
writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
3846
xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
3850
writePS("1 0 setcharwidth\n");
3852
writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
3855
inType3Char = gTrue;
3856
++numTilingPatterns;
3858
--numTilingPatterns;
3859
inType3Char = gFalse;
3863
writePS("currentdict end\n");
3864
writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
3867
writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
3868
writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
3869
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3870
writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
3871
y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
3872
writePS("grestore\n");
3877
GBool PSOutputDev::functionShadedFill(GfxState *state,
3878
GfxFunctionShading *shading) {
3879
double x0, y0, x1, y1;
3883
if (level == psLevel2Sep || level == psLevel3Sep) {
3884
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
3887
processColors |= psProcessCMYK;
3890
shading->getDomain(&x0, &y0, &x1, &y1);
3891
mat = shading->getMatrix();
3892
writePSFmt("/mat [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
3893
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
3894
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
3895
if (shading->getNFuncs() == 1) {
3897
cvtFunction(shading->getFunc(0));
3900
writePS("/func {\n");
3901
for (i = 0; i < shading->getNFuncs(); ++i) {
3902
if (i < shading->getNFuncs() - 1) {
3903
writePS("2 copy\n");
3905
cvtFunction(shading->getFunc(i));
3907
if (i < shading->getNFuncs() - 1) {
3908
writePS("3 1 roll\n");
3913
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1);
3918
GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
3919
double xMin, yMin, xMax, yMax;
3920
double x0, y0, x1, y1, dx, dy, mul;
3921
double tMin, tMax, t, t0, t1;
3924
if (level == psLevel2Sep || level == psLevel3Sep) {
3925
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
3928
processColors |= psProcessCMYK;
3931
// get the clip region bbox
3932
state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
3934
// compute min and max t values, based on the four corners of the
3936
shading->getCoords(&x0, &y0, &x1, &y1);
3939
if (fabs(dx) < 0.01 && fabs(dy) < 0.01) {
3942
mul = 1 / (dx * dx + dy * dy);
3943
tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
3944
t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
3947
} else if (t > tMax) {
3950
t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
3953
} else if (t > tMax) {
3956
t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
3959
} else if (t > tMax) {
3962
if (tMin < 0 && !shading->getExtend0()) {
3965
if (tMax > 1 && !shading->getExtend1()) {
3970
// get the function domain
3971
t0 = shading->getDomain0();
3972
t1 = shading->getDomain1();
3974
// generate the PS code
3975
writePSFmt("/t0 {0:.6g} def\n", t0);
3976
writePSFmt("/t1 {0:.6g} def\n", t1);
3977
writePSFmt("/dt {0:.6g} def\n", t1 - t0);
3978
writePSFmt("/x0 {0:.6g} def\n", x0);
3979
writePSFmt("/y0 {0:.6g} def\n", y0);
3980
writePSFmt("/dx {0:.6g} def\n", x1 - x0);
3981
writePSFmt("/x1 {0:.6g} def\n", x1);
3982
writePSFmt("/y1 {0:.6g} def\n", y1);
3983
writePSFmt("/dy {0:.6g} def\n", y1 - y0);
3984
writePSFmt("/xMin {0:.6g} def\n", xMin);
3985
writePSFmt("/yMin {0:.6g} def\n", yMin);
3986
writePSFmt("/xMax {0:.6g} def\n", xMax);
3987
writePSFmt("/yMax {0:.6g} def\n", yMax);
3988
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
3989
if (shading->getNFuncs() == 1) {
3991
cvtFunction(shading->getFunc(0));
3994
writePS("/func {\n");
3995
for (i = 0; i < shading->getNFuncs(); ++i) {
3996
if (i < shading->getNFuncs() - 1) {
3999
cvtFunction(shading->getFunc(i));
4001
if (i < shading->getNFuncs() - 1) {
4007
writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax);
4012
GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
4013
double xMin, yMin, xMax, yMax;
4014
double x0, y0, r0, x1, y1, r1, t0, t1;
4016
double sz, xz, yz, sMin, sMax, sa, ta;
4017
double theta, alpha, a1, a2;
4021
if (level == psLevel2Sep || level == psLevel3Sep) {
4022
if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
4025
processColors |= psProcessCMYK;
4028
// get the shading info
4029
shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
4030
t0 = shading->getDomain0();
4031
t1 = shading->getDomain1();
4033
// Compute the point at which r(s) = 0; check for the enclosed
4034
// circles case; and compute the angles for the tangent lines.
4036
enclosed = x0 == x1 && y0 == y1;
4038
sz = 0; // make gcc happy
4040
sz = -r0 / (r1 - r0);
4041
xz = x0 + sz * (x1 - x0);
4042
yz = y0 + sz * (y1 - y0);
4043
enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
4044
theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
4053
alpha = atan2(y1 - y0, x1 - x0);
4054
a1 = (180 / M_PI) * (alpha + theta) + 90;
4055
a2 = (180 / M_PI) * (alpha - theta) - 90;
4061
// compute the (possibly extended) s range
4062
state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
4069
// solve for x(s) + r(s) = xMin
4070
if ((x1 + r1) - (x0 + r0) != 0) {
4071
sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
4074
} else if (sa > sMax) {
4078
// solve for x(s) - r(s) = xMax
4079
if ((x1 - r1) - (x0 - r0) != 0) {
4080
sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
4083
} else if (sa > sMax) {
4087
// solve for y(s) + r(s) = yMin
4088
if ((y1 + r1) - (y0 + r0) != 0) {
4089
sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
4092
} else if (sa > sMax) {
4096
// solve for y(s) - r(s) = yMax
4097
if ((y1 - r1) - (y0 - r0) != 0) {
4098
sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
4101
} else if (sa > sMax) {
4110
} else if (r0 > r1) {
4115
// check the 'extend' flags
4116
if (!shading->getExtend0() && sMin < 0) {
4119
if (!shading->getExtend1() && sMax > 1) {
4124
// generate the PS code
4125
writePSFmt("/x0 {0:.6g} def\n", x0);
4126
writePSFmt("/x1 {0:.6g} def\n", x1);
4127
writePSFmt("/dx {0:.6g} def\n", x1 - x0);
4128
writePSFmt("/y0 {0:.6g} def\n", y0);
4129
writePSFmt("/y1 {0:.6g} def\n", y1);
4130
writePSFmt("/dy {0:.6g} def\n", y1 - y0);
4131
writePSFmt("/r0 {0:.6g} def\n", r0);
4132
writePSFmt("/r1 {0:.6g} def\n", r1);
4133
writePSFmt("/dr {0:.6g} def\n", r1 - r0);
4134
writePSFmt("/t0 {0:.6g} def\n", t0);
4135
writePSFmt("/t1 {0:.6g} def\n", t1);
4136
writePSFmt("/dt {0:.6g} def\n", t1 - t0);
4137
writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
4138
writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false");
4139
writePSFmt("/a1 {0:.6g} def\n", a1);
4140
writePSFmt("/a2 {0:.6g} def\n", a2);
4141
if (shading->getNFuncs() == 1) {
4143
cvtFunction(shading->getFunc(0));
4146
writePS("/func {\n");
4147
for (i = 0; i < shading->getNFuncs(); ++i) {
4148
if (i < shading->getNFuncs() - 1) {
4151
cvtFunction(shading->getFunc(i));
4153
if (i < shading->getNFuncs() - 1) {
4159
writePSFmt("{0:.6g} {1:.6g} 0 radialSH\n", sMin, sMax);
4161
// extend the 'enclosed' case
4163
// extend the smaller circle
4164
if ((shading->getExtend0() && r0 <= r1) ||
4165
(shading->getExtend1() && r1 < r0)) {
4177
if (level == psLevel2Sep || level == psLevel3Sep) {
4178
writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
4180
writePSFmt("{0:.6g} radialCol sc\n", ta);
4182
writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h f*\n", xa, ya, ra);
4185
// extend the larger circle
4186
if ((shading->getExtend0() && r0 > r1) ||
4187
(shading->getExtend1() && r1 >= r0)) {
4199
if (level == psLevel2Sep || level == psLevel3Sep) {
4200
writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
4202
writePSFmt("{0:.6g} radialCol sc\n", ta);
4204
writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h\n", xa, ya, ra);
4205
writePSFmt("{0:.6g} {1:.6g} m {2:.6g} {3:.6g} l {4:.6g} {5:.6g} l {6:.6g} {7:.6g} l h f*\n",
4206
xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin);
4213
void PSOutputDev::clip(GfxState *state) {
4214
doPath(state->getPath());
4218
void PSOutputDev::eoClip(GfxState *state) {
4219
doPath(state->getPath());
4223
void PSOutputDev::clipToStrokePath(GfxState *state) {
4224
doPath(state->getPath());
4228
void PSOutputDev::doPath(GfxPath *path) {
4229
GfxSubpath *subpath;
4230
double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
4233
n = path->getNumSubpaths();
4235
if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
4236
subpath = path->getSubpath(0);
4237
x0 = subpath->getX(0);
4238
y0 = subpath->getY(0);
4239
x4 = subpath->getX(4);
4240
y4 = subpath->getY(4);
4241
if (x4 == x0 && y4 == y0) {
4242
x1 = subpath->getX(1);
4243
y1 = subpath->getY(1);
4244
x2 = subpath->getX(2);
4245
y2 = subpath->getY(2);
4246
x3 = subpath->getX(3);
4247
y3 = subpath->getY(3);
4248
if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
4249
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4250
x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
4251
fabs(x2 - x0), fabs(y1 - y0));
4253
} else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
4254
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4255
x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
4256
fabs(x1 - x0), fabs(y2 - y0));
4262
for (i = 0; i < n; ++i) {
4263
subpath = path->getSubpath(i);
4264
m = subpath->getNumPoints();
4265
writePSFmt("{0:.6g} {1:.6g} m\n", subpath->getX(0), subpath->getY(0));
4268
if (subpath->getCurve(j)) {
4269
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} c\n",
4270
subpath->getX(j), subpath->getY(j),
4271
subpath->getX(j+1), subpath->getY(j+1),
4272
subpath->getX(j+2), subpath->getY(j+2));
4275
writePSFmt("{0:.6g} {1:.6g} l\n", subpath->getX(j), subpath->getY(j));
4279
if (subpath->isClosed()) {
4285
void PSOutputDev::drawString(GfxState *state, GooString *s) {
4290
double dx, dy, dx2, dy2, originX, originY;
4296
int len, nChars, uLen, n, m, i, j;
4298
// for pdftohtml, output PS without text
4299
if( displayText == gFalse )
4302
// check for invisible text -- this is used by Acrobat Capture
4303
if (state->getRender() == 3) {
4307
// ignore empty strings
4308
if (s->getLength() == 0) {
4313
if (!(font = state->getFont())) {
4316
wMode = font->getWMode();
4318
// check for a subtitute 16-bit font
4321
if (font->isCIDFont()) {
4322
for (i = 0; i < font16EncLen; ++i) {
4323
if (font->getID()->num == font16Enc[i].fontID.num &&
4324
font->getID()->gen == font16Enc[i].fontID.gen) {
4325
uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
4330
// check for a code-to-GID map
4332
for (i = 0; i < font8InfoLen; ++i) {
4333
if (font->getID()->num == font8Info[i].fontID.num &&
4334
font->getID()->gen == font8Info[i].fontID.gen) {
4335
codeToGID = font8Info[i].codeToGID;
4341
// compute width of chars in string, ignoring char spacing and word
4342
// spacing -- the Tj operator will adjust for the metrics of the
4343
// font that's actually used
4346
p = s->getCString();
4347
len = s->getLength();
4348
s2 = new GooString();
4350
n = font->getNextChar(p, len, &code,
4352
&dx2, &dy2, &originX, &originY);
4353
if (font->isCIDFont()) {
4355
for (i = 0; i < uLen; ++i) {
4356
m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
4357
for (j = 0; j < m; ++j) {
4361
//~ this really needs to get the number of chars in the target
4362
//~ encoding - which may be more than the number of Unicode
4366
s2->append((char)((code >> 8) & 0xff));
4367
s2->append((char)(code & 0xff));
4371
if (!codeToGID || codeToGID[code]) {
4372
s2->append((char)code);
4380
dx *= state->getFontSize() * state->getHorizScaling();
4381
dy *= state->getFontSize();
4386
if (s2->getLength() > 0) {
4388
if (font->isCIDFont()) {
4390
writePSFmt(" {0:d} {1:.6g} Tj16V\n", nChars, dy);
4392
writePSFmt(" {0:d} {1:.6g} Tj16\n", nChars, dx);
4395
writePSFmt(" {0:.6g} Tj\n", dx);
4400
if (state->getRender() & 4 || haveCSPattern) {
4401
haveTextClip = gTrue;
4405
void PSOutputDev::beginTextObject(GfxState *state) {
4406
if (state->getFillColorSpace()->getMode() == csPattern) {
4408
haveCSPattern = gTrue;
4409
writePS("true Tp\n");
4413
void PSOutputDev::endTextObject(GfxState *state) {
4414
if (haveCSPattern) {
4416
writePS("Tclip*\n");
4417
haveTextClip = gFalse;
4418
if (state->getFillColorSpace()->getMode() != csPattern) {
4419
double cxMin, cyMin, cxMax, cyMax;
4420
state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
4421
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4425
restoreState(state);
4426
updateFillColor(state);
4429
haveCSPattern = gFalse;
4430
} else if (haveTextClip) {
4432
haveTextClip = gFalse;
4436
void PSOutputDev::endMaskClip(GfxState * state) {
4437
writePS("pdfImClipEnd\n");
4440
void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
4441
int width, int height, GBool invert,
4442
GBool interpolate, GBool inlineImg) {
4445
len = height * ((width + 7) / 8);
4446
if (state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep)) {
4447
maskToClippingPath(str, width, height, invert);
4452
doImageL1(ref, NULL, invert, inlineImg, str, width, height, len,
4453
NULL, NULL, 0, 0, gFalse);
4457
doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
4458
NULL, NULL, 0, 0, gFalse);
4462
doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
4463
NULL, NULL, 0, 0, gFalse);
4469
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
4470
int width, int height, GfxImageColorMap *colorMap,
4471
GBool interpolate, int *maskColors, GBool inlineImg) {
4474
len = height * ((width * colorMap->getNumPixelComps() *
4475
colorMap->getBits() + 7) / 8);
4478
doImageL1(ref, colorMap, gFalse, inlineImg, str,
4479
width, height, len, maskColors, NULL, 0, 0, gFalse);
4482
//~ handle indexed, separation, ... color spaces
4483
doImageL1Sep(ref, colorMap, gFalse, inlineImg, str,
4484
width, height, len, maskColors, NULL, 0, 0, gFalse);
4488
doImageL2(ref, colorMap, gFalse, inlineImg, str,
4489
width, height, len, maskColors, NULL, 0, 0, gFalse);
4493
doImageL3(ref, colorMap, gFalse, inlineImg, str,
4494
width, height, len, maskColors, NULL, 0, 0, gFalse);
4497
t3Cacheable = gFalse;
4500
void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
4501
int width, int height,
4502
GfxImageColorMap *colorMap,
4505
int maskWidth, int maskHeight,
4506
GBool maskInvert, GBool maskInterpolate) {
4509
len = height * ((width * colorMap->getNumPixelComps() *
4510
colorMap->getBits() + 7) / 8);
4513
doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len,
4514
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4517
//~ handle indexed, separation, ... color spaces
4518
doImageL1Sep(ref, colorMap, gFalse, gFalse, str, width, height, len,
4519
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4523
doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
4524
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4528
doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
4529
NULL, maskStr, maskWidth, maskHeight, maskInvert);
4532
t3Cacheable = gFalse;
4535
void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
4536
GBool invert, GBool inlineImg,
4537
Stream *str, int width, int height, int len,
4538
int *maskColors, Stream *maskStr,
4539
int maskWidth, int maskHeight, GBool maskInvert) {
4540
ImageStream *imgStr;
4541
Guchar pixBuf[gfxColorMaxComps];
4543
int col, x, y, c, i;
4544
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
4545
Guchar digit, grayValue;
4548
if (maskStr && !(maskColors && colorMap)) {
4549
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
4552
if ((inType3Char || preload) && !colorMap) {
4555
str = new FixedLengthEncoder(str, len);
4556
str = new ASCIIHexEncoder(str);
4563
} while (c == '\n' || c == '\r');
4564
if (c == '>' || c == EOF) {
4569
// each line is: "<...data...><eol>"
4570
// so max data length = 255 - 4 = 251
4571
// but make it 240 just to be safe
4572
// chunks are 2 bytes each, so we need to stop on an even col number
4577
} while (c != '>' && c != EOF);
4583
// make sure the image is setup, it sometimes is not like on bug #17645
4584
setupImage(ref->getRef(), str);
4585
// set up to use the array already created by setupImages()
4586
writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
4590
// image/imagemask command
4591
if ((inType3Char || preload) && !colorMap) {
4592
writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n",
4593
width, height, invert ? "true" : "false",
4594
width, -height, height);
4595
} else if (colorMap) {
4596
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
4598
width, -height, height);
4600
writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n",
4601
width, height, invert ? "true" : "false",
4602
width, -height, height);
4606
if (!((inType3Char || preload) && !colorMap)) {
4610
// set up to process the data stream
4611
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
4612
colorMap->getBits());
4615
// process the data stream
4617
for (y = 0; y < height; ++y) {
4620
for (x = 0; x < width; ++x) {
4621
imgStr->getPixel(pixBuf);
4622
colorMap->getGray(pixBuf, &gray);
4623
grayValue = colToByte(gray);
4624
digit = grayValue / 16;
4625
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4626
digit = grayValue % 16;
4627
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4630
writePSBuf(hexBuf, i);
4637
writePSBuf(hexBuf, i);
4646
for (y = 0; y < height; ++y) {
4647
for (x = 0; x < width; x += 8) {
4648
grayValue = str->getChar();
4649
digit = grayValue / 16;
4650
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4651
digit = grayValue % 16;
4652
hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
4655
writePSBuf(hexBuf, i);
4662
writePSBuf(hexBuf, i);
4668
if (maskStr && !(maskColors && colorMap)) {
4669
writePS("pdfImClipEnd\n");
4673
void PSOutputDev::doImageL1Sep(Object *ref, GfxImageColorMap *colorMap,
4674
GBool invert, GBool inlineImg,
4675
Stream *str, int width, int height, int len,
4676
int *maskColors, Stream *maskStr,
4677
int maskWidth, int maskHeight, GBool maskInvert) {
4678
ImageStream *imgStr;
4680
Guchar pixBuf[gfxColorMaxComps];
4683
GBool checkProcessColor;
4684
char hexBuf[32*2 + 2]; // 32 values X 2 chars/value + line ending + null
4688
if (maskStr && !(maskColors && colorMap)) {
4689
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
4692
// width, height, matrix, bits per component
4693
writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
4695
width, -height, height);
4697
// allocate a line buffer
4698
lineBuf = (Guchar *)gmallocn(width, 4);
4700
// set up to process the data stream
4701
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
4702
colorMap->getBits());
4705
// process the data stream
4706
checkProcessColor = gTrue;
4708
for (y = 0; y < height; ++y) {
4711
if (checkProcessColor) {
4712
checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0);
4714
if (checkProcessColor) {
4715
for (x = 0; x < width; ++x) {
4716
imgStr->getPixel(pixBuf);
4717
colorMap->getCMYK(pixBuf, &cmyk);
4718
lineBuf[4*x+0] = colToByte(cmyk.c);
4719
lineBuf[4*x+1] = colToByte(cmyk.m);
4720
lineBuf[4*x+2] = colToByte(cmyk.y);
4721
lineBuf[4*x+3] = colToByte(cmyk.k);
4722
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
4723
colToDbl(cmyk.y), colToDbl(cmyk.k));
4726
for (x = 0; x < width; ++x) {
4727
imgStr->getPixel(pixBuf);
4728
colorMap->getCMYK(pixBuf, &cmyk);
4729
lineBuf[4*x+0] = colToByte(cmyk.c);
4730
lineBuf[4*x+1] = colToByte(cmyk.m);
4731
lineBuf[4*x+2] = colToByte(cmyk.y);
4732
lineBuf[4*x+3] = colToByte(cmyk.k);
4736
// write one line of each color component
4737
for (comp = 0; comp < 4; ++comp) {
4738
for (x = 0; x < width; ++x) {
4739
digit = lineBuf[4*x + comp] / 16;
4740
hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
4741
digit = lineBuf[4*x + comp] % 16;
4742
hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
4745
writePSBuf(hexBuf, i);
4754
writePSBuf(hexBuf, i);
4761
if (maskStr && !(maskColors && colorMap)) {
4762
writePS("pdfImClipEnd\n");
4766
void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) {
4767
ImageStream *imgStr;
4769
PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
4770
int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
4771
GBool emitRect, addRect, extendRect;
4772
int i, x0, x1, y, maskXor;
4774
imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
4776
rects0Len = rects1Len = rectsOutLen = 0;
4777
rectsSize = rectsOutSize = 64;
4778
rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4779
rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4780
rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect));
4781
maskXor = maskInvert ? 1 : 0;
4782
for (y = 0; y < maskHeight; ++y) {
4783
if (!(line = imgStr->getLine())) {
4788
for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
4789
for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
4790
while (x0 < maskWidth || i < rects0Len) {
4791
emitRect = addRect = extendRect = gFalse;
4792
if (x0 >= maskWidth) {
4794
} else if (i >= rects0Len) {
4796
} else if (rects0[i].x0 < x0) {
4798
} else if (x0 < rects0[i].x0) {
4800
} else if (rects0[i].x1 == x1) {
4803
emitRect = addRect = gTrue;
4806
if (rectsOutLen == rectsOutSize) {
4808
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
4810
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4811
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4812
rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
4813
rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
4817
if (addRect || extendRect) {
4818
if (rects1Len == rectsSize) {
4820
rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect));
4821
rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect));
4823
rects1[rects1Len].x0 = x0;
4824
rects1[rects1Len].x1 = x1;
4826
rects1[rects1Len].y0 = y;
4829
rects1[rects1Len].y0 = rects0[i].y0;
4833
for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
4834
for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
4841
rects0Len = rects1Len;
4844
for (i = 0; i < rects0Len; ++i) {
4845
if (rectsOutLen == rectsOutSize) {
4847
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
4849
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4850
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4851
rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
4852
rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
4855
if (rectsOutLen < 65536/4) {
4856
writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
4857
for (i = 0; i < rectsOutLen; ++i) {
4858
writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
4859
rectsOut[i].x0, rectsOut[i].y0,
4860
rectsOut[i].x1 - rectsOut[i].x0,
4861
rectsOut[i].y1 - rectsOut[i].y0);
4863
writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
4865
// would be over the limit of array size.
4866
// make each rectangle path and clip.
4867
writePS("gsave newpath\n");
4868
for (i = 0; i < rectsOutLen; ++i) {
4869
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
4870
((double)rectsOut[i].x0)/maskWidth,
4871
((double)rectsOut[i].y0)/maskHeight,
4872
((double)(rectsOut[i].x1 - rectsOut[i].x0))/maskWidth,
4873
((double)(rectsOut[i].y1 - rectsOut[i].y0))/maskHeight);
4884
void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
4885
GBool invert, GBool inlineImg,
4886
Stream *str, int width, int height, int len,
4887
int *maskColors, Stream *maskStr,
4888
int maskWidth, int maskHeight, GBool maskInvert) {
4890
ImageStream *imgStr;
4892
PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
4893
int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
4894
GBool emitRect, addRect, extendRect;
4897
GBool useRLE, useASCII, useASCIIHex, useCompressed;
4898
GfxSeparationColorSpace *sepCS;
4902
int col, i, j, x0, x1, y;
4907
// color key masking
4908
if (maskColors && colorMap && !inlineImg) {
4909
// can't read the stream twice for inline images -- but masking
4910
// isn't allowed with inline images anyway
4911
numComps = colorMap->getNumPixelComps();
4912
imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
4914
rects0Len = rects1Len = 0;
4915
rectsSize = rectsOutSize = 64;
4916
rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4917
rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
4918
rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
4919
sizeof(PSOutImgClipRect));
4920
for (y = 0; y < height; ++y) {
4921
if (!(line = imgStr->getLine())) {
4926
for (x0 = 0; x0 < width; ++x0) {
4927
for (j = 0; j < numComps; ++j) {
4928
if (line[x0*numComps+j] < maskColors[2*j] ||
4929
line[x0*numComps+j] > maskColors[2*j+1]) {
4937
for (x1 = x0; x1 < width; ++x1) {
4938
for (j = 0; j < numComps; ++j) {
4939
if (line[x1*numComps+j] < maskColors[2*j] ||
4940
line[x1*numComps+j] > maskColors[2*j+1]) {
4944
if (j == numComps) {
4948
while (x0 < width || i < rects0Len) {
4949
emitRect = addRect = extendRect = gFalse;
4952
} else if (i >= rects0Len) {
4954
} else if (rects0[i].x0 < x0) {
4956
} else if (x0 < rects0[i].x0) {
4958
} else if (rects0[i].x1 == x1) {
4961
emitRect = addRect = gTrue;
4964
if (rectsOutLen == rectsOutSize) {
4966
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
4967
sizeof(PSOutImgClipRect));
4969
rectsOut[rectsOutLen].x0 = rects0[i].x0;
4970
rectsOut[rectsOutLen].x1 = rects0[i].x1;
4971
rectsOut[rectsOutLen].y0 = height - y - 1;
4972
rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
4976
if (addRect || extendRect) {
4977
if (rects1Len == rectsSize) {
4979
rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
4980
sizeof(PSOutImgClipRect));
4981
rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
4982
sizeof(PSOutImgClipRect));
4984
rects1[rects1Len].x0 = x0;
4985
rects1[rects1Len].x1 = x1;
4987
rects1[rects1Len].y0 = y;
4990
rects1[rects1Len].y0 = rects0[i].y0;
4994
for (x0 = x1; x0 < width; ++x0) {
4995
for (j = 0; j < numComps; ++j) {
4996
if (line[x0*numComps+j] < maskColors[2*j] ||
4997
line[x0*numComps+j] > maskColors[2*j+1]) {
5005
for (x1 = x0; x1 < width; ++x1) {
5006
for (j = 0; j < numComps; ++j) {
5007
if (line[x1*numComps+j] < maskColors[2*j] ||
5008
line[x1*numComps+j] > maskColors[2*j+1]) {
5012
if (j == numComps) {
5022
rects0Len = rects1Len;
5025
for (i = 0; i < rects0Len; ++i) {
5026
if (rectsOutLen == rectsOutSize) {
5028
rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
5029
sizeof(PSOutImgClipRect));
5031
rectsOut[rectsOutLen].x0 = rects0[i].x0;
5032
rectsOut[rectsOutLen].x1 = rects0[i].x1;
5033
rectsOut[rectsOutLen].y0 = height - y - 1;
5034
rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
5037
if (rectsOutLen < 65536/4) {
5038
writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
5039
for (i = 0; i < rectsOutLen; ++i) {
5040
writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
5041
rectsOut[i].x0, rectsOut[i].y0,
5042
rectsOut[i].x1 - rectsOut[i].x0,
5043
rectsOut[i].y1 - rectsOut[i].y0);
5045
writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height);
5047
// would be over the limit of array size.
5048
// make each rectangle path and clip.
5049
writePS("gsave newpath\n");
5050
for (i = 0; i < rectsOutLen; ++i) {
5051
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
5052
((double)rectsOut[i].x0)/width,
5053
((double)rectsOut[i].y0)/height,
5054
((double)(rectsOut[i].x1 - rectsOut[i].x0))/width,
5055
((double)(rectsOut[i].y1 - rectsOut[i].y0))/height);
5066
} else if (maskStr) {
5067
maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
5072
dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
5073
writePS(" setcolorspace\n");
5076
useASCIIHex = globalParams->getPSASCIIHex();
5078
// set up the image data
5079
if (mode == psModeForm || inType3Char || preload) {
5082
str2 = new FixedLengthEncoder(str, len);
5083
str2 = new RunLengthEncoder(str2);
5085
str2 = new ASCIIHexEncoder(str2);
5087
str2 = new ASCII85Encoder(str2);
5091
writePS((char *)(useASCIIHex ? "[<" : "[<~"));
5094
c = str2->getChar();
5095
} while (c == '\n' || c == '\r');
5096
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5105
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
5107
c = str2->getChar();
5108
} while (c == '\n' || c == '\r');
5109
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5116
// each line is: "<~...data...~><eol>"
5117
// so max data length = 255 - 6 = 249
5118
// chunks are 1 or 5 bytes each, so we have to stop at 245
5119
// but make it 240 just to be safe
5121
writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
5124
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
5125
writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
5126
// add an extra entry because the RunLengthDecode filter may
5127
// read past the end
5133
// make sure the image is setup, it sometimes is not like on bug #17645
5134
setupImage(ref->getRef(), str);
5135
// set up to use the array already created by setupImages()
5136
writePSFmt("ImData_{0:d}_{1:d} 0 0\n",ref->getRefNum(), ref->getRefGen());
5141
writePS("<<\n /ImageType 1\n");
5143
// width, height, matrix, bits per component
5144
writePSFmt(" /Width {0:d}\n", width);
5145
writePSFmt(" /Height {0:d}\n", height);
5146
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5147
width, -height, height);
5148
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5149
writePS(" /BitsPerComponent 8\n");
5151
writePSFmt(" /BitsPerComponent {0:d}\n",
5152
colorMap ? colorMap->getBits() : 1);
5157
writePS(" /Decode [");
5158
if ((level == psLevel2Sep || level == psLevel3Sep) &&
5159
colorMap->getColorSpace()->getMode() == csSeparation) {
5160
// this matches up with the code in the pdfImSep operator
5161
n = (1 << colorMap->getBits()) - 1;
5162
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
5163
colorMap->getDecodeHigh(0) * n);
5164
} else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
5165
numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
5166
getAlt()->getNComps();
5167
for (i = 0; i < numComps; ++i) {
5174
numComps = colorMap->getNumPixelComps();
5175
for (i = 0; i < numComps; ++i) {
5179
writePSFmt("{0:.4g} {1:.4g}",
5180
colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
5185
writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
5189
if (mode == psModeForm || inType3Char || preload) {
5191
writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
5193
writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
5194
" index get 1 index get exch 1 add exch }\n");
5197
writePS(" /DataSource currentfile\n");
5201
s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
5203
if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
5206
useASCII = !(mode == psModeForm || inType3Char || preload);
5207
useCompressed = gFalse;
5210
useASCII = str->isBinary() &&
5211
!(mode == psModeForm || inType3Char || preload);
5212
useCompressed = gTrue;
5215
writePSFmt(" /ASCII{0:s}Decode filter\n",
5216
useASCIIHex ? "Hex" : "85");
5219
writePS(" /RunLengthDecode filter\n");
5221
if (useCompressed) {
5222
writePS(s->getCString());
5228
if (mode == psModeForm || inType3Char || preload) {
5230
// end of image dictionary
5231
writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask");
5233
// get rid of the array and index
5234
if (!inlineImg) writePS("pop ");
5235
writePS("pop pop\n");
5239
// cut off inline image streams at appropriate length
5241
str = new FixedLengthEncoder(str, len);
5242
} else if (useCompressed) {
5243
str = str->getUndecodedStream();
5246
// recode DeviceN data
5247
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5248
str = new DeviceNRecoder(str, width, height, colorMap);
5251
// add RunLengthEncode and ASCIIHex/85 encode filters
5253
str = new RunLengthEncoder(str);
5257
str = new ASCIIHexEncoder(str);
5259
str = new ASCII85Encoder(str);
5263
// end of image dictionary
5268
// this can't happen -- OPI dictionaries are in XObjects
5269
error(-1, "Internal: OPI in inline image");
5272
// need to read the stream to count characters -- the length
5273
// is data-dependent (because of ASCII and RLE filters)
5276
while ((c = str->getChar()) != EOF) {
5281
// +6/7 for "pdfIm\n" / "pdfImM\n"
5282
// +8 for newline + trailer
5283
n += colorMap ? 14 : 15;
5284
writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n);
5287
if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
5288
colorMap->getColorSpace()->getMode() == csSeparation) {
5289
color.c[0] = gfxColorComp1;
5290
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
5291
sepCS->getCMYK(&color, &cmyk);
5292
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
5293
colToDbl(cmyk.c), colToDbl(cmyk.m),
5294
colToDbl(cmyk.y), colToDbl(cmyk.k),
5297
writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
5300
// copy the stream data
5303
while ((c = str->getChar()) != EOF) {
5305
if (i >= (int)sizeof(dataBuf)) {
5306
writePSBuf(dataBuf, i);
5311
writePSBuf(dataBuf, i);
5315
// add newline and trailer to the end
5317
writePS("%-EOD-\n");
5320
writePS("%%EndData\n");
5325
if (useRLE || useASCII || inlineImg) {
5330
if ((maskColors && colorMap && !inlineImg) || maskStr) {
5331
if (rectsOutLen < 65536/4) {
5332
writePS("pdfImClipEnd\n");
5334
writePS("grestore\n");
5339
//~ this doesn't currently support OPI
5340
void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
5341
GBool invert, GBool inlineImg,
5342
Stream *str, int width, int height, int len,
5343
int *maskColors, Stream *maskStr,
5344
int maskWidth, int maskHeight, GBool maskInvert) {
5348
GBool useRLE, useASCII, useASCIIHex, useCompressed;
5349
GBool maskUseRLE, maskUseASCII, maskUseCompressed;
5350
GfxSeparationColorSpace *sepCS;
5356
useASCIIHex = globalParams->getPSASCIIHex();
5357
useRLE = useASCII = useCompressed = gFalse; // make gcc happy
5358
maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
5362
dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
5363
writePS(" setcolorspace\n");
5366
// set up the image data
5367
if (mode == psModeForm || inType3Char || preload) {
5370
str2 = new FixedLengthEncoder(str, len);
5371
str2 = new RunLengthEncoder(str2);
5373
str2 = new ASCIIHexEncoder(str2);
5375
str2 = new ASCII85Encoder(str2);
5379
writePS((char *)(useASCIIHex ? "[<" : "[<~"));
5382
c = str2->getChar();
5383
} while (c == '\n' || c == '\r');
5384
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5393
for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
5395
c = str2->getChar();
5396
} while (c == '\n' || c == '\r');
5397
if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
5404
// each line is: "<~...data...~><eol>"
5405
// so max data length = 255 - 6 = 249
5406
// chunks are 1 or 5 bytes each, so we have to stop at 245
5407
// but make it 240 just to be safe
5409
writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
5412
} while (c != (useASCIIHex ? '>' : '~') && c != EOF);
5413
writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
5414
// add an extra entry because the RunLengthDecode filter may
5415
// read past the end
5421
// make sure the image is setup, it sometimes is not like on bug #17645
5422
setupImage(ref->getRef(), str);
5423
// set up to use the array already created by setupImages()
5424
writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
5430
writePS("<<\n /ImageType 3\n");
5431
writePS(" /InterleaveType 3\n");
5432
writePS(" /DataDict\n");
5435
// image (data) dictionary
5436
writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
5438
// color key masking
5439
if (maskColors && colorMap) {
5440
writePS(" /MaskColor [\n");
5441
numComps = colorMap->getNumPixelComps();
5442
for (i = 0; i < 2 * numComps; i += 2) {
5443
writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]);
5448
// width, height, matrix, bits per component
5449
writePSFmt(" /Width {0:d}\n", width);
5450
writePSFmt(" /Height {0:d}\n", height);
5451
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5452
width, -height, height);
5453
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5454
writePS(" /BitsPerComponent 8\n");
5456
writePSFmt(" /BitsPerComponent {0:d}\n",
5457
colorMap ? colorMap->getBits() : 1);
5462
writePS(" /Decode [");
5463
if ((level == psLevel2Sep || level == psLevel3Sep) &&
5464
colorMap->getColorSpace()->getMode() == csSeparation) {
5465
// this matches up with the code in the pdfImSep operator
5466
n = (1 << colorMap->getBits()) - 1;
5467
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
5468
colorMap->getDecodeHigh(0) * n);
5469
} else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
5470
numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
5471
getAlt()->getNComps();
5472
for (i = 0; i < numComps; ++i) {
5479
numComps = colorMap->getNumPixelComps();
5480
for (i = 0; i < numComps; ++i) {
5484
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i),
5485
colorMap->getDecodeHigh(i));
5490
writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
5494
if (mode == psModeForm || inType3Char || preload) {
5496
writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
5498
writePS(" /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
5499
" index get 1 index get exch 1 add exch }\n");
5502
writePS(" /DataSource currentfile\n");
5506
s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
5508
if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
5511
useASCII = !(mode == psModeForm || inType3Char || preload);
5512
useCompressed = gFalse;
5515
useASCII = str->isBinary() &&
5516
!(mode == psModeForm || inType3Char || preload);
5517
useCompressed = gTrue;
5520
writePSFmt(" /ASCII{0:s}Decode filter\n",
5521
useASCIIHex ? "Hex" : "85");
5524
writePS(" /RunLengthDecode filter\n");
5526
if (useCompressed) {
5527
writePS(s->getCString());
5533
// end of image (data) dictionary
5538
writePS(" /MaskDict\n");
5540
writePS(" /ImageType 1\n");
5541
writePSFmt(" /Width {0:d}\n", maskWidth);
5542
writePSFmt(" /Height {0:d}\n", maskHeight);
5543
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
5544
maskWidth, -maskHeight, maskHeight);
5545
writePS(" /BitsPerComponent 1\n");
5546
writePSFmt(" /Decode [{0:d} {1:d}]\n",
5547
maskInvert ? 1 : 0, maskInvert ? 0 : 1);
5550
writePS(" /DataSource currentfile\n");
5551
s = maskStr->getPSFilter(3, " ");
5554
maskUseASCII = gTrue;
5555
maskUseCompressed = gFalse;
5557
maskUseRLE = gFalse;
5558
maskUseASCII = maskStr->isBinary();
5559
maskUseCompressed = gTrue;
5562
writePSFmt(" /ASCII{0:s}Decode filter\n",
5563
useASCIIHex ? "Hex" : "85");
5566
writePS(" /RunLengthDecode filter\n");
5568
if (maskUseCompressed) {
5569
writePS(s->getCString());
5579
if (mode == psModeForm || inType3Char || preload) {
5582
writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask");
5586
if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
5587
colorMap->getColorSpace()->getMode() == csSeparation) {
5588
color.c[0] = gfxColorComp1;
5589
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
5590
sepCS->getCMYK(&color, &cmyk);
5591
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
5592
colToDbl(cmyk.c), colToDbl(cmyk.m),
5593
colToDbl(cmyk.y), colToDbl(cmyk.k),
5596
writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
5604
if (maskUseCompressed) {
5605
maskStr = maskStr->getUndecodedStream();
5608
// add RunLengthEncode and ASCIIHex/85 encode filters
5610
maskStr = new RunLengthEncoder(maskStr);
5614
maskStr = new ASCIIHexEncoder(maskStr);
5616
maskStr = new ASCII85Encoder(maskStr);
5620
// copy the stream data
5622
while ((c = maskStr->getChar()) != EOF) {
5629
if (maskUseRLE || maskUseASCII) {
5634
// get rid of the array and index
5635
if (mode == psModeForm || inType3Char || preload) {
5636
if (!inlineImg) writePS("pop ");
5637
writePS("pop pop\n");
5642
// cut off inline image streams at appropriate length
5644
str = new FixedLengthEncoder(str, len);
5645
} else if (useCompressed) {
5646
str = str->getUndecodedStream();
5649
// recode DeviceN data
5650
if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
5651
str = new DeviceNRecoder(str, width, height, colorMap);
5654
// add RunLengthEncode and ASCIIHex/85 encode filters
5656
str = new RunLengthEncoder(str);
5660
str = new ASCIIHexEncoder(str);
5662
str = new ASCII85Encoder(str);
5666
// copy the stream data
5668
while ((c = str->getChar()) != EOF) {
5673
// add newline and trailer to the end
5675
writePS("%-EOD-\n");
5678
if (useRLE || useASCII || inlineImg) {
5684
void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
5685
GBool genXform, GBool updateColors,
5687
GfxCalGrayColorSpace *calGrayCS;
5688
GfxCalRGBColorSpace *calRGBCS;
5689
GfxLabColorSpace *labCS;
5690
GfxIndexedColorSpace *indexedCS;
5691
GfxSeparationColorSpace *separationCS;
5692
GfxDeviceNColorSpace *deviceNCS;
5693
GfxColorSpace *baseCS;
5695
double x[gfxColorMaxComps], y[gfxColorMaxComps];
5696
double low[gfxColorMaxComps], range[gfxColorMaxComps];
5700
int n, numComps, numAltComps;
5704
switch (colorSpace->getMode()) {
5707
writePS("/DeviceGray");
5712
processColors |= psProcessBlack;
5717
calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
5718
writePS("[/CIEBasedA <<\n");
5719
writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
5720
writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
5721
calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
5722
calGrayCS->getWhiteZ());
5723
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5724
calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
5725
calGrayCS->getWhiteZ());
5726
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5727
calGrayCS->getBlackX(), calGrayCS->getBlackY(),
5728
calGrayCS->getBlackZ());
5734
processColors |= psProcessBlack;
5739
writePS("/DeviceRGB");
5744
processColors |= psProcessCMYK;
5749
calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
5750
writePS("[/CIEBasedABC <<\n");
5751
writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
5752
calRGBCS->getGammaR(), calRGBCS->getGammaG(),
5753
calRGBCS->getGammaB());
5754
writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
5755
calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
5756
calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
5757
calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
5758
calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
5759
calRGBCS->getMatrix()[8]);
5760
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5761
calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
5762
calRGBCS->getWhiteZ());
5763
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5764
calRGBCS->getBlackX(), calRGBCS->getBlackY(),
5765
calRGBCS->getBlackZ());
5771
processColors |= psProcessCMYK;
5776
writePS("/DeviceCMYK");
5781
processColors |= psProcessCMYK;
5786
labCS = (GfxLabColorSpace *)colorSpace;
5787
writePS("[/CIEBasedABC <<\n");
5789
writePS(" /RangeABC [0 1 0 1 0 1]\n");
5790
writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
5791
(labCS->getAMax() - labCS->getAMin()) / 500.0,
5792
labCS->getAMin() / 500.0,
5793
(labCS->getBMax() - labCS->getBMin()) / 200.0,
5794
labCS->getBMin() / 200.0);
5796
writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
5797
labCS->getAMin(), labCS->getAMax(),
5798
labCS->getBMin(), labCS->getBMax());
5799
writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
5801
writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
5802
writePS(" /DecodeLMN\n");
5803
writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
5804
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
5805
labCS->getWhiteX());
5806
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
5807
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
5808
labCS->getWhiteY());
5809
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
5810
writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
5811
labCS->getWhiteZ());
5812
writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5813
labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
5814
writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
5815
labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
5821
processColors |= psProcessCMYK;
5826
// there is no transform function to the alternate color space, so
5827
// we can use it directly
5828
dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
5829
genXform, updateColors, gFalse);
5833
indexedCS = (GfxIndexedColorSpace *)colorSpace;
5834
baseCS = indexedCS->getBase();
5835
writePS("[/Indexed ");
5836
dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
5837
n = indexedCS->getIndexHigh();
5838
numComps = baseCS->getNComps();
5839
lookup = indexedCS->getLookup();
5840
writePSFmt(" {0:d} <\n", n);
5841
if (baseCS->getMode() == csDeviceN) {
5842
func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
5843
baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
5844
if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
5845
labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
5849
numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
5851
for (i = 0; i <= n; i += 8) {
5853
for (j = i; j < i+8 && j <= n; ++j) {
5854
for (k = 0; k < numComps; ++k) {
5855
x[k] = low[k] + (*p++ / 255.0) * range[k];
5857
func->transform(x, y);
5860
y[1] = (y[1] - labCS->getAMin()) /
5861
(labCS->getAMax() - labCS->getAMin());
5862
y[2] = (y[2] - labCS->getBMin()) /
5863
(labCS->getBMax() - labCS->getBMin());
5865
for (k = 0; k < numAltComps; ++k) {
5866
byte = (int)(y[k] * 255 + 0.5);
5869
} else if (byte > 255) {
5872
writePSFmt("{0:02x}", byte);
5875
color.c[0] = dblToCol(j);
5876
indexedCS->getCMYK(&color, &cmyk);
5877
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
5878
colToDbl(cmyk.y), colToDbl(cmyk.k));
5884
for (i = 0; i <= n; i += 8) {
5886
for (j = i; j < i+8 && j <= n; ++j) {
5887
for (k = 0; k < numComps; ++k) {
5888
writePSFmt("{0:02x}", lookup[j * numComps + k]);
5891
color.c[0] = dblToCol(j);
5892
indexedCS->getCMYK(&color, &cmyk);
5893
addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
5894
colToDbl(cmyk.y), colToDbl(cmyk.k));
5907
separationCS = (GfxSeparationColorSpace *)colorSpace;
5908
writePS("[/Separation ");
5909
writePSString(separationCS->getName());
5911
dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
5913
cvtFunction(separationCS->getFunc());
5919
addCustomColor(separationCS);
5924
// DeviceN color spaces are a Level 3 PostScript feature.
5925
deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
5926
dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
5929
cvtFunction(deviceNCS->getTintTransformFunc());
5940
void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
5943
if (globalParams->getPSOPI()) {
5944
opiDict->lookup("2.0", &dict);
5945
if (dict.isDict()) {
5946
opiBegin20(state, dict.getDict());
5950
opiDict->lookup("1.3", &dict);
5951
if (dict.isDict()) {
5952
opiBegin13(state, dict.getDict());
5959
void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
5960
Object obj1, obj2, obj3, obj4;
5961
double width, height, left, right, top, bottom;
5965
writePS("%%BeginOPI: 2.0\n");
5966
writePS("%%Distilled\n");
5968
dict->lookup("F", &obj1);
5969
if (getFileSpecName(&obj1, &obj2)) {
5970
writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
5975
dict->lookup("MainImage", &obj1);
5976
if (obj1.isString()) {
5977
writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
5981
//~ ignoring 'Tags' entry
5982
//~ need to use writePSString() and deal with >255-char lines
5984
dict->lookup("Size", &obj1);
5985
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
5986
obj1.arrayGet(0, &obj2);
5987
width = obj2.getNum();
5989
obj1.arrayGet(1, &obj2);
5990
height = obj2.getNum();
5992
writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
5996
dict->lookup("CropRect", &obj1);
5997
if (obj1.isArray() && obj1.arrayGetLength() == 4) {
5998
obj1.arrayGet(0, &obj2);
5999
left = obj2.getNum();
6001
obj1.arrayGet(1, &obj2);
6002
top = obj2.getNum();
6004
obj1.arrayGet(2, &obj2);
6005
right = obj2.getNum();
6007
obj1.arrayGet(3, &obj2);
6008
bottom = obj2.getNum();
6010
writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
6011
left, top, right, bottom);
6015
dict->lookup("Overprint", &obj1);
6016
if (obj1.isBool()) {
6017
writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
6021
dict->lookup("Inks", &obj1);
6022
if (obj1.isName()) {
6023
writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
6024
} else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
6025
obj1.arrayGet(0, &obj2);
6026
if (obj2.isName()) {
6027
writePSFmt("%%ImageInks: {0:s} {1:d}",
6028
obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
6029
for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
6030
obj1.arrayGet(i, &obj3);
6031
obj1.arrayGet(i+1, &obj4);
6032
if (obj3.isString() && obj4.isNum()) {
6034
writePSString(obj3.getString());
6035
writePSFmt(" {0:.6g}", obj4.getNum());
6048
writePS("%%BeginIncludedImage\n");
6050
dict->lookup("IncludedImageDimensions", &obj1);
6051
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6052
obj1.arrayGet(0, &obj2);
6055
obj1.arrayGet(1, &obj2);
6058
writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
6062
dict->lookup("IncludedImageQuality", &obj1);
6064
writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
6071
void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
6073
int left, right, top, bottom, samples, bits, width, height;
6075
double llx, lly, ulx, uly, urx, ury, lrx, lry;
6076
double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
6081
writePS("/opiMatrix2 matrix currentmatrix def\n");
6082
writePS("opiMatrix setmatrix\n");
6084
dict->lookup("F", &obj1);
6085
if (getFileSpecName(&obj1, &obj2)) {
6086
writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
6091
dict->lookup("CropRect", &obj1);
6092
if (obj1.isArray() && obj1.arrayGetLength() == 4) {
6093
obj1.arrayGet(0, &obj2);
6094
left = obj2.getInt();
6096
obj1.arrayGet(1, &obj2);
6097
top = obj2.getInt();
6099
obj1.arrayGet(2, &obj2);
6100
right = obj2.getInt();
6102
obj1.arrayGet(3, &obj2);
6103
bottom = obj2.getInt();
6105
writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
6106
left, top, right, bottom);
6110
dict->lookup("Color", &obj1);
6111
if (obj1.isArray() && obj1.arrayGetLength() == 5) {
6112
obj1.arrayGet(0, &obj2);
6115
obj1.arrayGet(1, &obj2);
6118
obj1.arrayGet(2, &obj2);
6121
obj1.arrayGet(3, &obj2);
6124
obj1.arrayGet(4, &obj2);
6125
if (obj2.isString()) {
6126
writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
6128
writePSString(obj2.getString());
6135
dict->lookup("ColorType", &obj1);
6136
if (obj1.isName()) {
6137
writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
6141
//~ ignores 'Comments' entry
6142
//~ need to handle multiple lines
6144
dict->lookup("CropFixed", &obj1);
6145
if (obj1.isArray()) {
6146
obj1.arrayGet(0, &obj2);
6147
ulx = obj2.getNum();
6149
obj1.arrayGet(1, &obj2);
6150
uly = obj2.getNum();
6152
obj1.arrayGet(2, &obj2);
6153
lrx = obj2.getNum();
6155
obj1.arrayGet(3, &obj2);
6156
lry = obj2.getNum();
6158
writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
6159
ulx, uly, lrx, lry);
6163
dict->lookup("GrayMap", &obj1);
6164
if (obj1.isArray()) {
6165
writePS("%ALDImageGrayMap:");
6166
for (i = 0; i < obj1.arrayGetLength(); i += 16) {
6170
for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
6171
obj1.arrayGet(i+j, &obj2);
6172
writePSFmt(" {0:d}", obj2.getInt());
6180
dict->lookup("ID", &obj1);
6181
if (obj1.isString()) {
6182
writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
6186
dict->lookup("ImageType", &obj1);
6187
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6188
obj1.arrayGet(0, &obj2);
6189
samples = obj2.getInt();
6191
obj1.arrayGet(1, &obj2);
6192
bits = obj2.getInt();
6194
writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
6198
dict->lookup("Overprint", &obj1);
6199
if (obj1.isBool()) {
6200
writePSFmt("%ALDImageOverprint: {0:s}\n",
6201
obj1.getBool() ? "true" : "false");
6205
dict->lookup("Position", &obj1);
6206
if (obj1.isArray() && obj1.arrayGetLength() == 8) {
6207
obj1.arrayGet(0, &obj2);
6208
llx = obj2.getNum();
6210
obj1.arrayGet(1, &obj2);
6211
lly = obj2.getNum();
6213
obj1.arrayGet(2, &obj2);
6214
ulx = obj2.getNum();
6216
obj1.arrayGet(3, &obj2);
6217
uly = obj2.getNum();
6219
obj1.arrayGet(4, &obj2);
6220
urx = obj2.getNum();
6222
obj1.arrayGet(5, &obj2);
6223
ury = obj2.getNum();
6225
obj1.arrayGet(6, &obj2);
6226
lrx = obj2.getNum();
6228
obj1.arrayGet(7, &obj2);
6229
lry = obj2.getNum();
6231
opiTransform(state, llx, lly, &tllx, &tlly);
6232
opiTransform(state, ulx, uly, &tulx, &tuly);
6233
opiTransform(state, urx, ury, &turx, &tury);
6234
opiTransform(state, lrx, lry, &tlrx, &tlry);
6235
writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
6236
tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
6241
dict->lookup("Resolution", &obj1);
6242
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6243
obj1.arrayGet(0, &obj2);
6244
horiz = obj2.getNum();
6246
obj1.arrayGet(1, &obj2);
6247
vert = obj2.getNum();
6249
writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
6254
dict->lookup("Size", &obj1);
6255
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
6256
obj1.arrayGet(0, &obj2);
6257
width = obj2.getInt();
6259
obj1.arrayGet(1, &obj2);
6260
height = obj2.getInt();
6262
writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
6266
//~ ignoring 'Tags' entry
6267
//~ need to use writePSString() and deal with >255-char lines
6269
dict->lookup("Tint", &obj1);
6271
writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
6275
dict->lookup("Transparency", &obj1);
6276
if (obj1.isBool()) {
6277
writePSFmt("%ALDImageTransparency: {0:s}\n",
6278
obj1.getBool() ? "true" : "false");
6282
writePS("%%BeginObject: image\n");
6283
writePS("opiMatrix2 setmatrix\n");
6287
// Convert PDF user space coordinates to PostScript default user space
6288
// coordinates. This has to account for both the PDF CTM and the
6289
// PSOutputDev page-fitting transform.
6290
void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
6291
double *x1, double *y1) {
6294
state->transform(x0, y0, x1, y1);
6301
} else if (rotate == 180) {
6304
} else if (rotate == 270) {
6313
void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
6316
if (globalParams->getPSOPI()) {
6317
opiDict->lookup("2.0", &dict);
6318
if (dict.isDict()) {
6319
writePS("%%EndIncludedImage\n");
6320
writePS("%%EndOPI\n");
6321
writePS("grestore\n");
6326
opiDict->lookup("1.3", &dict);
6327
if (dict.isDict()) {
6328
writePS("%%EndObject\n");
6329
writePS("restore\n");
6336
#endif // OPI_SUPPORT
6338
void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
6339
writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy);
6341
t3NeedsRestore = gTrue;
6344
void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
6345
double llx, double lly, double urx, double ury) {
6352
t3String = new GooString();
6354
t3Cacheable = gTrue;
6355
t3NeedsRestore = gTrue;
6358
void PSOutputDev::drawForm(Ref id) {
6359
writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
6362
void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
6366
if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
6372
while ((c = str->getChar()) != EOF) {
6378
//~ can nextFunc be reset to 0 -- maybe at the start of each page?
6379
//~ or maybe at the start of each color space / pattern?
6380
void PSOutputDev::cvtFunction(Function *func) {
6381
SampledFunction *func0;
6382
ExponentialFunction *func2;
6383
StitchingFunction *func3;
6384
PostScriptFunction *func4;
6385
int thisFunc, m, n, nSamples, i, j, k;
6387
switch (func->getType()) {
6389
case -1: // identity
6394
func0 = (SampledFunction *)func;
6395
thisFunc = nextFunc++;
6396
m = func0->getInputSize();
6397
n = func0->getOutputSize();
6399
for (i = 0; i < m; ++i) {
6400
nSamples *= func0->getSampleSize(i);
6402
writePSFmt("/xpdfSamples{0:d} [\n", thisFunc);
6403
for (i = 0; i < nSamples; ++i) {
6404
writePSFmt("{0:.6g}\n", func0->getSamples()[i]);
6407
writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2);
6408
// [e01] [efrac] x0 x1 ... xm-1
6409
for (i = m-1; i >= 0; --i) {
6410
// [e01] [efrac] x0 x1 ... xi
6411
writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add\n",
6412
func0->getDomainMin(i),
6413
(func0->getEncodeMax(i) - func0->getEncodeMin(i)) /
6414
(func0->getDomainMax(i) - func0->getDomainMin(i)),
6415
func0->getEncodeMin(i));
6416
// [e01] [efrac] x0 x1 ... xi-1 xi'
6417
writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n",
6418
func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1);
6419
// [e01] [efrac] x0 x1 ... xi-1 xi'
6420
writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
6421
// [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
6422
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i);
6423
// [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
6424
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1);
6425
// [e01] [efrac] x0 x1 ... xi-1 floor(xi')
6426
writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i);
6427
// [e01] [efrac] x0 x1 ... xi-1
6430
for (i = 0; i < n; ++i) {
6431
// [e01] [efrac] y(0) ... y(i-1)
6432
for (j = 0; j < (1<<m); ++j) {
6433
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
6434
writePSFmt("xpdfSamples{0:d}\n", thisFunc);
6436
writePSFmt("{0:d} index {1:d} get\n", i+j+2, 2 * k + ((j >> k) & 1));
6437
for (k = m - 2; k >= 0; --k) {
6438
writePSFmt("{0:d} mul {1:d} index {2:d} get add\n",
6439
func0->getSampleSize(k),
6441
2 * k + ((j >> k) & 1));
6444
writePSFmt("{0:d} mul {1:d} add ", n, i);
6448
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
6449
for (j = 0; j < m; ++j) {
6450
// [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
6451
for (k = 0; k < (1 << (m - j)); k += 2) {
6452
// [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
6453
writePSFmt("{0:d} index {1:d} get dup\n",
6454
i + k/2 + (1 << (m-j)) - k, j);
6455
writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
6456
writePSFmt("{0:d} 1 roll\n", k/2 + (1 << (m-j)) - k - 1);
6458
// [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
6460
// [e01] [efrac] y(0) ... y(i-1) s
6461
writePSFmt("{0:.6g} mul {1:.6g} add\n",
6462
func0->getDecodeMax(i) - func0->getDecodeMin(i),
6463
func0->getDecodeMin(i));
6464
writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6465
func0->getRangeMin(i), func0->getRangeMin(i),
6466
func0->getRangeMax(i), func0->getRangeMax(i));
6467
// [e01] [efrac] y(0) ... y(i-1) y(i)
6469
// [e01] [efrac] y(0) ... y(n-1)
6470
writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n);
6473
case 2: // exponential
6474
func2 = (ExponentialFunction *)func;
6475
n = func2->getOutputSize();
6476
writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6477
func2->getDomainMin(0), func2->getDomainMin(0),
6478
func2->getDomainMax(0), func2->getDomainMax(0));
6480
for (i = 0; i < n; ++i) {
6482
writePSFmt("{0:d} index {1:.6g} exp {2:.6g} mul {3:.6g} add\n",
6483
i, func2->getE(), func2->getC1()[i] - func2->getC0()[i],
6485
if (func2->getHasRange()) {
6486
writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6487
func2->getRangeMin(i), func2->getRangeMin(i),
6488
func2->getRangeMax(i), func2->getRangeMax(i));
6492
writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n);
6495
case 3: // stitching
6496
func3 = (StitchingFunction *)func;
6497
thisFunc = nextFunc++;
6498
for (i = 0; i < func3->getNumFuncs(); ++i) {
6499
cvtFunction(func3->getFunc(i));
6500
writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i);
6502
writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
6503
func3->getDomainMin(0), func3->getDomainMin(0),
6504
func3->getDomainMax(0), func3->getDomainMax(0));
6505
for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
6506
writePSFmt("dup {0:.6g} lt {{ {1:.6g} sub {2:.6g} mul {3:.6g} add xpdfFunc{4:d}_{5:d} }} {{\n",
6507
func3->getBounds()[i+1],
6508
func3->getBounds()[i],
6509
func3->getScale()[i],
6510
func3->getEncode()[2*i],
6513
writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add xpdfFunc{3:d}_{4:d}\n",
6514
func3->getBounds()[i],
6515
func3->getScale()[i],
6516
func3->getEncode()[2*i],
6518
for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
6519
writePS("} ifelse\n");
6524
case 4: // PostScript
6525
func4 = (PostScriptFunction *)func;
6526
writePS(func4->getCodeString()->getCString());
6532
void PSOutputDev::writePSChar(char c) {
6534
t3String->append(c);
6536
(*outputFunc)(outputStream, &c, 1);
6540
void PSOutputDev::writePS(char *s) {
6542
t3String->append(s);
6544
(*outputFunc)(outputStream, s, strlen(s));
6548
void PSOutputDev::writePSBuf(char *s, int len) {
6550
for (int i = 0; i < len; i++) {
6551
t3String->append(s[i]);
6554
(*outputFunc)(outputStream, s, len);
6558
void PSOutputDev::writePSFmt(const char *fmt, ...) {
6562
va_start(args, fmt);
6564
t3String->appendfv((char *)fmt, args);
6566
buf = GooString::formatv((char *)fmt, args);
6567
(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
6573
void PSOutputDev::writePSString(GooString *s) {
6580
for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
6586
if (*p == '(' || *p == ')' || *p == '\\') {
6588
writePSChar((char)*p);
6590
} else if (*p < 0x20 || *p >= 0x80) {
6591
sprintf(buf, "\\%03o", *p);
6595
writePSChar((char)*p);
6602
void PSOutputDev::writePSName(char *s) {
6607
while ((c = *p++)) {
6608
if (c <= (char)0x20 || c >= (char)0x7f ||
6609
c == '(' || c == ')' || c == '<' || c == '>' ||
6610
c == '[' || c == ']' || c == '{' || c == '}' ||
6611
c == '/' || c == '%' || c == '\\') {
6612
writePSFmt("#{0:02x}", c & 0xff);
6619
// Convert GooString to GooString, with appropriate escaping
6620
// of things that can't appear in a label
6621
// This is heavily based on the writePSTextLine() method
6622
GooString* PSOutputDev::filterPSLabel(GooString *label, GBool *needParens) {
6626
// - DSC comments must be printable ASCII; control chars and
6627
// backslashes have to be escaped (we do cheap UCS2-to-ASCII
6628
// conversion by simply ignoring the high byte)
6629
// - parentheses are escaped. this isn't strictly necessary for matched
6630
// parentheses, but shouldn't be a problem
6631
// - lines are limited to 255 chars (we limit to 200 here to allow
6632
// for the keyword, which was emitted by the caller)
6634
GooString *label2 = new GooString();
6635
int labelLength = label->getLength();
6637
if (labelLength == 0) {
6640
// this gets changed later if we find a non-numeric character
6644
if ( (labelLength >= 2) &&
6645
( (label->getChar(0) & 0xff) == 0xfe) &&
6646
( (label->getChar(1) & 0xff) == 0xff) ) {
6650
if ( (label->getChar(labelLength-1) == 0) ) {
6651
// prune the trailing null (0x000 for UCS2)
6658
for (int j = 0; i < labelLength && j < 200; i += step) {
6659
char c = label->getChar(i);
6660
if ( (c < '0') || (c > '9') ) {
6664
label2->append("\\\\");
6666
} else if (c == ')') {
6667
label2->append("\\)");
6668
} else if (c == '(') {
6669
label2->append("\\(");
6670
} else if (c < 0x20 || c > 0x7e) {
6671
label2->append(GooString::format("\\{0:03o}", c));
6679
*needParens = !(isNumeric);
6684
// Write a DSC-compliant <textline>.
6685
void PSOutputDev::writePSTextLine(GooString *s) {
6689
// - DSC comments must be printable ASCII; control chars and
6690
// backslashes have to be escaped (we do cheap Unicode-to-ASCII
6691
// conversion by simply ignoring the high byte)
6692
// - lines are limited to 255 chars (we limit to 200 here to allow
6693
// for the keyword, which was emitted by the caller)
6694
// - lines that start with a left paren are treated as <text>
6695
// instead of <textline>, so we escape a leading paren
6696
if (s->getLength() >= 2 &&
6697
(s->getChar(0) & 0xff) == 0xfe &&
6698
(s->getChar(1) & 0xff) == 0xff) {
6705
for (j = 0; i < s->getLength() && j < 200; i += step) {
6706
c = s->getChar(i) & 0xff;
6710
} else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
6711
writePSFmt("\\{0:03o}", c);