1 //========================================================================
5 // Copyright 2003 Glyph & Cog, LLC
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2005 Takashi Iwai <tiwai@suse.de>
17 // Copyright (C) 2006 Stefan Schweizer <genstef@gentoo.org>
18 // Copyright (C) 2006-2015 Albert Astals Cid <aacid@kde.org>
19 // Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
20 // Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
21 // Copyright (C) 2007 Koji Otani <sho@bbr.jp>
22 // Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
23 // Copyright (C) 2009-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
24 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
25 // Copyright (C) 2009, 2014, 2015 William Bader <williambader@hotmail.com>
26 // Copyright (C) 2010 Patrick Spendrin <ps_ml@gmx.de>
27 // Copyright (C) 2010 Brian Cameron <brian.cameron@oracle.com>
28 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
29 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
30 // Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
31 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
32 // Copyright (C) 2011, 2012 Adrian Johnson <ajohnson@redneon.com>
33 // Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
34 // Copyright (C) 2013 Li Junling <lijunling@sina.com>
35 // Copyright (C) 2014 Ed Porras <ed@moto-research.com>
36 // Copyright (C) 2014 Richard PALO <richard@netbsd.org>
37 // Copyright (C) 2015 Tamas Szekeres <szekerest@gmail.com>
39 // To see a description of the changes please see the Changelog file that
40 // came with your tarball or type make ChangeLog if you are building from git
42 //========================================================================
46 #ifdef USE_GCC_PRAGMAS
47 #pragma implementation
52 #include "goo/gfile.h"
53 #include "GlobalParams.h"
61 #include "FontEncodingTables.h"
62 #include "fofi/FoFiTrueType.h"
63 #include "splash/SplashBitmap.h"
64 #include "splash/SplashGlyphBitmap.h"
65 #include "splash/SplashPattern.h"
66 #include "splash/SplashScreen.h"
67 #include "splash/SplashPath.h"
68 #include "splash/SplashState.h"
69 #include "splash/SplashErrorCodes.h"
70 #include "splash/SplashFontEngine.h"
71 #include "splash/SplashFont.h"
72 #include "splash/SplashFontFile.h"
73 #include "splash/SplashFontFileID.h"
74 #include "splash/Splash.h"
75 #include "SplashOutputDev.h"
79 #if (__VMS_VER < 70000000)
80 extern "C" int unlink(char *filename
);
86 #define isfinite(x) _finite(x)
92 #define isfinite(x) finite(x)
96 static inline void convertGfxColor(SplashColorPtr dest
,
97 SplashColorMode colorMode
,
98 GfxColorSpace
*colorSpace
,
109 color
[0] = color
[1] = color
[2] = 0;
114 case splashModeMono1
:
115 case splashModeMono8
:
116 colorSpace
->getGray(src
, &gray
);
117 color
[0] = colToByte(gray
);
119 case splashModeXBGR8
:
123 colorSpace
->getRGB(src
, &rgb
);
124 color
[0] = colToByte(rgb
.r
);
125 color
[1] = colToByte(rgb
.g
);
126 color
[2] = colToByte(rgb
.b
);
129 case splashModeCMYK8
:
130 colorSpace
->getCMYK(src
, &cmyk
);
131 color
[0] = colToByte(cmyk
.c
);
132 color
[1] = colToByte(cmyk
.m
);
133 color
[2] = colToByte(cmyk
.y
);
134 color
[3] = colToByte(cmyk
.k
);
136 case splashModeDeviceN8
:
137 colorSpace
->getDeviceN(src
, &deviceN
);
138 for (int i
= 0; i
< SPOT_NCOMPS
+ 4; i
++)
139 color
[i
] = colToByte(deviceN
.c
[i
]);
143 splashColorCopy(dest
, color
);
146 // Copy a color according to the color mode.
147 // Use convertGfxShortColor() below when the destination is a bitmap
148 // to avoid overwriting cells.
149 // Calling this in SplashGouraudPattern::getParameterizedColor() fixes bug 90570.
150 // Use convertGfxColor() above when the destination is an array of SPOT_NCOMPS+4 bytes,
151 // to ensure that everything is initialized.
153 static inline void convertGfxShortColor(SplashColorPtr dest
,
154 SplashColorMode colorMode
,
155 GfxColorSpace
*colorSpace
,
158 case splashModeMono1
:
159 case splashModeMono8
:
162 colorSpace
->getGray(src
, &gray
);
163 dest
[0] = colToByte(gray
);
166 case splashModeXBGR8
:
172 colorSpace
->getRGB(src
, &rgb
);
173 dest
[0] = colToByte(rgb
.r
);
174 dest
[1] = colToByte(rgb
.g
);
175 dest
[2] = colToByte(rgb
.b
);
179 case splashModeCMYK8
:
182 colorSpace
->getCMYK(src
, &cmyk
);
183 dest
[0] = colToByte(cmyk
.c
);
184 dest
[1] = colToByte(cmyk
.m
);
185 dest
[2] = colToByte(cmyk
.y
);
186 dest
[3] = colToByte(cmyk
.k
);
189 case splashModeDeviceN8
:
192 colorSpace
->getDeviceN(src
, &deviceN
);
193 for (int i
= 0; i
< SPOT_NCOMPS
+ 4; i
++)
194 dest
[i
] = colToByte(deviceN
.c
[i
]);
201 //------------------------------------------------------------------------
202 // SplashGouraudPattern
203 //------------------------------------------------------------------------
204 SplashGouraudPattern::SplashGouraudPattern(GBool bDirectColorTranslationA
,
205 GfxState
*stateA
, GfxGouraudTriangleShading
*shadingA
, SplashColorMode modeA
) {
206 SplashColor defaultColor
;
211 bDirectColorTranslation
= bDirectColorTranslationA
;
212 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
213 convertGfxColor(defaultColor
, mode
, shadingA
->getColorSpace(), &srcColor
);
214 gfxMode
= shadingA
->getColorSpace()->getMode();
217 SplashGouraudPattern::~SplashGouraudPattern() {
220 void SplashGouraudPattern::getParameterizedColor(double colorinterp
, SplashColorMode mode
, SplashColorPtr dest
) {
222 GfxColorSpace
* srcColorSpace
= shading
->getColorSpace();
225 if (mode
== splashModeCMYK8
)
227 else if (mode
== splashModeDeviceN8
)
228 colorComps
=4 + SPOT_NCOMPS
;
231 shading
->getParameterizedColor(colorinterp
, &src
);
233 if (bDirectColorTranslation
) {
234 for (int m
= 0; m
< colorComps
; ++m
)
235 dest
[m
] = colToByte(src
.c
[m
]);
237 convertGfxShortColor(dest
, mode
, srcColorSpace
, &src
);
241 //------------------------------------------------------------------------
242 // SplashUnivariatePattern
243 //------------------------------------------------------------------------
245 SplashUnivariatePattern::SplashUnivariatePattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxUnivariateShading
*shadingA
) {
247 double xMin
, yMin
, xMax
, yMax
;
251 colorMode
= colorModeA
;
256 // get the function domain
257 t0
= shading
->getDomain0();
258 t1
= shading
->getDomain1();
261 stateA
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
262 shadingA
->setupCache(&ctm
, xMin
, yMin
, xMax
, yMax
);
263 gfxMode
= shadingA
->getColorSpace()->getMode();
266 SplashUnivariatePattern::~SplashUnivariatePattern() {
269 GBool
SplashUnivariatePattern::getColor(int x
, int y
, SplashColorPtr c
) {
273 ictm
.transform(x
, y
, &xc
, &yc
);
274 if (! getParameter (xc
, yc
, &t
))
277 shading
->getColor(t
, &gfxColor
);
278 convertGfxColor(c
, colorMode
, shading
->getColorSpace(), &gfxColor
);
282 GBool
SplashUnivariatePattern::testPosition(int x
, int y
) {
285 ictm
.transform(x
, y
, &xc
, &yc
);
286 if (! getParameter (xc
, yc
, &t
))
288 return (t0
< t1
) ? (t
> t0
&& t
< t1
) : (t
> t1
&& t
< t0
);
292 //------------------------------------------------------------------------
293 // SplashRadialPattern
294 //------------------------------------------------------------------------
295 #define RADIAL_EPSILON (1. / 1024 / 1024)
297 SplashRadialPattern::SplashRadialPattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxRadialShading
*shadingA
):
298 SplashUnivariatePattern(colorModeA
, stateA
, shadingA
)
300 SplashColor defaultColor
;
303 shadingA
->getCoords(&x0
, &y0
, &r0
, &dx
, &dy
, &dr
);
307 a
= dx
*dx
+ dy
*dy
- dr
*dr
;
308 if (fabs(a
) > RADIAL_EPSILON
)
310 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
311 convertGfxColor(defaultColor
, colorModeA
, shadingA
->getColorSpace(), &srcColor
);
314 SplashRadialPattern::~SplashRadialPattern() {
317 GBool
SplashRadialPattern::getParameter(double xs
, double ys
, double *t
) {
320 // We want to solve this system of equations:
322 // 1. (x - xc(s))^2 + (y -yc(s))^2 = rc(s)^2
323 // 2. xc(s) = x0 + s * (x1 - xo)
324 // 3. yc(s) = y0 + s * (y1 - yo)
325 // 4. rc(s) = r0 + s * (r1 - ro)
327 // To simplify the system a little, we translate
328 // our coordinates to have the origin in (x0,y0)
333 // Then we have to solve the equation:
334 // A*s^2 - 2*B*s + C = 0
336 // A = dx^2 + dy^2 - dr^2
337 // B = xs*dx + ys*dy + r0*dr
338 // C = xs^2 + ys^2 - r0^2
340 b
= xs
*dx
+ ys
*dy
+ r0
*dr
;
341 c
= xs
*xs
+ ys
*ys
- r0
*r0
;
343 if (fabs(a
) <= RADIAL_EPSILON
) {
344 // A is 0, thus the equation simplifies to:
346 // If B is 0, we can either have no solution or an indeterminate
347 // equation, thus we behave as if we had an invalid solution
348 if (fabs(b
) <= RADIAL_EPSILON
)
351 s0
= s1
= 0.5 * c
/ b
;
363 // If A < 0, one of the two solutions will have negative radius,
364 // thus it will be ignored. Otherwise we know that s1 <= s0
365 // (because d >=0 implies b - d <= b + d), so if both are valid it
366 // will be the true solution.
371 if (r0
+ s0
* dr
>= 0) {
372 if (0 <= s0
&& s0
<= 1) {
375 } else if (s0
< 0 && shading
->getExtend0()) {
378 } else if (s0
> 1 && shading
->getExtend1()) {
384 if (r0
+ s1
* dr
>= 0) {
385 if (0 <= s1
&& s1
<= 1) {
388 } else if (s1
< 0 && shading
->getExtend0()) {
391 } else if (s1
> 1 && shading
->getExtend1()) {
400 #undef RADIAL_EPSILON
402 //------------------------------------------------------------------------
403 // SplashAxialPattern
404 //------------------------------------------------------------------------
406 SplashAxialPattern::SplashAxialPattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxAxialShading
*shadingA
):
407 SplashUnivariatePattern(colorModeA
, stateA
, shadingA
)
409 SplashColor defaultColor
;
412 shadingA
->getCoords(&x0
, &y0
, &x1
, &y1
);
415 mul
= 1 / (dx
* dx
+ dy
* dy
);
416 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
417 convertGfxColor(defaultColor
, colorModeA
, shadingA
->getColorSpace(), &srcColor
);
420 SplashAxialPattern::~SplashAxialPattern() {
423 GBool
SplashAxialPattern::getParameter(double xc
, double yc
, double *t
) {
429 s
= (xc
* dx
+ yc
* dy
) * mul
;
430 if (0 <= s
&& s
<= 1) {
432 } else if (s
< 0 && shading
->getExtend0()) {
434 } else if (s
> 1 && shading
->getExtend1()) {
443 //------------------------------------------------------------------------
444 // Type 3 font cache size parameters
445 #define type3FontCacheAssoc 8
446 #define type3FontCacheMaxSets 8
447 #define type3FontCacheSize (128*1024)
449 //------------------------------------------------------------------------
450 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
451 static inline Guchar
div255(int x
) {
452 return (Guchar
)((x
+ (x
>> 8) + 0x80) >> 8);
457 #include "GfxState_helpers.h"
459 //-------------------------------------------------------------------------
460 // helper for Blend functions (convert CMYK to RGB, do blend, convert back)
461 //-------------------------------------------------------------------------
463 // based in GfxState.cc
465 static void cmykToRGB(SplashColorPtr cmyk
, SplashColor rgb
) {
466 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
468 c
= colToDbl(byteToCol(cmyk
[0]));
469 m
= colToDbl(byteToCol(cmyk
[1]));
470 y
= colToDbl(byteToCol(cmyk
[2]));
471 k
= colToDbl(byteToCol(cmyk
[3]));
476 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
477 rgb
[0] = colToByte(clip01(dblToCol(r
)));
478 rgb
[1] = colToByte(clip01(dblToCol(g
)));
479 rgb
[2] = colToByte(clip01(dblToCol(b
)));
482 static void rgbToCMYK(SplashColor rgb
, SplashColorPtr cmyk
) {
483 GfxColorComp c
, m
, y
, k
;
485 c
= clip01(gfxColorComp1
- byteToCol(rgb
[0]));
486 m
= clip01(gfxColorComp1
- byteToCol(rgb
[1]));
487 y
= clip01(gfxColorComp1
- byteToCol(rgb
[2]));
495 cmyk
[0] = colToByte(c
- k
);
496 cmyk
[1] = colToByte(m
- k
);
497 cmyk
[2] = colToByte(y
- k
);
498 cmyk
[3] = colToByte(k
);
503 //------------------------------------------------------------------------
505 //------------------------------------------------------------------------
507 static void splashOutBlendMultiply(SplashColorPtr src
, SplashColorPtr dest
,
508 SplashColorPtr blend
, SplashColorMode cm
) {
512 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
513 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
514 dest
[i
] = 255 - dest
[i
];
515 src
[i
] = 255 - src
[i
];
520 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
521 blend
[i
] = (dest
[i
] * src
[i
]) / 255;
525 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
526 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
527 dest
[i
] = 255 - dest
[i
];
528 src
[i
] = 255 - src
[i
];
529 blend
[i
] = 255 - blend
[i
];
535 static void splashOutBlendScreen(SplashColorPtr src
, SplashColorPtr dest
,
536 SplashColorPtr blend
, SplashColorMode cm
) {
540 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
541 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
542 dest
[i
] = 255 - dest
[i
];
543 src
[i
] = 255 - src
[i
];
548 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
549 blend
[i
] = dest
[i
] + src
[i
] - (dest
[i
] * src
[i
]) / 255;
553 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
554 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
555 dest
[i
] = 255 - dest
[i
];
556 src
[i
] = 255 - src
[i
];
557 blend
[i
] = 255 - blend
[i
];
563 static void splashOutBlendOverlay(SplashColorPtr src
, SplashColorPtr dest
,
564 SplashColorPtr blend
, SplashColorMode cm
) {
568 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
569 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
570 dest
[i
] = 255 - dest
[i
];
571 src
[i
] = 255 - src
[i
];
576 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
577 blend
[i
] = dest
[i
] < 0x80
578 ? (src
[i
] * 2 * dest
[i
]) / 255
579 : 255 - 2 * ((255 - src
[i
]) * (255 - dest
[i
])) / 255;
583 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
584 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
585 dest
[i
] = 255 - dest
[i
];
586 src
[i
] = 255 - src
[i
];
587 blend
[i
] = 255 - blend
[i
];
593 static void splashOutBlendDarken(SplashColorPtr src
, SplashColorPtr dest
,
594 SplashColorPtr blend
, SplashColorMode cm
) {
598 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
599 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
600 dest
[i
] = 255 - dest
[i
];
601 src
[i
] = 255 - src
[i
];
606 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
607 blend
[i
] = dest
[i
] < src
[i
] ? dest
[i
] : src
[i
];
611 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
612 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
613 dest
[i
] = 255 - dest
[i
];
614 src
[i
] = 255 - src
[i
];
615 blend
[i
] = 255 - blend
[i
];
621 static void splashOutBlendLighten(SplashColorPtr src
, SplashColorPtr dest
,
622 SplashColorPtr blend
, SplashColorMode cm
) {
626 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
627 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
628 dest
[i
] = 255 - dest
[i
];
629 src
[i
] = 255 - src
[i
];
634 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
635 blend
[i
] = dest
[i
] > src
[i
] ? dest
[i
] : src
[i
];
639 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
640 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
641 dest
[i
] = 255 - dest
[i
];
642 src
[i
] = 255 - src
[i
];
643 blend
[i
] = 255 - blend
[i
];
649 static void splashOutBlendColorDodge(SplashColorPtr src
, SplashColorPtr dest
,
650 SplashColorPtr blend
,
651 SplashColorMode cm
) {
655 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
656 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
657 dest
[i
] = 255 - dest
[i
];
658 src
[i
] = 255 - src
[i
];
663 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
667 x
= (dest
[i
] * 255) / (255 - src
[i
]);
668 blend
[i
] = x
<= 255 ? x
: 255;
673 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
674 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
675 dest
[i
] = 255 - dest
[i
];
676 src
[i
] = 255 - src
[i
];
677 blend
[i
] = 255 - blend
[i
];
683 static void splashOutBlendColorBurn(SplashColorPtr src
, SplashColorPtr dest
,
684 SplashColorPtr blend
, SplashColorMode cm
) {
688 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
689 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
690 dest
[i
] = 255 - dest
[i
];
691 src
[i
] = 255 - src
[i
];
696 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
700 x
= ((255 - dest
[i
]) * 255) / src
[i
];
701 blend
[i
] = x
<= 255 ? 255 - x
: 0;
706 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
707 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
708 dest
[i
] = 255 - dest
[i
];
709 src
[i
] = 255 - src
[i
];
710 blend
[i
] = 255 - blend
[i
];
716 static void splashOutBlendHardLight(SplashColorPtr src
, SplashColorPtr dest
,
717 SplashColorPtr blend
, SplashColorMode cm
) {
721 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
722 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
723 dest
[i
] = 255 - dest
[i
];
724 src
[i
] = 255 - src
[i
];
729 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
730 blend
[i
] = src
[i
] < 0x80
731 ? (dest
[i
] * 2 * src
[i
]) / 255
732 : 255 - 2 * ((255 - dest
[i
]) * (255 - src
[i
])) / 255;
736 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
737 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
738 dest
[i
] = 255 - dest
[i
];
739 src
[i
] = 255 - src
[i
];
740 blend
[i
] = 255 - blend
[i
];
746 static void splashOutBlendSoftLight(SplashColorPtr src
, SplashColorPtr dest
,
747 SplashColorPtr blend
, SplashColorMode cm
) {
751 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
752 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
753 dest
[i
] = 255 - dest
[i
];
754 src
[i
] = 255 - src
[i
];
759 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
761 blend
[i
] = dest
[i
] - (255 - 2 * src
[i
]) * dest
[i
] * (255 - dest
[i
]) / (255 * 255);
763 if (dest
[i
] < 0x40) {
764 x
= (((((16 * dest
[i
] - 12 * 255) * dest
[i
]) / 255) + 4 * 255) * dest
[i
]) / 255;
766 x
= (int)sqrt(255.0 * dest
[i
]);
768 blend
[i
] = dest
[i
] + (2 * src
[i
] - 255) * (x
- dest
[i
]) / 255;
773 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
774 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
775 dest
[i
] = 255 - dest
[i
];
776 src
[i
] = 255 - src
[i
];
777 blend
[i
] = 255 - blend
[i
];
783 static void splashOutBlendDifference(SplashColorPtr src
, SplashColorPtr dest
,
784 SplashColorPtr blend
,
785 SplashColorMode cm
) {
789 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
790 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
791 dest
[i
] = 255 - dest
[i
];
792 src
[i
] = 255 - src
[i
];
797 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
798 blend
[i
] = dest
[i
] < src
[i
] ? src
[i
] - dest
[i
] : dest
[i
] - src
[i
];
802 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
803 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
804 dest
[i
] = 255 - dest
[i
];
805 src
[i
] = 255 - src
[i
];
806 blend
[i
] = 255 - blend
[i
];
809 if (cm
== splashModeDeviceN8
) {
810 for (i
= 4; i
< splashColorModeNComps
[cm
]; ++i
) {
811 if (dest
[i
] == 0 && src
[i
] == 0)
818 static void splashOutBlendExclusion(SplashColorPtr src
, SplashColorPtr dest
,
819 SplashColorPtr blend
, SplashColorMode cm
) {
823 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
824 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
825 dest
[i
] = 255 - dest
[i
];
826 src
[i
] = 255 - src
[i
];
831 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
832 blend
[i
] = dest
[i
] + src
[i
] - (2 * dest
[i
] * src
[i
]) / 255;
836 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
837 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
838 dest
[i
] = 255 - dest
[i
];
839 src
[i
] = 255 - src
[i
];
840 blend
[i
] = 255 - blend
[i
];
843 if (cm
== splashModeDeviceN8
) {
844 for (i
= 4; i
< splashColorModeNComps
[cm
]; ++i
) {
845 if (dest
[i
] == 0 && src
[i
] == 0)
852 static int getLum(int r
, int g
, int b
) {
853 return (int)(0.3 * r
+ 0.59 * g
+ 0.11 * b
);
856 static int getSat(int r
, int g
, int b
) {
862 } else if (g
> rgbMax
) {
867 } else if (b
> rgbMax
) {
870 return rgbMax
- rgbMin
;
873 static void clipColor(int rIn
, int gIn
, int bIn
,
874 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
875 int lum
, rgbMin
, rgbMax
;
877 lum
= getLum(rIn
, gIn
, bIn
);
878 rgbMin
= rgbMax
= rIn
;
881 } else if (gIn
> rgbMax
) {
886 } else if (bIn
> rgbMax
) {
890 *rOut
= (Guchar
)(lum
+ ((rIn
- lum
) * lum
) / (lum
- rgbMin
));
891 *gOut
= (Guchar
)(lum
+ ((gIn
- lum
) * lum
) / (lum
- rgbMin
));
892 *bOut
= (Guchar
)(lum
+ ((bIn
- lum
) * lum
) / (lum
- rgbMin
));
893 } else if (rgbMax
> 255) {
894 *rOut
= (Guchar
)(lum
+ ((rIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
895 *gOut
= (Guchar
)(lum
+ ((gIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
896 *bOut
= (Guchar
)(lum
+ ((bIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
904 static void setLum(Guchar rIn
, Guchar gIn
, Guchar bIn
, int lum
,
905 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
908 d
= lum
- getLum(rIn
, gIn
, bIn
);
909 clipColor(rIn
+ d
, gIn
+ d
, bIn
+ d
, rOut
, gOut
, bOut
);
912 static void setSat(Guchar rIn
, Guchar gIn
, Guchar bIn
, int sat
,
913 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
914 int rgbMin
, rgbMid
, rgbMax
;
915 Guchar
*minOut
, *midOut
, *maxOut
;
918 rgbMin
= rIn
; minOut
= rOut
;
919 rgbMid
= gIn
; midOut
= gOut
;
921 rgbMin
= gIn
; minOut
= gOut
;
922 rgbMid
= rIn
; midOut
= rOut
;
925 rgbMax
= bIn
; maxOut
= bOut
;
926 } else if (bIn
> rgbMin
) {
927 rgbMax
= rgbMid
; maxOut
= midOut
;
928 rgbMid
= bIn
; midOut
= bOut
;
930 rgbMax
= rgbMid
; maxOut
= midOut
;
931 rgbMid
= rgbMin
; midOut
= minOut
;
932 rgbMin
= bIn
; minOut
= bOut
;
934 if (rgbMax
> rgbMin
) {
935 *midOut
= (Guchar
)((rgbMid
- rgbMin
) * sat
) / (rgbMax
- rgbMin
);
936 *maxOut
= (Guchar
)sat
;
938 *midOut
= *maxOut
= 0;
943 static void splashOutBlendHue(SplashColorPtr src
, SplashColorPtr dest
,
944 SplashColorPtr blend
, SplashColorMode cm
) {
949 SplashColor src2
, dest2
;
953 case splashModeMono1
:
954 case splashModeMono8
:
957 case splashModeXBGR8
:
961 setSat(src
[0], src
[1], src
[2], getSat(dest
[0], dest
[1], dest
[2]),
963 setLum(r0
, g0
, b0
, getLum(dest
[0], dest
[1], dest
[2]),
964 &blend
[0], &blend
[1], &blend
[2]);
967 case splashModeCMYK8
:
968 case splashModeDeviceN8
:
969 for (i
= 0; i
< 4; i
++) {
970 // convert to additive
971 src2
[i
] = 0xff - src
[i
];
972 dest2
[i
] = 0xff - dest
[i
];
974 // NB: inputs have already been converted to additive mode
975 setSat(src2
[0], src2
[1], src2
[2], getSat(dest2
[0], dest2
[1], dest2
[2]),
977 setLum(r0
, g0
, b0
, getLum(dest2
[0], dest2
[1], dest2
[2]),
983 for (i
= 0; i
< 4; i
++) {
984 // convert back to subtractive
985 blend
[i
] = 0xff - blend
[i
];
992 static void splashOutBlendSaturation(SplashColorPtr src
, SplashColorPtr dest
,
993 SplashColorPtr blend
,
994 SplashColorMode cm
) {
999 SplashColor src2
, dest2
;
1003 case splashModeMono1
:
1004 case splashModeMono8
:
1007 case splashModeXBGR8
:
1009 case splashModeRGB8
:
1010 case splashModeBGR8
:
1011 setSat(dest
[0], dest
[1], dest
[2], getSat(src
[0], src
[1], src
[2]),
1013 setLum(r0
, g0
, b0
, getLum(dest
[0], dest
[1], dest
[2]),
1014 &blend
[0], &blend
[1], &blend
[2]);
1017 case splashModeCMYK8
:
1018 case splashModeDeviceN8
:
1019 for (i
= 0; i
< 4; i
++) {
1020 // convert to additive
1021 src2
[i
] = 0xff - src
[i
];
1022 dest2
[i
] = 0xff - dest
[i
];
1024 setSat(dest2
[0], dest2
[1], dest2
[2], getSat(src2
[0], src2
[1], src2
[2]),
1026 setLum(r0
, g0
, b0
, getLum(dest2
[0], dest2
[1], dest2
[2]),
1031 blend
[3] = dest2
[3];
1032 for (i
= 0; i
< 4; i
++) {
1033 // convert back to subtractive
1034 blend
[i
] = 0xff - blend
[i
];
1041 static void splashOutBlendColor(SplashColorPtr src
, SplashColorPtr dest
,
1042 SplashColorPtr blend
, SplashColorMode cm
) {
1046 SplashColor src2
, dest2
;
1050 case splashModeMono1
:
1051 case splashModeMono8
:
1054 case splashModeXBGR8
:
1056 case splashModeRGB8
:
1057 case splashModeBGR8
:
1058 setLum(src
[0], src
[1], src
[2], getLum(dest
[0], dest
[1], dest
[2]),
1059 &blend
[0], &blend
[1], &blend
[2]);
1062 case splashModeCMYK8
:
1063 case splashModeDeviceN8
:
1064 for (i
= 0; i
< 4; i
++) {
1065 // convert to additive
1066 src2
[i
] = 0xff - src
[i
];
1067 dest2
[i
] = 0xff - dest
[i
];
1069 setLum(src2
[0], src2
[1], src2
[2], getLum(dest2
[0], dest2
[1], dest2
[2]),
1074 blend
[3] = dest2
[3];
1075 for (i
= 0; i
< 4; i
++) {
1076 // convert back to subtractive
1077 blend
[i
] = 0xff - blend
[i
];
1084 static void splashOutBlendLuminosity(SplashColorPtr src
, SplashColorPtr dest
,
1085 SplashColorPtr blend
,
1086 SplashColorMode cm
) {
1090 SplashColor src2
, dest2
;
1094 case splashModeMono1
:
1095 case splashModeMono8
:
1098 case splashModeXBGR8
:
1100 case splashModeRGB8
:
1101 case splashModeBGR8
:
1102 setLum(dest
[0], dest
[1], dest
[2], getLum(src
[0], src
[1], src
[2]),
1103 &blend
[0], &blend
[1], &blend
[2]);
1106 case splashModeCMYK8
:
1107 case splashModeDeviceN8
:
1108 for (i
= 0; i
< 4; i
++) {
1109 // convert to additive
1110 src2
[i
] = 0xff - src
[i
];
1111 dest2
[i
] = 0xff - dest
[i
];
1113 setLum(dest2
[0], dest2
[1], dest2
[2], getLum(src2
[0], src2
[1], src2
[2]),
1119 for (i
= 0; i
< 4; i
++) {
1120 // convert back to subtractive
1121 blend
[i
] = 0xff - blend
[i
];
1128 // NB: This must match the GfxBlendMode enum defined in GfxState.h.
1129 static const SplashBlendFunc splashOutBlendFuncs
[] = {
1131 &splashOutBlendMultiply
,
1132 &splashOutBlendScreen
,
1133 &splashOutBlendOverlay
,
1134 &splashOutBlendDarken
,
1135 &splashOutBlendLighten
,
1136 &splashOutBlendColorDodge
,
1137 &splashOutBlendColorBurn
,
1138 &splashOutBlendHardLight
,
1139 &splashOutBlendSoftLight
,
1140 &splashOutBlendDifference
,
1141 &splashOutBlendExclusion
,
1143 &splashOutBlendSaturation
,
1144 &splashOutBlendColor
,
1145 &splashOutBlendLuminosity
1148 //------------------------------------------------------------------------
1149 // SplashOutFontFileID
1150 //------------------------------------------------------------------------
1152 class SplashOutFontFileID
: public SplashFontFileID
{
1155 SplashOutFontFileID(Ref
*rA
) { r
= *rA
; }
1157 ~SplashOutFontFileID() {}
1159 GBool
matches(SplashFontFileID
*id
) {
1160 return ((SplashOutFontFileID
*)id
)->r
.num
== r
.num
&&
1161 ((SplashOutFontFileID
*)id
)->r
.gen
== r
.gen
;
1169 //------------------------------------------------------------------------
1171 //------------------------------------------------------------------------
1173 struct T3FontCacheTag
{
1175 Gushort mru
; // valid bit (0x8000) and MRU index
1181 T3FontCache(Ref
*fontID
, double m11A
, double m12A
,
1182 double m21A
, double m22A
,
1183 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
1184 GBool aa
, GBool validBBoxA
);
1186 GBool
matches(Ref
*idA
, double m11A
, double m12A
,
1187 double m21A
, double m22A
)
1188 { return fontID
.num
== idA
->num
&& fontID
.gen
== idA
->gen
&&
1189 m11
== m11A
&& m12
== m12A
&& m21
== m21A
&& m22
== m22A
; }
1191 Ref fontID
; // PDF font ID
1192 double m11
, m12
, m21
, m22
; // transform matrix
1193 int glyphX
, glyphY
; // pixel offset of glyph bitmaps
1194 int glyphW
, glyphH
; // size of glyph bitmaps, in pixels
1195 GBool validBBox
; // false if the bbox was [0 0 0 0]
1196 int glyphSize
; // size of glyph bitmaps, in bytes
1197 int cacheSets
; // number of sets in cache
1198 int cacheAssoc
; // cache associativity (glyphs per set)
1199 Guchar
*cacheData
; // glyph pixmap cache
1200 T3FontCacheTag
*cacheTags
; // cache tags, i.e., char codes
1203 T3FontCache::T3FontCache(Ref
*fontIDA
, double m11A
, double m12A
,
1204 double m21A
, double m22A
,
1205 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
1206 GBool validBBoxA
, GBool aa
) {
1218 validBBox
= validBBoxA
;
1219 // sanity check for excessively large glyphs (which most likely
1220 // indicate an incorrect BBox)
1221 i
= glyphW
* glyphH
;
1222 if (i
> 100000 || glyphW
> INT_MAX
/ glyphH
|| glyphW
<= 0 || glyphH
<= 0) {
1223 glyphW
= glyphH
= 100;
1227 glyphSize
= glyphW
* glyphH
;
1229 glyphSize
= ((glyphW
+ 7) >> 3) * glyphH
;
1231 cacheAssoc
= type3FontCacheAssoc
;
1232 for (cacheSets
= type3FontCacheMaxSets
;
1234 cacheSets
* cacheAssoc
* glyphSize
> type3FontCacheSize
;
1236 if (glyphSize
< 10485760 / cacheAssoc
/ cacheSets
) {
1237 cacheData
= (Guchar
*)gmallocn_checkoverflow(cacheSets
* cacheAssoc
, glyphSize
);
1239 error(errSyntaxWarning
, -1, "Not creating cacheData for T3FontCache, it asked for too much memory.\n"
1240 " This could teoretically result in wrong rendering,\n"
1241 " but most probably the document is bogus.\n"
1242 " Please report a bug if you think the rendering may be wrong because of this.");
1245 if (cacheData
!= NULL
)
1247 cacheTags
= (T3FontCacheTag
*)gmallocn(cacheSets
* cacheAssoc
,
1248 sizeof(T3FontCacheTag
));
1249 for (i
= 0; i
< cacheSets
* cacheAssoc
; ++i
) {
1250 cacheTags
[i
].mru
= i
& (cacheAssoc
- 1);
1259 T3FontCache::~T3FontCache() {
1264 struct T3GlyphStack
{
1265 Gushort code
; // character code
1268 T3FontCache
*cache
; // font cache for the current font
1269 T3FontCacheTag
*cacheTag
; // pointer to cache tag for the glyph
1270 Guchar
*cacheData
; // pointer to cache data for the glyph
1273 SplashBitmap
*origBitmap
;
1275 double origCTM4
, origCTM5
;
1277 T3GlyphStack
*next
; // next object on stack
1280 //------------------------------------------------------------------------
1281 // SplashTransparencyGroup
1282 //------------------------------------------------------------------------
1284 struct SplashTransparencyGroup
{
1285 int tx
, ty
; // translation coordinates
1286 SplashBitmap
*tBitmap
; // bitmap for transparency group
1287 SplashBitmap
*softmask
; // bitmap for softmasks
1288 GfxColorSpace
*blendingColorSpace
;
1291 //----- for knockout
1292 SplashBitmap
*shape
;
1294 SplashCoord knockoutOpacity
;
1298 SplashBitmap
*origBitmap
;
1301 SplashTransparencyGroup
*next
;
1304 //------------------------------------------------------------------------
1306 //------------------------------------------------------------------------
1308 SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA
,
1310 GBool reverseVideoA
,
1311 SplashColorPtr paperColorA
,
1312 GBool bitmapTopDownA
,
1313 SplashThinLineMode thinLineMode
,
1314 GBool overprintPreviewA
) {
1315 colorMode
= colorModeA
;
1316 bitmapRowPad
= bitmapRowPadA
;
1317 bitmapTopDown
= bitmapTopDownA
;
1318 bitmapUpsideDown
= gFalse
;
1319 fontAntialias
= gTrue
;
1320 vectorAntialias
= gTrue
;
1321 overprintPreview
= overprintPreviewA
;
1322 enableFreeTypeHinting
= gFalse
;
1323 enableSlightHinting
= gFalse
;
1324 setupScreenParams(72.0, 72.0);
1325 reverseVideo
= reverseVideoA
;
1326 if (paperColorA
!= NULL
) {
1327 splashColorCopy(paperColor
, paperColorA
);
1329 splashClearColor(paperColor
);
1331 skipHorizText
= gFalse
;
1332 skipRotatedText
= gFalse
;
1333 keepAlphaChannel
= paperColorA
== NULL
;
1337 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
,
1338 colorMode
!= splashModeMono1
, bitmapTopDown
);
1339 splash
= new Splash(bitmap
, vectorAntialias
, &screenParams
);
1340 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
1341 splash
->setThinLineMode(thinLineMode
);
1342 splash
->clear(paperColor
, 0);
1347 t3GlyphStack
= NULL
;
1350 needFontUpdate
= gFalse
;
1351 textClipPath
= NULL
;
1352 transpGroupStack
= NULL
;
1357 void SplashOutputDev::setupScreenParams(double hDPI
, double vDPI
) {
1358 screenParams
.size
= globalParams
->getScreenSize();
1359 screenParams
.dotRadius
= globalParams
->getScreenDotRadius();
1360 screenParams
.gamma
= (SplashCoord
)globalParams
->getScreenGamma();
1361 screenParams
.blackThreshold
=
1362 (SplashCoord
)globalParams
->getScreenBlackThreshold();
1363 screenParams
.whiteThreshold
=
1364 (SplashCoord
)globalParams
->getScreenWhiteThreshold();
1365 switch (globalParams
->getScreenType()) {
1366 case screenDispersed
:
1367 screenParams
.type
= splashScreenDispersed
;
1368 if (screenParams
.size
< 0) {
1369 screenParams
.size
= 4;
1372 case screenClustered
:
1373 screenParams
.type
= splashScreenClustered
;
1374 if (screenParams
.size
< 0) {
1375 screenParams
.size
= 10;
1378 case screenStochasticClustered
:
1379 screenParams
.type
= splashScreenStochasticClustered
;
1380 if (screenParams
.size
< 0) {
1381 screenParams
.size
= 64;
1383 if (screenParams
.dotRadius
< 0) {
1384 screenParams
.dotRadius
= 2;
1389 // use clustered dithering for resolution >= 300 dpi
1390 // (compare to 299.9 to avoid floating point issues)
1391 if (hDPI
> 299.9 && vDPI
> 299.9) {
1392 screenParams
.type
= splashScreenStochasticClustered
;
1393 if (screenParams
.size
< 0) {
1394 screenParams
.size
= 64;
1396 if (screenParams
.dotRadius
< 0) {
1397 screenParams
.dotRadius
= 2;
1400 screenParams
.type
= splashScreenDispersed
;
1401 if (screenParams
.size
< 0) {
1402 screenParams
.size
= 4;
1408 SplashOutputDev::~SplashOutputDev() {
1411 for (i
= 0; i
< nT3Fonts
; ++i
) {
1412 delete t3FontCache
[i
];
1425 void SplashOutputDev::startDoc(PDFDoc
*docA
) {
1432 fontEngine
= new SplashFontEngine(
1434 globalParams
->getEnableT1lib(),
1436 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
1437 globalParams
->getEnableFreeType(),
1438 enableFreeTypeHinting
,
1439 enableSlightHinting
,
1441 getFontAntialias() &&
1442 colorMode
!= splashModeMono1
);
1443 for (i
= 0; i
< nT3Fonts
; ++i
) {
1444 delete t3FontCache
[i
];
1449 void SplashOutputDev::startPage(int pageNum
, GfxState
*state
, XRef
*xrefA
) {
1457 setupScreenParams(state
->getHDPI(), state
->getVDPI());
1458 w
= (int)(state
->getPageWidth() + 0.5);
1462 h
= (int)(state
->getPageHeight() + 0.5);
1469 SplashThinLineMode thinLineMode
= splashThinLineDefault
;
1471 thinLineMode
= splash
->getThinLineMode();
1475 if (!bitmap
|| w
!= bitmap
->getWidth() || h
!= bitmap
->getHeight()) {
1480 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
,
1481 colorMode
!= splashModeMono1
, bitmapTopDown
);
1482 if (!bitmap
->getDataPtr()) {
1485 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
,
1486 colorMode
!= splashModeMono1
, bitmapTopDown
);
1489 splash
= new Splash(bitmap
, vectorAntialias
, &screenParams
);
1490 splash
->setThinLineMode(thinLineMode
);
1491 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
1493 ctm
= state
->getCTM();
1494 mat
[0] = (SplashCoord
)ctm
[0];
1495 mat
[1] = (SplashCoord
)ctm
[1];
1496 mat
[2] = (SplashCoord
)ctm
[2];
1497 mat
[3] = (SplashCoord
)ctm
[3];
1498 mat
[4] = (SplashCoord
)ctm
[4];
1499 mat
[5] = (SplashCoord
)ctm
[5];
1500 splash
->setMatrix(mat
);
1502 switch (colorMode
) {
1503 case splashModeMono1
:
1504 case splashModeMono8
:
1507 case splashModeXBGR8
:
1509 case splashModeRGB8
:
1510 case splashModeBGR8
:
1511 color
[0] = color
[1] = color
[2] = 0;
1514 case splashModeCMYK8
:
1515 color
[0] = color
[1] = color
[2] = color
[3] = 0;
1517 case splashModeDeviceN8
:
1518 for (int i
= 0; i
< 4 + SPOT_NCOMPS
; i
++)
1523 splash
->setStrokePattern(new SplashSolidColor(color
));
1524 splash
->setFillPattern(new SplashSolidColor(color
));
1525 splash
->setLineCap(splashLineCapButt
);
1526 splash
->setLineJoin(splashLineJoinMiter
);
1527 splash
->setLineDash(NULL
, 0, 0);
1528 splash
->setMiterLimit(10);
1529 splash
->setFlatness(1);
1530 // the SA parameter supposedly defaults to false, but Acrobat
1531 // apparently hardwires it to true
1532 splash
->setStrokeAdjust(globalParams
->getStrokeAdjust());
1533 splash
->clear(paperColor
, 0);
1536 void SplashOutputDev::endPage() {
1537 if (colorMode
!= splashModeMono1
&& !keepAlphaChannel
) {
1538 splash
->compositeBackground(paperColor
);
1542 void SplashOutputDev::saveState(GfxState
*state
) {
1543 splash
->saveState();
1546 void SplashOutputDev::restoreState(GfxState
*state
) {
1547 splash
->restoreState();
1548 needFontUpdate
= gTrue
;
1551 void SplashOutputDev::updateAll(GfxState
*state
) {
1552 updateLineDash(state
);
1553 updateLineJoin(state
);
1554 updateLineCap(state
);
1555 updateLineWidth(state
);
1556 updateFlatness(state
);
1557 updateMiterLimit(state
);
1558 updateStrokeAdjust(state
);
1559 updateFillColorSpace(state
);
1560 updateFillColor(state
);
1561 updateStrokeColorSpace(state
);
1562 updateStrokeColor(state
);
1563 needFontUpdate
= gTrue
;
1566 void SplashOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
1567 double m21
, double m22
,
1568 double m31
, double m32
) {
1572 ctm
= state
->getCTM();
1573 mat
[0] = (SplashCoord
)ctm
[0];
1574 mat
[1] = (SplashCoord
)ctm
[1];
1575 mat
[2] = (SplashCoord
)ctm
[2];
1576 mat
[3] = (SplashCoord
)ctm
[3];
1577 mat
[4] = (SplashCoord
)ctm
[4];
1578 mat
[5] = (SplashCoord
)ctm
[5];
1579 splash
->setMatrix(mat
);
1582 void SplashOutputDev::updateLineDash(GfxState
*state
) {
1583 double *dashPattern
;
1586 SplashCoord dash
[20];
1589 state
->getLineDash(&dashPattern
, &dashLength
, &dashStart
);
1590 if (dashLength
> 20) {
1593 for (i
= 0; i
< dashLength
; ++i
) {
1594 dash
[i
] = (SplashCoord
)dashPattern
[i
];
1599 splash
->setLineDash(dash
, dashLength
, (SplashCoord
)dashStart
);
1602 void SplashOutputDev::updateFlatness(GfxState
*state
) {
1603 #if 0 // Acrobat ignores the flatness setting, and always renders curves
1604 // with a fairly small flatness value
1605 splash
->setFlatness(state
->getFlatness());
1609 void SplashOutputDev::updateLineJoin(GfxState
*state
) {
1610 splash
->setLineJoin(state
->getLineJoin());
1613 void SplashOutputDev::updateLineCap(GfxState
*state
) {
1614 splash
->setLineCap(state
->getLineCap());
1617 void SplashOutputDev::updateMiterLimit(GfxState
*state
) {
1618 splash
->setMiterLimit(state
->getMiterLimit());
1621 void SplashOutputDev::updateLineWidth(GfxState
*state
) {
1622 splash
->setLineWidth(state
->getLineWidth());
1625 void SplashOutputDev::updateStrokeAdjust(GfxState
* /*state*/) {
1626 #if 0 // the SA parameter supposedly defaults to false, but Acrobat
1627 // apparently hardwires it to true
1628 splash
->setStrokeAdjust(state
->getStrokeAdjust());
1632 void SplashOutputDev::updateFillColorSpace(GfxState
*state
) {
1634 if (colorMode
== splashModeDeviceN8
)
1635 state
->getFillColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
1639 void SplashOutputDev::updateStrokeColorSpace(GfxState
*state
) {
1641 if (colorMode
== splashModeDeviceN8
)
1642 state
->getStrokeColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
1646 void SplashOutputDev::updateFillColor(GfxState
*state
) {
1654 switch (colorMode
) {
1655 case splashModeMono1
:
1656 case splashModeMono8
:
1657 state
->getFillGray(&gray
);
1658 splash
->setFillPattern(getColor(gray
));
1660 case splashModeXBGR8
:
1661 case splashModeRGB8
:
1662 case splashModeBGR8
:
1663 state
->getFillRGB(&rgb
);
1664 splash
->setFillPattern(getColor(&rgb
));
1667 case splashModeCMYK8
:
1668 state
->getFillCMYK(&cmyk
);
1669 splash
->setFillPattern(getColor(&cmyk
));
1671 case splashModeDeviceN8
:
1672 state
->getFillDeviceN(&deviceN
);
1673 splash
->setFillPattern(getColor(&deviceN
));
1679 void SplashOutputDev::updateStrokeColor(GfxState
*state
) {
1687 switch (colorMode
) {
1688 case splashModeMono1
:
1689 case splashModeMono8
:
1690 state
->getStrokeGray(&gray
);
1691 splash
->setStrokePattern(getColor(gray
));
1693 case splashModeXBGR8
:
1694 case splashModeRGB8
:
1695 case splashModeBGR8
:
1696 state
->getStrokeRGB(&rgb
);
1697 splash
->setStrokePattern(getColor(&rgb
));
1700 case splashModeCMYK8
:
1701 state
->getStrokeCMYK(&cmyk
);
1702 splash
->setStrokePattern(getColor(&cmyk
));
1704 case splashModeDeviceN8
:
1705 state
->getStrokeDeviceN(&deviceN
);
1706 splash
->setStrokePattern(getColor(&deviceN
));
1712 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
) {
1716 gray
= gfxColorComp1
- gray
;
1718 color
[0] = colToByte(gray
);
1719 return new SplashSolidColor(color
);
1722 SplashPattern
*SplashOutputDev::getColor(GfxRGB
*rgb
) {
1723 GfxColorComp r
, g
, b
;
1727 r
= gfxColorComp1
- rgb
->r
;
1728 g
= gfxColorComp1
- rgb
->g
;
1729 b
= gfxColorComp1
- rgb
->b
;
1735 color
[0] = colToByte(r
);
1736 color
[1] = colToByte(g
);
1737 color
[2] = colToByte(b
);
1738 if (colorMode
== splashModeXBGR8
) color
[3] = 255;
1739 return new SplashSolidColor(color
);
1743 SplashPattern
*SplashOutputDev::getColor(GfxCMYK
*cmyk
) {
1746 color
[0] = colToByte(cmyk
->c
);
1747 color
[1] = colToByte(cmyk
->m
);
1748 color
[2] = colToByte(cmyk
->y
);
1749 color
[3] = colToByte(cmyk
->k
);
1750 return new SplashSolidColor(color
);
1753 SplashPattern
*SplashOutputDev::getColor(GfxColor
*deviceN
) {
1756 for (int i
= 0; i
< 4 + SPOT_NCOMPS
; i
++)
1757 color
[i
] = colToByte(deviceN
->c
[i
]);
1758 return new SplashSolidColor(color
);
1762 void SplashOutputDev::setOverprintMask(GfxColorSpace
*colorSpace
,
1763 GBool overprintFlag
,
1765 GfxColor
*singleColor
,
1766 GBool grayIndexed
) {
1770 GBool additive
= gFalse
;
1773 if (colorSpace
->getMode() == csIndexed
) {
1774 setOverprintMask(((GfxIndexedColorSpace
*)colorSpace
)->getBase(),
1781 if (overprintFlag
&& overprintPreview
) {
1782 mask
= colorSpace
->getOverprintMask();
1783 if (singleColor
&& overprintMode
&&
1784 colorSpace
->getMode() == csDeviceCMYK
) {
1785 colorSpace
->getCMYK(singleColor
, &cmyk
);
1801 } else if (colorSpace
->getMode() == csSeparation
) {
1802 GfxSeparationColorSpace
*deviceSep
= (GfxSeparationColorSpace
*)colorSpace
;
1803 additive
= deviceSep
->getName()->cmp("All") != 0 && mask
== 0x0f && !deviceSep
->isNonMarking();
1804 } else if (colorSpace
->getMode() == csDeviceN
) {
1805 GfxDeviceNColorSpace
*deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
1806 additive
= mask
== 0x0f && !deviceNCS
->isNonMarking();
1807 for (i
= 0; i
< deviceNCS
->getNComps() && additive
; i
++) {
1808 if (deviceNCS
->getColorantName(i
)->cmp("Cyan") == 0) {
1810 } else if (deviceNCS
->getColorantName(i
)->cmp("Magenta") == 0) {
1812 } else if (deviceNCS
->getColorantName(i
)->cmp("Yellow") == 0) {
1814 } else if (deviceNCS
->getColorantName(i
)->cmp("Black") == 0) {
1822 splash
->setOverprintMask(mask
, additive
);
1826 void SplashOutputDev::updateBlendMode(GfxState
*state
) {
1827 splash
->setBlendFunc(splashOutBlendFuncs
[state
->getBlendMode()]);
1830 void SplashOutputDev::updateFillOpacity(GfxState
*state
) {
1831 splash
->setFillAlpha((SplashCoord
)state
->getFillOpacity());
1832 if (transpGroupStack
!= NULL
&& (SplashCoord
)state
->getFillOpacity() < transpGroupStack
->knockoutOpacity
) {
1833 transpGroupStack
->knockoutOpacity
= (SplashCoord
)state
->getFillOpacity();
1837 void SplashOutputDev::updateStrokeOpacity(GfxState
*state
) {
1838 splash
->setStrokeAlpha((SplashCoord
)state
->getStrokeOpacity());
1839 if (transpGroupStack
!= NULL
&& (SplashCoord
)state
->getStrokeOpacity() < transpGroupStack
->knockoutOpacity
) {
1840 transpGroupStack
->knockoutOpacity
= (SplashCoord
)state
->getStrokeOpacity();
1844 void SplashOutputDev::updateFillOverprint(GfxState
*state
) {
1845 splash
->setFillOverprint(state
->getFillOverprint());
1848 void SplashOutputDev::updateStrokeOverprint(GfxState
*state
) {
1849 splash
->setStrokeOverprint(state
->getStrokeOverprint());
1852 void SplashOutputDev::updateOverprintMode(GfxState
*state
) {
1853 splash
->setOverprintMode(state
->getOverprintMode());
1856 void SplashOutputDev::updateTransfer(GfxState
*state
) {
1857 Function
**transfer
;
1858 Guchar red
[256], green
[256], blue
[256], gray
[256];
1862 transfer
= state
->getTransfer();
1864 transfer
[0]->getInputSize() == 1 &&
1865 transfer
[0]->getOutputSize() == 1) {
1867 transfer
[1]->getInputSize() == 1 &&
1868 transfer
[1]->getOutputSize() == 1 &&
1870 transfer
[2]->getInputSize() == 1 &&
1871 transfer
[2]->getOutputSize() == 1 &&
1873 transfer
[3]->getInputSize() == 1 &&
1874 transfer
[3]->getOutputSize() == 1) {
1875 for (i
= 0; i
< 256; ++i
) {
1877 transfer
[0]->transform(&x
, &y
);
1878 red
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1879 transfer
[1]->transform(&x
, &y
);
1880 green
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1881 transfer
[2]->transform(&x
, &y
);
1882 blue
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1883 transfer
[3]->transform(&x
, &y
);
1884 gray
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1887 for (i
= 0; i
< 256; ++i
) {
1889 transfer
[0]->transform(&x
, &y
);
1890 red
[i
] = green
[i
] = blue
[i
] = gray
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1894 for (i
= 0; i
< 256; ++i
) {
1895 red
[i
] = green
[i
] = blue
[i
] = gray
[i
] = (Guchar
)i
;
1898 splash
->setTransfer(red
, green
, blue
, gray
);
1901 void SplashOutputDev::updateFont(GfxState
* /*state*/) {
1902 needFontUpdate
= gTrue
;
1905 void SplashOutputDev::doUpdateFont(GfxState
*state
) {
1907 GfxFontLoc
*fontLoc
;
1908 GfxFontType fontType
;
1909 SplashOutFontFileID
*id
;
1910 SplashFontFile
*fontFile
;
1911 SplashFontSrc
*fontsrc
= NULL
;
1913 Object refObj
, strObj
;
1914 GooString
*fileName
;
1919 double m11
, m12
, m21
, m22
, fontSize
;
1923 GBool recreateFont
= gFalse
;
1924 GBool doAdjustFontMatrix
= gFalse
;
1926 needFontUpdate
= gFalse
;
1932 if (!(gfxFont
= state
->getFont())) {
1935 fontType
= gfxFont
->getType();
1936 if (fontType
== fontType3
) {
1940 // sanity-check the font size - skip anything larger than 10 inches
1941 // (this avoids problems allocating memory for the font cache)
1942 if (state
->getTransformedFontSize()
1943 > 10 * (state
->getHDPI() + state
->getVDPI())) {
1947 // check the font file cache
1948 id
= new SplashOutFontFileID(gfxFont
->getID());
1949 if ((fontFile
= fontEngine
->getFontFile(id
))) {
1954 if (!(fontLoc
= gfxFont
->locateFont((xref
) ? xref
: doc
->getXRef(), NULL
))) {
1955 error(errSyntaxError
, -1, "Couldn't find a font for '{0:s}'",
1956 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1962 if (fontLoc
->locType
== gfxFontLocEmbedded
) {
1963 // if there is an embedded font, read it to memory
1964 tmpBuf
= gfxFont
->readEmbFontFile((xref
) ? xref
: doc
->getXRef(), &tmpBufLen
);
1969 } else { // gfxFontLocExternal
1970 fileName
= fontLoc
->path
;
1971 fontType
= fontLoc
->fontType
;
1972 doAdjustFontMatrix
= gTrue
;
1975 fontsrc
= new SplashFontSrc
;
1977 fontsrc
->setFile(fileName
, gFalse
);
1979 fontsrc
->setBuf(tmpBuf
, tmpBufLen
, gTrue
);
1981 // load the font file
1984 if (!(fontFile
= fontEngine
->loadType1Font(
1987 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1988 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
1989 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1995 if (!(fontFile
= fontEngine
->loadType1CFont(
1998 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
1999 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2000 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2006 if (!(fontFile
= fontEngine
->loadOpenTypeT1CFont(
2009 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
2010 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2011 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2017 case fontTrueTypeOT
:
2019 ff
= FoFiTrueType::load(fileName
->getCString());
2021 ff
= FoFiTrueType::make(tmpBuf
, tmpBufLen
);
2023 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(ff
);
2026 // if we're substituting for a non-TrueType font, we need to mark
2027 // all notdef codes as "do not draw" (rather than drawing TrueType
2029 if (gfxFont
->getType() != fontTrueType
&&
2030 gfxFont
->getType() != fontTrueTypeOT
) {
2031 for (i
= 0; i
< 256; ++i
) {
2032 if (codeToGID
[i
] == 0) {
2041 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
2045 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2046 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2053 if (!(fontFile
= fontEngine
->loadCIDFont(
2056 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2057 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2062 case fontCIDType0COT
:
2063 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
2064 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
2065 codeToGID
= (int *)gmallocn(n
, sizeof(int));
2066 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
2072 if (!(fontFile
= fontEngine
->loadOpenTypeCFFFont(
2076 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2077 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2083 case fontCIDType2OT
:
2086 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
2087 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
2089 codeToGID
= (int *)gmallocn(n
, sizeof(int));
2090 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
2095 ff
= FoFiTrueType::load(fileName
->getCString());
2097 ff
= FoFiTrueType::make(tmpBuf
, tmpBufLen
);
2100 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2101 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2105 codeToGID
= ((GfxCIDFont
*)gfxFont
)->getCodeToGIDMap(ff
, &n
);
2108 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
2111 codeToGID
, n
, faceIndex
))) {
2112 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2113 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2119 // this shouldn't happen
2122 fontFile
->doAdjustMatrix
= doAdjustFontMatrix
;
2125 // get the font matrix
2126 textMat
= state
->getTextMat();
2127 fontSize
= state
->getFontSize();
2128 m11
= textMat
[0] * fontSize
* state
->getHorizScaling();
2129 m12
= textMat
[1] * fontSize
* state
->getHorizScaling();
2130 m21
= textMat
[2] * fontSize
;
2131 m22
= textMat
[3] * fontSize
;
2133 // create the scaled font
2134 mat
[0] = m11
; mat
[1] = m12
;
2135 mat
[2] = m21
; mat
[3] = m22
;
2136 font
= fontEngine
->getFont(fontFile
, mat
, splash
->getMatrix());
2138 // for substituted fonts: adjust the font matrix -- compare the
2139 // width of 'm' in the original font and the substituted font
2140 if (fontFile
->doAdjustMatrix
&& !gfxFont
->isCIDFont()) {
2144 for (code
= 0; code
< 256; ++code
) {
2145 if ((name
= ((Gfx8BitFont
*)gfxFont
)->getCharName(code
)) &&
2146 name
[0] == 'm' && name
[1] == '\0') {
2151 w1
= ((Gfx8BitFont
*)gfxFont
)->getWidth(code
);
2152 w2
= font
->getGlyphAdvance(code
);
2153 if (!gfxFont
->isSymbolic() && w2
> 0) {
2154 // if real font is substantially narrower than substituted
2155 // font, reduce the font size accordingly
2156 if (w1
> 0.01 && w1
< 0.9 * w2
) {
2160 recreateFont
= gTrue
;
2168 mat
[0] = m11
; mat
[1] = m12
;
2169 mat
[2] = m21
; mat
[3] = m22
;
2170 font
= fontEngine
->getFont(fontFile
, mat
, splash
->getMatrix());
2174 if (fontsrc
&& !fontsrc
->isFile
)
2182 if (fontsrc
&& !fontsrc
->isFile
)
2187 void SplashOutputDev::stroke(GfxState
*state
) {
2190 if (state
->getStrokeColorSpace()->isNonMarking()) {
2193 setOverprintMask(state
->getStrokeColorSpace(), state
->getStrokeOverprint(),
2194 state
->getOverprintMode(), state
->getStrokeColor());
2195 path
= convertPath(state
, state
->getPath(), gFalse
);
2196 splash
->stroke(path
);
2200 void SplashOutputDev::fill(GfxState
*state
) {
2203 if (state
->getFillColorSpace()->isNonMarking()) {
2206 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2207 state
->getOverprintMode(), state
->getFillColor());
2208 path
= convertPath(state
, state
->getPath(), gTrue
);
2209 splash
->fill(path
, gFalse
);
2213 void SplashOutputDev::eoFill(GfxState
*state
) {
2216 if (state
->getFillColorSpace()->isNonMarking()) {
2219 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2220 state
->getOverprintMode(), state
->getFillColor());
2221 path
= convertPath(state
, state
->getPath(), gTrue
);
2222 splash
->fill(path
, gTrue
);
2226 void SplashOutputDev::clip(GfxState
*state
) {
2229 path
= convertPath(state
, state
->getPath(), gTrue
);
2230 splash
->clipToPath(path
, gFalse
);
2234 void SplashOutputDev::eoClip(GfxState
*state
) {
2237 path
= convertPath(state
, state
->getPath(), gTrue
);
2238 splash
->clipToPath(path
, gTrue
);
2242 void SplashOutputDev::clipToStrokePath(GfxState
*state
) {
2243 SplashPath
*path
, *path2
;
2245 path
= convertPath(state
, state
->getPath(), gFalse
);
2246 path2
= splash
->makeStrokePath(path
, state
->getLineWidth());
2248 splash
->clipToPath(path2
, gFalse
);
2252 SplashPath
*SplashOutputDev::convertPath(GfxState
*state
, GfxPath
*path
,
2253 GBool dropEmptySubpaths
) {
2255 GfxSubpath
*subpath
;
2258 n
= dropEmptySubpaths
? 1 : 0;
2259 sPath
= new SplashPath();
2260 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
2261 subpath
= path
->getSubpath(i
);
2262 if (subpath
->getNumPoints() > n
) {
2263 sPath
->moveTo((SplashCoord
)subpath
->getX(0),
2264 (SplashCoord
)subpath
->getY(0));
2266 while (j
< subpath
->getNumPoints()) {
2267 if (subpath
->getCurve(j
)) {
2268 sPath
->curveTo((SplashCoord
)subpath
->getX(j
),
2269 (SplashCoord
)subpath
->getY(j
),
2270 (SplashCoord
)subpath
->getX(j
+1),
2271 (SplashCoord
)subpath
->getY(j
+1),
2272 (SplashCoord
)subpath
->getX(j
+2),
2273 (SplashCoord
)subpath
->getY(j
+2));
2276 sPath
->lineTo((SplashCoord
)subpath
->getX(j
),
2277 (SplashCoord
)subpath
->getY(j
));
2281 if (subpath
->isClosed()) {
2289 void SplashOutputDev::drawChar(GfxState
*state
, double x
, double y
,
2290 double dx
, double dy
,
2291 double originX
, double originY
,
2292 CharCode code
, int nBytes
,
2293 Unicode
*u
, int uLen
) {
2296 GBool doFill
, doStroke
, doClip
, strokeAdjust
;
2300 if (skipHorizText
|| skipRotatedText
) {
2301 state
->getFontTransMat(&m
[0], &m
[1], &m
[2], &m
[3]);
2302 horiz
= m
[0] > 0 && fabs(m
[1]) < 0.001 &&
2303 fabs(m
[2]) < 0.001 && m
[3] < 0;
2304 if ((skipHorizText
&& horiz
) || (skipRotatedText
&& !horiz
)) {
2309 // check for invisible text -- this is used by Acrobat Capture
2310 render
= state
->getRender();
2315 if (needFontUpdate
) {
2316 doUpdateFont(state
);
2325 doFill
= !(render
& 1) && !state
->getFillColorSpace()->isNonMarking();
2326 doStroke
= ((render
& 3) == 1 || (render
& 3) == 2) &&
2327 !state
->getStrokeColorSpace()->isNonMarking();
2328 doClip
= render
& 4;
2331 if (doStroke
|| doClip
) {
2332 if ((path
= font
->getGlyphPath(code
))) {
2333 path
->offset((SplashCoord
)x
, (SplashCoord
)y
);
2337 // don't use stroke adjustment when stroking text -- the results
2338 // tend to be ugly (because characters with horizontal upper or
2339 // lower edges get misaligned relative to the other characters)
2340 strokeAdjust
= gFalse
; // make gcc happy
2342 strokeAdjust
= splash
->getStrokeAdjust();
2343 splash
->setStrokeAdjust(gFalse
);
2347 if (doFill
&& doStroke
) {
2349 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2350 state
->getOverprintMode(), state
->getFillColor());
2351 splash
->fill(path
, gFalse
);
2352 setOverprintMask(state
->getStrokeColorSpace(),
2353 state
->getStrokeOverprint(),
2354 state
->getOverprintMode(),
2355 state
->getStrokeColor());
2356 splash
->stroke(path
);
2360 } else if (doFill
) {
2361 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2362 state
->getOverprintMode(), state
->getFillColor());
2363 splash
->fillChar((SplashCoord
)x
, (SplashCoord
)y
, code
, font
);
2366 } else if (doStroke
) {
2368 setOverprintMask(state
->getStrokeColorSpace(),
2369 state
->getStrokeOverprint(),
2370 state
->getOverprintMode(),
2371 state
->getStrokeColor());
2372 splash
->stroke(path
);
2380 textClipPath
->append(path
);
2382 textClipPath
= path
;
2389 splash
->setStrokeAdjust(strokeAdjust
);
2397 GBool
SplashOutputDev::beginType3Char(GfxState
*state
, double x
, double y
,
2398 double dx
, double dy
,
2399 CharCode code
, Unicode
*u
, int uLen
) {
2403 T3FontCache
*t3Font
;
2408 double x1
, y1
, xMin
, yMin
, xMax
, yMax
, xt
, yt
;
2411 if (skipHorizText
|| skipRotatedText
) {
2412 state
->getFontTransMat(&m
[0], &m
[1], &m
[2], &m
[3]);
2413 horiz
= m
[0] > 0 && fabs(m
[1]) < 0.001 &&
2414 fabs(m
[2]) < 0.001 && m
[3] < 0;
2415 if ((skipHorizText
&& horiz
) || (skipRotatedText
&& !horiz
)) {
2420 if (!(gfxFont
= state
->getFont())) {
2423 fontID
= gfxFont
->getID();
2424 ctm
= state
->getCTM();
2425 state
->transform(0, 0, &xt
, &yt
);
2427 // is it the first (MRU) font in the cache?
2428 if (!(nT3Fonts
> 0 &&
2429 t3FontCache
[0]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3]))) {
2431 // is the font elsewhere in the cache?
2432 for (i
= 1; i
< nT3Fonts
; ++i
) {
2433 if (t3FontCache
[i
]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3])) {
2434 t3Font
= t3FontCache
[i
];
2435 for (j
= i
; j
> 0; --j
) {
2436 t3FontCache
[j
] = t3FontCache
[j
- 1];
2438 t3FontCache
[0] = t3Font
;
2442 if (i
>= nT3Fonts
) {
2444 // create new entry in the font cache
2445 if (nT3Fonts
== splashOutT3FontCacheSize
) {
2446 t3gs
= t3GlyphStack
;
2447 while (t3gs
!= NULL
) {
2448 if (t3gs
->cache
== t3FontCache
[nT3Fonts
- 1]) {
2449 error(errSyntaxWarning
, -1, "t3FontCache reaches limit but font still on stack in SplashOutputDev::beginType3Char");
2454 delete t3FontCache
[nT3Fonts
- 1];
2457 for (j
= nT3Fonts
; j
> 0; --j
) {
2458 t3FontCache
[j
] = t3FontCache
[j
- 1];
2461 bbox
= gfxFont
->getFontBBox();
2462 if (bbox
[0] == 0 && bbox
[1] == 0 && bbox
[2] == 0 && bbox
[3] == 0) {
2463 // unspecified bounding box -- just take a guess
2470 state
->transform(bbox
[0], bbox
[1], &x1
, &y1
);
2473 state
->transform(bbox
[0], bbox
[3], &x1
, &y1
);
2476 } else if (x1
> xMax
) {
2481 } else if (y1
> yMax
) {
2484 state
->transform(bbox
[2], bbox
[1], &x1
, &y1
);
2487 } else if (x1
> xMax
) {
2492 } else if (y1
> yMax
) {
2495 state
->transform(bbox
[2], bbox
[3], &x1
, &y1
);
2498 } else if (x1
> xMax
) {
2503 } else if (y1
> yMax
) {
2508 t3FontCache
[0] = new T3FontCache(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2509 (int)floor(xMin
- xt
) - 2,
2510 (int)floor(yMin
- yt
) - 2,
2511 (int)ceil(xMax
) - (int)floor(xMin
) + 4,
2512 (int)ceil(yMax
) - (int)floor(yMin
) + 4,
2514 colorMode
!= splashModeMono1
);
2517 t3Font
= t3FontCache
[0];
2519 // is the glyph in the cache?
2520 i
= (code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
2521 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
2522 if (t3Font
->cacheTags
!= NULL
) {
2523 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x8000) &&
2524 t3Font
->cacheTags
[i
+j
].code
== code
) {
2525 drawType3Glyph(state
, t3Font
, &t3Font
->cacheTags
[i
+j
],
2526 t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
);
2532 // push a new Type 3 glyph record
2533 t3gs
= new T3GlyphStack();
2534 t3gs
->next
= t3GlyphStack
;
2535 t3GlyphStack
= t3gs
;
2536 t3GlyphStack
->code
= code
;
2537 t3GlyphStack
->cache
= t3Font
;
2538 t3GlyphStack
->cacheTag
= NULL
;
2539 t3GlyphStack
->cacheData
= NULL
;
2546 void SplashOutputDev::endType3Char(GfxState
*state
) {
2550 if (t3GlyphStack
->cacheTag
) {
2552 memcpy(t3GlyphStack
->cacheData
, bitmap
->getDataPtr(),
2553 t3GlyphStack
->cache
->glyphSize
);
2556 bitmap
= t3GlyphStack
->origBitmap
;
2557 splash
= t3GlyphStack
->origSplash
;
2558 ctm
= state
->getCTM();
2559 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2560 t3GlyphStack
->origCTM4
, t3GlyphStack
->origCTM5
);
2561 updateCTM(state
, 0, 0, 0, 0, 0, 0);
2562 drawType3Glyph(state
, t3GlyphStack
->cache
,
2563 t3GlyphStack
->cacheTag
, t3GlyphStack
->cacheData
);
2565 t3gs
= t3GlyphStack
;
2566 t3GlyphStack
= t3gs
->next
;
2570 void SplashOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
2574 void SplashOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
2575 double llx
, double lly
, double urx
, double ury
) {
2577 T3FontCache
*t3Font
;
2579 double xt
, yt
, xMin
, xMax
, yMin
, yMax
, x1
, y1
;
2582 // ignore multiple d0/d1 operators
2588 if (unlikely(t3GlyphStack
== NULL
)) {
2589 error(errSyntaxWarning
, -1, "t3GlyphStack was null in SplashOutputDev::type3D1");
2593 if (unlikely(t3GlyphStack
->origBitmap
!= NULL
)) {
2594 error(errSyntaxWarning
, -1, "t3GlyphStack origBitmap was not null in SplashOutputDev::type3D1");
2598 if (unlikely(t3GlyphStack
->origSplash
!= NULL
)) {
2599 error(errSyntaxWarning
, -1, "t3GlyphStack origSplash was not null in SplashOutputDev::type3D1");
2603 t3Font
= t3GlyphStack
->cache
;
2605 // check for a valid bbox
2606 state
->transform(0, 0, &xt
, &yt
);
2607 state
->transform(llx
, lly
, &x1
, &y1
);
2610 state
->transform(llx
, ury
, &x1
, &y1
);
2613 } else if (x1
> xMax
) {
2618 } else if (y1
> yMax
) {
2621 state
->transform(urx
, lly
, &x1
, &y1
);
2624 } else if (x1
> xMax
) {
2629 } else if (y1
> yMax
) {
2632 state
->transform(urx
, ury
, &x1
, &y1
);
2635 } else if (x1
> xMax
) {
2640 } else if (y1
> yMax
) {
2643 if (xMin
- xt
< t3Font
->glyphX
||
2644 yMin
- yt
< t3Font
->glyphY
||
2645 xMax
- xt
> t3Font
->glyphX
+ t3Font
->glyphW
||
2646 yMax
- yt
> t3Font
->glyphY
+ t3Font
->glyphH
) {
2647 if (t3Font
->validBBox
) {
2648 error(errSyntaxWarning
, -1, "Bad bounding box in Type 3 glyph");
2653 if (t3Font
->cacheTags
== NULL
)
2656 // allocate a cache entry
2657 i
= (t3GlyphStack
->code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
2658 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
2659 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x7fff) == t3Font
->cacheAssoc
- 1) {
2660 t3Font
->cacheTags
[i
+j
].mru
= 0x8000;
2661 t3Font
->cacheTags
[i
+j
].code
= t3GlyphStack
->code
;
2662 t3GlyphStack
->cacheTag
= &t3Font
->cacheTags
[i
+j
];
2663 t3GlyphStack
->cacheData
= t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
;
2665 ++t3Font
->cacheTags
[i
+j
].mru
;
2670 t3GlyphStack
->origBitmap
= bitmap
;
2671 t3GlyphStack
->origSplash
= splash
;
2672 ctm
= state
->getCTM();
2673 t3GlyphStack
->origCTM4
= ctm
[4];
2674 t3GlyphStack
->origCTM5
= ctm
[5];
2676 // create the temporary bitmap
2677 if (colorMode
== splashModeMono1
) {
2678 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
2679 splashModeMono1
, gFalse
);
2680 splash
= new Splash(bitmap
, gFalse
,
2681 t3GlyphStack
->origSplash
->getScreen());
2683 splash
->clear(color
);
2686 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
2687 splashModeMono8
, gFalse
);
2688 splash
= new Splash(bitmap
, vectorAntialias
,
2689 t3GlyphStack
->origSplash
->getScreen());
2691 splash
->clear(color
);
2694 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
2695 splash
->setThinLineMode(splashThinLineDefault
);
2696 splash
->setFillPattern(new SplashSolidColor(color
));
2697 splash
->setStrokePattern(new SplashSolidColor(color
));
2698 //~ this should copy other state from t3GlyphStack->origSplash?
2699 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2700 -t3Font
->glyphX
, -t3Font
->glyphY
);
2701 updateCTM(state
, 0, 0, 0, 0, 0, 0);
2705 void SplashOutputDev::drawType3Glyph(GfxState
*state
, T3FontCache
*t3Font
,
2706 T3FontCacheTag
* /*tag*/, Guchar
*data
) {
2707 SplashGlyphBitmap glyph
;
2709 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2710 state
->getOverprintMode(), state
->getFillColor());
2711 glyph
.x
= -t3Font
->glyphX
;
2712 glyph
.y
= -t3Font
->glyphY
;
2713 glyph
.w
= t3Font
->glyphW
;
2714 glyph
.h
= t3Font
->glyphH
;
2715 glyph
.aa
= colorMode
!= splashModeMono1
;
2717 glyph
.freeData
= gFalse
;
2718 splash
->fillGlyph(0, 0, &glyph
);
2721 void SplashOutputDev::beginTextObject(GfxState
*state
) {
2724 void SplashOutputDev::endTextObject(GfxState
*state
) {
2726 splash
->clipToPath(textClipPath
, gFalse
);
2727 delete textClipPath
;
2728 textClipPath
= NULL
;
2732 struct SplashOutImageMaskData
{
2733 ImageStream
*imgStr
;
2735 int width
, height
, y
;
2738 GBool
SplashOutputDev::imageMaskSrc(void *data
, SplashColorPtr line
) {
2739 SplashOutImageMaskData
*imgMaskData
= (SplashOutImageMaskData
*)data
;
2744 if (imgMaskData
->y
== imgMaskData
->height
) {
2747 if (!(p
= imgMaskData
->imgStr
->getLine())) {
2750 for (x
= 0, q
= line
; x
< imgMaskData
->width
; ++x
) {
2751 *q
++ = *p
++ ^ imgMaskData
->invert
;
2757 void SplashOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
2758 int width
, int height
, GBool invert
,
2759 GBool interpolate
, GBool inlineImg
) {
2762 SplashOutImageMaskData imgMaskData
;
2764 if (state
->getFillColorSpace()->isNonMarking()) {
2767 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2768 state
->getOverprintMode(), state
->getFillColor());
2770 ctm
= state
->getCTM();
2771 for (int i
= 0; i
< 6; ++i
) {
2772 if (!isfinite(ctm
[i
])) return;
2778 mat
[4] = ctm
[2] + ctm
[4];
2779 mat
[5] = ctm
[3] + ctm
[5];
2781 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
2782 imgMaskData
.imgStr
->reset();
2783 imgMaskData
.invert
= invert
? 0 : 1;
2784 imgMaskData
.width
= width
;
2785 imgMaskData
.height
= height
;
2788 splash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
, t3GlyphStack
!= NULL
);
2790 while (imgMaskData
.y
< height
) {
2791 imgMaskData
.imgStr
->getLine();
2796 delete imgMaskData
.imgStr
;
2800 void SplashOutputDev::setSoftMaskFromImageMask(GfxState
*state
,
2801 Object
*ref
, Stream
*str
,
2802 int width
, int height
,
2804 GBool inlineImg
, double *baseMatrix
) {
2807 SplashOutImageMaskData imgMaskData
;
2809 SplashColor maskColor
;
2810 double bbox
[4] = {0, 0, 1, 1}; // default;
2812 if (state
->getFillColorSpace()->isNonMarking()) {
2816 ctm
= state
->getCTM();
2817 for (int i
= 0; i
< 6; ++i
) {
2818 if (!isfinite(ctm
[i
])) return;
2821 beginTransparencyGroup(state
, bbox
, NULL
, gFalse
, gFalse
, gFalse
);
2822 baseMatrix
[4] -= transpGroupStack
->tx
;
2823 baseMatrix
[5] -= transpGroupStack
->ty
;
2825 ctm
= state
->getCTM();
2830 mat
[4] = ctm
[2] + ctm
[4];
2831 mat
[5] = ctm
[3] + ctm
[5];
2832 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
2833 imgMaskData
.imgStr
->reset();
2834 imgMaskData
.invert
= invert
? 0 : 1;
2835 imgMaskData
.width
= width
;
2836 imgMaskData
.height
= height
;
2839 transpGroupStack
->softmask
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(), 1, splashModeMono8
, gFalse
);
2840 maskSplash
= new Splash(transpGroupStack
->softmask
, vectorAntialias
);
2842 maskSplash
->clear(maskColor
);
2843 maskColor
[0] = 0xff;
2844 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
2845 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
, t3GlyphStack
!= NULL
);
2847 delete imgMaskData
.imgStr
;
2851 void SplashOutputDev::unsetSoftMaskFromImageMask(GfxState
*state
, double *baseMatrix
) {
2852 double bbox
[4] = {0,0,1,1}; // dummy
2854 /* transfer mask to alpha channel! */
2855 // memcpy(maskBitmap->getAlphaPtr(), maskBitmap->getDataPtr(), bitmap->getRowSize() * bitmap->getHeight());
2856 // memset(maskBitmap->getDataPtr(), 0, bitmap->getRowSize() * bitmap->getHeight());
2857 if (transpGroupStack
->softmask
!= NULL
) {
2858 Guchar
*dest
= bitmap
->getAlphaPtr();
2859 Guchar
*src
= transpGroupStack
->softmask
->getDataPtr();
2860 for (int c
= 0; c
< transpGroupStack
->softmask
->getRowSize() * transpGroupStack
->softmask
->getHeight(); c
++) {
2863 delete transpGroupStack
->softmask
;
2864 transpGroupStack
->softmask
= NULL
;
2866 endTransparencyGroup(state
);
2867 baseMatrix
[4] += transpGroupStack
->tx
;
2868 baseMatrix
[5] += transpGroupStack
->ty
;
2869 paintTransparencyGroup(state
, bbox
);
2872 struct SplashOutImageData
{
2873 ImageStream
*imgStr
;
2874 GfxImageColorMap
*colorMap
;
2875 SplashColorPtr lookup
;
2877 SplashColorMode colorMode
;
2878 int width
, height
, y
;
2882 GBool
SplashOutputDev::useIccImageSrc(void *data
) {
2883 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
2885 if (!imgData
->lookup
&& imgData
->colorMap
->getColorSpace()->getMode() == csICCBased
) {
2886 GfxICCBasedColorSpace
*colorSpace
= (GfxICCBasedColorSpace
*) imgData
->colorMap
->getColorSpace();
2887 switch (imgData
->colorMode
) {
2888 case splashModeMono1
:
2889 case splashModeMono8
:
2890 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceGray
)
2893 case splashModeXBGR8
:
2894 case splashModeRGB8
:
2895 case splashModeBGR8
:
2896 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceRGB
)
2900 case splashModeCMYK8
:
2901 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceCMYK
)
2912 GBool
SplashOutputDev::imageSrc(void *data
, SplashColorPtr colorLine
,
2913 Guchar
* /*alphaLine*/) {
2914 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
2916 SplashColorPtr q
, col
;
2925 if (imgData
->y
== imgData
->height
) {
2928 if (!(p
= imgData
->imgStr
->getLine())) {
2930 if (imgData
->colorMode
== splashModeRGB8
|| imgData
->colorMode
== splashModeBGR8
)
2932 else if (imgData
->colorMode
== splashModeXBGR8
)
2935 else if (imgData
->colorMode
== splashModeCMYK8
)
2937 else if (imgData
->colorMode
== splashModeDeviceN8
)
2938 destComps
= SPOT_NCOMPS
+ 4;
2940 memset(colorLine
, 0, imgData
->width
* destComps
);
2944 nComps
= imgData
->colorMap
->getNumPixelComps();
2946 if (imgData
->lookup
) {
2947 switch (imgData
->colorMode
) {
2948 case splashModeMono1
:
2949 case splashModeMono8
:
2950 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2951 *q
++ = imgData
->lookup
[*p
];
2954 case splashModeRGB8
:
2955 case splashModeBGR8
:
2956 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2957 col
= &imgData
->lookup
[3 * *p
];
2963 case splashModeXBGR8
:
2964 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2965 col
= &imgData
->lookup
[4 * *p
];
2973 case splashModeCMYK8
:
2974 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2975 col
= &imgData
->lookup
[4 * *p
];
2982 case splashModeDeviceN8
:
2983 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2984 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
2985 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
2992 switch (imgData
->colorMode
) {
2993 case splashModeMono1
:
2994 case splashModeMono8
:
2995 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
2996 imgData
->colorMap
->getGray(p
, &gray
);
2997 *q
++ = colToByte(gray
);
3000 case splashModeRGB8
:
3001 case splashModeBGR8
:
3002 if (imgData
->colorMap
->useRGBLine()) {
3003 imgData
->colorMap
->getRGBLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3005 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3006 imgData
->colorMap
->getRGB(p
, &rgb
);
3007 *q
++ = colToByte(rgb
.r
);
3008 *q
++ = colToByte(rgb
.g
);
3009 *q
++ = colToByte(rgb
.b
);
3013 case splashModeXBGR8
:
3014 if (imgData
->colorMap
->useRGBLine()) {
3015 imgData
->colorMap
->getRGBXLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3017 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3018 imgData
->colorMap
->getRGB(p
, &rgb
);
3019 *q
++ = colToByte(rgb
.r
);
3020 *q
++ = colToByte(rgb
.g
);
3021 *q
++ = colToByte(rgb
.b
);
3027 case splashModeCMYK8
:
3028 if (imgData
->colorMap
->useCMYKLine()) {
3029 imgData
->colorMap
->getCMYKLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3031 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3032 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3033 *q
++ = colToByte(cmyk
.c
);
3034 *q
++ = colToByte(cmyk
.m
);
3035 *q
++ = colToByte(cmyk
.y
);
3036 *q
++ = colToByte(cmyk
.k
);
3040 case splashModeDeviceN8
:
3041 if (imgData
->colorMap
->useDeviceNLine()) {
3042 imgData
->colorMap
->getDeviceNLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3044 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3045 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3046 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3047 *q
++ = colToByte(deviceN
.c
[cp
]);
3060 GBool
SplashOutputDev::iccImageSrc(void *data
, SplashColorPtr colorLine
,
3061 Guchar
* /*alphaLine*/) {
3062 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3066 if (imgData
->y
== imgData
->height
) {
3069 if (!(p
= imgData
->imgStr
->getLine())) {
3071 if (imgData
->colorMode
== splashModeRGB8
|| imgData
->colorMode
== splashModeBGR8
)
3073 else if (imgData
->colorMode
== splashModeXBGR8
)
3076 else if (imgData
->colorMode
== splashModeCMYK8
)
3078 else if (imgData
->colorMode
== splashModeDeviceN8
)
3079 destComps
= SPOT_NCOMPS
+ 4;
3081 memset(colorLine
, 0, imgData
->width
* destComps
);
3085 if (imgData
->colorMode
== splashModeXBGR8
) {
3088 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
) {
3095 nComps
= imgData
->colorMap
->getNumPixelComps();
3096 memcpy(colorLine
, p
, imgData
->width
* nComps
);
3103 void SplashOutputDev::iccTransform(void *data
, SplashBitmap
*bitmap
) {
3104 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3105 int nComps
= imgData
->colorMap
->getNumPixelComps();
3107 Guchar
*colorLine
= (Guchar
*) gmalloc(nComps
* bitmap
->getWidth());
3108 Guchar
*rgbxLine
= (imgData
->colorMode
== splashModeXBGR8
) ? (Guchar
*) gmalloc(3 * bitmap
->getWidth()) : NULL
;
3109 for (int i
= 0; i
< bitmap
->getHeight(); i
++) {
3110 Guchar
*p
= bitmap
->getDataPtr() + i
* bitmap
->getRowSize();
3111 switch (imgData
->colorMode
) {
3112 case splashModeMono1
:
3113 case splashModeMono8
:
3114 imgData
->colorMap
->getGrayLine(p
, colorLine
, bitmap
->getWidth());
3115 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3117 case splashModeRGB8
:
3118 case splashModeBGR8
:
3119 imgData
->colorMap
->getRGBLine(p
, colorLine
, bitmap
->getWidth());
3120 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3123 case splashModeCMYK8
:
3124 imgData
->colorMap
->getCMYKLine(p
, colorLine
, bitmap
->getWidth());
3125 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3128 case splashModeXBGR8
:
3132 for (x
= 0, q
= rgbxLine
; x
< bitmap
->getWidth(); ++x
, ++b
) {
3137 imgData
->colorMap
->getRGBLine(rgbxLine
, colorLine
, bitmap
->getWidth());
3139 for (x
= 0, q
= colorLine
; x
< bitmap
->getWidth(); ++x
, ++b
) {
3148 if (rgbxLine
!= NULL
)
3153 GBool
SplashOutputDev::alphaImageSrc(void *data
, SplashColorPtr colorLine
,
3154 Guchar
*alphaLine
) {
3155 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3157 SplashColorPtr q
, col
;
3167 if (imgData
->y
== imgData
->height
) {
3170 if (!(p
= imgData
->imgStr
->getLine())) {
3174 nComps
= imgData
->colorMap
->getNumPixelComps();
3176 for (x
= 0, q
= colorLine
, aq
= alphaLine
;
3180 for (i
= 0; i
< nComps
; ++i
) {
3181 if (p
[i
] < imgData
->maskColors
[2*i
] ||
3182 p
[i
] > imgData
->maskColors
[2*i
+1]) {
3187 if (imgData
->lookup
) {
3188 switch (imgData
->colorMode
) {
3189 case splashModeMono1
:
3190 case splashModeMono8
:
3191 *q
++ = imgData
->lookup
[*p
];
3193 case splashModeRGB8
:
3194 case splashModeBGR8
:
3195 col
= &imgData
->lookup
[3 * *p
];
3200 case splashModeXBGR8
:
3201 col
= &imgData
->lookup
[4 * *p
];
3208 case splashModeCMYK8
:
3209 col
= &imgData
->lookup
[4 * *p
];
3215 case splashModeDeviceN8
:
3216 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
3217 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3224 switch (imgData
->colorMode
) {
3225 case splashModeMono1
:
3226 case splashModeMono8
:
3227 imgData
->colorMap
->getGray(p
, &gray
);
3228 *q
++ = colToByte(gray
);
3230 case splashModeXBGR8
:
3231 case splashModeRGB8
:
3232 case splashModeBGR8
:
3233 imgData
->colorMap
->getRGB(p
, &rgb
);
3234 *q
++ = colToByte(rgb
.r
);
3235 *q
++ = colToByte(rgb
.g
);
3236 *q
++ = colToByte(rgb
.b
);
3237 if (imgData
->colorMode
== splashModeXBGR8
) *q
++ = 255;
3240 case splashModeCMYK8
:
3241 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3242 *q
++ = colToByte(cmyk
.c
);
3243 *q
++ = colToByte(cmyk
.m
);
3244 *q
++ = colToByte(cmyk
.y
);
3245 *q
++ = colToByte(cmyk
.k
);
3247 case splashModeDeviceN8
:
3248 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3249 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3250 *q
++ = colToByte(deviceN
.c
[cp
]);
3262 struct TilingSplashOutBitmap
{
3263 SplashBitmap
*bitmap
;
3264 SplashPattern
*pattern
;
3265 SplashColorMode colorMode
;
3272 GBool
SplashOutputDev::tilingBitmapSrc(void *data
, SplashColorPtr colorLine
,
3273 Guchar
*alphaLine
) {
3274 TilingSplashOutBitmap
*imgData
= (TilingSplashOutBitmap
*)data
;
3276 if (imgData
->y
== imgData
->bitmap
->getHeight()) {
3278 if (imgData
->repeatY
== 0)
3283 if (imgData
->paintType
== 1) {
3284 const SplashColorMode cMode
= imgData
->bitmap
->getMode();
3285 SplashColorPtr q
= colorLine
;
3286 // For splashModeBGR8 and splashModeXBGR8 we need to use getPixel
3287 // for the others we can use raw access
3288 if (cMode
== splashModeBGR8
|| cMode
== splashModeXBGR8
) {
3289 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3290 for (int x
= 0; x
< imgData
->bitmap
->getWidth(); x
++) {
3291 imgData
->bitmap
->getPixel(x
, imgData
->y
, q
);
3292 q
+= splashColorModeNComps
[cMode
];
3296 const int n
= imgData
->bitmap
->getRowSize();
3298 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3299 p
= imgData
->bitmap
->getDataPtr() + imgData
->y
* imgData
->bitmap
->getRowSize();
3300 for (int x
= 0; x
< n
; ++x
) {
3305 if (alphaLine
!= NULL
) {
3306 SplashColorPtr aq
= alphaLine
;
3308 const int n
= imgData
->bitmap
->getWidth() - 1;
3309 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3310 p
= imgData
->bitmap
->getAlphaPtr() + imgData
->y
* imgData
->bitmap
->getWidth();
3311 for (int x
= 0; x
< n
; ++x
) {
3314 // This is a hack, because of how Splash antialias works if we overwrite the
3315 // last alpha pixel of the tile most/all of the files look much better
3316 *aq
++ = (n
== 0) ? *p
: *(p
- 1);
3320 SplashColor col
, pat
;
3321 SplashColorPtr dest
= colorLine
;
3322 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3323 for (int x
= 0; x
< imgData
->bitmap
->getWidth(); x
++) {
3324 imgData
->bitmap
->getPixel(x
, imgData
->y
, col
);
3325 imgData
->pattern
->getColor(x
, imgData
->y
, pat
);
3326 for (int i
= 0; i
< splashColorModeNComps
[imgData
->colorMode
]; ++i
) {
3328 if (imgData
->colorMode
== splashModeCMYK8
|| imgData
->colorMode
== splashModeDeviceN8
)
3329 dest
[i
] = div255(pat
[i
] * (255 - col
[0]));
3332 dest
[i
] = 255 - div255((255 - pat
[i
]) * (255 - col
[0]));
3334 dest
+= splashColorModeNComps
[imgData
->colorMode
];
3337 if (alphaLine
!= NULL
) {
3338 const int y
= (imgData
->y
== imgData
->bitmap
->getHeight() - 1 && imgData
->y
> 50) ? imgData
->y
- 1 : imgData
->y
;
3339 SplashColorPtr aq
= alphaLine
;
3341 const int n
= imgData
->bitmap
->getWidth();
3342 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3343 p
= imgData
->bitmap
->getAlphaPtr() + y
* imgData
->bitmap
->getWidth();
3344 for (int x
= 0; x
< n
; ++x
) {
3354 void SplashOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3355 int width
, int height
,
3356 GfxImageColorMap
*colorMap
,
3358 int *maskColors
, GBool inlineImg
) {
3361 SplashOutImageData imgData
;
3362 SplashColorMode srcMode
;
3363 SplashImageSource src
;
3364 SplashICCTransform tf
;
3369 GBool grayIndexed
= gFalse
;
3375 ctm
= state
->getCTM();
3376 for (i
= 0; i
< 6; ++i
) {
3377 if (!isfinite(ctm
[i
])) return;
3383 mat
[4] = ctm
[2] + ctm
[4];
3384 mat
[5] = ctm
[3] + ctm
[5];
3386 imgData
.imgStr
= new ImageStream(str
, width
,
3387 colorMap
->getNumPixelComps(),
3388 colorMap
->getBits());
3389 imgData
.imgStr
->reset();
3390 imgData
.colorMap
= colorMap
;
3391 imgData
.maskColors
= maskColors
;
3392 imgData
.colorMode
= colorMode
;
3393 imgData
.width
= width
;
3394 imgData
.height
= height
;
3397 // special case for one-channel (monochrome/gray/separation) images:
3398 // build a lookup table here
3399 imgData
.lookup
= NULL
;
3400 if (colorMap
->getNumPixelComps() == 1) {
3401 n
= 1 << colorMap
->getBits();
3402 switch (colorMode
) {
3403 case splashModeMono1
:
3404 case splashModeMono8
:
3405 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3406 for (i
= 0; i
< n
; ++i
) {
3408 colorMap
->getGray(&pix
, &gray
);
3409 imgData
.lookup
[i
] = colToByte(gray
);
3412 case splashModeRGB8
:
3413 case splashModeBGR8
:
3414 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3415 for (i
= 0; i
< n
; ++i
) {
3417 colorMap
->getRGB(&pix
, &rgb
);
3418 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3419 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3420 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3423 case splashModeXBGR8
:
3424 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3425 for (i
= 0; i
< n
; ++i
) {
3427 colorMap
->getRGB(&pix
, &rgb
);
3428 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3429 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3430 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3431 imgData
.lookup
[4*i
+3] = 255;
3435 case splashModeCMYK8
:
3436 grayIndexed
= colorMap
->getColorSpace()->getMode() != csDeviceGray
;
3437 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3438 for (i
= 0; i
< n
; ++i
) {
3440 colorMap
->getCMYK(&pix
, &cmyk
);
3441 if (cmyk
.c
!= 0 || cmyk
.m
!= 0 || cmyk
.y
!= 0) {
3442 grayIndexed
= gFalse
;
3444 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3445 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3446 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3447 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3450 case splashModeDeviceN8
:
3451 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3452 grayIndexed
= colorMap
->getColorSpace()->getMode() != csDeviceGray
;
3453 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3454 for (i
= 0; i
< n
; ++i
) {
3456 colorMap
->getCMYK(&pix
, &cmyk
);
3457 if (cmyk
.c
!= 0 || cmyk
.m
!= 0 || cmyk
.y
!= 0) {
3458 grayIndexed
= gFalse
;
3460 colorMap
->getDeviceN(&pix
, &deviceN
);
3461 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3462 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+cp
] = colToByte(deviceN
.c
[cp
]);
3470 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3471 state
->getOverprintMode(), NULL
, grayIndexed
);
3473 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3474 state
->getOverprintMode(), NULL
);
3477 if (colorMode
== splashModeMono1
) {
3478 srcMode
= splashModeMono8
;
3480 srcMode
= colorMode
;
3483 src
= maskColors
? &alphaImageSrc
: useIccImageSrc(&imgData
) ? &iccImageSrc
: &imageSrc
;
3484 tf
= maskColors
== NULL
&& useIccImageSrc(&imgData
) ? &iccTransform
: NULL
;
3486 src
= maskColors
? &alphaImageSrc
: &imageSrc
;
3489 splash
->drawImage(src
, tf
, &imgData
, srcMode
, maskColors
? gTrue
: gFalse
,
3490 width
, height
, mat
, interpolate
);
3492 while (imgData
.y
< height
) {
3493 imgData
.imgStr
->getLine();
3498 gfree(imgData
.lookup
);
3499 delete imgData
.imgStr
;
3503 struct SplashOutMaskedImageData
{
3504 ImageStream
*imgStr
;
3505 GfxImageColorMap
*colorMap
;
3507 SplashColorPtr lookup
;
3508 SplashColorMode colorMode
;
3509 int width
, height
, y
;
3512 GBool
SplashOutputDev::maskedImageSrc(void *data
, SplashColorPtr colorLine
,
3513 Guchar
*alphaLine
) {
3514 SplashOutMaskedImageData
*imgData
= (SplashOutMaskedImageData
*)data
;
3516 SplashColorPtr q
, col
;
3528 if (imgData
->y
== imgData
->height
) {
3531 if (!(p
= imgData
->imgStr
->getLine())) {
3535 nComps
= imgData
->colorMap
->getNumPixelComps();
3537 maskPtr
= imgData
->mask
->getDataPtr() +
3538 imgData
->y
* imgData
->mask
->getRowSize();
3540 for (x
= 0, q
= colorLine
, aq
= alphaLine
;
3543 alpha
= (*maskPtr
& maskBit
) ? 0xff : 0x00;
3544 if (!(maskBit
>>= 1)) {
3548 if (imgData
->lookup
) {
3549 switch (imgData
->colorMode
) {
3550 case splashModeMono1
:
3551 case splashModeMono8
:
3552 *q
++ = imgData
->lookup
[*p
];
3554 case splashModeRGB8
:
3555 case splashModeBGR8
:
3556 col
= &imgData
->lookup
[3 * *p
];
3561 case splashModeXBGR8
:
3562 col
= &imgData
->lookup
[4 * *p
];
3569 case splashModeCMYK8
:
3570 col
= &imgData
->lookup
[4 * *p
];
3576 case splashModeDeviceN8
:
3577 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
3578 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3585 switch (imgData
->colorMode
) {
3586 case splashModeMono1
:
3587 case splashModeMono8
:
3588 imgData
->colorMap
->getGray(p
, &gray
);
3589 *q
++ = colToByte(gray
);
3591 case splashModeXBGR8
:
3592 case splashModeRGB8
:
3593 case splashModeBGR8
:
3594 imgData
->colorMap
->getRGB(p
, &rgb
);
3595 *q
++ = colToByte(rgb
.r
);
3596 *q
++ = colToByte(rgb
.g
);
3597 *q
++ = colToByte(rgb
.b
);
3598 if (imgData
->colorMode
== splashModeXBGR8
) *q
++ = 255;
3601 case splashModeCMYK8
:
3602 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3603 *q
++ = colToByte(cmyk
.c
);
3604 *q
++ = colToByte(cmyk
.m
);
3605 *q
++ = colToByte(cmyk
.y
);
3606 *q
++ = colToByte(cmyk
.k
);
3608 case splashModeDeviceN8
:
3609 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3610 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3611 *q
++ = colToByte(deviceN
.c
[cp
]);
3623 void SplashOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
,
3624 Stream
*str
, int width
, int height
,
3625 GfxImageColorMap
*colorMap
,
3627 Stream
*maskStr
, int maskWidth
,
3628 int maskHeight
, GBool maskInvert
,
3629 GBool maskInterpolate
) {
3630 GfxImageColorMap
*maskColorMap
;
3631 Object maskDecode
, decodeLow
, decodeHigh
;
3634 SplashOutMaskedImageData imgData
;
3635 SplashOutImageMaskData imgMaskData
;
3636 SplashColorMode srcMode
;
3637 SplashBitmap
*maskBitmap
;
3639 SplashColor maskColor
;
3650 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3652 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3653 state
->getOverprintMode(), NULL
);
3655 // If the mask is higher resolution than the image, use
3656 // drawSoftMaskedImage() instead.
3657 if (maskWidth
> width
|| maskHeight
> height
) {
3658 decodeLow
.initInt(maskInvert
? 0 : 1);
3659 decodeHigh
.initInt(maskInvert
? 1 : 0);
3660 maskDecode
.initArray((xref
) ? xref
: doc
->getXRef());
3661 maskDecode
.arrayAdd(&decodeLow
);
3662 maskDecode
.arrayAdd(&decodeHigh
);
3663 maskColorMap
= new GfxImageColorMap(1, &maskDecode
,
3664 new GfxDeviceGrayColorSpace());
3666 drawSoftMaskedImage(state
, ref
, str
, width
, height
, colorMap
, interpolate
,
3667 maskStr
, maskWidth
, maskHeight
, maskColorMap
, maskInterpolate
);
3668 delete maskColorMap
;
3671 //----- scale the mask image to the same size as the source image
3673 mat
[0] = (SplashCoord
)width
;
3676 mat
[3] = (SplashCoord
)height
;
3679 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3680 imgMaskData
.imgStr
->reset();
3681 imgMaskData
.invert
= maskInvert
? 0 : 1;
3682 imgMaskData
.width
= maskWidth
;
3683 imgMaskData
.height
= maskHeight
;
3685 maskBitmap
= new SplashBitmap(width
, height
, 1, splashModeMono1
, gFalse
);
3686 maskSplash
= new Splash(maskBitmap
, gFalse
);
3688 maskSplash
->clear(maskColor
);
3689 maskColor
[0] = 0xff;
3690 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
3691 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
,
3692 maskWidth
, maskHeight
, mat
, gFalse
);
3693 delete imgMaskData
.imgStr
;
3697 //----- draw the source image
3699 ctm
= state
->getCTM();
3700 for (i
= 0; i
< 6; ++i
) {
3701 if (!isfinite(ctm
[i
])) {
3710 mat
[4] = ctm
[2] + ctm
[4];
3711 mat
[5] = ctm
[3] + ctm
[5];
3713 imgData
.imgStr
= new ImageStream(str
, width
,
3714 colorMap
->getNumPixelComps(),
3715 colorMap
->getBits());
3716 imgData
.imgStr
->reset();
3717 imgData
.colorMap
= colorMap
;
3718 imgData
.mask
= maskBitmap
;
3719 imgData
.colorMode
= colorMode
;
3720 imgData
.width
= width
;
3721 imgData
.height
= height
;
3724 // special case for one-channel (monochrome/gray/separation) images:
3725 // build a lookup table here
3726 imgData
.lookup
= NULL
;
3727 if (colorMap
->getNumPixelComps() == 1) {
3728 n
= 1 << colorMap
->getBits();
3729 switch (colorMode
) {
3730 case splashModeMono1
:
3731 case splashModeMono8
:
3732 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3733 for (i
= 0; i
< n
; ++i
) {
3735 colorMap
->getGray(&pix
, &gray
);
3736 imgData
.lookup
[i
] = colToByte(gray
);
3739 case splashModeRGB8
:
3740 case splashModeBGR8
:
3741 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3742 for (i
= 0; i
< n
; ++i
) {
3744 colorMap
->getRGB(&pix
, &rgb
);
3745 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3746 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3747 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3750 case splashModeXBGR8
:
3751 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3752 for (i
= 0; i
< n
; ++i
) {
3754 colorMap
->getRGB(&pix
, &rgb
);
3755 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3756 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3757 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3758 imgData
.lookup
[4*i
+3] = 255;
3762 case splashModeCMYK8
:
3763 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3764 for (i
= 0; i
< n
; ++i
) {
3766 colorMap
->getCMYK(&pix
, &cmyk
);
3767 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3768 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3769 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3770 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3773 case splashModeDeviceN8
:
3774 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3775 for (i
= 0; i
< n
; ++i
) {
3777 colorMap
->getDeviceN(&pix
, &deviceN
);
3778 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3779 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+ cp
] = colToByte(deviceN
.c
[cp
]);
3786 if (colorMode
== splashModeMono1
) {
3787 srcMode
= splashModeMono8
;
3789 srcMode
= colorMode
;
3791 splash
->drawImage(&maskedImageSrc
, NULL
, &imgData
, srcMode
, gTrue
,
3792 width
, height
, mat
, interpolate
);
3794 gfree(imgData
.lookup
);
3795 delete imgData
.imgStr
;
3800 void SplashOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
,
3801 Stream
*str
, int width
, int height
,
3802 GfxImageColorMap
*colorMap
,
3805 int maskWidth
, int maskHeight
,
3806 GfxImageColorMap
*maskColorMap
,
3807 GBool maskInterpolate
) {
3810 SplashOutImageData imgData
;
3811 SplashOutImageData imgMaskData
;
3812 SplashColorMode srcMode
;
3813 SplashBitmap
*maskBitmap
;
3815 SplashColor maskColor
;
3826 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3828 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3829 state
->getOverprintMode(), NULL
);
3831 ctm
= state
->getCTM();
3832 for (i
= 0; i
< 6; ++i
) {
3833 if (!isfinite(ctm
[i
])) return;
3839 mat
[4] = ctm
[2] + ctm
[4];
3840 mat
[5] = ctm
[3] + ctm
[5];
3842 //----- set up the soft mask
3844 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
,
3845 maskColorMap
->getNumPixelComps(),
3846 maskColorMap
->getBits());
3847 imgMaskData
.imgStr
->reset();
3848 imgMaskData
.colorMap
= maskColorMap
;
3849 imgMaskData
.maskColors
= NULL
;
3850 imgMaskData
.colorMode
= splashModeMono8
;
3851 imgMaskData
.width
= maskWidth
;
3852 imgMaskData
.height
= maskHeight
;
3854 n
= 1 << maskColorMap
->getBits();
3855 imgMaskData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3856 for (i
= 0; i
< n
; ++i
) {
3858 maskColorMap
->getGray(&pix
, &gray
);
3859 imgMaskData
.lookup
[i
] = colToByte(gray
);
3861 maskBitmap
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
3862 1, splashModeMono8
, gFalse
);
3863 maskSplash
= new Splash(maskBitmap
, vectorAntialias
);
3865 maskSplash
->clear(maskColor
);
3866 maskSplash
->drawImage(&imageSrc
, NULL
, &imgMaskData
, splashModeMono8
, gFalse
,
3867 maskWidth
, maskHeight
, mat
, maskInterpolate
);
3868 delete imgMaskData
.imgStr
;
3870 gfree(imgMaskData
.lookup
);
3872 splash
->setSoftMask(maskBitmap
);
3874 //----- draw the source image
3876 imgData
.imgStr
= new ImageStream(str
, width
,
3877 colorMap
->getNumPixelComps(),
3878 colorMap
->getBits());
3879 imgData
.imgStr
->reset();
3880 imgData
.colorMap
= colorMap
;
3881 imgData
.maskColors
= NULL
;
3882 imgData
.colorMode
= colorMode
;
3883 imgData
.width
= width
;
3884 imgData
.height
= height
;
3887 // special case for one-channel (monochrome/gray/separation) images:
3888 // build a lookup table here
3889 imgData
.lookup
= NULL
;
3890 if (colorMap
->getNumPixelComps() == 1) {
3891 n
= 1 << colorMap
->getBits();
3892 switch (colorMode
) {
3893 case splashModeMono1
:
3894 case splashModeMono8
:
3895 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3896 for (i
= 0; i
< n
; ++i
) {
3898 colorMap
->getGray(&pix
, &gray
);
3899 imgData
.lookup
[i
] = colToByte(gray
);
3902 case splashModeRGB8
:
3903 case splashModeBGR8
:
3904 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3905 for (i
= 0; i
< n
; ++i
) {
3907 colorMap
->getRGB(&pix
, &rgb
);
3908 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3909 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3910 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3913 case splashModeXBGR8
:
3914 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3915 for (i
= 0; i
< n
; ++i
) {
3917 colorMap
->getRGB(&pix
, &rgb
);
3918 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3919 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3920 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3921 imgData
.lookup
[4*i
+3] = 255;
3925 case splashModeCMYK8
:
3926 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3927 for (i
= 0; i
< n
; ++i
) {
3929 colorMap
->getCMYK(&pix
, &cmyk
);
3930 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3931 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3932 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3933 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3936 case splashModeDeviceN8
:
3937 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3938 for (i
= 0; i
< n
; ++i
) {
3940 colorMap
->getDeviceN(&pix
, &deviceN
);
3941 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3942 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+ cp
] = colToByte(deviceN
.c
[cp
]);
3949 if (colorMode
== splashModeMono1
) {
3950 srcMode
= splashModeMono8
;
3952 srcMode
= colorMode
;
3954 splash
->drawImage(&imageSrc
, NULL
, &imgData
, srcMode
, gFalse
, width
, height
, mat
, interpolate
);
3955 splash
->setSoftMask(NULL
);
3956 gfree(imgData
.lookup
);
3957 delete imgData
.imgStr
;
3961 GBool
SplashOutputDev::checkTransparencyGroup(GfxState
*state
, GBool knockout
) {
3962 if (state
->getFillOpacity() != 1 ||
3963 state
->getStrokeOpacity() != 1 ||
3964 state
->getAlphaIsShape() ||
3965 state
->getBlendMode() != gfxBlendNormal
||
3966 splash
->getSoftMask() != NULL
||
3969 return transpGroupStack
!= NULL
&& transpGroupStack
->shape
!= NULL
;
3972 void SplashOutputDev::beginTransparencyGroup(GfxState
*state
, double *bbox
,
3973 GfxColorSpace
*blendingColorSpace
,
3974 GBool isolated
, GBool knockout
,
3975 GBool forSoftMask
) {
3976 SplashTransparencyGroup
*transpGroup
;
3978 double xMin
, yMin
, xMax
, yMax
, x
, y
;
3979 int tx
, ty
, w
, h
, i
;
3981 // transform the bbox
3982 state
->transform(bbox
[0], bbox
[1], &x
, &y
);
3985 state
->transform(bbox
[0], bbox
[3], &x
, &y
);
3988 } else if (x
> xMax
) {
3993 } else if (y
> yMax
) {
3996 state
->transform(bbox
[2], bbox
[1], &x
, &y
);
3999 } else if (x
> xMax
) {
4004 } else if (y
> yMax
) {
4007 state
->transform(bbox
[2], bbox
[3], &x
, &y
);
4010 } else if (x
> xMax
) {
4015 } else if (y
> yMax
) {
4018 tx
= (int)floor(xMin
);
4021 } else if (tx
>= bitmap
->getWidth()) {
4022 tx
= bitmap
->getWidth() - 1;
4024 ty
= (int)floor(yMin
);
4027 } else if (ty
>= bitmap
->getHeight()) {
4028 ty
= bitmap
->getHeight() - 1;
4030 w
= (int)ceil(xMax
) - tx
+ 1;
4031 if (tx
+ w
> bitmap
->getWidth()) {
4032 w
= bitmap
->getWidth() - tx
;
4037 h
= (int)ceil(yMax
) - ty
+ 1;
4038 if (ty
+ h
> bitmap
->getHeight()) {
4039 h
= bitmap
->getHeight() - ty
;
4045 // push a new stack entry
4046 transpGroup
= new SplashTransparencyGroup();
4047 transpGroup
->softmask
= NULL
;
4048 transpGroup
->tx
= tx
;
4049 transpGroup
->ty
= ty
;
4050 transpGroup
->blendingColorSpace
= blendingColorSpace
;
4051 transpGroup
->isolated
= isolated
;
4052 transpGroup
->shape
= (knockout
&& !isolated
) ? SplashBitmap::copy(bitmap
) : NULL
;
4053 transpGroup
->knockout
= (knockout
&& isolated
);
4054 transpGroup
->knockoutOpacity
= 1.0;
4055 transpGroup
->next
= transpGroupStack
;
4056 transpGroupStack
= transpGroup
;
4059 transpGroup
->origBitmap
= bitmap
;
4060 transpGroup
->origSplash
= splash
;
4061 transpGroup
->fontAA
= fontEngine
->getAA();
4063 //~ this handles the blendingColorSpace arg for soft masks, but
4064 //~ not yet for transparency groups
4066 // switch to the blending color space
4067 if (forSoftMask
&& isolated
&& blendingColorSpace
) {
4068 if (blendingColorSpace
->getMode() == csDeviceGray
||
4069 blendingColorSpace
->getMode() == csCalGray
||
4070 (blendingColorSpace
->getMode() == csICCBased
&&
4071 blendingColorSpace
->getNComps() == 1)) {
4072 colorMode
= splashModeMono8
;
4073 } else if (blendingColorSpace
->getMode() == csDeviceRGB
||
4074 blendingColorSpace
->getMode() == csCalRGB
||
4075 (blendingColorSpace
->getMode() == csICCBased
&&
4076 blendingColorSpace
->getNComps() == 3)) {
4077 //~ does this need to use BGR8?
4078 colorMode
= splashModeRGB8
;
4080 } else if (blendingColorSpace
->getMode() == csDeviceCMYK
||
4081 (blendingColorSpace
->getMode() == csICCBased
&&
4082 blendingColorSpace
->getNComps() == 4)) {
4083 colorMode
= splashModeCMYK8
;
4088 // create the temporary bitmap
4089 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
, gTrue
,
4090 bitmapTopDown
, bitmap
->getSeparationList());
4091 splash
= new Splash(bitmap
, vectorAntialias
,
4092 transpGroup
->origSplash
->getScreen());
4093 if (transpGroup
->next
!= NULL
&& transpGroup
->next
->knockout
) {
4094 fontEngine
->setAA(gFalse
);
4096 splash
->setThinLineMode(transpGroup
->origSplash
->getThinLineMode());
4097 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
4098 //~ Acrobat apparently copies at least the fill and stroke colors, and
4099 //~ maybe other state(?) -- but not the clipping path (and not sure
4101 //~ [this is likely the same situation as in type3D1()]
4102 splash
->setFillPattern(transpGroup
->origSplash
->getFillPattern()->copy());
4103 splash
->setStrokePattern(
4104 transpGroup
->origSplash
->getStrokePattern()->copy());
4106 for (i
= 0; i
< splashMaxColorComps
; ++i
) {
4109 if (colorMode
== splashModeXBGR8
) color
[3] = 255;
4110 splash
->clear(color
, 0);
4112 SplashBitmap
*shape
= (knockout
) ? transpGroup
->shape
:
4113 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->shape
: transpGroup
->origBitmap
;
4114 int shapeTx
= (knockout
) ? tx
:
4115 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->tx
+ tx
: tx
;
4116 int shapeTy
= (knockout
) ? ty
:
4117 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->ty
+ ty
: ty
;
4118 splash
->blitTransparent(transpGroup
->origBitmap
, tx
, ty
, 0, 0, w
, h
);
4119 splash
->setInNonIsolatedGroup(shape
, shapeTx
, shapeTy
);
4121 transpGroup
->tBitmap
= bitmap
;
4122 state
->shiftCTMAndClip(-tx
, -ty
);
4123 updateCTM(state
, 0, 0, 0, 0, 0, 0);
4127 void SplashOutputDev::endTransparencyGroup(GfxState
*state
) {
4131 bitmap
= transpGroupStack
->origBitmap
;
4132 colorMode
= bitmap
->getMode();
4133 splash
= transpGroupStack
->origSplash
;
4134 state
->shiftCTMAndClip(transpGroupStack
->tx
, transpGroupStack
->ty
);
4135 updateCTM(state
, 0, 0, 0, 0, 0, 0);
4138 void SplashOutputDev::paintTransparencyGroup(GfxState
*state
, double *bbox
) {
4139 SplashBitmap
*tBitmap
;
4140 SplashTransparencyGroup
*transpGroup
;
4144 tx
= transpGroupStack
->tx
;
4145 ty
= transpGroupStack
->ty
;
4146 tBitmap
= transpGroupStack
->tBitmap
;
4147 isolated
= transpGroupStack
->isolated
;
4149 // paint the transparency group onto the parent bitmap
4150 // - the clip path was set in the parent's state)
4151 if (tx
< bitmap
->getWidth() && ty
< bitmap
->getHeight()) {
4152 SplashCoord knockoutOpacity
= (transpGroupStack
->next
!= NULL
) ? transpGroupStack
->next
->knockoutOpacity
4153 : transpGroupStack
->knockoutOpacity
;
4154 splash
->setOverprintMask(0xffffffff, gFalse
);
4155 splash
->composite(tBitmap
, 0, 0, tx
, ty
,
4156 tBitmap
->getWidth(), tBitmap
->getHeight(),
4157 gFalse
, !isolated
, transpGroupStack
->next
!= NULL
&& transpGroupStack
->next
->knockout
, knockoutOpacity
);
4158 fontEngine
->setAA(transpGroupStack
->fontAA
);
4159 if (transpGroupStack
->next
!= NULL
&& transpGroupStack
->next
->shape
!= NULL
) {
4160 transpGroupStack
->next
->knockout
= gTrue
;
4165 transpGroup
= transpGroupStack
;
4166 transpGroupStack
= transpGroup
->next
;
4167 if (transpGroupStack
!= NULL
&& transpGroup
->knockoutOpacity
< transpGroupStack
->knockoutOpacity
) {
4168 transpGroupStack
->knockoutOpacity
= transpGroup
->knockoutOpacity
;
4170 delete transpGroup
->shape
;
4176 void SplashOutputDev::setSoftMask(GfxState
*state
, double *bbox
,
4177 GBool alpha
, Function
*transferFunc
,
4178 GfxColor
*backdropColor
) {
4179 SplashBitmap
*softMask
, *tBitmap
;
4181 SplashTransparencyGroup
*transpGroup
;
4193 tx
= transpGroupStack
->tx
;
4194 ty
= transpGroupStack
->ty
;
4195 tBitmap
= transpGroupStack
->tBitmap
;
4197 // composite with backdrop color
4198 if (!alpha
&& tBitmap
->getMode() != splashModeMono1
) {
4199 //~ need to correctly handle the case where no blending color
4201 if (transpGroupStack
->blendingColorSpace
) {
4202 tSplash
= new Splash(tBitmap
, vectorAntialias
,
4203 transpGroupStack
->origSplash
->getScreen());
4204 switch (tBitmap
->getMode()) {
4205 case splashModeMono1
:
4206 // transparency is not supported in mono1 mode
4208 case splashModeMono8
:
4209 transpGroupStack
->blendingColorSpace
->getGray(backdropColor
, &gray
);
4210 color
[0] = colToByte(gray
);
4211 tSplash
->compositeBackground(color
);
4213 case splashModeXBGR8
:
4215 case splashModeRGB8
:
4216 case splashModeBGR8
:
4217 transpGroupStack
->blendingColorSpace
->getRGB(backdropColor
, &rgb
);
4218 color
[0] = colToByte(rgb
.r
);
4219 color
[1] = colToByte(rgb
.g
);
4220 color
[2] = colToByte(rgb
.b
);
4221 tSplash
->compositeBackground(color
);
4224 case splashModeCMYK8
:
4225 transpGroupStack
->blendingColorSpace
->getCMYK(backdropColor
, &cmyk
);
4226 color
[0] = colToByte(cmyk
.c
);
4227 color
[1] = colToByte(cmyk
.m
);
4228 color
[2] = colToByte(cmyk
.y
);
4229 color
[3] = colToByte(cmyk
.k
);
4230 tSplash
->compositeBackground(color
);
4232 case splashModeDeviceN8
:
4233 transpGroupStack
->blendingColorSpace
->getDeviceN(backdropColor
, &deviceN
);
4234 for (int cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
4235 color
[cp
] = colToByte(deviceN
.c
[cp
]);
4236 tSplash
->compositeBackground(color
);
4244 softMask
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
4245 1, splashModeMono8
, gFalse
);
4246 unsigned char fill
= 0;
4247 if (transpGroupStack
->blendingColorSpace
) {
4248 transpGroupStack
->blendingColorSpace
->getGray(backdropColor
, &gray
);
4249 fill
= colToByte(gray
);
4251 memset(softMask
->getDataPtr(), fill
,
4252 softMask
->getRowSize() * softMask
->getHeight());
4253 p
= softMask
->getDataPtr() + ty
* softMask
->getRowSize() + tx
;
4254 int xMax
= tBitmap
->getWidth();
4255 int yMax
= tBitmap
->getHeight();
4256 if (xMax
> bitmap
->getWidth() - tx
) xMax
= bitmap
->getWidth() - tx
;
4257 if (yMax
> bitmap
->getHeight() - ty
) yMax
= bitmap
->getHeight() - ty
;
4258 for (y
= 0; y
< yMax
; ++y
) {
4259 for (x
= 0; x
< xMax
; ++x
) {
4262 lum
= tBitmap
->getAlpha(x
, y
) / 255.0;
4263 transferFunc
->transform(&lum
, &lum2
);
4264 p
[x
] = (int)(lum2
* 255.0 + 0.5);
4266 p
[x
] = tBitmap
->getAlpha(x
, y
);
4268 tBitmap
->getPixel(x
, y
, color
);
4269 // convert to luminosity
4270 switch (tBitmap
->getMode()) {
4271 case splashModeMono1
:
4272 case splashModeMono8
:
4273 lum
= color
[0] / 255.0;
4275 case splashModeXBGR8
:
4276 case splashModeRGB8
:
4277 case splashModeBGR8
:
4278 lum
= (0.3 / 255.0) * color
[0] +
4279 (0.59 / 255.0) * color
[1] +
4280 (0.11 / 255.0) * color
[2];
4283 case splashModeCMYK8
:
4284 case splashModeDeviceN8
:
4285 lum
= (1 - color
[3] / 255.0)
4286 - (0.3 / 255.0) * color
[0]
4287 - (0.59 / 255.0) * color
[1]
4288 - (0.11 / 255.0) * color
[2];
4296 transferFunc
->transform(&lum
, &lum2
);
4300 p
[x
] = (int)(lum2
* 255.0 + 0.5);
4303 p
+= softMask
->getRowSize();
4305 splash
->setSoftMask(softMask
);
4308 transpGroup
= transpGroupStack
;
4309 transpGroupStack
= transpGroup
->next
;
4315 void SplashOutputDev::clearSoftMask(GfxState
*state
) {
4316 splash
->setSoftMask(NULL
);
4319 void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA
) {
4320 splashColorCopy(paperColor
, paperColorA
);
4323 int SplashOutputDev::getBitmapWidth() {
4324 return bitmap
->getWidth();
4327 int SplashOutputDev::getBitmapHeight() {
4328 return bitmap
->getHeight();
4331 SplashBitmap
*SplashOutputDev::takeBitmap() {
4335 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
,
4336 colorMode
!= splashModeMono1
, bitmapTopDown
);
4340 void SplashOutputDev::getModRegion(int *xMin
, int *yMin
,
4341 int *xMax
, int *yMax
) {
4342 splash
->getModRegion(xMin
, yMin
, xMax
, yMax
);
4345 void SplashOutputDev::clearModRegion() {
4346 splash
->clearModRegion();
4349 #if 1 //~tmp: turn off anti-aliasing temporarily
4350 GBool
SplashOutputDev::getVectorAntialias() {
4351 return splash
->getVectorAntialias();
4354 void SplashOutputDev::setVectorAntialias(GBool vaa
) {
4355 vaa
= vaa
&& colorMode
!= splashModeMono1
;
4356 vectorAntialias
= vaa
;
4357 splash
->setVectorAntialias(vaa
);
4361 void SplashOutputDev::setFreeTypeHinting(GBool enable
, GBool enableSlightHintingA
)
4363 enableFreeTypeHinting
= enable
;
4364 enableSlightHinting
= enableSlightHintingA
;
4367 GBool
SplashOutputDev::tilingPatternFill(GfxState
*state
, Gfx
*gfxA
, Catalog
*catalog
, Object
*str
,
4368 double *ptm
, int paintType
, int /*tilingType*/, Dict
*resDict
,
4369 double *mat
, double *bbox
,
4370 int x0
, int y0
, int x1
, int y1
,
4371 double xStep
, double yStep
)
4375 Splash
*formerSplash
= splash
;
4376 SplashBitmap
*formerBitmap
= bitmap
;
4377 double width
, height
;
4378 int surface_width
, surface_height
, result_width
, result_height
, i
;
4379 int repeatX
, repeatY
;
4380 SplashCoord matc
[6];
4382 double *ctm
, savedCTM
[6];
4383 double kx
, ky
, sx
, sy
;
4384 GBool retValue
= gFalse
;
4386 width
= bbox
[2] - bbox
[0];
4387 height
= bbox
[3] - bbox
[1];
4389 if (xStep
!= width
|| yStep
!= height
)
4392 // calculate offsets
4393 ctm
= state
->getCTM();
4394 for (i
= 0; i
< 6; ++i
) {
4395 savedCTM
[i
] = ctm
[i
];
4397 state
->concatCTM(mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
4398 state
->concatCTM(1, 0, 0, 1, bbox
[0], bbox
[1]);
4399 ctm
= state
->getCTM();
4400 for (i
= 0; i
< 6; ++i
) {
4401 if (!isfinite(ctm
[i
])) {
4402 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4406 matc
[4] = x0
* xStep
* ctm
[0] + y0
* yStep
* ctm
[2] + ctm
[4];
4407 matc
[5] = x0
* xStep
* ctm
[1] + y0
* yStep
* ctm
[3] + ctm
[5];
4408 if (splashAbs(ctm
[1]) > splashAbs(ctm
[0])) {
4410 ky
= ctm
[2] - (ctm
[0] * ctm
[3]) / ctm
[1];
4413 ky
= ctm
[3] - (ctm
[1] * ctm
[2]) / ctm
[0];
4415 result_width
= (int) ceil(fabs(kx
* width
* (x1
- x0
)));
4416 result_height
= (int) ceil(fabs(ky
* height
* (y1
- y0
)));
4417 kx
= state
->getHDPI() / 72.0;
4418 ky
= state
->getVDPI() / 72.0;
4419 m1
.m
[0] = (ptm
[0] == 0) ? fabs(ptm
[2]) * kx
: fabs(ptm
[0]) * kx
;
4422 m1
.m
[3] = (ptm
[3] == 0) ? fabs(ptm
[1]) * ky
: fabs(ptm
[3]) * ky
;
4425 m1
.transform(width
, height
, &kx
, &ky
);
4426 surface_width
= (int) ceil (fabs(kx
));
4427 surface_height
= (int) ceil (fabs(ky
));
4429 sx
= (double) result_width
/ (surface_width
* (x1
- x0
));
4430 sy
= (double) result_height
/ (surface_height
* (y1
- y0
));
4433 m1
.transform(width
, height
, &kx
, &ky
);
4435 if(fabs(kx
) < 1 && fabs(ky
) < 1) {
4436 kx
= std::min
<double>(kx
, ky
);
4440 m1
.transform(width
, height
, &kx
, &ky
);
4441 surface_width
= (int) ceil (fabs(kx
));
4442 surface_height
= (int) ceil (fabs(ky
));
4446 if ((unsigned long) result_width
* result_height
> 0x800000L
) {
4447 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4450 while(fabs(kx
) > 16384 || fabs(ky
) > 16384) {
4451 // limit pattern bitmap size
4454 m1
.transform(width
, height
, &kx
, &ky
);
4456 surface_width
= (int) ceil (fabs(kx
));
4457 surface_height
= (int) ceil (fabs(ky
));
4458 // adjust repeat values to completely fill region
4459 repeatX
= result_width
/ surface_width
;
4460 repeatY
= result_height
/ surface_height
;
4461 if (surface_width
* repeatX
< result_width
)
4463 if (surface_height
* repeatY
< result_height
)
4465 if (x1
- x0
> repeatX
)
4467 if (y1
- y0
> repeatY
)
4470 // restore CTM and calculate rotate and scale with rounded matric
4471 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4472 state
->concatCTM(mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
4473 state
->concatCTM(width
* repeatX
, 0, 0, height
* repeatY
, bbox
[0], bbox
[1]);
4474 ctm
= state
->getCTM();
4480 if (surface_width
== 0 || surface_height
== 0) {
4481 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4484 m1
.transform(bbox
[0], bbox
[1], &kx
, &ky
);
4488 bitmap
= new SplashBitmap(surface_width
, surface_height
, 1,
4489 (paintType
== 1) ? colorMode
: splashModeMono8
, gTrue
);
4490 splash
= new Splash(bitmap
, gTrue
);
4491 if (paintType
== 2) {
4492 SplashColor clearColor
;
4494 clearColor
[0] = (colorMode
== splashModeCMYK8
|| colorMode
== splashModeDeviceN8
) ? 0x00 : 0xFF;
4496 clearColor
[0] = 0xFF;
4498 splash
->clear(clearColor
, 0);
4500 splash
->clear(paperColor
, 0);
4502 splash
->setThinLineMode(formerSplash
->getThinLineMode());
4503 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
4505 box
.x1
= bbox
[0]; box
.y1
= bbox
[1];
4506 box
.x2
= bbox
[2]; box
.y2
= bbox
[3];
4507 gfx
= new Gfx(doc
, this, resDict
, &box
, NULL
, NULL
, NULL
, gfxA
->getXRef());
4508 // set pattern transformation matrix
4509 gfx
->getState()->setCTM(m1
.m
[0], m1
.m
[1], m1
.m
[2], m1
.m
[3], m1
.m
[4], m1
.m
[5]);
4510 updateCTM(gfx
->getState(), m1
.m
[0], m1
.m
[1], m1
.m
[2], m1
.m
[3], m1
.m
[4], m1
.m
[5]);
4513 splash
= formerSplash
;
4514 TilingSplashOutBitmap imgData
;
4515 imgData
.bitmap
= bitmap
;
4516 imgData
.paintType
= paintType
;
4517 imgData
.pattern
= splash
->getFillPattern();
4518 imgData
.colorMode
= colorMode
;
4520 imgData
.repeatX
= repeatX
;
4521 imgData
.repeatY
= repeatY
;
4522 SplashBitmap
*tBitmap
= bitmap
;
4523 bitmap
= formerBitmap
;
4524 result_width
= tBitmap
->getWidth() * imgData
.repeatX
;
4525 result_height
= tBitmap
->getHeight() * imgData
.repeatY
;
4527 if (splashAbs(matc
[1]) > splashAbs(matc
[0])) {
4529 ky
= matc
[2] - (matc
[0] * matc
[3]) / matc
[1];
4532 ky
= matc
[3] - (matc
[1] * matc
[2]) / matc
[0];
4534 kx
= result_width
/ (fabs(kx
) + 1);
4535 ky
= result_height
/ (fabs(ky
) + 1);
4536 state
->concatCTM(kx
, 0, 0, ky
, 0, 0);
4537 ctm
= state
->getCTM();
4542 GBool minorAxisZero
= matc
[1] == 0 && matc
[2] == 0;
4543 if (matc
[0] > 0 && minorAxisZero
&& matc
[3] > 0) {
4545 for (int y
= 0; y
< imgData
.repeatY
; ++y
) {
4546 for (int x
= 0; x
< imgData
.repeatX
; ++x
) {
4547 x0
= splashFloor(matc
[4]) + x
* tBitmap
->getWidth();
4548 y0
= splashFloor(matc
[5]) + y
* tBitmap
->getHeight();
4549 splash
->blitImage(tBitmap
, gTrue
, x0
, y0
);
4554 retValue
= splash
->drawImage(&tilingBitmapSrc
, NULL
, &imgData
, colorMode
, gTrue
, result_width
, result_height
, matc
, gFalse
, gTrue
) == splashOk
;
4561 GBool
SplashOutputDev::gouraudTriangleShadedFill(GfxState
*state
, GfxGouraudTriangleShading
*shading
)
4563 GfxColorSpaceMode shadingMode
= shading
->getColorSpace()->getMode();
4564 GBool bDirectColorTranslation
= gFalse
; // triggers an optimization.
4565 switch (colorMode
) {
4566 case splashModeRGB8
:
4567 bDirectColorTranslation
= (shadingMode
== csDeviceRGB
);
4570 case splashModeCMYK8
:
4571 case splashModeDeviceN8
:
4572 bDirectColorTranslation
= (shadingMode
== csDeviceCMYK
);
4578 SplashGouraudColor
*splashShading
= new SplashGouraudPattern(bDirectColorTranslation
, state
, shading
, colorMode
);
4579 // restore vector antialias because we support it here
4580 if (shading
->isParameterized()) {
4581 GBool vaa
= getVectorAntialias();
4582 GBool retVal
= gFalse
;
4583 setVectorAntialias(gTrue
);
4584 retVal
= splash
->gouraudTriangleShadedFill(splashShading
);
4585 setVectorAntialias(vaa
);
4588 delete splashShading
;
4592 GBool
SplashOutputDev::univariateShadedFill(GfxState
*state
, SplashUnivariatePattern
*pattern
, double tMin
, double tMax
) {
4593 double xMin
, yMin
, xMax
, yMax
;
4595 GBool vaa
= getVectorAntialias();
4596 // restore vector antialias because we support it here
4597 setVectorAntialias(gTrue
);
4599 GBool retVal
= gFalse
;
4600 // get the clip region bbox
4601 if (pattern
->getShading()->getHasBBox()) {
4602 pattern
->getShading()->getBBox(&xMin
, &yMin
, &xMax
, &yMax
);
4604 state
->getClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
4606 xMin
= floor (xMin
);
4607 yMin
= floor (yMin
);
4616 state
->getCTM(&ctm
);
4617 ctm
.invertTo(&ictm
);
4619 ictm
.transform(xMin
, yMin
, &x
[0], &y
[0]);
4620 ictm
.transform(xMax
, yMin
, &x
[1], &y
[1]);
4621 ictm
.transform(xMin
, yMax
, &x
[2], &y
[2]);
4622 ictm
.transform(xMax
, yMax
, &x
[3], &y
[3]);
4626 for (i
= 1; i
< 4; i
++) {
4627 xMin
= std::min
<double>(xMin
, x
[i
]);
4628 yMin
= std::min
<double>(yMin
, y
[i
]);
4629 xMax
= std::max
<double>(xMax
, x
[i
]);
4630 yMax
= std::max
<double>(yMax
, y
[i
]);
4636 state
->moveTo(xMin
, yMin
);
4637 state
->lineTo(xMax
, yMin
);
4638 state
->lineTo(xMax
, yMax
);
4639 state
->lineTo(xMin
, yMax
);
4641 path
= convertPath(state
, state
->getPath(), gTrue
);
4644 pattern
->getShading()->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
4646 setOverprintMask(pattern
->getShading()->getColorSpace(), state
->getFillOverprint(),
4647 state
->getOverprintMode(), NULL
);
4648 retVal
= (splash
->shadedFill(path
, pattern
->getShading()->getHasBBox(), pattern
) == splashOk
);
4650 setVectorAntialias(vaa
);
4656 GBool
SplashOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
, double tMin
, double tMax
) {
4657 SplashAxialPattern
*pattern
= new SplashAxialPattern(colorMode
, state
, shading
);
4658 GBool retVal
= univariateShadedFill(state
, pattern
, tMin
, tMax
);
4665 GBool
SplashOutputDev::radialShadedFill(GfxState
*state
, GfxRadialShading
*shading
, double tMin
, double tMax
) {
4666 SplashRadialPattern
*pattern
= new SplashRadialPattern(colorMode
, state
, shading
);
4667 GBool retVal
= univariateShadedFill(state
, pattern
, tMin
, tMax
);