~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/pdftoopvp/OPVPOutputDev.cxx

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-22 18:57:32 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20120722185732-26kkte5p1lth3rt5
Tags: 1.0.20-0bzr1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// OPVPOutputDev.cc
 
3
//      Based SplashOutputDev.cc : Copyright 2003 Glyph & Cog, LLC
 
4
//
 
5
// Copyright 2005 AXE,Inc.
 
6
//
 
7
// 2007,2008 Modified by BBR Inc.
 
8
//========================================================================
 
9
 
 
10
#include <config.h>
 
11
#ifdef HAVE_CPP_POPPLER_VERSION_H
 
12
#include "cpp/poppler-version.h"
 
13
#endif
 
14
 
 
15
#ifdef USE_GCC_PRAGMAS
 
16
#pragma implementation
 
17
#endif
 
18
 
 
19
#include <string.h>
 
20
#include <math.h>
 
21
#include "goo/gfile.h"
 
22
#include "GlobalParams.h"
 
23
#include "OPVPError.h"
 
24
#include "Object.h"
 
25
#include "GfxState.h"
 
26
#include "GfxFont.h"
 
27
#include "Link.h"
 
28
#include "CharCodeToUnicode.h"
 
29
#include "FontEncodingTables.h"
 
30
#include "fofi/FoFiTrueType.h"
 
31
#include "splash/SplashMath.h"
 
32
#include "CMap.h"
 
33
#include "splash/SplashBitmap.h"
 
34
#include "splash/SplashGlyphBitmap.h"
 
35
#include "splash/SplashPattern.h"
 
36
#include "splash/SplashScreen.h"
 
37
#include "splash/SplashErrorCodes.h"
 
38
#include "splash/SplashFontEngine.h"
 
39
#include "splash/SplashFont.h"
 
40
#include "splash/SplashFontFile.h"
 
41
#include "splash/SplashFontFileID.h"
 
42
#include "OPVPSplashPath.h"
 
43
#include "OPVPSplashState.h"
 
44
#include "OPRS.h"
 
45
#include "OPVPOutputDev.h"
 
46
 
 
47
#define SLICE_FOR_PATTERN 1000
 
48
 
 
49
//------------------------------------------------------------------------
 
50
// Font substitutions
 
51
//------------------------------------------------------------------------
 
52
 
 
53
struct SplashOutFontSubst {
 
54
  char *name;
 
55
  double mWidth;
 
56
};
 
57
 
 
58
//------------------------------------------------------------------------
 
59
 
 
60
#define soutRound(x) ((int)(x + 0.5))
 
61
 
 
62
//------------------------------------------------------------------------
 
63
// SplashOutFontFileID
 
64
//------------------------------------------------------------------------
 
65
 
 
66
class SplashOutFontFileID: public SplashFontFileID {
 
67
public:
 
68
 
 
69
  SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; }
 
70
 
 
71
  ~SplashOutFontFileID() {}
 
72
 
 
73
  GBool matches(SplashFontFileID *id) {
 
74
    return ((SplashOutFontFileID *)id)->r.num == r.num &&
 
75
           ((SplashOutFontFileID *)id)->r.gen == r.gen;
 
76
  }
 
77
 
 
78
  void setSubstIdx(int substIdxA) { substIdx = substIdxA; }
 
79
  int getSubstIdx() { return substIdx; }
 
80
 
 
81
private:
 
82
 
 
83
  Ref r;
 
84
  int substIdx;
 
85
};
 
86
 
 
87
//------------------------------------------------------------------------
 
88
// T3FontCache
 
89
//------------------------------------------------------------------------
 
90
 
 
91
struct T3FontCacheTag {
 
92
  Gushort code;
 
93
  Gushort mru;                  // valid bit (0x8000) and MRU index
 
94
};
 
95
 
 
96
class T3FontCache {
 
97
public:
 
98
 
 
99
  T3FontCache(Ref *fontID, double m11A, double m12A,
 
100
              double m21A, double m22A,
 
101
              int glyphXA, int glyphYA, int glyphWA, int glyphHA,
 
102
              GBool aa);
 
103
  ~T3FontCache();
 
104
  GBool matches(Ref *idA, double m11A, double m12A,
 
105
                double m21A, double m22A)
 
106
    { return fontID.num == idA->num && fontID.gen == idA->gen &&
 
107
             m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
 
108
 
 
109
  Ref fontID;                   // PDF font ID
 
110
  double m11, m12, m21, m22;    // transform matrix
 
111
  int glyphX, glyphY;           // pixel offset of glyph bitmaps
 
112
  int glyphW, glyphH;           // size of glyph bitmaps, in pixels
 
113
  int glyphSize;                // size of glyph bitmaps, in bytes
 
114
  int cacheSets;                // number of sets in cache
 
115
  int cacheAssoc;               // cache associativity (glyphs per set)
 
116
  Guchar *cacheData;            // glyph pixmap cache
 
117
  T3FontCacheTag *cacheTags;    // cache tags, i.e., char codes
 
118
};
 
119
 
 
120
T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
 
121
                         double m21A, double m22A,
 
122
                         int glyphXA, int glyphYA, int glyphWA, int glyphHA,
 
123
                         GBool aa) {
 
124
  int i;
 
125
 
 
126
  fontID = *fontIDA;
 
127
  m11 = m11A;
 
128
  m12 = m12A;
 
129
  m21 = m21A;
 
130
  m22 = m22A;
 
131
  glyphX = glyphXA;
 
132
  glyphY = glyphYA;
 
133
  glyphW = glyphWA;
 
134
  glyphH = glyphHA;
 
135
  if (aa) {
 
136
    glyphSize = glyphW * glyphH;
 
137
  } else {
 
138
    glyphSize = ((glyphW + 7) >> 3) * glyphH;
 
139
  }
 
140
  cacheAssoc = 8;
 
141
  if (glyphSize <= 256) {
 
142
    cacheSets = 8;
 
143
  } else if (glyphSize <= 512) {
 
144
    cacheSets = 4;
 
145
  } else if (glyphSize <= 1024) {
 
146
    cacheSets = 2;
 
147
  } else {
 
148
    cacheSets = 1;
 
149
  }
 
150
  cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
 
151
  cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
 
152
                                        sizeof(T3FontCacheTag));
 
153
  for (i = 0; i < cacheSets * cacheAssoc; ++i) {
 
154
    cacheTags[i].mru = i & (cacheAssoc - 1);
 
155
  }
 
156
}
 
157
 
 
158
T3FontCache::~T3FontCache() {
 
159
  gfree(cacheData);
 
160
  gfree(cacheTags);
 
161
}
 
162
 
 
163
struct T3GlyphStack {
 
164
  Gushort code;                 // character code
 
165
  double x, y;                  // position to draw the glyph
 
166
 
 
167
  //----- cache info
 
168
  T3FontCache *cache;           // font cache for the current font
 
169
  T3FontCacheTag *cacheTag;     // pointer to cache tag for the glyph
 
170
  Guchar *cacheData;            // pointer to cache data for the glyph
 
171
 
 
172
  //----- saved state
 
173
  SplashBitmap *origBitmap;
 
174
  OPRS *origOPRS;
 
175
  double origCTM4, origCTM5;
 
176
 
 
177
  T3GlyphStack *next;           // next object on stack
 
178
};
 
179
 
 
180
//------------------------------------------------------------------------
 
181
// OPVPOutputDev
 
182
//------------------------------------------------------------------------
 
183
 
 
184
OPVPOutputDev::OPVPOutputDev()
 
185
{
 
186
  xref = 0;
 
187
  bitmap = 0;
 
188
  fontEngine = 0;
 
189
  nT3Fonts = 0;
 
190
  t3GlyphStack = 0;
 
191
  font = NULL;
 
192
  needFontUpdate = gFalse;
 
193
  textClipPath = 0;
 
194
  underlayCbk = 0;
 
195
  underlayCbkData = 0;
 
196
  scaleWidth = scaleHeight = -1;
 
197
  leftMargin = 0;
 
198
  bottomMargin = 0;
 
199
  rotate = 0;
 
200
  sliceHeight = 0;
 
201
  yoffset = 0;
 
202
  oprs = 0;
 
203
}
 
204
 
 
205
void OPVPOutputDev::setScale(double w, double h,
 
206
  double leftMarginA, double bottomMarginA, int rotateA,
 
207
  int yoffsetA, int sliceHeightA)
 
208
{
 
209
  scaleWidth = w;
 
210
  scaleHeight = h;
 
211
  leftMargin = leftMarginA;
 
212
  bottomMargin = bottomMarginA;
 
213
  rotate = rotateA;
 
214
  yoffset = yoffsetA;
 
215
  sliceHeight = sliceHeightA;
 
216
}
 
217
 
 
218
int OPVPOutputDev::init(SplashColorMode colorModeA,
 
219
                                 GBool colorProfile,
 
220
                                 GBool reverseVideoA,
 
221
                                 SplashColor paperColorA,
 
222
                                 const char *driverName,
 
223
                                 int outputFD,
 
224
                                 const char *printerModel,
 
225
                                 int nOptions,
 
226
                                 const char *optionKeys[],
 
227
                                 const char *optionVals[]) {
 
228
  int result;
 
229
 
 
230
  oprs = new OPRS();
 
231
 
 
232
  if ((result = oprs->init(driverName, outputFD, printerModel,
 
233
       nOptions,optionKeys,optionVals)) < 0) {
 
234
    opvpError(-1,"OPRS initialization fail");
 
235
    return result;
 
236
  }
 
237
  colorMode = colorModeA;
 
238
  if ((result = oprs->setColorMode(colorMode,colorProfile)) < 0) {
 
239
    opvpError(-1,"Can't setColorMode");
 
240
    return result;
 
241
  }
 
242
  reverseVideo = reverseVideoA;
 
243
  splashColorCopy(paperColor,paperColorA);
 
244
 
 
245
  return 0;
 
246
}
 
