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"
40 //------------------------------------------------------------------------
42 //------------------------------------------------------------------------
44 static void splashOutBlendMultiply(SplashColorPtr src
, SplashColorPtr dest
,
45 SplashColorPtr blend
, SplashColorMode cm
) {
48 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
49 // note: floor(x / 255) = x >> 8 (for 16-bit x)
50 blend
[i
] = (dest
[i
] * src
[i
]) >> 8;
54 static void splashOutBlendScreen(SplashColorPtr src
, SplashColorPtr dest
,
55 SplashColorPtr blend
, SplashColorMode cm
) {
58 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
59 // note: floor(x / 255) = x >> 8 (for 16-bit x)
60 blend
[i
] = dest
[i
] + src
[i
] - ((dest
[i
] * src
[i
]) >> 8);
64 static void splashOutBlendOverlay(SplashColorPtr src
, SplashColorPtr dest
,
65 SplashColorPtr blend
, SplashColorMode cm
) {
68 //~ not sure if this is right
69 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
70 // note: floor(x / 255) = x >> 8 (for 16-bit x)
71 blend
[i
] = dest
[i
] < 0x80 ? ((dest
[i
] * src
[i
]) >> 8)
72 : dest
[i
] + src
[i
] - ((dest
[i
] * src
[i
]) >> 8);
76 static void splashOutBlendDarken(SplashColorPtr src
, SplashColorPtr dest
,
77 SplashColorPtr blend
, SplashColorMode cm
) {
80 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
81 blend
[i
] = dest
[i
] < src
[i
] ? dest
[i
] : src
[i
];
85 static void splashOutBlendLighten(SplashColorPtr src
, SplashColorPtr dest
,
86 SplashColorPtr blend
, SplashColorMode cm
) {
89 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
90 blend
[i
] = dest
[i
] > src
[i
] ? dest
[i
] : src
[i
];
94 static void splashOutBlendColorDodge(SplashColorPtr src
, SplashColorPtr dest
,
99 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
100 x
= dest
[i
] + src
[i
];
101 blend
[i
] = x
<= 255 ? x
: 255;
105 static void splashOutBlendColorBurn(SplashColorPtr src
, SplashColorPtr dest
,
106 SplashColorPtr blend
, SplashColorMode cm
) {
109 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
110 x
= dest
[i
] - (255 - src
[i
]);
111 blend
[i
] = x
>= 0 ? x
: 0;
115 static void splashOutBlendHardLight(SplashColorPtr src
, SplashColorPtr dest
,
116 SplashColorPtr blend
, SplashColorMode cm
) {
119 //~ not sure if this is right
120 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
121 // note: floor(x / 255) = x >> 8 (for 16-bit x)
122 blend
[i
] = src
[i
] < 0x80
123 ? ((dest
[i
] * (src
[i
] * 2)) >> 8)
124 : 0xff - (((0xff - dest
[i
]) * (0x1ff - src
[i
] * 2)) >> 8);
128 static void splashOutBlendSoftLight(SplashColorPtr src
, SplashColorPtr dest
,
129 SplashColorPtr blend
, SplashColorMode cm
) {
132 //~ not sure if this is right
133 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
135 x
= dest
[i
] - (0x80 - src
[i
]);
136 blend
[i
] = x
>= 0 ? x
: 0;
138 x
= dest
[i
] + (src
[i
] - 0x80);
139 blend
[i
] = x
<= 255 ? x
: 255;
144 static void splashOutBlendDifference(SplashColorPtr src
, SplashColorPtr dest
,
145 SplashColorPtr blend
,
146 SplashColorMode cm
) {
149 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
150 blend
[i
] = dest
[i
] < src
[i
] ? src
[i
] - dest
[i
] : dest
[i
] - src
[i
];
154 static void splashOutBlendExclusion(SplashColorPtr src
, SplashColorPtr dest
,
155 SplashColorPtr blend
, SplashColorMode cm
) {
158 //~ not sure what this is supposed to do
159 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
160 blend
[i
] = dest
[i
] < src
[i
] ? src
[i
] - dest
[i
] : dest
[i
] - src
[i
];
164 static void cvtRGBToHSV(Guchar r
, Guchar g
, Guchar b
, int *h
, int *s
, int *v
) {
165 int cmax
, cmid
, cmin
, x
;
168 if (g
>= b
) { x
= 0; cmax
= r
; cmid
= g
; cmin
= b
; }
169 else if (b
>= r
) { x
= 4; cmax
= b
; cmid
= r
; cmin
= g
; }
170 else { x
= 5; cmax
= r
; cmid
= b
; cmin
= g
; }
172 if (r
>= b
) { x
= 1; cmax
= g
; cmid
= r
; cmin
= b
; }
173 else if (g
>= b
) { x
= 2; cmax
= g
; cmid
= b
; cmin
= r
; }
174 else { x
= 3; cmax
= b
; cmid
= g
; cmin
= r
; }
181 *h
+= ((cmax
- cmid
) * 60) / (cmax
- cmin
);
183 *h
+= ((cmid
- cmin
) * 60) / (cmax
- cmin
);
185 *s
= (255 * (cmax
- cmin
)) / cmax
;
190 static void cvtHSVToRGB(int h
, int s
, int v
, Guchar
*r
, Guchar
*g
, Guchar
*b
) {
191 int x
, f
, cmax
, cmid
, cmin
;
200 cmid
= (v
* 255 - ((s
* f
) / 60)) >> 8;
202 cmid
= (v
* (255 - ((s
* (60 - f
)) / 60))) >> 8;
204 // note: floor(x / 255) = x >> 8 (for 16-bit x)
205 cmin
= (v
* (255 - s
)) >> 8;
207 case 0: *r
= cmax
; *g
= cmid
; *b
= cmin
; break;
208 case 1: *g
= cmax
; *r
= cmid
; *b
= cmin
; break;
209 case 2: *g
= cmax
; *b
= cmid
; *r
= cmin
; break;
210 case 3: *b
= cmax
; *g
= cmid
; *r
= cmin
; break;
211 case 4: *b
= cmax
; *r
= cmid
; *g
= cmin
; break;
212 case 5: *r
= cmax
; *b
= cmid
; *g
= cmin
; break;
217 static void splashOutBlendHue(SplashColorPtr src
, SplashColorPtr dest
,
218 SplashColorPtr blend
, SplashColorMode cm
) {
219 int hs
, ss
, vs
, hd
, sd
, vd
;
225 case splashModeMono1
:
226 case splashModeMono8
:
230 cvtRGBToHSV(src
[0], src
[1], src
[2], &hs
, &ss
, &vs
);
231 cvtRGBToHSV(dest
[0], dest
[1], dest
[2], &hd
, &sd
, &vd
);
232 cvtHSVToRGB(hs
, sd
, vd
, &blend
[0], &blend
[1], &blend
[2]);
235 cvtRGBToHSV(src
[2], src
[1], src
[0], &hs
, &ss
, &vs
);
236 cvtRGBToHSV(dest
[2], dest
[1], dest
[0], &hd
, &sd
, &vd
);
237 cvtHSVToRGB(hs
, sd
, vd
, &blend
[2], &blend
[1], &blend
[0]);
240 case splashModeCMYK8
:
241 //~ (0xff - ...) should be clipped
242 cvtRGBToHSV(0xff - (src
[0] + src
[3]),
243 0xff - (src
[1] + src
[3]),
244 0xff - (src
[2] + src
[3]), &hs
, &ss
, &vs
);
245 cvtRGBToHSV(0xff - (dest
[0] + dest
[3]),
246 0xff - (dest
[1] + dest
[3]),
247 0xff - (dest
[2] + dest
[3]), &hd
, &sd
, &vd
);
248 cvtHSVToRGB(hs
, sd
, vd
, &r
, &g
, &b
);
249 //~ should do black generation
262 static void splashOutBlendSaturation(SplashColorPtr src
, SplashColorPtr dest
,
263 SplashColorPtr blend
,
264 SplashColorMode cm
) {
265 int hs
, ss
, vs
, hd
, sd
, vd
;
271 case splashModeMono1
:
272 case splashModeMono8
:
276 cvtRGBToHSV(src
[0], src
[1], src
[2], &hs
, &ss
, &vs
);
277 cvtRGBToHSV(dest
[0], dest
[1], dest
[2], &hd
, &sd
, &vd
);
278 cvtHSVToRGB(hd
, ss
, vd
, &blend
[0], &blend
[1], &blend
[2]);
281 cvtRGBToHSV(src
[2], src
[1], src
[0], &hs
, &ss
, &vs
);
282 cvtRGBToHSV(dest
[2], dest
[1], dest
[0], &hd
, &sd
, &vd
);
283 cvtHSVToRGB(hd
, ss
, vd
, &blend
[2], &blend
[1], &blend
[0]);
286 case splashModeCMYK8
:
287 //~ (0xff - ...) should be clipped
288 cvtRGBToHSV(0xff - (src
[0] + src
[3]),
289 0xff - (src
[1] + src
[3]),
290 0xff - (src
[2] + src
[3]), &hs
, &ss
, &vs
);
291 cvtRGBToHSV(0xff - (dest
[0] + dest
[3]),
292 0xff - (dest
[1] + dest
[3]),
293 0xff - (dest
[2] + dest
[3]), &hd
, &sd
, &vd
);
294 cvtHSVToRGB(hd
, ss
, vd
, &r
, &g
, &b
);
295 //~ should do black generation
308 static void splashOutBlendColor(SplashColorPtr src
, SplashColorPtr dest
,
309 SplashColorPtr blend
, SplashColorMode cm
) {
310 int hs
, ss
, vs
, hd
, sd
, vd
;
316 case splashModeMono1
:
317 case splashModeMono8
:
321 cvtRGBToHSV(src
[0], src
[1], src
[2], &hs
, &ss
, &vs
);
322 cvtRGBToHSV(dest
[0], dest
[1], dest
[2], &hd
, &sd
, &vd
);
323 cvtHSVToRGB(hs
, ss
, vd
, &blend
[0], &blend
[1], &blend
[2]);
326 cvtRGBToHSV(src
[2], src
[1], src
[0], &hs
, &ss
, &vs
);
327 cvtRGBToHSV(dest
[2], dest
[1], dest
[0], &hd
, &sd
, &vd
);
328 cvtHSVToRGB(hs
, ss
, vd
, &blend
[2], &blend
[1], &blend
[0]);
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
353 static void splashOutBlendLuminosity(SplashColorPtr src
, SplashColorPtr dest
,
354 SplashColorPtr blend
,
355 SplashColorMode cm
) {
356 int hs
, ss
, vs
, hd
, sd
, vd
;
362 case splashModeMono1
:
363 case splashModeMono8
:
367 cvtRGBToHSV(src
[0], src
[1], src
[2], &hs
, &ss
, &vs
);
368 cvtRGBToHSV(dest
[0], dest
[1], dest
[2], &hd
, &sd
, &vd
);
369 cvtHSVToRGB(hd
, sd
, vs
, &blend
[0], &blend
[1], &blend
[2]);
372 cvtRGBToHSV(src
[2], src
[1], src
[0], &hs
, &ss
, &vs
);
373 cvtRGBToHSV(dest
[2], dest
[1], dest
[0], &hd
, &sd
, &vd
);
374 cvtHSVToRGB(hd
, sd
, vs
, &blend
[2], &blend
[1], &blend
[0]);
377 case splashModeCMYK8
:
378 //~ (0xff - ...) should be clipped
379 cvtRGBToHSV(0xff - (src
[0] + src
[3]),
380 0xff - (src
[1] + src
[3]),
381 0xff - (src
[2] + src
[3]), &hs
, &ss
, &vs
);
382 cvtRGBToHSV(0xff - (dest
[0] + dest
[3]),
383 0xff - (dest
[1] + dest
[3]),
384 0xff - (dest
[2] + dest
[3]), &hd
, &sd
, &vd
);
385 cvtHSVToRGB(hd
, sd
, vs
, &r
, &g
, &b
);
386 //~ should do black generation
399 // NB: This must match the GfxBlendMode enum defined in GfxState.h.
400 SplashBlendFunc splashOutBlendFuncs
[] = {
402 &splashOutBlendMultiply
,
403 &splashOutBlendScreen
,
404 &splashOutBlendOverlay
,
405 &splashOutBlendDarken
,
406 &splashOutBlendLighten
,
407 &splashOutBlendColorDodge
,
408 &splashOutBlendColorBurn
,
409 &splashOutBlendHardLight
,
410 &splashOutBlendSoftLight
,
411 &splashOutBlendDifference
,
412 &splashOutBlendExclusion
,
414 &splashOutBlendSaturation
,
415 &splashOutBlendColor
,
416 &splashOutBlendLuminosity
419 //------------------------------------------------------------------------
420 // Font substitutions
421 //------------------------------------------------------------------------
423 struct SplashOutFontSubst
{
428 // index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
429 static SplashOutFontSubst splashOutSubstFonts
[16] = {
430 {"Helvetica", 0.833},
431 {"Helvetica-Oblique", 0.833},
432 {"Helvetica-Bold", 0.889},
433 {"Helvetica-BoldOblique", 0.889},
434 {"Times-Roman", 0.788},
435 {"Times-Italic", 0.722},
436 {"Times-Bold", 0.833},
437 {"Times-BoldItalic", 0.778},
439 {"Courier-Oblique", 0.600},
440 {"Courier-Bold", 0.600},
441 {"Courier-BoldOblique", 0.600},
448 //------------------------------------------------------------------------
449 // SplashOutFontFileID
450 //------------------------------------------------------------------------
452 class SplashOutFontFileID
: public SplashFontFileID
{
455 SplashOutFontFileID(Ref
*rA
) { r
= *rA
; substIdx
= -1; }
457 ~SplashOutFontFileID() {}
459 GBool
matches(SplashFontFileID
*id
) {
460 return ((SplashOutFontFileID
*)id
)->r
.num
== r
.num
&&
461 ((SplashOutFontFileID
*)id
)->r
.gen
== r
.gen
;
464 void setSubstIdx(int substIdxA
) { substIdx
= substIdxA
; }
465 int getSubstIdx() { return substIdx
; }
473 //------------------------------------------------------------------------
475 //------------------------------------------------------------------------
477 struct T3FontCacheTag
{
479 Gushort mru
; // valid bit (0x8000) and MRU index
485 T3FontCache(Ref
*fontID
, double m11A
, double m12A
,
486 double m21A
, double m22A
,
487 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
490 GBool
matches(Ref
*idA
, double m11A
, double m12A
,
491 double m21A
, double m22A
)
492 { return fontID
.num
== idA
->num
&& fontID
.gen
== idA
->gen
&&
493 m11
== m11A
&& m12
== m12A
&& m21
== m21A
&& m22
== m22A
; }
495 Ref fontID
; // PDF font ID
496 double m11
, m12
, m21
, m22
; // transform matrix
497 int glyphX
, glyphY
; // pixel offset of glyph bitmaps
498 int glyphW
, glyphH
; // size of glyph bitmaps, in pixels
499 int glyphSize
; // size of glyph bitmaps, in bytes
500 int cacheSets
; // number of sets in cache
501 int cacheAssoc
; // cache associativity (glyphs per set)
502 Guchar
*cacheData
; // glyph pixmap cache
503 T3FontCacheTag
*cacheTags
; // cache tags, i.e., char codes
506 T3FontCache::T3FontCache(Ref
*fontIDA
, double m11A
, double m12A
,
507 double m21A
, double m22A
,
508 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
522 glyphSize
= glyphW
* glyphH
;
524 glyphSize
= ((glyphW
+ 7) >> 3) * glyphH
;
527 if (glyphSize
<= 256) {
529 } else if (glyphSize
<= 512) {
531 } else if (glyphSize
<= 1024) {
536 cacheData
= (Guchar
*)gmallocn(cacheSets
* cacheAssoc
, glyphSize
);
537 cacheTags
= (T3FontCacheTag
*)gmallocn(cacheSets
* cacheAssoc
,
538 sizeof(T3FontCacheTag
));
539 for (i
= 0; i
< cacheSets
* cacheAssoc
; ++i
) {
540 cacheTags
[i
].mru
= i
& (cacheAssoc
- 1);
544 T3FontCache::~T3FontCache() {
549 struct T3GlyphStack
{
550 Gushort code
; // character code
551 double x
, y
; // position to draw the glyph
554 T3FontCache
*cache
; // font cache for the current font
555 T3FontCacheTag
*cacheTag
; // pointer to cache tag for the glyph
556 Guchar
*cacheData
; // pointer to cache data for the glyph
559 SplashBitmap
*origBitmap
;
561 double origCTM4
, origCTM5
;
563 T3GlyphStack
*next
; // next object on stack
566 //------------------------------------------------------------------------
568 //------------------------------------------------------------------------
570 SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA
,
573 SplashColorPtr paperColorA
,
574 GBool bitmapTopDownA
,
575 GBool allowAntialiasA
) {
576 colorMode
= colorModeA
;
577 bitmapRowPad
= bitmapRowPadA
;
578 bitmapTopDown
= bitmapTopDownA
;
579 allowAntialias
= allowAntialiasA
;
580 reverseVideo
= reverseVideoA
;
581 splashColorCopy(paperColor
, paperColorA
);
585 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
, bitmapTopDown
);
586 splash
= new Splash(bitmap
);
587 splash
->clear(paperColor
);
595 needFontUpdate
= gFalse
;
599 SplashOutputDev::~SplashOutputDev() {
602 for (i
= 0; i
< nT3Fonts
; ++i
) {
603 delete t3FontCache
[i
];
616 void SplashOutputDev::startDoc(XRef
*xrefA
) {
623 fontEngine
= new SplashFontEngine(
625 globalParams
->getEnableT1lib(),
627 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
628 globalParams
->getEnableFreeType(),
631 globalParams
->getAntialias() &&
632 colorMode
!= splashModeMono1
);
633 for (i
= 0; i
< nT3Fonts
; ++i
) {
634 delete t3FontCache
[i
];
639 void SplashOutputDev::startPage(int pageNum
, GfxState
*state
) {
643 w
= state
? (int)(state
->getPageWidth() + 0.5) : 1;
644 h
= state
? (int)(state
->getPageHeight() + 0.5) : 1;
648 if (!bitmap
|| w
!= bitmap
->getWidth() || h
!= bitmap
->getHeight()) {
652 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
, bitmapTopDown
);
654 splash
= new Splash(bitmap
);
656 case splashModeMono1
:
657 case splashModeMono8
:
662 color
[0] = color
[1] = color
[2] = 0;
664 case splashModeAMono8
:
668 case splashModeARGB8
:
670 color
[1] = color
[2] = color
[3] = 0;
672 case splashModeBGRA8
:
673 color
[0] = color
[1] = color
[2] = 0;
677 case splashModeCMYK8
:
678 color
[0] = color
[1] = color
[2] = color
[3] = 0;
680 case splashModeACMYK8
:
682 color
[1] = color
[2] = color
[3] = color
[4] = 0;
686 splash
->setStrokePattern(new SplashSolidColor(color
));
687 splash
->setFillPattern(new SplashSolidColor(color
));
688 splash
->setLineCap(splashLineCapButt
);
689 splash
->setLineJoin(splashLineJoinMiter
);
690 splash
->setLineDash(NULL
, 0, 0);
691 splash
->setMiterLimit(10);
692 splash
->setFlatness(1);
693 splash
->clear(paperColor
);
696 void SplashOutputDev::endPage() {
699 void SplashOutputDev::drawLink(Link
*link
, Catalog
*catalog
) {
700 double x1
, y1
, x2
, y2
;
701 LinkBorderStyle
*borderStyle
;
710 SplashCoord dashList
[20];
714 link
->getRect(&x1
, &y1
, &x2
, &y2
);
715 borderStyle
= link
->getBorderStyle();
716 if (borderStyle
->getWidth() > 0) {
717 borderStyle
->getColor(&r
, &g
, &b
);
721 gray
= dblToCol(0.299 * r
+ 0.587 * g
+ 0.114 * b
);
722 if (gray
> gfxColorComp1
) {
723 gray
= gfxColorComp1
;
726 cmyk
.c
= gfxColorComp1
- rgb
.r
;
727 cmyk
.m
= gfxColorComp1
- rgb
.g
;
728 cmyk
.y
= gfxColorComp1
- rgb
.b
;
730 splash
->setStrokePattern(getColor(gray
, &rgb
, &cmyk
));
732 splash
->setStrokePattern(getColor(gray
, &rgb
));
734 splash
->setLineWidth((SplashCoord
)borderStyle
->getWidth());
735 borderStyle
->getDash(&dash
, &dashLength
);
736 if (borderStyle
->getType() == linkBorderDashed
&& dashLength
> 0) {
737 if (dashLength
> 20) {
740 for (i
= 0; i
< dashLength
; ++i
) {
741 dashList
[i
] = (SplashCoord
)dash
[i
];
743 splash
->setLineDash(dashList
, dashLength
, 0);
745 path
= new SplashPath();
746 if (borderStyle
->getType() == linkBorderUnderlined
) {
747 cvtUserToDev(x1
, y1
, &x
, &y
);
748 path
->moveTo((SplashCoord
)x
, (SplashCoord
)y
);
749 cvtUserToDev(x2
, y1
, &x
, &y
);
750 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
752 cvtUserToDev(x1
, y1
, &x
, &y
);
753 path
->moveTo((SplashCoord
)x
, (SplashCoord
)y
);
754 cvtUserToDev(x2
, y1
, &x
, &y
);
755 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
756 cvtUserToDev(x2
, y2
, &x
, &y
);
757 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
758 cvtUserToDev(x1
, y2
, &x
, &y
);
759 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
762 splash
->stroke(path
);
767 void SplashOutputDev::saveState(GfxState
*state
) {
771 void SplashOutputDev::restoreState(GfxState
*state
) {
772 splash
->restoreState();
773 needFontUpdate
= gTrue
;
776 void SplashOutputDev::updateAll(GfxState
*state
) {
777 updateLineDash(state
);
778 updateLineJoin(state
);
779 updateLineCap(state
);
780 updateLineWidth(state
);
781 updateFlatness(state
);
782 updateMiterLimit(state
);
783 updateFillColor(state
);
784 updateStrokeColor(state
);
785 needFontUpdate
= gTrue
;
788 void SplashOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
789 double m21
, double m22
,
790 double m31
, double m32
) {
791 updateLineDash(state
);
792 updateLineJoin(state
);
793 updateLineCap(state
);
794 updateLineWidth(state
);
797 void SplashOutputDev::updateLineDash(GfxState
*state
) {
801 SplashCoord dash
[20];
805 state
->getLineDash(&dashPattern
, &dashLength
, &dashStart
);
806 if (dashLength
> 20) {
809 for (i
= 0; i
< dashLength
; ++i
) {
810 dash
[i
] = (SplashCoord
)state
->transformWidth(dashPattern
[i
]);
815 phase
= (SplashCoord
)state
->transformWidth(dashStart
);
816 splash
->setLineDash(dash
, dashLength
, phase
);
819 void SplashOutputDev::updateFlatness(GfxState
*state
) {
820 splash
->setFlatness(state
->getFlatness());
823 void SplashOutputDev::updateLineJoin(GfxState
*state
) {
824 splash
->setLineJoin(state
->getLineJoin());
827 void SplashOutputDev::updateLineCap(GfxState
*state
) {
828 splash
->setLineCap(state
->getLineCap());
831 void SplashOutputDev::updateMiterLimit(GfxState
*state
) {
832 splash
->setMiterLimit(state
->getMiterLimit());
835 void SplashOutputDev::updateLineWidth(GfxState
*state
) {
836 splash
->setLineWidth(state
->getTransformedLineWidth());
839 void SplashOutputDev::updateFillColor(GfxState
*state
) {
846 state
->getFillGray(&gray
);
847 state
->getFillRGB(&rgb
);
849 state
->getFillCMYK(&cmyk
);
850 splash
->setFillPattern(getColor(gray
, &rgb
, &cmyk
));
852 splash
->setFillPattern(getColor(gray
, &rgb
));
856 void SplashOutputDev::updateStrokeColor(GfxState
*state
) {
863 state
->getStrokeGray(&gray
);
864 state
->getStrokeRGB(&rgb
);
866 state
->getStrokeCMYK(&cmyk
);
867 splash
->setStrokePattern(getColor(gray
, &rgb
, &cmyk
));
869 splash
->setStrokePattern(getColor(gray
, &rgb
));
874 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
, GfxRGB
*rgb
,
877 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
, GfxRGB
*rgb
) {
879 SplashPattern
*pattern
;
880 SplashColor color0
, color1
;
881 GfxColorComp r
, g
, b
;
884 gray
= gfxColorComp1
- gray
;
885 r
= gfxColorComp1
- rgb
->r
;
886 g
= gfxColorComp1
- rgb
->g
;
887 b
= gfxColorComp1
- rgb
->b
;
894 pattern
= NULL
; // make gcc happy
896 case splashModeMono1
:
899 pattern
= new SplashHalftone(color0
, color1
,
900 splash
->getScreen()->copy(),
901 (SplashCoord
)colToDbl(gray
));
903 case splashModeMono8
:
904 color1
[0] = colToByte(gray
);
905 pattern
= new SplashSolidColor(color1
);
907 case splashModeAMono8
:
909 color1
[1] = colToByte(gray
);
910 pattern
= new SplashSolidColor(color1
);
913 color1
[0] = colToByte(r
);
914 color1
[1] = colToByte(g
);
915 color1
[2] = colToByte(b
);
916 pattern
= new SplashSolidColor(color1
);
919 color1
[2] = colToByte(r
);
920 color1
[1] = colToByte(g
);
921 color1
[0] = colToByte(b
);
922 pattern
= new SplashSolidColor(color1
);
924 case splashModeARGB8
:
926 color1
[1] = colToByte(r
);
927 color1
[2] = colToByte(g
);
928 color1
[3] = colToByte(b
);
929 pattern
= new SplashSolidColor(color1
);
931 case splashModeBGRA8
:
933 color1
[2] = colToByte(r
);
934 color1
[1] = colToByte(g
);
935 color1
[0] = colToByte(b
);
936 pattern
= new SplashSolidColor(color1
);
939 case splashModeCMYK8
:
940 color1
[0] = colToByte(cmyk
->c
);
941 color1
[1] = colToByte(cmyk
->m
);
942 color1
[2] = colToByte(cmyk
->y
);
943 color1
[3] = colToByte(cmyk
->k
);
944 pattern
= new SplashSolidColor(color1
);
946 case splashModeACMYK8
:
948 color1
[1] = colToByte(cmyk
->c
);
949 color1
[2] = colToByte(cmyk
->m
);
950 color1
[3] = colToByte(cmyk
->y
);
951 color1
[4] = colToByte(cmyk
->k
);
952 pattern
= new SplashSolidColor(color1
);
960 void SplashOutputDev::updateBlendMode(GfxState
*state
) {
961 splash
->setBlendFunc(splashOutBlendFuncs
[state
->getBlendMode()]);
964 void SplashOutputDev::updateFillOpacity(GfxState
*state
) {
965 splash
->setFillAlpha((SplashCoord
)state
->getFillOpacity());
968 void SplashOutputDev::updateStrokeOpacity(GfxState
*state
) {
969 splash
->setStrokeAlpha((SplashCoord
)state
->getStrokeOpacity());
972 void SplashOutputDev::updateFont(GfxState
*state
) {
974 GfxFontType fontType
;
975 SplashOutFontFileID
*id
;
976 SplashFontFile
*fontFile
;
979 Object refObj
, strObj
;
980 GString
*tmpFileName
, *fileName
, *substName
;
983 DisplayFontParam
*dfp
;
984 CharCodeToUnicode
*ctu
;
985 double m11
, m12
, m21
, m22
, w1
, w2
;
989 int c
, substIdx
, n
, code
, cmap
;
991 needFontUpdate
= gFalse
;
997 if (!(gfxFont
= state
->getFont())) {
1000 fontType
= gfxFont
->getType();
1001 if (fontType
== fontType3
) {
1005 // check the font file cache
1006 id
= new SplashOutFontFileID(gfxFont
->getID());
1007 if ((fontFile
= fontEngine
->getFontFile(id
))) {
1012 // if there is an embedded font, write it to disk
1013 if (gfxFont
->getEmbeddedFontID(&embRef
)) {
1014 if (!openTempFile(&tmpFileName
, &tmpFile
, "wb", NULL
)) {
1015 error(-1, "Couldn't create temporary font file");
1018 refObj
.initRef(embRef
.num
, embRef
.gen
);
1019 refObj
.fetch(xref
, &strObj
);
1021 strObj
.streamReset();
1022 while ((c
= strObj
.streamGetChar()) != EOF
) {
1025 strObj
.streamClose();
1028 fileName
= tmpFileName
;
1030 // if there is an external font file, use it
1031 } else if (!(fileName
= gfxFont
->getExtFontFile())) {
1033 // look for a display font mapping or a substitute font
1034 if (gfxFont
->isCIDFont()) {
1035 if (((GfxCIDFont
*)gfxFont
)->getCollection()) {
1036 dfp
= globalParams
->
1037 getDisplayCIDFont(gfxFont
->getName(),
1038 ((GfxCIDFont
*)gfxFont
)->getCollection());
1041 if (gfxFont
->getName()) {
1042 dfp
= globalParams
->getDisplayFont(gfxFont
->getName());
1045 // 8-bit font substitution
1046 if (gfxFont
->isFixedWidth()) {
1048 } else if (gfxFont
->isSerif()) {
1053 if (gfxFont
->isBold()) {
1056 if (gfxFont
->isItalic()) {
1059 substName
= new GString(splashOutSubstFonts
[substIdx
].name
);
1060 dfp
= globalParams
->getDisplayFont(substName
);
1062 id
->setSubstIdx(substIdx
);
1066 error(-1, "Couldn't find a font for '%s'",
1067 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1071 switch (dfp
->kind
) {
1073 fileName
= dfp
->t1
.fileName
;
1074 fontType
= gfxFont
->isCIDFont() ? fontCIDType0
: fontType1
;
1077 fileName
= dfp
->tt
.fileName
;
1078 fontType
= gfxFont
->isCIDFont() ? fontCIDType2
: fontTrueType
;
1083 // load the font file
1086 if (!(fontFile
= fontEngine
->loadType1Font(
1088 fileName
->getCString(),
1089 fileName
== tmpFileName
,
1090 ((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1091 error(-1, "Couldn't create a font for '%s'",
1092 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1098 if (!(fontFile
= fontEngine
->loadType1CFont(
1100 fileName
->getCString(),
1101 fileName
== tmpFileName
,
1102 ((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1103 error(-1, "Couldn't create a font for '%s'",
1104 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1110 if ((ff
= FoFiTrueType::load(fileName
->getCString()))) {
1111 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(ff
);
1118 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
1120 fileName
->getCString(),
1121 fileName
== tmpFileName
,
1123 error(-1, "Couldn't create a font for '%s'",
1124 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1131 if (!(fontFile
= fontEngine
->loadCIDFont(
1133 fileName
->getCString(),
1134 fileName
== tmpFileName
))) {
1135 error(-1, "Couldn't create a font for '%s'",
1136 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1145 // create a CID-to-GID mapping, via Unicode
1146 if ((ctu
= ((GfxCIDFont
*)gfxFont
)->getToUnicode())) {
1147 if ((ff
= FoFiTrueType::load(fileName
->getCString()))) {
1148 // look for a Unicode cmap
1149 for (cmap
= 0; cmap
< ff
->getNumCmaps(); ++cmap
) {
1150 if ((ff
->getCmapPlatform(cmap
) == 3 &&
1151 ff
->getCmapEncoding(cmap
) == 1) ||
1152 ff
->getCmapPlatform(cmap
) == 0) {
1156 if (cmap
< ff
->getNumCmaps()) {
1157 // map CID -> Unicode -> GID
1158 n
= ctu
->getLength();
1159 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
1160 for (code
= 0; code
< n
; ++code
) {
1161 if (ctu
->mapToUnicode(code
, uBuf
, 8) > 0) {
1162 codeToGID
[code
] = ff
->mapCodeToGID(cmap
, uBuf
[0]);
1164 codeToGID
[code
] = 0;
1172 error(-1, "Couldn't find a mapping to Unicode for font '%s'",
1173 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1177 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
1178 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
1179 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
1180 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
1181 n
* sizeof(Gushort
));
1184 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
1186 fileName
->getCString(),
1187 fileName
== tmpFileName
,
1189 error(-1, "Couldn't create a font for '%s'",
1190 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1196 // this shouldn't happen
1201 // get the font matrix
1202 state
->getFontTransMat(&m11
, &m12
, &m21
, &m22
);
1203 m11
*= state
->getHorizScaling();
1204 m12
*= state
->getHorizScaling();
1206 // for substituted fonts: adjust the font matrix -- compare the
1207 // width of 'm' in the original font and the substituted font
1208 substIdx
= ((SplashOutFontFileID
*)fontFile
->getID())->getSubstIdx();
1209 if (substIdx
>= 0) {
1210 for (code
= 0; code
< 256; ++code
) {
1211 if ((name
= ((Gfx8BitFont
*)gfxFont
)->getCharName(code
)) &&
1212 name
[0] == 'm' && name
[1] == '\0') {
1217 w1
= ((Gfx8BitFont
*)gfxFont
)->getWidth(code
);
1218 w2
= splashOutSubstFonts
[substIdx
].mWidth
;
1219 if (!gfxFont
->isSymbolic()) {
1220 // if real font is substantially narrower than substituted
1221 // font, reduce the font size accordingly
1222 if (w1
> 0.01 && w1
< 0.9 * w2
) {
1231 // create the scaled font
1232 mat
[0] = m11
; mat
[1] = -m12
;
1233 mat
[2] = m21
; mat
[3] = -m22
;
1234 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.01) {
1235 // avoid a singular (or close-to-singular) matrix
1236 mat
[0] = 0.01; mat
[1] = 0;
1237 mat
[2] = 0; mat
[3] = 0.01;
1239 font
= fontEngine
->getFont(fontFile
, mat
);
1255 void SplashOutputDev::stroke(GfxState
*state
) {
1258 path
= convertPath(state
, state
->getPath());
1259 splash
->stroke(path
);
1263 void SplashOutputDev::fill(GfxState
*state
) {
1266 path
= convertPath(state
, state
->getPath());
1267 splash
->fill(path
, gFalse
);
1271 void SplashOutputDev::eoFill(GfxState
*state
) {
1274 path
= convertPath(state
, state
->getPath());
1275 splash
->fill(path
, gTrue
);
1279 void SplashOutputDev::clip(GfxState
*state
) {
1282 path
= convertPath(state
, state
->getPath());
1283 splash
->clipToPath(path
, gFalse
);
1287 void SplashOutputDev::eoClip(GfxState
*state
) {
1290 path
= convertPath(state
, state
->getPath());
1291 splash
->clipToPath(path
, gTrue
);
1295 SplashPath
*SplashOutputDev::convertPath(GfxState
*state
, GfxPath
*path
) {
1297 GfxSubpath
*subpath
;
1298 double x1
, y1
, x2
, y2
, x3
, y3
;
1301 sPath
= new SplashPath();
1302 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
1303 subpath
= path
->getSubpath(i
);
1304 if (subpath
->getNumPoints() > 0) {
1305 state
->transform(subpath
->getX(0), subpath
->getY(0), &x1
, &y1
);
1306 sPath
->moveTo((SplashCoord
)x1
, (SplashCoord
)y1
);
1308 while (j
< subpath
->getNumPoints()) {
1309 if (subpath
->getCurve(j
)) {
1310 state
->transform(subpath
->getX(j
), subpath
->getY(j
), &x1
, &y1
);
1311 state
->transform(subpath
->getX(j
+1), subpath
->getY(j
+1), &x2
, &y2
);
1312 state
->transform(subpath
->getX(j
+2), subpath
->getY(j
+2), &x3
, &y3
);
1313 sPath
->curveTo((SplashCoord
)x1
, (SplashCoord
)y1
,
1314 (SplashCoord
)x2
, (SplashCoord
)y2
,
1315 (SplashCoord
)x3
, (SplashCoord
)y3
);
1318 state
->transform(subpath
->getX(j
), subpath
->getY(j
), &x1
, &y1
);
1319 sPath
->lineTo((SplashCoord
)x1
, (SplashCoord
)y1
);
1323 if (subpath
->isClosed()) {
1331 void SplashOutputDev::drawChar(GfxState
*state
, double x
, double y
,
1332 double dx
, double dy
,
1333 double originX
, double originY
,
1334 CharCode code
, int nBytes
,
1335 Unicode
*u
, int uLen
) {
1340 if (needFontUpdate
) {
1347 // check for invisible text -- this is used by Acrobat Capture
1348 render
= state
->getRender();
1355 state
->transform(x
, y
, &x1
, &y1
);
1358 if (!(render
& 1)) {
1359 splash
->fillChar((SplashCoord
)x1
, (SplashCoord
)y1
, code
, font
);
1363 if ((render
& 3) == 1 || (render
& 3) == 2) {
1364 if ((path
= font
->getGlyphPath(code
))) {
1365 path
->offset((SplashCoord
)x1
, (SplashCoord
)y1
);
1366 splash
->stroke(path
);
1373 path
= font
->getGlyphPath(code
);
1374 path
->offset((SplashCoord
)x1
, (SplashCoord
)y1
);
1376 textClipPath
->append(path
);
1379 textClipPath
= path
;
1384 GBool
SplashOutputDev::beginType3Char(GfxState
*state
, double x
, double y
,
1385 double dx
, double dy
,
1386 CharCode code
, Unicode
*u
, int uLen
) {
1390 T3FontCache
*t3Font
;
1392 double x1
, y1
, xMin
, yMin
, xMax
, yMax
, xt
, yt
;
1395 if (!(gfxFont
= state
->getFont())) {
1398 fontID
= gfxFont
->getID();
1399 ctm
= state
->getCTM();
1400 state
->transform(0, 0, &xt
, &yt
);
1402 // is it the first (MRU) font in the cache?
1403 if (!(nT3Fonts
> 0 &&
1404 t3FontCache
[0]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3]))) {
1406 // is the font elsewhere in the cache?
1407 for (i
= 1; i
< nT3Fonts
; ++i
) {
1408 if (t3FontCache
[i
]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3])) {
1409 t3Font
= t3FontCache
[i
];
1410 for (j
= i
; j
> 0; --j
) {
1411 t3FontCache
[j
] = t3FontCache
[j
- 1];
1413 t3FontCache
[0] = t3Font
;
1417 if (i
>= nT3Fonts
) {
1419 // create new entry in the font cache
1420 if (nT3Fonts
== splashOutT3FontCacheSize
) {
1421 delete t3FontCache
[nT3Fonts
- 1];
1424 for (j
= nT3Fonts
; j
> 0; --j
) {
1425 t3FontCache
[j
] = t3FontCache
[j
- 1];
1428 bbox
= gfxFont
->getFontBBox();
1429 if (bbox
[0] == 0 && bbox
[1] == 0 && bbox
[2] == 0 && bbox
[3] == 0) {
1430 // broken bounding box -- just take a guess
1436 state
->transform(bbox
[0], bbox
[1], &x1
, &y1
);
1439 state
->transform(bbox
[0], bbox
[3], &x1
, &y1
);
1442 } else if (x1
> xMax
) {
1447 } else if (y1
> yMax
) {
1450 state
->transform(bbox
[2], bbox
[1], &x1
, &y1
);
1453 } else if (x1
> xMax
) {
1458 } else if (y1
> yMax
) {
1461 state
->transform(bbox
[2], bbox
[3], &x1
, &y1
);
1464 } else if (x1
> xMax
) {
1469 } else if (y1
> yMax
) {
1473 t3FontCache
[0] = new T3FontCache(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1474 (int)floor(xMin
- xt
),
1475 (int)floor(yMin
- yt
),
1476 (int)ceil(xMax
) - (int)floor(xMin
) + 3,
1477 (int)ceil(yMax
) - (int)floor(yMin
) + 3,
1478 colorMode
!= splashModeMono1
);
1481 t3Font
= t3FontCache
[0];
1483 // is the glyph in the cache?
1484 i
= (code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
1485 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
1486 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x8000) &&
1487 t3Font
->cacheTags
[i
+j
].code
== code
) {
1488 drawType3Glyph(t3Font
, &t3Font
->cacheTags
[i
+j
],
1489 t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
,
1495 // push a new Type 3 glyph record
1496 t3gs
= new T3GlyphStack();
1497 t3gs
->next
= t3GlyphStack
;
1498 t3GlyphStack
= t3gs
;
1499 t3GlyphStack
->code
= code
;
1500 t3GlyphStack
->x
= xt
;
1501 t3GlyphStack
->y
= yt
;
1502 t3GlyphStack
->cache
= t3Font
;
1503 t3GlyphStack
->cacheTag
= NULL
;
1504 t3GlyphStack
->cacheData
= NULL
;
1509 void SplashOutputDev::endType3Char(GfxState
*state
) {
1513 if (t3GlyphStack
->cacheTag
) {
1514 memcpy(t3GlyphStack
->cacheData
, bitmap
->getDataPtr(),
1515 t3GlyphStack
->cache
->glyphSize
);
1518 bitmap
= t3GlyphStack
->origBitmap
;
1519 splash
= t3GlyphStack
->origSplash
;
1520 ctm
= state
->getCTM();
1521 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1522 t3GlyphStack
->origCTM4
, t3GlyphStack
->origCTM5
);
1523 drawType3Glyph(t3GlyphStack
->cache
,
1524 t3GlyphStack
->cacheTag
, t3GlyphStack
->cacheData
,
1525 t3GlyphStack
->x
, t3GlyphStack
->y
);
1527 t3gs
= t3GlyphStack
;
1528 t3GlyphStack
= t3gs
->next
;
1532 void SplashOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
1535 void SplashOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
1536 double llx
, double lly
, double urx
, double ury
) {
1538 T3FontCache
*t3Font
;
1540 double xt
, yt
, xMin
, xMax
, yMin
, yMax
, x1
, y1
;
1543 t3Font
= t3GlyphStack
->cache
;
1545 // check for a valid bbox
1546 state
->transform(0, 0, &xt
, &yt
);
1547 state
->transform(llx
, lly
, &x1
, &y1
);
1550 state
->transform(llx
, ury
, &x1
, &y1
);
1553 } else if (x1
> xMax
) {
1558 } else if (y1
> yMax
) {
1561 state
->transform(urx
, lly
, &x1
, &y1
);
1564 } else if (x1
> xMax
) {
1569 } else if (y1
> yMax
) {
1572 state
->transform(urx
, ury
, &x1
, &y1
);
1575 } else if (x1
> xMax
) {
1580 } else if (y1
> yMax
) {
1583 if (xMin
- xt
< t3Font
->glyphX
||
1584 yMin
- yt
< t3Font
->glyphY
||
1585 xMax
- xt
> t3Font
->glyphX
+ t3Font
->glyphW
||
1586 yMax
- yt
> t3Font
->glyphY
+ t3Font
->glyphH
) {
1587 error(-1, "Bad bounding box in Type 3 glyph");
1591 // allocate a cache entry
1592 i
= (t3GlyphStack
->code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
1593 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
1594 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x7fff) == t3Font
->cacheAssoc
- 1) {
1595 t3Font
->cacheTags
[i
+j
].mru
= 0x8000;
1596 t3Font
->cacheTags
[i
+j
].code
= t3GlyphStack
->code
;
1597 t3GlyphStack
->cacheTag
= &t3Font
->cacheTags
[i
+j
];
1598 t3GlyphStack
->cacheData
= t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
;
1600 ++t3Font
->cacheTags
[i
+j
].mru
;
1605 t3GlyphStack
->origBitmap
= bitmap
;
1606 t3GlyphStack
->origSplash
= splash
;
1607 ctm
= state
->getCTM();
1608 t3GlyphStack
->origCTM4
= ctm
[4];
1609 t3GlyphStack
->origCTM5
= ctm
[5];
1611 // create the temporary bitmap
1612 if (colorMode
== splashModeMono1
) {
1613 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
1615 splash
= new Splash(bitmap
);
1617 splash
->clear(color
);
1620 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
1622 splash
= new Splash(bitmap
);
1624 splash
->clear(color
);
1627 splash
->setFillPattern(new SplashSolidColor(color
));
1628 splash
->setStrokePattern(new SplashSolidColor(color
));
1629 //~ this should copy other state from t3GlyphStack->origSplash?
1630 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1631 -t3Font
->glyphX
, -t3Font
->glyphY
);
1634 void SplashOutputDev::drawType3Glyph(T3FontCache
*t3Font
,
1635 T3FontCacheTag
*tag
, Guchar
*data
,
1636 double x
, double y
) {
1637 SplashGlyphBitmap glyph
;
1639 glyph
.x
= -t3Font
->glyphX
;
1640 glyph
.y
= -t3Font
->glyphY
;
1641 glyph
.w
= t3Font
->glyphW
;
1642 glyph
.h
= t3Font
->glyphH
;
1643 glyph
.aa
= colorMode
!= splashModeMono1
;
1645 glyph
.freeData
= gFalse
;
1646 splash
->fillGlyph((SplashCoord
)x
, (SplashCoord
)y
, &glyph
);
1649 void SplashOutputDev::endTextObject(GfxState
*state
) {
1651 splash
->clipToPath(textClipPath
, gFalse
);
1652 delete textClipPath
;
1653 textClipPath
= NULL
;
1657 struct SplashOutImageMaskData
{
1658 ImageStream
*imgStr
;
1660 int width
, height
, y
;
1663 GBool
SplashOutputDev::imageMaskSrc(void *data
, SplashColorPtr line
) {
1664 SplashOutImageMaskData
*imgMaskData
= (SplashOutImageMaskData
*)data
;
1669 if (imgMaskData
->y
== imgMaskData
->height
) {
1672 for (x
= 0, p
= imgMaskData
->imgStr
->getLine(), q
= line
;
1673 x
< imgMaskData
->width
;
1675 *q
++ = *p
++ ^ imgMaskData
->invert
;
1681 void SplashOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
1682 int width
, int height
, GBool invert
,
1686 SplashOutImageMaskData imgMaskData
;
1688 ctm
= state
->getCTM();
1693 mat
[4] = ctm
[2] + ctm
[4];
1694 mat
[5] = ctm
[3] + ctm
[5];
1696 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
1697 imgMaskData
.imgStr
->reset();
1698 imgMaskData
.invert
= invert
? 0 : 1;
1699 imgMaskData
.width
= width
;
1700 imgMaskData
.height
= height
;
1703 splash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
);
1705 while (imgMaskData
.y
< height
) {
1706 imgMaskData
.imgStr
->getLine();
1711 delete imgMaskData
.imgStr
;
1715 struct SplashOutImageData
{
1716 ImageStream
*imgStr
;
1717 GfxImageColorMap
*colorMap
;
1718 SplashColorPtr lookup
;
1720 SplashColorMode colorMode
;
1721 int width
, height
, y
;
1724 GBool
SplashOutputDev::imageSrc(void *data
, SplashColorPtr line
) {
1725 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
1727 SplashColorPtr q
, col
;
1735 if (imgData
->y
== imgData
->height
) {
1739 nComps
= imgData
->colorMap
->getNumPixelComps();
1741 if (imgData
->lookup
) {
1742 switch (imgData
->colorMode
) {
1743 case splashModeMono1
:
1744 case splashModeMono8
:
1745 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1748 *q
++ = imgData
->lookup
[*p
];
1751 case splashModeRGB8
:
1752 case splashModeBGR8
:
1753 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1756 col
= &imgData
->lookup
[3 * *p
];
1763 case splashModeCMYK8
:
1764 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1767 col
= &imgData
->lookup
[4 * *p
];
1775 case splashModeAMono8
:
1776 case splashModeARGB8
:
1777 case splashModeBGRA8
:
1779 case splashModeACMYK8
:
1785 switch (imgData
->colorMode
) {
1786 case splashModeMono1
:
1787 case splashModeMono8
:
1788 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1791 imgData
->colorMap
->getGray(p
, &gray
);
1792 *q
++ = colToByte(gray
);
1795 case splashModeRGB8
:
1796 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1799 imgData
->colorMap
->getRGB(p
, &rgb
);
1800 *q
++ = colToByte(rgb
.r
);
1801 *q
++ = colToByte(rgb
.g
);
1802 *q
++ = colToByte(rgb
.b
);
1805 case splashModeBGR8
:
1806 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1809 imgData
->colorMap
->getRGB(p
, &rgb
);
1810 *q
++ = colToByte(rgb
.b
);
1811 *q
++ = colToByte(rgb
.g
);
1812 *q
++ = colToByte(rgb
.r
);
1816 case splashModeCMYK8
:
1817 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1820 imgData
->colorMap
->getCMYK(p
, &cmyk
);
1821 *q
++ = colToByte(cmyk
.c
);
1822 *q
++ = colToByte(cmyk
.m
);
1823 *q
++ = colToByte(cmyk
.y
);
1824 *q
++ = colToByte(cmyk
.k
);
1828 case splashModeAMono8
:
1829 case splashModeARGB8
:
1830 case splashModeBGRA8
:
1832 case splashModeACMYK8
:
1843 GBool
SplashOutputDev::alphaImageSrc(void *data
, SplashColorPtr line
) {
1844 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
1846 SplashColorPtr q
, col
;
1855 if (imgData
->y
== imgData
->height
) {
1859 nComps
= imgData
->colorMap
->getNumPixelComps();
1861 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1865 for (i
= 0; i
< nComps
; ++i
) {
1866 if (p
[i
] < imgData
->maskColors
[2*i
] ||
1867 p
[i
] > imgData
->maskColors
[2*i
+1]) {
1872 if (imgData
->lookup
) {
1873 switch (imgData
->colorMode
) {
1874 case splashModeMono1
:
1875 case splashModeMono8
:
1877 *q
++ = imgData
->lookup
[*p
];
1879 case splashModeRGB8
:
1881 col
= &imgData
->lookup
[3 * *p
];
1886 case splashModeBGR8
:
1887 col
= &imgData
->lookup
[3 * *p
];
1894 case splashModeCMYK8
:
1896 col
= &imgData
->lookup
[4 * *p
];
1903 case splashModeAMono8
:
1904 case splashModeARGB8
:
1905 case splashModeBGRA8
:
1907 case splashModeACMYK8
:
1913 switch (imgData
->colorMode
) {
1914 case splashModeMono1
:
1915 case splashModeMono8
:
1916 imgData
->colorMap
->getGray(p
, &gray
);
1918 *q
++ = colToByte(gray
);
1920 case splashModeRGB8
:
1921 imgData
->colorMap
->getRGB(p
, &rgb
);
1923 *q
++ = colToByte(rgb
.r
);
1924 *q
++ = colToByte(rgb
.g
);
1925 *q
++ = colToByte(rgb
.b
);
1927 case splashModeBGR8
:
1928 imgData
->colorMap
->getRGB(p
, &rgb
);
1929 *q
++ = colToByte(rgb
.b
);
1930 *q
++ = colToByte(rgb
.g
);
1931 *q
++ = colToByte(rgb
.r
);
1935 case splashModeCMYK8
:
1936 imgData
->colorMap
->getCMYK(p
, &cmyk
);
1938 *q
++ = colToByte(cmyk
.c
);
1939 *q
++ = colToByte(cmyk
.m
);
1940 *q
++ = colToByte(cmyk
.y
);
1941 *q
++ = colToByte(cmyk
.k
);
1944 case splashModeAMono8
:
1945 case splashModeARGB8
:
1946 case splashModeBGRA8
:
1948 case splashModeACMYK8
:
1960 void SplashOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
1961 int width
, int height
,
1962 GfxImageColorMap
*colorMap
,
1963 int *maskColors
, GBool inlineImg
) {
1966 SplashOutImageData imgData
;
1967 SplashColorMode srcMode
;
1968 SplashImageSource src
;
1977 ctm
= state
->getCTM();
1982 mat
[4] = ctm
[2] + ctm
[4];
1983 mat
[5] = ctm
[3] + ctm
[5];
1985 imgData
.imgStr
= new ImageStream(str
, width
,
1986 colorMap
->getNumPixelComps(),
1987 colorMap
->getBits());
1988 imgData
.imgStr
->reset();
1989 imgData
.colorMap
= colorMap
;
1990 imgData
.maskColors
= maskColors
;
1991 imgData
.colorMode
= colorMode
;
1992 imgData
.width
= width
;
1993 imgData
.height
= height
;
1996 // special case for one-channel (monochrome/gray/separation) images:
1997 // build a lookup table here
1998 imgData
.lookup
= NULL
;
1999 if (colorMap
->getNumPixelComps() == 1) {
2000 n
= 1 << colorMap
->getBits();
2001 switch (colorMode
) {
2002 case splashModeMono1
:
2003 case splashModeMono8
:
2004 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2005 for (i
= 0; i
< n
; ++i
) {
2007 colorMap
->getGray(&pix
, &gray
);
2008 imgData
.lookup
[i
] = colToByte(gray
);
2011 case splashModeRGB8
:
2012 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2013 for (i
= 0; i
< n
; ++i
) {
2015 colorMap
->getRGB(&pix
, &rgb
);
2016 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2017 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2018 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2021 case splashModeBGR8
:
2022 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2023 for (i
= 0; i
< n
; ++i
) {
2025 colorMap
->getRGB(&pix
, &rgb
);
2026 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2027 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2028 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2032 case splashModeCMYK8
:
2033 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2034 for (i
= 0; i
< n
; ++i
) {
2036 colorMap
->getCMYK(&pix
, &cmyk
);
2037 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2038 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2039 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2040 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2050 switch (colorMode
) {
2051 case splashModeMono1
:
2052 case splashModeMono8
:
2053 srcMode
= maskColors
? splashModeAMono8
: splashModeMono8
;
2055 case splashModeRGB8
:
2056 srcMode
= maskColors
? splashModeARGB8
: splashModeRGB8
;
2058 case splashModeBGR8
:
2059 srcMode
= maskColors
? splashModeBGRA8
: splashModeBGR8
;
2062 case splashModeCMYK8
:
2063 srcMode
= maskColors
? splashModeACMYK8
: splashModeCMYK8
;
2068 srcMode
= splashModeRGB8
;
2071 src
= maskColors
? &alphaImageSrc
: &imageSrc
;
2072 splash
->drawImage(src
, &imgData
, srcMode
, width
, height
, mat
);
2074 while (imgData
.y
< height
) {
2075 imgData
.imgStr
->getLine();
2080 gfree(imgData
.lookup
);
2081 delete imgData
.imgStr
;
2085 struct SplashOutMaskedImageData
{
2086 ImageStream
*imgStr
;
2087 GfxImageColorMap
*colorMap
;
2089 SplashColorPtr lookup
;
2090 SplashColorMode colorMode
;
2091 int width
, height
, y
;
2094 GBool
SplashOutputDev::maskedImageSrc(void *data
, SplashColorPtr line
) {
2095 SplashOutMaskedImageData
*imgData
= (SplashOutMaskedImageData
*)data
;
2097 SplashColor maskColor
;
2098 SplashColorPtr q
, col
;
2107 if (imgData
->y
== imgData
->height
) {
2111 nComps
= imgData
->colorMap
->getNumPixelComps();
2113 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
2116 imgData
->mask
->getPixel(x
, imgData
->y
, maskColor
);
2117 alpha
= maskColor
[0] ? 0xff : 0x00;
2118 if (imgData
->lookup
) {
2119 switch (imgData
->colorMode
) {
2120 case splashModeMono1
:
2121 case splashModeMono8
:
2123 *q
++ = imgData
->lookup
[*p
];
2125 case splashModeRGB8
:
2127 col
= &imgData
->lookup
[3 * *p
];
2132 case splashModeBGR8
:
2133 col
= &imgData
->lookup
[3 * *p
];
2140 case splashModeCMYK8
:
2142 col
= &imgData
->lookup
[4 * *p
];
2149 case splashModeAMono8
:
2150 case splashModeARGB8
:
2151 case splashModeBGRA8
:
2153 case splashModeACMYK8
:
2159 switch (imgData
->colorMode
) {
2160 case splashModeMono1
:
2161 case splashModeMono8
:
2162 imgData
->colorMap
->getGray(p
, &gray
);
2164 *q
++ = colToByte(gray
);
2166 case splashModeRGB8
:
2167 imgData
->colorMap
->getRGB(p
, &rgb
);
2169 *q
++ = colToByte(rgb
.r
);
2170 *q
++ = colToByte(rgb
.g
);
2171 *q
++ = colToByte(rgb
.b
);
2173 case splashModeBGR8
:
2174 imgData
->colorMap
->getRGB(p
, &rgb
);
2175 *q
++ = colToByte(rgb
.b
);
2176 *q
++ = colToByte(rgb
.g
);
2177 *q
++ = colToByte(rgb
.r
);
2181 case splashModeCMYK8
:
2182 imgData
->colorMap
->getCMYK(p
, &cmyk
);
2184 *q
++ = colToByte(cmyk
.c
);
2185 *q
++ = colToByte(cmyk
.m
);
2186 *q
++ = colToByte(cmyk
.y
);
2187 *q
++ = colToByte(cmyk
.k
);
2190 case splashModeAMono8
:
2191 case splashModeARGB8
:
2192 case splashModeBGRA8
:
2194 case splashModeACMYK8
:
2206 void SplashOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
,
2207 Stream
*str
, int width
, int height
,
2208 GfxImageColorMap
*colorMap
,
2209 Stream
*maskStr
, int maskWidth
,
2210 int maskHeight
, GBool maskInvert
) {
2213 SplashOutMaskedImageData imgData
;
2214 SplashOutImageMaskData imgMaskData
;
2215 SplashColorMode srcMode
;
2216 SplashBitmap
*maskBitmap
;
2218 SplashColor maskColor
;
2227 //----- scale the mask image to the same size as the source image
2229 mat
[0] = (SplashCoord
)width
;
2232 mat
[3] = (SplashCoord
)height
;
2235 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
2236 imgMaskData
.imgStr
->reset();
2237 imgMaskData
.invert
= maskInvert
? 0 : 1;
2238 imgMaskData
.width
= maskWidth
;
2239 imgMaskData
.height
= maskHeight
;
2241 maskBitmap
= new SplashBitmap(width
, height
, 1, splashModeMono1
);
2242 maskSplash
= new Splash(maskBitmap
);
2244 maskSplash
->clear(maskColor
);
2246 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
2247 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
,
2248 maskWidth
, maskHeight
, mat
);
2249 delete imgMaskData
.imgStr
;
2253 //----- draw the source image
2255 ctm
= state
->getCTM();
2260 mat
[4] = ctm
[2] + ctm
[4];
2261 mat
[5] = ctm
[3] + ctm
[5];
2263 imgData
.imgStr
= new ImageStream(str
, width
,
2264 colorMap
->getNumPixelComps(),
2265 colorMap
->getBits());
2266 imgData
.imgStr
->reset();
2267 imgData
.colorMap
= colorMap
;
2268 imgData
.mask
= maskBitmap
;
2269 imgData
.colorMode
= colorMode
;
2270 imgData
.width
= width
;
2271 imgData
.height
= height
;
2274 // special case for one-channel (monochrome/gray/separation) images:
2275 // build a lookup table here
2276 imgData
.lookup
= NULL
;
2277 if (colorMap
->getNumPixelComps() == 1) {
2278 n
= 1 << colorMap
->getBits();
2279 switch (colorMode
) {
2280 case splashModeMono1
:
2281 case splashModeMono8
:
2282 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2283 for (i
= 0; i
< n
; ++i
) {
2285 colorMap
->getGray(&pix
, &gray
);
2286 imgData
.lookup
[i
] = colToByte(gray
);
2289 case splashModeRGB8
:
2290 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2291 for (i
= 0; i
< n
; ++i
) {
2293 colorMap
->getRGB(&pix
, &rgb
);
2294 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2295 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2296 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2299 case splashModeBGR8
:
2300 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2301 for (i
= 0; i
< n
; ++i
) {
2303 colorMap
->getRGB(&pix
, &rgb
);
2304 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2305 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2306 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2310 case splashModeCMYK8
:
2311 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2312 for (i
= 0; i
< n
; ++i
) {
2314 colorMap
->getCMYK(&pix
, &cmyk
);
2315 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2316 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2317 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2318 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2328 switch (colorMode
) {
2329 case splashModeMono1
:
2330 case splashModeMono8
:
2331 srcMode
= splashModeAMono8
;
2333 case splashModeRGB8
:
2334 srcMode
= splashModeARGB8
;
2336 case splashModeBGR8
:
2337 srcMode
= splashModeBGRA8
;
2340 case splashModeCMYK8
:
2341 srcMode
= splashModeACMYK8
;
2346 srcMode
= splashModeARGB8
;
2349 splash
->drawImage(&maskedImageSrc
, &imgData
, srcMode
, width
, height
, mat
);
2352 gfree(imgData
.lookup
);
2353 delete imgData
.imgStr
;
2357 void SplashOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
,
2358 Stream
*str
, int width
, int height
,
2359 GfxImageColorMap
*colorMap
,
2361 int maskWidth
, int maskHeight
,
2362 GfxImageColorMap
*maskColorMap
) {
2365 SplashOutImageData imgData
;
2366 SplashOutImageData imgMaskData
;
2367 SplashColorMode srcMode
;
2368 SplashBitmap
*maskBitmap
;
2370 SplashColor maskColor
;
2379 ctm
= state
->getCTM();
2384 mat
[4] = ctm
[2] + ctm
[4];
2385 mat
[5] = ctm
[3] + ctm
[5];
2387 //----- set up the soft mask
2389 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
,
2390 maskColorMap
->getNumPixelComps(),
2391 maskColorMap
->getBits());
2392 imgMaskData
.imgStr
->reset();
2393 imgMaskData
.colorMap
= maskColorMap
;
2394 imgMaskData
.maskColors
= NULL
;
2395 imgMaskData
.colorMode
= splashModeMono8
;
2396 imgMaskData
.width
= maskWidth
;
2397 imgMaskData
.height
= maskHeight
;
2399 n
= 1 << maskColorMap
->getBits();
2400 imgMaskData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2401 for (i
= 0; i
< n
; ++i
) {
2403 maskColorMap
->getGray(&pix
, &gray
);
2404 imgMaskData
.lookup
[i
] = colToByte(gray
);
2406 maskBitmap
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
2407 1, splashModeMono8
);
2408 maskSplash
= new Splash(maskBitmap
);
2410 maskSplash
->clear(maskColor
);
2411 maskSplash
->drawImage(&imageSrc
, &imgMaskData
,
2412 splashModeMono8
, maskWidth
, maskHeight
, mat
);
2413 delete imgMaskData
.imgStr
;
2415 gfree(imgMaskData
.lookup
);
2417 splash
->setSoftMask(maskBitmap
);
2419 //----- draw the source image
2421 imgData
.imgStr
= new ImageStream(str
, width
,
2422 colorMap
->getNumPixelComps(),
2423 colorMap
->getBits());
2424 imgData
.imgStr
->reset();
2425 imgData
.colorMap
= colorMap
;
2426 imgData
.maskColors
= NULL
;
2427 imgData
.colorMode
= colorMode
;
2428 imgData
.width
= width
;
2429 imgData
.height
= height
;
2432 // special case for one-channel (monochrome/gray/separation) images:
2433 // build a lookup table here
2434 imgData
.lookup
= NULL
;
2435 if (colorMap
->getNumPixelComps() == 1) {
2436 n
= 1 << colorMap
->getBits();
2437 switch (colorMode
) {
2438 case splashModeMono1
:
2439 case splashModeMono8
:
2440 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2441 for (i
= 0; i
< n
; ++i
) {
2443 colorMap
->getGray(&pix
, &gray
);
2444 imgData
.lookup
[i
] = colToByte(gray
);
2447 case splashModeRGB8
:
2448 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2449 for (i
= 0; i
< n
; ++i
) {
2451 colorMap
->getRGB(&pix
, &rgb
);
2452 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2453 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2454 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2457 case splashModeBGR8
:
2458 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2459 for (i
= 0; i
< n
; ++i
) {
2461 colorMap
->getRGB(&pix
, &rgb
);
2462 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2463 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2464 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2468 case splashModeCMYK8
:
2469 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2470 for (i
= 0; i
< n
; ++i
) {
2472 colorMap
->getCMYK(&pix
, &cmyk
);
2473 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2474 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2475 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2476 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2486 switch (colorMode
) {
2487 case splashModeMono1
:
2488 case splashModeMono8
:
2489 srcMode
= splashModeMono8
;
2491 case splashModeRGB8
:
2492 srcMode
= splashModeRGB8
;
2494 case splashModeBGR8
:
2495 srcMode
= splashModeBGR8
;
2498 case splashModeCMYK8
:
2499 srcMode
= splashModeCMYK8
;
2504 srcMode
= splashModeRGB8
;
2507 splash
->drawImage(&imageSrc
, &imgData
, srcMode
, width
, height
, mat
);
2509 splash
->setSoftMask(NULL
);
2510 gfree(imgData
.lookup
);
2511 delete imgData
.imgStr
;
2515 void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA
) {
2516 splashColorCopy(paperColor
, paperColorA
);
2519 int SplashOutputDev::getBitmapWidth() {
2520 return bitmap
->getWidth();
2523 int SplashOutputDev::getBitmapHeight() {
2524 return bitmap
->getHeight();
2527 SplashBitmap
*SplashOutputDev::takeBitmap() {
2531 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
, bitmapTopDown
);
2535 void SplashOutputDev::getModRegion(int *xMin
, int *yMin
,
2536 int *xMax
, int *yMax
) {
2537 splash
->getModRegion(xMin
, yMin
, xMax
, yMax
);
2540 void SplashOutputDev::clearModRegion() {
2541 splash
->clearModRegion();
2544 void SplashOutputDev::setFillColor(int r
, int g
, int b
) {
2551 rgb
.r
= byteToCol(r
);
2552 rgb
.g
= byteToCol(g
);
2553 rgb
.b
= byteToCol(b
);
2554 gray
= (GfxColorComp
)(0.299 * rgb
.r
+ 0.587 * rgb
.g
+ 0.114 * rgb
.g
+ 0.5);
2555 if (gray
> gfxColorComp1
) {
2556 gray
= gfxColorComp1
;
2559 cmyk
.c
= gfxColorComp1
- rgb
.r
;
2560 cmyk
.m
= gfxColorComp1
- rgb
.g
;
2561 cmyk
.y
= gfxColorComp1
- rgb
.b
;
2563 splash
->setFillPattern(getColor(gray
, &rgb
, &cmyk
));
2565 splash
->setFillPattern(getColor(gray
, &rgb
));
2569 SplashFont
*SplashOutputDev::getFont(GString
*name
, double *mat
) {
2570 DisplayFontParam
*dfp
;
2572 SplashOutFontFileID
*id
;
2573 SplashFontFile
*fontFile
;
2574 SplashFont
*fontObj
;
2580 for (i
= 0; i
< 16; ++i
) {
2581 if (!name
->cmp(splashOutSubstFonts
[i
].name
)) {
2590 id
= new SplashOutFontFileID(&ref
);
2592 // check the font file cache
2593 if ((fontFile
= fontEngine
->getFontFile(id
))) {
2596 // load the font file
2598 dfp
= globalParams
->getDisplayFont(name
);
2599 if (dfp
&& dfp
->kind
== displayFontT1
) {
2600 fontFile
= fontEngine
->loadType1Font(id
, dfp
->t1
.fileName
->getCString(),
2601 gFalse
, winAnsiEncoding
);
2602 } else if (dfp
&& dfp
->kind
== displayFontTT
) {
2603 if (!(ff
= FoFiTrueType::load(dfp
->tt
.fileName
->getCString()))) {
2606 for (cmap
= 0; cmap
< ff
->getNumCmaps(); ++cmap
) {
2607 if ((ff
->getCmapPlatform(cmap
) == 3 &&
2608 ff
->getCmapEncoding(cmap
) == 1) ||
2609 ff
->getCmapPlatform(cmap
) == 0) {
2613 if (cmap
== ff
->getNumCmaps()) {
2617 codeToGID
= (Gushort
*)gmallocn(256, sizeof(Gushort
));
2618 for (i
= 0; i
< 256; ++i
) {
2620 if (winAnsiEncoding
[i
] &&
2621 (u
= globalParams
->mapNameToUnicode(winAnsiEncoding
[i
]))) {
2622 codeToGID
[i
] = ff
->mapCodeToGID(cmap
, u
);
2626 fontFile
= fontEngine
->loadTrueTypeFont(id
,
2627 dfp
->tt
.fileName
->getCString(),
2628 gFalse
, codeToGID
, 256);
2634 // create the scaled font
2635 fontObj
= fontEngine
->getFont(fontFile
, (SplashCoord
*)mat
);