~matttbe/ubuntu/raring/poppler/lp1072129

« back to all changes in this revision

Viewing changes to .pc/15_output-tiling-patterns-issuing-PS-patterns.patch/poppler/PSOutputDev.cc

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2011-08-19 15:10:18 UTC
  • Revision ID: package-import@ubuntu.com-20110819151018-0b11268hfo5pidoe
Tags: 0.16.7-2ubuntu2
debian/patches/15_output-tiling-patterns-issuing-PS-patterns.patch,
debian/patches/17_dont-use-patterns-when-only-one-instance-is-used.patch:
Backported upstream patch to use PostScript Patterns for tiling fill when
output PostScript level >= 2 and to avoid using /PatternType if only one
instance of the pattern is used. This should fix LP: #817049.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//========================================================================
 
2
//
 
3
// PSOutputDev.cc
 
4
//
 
5
// Copyright 1996-2003 Glyph & Cog, LLC
 
6
//
 
7
//========================================================================
 
8
 
 
9
//========================================================================
 
10
//
 
11
// Modified under the Poppler project - http://poppler.freedesktop.org
 
12
//
 
13
// All changes made under the Poppler project to this file are licensed
 
14
// under GPL version 2 or later
 
15
//
 
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>
 
29
//
 
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
 
32
//
 
33
//========================================================================
 
34
 
 
35
#include <config.h>
 
36
 
 
37
#ifdef USE_GCC_PRAGMAS
 
38
#pragma implementation
 
39
#endif
 
40
 
 
41
#include <stdio.h>
 
42
#include <stddef.h>
 
43
#include <stdarg.h>
 
44
#include <signal.h>
 
45
#include <math.h>
 
46
#include <limits.h>
 
47
#include "goo/GooString.h"
 
48
#include "goo/GooList.h"
 
49
#include "poppler-config.h"
 
50
#include "GlobalParams.h"
 
51
#include "Object.h"
 
52
#include "Error.h"
 
53
#include "Function.h"
 
54
#include "Gfx.h"
 
55
#include "GfxState.h"
 
56
#include "GfxFont.h"
 
57
#include "UnicodeMap.h"
 
58
#include <fofi/FoFiType1C.h>
 
59
#include <fofi/FoFiTrueType.h>
 
60
#include "Catalog.h"
 
61
#include "Page.h"
 
62
#include "Stream.h"
 
63
#include "Annot.h"
 
64
#include "XRef.h"
 
65
#include "PreScanOutputDev.h"
 
66
#include "FileSpec.h"
 
67
#if HAVE_SPLASH
 
68
#  include "splash/Splash.h"
 
69
#  include "splash/SplashBitmap.h"
 
70
#  include "SplashOutputDev.h"
 
71
#endif
 
72
#include "PSOutputDev.h"
 
73
#include "PDFDoc.h"
 
74
 
 
75
#ifdef MACOS
 
76
// needed for setting type/creator of MacOS files
 
77
#include "ICSupport.h"
 
78
#endif
 
79
 
 
80
// the MSVC math.h doesn't define this
 
81
#ifndef M_PI
 
82
#define M_PI 3.14159265358979323846
 
83
#endif
 
84
 
 
85
//------------------------------------------------------------------------
 
86
 
 
87
// Resolution at which pages with transparency will be rasterized.
 
88
#define splashDPI 300
 
89
 
 
90
//------------------------------------------------------------------------
 
91
// PostScript prolog and setup
 
92
//------------------------------------------------------------------------
 
93
 
 
94
// The '~' escapes mark prolog code that is emitted only in certain
 
95
// levels:
 
96
//
 
97
//   ~[123][sn]
 
98
//      ^   ^----- s=psLevel*Sep, n=psLevel*
 
99
//      +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
 
100
 
 
101
static char *prolog[] = {
 
102
  "/xpdf 75 dict def xpdf begin",
 
103
  "% PDF special state",
 
104
  "/pdfDictSize 15 def",
 
105
  "~1sn",
 
106
  "/pdfStates 64 array def",
 
107
  "  0 1 63 {",
 
108
  "    pdfStates exch pdfDictSize dict",
 
109
  "    dup /pdfStateIdx 3 index put",
 
110
  "    put",
 
111
  "  } for",
 
112
  "~123sn",
 
113
  "/pdfSetup {",
 
114
  "  3 1 roll 2 array astore",
 
115
  "  /setpagedevice where {",
 
116
  "    pop 3 dict begin",
 
117
  "      /PageSize exch def",
 
118
  "      /ImagingBBox null def",
 
119
  "      { /Duplex true def } if",
 
120
  "    currentdict end setpagedevice",
 
121
  "  } {",
 
122
  "    pop pop",
 
123
  "  } ifelse",
 
124
  "} def",
 
125
  "~1sn",
 
126
  "/pdfOpNames [",
 
127
  "  /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
 
128
  "  /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender /pdfPatternCS",
 
129
  "  /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
 
130
  "] def",
 
131
  "~123sn",
 
132
  "/pdfStartPage {",
 
133
  "~1sn",
 
134
  "  pdfStates 0 get begin",
 
135
  "~23sn",
 
136
  "  pdfDictSize dict begin",
 
137
  "~23n",
 
138
  "  /pdfFillCS [] def",
 
139
  "  /pdfFillXform {} def",
 
140
  "  /pdfStrokeCS [] def",
 
141
  "  /pdfStrokeXform {} def",
 
142
  "~1n",
 
143
  "  /pdfFill 0 def",
 
144
  "  /pdfStroke 0 def",
 
145
  "~1s",
 
146
  "  /pdfFill [0 0 0 1] def",
 
147
  "  /pdfStroke [0 0 0 1] def",
 
148
  "~23sn",
 
149
  "  /pdfFill [0] def",
 
150
  "  /pdfStroke [0] def",
 
151
  "  /pdfFillOP false def",
 
152
  "  /pdfStrokeOP false def",
 
153
  "~123sn",
 
154
  "  /pdfLastFill false def",
 
155
  "  /pdfLastStroke false def",
 
156
  "  /pdfTextMat [1 0 0 1 0 0] def",
 
157
  "  /pdfFontSize 0 def",
 
158
  "  /pdfCharSpacing 0 def",
 
159
  "  /pdfTextRender 0 def",
 
160
  "  /pdfPatternCS false def", 
 
161
  "  /pdfTextRise 0 def",
 
162
  "  /pdfWordSpacing 0 def",
 
163
  "  /pdfHorizScaling 1 def",
 
164
  "  /pdfTextClipPath [] def",
 
165
  "} def",
 
166
  "/pdfEndPage { end } def",
 
167
  "~23s",
 
168
  "% separation convention operators",
 
169
  "/findcmykcustomcolor where {",
 
170
  "  pop",
 
171
  "}{",
 
172
  "  /findcmykcustomcolor { 5 array astore } def",
 
173
  "} ifelse",
 
174
  "/setcustomcolor where {",
 
175
  "  pop",
 
176
  "}{",
 
177
  "  /setcustomcolor {",
 
178
  "    exch",
 
179
  "    [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
 
180
  "      0 4 getinterval cvx",
 
181
  "      [ exch /dup load exch { mul exch dup } /forall load",
 
182
  "        /pop load dup ] cvx",
 
183
  "    ] setcolorspace setcolor",
 
184
  "  } def",
 
185
  "} ifelse",
 
186
  "/customcolorimage where {",
 
187
  "  pop",
 
188
  "}{",
 
189
  "  /customcolorimage {",
 
190
  "    gsave",
 
191
  "    [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
 
192
  "      0 4 getinterval",
 
193
  "      [ exch /dup load exch { mul exch dup } /forall load",
 
194
  "        /pop load dup ] cvx",
 
195
  "    ] setcolorspace",
 
196
  "    10 dict begin",
 
197
  "      /ImageType 1 def",
 
198
  "      /DataSource exch def",
 
199
  "      /ImageMatrix exch def",
 
200
  "      /BitsPerComponent exch def",
 
201
  "      /Height exch def",
 
202
  "      /Width exch def",
 
203
  "      /Decode [1 0] def",
 
204
  "    currentdict end",
 
205
  "    image",
 
206
  "    grestore",
 
207
  "  } def",
 
208
  "} ifelse",
 
209
  "~123sn",
 
210
  "% PDF color state",
 
211
  "~1n",
 
212
  "/g { dup /pdfFill exch def setgray",
 
213
  "     /pdfLastFill true def /pdfLastStroke false def } def",
 
214
  "/G { dup /pdfStroke exch def setgray",
 
215
  "     /pdfLastStroke true def /pdfLastFill false def } def",
 
216
  "/fCol {",
 
217
  "  pdfLastFill not {",
 
218
  "    pdfFill setgray",
 
219
  "    /pdfLastFill true def /pdfLastStroke false def",
 
220
  "  } if",
 
221
  "} def",
 
222
  "/sCol {",
 
223
  "  pdfLastStroke not {",
 
224
  "    pdfStroke setgray",
 
225
  "    /pdfLastStroke true def /pdfLastFill false def",
 
226
  "  } if",
 
227
  "} def",
 
228
  "~1s",
 
229
  "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
 
230
  "     /pdfLastFill true def /pdfLastStroke false def } def",
 
231
  "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
 
232
  "     /pdfLastStroke true def /pdfLastFill false def } def",
 
233
  "/fCol {",
 
234
  "  pdfLastFill not {",
 
235
  "    pdfFill aload pop setcmykcolor",
 
236
  "    /pdfLastFill true def /pdfLastStroke false def",
 
237
  "  } if",
 
238
  "} def",
 
239
  "/sCol {",
 
240
  "  pdfLastStroke not {",
 
241
  "    pdfStroke aload pop setcmykcolor",
 
242
  "    /pdfLastStroke true def /pdfLastFill false def",
 
243
  "  } if",
 
244
  "} def",
 
245
  "~23n",
 
246
  "/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
 
247
  "      setcolorspace } def",
 
248
  "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
 
249
  "      setcolorspace } def",
 
250
  "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
 
251
  "      dup /pdfFill exch def aload pop pdfFillXform setcolor",
 
252
  "     /pdfLastFill true def /pdfLastStroke false def } def",
 
253
  "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
 
254
  "      dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
 
255
  "     /pdfLastStroke true def /pdfLastFill false def } def",
 
256
  "/op { /pdfFillOP exch def",
 
257
  "      pdfLastFill { pdfFillOP setoverprint } if } def",
 
258
  "/OP { /pdfStrokeOP exch def",
 
259
  "      pdfLastStroke { pdfStrokeOP setoverprint } if } def",
 
260
  "/fCol {",
 
261
  "  pdfLastFill not {",
 
262
  "    pdfFillCS setcolorspace",
 
263
  "    pdfFill aload pop pdfFillXform setcolor",
 
264
  "    pdfFillOP setoverprint",
 
265
  "    /pdfLastFill true def /pdfLastStroke false def",
 
266
  "  } if",
 
267
  "} def",
 
268
  "/sCol {",
 
269
  "  pdfLastStroke not {",
 
270
  "    pdfStrokeCS setcolorspace",
 
271
  "    pdfStroke aload pop pdfStrokeXform setcolor",
 
272
  "    pdfStrokeOP setoverprint",
 
273
  "    /pdfLastStroke true def /pdfLastFill false def",
 
274
  "  } if",
 
275
  "} def",
 
276
  "~23s",
 
277
  "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
 
278
  "     /pdfLastFill true def /pdfLastStroke false def } def",
 
279
  "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
 
280
  "     /pdfLastStroke true def /pdfLastFill false def } def",
 
281
  "/ck { 6 copy 6 array astore /pdfFill exch def",
 
282
  "      findcmykcustomcolor exch setcustomcolor",
 
283
  "      /pdfLastFill true def /pdfLastStroke false def } def",
 
284
  "/CK { 6 copy 6 array astore /pdfStroke exch def",
 
285
  "      findcmykcustomcolor exch setcustomcolor",
 
286
  "      /pdfLastStroke true def /pdfLastFill false def } def",
 
287
  "/op { /pdfFillOP exch def",
 
288
  "      pdfLastFill { pdfFillOP setoverprint } if } def",
 
289
  "/OP { /pdfStrokeOP exch def",
 
290
  "      pdfLastStroke { pdfStrokeOP setoverprint } if } def",
 
291
  "/fCol {",
 
292
  "  pdfLastFill not {",
 
293
  "    pdfFill aload length 4 eq {",
 
294
  "      setcmykcolor",
 
295
  "    }{",
 
296
  "      findcmykcustomcolor exch setcustomcolor",
 
297
  "    } ifelse",
 
298
  "    pdfFillOP setoverprint",
 
299
  "    /pdfLastFill true def /pdfLastStroke false def",
 
300
  "  } if",
 
301
  "} def",
 
302
  "/sCol {",
 
303
  "  pdfLastStroke not {",
 
304
  "    pdfStroke aload length 4 eq {",
 
305
  "      setcmykcolor",
 
306
  "    }{",
 
307
  "      findcmykcustomcolor exch setcustomcolor",
 
308
  "    } ifelse",
 
309
  "    pdfStrokeOP setoverprint",
 
310
  "    /pdfLastStroke true def /pdfLastFill false def",
 
311
  "  } if",
 
312
  "} def",
 
313
  "~123sn",
 
314
  "% build a font",
 
315
  "/pdfMakeFont {",
 
316
  "  4 3 roll findfont",
 
317
  "  4 2 roll matrix scale makefont",
 
318
  "  dup length dict begin",
 
319
  "    { 1 index /FID ne { def } { pop pop } ifelse } forall",
 
320
  "    /Encoding exch def",
 
321
  "    currentdict",
 
322
  "  end",
 
323
  "  definefont pop",
 
324
  "} def",
 
325
  "/pdfMakeFont16 {",
 
326
  "  exch findfont",
 
327
  "  dup length dict begin",
 
328
  "    { 1 index /FID ne { def } { pop pop } ifelse } forall",
 
329
  "    /WMode exch def",
 
330
  "    currentdict",
 
331
  "  end",
 
332
  "  definefont pop",
 
333
  "} def",
 
334
  "~3sn",
 
335
  "/pdfMakeFont16L3 {",
 
336
  "  1 index /CIDFont resourcestatus {",
 
337
  "    pop pop 1 index /CIDFont findresource /CIDFontType known",
 
338
  "  } {",
 
339
  "    false",
 
340
  "  } ifelse",
 
341
  "  {",
 
342
  "    0 eq { /Identity-H } { /Identity-V } ifelse",
 
343
  "    exch 1 array astore composefont pop",
 
344
  "  } {",
 
345
  "    pdfMakeFont16",
 
346
  "  } ifelse",
 
347
  "} def",
 
348
  "~123sn",
 
349
  "% graphics state operators",
 
350
  "~1sn",
 
351
  "/q {",
 
352
  "  gsave",
 
353
  "  pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
 
354
  "  pdfStates pdfStateIdx 1 add get begin",
 
355
  "  pdfOpNames { exch def } forall",
 
356
  "} def",
 
357
  "/Q { end grestore } def",
 
358
  "~23sn",
 
359
  "/q { gsave pdfDictSize dict begin } def",
 
360
  "/Q {",
 
361
  "  end grestore",
 
362
  "  /pdfLastFill where {",
 
363
  "    pop",
 
364
  "    pdfLastFill {",
 
365
  "      pdfFillOP setoverprint",
 
366
  "    } {",
 
367
  "      pdfStrokeOP setoverprint",
 
368
  "    } ifelse",
 
369
  "  } if",
 
370
  "} def",
 
371
  "~123sn",
 
372
  "/cm { concat } def",
 
373
  "/d { setdash } def",
 
374
  "/i { setflat } def",
 
375
  "/j { setlinejoin } def",
 
376
  "/J { setlinecap } def",
 
377
  "/M { setmiterlimit } def",
 
378
  "/w { setlinewidth } def",
 
379
  "% path segment operators",
 
380
  "/m { moveto } def",
 
381
  "/l { lineto } def",
 
382
  "/c { curveto } def",
 
383
  "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
 
384
  "      neg 0 rlineto closepath } def",
 
385
  "/h { closepath } def",
 
386
  "% path painting operators",
 
387
  "/S { sCol stroke } def",
 
388
  "/Sf { fCol stroke } def",
 
389
  "/f { fCol fill } def",
 
390
  "/f* { fCol eofill } def",
 
391
  "% clipping operators",
 
392
  "/W { clip newpath } def",
 
393
  "/W* { eoclip newpath } def",
 
394
  "/Ws { strokepath clip newpath } def",
 
395
  "% text state operators",
 
396
  "/Tc { /pdfCharSpacing exch def } def",
 
397
  "/Tf { dup /pdfFontSize exch def",
 
398
  "      dup pdfHorizScaling mul exch matrix scale",
 
399
  "      pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
 
400
  "      exch findfont exch makefont setfont } def",
 
401
  "/Tr { /pdfTextRender exch def } def",
 
402
  "/Tp { /pdfPatternCS exch def } def", 
 
403
  "/Ts { /pdfTextRise exch def } def",
 
404
  "/Tw { /pdfWordSpacing exch def } def",
 
405
  "/Tz { /pdfHorizScaling exch def } def",
 
406
  "% text positioning operators",
 
407
  "/Td { pdfTextMat transform moveto } def",
 
408
  "/Tm { /pdfTextMat exch def } def",
 
409
  "% text string operators",
 
410
  "/cshow where {",
 
411
  "  pop",
 
412
  "  /cshow2 {",
 
413
  "    dup {",
 
414
  "      pop pop",
 
415
  "      1 string dup 0 3 index put 3 index exec",
 
416
  "    } exch cshow",
 
417
  "    pop pop",
 
418
  "  } def",
 
419
  "}{",
 
420
  "  /cshow2 {",
 
421
  "    currentfont /FontType get 0 eq {",
 
422
  "      0 2 2 index length 1 sub {",
 
423
  "        2 copy get exch 1 add 2 index exch get",
 
424
  "        2 copy exch 256 mul add",
 
425
  "        2 string dup 0 6 5 roll put dup 1 5 4 roll put",
 
426
  "        3 index exec",
 
427
  "      } for",
 
428
  "    } {",
 
429
  "      dup {",
 
430
  "        1 string dup 0 3 index put 3 index exec",
 
431
  "      } forall",
 
432
  "    } ifelse",
 
433
  "    pop pop",
 
434
  "  } def",
 
435
  "} ifelse",
 
436
  "/awcp {", // awidthcharpath
 
437
  "  exch {",
 
438
  "    false charpath",
 
439
  "    5 index 5 index rmoveto",
 
440
  "    6 index eq { 7 index 7 index rmoveto } if",
 
441
  "  } exch cshow2",
 
442
  "  6 {pop} repeat",
 
443
  "} def",
 
444
  "/Tj {",
 
445
  "  fCol",  // because stringwidth has to draw Type 3 chars
 
446
  "  1 index stringwidth pdfTextMat idtransform pop",
 
447
  "  sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
 
448
  "  pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
 
449
  "  4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
 
450
  "  pdfTextMat dtransform",
 
451
  "  6 5 roll Tj1",
 
452
  "} def",
 
453
  "/Tj16 {",
 
454
  "  fCol",  // because stringwidth has to draw Type 3 chars
 
455
  "  2 index stringwidth pdfTextMat idtransform pop",
 
456
  "  sub exch div",
 
457
  "  pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
 
458
  "  4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
 
459
  "  pdfTextMat dtransform",
 
460
  "  6 5 roll Tj1",
 
461
  "} def",
 
462
  "/Tj16V {",
 
463
  "  fCol",  // because stringwidth has to draw Type 3 chars
 
464
  "  2 index stringwidth pdfTextMat idtransform exch pop",
 
465
  "  sub exch div",
 
466
  "  0 pdfWordSpacing pdfTextMat dtransform 32",
 
467
  "  4 3 roll pdfCharSpacing add 0 exch",
 
468
  "  pdfTextMat dtransform",
 
469
  "  6 5 roll Tj1",
 
470
  "} def",
 
471
  "/Tj1 {",
 
472
  "  0 pdfTextRise pdfTextMat dtransform rmoveto",
 
473
  "  currentpoint 8 2 roll",
 
474
  "  pdfTextRender 1 and 0 eq pdfPatternCS not and {",
 
475
  "    6 copy awidthshow",
 
476
  "  } if",
 
477
  "  pdfTextRender 3 and dup 1 eq exch 2 eq or {",
 
478
  "    7 index 7 index moveto",
 
479
  "    6 copy",
 
480
  "    currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
 
481
  "    false awcp currentpoint stroke moveto",
 
482
  "  } if",
 
483
  "  pdfTextRender 4 and 0 ne pdfPatternCS or {",
 
484
  "    8 6 roll moveto",
 
485
  "    false awcp",
 
486
  "    /pdfTextClipPath [ pdfTextClipPath aload pop",
 
487
  "      {/moveto cvx}",
 
488
  "      {/lineto cvx}",
 
489
  "      {/curveto cvx}",
 
490
  "      {/closepath cvx}",
 
491
  "    pathforall ] def",
 
492
  "    currentpoint newpath moveto",
 
493
  "  } {",
 
494
  "    8 {pop} repeat",
 
495
  "  } ifelse",
 
496
  "  0 pdfTextRise neg pdfTextMat dtransform rmoveto",
 
497
  "} def",
 
498
  "/TJm { pdfFontSize 0.001 mul mul neg 0",
 
499
  "       pdfTextMat dtransform rmoveto } def",
 
500
  "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
 
501
  "        pdfTextMat dtransform rmoveto } def",
 
502
  "/Tclip { pdfTextClipPath cvx exec clip newpath",
 
503
  "         /pdfTextClipPath [] def } def",
 
504
  "/Tclip* { pdfTextClipPath cvx exec eoclip newpath",
 
505
  "         /pdfTextClipPath [] def } def",
 
506
  "~1ns",
 
507
  "% Level 1 image operators",
 
508
  "~1n",
 
509
  "/pdfIm1 {",
 
510
  "  /pdfImBuf1 4 index string def",
 
511
  "  { currentfile pdfImBuf1 readhexstring pop } image",
 
512
  "} def",
 
513
  "~1s",
 
514
  "/pdfIm1Sep {",
 
515
  "  /pdfImBuf1 4 index string def",
 
516
  "  /pdfImBuf2 4 index string def",
 
517
  "  /pdfImBuf3 4 index string def",
 
518
  "  /pdfImBuf4 4 index string def",
 
519
  "  { currentfile pdfImBuf1 readhexstring pop }",
 
520
  "  { currentfile pdfImBuf2 readhexstring pop }",
 
521
  "  { currentfile pdfImBuf3 readhexstring pop }",
 
522
  "  { currentfile pdfImBuf4 readhexstring pop }",
 
523
  "  true 4 colorimage",
 
524
  "} def",
 
525
  "~1ns",
 
526
  "/pdfImM1 {",
 
527
  "  fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
 
528
  "  { currentfile pdfImBuf1 readhexstring pop } imagemask",
 
529
  "} def",
 
530
  "/pdfImM1a {",
 
531
  "  { 2 copy get exch 1 add exch } imagemask",
 
532
  "  pop pop",
 
533
  "} def",
 
534
  "~23sn",
 
535
  "% Level 2 image operators",
 
536
  "/pdfImBuf 100 string def",
 
537
  "/pdfIm {",
 
538
  "  image",
 
539
  "  { currentfile pdfImBuf readline",
 
540
  "    not { pop exit } if",
 
541
  "    (%-EOD-) eq { exit } if } loop",
 
542
  "} def",
 
543
  "~23s",
 
544
  "/pdfImSep {",
 
545
  "  findcmykcustomcolor exch",
 
546
  "  dup /Width get /pdfImBuf1 exch string def",
 
547
  "  dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
 
548
  "  /pdfImDecodeLow exch def",
 
549
  "  begin Width Height BitsPerComponent ImageMatrix DataSource end",
 
550
  "  /pdfImData exch def",
 
551
  "  { pdfImData pdfImBuf1 readstring pop",
 
552
  "    0 1 2 index length 1 sub {",
 
553
  "      1 index exch 2 copy get",
 
554
  "      pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
 
555
  "      255 exch sub put",
 
556
  "    } for }",
 
557
  "  6 5 roll customcolorimage",
 
558
  "  { currentfile pdfImBuf readline",
 
559
  "    not { pop exit } if",
 
560
  "    (%-EOD-) eq { exit } if } loop",
 
561
  "} def",
 
562
  "~23sn",
 
563
  "/pdfImM {",
 
564
  "  fCol imagemask",
 
565
  "  { currentfile pdfImBuf readline",
 
566
  "    not { pop exit } if",
 
567
  "    (%-EOD-) eq { exit } if } loop",
 
568
  "} def",
 
569
  "~123sn",
 
570
  "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
 
571
  "/pdfImClip {",
 
572
  "  gsave",
 
573
  "  0 2 4 index length 1 sub {",
 
574
  "    dup 4 index exch 2 copy",
 
575
  "    get 5 index div put",
 
576
  "    1 add 3 index exch 2 copy",
 
577
  "    get 3 index div put",
 
578
  "  } for",
 
579
  "  pop pop rectclip",
 
580
  "} def",
 
581
  "/pdfImClipEnd { grestore } def",
 
582
  "~23sn",
 
583
  "% shading operators",
 
584
  "/colordelta {",
 
585
  "  false 0 1 3 index length 1 sub {",
 
586
  "    dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
 
587
  "      pop true",
 
588
  "    } if",
 
589
  "  } for",
 
590
  "  exch pop exch pop",
 
591
  "} def",
 
592
  "/funcCol { func n array astore } def",
 
593
  "/funcSH {",
 
594
  "  dup 0 eq {",
 
595
  "    true",
 
596
  "  } {",
 
597
  "    dup 6 eq {",
 
598
  "      false",
 
599
  "    } {",
 
600
  "      4 index 4 index funcCol dup",
 
601
  "      6 index 4 index funcCol dup",
 
602
  "      3 1 roll colordelta 3 1 roll",
 
603
  "      5 index 5 index funcCol dup",
 
604
  "      3 1 roll colordelta 3 1 roll",
 
605
  "      6 index 8 index funcCol dup",
 
606
  "      3 1 roll colordelta 3 1 roll",
 
607
  "      colordelta or or or",
 
608
  "    } ifelse",
 
609
  "  } ifelse",
 
610
  "  {",
 
611
  "    1 add",
 
612
  "    4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
 
613
  "    6 index 6 index 4 index 4 index 4 index funcSH",
 
614
  "    2 index 6 index 6 index 4 index 4 index funcSH",
 
615
  "    6 index 2 index 4 index 6 index 4 index funcSH",
 
616
  "    5 3 roll 3 2 roll funcSH pop pop",
 
617
  "  } {",
 
618
  "    pop 3 index 2 index add 0.5 mul 3 index  2 index add 0.5 mul",
 
619
  "~23n",
 
620
  "    funcCol sc",
 
621
  "~23s",
 
622
  "    funcCol aload pop k",
 
623
  "~23sn",
 
624
  "    dup 4 index exch mat transform m",
 
625
  "    3 index 3 index mat transform l",
 
626
  "    1 index 3 index mat transform l",
 
627
  "    mat transform l pop pop h f*",
 
628
  "  } ifelse",
 
629
  "} def",
 
630
  "/axialCol {",
 
631
  "  dup 0 lt {",
 
632
  "    pop t0",
 
633
  "  } {",
 
634
  "    dup 1 gt {",
 
635
  "      pop t1",
 
636
  "    } {",
 
637
  "      dt mul t0 add",
 
638
  "    } ifelse",
 
639
  "  } ifelse",
 
640
  "  func n array astore",
 
641
  "} def",
 
642
  "/axialSH {",
 
643
  "  dup 0 eq {",
 
644
  "    true",
 
645
  "  } {",
 
646
  "    dup 8 eq {",
 
647
  "      false",
 
648
  "    } {",
 
649
  "      2 index axialCol 2 index axialCol colordelta",
 
650
  "    } ifelse",
 
651
  "  } ifelse",
 
652
  "  {",
 
653
  "    1 add 3 1 roll 2 copy add 0.5 mul",
 
654
  "    dup 4 3 roll exch 4 index axialSH",
 
655
  "    exch 3 2 roll axialSH",
 
656
  "  } {",
 
657
  "    pop 2 copy add 0.5 mul",
 
658
  "~23n",
 
659
  "    axialCol sc",
 
660
  "~23s",
 
661
  "    axialCol aload pop k",
 
662
  "~23sn",
 
663
  "    exch dup dx mul x0 add exch dy mul y0 add",
 
664
  "    3 2 roll dup dx mul x0 add exch dy mul y0 add",
 
665
  "    dx abs dy abs ge {",
 
666
  "      2 copy yMin sub dy mul dx div add yMin m",
 
667
  "      yMax sub dy mul dx div add yMax l",
 
668
  "      2 copy yMax sub dy mul dx div add yMax l",
 
669
  "      yMin sub dy mul dx div add yMin l",
 
670
  "      h f*",
 
671
  "    } {",
 
672
  "      exch 2 copy xMin sub dx mul dy div add xMin exch m",
 
673
  "      xMax sub dx mul dy div add xMax exch l",
 
674
  "      exch 2 copy xMax sub dx mul dy div add xMax exch l",
 
675
  "      xMin sub dx mul dy div add xMin exch l",
 
676
  "      h f*",
 
677
  "    } ifelse",
 
678
  "  } ifelse",
 
679
  "} def",
 
680
  "/radialCol {",
 
681
  "  dup t0 lt {",
 
682
  "    pop t0",
 
683
  "  } {",
 
684
  "    dup t1 gt {",
 
685
  "      pop t1",
 
686
  "    } if",
 
687
  "  } ifelse",
 
688
  "  func n array astore",
 
689
  "} def",
 
690
  "/radialSH {",
 
691
  "  dup 0 eq {",
 
692
  "    true",
 
693
  "  } {",
 
694
  "    dup 8 eq {",
 
695
  "      false",
 
696
  "    } {",
 
697
  "      2 index dt mul t0 add radialCol",
 
698
  "      2 index dt mul t0 add radialCol colordelta",
 
699
  "    } ifelse",
 
700
  "  } ifelse",
 
701
  "  {",
 
702
  "    1 add 3 1 roll 2 copy add 0.5 mul",
 
703
  "    dup 4 3 roll exch 4 index radialSH",
 
704
  "    exch 3 2 roll radialSH",
 
705
  "  } {",
 
706
  "    pop 2 copy add 0.5 mul dt mul t0 add",
 
707
  "~23n",
 
708
  "    radialCol sc",
 
709
  "~23s",
 
710
  "    radialCol aload pop k",
 
711
  "~23sn",
 
712
  "    encl {",
 
713
  "      exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
714
  "      0 360 arc h",
 
715
  "      dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
716
  "      360 0 arcn h f",
 
717
  "    } {",
 
718
  "      2 copy",
 
719
  "      dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
720
  "      a1 a2 arcn",
 
721
  "      dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
722
  "      a2 a1 arcn h",
 
723
  "      dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
724
  "      a1 a2 arc",
 
725
  "      dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
 
726
  "      a2 a1 arc h f",
 
727
  "    } ifelse",
 
728
  "  } ifelse",
 
729
  "} def",
 
730
  "~123sn",
 
731
  "end",
 
732
  NULL
 
733
};
 
734
 
 
735
static char *cmapProlog[] = {
 
736
  "/CIDInit /ProcSet findresource begin",
 
737
  "10 dict begin",
 
738
  "  begincmap",
 
739
  "  /CMapType 1 def",
 
740
  "  /CMapName /Identity-H def",
 
741
  "  /CIDSystemInfo 3 dict dup begin",
 
742
  "    /Registry (Adobe) def",
 
743
  "    /Ordering (Identity) def",
 
744
  "    /Supplement 0 def",
 
745
  "  end def",
 
746
  "  1 begincodespacerange",
 
747
  "    <0000> <ffff>",
 
748
  "  endcodespacerange",
 
749
  "  0 usefont",
 
750
  "  1 begincidrange",
 
751
  "    <0000> <ffff> 0",
 
752
  "  endcidrange",
 
753
  "  endcmap",
 
754
  "  currentdict CMapName exch /CMap defineresource pop",
 
755
  "end",
 
756
  "10 dict begin",
 
757
  "  begincmap",
 
758
  "  /CMapType 1 def",
 
759
  "  /CMapName /Identity-V def",
 
760
  "  /CIDSystemInfo 3 dict dup begin",
 
761
  "    /Registry (Adobe) def",
 
762
  "    /Ordering (Identity) def",
 
763
  "    /Supplement 0 def",
 
764
  "  end def",
 
765
  "  /WMode 1 def",
 
766
  "  1 begincodespacerange",
 
767
  "    <0000> <ffff>",
 
768
  "  endcodespacerange",
 
769
  "  0 usefont",
 
770
  "  1 begincidrange",
 
771
  "    <0000> <ffff> 0",
 
772
  "  endcidrange",
 
773
  "  endcmap",
 
774
  "  currentdict CMapName exch /CMap defineresource pop",
 
775
  "end",
 
776
  "end",
 
777
  NULL
 
778
};
 
779
 
 
780
//------------------------------------------------------------------------
 
781
// Fonts
 
782
//------------------------------------------------------------------------
 
783
 
 
784
struct PSSubstFont {
 
785
  char *psName;                 // PostScript name
 
786
  double mWidth;                // width of 'm' character
 
787
};
 
788
 
 
789
static const char *psFonts[] = {
 
790
  "Courier",
 
791
  "Courier-Bold",
 
792
  "Courier-Oblique",
 
793
  "Courier-BoldOblique",
 
794
  "Helvetica",
 
795
  "Helvetica-Bold",
 
796
  "Helvetica-Oblique",
 
797
  "Helvetica-BoldOblique",
 
798
  "Symbol",
 
799
  "Times-Roman",
 
800
  "Times-Bold",
 
801
  "Times-Italic",
 
802
  "Times-BoldItalic",
 
803
  "ZapfDingbats",
 
804
  NULL
 
805
};
 