247
 
 
248
OPVPOutputDev::~OPVPOutputDev() {
 
249
  int i;
 
250
 
 
251
  for (i = 0; i < nT3Fonts; ++i) {
 
252
    delete t3FontCache[i];
 
253
  }
 
254
  if (fontEngine) {
 
255
    delete fontEngine;
 
256
  }
 
257
  if (oprs) {
 
258
    delete oprs;
 
259
  }
 
260
  if (bitmap) {
 
261
    delete bitmap;
 
262
  }
 
263
}
 
264
 
 
265
void OPVPOutputDev::startDoc(XRef *xrefA) {
 
266
  int i;
 
267
 
 
268
  xref = xrefA;
 
269
  if (fontEngine) {
 
270
    delete fontEngine;
 
271
  }
 
272
  fontEngine = new SplashFontEngine(
 
273
#if HAVE_T1LIB_H
 
274
                                    globalParams->getEnableT1lib(),
 
275
#endif
 
276
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
 
277
                                    globalParams->getEnableFreeType(),
 
278
                                    gFalse,
 
279
                                    gFalse,
 
280
#endif
 
281
                                    globalParams->getAntialias());
 
282
  for (i = 0; i < nT3Fonts; ++i) {
 
283
    delete t3FontCache[i];
 
284
  }
 
285
  nT3Fonts = 0;
 
286
}
 
287
 
 
288
void OPVPOutputDev::startPage(int pageNum, GfxState *state) {
 
289
  int w, h;
 
290
 
 
291
  if (state) {
 
292
    if (scaleWidth > 0 && scaleHeight > 0) {
 
293
      double *ctm = state->getCTM();
 
294
 
 
295
      switch (rotate) {
 
296
      case 90:
 
297
        state->setCTM(0,ctm[1],ctm[2],0,leftMargin,bottomMargin-yoffset);
 
298
        break;
 
299
      case 180:
 
300
        state->setCTM(ctm[0],0,0,ctm[3],paperWidth-leftMargin,
 
301
          bottomMargin-yoffset);
 
302
        break;
 
303
      case 270:
 
304
        state->setCTM(0,ctm[1],ctm[2],0,paperWidth-leftMargin,
 
305
          -bottomMargin+paperHeight-yoffset);
 
306
        break;
 
307
      default:
 
308
        state->setCTM(ctm[0],0,0,ctm[3],leftMargin,
 
309
          -bottomMargin+paperHeight-yoffset);
 
310
        break;
 
311
      }
 
312
      state->concatCTM(scaleWidth,0.0,0.0,scaleHeight,0,0);
 
313
    }
 
314
    w = (int)(state->getPageWidth()+0.5);
 
315
    h = (int)(state->getPageHeight()+0.5);
 
316
  } else {
 
317
    w = h = 1;
 
318
  }
 
319
  oprs->initGS(colorMode,w,h,paperColor);
 
320
 
 
321
  if (underlayCbk) {
 
322
    (*underlayCbk)(underlayCbkData);
 
323
  }
 
324
}
 
325
 
 
326
void OPVPOutputDev::endPage() {
 
327
  oprs->endPage();
 
328
}
 
329
 
 
330
void OPVPOutputDev::saveState(GfxState *state) {
 
331
  oprs->saveState();
 
332
}
 
333
 
 
334
void OPVPOutputDev::restoreState(GfxState *state) {
 
335
  oprs->restoreState();
 
336
  needFontUpdate = gTrue;
 
337
}
 
338
 
 
339
void OPVPOutputDev::updateAll(GfxState *state) {
 
340
  updateLineDash(state);
 
341
  updateLineJoin(state);
 
342
  updateLineCap(state);
 
343
  updateLineWidth(state);
 
344
  updateFlatness(state);
 
345
  updateMiterLimit(state);
 
346
  updateFillColor(state);
 
347
  updateStrokeColor(state);
 
348
  needFontUpdate = gTrue;
 
349
}
 
350
 
 
351
void OPVPOutputDev::updateCTM(GfxState *state, double m11, double m12,
 
352
                                double m21, double m22,
 
353
                                double m31, double m32) {
 
354
  updateLineDash(state);
 
355
  updateLineJoin(state);
 
356
  updateLineCap(state);
 
357
  updateLineWidth(state);
 
358
}
 
359
 
 
360
void OPVPOutputDev::transLineDash(GfxState *state, SplashCoord **adash,
 
361
  int *adashLength, SplashCoord *aphase) {
 
362
  double *dashPattern;
 
363
  double dashStart;
 
364
  static SplashCoord dash[20];
 
365
  int i;
 
366
 
 
367
  state->getLineDash(&dashPattern, adashLength, &dashStart);
 
368
  if (*adashLength > 20) {
 
369
    *adashLength = 20;
 
370
  }
 
371
  for (i = 0; i < *adashLength; ++i) {
 
372
    dash[i] =  (SplashCoord)state->transformWidth(dashPattern[i]);
 
373
    if (dash[i] < 1) {
 
374
      dash[i] = 1;
 
375
    }
 
376
  }
 
377
  *adash = dash;
 
378
  *aphase = (SplashCoord)state->transformWidth(dashStart);
 
379
}
 
380
 
 
381
void OPVPOutputDev::updateSplashLineDash(GfxState *state, Splash *splash) {
 
382
  int dashLength;
 
383
  SplashCoord *dash;
 
384
  SplashCoord phase;
 
385
 
 
386
  transLineDash(state, &dash, &dashLength, &phase);
 
387
  splash->setLineDash(dash, dashLength, phase);
 
388
}
 
389
 
 
390
void OPVPOutputDev::updateLineDash(GfxState *state) {
 
391
  int dashLength;
 
392
  SplashCoord *dash;
 
393
  SplashCoord phase;
 
394
 
 
395
  transLineDash(state, &dash, &dashLength, &phase);
 
396
  oprs->setLineDash(dash, dashLength, phase);
 
397
}
 
398
 
 
399
void OPVPOutputDev::updateFlatness(GfxState *state) {
 
400
  oprs->setFlatness(state->getFlatness());
 
401
}
 
402
 
 
403
void OPVPOutputDev::updateLineJoin(GfxState *state) {
 
404
  oprs->setLineJoin(state->getLineJoin());
 
405
}
 
406
 
 
407
void OPVPOutputDev::updateLineCap(GfxState *state) {
 
408
  oprs->setLineCap(state->getLineCap());
 
409
}
 
410
 
 
411
void OPVPOutputDev::updateMiterLimit(GfxState *state) {
 
412
  oprs->setMiterLimit(state->getMiterLimit());
 
413
}
 
414
 
 
415
void OPVPOutputDev::updateLineWidth(GfxState *state) {
 
416
  oprs->setLineWidth(state->getTransformedLineWidth());
 
417
}
 
418
 
 
419
void OPVPOutputDev::updateFillColor(GfxState *state) {
 
420
  GfxGray gray;
 
421
  GfxRGB rgb;
 
422
 
 
423
  state->getFillGray(&gray);
 
424
  state->getFillRGB(&rgb);
 
425
  oprs->setFillPattern(getColor(gray, &rgb));
 
426
}
 
427
 
 
428
void OPVPOutputDev::updateStrokeColor(GfxState *state) {
 
429
  GfxGray gray;
 
430
  GfxRGB rgb;
 
431
 
 
432
  state->getStrokeGray(&gray);
 
433
  state->getStrokeRGB(&rgb);
 
434
  oprs->setStrokePattern(getColor(gray, &rgb));
 
435
}
 
436
 
 
437
#ifdef SPLASH_CMYK
 
438
SplashPattern *OPVPOutputDev::getColor(double gray, GfxRGB *rgb,
 
439
     GfxCMYK *cmyk) {
 
440
#else
 
441
SplashPattern *OPVPOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
 
442
#endif
 
443
  SplashPattern *pattern;
 
444
  SplashColor  color1;
 
445
  GfxColorComp r, g, b;
 
446
 
 
447
  if (reverseVideo) {
 
448
    gray = gfxColorComp1 - gray;
 
449
    r = gfxColorComp1 - rgb->r;
 
450
    g = gfxColorComp1 - rgb->g;
 
451
    b = gfxColorComp1 - rgb->b;
 
452
  } else {
 
453
    r = rgb->r;
 
454
    g = rgb->g;
 
455
    b = rgb->b;
 
456
  }
 
457
 
 
458
  pattern = NULL; // make gcc happy
 
459
  switch (colorMode) {
 
460
  case splashModeMono1:
 
461
  case splashModeMono8:
 
462
    color1[0] = colToByte(gray);
 
463
    pattern = new SplashSolidColor(color1);
 
464
    break;
 
465
  case splashModeRGB8:
 
466
    color1[0] = colToByte(r);
 
467
    color1[1] = colToByte(g);
 
468
    color1[2] = colToByte(b);
 
469
    pattern = new SplashSolidColor(color1);
 
470
    break;
 
471
#if SPLASH_CMYK
 
472
  case splashModeCMYK8:
 
473
    color[0] = colToByte(cmyk->c);
 
474
    color[1] = colToByte(cmyk->m);
 
475
    color[2] = colToByte(cmyk->y);
 
476
    color[3] = colToByte(cmyk->k);
 
477
    pattern = new SplashSolidColor(color);
 
478
    break;
 
479
#endif
 
480
  default:
 
481
    opvpError(-1, "no supported color mode");
 
482
    break;
 
483
  }
 
484
 
 
485
  return pattern;
 
486
}
 
487
 
 
488
void OPVPOutputDev::updateFont(GfxState *state) {
 
489
    needFontUpdate = gTrue;
 
490
}
 
