~ubuntu-branches/ubuntu/precise/poppler/precise

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Sebastien Bacher
  • Date: 2011-12-05 17:23:02 UTC
  • mfrom: (1.7.1)
  • Revision ID: package-import@ubuntu.com-20111205172302-tmhrk7s9hikjsa79
Tags: 0.18.2-0ubuntu1
* New upstream version, bugs fixed in the new version (lp: #869850):
  - lines and graphics wrongly rendered (lp: #603929) (lp: #780169)
  - rendering issues on some documents (lp: #784154)
  - some pages are displayed blank (lp: #817626)
* debian/control, debian/rules:
  - updated for the libpoppler and libpoppler-glib soname changes
* drop patches included in the new version
* debian/libpoppler-glib-dev.install:
  - drop deprecated test-poppler-glib
* debian/rules: 
  - drop deprecated qt3 and abiword configure options

Show diffs side-by-side

added added

removed removed

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