806
 
 
807
static const PSSubstFont psSubstFonts[] = {
 
808
  {"Helvetica",             0.833},
 
809
  {"Helvetica-Oblique",     0.833},
 
810
  {"Helvetica-Bold",        0.889},
 
811
  {"Helvetica-BoldOblique", 0.889},
 
812
  {"Times-Roman",           0.788},
 
813
  {"Times-Italic",          0.722},
 
814
  {"Times-Bold",            0.833},
 
815
  {"Times-BoldItalic",      0.778},
 
816
  {"Courier",               0.600},
 
817
  {"Courier-Oblique",       0.600},
 
818
  {"Courier-Bold",          0.600},
 
819
  {"Courier-BoldOblique",   0.600}
 
820
};
 
821
 
 
822
// Info for 8-bit fonts
 
823
struct PSFont8Info {
 
824
  Ref fontID;
 
825
  Gushort *codeToGID;           // code-to-GID mapping for TrueType fonts
 
826
};
 
827
 
 
828
// Encoding info for substitute 16-bit font
 
829
struct PSFont16Enc {
 
830
  Ref fontID;
 
831
  GooString *enc;
 
832
};
 
833
 
 
834
//------------------------------------------------------------------------
 
835
// process colors
 
836
//------------------------------------------------------------------------
 
837
 
 
838
#define psProcessCyan     1
 
839
#define psProcessMagenta  2
 
840
#define psProcessYellow   4
 
841
#define psProcessBlack    8
 
842
#define psProcessCMYK    15
 
843
 
 
844
//------------------------------------------------------------------------
 
845
// PSOutCustomColor
 
846
//------------------------------------------------------------------------
 
847
 
 
848
class PSOutCustomColor {
 
849
public:
 
850
 
 
851
  PSOutCustomColor(double cA, double mA,
 
852
                   double yA, double kA, GooString *nameA);
 
853
  ~PSOutCustomColor();
 
854
 
 
855
  double c, m, y, k;
 
856
  GooString *name;
 
857
  PSOutCustomColor *next;
 
858
};
 
859
 
 
860
PSOutCustomColor::PSOutCustomColor(double cA, double mA,
 
861
                                   double yA, double kA, GooString *nameA) {
 
862
  c = cA;
 
863
  m = mA;
 
864
  y = yA;
 
865
  k = kA;
 
866
  name = nameA;
 
867
  next = NULL;
 
868
}
 
869
 
 
870
PSOutCustomColor::~PSOutCustomColor() {
 
871
  delete name;
 
872
}
 
873
 
 
874
//------------------------------------------------------------------------
 
875
 
 
876
struct PSOutImgClipRect {
 
877
  int x0, x1, y0, y1;
 
878
};
 
879
 
 
880
//------------------------------------------------------------------------
 
881
// DeviceNRecoder
 
882
//------------------------------------------------------------------------
 
883
 
 
884
class DeviceNRecoder: public FilterStream {
 
885
public:
 
886
 
 
887
  DeviceNRecoder(Stream *strA, int widthA, int heightA,
 
888
                 GfxImageColorMap *colorMapA);
 
889
  virtual ~DeviceNRecoder();
 
890
  virtual StreamKind getKind() { return strWeird; }
 
891
  virtual void reset();
 
892
  virtual int getChar()
 
893
    { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
 
894
  virtual int lookChar()
 
895
    { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
 
896
  virtual GooString *getPSFilter(int psLevel, char *indent) { return NULL; }
 
897
  virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
 
898
  virtual GBool isEncoder() { return gTrue; }
 
899
 
 
900
private:
 
901
 
 
902
  GBool fillBuf();
 
903
 
 
904
  int width, height;
 
905
  GfxImageColorMap *colorMap;
 
906
  Function *func;
 
907
  ImageStream *imgStr;
 
908
  int buf[gfxColorMaxComps];
 
909
  int pixelIdx;
 
910
  int bufIdx;
 
911
  int bufSize;
 
912
};
 
913
 
 
914
DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
 
915
                               GfxImageColorMap *colorMapA):
 
916
    FilterStream(strA) {
 
917
  width = widthA;
 
918
  height = heightA;
 
919
  colorMap = colorMapA;
 
920
  imgStr = NULL;
 
921
  pixelIdx = 0;
 
922
  bufIdx = gfxColorMaxComps;
 
923
  bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
 
924
              getAlt()->getNComps();
 
925
  func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
 
926
           getTintTransformFunc();
 
927
}
 
928
 
 
929
DeviceNRecoder::~DeviceNRecoder() {
 
930
  if (imgStr) {
 
931
    delete imgStr;
 
932
  }
 
933
}
 
934
 
 
935
void DeviceNRecoder::reset() {
 
936
  imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
 
937
                           colorMap->getBits());
 
938
  imgStr->reset();
 
939
}
 
940
 
 
941
GBool DeviceNRecoder::fillBuf() {
 
942
  Guchar pixBuf[gfxColorMaxComps];
 
943
  GfxColor color;
 
944
  double x[gfxColorMaxComps], y[gfxColorMaxComps];
 
945
  int i;
 
946
 
 
947
  if (pixelIdx >= width * height) {
 
948
    return gFalse;
 
949
  }
 
950
  imgStr->getPixel(pixBuf);
 
951
  colorMap->getColor(pixBuf, &color);
 
952
  for (i = 0;
 
953
       i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps();
 
954
       ++i) {
 
955
    x[i] = colToDbl(color.c[i]);
 
956
  }
 
957
  func->transform(x, y);
 
958
  for (i = 0; i < bufSize; ++i) {
 
959
    buf[i] = (int)(y[i] * 255 + 0.5);
 
960
  }
 
961
  bufIdx = 0;
 
962
  ++pixelIdx;
 
963
  return gTrue;
 
964
}
 
965
 
 
966
//------------------------------------------------------------------------
 
967
// PSOutputDev
 
968
//------------------------------------------------------------------------
 
969
 
 
970
extern "C" {
 
971
typedef void (*SignalFunc)(int);
 
972
}
 
973
 
 
974
static void outputToFile(void *stream, char *data, int len) {
 
975
  fwrite(data, 1, len, (FILE *)stream);
 
976
}
 
977
 
 
978
PSOutputDev::PSOutputDev(const char *fileName, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
 
979
                         char *psTitle,
 
980
                         int firstPage, int lastPage, PSOutMode modeA,
 
981
                         int paperWidthA, int paperHeightA, GBool duplexA,
 
982
                         int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
 
983
                         GBool forceRasterizeA,
 
984
                         GBool manualCtrlA) {
 
985
  FILE *f;
 
986
  PSFileType fileTypeA;
 
987
 
 
988
  underlayCbk = NULL;
 
989
  underlayCbkData = NULL;
 
990
  overlayCbk = NULL;
 
991
  overlayCbkData = NULL;
 
992
 
 
993
  fontIDs = NULL;
 
994
  fontFileIDs = NULL;
 
995
  fontFileNames = NULL;
 
996
  font8Info = NULL;
 
997
  font16Enc = NULL;
 
998
  imgIDs = NULL;
 
999
  formIDs = NULL;
 
1000
  xobjStack = NULL;
 
1001
  embFontList = NULL;
 
1002
  customColors = NULL;
 
1003
  haveTextClip = gFalse;
 
1004
  haveCSPattern = gFalse;
 
1005
  t3String = NULL;
 
1006
 
 
1007
  forceRasterize = forceRasterizeA;
 
1008
 
 
1009
  // open file or pipe
 
1010
  if (!strcmp(fileName, "-")) {
 
1011
    fileTypeA = psStdout;
 
1012
    f = stdout;
 
1013
  } else if (fileName[0] == '|') {
 
1014
    fileTypeA = psPipe;
 
1015
#ifdef HAVE_POPEN
 
1016
#ifndef _WIN32
 
1017
    signal(SIGPIPE, (SignalFunc)SIG_IGN);
 
1018
#endif
 
1019
    if (!(f = popen(fileName + 1, "w"))) {
 
1020
      error(-1, "Couldn't run print command '%s'", fileName);
 
1021
      ok = gFalse;
 
1022
      return;
 
1023
    }
 
1024
#else
 
1025
    error(-1, "Print commands are not supported ('%s')", fileName);
 
1026
    ok = gFalse;
 
1027
    return;
 
1028
#endif
 
1029
  } else {
 
1030
    fileTypeA = psFile;
 
1031
    if (!(f = fopen(fileName, "w"))) {
 
1032
      error(-1, "Couldn't open PostScript file '%s'", fileName);
 
1033
      ok = gFalse;
 
1034
      return;
 
1035
    }
 
1036
  }
 
1037
 
 
1038
  init(outputToFile, f, fileTypeA, psTitle,
 
1039
       doc, xrefA, catalog, firstPage, lastPage, modeA,
 
1040
       imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
 
1041
       paperWidthA, paperHeightA, duplexA);
 
1042
}
 
1043
 
 
1044
PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
 
1045
                         char *psTitle,
 
1046
                         PDFDoc *doc,
 
1047
                         XRef *xrefA, Catalog *catalog,
 
1048
                         int firstPage, int lastPage, PSOutMode modeA,
 
1049
                         int paperWidthA, int paperHeightA, GBool duplexA,
 
1050
                         int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
 
1051
                         GBool forceRasterizeA,
 
1052
                         GBool manualCtrlA) {
 
1053
  underlayCbk = NULL;
 
1054
  underlayCbkData = NULL;
 
1055
  overlayCbk = NULL;
 
1056
  overlayCbkData = NULL;
 
1057
 
 
1058
  fontIDs = NULL;
 
1059
  fontFileIDs = NULL;
 
1060
  fontFileNames = NULL;
 
1061
  font8Info = NULL;
 
1062
  font16Enc = NULL;
 
1063
  imgIDs = NULL;
 
1064
  formIDs = NULL;
 
1065
  xobjStack = NULL;
 
1066
  embFontList = NULL;
 
1067
  customColors = NULL;
 
1068
  haveTextClip = gFalse;
 
1069
  haveCSPattern = gFalse;
 
1070
  t3String = NULL;
 
1071
 
 
1072
  forceRasterize = forceRasterizeA;
 
1073
 
 
1074
  init(outputFuncA, outputStreamA, psGeneric, psTitle,
 
1075
       doc, xrefA, catalog, firstPage, lastPage, modeA,
 
1076
       imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA,
 
1077
       paperWidthA, paperHeightA, duplexA);
 
1078
}
 
1079
 
 
1080
void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
 
1081
                       PSFileType fileTypeA, char *pstitle, PDFDoc *doc, XRef *xrefA, Catalog *catalog,
 
1082
                       int firstPage, int lastPage, PSOutMode modeA,
 
1083
                       int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
 
1084
                       GBool manualCtrlA, int paperWidthA, int paperHeightA,
 
1085
                       GBool duplexA) {
 
1086
  PDFRectangle *box;
 
1087
 
 
1088
  // initialize
 
1089
  displayText = gTrue;
 
1090
  ok = gTrue;
 
1091
  outputFunc = outputFuncA;
 
1092
  outputStream = outputStreamA;
 
1093
  fileType = fileTypeA;
 
1094
  m_catalog = catalog;
 
1095
  xref = xrefA;
 
1096
  level = globalParams->getPSLevel();
 
1097
  mode = modeA;
 
1098
  paperWidth = paperWidthA;
 
1099
  paperHeight = paperHeightA;
 
1100
  imgLLX = imgLLXA;
 
1101
  imgLLY = imgLLYA;
 
1102
  imgURX = imgURXA;
 
1103
  imgURY = imgURYA;
 
1104
  if (paperWidth < 0 || paperHeight < 0) {
 
1105
    Page *page;
 
1106
    if ((page = doc->getPage(firstPage))) {
 
1107
      paperWidth = (int)ceil(page->getMediaWidth());
 
1108
      paperHeight = (int)ceil(page->getMediaHeight());
 
1109
    } else {
 
1110
      error(-1, "Invalid page %d", firstPage);
 
1111
      paperWidth = 1;
 
1112
      paperHeight = 1;
 
1113
    }
 
1114
  }
 
1115
  substFonts = globalParams->getPSSubstFonts();
 
1116
  preload = globalParams->getPSPreload();
 
1117
  if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
 
1118
    imgLLX = imgLLY = 0;
 
1119
    imgURX = paperWidth;
 
1120
    imgURY = paperHeight;
 
1121
  }
 
1122
  if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
 
1123
    imgLLX = imgLLY = 0;
 
1124
    imgURX = paperWidth;
 
1125
    imgURY = paperHeight;
 
1126
  }
 
1127
  manualCtrl = manualCtrlA;
 
1128
  if (mode == psModeForm) {
 
1129
    lastPage = firstPage;
 
1130
  }
 
1131
  processColors = 0;
 
1132
  inType3Char = gFalse;
 
1133
 
 
1134
#if OPI_SUPPORT
 
1135
  // initialize OPI nesting levels
 
1136
  opi13Nest = 0;
 
1137
  opi20Nest = 0;
 
1138
#endif
 
1139
 
 
1140
  tx0 = ty0 = -1;
 
1141
  xScale0 = yScale0 = 0;
 
1142
  rotate0 = -1;
 
1143
  clipLLX0 = clipLLY0 = 0;
 
1144
  clipURX0 = clipURY0 = -1;
 
1145
 
 
1146
  // initialize fontIDs, fontFileIDs, and fontFileNames lists
 
1147
  fontIDSize = 64;
 
1148
  fontIDLen = 0;
 
1149
  fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
 
1150
  fontFileIDSize = 64;
 
1151
  fontFileIDLen = 0;
 
1152
  fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
 
1153
  fontFileNameSize = 64;
 
1154
  fontFileNameLen = 0;
 
1155
  fontFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
 
1156
  psFileNames = (GooString **)gmallocn(fontFileNameSize, sizeof(GooString *));
 
1157
  nextTrueTypeNum = 0;
 
1158
  font8InfoLen = 0;
 
1159
  font8InfoSize = 0;
 
1160
  font16EncLen = 0;
 
1161
  font16EncSize = 0;
 
1162
  imgIDLen = 0;
 
1163
  imgIDSize = 0;
 
1164
  formIDLen = 0;
 
1165
  formIDSize = 0;
 
1166
 
 
1167
  xobjStack = new GooList();
 
1168
  numSaves = 0;
 
1169
  numTilingPatterns = 0;
 
1170
  nextFunc = 0;
 
1171
 
 
1172
  // initialize embedded font resource comment list
 
1173
  embFontList = new GooString();
 
1174
 
 
1175
  if (!manualCtrl) {
 
1176
    Page *page;
 
1177
    // this check is needed in case the document has zero pages
 
1178
    if ((page = doc->getPage(firstPage))) {
 
1179
      writeHeader(firstPage, lastPage,
 
1180
                  page->getMediaBox(),
 
1181
                  page->getCropBox(),
 
1182
                  page->getRotate(),
 
1183
                  pstitle);
 
1184
    } else {
 
1185
      error(-1, "Invalid page %d", firstPage);
 
1186
      box = new PDFRectangle(0, 0, 1, 1);
 
1187
      writeHeader(firstPage, lastPage, box, box, 0, pstitle);
 
1188
      delete box;
 
1189
    }
 
1190
    if (mode != psModeForm) {
 
1191
      writePS("%%BeginProlog\n");
 
1192
    }
 
1193
    writeXpdfProcset();
 
1194
    if (mode != psModeForm) {
 
1195
      writePS("%%EndProlog\n");
 
1196
      writePS("%%BeginSetup\n");
 
1197
    }
 
1198
    writeDocSetup(doc, catalog, firstPage, lastPage, duplexA);
 
1199
    if (mode != psModeForm) {
 
1200
      writePS("%%EndSetup\n");
 
1201
    }
 
1202
  }
 
1203
 
 
1204
  // initialize sequential page number
 
1205
  seqPage = 1;
 
1206
}
 
1207
 
 
1208
PSOutputDev::~PSOutputDev() {
 
1209
  PSOutCustomColor *cc;
 
1210
  int i;
 
1211
 
 
1212
  if (ok) {
 
1213
    if (!manualCtrl) {
 
1214
      writePS("%%Trailer\n");
 
1215
      writeTrailer();
 
1216
      if (mode != psModeForm) {
 
1217
        writePS("%%EOF\n");
 
1218
      }
 
1219
    }
 
1220
    if (fileType == psFile) {
 
1221
#ifdef MACOS
 
1222
      ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
 
1223
#endif
 
1224
      fclose((FILE *)outputStream);
 
1225
    }
 
1226
#ifdef HAVE_POPEN
 
1227
    else if (fileType == psPipe) {
 
1228
      pclose((FILE *)outputStream);
 
1229
#ifndef _WIN32
 
1230
      signal(SIGPIPE, (SignalFunc)SIG_DFL);
 
1231
#endif
 
1232
    }
 
1233
#endif
 
1234
  }
 
1235
  if (embFontList) {
 
1236
    delete embFontList;
 
1237
  }
 
1238
  if (fontIDs) {
 
1239
    gfree(fontIDs);
 
1240
  }
 
1241
  if (fontFileIDs) {
 
1242
    gfree(fontFileIDs);
 
1243
  }
 
1244
  if (fontFileNames) {
 
1245
    for (i = 0; i < fontFileNameLen; ++i) {
 
1246
      delete fontFileNames[i];
 
1247
    }
 
1248
    gfree(fontFileNames);
 
1249
  }
 
1250
  if (font8Info) {
 
1251
    for (i = 0; i < font8InfoLen; ++i) {
 
1252
      gfree(font8Info[i].codeToGID);
 
1253
    }
 
1254
    gfree(font8Info);
 
1255
  }
 
1256
  if (psFileNames) {
 
1257
    for (i = 0; i < fontFileNameLen; ++i) {
 
1258
      if (psFileNames[i])
 
1259
        delete psFileNames[i];
 
1260
    }
 
1261
    gfree(psFileNames);
 
1262
  }
 
1263
  if (font16Enc) {
 
1264
    for (i = 0; i < font16EncLen; ++i) {
 
1265
      delete font16Enc[i].enc;
 
1266
    }
 
1267
    gfree(font16Enc);
 
1268
  }
 
1269
  gfree(imgIDs);
 
1270
  gfree(formIDs);
 
1271
  if (xobjStack) {
 
1272
    delete xobjStack;
 
1273
  }
 
1274
  while (customColors) {
 
1275
    cc = customColors;
 
1276
    customColors = cc->next;
 
1277
    delete cc;
 
1278
  }
 
1279
}
 
1280
 
 
1281
void PSOutputDev::writeHeader(int firstPage, int lastPage,
 
1282
                              PDFRectangle *mediaBox, PDFRectangle *cropBox,
 
1283
                              int pageRotate, char *psTitle) {
 
1284
  double x1, y1, x2, y2;
 
1285
  Object info, obj1;
 
1286
 
 
1287
  switch (mode) {
 
1288
  case psModePSOrigPageSizes:
 
1289
  case psModePS:
 
1290
    writePS("%!PS-Adobe-3.0\n");
 
1291
    break;
 
1292
  case psModeEPS:
 
1293
    writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
 
1294
    break;
 
1295
  case psModeForm:
 
1296
    writePS("%!PS-Adobe-3.0 Resource-Form\n");
 
1297
    break;
 
1298
  }
 
1299
  xref->getDocInfo(&info);
 
1300
  if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
 
1301
    writePS("%%Creator: ");
 
1302
    writePSTextLine(obj1.getString());
 
1303
  }
 
1304
  obj1.free();
 
1305
  info.free();
 
1306
  if(psTitle) {
 
1307
    writePSFmt("%%Title: {0:s}\n", psTitle);
 
1308
  }
 
1309
  writePSFmt("%%LanguageLevel: {0:d}\n",
 
1310
             (level == psLevel1 || level == psLevel1Sep) ? 1 :
 
1311
             (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
 
1312
  if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
 
1313
    writePS("%%DocumentProcessColors: (atend)\n");
 
1314
    writePS("%%DocumentCustomColors: (atend)\n");
 
1315
  }
 
1316
  writePS("%%DocumentSuppliedResources: (atend)\n");
 
1317
 
 
1318
  switch (mode) {
 
1319
  case psModePSOrigPageSizes:
 
1320
    prevWidth = 0;
 
1321
    prevHeight = 0;
 
1322
  case psModePS:
 
1323
    writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
 
1324
               paperWidth, paperHeight);
 
1325
    writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
 
1326
    writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
 
1327
    writePS("%%EndComments\n");
 
1328
    writePS("%%BeginDefaults\n");
 
1329
    writePS("%%PageMedia: plain\n");
 
1330
    writePS("%%EndDefaults\n");
 
1331
    break;
 
1332
  case psModeEPS:
 
1333
    epsX1 = cropBox->x1;
 
1334
    epsY1 = cropBox->y1;
 
1335
    epsX2 = cropBox->x2;
 
1336
    epsY2 = cropBox->y2;
 
1337
    if (pageRotate == 0 || pageRotate == 180) {
 
1338
      x1 = epsX1;
 
1339
      y1 = epsY1;
 
1340
      x2 = epsX2;
 
1341
      y2 = epsY2;
 
1342
    } else { // pageRotate == 90 || pageRotate == 270
 
1343
      x1 = 0;
 
1344
      y1 = 0;
 
1345
      x2 = epsY2 - epsY1;
 
1346
      y2 = epsX2 - epsX1;
 
1347
    }
 
1348
    writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
 
1349
               (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
 
1350
    if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) ||
 
1351
        floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) {
 
1352
      writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 
1353
                 x1, y1, x2, y2);
 
1354
    }
 
1355
    writePS("%%DocumentSuppliedResources: (atend)\n");
 
1356
    writePS("%%EndComments\n");
 
1357
    break;
 
1358
  case psModeForm:
 
1359
    writePS("%%EndComments\n");
 
1360
    writePS("32 dict dup begin\n");
 
1361
    writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n",
 
1362
               (int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
 
1363
               (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
 
1364
    writePS("/FormType 1 def\n");
 
1365
    writePS("/Matrix [1 0 0 1 0 0] def\n");
 
1366
    break;
 
1367
  }
 
1368
}
 
1369
 
 
1370
void PSOutputDev::writeXpdfProcset() {
 
1371
  GBool lev1, lev2, lev3, sep, nonSep;
 
1372
  char **p;
 
1373
  char *q;
 
1374
 
 
1375
  writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", "3.00");
 
1376
  writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
 
1377
  lev1 = lev2 = lev3 = sep = nonSep = gTrue;
 
1378
  for (p = prolog; *p; ++p) {
 
1379
    if ((*p)[0] == '~') {
 
1380
      lev1 = lev2 = lev3 = sep = nonSep = gFalse;
 
1381
      for (q = *p + 1; *q; ++q) {
 
1382
        switch (*q) {
 
1383
        case '1': lev1 = gTrue; break;
 
1384
        case '2': lev2 = gTrue; break;
 
1385
        case '3': lev3 = gTrue; break;
 
1386
        case 's': sep = gTrue; break;
 
1387
        case 'n': nonSep = gTrue; break;
 
1388
        }
 
1389
      }
 
1390
    } else if ((level == psLevel1 && lev1 && nonSep) ||
 
1391
               (level == psLevel1Sep && lev1 && sep) ||
 
1392
               (level == psLevel2 && lev2 && nonSep) ||
 
1393
               (level == psLevel2Sep && lev2 && sep) ||
 
1394
               (level == psLevel3 && lev3 && nonSep) ||
 
1395
               (level == psLevel3Sep && lev3 && sep)) {
 
1396
      writePSFmt("{0:s}\n", *p);
 
1397
    }
 
1398
  }
 
1399
  writePS("%%EndResource\n");
 
1400
 
 
1401
  if (level >= psLevel3) {
 
1402
    for (p = cmapProlog; *p; ++p) {
 
1403
      writePSFmt("{0:s}\n", *p);
 
1404
    }
 
1405
  }
 
1406
}
 
1407
 
 
1408
void PSOutputDev::writeDocSetup(PDFDoc *doc, Catalog *catalog,
 
1409
                                int firstPage, int lastPage,
 
1410
                                GBool duplexA) {
 
1411
  Page *page;
 
1412
  Dict *resDict;
 
1413
  Annots *annots;
 
1414
  Object obj1, obj2;
 
1415
  int pg, i;
 
1416
 
 
1417
  if (mode == psModeForm) {
 
1418
    // swap the form and xpdf dicts
 
1419
    writePS("xpdf end begin dup begin\n");
 
1420
  } else {
 
1421
    writePS("xpdf begin\n");
 
1422
  }
 
1423
  for (pg = firstPage; pg <= lastPage; ++pg) {
 
1424
    page = doc->getPage(pg);
 
1425
    if (!page) {
 
1426
      error(-1, "Failed writing resources for page %d", pg);
 
1427
      continue;
 
1428
    }
 
1429
    if ((resDict = page->getResourceDict())) {
 
1430
      setupResources(resDict);
 
1431
    }
 
1432
    annots = new Annots(xref, catalog, page->getAnnots(&obj1));
 
1433
    obj1.free();
 
1434
    for (i = 0; i < annots->getNumAnnots(); ++i) {
 
1435
      if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
 
1436
        obj1.streamGetDict()->lookup("Resources", &obj2);
 
1437
        if (obj2.isDict()) {
 
1438
          setupResources(obj2.getDict());
 
1439
        }
 
1440
        obj2.free();
 
1441
      }
 
1442
      obj1.free();
 
1443
    }
 
1444
    delete annots;
 
1445
  }
 
1446
  if (mode != psModeForm) {
 
1447
    if (mode != psModeEPS && !manualCtrl) {
 
1448
      writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
 
1449
                 paperWidth, paperHeight, duplexA ? "true" : "false");
 
1450
    }
 
1451
#if OPI_SUPPORT
 
1452
    if (globalParams->getPSOPI()) {
 
1453
      writePS("/opiMatrix matrix currentmatrix def\n");
 
1454
    }
 
1455
#endif
 
1456
  }
 
1457
}
 
1458
 
 
1459
void PSOutputDev::writePageTrailer() {
 
1460
  if (mode != psModeForm) {
 
1461
    writePS("pdfEndPage\n");
 
1462
  }
 
1463
}
 
1464
 
 
1465
void PSOutputDev::writeTrailer() {
 
1466
  PSOutCustomColor *cc;
 
1467
 
 
1468
  if (mode == psModeForm) {
 
1469
    writePS("/Foo exch /Form defineresource pop\n");
 
1470
  } else {
 
1471
    writePS("end\n");
 
1472
    writePS("%%DocumentSuppliedResources:\n");
 
1473
    writePS(embFontList->getCString());
 
1474
    if (level == psLevel1Sep || level == psLevel2Sep ||
 
1475
        level == psLevel3Sep) {
 
1476
      writePS("%%DocumentProcessColors:");
 
1477
      if (processColors & psProcessCyan) {
 
1478
        writePS(" Cyan");
 
1479
         }
 
1480
      if (processColors & psProcessMagenta) {
 
1481
        writePS(" Magenta");
 
1482
      }
 
1483
      if (processColors & psProcessYellow) {
 
1484
        writePS(" Yellow");
 
1485
      }
 
1486
      if (processColors & psProcessBlack) {
 
1487
        writePS(" Black");
 
1488
      }
 
1489
      writePS("\n");
 
1490
      writePS("%%DocumentCustomColors:");
 
1491
      for (cc = customColors; cc; cc = cc->next) {
 
1492
        writePSFmt(" ({0:s})", cc->name->getCString());
 
1493
      }
 
1494
      writePS("\n");
 
1495
      writePS("%%CMYKCustomColor:\n");
 
1496
      for (cc = customColors; cc; cc = cc->next) {
 
1497
        writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t})\n",
 
1498
                   cc->c, cc->m, cc->y, cc->k, cc->name);
 
1499
      }
 
1500
    }
 
1501
  }
 
1502
}
 
1503
 
 
1504
void PSOutputDev::setupResources(Dict *resDict) {
 
1505
  Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
 
1506
  Ref ref0, ref1;
 
1507
  GBool skip;
 
1508
  int i, j;
 
1509
 
 
1510
  setupFonts(resDict);
 
1511
  setupImages(resDict);
 
1512
  setupForms(resDict);
 
1513
 
 
1514
  //----- recursively scan XObjects
 
1515
  resDict->lookup("XObject", &xObjDict);
 
1516
  if (xObjDict.isDict()) {
 
1517
    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
 
1518
 
 
1519
      // avoid infinite recursion on XObjects
 
1520
      skip = gFalse;
 
1521
      if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
 
1522
        ref0 = xObjRef.getRef();
 
1523
        for (j = 0; j < xobjStack->getLength(); ++j) {
 
1524
          ref1 = *(Ref *)xobjStack->get(j);
 
1525
          if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
 
1526
            skip = gTrue;
 
1527
            break;
 
1528
          }
 
1529
        }
 
1530
        if (!skip) {
 
1531
          xobjStack->append(&ref0);
 
1532
        }
 
1533
      }
 
1534
      if (!skip) {
 
1535
 
 
1536
        // process the XObject's resource dictionary
 
1537
        xObjDict.dictGetVal(i, &xObj);
 
1538
        if (xObj.isStream()) {
 
1539
          xObj.streamGetDict()->lookup("Resources", &resObj);
 
1540
          if (resObj.isDict()) {
 
1541
            setupResources(resObj.getDict());
 
1542
          }
 
1543
          resObj.free();
 
1544
        }
 
1545
        xObj.free();
 
1546
      }
 
1547
 
 
1548
      if (xObjRef.isRef() && !skip) {
 
1549
        xobjStack->del(xobjStack->getLength() - 1);
 
1550
      }
 
1551
      xObjRef.free();
 
1552
    }
 
1553
  }
 
1554
  xObjDict.free();
 
1555
 
 
1556
  //----- recursively scan Patterns
 
1557
  resDict->lookup("Pattern", &patDict);
 
1558
  if (patDict.isDict()) {
 
1559
    inType3Char = gTrue;
 
1560
    for (i = 0; i < patDict.dictGetLength(); ++i) {
 
1561
 
 
1562
      // avoid infinite recursion on Patterns
 
1563
      skip = gFalse;
 
1564
      if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
 
1565
        ref0 = patRef.getRef();
 
1566
        for (j = 0; j < xobjStack->getLength(); ++j) {
 
1567
          ref1 = *(Ref *)xobjStack->get(j);
 
1568
          if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
 
1569
            skip = gTrue;
 
1570
            break;
 
1571
          }
 
1572
        }
 
1573
        if (!skip) {
 
1574
          xobjStack->append(&ref0);
 
1575
        }
 
1576
      }
 
1577
      if (!skip) {
 
1578
 
 
1579
        // process the Pattern's resource dictionary
 
1580
        patDict.dictGetVal(i, &pat);
 
1581
        if (pat.isStream()) {
 
1582
          pat.streamGetDict()->lookup("Resources", &resObj);
 
1583
          if (resObj.isDict()) {
 
1584
            setupResources(resObj.getDict());
 
1585
          }
 
1586
          resObj.free();
 
1587
        }
 
1588
        pat.free();
 
1589
      }
 
1590
 
 
1591
      if (patRef.isRef() && !skip) {
 
1592
        xobjStack->del(xobjStack->getLength() - 1);
 
1593
      }
 
1594
      patRef.free();
 
1595
    }
 
1596
    inType3Char = gFalse;
 
1597
  }
 
1598
  patDict.free();
 
1599
}
 
1600
 
 
1601
void PSOutputDev::setupFonts(Dict *resDict) {
 
1602
  Object obj1, obj2;
 
1603
  Ref r;
 
1604
  GfxFontDict *gfxFontDict;
 
1605
  GfxFont *font;
 
1606
  int i;
 
1607
 
 
1608
  if (forceRasterize) return;
 
1609
 
 
1610
  gfxFontDict = NULL;
 
1611
  resDict->lookupNF("Font", &obj1);
 
1612
  if (obj1.isRef()) {
 
1613
    obj1.fetch(xref, &obj2);
 
1614
    if (obj2.isDict()) {
 
1615
      r = obj1.getRef();
 
1616
      gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
 
1617
    }
 
1618
    obj2.free();
 
1619
  } else if (obj1.isDict()) {
 
1620
    gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
 
1621
  }
 
1622
  if (gfxFontDict) {
 
1623
    for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
 
1624
      if ((font = gfxFontDict->getFont(i))) {
 
1625
        setupFont(font, resDict);
 
1626
      }
 
1627
    }
 
1628
    delete gfxFontDict;
 
1629
  }
 
1630
  obj1.free();
 
1631
}
 
1632
 
 
1633
void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
1634
  Ref fontFileID;
 
1635
  GooString *name;
 
1636
  PSFontParam *fontParam;
 
1637
  GooString *psName;
 
1638
  char buf[16];
 
1639
  GBool subst;
 
1640
  UnicodeMap *uMap;
 
1641
  char *charName;
 
1642
  double xs, ys;
 
1643
  int code;
 
1644
  double w1, w2;
 
1645
  double *fm;
 
1646
  int i, j;
 
1647
  DisplayFontParam *dfp;
 
1648
 
 
1649
  // check if font is already set up
 
1650
  for (i = 0; i < fontIDLen; ++i) {
 
1651
    if (fontIDs[i].num == font->getID()->num &&
 
1652
        fontIDs[i].gen == font->getID()->gen) {
 
1653
      return;
 
1654
    }
 
1655
  }
 
1656
 
 
1657
  // add entry to fontIDs list
 
1658
  if (fontIDLen >= fontIDSize) {
 
1659
    fontIDSize += 64;
 
1660
    fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref));
 
1661
  }
 
1662
  fontIDs[fontIDLen++] = *font->getID();
 
1663
 
 
1664
  xs = ys = 1;
 
1665
  subst = gFalse;
 
1666
 
 
1667
  // check for resident 8-bit font
 