491
 
 
492
void OPVPOutputDev::doUpdateFont(GfxState *state) {
 
493
  GfxFont *gfxFont;
 
494
  GfxFontType fontType;
 
495
  SplashOutFontFileID *id;
 
496
  SplashFontFile *fontFile;
 
497
  SplashFontSrc *fontsrc = NULL;
 
498
  FoFiTrueType *ff;
 
499
  Ref embRef;
 
500
  Object refObj, strObj;
 
501
  GooString *fileName;
 
502
  char *tmpBuf;
 
503
  int tmpBufLen;
 
504
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
505
  int *codeToGID;
 
506
#else
 
507
  Gushort *codeToGID;
 
508
#endif
 
509
  double m11, m12, m21, m22;
 
510
  int substIdx, n;
 
511
  int faceIndex = 0;
 
512
  GBool recreateFont = gFalse;
 
513
 
 
514
  needFontUpdate = gFalse;
 
515
  font = NULL;
 
516
  fileName = NULL;
 
517
  tmpBuf = NULL;
 
518
  substIdx = -1;
 
519
 
 
520
  if (!(gfxFont = state->getFont())) {
 
521
    goto err1;
 
522
  }
 
523
  fontType = gfxFont->getType();
 
524
  if (fontType == fontType3) {
 
525
    goto err1;
 
526
  }
 
527
 
 
528
  // check the font file cache
 
529
  id = new SplashOutFontFileID(gfxFont->getID());
 
530
  if ((fontFile = fontEngine->getFontFile(id))) {
 
531
    delete id;
 
532
 
 
533
  } else {
 
534
 
 
535
    // if there is an embedded font, write it to disk
 
536
    if (gfxFont->getEmbeddedFontID(&embRef)) {
 
537
      tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
 
538
      if (! tmpBuf)
 
539
        goto err2;
 
540
 
 
541
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
542
    } else {
 
543
      SysFontType sftype;
 
544
      fileName = globalParams->findSystemFontFile(gfxFont,&sftype,
 
545
                          &faceIndex, NULL);
 
546
      if (fileName == 0) {
 
547
        opvpError(-1, "Couldn't find a font for '%s'",
 
548
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
549
                                 : "(unnamed)");
 
550
        goto err2;
 
551
      }
 
552
      switch (sftype) {
 
553
      case sysFontPFA:
 
554
      case sysFontPFB:
 
555
        fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
 
556
        break;
 
557
      case sysFontTTF:
 
558
      case sysFontTTC:
 
559
        fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
 
560
        break;
 
561
      }
 
562
    }
 
563
#else
 
564
    // if there is an external font file, use it
 
565
    } else if (!(fileName = gfxFont->getExtFontFile())) {
 
566
      DisplayFontParam *dfp;
 
567
      // look for a display font mapping or a substitute font
 
568
      dfp = NULL;
 
569
      if (gfxFont->getName()) {
 
570
        dfp = globalParams->getDisplayFont(gfxFont);
 
571
      }
 
572
      if (!dfp) {
 
573
        opvpError(-1, "Couldn't find a font for '%s'",
 
574
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
575
                                 : "(unnamed)");
 
576
        goto err2;
 
577
      }
 
578
      switch (dfp->kind) {
 
579
      case displayFontT1:
 
580
        fileName = dfp->t1.fileName;
 
581
        fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
 
582
        break;
 
583
      case displayFontTT:
 
584
        fileName = dfp->tt.fileName;
 
585
        fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
 
586
        faceIndex = dfp->tt.faceIndex;
 
587
        break;
 
588
      }
 
589
    }
 
590
#endif
 
591
 
 
592
    fontsrc = new SplashFontSrc;
 
593
    if (fileName)
 
594
      fontsrc->setFile(fileName, gFalse);
 
595
    else
 
596
      fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
 
597
 
 
598
    // load the font file
 
599
    switch (fontType) {
 
600
    case fontType1:
 
601
      if (!(fontFile = fontEngine->loadType1Font(
 
602
                           id,
 
603
                           fontsrc,
 
604
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
605
                           (const char **)
 
606
#endif
 
607
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
608
        opvpError(-1, "Couldn't create a font for '%s'",
 
609
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
610
                                 : "(unnamed)");
 
611
        goto err2;
 
612
      }
 
613
      break;
 
614
    case fontType1C:
 
615
      if (!(fontFile = fontEngine->loadType1CFont(
 
616
                           id,
 
617
                           fontsrc,
 
618
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
619
                           (const char **)
 
620
#endif
 
621
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
622
        opvpError(-1, "Couldn't create a font for '%s'",
 
623
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
624
                                 : "(unnamed)");
 
625
        goto err2;
 
626
      }
 
627
      break;
 
628
    case fontType1COT:
 
629
      if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
 
630
                           id,
 
631
                           fontsrc,
 
632
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
633
                           (const char **)
 
634
#endif
 
635
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
636
        opvpError(-1, "Couldn't create a font for '%s'",
 
637
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
638
                                 : "(unnamed)");
 
639
        goto err2;
 
640
      }
 
641
      break;
 
642
    case fontTrueTypeOT:
 
643
    case fontTrueType:
 
644
        if (fileName)
 
645
         ff = FoFiTrueType::load(fileName->getCString());
 
646
        else
 
647
        ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
 
648
      if (ff) {
 
649
        codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
 
650
        n = 256;
 
651
        delete ff;
 
652
      } else {
 
653
        codeToGID = NULL;
 
654
        n = 0;
 
655
      }
 
656
      if (!(fontFile = fontEngine->loadTrueTypeFont(
 
657
                           id,
 
658
                           fontsrc,
 
659
                           codeToGID, n))) {
 
660
        opvpError(-1, "Couldn't create a font for '%s'",
 
661
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
662
                                 : "(unnamed)");
 
663
        goto err2;
 
664
      }
 
665
      break;
 
666
    case fontCIDType0:
 
667
    case fontCIDType0C:
 
668
      if (!(fontFile = fontEngine->loadCIDFont(
 
669
                           id,
 
670
                           fontsrc))) {
 
671
        opvpError(-1, "Couldn't create a font for '%s'",
 
672
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
673
                                 : "(unnamed)");
 
674
        goto err2;
 
675
      }
 
676
      break;
 
677
    case fontCIDType0COT:
 
678
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
679
      n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
 
680
      if (n) {
 
681
        codeToGID = (int *)gmallocn(n, sizeof(int));
 
682
        memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
 
683
                n * sizeof(int));
 
684
      } else {
 
685
          codeToGID = NULL;
 
686
      }
 
687
      if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
 
688
                           id,
 
689
                           fontsrc,codeToGID,n))) {
 
690
#else
 
691
      if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
 
692
                           id,
 
693
                           fontsrc))) {
 
694
#endif
 
695
        opvpError(-1, "Couldn't create a font for '%s'",
 
696
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
697
                                 : "(unnamed)");
 
698
        goto err2;
 
699
      }
 
700
      break;
 
701
    case fontCIDType2OT:
 
702
    case fontCIDType2:
 
703
      codeToGID = NULL;
 
704
      n = 0;
 
705
      if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
 
706
        n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
 
707
        if (n) {
 
708
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
709
          codeToGID = (int *)gmallocn(n, sizeof(int));
 
710
          memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
 
711
                  n * sizeof(int));
 
712
#else
 
713
          codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
 
714
          memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
 
715
                  n * sizeof(Gushort));
 
716
#endif
 
717
        }
 
718
      } else {
 
719
        if (fileName)
 
720
          ff = FoFiTrueType::load(fileName->getCString());
 
721
        else
 
722
          ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
 
723
        if (! ff)
 
724
          goto err2;
 
725
        codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
 
726
        delete ff;
 
727
      }
 
728
      if (!(fontFile = fontEngine->loadTrueTypeFont(
 
729
                           id,
 
730
                           fontsrc,
 
731
                           codeToGID, n, faceIndex))) {
 
732
        opvpError(-1, "Couldn't create a font for '%s'",
 
733
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
734
                                 : "(unnamed)");
 
735
        goto err2;
 
736
      }
 
737
      break;
 
738
    default:
 
739
      // this shouldn't happen
 
740
      goto err2;
 
741
    }
 
742
    fontFile->doAdjustMatrix = gTrue;
 
743
  }
 
744
 
 
745
  // get the font matrix
 
746
  state->getFontTransMat(&m11, &m12, &m21, &m22);
 
747
  m11 *= state->getHorizScaling();
 
748
  m12 *= state->getHorizScaling();
 
749
 
 
750
  // create the scaled font
 
751
  fontMat[0] = m11;  fontMat[1] = m12;
 
752
  fontMat[2] = m21;  fontMat[3] = m22;
 
753
  font = fontEngine->getFont(fontFile, fontMat, oprs->getMatrix());
 
754
 
 
755
  // for substituted fonts: adjust the font matrix -- compare the
 
756
  // width of 'm' in the original font and the substituted font
 
757
  if (fontFile->doAdjustMatrix && !gfxFont->isCIDFont()) {
 
758
    double w1, w2;
 
759
    CharCode code;
 
760
    char *name;
 
761
    for (code = 0; code < 256; ++code) {
 
762
      if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
 
763
          name[0] == 'm' && name[1] == '\0') {
 
764
        break;
 
765
      }
 
766
    }
 
767
    if (code < 256) {
 
768
      w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
 
769
      w2 = font->getGlyphAdvance(code);
 
770
      if (!gfxFont->isSymbolic() && w2 > 0) {
 
771
        // if real font is substantially narrower than substituted
 
772
        // font, reduce the font size accordingly
 
773
        if (w1 > 0.01 && w1 < 0.9 * w2) {
 
774
          w1 /= w2;
 
775
          m11 *= w1;
 
776
          m21 *= w1;
 
777
          recreateFont = gTrue;
 
778
        }
 
779
      }
 
780
    }
 
781
  }
 
782
 
 
783
  if (recreateFont)
 
