1
//========================================================================
5
// Copyright 2003 Glyph & Cog, LLC
7
//========================================================================
11
#ifdef USE_GCC_PRAGMAS
12
#pragma implementation
18
#include "GlobalParams.h"
23
#include "CharCodeToUnicode.h"
24
#include "FontEncodingTables.h"
25
#include "FoFiTrueType.h"
26
#include "SplashBitmap.h"
27
#include "SplashGlyphBitmap.h"
28
#include "SplashPattern.h"
29
#include "SplashScreen.h"
30
#include "SplashPath.h"
31
#include "SplashState.h"
32
#include "SplashErrorCodes.h"
33
#include "SplashFontEngine.h"
34
#include "SplashFont.h"
35
#include "SplashFontFile.h"
36
#include "SplashFontFileID.h"
38
#include "SplashOutputDev.h"
41
#if (__VMS_VER < 70000000)
42
extern "C" int unlink(char *filename);
46
//------------------------------------------------------------------------
48
// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
49
static inline Guchar div255(int x) {
50
return (Guchar)((x + (x >> 8) + 0x80) >> 8);
53
//------------------------------------------------------------------------
55
//------------------------------------------------------------------------
57
static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
58
SplashColorPtr blend, SplashColorMode cm) {
61
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
62
blend[i] = (dest[i] * src[i]) / 255;
66
static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
67
SplashColorPtr blend, SplashColorMode cm) {
70
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
71
blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
75
static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
76
SplashColorPtr blend, SplashColorMode cm) {
79
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
80
blend[i] = dest[i] < 0x80
81
? (src[i] * 2 * dest[i]) / 255
82
: 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
86
static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
87
SplashColorPtr blend, SplashColorMode cm) {
90
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
91
blend[i] = dest[i] < src[i] ? dest[i] : src[i];
95
static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
96
SplashColorPtr blend, SplashColorMode cm) {
99
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
100
blend[i] = dest[i] > src[i] ? dest[i] : src[i];
104
static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
105
SplashColorPtr blend,
106
SplashColorMode cm) {
109
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
113
x = (dest[i] * 255) / (255 - src[i]);
114
blend[i] = x <= 255 ? x : 255;
119
static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
120
SplashColorPtr blend, SplashColorMode cm) {
123
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
127
x = ((255 - dest[i]) * 255) / src[i];
128
blend[i] = x <= 255 ? 255 - x : 0;
133
static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
134
SplashColorPtr blend, SplashColorMode cm) {
137
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
138
blend[i] = src[i] < 0x80
139
? (dest[i] * 2 * src[i]) / 255
140
: 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
144
static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
145
SplashColorPtr blend, SplashColorMode cm) {
148
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
150
blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) /
153
if (dest[i] < 0x40) {
154
x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255)
155
+ 4 * 255) * dest[i]) / 255;
157
x = (int)sqrt(255.0 * dest[i]);
159
blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
164
static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
165
SplashColorPtr blend,
166
SplashColorMode cm) {
169
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
170
blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
174
static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
175
SplashColorPtr blend, SplashColorMode cm) {
178
for (i = 0; i < splashColorModeNComps[cm]; ++i) {
179
blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
183
static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) {
184
int cmax, cmid, cmin, x;
187
if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; }
188
else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; }
189
else { x = 5; cmax = r; cmid = b; cmin = g; }
191
if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; }
192
else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; }
193
else { x = 3; cmax = b; cmid = g; cmin = r; }
200
*h += ((cmax - cmid) * 60) / (cmax - cmin);
202
*h += ((cmid - cmin) * 60) / (cmax - cmin);
204
*s = (255 * (cmax - cmin)) / cmax;
209
static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) {
210
int x, f, cmax, cmid, cmin;
219
cmid = div255(v * 255 - ((s * f) / 60));
221
cmid = div255(v * (255 - ((s * (60 - f)) / 60)));
223
cmin = div255(v * (255 - s));
225
case 0: *r = cmax; *g = cmid; *b = cmin; break;
226
case 1: *g = cmax; *r = cmid; *b = cmin; break;
227
case 2: *g = cmax; *b = cmid; *r = cmin; break;
228
case 3: *b = cmax; *g = cmid; *r = cmin; break;
229
case 4: *b = cmax; *r = cmid; *g = cmin; break;
230
case 5: *r = cmax; *b = cmid; *g = cmin; break;
235
static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
236
SplashColorPtr blend, SplashColorMode cm) {
237
int hs, ss, vs, hd, sd, vd;
243
case splashModeMono1:
244
case splashModeMono8:
249
cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
250
cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
251
cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]);
254
case splashModeCMYK8:
255
//~ (0xff - ...) should be clipped
256
cvtRGBToHSV(0xff - (src[0] + src[3]),
257
0xff - (src[1] + src[3]),
258
0xff - (src[2] + src[3]), &hs, &ss, &vs);
259
cvtRGBToHSV(0xff - (dest[0] + dest[3]),
260
0xff - (dest[1] + dest[3]),
261
0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
262
cvtHSVToRGB(hs, sd, vd, &r, &g, &b);
263
//~ should do black generation
273
static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
274
SplashColorPtr blend,
275
SplashColorMode cm) {
276
int hs, ss, vs, hd, sd, vd;
282
case splashModeMono1:
283
case splashModeMono8:
288
cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
289
cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
290
cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]);
293
case splashModeCMYK8:
294
//~ (0xff - ...) should be clipped
295
cvtRGBToHSV(0xff - (src[0] + src[3]),
296
0xff - (src[1] + src[3]),
297
0xff - (src[2] + src[3]), &hs, &ss, &vs);
298
cvtRGBToHSV(0xff - (dest[0] + dest[3]),
299
0xff - (dest[1] + dest[3]),
300
0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
301
cvtHSVToRGB(hd, ss, vd, &r, &g, &b);
302
//~ should do black generation
312
static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
313
SplashColorPtr blend, SplashColorMode cm) {
314
int hs, ss, vs, hd, sd, vd;
320
case splashModeMono1:
321
case splashModeMono8:
326
cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
327
cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
328
cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]);
331
case splashModeCMYK8:
332
//~ (0xff - ...) should be clipped
333
cvtRGBToHSV(0xff - (src[0] + src[3]),
334
0xff - (src[1] + src[3]),
335
0xff - (src[2] + src[3]), &hs, &ss, &vs);
336
cvtRGBToHSV(0xff - (dest[0] + dest[3]),
337
0xff - (dest[1] + dest[3]),
338
0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
339
cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
340
//~ should do black generation
350
static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
351
SplashColorPtr blend,
352
SplashColorMode cm) {
353
int hs, ss, vs, hd, sd, vd;
359
case splashModeMono1:
360
case splashModeMono8:
365
cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
366
cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
367
cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]);
370
case splashModeCMYK8:
371
//~ (0xff - ...) should be clipped
372
cvtRGBToHSV(0xff - (src[0] + src[3]),
373
0xff - (src[1] + src[3]),
374
0xff - (src[2] + src[3]), &hs, &ss, &vs);
375
cvtRGBToHSV(0xff - (dest[0] + dest[3]),
376
0xff - (dest[1] + dest[3]),
377
0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
378
cvtHSVToRGB(hd, sd, vs, &r, &g, &b);
379
//~ should do black generation
389
// NB: This must match the GfxBlendMode enum defined in GfxState.h.
390
SplashBlendFunc splashOutBlendFuncs[] = {
392
&splashOutBlendMultiply,
393
&splashOutBlendScreen,
394
&splashOutBlendOverlay,
395
&splashOutBlendDarken,
396
&splashOutBlendLighten,
397
&splashOutBlendColorDodge,
398
&splashOutBlendColorBurn,
399
&splashOutBlendHardLight,
400
&splashOutBlendSoftLight,
401
&splashOutBlendDifference,
402
&splashOutBlendExclusion,
404
&splashOutBlendSaturation,
405
&splashOutBlendColor,
406
&splashOutBlendLuminosity
409
//------------------------------------------------------------------------
410
// Font substitutions
411
//------------------------------------------------------------------------
413
struct SplashOutFontSubst {
418
// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
419
static SplashOutFontSubst splashOutSubstFonts[16] = {
420
{"Helvetica", 0.833},
421
{"Helvetica-Oblique", 0.833},
422
{"Helvetica-Bold", 0.889},
423
{"Helvetica-BoldOblique", 0.889},
424
{"Times-Roman", 0.788},
425
{"Times-Italic", 0.722},
426
{"Times-Bold", 0.833},
427
{"Times-BoldItalic", 0.778},
429
{"Courier-Oblique", 0.600},
430
{"Courier-Bold", 0.600},
431
{"Courier-BoldOblique", 0.600},
438
//------------------------------------------------------------------------
439
// SplashOutFontFileID
440
//------------------------------------------------------------------------
442
class SplashOutFontFileID: public SplashFontFileID {
445
SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; }
447
~SplashOutFontFileID() {}
449
GBool matches(SplashFontFileID *id) {
450
return ((SplashOutFontFileID *)id)->r.num == r.num &&
451
((SplashOutFontFileID *)id)->r.gen == r.gen;
454
void setSubstIdx(int substIdxA) { substIdx = substIdxA; }
455
int getSubstIdx() { return substIdx; }
463
//------------------------------------------------------------------------
465
//------------------------------------------------------------------------
467
struct T3FontCacheTag {
469
Gushort mru; // valid bit (0x8000) and MRU index
475
T3FontCache(Ref *fontID, double m11A, double m12A,
476
double m21A, double m22A,
477
int glyphXA, int glyphYA, int glyphWA, int glyphHA,
478
GBool aa, GBool validBBoxA);
480
GBool matches(Ref *idA, double m11A, double m12A,
481
double m21A, double m22A)
482
{ return fontID.num == idA->num && fontID.gen == idA->gen &&
483
m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
485
Ref fontID; // PDF font ID
486
double m11, m12, m21, m22; // transform matrix
487
int glyphX, glyphY; // pixel offset of glyph bitmaps
488
int glyphW, glyphH; // size of glyph bitmaps, in pixels
489
GBool validBBox; // false if the bbox was [0 0 0 0]
490
int glyphSize; // size of glyph bitmaps, in bytes
491
int cacheSets; // number of sets in cache
492
int cacheAssoc; // cache associativity (glyphs per set)
493
Guchar *cacheData; // glyph pixmap cache
494
T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
497
T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
498
double m21A, double m22A,
499
int glyphXA, int glyphYA, int glyphWA, int glyphHA,
500
GBool validBBoxA, GBool aa) {
512
validBBox = validBBoxA;
514
glyphSize = glyphW * glyphH;
516
glyphSize = ((glyphW + 7) >> 3) * glyphH;
519
if (glyphSize <= 256) {
521
} else if (glyphSize <= 512) {
523
} else if (glyphSize <= 1024) {
528
cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
529
cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
530
sizeof(T3FontCacheTag));
531
for (i = 0; i < cacheSets * cacheAssoc; ++i) {
532
cacheTags[i].mru = i & (cacheAssoc - 1);
536
T3FontCache::~T3FontCache() {
541
struct T3GlyphStack {
542
Gushort code; // character code
545
T3FontCache *cache; // font cache for the current font
546
T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph
547
Guchar *cacheData; // pointer to cache data for the glyph
550
SplashBitmap *origBitmap;
552
double origCTM4, origCTM5;
554
T3GlyphStack *next; // next object on stack
557
//------------------------------------------------------------------------
558
// SplashTransparencyGroup
559
//------------------------------------------------------------------------
561
struct SplashTransparencyGroup {
562
int tx, ty; // translation coordinates
563
SplashBitmap *tBitmap; // bitmap for transparency group
564
GfxColorSpace *blendingColorSpace;
568
SplashBitmap *origBitmap;
571
SplashTransparencyGroup *next;
574
//------------------------------------------------------------------------
576
//------------------------------------------------------------------------
578
SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
581
SplashColorPtr paperColorA,
582
GBool bitmapTopDownA,
583
GBool allowAntialiasA) {
584
colorMode = colorModeA;
585
bitmapRowPad = bitmapRowPadA;
586
bitmapTopDown = bitmapTopDownA;
587
allowAntialias = allowAntialiasA;
588
vectorAntialias = allowAntialias &&
589
globalParams->getVectorAntialias() &&
590
colorMode != splashModeMono1;
591
setupScreenParams(72.0, 72.0);
592
reverseVideo = reverseVideoA;
593
splashColorCopy(paperColor, paperColorA);
597
bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
598
colorMode != splashModeMono1, bitmapTopDown);
599
splash = new Splash(bitmap, vectorAntialias, &screenParams);
600
splash->clear(paperColor, 0);
608
needFontUpdate = gFalse;
611
transpGroupStack = NULL;
614
void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
615
screenParams.size = globalParams->getScreenSize();
616
screenParams.dotRadius = globalParams->getScreenDotRadius();
617
screenParams.gamma = (SplashCoord)globalParams->getScreenGamma();
618
screenParams.blackThreshold =
619
(SplashCoord)globalParams->getScreenBlackThreshold();
620
screenParams.whiteThreshold =
621
(SplashCoord)globalParams->getScreenWhiteThreshold();
622
switch (globalParams->getScreenType()) {
623
case screenDispersed:
624
screenParams.type = splashScreenDispersed;
625
if (screenParams.size < 0) {
626
screenParams.size = 4;
629
case screenClustered:
630
screenParams.type = splashScreenClustered;
631
if (screenParams.size < 0) {
632
screenParams.size = 10;
635
case screenStochasticClustered:
636
screenParams.type = splashScreenStochasticClustered;
637
if (screenParams.size < 0) {
638
screenParams.size = 100;
640
if (screenParams.dotRadius < 0) {
641
screenParams.dotRadius = 2;
646
// use clustered dithering for resolution >= 300 dpi
647
// (compare to 299.9 to avoid floating point issues)
648
if (hDPI > 299.9 && vDPI > 299.9) {
649
screenParams.type = splashScreenStochasticClustered;
650
if (screenParams.size < 0) {
651
screenParams.size = 100;
653
if (screenParams.dotRadius < 0) {
654
screenParams.dotRadius = 2;
657
screenParams.type = splashScreenDispersed;
658
if (screenParams.size < 0) {
659
screenParams.size = 4;
665
SplashOutputDev::~SplashOutputDev() {
668
for (i = 0; i < nT3Fonts; ++i) {
669
delete t3FontCache[i];
682
void SplashOutputDev::startDoc(XRef *xrefA) {
689
fontEngine = new SplashFontEngine(
691
globalParams->getEnableT1lib(),
693
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
694
globalParams->getEnableFreeType(),
697
globalParams->getAntialias() &&
698
colorMode != splashModeMono1);
699
for (i = 0; i < nT3Fonts; ++i) {
700
delete t3FontCache[i];
705
void SplashOutputDev::startPage(int pageNum, GfxState *state) {
712
setupScreenParams(state->getHDPI(), state->getVDPI());
713
w = (int)(state->getPageWidth() + 0.5);
717
h = (int)(state->getPageHeight() + 0.5);
727
if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) {
731
bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
732
colorMode != splashModeMono1, bitmapTopDown);
734
splash = new Splash(bitmap, vectorAntialias, &screenParams);
736
ctm = state->getCTM();
737
mat[0] = (SplashCoord)ctm[0];
738
mat[1] = (SplashCoord)ctm[1];
739
mat[2] = (SplashCoord)ctm[2];
740
mat[3] = (SplashCoord)ctm[3];
741
mat[4] = (SplashCoord)ctm[4];
742
mat[5] = (SplashCoord)ctm[5];
743
splash->setMatrix(mat);
746
case splashModeMono1:
747
case splashModeMono8:
752
color[0] = color[1] = color[2] = 0;
755
case splashModeCMYK8:
756
color[0] = color[1] = color[2] = color[3] = 0;
760
splash->setStrokePattern(new SplashSolidColor(color));
761
splash->setFillPattern(new SplashSolidColor(color));
762
splash->setLineCap(splashLineCapButt);
763
splash->setLineJoin(splashLineJoinMiter);
764
splash->setLineDash(NULL, 0, 0);
765
splash->setMiterLimit(10);
766
splash->setFlatness(1);
767
// the SA parameter supposedly defaults to false, but Acrobat
768
// apparently hardwires it to true
769
splash->setStrokeAdjust(globalParams->getStrokeAdjust());
770
splash->clear(paperColor, 0);
773
void SplashOutputDev::endPage() {
774
if (colorMode != splashModeMono1) {
775
splash->compositeBackground(paperColor);
779
void SplashOutputDev::saveState(GfxState *state) {
783
void SplashOutputDev::restoreState(GfxState *state) {
784
splash->restoreState();
785
needFontUpdate = gTrue;
788
void SplashOutputDev::updateAll(GfxState *state) {
789
updateLineDash(state);
790
updateLineJoin(state);
791
updateLineCap(state);
792
updateLineWidth(state);
793
updateFlatness(state);
794
updateMiterLimit(state);
795
updateStrokeAdjust(state);
796
updateFillColor(state);
797
updateStrokeColor(state);
798
needFontUpdate = gTrue;
801
void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12,
802
double m21, double m22,
803
double m31, double m32) {
807
ctm = state->getCTM();
808
mat[0] = (SplashCoord)ctm[0];
809
mat[1] = (SplashCoord)ctm[1];
810
mat[2] = (SplashCoord)ctm[2];
811
mat[3] = (SplashCoord)ctm[3];
812
mat[4] = (SplashCoord)ctm[4];
813
mat[5] = (SplashCoord)ctm[5];
814
splash->setMatrix(mat);
817
void SplashOutputDev::updateLineDash(GfxState *state) {
821
SplashCoord dash[20];
824
state->getLineDash(&dashPattern, &dashLength, &dashStart);
825
if (dashLength > 20) {
828
for (i = 0; i < dashLength; ++i) {
829
dash[i] = (SplashCoord)dashPattern[i];
834
splash->setLineDash(dash, dashLength, (SplashCoord)dashStart);
837
void SplashOutputDev::updateFlatness(GfxState *state) {
838
splash->setFlatness(state->getFlatness());
841
void SplashOutputDev::updateLineJoin(GfxState *state) {
842
splash->setLineJoin(state->getLineJoin());
845
void SplashOutputDev::updateLineCap(GfxState *state) {
846
splash->setLineCap(state->getLineCap());
849
void SplashOutputDev::updateMiterLimit(GfxState *state) {
850
splash->setMiterLimit(state->getMiterLimit());
853
void SplashOutputDev::updateLineWidth(GfxState *state) {
854
splash->setLineWidth(state->getLineWidth());
857
void SplashOutputDev::updateStrokeAdjust(GfxState *state) {
858
#if 0 // the SA parameter supposedly defaults to false, but Acrobat
859
// apparently hardwires it to true
860
splash->setStrokeAdjust(state->getStrokeAdjust());
864
void SplashOutputDev::updateFillColor(GfxState *state) {
871
state->getFillGray(&gray);
872
state->getFillRGB(&rgb);
874
state->getFillCMYK(&cmyk);
875
splash->setFillPattern(getColor(gray, &rgb, &cmyk));
877
splash->setFillPattern(getColor(gray, &rgb));
881
void SplashOutputDev::updateStrokeColor(GfxState *state) {
888
state->getStrokeGray(&gray);
889
state->getStrokeRGB(&rgb);
891
state->getStrokeCMYK(&cmyk);
892
splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
894
splash->setStrokePattern(getColor(gray, &rgb));
899
SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
902
SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
904
SplashPattern *pattern;
906
GfxColorComp r, g, b;
909
gray = gfxColorComp1 - gray;
910
r = gfxColorComp1 - rgb->r;
911
g = gfxColorComp1 - rgb->g;
912
b = gfxColorComp1 - rgb->b;
919
pattern = NULL; // make gcc happy
921
case splashModeMono1:
922
case splashModeMono8:
923
color[0] = colToByte(gray);
924
pattern = new SplashSolidColor(color);
928
color[0] = colToByte(r);
929
color[1] = colToByte(g);
930
color[2] = colToByte(b);
931
pattern = new SplashSolidColor(color);
934
case splashModeCMYK8:
935
color[0] = colToByte(cmyk->c);
936
color[1] = colToByte(cmyk->m);
937
color[2] = colToByte(cmyk->y);
938
color[3] = colToByte(cmyk->k);
939
pattern = new SplashSolidColor(color);
947
void SplashOutputDev::updateBlendMode(GfxState *state) {
948
splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
951
void SplashOutputDev::updateFillOpacity(GfxState *state) {
952
splash->setFillAlpha((SplashCoord)state->getFillOpacity());
955
void SplashOutputDev::updateStrokeOpacity(GfxState *state) {
956
splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
959
void SplashOutputDev::updateFont(GfxState *state) {
960
needFontUpdate = gTrue;
963
void SplashOutputDev::doUpdateFont(GfxState *state) {
965
GfxFontType fontType;
966
SplashOutFontFileID *id;
967
SplashFontFile *fontFile;
970
Object refObj, strObj;
971
GString *tmpFileName, *fileName, *substName;
974
DisplayFontParam *dfp;
975
CharCodeToUnicode *ctu;
977
double m11, m12, m21, m22, w1, w2, fontSize;
981
int c, substIdx, n, code, cmap;
983
needFontUpdate = gFalse;
989
if (!(gfxFont = state->getFont())) {
992
fontType = gfxFont->getType();
993
if (fontType == fontType3) {
997
// check the font file cache
998
id = new SplashOutFontFileID(gfxFont->getID());
999
if ((fontFile = fontEngine->getFontFile(id))) {
1004
// if there is an embedded font, write it to disk
1005
if (gfxFont->getEmbeddedFontID(&embRef)) {
1006
if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
1007
error(-1, "Couldn't create temporary font file");
1010
refObj.initRef(embRef.num, embRef.gen);
1011
refObj.fetch(xref, &strObj);
1013
if (!strObj.isStream()) {
1014
error(-1, "Embedded font object is wrong type");
1019
strObj.streamReset();
1020
while ((c = strObj.streamGetChar()) != EOF) {
1023
strObj.streamClose();
1026
fileName = tmpFileName;
1028
// if there is an external font file, use it
1029
} else if (!(fileName = gfxFont->getExtFontFile())) {
1031
// look for a display font mapping or a substitute font
1032
if (gfxFont->isCIDFont()) {
1033
if (((GfxCIDFont *)gfxFont)->getCollection()) {
1034
dfp = globalParams->
1035
getDisplayCIDFont(gfxFont->getName(),
1036
((GfxCIDFont *)gfxFont)->getCollection());
1039
if (gfxFont->getName()) {
1040
dfp = globalParams->getDisplayFont(gfxFont->getName());
1043
// 8-bit font substitution
1044
if (gfxFont->isFixedWidth()) {
1046
} else if (gfxFont->isSerif()) {
1051
if (gfxFont->isBold()) {
1054
if (gfxFont->isItalic()) {
1057
substName = new GString(splashOutSubstFonts[substIdx].name);
1058
dfp = globalParams->getDisplayFont(substName);
1060
id->setSubstIdx(substIdx);
1064
error(-1, "Couldn't find a font for '%s'",
1065
gfxFont->getName() ? gfxFont->getName()->getCString()
1069
switch (dfp->kind) {
1071
fileName = dfp->t1.fileName;
1072
fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
1075
fileName = dfp->tt.fileName;
1076
fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
1081
// load the font file
1084
if (!(fontFile = fontEngine->loadType1Font(
1086
fileName->getCString(),
1087
fileName == tmpFileName,
1088
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
1089
error(-1, "Couldn't create a font for '%s'",
1090
gfxFont->getName() ? gfxFont->getName()->getCString()
1096
if (!(fontFile = fontEngine->loadType1CFont(
1098
fileName->getCString(),
1099
fileName == tmpFileName,
1100
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
1101
error(-1, "Couldn't create a font for '%s'",
1102
gfxFont->getName() ? gfxFont->getName()->getCString()
1108
if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
1110
fileName->getCString(),
1111
fileName == tmpFileName,
1112
((Gfx8BitFont *)gfxFont)->getEncoding()))) {
1113
error(-1, "Couldn't create a font for '%s'",
1114
gfxFont->getName() ? gfxFont->getName()->getCString()
1120
case fontTrueTypeOT:
1121
if ((ff = FoFiTrueType::load(fileName->getCString()))) {
1122
codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
1129
if (!(fontFile = fontEngine->loadTrueTypeFont(
1131
fileName->getCString(),
1132
fileName == tmpFileName,
1134
error(-1, "Couldn't create a font for '%s'",
1135
gfxFont->getName() ? gfxFont->getName()->getCString()
1142
if (!(fontFile = fontEngine->loadCIDFont(
1144
fileName->getCString(),
1145
fileName == tmpFileName))) {
1146
error(-1, "Couldn't create a font for '%s'",
1147
gfxFont->getName() ? gfxFont->getName()->getCString()
1152
case fontCIDType0COT:
1153
if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
1155
fileName->getCString(),
1156
fileName == tmpFileName))) {
1157
error(-1, "Couldn't create a font for '%s'",
1158
gfxFont->getName() ? gfxFont->getName()->getCString()
1164
case fontCIDType2OT:
1168
// create a CID-to-GID mapping, via Unicode
1169
if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
1170
if ((ff = FoFiTrueType::load(fileName->getCString()))) {
1171
// look for a Unicode cmap
1172
for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
1173
if ((ff->getCmapPlatform(cmap) == 3 &&
1174
ff->getCmapEncoding(cmap) == 1) ||
1175
ff->getCmapPlatform(cmap) == 0) {
1179
if (cmap < ff->getNumCmaps()) {
1180
// map CID -> Unicode -> GID
1181
n = ctu->getLength();
1182
codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
1183
for (code = 0; code < n; ++code) {
1184
if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
1185
codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
1187
codeToGID[code] = 0;
1195
error(-1, "Couldn't find a mapping to Unicode for font '%s'",
1196
gfxFont->getName() ? gfxFont->getName()->getCString()
1200
if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
1201
n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
1202
codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
1203
memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1204
n * sizeof(Gushort));
1207
if (!(fontFile = fontEngine->loadTrueTypeFont(
1209
fileName->getCString(),
1210
fileName == tmpFileName,
1212
error(-1, "Couldn't create a font for '%s'",
1213
gfxFont->getName() ? gfxFont->getName()->getCString()
1219
// this shouldn't happen
1224
// get the font matrix
1225
textMat = state->getTextMat();
1226
fontSize = state->getFontSize();
1227
m11 = textMat[0] * fontSize * state->getHorizScaling();
1228
m12 = textMat[1] * fontSize * state->getHorizScaling();
1229
m21 = textMat[2] * fontSize;
1230
m22 = textMat[3] * fontSize;
1232
// for substituted fonts: adjust the font matrix -- compare the
1233
// width of 'm' in the original font and the substituted font
1234
substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
1235
if (substIdx >= 0) {
1236
for (code = 0; code < 256; ++code) {
1237
if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
1238
name[0] == 'm' && name[1] == '\0') {
1243
w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
1244
w2 = splashOutSubstFonts[substIdx].mWidth;
1245
if (!gfxFont->isSymbolic()) {
1246
// if real font is substantially narrower than substituted
1247
// font, reduce the font size accordingly
1248
if (w1 > 0.01 && w1 < 0.9 * w2) {
1257
// create the scaled font
1258
mat[0] = m11; mat[1] = m12;
1259
mat[2] = m21; mat[3] = m22;
1260
font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
1271
unlink(tmpFileName->getCString());
1277
void SplashOutputDev::stroke(GfxState *state) {
1280
if (state->getStrokeColorSpace()->isNonMarking()) {
1283
path = convertPath(state, state->getPath());
1284
splash->stroke(path);
1288
void SplashOutputDev::fill(GfxState *state) {
1291
if (state->getFillColorSpace()->isNonMarking()) {
1294
path = convertPath(state, state->getPath());
1295
splash->fill(path, gFalse);
1299
void SplashOutputDev::eoFill(GfxState *state) {
1302
if (state->getFillColorSpace()->isNonMarking()) {
1305
path = convertPath(state, state->getPath());
1306
splash->fill(path, gTrue);
1310
void SplashOutputDev::clip(GfxState *state) {
1313
path = convertPath(state, state->getPath());
1314
splash->clipToPath(path, gFalse);
1318
void SplashOutputDev::eoClip(GfxState *state) {
1321
path = convertPath(state, state->getPath());
1322
splash->clipToPath(path, gTrue);
1326
void SplashOutputDev::clipToStrokePath(GfxState *state) {
1327
SplashPath *path, *path2;
1329
path = convertPath(state, state->getPath());
1330
path2 = splash->makeStrokePath(path);
1332
splash->clipToPath(path2, gFalse);
1336
SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) {
1338
GfxSubpath *subpath;
1341
sPath = new SplashPath();
1342
for (i = 0; i < path->getNumSubpaths(); ++i) {
1343
subpath = path->getSubpath(i);
1344
if (subpath->getNumPoints() > 0) {
1345
sPath->moveTo((SplashCoord)subpath->getX(0),
1346
(SplashCoord)subpath->getY(0));
1348
while (j < subpath->getNumPoints()) {
1349
if (subpath->getCurve(j)) {
1350
sPath->curveTo((SplashCoord)subpath->getX(j),
1351
(SplashCoord)subpath->getY(j),
1352
(SplashCoord)subpath->getX(j+1),
1353
(SplashCoord)subpath->getY(j+1),
1354
(SplashCoord)subpath->getX(j+2),
1355
(SplashCoord)subpath->getY(j+2));
1358
sPath->lineTo((SplashCoord)subpath->getX(j),
1359
(SplashCoord)subpath->getY(j));
1363
if (subpath->isClosed()) {
1371
void SplashOutputDev::drawChar(GfxState *state, double x, double y,
1372
double dx, double dy,
1373
double originX, double originY,
1374
CharCode code, int nBytes,
1375
Unicode *u, int uLen) {
1379
// check for invisible text -- this is used by Acrobat Capture
1380
render = state->getRender();
1385
if (needFontUpdate) {
1386
doUpdateFont(state);
1396
if (!(render & 1)) {
1397
if (!state->getFillColorSpace()->isNonMarking()) {
1398
splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
1403
if ((render & 3) == 1 || (render & 3) == 2) {
1404
if (!state->getStrokeColorSpace()->isNonMarking()) {
1405
if ((path = font->getGlyphPath(code))) {
1406
path->offset((SplashCoord)x, (SplashCoord)y);
1407
splash->stroke(path);
1415
if ((path = font->getGlyphPath(code))) {
1416
path->offset((SplashCoord)x, (SplashCoord)y);
1418
textClipPath->append(path);
1421
textClipPath = path;
1427
GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
1428
double dx, double dy,
1429
CharCode code, Unicode *u, int uLen) {
1433
T3FontCache *t3Font;
1436
double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
1439
if (!(gfxFont = state->getFont())) {
1442
fontID = gfxFont->getID();
1443
ctm = state->getCTM();
1444
state->transform(0, 0, &xt, &yt);
1446
// is it the first (MRU) font in the cache?
1447
if (!(nT3Fonts > 0 &&
1448
t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
1450
// is the font elsewhere in the cache?
1451
for (i = 1; i < nT3Fonts; ++i) {
1452
if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
1453
t3Font = t3FontCache[i];
1454
for (j = i; j > 0; --j) {
1455
t3FontCache[j] = t3FontCache[j - 1];
1457
t3FontCache[0] = t3Font;
1461
if (i >= nT3Fonts) {
1463
// create new entry in the font cache
1464
if (nT3Fonts == splashOutT3FontCacheSize) {
1465
delete t3FontCache[nT3Fonts - 1];
1468
for (j = nT3Fonts; j > 0; --j) {
1469
t3FontCache[j] = t3FontCache[j - 1];
1472
bbox = gfxFont->getFontBBox();
1473
if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
1474
// unspecified bounding box -- just take a guess
1481
state->transform(bbox[0], bbox[1], &x1, &y1);
1484
state->transform(bbox[0], bbox[3], &x1, &y1);
1487
} else if (x1 > xMax) {
1492
} else if (y1 > yMax) {
1495
state->transform(bbox[2], bbox[1], &x1, &y1);
1498
} else if (x1 > xMax) {
1503
} else if (y1 > yMax) {
1506
state->transform(bbox[2], bbox[3], &x1, &y1);
1509
} else if (x1 > xMax) {
1514
} else if (y1 > yMax) {
1519
t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
1520
(int)floor(xMin - xt),
1521
(int)floor(yMin - yt),
1522
(int)ceil(xMax) - (int)floor(xMin) + 3,
1523
(int)ceil(yMax) - (int)floor(yMin) + 3,
1525
colorMode != splashModeMono1);
1528
t3Font = t3FontCache[0];
1530
// is the glyph in the cache?
1531
i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
1532
for (j = 0; j < t3Font->cacheAssoc; ++j) {
1533
if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
1534
t3Font->cacheTags[i+j].code == code) {
1535
drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
1536
t3Font->cacheData + (i+j) * t3Font->glyphSize);
1541
// push a new Type 3 glyph record
1542
t3gs = new T3GlyphStack();
1543
t3gs->next = t3GlyphStack;
1544
t3GlyphStack = t3gs;
1545
t3GlyphStack->code = code;
1546
t3GlyphStack->cache = t3Font;
1547
t3GlyphStack->cacheTag = NULL;
1548
t3GlyphStack->cacheData = NULL;
1553
void SplashOutputDev::endType3Char(GfxState *state) {
1557
if (t3GlyphStack->cacheTag) {
1558
memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
1559
t3GlyphStack->cache->glyphSize);
1562
bitmap = t3GlyphStack->origBitmap;
1563
splash = t3GlyphStack->origSplash;
1564
ctm = state->getCTM();
1565
state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
1566
t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
1567
updateCTM(state, 0, 0, 0, 0, 0, 0);
1568
drawType3Glyph(t3GlyphStack->cache,
1569
t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
1571
t3gs = t3GlyphStack;
1572
t3GlyphStack = t3gs->next;
1576
void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
1579
void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
1580
double llx, double lly, double urx, double ury) {
1582
T3FontCache *t3Font;
1584
double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
1587
t3Font = t3GlyphStack->cache;
1589
// check for a valid bbox
1590
state->transform(0, 0, &xt, &yt);
1591
state->transform(llx, lly, &x1, &y1);
1594
state->transform(llx, ury, &x1, &y1);
1597
} else if (x1 > xMax) {
1602
} else if (y1 > yMax) {
1605
state->transform(urx, lly, &x1, &y1);
1608
} else if (x1 > xMax) {
1613
} else if (y1 > yMax) {
1616
state->transform(urx, ury, &x1, &y1);
1619
} else if (x1 > xMax) {
1624
} else if (y1 > yMax) {
1627
if (xMin - xt < t3Font->glyphX ||
1628
yMin - yt < t3Font->glyphY ||
1629
xMax - xt > t3Font->glyphX + t3Font->glyphW ||
1630
yMax - yt > t3Font->glyphY + t3Font->glyphH) {
1631
if (t3Font->validBBox) {
1632
error(-1, "Bad bounding box in Type 3 glyph");
1637
// allocate a cache entry
1638
i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
1639
for (j = 0; j < t3Font->cacheAssoc; ++j) {
1640
if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
1641
t3Font->cacheTags[i+j].mru = 0x8000;
1642
t3Font->cacheTags[i+j].code = t3GlyphStack->code;
1643
t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
1644
t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
1646
++t3Font->cacheTags[i+j].mru;
1651
t3GlyphStack->origBitmap = bitmap;
1652
t3GlyphStack->origSplash = splash;
1653
ctm = state->getCTM();
1654
t3GlyphStack->origCTM4 = ctm[4];
1655
t3GlyphStack->origCTM5 = ctm[5];
1657
// create the temporary bitmap
1658
if (colorMode == splashModeMono1) {
1659
bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
1660
splashModeMono1, gFalse);
1661
splash = new Splash(bitmap, gFalse,
1662
t3GlyphStack->origSplash->getScreen());
1664
splash->clear(color);
1667
bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
1668
splashModeMono8, gFalse);
1669
splash = new Splash(bitmap, vectorAntialias,
1670
t3GlyphStack->origSplash->getScreen());
1672
splash->clear(color);
1675
splash->setFillPattern(new SplashSolidColor(color));
1676
splash->setStrokePattern(new SplashSolidColor(color));
1677
//~ this should copy other state from t3GlyphStack->origSplash?
1678
state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
1679
-t3Font->glyphX, -t3Font->glyphY);
1680
updateCTM(state, 0, 0, 0, 0, 0, 0);
1683
void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
1684
T3FontCacheTag *tag, Guchar *data) {
1685
SplashGlyphBitmap glyph;
1687
glyph.x = -t3Font->glyphX;
1688
glyph.y = -t3Font->glyphY;
1689
glyph.w = t3Font->glyphW;
1690
glyph.h = t3Font->glyphH;
1691
glyph.aa = colorMode != splashModeMono1;
1693
glyph.freeData = gFalse;
1694
splash->fillGlyph(0, 0, &glyph);
1697
void SplashOutputDev::endTextObject(GfxState *state) {
1699
splash->clipToPath(textClipPath, gFalse);
1700
delete textClipPath;
1701
textClipPath = NULL;
1705
struct SplashOutImageMaskData {
1706
ImageStream *imgStr;
1708
int width, height, y;
1711
GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
1712
SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
1717
if (imgMaskData->y == imgMaskData->height) {
1720
for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
1721
x < imgMaskData->width;
1723
*q++ = *p++ ^ imgMaskData->invert;
1729
void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1730
int width, int height, GBool invert,
1734
SplashOutImageMaskData imgMaskData;
1736
if (state->getFillColorSpace()->isNonMarking()) {
1740
ctm = state->getCTM();
1745
mat[4] = ctm[2] + ctm[4];
1746
mat[5] = ctm[3] + ctm[5];
1748
imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
1749
imgMaskData.imgStr->reset();
1750
imgMaskData.invert = invert ? 0 : 1;
1751
imgMaskData.width = width;
1752
imgMaskData.height = height;
1755
splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat,
1756
t3GlyphStack != NULL);
1758
while (imgMaskData.y < height) {
1759
imgMaskData.imgStr->getLine();
1764
delete imgMaskData.imgStr;
1768
struct SplashOutImageData {
1769
ImageStream *imgStr;
1770
GfxImageColorMap *colorMap;
1771
SplashColorPtr lookup;
1773
SplashColorMode colorMode;
1774
int width, height, y;
1777
GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
1778
Guchar *alphaLine) {
1779
SplashOutImageData *imgData = (SplashOutImageData *)data;
1781
SplashColorPtr q, col;
1789
if (imgData->y == imgData->height) {
1793
nComps = imgData->colorMap->getNumPixelComps();
1795
if (imgData->lookup) {
1796
switch (imgData->colorMode) {
1797
case splashModeMono1:
1798
case splashModeMono8:
1799
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1802
*q++ = imgData->lookup[*p];
1805
case splashModeRGB8:
1806
case splashModeBGR8:
1807
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1810
col = &imgData->lookup[3 * *p];
1817
case splashModeCMYK8:
1818
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1821
col = &imgData->lookup[4 * *p];
1831
switch (imgData->colorMode) {
1832
case splashModeMono1:
1833
case splashModeMono8:
1834
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1837
imgData->colorMap->getGray(p, &gray);
1838
*q++ = colToByte(gray);
1841
case splashModeRGB8:
1842
case splashModeBGR8:
1843
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1846
imgData->colorMap->getRGB(p, &rgb);
1847
*q++ = colToByte(rgb.r);
1848
*q++ = colToByte(rgb.g);
1849
*q++ = colToByte(rgb.b);
1853
case splashModeCMYK8:
1854
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
1857
imgData->colorMap->getCMYK(p, &cmyk);
1858
*q++ = colToByte(cmyk.c);
1859
*q++ = colToByte(cmyk.m);
1860
*q++ = colToByte(cmyk.y);
1861
*q++ = colToByte(cmyk.k);
1872
GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
1873
Guchar *alphaLine) {
1874
SplashOutImageData *imgData = (SplashOutImageData *)data;
1876
SplashColorPtr q, col;
1885
if (imgData->y == imgData->height) {
1889
nComps = imgData->colorMap->getNumPixelComps();
1891
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
1895
for (i = 0; i < nComps; ++i) {
1896
if (p[i] < imgData->maskColors[2*i] ||
1897
p[i] > imgData->maskColors[2*i+1]) {
1902
if (imgData->lookup) {
1903
switch (imgData->colorMode) {
1904
case splashModeMono1:
1905
case splashModeMono8:
1906
*q++ = imgData->lookup[*p];
1909
case splashModeRGB8:
1910
case splashModeBGR8:
1911
col = &imgData->lookup[3 * *p];
1918
case splashModeCMYK8:
1919
col = &imgData->lookup[4 * *p];
1929
switch (imgData->colorMode) {
1930
case splashModeMono1:
1931
case splashModeMono8:
1932
imgData->colorMap->getGray(p, &gray);
1933
*q++ = colToByte(gray);
1936
case splashModeRGB8:
1937
case splashModeBGR8:
1938
imgData->colorMap->getRGB(p, &rgb);
1939
*q++ = colToByte(rgb.r);
1940
*q++ = colToByte(rgb.g);
1941
*q++ = colToByte(rgb.b);
1945
case splashModeCMYK8:
1946
imgData->colorMap->getCMYK(p, &cmyk);
1947
*q++ = colToByte(cmyk.c);
1948
*q++ = colToByte(cmyk.m);
1949
*q++ = colToByte(cmyk.y);
1950
*q++ = colToByte(cmyk.k);
1962
void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
1963
int width, int height,
1964
GfxImageColorMap *colorMap,
1965
int *maskColors, GBool inlineImg) {
1968
SplashOutImageData imgData;
1969
SplashColorMode srcMode;
1970
SplashImageSource src;
1979
ctm = state->getCTM();
1984
mat[4] = ctm[2] + ctm[4];
1985
mat[5] = ctm[3] + ctm[5];
1987
imgData.imgStr = new ImageStream(str, width,
1988
colorMap->getNumPixelComps(),
1989
colorMap->getBits());
1990
imgData.imgStr->reset();
1991
imgData.colorMap = colorMap;
1992
imgData.maskColors = maskColors;
1993
imgData.colorMode = colorMode;
1994
imgData.width = width;
1995
imgData.height = height;
1998
// special case for one-channel (monochrome/gray/separation) images:
1999
// build a lookup table here
2000
imgData.lookup = NULL;
2001
if (colorMap->getNumPixelComps() == 1) {
2002
n = 1 << colorMap->getBits();
2003
switch (colorMode) {
2004
case splashModeMono1:
2005
case splashModeMono8:
2006
imgData.lookup = (SplashColorPtr)gmalloc(n);
2007
for (i = 0; i < n; ++i) {
2009
colorMap->getGray(&pix, &gray);
2010
imgData.lookup[i] = colToByte(gray);
2013
case splashModeRGB8:
2014
case splashModeBGR8:
2015
imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
2016
for (i = 0; i < n; ++i) {
2018
colorMap->getRGB(&pix, &rgb);
2019
imgData.lookup[3*i] = colToByte(rgb.r);
2020
imgData.lookup[3*i+1] = colToByte(rgb.g);
2021
imgData.lookup[3*i+2] = colToByte(rgb.b);
2025
case splashModeCMYK8:
2026
imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
2027
for (i = 0; i < n; ++i) {
2029
colorMap->getCMYK(&pix, &cmyk);
2030
imgData.lookup[4*i] = colToByte(cmyk.c);
2031
imgData.lookup[4*i+1] = colToByte(cmyk.m);
2032
imgData.lookup[4*i+2] = colToByte(cmyk.y);
2033
imgData.lookup[4*i+3] = colToByte(cmyk.k);
2041
if (colorMode == splashModeMono1) {
2042
srcMode = splashModeMono8;
2044
srcMode = colorMode;
2046
src = maskColors ? &alphaImageSrc : &imageSrc;
2047
splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse,
2048
width, height, mat);
2050
while (imgData.y < height) {
2051
imgData.imgStr->getLine();
2056
gfree(imgData.lookup);
2057
delete imgData.imgStr;
2061
struct SplashOutMaskedImageData {
2062
ImageStream *imgStr;
2063
GfxImageColorMap *colorMap;
2065
SplashColorPtr lookup;
2066
SplashColorMode colorMode;
2067
int width, height, y;
2070
GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
2071
Guchar *alphaLine) {
2072
SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
2074
SplashColor maskColor;
2075
SplashColorPtr q, col;
2084
if (imgData->y == imgData->height) {
2088
nComps = imgData->colorMap->getNumPixelComps();
2090
for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
2093
imgData->mask->getPixel(x, imgData->y, maskColor);
2094
alpha = maskColor[0] ? 0xff : 0x00;
2095
if (imgData->lookup) {
2096
switch (imgData->colorMode) {
2097
case splashModeMono1:
2098
case splashModeMono8:
2099
*q++ = imgData->lookup[*p];
2102
case splashModeRGB8:
2103
case splashModeBGR8:
2104
col = &imgData->lookup[3 * *p];
2111
case splashModeCMYK8:
2112
col = &imgData->lookup[4 * *p];
2122
switch (imgData->colorMode) {
2123
case splashModeMono1:
2124
case splashModeMono8:
2125
imgData->colorMap->getGray(p, &gray);
2126
*q++ = colToByte(gray);
2129
case splashModeRGB8:
2130
case splashModeBGR8:
2131
imgData->colorMap->getRGB(p, &rgb);
2132
*q++ = colToByte(rgb.r);
2133
*q++ = colToByte(rgb.g);
2134
*q++ = colToByte(rgb.b);
2138
case splashModeCMYK8:
2139
imgData->colorMap->getCMYK(p, &cmyk);
2140
*q++ = colToByte(cmyk.c);
2141
*q++ = colToByte(cmyk.m);
2142
*q++ = colToByte(cmyk.y);
2143
*q++ = colToByte(cmyk.k);
2155
void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
2156
Stream *str, int width, int height,
2157
GfxImageColorMap *colorMap,
2158
Stream *maskStr, int maskWidth,
2159
int maskHeight, GBool maskInvert) {
2160
GfxImageColorMap *maskColorMap;
2161
Object maskDecode, decodeLow, decodeHigh;
2164
SplashOutMaskedImageData imgData;
2165
SplashOutImageMaskData imgMaskData;
2166
SplashColorMode srcMode;
2167
SplashBitmap *maskBitmap;
2169
SplashColor maskColor;
2178
// If the mask is higher resolution than the image, use
2179
// drawSoftMaskedImage() instead.
2180
if (maskWidth > width || maskHeight > height) {
2181
decodeLow.initInt(maskInvert ? 0 : 1);
2182
decodeHigh.initInt(maskInvert ? 1 : 0);
2183
maskDecode.initArray(xref);
2184
maskDecode.arrayAdd(&decodeLow);
2185
maskDecode.arrayAdd(&decodeHigh);
2186
maskColorMap = new GfxImageColorMap(1, &maskDecode,
2187
new GfxDeviceGrayColorSpace());
2189
drawSoftMaskedImage(state, ref, str, width, height, colorMap,
2190
maskStr, maskWidth, maskHeight, maskColorMap);
2191
delete maskColorMap;
2195
//----- scale the mask image to the same size as the source image
2197
mat[0] = (SplashCoord)width;
2200
mat[3] = (SplashCoord)height;
2203
imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
2204
imgMaskData.imgStr->reset();
2205
imgMaskData.invert = maskInvert ? 0 : 1;
2206
imgMaskData.width = maskWidth;
2207
imgMaskData.height = maskHeight;
2209
maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse);
2210
maskSplash = new Splash(maskBitmap, gFalse);
2212
maskSplash->clear(maskColor);
2213
maskColor[0] = 0xff;
2214
maskSplash->setFillPattern(new SplashSolidColor(maskColor));
2215
maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
2216
maskWidth, maskHeight, mat, gFalse);
2217
delete imgMaskData.imgStr;
2221
//----- draw the source image
2223
ctm = state->getCTM();
2228
mat[4] = ctm[2] + ctm[4];
2229
mat[5] = ctm[3] + ctm[5];
2231
imgData.imgStr = new ImageStream(str, width,
2232
colorMap->getNumPixelComps(),
2233
colorMap->getBits());
2234
imgData.imgStr->reset();
2235
imgData.colorMap = colorMap;
2236
imgData.mask = maskBitmap;
2237
imgData.colorMode = colorMode;
2238
imgData.width = width;
2239
imgData.height = height;
2242
// special case for one-channel (monochrome/gray/separation) images:
2243
// build a lookup table here
2244
imgData.lookup = NULL;
2245
if (colorMap->getNumPixelComps() == 1) {
2246
n = 1 << colorMap->getBits();
2247
switch (colorMode) {
2248
case splashModeMono1:
2249
case splashModeMono8:
2250
imgData.lookup = (SplashColorPtr)gmalloc(n);
2251
for (i = 0; i < n; ++i) {
2253
colorMap->getGray(&pix, &gray);
2254
imgData.lookup[i] = colToByte(gray);
2257
case splashModeRGB8:
2258
case splashModeBGR8:
2259
imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
2260
for (i = 0; i < n; ++i) {
2262
colorMap->getRGB(&pix, &rgb);
2263
imgData.lookup[3*i] = colToByte(rgb.r);
2264
imgData.lookup[3*i+1] = colToByte(rgb.g);
2265
imgData.lookup[3*i+2] = colToByte(rgb.b);
2269
case splashModeCMYK8:
2270
imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
2271
for (i = 0; i < n; ++i) {
2273
colorMap->getCMYK(&pix, &cmyk);
2274
imgData.lookup[4*i] = colToByte(cmyk.c);
2275
imgData.lookup[4*i+1] = colToByte(cmyk.m);
2276
imgData.lookup[4*i+2] = colToByte(cmyk.y);
2277
imgData.lookup[4*i+3] = colToByte(cmyk.k);
2284
if (colorMode == splashModeMono1) {
2285
srcMode = splashModeMono8;
2287
srcMode = colorMode;
2289
splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue,
2290
width, height, mat);
2293
gfree(imgData.lookup);
2294
delete imgData.imgStr;
2299
void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
2300
Stream *str, int width, int height,
2301
GfxImageColorMap *colorMap,
2303
int maskWidth, int maskHeight,
2304
GfxImageColorMap *maskColorMap) {
2307
SplashOutImageData imgData;
2308
SplashOutImageData imgMaskData;
2309
SplashColorMode srcMode;
2310
SplashBitmap *maskBitmap;
2312
SplashColor maskColor;
2321
ctm = state->getCTM();
2326
mat[4] = ctm[2] + ctm[4];
2327
mat[5] = ctm[3] + ctm[5];
2329
//----- set up the soft mask
2331
imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
2332
maskColorMap->getNumPixelComps(),
2333
maskColorMap->getBits());
2334
imgMaskData.imgStr->reset();
2335
imgMaskData.colorMap = maskColorMap;
2336
imgMaskData.maskColors = NULL;
2337
imgMaskData.colorMode = splashModeMono8;
2338
imgMaskData.width = maskWidth;
2339
imgMaskData.height = maskHeight;
2341
n = 1 << maskColorMap->getBits();
2342
imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
2343
for (i = 0; i < n; ++i) {
2345
maskColorMap->getGray(&pix, &gray);
2346
imgMaskData.lookup[i] = colToByte(gray);
2348
maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
2349
1, splashModeMono8, gFalse);
2350
maskSplash = new Splash(maskBitmap, vectorAntialias);
2352
maskSplash->clear(maskColor);
2353
maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse,
2354
maskWidth, maskHeight, mat);
2355
delete imgMaskData.imgStr;
2357
gfree(imgMaskData.lookup);
2359
splash->setSoftMask(maskBitmap);
2361
//----- draw the source image
2363
imgData.imgStr = new ImageStream(str, width,
2364
colorMap->getNumPixelComps(),
2365
colorMap->getBits());
2366
imgData.imgStr->reset();
2367
imgData.colorMap = colorMap;
2368
imgData.maskColors = NULL;
2369
imgData.colorMode = colorMode;
2370
imgData.width = width;
2371
imgData.height = height;
2374
// special case for one-channel (monochrome/gray/separation) images:
2375
// build a lookup table here
2376
imgData.lookup = NULL;
2377
if (colorMap->getNumPixelComps() == 1) {
2378
n = 1 << colorMap->getBits();
2379
switch (colorMode) {
2380
case splashModeMono1:
2381
case splashModeMono8:
2382
imgData.lookup = (SplashColorPtr)gmalloc(n);
2383
for (i = 0; i < n; ++i) {
2385
colorMap->getGray(&pix, &gray);
2386
imgData.lookup[i] = colToByte(gray);
2389
case splashModeRGB8:
2390
case splashModeBGR8:
2391
imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
2392
for (i = 0; i < n; ++i) {
2394
colorMap->getRGB(&pix, &rgb);
2395
imgData.lookup[3*i] = colToByte(rgb.r);
2396
imgData.lookup[3*i+1] = colToByte(rgb.g);
2397
imgData.lookup[3*i+2] = colToByte(rgb.b);
2401
case splashModeCMYK8:
2402
imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
2403
for (i = 0; i < n; ++i) {
2405
colorMap->getCMYK(&pix, &cmyk);
2406
imgData.lookup[4*i] = colToByte(cmyk.c);
2407
imgData.lookup[4*i+1] = colToByte(cmyk.m);
2408
imgData.lookup[4*i+2] = colToByte(cmyk.y);
2409
imgData.lookup[4*i+3] = colToByte(cmyk.k);
2416
if (colorMode == splashModeMono1) {
2417
srcMode = splashModeMono8;
2419
srcMode = colorMode;
2421
splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat);
2423
splash->setSoftMask(NULL);
2424
gfree(imgData.lookup);
2425
delete imgData.imgStr;
2429
void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
2430
GfxColorSpace *blendingColorSpace,
2431
GBool isolated, GBool knockout,
2432
GBool forSoftMask) {
2433
SplashTransparencyGroup *transpGroup;
2435
double xMin, yMin, xMax, yMax, x, y;
2438
// transform the bbox
2439
state->transform(bbox[0], bbox[1], &x, &y);
2442
state->transform(bbox[0], bbox[3], &x, &y);
2445
} else if (x > xMax) {
2450
} else if (y > yMax) {
2453
state->transform(bbox[2], bbox[1], &x, &y);
2456
} else if (x > xMax) {
2461
} else if (y > yMax) {
2464
state->transform(bbox[2], bbox[3], &x, &y);
2467
} else if (x > xMax) {
2472
} else if (y > yMax) {
2475
tx = (int)floor(xMin);
2478
} else if (tx > bitmap->getWidth()) {
2479
tx = bitmap->getWidth();
2481
ty = (int)floor(yMin);
2484
} else if (ty > bitmap->getHeight()) {
2485
ty = bitmap->getHeight();
2487
w = (int)ceil(xMax) - tx + 1;
2488
if (tx + w > bitmap->getWidth()) {
2489
w = bitmap->getWidth() - tx;
2494
h = (int)ceil(yMax) - ty + 1;
2495
if (ty + h > bitmap->getHeight()) {
2496
h = bitmap->getHeight() - ty;
2502
// push a new stack entry
2503
transpGroup = new SplashTransparencyGroup();
2504
transpGroup->tx = tx;
2505
transpGroup->ty = ty;
2506
transpGroup->blendingColorSpace = blendingColorSpace;
2507
transpGroup->isolated = isolated;
2508
transpGroup->next = transpGroupStack;
2509
transpGroupStack = transpGroup;
2512
transpGroup->origBitmap = bitmap;
2513
transpGroup->origSplash = splash;
2515
//~ this ignores the blendingColorSpace arg
2517
// create the temporary bitmap
2518
bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
2520
splash = new Splash(bitmap, vectorAntialias,
2521
transpGroup->origSplash->getScreen());
2523
switch (colorMode) {
2524
case splashModeMono1:
2525
case splashModeMono8:
2528
case splashModeRGB8:
2529
case splashModeBGR8:
2530
color[0] = color[1] = color[2] = 0;
2533
case splashModeCMYK8:
2534
color[0] = color[1] = color[2] = color[3] = 0;
2541
splash->clear(color, 0);
2543
splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
2544
splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty);
2546
transpGroup->tBitmap = bitmap;
2547
state->shiftCTM(-tx, -ty);
2548
updateCTM(state, 0, 0, 0, 0, 0, 0);
2551
void SplashOutputDev::endTransparencyGroup(GfxState *state) {
2556
bitmap = transpGroupStack->origBitmap;
2557
splash = transpGroupStack->origSplash;
2558
ctm = state->getCTM();
2559
state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty);
2560
updateCTM(state, 0, 0, 0, 0, 0, 0);
2563
void SplashOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) {
2564
SplashBitmap *tBitmap;
2565
SplashTransparencyGroup *transpGroup;
2569
tx = transpGroupStack->tx;
2570
ty = transpGroupStack->ty;
2571
tBitmap = transpGroupStack->tBitmap;
2572
isolated = transpGroupStack->isolated;
2574
// paint the transparency group onto the parent bitmap
2575
// - the clip path was set in the parent's state)
2576
splash->composite(tBitmap, 0, 0, tx, ty,
2577
tBitmap->getWidth(), tBitmap->getHeight(),
2581
transpGroup = transpGroupStack;
2582
transpGroupStack = transpGroup->next;
2588
void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
2589
GBool alpha, Function *transferFunc,
2590
GfxColor *backdropColor) {
2591
SplashBitmap *softMask, *tBitmap;
2593
SplashTransparencyGroup *transpGroup;
2604
tx = transpGroupStack->tx;
2605
ty = transpGroupStack->ty;
2606
tBitmap = transpGroupStack->tBitmap;
2608
// composite with backdrop color
2609
if (!alpha && colorMode != splashModeMono1) {
2610
//~ need to correctly handle the case where no blending color
2612
tSplash = new Splash(tBitmap, vectorAntialias,
2613
transpGroupStack->origSplash->getScreen());
2614
if (transpGroupStack->blendingColorSpace) {
2615
switch (colorMode) {
2616
case splashModeMono1:
2617
// transparency is not supported in mono1 mode
2619
case splashModeMono8:
2620
transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray);
2621
color[0] = colToByte(gray);
2622
tSplash->compositeBackground(color);
2624
case splashModeRGB8:
2625
case splashModeBGR8:
2626
transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb);
2627
color[0] = colToByte(rgb.r);
2628
color[1] = colToByte(rgb.g);
2629
color[2] = colToByte(rgb.b);
2630
tSplash->compositeBackground(color);
2633
case splashModeCMYK8:
2634
transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk);
2635
color[0] = colToByte(cmyk.c);
2636
color[1] = colToByte(cmyk.m);
2637
color[2] = colToByte(cmyk.y);
2638
color[3] = colToByte(cmyk.k);
2639
tSplash->compositeBackground(color);
2647
softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
2648
1, splashModeMono8, gFalse);
2649
memset(softMask->getDataPtr(), 0,
2650
softMask->getRowSize() * softMask->getHeight());
2651
p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
2652
for (y = 0; y < tBitmap->getHeight(); ++y) {
2653
for (x = 0; x < tBitmap->getWidth(); ++x) {
2654
tBitmap->getPixel(x, y, color);
2658
// convert to luminosity
2659
switch (colorMode) {
2660
case splashModeMono1:
2661
case splashModeMono8:
2662
lum = color[0] / 255.0;
2664
case splashModeRGB8:
2665
case splashModeBGR8:
2666
lum = (0.3 / 255.0) * color[0] +
2667
(0.59 / 255.0) * color[1] +
2668
(0.11 / 255.0) * color[2];
2671
case splashModeCMYK8:
2672
lum = (1 - color[4] / 255.0)
2673
- (0.3 / 255.0) * color[0]
2674
- (0.59 / 255.0) * color[1]
2675
- (0.11 / 255.0) * color[2];
2683
transferFunc->transform(&lum, &lum2);
2687
p[x] = (int)(lum2 * 255.0 + 0.5);
2690
p += softMask->getRowSize();
2692
splash->setSoftMask(softMask);
2695
transpGroup = transpGroupStack;
2696
transpGroupStack = transpGroup->next;
2702
void SplashOutputDev::clearSoftMask(GfxState *state) {
2703
splash->setSoftMask(NULL);
2706
void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) {
2707
splashColorCopy(paperColor, paperColorA);
2710
int SplashOutputDev::getBitmapWidth() {
2711
return bitmap->getWidth();
2714
int SplashOutputDev::getBitmapHeight() {
2715
return bitmap->getHeight();
2718
SplashBitmap *SplashOutputDev::takeBitmap() {
2722
bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
2723
colorMode != splashModeMono1, bitmapTopDown);
2727
void SplashOutputDev::getModRegion(int *xMin, int *yMin,
2728
int *xMax, int *yMax) {
2729
splash->getModRegion(xMin, yMin, xMax, yMax);
2732
void SplashOutputDev::clearModRegion() {
2733
splash->clearModRegion();
2736
void SplashOutputDev::setFillColor(int r, int g, int b) {
2743
rgb.r = byteToCol(r);
2744
rgb.g = byteToCol(g);
2745
rgb.b = byteToCol(b);
2746
gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
2747
if (gray > gfxColorComp1) {
2748
gray = gfxColorComp1;
2751
cmyk.c = gfxColorComp1 - rgb.r;
2752
cmyk.m = gfxColorComp1 - rgb.g;
2753
cmyk.y = gfxColorComp1 - rgb.b;
2755
splash->setFillPattern(getColor(gray, &rgb, &cmyk));
2757
splash->setFillPattern(getColor(gray, &rgb));
2761
SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) {
2762
DisplayFontParam *dfp;
2764
SplashOutFontFileID *id;
2765
SplashFontFile *fontFile;
2766
SplashFont *fontObj;
2770
SplashCoord textMat[4];
2773
for (i = 0; i < 16; ++i) {
2774
if (!name->cmp(splashOutSubstFonts[i].name)) {
2783
id = new SplashOutFontFileID(&ref);
2785
// check the font file cache
2786
if ((fontFile = fontEngine->getFontFile(id))) {
2789
// load the font file
2791
dfp = globalParams->getDisplayFont(name);
2792
if (dfp && dfp->kind == displayFontT1) {
2793
fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(),
2794
gFalse, winAnsiEncoding);
2795
} else if (dfp && dfp->kind == displayFontTT) {
2796
if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) {
2799
for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
2800
if ((ff->getCmapPlatform(cmap) == 3 &&
2801
ff->getCmapEncoding(cmap) == 1) ||
2802
ff->getCmapPlatform(cmap) == 0) {
2806
if (cmap == ff->getNumCmaps()) {
2810
codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort));
2811
for (i = 0; i < 256; ++i) {
2813
if (winAnsiEncoding[i] &&
2814
(u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) {
2815
codeToGID[i] = ff->mapCodeToGID(cmap, u);
2819
fontFile = fontEngine->loadTrueTypeFont(id,
2820
dfp->tt.fileName->getCString(),
2821
gFalse, codeToGID, 256);
2827
// create the scaled font
2828
textMat[0] = (SplashCoord)textMatA[0];
2829
textMat[1] = (SplashCoord)textMatA[1];
2830
textMat[2] = (SplashCoord)textMatA[2];
2831
textMat[3] = (SplashCoord)textMatA[3];
2832
fontObj = fontEngine->getFont(fontFile, textMat, splash->getMatrix());
2837
#if 1 //~tmp: turn off anti-aliasing temporarily
2838
GBool SplashOutputDev::getVectorAntialias() {
2839
return splash->getVectorAntialias();
2842
void SplashOutputDev::setVectorAntialias(GBool vaa) {
2843
splash->setVectorAntialias(vaa);