1668
  if (font->getName() &&
 
1669
      (fontParam = globalParams->getPSFont(font->getName()))) {
 
1670
    psName = new GooString(fontParam->psFontName->getCString());
 
1671
 
 
1672
  // check for embedded Type 1 font
 
1673
  } else if (globalParams->getPSEmbedType1() &&
 
1674
             font->getType() == fontType1 &&
 
1675
             font->getEmbeddedFontID(&fontFileID) &&
 
1676
             font->getEmbeddedFontName()) {
 
1677
    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
 
1678
    setupEmbeddedType1Font(&fontFileID, psName);
 
1679
 
 
1680
  // check for embedded Type 1C font
 
1681
  } else if (globalParams->getPSEmbedType1() &&
 
1682
             font->getType() == fontType1C &&
 
1683
             font->getEmbeddedFontID(&fontFileID) &&
 
1684
             font->getOrigName()) {
 
1685
    // use the PDF font name because the embedded font name might
 
1686
    // not include the subset prefix
 
1687
    psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
 
1688
    setupEmbeddedType1CFont(font, &fontFileID, psName);
 
1689
 
 
1690
  // check for embedded OpenType - Type 1C font
 
1691
  } else if (globalParams->getPSEmbedType1() &&
 
1692
             font->getType() == fontType1COT &&
 
1693
             font->getEmbeddedFontID(&fontFileID) &&
 
1694
             font->getOrigName()) {
 
1695
    // use the PDF font name because the embedded font name might
 
1696
    // not include the subset prefix
 
1697
    psName = font->getOrigName()->sanitizedName(gTrue /* ps mode */);
 
1698
    setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
 
1699
 
 
1700
  // check for external Type 1 font file
 
1701
  } else if (globalParams->getPSEmbedType1() &&
 
1702
             font->getType() == fontType1 &&
 
1703
             font->getExtFontFile() &&
 
1704
             font->getName()) {
 
1705
    // this assumes that the PS font name matches the PDF font name
 
1706
    psName = font->getName()->copy();
 
1707
    setupExternalType1Font(font->getExtFontFile(), psName);
 
1708
 
 
1709
  // check for embedded TrueType font
 
1710
  } else if (globalParams->getPSEmbedTrueType() &&
 
1711
             (font->getType() == fontTrueType ||
 
1712
              font->getType() == fontTrueTypeOT) &&
 
1713
             font->getEmbeddedFontID(&fontFileID) &&
 
1714
             font->getEmbeddedFontName()) {
 
1715
    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
 
1716
    setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
 
1717
 
 
1718
  // check for external TrueType font file
 
1719
  } else if (globalParams->getPSEmbedTrueType() &&
 
1720
             font->getType() == fontTrueType &&
 
1721
             font->getExtFontFile()) {
 
1722
    psName = setupExternalTrueTypeFont(font);
 
1723
 
 
1724
  // check for embedded CID PostScript font
 
1725
  } else if (globalParams->getPSEmbedCIDPostScript() &&
 
1726
             font->getType() == fontCIDType0C &&
 
1727
             font->getEmbeddedFontID(&fontFileID) &&
 
1728
             font->getEmbeddedFontName()) {
 
1729
    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
 
1730
    setupEmbeddedCIDType0Font(font, &fontFileID, psName);
 
1731
 
 
1732
  // check for embedded CID TrueType font
 
1733
  } else if (globalParams->getPSEmbedCIDTrueType() &&
 
1734
             (font->getType() == fontCIDType2 ||
 
1735
              font->getType() == fontCIDType2OT) &&
 
1736
             font->getEmbeddedFontID(&fontFileID) &&
 
1737
             font->getEmbeddedFontName()) {
 
1738
    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
 
1739
    setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
 
1740
 
 
1741
  // check for embedded OpenType - CID CFF font
 
1742
  } else if (globalParams->getPSEmbedCIDPostScript() &&
 
1743
             font->getType() == fontCIDType0COT &&
 
1744
             font->getEmbeddedFontID(&fontFileID) &&
 
1745
             font->getEmbeddedFontName()) {
 
1746
    psName = font->getEmbeddedFontName()->sanitizedName(gTrue /* ps mode */);
 
1747
    setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
 
1748
 
 
1749
  // check for Type 3 font
 
1750
  } else if (font->getType() == fontType3) {
 
1751
    psName = GooString::format("T3_{0:d}_{1:d}",
 
1752
                             font->getID()->num, font->getID()->gen);
 
1753
    setupType3Font(font, psName, parentResDict);
 
1754
 
 
1755
  // check for external CID TrueType font file
 
1756
  } else if (globalParams->getPSEmbedCIDTrueType() &&
 
1757
             font->getType() == fontCIDType2 &&
 
1758
             font->getExtFontFile()) {
 
1759
    psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile());
 
1760
 
 
1761
  // do 8-bit font substitution
 
1762
  } else if (!font->isCIDFont()) {
 
1763
    subst = gTrue;
 
1764
    name = font->getName();
 
1765
    psName = NULL;
 
1766
    if (name) {
 
1767
      for (i = 0; psFonts[i]; ++i) {
 
1768
        if (name->cmp(psFonts[i]) == 0) {
 
1769
          psName = new GooString(psFonts[i]);
 
1770
          break;
 
1771
        }
 
1772
      }
 
1773
    }
 
1774
    if (!psName) {
 
1775
      if (substFonts) {
 
1776
        if (font->isFixedWidth()) {
 
1777
          i = 8;
 
1778
        } else if (font->isSerif()) {
 
1779
          i = 4;
 
1780
        } else {
 
1781
          i = 0;
 
1782
        }
 
1783
        if (font->isBold()) {
 
1784
          i += 2;
 
1785
        }
 
1786
        if (font->isItalic()) {
 
1787
          i += 1;
 
1788
        }
 
1789
        psName = new GooString(psSubstFonts[i].psName);
 
1790
        for (code = 0; code < 256; ++code) {
 
1791
          if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
 
1792
              charName[0] == 'm' && charName[1] == '\0') {
 
1793
            break;
 
1794
          }
 
1795
        }
 
1796
        if (code < 256) {
 
1797
          w1 = ((Gfx8BitFont *)font)->getWidth(code);
 
1798
        } else {
 
1799
          w1 = 0;
 
1800
        }
 
1801
        w2 = psSubstFonts[i].mWidth;
 
1802
        xs = w1 / w2;
 
1803
        if (xs < 0.1) {
 
1804
          xs = 1;
 
1805
        }
 
1806
      } else {
 
1807
        psName = new GooString(name);
 
1808
        xs = 1;
 
1809
      }
 
1810
      if (font->getType() == fontType3) {
 
1811
        // This is a hack which makes it possible to substitute for some
 
1812
        // Type 3 fonts.  The problem is that it's impossible to know what
 
1813
        // the base coordinate system used in the font is without actually
 
1814
        // rendering the font.
 
1815
        ys = xs;
 
1816
        fm = font->getFontMatrix();
 
1817
        if (fm[0] != 0) {
 
1818
          ys *= fm[3] / fm[0];
 
1819
        }
 
1820
      } else {
 
1821
        ys = 1;
 
1822
      }
 
1823
    }
 
1824
 
 
1825
  // do 16-bit font substitution
 
1826
  } else if ((fontParam = globalParams->
 
1827
                getPSFont16(font->getName(),
 
1828
                            ((GfxCIDFont *)font)->getCollection(),
 
1829
                            font->getWMode()))) {
 
1830
    subst = gTrue;
 
1831
    psName = fontParam->psFontName->copy();
 
1832
    if (font16EncLen >= font16EncSize) {
 
1833
      font16EncSize += 16;
 
1834
      font16Enc = (PSFont16Enc *)greallocn(font16Enc,
 
1835
                                           font16EncSize, sizeof(PSFont16Enc));
 
1836
    }
 
1837
    font16Enc[font16EncLen].fontID = *font->getID();
 
1838
    font16Enc[font16EncLen].enc = fontParam->encoding->copy();
 
1839
    if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
 
1840
      uMap->decRefCnt();
 
1841
      ++font16EncLen;
 
1842
    } else {
 
1843
      error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
 
1844
            font16Enc[font16EncLen].enc->getCString());
 
1845
    }
 
1846
 
 
1847
    // try the display font for embedding
 
1848
  } else if (globalParams->getPSEmbedCIDTrueType() &&
 
1849
             ((GfxCIDFont *)font)->getCollection() &&
 
1850
             (dfp = globalParams->
 
1851
              getDisplayFont(font)) &&
 
1852
             dfp->kind == displayFontTT) {
 
1853
    psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex);
 
1854
 
 
1855
  // give up - can't do anything with this font
 
1856
  } else {
 
1857
    error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
 
1858
          font->getName() ? font->getName()->getCString() : "(unnamed)",
 
1859
          ((GfxCIDFont *)font)->getCollection()
 
1860
            ? ((GfxCIDFont *)font)->getCollection()->getCString()
 
1861
            : "(unknown)");
 
1862
    return;
 
1863
  }
 
1864
 
 
1865
  // generate PostScript code to set up the font
 
1866
  if (font->isCIDFont()) {
 
1867
    if (level == psLevel3 || level == psLevel3Sep) {
 
1868
      writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
 
1869
                 font->getID()->num, font->getID()->gen, psName,
 
1870
                 font->getWMode());
 
1871
    } else {
 
1872
      writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n",
 
1873
                 font->getID()->num, font->getID()->gen, psName,
 
1874
                 font->getWMode());
 
1875
    }
 
1876
  } else {
 
1877
    writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.6g} {4:.6g}\n",
 
1878
               font->getID()->num, font->getID()->gen, psName, xs, ys);
 
1879
    for (i = 0; i < 256; i += 8) {
 
1880
      writePS((char *)((i == 0) ? "[ " : "  "));
 
1881
      for (j = 0; j < 8; ++j) {
 
1882
        if (font->getType() == fontTrueType &&
 
1883
            !subst &&
 
1884
            !((Gfx8BitFont *)font)->getHasEncoding()) {
 
1885
          sprintf(buf, "c%02x", i+j);
 
1886
          charName = buf;
 
1887
        } else {
 
1888
          charName = ((Gfx8BitFont *)font)->getCharName(i+j);
 
1889
          // this is a kludge for broken PDF files that encode char 32
 
1890
          // as .notdef
 
1891
          if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
 
1892
            charName = "space";
 
1893
          }
 
1894
        }
 
1895
        writePS("/");
 
1896
        writePSName(charName ? charName : (char *)".notdef");
 
1897
        // the empty name is legal in PDF and PostScript, but PostScript
 
1898
        // uses a double-slash (//...) for "immediately evaluated names",
 
1899
        // so we need to add a space character here
 
1900
        if (charName && !charName[0]) {
 
1901
          writePS(" ");
 
1902
        }
 
1903
      }
 
1904
      writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
 
1905
    }
 
1906
    writePS("pdfMakeFont\n");
 
1907
  }
 
1908
 
 
1909
  delete psName;
 
1910
}
 
1911
 
 
1912
void PSOutputDev::setupEmbeddedType1Font(Ref *id, GooString *psName) {
 
1913
  static const char hexChar[17] = "0123456789abcdef";
 
1914
  Object refObj, strObj, obj1, obj2, obj3;
 
1915
  Dict *dict;
 
1916
  int length1, length2, length3;
 
1917
  int c;
 
1918
  int start[4];
 
1919
  GBool binMode;
 
1920
  GBool writePadding = gTrue;
 
1921
  int i;
 
1922
 
 
1923
  // check if font is already embedded
 
1924
  for (i = 0; i < fontFileIDLen; ++i) {
 
1925
    if (fontFileIDs[i].num == id->num &&
 
1926
        fontFileIDs[i].gen == id->gen)
 
1927
      return;
 
1928
  }
 
1929
 
 
1930
  // add entry to fontFileIDs list
 
1931
  if (fontFileIDLen >= fontFileIDSize) {
 
1932
    fontFileIDSize += 64;
 
1933
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
1934
  }
 
1935
  fontFileIDs[fontFileIDLen++] = *id;
 
1936
 
 
1937
  // get the font stream and info
 
1938
  refObj.initRef(id->num, id->gen);
 
1939
  refObj.fetch(xref, &strObj);
 
1940
  refObj.free();
 
1941
  if (!strObj.isStream()) {
 
1942
    error(-1, "Embedded font file object is not a stream");
 
1943
    goto err1;
 
1944
  }
 
1945
  if (!(dict = strObj.streamGetDict())) {
 
1946
    error(-1, "Embedded font stream is missing its dictionary");
 
1947
    goto err1;
 
1948
  }
 
1949
  dict->lookup("Length1", &obj1);
 
1950
  dict->lookup("Length2", &obj2);
 
1951
  dict->lookup("Length3", &obj3);
 
1952
  if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
 
1953
    error(-1, "Missing length fields in embedded font stream dictionary");
 
1954
    obj1.free();
 
1955
    obj2.free();
 
1956
    obj3.free();
 
1957
    goto err1;
 
1958
  }
 
1959
  length1 = obj1.getInt();
 
1960
  length2 = obj2.getInt();
 
1961
  length3 = obj3.getInt();
 
1962
  obj1.free();
 
1963
  obj2.free();
 
1964
  obj3.free();
 
1965
 
 
1966
  // beginning comment
 
1967
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
1968
  embFontList->append("%%+ font ");
 
1969
  embFontList->append(psName->getCString());
 
1970
  embFontList->append("\n");
 
1971
 
 
1972
  // copy ASCII portion of font
 
1973
  strObj.streamReset();
 
1974
  for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
 
1975
    writePSChar(c);
 
1976
  }
 
1977
 
 
1978
  // figure out if encrypted portion is binary or ASCII
 
1979
  binMode = gFalse;
 
1980
  for (i = 0; i < 4; ++i) {
 
1981
    start[i] = strObj.streamGetChar();
 
1982
    if (start[i] == EOF) {
 
1983
      error(-1, "Unexpected end of file in embedded font stream");
 
1984
      goto err1;
 
1985
    }
 
1986
    if (!((start[i] >= '0' && start[i] <= '9') ||
 
1987
          (start[i] >= 'A' && start[i] <= 'F') ||
 
1988
          (start[i] >= 'a' && start[i] <= 'f')))
 
1989
      binMode = gTrue;
 
1990
  }
 
1991
 
 
1992
  if (length2 == 0)
 
1993
  {
 
1994
    // length2 == 0 is an error
 
1995
    // trying to solve it by just piping all
 
1996
    // the stream data
 
1997
    error(-1, "Font has length2 as 0, trying to overcome the problem reading the stream until the end");
 
1998
    length2 = INT_MAX;
 
1999
    writePadding = gFalse;
 
2000
  }
 
2001
 
 
2002
 
 
2003
  // convert binary data to ASCII
 
2004
  if (binMode) {
 
2005
    for (i = 0; i < 4; ++i) {
 
2006
      writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
 
2007
      writePSChar(hexChar[start[i] & 0x0f]);
 
2008
    }
 
2009
#if 0 // this causes trouble for various PostScript printers
 
2010
    // if Length2 is incorrect (too small), font data gets chopped, so
 
2011
    // we take a few extra characters from the trailer just in case
 
2012
    length2 += length3 >= 8 ? 8 : length3;
 
2013
#endif
 
2014
    while (i < length2) {
 
2015
      if ((c = strObj.streamGetChar()) == EOF) {
 
2016
        break;
 
2017
      }
 
2018
      writePSChar(hexChar[(c >> 4) & 0x0f]);
 
2019
      writePSChar(hexChar[c & 0x0f]);
 
2020
      if (++i % 32 == 0) {
 
2021
        writePSChar('\n');
 
2022
      }
 
2023
    }
 
2024
    if (i % 32 > 0) {
 
2025
      writePSChar('\n');
 
2026
    }
 
2027
 
 
2028
  // already in ASCII format -- just copy it
 
2029
  } else {
 
2030
    for (i = 0; i < 4; ++i) {
 
2031
      writePSChar(start[i]);
 
2032
    }
 
2033
    for (i = 4; i < length2; ++i) {
 
2034
      if ((c = strObj.streamGetChar()) == EOF) {
 
2035
        break;
 
2036
      }
 
2037
      writePSChar(c);
 
2038
    }
 
2039
  }
 
2040
 
 
2041
  if (writePadding)
 
2042
  {
 
2043
    if (length3 > 0) {
 
2044
      // write fixed-content portion
 
2045
      while ((c = strObj.streamGetChar()) != EOF) {
 
2046
        writePSChar(c);
 
2047
      }
 
2048
    } else {
 
2049
      // write padding and "cleartomark"
 
2050
      for (i = 0; i < 8; ++i) {
 
2051
        writePS("00000000000000000000000000000000"
 
2052
                "00000000000000000000000000000000\n");
 
2053
      }
 
2054
      writePS("cleartomark\n");
 
2055
    }
 
2056
  }
 
2057
 
 
2058
  // ending comment
 
2059
  writePS("%%EndResource\n");
 
2060
 
 
2061
 err1:
 
2062
  strObj.streamClose();
 
2063
  strObj.free();
 
2064
}
 
2065
 
 
2066
//~ This doesn't handle .pfb files or binary eexec data (which only
 
2067
//~ happens in pfb files?).
 
2068
void PSOutputDev::setupExternalType1Font(GooString *fileName, GooString *psName) {
 
2069
  FILE *fontFile;
 
2070
  int c;
 
2071
  int i;
 
2072
 
 
2073
  // check if font is already embedded
 
2074
  for (i = 0; i < fontFileNameLen; ++i) {
 
2075
    if (!fontFileNames[i]->cmp(fileName)) {
 
2076
      return;
 
2077
    }
 
2078
  }
 
2079
 
 
2080
  // add entry to fontFileNames list
 
2081
  if (fontFileNameLen >= fontFileNameSize) {
 
2082
    fontFileNameSize += 64;
 
2083
    fontFileNames = (GooString **)greallocn(fontFileNames,
 
2084
                                          fontFileNameSize, sizeof(GooString *));
 
2085
    psFileNames = (GooString **)greallocn(psFileNames,
 
2086
                                       fontFileNameSize, sizeof(GooString *));
 
2087
  }
 
2088
  fontFileNames[fontFileNameLen] = fileName->copy();
 
2089
  psFileNames[fontFileNameLen] = psName->copy();
 
2090
  fontFileNameLen++;
 
2091
 
 
2092
  // beginning comment
 
2093
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2094
  embFontList->append("%%+ font ");
 
2095
  embFontList->append(psName->getCString());
 
2096
  embFontList->append("\n");
 
2097
 
 
2098
  // copy the font file
 
2099
  if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
 
2100
    error(-1, "Couldn't open external font file");
 
2101
    return;
 
2102
  }
 
2103
  while ((c = fgetc(fontFile)) != EOF) {
 
2104
    writePSChar(c);
 
2105
  }
 
2106
  fclose(fontFile);
 
2107
 
 
2108
  // ending comment
 
2109
  writePS("%%EndResource\n");
 
2110
}
 
2111
 
 
2112
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
 
2113
                                          GooString *psName) {
 
2114
  char *fontBuf;
 
2115
  int fontLen;
 
2116
  FoFiType1C *ffT1C;
 
2117
  int i;
 
2118
 
 
2119
  // check if font is already embedded
 
2120
  for (i = 0; i < fontFileIDLen; ++i) {
 
2121
    if (fontFileIDs[i].num == id->num &&
 
2122
        fontFileIDs[i].gen == id->gen)
 
2123
      return;
 
2124
  }
 
2125
 
 
2126
  // add entry to fontFileIDs list
 
2127
  if (fontFileIDLen >= fontFileIDSize) {
 
2128
    fontFileIDSize += 64;
 
2129
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2130
  }
 
2131
  fontFileIDs[fontFileIDLen++] = *id;
 
2132
 
 
2133
  // beginning comment
 
2134
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2135
  embFontList->append("%%+ font ");
 
2136
  embFontList->append(psName->getCString());
 
2137
  embFontList->append("\n");
 
2138
 
 
2139
  // convert it to a Type 1 font
 
2140
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2141
  if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
 
2142
    ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
 
2143
                          outputFunc, outputStream);
 
2144
    delete ffT1C;
 
2145
  }
 
2146
  gfree(fontBuf);
 
2147
 
 
2148
  // ending comment
 
2149
  writePS("%%EndResource\n");
 
2150
}
 
2151
 
 
2152
void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
 
2153
                                               GooString *psName) {
 
2154
  char *fontBuf;
 
2155
  int fontLen;
 
2156
  FoFiTrueType *ffTT;
 
2157
  int i;
 
2158
 
 
2159
  // check if font is already embedded
 
2160
  for (i = 0; i < fontFileIDLen; ++i) {
 
2161
    if (fontFileIDs[i].num == id->num &&
 
2162
        fontFileIDs[i].gen == id->gen)
 
2163
      return;
 
2164
  }
 
2165
 
 
2166
  // add entry to fontFileIDs list
 
2167
  if (fontFileIDLen >= fontFileIDSize) {
 
2168
    fontFileIDSize += 64;
 
2169
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2170
  }
 
2171
  fontFileIDs[fontFileIDLen++] = *id;
 
2172
 
 
2173
  // beginning comment
 
2174
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2175
  embFontList->append("%%+ font ");
 
2176
  embFontList->append(psName->getCString());
 
2177
  embFontList->append("\n");
 
2178
 
 
2179
  // convert it to a Type 1 font
 
2180
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2181
  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
 
2182
    if (ffTT->isOpenTypeCFF()) {
 
2183
      ffTT->convertToType1(psName->getCString(), NULL, gTrue,
 
2184
                           outputFunc, outputStream);
 
2185
    }
 
2186
    delete ffTT;
 
2187
  }
 
2188
  gfree(fontBuf);
 
2189
 
 
2190
  // ending comment
 
2191
  writePS("%%EndResource\n");
 
2192
}
 
2193
 
 
2194
void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
 
2195
                                            GooString *psName) {
 
2196
  char *fontBuf;
 
2197
  int fontLen;
 
2198
  FoFiTrueType *ffTT;
 
2199
  Gushort *codeToGID;
 
2200
  int i;
 
2201
 
 
2202
  // check if font is already embedded
 
2203
  for (i = 0; i < fontFileIDLen; ++i) {
 
2204
    if (fontFileIDs[i].num == id->num &&
 
2205
        fontFileIDs[i].gen == id->gen) {
 
2206
      psName->appendf("_{0:d}", nextTrueTypeNum++);
 
2207
      break;
 
2208
    }
 
2209
  }
 
2210
 
 
2211
  // add entry to fontFileIDs list
 
2212
  if (i == fontFileIDLen) {
 
2213
    if (fontFileIDLen >= fontFileIDSize) {
 
2214
      fontFileIDSize += 64;
 
2215
      fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2216
    }
 
2217
    fontFileIDs[fontFileIDLen++] = *id;
 
2218
  }
 
2219
 
 
2220
  // beginning comment
 
2221
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2222
  embFontList->append("%%+ font ");
 
2223
  embFontList->append(psName->getCString());
 
2224
  embFontList->append("\n");
 
2225
 
 
2226
  // convert it to a Type 42 font
 
2227
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2228
  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
 
2229
    codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
 
2230
    ffTT->convertToType42(psName->getCString(),
 
2231
                          ((Gfx8BitFont *)font)->getHasEncoding()
 
2232
                            ? ((Gfx8BitFont *)font)->getEncoding()
 
2233
                            : (char **)NULL,
 
2234
                          codeToGID, outputFunc, outputStream);
 
2235
    if (codeToGID) {
 
2236
      if (font8InfoLen >= font8InfoSize) {
 
2237
        font8InfoSize += 16;
 
2238
        font8Info = (PSFont8Info *)greallocn(font8Info,
 
2239
                                             font8InfoSize,
 
2240
                                             sizeof(PSFont8Info));
 
2241
      }
 
2242
      font8Info[font8InfoLen].fontID = *font->getID();
 
2243
      font8Info[font8InfoLen].codeToGID = codeToGID;
 
2244
      ++font8InfoLen;
 
2245
    }
 
2246
    delete ffTT;
 
2247
  }
 
2248
  gfree(fontBuf);
 
2249
 
 
2250
  // ending comment
 
2251
  writePS("%%EndResource\n");
 
2252
}
 
2253
 
 
2254
GooString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
 
2255
  GooString *fileName;
 
2256
  char *fontBuf;
 
2257
  int fontLen;
 
2258
  FoFiTrueType *ffTT;
 
2259
  Gushort *codeToGID;
 
2260
  GooString *psName;
 
2261
  int i;
 
2262
 
 
2263
  // check if font is already embedded
 
2264
  fileName = font->getExtFontFile();
 
2265
  for (i = 0; i < fontFileNameLen; ++i) {
 
2266
    if (!fontFileNames[i]->cmp(fileName)) {
 
2267
      return psFileNames[i]->copy();
 
2268
    }
 
2269
  }
 
2270
 
 
2271
  psName = font->getName()->sanitizedName(gTrue /* ps mode */);
 
2272
  // add entry to fontFileNames list
 
2273
  if (i == fontFileNameLen) {
 
2274
    if (fontFileNameLen >= fontFileNameSize) {
 
2275
      fontFileNameSize += 64;
 
2276
      fontFileNames =
 
2277
        (GooString **)greallocn(fontFileNames,
 
2278
                              fontFileNameSize, sizeof(GooString *));
 
2279
      psFileNames =
 
2280
        (GooString **)greallocn(psFileNames,
 
2281
                             fontFileNameSize, sizeof(GooString *));
 
2282
    }
 
2283
    fontFileNames[fontFileNameLen] = fileName->copy();
 
2284
    psFileNames[fontFileNameLen] = psName->copy();
 
2285
    fontFileNameLen++;
 
2286
  }
 
2287
 
 
2288
  // beginning comment
 
2289
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2290
  embFontList->append("%%+ font ");
 
2291
  embFontList->append(psName->getCString());
 
2292
  embFontList->append("\n");
 
2293
 
 
2294
  // convert it to a Type 42 font
 
2295
  fontBuf = font->readExtFontFile(&fontLen);
 
2296
  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
 
2297
    codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
 
2298
    ffTT->convertToType42(psName->getCString(),
 
2299
                          ((Gfx8BitFont *)font)->getHasEncoding()
 
2300
                            ? ((Gfx8BitFont *)font)->getEncoding()
 
2301
                            : (char **)NULL,
 
2302
                          codeToGID, outputFunc, outputStream);
 
2303
    if (codeToGID) {
 
2304
      if (font8InfoLen >= font8InfoSize) {
 
2305
        font8InfoSize += 16;
 
2306
        font8Info = (PSFont8Info *)greallocn(font8Info,
 
2307
                                             font8InfoSize,
 
2308
                                             sizeof(PSFont8Info));
 
2309
      }
 
2310
      font8Info[font8InfoLen].fontID = *font->getID();
 
2311
      font8Info[font8InfoLen].codeToGID = codeToGID;
 
2312
      ++font8InfoLen;
 
2313
    }
 
2314
    delete ffTT;
 
2315
  }
 
2316
  gfree(fontBuf);
 
2317
 
 
2318
  // ending comment
 
2319
  writePS("%%EndResource\n");
 
2320
  return psName;
 
2321
}
 
2322
 
 
2323
GooString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GooString *fileName, int faceIndex) {
 
2324
  FoFiTrueType *ffTT;
 
2325
  Gushort *codeToGID;
 
2326
  GooString *psName;
 
2327
  int i;
 
2328
  GooString *myFileName;
 
2329
 
 
2330
  myFileName = fileName->copy();
 
2331
  if (faceIndex > 0) {
 
2332
    char tmp[32];
 
2333
    sprintf(tmp, ",%d", faceIndex);
 
2334
    myFileName->append(tmp);
 
2335
  }
 
2336
  // check if font is already embedded
 
2337
  for (i = 0; i < fontFileNameLen; ++i) {
 
2338
    if (!fontFileNames[i]->cmp(myFileName)) {
 
2339
      delete myFileName;
 
2340
      return psFileNames[i]->copy();
 
2341
    }
 
2342
  }
 
2343
 
 
2344
  psName = font->getName()->sanitizedName(gTrue /* ps mode */);
 
2345
  // add entry to fontFileNames list
 
2346
  if (i == fontFileNameLen) {
 
2347
    if (fontFileNameLen >= fontFileNameSize) {
 
2348
      fontFileNameSize += 64;
 
2349
      fontFileNames =
 
2350
        (GooString **)grealloc(fontFileNames,
 
2351
                             fontFileNameSize * sizeof(GooString *));
 
2352
      psFileNames =
 
2353
        (GooString **)grealloc(psFileNames,
 
2354
                             fontFileNameSize * sizeof(GooString *));
 
2355
    }
 
2356
  }
 
2357
  fontFileNames[fontFileNameLen] = myFileName;
 
2358
  psFileNames[fontFileNameLen] = psName->copy();
 
2359
  fontFileNameLen++;
 
2360
 
 
2361
  // beginning comment
 
2362
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2363
  embFontList->append("%%+ font ");
 
2364
  embFontList->append(psName->getCString());
 
2365
  embFontList->append("\n");
 
2366
 
 
2367
  // convert it to a CID type2 font
 
2368
  if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) {
 
2369
      int n = ((GfxCIDFont *)font)->getCIDToGIDLen();
 
2370
      if (n) {
 
2371
        codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
 
2372
        memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort));
 
2373
      } else {
 
2374
        codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n);
 
2375
      }
 
2376
      if (globalParams->getPSLevel() >= psLevel3) {
 
2377
        // Level 3: use a CID font
 
2378
        ffTT->convertToCIDType2(psName->getCString(),
 
2379
                                codeToGID, n, gTrue,
 
2380
                                outputFunc, outputStream);
 
2381
      } else {
 
2382
        // otherwise: use a non-CID composite font
 
2383
        ffTT->convertToType0(psName->getCString(),
 
2384
                             codeToGID, n, gTrue,
 
2385
                             outputFunc, outputStream);
 
2386
      }
 
2387
      gfree(codeToGID);
 
2388
      delete ffTT;
 
2389
  }
 
2390
 
 
2391
  // ending comment
 
2392
  writePS("%%EndResource\n");
 
2393
  return psName;
 
2394
}
 
2395
 
 
2396
void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
 
2397
                                            GooString *psName) {
 
2398
  char *fontBuf;
 
2399
  int fontLen;
 
2400
  FoFiType1C *ffT1C;
 
2401
  int i;
 
2402
 
 
2403
  // check if font is already embedded
 
2404
  for (i = 0; i < fontFileIDLen; ++i) {
 
2405
    if (fontFileIDs[i].num == id->num &&
 
2406
        fontFileIDs[i].gen == id->gen)
 
2407
      return;
 
2408
  }
 
2409
 
 
2410
  // add entry to fontFileIDs list
 
2411
  if (fontFileIDLen >= fontFileIDSize) {
 
2412
    fontFileIDSize += 64;
 
2413
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2414
  }
 
2415
  fontFileIDs[fontFileIDLen++] = *id;
 
2416
 
 
2417
  // beginning comment
 
2418
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2419
  embFontList->append("%%+ font ");
 
2420
  embFontList->append(psName->getCString());
 
2421
  embFontList->append("\n");
 
2422
 
 
2423
  // convert it to a Type 0 font
 
2424
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2425
  if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
 
2426
    if (globalParams->getPSLevel() >= psLevel3) {
 
2427
      // Level 3: use a CID font
 
2428
      ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
 
2429
    } else {
 
2430
      // otherwise: use a non-CID composite font
 
2431
      ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
 
2432
    }
 
2433
    delete ffT1C;
 
2434
  }
 
2435
  gfree(fontBuf);
 
2436
 
 
2437
  // ending comment
 
2438
  writePS("%%EndResource\n");
 
2439
}
 
2440
 
 
2441
void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
 
2442
                                               GooString *psName,
 
2443
                                               GBool needVerticalMetrics) {
 
2444
  char *fontBuf;
 
2445
  int fontLen;
 
2446
  FoFiTrueType *ffTT;
 
2447
  int i;
 
2448
 
 
2449
  // check if font is already embedded
 
2450
  for (i = 0; i < fontFileIDLen; ++i) {
 
2451
    if (fontFileIDs[i].num == id->num &&
 
2452
        fontFileIDs[i].gen == id->gen) {
 
2453
      psName->appendf("_{0:d}", nextTrueTypeNum++);
 
2454
      break;
 
2455
    }
 
2456
  }
 
2457
 
 
2458
  // add entry to fontFileIDs list
 
2459
  if (fontFileIDLen >= fontFileIDSize) {
 
2460
    fontFileIDSize += 64;
 
2461
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2462
  }
 
2463
  fontFileIDs[fontFileIDLen++] = *id;
 
2464
 
 
2465
  // beginning comment
 
2466
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2467
  embFontList->append("%%+ font ");
 
2468
  embFontList->append(psName->getCString());
 
2469
  embFontList->append("\n");
 
2470
 
 
2471
  // convert it to a Type 0 font
 
2472
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2473
  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
 
2474
    if (globalParams->getPSLevel() >= psLevel3) {
 
2475
      // Level 3: use a CID font
 
2476
      ffTT->convertToCIDType2(psName->getCString(),
 
2477
                              ((GfxCIDFont *)font)->getCIDToGID(),
 
2478
                              ((GfxCIDFont *)font)->getCIDToGIDLen(),
 
2479
                              needVerticalMetrics,
 
2480
                              outputFunc, outputStream);
 
2481
    } else {
 
2482
      // otherwise: use a non-CID composite font
 
2483
      ffTT->convertToType0(psName->getCString(),
 
2484
                           ((GfxCIDFont *)font)->getCIDToGID(),
 
2485
                           ((GfxCIDFont *)font)->getCIDToGIDLen(),
 
2486
                           needVerticalMetrics,
 
2487
                           outputFunc, outputStream);
 
2488
    }
 
2489
    delete ffTT;
 
2490
  }
 
2491
  gfree(fontBuf);
 
2492
 
 
2493
  // ending comment
 
2494
  writePS("%%EndResource\n");
 
2495
}
 
2496
 
 
2497
void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
 