784
  {
 
785
    fontMat[0] = m11;  fontMat[1] = m12;
 
786
    fontMat[2] = m21;  fontMat[3] = m22;
 
787
    font = fontEngine->getFont(fontFile, fontMat, oprs->getMatrix());
 
788
  }
 
789
 
 
790
  if (fontsrc && !fontsrc->isFile)
 
791
      fontsrc->unref();
 
792
  return;
 
793
 
 
794
 err2:
 
795
  delete id;
 
796
 err1:
 
797
  if (fontsrc && !fontsrc->isFile)
 
798
      fontsrc->unref();
 
799
  return;
 
800
}
 
801
 
 
802
void OPVPOutputDev::stroke(GfxState *state) {
 
803
  OPVPSplashPath *path;
 
804
  GfxColorSpace *cs;
 
805
 
 
806
  /* check None separate color */
 
807
  if ((cs = state->getStrokeColorSpace()) == NULL) return;
 
808
  if (cs->getMode() == csSeparation) {
 
809
    GooString *name;
 
810
 
 
811
    name = (dynamic_cast<GfxSeparationColorSpace *>(cs))->getName();
 
812
    if (name == NULL) return;
 
813
    if (name->cmp("None") == 0) return;
 
814
  }
 
815
 
 
816
  path = convertPath(state, state->getPath());
 
817
  oprs->stroke(path);
 
818
  delete path;
 
819
}
 
820
 
 
821
void OPVPOutputDev::fill(GfxState *state) {
 
822
  OPVPSplashPath *path;
 
823
  GfxColorSpace *cs;
 
824
 
 
825
  /* check None separate color */
 
826
  if ((cs = state->getFillColorSpace()) == NULL) return;
 
827
  if (cs->getMode() == csSeparation) {
 
828
    GooString *name;
 
829
 
 
830
    name = (dynamic_cast<GfxSeparationColorSpace *>(cs))->getName();
 
831
    if (name == NULL) return;
 
832
    if (name->cmp("None") == 0) return;
 
833
  }
 
834
 
 
835
  path = convertPath(state, state->getPath());
 
836
  oprs->fill(path, gFalse);
 
837
  delete path;
 
838
}
 
839
 
 
840
void OPVPOutputDev::eoFill(GfxState *state) {
 
841
  OPVPSplashPath *path;
 
842
  GfxColorSpace *cs;
 
843
 
 
844
  /* check None separate color */
 
845
  if ((cs = state->getFillColorSpace()) == NULL) return;
 
846
  if (cs->getMode() == csSeparation) {
 
847
    GooString *name;
 
848
 
 
849
    name = (dynamic_cast<GfxSeparationColorSpace *>(cs))->getName();
 
850
    if (name == NULL) return;
 
851
    if (name->cmp("None") == 0) return;
 
852
  }
 
853
 
 
854
  path = convertPath(state, state->getPath());
 
855
  oprs->fill(path, gTrue);
 
856
  delete path;
 
857
}
 
858
 
 
859
void OPVPOutputDev::clip(GfxState *state) {
 
860
  OPVPSplashPath *path;
 
861
 
 
862
  path = convertPath(state, state->getPath());
 
863
  oprs->clipToPath(path, gFalse);
 
864
  delete path;
 
865
}
 
866
 
 
867
void OPVPOutputDev::eoClip(GfxState *state) {
 
868
  OPVPSplashPath *path;
 
869
 
 
870
  path = convertPath(state, state->getPath());
 
871
  oprs->clipToPath(path, gTrue);
 
872
  delete path;
 
873
}
 
874
 
 
875
OPVPSplashPath *OPVPOutputDev::bitmapToPath(SplashBitmap *bitmapA,
 
876
    int width, int height)
 
877
{
 
878
  int x,y;
 
879
  OPVPSplashPath *path;
 
880
  int x1, x2;
 
881
  SplashColor pix;
 
882
 
 
883
  path =  new OPVPSplashPath();
 
884
 
 
885
  for (y = 0;y < height;y++) {
 
886
    for (x = 0;x < width;x++) {
 
887
      bitmapA->getPixel(x,y,pix);
 
888
      if (pix[0] == 0) {
 
889
        /* start */
 
890
        x1 = x;
 
891
        for (x++;x < width;x++) {
 
892
          bitmapA->getPixel(x,y,pix);
 
893
          if (pix[0] != 0) {
 
894
            /* end */
 
895
            break;
 
896
          }
 
897
        }
 
898
        x2 = x-1;
 
899
        path->moveTo(x1,y);
 
900
        path->lineTo(x2,y);
 
901
        path->lineTo(x2,(y+1));
 
902
        path->lineTo(x1,(y+1));
 
903
        path->close();
 
904
      }
 
905
    }
 
906
  }
 
907
  return path;
 
908
}
 
909
 
 
910
void OPVPOutputDev::clipToStrokePath(GfxState *state) {
 
911
  SplashBitmap *tbitmap;
 
912
  Splash *tsplash;
 
913
  SplashPath *spath;
 
914
  OPVPSplashPath *path, *path2;
 
915
 
 
916
  // use splash for makeStrokePath
 
917
  // create dummy bitmap for creating splash
 
918
  tbitmap = new SplashBitmap(1, 1, 1, splashModeMono1, gFalse);
 
919
  tsplash = new Splash(tbitmap, gFalse);
 
920
  // set line parameters
 
921
  //  except colors
 
922
  updateSplashLineDash(state, tsplash);
 
923
  tsplash->setLineJoin(state->getLineJoin());
 
924
  tsplash->setLineCap(state->getLineCap());
 
925
  tsplash->setMiterLimit(state->getMiterLimit());
 
926
  tsplash->setLineWidth(state->getTransformedLineWidth());
 
927
 
 
928
  path = convertPath(state, state->getPath());
 
929
#if POPPLER_VERSION_MAJOR > 0 || POPPLER_VERSION_MINOR >= 19
 
930
  spath = tsplash->makeStrokePath(path,0);
 
931
#else
 
932
  spath = tsplash->makeStrokePath(path);
 
933
#endif
 
934
  path2 = new OPVPSplashPath(spath);
 
935
  delete spath;
 
936
  delete path;
 
937
  delete tsplash;
 
938
  delete tbitmap;
 
939
  oprs->clipToPath(path2, gFalse);
 
940
  delete path2;
 
941
}
 
942
 
 
943
OPVPSplashPath *OPVPOutputDev::convertPath(GfxState *state, GfxPath *path) {
 
944
  OPVPSplashPath *sPath;
 
945
  GfxSubpath *subpath;
 
946
  double x1, y1, x2, y2, x3, y3;
 
947
  int i, j;
 
948
 
 
949
  sPath = new OPVPSplashPath();
 
950
  for (i = 0; i < path->getNumSubpaths(); ++i) {
 
951
    subpath = path->getSubpath(i);
 
952
    if (subpath->getNumPoints() > 0) {
 
953
      state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1);
 
954
      sPath->moveTo((SplashCoord)x1, (SplashCoord)y1);
 
955
      j = 1;
 
956
      while (j < subpath->getNumPoints()) {
 
957
        if (subpath->getCurve(j)) {
 
958
          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
 
959
          state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2);
 
960
          state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3);
 
961
          sPath->curveTo((SplashCoord)x1, (SplashCoord)y1,
 
962
                         (SplashCoord)x2, (SplashCoord)y2,
 
963
                         (SplashCoord)x3, (SplashCoord)y3);
 
964
          j += 3;
 
965
        } else {
 
966
          state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1);
 
967
          sPath->lineTo((SplashCoord)x1, (SplashCoord)y1);
 
968
          ++j;
 
969
        }
 
970
      }
 
971
      if (subpath->isClosed()) {
 
972
        sPath->close();
 
973
      }
 
974
    }
 
975
  }
 
976
  return sPath;
 
977
}
 
978
 
 
979
void OPVPOutputDev::drawChar(GfxState *state, double x, double y,
 
980
                               double dx, double dy,
 
981
                               double originX, double originY,
 
982
                               CharCode code, int nBytes,
 
983
                               Unicode *u, int uLen) {
 
984
  double x1, y1;
 
985
  SplashPath *spath;
 
986
  OPVPSplashPath *path;
 
987
  int render;
 
988
 
 
989
  // check for invisible text -- this is used by Acrobat Capture
 
990
  render = state->getRender();
 
991
  if (render == 3) {
 
992
    return;
 
993
  }
 
994
 
 
995
  if (needFontUpdate) {
 
996
    doUpdateFont(state);
 
997
  }
 
998
  if (!font) {
 
999
    return;
 
1000
  }
 
1001
 
 
1002
  x -= originX;
 
1003
  y -= originY;
 
1004
  state->transform(x,y,&x1,&y1);
 
1005
 
 
1006
  // fill
 
1007
  if (!(render & 1)) {
 
1008
    oprs->fillChar((SplashCoord)x1, (SplashCoord)y1, code, font, u, fontMat);
 
1009
  }
 
1010
 
 
1011
  // stroke
 
1012
  if ((render & 3) == 1 || (render & 3) == 2) {
 
1013
    if ((spath = font->getGlyphPath(code))) {
 
1014
      path = new OPVPSplashPath(spath);
 
1015
      delete spath;
 
1016
      path->closeAllSubPath();
 
1017
      path->offset((SplashCoord)x1, (SplashCoord)y1);
 
1018
      oprs->stroke(path);
 
1019
      delete path;
 
1020
    } else {
 
1021
      opvpError(-1,"No glyph outline infomation");
 
1022
    }
 
1023
  }
 
1024
 
 
1025
  // clip
 
1026
  if (render & 4) {
 
1027
    if ((spath = font->getGlyphPath(code)) != NULL) {
 
1028
      path = new OPVPSplashPath(spath);
 
1029
      delete spath;
 
1030
      path->offset((SplashCoord)x1, (SplashCoord)y1);
 
1031
      if (textClipPath) {
 
1032
        textClipPath->append(path);
 
1033
        delete path;
 
1034
      } else {
 
1035
        textClipPath = path;
 
1036
      }
 
1037
    } else {
 
1038
      opvpError(-1,"No glyph outline infomation");
 
1039
    }
 
1040
  }
 
1041
}
 
