~ubuntu-branches/ubuntu/vivid/emscripten/vivid

« back to all changes in this revision

Viewing changes to tests/poppler/poppler/PSOutputDev.cc

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-02 13:11:51 UTC
  • Revision ID: package-import@ubuntu.com-20130502131151-q8dvteqr1ef2x7xz
Tags: upstream-1.4.1~20130504~adb56cb
ImportĀ upstreamĀ versionĀ 1.4.1~20130504~adb56cb

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