2498
                                               GooString *psName) {
 
2499
  char *fontBuf;
 
2500
  int fontLen;
 
2501
  FoFiTrueType *ffTT;
 
2502
  int i;
 
2503
 
 
2504
  // check if font is already embedded
 
2505
  for (i = 0; i < fontFileIDLen; ++i) {
 
2506
    if (fontFileIDs[i].num == id->num &&
 
2507
        fontFileIDs[i].gen == id->gen)
 
2508
      return;
 
2509
  }
 
2510
 
 
2511
  // add entry to fontFileIDs list
 
2512
  if (fontFileIDLen >= fontFileIDSize) {
 
2513
    fontFileIDSize += 64;
 
2514
    fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
 
2515
  }
 
2516
  fontFileIDs[fontFileIDLen++] = *id;
 
2517
 
 
2518
  // beginning comment
 
2519
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2520
  embFontList->append("%%+ font ");
 
2521
  embFontList->append(psName->getCString());
 
2522
  embFontList->append("\n");
 
2523
 
 
2524
  // convert it to a Type 0 font
 
2525
  fontBuf = font->readEmbFontFile(xref, &fontLen);
 
2526
  if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
 
2527
    if (ffTT->isOpenTypeCFF()) {
 
2528
      if (globalParams->getPSLevel() >= psLevel3) {
 
2529
        // Level 3: use a CID font
 
2530
        ffTT->convertToCIDType0(psName->getCString(),
 
2531
                                outputFunc, outputStream);
 
2532
      } else {
 
2533
        // otherwise: use a non-CID composite font
 
2534
        ffTT->convertToType0(psName->getCString(), outputFunc, outputStream);
 
2535
      }
 
2536
    }
 
2537
    delete ffTT;
 
2538
  }
 
2539
  gfree(fontBuf);
 
2540
 
 
2541
  // ending comment
 
2542
  writePS("%%EndResource\n");
 
2543
}
 
2544
 
 
2545
void PSOutputDev::setupType3Font(GfxFont *font, GooString *psName,
 
2546
                                 Dict *parentResDict) {
 
2547
  Dict *resDict;
 
2548
  Dict *charProcs;
 
2549
  Object charProc;
 
2550
  Gfx *gfx;
 
2551
  PDFRectangle box;
 
2552
  double *m;
 
2553
  GooString *buf;
 
2554
  int i;
 
2555
 
 
2556
  // set up resources used by font
 
2557
  if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
 
2558
    inType3Char = gTrue;
 
2559
    setupResources(resDict);
 
2560
    inType3Char = gFalse;
 
2561
  } else {
 
2562
    resDict = parentResDict;
 
2563
  }
 
2564
 
 
2565
  // beginning comment
 
2566
  writePSFmt("%%BeginResource: font {0:t}\n", psName);
 
2567
  embFontList->append("%%+ font ");
 
2568
  embFontList->append(psName->getCString());
 
2569
  embFontList->append("\n");
 
2570
 
 
2571
  // font dictionary
 
2572
  writePS("8 dict begin\n");
 
2573
  writePS("/FontType 3 def\n");
 
2574
  m = font->getFontMatrix();
 
2575
  writePSFmt("/FontMatrix [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
 
2576
             m[0], m[1], m[2], m[3], m[4], m[5]);
 
2577
  m = font->getFontBBox();
 
2578
  writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
 
2579
             m[0], m[1], m[2], m[3]);
 
2580
  writePS("/Encoding 256 array def\n");
 
2581
  writePS("  0 1 255 { Encoding exch /.notdef put } for\n");
 
2582
  writePS("/BuildGlyph {\n");
 
2583
  writePS("  exch /CharProcs get exch\n");
 
2584
  writePS("  2 copy known not { pop /.notdef } if\n");
 
2585
  writePS("  get exec\n");
 
2586
  writePS("} bind def\n");
 
2587
  writePS("/BuildChar {\n");
 
2588
  writePS("  1 index /Encoding get exch get\n");
 
2589
  writePS("  1 index /BuildGlyph get exec\n");
 
2590
  writePS("} bind def\n");
 
2591
  if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
 
2592
    writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength());
 
2593
    writePS("CharProcs begin\n");
 
2594
    box.x1 = m[0];
 
2595
    box.y1 = m[1];
 
2596
    box.x2 = m[2];
 
2597
    box.y2 = m[3];
 
2598
    gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
 
2599
    inType3Char = gTrue;
 
2600
    for (i = 0; i < charProcs->getLength(); ++i) {
 
2601
      t3Cacheable = gFalse;
 
2602
      t3NeedsRestore = gFalse;
 
2603
      writePS("/");
 
2604
      writePSName(charProcs->getKey(i));
 
2605
      writePS(" {\n");
 
2606
      gfx->display(charProcs->getVal(i, &charProc));
 
2607
      charProc.free();
 
2608
      if (t3String) {
 
2609
        if (t3Cacheable) {
 
2610
          buf = GooString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n",
 
2611
                                t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
 
2612
        } else {
 
2613
          buf = GooString::format("{0:.6g} {1:.6g} setcharwidth\n", t3WX, t3WY);
 
2614
        }
 
2615
        (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
 
2616
        delete buf;
 
2617
        (*outputFunc)(outputStream, t3String->getCString(),
 
2618
                      t3String->getLength());
 
2619
        delete t3String;
 
2620
        t3String = NULL;
 
2621
      }
 
2622
      if (t3NeedsRestore) {
 
2623
        (*outputFunc)(outputStream, "Q\n", 2);
 
2624
      }
 
2625
      writePS("} def\n");
 
2626
    }
 
2627
    inType3Char = gFalse;
 
2628
    delete gfx;
 
2629
    writePS("end\n");
 
2630
  }
 
2631
  writePS("currentdict end\n");
 
2632
  writePSFmt("/{0:t} exch definefont pop\n", psName);
 
2633
 
 
2634
  // ending comment
 
2635
  writePS("%%EndResource\n");
 
2636
}
 
2637
 
 
2638
void PSOutputDev::setupImages(Dict *resDict) {
 
2639
  Object xObjDict, xObj, xObjRef, subtypeObj;
 
2640
  int i;
 
2641
 
 
2642
  if (!(mode == psModeForm || inType3Char || preload)) {
 
2643
    return;
 
2644
  }
 
2645
 
 
2646
  //----- recursively scan XObjects
 
2647
  resDict->lookup("XObject", &xObjDict);
 
2648
  if (xObjDict.isDict()) {
 
2649
    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
 
2650
      xObjDict.dictGetValNF(i, &xObjRef);
 
2651
      xObjDict.dictGetVal(i, &xObj);
 
2652
      if (xObj.isStream()) {
 
2653
        xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
 
2654
        if (subtypeObj.isName("Image")) {
 
2655
          if (xObjRef.isRef()) {
 
2656
            setupImage(xObjRef.getRef(), xObj.getStream());
 
2657
          } else {
 
2658
            error(-1, "Image in resource dict is not an indirect reference");
 
2659
          }
 
2660
        }
 
2661
        subtypeObj.free();
 
2662
      }
 
2663
      xObj.free();
 
2664
      xObjRef.free();
 
2665
    }
 
2666
  }
 
2667
  xObjDict.free();
 
2668
}
 
2669
 
 
2670
void PSOutputDev::setupImage(Ref id, Stream *str) {
 
2671
  GBool useRLE, useCompressed, useASCIIHex;
 
2672
  GooString *s;
 
2673
  int c;
 
2674
  int size, line, col, i;
 
2675
  int outerSize, outer;
 
2676
 
 
2677
  // check if image is already setup
 
2678
  for (i = 0; i < imgIDLen; ++i) {
 
2679
    if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
 
2680
      return;
 
2681
    }
 
2682
  }
 
2683
 
 
2684
  // add entry to imgIDs list
 
2685
  if (imgIDLen >= imgIDSize) {
 
2686
    if (imgIDSize == 0) {
 
2687
      imgIDSize = 64;
 
2688
    } else {
 
2689
      imgIDSize *= 2;
 
2690
    }
 
2691
    imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
 
2692
  }
 
2693
  imgIDs[imgIDLen++] = id;
 
2694
 
 
2695
  // filters
 
2696
  //~ this does not correctly handle the DeviceN color space
 
2697
  //~   -- need to use DeviceNRecoder
 
2698
  if (level < psLevel2) {
 
2699
    useRLE = gFalse;
 
2700
    useCompressed = gFalse;
 
2701
    useASCIIHex = gTrue;
 
2702
  } else {
 
2703
    s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
 
2704
    if (s) {
 
2705
      useRLE = gFalse;
 
2706
      useCompressed = gTrue;
 
2707
      delete s;
 
2708
    } else {
 
2709
      useRLE = gTrue;
 
2710
      useCompressed = gFalse;
 
2711
    }
 
2712
    useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
 
2713
                  globalParams->getPSASCIIHex();
 
2714
  }
 
2715
  if (useCompressed) {
 
2716
    str = str->getUndecodedStream();
 
2717
  }
 
2718
  if (useRLE) {
 
2719
    str = new RunLengthEncoder(str);
 
2720
  }
 
2721
  if (useASCIIHex) {
 
2722
    str = new ASCIIHexEncoder(str);
 
2723
  } else {
 
2724
    str = new ASCII85Encoder(str);
 
2725
  }
 
2726
 
 
2727
  // compute image data size
 
2728
  str->reset();
 
2729
  col = size = 0;
 
2730
  do {
 
2731
    do {
 
2732
      c = str->getChar();
 
2733
    } while (c == '\n' || c == '\r');
 
2734
    if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2735
      break;
 
2736
    }
 
2737
    if (c == 'z') {
 
2738
      ++col;
 
2739
    } else {
 
2740
      ++col;
 
2741
      for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
 
2742
        do {
 
2743
          c = str->getChar();
 
2744
        } while (c == '\n' || c == '\r');
 
2745
        if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2746
          break;
 
2747
        }
 
2748
        ++col;
 
2749
      }
 
2750
      if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2751
        break;
 
2752
      }
 
2753
    }
 
2754
    if (col > 225) {
 
2755
      ++size;
 
2756
      col = 0;
 
2757
    }
 
2758
  } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
 
2759
  // add one entry for the final line of data; add another entry
 
2760
  // because the RunLengthDecode filter may read past the end
 
2761
  ++size;
 
2762
  if (useRLE) {
 
2763
    ++size;
 
2764
  }
 
2765
  outerSize = size/65535 + 1;
 
2766
 
 
2767
  writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
 
2768
             outerSize, id.num, id.gen);
 
2769
  str->close();
 
2770
 
 
2771
  // write the data into the array
 
2772
  str->reset();
 
2773
  for (outer = 0;outer < outerSize;outer++) {
 
2774
    int innerSize = size > 65535 ? 65535 : size;
 
2775
 
 
2776
    // put the inner array into the outer array
 
2777
    writePSFmt("{0:d} array 1 index {1:d} 2 index put\n",
 
2778
               innerSize, outer);
 
2779
    line = col = 0;
 
2780
    writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
 
2781
    for (;;) {
 
2782
      do {
 
2783
        c = str->getChar();
 
2784
      } while (c == '\n' || c == '\r');
 
2785
      if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2786
        break;
 
2787
      }
 
2788
      if (c == 'z') {
 
2789
        writePSChar(c);
 
2790
        ++col;
 
2791
      } else {
 
2792
        writePSChar(c);
 
2793
        ++col;
 
2794
        for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
 
2795
          do {
 
2796
            c = str->getChar();
 
2797
          } while (c == '\n' || c == '\r');
 
2798
          if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2799
            break;
 
2800
          }
 
2801
          writePSChar(c);
 
2802
          ++col;
 
2803
        }
 
2804
      }
 
2805
      if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2806
        break;
 
2807
      }
 
2808
      // each line is: "dup nnnnn <~...data...~> put<eol>"
 
2809
      // so max data length = 255 - 20 = 235
 
2810
      // chunks are 1 or 4 bytes each, so we have to stop at 232
 
2811
      // but make it 225 just to be safe
 
2812
      if (col > 225) {
 
2813
        writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
 
2814
        ++line;
 
2815
        if (line >= innerSize) break;
 
2816
        writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line);
 
2817
        col = 0;
 
2818
      }
 
2819
    }
 
2820
    if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
2821
      writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
 
2822
      if (useRLE) {
 
2823
        ++line;
 
2824
        writePSFmt("{0:d} <> put\n", line);
 
2825
      } else {
 
2826
        writePS("pop\n");
 
2827
      }
 
2828
      break;
 
2829
    }
 
2830
    writePS("pop\n");
 
2831
    size -= innerSize;
 
2832
  }
 
2833
  writePS("pop\n");
 
2834
  str->close();
 
2835
 
 
2836
  delete str;
 
2837
}
 
2838
 
 
2839
void PSOutputDev::setupForms(Dict *resDict) {
 
2840
  Object xObjDict, xObj, xObjRef, subtypeObj;
 
2841
  int i;
 
2842
 
 
2843
  if (!preload) {
 
2844
    return;
 
2845
  }
 
2846
 
 
2847
  resDict->lookup("XObject", &xObjDict);
 
2848
  if (xObjDict.isDict()) {
 
2849
    for (i = 0; i < xObjDict.dictGetLength(); ++i) {
 
2850
      xObjDict.dictGetValNF(i, &xObjRef);
 
2851
      xObjDict.dictGetVal(i, &xObj);
 
2852
      if (xObj.isStream()) {
 
2853
        xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
 
2854
        if (subtypeObj.isName("Form")) {
 
2855
          if (xObjRef.isRef()) {
 
2856
            setupForm(xObjRef.getRef(), &xObj);
 
2857
          } else {
 
2858
            error(-1, "Form in resource dict is not an indirect reference");
 
2859
          }
 
2860
        }
 
2861
        subtypeObj.free();
 
2862
      }
 
2863
      xObj.free();
 
2864
      xObjRef.free();
 
2865
    }
 
2866
  }
 
2867
  xObjDict.free();
 
2868
}
 
2869
 
 
2870
void PSOutputDev::setupForm(Ref id, Object *strObj) {
 
2871
  Dict *dict, *resDict;
 
2872
  Object matrixObj, bboxObj, resObj, obj1;
 
2873
  double m[6], bbox[4];
 
2874
  PDFRectangle box;
 
2875
  Gfx *gfx;
 
2876
  int i;
 
2877
 
 
2878
  // check if form is already defined
 
2879
  for (i = 0; i < formIDLen; ++i) {
 
2880
    if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
 
2881
      return;
 
2882
    }
 
2883
  }
 
2884
 
 
2885
  // add entry to formIDs list
 
2886
  if (formIDLen >= formIDSize) {
 
2887
    if (formIDSize == 0) {
 
2888
      formIDSize = 64;
 
2889
    } else {
 
2890
      formIDSize *= 2;
 
2891
    }
 
2892
    formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref));
 
2893
  }
 
2894
  formIDs[formIDLen++] = id;
 
2895
 
 
2896
  dict = strObj->streamGetDict();
 
2897
 
 
2898
  // get bounding box
 
2899
  dict->lookup("BBox", &bboxObj);
 
2900
  if (!bboxObj.isArray()) {
 
2901
    bboxObj.free();
 
2902
    error(-1, "Bad form bounding box");
 
2903
    return;
 
2904
  }
 
2905
  for (i = 0; i < 4; ++i) {
 
2906
    bboxObj.arrayGet(i, &obj1);
 
2907
    bbox[i] = obj1.getNum();
 
2908
    obj1.free();
 
2909
  }
 
2910
  bboxObj.free();
 
2911
 
 
2912
  // get matrix
 
2913
  dict->lookup("Matrix", &matrixObj);
 
2914
  if (matrixObj.isArray()) {
 
2915
    for (i = 0; i < 6; ++i) {
 
2916
      matrixObj.arrayGet(i, &obj1);
 
2917
      m[i] = obj1.getNum();
 
2918
      obj1.free();
 
2919
    }
 
2920
  } else {
 
2921
    m[0] = 1; m[1] = 0;
 
2922
    m[2] = 0; m[3] = 1;
 
2923
    m[4] = 0; m[5] = 0;
 
2924
  }
 
2925
  matrixObj.free();
 
2926
 
 
2927
  // get resources
 
2928
  dict->lookup("Resources", &resObj);
 
2929
  resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
 
2930
 
 
2931
  writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
 
2932
  writePS("q\n");
 
2933
  writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
 
2934
             m[0], m[1], m[2], m[3], m[4], m[5]);
 
2935
 
 
2936
  box.x1 = bbox[0];
 
2937
  box.y1 = bbox[1];
 
2938
  box.x2 = bbox[2];
 
2939
  box.y2 = bbox[3];
 
2940
  gfx = new Gfx(xref, this, resDict, m_catalog, &box, &box);
 
2941
  gfx->display(strObj);
 
2942
  delete gfx;
 
2943
 
 
2944
  writePS("Q\n");
 
2945
  writePS("} def\n");
 
2946
 
 
2947
  resObj.free();
 
2948
}
 
2949
 
 
2950
GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
 
2951
                                  int rotateA, GBool useMediaBox, GBool crop,
 
2952
                                  int sliceX, int sliceY,
 
2953
                                  int sliceW, int sliceH,
 
2954
                                  GBool printing, Catalog *catalog,
 
2955
                                  GBool (*abortCheckCbk)(void *data),
 
2956
                                  void *abortCheckCbkData) {
 
2957
#if HAVE_SPLASH
 
2958
  PreScanOutputDev *scan;
 
2959
  GBool rasterize;
 
2960
  SplashOutputDev *splashOut;
 
2961
  SplashColor paperColor;
 
2962
  PDFRectangle box;
 
2963
  GfxState *state;
 
2964
  SplashBitmap *bitmap;
 
2965
  Stream *str0, *str;
 
2966
  Object obj;
 
2967
  Guchar *p;
 
2968
  Guchar col[4];
 
2969
  double m0, m1, m2, m3, m4, m5;
 
2970
  int c, w, h, x, y, comp, i;
 
2971
  char hexBuf[32*2 + 2];        // 32 values X 2 chars/value + line ending + null
 
2972
  Guchar digit;
 
2973
 
 
2974
  if (!forceRasterize) {
 
2975
    scan = new PreScanOutputDev();
 
2976
    page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
 
2977
                     sliceX, sliceY, sliceW, sliceH,
 
2978
                     printing, catalog, abortCheckCbk, abortCheckCbkData);
 
2979
    rasterize = scan->usesTransparency() || scan->hasLevel1PSBug();
 
2980
    delete scan;
 
2981
  } else {
 
2982
    rasterize = gTrue;
 
2983
  }
 
2984
  if (!rasterize) {
 
2985
    return gTrue;
 
2986
  }
 
2987
 
 
2988
  // rasterize the page
 
2989
  if (level == psLevel1) {
 
2990
    paperColor[0] = 0xff;
 
2991
    splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
 
2992
                                    paperColor, gTrue, gFalse);
 
2993
#if SPLASH_CMYK
 
2994
  } else if (level == psLevel1Sep) {
 
2995
    paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
 
2996
    splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
 
2997
                                    paperColor, gTrue, gFalse);
 
2998
#else
 
2999
  } else if (level == psLevel1Sep) {
 
3000
    error(-1, "pdftops was built without CMYK support, level1sep needs it to work in this file");
 
3001
    return gFalse;
 
3002
#endif
 
3003
  } else {
 
3004
    paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
 
3005
    splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
 
3006
                                    paperColor, gTrue, gFalse);
 
3007
  }
 
3008
  splashOut->startDoc(xref);
 
3009
  page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
 
3010
                     useMediaBox, crop,
 
3011
                     sliceX, sliceY, sliceW, sliceH,
 
3012
                     printing, catalog, abortCheckCbk, abortCheckCbkData);
 
3013
 
 
3014
  // start the PS page
 
3015
  page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
 
3016
                sliceX, sliceY, sliceW, sliceH, &box, &crop);
 
3017
  rotateA += page->getRotate();
 
3018
  if (rotateA >= 360) {
 
3019
    rotateA -= 360;
 
3020
  } else if (rotateA < 0) {
 
3021
    rotateA += 360;
 
3022
  }
 
3023
  state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
 
3024
  startPage(page->getNum(), state);
 
3025
  delete state;
 
3026
  switch (rotateA) {
 
3027
  case 0:
 
3028
  default:  // this should never happen
 
3029
    m0 = box.x2 - box.x1;
 
3030
    m1 = 0;
 
3031
    m2 = 0;
 
3032
    m3 = box.y2 - box.y1;
 
3033
    m4 = box.x1;
 
3034
    m5 = box.y1;
 
3035
    break;
 
3036
  case 90:
 
3037
    m0 = 0;
 
3038
    m1 = box.y2 - box.y1;
 
3039
    m2 = -(box.x2 - box.x1);
 
3040
    m3 = 0;
 
3041
    m4 = box.x2;
 
3042
    m5 = box.y1;
 
3043
    break;
 
3044
  case 180:
 
3045
    m0 = -(box.x2 - box.x1);
 
3046
    m1 = 0;
 
3047
    m2 = 0;
 
3048
    m3 = -(box.y2 - box.y1);
 
3049
    m4 = box.x2;
 
3050
    m5 = box.y2;
 
3051
    break;
 
3052
  case 270:
 
3053
    m0 = 0;
 
3054
    m1 = -(box.y2 - box.y1);
 
3055
    m2 = box.x2 - box.x1;
 
3056
    m3 = 0;
 
3057
    m4 = box.x1;
 
3058
    m5 = box.y2;
 
3059
    break;
 
3060
  }
 
3061
 
 
3062
  //~ need to add the process colors
 
3063
 
 
3064
  // draw the rasterized image
 
3065
  bitmap = splashOut->getBitmap();
 
3066
  w = bitmap->getWidth();
 
3067
  h = bitmap->getHeight();
 
3068
  writePS("gsave\n");
 
3069
  writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
 
3070
             m0, m1, m2, m3, m4, m5);
 
3071
  switch (level) {
 
3072
  case psLevel1:
 
3073
    writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
 
3074
               w, h, w, -h, h);
 
3075
    p = bitmap->getDataPtr();
 
3076
    i = 0;
 
3077
    for (y = 0; y < h; ++y) {
 
3078
      for (x = 0; x < w; ++x) {
 
3079
        digit = *p / 16;
 
3080
        hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3081
        digit = *p++ % 16;
 
3082
        hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3083
        if (i >= 64) {
 
3084
          hexBuf[i++] = '\n';
 
3085
          writePSBuf(hexBuf, i);
 
3086
          i = 0;
 
3087
        }
 
3088
      }
 
3089
    }
 
3090
    if (i != 0) {
 
3091
      hexBuf[i++] = '\n';
 
3092
      writePSBuf(hexBuf, i);
 
3093
    }
 
3094
    break;
 
3095
  case psLevel1Sep:
 
3096
    writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
 
3097
               w, h, w, -h, h);
 
3098
    p = bitmap->getDataPtr();
 
3099
    i = 0;
 
3100
    col[0] = col[1] = col[2] = col[3] = 0;
 
3101
    if (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0) {
 
3102
      for (y = 0; y < h; ++y) {
 
3103
        for (comp = 0; comp < 4; ++comp) {
 
3104
          for (x = 0; x < w; ++x) {
 
3105
            col[comp] |= p[4*x + comp];
 
3106
            digit = p[4*x + comp] / 16;
 
3107
            hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3108
            digit = p[4*x + comp] % 16;
 
3109
            hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3110
            if (i >= 64) {
 
3111
              hexBuf[i++] = '\n';
 
3112
              writePSBuf(hexBuf, i);
 
3113
              i = 0;
 
3114
            }
 
3115
          }
 
3116
        }
 
3117
        p += bitmap->getRowSize();
 
3118
      }
 
3119
    } else {
 
3120
      for (y = 0; y < h; ++y) {
 
3121
        for (comp = 0; comp < 4; ++comp) {
 
3122
          for (x = 0; x < w; ++x) {
 
3123
            digit = p[4*x + comp] / 16;
 
3124
            hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3125
            digit = p[4*x + comp] % 16;
 
3126
            hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
3127
            if (i >= 64) {
 
3128
              hexBuf[i++] = '\n';
 
3129
              writePSBuf(hexBuf, i);
 
3130
              i = 0;
 
3131
            }
 
3132
          }
 
3133
        }
 
3134
        p += bitmap->getRowSize();
 
3135
      }
 
3136
    }
 
3137
    if (i != 0) {
 
3138
      hexBuf[i++] = '\n';
 
3139
      writePSBuf(hexBuf, i);
 
3140
    }
 
3141
    if (col[0]) {
 
3142
      processColors |= psProcessCyan;
 
3143
    }
 
3144
    if (col[1]) {
 
3145
      processColors |= psProcessMagenta;
 
3146
    }
 
3147
    if (col[2]) {
 
3148
      processColors |= psProcessYellow;
 
3149
    }
 
3150
    if (col[3]) {
 
3151
      processColors |= psProcessBlack;
 
3152
    }
 
3153
    break;
 
3154
  case psLevel2:
 
3155
  case psLevel2Sep:
 
3156
  case psLevel3:
 
3157
  case psLevel3Sep:
 
3158
    writePS("/DeviceRGB setcolorspace\n");
 
3159
    writePS("<<\n  /ImageType 1\n");
 
3160
    writePSFmt("  /Width {0:d}\n", bitmap->getWidth());
 
3161
    writePSFmt("  /Height {0:d}\n", bitmap->getHeight());
 
3162
    writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
 
3163
    writePS("  /BitsPerComponent 8\n");
 
3164
    writePS("  /Decode [0 1 0 1 0 1]\n");
 
3165
    writePS("  /DataSource currentfile\n");
 
3166
    if (globalParams->getPSASCIIHex()) {
 
3167
      writePS("    /ASCIIHexDecode filter\n");
 
3168
    } else {
 
3169
      writePS("    /ASCII85Decode filter\n");
 
3170
    }
 
3171
    writePS("    /RunLengthDecode filter\n");
 
3172
    writePS(">>\n");
 
3173
    writePS("image\n");
 
3174
    obj.initNull();
 
3175
    str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
 
3176
    str = new RunLengthEncoder(str0);
 
3177
    if (globalParams->getPSASCIIHex()) {
 
3178
      str = new ASCIIHexEncoder(str);
 
3179
    } else {
 
3180
      str = new ASCII85Encoder(str);
 
3181
    }
 
3182
    str->reset();
 
3183
    while ((c = str->getChar()) != EOF) {
 
3184
      writePSChar(c);
 
3185
    }
 
3186
    str->close();
 
3187
    delete str;
 
3188
    delete str0;
 
3189
    processColors |= psProcessCMYK;
 
3190
    break;
 
3191
  }
 
3192
  delete splashOut;
 
3193
  writePS("grestore\n");
 
3194
 
 
3195
  // finish the PS page
 
3196
  endPage();
 
3197
 
 
3198
  return gFalse;
 
3199
#else
 
3200
  return gTrue;
 
3201
#endif
 
3202
}
 
3203
 
 
3204
void PSOutputDev::startPage(int pageNum, GfxState *state) {
 
3205
  int x1, y1, x2, y2, width, height;
 
3206
  int imgWidth, imgHeight, imgWidth2, imgHeight2;
 
3207
  GBool landscape;
 
3208
 
 
3209
 
 
3210
  if (mode == psModePS || mode == psModePSOrigPageSizes) {
 
3211
    GooString pageLabel;
 
3212
    const GBool gotLabel = m_catalog->indexToLabel(pageNum -1, &pageLabel);
 
3213
    if (gotLabel) {
 
3214
      // See bug13338 for why we try to avoid parentheses...
 
3215
      GBool needParens;
 
3216
      GooString *filteredString = filterPSLabel(&pageLabel, &needParens);
 
3217
      if (needParens) {
 
3218
        writePSFmt("%%Page: ({0:t}) {1:d}\n", filteredString, seqPage);
 
3219
      } else {
 
3220
        writePSFmt("%%Page: {0:t} {1:d}\n", filteredString, seqPage);
 
3221
      }
 
3222
      delete filteredString;
 
3223
    } else {
 
3224
      writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
 
3225
    }
 
3226
    if (mode != psModePSOrigPageSizes)
 
3227
      writePS("%%BeginPageSetup\n");
 
3228
  }
 
3229
 
 
3230
  // underlays
 
3231
  if (underlayCbk) {
 
3232
    (*underlayCbk)(this, underlayCbkData);
 
3233
  }
 
3234
  if (overlayCbk) {
 
3235
    saveState(NULL);
 
3236
  }
 
3237
 
 
3238
  switch (mode) {
 
3239
 
 
3240
  case psModePSOrigPageSizes:
 
3241
    x1 = (int)floor(state->getX1());
 
3242
    y1 = (int)floor(state->getY1());
 
3243
    x2 = (int)ceil(state->getX2());
 
3244
    y2 = (int)ceil(state->getY2());
 
3245
    width = x2 - x1;
 
3246
    height = y2 - y1;
 
3247
    if (width > height) {
 
3248
      landscape = gTrue;
 
3249
    } else {
 
3250
      landscape = gFalse;
 
3251
    }
 
3252
    writePSFmt("%%PageBoundingBox: {0:d} {1:d} {2:d} {3:d}\n", x1, y1, x2 - x1, y2 - y1);
 
3253
    writePS("%%BeginPageSetup\n");
 
3254
    writePSFmt("%%PageOrientation: {0:s}\n",
 
3255
               landscape ? "Landscape" : "Portrait");
 
3256
    if ((width != prevWidth) || (height != prevHeight)) {
 
3257
      // Set page size only when it actually changes, as otherwise Duplex
 
3258
      // printing does not work
 
3259
      writePSFmt("<</PageSize [{0:d} {1:d}]>> setpagedevice\n", width, height);
 
3260
      prevWidth = width;
 
3261
      prevHeight = height;
 
3262
    }
 
3263
    writePS("pdfStartPage\n");
 
3264
    writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
 
3265
    writePS("%%EndPageSetup\n");
 
3266
    ++seqPage;
 
3267
    break;
 
3268
 
 
3269
  case psModePS:
 
3270
    // rotate, translate, and scale page
 
3271
    imgWidth = imgURX - imgLLX;
 
3272
    imgHeight = imgURY - imgLLY;
 
3273
    x1 = (int)floor(state->getX1());
 
3274
    y1 = (int)floor(state->getY1());
 
3275
    x2 = (int)ceil(state->getX2());
 
3276
    y2 = (int)ceil(state->getY2());
 
3277
    width = x2 - x1;
 
3278
    height = y2 - y1;
 
3279
    tx = ty = 0;
 
3280
    // rotation and portrait/landscape mode
 
3281
    if (rotate0 >= 0) {
 
3282
      rotate = (360 - rotate0) % 360;
 
3283
      landscape = gFalse;
 
3284
    } else {
 
3285
      rotate = (360 - state->getRotate()) % 360;
 
3286
      if (rotate == 0 || rotate == 180) {
 
3287
        if (width > height && width > imgWidth) {
 
3288
          rotate += 90;
 
3289
          landscape = gTrue;
 
3290
        } else {
 
3291
          landscape = gFalse;
 
3292
        }
 
3293
      } else { // rotate == 90 || rotate == 270
 
3294
        if (height > width && height > imgWidth) {
 
3295
          rotate = 270 - rotate;
 
3296
          landscape = gTrue;
 
3297
        } else {
 
3298
          landscape = gFalse;
 
3299
        }
 
3300
      }
 
3301
    }
 
3302
    writePSFmt("%%PageOrientation: {0:s}\n",
 
3303
               landscape ? "Landscape" : "Portrait");
 
3304
    writePS("pdfStartPage\n");
 
3305
    if (rotate == 0) {
 
3306
      imgWidth2 = imgWidth;
 
3307
      imgHeight2 = imgHeight;
 
3308
    } else if (rotate == 90) {
 
3309
      writePS("90 rotate\n");
 
3310
      ty = -imgWidth;
 
3311
      imgWidth2 = imgHeight;
 
3312
      imgHeight2 = imgWidth;
 
3313
    } else if (rotate == 180) {
 
3314
      writePS("180 rotate\n");
 
3315
      imgWidth2 = imgWidth;
 
3316
      imgHeight2 = imgHeight;
 
3317
      tx = -imgWidth;
 
3318
      ty = -imgHeight;
 
3319
    } else { // rotate == 270
 
3320
      writePS("270 rotate\n");
 
3321
      tx = -imgHeight;
 
3322
      imgWidth2 = imgHeight;
 
3323
      imgHeight2 = imgWidth;
 
3324
    }
 
3325
    // shrink or expand
 
3326
    if (xScale0 > 0 && yScale0 > 0) {
 
3327
      xScale = xScale0;
 
3328
      yScale = yScale0;
 
3329
    } else if ((globalParams->getPSShrinkLarger() &&
 
3330
         (width > imgWidth2 || height > imgHeight2)) ||
 
3331
        (globalParams->getPSExpandSmaller() &&
 
3332
         (width < imgWidth2 && height < imgHeight2))) {
 
3333
      xScale = (double)imgWidth2 / (double)width;
 
3334
      yScale = (double)imgHeight2 / (double)height;
 
3335
      if (yScale < xScale) {
 
3336
        xScale = yScale;
 
3337
      } else {
 
3338
        yScale = xScale;
 
3339
      }
 
3340
    } else {
 
3341
      xScale = yScale = 1;
 
3342
    }
 
3343
    // deal with odd bounding boxes or clipping
 
3344
    if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
 
3345
      tx -= xScale * clipLLX0;
 
3346
      ty -= yScale * clipLLY0;
 
3347
    } else {
 
3348
      tx -= xScale * x1;
 
3349
      ty -= yScale * y1;
 
3350
    }
 
3351
    // center
 
3352
    if (tx0 >= 0 && ty0 >= 0) {
 
3353
      tx += rotate == 0 ? tx0 : ty0;
 
3354
      ty += rotate == 0 ? ty0 : -tx0;
 
3355
    } else if (globalParams->getPSCenter()) {
 
3356
      if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
 
3357
        tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
 
3358
        ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2;
 
3359
      } else {
 
3360
        tx += (imgWidth2 - xScale * width) / 2;
 
3361
        ty += (imgHeight2 - yScale * height) / 2;
 
3362
      }
 
3363
    }
 