1042
 
 
1043
GBool OPVPOutputDev::beginType3Char(GfxState *state, double x, double y,
 
1044
                                      double dx, double dy,
 
1045
                                      CharCode code, Unicode *u, int uLen) {
 
1046
  /* In a vector mode, cache is not needed */
 
1047
  return gFalse;
 
1048
}
 
1049
 
 
1050
void OPVPOutputDev::endType3Char(GfxState *state) {
 
1051
  /* In a vector mode, cache is not needed */
 
1052
  /* do nothing */
 
1053
}
 
1054
 
 
1055
void OPVPOutputDev::type3D0(GfxState *state, double wx, double wy) {
 
1056
  /* In a vector mode, cache is not needed */
 
1057
  /* do nothing */
 
1058
}
 
1059
 
 
1060
void OPVPOutputDev::type3D1(GfxState *state, double wx, double wy,
 
1061
                              double llx, double lly, double urx, double ury) {
 
1062
}
 
1063
 
 
1064
void OPVPOutputDev::drawType3Glyph(T3FontCache *t3Font,
 
1065
                                     T3FontCacheTag *tag, Guchar *data,
 
1066
                                     double x, double y) {
 
1067
  SplashGlyphBitmap glyph;
 
1068
 
 
1069
  glyph.x = -t3Font->glyphX;
 
1070
  glyph.y = -t3Font->glyphY;
 
1071
  glyph.w = t3Font->glyphW;
 
1072
  glyph.h = t3Font->glyphH;
 
1073
  glyph.aa = colorMode != splashModeMono1;
 
1074
  glyph.data = data;
 
1075
  glyph.freeData = gFalse;
 
1076
  oprs->fillGlyph((SplashCoord)x, (SplashCoord)y, &glyph);
 
1077
}
 
1078
 
 
1079
void OPVPOutputDev::endTextObject(GfxState *state) {
 
1080
  if (textClipPath) {
 
1081
    oprs->clipToPath(textClipPath, gFalse);
 
1082
    delete textClipPath;
 
1083
    textClipPath = NULL;
 
1084
  }
 
1085
}
 
1086
 
 
1087
struct SplashOutImageMaskData {
 
1088
  ImageStream *imgStr;
 
1089
  GBool invert;
 
1090
  int width, height, y;
 
1091
};
 
1092
 
 
1093
GBool OPVPOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
 
1094
  SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
 
1095
  Guchar *p;
 
1096
  SplashColorPtr q;
 
1097
  int x;
 
1098
 
 
1099
  if (imgMaskData->y == imgMaskData->height) {
 
1100
    return gFalse;
 
1101
  }
 
1102
  for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
 
1103
       x < imgMaskData->width;
 
1104
       ++x) {
 
1105
    *q++ = *p++ ^ imgMaskData->invert;
 
1106
  }
 
1107
  ++imgMaskData->y;
 
1108
  return gTrue;
 
1109
}
 
1110
 
 
1111
void OPVPOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 
1112
                                    int width, int height, GBool invert,
 
1113
                                    GBool interpolate,
 
1114
                                    GBool inlineImg) {
 
1115
  double *ctm;
 
1116
  SplashCoord mat[6];
 
1117
  SplashOutImageMaskData imgMaskData;
 
1118
 
 
1119
  ctm = state->getCTM();
 
1120
  mat[0] = ctm[0];
 
1121
  mat[1] = ctm[1];
 
1122
  mat[2] = -ctm[2];
 
1123
  mat[3] = -ctm[3];
 
1124
  mat[4] = ctm[2] + ctm[4];
 
1125
  mat[5] = ctm[3] + ctm[5];
 
1126
 
 
1127
  imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
 
1128
  imgMaskData.imgStr->reset();
 
1129
  imgMaskData.invert = invert ? 0 : 1;
 
1130
  imgMaskData.width = width;
 
1131
  imgMaskData.height =  height;
 
1132
  imgMaskData.y = 0;
 
1133
 
 
1134
  oprs->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat,
 
1135
                t3GlyphStack != NULL);
 
1136
  if (inlineImg) {
 
1137
    while (imgMaskData.y < height) {
 
1138
      imgMaskData.imgStr->getLine();
 
1139
      ++imgMaskData.y;
 
1140
    }
 
1141
  }
 
1142
 
 
1143
  delete imgMaskData.imgStr;
 
1144
}
 
1145
 
 
1146
struct SplashOutImageData {
 
1147
  ImageStream *imgStr;
 
1148
  GfxImageColorMap *colorMap;
 
1149
  SplashColorPtr lookup;
 
1150
  int *maskColors;
 
1151
  SplashColorMode colorMode;
 
1152
  int width, height, y;
 
1153
};
 
1154
 
 
1155
GBool OPVPOutputDev::imageSrc(void *data, SplashColorPtr line,
 
1156
                              Guchar *alphaLine)
 
1157
{
 
1158
  SplashOutImageData *imgData = (SplashOutImageData *)data;
 
1159
  Guchar *p;
 
1160
  SplashColorPtr q, col;
 
1161
  GfxRGB rgb;
 
1162
  GfxGray gray;
 
1163
#if SPLASH_CMYK
 
1164
  GfxCMYK cmyk;
 
1165
#endif
 
1166
  int nComps, x;
 
1167
 
 
1168
  if (imgData->y == imgData->height) {
 
1169
    return gFalse;
 
1170
  }
 
1171
 
 
1172
  nComps = imgData->colorMap->getNumPixelComps();
 
1173
 
 
1174
  if (imgData->lookup) {
 
1175
    switch (imgData->colorMode) {
 
1176
    case splashModeMono1:
 
1177
    case splashModeMono8:
 
1178
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1179
           x < imgData->width;
 
1180
           ++x, ++p) {
 
1181
        *q++ = imgData->lookup[*p];
 
1182
      }
 
1183
      break;
 
1184
    case splashModeRGB8:
 
1185
    case splashModeBGR8:
 
1186
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1187
           x < imgData->width;
 
1188
           ++x, ++p) {
 
1189
        col = &imgData->lookup[3 * *p];
 
1190
        *q++ = col[0];
 
1191
        *q++ = col[1];
 
1192
        *q++ = col[2];
 
1193
      }
 
1194
      break;
 
1195
#if SPLASH_CMYK
 
1196
    case splashModeCMYK8:
 
1197
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1198
           x < imgData->width;
 
1199
           ++x, ++p) {
 
1200
        col = &imgData->lookup[4 * *p];
 
1201
        *q++ = col[0];
 
1202
        *q++ = col[1];
 
1203
        *q++ = col[2];
 
1204
        *q++ = col[3];
 
1205
      }
 
1206
      break;
 
1207
#endif
 
1208
    default:
 
1209
      //~ unimplemented
 
1210
      break;
 
1211
  }
 
1212
  } else {
 
1213
    switch (imgData->colorMode) {
 
1214
    case splashModeMono1:
 
1215
    case splashModeMono8:
 
1216
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1217
           x < imgData->width;
 
1218
           ++x, p += nComps) {
 
1219
        imgData->colorMap->getGray(p, &gray);
 
1220
        *q++ = colToByte(gray);
 
1221
      }
 
1222
        break;
 
1223
    case splashModeRGB8:
 
1224
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1225
           x < imgData->width;
 
1226
           ++x, p += nComps) {
 
1227
        imgData->colorMap->getRGB(p, &rgb);
 
1228
        *q++ = colToByte(rgb.r);
 
1229
        *q++ = colToByte(rgb.g);
 
1230
        *q++ = colToByte(rgb.b);
 
1231
      }
 
1232
      break;
 
1233
    case splashModeBGR8:
 
1234
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1235
           x < imgData->width;
 
1236
           ++x, p += nComps) {
 
1237
        imgData->colorMap->getRGB(p, &rgb);
 
1238
        *q++ = colToByte(rgb.b);
 
1239
        *q++ = colToByte(rgb.g);
 
1240
        *q++ = colToByte(rgb.r);
 
1241
      }
 
1242
      break;
 
1243
#if SPLASH_CMYK
 
1244
    case splashModeCMYK8:
 
1245
      for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1246
           x < imgData->width;
 
1247
           ++x, p += nComps) {
 
1248
        imgData->colorMap->getCMYK(p, &cmyk);
 
1249
        *q++ = colToByte(cmyk.c);
 
1250
        *q++ = colToByte(cmyk.m);
 
1251
        *q++ = colToByte(cmyk.y);
 
1252
        *q++ = colToByte(cmyk.k);
 
1253
      }
 
1254
      break;
 
1255
#endif
 
1256
    default:
 
1257
      //~ unimplemented
 
1258
      break;
 
1259
    }
 
1260
  }
 
1261
 
 
1262
  ++imgData->y;
 
1263
  return gTrue;
 
1264
}
 
