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-2016 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>
38 // Copyright (C) 2015 Kenji Uno <ku@digitaldolphins.jp>
40 // To see a description of the changes please see the Changelog file that
41 // came with your tarball or type make ChangeLog if you are building from git
43 //========================================================================
47 #ifdef USE_GCC_PRAGMAS
48 #pragma implementation
53 #include "goo/gfile.h"
54 #include "GlobalParams.h"
62 #include "FontEncodingTables.h"
63 #include "fofi/FoFiTrueType.h"
64 #include "splash/SplashBitmap.h"
65 #include "splash/SplashGlyphBitmap.h"
66 #include "splash/SplashPattern.h"
67 #include "splash/SplashScreen.h"
68 #include "splash/SplashPath.h"
69 #include "splash/SplashState.h"
70 #include "splash/SplashErrorCodes.h"
71 #include "splash/SplashFontEngine.h"
72 #include "splash/SplashFont.h"
73 #include "splash/SplashFontFile.h"
74 #include "splash/SplashFontFileID.h"
75 #include "splash/Splash.h"
76 #include "SplashOutputDev.h"
80 #if (__VMS_VER < 70000000)
81 extern "C" int unlink(char *filename
);
87 #define isfinite(x) _finite(x)
93 #define isfinite(x) finite(x)
97 static inline void convertGfxColor(SplashColorPtr dest
,
98 SplashColorMode colorMode
,
99 GfxColorSpace
*colorSpace
,
110 color
[0] = color
[1] = color
[2] = 0;
115 case splashModeMono1
:
116 case splashModeMono8
:
117 colorSpace
->getGray(src
, &gray
);
118 color
[0] = colToByte(gray
);
120 case splashModeXBGR8
:
124 colorSpace
->getRGB(src
, &rgb
);
125 color
[0] = colToByte(rgb
.r
);
126 color
[1] = colToByte(rgb
.g
);
127 color
[2] = colToByte(rgb
.b
);
130 case splashModeCMYK8
:
131 colorSpace
->getCMYK(src
, &cmyk
);
132 color
[0] = colToByte(cmyk
.c
);
133 color
[1] = colToByte(cmyk
.m
);
134 color
[2] = colToByte(cmyk
.y
);
135 color
[3] = colToByte(cmyk
.k
);
137 case splashModeDeviceN8
:
138 colorSpace
->getDeviceN(src
, &deviceN
);
139 for (int i
= 0; i
< SPOT_NCOMPS
+ 4; i
++)
140 color
[i
] = colToByte(deviceN
.c
[i
]);
144 splashColorCopy(dest
, color
);
147 // Copy a color according to the color mode.
148 // Use convertGfxShortColor() below when the destination is a bitmap
149 // to avoid overwriting cells.
150 // Calling this in SplashGouraudPattern::getParameterizedColor() fixes bug 90570.
151 // Use convertGfxColor() above when the destination is an array of SPOT_NCOMPS+4 bytes,
152 // to ensure that everything is initialized.
154 static inline void convertGfxShortColor(SplashColorPtr dest
,
155 SplashColorMode colorMode
,
156 GfxColorSpace
*colorSpace
,
159 case splashModeMono1
:
160 case splashModeMono8
:
163 colorSpace
->getGray(src
, &gray
);
164 dest
[0] = colToByte(gray
);
167 case splashModeXBGR8
:
173 colorSpace
->getRGB(src
, &rgb
);
174 dest
[0] = colToByte(rgb
.r
);
175 dest
[1] = colToByte(rgb
.g
);
176 dest
[2] = colToByte(rgb
.b
);
180 case splashModeCMYK8
:
183 colorSpace
->getCMYK(src
, &cmyk
);
184 dest
[0] = colToByte(cmyk
.c
);
185 dest
[1] = colToByte(cmyk
.m
);
186 dest
[2] = colToByte(cmyk
.y
);
187 dest
[3] = colToByte(cmyk
.k
);
190 case splashModeDeviceN8
:
193 colorSpace
->getDeviceN(src
, &deviceN
);
194 for (int i
= 0; i
< SPOT_NCOMPS
+ 4; i
++)
195 dest
[i
] = colToByte(deviceN
.c
[i
]);
202 //------------------------------------------------------------------------
203 // SplashGouraudPattern
204 //------------------------------------------------------------------------
205 SplashGouraudPattern::SplashGouraudPattern(GBool bDirectColorTranslationA
,
206 GfxState
*stateA
, GfxGouraudTriangleShading
*shadingA
, SplashColorMode modeA
) {
207 SplashColor defaultColor
;
212 bDirectColorTranslation
= bDirectColorTranslationA
;
213 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
214 convertGfxColor(defaultColor
, mode
, shadingA
->getColorSpace(), &srcColor
);
215 gfxMode
= shadingA
->getColorSpace()->getMode();
218 SplashGouraudPattern::~SplashGouraudPattern() {
221 void SplashGouraudPattern::getParameterizedColor(double colorinterp
, SplashColorMode mode
, SplashColorPtr dest
) {
223 GfxColorSpace
* srcColorSpace
= shading
->getColorSpace();
226 if (mode
== splashModeCMYK8
)
228 else if (mode
== splashModeDeviceN8
)
229 colorComps
=4 + SPOT_NCOMPS
;
232 shading
->getParameterizedColor(colorinterp
, &src
);
234 if (bDirectColorTranslation
) {
235 for (int m
= 0; m
< colorComps
; ++m
)
236 dest
[m
] = colToByte(src
.c
[m
]);
238 convertGfxShortColor(dest
, mode
, srcColorSpace
, &src
);
242 //------------------------------------------------------------------------
243 // SplashUnivariatePattern
244 //------------------------------------------------------------------------
246 SplashUnivariatePattern::SplashUnivariatePattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxUnivariateShading
*shadingA
) {
248 double xMin
, yMin
, xMax
, yMax
;
252 colorMode
= colorModeA
;
257 // get the function domain
258 t0
= shading
->getDomain0();
259 t1
= shading
->getDomain1();
262 stateA
->getUserClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
263 shadingA
->setupCache(&ctm
, xMin
, yMin
, xMax
, yMax
);
264 gfxMode
= shadingA
->getColorSpace()->getMode();
267 SplashUnivariatePattern::~SplashUnivariatePattern() {
270 GBool
SplashUnivariatePattern::getColor(int x
, int y
, SplashColorPtr c
) {
274 ictm
.transform(x
, y
, &xc
, &yc
);
275 if (! getParameter (xc
, yc
, &t
))
278 shading
->getColor(t
, &gfxColor
);
279 convertGfxColor(c
, colorMode
, shading
->getColorSpace(), &gfxColor
);
283 GBool
SplashUnivariatePattern::testPosition(int x
, int y
) {
286 ictm
.transform(x
, y
, &xc
, &yc
);
287 if (! getParameter (xc
, yc
, &t
))
289 return (t0
< t1
) ? (t
> t0
&& t
< t1
) : (t
> t1
&& t
< t0
);
293 //------------------------------------------------------------------------
294 // SplashRadialPattern
295 //------------------------------------------------------------------------
296 #define RADIAL_EPSILON (1. / 1024 / 1024)
298 SplashRadialPattern::SplashRadialPattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxRadialShading
*shadingA
):
299 SplashUnivariatePattern(colorModeA
, stateA
, shadingA
)
301 SplashColor defaultColor
;
304 shadingA
->getCoords(&x0
, &y0
, &r0
, &dx
, &dy
, &dr
);
308 a
= dx
*dx
+ dy
*dy
- dr
*dr
;
309 if (fabs(a
) > RADIAL_EPSILON
)
311 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
312 convertGfxColor(defaultColor
, colorModeA
, shadingA
->getColorSpace(), &srcColor
);
315 SplashRadialPattern::~SplashRadialPattern() {
318 GBool
SplashRadialPattern::getParameter(double xs
, double ys
, double *t
) {
321 // We want to solve this system of equations:
323 // 1. (x - xc(s))^2 + (y -yc(s))^2 = rc(s)^2
324 // 2. xc(s) = x0 + s * (x1 - xo)
325 // 3. yc(s) = y0 + s * (y1 - yo)
326 // 4. rc(s) = r0 + s * (r1 - ro)
328 // To simplify the system a little, we translate
329 // our coordinates to have the origin in (x0,y0)
334 // Then we have to solve the equation:
335 // A*s^2 - 2*B*s + C = 0
337 // A = dx^2 + dy^2 - dr^2
338 // B = xs*dx + ys*dy + r0*dr
339 // C = xs^2 + ys^2 - r0^2
341 b
= xs
*dx
+ ys
*dy
+ r0
*dr
;
342 c
= xs
*xs
+ ys
*ys
- r0
*r0
;
344 if (fabs(a
) <= RADIAL_EPSILON
) {
345 // A is 0, thus the equation simplifies to:
347 // If B is 0, we can either have no solution or an indeterminate
348 // equation, thus we behave as if we had an invalid solution
349 if (fabs(b
) <= RADIAL_EPSILON
)
352 s0
= s1
= 0.5 * c
/ b
;
364 // If A < 0, one of the two solutions will have negative radius,
365 // thus it will be ignored. Otherwise we know that s1 <= s0
366 // (because d >=0 implies b - d <= b + d), so if both are valid it
367 // will be the true solution.
372 if (r0
+ s0
* dr
>= 0) {
373 if (0 <= s0
&& s0
<= 1) {
376 } else if (s0
< 0 && shading
->getExtend0()) {
379 } else if (s0
> 1 && shading
->getExtend1()) {
385 if (r0
+ s1
* dr
>= 0) {
386 if (0 <= s1
&& s1
<= 1) {
389 } else if (s1
< 0 && shading
->getExtend0()) {
392 } else if (s1
> 1 && shading
->getExtend1()) {
401 #undef RADIAL_EPSILON
403 //------------------------------------------------------------------------
404 // SplashAxialPattern
405 //------------------------------------------------------------------------
407 SplashAxialPattern::SplashAxialPattern(SplashColorMode colorModeA
, GfxState
*stateA
, GfxAxialShading
*shadingA
):
408 SplashUnivariatePattern(colorModeA
, stateA
, shadingA
)
410 SplashColor defaultColor
;
413 shadingA
->getCoords(&x0
, &y0
, &x1
, &y1
);
416 mul
= 1 / (dx
* dx
+ dy
* dy
);
417 shadingA
->getColorSpace()->getDefaultColor(&srcColor
);
418 convertGfxColor(defaultColor
, colorModeA
, shadingA
->getColorSpace(), &srcColor
);
421 SplashAxialPattern::~SplashAxialPattern() {
424 GBool
SplashAxialPattern::getParameter(double xc
, double yc
, double *t
) {
430 s
= (xc
* dx
+ yc
* dy
) * mul
;
431 if (0 <= s
&& s
<= 1) {
433 } else if (s
< 0 && shading
->getExtend0()) {
435 } else if (s
> 1 && shading
->getExtend1()) {
444 //------------------------------------------------------------------------
445 // Type 3 font cache size parameters
446 #define type3FontCacheAssoc 8
447 #define type3FontCacheMaxSets 8
448 #define type3FontCacheSize (128*1024)
450 //------------------------------------------------------------------------
451 // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
452 static inline Guchar
div255(int x
) {
453 return (Guchar
)((x
+ (x
>> 8) + 0x80) >> 8);
458 #include "GfxState_helpers.h"
460 //-------------------------------------------------------------------------
461 // helper for Blend functions (convert CMYK to RGB, do blend, convert back)
462 //-------------------------------------------------------------------------
464 // based in GfxState.cc
466 static void cmykToRGB(SplashColorPtr cmyk
, SplashColor rgb
) {
467 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
469 c
= colToDbl(byteToCol(cmyk
[0]));
470 m
= colToDbl(byteToCol(cmyk
[1]));
471 y
= colToDbl(byteToCol(cmyk
[2]));
472 k
= colToDbl(byteToCol(cmyk
[3]));
477 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
478 rgb
[0] = colToByte(clip01(dblToCol(r
)));
479 rgb
[1] = colToByte(clip01(dblToCol(g
)));
480 rgb
[2] = colToByte(clip01(dblToCol(b
)));
483 static void rgbToCMYK(SplashColor rgb
, SplashColorPtr cmyk
) {
484 GfxColorComp c
, m
, y
, k
;
486 c
= clip01(gfxColorComp1
- byteToCol(rgb
[0]));
487 m
= clip01(gfxColorComp1
- byteToCol(rgb
[1]));
488 y
= clip01(gfxColorComp1
- byteToCol(rgb
[2]));
496 cmyk
[0] = colToByte(c
- k
);
497 cmyk
[1] = colToByte(m
- k
);
498 cmyk
[2] = colToByte(y
- k
);
499 cmyk
[3] = colToByte(k
);
504 //------------------------------------------------------------------------
506 //------------------------------------------------------------------------
508 static void splashOutBlendMultiply(SplashColorPtr src
, SplashColorPtr dest
,
509 SplashColorPtr blend
, SplashColorMode cm
) {
513 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
514 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
515 dest
[i
] = 255 - dest
[i
];
516 src
[i
] = 255 - src
[i
];
521 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
522 blend
[i
] = (dest
[i
] * src
[i
]) / 255;
526 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
527 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
528 dest
[i
] = 255 - dest
[i
];
529 src
[i
] = 255 - src
[i
];
530 blend
[i
] = 255 - blend
[i
];
536 static void splashOutBlendScreen(SplashColorPtr src
, SplashColorPtr dest
,
537 SplashColorPtr blend
, SplashColorMode cm
) {
541 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
542 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
543 dest
[i
] = 255 - dest
[i
];
544 src
[i
] = 255 - src
[i
];
549 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
550 blend
[i
] = dest
[i
] + src
[i
] - (dest
[i
] * src
[i
]) / 255;
554 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
555 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
556 dest
[i
] = 255 - dest
[i
];
557 src
[i
] = 255 - src
[i
];
558 blend
[i
] = 255 - blend
[i
];
564 static void splashOutBlendOverlay(SplashColorPtr src
, SplashColorPtr dest
,
565 SplashColorPtr blend
, SplashColorMode cm
) {
569 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
570 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
571 dest
[i
] = 255 - dest
[i
];
572 src
[i
] = 255 - src
[i
];
577 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
578 blend
[i
] = dest
[i
] < 0x80
579 ? (src
[i
] * 2 * dest
[i
]) / 255
580 : 255 - 2 * ((255 - src
[i
]) * (255 - dest
[i
])) / 255;
584 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
585 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
586 dest
[i
] = 255 - dest
[i
];
587 src
[i
] = 255 - src
[i
];
588 blend
[i
] = 255 - blend
[i
];
594 static void splashOutBlendDarken(SplashColorPtr src
, SplashColorPtr dest
,
595 SplashColorPtr blend
, SplashColorMode cm
) {
599 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
600 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
601 dest
[i
] = 255 - dest
[i
];
602 src
[i
] = 255 - src
[i
];
607 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
608 blend
[i
] = dest
[i
] < src
[i
] ? dest
[i
] : src
[i
];
612 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
613 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
614 dest
[i
] = 255 - dest
[i
];
615 src
[i
] = 255 - src
[i
];
616 blend
[i
] = 255 - blend
[i
];
622 static void splashOutBlendLighten(SplashColorPtr src
, SplashColorPtr dest
,
623 SplashColorPtr blend
, SplashColorMode cm
) {
627 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
628 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
629 dest
[i
] = 255 - dest
[i
];
630 src
[i
] = 255 - src
[i
];
635 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
636 blend
[i
] = dest
[i
] > src
[i
] ? dest
[i
] : src
[i
];
640 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
641 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
642 dest
[i
] = 255 - dest
[i
];
643 src
[i
] = 255 - src
[i
];
644 blend
[i
] = 255 - blend
[i
];
650 static void splashOutBlendColorDodge(SplashColorPtr src
, SplashColorPtr dest
,
651 SplashColorPtr blend
,
652 SplashColorMode cm
) {
656 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
657 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
658 dest
[i
] = 255 - dest
[i
];
659 src
[i
] = 255 - src
[i
];
664 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
668 x
= (dest
[i
] * 255) / (255 - src
[i
]);
669 blend
[i
] = x
<= 255 ? x
: 255;
674 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
675 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
676 dest
[i
] = 255 - dest
[i
];
677 src
[i
] = 255 - src
[i
];
678 blend
[i
] = 255 - blend
[i
];
684 static void splashOutBlendColorBurn(SplashColorPtr src
, SplashColorPtr dest
,
685 SplashColorPtr blend
, SplashColorMode cm
) {
689 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
690 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
691 dest
[i
] = 255 - dest
[i
];
692 src
[i
] = 255 - src
[i
];
697 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
701 x
= ((255 - dest
[i
]) * 255) / src
[i
];
702 blend
[i
] = x
<= 255 ? 255 - x
: 0;
707 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
708 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
709 dest
[i
] = 255 - dest
[i
];
710 src
[i
] = 255 - src
[i
];
711 blend
[i
] = 255 - blend
[i
];
717 static void splashOutBlendHardLight(SplashColorPtr src
, SplashColorPtr dest
,
718 SplashColorPtr blend
, SplashColorMode cm
) {
722 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
723 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
724 dest
[i
] = 255 - dest
[i
];
725 src
[i
] = 255 - src
[i
];
730 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
731 blend
[i
] = src
[i
] < 0x80
732 ? (dest
[i
] * 2 * src
[i
]) / 255
733 : 255 - 2 * ((255 - dest
[i
]) * (255 - src
[i
])) / 255;
737 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
738 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
739 dest
[i
] = 255 - dest
[i
];
740 src
[i
] = 255 - src
[i
];
741 blend
[i
] = 255 - blend
[i
];
747 static void splashOutBlendSoftLight(SplashColorPtr src
, SplashColorPtr dest
,
748 SplashColorPtr blend
, SplashColorMode cm
) {
752 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
753 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
754 dest
[i
] = 255 - dest
[i
];
755 src
[i
] = 255 - src
[i
];
760 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
762 blend
[i
] = dest
[i
] - (255 - 2 * src
[i
]) * dest
[i
] * (255 - dest
[i
]) / (255 * 255);
764 if (dest
[i
] < 0x40) {
765 x
= (((((16 * dest
[i
] - 12 * 255) * dest
[i
]) / 255) + 4 * 255) * dest
[i
]) / 255;
767 x
= (int)sqrt(255.0 * dest
[i
]);
769 blend
[i
] = dest
[i
] + (2 * src
[i
] - 255) * (x
- dest
[i
]) / 255;
774 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
775 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
776 dest
[i
] = 255 - dest
[i
];
777 src
[i
] = 255 - src
[i
];
778 blend
[i
] = 255 - blend
[i
];
784 static void splashOutBlendDifference(SplashColorPtr src
, SplashColorPtr dest
,
785 SplashColorPtr blend
,
786 SplashColorMode cm
) {
790 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
791 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
792 dest
[i
] = 255 - dest
[i
];
793 src
[i
] = 255 - src
[i
];
798 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
799 blend
[i
] = dest
[i
] < src
[i
] ? src
[i
] - dest
[i
] : dest
[i
] - src
[i
];
803 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
804 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
805 dest
[i
] = 255 - dest
[i
];
806 src
[i
] = 255 - src
[i
];
807 blend
[i
] = 255 - blend
[i
];
810 if (cm
== splashModeDeviceN8
) {
811 for (i
= 4; i
< splashColorModeNComps
[cm
]; ++i
) {
812 if (dest
[i
] == 0 && src
[i
] == 0)
819 static void splashOutBlendExclusion(SplashColorPtr src
, SplashColorPtr dest
,
820 SplashColorPtr blend
, SplashColorMode cm
) {
824 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
825 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
826 dest
[i
] = 255 - dest
[i
];
827 src
[i
] = 255 - src
[i
];
832 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
833 blend
[i
] = dest
[i
] + src
[i
] - (2 * dest
[i
] * src
[i
]) / 255;
837 if (cm
== splashModeCMYK8
|| cm
== splashModeDeviceN8
) {
838 for (i
= 0; i
< splashColorModeNComps
[cm
]; ++i
) {
839 dest
[i
] = 255 - dest
[i
];
840 src
[i
] = 255 - src
[i
];
841 blend
[i
] = 255 - blend
[i
];
844 if (cm
== splashModeDeviceN8
) {
845 for (i
= 4; i
< splashColorModeNComps
[cm
]; ++i
) {
846 if (dest
[i
] == 0 && src
[i
] == 0)
853 static int getLum(int r
, int g
, int b
) {
854 return (int)(0.3 * r
+ 0.59 * g
+ 0.11 * b
);
857 static int getSat(int r
, int g
, int b
) {
863 } else if (g
> rgbMax
) {
868 } else if (b
> rgbMax
) {
871 return rgbMax
- rgbMin
;
874 static void clipColor(int rIn
, int gIn
, int bIn
,
875 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
876 int lum
, rgbMin
, rgbMax
;
878 lum
= getLum(rIn
, gIn
, bIn
);
879 rgbMin
= rgbMax
= rIn
;
882 } else if (gIn
> rgbMax
) {
887 } else if (bIn
> rgbMax
) {
891 *rOut
= (Guchar
)(lum
+ ((rIn
- lum
) * lum
) / (lum
- rgbMin
));
892 *gOut
= (Guchar
)(lum
+ ((gIn
- lum
) * lum
) / (lum
- rgbMin
));
893 *bOut
= (Guchar
)(lum
+ ((bIn
- lum
) * lum
) / (lum
- rgbMin
));
894 } else if (rgbMax
> 255) {
895 *rOut
= (Guchar
)(lum
+ ((rIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
896 *gOut
= (Guchar
)(lum
+ ((gIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
897 *bOut
= (Guchar
)(lum
+ ((bIn
- lum
) * (255 - lum
)) / (rgbMax
- lum
));
905 static void setLum(Guchar rIn
, Guchar gIn
, Guchar bIn
, int lum
,
906 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
909 d
= lum
- getLum(rIn
, gIn
, bIn
);
910 clipColor(rIn
+ d
, gIn
+ d
, bIn
+ d
, rOut
, gOut
, bOut
);
913 static void setSat(Guchar rIn
, Guchar gIn
, Guchar bIn
, int sat
,
914 Guchar
*rOut
, Guchar
*gOut
, Guchar
*bOut
) {
915 int rgbMin
, rgbMid
, rgbMax
;
916 Guchar
*minOut
, *midOut
, *maxOut
;
919 rgbMin
= rIn
; minOut
= rOut
;
920 rgbMid
= gIn
; midOut
= gOut
;
922 rgbMin
= gIn
; minOut
= gOut
;
923 rgbMid
= rIn
; midOut
= rOut
;
926 rgbMax
= bIn
; maxOut
= bOut
;
927 } else if (bIn
> rgbMin
) {
928 rgbMax
= rgbMid
; maxOut
= midOut
;
929 rgbMid
= bIn
; midOut
= bOut
;
931 rgbMax
= rgbMid
; maxOut
= midOut
;
932 rgbMid
= rgbMin
; midOut
= minOut
;
933 rgbMin
= bIn
; minOut
= bOut
;
935 if (rgbMax
> rgbMin
) {
936 *midOut
= (Guchar
)((rgbMid
- rgbMin
) * sat
) / (rgbMax
- rgbMin
);
937 *maxOut
= (Guchar
)sat
;
939 *midOut
= *maxOut
= 0;
944 static void splashOutBlendHue(SplashColorPtr src
, SplashColorPtr dest
,
945 SplashColorPtr blend
, SplashColorMode cm
) {
950 SplashColor src2
, dest2
;
954 case splashModeMono1
:
955 case splashModeMono8
:
958 case splashModeXBGR8
:
962 setSat(src
[0], src
[1], src
[2], getSat(dest
[0], dest
[1], dest
[2]),
964 setLum(r0
, g0
, b0
, getLum(dest
[0], dest
[1], dest
[2]),
965 &blend
[0], &blend
[1], &blend
[2]);
968 case splashModeCMYK8
:
969 case splashModeDeviceN8
:
970 for (i
= 0; i
< 4; i
++) {
971 // convert to additive
972 src2
[i
] = 0xff - src
[i
];
973 dest2
[i
] = 0xff - dest
[i
];
975 // NB: inputs have already been converted to additive mode
976 setSat(src2
[0], src2
[1], src2
[2], getSat(dest2
[0], dest2
[1], dest2
[2]),
978 setLum(r0
, g0
, b0
, getLum(dest2
[0], dest2
[1], dest2
[2]),
984 for (i
= 0; i
< 4; i
++) {
985 // convert back to subtractive
986 blend
[i
] = 0xff - blend
[i
];
993 static void splashOutBlendSaturation(SplashColorPtr src
, SplashColorPtr dest
,
994 SplashColorPtr blend
,
995 SplashColorMode cm
) {
1000 SplashColor src2
, dest2
;
1004 case splashModeMono1
:
1005 case splashModeMono8
:
1008 case splashModeXBGR8
:
1010 case splashModeRGB8
:
1011 case splashModeBGR8
:
1012 setSat(dest
[0], dest
[1], dest
[2], getSat(src
[0], src
[1], src
[2]),
1014 setLum(r0
, g0
, b0
, getLum(dest
[0], dest
[1], dest
[2]),
1015 &blend
[0], &blend
[1], &blend
[2]);
1018 case splashModeCMYK8
:
1019 case splashModeDeviceN8
:
1020 for (i
= 0; i
< 4; i
++) {
1021 // convert to additive
1022 src2
[i
] = 0xff - src
[i
];
1023 dest2
[i
] = 0xff - dest
[i
];
1025 setSat(dest2
[0], dest2
[1], dest2
[2], getSat(src2
[0], src2
[1], src2
[2]),
1027 setLum(r0
, g0
, b0
, getLum(dest2
[0], dest2
[1], dest2
[2]),
1032 blend
[3] = dest2
[3];
1033 for (i
= 0; i
< 4; i
++) {
1034 // convert back to subtractive
1035 blend
[i
] = 0xff - blend
[i
];
1042 static void splashOutBlendColor(SplashColorPtr src
, SplashColorPtr dest
,
1043 SplashColorPtr blend
, SplashColorMode cm
) {
1047 SplashColor src2
, dest2
;
1051 case splashModeMono1
:
1052 case splashModeMono8
:
1055 case splashModeXBGR8
:
1057 case splashModeRGB8
:
1058 case splashModeBGR8
:
1059 setLum(src
[0], src
[1], src
[2], getLum(dest
[0], dest
[1], dest
[2]),
1060 &blend
[0], &blend
[1], &blend
[2]);
1063 case splashModeCMYK8
:
1064 case splashModeDeviceN8
:
1065 for (i
= 0; i
< 4; i
++) {
1066 // convert to additive
1067 src2
[i
] = 0xff - src
[i
];
1068 dest2
[i
] = 0xff - dest
[i
];
1070 setLum(src2
[0], src2
[1], src2
[2], getLum(dest2
[0], dest2
[1], dest2
[2]),
1075 blend
[3] = dest2
[3];
1076 for (i
= 0; i
< 4; i
++) {
1077 // convert back to subtractive
1078 blend
[i
] = 0xff - blend
[i
];
1085 static void splashOutBlendLuminosity(SplashColorPtr src
, SplashColorPtr dest
,
1086 SplashColorPtr blend
,
1087 SplashColorMode cm
) {
1091 SplashColor src2
, dest2
;
1095 case splashModeMono1
:
1096 case splashModeMono8
:
1099 case splashModeXBGR8
:
1101 case splashModeRGB8
:
1102 case splashModeBGR8
:
1103 setLum(dest
[0], dest
[1], dest
[2], getLum(src
[0], src
[1], src
[2]),
1104 &blend
[0], &blend
[1], &blend
[2]);
1107 case splashModeCMYK8
:
1108 case splashModeDeviceN8
:
1109 for (i
= 0; i
< 4; i
++) {
1110 // convert to additive
1111 src2
[i
] = 0xff - src
[i
];
1112 dest2
[i
] = 0xff - dest
[i
];
1114 setLum(dest2
[0], dest2
[1], dest2
[2], getLum(src2
[0], src2
[1], src2
[2]),
1120 for (i
= 0; i
< 4; i
++) {
1121 // convert back to subtractive
1122 blend
[i
] = 0xff - blend
[i
];
1129 // NB: This must match the GfxBlendMode enum defined in GfxState.h.
1130 static const SplashBlendFunc splashOutBlendFuncs
[] = {
1132 &splashOutBlendMultiply
,
1133 &splashOutBlendScreen
,
1134 &splashOutBlendOverlay
,
1135 &splashOutBlendDarken
,
1136 &splashOutBlendLighten
,
1137 &splashOutBlendColorDodge
,
1138 &splashOutBlendColorBurn
,
1139 &splashOutBlendHardLight
,
1140 &splashOutBlendSoftLight
,
1141 &splashOutBlendDifference
,
1142 &splashOutBlendExclusion
,
1144 &splashOutBlendSaturation
,
1145 &splashOutBlendColor
,
1146 &splashOutBlendLuminosity
1149 //------------------------------------------------------------------------
1150 // SplashOutFontFileID
1151 //------------------------------------------------------------------------
1153 class SplashOutFontFileID
: public SplashFontFileID
{
1156 SplashOutFontFileID(Ref
*rA
) { r
= *rA
; }
1158 ~SplashOutFontFileID() {}
1160 GBool
matches(SplashFontFileID
*id
) {
1161 return ((SplashOutFontFileID
*)id
)->r
.num
== r
.num
&&
1162 ((SplashOutFontFileID
*)id
)->r
.gen
== r
.gen
;
1170 //------------------------------------------------------------------------
1172 //------------------------------------------------------------------------
1174 struct T3FontCacheTag
{
1176 Gushort mru
; // valid bit (0x8000) and MRU index
1182 T3FontCache(Ref
*fontID
, double m11A
, double m12A
,
1183 double m21A
, double m22A
,
1184 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
1185 GBool aa
, GBool validBBoxA
);
1187 GBool
matches(Ref
*idA
, double m11A
, double m12A
,
1188 double m21A
, double m22A
)
1189 { return fontID
.num
== idA
->num
&& fontID
.gen
== idA
->gen
&&
1190 m11
== m11A
&& m12
== m12A
&& m21
== m21A
&& m22
== m22A
; }
1192 Ref fontID
; // PDF font ID
1193 double m11
, m12
, m21
, m22
; // transform matrix
1194 int glyphX
, glyphY
; // pixel offset of glyph bitmaps
1195 int glyphW
, glyphH
; // size of glyph bitmaps, in pixels
1196 GBool validBBox
; // false if the bbox was [0 0 0 0]
1197 int glyphSize
; // size of glyph bitmaps, in bytes
1198 int cacheSets
; // number of sets in cache
1199 int cacheAssoc
; // cache associativity (glyphs per set)
1200 Guchar
*cacheData
; // glyph pixmap cache
1201 T3FontCacheTag
*cacheTags
; // cache tags, i.e., char codes
1204 T3FontCache::T3FontCache(Ref
*fontIDA
, double m11A
, double m12A
,
1205 double m21A
, double m22A
,
1206 int glyphXA
, int glyphYA
, int glyphWA
, int glyphHA
,
1207 GBool validBBoxA
, GBool aa
) {
1219 validBBox
= validBBoxA
;
1220 // sanity check for excessively large glyphs (which most likely
1221 // indicate an incorrect BBox)
1222 i
= glyphW
* glyphH
;
1223 if (i
> 100000 || glyphW
> INT_MAX
/ glyphH
|| glyphW
<= 0 || glyphH
<= 0) {
1224 glyphW
= glyphH
= 100;
1228 glyphSize
= glyphW
* glyphH
;
1230 glyphSize
= ((glyphW
+ 7) >> 3) * glyphH
;
1232 cacheAssoc
= type3FontCacheAssoc
;
1233 for (cacheSets
= type3FontCacheMaxSets
;
1235 cacheSets
* cacheAssoc
* glyphSize
> type3FontCacheSize
;
1237 if (glyphSize
< 10485760 / cacheAssoc
/ cacheSets
) {
1238 cacheData
= (Guchar
*)gmallocn_checkoverflow(cacheSets
* cacheAssoc
, glyphSize
);
1240 error(errSyntaxWarning
, -1, "Not creating cacheData for T3FontCache, it asked for too much memory.\n"
1241 " This could teoretically result in wrong rendering,\n"
1242 " but most probably the document is bogus.\n"
1243 " Please report a bug if you think the rendering may be wrong because of this.");
1246 if (cacheData
!= NULL
)
1248 cacheTags
= (T3FontCacheTag
*)gmallocn(cacheSets
* cacheAssoc
,
1249 sizeof(T3FontCacheTag
));
1250 for (i
= 0; i
< cacheSets
* cacheAssoc
; ++i
) {
1251 cacheTags
[i
].mru
= i
& (cacheAssoc
- 1);
1260 T3FontCache::~T3FontCache() {
1265 struct T3GlyphStack
{
1266 Gushort code
; // character code
1269 T3FontCache
*cache
; // font cache for the current font
1270 T3FontCacheTag
*cacheTag
; // pointer to cache tag for the glyph
1271 Guchar
*cacheData
; // pointer to cache data for the glyph
1274 SplashBitmap
*origBitmap
;
1276 double origCTM4
, origCTM5
;
1278 T3GlyphStack
*next
; // next object on stack
1281 //------------------------------------------------------------------------
1282 // SplashTransparencyGroup
1283 //------------------------------------------------------------------------
1285 struct SplashTransparencyGroup
{
1286 int tx
, ty
; // translation coordinates
1287 SplashBitmap
*tBitmap
; // bitmap for transparency group
1288 SplashBitmap
*softmask
; // bitmap for softmasks
1289 GfxColorSpace
*blendingColorSpace
;
1292 //----- for knockout
1293 SplashBitmap
*shape
;
1295 SplashCoord knockoutOpacity
;
1299 SplashBitmap
*origBitmap
;
1302 SplashTransparencyGroup
*next
;
1305 //------------------------------------------------------------------------
1307 //------------------------------------------------------------------------
1309 SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA
,
1311 GBool reverseVideoA
,
1312 SplashColorPtr paperColorA
,
1313 GBool bitmapTopDownA
,
1314 SplashThinLineMode thinLineMode
,
1315 GBool overprintPreviewA
) {
1316 colorMode
= colorModeA
;
1317 bitmapRowPad
= bitmapRowPadA
;
1318 bitmapTopDown
= bitmapTopDownA
;
1319 bitmapUpsideDown
= gFalse
;
1320 fontAntialias
= gTrue
;
1321 vectorAntialias
= gTrue
;
1322 overprintPreview
= overprintPreviewA
;
1323 enableFreeTypeHinting
= gFalse
;
1324 enableSlightHinting
= gFalse
;
1325 setupScreenParams(72.0, 72.0);
1326 reverseVideo
= reverseVideoA
;
1327 if (paperColorA
!= NULL
) {
1328 splashColorCopy(paperColor
, paperColorA
);
1330 splashClearColor(paperColor
);
1332 skipHorizText
= gFalse
;
1333 skipRotatedText
= gFalse
;
1334 keepAlphaChannel
= paperColorA
== NULL
;
1338 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
,
1339 colorMode
!= splashModeMono1
, bitmapTopDown
);
1340 splash
= new Splash(bitmap
, vectorAntialias
, &screenParams
);
1341 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
1342 splash
->setThinLineMode(thinLineMode
);
1343 splash
->clear(paperColor
, 0);
1348 t3GlyphStack
= NULL
;
1351 needFontUpdate
= gFalse
;
1352 textClipPath
= NULL
;
1353 transpGroupStack
= NULL
;
1358 void SplashOutputDev::setupScreenParams(double hDPI
, double vDPI
) {
1359 screenParams
.size
= globalParams
->getScreenSize();
1360 screenParams
.dotRadius
= globalParams
->getScreenDotRadius();
1361 screenParams
.gamma
= (SplashCoord
)globalParams
->getScreenGamma();
1362 screenParams
.blackThreshold
=
1363 (SplashCoord
)globalParams
->getScreenBlackThreshold();
1364 screenParams
.whiteThreshold
=
1365 (SplashCoord
)globalParams
->getScreenWhiteThreshold();
1366 switch (globalParams
->getScreenType()) {
1367 case screenDispersed
:
1368 screenParams
.type
= splashScreenDispersed
;
1369 if (screenParams
.size
< 0) {
1370 screenParams
.size
= 4;
1373 case screenClustered
:
1374 screenParams
.type
= splashScreenClustered
;
1375 if (screenParams
.size
< 0) {
1376 screenParams
.size
= 10;
1379 case screenStochasticClustered
:
1380 screenParams
.type
= splashScreenStochasticClustered
;
1381 if (screenParams
.size
< 0) {
1382 screenParams
.size
= 64;
1384 if (screenParams
.dotRadius
< 0) {
1385 screenParams
.dotRadius
= 2;
1390 // use clustered dithering for resolution >= 300 dpi
1391 // (compare to 299.9 to avoid floating point issues)
1392 if (hDPI
> 299.9 && vDPI
> 299.9) {
1393 screenParams
.type
= splashScreenStochasticClustered
;
1394 if (screenParams
.size
< 0) {
1395 screenParams
.size
= 64;
1397 if (screenParams
.dotRadius
< 0) {
1398 screenParams
.dotRadius
= 2;
1401 screenParams
.type
= splashScreenDispersed
;
1402 if (screenParams
.size
< 0) {
1403 screenParams
.size
= 4;
1409 SplashOutputDev::~SplashOutputDev() {
1412 for (i
= 0; i
< nT3Fonts
; ++i
) {
1413 delete t3FontCache
[i
];
1426 void SplashOutputDev::startDoc(PDFDoc
*docA
) {
1433 fontEngine
= new SplashFontEngine(
1435 globalParams
->getEnableT1lib(),
1437 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
1438 globalParams
->getEnableFreeType(),
1439 enableFreeTypeHinting
,
1440 enableSlightHinting
,
1442 getFontAntialias() &&
1443 colorMode
!= splashModeMono1
);
1444 for (i
= 0; i
< nT3Fonts
; ++i
) {
1445 delete t3FontCache
[i
];
1450 void SplashOutputDev::startPage(int pageNum
, GfxState
*state
, XRef
*xrefA
) {
1458 setupScreenParams(state
->getHDPI(), state
->getVDPI());
1459 w
= (int)(state
->getPageWidth() + 0.5);
1463 h
= (int)(state
->getPageHeight() + 0.5);
1470 SplashThinLineMode thinLineMode
= splashThinLineDefault
;
1472 thinLineMode
= splash
->getThinLineMode();
1476 if (!bitmap
|| w
!= bitmap
->getWidth() || h
!= bitmap
->getHeight()) {
1481 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
,
1482 colorMode
!= splashModeMono1
, bitmapTopDown
);
1483 if (!bitmap
->getDataPtr()) {
1486 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
,
1487 colorMode
!= splashModeMono1
, bitmapTopDown
);
1490 splash
= new Splash(bitmap
, vectorAntialias
, &screenParams
);
1491 splash
->setThinLineMode(thinLineMode
);
1492 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
1494 ctm
= state
->getCTM();
1495 mat
[0] = (SplashCoord
)ctm
[0];
1496 mat
[1] = (SplashCoord
)ctm
[1];
1497 mat
[2] = (SplashCoord
)ctm
[2];
1498 mat
[3] = (SplashCoord
)ctm
[3];
1499 mat
[4] = (SplashCoord
)ctm
[4];
1500 mat
[5] = (SplashCoord
)ctm
[5];
1501 splash
->setMatrix(mat
);
1503 switch (colorMode
) {
1504 case splashModeMono1
:
1505 case splashModeMono8
:
1508 case splashModeXBGR8
:
1510 case splashModeRGB8
:
1511 case splashModeBGR8
:
1512 color
[0] = color
[1] = color
[2] = 0;
1515 case splashModeCMYK8
:
1516 color
[0] = color
[1] = color
[2] = color
[3] = 0;
1518 case splashModeDeviceN8
:
1519 for (int i
= 0; i
< 4 + SPOT_NCOMPS
; i
++)
1524 splash
->setStrokePattern(new SplashSolidColor(color
));
1525 splash
->setFillPattern(new SplashSolidColor(color
));
1526 splash
->setLineCap(splashLineCapButt
);
1527 splash
->setLineJoin(splashLineJoinMiter
);
1528 splash
->setLineDash(NULL
, 0, 0);
1529 splash
->setMiterLimit(10);
1530 splash
->setFlatness(1);
1531 // the SA parameter supposedly defaults to false, but Acrobat
1532 // apparently hardwires it to true
1533 splash
->setStrokeAdjust(globalParams
->getStrokeAdjust());
1534 splash
->clear(paperColor
, 0);
1537 void SplashOutputDev::endPage() {
1538 if (colorMode
!= splashModeMono1
&& !keepAlphaChannel
) {
1539 splash
->compositeBackground(paperColor
);
1543 void SplashOutputDev::saveState(GfxState
*state
) {
1544 splash
->saveState();
1547 void SplashOutputDev::restoreState(GfxState
*state
) {
1548 splash
->restoreState();
1549 needFontUpdate
= gTrue
;
1552 void SplashOutputDev::updateAll(GfxState
*state
) {
1553 updateLineDash(state
);
1554 updateLineJoin(state
);
1555 updateLineCap(state
);
1556 updateLineWidth(state
);
1557 updateFlatness(state
);
1558 updateMiterLimit(state
);
1559 updateStrokeAdjust(state
);
1560 updateFillColorSpace(state
);
1561 updateFillColor(state
);
1562 updateStrokeColorSpace(state
);
1563 updateStrokeColor(state
);
1564 needFontUpdate
= gTrue
;
1567 void SplashOutputDev::updateCTM(GfxState
*state
, double m11
, double m12
,
1568 double m21
, double m22
,
1569 double m31
, double m32
) {
1573 ctm
= state
->getCTM();
1574 mat
[0] = (SplashCoord
)ctm
[0];
1575 mat
[1] = (SplashCoord
)ctm
[1];
1576 mat
[2] = (SplashCoord
)ctm
[2];
1577 mat
[3] = (SplashCoord
)ctm
[3];
1578 mat
[4] = (SplashCoord
)ctm
[4];
1579 mat
[5] = (SplashCoord
)ctm
[5];
1580 splash
->setMatrix(mat
);
1583 void SplashOutputDev::updateLineDash(GfxState
*state
) {
1584 double *dashPattern
;
1587 SplashCoord dash
[20];
1590 state
->getLineDash(&dashPattern
, &dashLength
, &dashStart
);
1591 if (dashLength
> 20) {
1594 for (i
= 0; i
< dashLength
; ++i
) {
1595 dash
[i
] = (SplashCoord
)dashPattern
[i
];
1600 splash
->setLineDash(dash
, dashLength
, (SplashCoord
)dashStart
);
1603 void SplashOutputDev::updateFlatness(GfxState
*state
) {
1604 #if 0 // Acrobat ignores the flatness setting, and always renders curves
1605 // with a fairly small flatness value
1606 splash
->setFlatness(state
->getFlatness());
1610 void SplashOutputDev::updateLineJoin(GfxState
*state
) {
1611 splash
->setLineJoin(state
->getLineJoin());
1614 void SplashOutputDev::updateLineCap(GfxState
*state
) {
1615 splash
->setLineCap(state
->getLineCap());
1618 void SplashOutputDev::updateMiterLimit(GfxState
*state
) {
1619 splash
->setMiterLimit(state
->getMiterLimit());
1622 void SplashOutputDev::updateLineWidth(GfxState
*state
) {
1623 splash
->setLineWidth(state
->getLineWidth());
1626 void SplashOutputDev::updateStrokeAdjust(GfxState
* /*state*/) {
1627 #if 0 // the SA parameter supposedly defaults to false, but Acrobat
1628 // apparently hardwires it to true
1629 splash
->setStrokeAdjust(state
->getStrokeAdjust());
1633 void SplashOutputDev::updateFillColorSpace(GfxState
*state
) {
1635 if (colorMode
== splashModeDeviceN8
)
1636 state
->getFillColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
1640 void SplashOutputDev::updateStrokeColorSpace(GfxState
*state
) {
1642 if (colorMode
== splashModeDeviceN8
)
1643 state
->getStrokeColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
1647 void SplashOutputDev::updateFillColor(GfxState
*state
) {
1655 switch (colorMode
) {
1656 case splashModeMono1
:
1657 case splashModeMono8
:
1658 state
->getFillGray(&gray
);
1659 splash
->setFillPattern(getColor(gray
));
1661 case splashModeXBGR8
:
1662 case splashModeRGB8
:
1663 case splashModeBGR8
:
1664 state
->getFillRGB(&rgb
);
1665 splash
->setFillPattern(getColor(&rgb
));
1668 case splashModeCMYK8
:
1669 state
->getFillCMYK(&cmyk
);
1670 splash
->setFillPattern(getColor(&cmyk
));
1672 case splashModeDeviceN8
:
1673 state
->getFillDeviceN(&deviceN
);
1674 splash
->setFillPattern(getColor(&deviceN
));
1680 void SplashOutputDev::updateStrokeColor(GfxState
*state
) {
1688 switch (colorMode
) {
1689 case splashModeMono1
:
1690 case splashModeMono8
:
1691 state
->getStrokeGray(&gray
);
1692 splash
->setStrokePattern(getColor(gray
));
1694 case splashModeXBGR8
:
1695 case splashModeRGB8
:
1696 case splashModeBGR8
:
1697 state
->getStrokeRGB(&rgb
);
1698 splash
->setStrokePattern(getColor(&rgb
));
1701 case splashModeCMYK8
:
1702 state
->getStrokeCMYK(&cmyk
);
1703 splash
->setStrokePattern(getColor(&cmyk
));
1705 case splashModeDeviceN8
:
1706 state
->getStrokeDeviceN(&deviceN
);
1707 splash
->setStrokePattern(getColor(&deviceN
));
1713 SplashPattern
*SplashOutputDev::getColor(GfxGray gray
) {
1717 gray
= gfxColorComp1
- gray
;
1719 color
[0] = colToByte(gray
);
1720 return new SplashSolidColor(color
);
1723 SplashPattern
*SplashOutputDev::getColor(GfxRGB
*rgb
) {
1724 GfxColorComp r
, g
, b
;
1728 r
= gfxColorComp1
- rgb
->r
;
1729 g
= gfxColorComp1
- rgb
->g
;
1730 b
= gfxColorComp1
- rgb
->b
;
1736 color
[0] = colToByte(r
);
1737 color
[1] = colToByte(g
);
1738 color
[2] = colToByte(b
);
1739 if (colorMode
== splashModeXBGR8
) color
[3] = 255;
1740 return new SplashSolidColor(color
);
1744 SplashPattern
*SplashOutputDev::getColor(GfxCMYK
*cmyk
) {
1747 color
[0] = colToByte(cmyk
->c
);
1748 color
[1] = colToByte(cmyk
->m
);
1749 color
[2] = colToByte(cmyk
->y
);
1750 color
[3] = colToByte(cmyk
->k
);
1751 return new SplashSolidColor(color
);
1754 SplashPattern
*SplashOutputDev::getColor(GfxColor
*deviceN
) {
1757 for (int i
= 0; i
< 4 + SPOT_NCOMPS
; i
++)
1758 color
[i
] = colToByte(deviceN
->c
[i
]);
1759 return new SplashSolidColor(color
);
1763 void SplashOutputDev::setOverprintMask(GfxColorSpace
*colorSpace
,
1764 GBool overprintFlag
,
1766 GfxColor
*singleColor
,
1767 GBool grayIndexed
) {
1771 GBool additive
= gFalse
;
1774 if (colorSpace
->getMode() == csIndexed
) {
1775 setOverprintMask(((GfxIndexedColorSpace
*)colorSpace
)->getBase(),
1782 if (overprintFlag
&& overprintPreview
) {
1783 mask
= colorSpace
->getOverprintMask();
1784 if (singleColor
&& overprintMode
&&
1785 colorSpace
->getMode() == csDeviceCMYK
) {
1786 colorSpace
->getCMYK(singleColor
, &cmyk
);
1802 } else if (colorSpace
->getMode() == csSeparation
) {
1803 GfxSeparationColorSpace
*deviceSep
= (GfxSeparationColorSpace
*)colorSpace
;
1804 additive
= deviceSep
->getName()->cmp("All") != 0 && mask
== 0x0f && !deviceSep
->isNonMarking();
1805 } else if (colorSpace
->getMode() == csDeviceN
) {
1806 GfxDeviceNColorSpace
*deviceNCS
= (GfxDeviceNColorSpace
*)colorSpace
;
1807 additive
= mask
== 0x0f && !deviceNCS
->isNonMarking();
1808 for (i
= 0; i
< deviceNCS
->getNComps() && additive
; i
++) {
1809 if (deviceNCS
->getColorantName(i
)->cmp("Cyan") == 0) {
1811 } else if (deviceNCS
->getColorantName(i
)->cmp("Magenta") == 0) {
1813 } else if (deviceNCS
->getColorantName(i
)->cmp("Yellow") == 0) {
1815 } else if (deviceNCS
->getColorantName(i
)->cmp("Black") == 0) {
1823 splash
->setOverprintMask(mask
, additive
);
1827 void SplashOutputDev::updateBlendMode(GfxState
*state
) {
1828 splash
->setBlendFunc(splashOutBlendFuncs
[state
->getBlendMode()]);
1831 void SplashOutputDev::updateFillOpacity(GfxState
*state
) {
1832 splash
->setFillAlpha((SplashCoord
)state
->getFillOpacity());
1833 if (transpGroupStack
!= NULL
&& (SplashCoord
)state
->getFillOpacity() < transpGroupStack
->knockoutOpacity
) {
1834 transpGroupStack
->knockoutOpacity
= (SplashCoord
)state
->getFillOpacity();
1838 void SplashOutputDev::updateStrokeOpacity(GfxState
*state
) {
1839 splash
->setStrokeAlpha((SplashCoord
)state
->getStrokeOpacity());
1840 if (transpGroupStack
!= NULL
&& (SplashCoord
)state
->getStrokeOpacity() < transpGroupStack
->knockoutOpacity
) {
1841 transpGroupStack
->knockoutOpacity
= (SplashCoord
)state
->getStrokeOpacity();
1845 void SplashOutputDev::updatePatternOpacity(GfxState
*state
) {
1846 splash
->setPatternAlpha((SplashCoord
)state
->getStrokeOpacity(), (SplashCoord
)state
->getFillOpacity());
1849 void SplashOutputDev::clearPatternOpacity(GfxState
*state
) {
1850 splash
->clearPatternAlpha();
1853 void SplashOutputDev::updateFillOverprint(GfxState
*state
) {
1854 splash
->setFillOverprint(state
->getFillOverprint());
1857 void SplashOutputDev::updateStrokeOverprint(GfxState
*state
) {
1858 splash
->setStrokeOverprint(state
->getStrokeOverprint());
1861 void SplashOutputDev::updateOverprintMode(GfxState
*state
) {
1862 splash
->setOverprintMode(state
->getOverprintMode());
1865 void SplashOutputDev::updateTransfer(GfxState
*state
) {
1866 Function
**transfer
;
1867 Guchar red
[256], green
[256], blue
[256], gray
[256];
1871 transfer
= state
->getTransfer();
1873 transfer
[0]->getInputSize() == 1 &&
1874 transfer
[0]->getOutputSize() == 1) {
1876 transfer
[1]->getInputSize() == 1 &&
1877 transfer
[1]->getOutputSize() == 1 &&
1879 transfer
[2]->getInputSize() == 1 &&
1880 transfer
[2]->getOutputSize() == 1 &&
1882 transfer
[3]->getInputSize() == 1 &&
1883 transfer
[3]->getOutputSize() == 1) {
1884 for (i
= 0; i
< 256; ++i
) {
1886 transfer
[0]->transform(&x
, &y
);
1887 red
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1888 transfer
[1]->transform(&x
, &y
);
1889 green
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1890 transfer
[2]->transform(&x
, &y
);
1891 blue
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1892 transfer
[3]->transform(&x
, &y
);
1893 gray
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1896 for (i
= 0; i
< 256; ++i
) {
1898 transfer
[0]->transform(&x
, &y
);
1899 red
[i
] = green
[i
] = blue
[i
] = gray
[i
] = (Guchar
)(y
* 255.0 + 0.5);
1903 for (i
= 0; i
< 256; ++i
) {
1904 red
[i
] = green
[i
] = blue
[i
] = gray
[i
] = (Guchar
)i
;
1907 splash
->setTransfer(red
, green
, blue
, gray
);
1910 void SplashOutputDev::updateFont(GfxState
* /*state*/) {
1911 needFontUpdate
= gTrue
;
1914 void SplashOutputDev::doUpdateFont(GfxState
*state
) {
1916 GfxFontLoc
*fontLoc
;
1917 GfxFontType fontType
;
1918 SplashOutFontFileID
*id
= NULL
;
1919 SplashFontFile
*fontFile
;
1920 SplashFontSrc
*fontsrc
= NULL
;
1922 Object refObj
, strObj
;
1923 GooString
*fileName
;
1928 double m11
, m12
, m21
, m22
, fontSize
;
1932 GBool recreateFont
= gFalse
;
1933 GBool doAdjustFontMatrix
= gFalse
;
1935 needFontUpdate
= gFalse
;
1941 if (!(gfxFont
= state
->getFont())) {
1944 fontType
= gfxFont
->getType();
1945 if (fontType
== fontType3
) {
1949 // sanity-check the font size - skip anything larger than 10 inches
1950 // (this avoids problems allocating memory for the font cache)
1951 if (state
->getTransformedFontSize()
1952 > 10 * (state
->getHDPI() + state
->getVDPI())) {
1956 // check the font file cache
1960 if (fontsrc
&& !fontsrc
->isFile
)
1963 id
= new SplashOutFontFileID(gfxFont
->getID());
1964 if ((fontFile
= fontEngine
->getFontFile(id
))) {
1969 if (!(fontLoc
= gfxFont
->locateFont((xref
) ? xref
: doc
->getXRef(), NULL
))) {
1970 error(errSyntaxError
, -1, "Couldn't find a font for '{0:s}'",
1971 gfxFont
->getName() ? gfxFont
->getName()->getCString()
1977 if (fontLoc
->locType
== gfxFontLocEmbedded
) {
1978 // if there is an embedded font, read it to memory
1979 tmpBuf
= gfxFont
->readEmbFontFile((xref
) ? xref
: doc
->getXRef(), &tmpBufLen
);
1984 } else { // gfxFontLocExternal
1985 fileName
= fontLoc
->path
;
1986 fontType
= fontLoc
->fontType
;
1987 doAdjustFontMatrix
= gTrue
;
1990 fontsrc
= new SplashFontSrc
;
1992 fontsrc
->setFile(fileName
, gFalse
);
1994 fontsrc
->setBuf(tmpBuf
, tmpBufLen
, gTrue
);
1996 // load the font file
1999 if (!(fontFile
= fontEngine
->loadType1Font(
2002 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
2003 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2004 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2006 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2011 if (!(fontFile
= fontEngine
->loadType1CFont(
2014 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
2015 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2016 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2018 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2023 if (!(fontFile
= fontEngine
->loadOpenTypeT1CFont(
2026 (const char **)((Gfx8BitFont
*)gfxFont
)->getEncoding()))) {
2027 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2028 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2030 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2035 case fontTrueTypeOT
:
2037 ff
= FoFiTrueType::load(fileName
->getCString());
2039 ff
= FoFiTrueType::make(tmpBuf
, tmpBufLen
);
2041 codeToGID
= ((Gfx8BitFont
*)gfxFont
)->getCodeToGIDMap(ff
);
2044 // if we're substituting for a non-TrueType font, we need to mark
2045 // all notdef codes as "do not draw" (rather than drawing TrueType
2047 if (gfxFont
->getType() != fontTrueType
&&
2048 gfxFont
->getType() != fontTrueTypeOT
) {
2049 for (i
= 0; i
< 256; ++i
) {
2050 if (codeToGID
[i
] == 0) {
2059 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
2063 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2064 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2066 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2072 if (!(fontFile
= fontEngine
->loadCIDFont(
2075 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2076 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2078 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2082 case fontCIDType0COT
:
2083 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
2084 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
2085 codeToGID
= (int *)gmallocn(n
, sizeof(int));
2086 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
2092 if (!(fontFile
= fontEngine
->loadOpenTypeCFFFont(
2096 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2097 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2099 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2104 case fontCIDType2OT
:
2107 if (((GfxCIDFont
*)gfxFont
)->getCIDToGID()) {
2108 n
= ((GfxCIDFont
*)gfxFont
)->getCIDToGIDLen();
2110 codeToGID
= (int *)gmallocn(n
, sizeof(int));
2111 memcpy(codeToGID
, ((GfxCIDFont
*)gfxFont
)->getCIDToGID(),
2116 ff
= FoFiTrueType::load(fileName
->getCString());
2118 ff
= FoFiTrueType::make(tmpBuf
, tmpBufLen
);
2121 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2122 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2126 codeToGID
= ((GfxCIDFont
*)gfxFont
)->getCodeToGIDMap(ff
, &n
);
2129 if (!(fontFile
= fontEngine
->loadTrueTypeFont(
2132 codeToGID
, n
, faceIndex
))) {
2133 error(errSyntaxError
, -1, "Couldn't create a font for '{0:s}'",
2134 gfxFont
->getName() ? gfxFont
->getName()->getCString()
2136 if (gfxFont
->invalidateEmbeddedFont()) goto reload
;
2141 // this shouldn't happen
2144 fontFile
->doAdjustMatrix
= doAdjustFontMatrix
;
2147 // get the font matrix
2148 textMat
= state
->getTextMat();
2149 fontSize
= state
->getFontSize();
2150 m11
= textMat
[0] * fontSize
* state
->getHorizScaling();
2151 m12
= textMat
[1] * fontSize
* state
->getHorizScaling();
2152 m21
= textMat
[2] * fontSize
;
2153 m22
= textMat
[3] * fontSize
;
2155 // create the scaled font
2156 mat
[0] = m11
; mat
[1] = m12
;
2157 mat
[2] = m21
; mat
[3] = m22
;
2158 font
= fontEngine
->getFont(fontFile
, mat
, splash
->getMatrix());
2160 // for substituted fonts: adjust the font matrix -- compare the
2161 // width of 'm' in the original font and the substituted font
2162 if (fontFile
->doAdjustMatrix
&& !gfxFont
->isCIDFont()) {
2166 for (code
= 0; code
< 256; ++code
) {
2167 if ((name
= ((Gfx8BitFont
*)gfxFont
)->getCharName(code
)) &&
2168 name
[0] == 'm' && name
[1] == '\0') {
2173 w1
= ((Gfx8BitFont
*)gfxFont
)->getWidth(code
);
2174 w2
= font
->getGlyphAdvance(code
);
2175 if (!gfxFont
->isSymbolic() && w2
> 0) {
2176 // if real font is substantially narrower than substituted
2177 // font, reduce the font size accordingly
2178 if (w1
> 0.01 && w1
< 0.9 * w2
) {
2182 recreateFont
= gTrue
;
2190 mat
[0] = m11
; mat
[1] = m12
;
2191 mat
[2] = m21
; mat
[3] = m22
;
2192 font
= fontEngine
->getFont(fontFile
, mat
, splash
->getMatrix());
2196 if (fontsrc
&& !fontsrc
->isFile
)
2204 if (fontsrc
&& !fontsrc
->isFile
)
2209 void SplashOutputDev::stroke(GfxState
*state
) {
2212 if (state
->getStrokeColorSpace()->isNonMarking()) {
2215 setOverprintMask(state
->getStrokeColorSpace(), state
->getStrokeOverprint(),
2216 state
->getOverprintMode(), state
->getStrokeColor());
2217 path
= convertPath(state
, state
->getPath(), gFalse
);
2218 splash
->stroke(path
);
2222 void SplashOutputDev::fill(GfxState
*state
) {
2225 if (state
->getFillColorSpace()->isNonMarking()) {
2228 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2229 state
->getOverprintMode(), state
->getFillColor());
2230 path
= convertPath(state
, state
->getPath(), gTrue
);
2231 splash
->fill(path
, gFalse
);
2235 void SplashOutputDev::eoFill(GfxState
*state
) {
2238 if (state
->getFillColorSpace()->isNonMarking()) {
2241 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2242 state
->getOverprintMode(), state
->getFillColor());
2243 path
= convertPath(state
, state
->getPath(), gTrue
);
2244 splash
->fill(path
, gTrue
);
2248 void SplashOutputDev::clip(GfxState
*state
) {
2251 path
= convertPath(state
, state
->getPath(), gTrue
);
2252 splash
->clipToPath(path
, gFalse
);
2256 void SplashOutputDev::eoClip(GfxState
*state
) {
2259 path
= convertPath(state
, state
->getPath(), gTrue
);
2260 splash
->clipToPath(path
, gTrue
);
2264 void SplashOutputDev::clipToStrokePath(GfxState
*state
) {
2265 SplashPath
*path
, *path2
;
2267 path
= convertPath(state
, state
->getPath(), gFalse
);
2268 path2
= splash
->makeStrokePath(path
, state
->getLineWidth());
2270 splash
->clipToPath(path2
, gFalse
);
2274 SplashPath
*SplashOutputDev::convertPath(GfxState
*state
, GfxPath
*path
,
2275 GBool dropEmptySubpaths
) {
2277 GfxSubpath
*subpath
;
2280 n
= dropEmptySubpaths
? 1 : 0;
2281 sPath
= new SplashPath();
2282 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
2283 subpath
= path
->getSubpath(i
);
2284 if (subpath
->getNumPoints() > n
) {
2285 sPath
->moveTo((SplashCoord
)subpath
->getX(0),
2286 (SplashCoord
)subpath
->getY(0));
2288 while (j
< subpath
->getNumPoints()) {
2289 if (subpath
->getCurve(j
)) {
2290 sPath
->curveTo((SplashCoord
)subpath
->getX(j
),
2291 (SplashCoord
)subpath
->getY(j
),
2292 (SplashCoord
)subpath
->getX(j
+1),
2293 (SplashCoord
)subpath
->getY(j
+1),
2294 (SplashCoord
)subpath
->getX(j
+2),
2295 (SplashCoord
)subpath
->getY(j
+2));
2298 sPath
->lineTo((SplashCoord
)subpath
->getX(j
),
2299 (SplashCoord
)subpath
->getY(j
));
2303 if (subpath
->isClosed()) {
2311 void SplashOutputDev::drawChar(GfxState
*state
, double x
, double y
,
2312 double dx
, double dy
,
2313 double originX
, double originY
,
2314 CharCode code
, int nBytes
,
2315 Unicode
*u
, int uLen
) {
2318 GBool doFill
, doStroke
, doClip
, strokeAdjust
;
2322 if (skipHorizText
|| skipRotatedText
) {
2323 state
->getFontTransMat(&m
[0], &m
[1], &m
[2], &m
[3]);
2324 horiz
= m
[0] > 0 && fabs(m
[1]) < 0.001 &&
2325 fabs(m
[2]) < 0.001 && m
[3] < 0;
2326 if ((skipHorizText
&& horiz
) || (skipRotatedText
&& !horiz
)) {
2331 // check for invisible text -- this is used by Acrobat Capture
2332 render
= state
->getRender();
2337 if (needFontUpdate
) {
2338 doUpdateFont(state
);
2347 doFill
= !(render
& 1) && !state
->getFillColorSpace()->isNonMarking();
2348 doStroke
= ((render
& 3) == 1 || (render
& 3) == 2) &&
2349 !state
->getStrokeColorSpace()->isNonMarking();
2350 doClip
= render
& 4;
2353 if (doStroke
|| doClip
) {
2354 if ((path
= font
->getGlyphPath(code
))) {
2355 path
->offset((SplashCoord
)x
, (SplashCoord
)y
);
2359 // don't use stroke adjustment when stroking text -- the results
2360 // tend to be ugly (because characters with horizontal upper or
2361 // lower edges get misaligned relative to the other characters)
2362 strokeAdjust
= gFalse
; // make gcc happy
2364 strokeAdjust
= splash
->getStrokeAdjust();
2365 splash
->setStrokeAdjust(gFalse
);
2369 if (doFill
&& doStroke
) {
2371 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2372 state
->getOverprintMode(), state
->getFillColor());
2373 splash
->fill(path
, gFalse
);
2374 setOverprintMask(state
->getStrokeColorSpace(),
2375 state
->getStrokeOverprint(),
2376 state
->getOverprintMode(),
2377 state
->getStrokeColor());
2378 splash
->stroke(path
);
2382 } else if (doFill
) {
2383 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2384 state
->getOverprintMode(), state
->getFillColor());
2385 splash
->fillChar((SplashCoord
)x
, (SplashCoord
)y
, code
, font
);
2388 } else if (doStroke
) {
2390 setOverprintMask(state
->getStrokeColorSpace(),
2391 state
->getStrokeOverprint(),
2392 state
->getOverprintMode(),
2393 state
->getStrokeColor());
2394 splash
->stroke(path
);
2402 textClipPath
->append(path
);
2404 textClipPath
= path
;
2411 splash
->setStrokeAdjust(strokeAdjust
);
2419 GBool
SplashOutputDev::beginType3Char(GfxState
*state
, double x
, double y
,
2420 double dx
, double dy
,
2421 CharCode code
, Unicode
*u
, int uLen
) {
2425 T3FontCache
*t3Font
;
2430 double x1
, y1
, xMin
, yMin
, xMax
, yMax
, xt
, yt
;
2433 if (skipHorizText
|| skipRotatedText
) {
2434 state
->getFontTransMat(&m
[0], &m
[1], &m
[2], &m
[3]);
2435 horiz
= m
[0] > 0 && fabs(m
[1]) < 0.001 &&
2436 fabs(m
[2]) < 0.001 && m
[3] < 0;
2437 if ((skipHorizText
&& horiz
) || (skipRotatedText
&& !horiz
)) {
2442 if (!(gfxFont
= state
->getFont())) {
2445 fontID
= gfxFont
->getID();
2446 ctm
= state
->getCTM();
2447 state
->transform(0, 0, &xt
, &yt
);
2449 // is it the first (MRU) font in the cache?
2450 if (!(nT3Fonts
> 0 &&
2451 t3FontCache
[0]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3]))) {
2453 // is the font elsewhere in the cache?
2454 for (i
= 1; i
< nT3Fonts
; ++i
) {
2455 if (t3FontCache
[i
]->matches(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3])) {
2456 t3Font
= t3FontCache
[i
];
2457 for (j
= i
; j
> 0; --j
) {
2458 t3FontCache
[j
] = t3FontCache
[j
- 1];
2460 t3FontCache
[0] = t3Font
;
2464 if (i
>= nT3Fonts
) {
2466 // create new entry in the font cache
2467 if (nT3Fonts
== splashOutT3FontCacheSize
) {
2468 t3gs
= t3GlyphStack
;
2469 while (t3gs
!= NULL
) {
2470 if (t3gs
->cache
== t3FontCache
[nT3Fonts
- 1]) {
2471 error(errSyntaxWarning
, -1, "t3FontCache reaches limit but font still on stack in SplashOutputDev::beginType3Char");
2476 delete t3FontCache
[nT3Fonts
- 1];
2479 for (j
= nT3Fonts
; j
> 0; --j
) {
2480 t3FontCache
[j
] = t3FontCache
[j
- 1];
2483 bbox
= gfxFont
->getFontBBox();
2484 if (bbox
[0] == 0 && bbox
[1] == 0 && bbox
[2] == 0 && bbox
[3] == 0) {
2485 // unspecified bounding box -- just take a guess
2492 state
->transform(bbox
[0], bbox
[1], &x1
, &y1
);
2495 state
->transform(bbox
[0], bbox
[3], &x1
, &y1
);
2498 } else if (x1
> xMax
) {
2503 } else if (y1
> yMax
) {
2506 state
->transform(bbox
[2], bbox
[1], &x1
, &y1
);
2509 } else if (x1
> xMax
) {
2514 } else if (y1
> yMax
) {
2517 state
->transform(bbox
[2], bbox
[3], &x1
, &y1
);
2520 } else if (x1
> xMax
) {
2525 } else if (y1
> yMax
) {
2530 t3FontCache
[0] = new T3FontCache(fontID
, ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2531 (int)floor(xMin
- xt
) - 2,
2532 (int)floor(yMin
- yt
) - 2,
2533 (int)ceil(xMax
) - (int)floor(xMin
) + 4,
2534 (int)ceil(yMax
) - (int)floor(yMin
) + 4,
2536 colorMode
!= splashModeMono1
);
2539 t3Font
= t3FontCache
[0];
2541 // is the glyph in the cache?
2542 i
= (code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
2543 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
2544 if (t3Font
->cacheTags
!= NULL
) {
2545 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x8000) &&
2546 t3Font
->cacheTags
[i
+j
].code
== code
) {
2547 drawType3Glyph(state
, t3Font
, &t3Font
->cacheTags
[i
+j
],
2548 t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
);
2554 // push a new Type 3 glyph record
2555 t3gs
= new T3GlyphStack();
2556 t3gs
->next
= t3GlyphStack
;
2557 t3GlyphStack
= t3gs
;
2558 t3GlyphStack
->code
= code
;
2559 t3GlyphStack
->cache
= t3Font
;
2560 t3GlyphStack
->cacheTag
= NULL
;
2561 t3GlyphStack
->cacheData
= NULL
;
2568 void SplashOutputDev::endType3Char(GfxState
*state
) {
2572 if (t3GlyphStack
->cacheTag
) {
2574 memcpy(t3GlyphStack
->cacheData
, bitmap
->getDataPtr(),
2575 t3GlyphStack
->cache
->glyphSize
);
2578 bitmap
= t3GlyphStack
->origBitmap
;
2579 splash
= t3GlyphStack
->origSplash
;
2580 ctm
= state
->getCTM();
2581 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2582 t3GlyphStack
->origCTM4
, t3GlyphStack
->origCTM5
);
2583 updateCTM(state
, 0, 0, 0, 0, 0, 0);
2584 drawType3Glyph(state
, t3GlyphStack
->cache
,
2585 t3GlyphStack
->cacheTag
, t3GlyphStack
->cacheData
);
2587 t3gs
= t3GlyphStack
;
2588 t3GlyphStack
= t3gs
->next
;
2592 void SplashOutputDev::type3D0(GfxState
*state
, double wx
, double wy
) {
2596 void SplashOutputDev::type3D1(GfxState
*state
, double wx
, double wy
,
2597 double llx
, double lly
, double urx
, double ury
) {
2599 T3FontCache
*t3Font
;
2601 double xt
, yt
, xMin
, xMax
, yMin
, yMax
, x1
, y1
;
2604 // ignore multiple d0/d1 operators
2610 if (unlikely(t3GlyphStack
== NULL
)) {
2611 error(errSyntaxWarning
, -1, "t3GlyphStack was null in SplashOutputDev::type3D1");
2615 if (unlikely(t3GlyphStack
->origBitmap
!= NULL
)) {
2616 error(errSyntaxWarning
, -1, "t3GlyphStack origBitmap was not null in SplashOutputDev::type3D1");
2620 if (unlikely(t3GlyphStack
->origSplash
!= NULL
)) {
2621 error(errSyntaxWarning
, -1, "t3GlyphStack origSplash was not null in SplashOutputDev::type3D1");
2625 t3Font
= t3GlyphStack
->cache
;
2627 // check for a valid bbox
2628 state
->transform(0, 0, &xt
, &yt
);
2629 state
->transform(llx
, lly
, &x1
, &y1
);
2632 state
->transform(llx
, ury
, &x1
, &y1
);
2635 } else if (x1
> xMax
) {
2640 } else if (y1
> yMax
) {
2643 state
->transform(urx
, lly
, &x1
, &y1
);
2646 } else if (x1
> xMax
) {
2651 } else if (y1
> yMax
) {
2654 state
->transform(urx
, ury
, &x1
, &y1
);
2657 } else if (x1
> xMax
) {
2662 } else if (y1
> yMax
) {
2665 if (xMin
- xt
< t3Font
->glyphX
||
2666 yMin
- yt
< t3Font
->glyphY
||
2667 xMax
- xt
> t3Font
->glyphX
+ t3Font
->glyphW
||
2668 yMax
- yt
> t3Font
->glyphY
+ t3Font
->glyphH
) {
2669 if (t3Font
->validBBox
) {
2670 error(errSyntaxWarning
, -1, "Bad bounding box in Type 3 glyph");
2675 if (t3Font
->cacheTags
== NULL
)
2678 // allocate a cache entry
2679 i
= (t3GlyphStack
->code
& (t3Font
->cacheSets
- 1)) * t3Font
->cacheAssoc
;
2680 for (j
= 0; j
< t3Font
->cacheAssoc
; ++j
) {
2681 if ((t3Font
->cacheTags
[i
+j
].mru
& 0x7fff) == t3Font
->cacheAssoc
- 1) {
2682 t3Font
->cacheTags
[i
+j
].mru
= 0x8000;
2683 t3Font
->cacheTags
[i
+j
].code
= t3GlyphStack
->code
;
2684 t3GlyphStack
->cacheTag
= &t3Font
->cacheTags
[i
+j
];
2685 t3GlyphStack
->cacheData
= t3Font
->cacheData
+ (i
+j
) * t3Font
->glyphSize
;
2687 ++t3Font
->cacheTags
[i
+j
].mru
;
2692 t3GlyphStack
->origBitmap
= bitmap
;
2693 t3GlyphStack
->origSplash
= splash
;
2694 ctm
= state
->getCTM();
2695 t3GlyphStack
->origCTM4
= ctm
[4];
2696 t3GlyphStack
->origCTM5
= ctm
[5];
2698 // create the temporary bitmap
2699 if (colorMode
== splashModeMono1
) {
2700 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
2701 splashModeMono1
, gFalse
);
2702 splash
= new Splash(bitmap
, gFalse
,
2703 t3GlyphStack
->origSplash
->getScreen());
2705 splash
->clear(color
);
2708 bitmap
= new SplashBitmap(t3Font
->glyphW
, t3Font
->glyphH
, 1,
2709 splashModeMono8
, gFalse
);
2710 splash
= new Splash(bitmap
, vectorAntialias
,
2711 t3GlyphStack
->origSplash
->getScreen());
2713 splash
->clear(color
);
2716 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
2717 splash
->setThinLineMode(splashThinLineDefault
);
2718 splash
->setFillPattern(new SplashSolidColor(color
));
2719 splash
->setStrokePattern(new SplashSolidColor(color
));
2720 //~ this should copy other state from t3GlyphStack->origSplash?
2721 state
->setCTM(ctm
[0], ctm
[1], ctm
[2], ctm
[3],
2722 -t3Font
->glyphX
, -t3Font
->glyphY
);
2723 updateCTM(state
, 0, 0, 0, 0, 0, 0);
2727 void SplashOutputDev::drawType3Glyph(GfxState
*state
, T3FontCache
*t3Font
,
2728 T3FontCacheTag
* /*tag*/, Guchar
*data
) {
2729 SplashGlyphBitmap glyph
;
2731 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2732 state
->getOverprintMode(), state
->getFillColor());
2733 glyph
.x
= -t3Font
->glyphX
;
2734 glyph
.y
= -t3Font
->glyphY
;
2735 glyph
.w
= t3Font
->glyphW
;
2736 glyph
.h
= t3Font
->glyphH
;
2737 glyph
.aa
= colorMode
!= splashModeMono1
;
2739 glyph
.freeData
= gFalse
;
2740 splash
->fillGlyph(0, 0, &glyph
);
2743 void SplashOutputDev::beginTextObject(GfxState
*state
) {
2746 void SplashOutputDev::endTextObject(GfxState
*state
) {
2748 splash
->clipToPath(textClipPath
, gFalse
);
2749 delete textClipPath
;
2750 textClipPath
= NULL
;
2754 struct SplashOutImageMaskData
{
2755 ImageStream
*imgStr
;
2757 int width
, height
, y
;
2760 GBool
SplashOutputDev::imageMaskSrc(void *data
, SplashColorPtr line
) {
2761 SplashOutImageMaskData
*imgMaskData
= (SplashOutImageMaskData
*)data
;
2766 if (imgMaskData
->y
== imgMaskData
->height
) {
2769 if (!(p
= imgMaskData
->imgStr
->getLine())) {
2772 for (x
= 0, q
= line
; x
< imgMaskData
->width
; ++x
) {
2773 *q
++ = *p
++ ^ imgMaskData
->invert
;
2779 void SplashOutputDev::drawImageMask(GfxState
*state
, Object
*ref
, Stream
*str
,
2780 int width
, int height
, GBool invert
,
2781 GBool interpolate
, GBool inlineImg
) {
2784 SplashOutImageMaskData imgMaskData
;
2786 if (state
->getFillColorSpace()->isNonMarking()) {
2789 setOverprintMask(state
->getFillColorSpace(), state
->getFillOverprint(),
2790 state
->getOverprintMode(), state
->getFillColor());
2792 ctm
= state
->getCTM();
2793 for (int i
= 0; i
< 6; ++i
) {
2794 if (!isfinite(ctm
[i
])) return;
2800 mat
[4] = ctm
[2] + ctm
[4];
2801 mat
[5] = ctm
[3] + ctm
[5];
2803 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
2804 imgMaskData
.imgStr
->reset();
2805 imgMaskData
.invert
= invert
? 0 : 1;
2806 imgMaskData
.width
= width
;
2807 imgMaskData
.height
= height
;
2810 splash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
, t3GlyphStack
!= NULL
);
2812 while (imgMaskData
.y
< height
) {
2813 imgMaskData
.imgStr
->getLine();
2818 delete imgMaskData
.imgStr
;
2822 void SplashOutputDev::setSoftMaskFromImageMask(GfxState
*state
,
2823 Object
*ref
, Stream
*str
,
2824 int width
, int height
,
2826 GBool inlineImg
, double *baseMatrix
) {
2829 SplashOutImageMaskData imgMaskData
;
2831 SplashColor maskColor
;
2832 double bbox
[4] = {0, 0, 1, 1}; // default;
2834 if (state
->getFillColorSpace()->isNonMarking()) {
2838 ctm
= state
->getCTM();
2839 for (int i
= 0; i
< 6; ++i
) {
2840 if (!isfinite(ctm
[i
])) return;
2843 beginTransparencyGroup(state
, bbox
, NULL
, gFalse
, gFalse
, gFalse
);
2844 baseMatrix
[4] -= transpGroupStack
->tx
;
2845 baseMatrix
[5] -= transpGroupStack
->ty
;
2847 ctm
= state
->getCTM();
2852 mat
[4] = ctm
[2] + ctm
[4];
2853 mat
[5] = ctm
[3] + ctm
[5];
2854 imgMaskData
.imgStr
= new ImageStream(str
, width
, 1, 1);
2855 imgMaskData
.imgStr
->reset();
2856 imgMaskData
.invert
= invert
? 0 : 1;
2857 imgMaskData
.width
= width
;
2858 imgMaskData
.height
= height
;
2861 transpGroupStack
->softmask
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(), 1, splashModeMono8
, gFalse
);
2862 maskSplash
= new Splash(transpGroupStack
->softmask
, vectorAntialias
);
2864 maskSplash
->clear(maskColor
);
2865 maskColor
[0] = 0xff;
2866 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
2867 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
, width
, height
, mat
, t3GlyphStack
!= NULL
);
2869 delete imgMaskData
.imgStr
;
2873 void SplashOutputDev::unsetSoftMaskFromImageMask(GfxState
*state
, double *baseMatrix
) {
2874 double bbox
[4] = {0,0,1,1}; // dummy
2876 /* transfer mask to alpha channel! */
2877 // memcpy(maskBitmap->getAlphaPtr(), maskBitmap->getDataPtr(), bitmap->getRowSize() * bitmap->getHeight());
2878 // memset(maskBitmap->getDataPtr(), 0, bitmap->getRowSize() * bitmap->getHeight());
2879 if (transpGroupStack
->softmask
!= NULL
) {
2880 Guchar
*dest
= bitmap
->getAlphaPtr();
2881 Guchar
*src
= transpGroupStack
->softmask
->getDataPtr();
2882 for (int c
= 0; c
< transpGroupStack
->softmask
->getRowSize() * transpGroupStack
->softmask
->getHeight(); c
++) {
2885 delete transpGroupStack
->softmask
;
2886 transpGroupStack
->softmask
= NULL
;
2888 endTransparencyGroup(state
);
2889 baseMatrix
[4] += transpGroupStack
->tx
;
2890 baseMatrix
[5] += transpGroupStack
->ty
;
2891 paintTransparencyGroup(state
, bbox
);
2894 struct SplashOutImageData
{
2895 ImageStream
*imgStr
;
2896 GfxImageColorMap
*colorMap
;
2897 SplashColorPtr lookup
;
2899 SplashColorMode colorMode
;
2900 int width
, height
, y
;
2904 GBool
SplashOutputDev::useIccImageSrc(void *data
) {
2905 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
2907 if (!imgData
->lookup
&& imgData
->colorMap
->getColorSpace()->getMode() == csICCBased
) {
2908 GfxICCBasedColorSpace
*colorSpace
= (GfxICCBasedColorSpace
*) imgData
->colorMap
->getColorSpace();
2909 switch (imgData
->colorMode
) {
2910 case splashModeMono1
:
2911 case splashModeMono8
:
2912 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceGray
)
2915 case splashModeXBGR8
:
2916 case splashModeRGB8
:
2917 case splashModeBGR8
:
2918 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceRGB
)
2922 case splashModeCMYK8
:
2923 if (colorSpace
->getAlt() != NULL
&& colorSpace
->getAlt()->getMode() == csDeviceCMYK
)
2934 GBool
SplashOutputDev::imageSrc(void *data
, SplashColorPtr colorLine
,
2935 Guchar
* /*alphaLine*/) {
2936 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
2938 SplashColorPtr q
, col
;
2947 if (imgData
->y
== imgData
->height
) {
2950 if (!(p
= imgData
->imgStr
->getLine())) {
2952 if (imgData
->colorMode
== splashModeRGB8
|| imgData
->colorMode
== splashModeBGR8
)
2954 else if (imgData
->colorMode
== splashModeXBGR8
)
2957 else if (imgData
->colorMode
== splashModeCMYK8
)
2959 else if (imgData
->colorMode
== splashModeDeviceN8
)
2960 destComps
= SPOT_NCOMPS
+ 4;
2962 memset(colorLine
, 0, imgData
->width
* destComps
);
2966 nComps
= imgData
->colorMap
->getNumPixelComps();
2968 if (imgData
->lookup
) {
2969 switch (imgData
->colorMode
) {
2970 case splashModeMono1
:
2971 case splashModeMono8
:
2972 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2973 *q
++ = imgData
->lookup
[*p
];
2976 case splashModeRGB8
:
2977 case splashModeBGR8
:
2978 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2979 col
= &imgData
->lookup
[3 * *p
];
2985 case splashModeXBGR8
:
2986 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2987 col
= &imgData
->lookup
[4 * *p
];
2995 case splashModeCMYK8
:
2996 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
2997 col
= &imgData
->lookup
[4 * *p
];
3004 case splashModeDeviceN8
:
3005 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, ++p
) {
3006 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
3007 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3014 switch (imgData
->colorMode
) {
3015 case splashModeMono1
:
3016 case splashModeMono8
:
3017 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3018 imgData
->colorMap
->getGray(p
, &gray
);
3019 *q
++ = colToByte(gray
);
3022 case splashModeRGB8
:
3023 case splashModeBGR8
:
3024 if (imgData
->colorMap
->useRGBLine()) {
3025 imgData
->colorMap
->getRGBLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3027 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3028 imgData
->colorMap
->getRGB(p
, &rgb
);
3029 *q
++ = colToByte(rgb
.r
);
3030 *q
++ = colToByte(rgb
.g
);
3031 *q
++ = colToByte(rgb
.b
);
3035 case splashModeXBGR8
:
3036 if (imgData
->colorMap
->useRGBLine()) {
3037 imgData
->colorMap
->getRGBXLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3039 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3040 imgData
->colorMap
->getRGB(p
, &rgb
);
3041 *q
++ = colToByte(rgb
.r
);
3042 *q
++ = colToByte(rgb
.g
);
3043 *q
++ = colToByte(rgb
.b
);
3049 case splashModeCMYK8
:
3050 if (imgData
->colorMap
->useCMYKLine()) {
3051 imgData
->colorMap
->getCMYKLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3053 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3054 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3055 *q
++ = colToByte(cmyk
.c
);
3056 *q
++ = colToByte(cmyk
.m
);
3057 *q
++ = colToByte(cmyk
.y
);
3058 *q
++ = colToByte(cmyk
.k
);
3062 case splashModeDeviceN8
:
3063 if (imgData
->colorMap
->useDeviceNLine()) {
3064 imgData
->colorMap
->getDeviceNLine(p
, (Guchar
*) colorLine
, imgData
->width
);
3066 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
, p
+= nComps
) {
3067 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3068 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3069 *q
++ = colToByte(deviceN
.c
[cp
]);
3082 GBool
SplashOutputDev::iccImageSrc(void *data
, SplashColorPtr colorLine
,
3083 Guchar
* /*alphaLine*/) {
3084 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3088 if (imgData
->y
== imgData
->height
) {
3091 if (!(p
= imgData
->imgStr
->getLine())) {
3093 if (imgData
->colorMode
== splashModeRGB8
|| imgData
->colorMode
== splashModeBGR8
)
3095 else if (imgData
->colorMode
== splashModeXBGR8
)
3098 else if (imgData
->colorMode
== splashModeCMYK8
)
3100 else if (imgData
->colorMode
== splashModeDeviceN8
)
3101 destComps
= SPOT_NCOMPS
+ 4;
3103 memset(colorLine
, 0, imgData
->width
* destComps
);
3107 if (imgData
->colorMode
== splashModeXBGR8
) {
3110 for (x
= 0, q
= colorLine
; x
< imgData
->width
; ++x
) {
3117 nComps
= imgData
->colorMap
->getNumPixelComps();
3118 memcpy(colorLine
, p
, imgData
->width
* nComps
);
3125 void SplashOutputDev::iccTransform(void *data
, SplashBitmap
*bitmap
) {
3126 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3127 int nComps
= imgData
->colorMap
->getNumPixelComps();
3129 Guchar
*colorLine
= (Guchar
*) gmalloc(nComps
* bitmap
->getWidth());
3130 Guchar
*rgbxLine
= (imgData
->colorMode
== splashModeXBGR8
) ? (Guchar
*) gmalloc(3 * bitmap
->getWidth()) : NULL
;
3131 for (int i
= 0; i
< bitmap
->getHeight(); i
++) {
3132 Guchar
*p
= bitmap
->getDataPtr() + i
* bitmap
->getRowSize();
3133 switch (imgData
->colorMode
) {
3134 case splashModeMono1
:
3135 case splashModeMono8
:
3136 imgData
->colorMap
->getGrayLine(p
, colorLine
, bitmap
->getWidth());
3137 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3139 case splashModeRGB8
:
3140 case splashModeBGR8
:
3141 imgData
->colorMap
->getRGBLine(p
, colorLine
, bitmap
->getWidth());
3142 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3145 case splashModeCMYK8
:
3146 imgData
->colorMap
->getCMYKLine(p
, colorLine
, bitmap
->getWidth());
3147 memcpy(p
, colorLine
, nComps
* bitmap
->getWidth());
3150 case splashModeXBGR8
:
3154 for (x
= 0, q
= rgbxLine
; x
< bitmap
->getWidth(); ++x
, ++b
) {
3159 imgData
->colorMap
->getRGBLine(rgbxLine
, colorLine
, bitmap
->getWidth());
3161 for (x
= 0, q
= colorLine
; x
< bitmap
->getWidth(); ++x
, ++b
) {
3170 if (rgbxLine
!= NULL
)
3175 GBool
SplashOutputDev::alphaImageSrc(void *data
, SplashColorPtr colorLine
,
3176 Guchar
*alphaLine
) {
3177 SplashOutImageData
*imgData
= (SplashOutImageData
*)data
;
3179 SplashColorPtr q
, col
;
3189 if (imgData
->y
== imgData
->height
) {
3192 if (!(p
= imgData
->imgStr
->getLine())) {
3196 nComps
= imgData
->colorMap
->getNumPixelComps();
3198 for (x
= 0, q
= colorLine
, aq
= alphaLine
;
3202 for (i
= 0; i
< nComps
; ++i
) {
3203 if (p
[i
] < imgData
->maskColors
[2*i
] ||
3204 p
[i
] > imgData
->maskColors
[2*i
+1]) {
3209 if (imgData
->lookup
) {
3210 switch (imgData
->colorMode
) {
3211 case splashModeMono1
:
3212 case splashModeMono8
:
3213 *q
++ = imgData
->lookup
[*p
];
3215 case splashModeRGB8
:
3216 case splashModeBGR8
:
3217 col
= &imgData
->lookup
[3 * *p
];
3222 case splashModeXBGR8
:
3223 col
= &imgData
->lookup
[4 * *p
];
3230 case splashModeCMYK8
:
3231 col
= &imgData
->lookup
[4 * *p
];
3237 case splashModeDeviceN8
:
3238 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
3239 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3246 switch (imgData
->colorMode
) {
3247 case splashModeMono1
:
3248 case splashModeMono8
:
3249 imgData
->colorMap
->getGray(p
, &gray
);
3250 *q
++ = colToByte(gray
);
3252 case splashModeXBGR8
:
3253 case splashModeRGB8
:
3254 case splashModeBGR8
:
3255 imgData
->colorMap
->getRGB(p
, &rgb
);
3256 *q
++ = colToByte(rgb
.r
);
3257 *q
++ = colToByte(rgb
.g
);
3258 *q
++ = colToByte(rgb
.b
);
3259 if (imgData
->colorMode
== splashModeXBGR8
) *q
++ = 255;
3262 case splashModeCMYK8
:
3263 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3264 *q
++ = colToByte(cmyk
.c
);
3265 *q
++ = colToByte(cmyk
.m
);
3266 *q
++ = colToByte(cmyk
.y
);
3267 *q
++ = colToByte(cmyk
.k
);
3269 case splashModeDeviceN8
:
3270 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3271 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3272 *q
++ = colToByte(deviceN
.c
[cp
]);
3284 struct TilingSplashOutBitmap
{
3285 SplashBitmap
*bitmap
;
3286 SplashPattern
*pattern
;
3287 SplashColorMode colorMode
;
3294 GBool
SplashOutputDev::tilingBitmapSrc(void *data
, SplashColorPtr colorLine
,
3295 Guchar
*alphaLine
) {
3296 TilingSplashOutBitmap
*imgData
= (TilingSplashOutBitmap
*)data
;
3298 if (imgData
->y
== imgData
->bitmap
->getHeight()) {
3300 if (imgData
->repeatY
== 0)
3305 if (imgData
->paintType
== 1) {
3306 const SplashColorMode cMode
= imgData
->bitmap
->getMode();
3307 SplashColorPtr q
= colorLine
;
3308 // For splashModeBGR8 and splashModeXBGR8 we need to use getPixel
3309 // for the others we can use raw access
3310 if (cMode
== splashModeBGR8
|| cMode
== splashModeXBGR8
) {
3311 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3312 for (int x
= 0; x
< imgData
->bitmap
->getWidth(); x
++) {
3313 imgData
->bitmap
->getPixel(x
, imgData
->y
, q
);
3314 q
+= splashColorModeNComps
[cMode
];
3318 const int n
= imgData
->bitmap
->getRowSize();
3320 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3321 p
= imgData
->bitmap
->getDataPtr() + imgData
->y
* imgData
->bitmap
->getRowSize();
3322 for (int x
= 0; x
< n
; ++x
) {
3327 if (alphaLine
!= NULL
) {
3328 SplashColorPtr aq
= alphaLine
;
3330 const int n
= imgData
->bitmap
->getWidth() - 1;
3331 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3332 p
= imgData
->bitmap
->getAlphaPtr() + imgData
->y
* imgData
->bitmap
->getWidth();
3333 for (int x
= 0; x
< n
; ++x
) {
3336 // This is a hack, because of how Splash antialias works if we overwrite the
3337 // last alpha pixel of the tile most/all of the files look much better
3338 *aq
++ = (n
== 0) ? *p
: *(p
- 1);
3342 SplashColor col
, pat
;
3343 SplashColorPtr dest
= colorLine
;
3344 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3345 for (int x
= 0; x
< imgData
->bitmap
->getWidth(); x
++) {
3346 imgData
->bitmap
->getPixel(x
, imgData
->y
, col
);
3347 imgData
->pattern
->getColor(x
, imgData
->y
, pat
);
3348 for (int i
= 0; i
< splashColorModeNComps
[imgData
->colorMode
]; ++i
) {
3350 if (imgData
->colorMode
== splashModeCMYK8
|| imgData
->colorMode
== splashModeDeviceN8
)
3351 dest
[i
] = div255(pat
[i
] * (255 - col
[0]));
3354 dest
[i
] = 255 - div255((255 - pat
[i
]) * (255 - col
[0]));
3356 dest
+= splashColorModeNComps
[imgData
->colorMode
];
3359 if (alphaLine
!= NULL
) {
3360 const int y
= (imgData
->y
== imgData
->bitmap
->getHeight() - 1 && imgData
->y
> 50) ? imgData
->y
- 1 : imgData
->y
;
3361 SplashColorPtr aq
= alphaLine
;
3363 const int n
= imgData
->bitmap
->getWidth();
3364 for (int m
= 0; m
< imgData
->repeatX
; m
++) {
3365 p
= imgData
->bitmap
->getAlphaPtr() + y
* imgData
->bitmap
->getWidth();
3366 for (int x
= 0; x
< n
; ++x
) {
3376 void SplashOutputDev::drawImage(GfxState
*state
, Object
*ref
, Stream
*str
,
3377 int width
, int height
,
3378 GfxImageColorMap
*colorMap
,
3380 int *maskColors
, GBool inlineImg
) {
3383 SplashOutImageData imgData
;
3384 SplashColorMode srcMode
;
3385 SplashImageSource src
;
3386 SplashICCTransform tf
;
3391 GBool grayIndexed
= gFalse
;
3397 ctm
= state
->getCTM();
3398 for (i
= 0; i
< 6; ++i
) {
3399 if (!isfinite(ctm
[i
])) return;
3405 mat
[4] = ctm
[2] + ctm
[4];
3406 mat
[5] = ctm
[3] + ctm
[5];
3408 imgData
.imgStr
= new ImageStream(str
, width
,
3409 colorMap
->getNumPixelComps(),
3410 colorMap
->getBits());
3411 imgData
.imgStr
->reset();
3412 imgData
.colorMap
= colorMap
;
3413 imgData
.maskColors
= maskColors
;
3414 imgData
.colorMode
= colorMode
;
3415 imgData
.width
= width
;
3416 imgData
.height
= height
;
3419 // special case for one-channel (monochrome/gray/separation) images:
3420 // build a lookup table here
3421 imgData
.lookup
= NULL
;
3422 if (colorMap
->getNumPixelComps() == 1) {
3423 n
= 1 << colorMap
->getBits();
3424 switch (colorMode
) {
3425 case splashModeMono1
:
3426 case splashModeMono8
:
3427 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3428 for (i
= 0; i
< n
; ++i
) {
3430 colorMap
->getGray(&pix
, &gray
);
3431 imgData
.lookup
[i
] = colToByte(gray
);
3434 case splashModeRGB8
:
3435 case splashModeBGR8
:
3436 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3437 for (i
= 0; i
< n
; ++i
) {
3439 colorMap
->getRGB(&pix
, &rgb
);
3440 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3441 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3442 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3445 case splashModeXBGR8
:
3446 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3447 for (i
= 0; i
< n
; ++i
) {
3449 colorMap
->getRGB(&pix
, &rgb
);
3450 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3451 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3452 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3453 imgData
.lookup
[4*i
+3] = 255;
3457 case splashModeCMYK8
:
3458 grayIndexed
= colorMap
->getColorSpace()->getMode() != csDeviceGray
;
3459 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3460 for (i
= 0; i
< n
; ++i
) {
3462 colorMap
->getCMYK(&pix
, &cmyk
);
3463 if (cmyk
.c
!= 0 || cmyk
.m
!= 0 || cmyk
.y
!= 0) {
3464 grayIndexed
= gFalse
;
3466 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3467 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3468 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3469 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3472 case splashModeDeviceN8
:
3473 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3474 grayIndexed
= colorMap
->getColorSpace()->getMode() != csDeviceGray
;
3475 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3476 for (i
= 0; i
< n
; ++i
) {
3478 colorMap
->getCMYK(&pix
, &cmyk
);
3479 if (cmyk
.c
!= 0 || cmyk
.m
!= 0 || cmyk
.y
!= 0) {
3480 grayIndexed
= gFalse
;
3482 colorMap
->getDeviceN(&pix
, &deviceN
);
3483 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3484 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+cp
] = colToByte(deviceN
.c
[cp
]);
3492 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3493 state
->getOverprintMode(), NULL
, grayIndexed
);
3495 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3496 state
->getOverprintMode(), NULL
);
3499 if (colorMode
== splashModeMono1
) {
3500 srcMode
= splashModeMono8
;
3502 srcMode
= colorMode
;
3505 src
= maskColors
? &alphaImageSrc
: useIccImageSrc(&imgData
) ? &iccImageSrc
: &imageSrc
;
3506 tf
= maskColors
== NULL
&& useIccImageSrc(&imgData
) ? &iccTransform
: NULL
;
3508 src
= maskColors
? &alphaImageSrc
: &imageSrc
;
3511 splash
->drawImage(src
, tf
, &imgData
, srcMode
, maskColors
? gTrue
: gFalse
,
3512 width
, height
, mat
, interpolate
);
3514 while (imgData
.y
< height
) {
3515 imgData
.imgStr
->getLine();
3520 gfree(imgData
.lookup
);
3521 delete imgData
.imgStr
;
3525 struct SplashOutMaskedImageData
{
3526 ImageStream
*imgStr
;
3527 GfxImageColorMap
*colorMap
;
3529 SplashColorPtr lookup
;
3530 SplashColorMode colorMode
;
3531 int width
, height
, y
;
3534 GBool
SplashOutputDev::maskedImageSrc(void *data
, SplashColorPtr colorLine
,
3535 Guchar
*alphaLine
) {
3536 SplashOutMaskedImageData
*imgData
= (SplashOutMaskedImageData
*)data
;
3538 SplashColorPtr q
, col
;
3550 if (imgData
->y
== imgData
->height
) {
3553 if (!(p
= imgData
->imgStr
->getLine())) {
3557 nComps
= imgData
->colorMap
->getNumPixelComps();
3559 maskPtr
= imgData
->mask
->getDataPtr() +
3560 imgData
->y
* imgData
->mask
->getRowSize();
3562 for (x
= 0, q
= colorLine
, aq
= alphaLine
;
3565 alpha
= (*maskPtr
& maskBit
) ? 0xff : 0x00;
3566 if (!(maskBit
>>= 1)) {
3570 if (imgData
->lookup
) {
3571 switch (imgData
->colorMode
) {
3572 case splashModeMono1
:
3573 case splashModeMono8
:
3574 *q
++ = imgData
->lookup
[*p
];
3576 case splashModeRGB8
:
3577 case splashModeBGR8
:
3578 col
= &imgData
->lookup
[3 * *p
];
3583 case splashModeXBGR8
:
3584 col
= &imgData
->lookup
[4 * *p
];
3591 case splashModeCMYK8
:
3592 col
= &imgData
->lookup
[4 * *p
];
3598 case splashModeDeviceN8
:
3599 col
= &imgData
->lookup
[(SPOT_NCOMPS
+4) * *p
];
3600 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3607 switch (imgData
->colorMode
) {
3608 case splashModeMono1
:
3609 case splashModeMono8
:
3610 imgData
->colorMap
->getGray(p
, &gray
);
3611 *q
++ = colToByte(gray
);
3613 case splashModeXBGR8
:
3614 case splashModeRGB8
:
3615 case splashModeBGR8
:
3616 imgData
->colorMap
->getRGB(p
, &rgb
);
3617 *q
++ = colToByte(rgb
.r
);
3618 *q
++ = colToByte(rgb
.g
);
3619 *q
++ = colToByte(rgb
.b
);
3620 if (imgData
->colorMode
== splashModeXBGR8
) *q
++ = 255;
3623 case splashModeCMYK8
:
3624 imgData
->colorMap
->getCMYK(p
, &cmyk
);
3625 *q
++ = colToByte(cmyk
.c
);
3626 *q
++ = colToByte(cmyk
.m
);
3627 *q
++ = colToByte(cmyk
.y
);
3628 *q
++ = colToByte(cmyk
.k
);
3630 case splashModeDeviceN8
:
3631 imgData
->colorMap
->getDeviceN(p
, &deviceN
);
3632 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3633 *q
++ = colToByte(deviceN
.c
[cp
]);
3645 void SplashOutputDev::drawMaskedImage(GfxState
*state
, Object
*ref
,
3646 Stream
*str
, int width
, int height
,
3647 GfxImageColorMap
*colorMap
,
3649 Stream
*maskStr
, int maskWidth
,
3650 int maskHeight
, GBool maskInvert
,
3651 GBool maskInterpolate
) {
3652 GfxImageColorMap
*maskColorMap
;
3653 Object maskDecode
, decodeLow
, decodeHigh
;
3656 SplashOutMaskedImageData imgData
;
3657 SplashOutImageMaskData imgMaskData
;
3658 SplashColorMode srcMode
;
3659 SplashBitmap
*maskBitmap
;
3661 SplashColor maskColor
;
3672 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3674 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3675 state
->getOverprintMode(), NULL
);
3677 // If the mask is higher resolution than the image, use
3678 // drawSoftMaskedImage() instead.
3679 if (maskWidth
> width
|| maskHeight
> height
) {
3680 decodeLow
.initInt(maskInvert
? 0 : 1);
3681 decodeHigh
.initInt(maskInvert
? 1 : 0);
3682 maskDecode
.initArray((xref
) ? xref
: doc
->getXRef());
3683 maskDecode
.arrayAdd(&decodeLow
);
3684 maskDecode
.arrayAdd(&decodeHigh
);
3685 maskColorMap
= new GfxImageColorMap(1, &maskDecode
,
3686 new GfxDeviceGrayColorSpace());
3688 drawSoftMaskedImage(state
, ref
, str
, width
, height
, colorMap
, interpolate
,
3689 maskStr
, maskWidth
, maskHeight
, maskColorMap
, maskInterpolate
);
3690 delete maskColorMap
;
3693 //----- scale the mask image to the same size as the source image
3695 mat
[0] = (SplashCoord
)width
;
3698 mat
[3] = (SplashCoord
)height
;
3701 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
, 1, 1);
3702 imgMaskData
.imgStr
->reset();
3703 imgMaskData
.invert
= maskInvert
? 0 : 1;
3704 imgMaskData
.width
= maskWidth
;
3705 imgMaskData
.height
= maskHeight
;
3707 maskBitmap
= new SplashBitmap(width
, height
, 1, splashModeMono1
, gFalse
);
3708 if (!maskBitmap
->getDataPtr()) {
3711 maskBitmap
= new SplashBitmap(width
, height
, 1, splashModeMono1
, gFalse
);
3713 maskSplash
= new Splash(maskBitmap
, gFalse
);
3715 maskSplash
->clear(maskColor
);
3716 maskColor
[0] = 0xff;
3717 maskSplash
->setFillPattern(new SplashSolidColor(maskColor
));
3718 maskSplash
->fillImageMask(&imageMaskSrc
, &imgMaskData
,
3719 maskWidth
, maskHeight
, mat
, gFalse
);
3720 delete imgMaskData
.imgStr
;
3724 //----- draw the source image
3726 ctm
= state
->getCTM();
3727 for (i
= 0; i
< 6; ++i
) {
3728 if (!isfinite(ctm
[i
])) {
3737 mat
[4] = ctm
[2] + ctm
[4];
3738 mat
[5] = ctm
[3] + ctm
[5];
3740 imgData
.imgStr
= new ImageStream(str
, width
,
3741 colorMap
->getNumPixelComps(),
3742 colorMap
->getBits());
3743 imgData
.imgStr
->reset();
3744 imgData
.colorMap
= colorMap
;
3745 imgData
.mask
= maskBitmap
;
3746 imgData
.colorMode
= colorMode
;
3747 imgData
.width
= width
;
3748 imgData
.height
= height
;
3751 // special case for one-channel (monochrome/gray/separation) images:
3752 // build a lookup table here
3753 imgData
.lookup
= NULL
;
3754 if (colorMap
->getNumPixelComps() == 1) {
3755 n
= 1 << colorMap
->getBits();
3756 switch (colorMode
) {
3757 case splashModeMono1
:
3758 case splashModeMono8
:
3759 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3760 for (i
= 0; i
< n
; ++i
) {
3762 colorMap
->getGray(&pix
, &gray
);
3763 imgData
.lookup
[i
] = colToByte(gray
);
3766 case splashModeRGB8
:
3767 case splashModeBGR8
:
3768 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3769 for (i
= 0; i
< n
; ++i
) {
3771 colorMap
->getRGB(&pix
, &rgb
);
3772 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3773 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3774 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3777 case splashModeXBGR8
:
3778 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3779 for (i
= 0; i
< n
; ++i
) {
3781 colorMap
->getRGB(&pix
, &rgb
);
3782 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3783 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3784 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3785 imgData
.lookup
[4*i
+3] = 255;
3789 case splashModeCMYK8
:
3790 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3791 for (i
= 0; i
< n
; ++i
) {
3793 colorMap
->getCMYK(&pix
, &cmyk
);
3794 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3795 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3796 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3797 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3800 case splashModeDeviceN8
:
3801 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3802 for (i
= 0; i
< n
; ++i
) {
3804 colorMap
->getDeviceN(&pix
, &deviceN
);
3805 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3806 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+ cp
] = colToByte(deviceN
.c
[cp
]);
3813 if (colorMode
== splashModeMono1
) {
3814 srcMode
= splashModeMono8
;
3816 srcMode
= colorMode
;
3818 splash
->drawImage(&maskedImageSrc
, NULL
, &imgData
, srcMode
, gTrue
,
3819 width
, height
, mat
, interpolate
);
3821 gfree(imgData
.lookup
);
3822 delete imgData
.imgStr
;
3827 void SplashOutputDev::drawSoftMaskedImage(GfxState
*state
, Object
*ref
,
3828 Stream
*str
, int width
, int height
,
3829 GfxImageColorMap
*colorMap
,
3832 int maskWidth
, int maskHeight
,
3833 GfxImageColorMap
*maskColorMap
,
3834 GBool maskInterpolate
) {
3837 SplashOutImageData imgData
;
3838 SplashOutImageData imgMaskData
;
3839 SplashColorMode srcMode
;
3840 SplashBitmap
*maskBitmap
;
3842 SplashColor maskColor
;
3853 colorMap
->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
3855 setOverprintMask(colorMap
->getColorSpace(), state
->getFillOverprint(),
3856 state
->getOverprintMode(), NULL
);
3858 ctm
= state
->getCTM();
3859 for (i
= 0; i
< 6; ++i
) {
3860 if (!isfinite(ctm
[i
])) return;
3866 mat
[4] = ctm
[2] + ctm
[4];
3867 mat
[5] = ctm
[3] + ctm
[5];
3869 //----- set up the soft mask
3871 imgMaskData
.imgStr
= new ImageStream(maskStr
, maskWidth
,
3872 maskColorMap
->getNumPixelComps(),
3873 maskColorMap
->getBits());
3874 imgMaskData
.imgStr
->reset();
3875 imgMaskData
.colorMap
= maskColorMap
;
3876 imgMaskData
.maskColors
= NULL
;
3877 imgMaskData
.colorMode
= splashModeMono8
;
3878 imgMaskData
.width
= maskWidth
;
3879 imgMaskData
.height
= maskHeight
;
3881 n
= 1 << maskColorMap
->getBits();
3882 imgMaskData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3883 for (i
= 0; i
< n
; ++i
) {
3885 maskColorMap
->getGray(&pix
, &gray
);
3886 imgMaskData
.lookup
[i
] = colToByte(gray
);
3888 maskBitmap
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
3889 1, splashModeMono8
, gFalse
);
3890 maskSplash
= new Splash(maskBitmap
, vectorAntialias
);
3892 maskSplash
->clear(maskColor
);
3893 maskSplash
->drawImage(&imageSrc
, NULL
, &imgMaskData
, splashModeMono8
, gFalse
,
3894 maskWidth
, maskHeight
, mat
, maskInterpolate
);
3895 delete imgMaskData
.imgStr
;
3897 gfree(imgMaskData
.lookup
);
3899 splash
->setSoftMask(maskBitmap
);
3901 //----- draw the source image
3903 imgData
.imgStr
= new ImageStream(str
, width
,
3904 colorMap
->getNumPixelComps(),
3905 colorMap
->getBits());
3906 imgData
.imgStr
->reset();
3907 imgData
.colorMap
= colorMap
;
3908 imgData
.maskColors
= NULL
;
3909 imgData
.colorMode
= colorMode
;
3910 imgData
.width
= width
;
3911 imgData
.height
= height
;
3914 // special case for one-channel (monochrome/gray/separation) images:
3915 // build a lookup table here
3916 imgData
.lookup
= NULL
;
3917 if (colorMap
->getNumPixelComps() == 1) {
3918 n
= 1 << colorMap
->getBits();
3919 switch (colorMode
) {
3920 case splashModeMono1
:
3921 case splashModeMono8
:
3922 imgData
.lookup
= (SplashColorPtr
)gmalloc(n
);
3923 for (i
= 0; i
< n
; ++i
) {
3925 colorMap
->getGray(&pix
, &gray
);
3926 imgData
.lookup
[i
] = colToByte(gray
);
3929 case splashModeRGB8
:
3930 case splashModeBGR8
:
3931 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 3);
3932 for (i
= 0; i
< n
; ++i
) {
3934 colorMap
->getRGB(&pix
, &rgb
);
3935 imgData
.lookup
[3*i
] = colToByte(rgb
.r
);
3936 imgData
.lookup
[3*i
+1] = colToByte(rgb
.g
);
3937 imgData
.lookup
[3*i
+2] = colToByte(rgb
.b
);
3940 case splashModeXBGR8
:
3941 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3942 for (i
= 0; i
< n
; ++i
) {
3944 colorMap
->getRGB(&pix
, &rgb
);
3945 imgData
.lookup
[4*i
] = colToByte(rgb
.r
);
3946 imgData
.lookup
[4*i
+1] = colToByte(rgb
.g
);
3947 imgData
.lookup
[4*i
+2] = colToByte(rgb
.b
);
3948 imgData
.lookup
[4*i
+3] = 255;
3952 case splashModeCMYK8
:
3953 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, 4);
3954 for (i
= 0; i
< n
; ++i
) {
3956 colorMap
->getCMYK(&pix
, &cmyk
);
3957 imgData
.lookup
[4*i
] = colToByte(cmyk
.c
);
3958 imgData
.lookup
[4*i
+1] = colToByte(cmyk
.m
);
3959 imgData
.lookup
[4*i
+2] = colToByte(cmyk
.y
);
3960 imgData
.lookup
[4*i
+3] = colToByte(cmyk
.k
);
3963 case splashModeDeviceN8
:
3964 imgData
.lookup
= (SplashColorPtr
)gmallocn(n
, SPOT_NCOMPS
+4);
3965 for (i
= 0; i
< n
; ++i
) {
3967 colorMap
->getDeviceN(&pix
, &deviceN
);
3968 for (int cp
= 0; cp
< SPOT_NCOMPS
+4; cp
++)
3969 imgData
.lookup
[(SPOT_NCOMPS
+4)*i
+ cp
] = colToByte(deviceN
.c
[cp
]);
3976 if (colorMode
== splashModeMono1
) {
3977 srcMode
= splashModeMono8
;
3979 srcMode
= colorMode
;
3981 splash
->drawImage(&imageSrc
, NULL
, &imgData
, srcMode
, gFalse
, width
, height
, mat
, interpolate
);
3982 splash
->setSoftMask(NULL
);
3983 gfree(imgData
.lookup
);
3984 delete imgData
.imgStr
;
3988 GBool
SplashOutputDev::checkTransparencyGroup(GfxState
*state
, GBool knockout
) {
3989 if (state
->getFillOpacity() != 1 ||
3990 state
->getStrokeOpacity() != 1 ||
3991 state
->getAlphaIsShape() ||
3992 state
->getBlendMode() != gfxBlendNormal
||
3993 splash
->getSoftMask() != NULL
||
3996 return transpGroupStack
!= NULL
&& transpGroupStack
->shape
!= NULL
;
3999 void SplashOutputDev::beginTransparencyGroup(GfxState
*state
, double *bbox
,
4000 GfxColorSpace
*blendingColorSpace
,
4001 GBool isolated
, GBool knockout
,
4002 GBool forSoftMask
) {
4003 SplashTransparencyGroup
*transpGroup
;
4005 double xMin
, yMin
, xMax
, yMax
, x
, y
;
4006 int tx
, ty
, w
, h
, i
;
4008 // transform the bbox
4009 state
->transform(bbox
[0], bbox
[1], &x
, &y
);
4012 state
->transform(bbox
[0], bbox
[3], &x
, &y
);
4015 } else if (x
> xMax
) {
4020 } else if (y
> yMax
) {
4023 state
->transform(bbox
[2], bbox
[1], &x
, &y
);
4026 } else if (x
> xMax
) {
4031 } else if (y
> yMax
) {
4034 state
->transform(bbox
[2], bbox
[3], &x
, &y
);
4037 } else if (x
> xMax
) {
4042 } else if (y
> yMax
) {
4045 tx
= (int)floor(xMin
);
4048 } else if (tx
>= bitmap
->getWidth()) {
4049 tx
= bitmap
->getWidth() - 1;
4051 ty
= (int)floor(yMin
);
4054 } else if (ty
>= bitmap
->getHeight()) {
4055 ty
= bitmap
->getHeight() - 1;
4057 w
= (int)ceil(xMax
) - tx
+ 1;
4058 if (tx
+ w
> bitmap
->getWidth()) {
4059 w
= bitmap
->getWidth() - tx
;
4064 h
= (int)ceil(yMax
) - ty
+ 1;
4065 if (ty
+ h
> bitmap
->getHeight()) {
4066 h
= bitmap
->getHeight() - ty
;
4072 // push a new stack entry
4073 transpGroup
= new SplashTransparencyGroup();
4074 transpGroup
->softmask
= NULL
;
4075 transpGroup
->tx
= tx
;
4076 transpGroup
->ty
= ty
;
4077 transpGroup
->blendingColorSpace
= blendingColorSpace
;
4078 transpGroup
->isolated
= isolated
;
4079 transpGroup
->shape
= (knockout
&& !isolated
) ? SplashBitmap::copy(bitmap
) : NULL
;
4080 transpGroup
->knockout
= (knockout
&& isolated
);
4081 transpGroup
->knockoutOpacity
= 1.0;
4082 transpGroup
->next
= transpGroupStack
;
4083 transpGroupStack
= transpGroup
;
4086 transpGroup
->origBitmap
= bitmap
;
4087 transpGroup
->origSplash
= splash
;
4088 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
4089 transpGroup
->fontAA
= fontEngine
->getAA();
4092 //~ this handles the blendingColorSpace arg for soft masks, but
4093 //~ not yet for transparency groups
4095 // switch to the blending color space
4096 if (forSoftMask
&& isolated
&& blendingColorSpace
) {
4097 if (blendingColorSpace
->getMode() == csDeviceGray
||
4098 blendingColorSpace
->getMode() == csCalGray
||
4099 (blendingColorSpace
->getMode() == csICCBased
&&
4100 blendingColorSpace
->getNComps() == 1)) {
4101 colorMode
= splashModeMono8
;
4102 } else if (blendingColorSpace
->getMode() == csDeviceRGB
||
4103 blendingColorSpace
->getMode() == csCalRGB
||
4104 (blendingColorSpace
->getMode() == csICCBased
&&
4105 blendingColorSpace
->getNComps() == 3)) {
4106 //~ does this need to use BGR8?
4107 colorMode
= splashModeRGB8
;
4109 } else if (blendingColorSpace
->getMode() == csDeviceCMYK
||
4110 (blendingColorSpace
->getMode() == csICCBased
&&
4111 blendingColorSpace
->getNComps() == 4)) {
4112 colorMode
= splashModeCMYK8
;
4117 // create the temporary bitmap
4118 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
, gTrue
,
4119 bitmapTopDown
, bitmap
->getSeparationList());
4120 if (!bitmap
->getDataPtr()) {
4123 bitmap
= new SplashBitmap(w
, h
, bitmapRowPad
, colorMode
, gTrue
, bitmapTopDown
);
4125 splash
= new Splash(bitmap
, vectorAntialias
,
4126 transpGroup
->origSplash
->getScreen());
4127 if (transpGroup
->next
!= NULL
&& transpGroup
->next
->knockout
) {
4128 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
4129 fontEngine
->setAA(gFalse
);
4132 splash
->setThinLineMode(transpGroup
->origSplash
->getThinLineMode());
4133 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
4134 //~ Acrobat apparently copies at least the fill and stroke colors, and
4135 //~ maybe other state(?) -- but not the clipping path (and not sure
4137 //~ [this is likely the same situation as in type3D1()]
4138 splash
->setFillPattern(transpGroup
->origSplash
->getFillPattern()->copy());
4139 splash
->setStrokePattern(
4140 transpGroup
->origSplash
->getStrokePattern()->copy());
4142 for (i
= 0; i
< splashMaxColorComps
; ++i
) {
4145 if (colorMode
== splashModeXBGR8
) color
[3] = 255;
4146 splash
->clear(color
, 0);
4148 SplashBitmap
*shape
= (knockout
) ? transpGroup
->shape
:
4149 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->shape
: transpGroup
->origBitmap
;
4150 int shapeTx
= (knockout
) ? tx
:
4151 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->tx
+ tx
: tx
;
4152 int shapeTy
= (knockout
) ? ty
:
4153 (transpGroup
->next
!= NULL
&& transpGroup
->next
->shape
!= NULL
) ? transpGroup
->next
->ty
+ ty
: ty
;
4154 splash
->blitTransparent(transpGroup
->origBitmap
, tx
, ty
, 0, 0, w
, h
);
4155 splash
->setInNonIsolatedGroup(shape
, shapeTx
, shapeTy
);
4157 transpGroup
->tBitmap
= bitmap
;
4158 state
->shiftCTMAndClip(-tx
, -ty
);
4159 updateCTM(state
, 0, 0, 0, 0, 0, 0);
4163 void SplashOutputDev::endTransparencyGroup(GfxState
*state
) {
4167 bitmap
= transpGroupStack
->origBitmap
;
4168 colorMode
= bitmap
->getMode();
4169 splash
= transpGroupStack
->origSplash
;
4170 state
->shiftCTMAndClip(transpGroupStack
->tx
, transpGroupStack
->ty
);
4171 updateCTM(state
, 0, 0, 0, 0, 0, 0);
4174 void SplashOutputDev::paintTransparencyGroup(GfxState
*state
, double *bbox
) {
4175 SplashBitmap
*tBitmap
;
4176 SplashTransparencyGroup
*transpGroup
;
4180 tx
= transpGroupStack
->tx
;
4181 ty
= transpGroupStack
->ty
;
4182 tBitmap
= transpGroupStack
->tBitmap
;
4183 isolated
= transpGroupStack
->isolated
;
4185 // paint the transparency group onto the parent bitmap
4186 // - the clip path was set in the parent's state)
4187 if (tx
< bitmap
->getWidth() && ty
< bitmap
->getHeight()) {
4188 SplashCoord knockoutOpacity
= (transpGroupStack
->next
!= NULL
) ? transpGroupStack
->next
->knockoutOpacity
4189 : transpGroupStack
->knockoutOpacity
;
4190 splash
->setOverprintMask(0xffffffff, gFalse
);
4191 splash
->composite(tBitmap
, 0, 0, tx
, ty
,
4192 tBitmap
->getWidth(), tBitmap
->getHeight(),
4193 gFalse
, !isolated
, transpGroupStack
->next
!= NULL
&& transpGroupStack
->next
->knockout
, knockoutOpacity
);
4194 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
4195 fontEngine
->setAA(transpGroupStack
->fontAA
);
4197 if (transpGroupStack
->next
!= NULL
&& transpGroupStack
->next
->shape
!= NULL
) {
4198 transpGroupStack
->next
->knockout
= gTrue
;
4203 transpGroup
= transpGroupStack
;
4204 transpGroupStack
= transpGroup
->next
;
4205 if (transpGroupStack
!= NULL
&& transpGroup
->knockoutOpacity
< transpGroupStack
->knockoutOpacity
) {
4206 transpGroupStack
->knockoutOpacity
= transpGroup
->knockoutOpacity
;
4208 delete transpGroup
->shape
;
4214 void SplashOutputDev::setSoftMask(GfxState
*state
, double *bbox
,
4215 GBool alpha
, Function
*transferFunc
,
4216 GfxColor
*backdropColor
) {
4217 SplashBitmap
*softMask
, *tBitmap
;
4219 SplashTransparencyGroup
*transpGroup
;
4231 tx
= transpGroupStack
->tx
;
4232 ty
= transpGroupStack
->ty
;
4233 tBitmap
= transpGroupStack
->tBitmap
;
4235 // composite with backdrop color
4236 if (!alpha
&& tBitmap
->getMode() != splashModeMono1
) {
4237 //~ need to correctly handle the case where no blending color
4239 if (transpGroupStack
->blendingColorSpace
) {
4240 tSplash
= new Splash(tBitmap
, vectorAntialias
,
4241 transpGroupStack
->origSplash
->getScreen());
4242 switch (tBitmap
->getMode()) {
4243 case splashModeMono1
:
4244 // transparency is not supported in mono1 mode
4246 case splashModeMono8
:
4247 transpGroupStack
->blendingColorSpace
->getGray(backdropColor
, &gray
);
4248 color
[0] = colToByte(gray
);
4249 tSplash
->compositeBackground(color
);
4251 case splashModeXBGR8
:
4253 case splashModeRGB8
:
4254 case splashModeBGR8
:
4255 transpGroupStack
->blendingColorSpace
->getRGB(backdropColor
, &rgb
);
4256 color
[0] = colToByte(rgb
.r
);
4257 color
[1] = colToByte(rgb
.g
);
4258 color
[2] = colToByte(rgb
.b
);
4259 tSplash
->compositeBackground(color
);
4262 case splashModeCMYK8
:
4263 transpGroupStack
->blendingColorSpace
->getCMYK(backdropColor
, &cmyk
);
4264 color
[0] = colToByte(cmyk
.c
);
4265 color
[1] = colToByte(cmyk
.m
);
4266 color
[2] = colToByte(cmyk
.y
);
4267 color
[3] = colToByte(cmyk
.k
);
4268 tSplash
->compositeBackground(color
);
4270 case splashModeDeviceN8
:
4271 transpGroupStack
->blendingColorSpace
->getDeviceN(backdropColor
, &deviceN
);
4272 for (int cp
=0; cp
< SPOT_NCOMPS
+4; cp
++)
4273 color
[cp
] = colToByte(deviceN
.c
[cp
]);
4274 tSplash
->compositeBackground(color
);
4282 softMask
= new SplashBitmap(bitmap
->getWidth(), bitmap
->getHeight(),
4283 1, splashModeMono8
, gFalse
);
4284 unsigned char fill
= 0;
4285 if (transpGroupStack
->blendingColorSpace
) {
4286 transpGroupStack
->blendingColorSpace
->getGray(backdropColor
, &gray
);
4287 fill
= colToByte(gray
);
4289 memset(softMask
->getDataPtr(), fill
,
4290 softMask
->getRowSize() * softMask
->getHeight());
4291 p
= softMask
->getDataPtr() + ty
* softMask
->getRowSize() + tx
;
4292 int xMax
= tBitmap
->getWidth();
4293 int yMax
= tBitmap
->getHeight();
4294 if (xMax
> bitmap
->getWidth() - tx
) xMax
= bitmap
->getWidth() - tx
;
4295 if (yMax
> bitmap
->getHeight() - ty
) yMax
= bitmap
->getHeight() - ty
;
4296 for (y
= 0; y
< yMax
; ++y
) {
4297 for (x
= 0; x
< xMax
; ++x
) {
4300 lum
= tBitmap
->getAlpha(x
, y
) / 255.0;
4301 transferFunc
->transform(&lum
, &lum2
);
4302 p
[x
] = (int)(lum2
* 255.0 + 0.5);
4304 p
[x
] = tBitmap
->getAlpha(x
, y
);
4306 tBitmap
->getPixel(x
, y
, color
);
4307 // convert to luminosity
4308 switch (tBitmap
->getMode()) {
4309 case splashModeMono1
:
4310 case splashModeMono8
:
4311 lum
= color
[0] / 255.0;
4313 case splashModeXBGR8
:
4314 case splashModeRGB8
:
4315 case splashModeBGR8
:
4316 lum
= (0.3 / 255.0) * color
[0] +
4317 (0.59 / 255.0) * color
[1] +
4318 (0.11 / 255.0) * color
[2];
4321 case splashModeCMYK8
:
4322 case splashModeDeviceN8
:
4323 lum
= (1 - color
[3] / 255.0)
4324 - (0.3 / 255.0) * color
[0]
4325 - (0.59 / 255.0) * color
[1]
4326 - (0.11 / 255.0) * color
[2];
4334 transferFunc
->transform(&lum
, &lum2
);
4338 p
[x
] = (int)(lum2
* 255.0 + 0.5);
4341 p
+= softMask
->getRowSize();
4343 splash
->setSoftMask(softMask
);
4346 transpGroup
= transpGroupStack
;
4347 transpGroupStack
= transpGroup
->next
;
4353 void SplashOutputDev::clearSoftMask(GfxState
*state
) {
4354 splash
->setSoftMask(NULL
);
4357 void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA
) {
4358 splashColorCopy(paperColor
, paperColorA
);
4361 int SplashOutputDev::getBitmapWidth() {
4362 return bitmap
->getWidth();
4365 int SplashOutputDev::getBitmapHeight() {
4366 return bitmap
->getHeight();
4369 SplashBitmap
*SplashOutputDev::takeBitmap() {
4373 bitmap
= new SplashBitmap(1, 1, bitmapRowPad
, colorMode
,
4374 colorMode
!= splashModeMono1
, bitmapTopDown
);
4378 void SplashOutputDev::getModRegion(int *xMin
, int *yMin
,
4379 int *xMax
, int *yMax
) {
4380 splash
->getModRegion(xMin
, yMin
, xMax
, yMax
);
4383 void SplashOutputDev::clearModRegion() {
4384 splash
->clearModRegion();
4387 #if 1 //~tmp: turn off anti-aliasing temporarily
4388 GBool
SplashOutputDev::getVectorAntialias() {
4389 return splash
->getVectorAntialias();
4392 void SplashOutputDev::setVectorAntialias(GBool vaa
) {
4393 vaa
= vaa
&& colorMode
!= splashModeMono1
;
4394 vectorAntialias
= vaa
;
4395 splash
->setVectorAntialias(vaa
);
4399 void SplashOutputDev::setFreeTypeHinting(GBool enable
, GBool enableSlightHintingA
)
4401 enableFreeTypeHinting
= enable
;
4402 enableSlightHinting
= enableSlightHintingA
;
4405 GBool
SplashOutputDev::tilingPatternFill(GfxState
*state
, Gfx
*gfxA
, Catalog
*catalog
, Object
*str
,
4406 double *ptm
, int paintType
, int /*tilingType*/, Dict
*resDict
,
4407 double *mat
, double *bbox
,
4408 int x0
, int y0
, int x1
, int y1
,
4409 double xStep
, double yStep
)
4413 Splash
*formerSplash
= splash
;
4414 SplashBitmap
*formerBitmap
= bitmap
;
4415 double width
, height
;
4416 int surface_width
, surface_height
, result_width
, result_height
, i
;
4417 int repeatX
, repeatY
;
4418 SplashCoord matc
[6];
4420 double *ctm
, savedCTM
[6];
4421 double kx
, ky
, sx
, sy
;
4422 GBool retValue
= gFalse
;
4424 width
= bbox
[2] - bbox
[0];
4425 height
= bbox
[3] - bbox
[1];
4427 if (xStep
!= width
|| yStep
!= height
)
4430 // calculate offsets
4431 ctm
= state
->getCTM();
4432 for (i
= 0; i
< 6; ++i
) {
4433 savedCTM
[i
] = ctm
[i
];
4435 state
->concatCTM(mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
4436 state
->concatCTM(1, 0, 0, 1, bbox
[0], bbox
[1]);
4437 ctm
= state
->getCTM();
4438 for (i
= 0; i
< 6; ++i
) {
4439 if (!isfinite(ctm
[i
])) {
4440 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4444 matc
[4] = x0
* xStep
* ctm
[0] + y0
* yStep
* ctm
[2] + ctm
[4];
4445 matc
[5] = x0
* xStep
* ctm
[1] + y0
* yStep
* ctm
[3] + ctm
[5];
4446 if (splashAbs(ctm
[1]) > splashAbs(ctm
[0])) {
4448 ky
= ctm
[2] - (ctm
[0] * ctm
[3]) / ctm
[1];
4451 ky
= ctm
[3] - (ctm
[1] * ctm
[2]) / ctm
[0];
4453 result_width
= (int) ceil(fabs(kx
* width
* (x1
- x0
)));
4454 result_height
= (int) ceil(fabs(ky
* height
* (y1
- y0
)));
4455 kx
= state
->getHDPI() / 72.0;
4456 ky
= state
->getVDPI() / 72.0;
4457 m1
.m
[0] = (ptm
[0] == 0) ? fabs(ptm
[2]) * kx
: fabs(ptm
[0]) * kx
;
4460 m1
.m
[3] = (ptm
[3] == 0) ? fabs(ptm
[1]) * ky
: fabs(ptm
[3]) * ky
;
4463 m1
.transform(width
, height
, &kx
, &ky
);
4464 surface_width
= (int) ceil (fabs(kx
));
4465 surface_height
= (int) ceil (fabs(ky
));
4467 sx
= (double) result_width
/ (surface_width
* (x1
- x0
));
4468 sy
= (double) result_height
/ (surface_height
* (y1
- y0
));
4471 m1
.transform(width
, height
, &kx
, &ky
);
4473 if(fabs(kx
) < 1 && fabs(ky
) < 1) {
4474 kx
= std::min
<double>(kx
, ky
);
4478 m1
.transform(width
, height
, &kx
, &ky
);
4479 surface_width
= (int) ceil (fabs(kx
));
4480 surface_height
= (int) ceil (fabs(ky
));
4484 if ((unsigned long) surface_width
* surface_height
> 0x800000L
) {
4485 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4488 while(fabs(kx
) > 16384 || fabs(ky
) > 16384) {
4489 // limit pattern bitmap size
4492 m1
.transform(width
, height
, &kx
, &ky
);
4494 surface_width
= (int) ceil (fabs(kx
));
4495 surface_height
= (int) ceil (fabs(ky
));
4496 // adjust repeat values to completely fill region
4497 repeatX
= result_width
/ surface_width
;
4498 repeatY
= result_height
/ surface_height
;
4499 if (surface_width
* repeatX
< result_width
)
4501 if (surface_height
* repeatY
< result_height
)
4503 if (x1
- x0
> repeatX
)
4505 if (y1
- y0
> repeatY
)
4508 // restore CTM and calculate rotate and scale with rounded matric
4509 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4510 state
->concatCTM(mat
[0], mat
[1], mat
[2], mat
[3], mat
[4], mat
[5]);
4511 state
->concatCTM(width
* repeatX
, 0, 0, height
* repeatY
, bbox
[0], bbox
[1]);
4512 ctm
= state
->getCTM();
4518 if (surface_width
== 0 || surface_height
== 0) {
4519 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4522 m1
.transform(bbox
[0], bbox
[1], &kx
, &ky
);
4526 bitmap
= new SplashBitmap(surface_width
, surface_height
, 1,
4527 (paintType
== 1) ? colorMode
: splashModeMono8
, gTrue
);
4528 if (bitmap
->getDataPtr() == NULL
) {
4529 SplashBitmap
*tBitmap
= bitmap
;
4530 bitmap
= formerBitmap
;
4532 state
->setCTM(savedCTM
[0], savedCTM
[1], savedCTM
[2], savedCTM
[3], savedCTM
[4], savedCTM
[5]);
4535 splash
= new Splash(bitmap
, gTrue
);
4536 if (paintType
== 2) {
4537 SplashColor clearColor
;
4539 clearColor
[0] = (colorMode
== splashModeCMYK8
|| colorMode
== splashModeDeviceN8
) ? 0x00 : 0xFF;
4541 clearColor
[0] = 0xFF;
4543 splash
->clear(clearColor
, 0);
4545 splash
->clear(paperColor
, 0);
4547 splash
->setThinLineMode(formerSplash
->getThinLineMode());
4548 splash
->setMinLineWidth(globalParams
->getMinLineWidth());
4550 box
.x1
= bbox
[0]; box
.y1
= bbox
[1];
4551 box
.x2
= bbox
[2]; box
.y2
= bbox
[3];
4552 gfx
= new Gfx(doc
, this, resDict
, &box
, NULL
, NULL
, NULL
, gfxA
->getXRef());
4553 // set pattern transformation matrix
4554 gfx
->getState()->setCTM(m1
.m
[0], m1
.m
[1], m1
.m
[2], m1
.m
[3], m1
.m
[4], m1
.m
[5]);
4555 updateCTM(gfx
->getState(), m1
.m
[0], m1
.m
[1], m1
.m
[2], m1
.m
[3], m1
.m
[4], m1
.m
[5]);
4558 splash
= formerSplash
;
4559 TilingSplashOutBitmap imgData
;
4560 imgData
.bitmap
= bitmap
;
4561 imgData
.paintType
= paintType
;
4562 imgData
.pattern
= splash
->getFillPattern();
4563 imgData
.colorMode
= colorMode
;
4565 imgData
.repeatX
= repeatX
;
4566 imgData
.repeatY
= repeatY
;
4567 SplashBitmap
*tBitmap
= bitmap
;
4568 bitmap
= formerBitmap
;
4569 result_width
= tBitmap
->getWidth() * imgData
.repeatX
;
4570 result_height
= tBitmap
->getHeight() * imgData
.repeatY
;
4572 if (splashAbs(matc
[1]) > splashAbs(matc
[0])) {
4574 ky
= matc
[2] - (matc
[0] * matc
[3]) / matc
[1];
4577 ky
= matc
[3] - (matc
[1] * matc
[2]) / matc
[0];
4579 kx
= result_width
/ (fabs(kx
) + 1);
4580 ky
= result_height
/ (fabs(ky
) + 1);
4581 state
->concatCTM(kx
, 0, 0, ky
, 0, 0);
4582 ctm
= state
->getCTM();
4587 GBool minorAxisZero
= matc
[1] == 0 && matc
[2] == 0;
4588 if (matc
[0] > 0 && minorAxisZero
&& matc
[3] > 0) {
4590 for (int y
= 0; y
< imgData
.repeatY
; ++y
) {
4591 for (int x
= 0; x
< imgData
.repeatX
; ++x
) {
4592 x0
= splashFloor(matc
[4]) + x
* tBitmap
->getWidth();
4593 y0
= splashFloor(matc
[5]) + y
* tBitmap
->getHeight();
4594 splash
->blitImage(tBitmap
, gTrue
, x0
, y0
);
4599 retValue
= splash
->drawImage(&tilingBitmapSrc
, NULL
, &imgData
, colorMode
, gTrue
, result_width
, result_height
, matc
, gFalse
, gTrue
) == splashOk
;
4606 GBool
SplashOutputDev::gouraudTriangleShadedFill(GfxState
*state
, GfxGouraudTriangleShading
*shading
)
4608 GfxColorSpaceMode shadingMode
= shading
->getColorSpace()->getMode();
4609 GBool bDirectColorTranslation
= gFalse
; // triggers an optimization.
4610 switch (colorMode
) {
4611 case splashModeRGB8
:
4612 bDirectColorTranslation
= (shadingMode
== csDeviceRGB
);
4615 case splashModeCMYK8
:
4616 case splashModeDeviceN8
:
4617 bDirectColorTranslation
= (shadingMode
== csDeviceCMYK
);
4623 SplashGouraudColor
*splashShading
= new SplashGouraudPattern(bDirectColorTranslation
, state
, shading
, colorMode
);
4624 // restore vector antialias because we support it here
4625 if (shading
->isParameterized()) {
4626 GBool vaa
= getVectorAntialias();
4627 GBool retVal
= gFalse
;
4628 setVectorAntialias(gTrue
);
4629 retVal
= splash
->gouraudTriangleShadedFill(splashShading
);
4630 setVectorAntialias(vaa
);
4633 delete splashShading
;
4637 GBool
SplashOutputDev::univariateShadedFill(GfxState
*state
, SplashUnivariatePattern
*pattern
, double tMin
, double tMax
) {
4638 double xMin
, yMin
, xMax
, yMax
;
4640 GBool vaa
= getVectorAntialias();
4641 // restore vector antialias because we support it here
4642 setVectorAntialias(gTrue
);
4644 GBool retVal
= gFalse
;
4645 // get the clip region bbox
4646 if (pattern
->getShading()->getHasBBox()) {
4647 pattern
->getShading()->getBBox(&xMin
, &yMin
, &xMax
, &yMax
);
4649 state
->getClipBBox(&xMin
, &yMin
, &xMax
, &yMax
);
4651 xMin
= floor (xMin
);
4652 yMin
= floor (yMin
);
4661 state
->getCTM(&ctm
);
4662 ctm
.invertTo(&ictm
);
4664 ictm
.transform(xMin
, yMin
, &x
[0], &y
[0]);
4665 ictm
.transform(xMax
, yMin
, &x
[1], &y
[1]);
4666 ictm
.transform(xMin
, yMax
, &x
[2], &y
[2]);
4667 ictm
.transform(xMax
, yMax
, &x
[3], &y
[3]);
4671 for (i
= 1; i
< 4; i
++) {
4672 xMin
= std::min
<double>(xMin
, x
[i
]);
4673 yMin
= std::min
<double>(yMin
, y
[i
]);
4674 xMax
= std::max
<double>(xMax
, x
[i
]);
4675 yMax
= std::max
<double>(yMax
, y
[i
]);
4681 state
->moveTo(xMin
, yMin
);
4682 state
->lineTo(xMax
, yMin
);
4683 state
->lineTo(xMax
, yMax
);
4684 state
->lineTo(xMin
, yMax
);
4686 path
= convertPath(state
, state
->getPath(), gTrue
);
4689 pattern
->getShading()->getColorSpace()->createMapping(bitmap
->getSeparationList(), SPOT_NCOMPS
);
4691 setOverprintMask(pattern
->getShading()->getColorSpace(), state
->getFillOverprint(),
4692 state
->getOverprintMode(), NULL
);
4693 retVal
= (splash
->shadedFill(path
, pattern
->getShading()->getHasBBox(), pattern
) == splashOk
);
4695 setVectorAntialias(vaa
);
4701 GBool
SplashOutputDev::axialShadedFill(GfxState
*state
, GfxAxialShading
*shading
, double tMin
, double tMax
) {
4702 SplashAxialPattern
*pattern
= new SplashAxialPattern(colorMode
, state
, shading
);
4703 GBool retVal
= univariateShadedFill(state
, pattern
, tMin
, tMax
);
4710 GBool
SplashOutputDev::radialShadedFill(GfxState
*state
, GfxRadialShading
*shading
, double tMin
, double tMax
) {
4711 SplashRadialPattern
*pattern
= new SplashRadialPattern(colorMode
, state
, shading
);
4712 GBool retVal
= univariateShadedFill(state
, pattern
, tMin
, tMax
);