3364
    tx += rotate == 0 ? imgLLX : imgLLY;
 
3365
    ty += rotate == 0 ? imgLLY : -imgLLX;
 
3366
    if (tx != 0 || ty != 0) {
 
3367
      writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
 
3368
    }
 
3369
    if (xScale != 1 || yScale != 1) {
 
3370
      writePSFmt("{0:.6f} {1:.6f} scale\n", xScale, yScale);
 
3371
    }
 
3372
    if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
 
3373
      writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n",
 
3374
                 clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
 
3375
    } else {
 
3376
      writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
 
3377
    }
 
3378
 
 
3379
    writePS("%%EndPageSetup\n");
 
3380
    ++seqPage;
 
3381
    break;
 
3382
 
 
3383
  case psModeEPS:
 
3384
    writePS("pdfStartPage\n");
 
3385
    tx = ty = 0;
 
3386
    rotate = (360 - state->getRotate()) % 360;
 
3387
    if (rotate == 0) {
 
3388
    } else if (rotate == 90) {
 
3389
      writePS("90 rotate\n");
 
3390
      tx = -epsX1;
 
3391
      ty = -epsY2;
 
3392
    } else if (rotate == 180) {
 
3393
      writePS("180 rotate\n");
 
3394
      tx = -(epsX1 + epsX2);
 
3395
      ty = -(epsY1 + epsY2);
 
3396
    } else { // rotate == 270
 
3397
      writePS("270 rotate\n");
 
3398
      tx = -epsX2;
 
3399
      ty = -epsY1;
 
3400
    }
 
3401
    if (tx != 0 || ty != 0) {
 
3402
      writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty);
 
3403
    }
 
3404
    xScale = yScale = 1;
 
3405
    break;
 
3406
 
 
3407
  case psModeForm:
 
3408
    writePS("/PaintProc {\n");
 
3409
    writePS("begin xpdf begin\n");
 
3410
    writePS("pdfStartPage\n");
 
3411
    tx = ty = 0;
 
3412
    xScale = yScale = 1;
 
3413
    rotate = 0;
 
3414
    break;
 
3415
  }
 
3416
}
 
3417
 
 
3418
void PSOutputDev::endPage() {
 
3419
  if (overlayCbk) {
 
3420
    restoreState(NULL);
 
3421
    (*overlayCbk)(this, overlayCbkData);
 
3422
  }
 
3423
 
 
3424
 
 
3425
  if (mode == psModeForm) {
 
3426
    writePS("pdfEndPage\n");
 
3427
    writePS("end end\n");
 
3428
    writePS("} def\n");
 
3429
    writePS("end end\n");
 
3430
  } else {
 
3431
    if (!manualCtrl) {
 
3432
      writePS("showpage\n");
 
3433
    }
 
3434
      writePS("%%PageTrailer\n");
 
3435
      writePageTrailer();
 
3436
    }
 
3437
}
 
3438
 
 
3439
void PSOutputDev::saveState(GfxState *state) {
 
3440
  writePS("q\n");
 
3441
  ++numSaves;
 
3442
}
 
3443
 
 
3444
void PSOutputDev::restoreState(GfxState *state) {
 
3445
  writePS("Q\n");
 
3446
  --numSaves;
 
3447
}
 
3448
 
 
3449
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
 
3450
                            double m21, double m22, double m31, double m32) {
 
3451
  writePSFmt("[{0:.6gs} {1:.6gs} {2:.6gs} {3:.6gs} {4:.6gs} {5:.6gs}] cm\n",
 
3452
             m11, m12, m21, m22, m31, m32);
 
3453
}
 
3454
 
 
3455
void PSOutputDev::updateLineDash(GfxState *state) {
 
3456
  double *dash;
 
3457
  double start;
 
3458
  int length, i;
 
3459
 
 
3460
  state->getLineDash(&dash, &length, &start);
 
3461
  writePS("[");
 
3462
  for (i = 0; i < length; ++i) {
 
3463
    writePSFmt("{0:.6g}{1:w}",
 
3464
               dash[i] < 0 ? 0 : dash[i],
 
3465
               (i == length-1) ? 0 : 1);
 
3466
  }
 
3467
  writePSFmt("] {0:.6g} d\n", start);
 
3468
}
 
3469
 
 
3470
void PSOutputDev::updateFlatness(GfxState *state) {
 
3471
  writePSFmt("{0:d} i\n", state->getFlatness());
 
3472
}
 
3473
 
 
3474
void PSOutputDev::updateLineJoin(GfxState *state) {
 
3475
  writePSFmt("{0:d} j\n", state->getLineJoin());
 
3476
}
 
3477
 
 
3478
void PSOutputDev::updateLineCap(GfxState *state) {
 
3479
  writePSFmt("{0:d} J\n", state->getLineCap());
 
3480
}
 
3481
 
 
3482
void PSOutputDev::updateMiterLimit(GfxState *state) {
 
3483
  writePSFmt("{0:.6g} M\n", state->getMiterLimit());
 
3484
}
 
3485
 
 
3486
void PSOutputDev::updateLineWidth(GfxState *state) {
 
3487
  writePSFmt("{0:.6g} w\n", state->getLineWidth());
 
3488
}
 
3489
 
 
3490
void PSOutputDev::updateFillColorSpace(GfxState *state) {
 
3491
  switch (level) {
 
3492
  case psLevel1:
 
3493
  case psLevel1Sep:
 
3494
    break;
 
3495
  case psLevel2:
 
3496
  case psLevel3:
 
3497
    if (state->getFillColorSpace()->getMode() != csPattern) {
 
3498
      dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
 
3499
      writePS(" cs\n");
 
3500
    }
 
3501
    break;
 
3502
  case psLevel2Sep:
 
3503
  case psLevel3Sep:
 
3504
    break;
 
3505
  }
 
3506
}
 
3507
 
 
3508
void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
 
3509
  switch (level) {
 
3510
  case psLevel1:
 
3511
  case psLevel1Sep:
 
3512
    break;
 
3513
  case psLevel2:
 
3514
  case psLevel3:
 
3515
    if (state->getStrokeColorSpace()->getMode() != csPattern) {
 
3516
      dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
 
3517
      writePS(" CS\n");
 
3518
    }
 
3519
    break;
 
3520
  case psLevel2Sep:
 
3521
  case psLevel3Sep:
 
3522
    break;
 
3523
  }
 
3524
}
 
3525
 
 
3526
void PSOutputDev::updateFillColor(GfxState *state) {
 
3527
  GfxColor color;
 
3528
  GfxColor *colorPtr;
 
3529
  GfxGray gray;
 
3530
  GfxCMYK cmyk;
 
3531
  GfxSeparationColorSpace *sepCS;
 
3532
  double c, m, y, k;
 
3533
  int i;
 
3534
 
 
3535
  switch (level) {
 
3536
  case psLevel1:
 
3537
    state->getFillGray(&gray);
 
3538
    writePSFmt("{0:.4g} g\n", colToDbl(gray));
 
3539
    break;
 
3540
  case psLevel1Sep:
 
3541
    state->getFillCMYK(&cmyk);
 
3542
    c = colToDbl(cmyk.c);
 
3543
    m = colToDbl(cmyk.m);
 
3544
    y = colToDbl(cmyk.y);
 
3545
    k = colToDbl(cmyk.k);
 
3546
    writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
 
3547
    addProcessColor(c, m, y, k);
 
3548
    break;
 
3549
  case psLevel2:
 
3550
  case psLevel3:
 
3551
    if (state->getFillColorSpace()->getMode() != csPattern) {
 
3552
      colorPtr = state->getFillColor();
 
3553
      writePS("[");
 
3554
      for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) {
 
3555
        if (i > 0) {
 
3556
          writePS(" ");
 
3557
      }
 
3558
        writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
 
3559
      }
 
3560
      writePS("] sc\n");
 
3561
    }
 
3562
    break;
 
3563
  case psLevel2Sep:
 
3564
  case psLevel3Sep:
 
3565
    if (state->getFillColorSpace()->getMode() == csSeparation) {
 
3566
      sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
 
3567
      color.c[0] = gfxColorComp1;
 
3568
      sepCS->getCMYK(&color, &cmyk);
 
3569
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
 
3570
                 colToDbl(state->getFillColor()->c[0]),
 
3571
                 colToDbl(cmyk.c), colToDbl(cmyk.m),
 
3572
                 colToDbl(cmyk.y), colToDbl(cmyk.k),
 
3573
                 sepCS->getName());
 
3574
      addCustomColor(sepCS);
 
3575
    } else {
 
3576
      state->getFillCMYK(&cmyk);
 
3577
      c = colToDbl(cmyk.c);
 
3578
      m = colToDbl(cmyk.m);
 
3579
      y = colToDbl(cmyk.y);
 
3580
      k = colToDbl(cmyk.k);
 
3581
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
 
3582
      addProcessColor(c, m, y, k);
 
3583
    }
 
3584
    break;
 
3585
  }
 
3586
  t3Cacheable = gFalse;
 
3587
}
 
3588
 
 
3589
void PSOutputDev::updateStrokeColor(GfxState *state) {
 
3590
  GfxColor color;
 
3591
  GfxColor *colorPtr;
 
3592
  GfxGray gray;
 
3593
  GfxCMYK cmyk;
 
3594
  GfxSeparationColorSpace *sepCS;
 
3595
  double c, m, y, k;
 
3596
  int i;
 
3597
 
 
3598
  switch (level) {
 
3599
  case psLevel1:
 
3600
    state->getStrokeGray(&gray);
 
3601
    writePSFmt("{0:.4g} G\n", colToDbl(gray));
 
3602
    break;
 
3603
  case psLevel1Sep:
 
3604
    state->getStrokeCMYK(&cmyk);
 
3605
    c = colToDbl(cmyk.c);
 
3606
    m = colToDbl(cmyk.m);
 
3607
    y = colToDbl(cmyk.y);
 
3608
    k = colToDbl(cmyk.k);
 
3609
    writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
 
3610
    addProcessColor(c, m, y, k);
 
3611
    break;
 
3612
  case psLevel2:
 
3613
  case psLevel3:
 
3614
    if (state->getStrokeColorSpace()->getMode() != csPattern) {
 
3615
      colorPtr = state->getStrokeColor();
 
3616
      writePS("[");
 
3617
      for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) {
 
3618
        if (i > 0) {
 
3619
          writePS(" ");
 
3620
        }
 
3621
        writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
 
3622
      }
 
3623
      writePS("] SC\n");
 
3624
    }
 
3625
    break;
 
3626
  case psLevel2Sep:
 
3627
  case psLevel3Sep:
 
3628
    if (state->getStrokeColorSpace()->getMode() == csSeparation) {
 
3629
      sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
 
3630
      color.c[0] = gfxColorComp1;
 
3631
      sepCS->getCMYK(&color, &cmyk);
 
3632
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
 
3633
                 colToDbl(state->getStrokeColor()->c[0]),
 
3634
                 colToDbl(cmyk.c), colToDbl(cmyk.m),
 
3635
                 colToDbl(cmyk.y), colToDbl(cmyk.k),
 
3636
                 sepCS->getName());
 
3637
      addCustomColor(sepCS);
 
3638
    } else {
 
3639
      state->getStrokeCMYK(&cmyk);
 
3640
      c = colToDbl(cmyk.c);
 
3641
      m = colToDbl(cmyk.m);
 
3642
      y = colToDbl(cmyk.y);
 
3643
      k = colToDbl(cmyk.k);
 
3644
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
 
3645
      addProcessColor(c, m, y, k);
 
3646
    }
 
3647
    break;
 
3648
  }
 
3649
  t3Cacheable = gFalse;
 
3650
}
 
3651
 
 
3652
void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
 
3653
  if (c > 0) {
 
3654
    processColors |= psProcessCyan;
 
3655
  }
 
3656
  if (m > 0) {
 
3657
    processColors |= psProcessMagenta;
 
3658
  }
 
3659
  if (y > 0) {
 
3660
    processColors |= psProcessYellow;
 
3661
  }
 
3662
  if (k > 0) {
 
3663
    processColors |= psProcessBlack;
 
3664
  }
 
3665
}
 
3666
 
 
3667
void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
 
3668
  PSOutCustomColor *cc;
 
3669
  GfxColor color;
 
3670
  GfxCMYK cmyk;
 
3671
 
 
3672
  for (cc = customColors; cc; cc = cc->next) {
 
3673
    if (!cc->name->cmp(sepCS->getName())) {
 
3674
      return;
 
3675
    }
 
3676
  }
 
3677
  color.c[0] = gfxColorComp1;
 
3678
  sepCS->getCMYK(&color, &cmyk);
 
3679
  cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
 
3680
                            colToDbl(cmyk.y), colToDbl(cmyk.k),
 
3681
                            sepCS->getName()->copy());
 
3682
  cc->next = customColors;
 
3683
  customColors = cc;
 
3684
}
 
3685
 
 
3686
void PSOutputDev::updateFillOverprint(GfxState *state) {
 
3687
  if (level >= psLevel2) {
 
3688
    writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
 
3689
  }
 
3690
}
 
3691
 
 
3692
void PSOutputDev::updateStrokeOverprint(GfxState *state) {
 
3693
  if (level >= psLevel2) {
 
3694
    writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
 
3695
  }
 
3696
}
 
3697
 
 
3698
void PSOutputDev::updateTransfer(GfxState *state) {
 
3699
  Function **funcs;
 
3700
  int i;
 
3701
 
 
3702
  funcs = state->getTransfer();
 
3703
  if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
 
3704
    if (level >= psLevel2) {
 
3705
      for (i = 0; i < 4; ++i) {
 
3706
        cvtFunction(funcs[i]);
 
3707
      }
 
3708
      writePS("setcolortransfer\n");
 
3709
    } else {
 
3710
      cvtFunction(funcs[3]);
 
3711
      writePS("settransfer\n");
 
3712
    }
 
3713
  } else if (funcs[0]) {
 
3714
    cvtFunction(funcs[0]);
 
3715
    writePS("settransfer\n");
 
3716
  } else {
 
3717
    writePS("{} settransfer\n");
 
3718
  }
 
3719
}
 
3720
 
 
3721
void PSOutputDev::updateFont(GfxState *state) {
 
3722
  if (state->getFont()) {
 
3723
    writePSFmt("/F{0:d}_{1:d} {2:.6g} Tf\n",
 
3724
               state->getFont()->getID()->num, state->getFont()->getID()->gen,
 
3725
               fabs(state->getFontSize()) < 0.00001 ? 0.00001
 
3726
                                                    : state->getFontSize());
 
3727
  }
 
3728
}
 
3729
 
 
3730
void PSOutputDev::updateTextMat(GfxState *state) {
 
3731
  double *mat;
 
3732
 
 
3733
  mat = state->getTextMat();
 
3734
  if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
 
3735
    // avoid a singular (or close-to-singular) matrix
 
3736
    writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]);
 
3737
  } else {
 
3738
    writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n",
 
3739
               mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
 
3740
  }
 
3741
}
 
3742
 
 
3743
void PSOutputDev::updateCharSpace(GfxState *state) {
 
3744
  writePSFmt("{0:.6g} Tc\n", state->getCharSpace());
 
3745
}
 
3746
 
 
3747
void PSOutputDev::updateRender(GfxState *state) {
 
3748
  int rm;
 
3749
 
 
3750
  rm = state->getRender();
 
3751
  writePSFmt("{0:d} Tr\n", rm);
 
3752
  rm &= 3;
 
3753
  if (rm != 0 && rm != 3) {
 
3754
    t3Cacheable = gFalse;
 
3755
  }
 
3756
}
 
3757
 
 
3758
void PSOutputDev::updateRise(GfxState *state) {
 
3759
  writePSFmt("{0:.6g} Ts\n", state->getRise());
 
3760
}
 
3761
 
 
3762
void PSOutputDev::updateWordSpace(GfxState *state) {
 
3763
  writePSFmt("{0:.6g} Tw\n", state->getWordSpace());
 
3764
}
 
3765
 
 
3766
void PSOutputDev::updateHorizScaling(GfxState *state) {
 
3767
  double h;
 
3768
 
 
3769
  h = state->getHorizScaling();
 
3770
  if (fabs(h) < 0.01) {
 
3771
    h = 0.01;
 
3772
  }
 
3773
  writePSFmt("{0:.6g} Tz\n", h);
 
3774
}
 
3775
 
 
3776
void PSOutputDev::updateTextPos(GfxState *state) {
 
3777
  writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY());
 
3778
}
 
3779
 
 
3780
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
 
3781
  if (state->getFont()->getWMode()) {
 
3782
    writePSFmt("{0:.6g} TJmV\n", shift);
 
3783
  } else {
 
3784
    writePSFmt("{0:.6g} TJm\n", shift);
 
3785
  }
 
3786
}
 
3787
 
 
3788
void PSOutputDev::stroke(GfxState *state) {
 
3789
  doPath(state->getPath());
 
3790
  if (t3String) {
 
3791
    // if we're construct a cacheable Type 3 glyph, we need to do
 
3792
    // everything in the fill color
 
3793
    writePS("Sf\n");
 
3794
  } else {
 
3795
    writePS("S\n");
 
3796
  }
 
3797
}
 
3798
 
 
3799
void PSOutputDev::fill(GfxState *state) {
 
3800
  doPath(state->getPath());
 
3801
  writePS("f\n");
 
3802
}
 
3803
 
 
3804
void PSOutputDev::eoFill(GfxState *state) {
 
3805
  doPath(state->getPath());
 
3806
  writePS("f*\n");
 
3807
}
 
3808
 
 
3809
GBool PSOutputDev::tilingPatternFill(GfxState *state, Object *str,
 
3810
                                     int paintType, Dict *resDict,
 
3811
                                     double *mat, double *bbox,
 
3812
                                     int x0, int y0, int x1, int y1,
 
3813
                                     double xStep, double yStep) {
 
3814
  PDFRectangle box;
 
3815
  Gfx *gfx;
 
3816
 
 
3817
  // define a Type 3 font
 
3818
  writePS("8 dict begin\n");
 
3819
  writePS("/FontType 3 def\n");
 
3820
  writePS("/FontMatrix [1 0 0 1 0 0] def\n");
 
3821
  writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n",
 
3822
             bbox[0], bbox[1], bbox[2], bbox[3]);
 
3823
  writePS("/Encoding 256 array def\n");
 
3824
  writePS("  0 1 255 { Encoding exch /.notdef put } for\n");
 
3825
  writePS("  Encoding 120 /x put\n");
 
3826
  writePS("/BuildGlyph {\n");
 
3827
  writePS("  exch /CharProcs get exch\n");
 
3828
  writePS("  2 copy known not { pop /.notdef } if\n");
 
3829
  writePS("  get exec\n");
 
3830
  writePS("} bind def\n");
 
3831
  writePS("/BuildChar {\n");
 
3832
  writePS("  1 index /Encoding get exch get\n");
 
3833
  writePS("  1 index /BuildGlyph get exec\n");
 
3834
  writePS("} bind def\n");
 
3835
  writePS("/CharProcs 1 dict def\n");
 
3836
  writePS("CharProcs begin\n");
 
3837
  box.x1 = bbox[0];
 
3838
  box.y1 = bbox[1];
 
3839
  box.x2 = bbox[2];
 
3840
  box.y2 = bbox[3];
 
3841
  gfx = new Gfx(xref, this, resDict, m_catalog, &box, NULL);
 
3842
  writePS("/x {\n");
 
3843
  if (paintType == 2) {
 
3844
    writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n",
 
3845
               xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
 
3846
  } else
 
3847
  {
 
3848
    if (x1 - 1 <= x0) {
 
3849
      writePS("1 0 setcharwidth\n");
 
3850
    } else {
 
3851
      writePSFmt("{0:.6g} 0 setcharwidth\n", xStep);
 
3852
    }
 
3853
  }
 
3854
  inType3Char = gTrue;
 
3855
  ++numTilingPatterns;
 
3856
  gfx->display(str);
 
3857
  --numTilingPatterns;
 
3858
  inType3Char = gFalse;
 
3859
  writePS("} def\n");
 
3860
  delete gfx;
 
3861
  writePS("end\n");
 
3862
  writePS("currentdict end\n");
 
3863
  writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
 
3864
 
 
3865
  // draw the tiles
 
3866
  writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
 
3867
  writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
 
3868
             mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
 
3869
  writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
 
3870
             y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
 
3871
  writePS("grestore\n");
 
3872
 
 
3873
  return gTrue;
 
3874
}
 
3875
 
 
3876
GBool PSOutputDev::functionShadedFill(GfxState *state,
 
3877
                                     GfxFunctionShading *shading) {
 
3878
  double x0, y0, x1, y1;
 
3879
  double *mat;
 
3880
  int i;
 
3881
 
 
3882
  if (level == psLevel2Sep || level == psLevel3Sep) {
 
3883
    if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
 
3884
      return gFalse;
 
3885
    }
 
3886
    processColors |= psProcessCMYK;
 
3887
  }
 
3888
 
 
3889
  shading->getDomain(&x0, &y0, &x1, &y1);
 
3890
  mat = shading->getMatrix();
 
3891
  writePSFmt("/mat [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n",
 
3892
             mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
 
3893
  writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
 
3894
  if (shading->getNFuncs() == 1) {
 
3895
    writePS("/func ");
 
3896
    cvtFunction(shading->getFunc(0));
 
3897
    writePS("def\n");
 
3898
  } else {
 
3899
    writePS("/func {\n");
 
3900
    for (i = 0; i < shading->getNFuncs(); ++i) {
 
3901
      if (i < shading->getNFuncs() - 1) {
 
3902
        writePS("2 copy\n");
 
3903
      }
 
3904
      cvtFunction(shading->getFunc(i));
 
3905
      writePS("exec\n");
 
3906
      if (i < shading->getNFuncs() - 1) {
 
3907
        writePS("3 1 roll\n");
 
3908
      }
 
3909
    }
 
3910
    writePS("} def\n");
 
3911
  }
 
3912
  writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1);
 
3913
 
 
3914
  return gTrue;
 
3915
}
 
3916
 
 
3917
GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double /*tMin*/, double /*tMax*/) {
 
3918
  double xMin, yMin, xMax, yMax;
 
3919
  double x0, y0, x1, y1, dx, dy, mul;
 
3920
  double tMin, tMax, t, t0, t1;
 
3921
  int i;
 
3922
 
 
3923
  if (level == psLevel2Sep || level == psLevel3Sep) {
 
3924
    if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
 
3925
      return gFalse;
 
3926
    }
 
3927
    processColors |= psProcessCMYK;
 
3928
  }
 
3929
 
 
3930
  // get the clip region bbox
 
3931
  state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
 
3932
 
 
3933
  // compute min and max t values, based on the four corners of the
 
3934
  // clip region bbox
 
3935
  shading->getCoords(&x0, &y0, &x1, &y1);
 
3936
  dx = x1 - x0;
 
3937
  dy = y1 - y0;
 
3938
  if (fabs(dx) < 0.01 && fabs(dy) < 0.01) {
 
3939
    return gTrue;
 
3940
  } else {
 
3941
    mul = 1 / (dx * dx + dy * dy);
 
3942
    tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
 
3943
    t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
 
3944
    if (t < tMin) {
 
3945
      tMin = t;
 
3946
    } else if (t > tMax) {
 
3947
      tMax = t;
 
3948
    }
 
3949
    t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
 
3950
    if (t < tMin) {
 
3951
      tMin = t;
 
3952
    } else if (t > tMax) {
 
3953
      tMax = t;
 
3954
    }
 
3955
    t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
 
3956
    if (t < tMin) {
 
3957
      tMin = t;
 
3958
    } else if (t > tMax) {
 
3959
      tMax = t;
 
3960
    }
 
3961
    if (tMin < 0 && !shading->getExtend0()) {
 
3962
      tMin = 0;
 
3963
    }
 
3964
    if (tMax > 1 && !shading->getExtend1()) {
 
3965
      tMax = 1;
 
3966
    }
 
3967
  }
 
3968
 
 
3969
  // get the function domain
 
3970
  t0 = shading->getDomain0();
 
3971
  t1 = shading->getDomain1();
 
3972
 
 
3973
  // generate the PS code
 
3974
  writePSFmt("/t0 {0:.6g} def\n", t0);
 
3975
  writePSFmt("/t1 {0:.6g} def\n", t1);
 
3976
  writePSFmt("/dt {0:.6g} def\n", t1 - t0);
 
3977
  writePSFmt("/x0 {0:.6g} def\n", x0);
 
3978
  writePSFmt("/y0 {0:.6g} def\n", y0);
 
3979
  writePSFmt("/dx {0:.6g} def\n", x1 - x0);
 
3980
  writePSFmt("/x1 {0:.6g} def\n", x1);
 
3981
  writePSFmt("/y1 {0:.6g} def\n", y1);
 
3982
  writePSFmt("/dy {0:.6g} def\n", y1 - y0);
 
3983
  writePSFmt("/xMin {0:.6g} def\n", xMin);
 
3984
  writePSFmt("/yMin {0:.6g} def\n", yMin);
 
3985
  writePSFmt("/xMax {0:.6g} def\n", xMax);
 
3986
  writePSFmt("/yMax {0:.6g} def\n", yMax);
 
3987
  writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
 
3988
  if (shading->getNFuncs() == 1) {
 
3989
    writePS("/func ");
 
3990
    cvtFunction(shading->getFunc(0));
 
3991
    writePS("def\n");
 
3992
  } else {
 
3993
    writePS("/func {\n");
 
3994
    for (i = 0; i < shading->getNFuncs(); ++i) {
 
3995
      if (i < shading->getNFuncs() - 1) {
 
3996
        writePS("dup\n");
 
3997
      }
 
3998
      cvtFunction(shading->getFunc(i));
 
3999
      writePS("exec\n");
 
4000
      if (i < shading->getNFuncs() - 1) {
 
4001
        writePS("exch\n");
 
4002
      }
 
4003
    }
 
4004
    writePS("} def\n");
 
4005
  }
 
4006
  writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax);
 
4007
 
 
4008
  return gTrue;
 
4009
}
 
4010
 
 
4011
GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double /*sMin*/, double /*sMax*/) {
 
4012
  double xMin, yMin, xMax, yMax;
 
4013
  double x0, y0, r0, x1, y1, r1, t0, t1;
 
4014
  double xa, ya, ra;
 
4015
  double sz, xz, yz, sMin, sMax, sa, ta;
 
4016
  double theta, alpha, a1, a2;
 
4017
  GBool enclosed;
 
4018
  int i;
 
4019
 
 
4020
  if (level == psLevel2Sep || level == psLevel3Sep) {
 
4021
    if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
 
4022
      return gFalse;
 
4023
    }
 
4024
    processColors |= psProcessCMYK;
 
4025
  }
 
4026
 
 
4027
  // get the shading info
 
4028
  shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
 
4029
  t0 = shading->getDomain0();
 
4030
  t1 = shading->getDomain1();
 
4031
 
 
4032
  // Compute the point at which r(s) = 0; check for the enclosed
 
4033
  // circles case; and compute the angles for the tangent lines.
 
4034
  if (r0 == r1) {
 
4035
    enclosed = x0 == x1 && y0 == y1;
 
4036
    theta = 0;
 
4037
    sz = 0; // make gcc happy
 
4038
  } else {
 
4039
    sz = -r0 / (r1 - r0);
 
4040
    xz = x0 + sz * (x1 - x0);
 
4041
    yz = y0 + sz * (y1 - y0);
 
4042
    enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
 
4043
    theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
 
4044
    if (r0 > r1) {
 
4045
      theta = -theta;
 
4046
    }
 
4047
  }
 
4048
  if (enclosed) {
 
4049
    a1 = 0;
 
4050
    a2 = 360;
 
4051
  } else {
 
4052
    alpha = atan2(y1 - y0, x1 - x0);
 
4053
    a1 = (180 / M_PI) * (alpha + theta) + 90;
 
4054
    a2 = (180 / M_PI) * (alpha - theta) - 90;
 
4055
    while (a2 < a1) {
 
4056
      a2 += 360;
 
4057
    }
 
4058
  }
 
4059
 
 
4060
  // compute the (possibly extended) s range
 
4061
  state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
 
4062
  if (enclosed) {
 
4063
    sMin = 0;
 
4064
    sMax = 1;
 
4065
  } else {
 
4066
    sMin = 1;
 
4067
    sMax = 0;
 
4068
    // solve for x(s) + r(s) = xMin
 
4069
    if ((x1 + r1) - (x0 + r0) != 0) {
 
4070
      sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
 
4071
      if (sa < sMin) {
 
4072
        sMin = sa;
 
4073
      } else if (sa > sMax) {
 
4074
        sMax = sa;
 
4075
      }
 
4076
    }
 
4077
    // solve for x(s) - r(s) = xMax
 
4078
    if ((x1 - r1) - (x0 - r0) != 0) {
 
4079
      sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
 
4080
      if (sa < sMin) {
 
4081
        sMin = sa;
 
4082
      } else if (sa > sMax) {
 
4083
        sMax = sa;
 
4084
      }
 
4085
    }
 
4086
    // solve for y(s) + r(s) = yMin
 
4087
    if ((y1 + r1) - (y0 + r0) != 0) {
 
4088
      sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
 
4089
      if (sa < sMin) {
 
4090
        sMin = sa;
 
4091
      } else if (sa > sMax) {
 
4092
        sMax = sa;
 
4093
      }
 
4094
    }
 
4095
    // solve for y(s) - r(s) = yMax
 
4096
    if ((y1 - r1) - (y0 - r0) != 0) {
 
4097
      sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
 
4098
      if (sa < sMin) {
 
4099
        sMin = sa;
 
4100
      } else if (sa > sMax) {
 
4101
        sMax = sa;
 
4102
      }
 
4103
    }
 
4104
    // check against sz
 
4105
    if (r0 < r1) {
 
4106
      if (sMin < sz) {
 
4107
        sMin = sz;
 
4108
      }
 
4109
    } else if (r0 > r1) {
 
4110
      if (sMax > sz) {
 
4111
        sMax = sz;
 
4112
      }
 
4113
    }
 
4114
    // check the 'extend' flags
 
4115
    if (!shading->getExtend0() && sMin < 0) {
 
4116
      sMin = 0;
 
4117
    }
 
4118
    if (!shading->getExtend1() && sMax > 1) {
 
4119
      sMax = 1;
 
4120
    }
 
4121
  }
 
4122
 
 
4123
  // generate the PS code
 
4124
  writePSFmt("/x0 {0:.6g} def\n", x0);
 
4125
  writePSFmt("/x1 {0:.6g} def\n", x1);
 
4126
  writePSFmt("/dx {0:.6g} def\n", x1 - x0);
 
4127
  writePSFmt("/y0 {0:.6g} def\n", y0);
 
4128
  writePSFmt("/y1 {0:.6g} def\n", y1);
 
4129
  writePSFmt("/dy {0:.6g} def\n", y1 - y0);
 
4130
  writePSFmt("/r0 {0:.6g} def\n", r0);
 
4131
  writePSFmt("/r1 {0:.6g} def\n", r1);
 
4132
  writePSFmt("/dr {0:.6g} def\n", r1 - r0);
 
4133
  writePSFmt("/t0 {0:.6g} def\n", t0);
 
4134
  writePSFmt("/t1 {0:.6g} def\n", t1);
 
4135
  writePSFmt("/dt {0:.6g} def\n", t1 - t0);
 
4136
  writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
 
4137
  writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false");
 
4138
  writePSFmt("/a1 {0:.6g} def\n", a1);
 
4139
  writePSFmt("/a2 {0:.6g} def\n", a2);
 
4140
  if (shading->getNFuncs() == 1) {
 
4141
    writePS("/func ");
 
4142
    cvtFunction(shading->getFunc(0));
 
4143
    writePS("def\n");
 
4144
  } else {
 
4145
    writePS("/func {\n");
 
4146
    for (i = 0; i < shading->getNFuncs(); ++i) {
 
4147
      if (i < shading->getNFuncs() - 1) {
 
4148
        writePS("dup\n");
 
4149
      }
 
4150
      cvtFunction(shading->getFunc(i));
 
4151
      writePS("exec\n");
 
4152
      if (i < shading->getNFuncs() - 1) {
 
4153
        writePS("exch\n");
 
4154
      }
 
4155
    }
 
4156
    writePS("} def\n");
 
4157
  }
 
4158
  writePSFmt("{0:.6g} {1:.6g} 0 radialSH\n", sMin, sMax);
 
4159
 
 
4160
  // extend the 'enclosed' case
 
4161
  if (enclosed) {
 
4162
    // extend the smaller circle
 
4163
    if ((shading->getExtend0() && r0 <= r1) ||
 
4164
        (shading->getExtend1() && r1 < r0)) {
 
4165
      if (r0 <= r1) {
 
4166
        ta = t0;
 
4167
        ra = r0;
 
4168
        xa = x0;
 
4169
        ya = y0;
 
4170
      } else {
 
4171
        ta = t1;
 
4172
        ra = r1;
 
4173
        xa = x1;
 
4174
        ya = y1;
 
4175
      }
 
4176
      if (level == psLevel2Sep || level == psLevel3Sep) {
 
4177
        writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
 
4178
      } else {
 
4179
        writePSFmt("{0:.6g} radialCol sc\n", ta);
 
4180
      }
 
4181
      writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h f*\n", xa, ya, ra);
 
4182
    }
 
4183
 
 
4184
    // extend the larger circle
 
4185
    if ((shading->getExtend0() && r0 > r1) ||
 
4186
        (shading->getExtend1() && r1 >= r0)) {
 
4187
      if (r0 > r1) {
 
4188
        ta = t0;
 
4189
        ra = r0;
 
4190
        xa = x0;
 
4191
        ya = y0;
 
4192
      } else {
 
4193
        ta = t1;
 
4194
        ra = r1;
 
4195
        xa = x1;
 
4196
        ya = y1;
 
4197
      }
 
4198
      if (level == psLevel2Sep || level == psLevel3Sep) {
 
4199
        writePSFmt("{0:.6g} radialCol aload pop k\n", ta);
 
4200
      } else {
 
4201
        writePSFmt("{0:.6g} radialCol sc\n", ta);
 
4202
      }
 
4203
      writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h\n", xa, ya, ra);
 
4204
      writePSFmt("{0:.6g} {1:.6g} m {2:.6g} {3:.6g} l {4:.6g} {5:.6g} l {6:.6g} {7:.6g} l h f*\n",
 
4205
                 xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin);
 
4206
    }
 
4207
  }
 