1265
 
 
1266
GBool OPVPOutputDev::alphaImageSrc(void *data, SplashColorPtr line,
 
1267
                                  Guchar *alphaLine) {
 
1268
  SplashOutImageData *imgData = (SplashOutImageData *)data;
 
1269
  Guchar *p;
 
1270
  SplashColorPtr q, col;
 
1271
  GfxRGB rgb;
 
1272
  GfxGray gray;
 
1273
#if SPLASH_CMYK
 
1274
  GfxCMYK cmyk;
 
1275
#endif
 
1276
  Guchar alpha;
 
1277
  int nComps, x, i;
 
1278
 
 
1279
  if (imgData->y == imgData->height) {
 
1280
    return gFalse;
 
1281
  }
 
1282
 
 
1283
  nComps = imgData->colorMap->getNumPixelComps();
 
1284
 
 
1285
  for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1286
       x < imgData->width;
 
1287
       ++x, p += nComps) {
 
1288
    alpha = 0;
 
1289
    for (i = 0; i < nComps; ++i) {
 
1290
      if (p[i] < imgData->maskColors[2*i] ||
 
1291
          p[i] > imgData->maskColors[2*i+1]) {
 
1292
        alpha = 0xff;
 
1293
        break;
 
1294
      }
 
1295
    }
 
1296
    if (imgData->lookup) {
 
1297
      switch (imgData->colorMode) {
 
1298
      case splashModeMono1:
 
1299
      case splashModeMono8:
 
1300
        *q++ = alpha;
 
1301
        *q++ = imgData->lookup[*p];
 
1302
        break;
 
1303
      case splashModeRGB8:
 
1304
        *q++ = alpha;
 
1305
        col = &imgData->lookup[3 * *p];
 
1306
        *q++ = col[0];
 
1307
        *q++ = col[1];
 
1308
        *q++ = col[2];
 
1309
        break;
 
1310
      case splashModeBGR8:
 
1311
        col = &imgData->lookup[3 * *p];
 
1312
        *q++ = col[0];
 
1313
        *q++ = col[1];
 
1314
        *q++ = col[2];
 
1315
        *q++ = alpha;
 
1316
        break;
 
1317
#if SPLASH_CMYK
 
1318
      case splashModeCMYK8:
 
1319
        *q++ = alpha;
 
1320
        col = &imgData->lookup[4 * *p];
 
1321
        *q++ = col[0];
 
1322
        *q++ = col[1];
 
1323
        *q++ = col[2];
 
1324
        *q++ = col[3];
 
1325
        break;
 
1326
#endif
 
1327
      default:
 
1328
        //~ unimplemented
 
1329
        break;
 
1330
      }
 
1331
    } else {
 
1332
      switch (imgData->colorMode) {
 
1333
      case splashModeMono1:
 
1334
      case splashModeMono8:
 
1335
        imgData->colorMap->getGray(p, &gray);
 
1336
        *q++ = alpha;
 
1337
        *q++ = colToByte(gray);
 
1338
        break;
 
1339
      case splashModeRGB8:
 
1340
        imgData->colorMap->getRGB(p, &rgb);
 
1341
        *q++ = alpha;
 
1342
        *q++ = colToByte(rgb.r);
 
1343
        *q++ = colToByte(rgb.g);
 
1344
        *q++ = colToByte(rgb.b);
 
1345
        break;
 
1346
      case splashModeBGR8:
 
1347
        imgData->colorMap->getRGB(p, &rgb);
 
1348
        *q++ = colToByte(rgb.b);
 
1349
        *q++ = colToByte(rgb.g);
 
1350
        *q++ = colToByte(rgb.r);
 
1351
        *q++ = alpha;
 
1352
        break;
 
1353
#if SPLASH_CMYK
 
1354
      case splashModeCMYK8:
 
1355
        imgData->colorMap->getCMYK(p, &cmyk);
 
1356
        *q++ = alpha;
 
1357
        *q++ = colToByte(cmyk.c);
 
1358
        *q++ = colToByte(cmyk.m);
 
1359
        *q++ = colToByte(cmyk.y);
 
1360
        *q++ = colToByte(cmyk.k);
 
1361
        break;
 
1362
#endif
 
1363
      default:
 
1364
        //~ unimplemented
 
1365
        break;
 
1366
      }
 
1367
    }
 
1368
  }
 
1369
 
 
1370
  ++imgData->y;
 
1371
  return gTrue;
 
1372
}
 
1373
 
 
1374
void OPVPOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 
1375
                                int width, int height,
 
1376
                                GfxImageColorMap *colorMap,
 
1377
                                GBool interpolate,
 
1378
                                int *maskColors, GBool inlineImg) {
 
1379
  double *ctm;
 
1380
  SplashCoord mat[6];
 
1381
  SplashOutImageData imgData;
 
1382
  SplashColorMode srcMode;
 
1383
  SplashImageSource src;
 
1384
  GfxGray gray;
 
1385
  GfxRGB rgb;
 
1386
#if SPLASH_CMYK
 
1387
  GfxCMYK cmyk;
 
1388
#endif
 
1389
  Guchar pix;
 
1390
  int n, i;
 
1391
 
 
1392
  ctm = state->getCTM();
 
1393
  mat[0] = ctm[0];
 
1394
  mat[1] = ctm[1];
 
1395
  mat[2] = -ctm[2];
 
1396
  mat[3] = -ctm[3];
 
1397
  mat[4] = ctm[2] + ctm[4];
 
1398
  mat[5] = ctm[3] + ctm[5];
 
1399
 
 
1400
  imgData.imgStr = new ImageStream(str, width,
 
1401
                                   colorMap->getNumPixelComps(),
 
1402
                                   colorMap->getBits());
 
1403
  imgData.imgStr->reset();
 
1404
  imgData.colorMap = colorMap;
 
1405
  imgData.maskColors = maskColors;
 
1406
  imgData.colorMode = colorMode;
 
1407
  imgData.width = width;
 
1408
  imgData.height = height;
 
1409
  imgData.y = 0;
 
1410
 
 
1411
  // special case for one-channel (monochrome/gray/separation) images:
 
1412
  // build a lookup table here
 
1413
  imgData.lookup = NULL;
 
1414
  if (colorMap->getNumPixelComps() == 1) {
 
1415
    n = 1 << colorMap->getBits();
 
1416
    switch (colorMode) {
 
1417
    case splashModeMono1:
 
1418
    case splashModeMono8:
 
1419
      imgData.lookup = (SplashColorPtr)gmalloc(n);
 
1420
      for (i = 0; i < n; ++i) {
 
1421
        pix = (Guchar)i;
 
1422
        colorMap->getGray(&pix, &gray);
 
1423
        imgData.lookup[i] = colToByte(gray);
 
1424
      }
 
1425
      break;
 
1426
    case splashModeRGB8:
 
1427
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1428
      for (i = 0; i < n; ++i) {
 
1429
        pix = (Guchar)i;
 
1430
        colorMap->getRGB(&pix, &rgb);
 
1431
        imgData.lookup[3*i] = colToByte(rgb.r);
 
1432
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1433
        imgData.lookup[3*i+2] = colToByte(rgb.b);
 
1434
      }
 
1435
      break;
 
1436
    case splashModeBGR8:
 
1437
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1438
      for (i = 0; i < n; ++i) {
 
1439
        pix = (Guchar)i;
 
1440
        colorMap->getRGB(&pix, &rgb);
 
1441
        imgData.lookup[3*i] = colToByte(rgb.b);
 
1442
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1443
        imgData.lookup[3*i+2] = colToByte(rgb.r);
 
1444
      }
 
1445
      break;
 
1446
#if SPLASH_CMYK
 
1447
    case splashModeCMYK8:
 
1448
      imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
1449
      for (i = 0; i < n; ++i) {
 
1450
        pix = (Guchar)i;
 
1451
        colorMap->getCMYK(&pix, &cmyk);
 
1452
        imgData.lookup[4*i] = colToByte(cmyk.c);
 
1453
        imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
1454
        imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
1455
        imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
1456
      }
 
1457
      break;
 
1458
#endif
 
1459
    default:
 
1460
      //~ unimplemented
 
1461
      break;
 
1462
    }
 
1463
  }
 
1464
 
 
1465
  if (colorMode == splashModeMono1) {
 
1466
    srcMode = splashModeMono8;
 
1467
  } else {
 
1468
    srcMode = colorMode;
 
1469
  }
 
1470
  src = maskColors ? &alphaImageSrc : &imageSrc;
 
1471
  oprs->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse,
 
1472
                  width, height, mat);
 
1473
  if (inlineImg) {
 
1474
    while (imgData.y < height) {
 
1475
      imgData.imgStr->getLine();
 
1476
      ++imgData.y;
 
1477
    }
 
1478
  }
 
1479
 
 
1480
  gfree(imgData.lookup);
 
1481
  delete imgData.imgStr;
 
1482
  str->close();
 
1483
}
 
1484
 
 
1485
struct SplashOutMaskedImageData {
 
1486
  ImageStream *imgStr;
 
1487
  GfxImageColorMap *colorMap;
 
1488
  SplashBitmap *mask;
 
1489
  SplashColorPtr lookup;
 
1490
  SplashColorMode colorMode;
 
1491
  int width, height, y;
 
1492
};
 
