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 GBool
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
);
698 void SplashOutputDev::endPage() {
701 void SplashOutputDev::drawLink(Link
*link
, Catalog
*catalog
) {
702 double x1
, y1
, x2
, y2
;
703 LinkBorderStyle
*borderStyle
;
712 SplashCoord dashList
[20];
716 link
->getRect(&x1
, &y1
, &x2
, &y2
);
717 borderStyle
= link
->getBorderStyle();
718 if (borderStyle
->getWidth() > 0) {
719 borderStyle
->getColor(&r
, &g
, &b
);
723 gray
= dblToCol(0.299 * r
+ 0.587 * g
+ 0.114 * b
);
724 if (gray
> gfxColorComp1
) {
725 gray
= gfxColorComp1
;
728 cmyk
.c
= gfxColorComp1
- rgb
.r
;
729 cmyk
.m
= gfxColorComp1
- rgb
.g
;
730 cmyk
.y
= gfxColorComp1
- rgb
.b
;
732 splash
->setStrokePattern(getColor(gray
, &rgb
, &cmyk
));
734 splash
->setStrokePattern(getColor(gray
, &rgb
));
736 splash
->setLineWidth((SplashCoord
)borderStyle
->getWidth());
737 borderStyle
->getDash(&dash
, &dashLength
);
738 if (borderStyle
->getType() == linkBorderDashed
&& dashLength
> 0) {
739 if (dashLength
> 20) {
742 for (i
= 0; i
< dashLength
; ++i
) {
743 dashList
[i
] = (SplashCoord
)dash
[i
];
745 splash
->setLineDash(dashList
, dashLength
, 0);
747 path
= new SplashPath();
748 if (borderStyle
->getType() == linkBorderUnderlined
) {
749 cvtUserToDev(x1
, y1
, &x
, &y
);
750 path
->moveTo((SplashCoord
)x
, (SplashCoord
)y
);
751 cvtUserToDev(x2
, y1
, &x
, &y
);
752 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
754 cvtUserToDev(x1
, y1
, &x
, &y
);
755 path
->moveTo((SplashCoord
)x
, (SplashCoord
)y
);
756 cvtUserToDev(x2
, y1
, &x
, &y
);
757 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
758 cvtUserToDev(x2
, y2
, &x
, &y
);
759 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
760 cvtUserToDev(x1
, y2
, &x
, &y
);
761 path
->lineTo((SplashCoord
)x
, (SplashCoord
)y
);
764 splash
->stroke(path
);
769 void SplashOutputDev::saveState(GfxState
*state
) {
773 void SplashOutputDev::restoreState(GfxState
*state
) {
774 splash
->restoreState();
775 needFontUpdate
= gTrue
;
778 void SplashOutputDev::updateAll(GfxState
*state
) {
779 updateLineDash(state
);
780 updateLineJoin(state
);
781 updateLineCap(state
);
782 updateLineWidth(state
);
783 updateFlatness(state
);
784 updateMiterLimit(state
);
785 updateFillColor(state
);
786 updateStrokeColor(state
);
787 needFontUpdate
= gTrue
;
790 void SplashOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
791 double m21
, double m22
,
792 double m31
, double m32
) {
793 updateLineDash(state
);
794 updateLineJoin(state
);
795 updateLineCap(state
);
796 updateLineWidth(state
);
799 void SplashOutputDev::updateLineDash(GfxState
*state
) {
803 SplashCoord dash
[20];
807 state
->getLineDash(&dashPattern
, &dashLength
, &dashStart
);
808 if (dashLength
> 20) {
811 for (i
= 0; i
< dashLength
; ++i
) {
812 dash
[i
] = (SplashCoord
)state
->transformWidth(dashPattern
[i
]);
817 phase
= (SplashCoord
)state
->transformWidth(dashStart
);
818 splash
->setLineDash(dash
, dashLength
, phase
);
821 void SplashOutputDev::updateFlatness(GfxState
*state
) {
822 splash
->setFlatness(state
->getFlatness());
825 void SplashOutputDev::updateLineJoin(GfxState
*state
) {
826 splash
->setLineJoin(state
->getLineJoin());
829 void SplashOutputDev::updateLineCap(GfxState
*state
) {
830 splash
->setLineCap(state
->getLineCap());
833 void SplashOutputDev::updateMiterLimit(GfxState
*state
) {
834 splash
->setMiterLimit(state
->getMiterLimit());
837 void SplashOutputDev::updateLineWidth(GfxState
*state
) {
838 splash
->setLineWidth(state
->getTransformedLineWidth());
841 void SplashOutputDev::updateFillColor(GfxState
*state
) {
848 state
->getFillGray(&gray
);
849 state
->getFillRGB(&rgb
);
851 state
->getFillCMYK(&cmyk
);
852 splash
->setFillPattern(getColor(gray
, &rgb
, &cmyk
));
854 splash
->setFillPattern(getColor(gray
, &rgb
));
858 void SplashOutputDev::updateStrokeColor(GfxState
*state
) {
865 state
->getStrokeGray(&gray
);
866 state
->getStrokeRGB(&rgb
);
868 state
->getStrokeCMYK(&cmyk
);
869 splash
->setStrokePattern(getColor(gray
, &rgb
, &cmyk
));
871 splash
->setStrokePattern(getColor(gray
, &rgb
));
876 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
, GfxRGB
*rgb
,
879 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
, GfxRGB
*rgb
) {
881 SplashPattern
*pattern
;
882 SplashColor color0
, color1
;
883 GfxColorComp r
, g
, b
;
886 gray
= gfxColorComp1
- gray
;
887 r
= gfxColorComp1
- rgb
->r
;
888 g
= gfxColorComp1
- rgb
->g
;
889 b
= gfxColorComp1
- rgb
->b
;
896 pattern
= NULL
; // make gcc happy
898 case splashModeMono1
:
901 pattern
= new SplashHalftone(color0
, color1
,
902 splash
->getScreen()->copy(),
903 (SplashCoord
)colToDbl(gray
));
905 case splashModeMono8
:
906 color1
[0] = colToByte(gray
);
907 pattern
= new SplashSolidColor(color1
);
909 case splashModeAMono8
:
911 color1
[1] = colToByte(gray
);
912 pattern
= new SplashSolidColor(color1
);
915 color1
[0] = colToByte(r
);
916 color1
[1] = colToByte(g
);
917 color1
[2] = colToByte(b
);
918 pattern
= new SplashSolidColor(color1
);
921 color1
[2] = colToByte(r
);
922 color1
[1] = colToByte(g
);
923 color1
[0] = colToByte(b
);
924 pattern
= new SplashSolidColor(color1
);
926 case splashModeARGB8
:
928 color1
[1] = colToByte(r
);
929 color1
[2] = colToByte(g
);
930 color1
[3] = colToByte(b
);
931 pattern
= new SplashSolidColor(color1
);
933 case splashModeBGRA8
:
935 color1
[2] = colToByte(r
);
936 color1
[1] = colToByte(g
);
937 color1
[0] = colToByte(b
);
938 pattern
= new SplashSolidColor(color1
);
941 case splashModeCMYK8
:
942 color1
[0] = colToByte(cmyk
->c
);
943 color1
[1] = colToByte(cmyk
->m
);
944 color1
[2] = colToByte(cmyk
->y
);
945 color1
[3] = colToByte(cmyk
->k
);
946 pattern
= new SplashSolidColor(color1
);
948 case splashModeACMYK8
:
950 color1
[1] = colToByte(cmyk
->c
);
951 color1
[2] = colToByte(cmyk
->m
);
952 color1
[3] = colToByte(cmyk
->y
);
953 color1
[4] = colToByte(cmyk
->k
);
954 pattern
= new SplashSolidColor(color1
);
962 void SplashOutputDev::updateBlendMode(GfxState
*state
) {
963 splash
->setBlendFunc(splashOutBlendFuncs
[state
->getBlendMode()]);
966 void SplashOutputDev::updateFillOpacity(GfxState
*state
) {
967 splash
->setFillAlpha((SplashCoord
)state
->getFillOpacity());
970 void SplashOutputDev::updateStrokeOpacity(GfxState
*state
) {
971 splash
->setStrokeAlpha((SplashCoord
)state
->getStrokeOpacity());
974 void SplashOutputDev::updateFont(GfxState
*state
) {
976 GfxFontType fontType
;
977 SplashOutFontFileID
*id
;
978 SplashFontFile
*fontFile
;
981 Object refObj
, strObj
;
982 GString
*tmpFileName
, *fileName
, *substName
;
985 DisplayFontParam
*dfp
;
986 CharCodeToUnicode
*ctu
;
987 double m11
, m12
, m21
, m22
, w1
, w2
;
991 int c
, substIdx
, n
, code
, cmap
;
993 needFontUpdate
= gFalse
;
999 if (!(gfxFont
= state
->getFont())) {
1002 fontType
= gfxFont
->getType();
1003 if (fontType
== fontType3
) {
1007 // check the font file cache
1008 id
= new SplashOutFontFileID(gfxFont
->getID());
1009 if ((fontFile
= fontEngine
->getFontFile(id
))) {
1014 // if there is an embedded font, write it to disk
1015 if (gfxFont
->getEmbeddedFontID(&embRef
)) {
1016 if (!openTempFile(&tmpFileName
, &tmpFile
, "wb", NULL
)) {
1017 error(-1, "Couldn't create temporary font file");
1020 refObj
.initRef(embRef
.num
, embRef
.gen
);
1021 refObj
.fetch(xref
, &strObj
);
1023 strObj
.streamReset();
1024 while ((c
= strObj
.streamGetChar()) != EOF
) {
1027 strObj
.streamClose();
1030 fileName
= tmpFileName
;
1032 // if there is an external font file, use it
1033 } else if (!(fileName
= gfxFont
->getExtFontFile())) {
1035 // look for a display font mapping or a substitute font
1036 if (gfxFont
->isCIDFont()) {
1037 if (((GfxCIDFont
*)gfxFont
)->getCollection()) {
1038 dfp
= globalParams
->
1039 getDisplayCIDFont(gfxFont
->getName(),
1040 ((GfxCIDFont
*)gfxFont
)->getCollection());
1043 if (gfxFont
->getName()) {
1044 dfp
= globalParams
->getDisplayFont(gfxFont
->getName());
1047 // 8-bit font substitution
1048 if (gfxFont
->isFixedWidth()) {
1050 } else if (gfxFont
->isSerif()) {
1055 if (gfxFont
->isBold()) {
1058 if (gfxFont
->isItalic()) {
1061 substName
= new GString(splashOutSubstFonts
[substIdx
].name
);
1062 dfp
= globalParams
->getDisplayFont(substName
);
1064 id
->setSubstIdx(substIdx
);
1068 error(-1, "Couldn't find a font for '%s'",
1069 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1073 switch (dfp
->kind
) {
1075 fileName
= dfp
->t1
.fileName
;
1076 fontType
= gfxFont
->isCIDFont() ? fontCIDType0
: fontType1
;
1079 fileName
= dfp
->tt
.fileName
;
1080 fontType
= gfxFont
->isCIDFont() ? fontCIDType2
: fontTrueType
;
1085 // load the font file
1088 if (!(fontFile
= fontEngine
->loadType1Font(
1090 fileName
->getCString(),
1091 fileName
== tmpFileName
,
1092 ((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1093 error(-1, "Couldn't create a font for '%s'",
1094 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1100 if (!(fontFile
= fontEngine
->loadType1CFont(
1102 fileName
->getCString(),
1103 fileName
== tmpFileName
,
1104 ((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1105 error(-1, "Couldn't create a font for '%s'",
1106 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1112 if ((ff
= FoFiTrueType::load(fileName
->getCString()))) {
1113 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(ff
);
1120 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
1122 fileName
->getCString(),
1123 fileName
== tmpFileName
,
1125 error(-1, "Couldn't create a font for '%s'",
1126 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1133 if (!(fontFile
= fontEngine
->loadCIDFont(
1135 fileName
->getCString(),
1136 fileName
== tmpFileName
))) {
1137 error(-1, "Couldn't create a font for '%s'",
1138 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1147 // create a CID-to-GID mapping, via Unicode
1148 if ((ctu
= ((GfxCIDFont
*)gfxFont
)->getToUnicode())) {
1149 if ((ff
= FoFiTrueType::load(fileName
->getCString()))) {
1150 // look for a Unicode cmap
1151 for (cmap
= 0; cmap
< ff
->getNumCmaps(); ++cmap
) {
1152 if ((ff
->getCmapPlatform(cmap
) == 3 &&
1153 ff
->getCmapEncoding(cmap
) == 1) ||
1154 ff
->getCmapPlatform(cmap
) == 0) {
1158 if (cmap
< ff
->getNumCmaps()) {
1159 // map CID -> Unicode -> GID
1160 n
= ctu
->getLength();
1161 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
1162 for (code
= 0; code
< n
; ++code
) {
1163 if (ctu
->mapToUnicode(code
, uBuf
, 8) > 0) {
1164 codeToGID
[code
] = ff
->mapCodeToGID(cmap
, uBuf
[0]);
1166 codeToGID
[code
] = 0;
1174 error(-1, "Couldn't find a mapping to Unicode for font '%s'",
1175 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1179 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
1180 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
1181 codeToGID
= (Gushort
*)gmallocn(n
, sizeof(Gushort
));
1182 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
1183 n
* sizeof(Gushort
));
1186 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
1188 fileName
->getCString(),
1189 fileName
== tmpFileName
,
1191 error(-1, "Couldn't create a font for '%s'",
1192 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1198 // this shouldn't happen
1203 // get the font matrix
1204 state
->getFontTransMat(&m11
, &m12
, &m21
, &m22
);
1205 m11
*= state
->getHorizScaling();
1206 m12
*= state
->getHorizScaling();
1208 // for substituted fonts: adjust the font matrix -- compare the
1209 // width of 'm' in the original font and the substituted font
1210 substIdx
= ((SplashOutFontFileID
*)fontFile
->getID())->getSubstIdx();
1211 if (substIdx
>= 0) {
1212 for (code
= 0; code
< 256; ++code
) {
1213 if ((name
= ((Gfx8BitFont
*)gfxFont
)->getCharName(code
)) &&
1214 name
[0] == 'm' && name
[1] == '\0') {
1219 w1
= ((Gfx8BitFont
*)gfxFont
)->getWidth(code
);
1220 w2
= splashOutSubstFonts
[substIdx
].mWidth
;
1221 if (!gfxFont
->isSymbolic()) {
1222 // if real font is substantially narrower than substituted
1223 // font, reduce the font size accordingly
1224 if (w1
> 0.01 && w1
< 0.9 * w2
) {
1233 // create the scaled font
1234 mat
[0] = m11
; mat
[1] = -m12
;
1235 mat
[2] = m21
; mat
[3] = -m22
;
1236 if (fabs(mat
[0] * mat
[3] - mat
[1] * mat
[2]) < 0.01) {
1237 // avoid a singular (or close-to-singular) matrix
1238 mat
[0] = 0.01; mat
[1] = 0;
1239 mat
[2] = 0; mat
[3] = 0.01;
1241 font
= fontEngine
->getFont(fontFile
, mat
);
1257 void SplashOutputDev::stroke(GfxState
*state
) {
1260 path
= convertPath(state
, state
->getPath());
1261 splash
->stroke(path
);
1265 void SplashOutputDev::fill(GfxState
*state
) {
1268 path
= convertPath(state
, state
->getPath());
1269 splash
->fill(path
, gFalse
);
1273 void SplashOutputDev::eoFill(GfxState
*state
) {
1276 path
= convertPath(state
, state
->getPath());
1277 splash
->fill(path
, gTrue
);
1281 void SplashOutputDev::clip(GfxState
*state
) {
1284 path
= convertPath(state
, state
->getPath());
1285 splash
->clipToPath(path
, gFalse
);
1289 void SplashOutputDev::eoClip(GfxState
*state
) {
1292 path
= convertPath(state
, state
->getPath());
1293 splash
->clipToPath(path
, gTrue
);
1297 SplashPath
*SplashOutputDev::convertPath(GfxState
*state
, GfxPath
*path
) {
1299 GfxSubpath
*subpath
;
1300 double x1
, y1
, x2
, y2
, x3
, y3
;
1303 sPath
= new SplashPath();
1304 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
1305 subpath
= path
->getSubpath(i
);
1306 if (subpath
->getNumPoints() > 0) {
1307 state
->transform(subpath
->getX(0), subpath
->getY(0), &x1
, &y1
);
1308 sPath
->moveTo((SplashCoord
)x1
, (SplashCoord
)y1
);
1310 while (j
< subpath
->getNumPoints()) {
1311 if (subpath
->getCurve(j
)) {
1312 state
->transform(subpath
->getX(j
), subpath
->getY(j
), &x1
, &y1
);
1313 state
->transform(subpath
->getX(j
+1), subpath
->getY(j
+1), &x2
, &y2
);
1314 state
->transform(subpath
->getX(j
+2), subpath
->getY(j
+2), &x3
, &y3
);
1315 sPath
->curveTo((SplashCoord
)x1
, (SplashCoord
)y1
,
1316 (SplashCoord
)x2
, (SplashCoord
)y2
,
1317 (SplashCoord
)x3
, (SplashCoord
)y3
);
1320 state
->transform(subpath
->getX(j
), subpath
->getY(j
), &x1
, &y1
);
1321 sPath
->lineTo((SplashCoord
)x1
, (SplashCoord
)y1
);
1325 if (subpath
->isClosed()) {
1333 void SplashOutputDev::drawChar(GfxState
*state
, double x
, double y
,
1334 double dx
, double dy
,
1335 double originX
, double originY
,
1336 CharCode code
, int nBytes
,
1337 Unicode
*u
, int uLen
) {
1342 if (needFontUpdate
) {
1349 // check for invisible text -- this is used by Acrobat Capture
1350 render
= state
->getRender();
1357 state
->transform(x
, y
, &x1
, &y1
);
1360 if (!(render
& 1)) {
1361 splash
->fillChar((SplashCoord
)x1
, (SplashCoord
)y1
, code
, font
);
1365 if ((render
& 3) == 1 || (render
& 3) == 2) {
1366 if ((path
= font
->getGlyphPath(code
))) {
1367 path
->offset((SplashCoord
)x1
, (SplashCoord
)y1
);
1368 splash
->stroke(path
);
1375 path
= font
->getGlyphPath(code
);
1376 path
->offset((SplashCoord
)x1
, (SplashCoord
)y1
);
1378 textClipPath
->append(path
);
1381 textClipPath
= path
;
1386 GBool
SplashOutputDev::beginType3Char(GfxState
*state
, double x
, double y
,
1387 double dx
, double dy
,
1388 CharCode code
, Unicode
*u
, int uLen
) {
1392 T3FontCache
*t3Font
;
1394 double x1
, y1
, xMin
, yMin
, xMax
, yMax
, xt
, yt
;
1397 if (!(gfxFont
= state
->getFont())) {
1400 fontID
= gfxFont
->getID();
1401 ctm
= state
->getCTM();
1402 state
->transform(0, 0, &xt
, &yt
);
1404 // is it the first (MRU) font in the cache?
1405 if (!(nT3Fonts
> 0 &&
1406 t3FontCache
[0]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3]))) {
1408 // is the font elsewhere in the cache?
1409 for (i
= 1; i
< nT3Fonts
; ++i
) {
1410 if (t3FontCache
[i
]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3])) {
1411 t3Font
= t3FontCache
[i
];
1412 for (j
= i
; j
> 0; --j
) {
1413 t3FontCache
[j
] = t3FontCache
[j
- 1];
1415 t3FontCache
[0] = t3Font
;
1419 if (i
>= nT3Fonts
) {
1421 // create new entry in the font cache
1422 if (nT3Fonts
== splashOutT3FontCacheSize
) {
1423 delete t3FontCache
[nT3Fonts
- 1];
1426 for (j
= nT3Fonts
; j
> 0; --j
) {
1427 t3FontCache
[j
] = t3FontCache
[j
- 1];
1430 bbox
= gfxFont
->getFontBBox();
1431 if (bbox
[0] == 0 && bbox
[1] == 0 && bbox
[2] == 0 && bbox
[3] == 0) {
1432 // broken bounding box -- just take a guess
1438 state
->transform(bbox
[0], bbox
[1], &x1
, &y1
);
1441 state
->transform(bbox
[0], bbox
[3], &x1
, &y1
);
1444 } else if (x1
> xMax
) {
1449 } else if (y1
> yMax
) {
1452 state
->transform(bbox
[2], bbox
[1], &x1
, &y1
);
1455 } else if (x1
> xMax
) {
1460 } else if (y1
> yMax
) {
1463 state
->transform(bbox
[2], bbox
[3], &x1
, &y1
);
1466 } else if (x1
> xMax
) {
1471 } else if (y1
> yMax
) {
1475 t3FontCache
[0] = new T3FontCache(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1476 (int)floor(xMin
- xt
),
1477 (int)floor(yMin
- yt
),
1478 (int)ceil(xMax
) - (int)floor(xMin
) + 3,
1479 (int)ceil(yMax
) - (int)floor(yMin
) + 3,
1480 colorMode
!= splashModeMono1
);
1483 t3Font
= t3FontCache
[0];
1485 // is the glyph in the cache?
1486 i
= (code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
1487 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
1488 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x8000) &&
1489 t3Font
->cacheTags
[i
+j
].code
== code
) {
1490 drawType3Glyph(t3Font
, &t3Font
->cacheTags
[i
+j
],
1491 t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
,
1497 // push a new Type 3 glyph record
1498 t3gs
= new T3GlyphStack();
1499 t3gs
->next
= t3GlyphStack
;
1500 t3GlyphStack
= t3gs
;
1501 t3GlyphStack
->code
= code
;
1502 t3GlyphStack
->x
= xt
;
1503 t3GlyphStack
->y
= yt
;
1504 t3GlyphStack
->cache
= t3Font
;
1505 t3GlyphStack
->cacheTag
= NULL
;
1506 t3GlyphStack
->cacheData
= NULL
;
1511 void SplashOutputDev::endType3Char(GfxState
*state
) {
1515 if (t3GlyphStack
->cacheTag
) {
1516 memcpy(t3GlyphStack
->cacheData
, bitmap
->getDataPtr(),
1517 t3GlyphStack
->cache
->glyphSize
);
1520 bitmap
= t3GlyphStack
->origBitmap
;
1521 splash
= t3GlyphStack
->origSplash
;
1522 ctm
= state
->getCTM();
1523 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1524 t3GlyphStack
->origCTM4
, t3GlyphStack
->origCTM5
);
1525 drawType3Glyph(t3GlyphStack
->cache
,
1526 t3GlyphStack
->cacheTag
, t3GlyphStack
->cacheData
,
1527 t3GlyphStack
->x
, t3GlyphStack
->y
);
1529 t3gs
= t3GlyphStack
;
1530 t3GlyphStack
= t3gs
->next
;
1534 void SplashOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
1537 void SplashOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
1538 double llx
, double lly
, double urx
, double ury
) {
1540 T3FontCache
*t3Font
;
1542 double xt
, yt
, xMin
, xMax
, yMin
, yMax
, x1
, y1
;
1545 t3Font
= t3GlyphStack
->cache
;
1547 // check for a valid bbox
1548 state
->transform(0, 0, &xt
, &yt
);
1549 state
->transform(llx
, lly
, &x1
, &y1
);
1552 state
->transform(llx
, ury
, &x1
, &y1
);
1555 } else if (x1
> xMax
) {
1560 } else if (y1
> yMax
) {
1563 state
->transform(urx
, lly
, &x1
, &y1
);
1566 } else if (x1
> xMax
) {
1571 } else if (y1
> yMax
) {
1574 state
->transform(urx
, ury
, &x1
, &y1
);
1577 } else if (x1
> xMax
) {
1582 } else if (y1
> yMax
) {
1585 if (xMin
- xt
< t3Font
->glyphX
||
1586 yMin
- yt
< t3Font
->glyphY
||
1587 xMax
- xt
> t3Font
->glyphX
+ t3Font
->glyphW
||
1588 yMax
- yt
> t3Font
->glyphY
+ t3Font
->glyphH
) {
1589 error(-1, "Bad bounding box in Type 3 glyph");
1593 // allocate a cache entry
1594 i
= (t3GlyphStack
->code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
1595 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
1596 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x7fff) == t3Font
->cacheAssoc
- 1) {
1597 t3Font
->cacheTags
[i
+j
].mru
= 0x8000;
1598 t3Font
->cacheTags
[i
+j
].code
= t3GlyphStack
->code
;
1599 t3GlyphStack
->cacheTag
= &t3Font
->cacheTags
[i
+j
];
1600 t3GlyphStack
->cacheData
= t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
;
1602 ++t3Font
->cacheTags
[i
+j
].mru
;
1607 t3GlyphStack
->origBitmap
= bitmap
;
1608 t3GlyphStack
->origSplash
= splash
;
1609 ctm
= state
->getCTM();
1610 t3GlyphStack
->origCTM4
= ctm
[4];
1611 t3GlyphStack
->origCTM5
= ctm
[5];
1613 // create the temporary bitmap
1614 if (colorMode
== splashModeMono1
) {
1615 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
1617 splash
= new Splash(bitmap
);
1619 splash
->clear(color
);
1622 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
1624 splash
= new Splash(bitmap
);
1626 splash
->clear(color
);
1629 splash
->setFillPattern(new SplashSolidColor(color
));
1630 splash
->setStrokePattern(new SplashSolidColor(color
));
1631 //~ this should copy other state from t3GlyphStack->origSplash?
1632 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
1633 -t3Font
->glyphX
, -t3Font
->glyphY
);
1636 void SplashOutputDev::drawType3Glyph(T3FontCache
*t3Font
,
1637 T3FontCacheTag
*tag
, Guchar
*data
,
1638 double x
, double y
) {
1639 SplashGlyphBitmap glyph
;
1641 glyph
.x
= -t3Font
->glyphX
;
1642 glyph
.y
= -t3Font
->glyphY
;
1643 glyph
.w
= t3Font
->glyphW
;
1644 glyph
.h
= t3Font
->glyphH
;
1645 glyph
.aa
= colorMode
!= splashModeMono1
;
1647 glyph
.freeData
= gFalse
;
1648 splash
->fillGlyph((SplashCoord
)x
, (SplashCoord
)y
, &glyph
);
1651 void SplashOutputDev::endTextObject(GfxState
*state
) {
1653 splash
->clipToPath(textClipPath
, gFalse
);
1654 delete textClipPath
;
1655 textClipPath
= NULL
;
1659 struct SplashOutImageMaskData
{
1660 ImageStream
*imgStr
;
1662 int width
, height
, y
;
1665 GBool
SplashOutputDev::imageMaskSrc(void *data
, SplashColorPtr line
) {
1666 SplashOutImageMaskData
*imgMaskData
= (SplashOutImageMaskData
*)data
;
1671 if (imgMaskData
->y
== imgMaskData
->height
) {
1674 for (x
= 0, p
= imgMaskData
->imgStr
->getLine(), q
= line
;
1675 x
< imgMaskData
->width
;
1677 *q
++ = *p
++ ^ imgMaskData
->invert
;
1683 void SplashOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
1684 int width
, int height
, GBool invert
,
1688 SplashOutImageMaskData imgMaskData
;
1690 ctm
= state
->getCTM();
1695 mat
[4] = ctm
[2] + ctm
[4];
1696 mat
[5] = ctm
[3] + ctm
[5];
1698 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
1699 imgMaskData
.imgStr
->reset();
1700 imgMaskData
.invert
= invert
? 0 : 1;
1701 imgMaskData
.width
= width
;
1702 imgMaskData
.height
= height
;
1705 splash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
);
1707 while (imgMaskData
.y
< height
) {
1708 imgMaskData
.imgStr
->getLine();
1713 delete imgMaskData
.imgStr
;
1717 struct SplashOutImageData
{
1718 ImageStream
*imgStr
;
1719 GfxImageColorMap
*colorMap
;
1720 SplashColorPtr lookup
;
1722 SplashColorMode colorMode
;
1723 int width
, height
, y
;
1726 GBool
SplashOutputDev::imageSrc(void *data
, SplashColorPtr line
) {
1727 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
1729 SplashColorPtr q
, col
;
1737 if (imgData
->y
== imgData
->height
) {
1741 nComps
= imgData
->colorMap
->getNumPixelComps();
1743 if (imgData
->lookup
) {
1744 switch (imgData
->colorMode
) {
1745 case splashModeMono1
:
1746 case splashModeMono8
:
1747 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1750 *q
++ = imgData
->lookup
[*p
];
1753 case splashModeRGB8
:
1754 case splashModeBGR8
:
1755 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1758 col
= &imgData
->lookup
[3 * *p
];
1765 case splashModeCMYK8
:
1766 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1769 col
= &imgData
->lookup
[4 * *p
];
1777 case splashModeAMono8
:
1778 case splashModeARGB8
:
1779 case splashModeBGRA8
:
1781 case splashModeACMYK8
:
1787 switch (imgData
->colorMode
) {
1788 case splashModeMono1
:
1789 case splashModeMono8
:
1790 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1793 imgData
->colorMap
->getGray(p
, &gray
);
1794 *q
++ = colToByte(gray
);
1797 case splashModeRGB8
:
1798 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1801 imgData
->colorMap
->getRGB(p
, &rgb
);
1802 *q
++ = colToByte(rgb
.r
);
1803 *q
++ = colToByte(rgb
.g
);
1804 *q
++ = colToByte(rgb
.b
);
1807 case splashModeBGR8
:
1808 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1811 imgData
->colorMap
->getRGB(p
, &rgb
);
1812 *q
++ = colToByte(rgb
.b
);
1813 *q
++ = colToByte(rgb
.g
);
1814 *q
++ = colToByte(rgb
.r
);
1818 case splashModeCMYK8
:
1819 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1822 imgData
->colorMap
->getCMYK(p
, &cmyk
);
1823 *q
++ = colToByte(cmyk
.c
);
1824 *q
++ = colToByte(cmyk
.m
);
1825 *q
++ = colToByte(cmyk
.y
);
1826 *q
++ = colToByte(cmyk
.k
);
1830 case splashModeAMono8
:
1831 case splashModeARGB8
:
1832 case splashModeBGRA8
:
1834 case splashModeACMYK8
:
1845 GBool
SplashOutputDev::alphaImageSrc(void *data
, SplashColorPtr line
) {
1846 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
1848 SplashColorPtr q
, col
;
1857 if (imgData
->y
== imgData
->height
) {
1861 nComps
= imgData
->colorMap
->getNumPixelComps();
1863 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
1867 for (i
= 0; i
< nComps
; ++i
) {
1868 if (p
[i
] < imgData
->maskColors
[2*i
] ||
1869 p
[i
] > imgData
->maskColors
[2*i
+1]) {
1874 if (imgData
->lookup
) {
1875 switch (imgData
->colorMode
) {
1876 case splashModeMono1
:
1877 case splashModeMono8
:
1879 *q
++ = imgData
->lookup
[*p
];
1881 case splashModeRGB8
:
1883 col
= &imgData
->lookup
[3 * *p
];
1888 case splashModeBGR8
:
1889 col
= &imgData
->lookup
[3 * *p
];
1896 case splashModeCMYK8
:
1898 col
= &imgData
->lookup
[4 * *p
];
1905 case splashModeAMono8
:
1906 case splashModeARGB8
:
1907 case splashModeBGRA8
:
1909 case splashModeACMYK8
:
1915 switch (imgData
->colorMode
) {
1916 case splashModeMono1
:
1917 case splashModeMono8
:
1918 imgData
->colorMap
->getGray(p
, &gray
);
1920 *q
++ = colToByte(gray
);
1922 case splashModeRGB8
:
1923 imgData
->colorMap
->getRGB(p
, &rgb
);
1925 *q
++ = colToByte(rgb
.r
);
1926 *q
++ = colToByte(rgb
.g
);
1927 *q
++ = colToByte(rgb
.b
);
1929 case splashModeBGR8
:
1930 imgData
->colorMap
->getRGB(p
, &rgb
);
1931 *q
++ = colToByte(rgb
.b
);
1932 *q
++ = colToByte(rgb
.g
);
1933 *q
++ = colToByte(rgb
.r
);
1937 case splashModeCMYK8
:
1938 imgData
->colorMap
->getCMYK(p
, &cmyk
);
1940 *q
++ = colToByte(cmyk
.c
);
1941 *q
++ = colToByte(cmyk
.m
);
1942 *q
++ = colToByte(cmyk
.y
);
1943 *q
++ = colToByte(cmyk
.k
);
1946 case splashModeAMono8
:
1947 case splashModeARGB8
:
1948 case splashModeBGRA8
:
1950 case splashModeACMYK8
:
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 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2015 for (i
= 0; i
< n
; ++i
) {
2017 colorMap
->getRGB(&pix
, &rgb
);
2018 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2019 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2020 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2023 case splashModeBGR8
:
2024 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2025 for (i
= 0; i
< n
; ++i
) {
2027 colorMap
->getRGB(&pix
, &rgb
);
2028 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2029 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2030 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2034 case splashModeCMYK8
:
2035 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2036 for (i
= 0; i
< n
; ++i
) {
2038 colorMap
->getCMYK(&pix
, &cmyk
);
2039 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2040 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2041 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2042 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2052 switch (colorMode
) {
2053 case splashModeMono1
:
2054 case splashModeMono8
:
2055 srcMode
= maskColors
? splashModeAMono8
: splashModeMono8
;
2057 case splashModeRGB8
:
2058 srcMode
= maskColors
? splashModeARGB8
: splashModeRGB8
;
2060 case splashModeBGR8
:
2061 srcMode
= maskColors
? splashModeBGRA8
: splashModeBGR8
;
2064 case splashModeCMYK8
:
2065 srcMode
= maskColors
? splashModeACMYK8
: splashModeCMYK8
;
2070 srcMode
= splashModeRGB8
;
2073 src
= maskColors
? &alphaImageSrc
: &imageSrc
;
2074 splash
->drawImage(src
, &imgData
, srcMode
, width
, height
, mat
);
2076 while (imgData
.y
< height
) {
2077 imgData
.imgStr
->getLine();
2082 gfree(imgData
.lookup
);
2083 delete imgData
.imgStr
;
2087 struct SplashOutMaskedImageData
{
2088 ImageStream
*imgStr
;
2089 GfxImageColorMap
*colorMap
;
2091 SplashColorPtr lookup
;
2092 SplashColorMode colorMode
;
2093 int width
, height
, y
;
2096 GBool
SplashOutputDev::maskedImageSrc(void *data
, SplashColorPtr line
) {
2097 SplashOutMaskedImageData
*imgData
= (SplashOutMaskedImageData
*)data
;
2099 SplashColor maskColor
;
2100 SplashColorPtr q
, col
;
2109 if (imgData
->y
== imgData
->height
) {
2113 nComps
= imgData
->colorMap
->getNumPixelComps();
2115 for (x
= 0, p
= imgData
->imgStr
->getLine(), q
= line
;
2118 imgData
->mask
->getPixel(x
, imgData
->y
, maskColor
);
2119 alpha
= maskColor
[0] ? 0xff : 0x00;
2120 if (imgData
->lookup
) {
2121 switch (imgData
->colorMode
) {
2122 case splashModeMono1
:
2123 case splashModeMono8
:
2125 *q
++ = imgData
->lookup
[*p
];
2127 case splashModeRGB8
:
2129 col
= &imgData
->lookup
[3 * *p
];
2134 case splashModeBGR8
:
2135 col
= &imgData
->lookup
[3 * *p
];
2142 case splashModeCMYK8
:
2144 col
= &imgData
->lookup
[4 * *p
];
2151 case splashModeAMono8
:
2152 case splashModeARGB8
:
2153 case splashModeBGRA8
:
2155 case splashModeACMYK8
:
2161 switch (imgData
->colorMode
) {
2162 case splashModeMono1
:
2163 case splashModeMono8
:
2164 imgData
->colorMap
->getGray(p
, &gray
);
2166 *q
++ = colToByte(gray
);
2168 case splashModeRGB8
:
2169 imgData
->colorMap
->getRGB(p
, &rgb
);
2171 *q
++ = colToByte(rgb
.r
);
2172 *q
++ = colToByte(rgb
.g
);
2173 *q
++ = colToByte(rgb
.b
);
2175 case splashModeBGR8
:
2176 imgData
->colorMap
->getRGB(p
, &rgb
);
2177 *q
++ = colToByte(rgb
.b
);
2178 *q
++ = colToByte(rgb
.g
);
2179 *q
++ = colToByte(rgb
.r
);
2183 case splashModeCMYK8
:
2184 imgData
->colorMap
->getCMYK(p
, &cmyk
);
2186 *q
++ = colToByte(cmyk
.c
);
2187 *q
++ = colToByte(cmyk
.m
);
2188 *q
++ = colToByte(cmyk
.y
);
2189 *q
++ = colToByte(cmyk
.k
);
2192 case splashModeAMono8
:
2193 case splashModeARGB8
:
2194 case splashModeBGRA8
:
2196 case splashModeACMYK8
:
2208 void SplashOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
,
2209 Stream
*str
, int width
, int height
,
2210 GfxImageColorMap
*colorMap
,
2211 Stream
*maskStr
, int maskWidth
,
2212 int maskHeight
, GBool maskInvert
) {
2215 SplashOutMaskedImageData imgData
;
2216 SplashOutImageMaskData imgMaskData
;
2217 SplashColorMode srcMode
;
2218 SplashBitmap
*maskBitmap
;
2220 SplashColor maskColor
;
2229 //----- scale the mask image to the same size as the source image
2231 mat
[0] = (SplashCoord
)width
;
2234 mat
[3] = (SplashCoord
)height
;
2237 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
2238 imgMaskData
.imgStr
->reset();
2239 imgMaskData
.invert
= maskInvert
? 0 : 1;
2240 imgMaskData
.width
= maskWidth
;
2241 imgMaskData
.height
= maskHeight
;
2243 maskBitmap
= new SplashBitmap(width
, height
, 1, splashModeMono1
);
2244 maskSplash
= new Splash(maskBitmap
);
2246 maskSplash
->clear(maskColor
);
2248 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
2249 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
,
2250 maskWidth
, maskHeight
, mat
);
2251 delete imgMaskData
.imgStr
;
2255 //----- draw the source image
2257 ctm
= state
->getCTM();
2262 mat
[4] = ctm
[2] + ctm
[4];
2263 mat
[5] = ctm
[3] + ctm
[5];
2265 imgData
.imgStr
= new ImageStream(str
, width
,
2266 colorMap
->getNumPixelComps(),
2267 colorMap
->getBits());
2268 imgData
.imgStr
->reset();
2269 imgData
.colorMap
= colorMap
;
2270 imgData
.mask
= maskBitmap
;
2271 imgData
.colorMode
= colorMode
;
2272 imgData
.width
= width
;
2273 imgData
.height
= height
;
2276 // special case for one-channel (monochrome/gray/separation) images:
2277 // build a lookup table here
2278 imgData
.lookup
= NULL
;
2279 if (colorMap
->getNumPixelComps() == 1) {
2280 n
= 1 << colorMap
->getBits();
2281 switch (colorMode
) {
2282 case splashModeMono1
:
2283 case splashModeMono8
:
2284 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2285 for (i
= 0; i
< n
; ++i
) {
2287 colorMap
->getGray(&pix
, &gray
);
2288 imgData
.lookup
[i
] = colToByte(gray
);
2291 case splashModeRGB8
:
2292 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2293 for (i
= 0; i
< n
; ++i
) {
2295 colorMap
->getRGB(&pix
, &rgb
);
2296 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2297 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2298 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2301 case splashModeBGR8
:
2302 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2303 for (i
= 0; i
< n
; ++i
) {
2305 colorMap
->getRGB(&pix
, &rgb
);
2306 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2307 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2308 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2312 case splashModeCMYK8
:
2313 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2314 for (i
= 0; i
< n
; ++i
) {
2316 colorMap
->getCMYK(&pix
, &cmyk
);
2317 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2318 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2319 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2320 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2330 switch (colorMode
) {
2331 case splashModeMono1
:
2332 case splashModeMono8
:
2333 srcMode
= splashModeAMono8
;
2335 case splashModeRGB8
:
2336 srcMode
= splashModeARGB8
;
2338 case splashModeBGR8
:
2339 srcMode
= splashModeBGRA8
;
2342 case splashModeCMYK8
:
2343 srcMode
= splashModeACMYK8
;
2348 srcMode
= splashModeARGB8
;
2351 splash
->drawImage(&maskedImageSrc
, &imgData
, srcMode
, width
, height
, mat
);
2354 gfree(imgData
.lookup
);
2355 delete imgData
.imgStr
;
2359 void SplashOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
,
2360 Stream
*str
, int width
, int height
,
2361 GfxImageColorMap
*colorMap
,
2363 int maskWidth
, int maskHeight
,
2364 GfxImageColorMap
*maskColorMap
) {
2367 SplashOutImageData imgData
;
2368 SplashOutImageData imgMaskData
;
2369 SplashColorMode srcMode
;
2370 SplashBitmap
*maskBitmap
;
2372 SplashColor maskColor
;
2381 ctm
= state
->getCTM();
2386 mat
[4] = ctm
[2] + ctm
[4];
2387 mat
[5] = ctm
[3] + ctm
[5];
2389 //----- set up the soft mask
2391 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
,
2392 maskColorMap
->getNumPixelComps(),
2393 maskColorMap
->getBits());
2394 imgMaskData
.imgStr
->reset();
2395 imgMaskData
.colorMap
= maskColorMap
;
2396 imgMaskData
.maskColors
= NULL
;
2397 imgMaskData
.colorMode
= splashModeMono8
;
2398 imgMaskData
.width
= maskWidth
;
2399 imgMaskData
.height
= maskHeight
;
2401 n
= 1 << maskColorMap
->getBits();
2402 imgMaskData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2403 for (i
= 0; i
< n
; ++i
) {
2405 maskColorMap
->getGray(&pix
, &gray
);
2406 imgMaskData
.lookup
[i
] = colToByte(gray
);
2408 maskBitmap
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
2409 1, splashModeMono8
);
2410 maskSplash
= new Splash(maskBitmap
);
2412 maskSplash
->clear(maskColor
);
2413 maskSplash
->drawImage(&imageSrc
, &imgMaskData
,
2414 splashModeMono8
, maskWidth
, maskHeight
, mat
);
2415 delete imgMaskData
.imgStr
;
2417 gfree(imgMaskData
.lookup
);
2419 splash
->setSoftMask(maskBitmap
);
2421 //----- draw the source image
2423 imgData
.imgStr
= new ImageStream(str
, width
,
2424 colorMap
->getNumPixelComps(),
2425 colorMap
->getBits());
2426 imgData
.imgStr
->reset();
2427 imgData
.colorMap
= colorMap
;
2428 imgData
.maskColors
= NULL
;
2429 imgData
.colorMode
= colorMode
;
2430 imgData
.width
= width
;
2431 imgData
.height
= height
;
2434 // special case for one-channel (monochrome/gray/separation) images:
2435 // build a lookup table here
2436 imgData
.lookup
= NULL
;
2437 if (colorMap
->getNumPixelComps() == 1) {
2438 n
= 1 << colorMap
->getBits();
2439 switch (colorMode
) {
2440 case splashModeMono1
:
2441 case splashModeMono8
:
2442 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
2443 for (i
= 0; i
< n
; ++i
) {
2445 colorMap
->getGray(&pix
, &gray
);
2446 imgData
.lookup
[i
] = colToByte(gray
);
2449 case splashModeRGB8
:
2450 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2451 for (i
= 0; i
< n
; ++i
) {
2453 colorMap
->getRGB(&pix
, &rgb
);
2454 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
2455 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2456 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
2459 case splashModeBGR8
:
2460 imgData
.lookup
= (SplashColorPtr
)gmalloc(3 * n
);
2461 for (i
= 0; i
< n
; ++i
) {
2463 colorMap
->getRGB(&pix
, &rgb
);
2464 imgData
.lookup
[3*i
] = colToByte(rgb
.b
);
2465 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
2466 imgData
.lookup
[3*i
+2] = colToByte(rgb
.r
);
2470 case splashModeCMYK8
:
2471 imgData
.lookup
= (SplashColorPtr
)gmalloc(4 * n
);
2472 for (i
= 0; i
< n
; ++i
) {
2474 colorMap
->getCMYK(&pix
, &cmyk
);
2475 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
2476 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
2477 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
2478 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
2488 switch (colorMode
) {
2489 case splashModeMono1
:
2490 case splashModeMono8
:
2491 srcMode
= splashModeMono8
;
2493 case splashModeRGB8
:
2494 srcMode
= splashModeRGB8
;
2496 case splashModeBGR8
:
2497 srcMode
= splashModeBGR8
;
2500 case splashModeCMYK8
:
2501 srcMode
= splashModeCMYK8
;
2506 srcMode
= splashModeRGB8
;
2509 splash
->drawImage(&imageSrc
, &imgData
, srcMode
, width
, height
, mat
);
2511 splash
->setSoftMask(NULL
);
2512 gfree(imgData
.lookup
);
2513 delete imgData
.imgStr
;
2517 void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA
) {
2518 splashColorCopy(paperColor
, paperColorA
);
2521 int SplashOutputDev::getBitmapWidth() {
2522 return bitmap
->getWidth();
2525 int SplashOutputDev::getBitmapHeight() {
2526 return bitmap
->getHeight();
2529 SplashBitmap
*SplashOutputDev::takeBitmap() {
2533 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
, bitmapTopDown
);
2537 void SplashOutputDev::getModRegion(int *xMin
, int *yMin
,
2538 int *xMax
, int *yMax
) {
2539 splash
->getModRegion(xMin
, yMin
, xMax
, yMax
);
2542 void SplashOutputDev::clearModRegion() {
2543 splash
->clearModRegion();
2546 void SplashOutputDev::setFillColor(int r
, int g
, int b
) {
2553 rgb
.r
= byteToCol(r
);
2554 rgb
.g
= byteToCol(g
);
2555 rgb
.b
= byteToCol(b
);
2556 gray
= (GfxColorComp
)(0.299 * rgb
.r
+ 0.587 * rgb
.g
+ 0.114 * rgb
.g
+ 0.5);
2557 if (gray
> gfxColorComp1
) {
2558 gray
= gfxColorComp1
;
2561 cmyk
.c
= gfxColorComp1
- rgb
.r
;
2562 cmyk
.m
= gfxColorComp1
- rgb
.g
;
2563 cmyk
.y
= gfxColorComp1
- rgb
.b
;
2565 splash
->setFillPattern(getColor(gray
, &rgb
, &cmyk
));
2567 splash
->setFillPattern(getColor(gray
, &rgb
));
2571 SplashFont
*SplashOutputDev::getFont(GString
*name
, double *mat
) {
2572 DisplayFontParam
*dfp
;
2574 SplashOutFontFileID
*id
;
2575 SplashFontFile
*fontFile
;
2576 SplashFont
*fontObj
;
2582 for (i
= 0; i
< 16; ++i
) {
2583 if (!name
->cmp(splashOutSubstFonts
[i
].name
)) {
2592 id
= new SplashOutFontFileID(&ref
);
2594 // check the font file cache
2595 if ((fontFile
= fontEngine
->getFontFile(id
))) {
2598 // load the font file
2600 dfp
= globalParams
->getDisplayFont(name
);
2601 if (dfp
&& dfp
->kind
== displayFontT1
) {
2602 fontFile
= fontEngine
->loadType1Font(id
, dfp
->t1
.fileName
->getCString(),
2603 gFalse
, winAnsiEncoding
);
2604 } else if (dfp
&& dfp
->kind
== displayFontTT
) {
2605 if (!(ff
= FoFiTrueType::load(dfp
->tt
.fileName
->getCString()))) {
2608 for (cmap
= 0; cmap
< ff
->getNumCmaps(); ++cmap
) {
2609 if ((ff
->getCmapPlatform(cmap
) == 3 &&
2610 ff
->getCmapEncoding(cmap
) == 1) ||
2611 ff
->getCmapPlatform(cmap
) == 0) {
2615 if (cmap
== ff
->getNumCmaps()) {
2619 codeToGID
= (Gushort
*)gmallocn(256, sizeof(Gushort
));
2620 for (i
= 0; i
< 256; ++i
) {
2622 if (winAnsiEncoding
[i
] &&
2623 (u
= globalParams
->mapNameToUnicode(winAnsiEncoding
[i
]))) {
2624 codeToGID
[i
] = ff
->mapCodeToGID(cmap
, u
);
2628 fontFile
= fontEngine
->loadTrueTypeFont(id
,
2629 dfp
->tt
.fileName
->getCString(),
2630 gFalse
, codeToGID
, 256);
2636 // create the scaled font
2637 fontObj
= fontEngine
->getFont(fontFile
, (SplashCoord
*)mat
);