4208
 
 
4209
  return gTrue;
 
4210
}
 
4211
 
 
4212
void PSOutputDev::clip(GfxState *state) {
 
4213
  doPath(state->getPath());
 
4214
  writePS("W\n");
 
4215
}
 
4216
 
 
4217
void PSOutputDev::eoClip(GfxState *state) {
 
4218
  doPath(state->getPath());
 
4219
  writePS("W*\n");
 
4220
}
 
4221
 
 
4222
void PSOutputDev::clipToStrokePath(GfxState *state) {
 
4223
  doPath(state->getPath());
 
4224
  writePS("Ws\n");
 
4225
}
 
4226
 
 
4227
void PSOutputDev::doPath(GfxPath *path) {
 
4228
  GfxSubpath *subpath;
 
4229
  double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
 
4230
  int n, m, i, j;
 
4231
 
 
4232
  n = path->getNumSubpaths();
 
4233
 
 
4234
  if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
 
4235
    subpath = path->getSubpath(0);
 
4236
    x0 = subpath->getX(0);
 
4237
    y0 = subpath->getY(0);
 
4238
    x4 = subpath->getX(4);
 
4239
    y4 = subpath->getY(4);
 
4240
    if (x4 == x0 && y4 == y0) {
 
4241
      x1 = subpath->getX(1);
 
4242
      y1 = subpath->getY(1);
 
4243
      x2 = subpath->getX(2);
 
4244
      y2 = subpath->getY(2);
 
4245
      x3 = subpath->getX(3);
 
4246
      y3 = subpath->getY(3);
 
4247
      if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
 
4248
        writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
 
4249
                   x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
 
4250
                   fabs(x2 - x0), fabs(y1 - y0));
 
4251
        return;
 
4252
      } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
 
4253
        writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
 
4254
                   x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
 
4255
                   fabs(x1 - x0), fabs(y2 - y0));
 
4256
        return;
 
4257
      }
 
4258
    }
 
4259
  }
 
4260
 
 
4261
  for (i = 0; i < n; ++i) {
 
4262
    subpath = path->getSubpath(i);
 
4263
    m = subpath->getNumPoints();
 
4264
    writePSFmt("{0:.6g} {1:.6g} m\n", subpath->getX(0), subpath->getY(0));
 
4265
    j = 1;
 
4266
    while (j < m) {
 
4267
      if (subpath->getCurve(j)) {
 
4268
        writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} c\n",
 
4269
                   subpath->getX(j), subpath->getY(j),
 
4270
                   subpath->getX(j+1), subpath->getY(j+1),
 
4271
                   subpath->getX(j+2), subpath->getY(j+2));
 
4272
        j += 3;
 
4273
      } else {
 
4274
        writePSFmt("{0:.6g} {1:.6g} l\n", subpath->getX(j), subpath->getY(j));
 
4275
        ++j;
 
4276
      }
 
4277
    }
 
4278
    if (subpath->isClosed()) {
 
4279
      writePS("h\n");
 
4280
    }
 
4281
  }
 
4282
}
 
4283
 
 
4284
void PSOutputDev::drawString(GfxState *state, GooString *s) {
 
4285
  GfxFont *font;
 
4286
  int wMode;
 
4287
  Gushort *codeToGID;
 
4288
  GooString *s2;
 
4289
  double dx, dy, dx2, dy2, originX, originY;
 
4290
  char *p;
 
4291
  UnicodeMap *uMap;
 
4292
  CharCode code;
 
4293
  Unicode *u;
 
4294
  char buf[8];
 
4295
  int len, nChars, uLen, n, m, i, j;
 
4296
 
 
4297
  // for pdftohtml, output PS without text
 
4298
  if( displayText == gFalse )
 
4299
    return;
 
4300
 
 
4301
  // check for invisible text -- this is used by Acrobat Capture
 
4302
  if (state->getRender() == 3) {
 
4303
    return;
 
4304
  }
 
4305
 
 
4306
  // ignore empty strings
 
4307
  if (s->getLength() == 0) {
 
4308
    return;
 
4309
  }
 
4310
 
 
4311
  // get the font
 
4312
  if (!(font = state->getFont())) {
 
4313
    return;
 
4314
  }
 
4315
  wMode = font->getWMode();
 
4316
 
 
4317
  // check for a subtitute 16-bit font
 
4318
  uMap = NULL;
 
4319
  codeToGID = NULL;
 
4320
  if (font->isCIDFont()) {
 
4321
    for (i = 0; i < font16EncLen; ++i) {
 
4322
      if (font->getID()->num == font16Enc[i].fontID.num &&
 
4323
          font->getID()->gen == font16Enc[i].fontID.gen) {
 
4324
        uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
 
4325
        break;
 
4326
      }
 
4327
    }
 
4328
 
 
4329
  // check for a code-to-GID map
 
4330
  } else {
 
4331
    for (i = 0; i < font8InfoLen; ++i) {
 
4332
      if (font->getID()->num == font8Info[i].fontID.num &&
 
4333
          font->getID()->gen == font8Info[i].fontID.gen) {
 
4334
        codeToGID = font8Info[i].codeToGID;
 
4335
        break;
 
4336
      }
 
4337
    }
 
4338
  }
 
4339
 
 
4340
  // compute width of chars in string, ignoring char spacing and word
 
4341
  // spacing -- the Tj operator will adjust for the metrics of the
 
4342
  // font that's actually used
 
4343
  dx = dy = 0;
 
4344
  nChars = 0;
 
4345
  p = s->getCString();
 
4346
  len = s->getLength();
 
4347
  s2 = new GooString();
 
4348
  while (len > 0) {
 
4349
    n = font->getNextChar(p, len, &code,
 
4350
                          &u, &uLen,
 
4351
                          &dx2, &dy2, &originX, &originY);
 
4352
    if (font->isCIDFont()) {
 
4353
      if (uMap) {
 
4354
        for (i = 0; i < uLen; ++i) {
 
4355
          m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
 
4356
          for (j = 0; j < m; ++j) {
 
4357
            s2->append(buf[j]);
 
4358
          }
 
4359
        }
 
4360
        //~ this really needs to get the number of chars in the target
 
4361
        //~ encoding - which may be more than the number of Unicode
 
4362
        //~ chars
 
4363
        nChars += uLen;
 
4364
      } else {
 
4365
        s2->append((char)((code >> 8) & 0xff));
 
4366
        s2->append((char)(code & 0xff));
 
4367
        ++nChars;
 
4368
      }
 
4369
    } else {
 
4370
      if (!codeToGID || codeToGID[code]) {
 
4371
        s2->append((char)code);
 
4372
      }
 
4373
    }
 
4374
    dx += dx2;
 
4375
    dy += dy2;
 
4376
    p += n;
 
4377
    len -= n;
 
4378
  }
 
4379
  dx *= state->getFontSize() * state->getHorizScaling();
 
4380
  dy *= state->getFontSize();
 
4381
  if (uMap) {
 
4382
    uMap->decRefCnt();
 
4383
  }
 
4384
 
 
4385
  if (s2->getLength() > 0) {
 
4386
    writePSString(s2);
 
4387
    if (font->isCIDFont()) {
 
4388
      if (wMode) {
 
4389
        writePSFmt(" {0:d} {1:.6g} Tj16V\n", nChars, dy);
 
4390
      } else {
 
4391
        writePSFmt(" {0:d} {1:.6g} Tj16\n", nChars, dx);
 
4392
      }
 
4393
    } else {
 
4394
      writePSFmt(" {0:.6g} Tj\n", dx);
 
4395
    }
 
4396
  }
 
4397
  delete s2;
 
4398
 
 
4399
  if (state->getRender() & 4 || haveCSPattern) {
 
4400
    haveTextClip = gTrue;
 
4401
  }
 
4402
}
 
4403
 
 
4404
void PSOutputDev::beginTextObject(GfxState *state) {
 
4405
  if (state->getFillColorSpace()->getMode() == csPattern) {
 
4406
    saveState(state);
 
4407
    haveCSPattern = gTrue;
 
4408
    writePS("true Tp\n");
 
4409
  }
 
4410
}
 
4411
 
 
4412
void PSOutputDev::endTextObject(GfxState *state) {
 
4413
  if (haveCSPattern) {
 
4414
    if (haveTextClip) {
 
4415
      writePS("Tclip*\n");
 
4416
      haveTextClip = gFalse;
 
4417
      if (state->getFillColorSpace()->getMode() != csPattern) {
 
4418
        double cxMin, cyMin, cxMax, cyMax;
 
4419
        state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
 
4420
        writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
 
4421
                   cxMin, cyMin,
 
4422
                   cxMax, cyMax);
 
4423
        writePS("f*\n");
 
4424
        restoreState(state);
 
4425
        updateFillColor(state);
 
4426
      }
 
4427
    }
 
4428
    haveCSPattern = gFalse;
 
4429
  } else if (haveTextClip) {
 
4430
    writePS("Tclip\n");
 
4431
    haveTextClip = gFalse;
 
4432
  }
 
4433
}
 
4434
 
 
4435
void PSOutputDev::endMaskClip(GfxState * state) {
 
4436
  writePS("pdfImClipEnd\n");
 
4437
}
 
4438
 
 
4439
void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 
4440
                                int width, int height, GBool invert,
 
4441
                                GBool interpolate, GBool inlineImg) {
 
4442
  int len;
 
4443
 
 
4444
  len = height * ((width + 7) / 8);
 
4445
  if (state->getFillColorSpace()->getMode() == csPattern && (level != psLevel1 && level != psLevel1Sep)) {
 
4446
    maskToClippingPath(str, width, height, invert);
 
4447
  } else {
 
4448
    switch (level) {
 
4449
      case psLevel1:
 
4450
      case psLevel1Sep:
 
4451
        doImageL1(ref, NULL, invert, inlineImg, str, width, height, len,
 
4452
                  NULL, NULL, 0, 0, gFalse);
 
4453
      break;
 
4454
      case psLevel2:
 
4455
      case psLevel2Sep:
 
4456
        doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
 
4457
                  NULL, NULL, 0, 0, gFalse);
 
4458
      break;
 
4459
      case psLevel3:
 
4460
      case psLevel3Sep:
 
4461
        doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
 
4462
                  NULL, NULL, 0, 0, gFalse);
 
4463
      break;
 
4464
    }
 
4465
  }
 
4466
}
 
4467
 
 
4468
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 
4469
                            int width, int height, GfxImageColorMap *colorMap,
 
4470
                            GBool interpolate, int *maskColors, GBool inlineImg) {
 
4471
  int len;
 
4472
 
 
4473
  len = height * ((width * colorMap->getNumPixelComps() *
 
4474
                   colorMap->getBits() + 7) / 8);
 
4475
  switch (level) {
 
4476
  case psLevel1:
 
4477
    doImageL1(ref, colorMap, gFalse, inlineImg, str,
 
4478
             width, height, len, maskColors, NULL, 0, 0, gFalse);
 
4479
    break;
 
4480
  case psLevel1Sep:
 
4481
    //~ handle indexed, separation, ... color spaces
 
4482
    doImageL1Sep(ref, colorMap, gFalse, inlineImg, str,
 
4483
             width, height, len, maskColors, NULL, 0, 0, gFalse);
 
4484
    break;
 
4485
  case psLevel2:
 
4486
  case psLevel2Sep:
 
4487
    doImageL2(ref, colorMap, gFalse, inlineImg, str,
 
4488
              width, height, len, maskColors, NULL, 0, 0, gFalse);
 
4489
    break;
 
4490
  case psLevel3:
 
4491
  case psLevel3Sep:
 
4492
    doImageL3(ref, colorMap, gFalse, inlineImg, str,
 
4493
              width, height, len, maskColors, NULL, 0, 0, gFalse);
 
4494
    break;
 
4495
  }
 
4496
  t3Cacheable = gFalse;
 
4497
}
 
4498
 
 
4499
void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 
4500
                                  int width, int height,
 
4501
                                  GfxImageColorMap *colorMap,
 
4502
                                  GBool interpolate,
 
4503
                                  Stream *maskStr,
 
4504
                                  int maskWidth, int maskHeight,
 
4505
                                  GBool maskInvert, GBool maskInterpolate) {
 
4506
  int len;
 
4507
 
 
4508
  len = height * ((width * colorMap->getNumPixelComps() *
 
4509
                   colorMap->getBits() + 7) / 8);
 
4510
  switch (level) {
 
4511
  case psLevel1:
 
4512
    doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len,
 
4513
              NULL, maskStr, maskWidth, maskHeight, maskInvert);    
 
4514
    break;
 
4515
  case psLevel1Sep:
 
4516
    //~ handle indexed, separation, ... color spaces
 
4517
    doImageL1Sep(ref, colorMap, gFalse, gFalse, str, width, height, len,
 
4518
              NULL, maskStr, maskWidth, maskHeight, maskInvert);    
 
4519
    break;
 
4520
  case psLevel2:
 
4521
  case psLevel2Sep:
 
4522
    doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
 
4523
              NULL, maskStr, maskWidth, maskHeight, maskInvert);
 
4524
    break;
 
4525
  case psLevel3:
 
4526
  case psLevel3Sep:
 
4527
    doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
 
4528
              NULL, maskStr, maskWidth, maskHeight, maskInvert);
 
4529
    break;
 
4530
  }
 
4531
  t3Cacheable = gFalse;
 
4532
}
 
4533
 
 
4534
void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
 
4535
                            GBool invert, GBool inlineImg,
 
4536
                            Stream *str, int width, int height, int len,
 
4537
                            int *maskColors, Stream *maskStr,
 
4538
                            int maskWidth, int maskHeight, GBool maskInvert) {
 
4539
  ImageStream *imgStr;
 
4540
  Guchar pixBuf[gfxColorMaxComps];
 
4541
  GfxGray gray;
 
4542
  int col, x, y, c, i;
 
4543
  char hexBuf[32*2 + 2];        // 32 values X 2 chars/value + line ending + null
 
4544
  Guchar digit, grayValue;
 
4545
 
 
4546
  // explicit masking
 
4547
  if (maskStr && !(maskColors && colorMap)) {
 
4548
    maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
 
4549
  }
 
4550
 
 
4551
  if ((inType3Char || preload) && !colorMap) {
 
4552
    if (inlineImg) {
 
4553
      // create an array
 
4554
      str = new FixedLengthEncoder(str, len);
 
4555
      str = new ASCIIHexEncoder(str);
 
4556
      str->reset();
 
4557
      col = 0;
 
4558
      writePS("[<");
 
4559
      do {
 
4560
        do {
 
4561
          c = str->getChar();
 
4562
        } while (c == '\n' || c == '\r');
 
4563
        if (c == '>' || c == EOF) {
 
4564
          break;
 
4565
        }
 
4566
        writePSChar(c);
 
4567
        ++col;
 
4568
        // each line is: "<...data...><eol>"
 
4569
        // so max data length = 255 - 4 = 251
 
4570
        // but make it 240 just to be safe
 
4571
        // chunks are 2 bytes each, so we need to stop on an even col number
 
4572
        if (col == 240) {
 
4573
          writePS(">\n<");
 
4574
          col = 0;
 
4575
        }
 
4576
      } while (c != '>' && c != EOF);
 
4577
      writePS(">]\n");
 
4578
      writePS("0\n");
 
4579
      str->close();
 
4580
      delete str;
 
4581
    } else {
 
4582
      // make sure the image is setup, it sometimes is not like on bug #17645
 
4583
      setupImage(ref->getRef(), str);
 
4584
      // set up to use the array already created by setupImages()
 
4585
      writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
 
4586
    }
 
4587
  }
 
4588
 
 
4589
  // image/imagemask command
 
4590
  if ((inType3Char || preload) && !colorMap) {
 
4591
    writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n",
 
4592
               width, height, invert ? "true" : "false",
 
4593
               width, -height, height);
 
4594
  } else if (colorMap) {
 
4595
    writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
 
4596
               width, height,
 
4597
               width, -height, height);
 
4598
  } else {
 
4599
    writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n",
 
4600
               width, height, invert ? "true" : "false",
 
4601
               width, -height, height);
 
4602
  }
 
4603
 
 
4604
  // image data
 
4605
  if (!((inType3Char || preload) && !colorMap)) {
 
4606
 
 
4607
    if (colorMap) {
 
4608
 
 
4609
      // set up to process the data stream
 
4610
      imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
 
4611
                               colorMap->getBits());
 
4612
      imgStr->reset();
 
4613
 
 
4614
      // process the data stream
 
4615
      i = 0;
 
4616
      for (y = 0; y < height; ++y) {
 
4617
 
 
4618
        // write the line
 
4619
        for (x = 0; x < width; ++x) {
 
4620
          imgStr->getPixel(pixBuf);
 
4621
          colorMap->getGray(pixBuf, &gray);
 
4622
          grayValue = colToByte(gray);
 
4623
          digit = grayValue / 16;
 
4624
          hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
4625
          digit = grayValue % 16;
 
4626
          hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
4627
          if (i >= 64) {
 
4628
            hexBuf[i++] = '\n';
 
4629
            writePSBuf(hexBuf, i);
 
4630
            i = 0;
 
4631
          }
 
4632
        }
 
4633
      }
 
4634
      if (i != 0) {
 
4635
        hexBuf[i++] = '\n';
 
4636
        writePSBuf(hexBuf, i);
 
4637
      }
 
4638
      str->close();
 
4639
      delete imgStr;
 
4640
 
 
4641
    // imagemask
 
4642
    } else {
 
4643
      str->reset();
 
4644
      i = 0;
 
4645
      for (y = 0; y < height; ++y) {
 
4646
        for (x = 0; x < width; x += 8) {
 
4647
          grayValue = str->getChar();
 
4648
          digit = grayValue / 16;
 
4649
          hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
4650
          digit = grayValue % 16;
 
4651
          hexBuf[i++] = digit + ((digit >= 10)? 'a' - 10: '0');
 
4652
          if (i >= 64) {
 
4653
            hexBuf[i++] = '\n';
 
4654
            writePSBuf(hexBuf, i);
 
4655
            i = 0;
 
4656
          }
 
4657
        }
 
4658
      }
 
4659
      if (i != 0) {
 
4660
        hexBuf[i++] = '\n';
 
4661
        writePSBuf(hexBuf, i);
 
4662
      }
 
4663
      str->close();
 
4664
    }
 
4665
  }
 
4666
 
 
4667
  if (maskStr && !(maskColors && colorMap)) {
 
4668
    writePS("pdfImClipEnd\n");
 
4669
  }
 
4670
}
 
4671
 
 
4672
void PSOutputDev::doImageL1Sep(Object *ref, GfxImageColorMap *colorMap,
 
4673
                               GBool invert, GBool inlineImg,
 
4674
                               Stream *str, int width, int height, int len,
 
4675
                               int *maskColors, Stream *maskStr,
 
4676
                               int maskWidth, int maskHeight, GBool maskInvert) {
 
4677
  ImageStream *imgStr;
 
4678
  Guchar *lineBuf;
 
4679
  Guchar pixBuf[gfxColorMaxComps];
 
4680
  GfxCMYK cmyk;
 
4681
  int x, y, i, comp;
 
4682
  GBool checkProcessColor;
 
4683
  char hexBuf[32*2 + 2];        // 32 values X 2 chars/value + line ending + null
 
4684
  Guchar digit;
 
4685
 
 
4686
  // explicit masking
 
4687
  if (maskStr && !(maskColors && colorMap)) {
 
4688
    maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
 
4689
  }
 
4690
 
 
4691
  // width, height, matrix, bits per component
 
4692
  writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
 
4693
             width, height,
 
4694
             width, -height, height);
 
4695
 
 
4696
  // allocate a line buffer
 
4697
  lineBuf = (Guchar *)gmallocn(width, 4);
 
4698
 
 
4699
  // set up to process the data stream
 
4700
  imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
 
4701
                           colorMap->getBits());
 
4702
  imgStr->reset();
 
4703
 
 
4704
  // process the data stream
 
4705
  checkProcessColor = gTrue;
 
4706
  i = 0;
 
4707
  for (y = 0; y < height; ++y) {
 
4708
 
 
4709
    // read the line
 
4710
    if (checkProcessColor) {
 
4711
      checkProcessColor = (((psProcessCyan | psProcessMagenta | psProcessYellow | psProcessBlack) & ~processColors) != 0);
 
4712
    }
 
4713
    if (checkProcessColor) {
 
4714
      for (x = 0; x < width; ++x) {
 
4715
        imgStr->getPixel(pixBuf);
 
4716
        colorMap->getCMYK(pixBuf, &cmyk);
 
4717
        lineBuf[4*x+0] = colToByte(cmyk.c);
 
4718
        lineBuf[4*x+1] = colToByte(cmyk.m);
 
4719
        lineBuf[4*x+2] = colToByte(cmyk.y);
 
4720
        lineBuf[4*x+3] = colToByte(cmyk.k);
 
4721
        addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
 
4722
                        colToDbl(cmyk.y), colToDbl(cmyk.k));
 
4723
      }
 
4724
    } else {
 
4725
      for (x = 0; x < width; ++x) {
 
4726
        imgStr->getPixel(pixBuf);
 
4727
        colorMap->getCMYK(pixBuf, &cmyk);
 
4728
        lineBuf[4*x+0] = colToByte(cmyk.c);
 
4729
        lineBuf[4*x+1] = colToByte(cmyk.m);
 
4730
        lineBuf[4*x+2] = colToByte(cmyk.y);
 
4731
        lineBuf[4*x+3] = colToByte(cmyk.k);
 
4732
      }
 
4733
    }
 
4734
 
 
4735
    // write one line of each color component
 
4736
    for (comp = 0; comp < 4; ++comp) {
 
4737
      for (x = 0; x < width; ++x) {
 
4738
        digit = lineBuf[4*x + comp] / 16;
 
4739
        hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
 
4740
        digit = lineBuf[4*x + comp] % 16;
 
4741
        hexBuf[i++] = digit + ((digit >= 10)? 'a'-10: '0');
 
4742
        if (i >= 64) {
 
4743
          hexBuf[i++] = '\n';
 
4744
          writePSBuf(hexBuf, i);
 
4745
          i = 0;
 
4746
        }
 
4747
      }
 
4748
    }
 
4749
  }
 
4750
 
 
4751
  if (i != 0) {
 
4752
    hexBuf[i++] = '\n';
 
4753
    writePSBuf(hexBuf, i);
 
4754
  }
 
4755
 
 
4756
  str->close();
 
4757
  delete imgStr;
 
4758
  gfree(lineBuf);
 
4759
 
 
4760
  if (maskStr && !(maskColors && colorMap)) {
 
4761
    writePS("pdfImClipEnd\n");
 
4762
  }
 
4763
}
 
4764
 
 
4765
void PSOutputDev::maskToClippingPath(Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) {
 
4766
  ImageStream *imgStr;
 
4767
  Guchar *line;
 
4768
  PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
 
4769
  int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
 
4770
  GBool emitRect, addRect, extendRect;
 
4771
  int i, x0, x1, y, maskXor;
 
4772
 
 
4773
  imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
 
4774
  imgStr->reset();
 
4775
  rects0Len = rects1Len = rectsOutLen = 0;
 
4776
  rectsSize = rectsOutSize = 64;
 
4777
  rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
 
4778
  rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
 
4779
  rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect));
 
4780
  maskXor = maskInvert ? 1 : 0;
 
4781
  for (y = 0; y < maskHeight; ++y) {
 
4782
    if (!(line = imgStr->getLine())) {
 
4783
      break;
 
4784
    }
 
4785
    i = 0;
 
4786
    rects1Len = 0;
 
4787
    for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
 
4788
    for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
 
4789
    while (x0 < maskWidth || i < rects0Len) {
 
4790
      emitRect = addRect = extendRect = gFalse;
 
4791
      if (x0 >= maskWidth) {
 
4792
        emitRect = gTrue;
 
4793
      } else if (i >= rects0Len) {
 
4794
        addRect = gTrue;
 
4795
      } else if (rects0[i].x0 < x0) {
 
4796
        emitRect = gTrue;
 
4797
      } else if (x0 < rects0[i].x0) {
 
4798
        addRect = gTrue;
 
4799
      } else if (rects0[i].x1 == x1) {
 
4800
        extendRect = gTrue;
 
4801
      } else {
 
4802
        emitRect = addRect = gTrue;
 
4803
      }
 
4804
      if (emitRect) {
 
4805
        if (rectsOutLen == rectsOutSize) {
 
4806
          rectsOutSize *= 2;
 
4807
          rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
 
4808
        }
 
4809
        rectsOut[rectsOutLen].x0 = rects0[i].x0;
 
4810
        rectsOut[rectsOutLen].x1 = rects0[i].x1;
 
4811
        rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
 
4812
        rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
 
4813
        ++rectsOutLen;
 
4814
        ++i;
 
4815
      }
 
4816
      if (addRect || extendRect) {
 
4817
        if (rects1Len == rectsSize) {
 
4818
          rectsSize *= 2;
 
4819
          rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect));
 
4820
          rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect));
 
4821
        }
 
4822
        rects1[rects1Len].x0 = x0;
 
4823
        rects1[rects1Len].x1 = x1;
 
4824
        if (addRect) {
 
4825
          rects1[rects1Len].y0 = y;
 
4826
        }
 
4827
        if (extendRect) {
 
4828
          rects1[rects1Len].y0 = rects0[i].y0;
 
4829
          ++i;
 
4830
        }
 
4831
        ++rects1Len;
 
4832
        for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
 
4833
        for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
 
4834
      }
 
4835
    }
 
4836
    rectsTmp = rects0;
 
4837
    rects0 = rects1;
 
4838
    rects1 = rectsTmp;
 
4839
    i = rects0Len;
 
4840
    rects0Len = rects1Len;
 
4841
    rects1Len = i;
 
4842
  }
 
4843
  for (i = 0; i < rects0Len; ++i) {
 
4844
    if (rectsOutLen == rectsOutSize) {
 
4845
      rectsOutSize *= 2;
 
4846
      rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect));
 
4847
    }
 
4848
    rectsOut[rectsOutLen].x0 = rects0[i].x0;
 
4849
    rectsOut[rectsOutLen].x1 = rects0[i].x1;
 
4850
    rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
 
4851
    rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
 
4852
    ++rectsOutLen;
 
4853
  }
 
4854
  if (rectsOutLen < 65536/4) {
 
4855
    writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
 
4856
    for (i = 0; i < rectsOutLen; ++i) {
 
4857
      writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
 
4858
                 rectsOut[i].x0, rectsOut[i].y0,
 
4859
                 rectsOut[i].x1 - rectsOut[i].x0,
 
4860
                 rectsOut[i].y1 - rectsOut[i].y0);
 
4861
    }
 
4862
    writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
 
4863
  } else {
 
4864
    //  would be over the limit of array size.
 
4865
    //  make each rectangle path and clip.
 
4866
    writePS("gsave newpath\n");
 
4867
    for (i = 0; i < rectsOutLen; ++i) {
 
4868
      writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
 
4869
                 ((double)rectsOut[i].x0)/maskWidth,
 
4870
                 ((double)rectsOut[i].y0)/maskHeight,
 
4871
                 ((double)(rectsOut[i].x1 - rectsOut[i].x0))/maskWidth,
 
4872
                 ((double)(rectsOut[i].y1 - rectsOut[i].y0))/maskHeight);
 
4873
    }
 
4874
    writePS("clip\n");
 
4875
  }
 
4876
  gfree(rectsOut);
 
4877
  gfree(rects0);
 
4878
  gfree(rects1);
 
4879
  delete imgStr;
 
4880
  maskStr->close();
 
4881
}
 
4882
 
 
4883
void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
 
4884
                            GBool invert, GBool inlineImg,
 
4885
                            Stream *str, int width, int height, int len,
 
4886
                            int *maskColors, Stream *maskStr,
 
4887
                            int maskWidth, int maskHeight, GBool maskInvert) {
 
4888
  Stream *str2;
 
4889
  ImageStream *imgStr;
 
4890
  Guchar *line;
 
4891
  PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
 
4892
  int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
 
4893
  GBool emitRect, addRect, extendRect;
 
4894
  GooString *s;
 
4895
  int n, numComps;
 
4896
  GBool useRLE, useASCII, useASCIIHex, useCompressed;
 
4897
  GfxSeparationColorSpace *sepCS;
 
4898
  GfxColor color;
 
4899
  GfxCMYK cmyk;
 
4900
  int c;
 
4901
  int col, i, j, x0, x1, y;
 
4902
  char dataBuf[4096];
 
4903
  
 
4904
  rectsOutLen = 0;
 
4905
 
 
4906
  // color key masking
 
4907
  if (maskColors && colorMap && !inlineImg) {
 
4908
    // can't read the stream twice for inline images -- but masking
 
4909
    // isn't allowed with inline images anyway
 
4910
    numComps = colorMap->getNumPixelComps();
 
4911
    imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
 
4912
    imgStr->reset();
 
4913
    rects0Len = rects1Len = 0;
 
4914
    rectsSize = rectsOutSize = 64;
 
4915
    rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
 
4916
    rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
 
4917
    rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
 
4918
                                            sizeof(PSOutImgClipRect));
 
4919
    for (y = 0; y < height; ++y) {
 
4920
      if (!(line = imgStr->getLine())) {
 
4921
        break;
 
4922
      }
 
4923
      i = 0;
 
4924
      rects1Len = 0;
 
4925
      for (x0 = 0; x0 < width; ++x0) {
 
4926
        for (j = 0; j < numComps; ++j) {
 
4927
          if (line[x0*numComps+j] < maskColors[2*j] ||
 
4928
              line[x0*numComps+j] > maskColors[2*j+1]) {
 
4929
            break;
 
4930
          }
 
4931
        }
 
4932
        if (j < numComps) {
 
4933
          break;
 
4934
        }
 
4935
      }
 
4936
      for (x1 = x0; x1 < width; ++x1) {
 
4937
        for (j = 0; j < numComps; ++j) {
 
4938
          if (line[x1*numComps+j] < maskColors[2*j] ||
 
4939
              line[x1*numComps+j] > maskColors[2*j+1]) {
 
4940
            break;
 
4941
          }
 
4942
        }
 
4943
        if (j == numComps) {
 
4944
          break;
 
4945
        }
 
4946
      }
 
4947
      while (x0 < width || i < rects0Len) {
 
4948
        emitRect = addRect = extendRect = gFalse;
 
4949
        if (x0 >= width) {
 
4950
          emitRect = gTrue;
 
4951
        } else if (i >= rects0Len) {
 
4952
          addRect = gTrue;
 
4953
        } else if (rects0[i].x0 < x0) {
 
4954
          emitRect = gTrue;
 
4955
        } else if (x0 < rects0[i].x0) {
 
4956
          addRect = gTrue;
 
4957
        } else if (rects0[i].x1 == x1) {
 
4958
          extendRect = gTrue;
 
4959
        } else {
 
4960
          emitRect = addRect = gTrue;
 
4961
        }
 
4962
        if (emitRect) {
 
4963
          if (rectsOutLen == rectsOutSize) {
 
4964
            rectsOutSize *= 2;
 
4965
            rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
 
4966
                                                     sizeof(PSOutImgClipRect));
 
4967
          }
 
4968
          rectsOut[rectsOutLen].x0 = rects0[i].x0;
 
4969
          rectsOut[rectsOutLen].x1 = rects0[i].x1;
 
4970
          rectsOut[rectsOutLen].y0 = height - y - 1;
 
4971
          rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
 
4972
          ++rectsOutLen;
 
4973
          ++i;
 
4974
        }
 
4975
        if (addRect || extendRect) {
 
4976
          if (rects1Len == rectsSize) {
 
4977
            rectsSize *= 2;
 
4978
            rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
 
4979
                                                   sizeof(PSOutImgClipRect));
 
4980
            rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
 
4981
                                                   sizeof(PSOutImgClipRect));
 
4982
          }
 
4983
          rects1[rects1Len].x0 = x0;
 
4984
          rects1[rects1Len].x1 = x1;
 
4985
          if (addRect) {
 
4986
            rects1[rects1Len].y0 = y;
 
4987
          }
 
4988
          if (extendRect) {
 
4989
            rects1[rects1Len].y0 = rects0[i].y0;
 
4990
            ++i;
 
4991
          }
 
4992
          ++rects1Len;
 
4993
          for (x0 = x1; x0 < width; ++x0) {
 
4994
            for (j = 0; j < numComps; ++j) {
 
4995
              if (line[x0*numComps+j] < maskColors[2*j] ||
 
4996
                  line[x0*numComps+j] > maskColors[2*j+1]) {
 
4997
                break;
 
4998
              }
 
4999
            }
 
5000
            if (j < numComps) {
 
5001
              break;
 
5002
            }
 
5003
          }
 
5004
          for (x1 = x0; x1 < width; ++x1) {
 
5005
            for (j = 0; j < numComps; ++j) {
 
5006
              if (line[x1*numComps+j] < maskColors[2*j] ||
 
5007
                  line[x1*numComps+j] > maskColors[2*j+1]) {
 
5008
                break;
 
5009
              }
 
5010
            }
 
5011
            if (j == numComps) {
 
5012
              break;
 
5013
            }
 
5014
          }
 
5015
        }
 
5016
      }
 
5017
      rectsTmp = rects0;
 
5018
      rects0 = rects1;
 