1493
 
 
1494
GBool OPVPOutputDev::maskedImageSrc(void *data, SplashColorPtr line,
 
1495
     Guchar *alphaLine) {
 
1496
  SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
 
1497
  Guchar *p;
 
1498
  SplashColor maskColor;
 
1499
  SplashColorPtr q, col;
 
1500
  GfxRGB rgb;
 
1501
  GfxGray gray;
 
1502
#if SPLASH_CMYK
 
1503
  GfxCMYK cmyk;
 
1504
#endif
 
1505
  Guchar alpha;
 
1506
  int nComps, x;
 
1507
 
 
1508
  if (imgData->y == imgData->height) {
 
1509
    return gFalse;
 
1510
  }
 
1511
 
 
1512
  nComps = imgData->colorMap->getNumPixelComps();
 
1513
 
 
1514
  for (x = 0, p = imgData->imgStr->getLine(), q = line;
 
1515
       x < imgData->width;
 
1516
       ++x, p += nComps) {
 
1517
    imgData->mask->getPixel(x, imgData->y, maskColor);
 
1518
    alpha = maskColor[0] ? 0xff : 0x00;
 
1519
    if (imgData->lookup) {
 
1520
      switch (imgData->colorMode) {
 
1521
      case splashModeMono1:
 
1522
      case splashModeMono8:
 
1523
        *q++ = alpha;
 
1524
        *q++ = imgData->lookup[*p];
 
1525
        break;
 
1526
      case splashModeRGB8:
 
1527
        *q++ = alpha;
 
1528
        col = &imgData->lookup[3 * *p];
 
1529
        *q++ = col[0];
 
1530
        *q++ = col[1];
 
1531
        *q++ = col[2];
 
1532
        break;
 
1533
      case splashModeBGR8:
 
1534
        col = &imgData->lookup[3 * *p];
 
1535
        *q++ = col[0];
 
1536
        *q++ = col[1];
 
1537
        *q++ = col[2];
 
1538
        *q++ = alpha;
 
1539
        break;
 
1540
#if SPLASH_CMYK
 
1541
      case splashModeCMYK8:
 
1542
        *q++ = alpha;
 
1543
        col = &imgData->lookup[4 * *p];
 
1544
        *q++ = col[0];
 
1545
        *q++ = col[1];
 
1546
        *q++ = col[2];
 
1547
        *q++ = col[3];
 
1548
        break;
 
1549
#endif
 
1550
      default:
 
1551
        //~ unimplemented
 
1552
        break;
 
1553
      }
 
1554
    } else {
 
1555
      switch (imgData->colorMode) {
 
1556
      case splashModeMono1:
 
1557
      case splashModeMono8:
 
1558
        imgData->colorMap->getGray(p, &gray);
 
1559
        *q++ = alpha;
 
1560
        *q++ = colToByte(gray);
 
1561
        break;
 
1562
      case splashModeRGB8:
 
1563
        imgData->colorMap->getRGB(p, &rgb);
 
1564
        *q++ = alpha;
 
1565
        *q++ = colToByte(rgb.r);
 
1566
        *q++ = colToByte(rgb.g);
 
1567
        *q++ = colToByte(rgb.b);
 
1568
        break;
 
1569
      case splashModeBGR8:
 
1570
        imgData->colorMap->getRGB(p, &rgb);
 
1571
        *q++ = colToByte(rgb.b);
 
1572
        *q++ = colToByte(rgb.g);
 
1573
        *q++ = colToByte(rgb.r);
 
1574
        *q++ = alpha;
 
1575
        break;
 
1576
#if SPLASH_CMYK
 
1577
      case splashModeCMYK8:
 
1578
        imgData->colorMap->getCMYK(p, &cmyk);
 
1579
        *q++ = alpha;
 
1580
        *q++ = colToByte(cmyk.c);
 
1581
        *q++ = colToByte(cmyk.m);
 
1582
        *q++ = colToByte(cmyk.y);
 
1583
        *q++ = colToByte(cmyk.k);
 
1584
        break;
 
1585
#endif
 
1586
      default:
 
1587
        //~ unimplemented
 
1588
        break;
 
1589
      }
 
1590
    }
 
1591
  }
 
1592
 
 
1593
  ++imgData->y;
 
1594
  return gTrue;
 
1595
}
 
1596
 
 
1597
void OPVPOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 
1598
                                      Stream *str, int width, int height,
 
1599
                                      GfxImageColorMap *colorMap,
 
1600
                                      GBool interpolate,
 
1601
                                      Stream *maskStr, int maskWidth,
 
1602
                                      int maskHeight, GBool maskInvert,
 
1603
                                      GBool maskInterpolate) {
 
1604
  double *ctm;
 
1605
  SplashCoord mat[6];
 
1606
  SplashOutMaskedImageData imgData;
 
1607
  SplashOutImageMaskData imgMaskData;
 
1608
  SplashColorMode srcMode;
 
1609
  SplashBitmap *maskBitmap;
 
1610
  Splash *maskSplash;
 
1611
  SplashColor maskColor;
 
1612
  GfxGray gray;
 
1613
  GfxRGB rgb;
 
1614
#if SPLASH_CMYK
 
1615
  GfxCMYK cmyk;
 
1616
#endif
 
1617
  Guchar pix;
 
1618
  int n, i;
 
1619
 
 
1620
  //----- scale the mask image to the same size as the source image
 
1621
 
 
1622
  mat[0] = (SplashCoord)width;
 
1623
  mat[1] = 0;
 
1624
  mat[2] = 0;
 
1625
  mat[3] = (SplashCoord)height;
 
1626
  mat[4] = 0;
 
1627
  mat[5] = 0;
 
1628
  imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
 
1629
  imgMaskData.imgStr->reset();
 
1630
  imgMaskData.invert = maskInvert ? 0 : 1;
 
1631
  imgMaskData.width = maskWidth;
 
1632
  imgMaskData.height = maskHeight;
 
1633
  imgMaskData.y = 0;
 
1634
  maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse);
 
1635
  maskSplash = new Splash(maskBitmap, gFalse);
 
1636
  maskColor[0] = 0;
 
1637
  maskSplash->clear(maskColor);
 
1638
  maskColor[0] = 1;
 
1639
  maskSplash->setFillPattern(new SplashSolidColor(maskColor));
 
1640
  maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
 
1641
                            maskWidth, maskHeight, mat, gFalse);
 
1642
  delete imgMaskData.imgStr;
 
1643
  maskStr->close();
 
1644
  delete maskSplash;
 
1645
 
 
1646
  //----- draw the source image
 
1647
 
 
1648
  ctm = state->getCTM();
 
1649
  mat[0] = ctm[0];
 
1650
  mat[1] = ctm[1];
 
1651
  mat[2] = -ctm[2];
 
1652
  mat[3] = -ctm[3];
 
1653
  mat[4] = ctm[2] + ctm[4];
 
1654
  mat[5] = ctm[3] + ctm[5];
 
1655
 
 
1656
  imgData.imgStr = new ImageStream(str, width,
 
1657
                                   colorMap->getNumPixelComps(),
 
1658
                                   colorMap->getBits());
 
1659
  imgData.imgStr->reset();
 
1660
  imgData.colorMap = colorMap;
 
1661
  imgData.mask = maskBitmap;
 
1662
  imgData.colorMode = colorMode;
 
1663
  imgData.width = width;
 
1664
  imgData.height = height;
 
1665
  imgData.y = 0;
 
1666
 
 
1667
  // special case for one-channel (monochrome/gray/separation) images:
 
1668
  // build a lookup table here
 
1669
  imgData.lookup = NULL;
 
1670
  if (colorMap->getNumPixelComps() == 1) {
 
1671
    n = 1 << colorMap->getBits();
 
1672
    switch (colorMode) {
 
1673
    case splashModeMono1:
 
1674
    case splashModeMono8:
 
1675
      imgData.lookup = (SplashColorPtr)gmalloc(n);
 
1676
      for (i = 0; i < n; ++i) {
 
1677
        pix = (Guchar)i;
 
1678
        colorMap->getGray(&pix, &gray);
 
1679
        imgData.lookup[i] = colToByte(gray);
 
1680
      }
 
1681
      break;
 
1682
    case splashModeRGB8:
 
1683
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1684
      for (i = 0; i < n; ++i) {
 
1685
        pix = (Guchar)i;
 
1686
        colorMap->getRGB(&pix, &rgb);
 
1687
        imgData.lookup[3*i] = colToByte(rgb.r);
 
1688
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1689
        imgData.lookup[3*i+2] = colToByte(rgb.b);
 
1690
      }
 
1691
      break;
 
1692
    case splashModeBGR8:
 
1693
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1694
      for (i = 0; i < n; ++i) {
 
1695
        pix = (Guchar)i;
 
1696
        colorMap->getRGB(&pix, &rgb);
 
1697
        imgData.lookup[3*i] = colToByte(rgb.b);
 
1698
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1699
        imgData.lookup[3*i+2] = colToByte(rgb.r);
 
1700
      }
 
1701
      break;
 
1702
#if SPLASH_CMYK
 
1703
    case splashModeCMYK8:
 
1704
      imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
1705
      for (i = 0; i < n; ++i) {
 
1706
        pix = (Guchar)i;
 
1707
        colorMap->getCMYK(&pix, &cmyk);
 
1708
        imgData.lookup[4*i] = colToByte(cmyk.c);
 
1709
        imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
1710
        imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
1711
        imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
1712
      }
 
1713
      break;
 
1714
#endif
 
1715
    default:
 
1716
      //~ unimplemented
 
1717
      break;
 
1718
    }
 
1719
  }
 
1720
 
 
1721
  switch (colorMode) {
 
1722
  case splashModeMono1:
 
1723
  case splashModeMono8:
 
1724
    srcMode = splashModeMono8;
 
1725
    break;
 
1726
  case splashModeRGB8:
 
1727
    srcMode = splashModeRGB8;
 
1728
    break;
 
1729
  case splashModeBGR8:
 
1730
    srcMode = splashModeBGR8;
 
1731
    break;
 
1732
#if SPLASH_CMYK
 
1733
  case splashModeCMYK8:
 
1734
    srcMode = splashModeCMYK8;
 
1735
    break;
 
1736
#endif
 
1737
  default:
 
1738
    //~ unimplemented
 
1739
    srcMode = splashModeRGB8;
 
1740
    break;
 
1741
  }  
 
1742
  oprs->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue, 
 
1743
                  width, height, mat);
 
1744
 
 
1745
  delete maskBitmap;
 
1746
  gfree(imgData.lookup);
 
1747
  delete imgData.imgStr;
 
1748
  str->close();
 
1749
}
 
1750
 
 
1751
void OPVPOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
 
1752
                                          Stream *str, int width, int height,
 
1753
                                          GfxImageColorMap *colorMap,
 
1754
                                          GBool interpolate,
 
1755
                                          Stream *maskStr,
 
1756
                                          int maskWidth, int maskHeight,
 
1757
                                          GfxImageColorMap *maskColorMap,
 
1758
                                          GBool maskInterpolate) {
 
1759
  double *ctm;
 
1760
  SplashCoord mat[6];
 
1761
  SplashOutImageData imgData;
 
1762
  SplashOutImageData imgMaskData;
 
1763
  SplashColorMode srcMode;
 
1764
  SplashBitmap *maskBitmap;
 
1765
  Splash *maskSplash;
 
1766
  SplashColor maskColor;
 
1767
  GfxGray gray;
 
1768
  GfxRGB rgb;
 
1769
#if SPLASH_CMYK
 
1770
  GfxCMYK cmyk;
 
1771
#endif
 
1772
  Guchar pix;
 
1773
  int n, i;
 
1774
 
 
1775
  ctm = state->getCTM();
 
1776
  mat[0] = ctm[0];
 
1777
  mat[1] = ctm[1];
 
1778
  mat[2] = -ctm[2];
 
1779
  mat[3] = -ctm[3];
 
1780
  mat[4] = ctm[2] + ctm[4];
 
1781
  mat[5] = ctm[3] + ctm[5];
 
1782
 
 
1783
  //----- set up the soft mask
 
1784
 
 
1785
  imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
 
1786
                                       maskColorMap->getNumPixelComps(),
 
1787
                                       maskColorMap->getBits());
 
1788
  imgMaskData.imgStr->reset();
 
1789
  imgMaskData.colorMap = maskColorMap;
 
1790
  imgMaskData.maskColors = NULL;
 
1791
  imgMaskData.colorMode = splashModeMono8;
 
1792
  imgMaskData.width = maskWidth;
 
1793
  imgMaskData.height = maskHeight;
 
1794
  imgMaskData.y = 0;
 
1795
  n = 1 << maskColorMap->getBits();
 
1796
  imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
 
1797
  for (i = 0; i < n; ++i) {
 
1798
    pix = (Guchar)i;
 
1799
    maskColorMap->getGray(&pix, &gray);
 
1800
    imgMaskData.lookup[i] = colToByte(gray);
 
1801
  }
 
1802
  maskBitmap = new SplashBitmap(maskWidth,maskHeight,
 
1803
                                1, splashModeMono8, gFalse);
 
1804
  maskSplash = new Splash(maskBitmap, gFalse);
 
1805
  maskColor[0] = 0;
 
1806
  maskSplash->clear(maskColor);
 
1807
  maskSplash->drawImage(&imageSrc, &imgMaskData,
 
1808
                        splashModeMono8, gFalse, maskWidth, maskHeight, mat);
 
1809
  delete imgMaskData.imgStr;
 
1810
  maskStr->close();
 
1811
  gfree(imgMaskData.lookup);
 
1812
  delete maskSplash;
 
1813
  oprs->setSoftMask(maskBitmap);
 
1814
 
 
1815
  //----- draw the source image
 
1816
 
 
1817
  imgData.imgStr = new ImageStream(str, width,
 
1818
                                   colorMap->getNumPixelComps(),
 
1819
                                   colorMap->getBits());
 
1820
  imgData.imgStr->reset();
 
1821
  imgData.colorMap = colorMap;
 
1822
  imgData.maskColors = NULL;
 
1823
  imgData.colorMode = colorMode;
 
1824
  imgData.width = width;
 
1825
  imgData.height = height;
 
1826
  imgData.y = 0;
 
1827
 
 
1828
  // special case for one-channel (monochrome/gray/separation) images:
 
1829
  // build a lookup table here
 
1830
  imgData.lookup = NULL;
 
1831
  if (colorMap->getNumPixelComps() == 1) {
 
1832
    n = 1 << colorMap->getBits();
 
1833
    switch (colorMode) {
 
1834
    case splashModeMono1:
 
1835
    case splashModeMono8:
 
1836
      imgData.lookup = (SplashColorPtr)gmalloc(n);
 
1837
      for (i = 0; i < n; ++i) {
 
1838
        pix = (Guchar)i;
 
1839
        colorMap->getGray(&pix, &gray);
 
1840
        imgData.lookup[i] = colToByte(gray);
 
1841
      }
 
1842
      break;
 
1843
    case splashModeRGB8:
 
1844
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1845
      for (i = 0; i < n; ++i) {
 
1846
        pix = (Guchar)i;
 
1847
        colorMap->getRGB(&pix, &rgb);
 
1848
        imgData.lookup[3*i] = colToByte(rgb.r);
 
1849
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1850
        imgData.lookup[3*i+2] = colToByte(rgb.b);
 
1851
      }
 
1852
      break;
 
1853
    case splashModeBGR8:
 
1854
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
1855
      for (i = 0; i < n; ++i) {
 
1856
        pix = (Guchar)i;
 
1857
        colorMap->getRGB(&pix, &rgb);
 
1858
        imgData.lookup[3*i] = colToByte(rgb.b);
 
1859
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
1860
        imgData.lookup[3*i+2] = colToByte(rgb.r);
 
1861
      }
 
1862
      break;
 
1863
#if SPLASH_CMYK
 
1864
    case splashModeCMYK8:
 
1865
      imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
1866
      for (i = 0; i < n; ++i) {
 
1867
        pix = (Guchar)i;
 
1868
        colorMap->getCMYK(&pix, &cmyk);
 
1869
        imgData.lookup[4*i] = colToByte(cmyk.c);
 
1870
        imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
1871
        imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
1872
        imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
1873
      }
 
1874
      break;
 
1875
#endif
 
1876
    default:
 
1877
      //~ unimplemented
 
1878
      break;
 
1879
    }
 
1880
  }
 
1881
 
 
1882
  switch (colorMode) {
 
1883
  case splashModeMono1:
 
1884
  case splashModeMono8:
 
1885
    srcMode = splashModeMono8;
 
1886
    break;
 
1887
  case splashModeRGB8:
 
1888
    srcMode = splashModeRGB8;
 
1889
    break;
 
1890
  case splashModeBGR8:
 
1891
    srcMode = splashModeBGR8;
 
1892
    break;
 
1893
#if SPLASH_CMYK
 
1894
  case splashModeCMYK8:
 
1895
    srcMode = splashModeCMYK8;
 
1896
    break;
 
1897
#endif
 
1898
  default:
 
1899
    //~ unimplemented
 
1900
    srcMode = splashModeRGB8;
 
1901
    break;
 
1902
  }  
 
1903
  oprs->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat);
 
1904
 
 
1905
  oprs->setSoftMask(NULL);
 
1906
  gfree(imgData.lookup);
 
1907
  delete imgData.imgStr;
 
1908
  str->close();
 
1909
}
 
1910
 
 
1911
int OPVPOutputDev::getBitmapWidth() {
 
1912
  return bitmap->getWidth();
 
1913
}
 
1914
 
 
1915
int OPVPOutputDev::getBitmapHeight() {
 
1916
  return bitmap->getHeight();
 
1917
}
 
1918
 
 
1919
void OPVPOutputDev::xorRectangle(int x0, int y0, int x1, int y1,
 
1920
                                   SplashPattern *pattern) {
 
1921
    /* no need in printing */
 
1922
}
 
1923
 
 
1924
void OPVPOutputDev::setFillColor(int r, int g, int b) {
 
1925
  GfxRGB rgb;
 
1926
  GfxGray gray;
 
1927
#if SPLASH_CMYK
 
1928
  GfxCMYK cmyk;
 
1929
#endif
 
1930
 
 
1931
  rgb.r = byteToCol(r);
 
1932
  rgb.g = byteToCol(g);
 
1933
  rgb.b = byteToCol(b);
 
1934
  gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
 
1935
  if (gray > gfxColorComp1) {
 
1936
    gray = gfxColorComp1;
 
1937
  }
 
1938
#if SPLASH_CMYK
 
1939
  cmyk.c = gfxColorComp1 - rgb.r;
 
1940
  cmyk.m = gfxColorComp1 - rgb.g;
 
1941
  cmyk.y = gfxColorComp1 - rgb.b;
 
1942
  cmyk.k = 0;
 
1943
  oprs->setFillPattern(getColor(gray, &rgb, &cmyk));
 
1944
#else
 
1945
  oprs->setFillPattern(getColor(gray, &rgb));
 
1946
#endif
 
1947
}
 
1948
 
 
1949
int OPVPOutputDev::OPVPStartJob(char *jobInfo)
 
1950
{
 
1951
    return oprs->OPVPStartJob(jobInfo);
 
1952
}
 
1953
 
 
1954
int OPVPOutputDev::OPVPEndJob()
 
1955
{
 
1956
    return oprs->OPVPEndJob();
 
1957
}
 
1958
 
 
1959
int OPVPOutputDev::OPVPStartDoc(char *docInfo)
 
1960
{
 
1961
    return oprs->OPVPStartDoc(docInfo);
 
1962
}
 
1963
 
 
1964
int OPVPOutputDev::OPVPEndDoc()
 
1965
{
 
1966
    return oprs->OPVPEndDoc();
 
1967
}
 
1968
 
 
1969
int OPVPOutputDev::OPVPStartPage(char *pageInfo,
 
1970
  int rasterWidth, int rasterHeight)
 
1971
{
 
1972
    paperWidth = rasterWidth;
 
1973
    paperHeight = rasterHeight;
 
1974
    return oprs->OPVPStartPage(pageInfo,rasterWidth);
 
1975
}
 
1976
 
 
1977
int OPVPOutputDev::OPVPEndPage()
 
1978
{
 
1979
    return oprs->OPVPEndPage();
 
1980
}
 
1981
 
 
1982
int OPVPOutputDev::outSlice()
 
1983
{
 
1984
    return oprs->outSlice();
 
1985
}
 
1986
 
 
1987
void OPVPOutputDev::psXObject(Stream *psStream, Stream *level1Stream)
 
1988
{
 
1989
  opvpError(-1,"psXObject is found, but it is not supported");
 
1990
}