5019
      rects1 = rectsTmp;
 
5020
      i = rects0Len;
 
5021
      rects0Len = rects1Len;
 
5022
      rects1Len = i;
 
5023
    }
 
5024
    for (i = 0; i < rects0Len; ++i) {
 
5025
      if (rectsOutLen == rectsOutSize) {
 
5026
        rectsOutSize *= 2;
 
5027
        rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
 
5028
                                                 sizeof(PSOutImgClipRect));
 
5029
      }
 
5030
      rectsOut[rectsOutLen].x0 = rects0[i].x0;
 
5031
      rectsOut[rectsOutLen].x1 = rects0[i].x1;
 
5032
      rectsOut[rectsOutLen].y0 = height - y - 1;
 
5033
      rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
 
5034
      ++rectsOutLen;
 
5035
    }
 
5036
    if (rectsOutLen < 65536/4) {
 
5037
      writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
 
5038
      for (i = 0; i < rectsOutLen; ++i) {
 
5039
        writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
 
5040
                   rectsOut[i].x0, rectsOut[i].y0,
 
5041
                   rectsOut[i].x1 - rectsOut[i].x0,
 
5042
                   rectsOut[i].y1 - rectsOut[i].y0);
 
5043
      }
 
5044
      writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height);
 
5045
    } else {
 
5046
      //  would be over the limit of array size.
 
5047
      //  make each rectangle path and clip.
 
5048
      writePS("gsave newpath\n");
 
5049
      for (i = 0; i < rectsOutLen; ++i) {
 
5050
        writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n",
 
5051
                   ((double)rectsOut[i].x0)/width,
 
5052
                   ((double)rectsOut[i].y0)/height,
 
5053
                   ((double)(rectsOut[i].x1 - rectsOut[i].x0))/width,
 
5054
                   ((double)(rectsOut[i].y1 - rectsOut[i].y0))/height);
 
5055
      }
 
5056
      writePS("clip\n");
 
5057
    }
 
5058
    gfree(rectsOut);
 
5059
    gfree(rects0);
 
5060
    gfree(rects1);
 
5061
    delete imgStr;
 
5062
    str->close();
 
5063
 
 
5064
  // explicit masking
 
5065
  } else if (maskStr) {
 
5066
    maskToClippingPath(maskStr, maskWidth, maskHeight, maskInvert);
 
5067
  }
 
5068
 
 
5069
  // color space
 
5070
  if (colorMap) {
 
5071
    dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
 
5072
    writePS(" setcolorspace\n");
 
5073
  }
 
5074
 
 
5075
  useASCIIHex = globalParams->getPSASCIIHex();
 
5076
 
 
5077
  // set up the image data
 
5078
  if (mode == psModeForm || inType3Char || preload) {
 
5079
    if (inlineImg) {
 
5080
      // create an array
 
5081
      str2 = new FixedLengthEncoder(str, len);
 
5082
      str2 = new RunLengthEncoder(str2);
 
5083
      if (useASCIIHex) {
 
5084
        str2 = new ASCIIHexEncoder(str2);
 
5085
      } else {
 
5086
        str2 = new ASCII85Encoder(str2);
 
5087
      }
 
5088
      str2->reset();
 
5089
      col = 0;
 
5090
      writePS((char *)(useASCIIHex ? "[<" : "[<~"));
 
5091
      do {
 
5092
        do {
 
5093
          c = str2->getChar();
 
5094
        } while (c == '\n' || c == '\r');
 
5095
        if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
5096
          break;
 
5097
        }
 
5098
        if (c == 'z') {
 
5099
          writePSChar(c);
 
5100
          ++col;
 
5101
        } else {
 
5102
          writePSChar(c);
 
5103
          ++col;
 
5104
          for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
 
5105
            do {
 
5106
              c = str2->getChar();
 
5107
            } while (c == '\n' || c == '\r');
 
5108
            if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
5109
              break;
 
5110
            }
 
5111
            writePSChar(c);
 
5112
            ++col;
 
5113
          }
 
5114
        }
 
5115
        // each line is: "<~...data...~><eol>"
 
5116
        // so max data length = 255 - 6 = 249
 
5117
        // chunks are 1 or 5 bytes each, so we have to stop at 245
 
5118
        // but make it 240 just to be safe
 
5119
        if (col > 240) {
 
5120
          writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
 
5121
          col = 0;
 
5122
        }
 
5123
      } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
 
5124
      writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
 
5125
      // add an extra entry because the RunLengthDecode filter may
 
5126
      // read past the end
 
5127
      writePS("<>]\n");
 
5128
      writePS("0\n");
 
5129
      str2->close();
 
5130
      delete str2;
 
5131
    } else {
 
5132
      // make sure the image is setup, it sometimes is not like on bug #17645
 
5133
      setupImage(ref->getRef(), str);
 
5134
      // set up to use the array already created by setupImages()
 
5135
      writePSFmt("ImData_{0:d}_{1:d} 0 0\n",ref->getRefNum(), ref->getRefGen());
 
5136
    }
 
5137
  }
 
5138
 
 
5139
  // image dictionary
 
5140
  writePS("<<\n  /ImageType 1\n");
 
5141
 
 
5142
  // width, height, matrix, bits per component
 
5143
  writePSFmt("  /Width {0:d}\n", width);
 
5144
  writePSFmt("  /Height {0:d}\n", height);
 
5145
  writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
 
5146
             width, -height, height);
 
5147
  if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5148
    writePS("  /BitsPerComponent 8\n");
 
5149
  } else {
 
5150
    writePSFmt("  /BitsPerComponent {0:d}\n",
 
5151
               colorMap ? colorMap->getBits() : 1);
 
5152
  }
 
5153
 
 
5154
  // decode 
 
5155
  if (colorMap) {
 
5156
    writePS("  /Decode [");
 
5157
    if ((level == psLevel2Sep || level == psLevel3Sep) &&
 
5158
        colorMap->getColorSpace()->getMode() == csSeparation) {
 
5159
      // this matches up with the code in the pdfImSep operator
 
5160
      n = (1 << colorMap->getBits()) - 1;
 
5161
      writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
 
5162
                 colorMap->getDecodeHigh(0) * n);
 
5163
    } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5164
      numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
 
5165
                   getAlt()->getNComps();
 
5166
      for (i = 0; i < numComps; ++i) {
 
5167
        if (i > 0) {
 
5168
          writePS(" ");
 
5169
        }
 
5170
        writePS("0 1");
 
5171
      }
 
5172
    } else {
 
5173
      numComps = colorMap->getNumPixelComps();
 
5174
      for (i = 0; i < numComps; ++i) {
 
5175
        if (i > 0) {
 
5176
          writePS(" ");
 
5177
        }
 
5178
        writePSFmt("{0:.4g} {1:.4g}",
 
5179
                   colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
 
5180
      }
 
5181
    }
 
5182
    writePS("]\n");
 
5183
  } else {
 
5184
    writePSFmt("  /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
 
5185
  }
 
5186
 
 
5187
  // data source
 
5188
  if (mode == psModeForm || inType3Char || preload) {
 
5189
    if (inlineImg) {
 
5190
      writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
 
5191
    } else {
 
5192
      writePS("  /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
 
5193
        " index get 1 index get exch 1 add exch }\n");
 
5194
    }
 
5195
  } else {
 
5196
    writePS("  /DataSource currentfile\n");
 
5197
  }
 
5198
 
 
5199
  // filters
 
5200
  s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
 
5201
                       "    ");
 
5202
  if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
 
5203
      inlineImg || !s) {
 
5204
    useRLE = gTrue;
 
5205
    useASCII = !(mode == psModeForm || inType3Char || preload);
 
5206
    useCompressed = gFalse;
 
5207
  } else {
 
5208
    useRLE = gFalse;
 
5209
    useASCII = str->isBinary() &&
 
5210
               !(mode == psModeForm || inType3Char || preload);
 
5211
    useCompressed = gTrue;
 
5212
  }
 
5213
  if (useASCII) {
 
5214
    writePSFmt("    /ASCII{0:s}Decode filter\n",
 
5215
               useASCIIHex ? "Hex" : "85");
 
5216
  }
 
5217
  if (useRLE) {
 
5218
    writePS("    /RunLengthDecode filter\n");
 
5219
  }
 
5220
  if (useCompressed) {
 
5221
    writePS(s->getCString());
 
5222
  }
 
5223
  if (s) {
 
5224
    delete s;
 
5225
  }
 
5226
 
 
5227
  if (mode == psModeForm || inType3Char || preload) {
 
5228
 
 
5229
    // end of image dictionary
 
5230
    writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask");
 
5231
 
 
5232
    // get rid of the array and index
 
5233
    if (!inlineImg) writePS("pop ");
 
5234
    writePS("pop pop\n");
 
5235
 
 
5236
  } else {
 
5237
 
 
5238
    // cut off inline image streams at appropriate length
 
5239
    if (inlineImg) {
 
5240
      str = new FixedLengthEncoder(str, len);
 
5241
    } else if (useCompressed) {
 
5242
      str = str->getUndecodedStream();
 
5243
    }
 
5244
 
 
5245
    // recode DeviceN data
 
5246
    if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5247
      str = new DeviceNRecoder(str, width, height, colorMap);
 
5248
    }
 
5249
 
 
5250
    // add RunLengthEncode and ASCIIHex/85 encode filters
 
5251
    if (useRLE) {
 
5252
      str = new RunLengthEncoder(str);
 
5253
    }
 
5254
    if (useASCII) {
 
5255
      if (useASCIIHex) {
 
5256
        str = new ASCIIHexEncoder(str);
 
5257
      } else {
 
5258
        str = new ASCII85Encoder(str);
 
5259
      }
 
5260
    }
 
5261
 
 
5262
    // end of image dictionary
 
5263
    writePS(">>\n");
 
5264
#if OPI_SUPPORT
 
5265
    if (opi13Nest) {
 
5266
      if (inlineImg) {
 
5267
        // this can't happen -- OPI dictionaries are in XObjects
 
5268
        error(-1, "Internal: OPI in inline image");
 
5269
        n = 0;
 
5270
      } else {
 
5271
        // need to read the stream to count characters -- the length
 
5272
        // is data-dependent (because of ASCII and RLE filters)
 
5273
        str->reset();
 
5274
        n = 0;
 
5275
        while ((c = str->getChar()) != EOF) {
 
5276
          ++n;
 
5277
        }
 
5278
        str->close();
 
5279
      }
 
5280
      // +6/7 for "pdfIm\n" / "pdfImM\n"
 
5281
      // +8 for newline + trailer
 
5282
      n += colorMap ? 14 : 15;
 
5283
      writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n);
 
5284
    }
 
5285
#endif
 
5286
    if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
 
5287
        colorMap->getColorSpace()->getMode() == csSeparation) {
 
5288
      color.c[0] = gfxColorComp1;
 
5289
      sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
 
5290
      sepCS->getCMYK(&color, &cmyk);
 
5291
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
 
5292
                 colToDbl(cmyk.c), colToDbl(cmyk.m),
 
5293
                 colToDbl(cmyk.y), colToDbl(cmyk.k),
 
5294
                 sepCS->getName());
 
5295
    } else {
 
5296
      writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
 
5297
    }
 
5298
 
 
5299
    // copy the stream data
 
5300
    str->reset();
 
5301
    i = 0;
 
5302
    while ((c = str->getChar()) != EOF) {
 
5303
      dataBuf[i++] = c;
 
5304
      if (i >= (int)sizeof(dataBuf)) {
 
5305
        writePSBuf(dataBuf, i);
 
5306
        i = 0;
 
5307
      }
 
5308
    }
 
5309
    if (i > 0) {
 
5310
      writePSBuf(dataBuf, i);
 
5311
    }
 
5312
    str->close();
 
5313
 
 
5314
    // add newline and trailer to the end
 
5315
    writePSChar('\n');
 
5316
    writePS("%-EOD-\n");
 
5317
#if OPI_SUPPORT
 
5318
    if (opi13Nest) {
 
5319
      writePS("%%EndData\n");
 
5320
    }
 
5321
#endif
 
5322
 
 
5323
    // delete encoders
 
5324
    if (useRLE || useASCII || inlineImg) {
 
5325
      delete str;
 
5326
    }
 
5327
  }
 
5328
 
 
5329
  if ((maskColors && colorMap && !inlineImg) || maskStr) {
 
5330
    if (rectsOutLen < 65536/4) {
 
5331
        writePS("pdfImClipEnd\n");
 
5332
    } else {
 
5333
        writePS("grestore\n");
 
5334
    }
 
5335
  }
 
5336
}
 
5337
 
 
5338
//~ this doesn't currently support OPI
 
5339
void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
 
5340
                            GBool invert, GBool inlineImg,
 
5341
                            Stream *str, int width, int height, int len,
 
5342
                            int *maskColors, Stream *maskStr,
 
5343
                            int maskWidth, int maskHeight, GBool maskInvert) {
 
5344
  Stream *str2;
 
5345
  GooString *s;
 
5346
  int n, numComps;
 
5347
  GBool useRLE, useASCII, useASCIIHex, useCompressed;
 
5348
  GBool maskUseRLE, maskUseASCII, maskUseCompressed;
 
5349
  GfxSeparationColorSpace *sepCS;
 
5350
  GfxColor color;
 
5351
  GfxCMYK cmyk;
 
5352
  int c;
 
5353
  int col, i;
 
5354
 
 
5355
  useASCIIHex = globalParams->getPSASCIIHex();
 
5356
  useRLE = useASCII = useCompressed = gFalse; // make gcc happy
 
5357
  maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
 
5358
 
 
5359
  // color space
 
5360
  if (colorMap) {
 
5361
    dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
 
5362
    writePS(" setcolorspace\n");
 
5363
  }
 
5364
 
 
5365
  // set up the image data
 
5366
  if (mode == psModeForm || inType3Char || preload) {
 
5367
    if (inlineImg) {
 
5368
      // create an array
 
5369
      str2 = new FixedLengthEncoder(str, len);
 
5370
      str2 = new RunLengthEncoder(str2);
 
5371
      if (useASCIIHex) {
 
5372
        str2 = new ASCIIHexEncoder(str2);
 
5373
      } else {
 
5374
        str2 = new ASCII85Encoder(str2);
 
5375
      }
 
5376
      str2->reset();
 
5377
      col = 0;
 
5378
      writePS((char *)(useASCIIHex ? "[<" : "[<~"));
 
5379
      do {
 
5380
        do {
 
5381
          c = str2->getChar();
 
5382
        } while (c == '\n' || c == '\r');
 
5383
        if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
5384
          break;
 
5385
        }
 
5386
        if (c == 'z') {
 
5387
          writePSChar(c);
 
5388
          ++col;
 
5389
        } else {
 
5390
          writePSChar(c);
 
5391
          ++col;
 
5392
          for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
 
5393
            do {
 
5394
              c = str2->getChar();
 
5395
            } while (c == '\n' || c == '\r');
 
5396
            if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
 
5397
              break;
 
5398
            }
 
5399
            writePSChar(c);
 
5400
            ++col;
 
5401
          }
 
5402
        }
 
5403
        // each line is: "<~...data...~><eol>"
 
5404
        // so max data length = 255 - 6 = 249
 
5405
        // chunks are 1 or 5 bytes each, so we have to stop at 245
 
5406
        // but make it 240 just to be safe
 
5407
        if (col > 240) {
 
5408
          writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
 
5409
          col = 0;
 
5410
        }
 
5411
      } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
 
5412
      writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
 
5413
      // add an extra entry because the RunLengthDecode filter may
 
5414
      // read past the end
 
5415
      writePS("<>]\n");
 
5416
      writePS("0\n");
 
5417
      str2->close();
 
5418
      delete str2;
 
5419
    } else {
 
5420
      // make sure the image is setup, it sometimes is not like on bug #17645
 
5421
      setupImage(ref->getRef(), str);
 
5422
      // set up to use the array already created by setupImages()
 
5423
      writePSFmt("ImData_{0:d}_{1:d} 0 0\n", ref->getRefNum(), ref->getRefGen());
 
5424
    }
 
5425
  }
 
5426
 
 
5427
  // explicit masking
 
5428
  if (maskStr) {
 
5429
    writePS("<<\n  /ImageType 3\n");
 
5430
    writePS("  /InterleaveType 3\n");
 
5431
    writePS("  /DataDict\n");
 
5432
  }
 
5433
 
 
5434
  // image (data) dictionary
 
5435
  writePSFmt("<<\n  /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
 
5436
 
 
5437
  // color key masking
 
5438
  if (maskColors && colorMap) {
 
5439
    writePS("  /MaskColor [\n");
 
5440
    numComps = colorMap->getNumPixelComps();
 
5441
    for (i = 0; i < 2 * numComps; i += 2) {
 
5442
      writePSFmt("    {0:d} {1:d}\n", maskColors[i], maskColors[i+1]);
 
5443
    }
 
5444
    writePS("  ]\n");
 
5445
  }
 
5446
 
 
5447
  // width, height, matrix, bits per component
 
5448
  writePSFmt("  /Width {0:d}\n", width);
 
5449
  writePSFmt("  /Height {0:d}\n", height);
 
5450
  writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
 
5451
             width, -height, height);
 
5452
  if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5453
    writePS("  /BitsPerComponent 8\n");
 
5454
  } else {
 
5455
    writePSFmt("  /BitsPerComponent {0:d}\n",
 
5456
               colorMap ? colorMap->getBits() : 1);
 
5457
  }
 
5458
 
 
5459
  // decode 
 
5460
  if (colorMap) {
 
5461
    writePS("  /Decode [");
 
5462
    if ((level == psLevel2Sep || level == psLevel3Sep) &&
 
5463
        colorMap->getColorSpace()->getMode() == csSeparation) {
 
5464
      // this matches up with the code in the pdfImSep operator
 
5465
      n = (1 << colorMap->getBits()) - 1;
 
5466
      writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
 
5467
                 colorMap->getDecodeHigh(0) * n);
 
5468
    } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5469
      numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
 
5470
                   getAlt()->getNComps();
 
5471
      for (i = 0; i < numComps; ++i) {
 
5472
        if (i > 0) {
 
5473
          writePS(" ");
 
5474
        }
 
5475
        writePS("0 1");
 
5476
      }
 
5477
    } else {
 
5478
      numComps = colorMap->getNumPixelComps();
 
5479
      for (i = 0; i < numComps; ++i) {
 
5480
        if (i > 0) {
 
5481
          writePS(" ");
 
5482
        }
 
5483
        writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i),
 
5484
                   colorMap->getDecodeHigh(i));
 
5485
      }
 
5486
    }
 
5487
    writePS("]\n");
 
5488
  } else {
 
5489
    writePSFmt("  /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
 
5490
  }
 
5491
 
 
5492
  // data source
 
5493
  if (mode == psModeForm || inType3Char || preload) {
 
5494
    if (inlineImg) {
 
5495
        writePS("  /DataSource { 2 copy get exch 1 add exch }\n");
 
5496
    } else {
 
5497
        writePS("  /DataSource { dup 65535 ge { pop 1 add 0 } if 2 index 2"
 
5498
          " index get 1 index get exch 1 add exch }\n");
 
5499
    }
 
5500
  } else {
 
5501
    writePS("  /DataSource currentfile\n");
 
5502
  }
 
5503
 
 
5504
  // filters
 
5505
  s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
 
5506
                       "    ");
 
5507
  if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
 
5508
      inlineImg || !s) {
 
5509
    useRLE = gTrue;
 
5510
    useASCII = !(mode == psModeForm || inType3Char || preload);
 
5511
    useCompressed = gFalse;
 
5512
  } else {
 
5513
    useRLE = gFalse;
 
5514
    useASCII = str->isBinary() &&
 
5515
               !(mode == psModeForm || inType3Char || preload);
 
5516
    useCompressed = gTrue;
 
5517
  }
 
5518
  if (useASCII) {
 
5519
    writePSFmt("    /ASCII{0:s}Decode filter\n",
 
5520
               useASCIIHex ? "Hex" : "85");
 
5521
  }
 
5522
  if (useRLE) {
 
5523
    writePS("    /RunLengthDecode filter\n");
 
5524
  }
 
5525
  if (useCompressed) {
 
5526
    writePS(s->getCString());
 
5527
  }
 
5528
  if (s) {
 
5529
    delete s;
 
5530
  }
 
5531
 
 
5532
  // end of image (data) dictionary
 
5533
  writePS(">>\n");
 
5534
 
 
5535
  // explicit masking
 
5536
  if (maskStr) {
 
5537
    writePS("  /MaskDict\n");
 
5538
    writePS("<<\n");
 
5539
    writePS("  /ImageType 1\n");
 
5540
    writePSFmt("  /Width {0:d}\n", maskWidth);
 
5541
    writePSFmt("  /Height {0:d}\n", maskHeight);
 
5542
    writePSFmt("  /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
 
5543
               maskWidth, -maskHeight, maskHeight);
 
5544
    writePS("  /BitsPerComponent 1\n");
 
5545
    writePSFmt("  /Decode [{0:d} {1:d}]\n",
 
5546
               maskInvert ? 1 : 0, maskInvert ? 0 : 1);
 
5547
 
 
5548
    // mask data source
 
5549
    writePS("  /DataSource currentfile\n");
 
5550
    s = maskStr->getPSFilter(3, "    ");
 
5551
    if (!s) {
 
5552
      maskUseRLE = gTrue;
 
5553
      maskUseASCII = gTrue;
 
5554
      maskUseCompressed = gFalse;
 
5555
    } else {
 
5556
      maskUseRLE = gFalse;
 
5557
      maskUseASCII = maskStr->isBinary();
 
5558
      maskUseCompressed = gTrue;
 
5559
    }
 
5560
    if (maskUseASCII) {
 
5561
      writePSFmt("    /ASCII{0:s}Decode filter\n",
 
5562
                 useASCIIHex ? "Hex" : "85");
 
5563
    }
 
5564
    if (maskUseRLE) {
 
5565
      writePS("    /RunLengthDecode filter\n");
 
5566
    }
 
5567
    if (maskUseCompressed) {
 
5568
      writePS(s->getCString());
 
5569
    }
 
5570
    if (s) {
 
5571
      delete s;
 
5572
    }
 
5573
 
 
5574
    writePS(">>\n");
 
5575
    writePS(">>\n");
 
5576
  }
 
5577
 
 
5578
  if (mode == psModeForm || inType3Char || preload) {
 
5579
 
 
5580
    // image command
 
5581
    writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask");
 
5582
 
 
5583
  } else {
 
5584
 
 
5585
    if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
 
5586
        colorMap->getColorSpace()->getMode() == csSeparation) {
 
5587
      color.c[0] = gfxColorComp1;
 
5588
      sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
 
5589
      sepCS->getCMYK(&color, &cmyk);
 
5590
      writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
 
5591
                 colToDbl(cmyk.c), colToDbl(cmyk.m),
 
5592
                 colToDbl(cmyk.y), colToDbl(cmyk.k),
 
5593
                 sepCS->getName());
 
5594
    } else {
 
5595
      writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
 
5596
    }
 
5597
 
 
5598
  }
 
5599
 
 
5600
  // explicit masking
 
5601
  if (maskStr) {
 
5602
 
 
5603
    if (maskUseCompressed) {
 
5604
      maskStr = maskStr->getUndecodedStream();
 
5605
    }
 
5606
 
 
5607
    // add RunLengthEncode and ASCIIHex/85 encode filters
 
5608
    if (maskUseRLE) {
 
5609
      maskStr = new RunLengthEncoder(maskStr);
 
5610
    }
 
5611
    if (maskUseASCII) {
 
5612
      if (useASCIIHex) {
 
5613
        maskStr = new ASCIIHexEncoder(maskStr);
 
5614
      } else {
 
5615
        maskStr = new ASCII85Encoder(maskStr);
 
5616
      }
 
5617
    }
 
5618
 
 
5619
    // copy the stream data
 
5620
    maskStr->reset();
 
5621
    while ((c = maskStr->getChar()) != EOF) {
 
5622
      writePSChar(c);
 
5623
    }
 
5624
    maskStr->close();
 
5625
    writePSChar('\n');
 
5626
 
 
5627
    // delete encoders
 
5628
    if (maskUseRLE || maskUseASCII) {
 
5629
      delete maskStr;
 
5630
    }
 
5631
  }
 
5632
 
 
5633
  // get rid of the array and index
 
5634
  if (mode == psModeForm || inType3Char || preload) {
 
5635
    if (!inlineImg) writePS("pop ");
 
5636
    writePS("pop pop\n");
 
5637
 
 
5638
  // image data
 
5639
  } else {
 
5640
 
 
5641
    // cut off inline image streams at appropriate length
 
5642
    if (inlineImg) {
 
5643
      str = new FixedLengthEncoder(str, len);
 
5644
    } else if (useCompressed) {
 
5645
      str = str->getUndecodedStream();
 
5646
    }
 
5647
 
 
5648
    // recode DeviceN data
 
5649
    if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
 
5650
      str = new DeviceNRecoder(str, width, height, colorMap);
 
5651
    }
 
5652
 
 
5653
    // add RunLengthEncode and ASCIIHex/85 encode filters
 
5654
    if (useRLE) {
 
5655
      str = new RunLengthEncoder(str);
 
5656
    }
 
5657
    if (useASCII) {
 
5658
      if (useASCIIHex) {
 
5659
        str = new ASCIIHexEncoder(str);
 
5660
      } else {
 
5661
        str = new ASCII85Encoder(str);
 
5662
      }
 
5663
    }
 
5664
 
 
5665
    // copy the stream data
 
5666
    str->reset();
 
5667
    while ((c = str->getChar()) != EOF) {
 
5668
      writePSChar(c);
 
5669
    }
 
5670
    str->close();
 
5671
 
 
5672
    // add newline and trailer to the end
 
5673
    writePSChar('\n');
 
5674
    writePS("%-EOD-\n");
 
5675
 
 
5676
    // delete encoders
 
5677
    if (useRLE || useASCII || inlineImg) {
 
5678
      delete str;
 
5679
    }
 
5680
  }
 
5681
}
 
5682
 
 
5683
void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
 
5684
                                   GBool genXform, GBool updateColors,
 
5685
                                   GBool map01) {
 
5686
  GfxCalGrayColorSpace *calGrayCS;
 
5687
  GfxCalRGBColorSpace *calRGBCS;
 
5688
  GfxLabColorSpace *labCS;
 
5689
  GfxIndexedColorSpace *indexedCS;
 
5690
  GfxSeparationColorSpace *separationCS;
 
5691
  GfxDeviceNColorSpace *deviceNCS;
 
5692
  GfxColorSpace *baseCS;
 
5693
  Guchar *lookup, *p;
 
5694
  double x[gfxColorMaxComps], y[gfxColorMaxComps];
 
5695
  double low[gfxColorMaxComps], range[gfxColorMaxComps];
 
5696
  GfxColor color;
 
5697
  GfxCMYK cmyk;
 
5698
  Function *func;
 
5699
  int n, numComps, numAltComps;
 
5700
  int byte;
 
5701
  int i, j, k;
 
5702
 
 
5703
  switch (colorSpace->getMode()) {
 
5704
 
 
5705
  case csDeviceGray:
 
5706
    writePS("/DeviceGray");
 
5707
    if (genXform) {
 
5708
      writePS(" {}");
 
5709
    }
 
5710
    if (updateColors) {
 
5711
      processColors |= psProcessBlack;
 
5712
    }
 
5713
    break;
 
5714
 
 
5715
  case csCalGray:
 
5716
    calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
 
5717
    writePS("[/CIEBasedA <<\n");
 
5718
    writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
 
5719
    writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5720
               calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
 
5721
               calGrayCS->getWhiteZ());
 
5722
    writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5723
               calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
 
5724
               calGrayCS->getWhiteZ());
 
5725
    writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5726
               calGrayCS->getBlackX(), calGrayCS->getBlackY(),
 
5727
               calGrayCS->getBlackZ());
 
5728
    writePS(">>]");
 
5729
    if (genXform) {
 
5730
      writePS(" {}");
 
5731
    }
 
5732
    if (updateColors) {
 
5733
      processColors |= psProcessBlack;
 
5734
    }
 
5735
    break;
 
5736
 
 
5737
  case csDeviceRGB:
 
5738
    writePS("/DeviceRGB");
 
5739
    if (genXform) {
 
5740
      writePS(" {}");
 
5741
    }
 
5742
    if (updateColors) {
 
5743
      processColors |= psProcessCMYK;
 
5744
    }
 
5745
    break;
 
5746
 
 
5747
  case csCalRGB:
 
5748
    calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
 
5749
    writePS("[/CIEBasedABC <<\n");
 
5750
    writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
 
5751
               calRGBCS->getGammaR(), calRGBCS->getGammaG(),
 
5752
               calRGBCS->getGammaB());
 
5753
    writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
 
5754
               calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
 
5755
               calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
 
5756
               calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
 
5757
               calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
 
5758
               calRGBCS->getMatrix()[8]);
 
5759
    writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5760
               calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
 
5761
               calRGBCS->getWhiteZ());
 
5762
    writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5763
               calRGBCS->getBlackX(), calRGBCS->getBlackY(),
 
5764
               calRGBCS->getBlackZ());
 
5765
    writePS(">>]");
 
5766
    if (genXform) {
 
5767
      writePS(" {}");
 
5768
    }
 
5769
    if (updateColors) {
 
5770
      processColors |= psProcessCMYK;
 
5771
    }
 
5772
    break;
 
5773
 
 
5774
  case csDeviceCMYK:
 
5775
    writePS("/DeviceCMYK");
 
5776
    if (genXform) {
 
5777
      writePS(" {}");
 
5778
    }
 
5779
    if (updateColors) {
 
5780
      processColors |= psProcessCMYK;
 
5781
    }
 
5782
    break;
 
5783
 
 
5784
  case csLab:
 
5785
    labCS = (GfxLabColorSpace *)colorSpace;
 
5786
    writePS("[/CIEBasedABC <<\n");
 
5787
    if (map01) {
 
5788
      writePS(" /RangeABC [0 1 0 1 0 1]\n");
 
5789
      writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
 
5790
                 (labCS->getAMax() - labCS->getAMin()) / 500.0,
 
5791
                 labCS->getAMin() / 500.0,
 
5792
                 (labCS->getBMax() - labCS->getBMin()) / 200.0,
 
5793
                 labCS->getBMin() / 200.0);
 
5794
    } else {
 
5795
      writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
 
5796
                 labCS->getAMin(), labCS->getAMax(),
 
5797
                 labCS->getBMin(), labCS->getBMax());
 
5798
      writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
 
5799
    }
 
5800
    writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
 
5801
    writePS(" /DecodeLMN\n");
 
5802
    writePS("   [{dup 6 29 div ge {dup dup mul mul}\n");
 
5803
    writePSFmt("     {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
 
5804
               labCS->getWhiteX());
 
5805
    writePS("    {dup 6 29 div ge {dup dup mul mul}\n");
 
5806
    writePSFmt("     {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
 
5807
               labCS->getWhiteY());
 
5808
    writePS("    {dup 6 29 div ge {dup dup mul mul}\n");
 
5809
    writePSFmt("     {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
 
5810
               labCS->getWhiteZ());
 
5811
    writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5812
               labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
 
5813
    writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
 
5814
               labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
 
5815
    writePS(">>]");
 
5816
    if (genXform) {
 
5817
      writePS(" {}");
 
5818
    }
 
5819
    if (updateColors) {
 
5820
      processColors |= psProcessCMYK;
 
5821
    }
 
5822
    break;
 
5823
 
 
5824
  case csICCBased:
 
5825
    // there is no transform function to the alternate color space, so
 
5826
    // we can use it directly
 
5827
    dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
 
5828
                     genXform, updateColors, gFalse);
 
5829
    break;
 
5830
 
 
5831
  case csIndexed:
 
5832
    indexedCS = (GfxIndexedColorSpace *)colorSpace;
 
5833
    baseCS = indexedCS->getBase();
 
5834
    writePS("[/Indexed ");
 
5835
    dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
 
5836
    n = indexedCS->getIndexHigh();
 
5837
    numComps = baseCS->getNComps();
 
5838
    lookup = indexedCS->getLookup();
 
5839
    writePSFmt(" {0:d} <\n", n);
 
5840
    if (baseCS->getMode() == csDeviceN) {
 
5841
      func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
 
5842
      baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
 
5843
      if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
 
5844
        labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
 
5845
      } else {
 
5846
        labCS = NULL;
 
5847
      }
 
5848
      numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
 
5849
      p = lookup;
 
5850
      for (i = 0; i <= n; i += 8) {
 
5851
        writePS("  ");
 
5852
        for (j = i; j < i+8 && j <= n; ++j) {
 
5853
          for (k = 0; k < numComps; ++k) {
 
5854
            x[k] = low[k] + (*p++ / 255.0) * range[k];
 
5855
          }
 
5856
          func->transform(x, y);
 
5857
          if (labCS) {
 
5858
            y[0] /= 100.0;
 
5859
            y[1] = (y[1] - labCS->getAMin()) /
 
5860
                   (labCS->getAMax() - labCS->getAMin());
 
5861
            y[2] = (y[2] - labCS->getBMin()) /
 
5862
                   (labCS->getBMax() - labCS->getBMin());
 
5863
          }
 
5864
          for (k = 0; k < numAltComps; ++k) {
 
5865
            byte = (int)(y[k] * 255 + 0.5);
 
5866
            if (byte < 0) {
 
5867
              byte = 0;
 
5868
            } else if (byte > 255) {
 
5869
              byte = 255;
 
5870
            }
 
5871
            writePSFmt("{0:02x}", byte);
 
5872
          }
 
5873
          if (updateColors) {
 
5874
            color.c[0] = dblToCol(j);
 
5875
            indexedCS->getCMYK(&color, &cmyk);
 
5876
            addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
 
5877
                            colToDbl(cmyk.y), colToDbl(cmyk.k));
 
5878
          }
 
5879
        }
 
5880
        writePS("\n");
 
5881
      }
 
5882
    } else {
 
5883
      for (i = 0; i <= n; i += 8) {
 
5884
        writePS("  ");
 
5885
        for (j = i; j < i+8 && j <= n; ++j) {
 
5886
          for (k = 0; k < numComps; ++k) {
 
5887
            writePSFmt("{0:02x}", lookup[j * numComps + k]);
 
5888
          }
 
5889
          if (updateColors) {
 
5890
            color.c[0] = dblToCol(j);
 
5891
            indexedCS->getCMYK(&color, &cmyk);
 
5892
            addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
 
5893
                            colToDbl(cmyk.y), colToDbl(cmyk.k));
 
5894
          }
 
5895
        }
 
5896
        writePS("\n");
 
5897
      }
 
5898
    }
 
5899
    writePS(">]");
 
5900
    if (genXform) {
 
5901
      writePS(" {}");
 
5902
    }
 
5903
    break;
 
5904
 
 
5905
  case csSeparation:
 
5906
    separationCS = (GfxSeparationColorSpace *)colorSpace;
 
5907
    writePS("[/Separation ");
 
5908
    writePSString(separationCS->getName());
 
5909
    writePS(" ");
 
5910
    dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
 
5911
    writePS("\n");
 
5912
    cvtFunction(separationCS->getFunc());
 
5913
    writePS("]");
 
5914
    if (genXform) {
 
5915
      writePS(" {}");
 
5916
    }
 
5917
    if (updateColors) {
 
5918
      addCustomColor(separationCS);
 
5919
    }
 
5920
    break;
 
5921
 
 
5922
  case csDeviceN:
 
5923
    // DeviceN color spaces are a Level 3 PostScript feature.
 
5924
    deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
 
5925
    dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
 
5926
    if (genXform) {
 
5927
      writePS(" ");
 
5928
      cvtFunction(deviceNCS->getTintTransformFunc());
 
5929
    }
 
5930
    break;
 
5931
 
 
5932
  case csPattern:
 
5933
    //~ unimplemented
 
5934
    break;
 
5935
  }
 
5936
}
 
5937
 
 
5938
#if OPI_SUPPORT
 
5939
void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
 
5940
  Object dict;
 
5941
 
 
5942
  if (globalParams->getPSOPI()) {
 
5943
    opiDict->lookup("2.0", &dict);
 
5944
    if (dict.isDict()) {
 
5945
      opiBegin20(state, dict.getDict());
 
5946
      dict.free();
 
5947
    } else {
 
5948
      dict.free();
 
5949
      opiDict->lookup("1.3", &dict);
 
5950
      if (dict.isDict()) {
 
5951
        opiBegin13(state, dict.getDict());
 
5952
      }
 
5953
      dict.free();
 
5954
    }
 
5955
  }
 
5956
}
 
5957
 
 
5958
void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
 
5959
  Object obj1, obj2, obj3, obj4;
 
5960
  double width, height, left, right, top, bottom;
 
5961
  int w, h;
 
5962
  int i;
 
5963
 
 
5964
  writePS("%%BeginOPI: 2.0\n");
 
5965
  writePS("%%Distilled\n");
 
5966
 
 
5967
  dict->lookup("F", &obj1);
 
5968
  if (getFileSpecName(&obj1, &obj2)) {
 
5969
    writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
 
5970
    obj2.free();
 
5971
  }
 
5972
  obj1.free();
 
5973
 
 
5974
  dict->lookup("MainImage", &obj1);
 
5975
  if (obj1.isString()) {
 
5976
    writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
 
5977
  }
 
5978
  obj1.free();
 
5979
 
 
5980
  //~ ignoring 'Tags' entry
 
5981
  //~ need to use writePSString() and deal with >255-char lines
 
5982
 
 
5983
  dict->lookup("Size", &obj1);
 
5984
  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
 
5985
    obj1.arrayGet(0, &obj2);
 
5986
    width = obj2.getNum();
 
5987
    obj2.free();
 
5988
    obj1.arrayGet(1, &obj2);
 
5989
    height = obj2.getNum();
 
5990
    obj2.free();
 
5991
    writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height);
 
5992
  }
 
5993
  obj1.free();
 
5994
 
 
5995
  dict->lookup("CropRect", &obj1);
 
5996
  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
 
5997
    obj1.arrayGet(0, &obj2);
 
5998
    left = obj2.getNum();
 
5999
    obj2.free();
 
6000
    obj1.arrayGet(1, &obj2);
 
6001
    top = obj2.getNum();
 
6002
    obj2.free();
 
6003
    obj1.arrayGet(2, &obj2);
 
6004
    right = obj2.getNum();
 
6005
    obj2.free();
 
6006
    obj1.arrayGet(3, &obj2);
 
6007
    bottom = obj2.getNum();
 
6008
    obj2.free();
 
6009
    writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 
6010
               left, top, right, bottom);
 
6011
  }
 
6012
  obj1.free();
 
6013
 
 
6014
  dict->lookup("Overprint", &obj1);
 
6015
  if (obj1.isBool()) {
 
6016
    writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
 
6017
  }
 
6018
  obj1.free();
 
6019
 
 
6020
  dict->lookup("Inks", &obj1);
 
6021
  if (obj1.isName()) {
 
6022
    writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
 
6023
  } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
 
6024
    obj1.arrayGet(0, &obj2);
 
6025
    if (obj2.isName()) {
 
6026
      writePSFmt("%%ImageInks: {0:s} {1:d}",
 
6027
                 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
 
6028
      for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
 
6029
        obj1.arrayGet(i, &obj3);
 
6030
        obj1.arrayGet(i+1, &obj4);
 
6031
        if (obj3.isString() && obj4.isNum()) {
 
6032
          writePS(" ");
 
6033
          writePSString(obj3.getString());
 
6034
          writePSFmt(" {0:.6g}", obj4.getNum());
 
6035
        }
 
6036
        obj3.free();
 
6037
        obj4.free();
 
6038
      }
 
6039
      writePS("\n");
 
6040
    }
 
6041
    obj2.free();
 
6042
  }
 
6043
  obj1.free();
 
6044
 
 
6045
  writePS("gsave\n");
 
6046
 
 
6047
  writePS("%%BeginIncludedImage\n");
 
6048
 
 
6049
  dict->lookup("IncludedImageDimensions", &obj1);
 
6050
  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
 
6051
    obj1.arrayGet(0, &obj2);
 
6052
    w = obj2.getInt();
 
6053
    obj2.free();
 
6054
    obj1.arrayGet(1, &obj2);
 
6055
    h = obj2.getInt();
 
6056
    obj2.free();
 
6057
    writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
 
6058
  }
 
6059
  obj1.free();
 
6060
 
 
6061
  dict->lookup("IncludedImageQuality", &obj1);
 
6062
  if (obj1.isNum()) {
 
6063
    writePSFmt("%%IncludedImageQuality: {0:.6g}\n", obj1.getNum());
 
6064
  }
 
6065
  obj1.free();
 
6066
 
 
6067
  ++opi20Nest;
 
6068
}
 
6069
 
 
6070
void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
 
6071
  Object obj1, obj2;
 
6072
  int left, right, top, bottom, samples, bits, width, height;
 
6073
  double c, m, y, k;
 
6074
  double llx, lly, ulx, uly, urx, ury, lrx, lry;
 
6075
  double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
 
6076
  double horiz, vert;
 
6077
  int i, j;
 
6078
 
 
6079
  writePS("save\n");
 
6080
  writePS("/opiMatrix2 matrix currentmatrix def\n");
 
6081
  writePS("opiMatrix setmatrix\n");
 
6082
 
 
6083
  dict->lookup("F", &obj1);
 
6084
  if (getFileSpecName(&obj1, &obj2)) {
 
6085
    writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
 
6086
    obj2.free();
 
6087
  }
 
6088
  obj1.free();
 
6089
 
 
6090
  dict->lookup("CropRect", &obj1);
 
6091
  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
 
6092
    obj1.arrayGet(0, &obj2);
 
6093
    left = obj2.getInt();
 
6094
    obj2.free();
 
6095
    obj1.arrayGet(1, &obj2);
 
6096
    top = obj2.getInt();
 
6097
    obj2.free();
 
6098
    obj1.arrayGet(2, &obj2);
 
6099
    right = obj2.getInt();
 
6100
    obj2.free();
 
6101
    obj1.arrayGet(3, &obj2);
 
6102
    bottom = obj2.getInt();
 
6103
    obj2.free();
 
6104
    writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
 
6105
               left, top, right, bottom);
 
6106
  }
 
6107
  obj1.free();
 
6108
 
 
6109
  dict->lookup("Color", &obj1);
 
6110
  if (obj1.isArray() && obj1.arrayGetLength() == 5) {
 
6111
    obj1.arrayGet(0, &obj2);
 
6112
    c = obj2.getNum();
 
6113
    obj2.free();
 
6114
    obj1.arrayGet(1, &obj2);
 
6115
    m = obj2.getNum();
 
6116
    obj2.free();
 
6117
    obj1.arrayGet(2, &obj2);
 
6118
    y = obj2.getNum();
 
6119
    obj2.free();
 
6120
    obj1.arrayGet(3, &obj2);
 
6121
    k = obj2.getNum();
 
6122
    obj2.free();
 
6123
    obj1.arrayGet(4, &obj2);
 
6124
    if (obj2.isString()) {
 
6125
      writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
 
6126
                 c, m, y, k);
 
6127
      writePSString(obj2.getString());
 
6128
      writePS("\n");
 
6129
    }
 
6130
    obj2.free();
 
6131
  }
 
6132
  obj1.free();
 
6133
 
 
6134
  dict->lookup("ColorType", &obj1);
 
6135
  if (obj1.isName()) {
 
6136
    writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
 
6137
  }
 
6138
  obj1.free();
 
6139
 
 
6140
  //~ ignores 'Comments' entry
 
6141
  //~ need to handle multiple lines
 
6142
 
 
6143
  dict->lookup("CropFixed", &obj1);
 
6144
  if (obj1.isArray()) {
 
6145
    obj1.arrayGet(0, &obj2);
 
6146
    ulx = obj2.getNum();
 
6147
    obj2.free();
 
6148
    obj1.arrayGet(1, &obj2);
 
6149
    uly = obj2.getNum();
 
6150
    obj2.free();
 
6151
    obj1.arrayGet(2, &obj2);
 
6152
    lrx = obj2.getNum();
 
6153
    obj2.free();
 
6154
    obj1.arrayGet(3, &obj2);
 
6155
    lry = obj2.getNum();
 
6156
    obj2.free();
 
6157
    writePSFmt("%ALDImageCropFixed: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
 
6158
               ulx, uly, lrx, lry);
 
6159
  }
 
6160
  obj1.free();
 
6161
 
 
6162
  dict->lookup("GrayMap", &obj1);
 
6163
  if (obj1.isArray()) {
 
6164
    writePS("%ALDImageGrayMap:");
 
6165
    for (i = 0; i < obj1.arrayGetLength(); i += 16) {
 
6166
      if (i > 0) {
 
6167
        writePS("\n%%+");
 
6168
      }
 
6169
      for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
 
6170
        obj1.arrayGet(i+j, &obj2);
 
6171
        writePSFmt(" {0:d}", obj2.getInt());
 
6172
        obj2.free();
 
6173
      }
 
6174
    }
 
6175
    writePS("\n");
 
6176
  }
 
6177
  obj1.free();
 
6178
 
 
6179
  dict->lookup("ID", &obj1);
 
6180
  if (obj1.isString()) {
 
6181
    writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
 
6182
  }
 
6183
  obj1.free();
 
6184
 
 
6185
  dict->lookup("ImageType", &obj1);
 
6186
  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
 
6187
    obj1.arrayGet(0, &obj2);
 
6188
    samples = obj2.getInt();
 
6189
    obj2.free();
 
6190
    obj1.arrayGet(1, &obj2);
 
6191
    bits = obj2.getInt();
 
6192
    obj2.free();
 
6193
    writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
 
6194
  }
 
6195
  obj1.free();
 
6196
 
 
6197
  dict->lookup("Overprint", &obj1);
 
6198
  if (obj1.isBool()) {
 
6199
    writePSFmt("%ALDImageOverprint: {0:s}\n",
 
6200
               obj1.getBool() ? "true" : "false");
 
6201
  }
 
6202
  obj1.free();
 
6203
 
 
6204
  dict->lookup("Position", &obj1);
 
6205
  if (obj1.isArray() && obj1.arrayGetLength() == 8) {
 
6206
    obj1.arrayGet(0, &obj2);
 
6207
    llx = obj2.getNum();
 
6208
    obj2.free();
 
6209
    obj1.arrayGet(1, &obj2);
 
6210
    lly = obj2.getNum();
 
6211
    obj2.free();
 
6212
    obj1.arrayGet(2, &obj2);
 
6213
    ulx = obj2.getNum();
 
6214
    obj2.free();
 
6215
    obj1.arrayGet(3, &obj2);
 
6216
    uly = obj2.getNum();
 
6217
    obj2.free();
 
6218
    obj1.arrayGet(4, &obj2);
 
6219
    urx = obj2.getNum();
 
6220
    obj2.free();
 
6221
    obj1.arrayGet(5, &obj2);
 
6222
    ury = obj2.getNum();
 
6223
    obj2.free();
 
6224
    obj1.arrayGet(6, &obj2);
 
6225
    lrx = obj2.getNum();
 
6226
    obj2.free();
 
6227
    obj1.arrayGet(7, &obj2);
 
6228
    lry = obj2.getNum();
 
6229
    obj2.free();
 
6230
    opiTransform(state, llx, lly, &tllx, &tlly);
 
6231
    opiTransform(state, ulx, uly, &tulx, &tuly);
 
6232
    opiTransform(state, urx, ury, &turx, &tury);
 
6233
    opiTransform(state, lrx, lry, &tlrx, &tlry);
 
6234
    writePSFmt("%ALDImagePosition: {0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} {6:.6g} {7:.6g}\n",
 
6235
               tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
 
6236
    obj2.free();
 
6237
  }
 
6238
  obj1.free();
 
6239
 
 
6240
  dict->lookup("Resolution", &obj1);
 
6241
  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
 
6242
    obj1.arrayGet(0, &obj2);
 
6243
    horiz = obj2.getNum();
 
6244
    obj2.free();
 
6245
    obj1.arrayGet(1, &obj2);
 
6246
    vert = obj2.getNum();
 
6247
    obj2.free();
 
6248
    writePSFmt("%ALDImageResoution: {0:.6g} {1:.6g}\n", horiz, vert);
 
6249
    obj2.free();
 
6250
  }
 
6251
  obj1.free();
 
6252
 
 
6253
  dict->lookup("Size", &obj1);
 
6254
  if (obj1.isArray() && obj1.arrayGetLength() == 2) {
 
6255
    obj1.arrayGet(0, &obj2);
 
6256
    width = obj2.getInt();
 
6257
    obj2.free();
 
6258
    obj1.arrayGet(1, &obj2);
 
6259
    height = obj2.getInt();
 
6260
    obj2.free();
 
6261
    writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
 
6262
  }
 
6263
  obj1.free();
 
6264
 
 
6265
  //~ ignoring 'Tags' entry
 
6266
  //~ need to use writePSString() and deal with >255-char lines
 
6267
 
 
6268
  dict->lookup("Tint", &obj1);
 
6269
  if (obj1.isNum()) {
 
6270
    writePSFmt("%ALDImageTint: {0:.6g}\n", obj1.getNum());
 
6271
  }
 
6272
  obj1.free();
 
6273
 
 
6274
  dict->lookup("Transparency", &obj1);
 
6275
  if (obj1.isBool()) {
 
6276
    writePSFmt("%ALDImageTransparency: {0:s}\n",
 
6277
               obj1.getBool() ? "true" : "false");
 
6278
  }
 
6279
  obj1.free();
 
6280
 
 
6281
  writePS("%%BeginObject: image\n");
 
6282
  writePS("opiMatrix2 setmatrix\n");
 
6283
  ++opi13Nest;
 
6284
}
 
6285
 
 
6286
// Convert PDF user space coordinates to PostScript default user space
 
6287
// coordinates.  This has to account for both the PDF CTM and the
 
6288
// PSOutputDev page-fitting transform.
 
6289
void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
 
6290
                               double *x1, double *y1) {
 
6291
  double t;
 
6292
 
 
6293
  state->transform(x0, y0, x1, y1);
 
6294
  *x1 += tx;
 
6295
  *y1 += ty;
 
6296
  if (rotate == 90) {
 
6297
    t = *x1;
 
6298
    *x1 = -*y1;
 
6299
    *y1 = t;
 
6300
  } else if (rotate == 180) {
 
6301
    *x1 = -*x1;
 
6302
    *y1 = -*y1;
 
6303
  } else if (rotate == 270) {
 
6304
    t = *x1;
 
6305
    *x1 = *y1;
 
6306
    *y1 = -t;
 
6307
  }
 
6308
  *x1 *= xScale;
 
6309
  *y1 *= yScale;
 
6310
}
 
6311
 
 
6312
void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
 
6313
  Object dict;
 
6314
 
 
6315
  if (globalParams->getPSOPI()) {
 
6316
    opiDict->lookup("2.0", &dict);
 
6317
    if (dict.isDict()) {
 
6318
      writePS("%%EndIncludedImage\n");
 
6319
      writePS("%%EndOPI\n");
 
6320
      writePS("grestore\n");
 
6321
      --opi20Nest;
 
6322
      dict.free();
 
6323
    } else {
 
6324
      dict.free();
 
6325
      opiDict->lookup("1.3", &dict);
 
6326
      if (dict.isDict()) {
 
6327
        writePS("%%EndObject\n");
 
6328
        writePS("restore\n");
 
6329
        --opi13Nest;
 
6330
      }
 
6331
      dict.free();
 
6332
    }
 
6333
  }
 
6334
}
 
6335
#endif // OPI_SUPPORT
 
6336
 
 
6337
void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
 
6338
  writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy);
 
6339
  writePS("q\n");
 
6340
  t3NeedsRestore = gTrue;
 
6341
}
 
6342
 
 
6343
void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
 
6344
                          double llx, double lly, double urx, double ury) {
 
6345
  t3WX = wx;
 
6346
  t3WY = wy;
 
6347
  t3LLX = llx;
 
6348
  t3LLY = lly;
 
6349
  t3URX = urx;
 
6350
  t3URY = ury;
 
6351
  t3String = new GooString();
 
6352
  writePS("q\n");
 
6353
  t3Cacheable = gTrue;
 
6354
  t3NeedsRestore = gTrue;
 
6355
}
 
6356
 
 
6357
void PSOutputDev::drawForm(Ref id) {
 
6358
  writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
 
6359
}
 
6360
 
 
6361
void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
 
6362
  Stream *str;
 
6363
  int c;
 
6364
 
 
6365
  if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
 
6366
    str = level1Stream;
 
6367
  } else {
 
6368
    str = psStream;
 
6369
  }
 
6370
  str->reset();
 
6371
  while ((c = str->getChar()) != EOF) {
 
6372
    writePSChar(c);
 
6373
  }
 
6374
  str->close();
 
6375
}
 
6376
 
 
6377
//~ can nextFunc be reset to 0 -- maybe at the start of each page?
 
6378
//~   or maybe at the start of each color space / pattern?
 
6379
void PSOutputDev::cvtFunction(Function *func) {
 
6380
  SampledFunction *func0;
 
6381
  ExponentialFunction *func2;
 
6382
  StitchingFunction *func3;
 
6383
  PostScriptFunction *func4;
 
6384
  int thisFunc, m, n, nSamples, i, j, k;
 
6385
 
 
6386
  switch (func->getType()) {
 
6387
 
 
6388
  case -1:                      // identity
 
6389
    writePS("{}\n");
 
6390
    break;
 
6391
 
 
6392
  case 0:                       // sampled
 
6393
    func0 = (SampledFunction *)func;
 
6394
    thisFunc = nextFunc++;
 
6395
    m = func0->getInputSize();
 
6396
    n = func0->getOutputSize();
 
6397
    nSamples = n;
 
6398
    for (i = 0; i < m; ++i) {
 
6399
      nSamples *= func0->getSampleSize(i);
 
6400
    }
 
6401
    writePSFmt("/xpdfSamples{0:d} [\n", thisFunc);
 
6402
    for (i = 0; i < nSamples; ++i) {
 
6403
      writePSFmt("{0:.6g}\n", func0->getSamples()[i]);
 
6404
    }
 
6405
    writePS("] def\n");
 
6406
    writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2);
 
6407
    // [e01] [efrac] x0 x1 ... xm-1
 
6408
    for (i = m-1; i >= 0; --i) {
 
6409
      // [e01] [efrac] x0 x1 ... xi
 
6410
      writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add\n",
 
6411
              func0->getDomainMin(i),
 
6412
              (func0->getEncodeMax(i) - func0->getEncodeMin(i)) /
 
6413
                (func0->getDomainMax(i) - func0->getDomainMin(i)),
 
6414
              func0->getEncodeMin(i));
 
6415
      // [e01] [efrac] x0 x1 ... xi-1 xi'
 
6416
      writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n",
 
6417
                 func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1);
 
6418
      // [e01] [efrac] x0 x1 ... xi-1 xi'
 
6419
      writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
 
6420
      // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
 
6421
      writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i);
 
6422
      // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
 
6423
      writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1);
 
6424
      // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
 
6425
      writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i);
 
6426
      // [e01] [efrac] x0 x1 ... xi-1
 
6427
    }
 
6428
    // [e01] [efrac]
 
6429
    for (i = 0; i < n; ++i) {
 
6430
      // [e01] [efrac] y(0) ... y(i-1)
 
6431
      for (j = 0; j < (1<<m); ++j) {
 
6432
        // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
 
6433
        writePSFmt("xpdfSamples{0:d}\n", thisFunc);
 
6434
        k = m - 1;
 
6435
        writePSFmt("{0:d} index {1:d} get\n", i+j+2, 2 * k + ((j >> k) & 1));
 
6436
        for (k = m - 2; k >= 0; --k) {
 
6437
          writePSFmt("{0:d} mul {1:d} index {2:d} get add\n",
 
6438
                     func0->getSampleSize(k),
 
6439
                     i + j + 3,
 
6440
                     2 * k + ((j >> k) & 1));
 
6441
        }
 
6442
        if (n > 1) {
 
6443
          writePSFmt("{0:d} mul {1:d} add ", n, i);
 
6444
        }
 
6445
        writePS("get\n");
 
6446
      }
 
6447
      // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
 
6448
      for (j = 0; j < m; ++j) {
 
6449
        // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
 
6450
        for (k = 0; k < (1 << (m - j)); k += 2) {
 
6451
          // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
 
6452
          writePSFmt("{0:d} index {1:d} get dup\n",
 
6453
                     i + k/2 + (1 << (m-j)) - k, j);
 
6454
          writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
 
6455
          writePSFmt("{0:d} 1 roll\n", k/2 + (1 << (m-j)) - k - 1);
 
6456
        }
 
6457
        // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
 
6458
      }
 
6459
      // [e01] [efrac] y(0) ... y(i-1) s
 
6460
      writePSFmt("{0:.6g} mul {1:.6g} add\n",
 
6461
                 func0->getDecodeMax(i) - func0->getDecodeMin(i),
 
6462
                 func0->getDecodeMin(i));
 
6463
      writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
 
6464
                 func0->getRangeMin(i), func0->getRangeMin(i),
 
6465
                 func0->getRangeMax(i), func0->getRangeMax(i));
 
6466
      // [e01] [efrac] y(0) ... y(i-1) y(i)
 
6467
    }
 
6468
    // [e01] [efrac] y(0) ... y(n-1)
 
6469
    writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n);
 
6470
    break;
 
6471
 
 
6472
  case 2:                       // exponential
 
6473
    func2 = (ExponentialFunction *)func;
 
6474
    n = func2->getOutputSize();
 
6475
    writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
 
6476
               func2->getDomainMin(0), func2->getDomainMin(0),
 
6477
               func2->getDomainMax(0), func2->getDomainMax(0));
 
6478
    // x
 
6479
    for (i = 0; i < n; ++i) {
 
6480
      // x y(0) .. y(i-1)
 
6481
      writePSFmt("{0:d} index {1:.6g} exp {2:.6g} mul {3:.6g} add\n",
 
6482
                 i, func2->getE(), func2->getC1()[i] - func2->getC0()[i],
 
6483
                 func2->getC0()[i]);
 
6484
      if (func2->getHasRange()) {
 
6485
        writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
 
6486
                   func2->getRangeMin(i), func2->getRangeMin(i),
 
6487
                   func2->getRangeMax(i), func2->getRangeMax(i));
 
6488
      }
 
6489
    }
 
6490
    // x y(0) .. y(n-1)
 
6491
    writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n);
 
6492
    break;
 
6493
 
 
6494
  case 3:                       // stitching
 
6495
    func3 = (StitchingFunction *)func;
 
6496
    thisFunc = nextFunc++;
 
6497
    for (i = 0; i < func3->getNumFuncs(); ++i) {
 
6498
      cvtFunction(func3->getFunc(i));
 
6499
      writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i);
 
6500
    }
 
6501
    writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n",
 
6502
               func3->getDomainMin(0), func3->getDomainMin(0),
 
6503
               func3->getDomainMax(0), func3->getDomainMax(0));
 
6504
    for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
 
6505
      writePSFmt("dup {0:.6g} lt {{ {1:.6g} sub {2:.6g} mul {3:.6g} add xpdfFunc{4:d}_{5:d} }} {{\n",
 
6506
                 func3->getBounds()[i+1],
 
6507
                 func3->getBounds()[i],
 
6508
                 func3->getScale()[i],
 
6509
                 func3->getEncode()[2*i],
 
6510
                 thisFunc, i);
 
6511
    }
 
6512
    writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add xpdfFunc{3:d}_{4:d}\n",
 
6513
               func3->getBounds()[i],
 
6514
               func3->getScale()[i],
 
6515
               func3->getEncode()[2*i],
 
6516
               thisFunc, i);
 
6517
    for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
 
6518
      writePS("} ifelse\n");
 
6519
    }
 
6520
    writePS("}\n");
 
6521
    break;
 
6522
 
 
6523
  case 4:                       // PostScript
 
6524
    func4 = (PostScriptFunction *)func;
 
6525
    writePS(func4->getCodeString()->getCString());
 
6526
    writePS("\n");
 
6527
    break;
 
6528
  }
 
6529
}
 
6530
 
 
6531
void PSOutputDev::writePSChar(char c) {
 
6532
  if (t3String) {
 
6533
    t3String->append(c);
 
6534
  } else {
 
6535
    (*outputFunc)(outputStream, &c, 1);
 
6536
  }
 
6537
}
 
6538
 
 
6539
void PSOutputDev::writePS(char *s) {
 
6540
  if (t3String) {
 
6541
    t3String->append(s);
 
6542
  } else {
 
6543
    (*outputFunc)(outputStream, s, strlen(s));
 
6544
  }
 
6545
}
 
6546
 
 
6547
void PSOutputDev::writePSBuf(char *s, int len) {
 
6548
  if (t3String) {
 
6549
    for (int i = 0; i < len; i++) {
 
6550
      t3String->append(s[i]);
 
6551
    }
 
6552
  } else {
 
6553
    (*outputFunc)(outputStream, s, len);
 
6554
  }
 
6555
}
 
6556
 
 
6557
void PSOutputDev::writePSFmt(const char *fmt, ...) {
 
6558
  va_list args;
 
6559
  GooString *buf;
 
6560
 
 
6561
  va_start(args, fmt);
 
6562
  if (t3String) {
 
6563
    t3String->appendfv((char *)fmt, args);
 
6564
  } else {
 
6565
    buf = GooString::formatv((char *)fmt, args);
 
6566
    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
 
6567
    delete buf;
 
6568
  }
 
6569
  va_end(args);
 
6570
}
 
6571
 
 
6572
void PSOutputDev::writePSString(GooString *s) {
 
6573
  Guchar *p;
 
6574
  int n, line;
 
6575
  char buf[8];
 
6576
 
 
6577
  writePSChar('(');
 
6578
  line = 1;
 
6579
  for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
 
6580
    if (line >= 64) {
 
6581
      writePSChar('\\');
 
6582
      writePSChar('\n');
 
6583
      line = 0;
 
6584
    }
 
6585
    if (*p == '(' || *p == ')' || *p == '\\') {
 
6586
      writePSChar('\\');
 
6587
      writePSChar((char)*p);
 
6588
      line += 2;
 
6589
    } else if (*p < 0x20 || *p >= 0x80) {
 
6590
      sprintf(buf, "\\%03o", *p);
 
6591
      writePS(buf);
 
6592
      line += 4;
 
6593
    } else {
 
6594
      writePSChar((char)*p);
 
6595
      ++line;
 
6596
    }
 
6597
  }
 
6598
  writePSChar(')');
 
6599
}
 
6600
 
 
6601
void PSOutputDev::writePSName(char *s) {
 
6602
  char *p;
 
6603
  char c;
 
6604
 
 
6605
  p = s;
 
6606
  while ((c = *p++)) {
 
6607
    if (c <= (char)0x20 || c >= (char)0x7f ||
 
6608
        c == '(' || c == ')' || c == '<' || c == '>' ||
 
6609
        c == '[' || c == ']' || c == '{' || c == '}' ||
 
6610
        c == '/' || c == '%' || c == '\\') {
 
6611
      writePSFmt("#{0:02x}", c & 0xff);
 
6612
    } else {
 
6613
      writePSChar(c);
 
6614
    }
 
6615
  }
 
6616
}
 
6617
 
 
6618
// Convert GooString to GooString, with appropriate escaping
 
6619
// of things that can't appear in a label
 
6620
// This is heavily based on the writePSTextLine() method
 
6621
GooString* PSOutputDev::filterPSLabel(GooString *label, GBool *needParens) {
 
6622
  int i, step;
 
6623
  GBool isNumeric;
 
6624
 
 
6625
  // - DSC comments must be printable ASCII; control chars and
 
6626
  //   backslashes have to be escaped (we do cheap UCS2-to-ASCII
 
6627
  //   conversion by simply ignoring the high byte)
 
6628
  // - parentheses are escaped. this isn't strictly necessary for matched
 
6629
  //   parentheses, but shouldn't be a problem
 
6630
  // - lines are limited to 255 chars (we limit to 200 here to allow
 
6631
  //   for the keyword, which was emitted by the caller)
 
6632
 
 
6633
  GooString *label2 = new GooString();
 
6634
  int labelLength = label->getLength();
 
6635
 
 
6636
  if (labelLength == 0) {
 
6637
    isNumeric = false;
 
6638
  } else {
 
6639
    // this gets changed later if we find a non-numeric character
 
6640
    isNumeric = true;
 
6641
  }
 
6642
 
 
6643
  if ( (labelLength >= 2) &&
 
6644
       ( (label->getChar(0) & 0xff) == 0xfe) &&
 
6645
       ( (label->getChar(1) & 0xff) == 0xff) ) {
 
6646
    // UCS2 mode
 
6647
    i = 3;
 
6648
    step = 2;
 
6649
    if ( (label->getChar(labelLength-1) == 0) ) {
 
6650
      // prune the trailing null (0x000 for UCS2)
 
6651
      labelLength -= 2;
 
6652
    }
 
6653
  } else {
 
6654
    i = 0;
 
6655
    step = 1;
 
6656
  }
 
6657
  for (int j = 0; i < labelLength && j < 200; i += step) {
 
6658
    char c = label->getChar(i);
 
6659
    if ( (c < '0') || (c > '9') ) {
 
6660
      isNumeric = false;
 
6661
    }
 
6662
    if (c == '\\') {
 
6663
      label2->append("\\\\");
 
6664
      j += 2;
 
6665
    } else if (c == ')') {
 
6666
      label2->append("\\)");
 
6667
    } else if (c == '(') {
 
6668
      label2->append("\\(");
 
6669
    } else if (c < 0x20 || c > 0x7e) {
 
6670
      label2->append(GooString::format("\\{0:03o}", c));
 
6671
      j += 4;
 
6672
    } else {
 
6673
      label2->append(c);
 
6674
      ++j;
 
6675
    }
 
6676
  }
 
6677
  if (needParens) {
 
6678
    *needParens = !(isNumeric);
 
6679
  }
 
6680
  return label2;
 
6681
}
 
6682
 
 
6683
// Write a DSC-compliant <textline>.
 
6684
void PSOutputDev::writePSTextLine(GooString *s) {
 
6685
  int i, j, step;
 
6686
  int c;
 
6687
 
 
6688
  // - DSC comments must be printable ASCII; control chars and
 
6689
  //   backslashes have to be escaped (we do cheap Unicode-to-ASCII
 
6690
  //   conversion by simply ignoring the high byte)
 
6691
  // - lines are limited to 255 chars (we limit to 200 here to allow
 
6692
  //   for the keyword, which was emitted by the caller)
 
6693
  // - lines that start with a left paren are treated as <text>
 
6694
  //   instead of <textline>, so we escape a leading paren
 
6695
  if (s->getLength() >= 2 &&
 
6696
      (s->getChar(0) & 0xff) == 0xfe &&
 
6697
      (s->getChar(1) & 0xff) == 0xff) {
 
6698
    i = 3;
 
6699
    step = 2;
 
6700
  } else {
 
6701
    i = 0;
 
6702
    step = 1;
 
6703
  }
 
6704
  for (j = 0; i < s->getLength() && j < 200; i += step) {
 
6705
    c = s->getChar(i) & 0xff;
 
6706
    if (c == '\\') {
 
6707
      writePS("\\\\");
 
6708
      j += 2;
 
6709
    } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
 
6710
      writePSFmt("\\{0:03o}", c);
 
6711
      j += 4;
 
6712
    } else {
 
6713
      writePSChar(c);
 
6714
      ++j;
 
6715
    }
 
6716
  }
 
6717
  writePS("\n");
 
6718
}