1 //========================================================================
5 // Copyright 1996-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 Kristian Høgsberg <krh@redhat.com>
17 // Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2006, 2010 Carlos Garcia Campos <carlosgc@gnome.org>
19 // Copyright (C) 2006-2015 Albert Astals Cid <aacid@kde.org>
20 // Copyright (C) 2009, 2012 Koji Otani <sho@bbr.jp>
21 // Copyright (C) 2009, 2011-2015 Thomas Freitag <Thomas.Freitag@alfa.de>
22 // Copyright (C) 2009 Christian Persch <chpe@gnome.org>
23 // Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
24 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
25 // Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
26 // Copyright (C) 2012 William Bader <williambader@hotmail.com>
27 // Copyright (C) 2013 Lu Wang <coolwanglu@gmail.com>
28 // Copyright (C) 2013 Hib Eris <hib@hiberis.nl>
29 // Copyright (C) 2013 Fabio D'Urso <fabiodurso@hotmail.it>
30 // Copyright (C) 2015 Adrian Johnson <ajohnson@redneon.com>
32 // To see a description of the changes please see the Changelog file that
33 // came with your tarball or type make ChangeLog if you are building from git
35 //========================================================================
39 #ifdef USE_GCC_PRAGMAS
40 #pragma implementation
54 #include "GfxState_helpers.h"
56 #include "GlobalParams.h"
57 #include "PopplerCache.h"
58 #include "OutputDev.h"
59 #include "splash/SplashTypes.h"
61 //------------------------------------------------------------------------
63 // Max depth of nested color spaces. This is used to catch infinite
64 // loops in the color space object structure.
65 #define colorSpaceRecursionLimit 8
67 //------------------------------------------------------------------------
69 GBool
Matrix::invertTo(Matrix
*other
) const
73 det
= 1 / determinant();
74 other
->m
[0] = m
[3] * det
;
75 other
->m
[1] = -m
[1] * det
;
76 other
->m
[2] = -m
[2] * det
;
77 other
->m
[3] = m
[0] * det
;
78 other
->m
[4] = (m
[2] * m
[5] - m
[3] * m
[4]) * det
;
79 other
->m
[5] = (m
[1] * m
[4] - m
[0] * m
[5]) * det
;
84 void Matrix::translate(double tx
, double ty
)
86 double x0
= tx
*m
[0] + ty
*m
[2] + m
[4];
87 double y0
= tx
*m
[1] + ty
*m
[3] + m
[5];
92 void Matrix::scale(double sx
, double sy
)
100 void Matrix::transform(double x
, double y
, double *tx
, double *ty
) const
102 double temp_x
, temp_y
;
104 temp_x
= m
[0] * x
+ m
[2] * y
+ m
[4];
105 temp_y
= m
[1] * x
+ m
[3] * y
+ m
[5];
111 // Matrix norm, taken from _cairo_matrix_transformed_circle_major_axis
112 double Matrix::norm() const
114 double f
, g
, h
, i
, j
;
116 i
= m
[0]*m
[0] + m
[1]*m
[1];
117 j
= m
[2]*m
[2] + m
[3]*m
[3];
121 h
= m
[0]*m
[2] + m
[1]*m
[3];
123 return sqrt (f
+ hypot (g
, h
));
126 //------------------------------------------------------------------------
128 struct GfxBlendModeInfo
{
133 static const GfxBlendModeInfo gfxBlendModeNames
[] = {
134 { "Normal", gfxBlendNormal
},
135 { "Compatible", gfxBlendNormal
},
136 { "Multiply", gfxBlendMultiply
},
137 { "Screen", gfxBlendScreen
},
138 { "Overlay", gfxBlendOverlay
},
139 { "Darken", gfxBlendDarken
},
140 { "Lighten", gfxBlendLighten
},
141 { "ColorDodge", gfxBlendColorDodge
},
142 { "ColorBurn", gfxBlendColorBurn
},
143 { "HardLight", gfxBlendHardLight
},
144 { "SoftLight", gfxBlendSoftLight
},
145 { "Difference", gfxBlendDifference
},
146 { "Exclusion", gfxBlendExclusion
},
147 { "Hue", gfxBlendHue
},
148 { "Saturation", gfxBlendSaturation
},
149 { "Color", gfxBlendColor
},
150 { "Luminosity", gfxBlendLuminosity
}
153 #define nGfxBlendModeNames \
154 ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
156 //------------------------------------------------------------------------
158 // NB: This must match the GfxColorSpaceMode enum defined in
160 static const char *gfxColorSpaceModeNames
[] = {
174 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
178 static const std::map
<unsigned int, unsigned int>::size_type CMSCACHE_LIMIT
= 2048;
182 #define cmsColorSpaceSignature icColorSpaceSignature
183 #define cmsSetLogErrorHandler cmsSetErrorHandler
184 #define cmsSigXYZData icSigXYZData
185 #define cmsSigLuvData icSigLuvData
186 #define cmsSigLabData icSigLabData
187 #define cmsSigYCbCrData icSigYCbCrData
188 #define cmsSigYxyData icSigYxyData
189 #define cmsSigRgbData icSigRgbData
190 #define cmsSigHsvData icSigHsvData
191 #define cmsSigHlsData icSigHlsData
192 #define cmsSigCmyData icSigCmyData
193 #define cmsSig3colorData icSig3colorData
194 #define cmsSigGrayData icSigGrayData
195 #define cmsSigCmykData icSigCmykData
196 #define cmsSig4colorData icSig4colorData
197 #define cmsSig2colorData icSig2colorData
198 #define cmsSig5colorData icSig5colorData
199 #define cmsSig6colorData icSig6colorData
200 #define cmsSig7colorData icSig7colorData
201 #define cmsSig8colorData icSig8colorData
202 #define cmsSig9colorData icSig9colorData
203 #define cmsSig10colorData icSig10colorData
204 #define cmsSig11colorData icSig11colorData
205 #define cmsSig12colorData icSig12colorData
206 #define cmsSig13colorData icSig13colorData
207 #define cmsSig14colorData icSig14colorData
208 #define cmsSig15colorData icSig15colorData
212 #define LCMS_FLAGS cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION
215 #define COLOR_PROFILE_DIR "/ColorProfiles/"
216 #define GLOBAL_COLOR_PROFILE_DIR POPPLER_DATADIR COLOR_PROFILE_DIR
218 void GfxColorTransform::doTransform(void *in
, void *out
, unsigned int size
) {
219 cmsDoTransform(transform
, in
, out
, size
);
222 // transformA should be a cmsHTRANSFORM
223 GfxColorTransform::GfxColorTransform(void *transformA
, int cmsIntentA
, unsigned int inputPixelTypeA
, unsigned int transformPixelTypeA
) {
224 transform
= transformA
;
226 cmsIntent
= cmsIntentA
;
227 inputPixelType
= inputPixelTypeA
;
228 transformPixelType
= transformPixelTypeA
;
231 GfxColorTransform::~GfxColorTransform() {
232 cmsDeleteTransform(transform
);
235 void GfxColorTransform::ref() {
239 unsigned int GfxColorTransform::unref() {
243 static cmsHPROFILE RGBProfile
= NULL
;
244 static GooString
*displayProfileName
= NULL
; // display profile file Name
245 static cmsHPROFILE displayProfile
= NULL
; // display profile
246 static unsigned int displayPixelType
= 0;
247 static GfxColorTransform
*XYZ2DisplayTransform
= NULL
;
249 // convert color space signature to cmsColor type
250 static unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs
);
251 static unsigned int getCMSNChannels(cmsColorSpaceSignature cs
);
252 static cmsHPROFILE
loadColorProfile(const char *fileName
);
254 void GfxColorSpace::setDisplayProfile(void *displayProfileA
) {
255 displayProfile
= displayProfileA
;
256 if (displayProfile
!= NULL
) {
257 cmsHTRANSFORM transform
;
258 unsigned int nChannels
;
260 displayPixelType
= getCMSColorSpaceType(cmsGetColorSpace(displayProfile
));
261 nChannels
= getCMSNChannels(cmsGetColorSpace(displayProfile
));
262 // create transform from XYZ
263 cmsHPROFILE XYZProfile
= cmsCreateXYZProfile();
264 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
266 COLORSPACE_SH(displayPixelType
) |
267 CHANNELS_SH(nChannels
) | BYTES_SH(1),
268 INTENT_RELATIVE_COLORIMETRIC
,LCMS_FLAGS
)) == 0) {
269 error(errSyntaxWarning
, -1, "Can't create Lab transform");
271 XYZ2DisplayTransform
= new GfxColorTransform(transform
, INTENT_RELATIVE_COLORIMETRIC
, PT_XYZ
, displayPixelType
);
273 cmsCloseProfile(XYZProfile
);
277 void GfxColorSpace::setDisplayProfileName(GooString
*name
) {
278 displayProfileName
= name
->copy();
281 cmsHPROFILE
GfxColorSpace::getRGBProfile() {
285 cmsHPROFILE
GfxColorSpace::getDisplayProfile() {
286 return displayProfile
;
291 //------------------------------------------------------------------------
293 //------------------------------------------------------------------------
295 GfxColorSpace::GfxColorSpace() {
296 overprintMask
= 0x0f;
300 GfxColorSpace::~GfxColorSpace() {
303 GfxColorSpace
*GfxColorSpace::parse(GfxResources
*res
, Object
*csObj
, OutputDev
*out
, GfxState
*state
, int recursion
) {
307 if (recursion
> colorSpaceRecursionLimit
) {
308 error(errSyntaxError
, -1, "Loop detected in color space objects");
313 if (csObj
->isName()) {
314 if (csObj
->isName("DeviceGray") || csObj
->isName("G")) {
317 res
->lookupColorSpace("DefaultGray", &objCS
);
318 if (objCS
.isNull()) {
319 cs
= new GfxDeviceGrayColorSpace();
321 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
325 cs
= new GfxDeviceGrayColorSpace();
327 } else if (csObj
->isName("DeviceRGB") || csObj
->isName("RGB")) {
330 res
->lookupColorSpace("DefaultRGB", &objCS
);
331 if (objCS
.isNull()) {
332 cs
= new GfxDeviceRGBColorSpace();
334 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
338 cs
= new GfxDeviceRGBColorSpace();
340 } else if (csObj
->isName("DeviceCMYK") || csObj
->isName("CMYK")) {
343 res
->lookupColorSpace("DefaultCMYK", &objCS
);
344 if (objCS
.isNull()) {
345 cs
= new GfxDeviceCMYKColorSpace();
347 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
351 cs
= new GfxDeviceCMYKColorSpace();
353 } else if (csObj
->isName("Pattern")) {
354 cs
= new GfxPatternColorSpace(NULL
);
356 error(errSyntaxWarning
, -1, "Bad color space '{0:s}'", csObj
->getName());
358 } else if (csObj
->isArray() && csObj
->arrayGetLength() > 0) {
359 csObj
->arrayGet(0, &obj1
);
360 if (obj1
.isName("DeviceGray") || obj1
.isName("G")) {
363 res
->lookupColorSpace("DefaultGray", &objCS
);
364 if (objCS
.isNull()) {
365 cs
= new GfxDeviceGrayColorSpace();
367 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
371 cs
= new GfxDeviceGrayColorSpace();
373 } else if (obj1
.isName("DeviceRGB") || obj1
.isName("RGB")) {
376 res
->lookupColorSpace("DefaultRGB", &objCS
);
377 if (objCS
.isNull()) {
378 cs
= new GfxDeviceRGBColorSpace();
380 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
384 cs
= new GfxDeviceRGBColorSpace();
386 } else if (obj1
.isName("DeviceCMYK") || obj1
.isName("CMYK")) {
389 res
->lookupColorSpace("DefaultCMYK", &objCS
);
390 if (objCS
.isNull()) {
391 cs
= new GfxDeviceCMYKColorSpace();
393 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
397 cs
= new GfxDeviceCMYKColorSpace();
399 } else if (obj1
.isName("CalGray")) {
400 cs
= GfxCalGrayColorSpace::parse(csObj
->getArray(), state
);
401 } else if (obj1
.isName("CalRGB")) {
402 cs
= GfxCalRGBColorSpace::parse(csObj
->getArray(), state
);
403 } else if (obj1
.isName("Lab")) {
404 cs
= GfxLabColorSpace::parse(csObj
->getArray(), state
);
405 } else if (obj1
.isName("ICCBased")) {
406 cs
= GfxICCBasedColorSpace::parse(csObj
->getArray(), out
, state
, recursion
);
407 } else if (obj1
.isName("Indexed") || obj1
.isName("I")) {
408 cs
= GfxIndexedColorSpace::parse(res
, csObj
->getArray(), out
, state
, recursion
);
409 } else if (obj1
.isName("Separation")) {
410 cs
= GfxSeparationColorSpace::parse(res
, csObj
->getArray(), out
, state
, recursion
);
411 } else if (obj1
.isName("DeviceN")) {
412 cs
= GfxDeviceNColorSpace::parse(res
, csObj
->getArray(), out
, state
, recursion
);
413 } else if (obj1
.isName("Pattern")) {
414 cs
= GfxPatternColorSpace::parse(res
, csObj
->getArray(), out
, state
, recursion
);
416 error(errSyntaxWarning
, -1, "Bad color space");
419 } else if (csObj
->isDict()) {
420 csObj
->dictLookup("ColorSpace", &obj1
);
421 if (obj1
.isName("DeviceGray")) {
424 res
->lookupColorSpace("DefaultGray", &objCS
);
425 if (objCS
.isNull()) {
426 cs
= new GfxDeviceGrayColorSpace();
428 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
432 cs
= new GfxDeviceGrayColorSpace();
434 } else if (obj1
.isName("DeviceRGB")) {
437 res
->lookupColorSpace("DefaultRGB", &objCS
);
438 if (objCS
.isNull()) {
439 cs
= new GfxDeviceRGBColorSpace();
441 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
445 cs
= new GfxDeviceRGBColorSpace();
447 } else if (obj1
.isName("DeviceCMYK")) {
450 res
->lookupColorSpace("DefaultCMYK", &objCS
);
451 if (objCS
.isNull()) {
452 cs
= new GfxDeviceCMYKColorSpace();
454 cs
= GfxColorSpace::parse(NULL
, &objCS
, out
, state
);
458 cs
= new GfxDeviceCMYKColorSpace();
461 error(errSyntaxWarning
, -1, "Bad color space dict'");
465 error(errSyntaxWarning
, -1, "Bad color space - expected name or array or dict");
470 void GfxColorSpace::createMapping(GooList
*separationList
, int maxSepComps
) {
474 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
478 for (i
= 0; i
< getNComps(); ++i
) {
484 int GfxColorSpace::getNumColorSpaceModes() {
485 return nGfxColorSpaceModes
;
488 const char *GfxColorSpace::getColorSpaceModeName(int idx
) {
489 return gfxColorSpaceModeNames
[idx
];
493 cmsHPROFILE
loadColorProfile(const char *fileName
)
495 cmsHPROFILE hp
= NULL
;
498 if (fileName
[0] == '/') {
500 // check if open the file
501 if ((fp
= fopen(fileName
,"r")) != NULL
) {
503 hp
= cmsOpenProfileFromFile(fileName
,"r");
507 // try to load from global directory
508 GooString
*path
= new GooString(GLOBAL_COLOR_PROFILE_DIR
);
509 path
->append(fileName
);
510 // check if open the file
511 if ((fp
= fopen(path
->getCString(),"r")) != NULL
) {
513 hp
= cmsOpenProfileFromFile(path
->getCString(),"r");
520 static int CMSError(int ecode
, const char *msg
)
522 error(errSyntaxWarning
, -1, "{0:s}", msg
);
526 static void CMSError(cmsContext
/*contextId*/, cmsUInt32Number
/*ecode*/, const char *text
)
528 error(errSyntaxWarning
, -1, "{0:s}", text
);
532 int GfxColorSpace::setupColorProfiles()
534 static GBool initialized
= gFalse
;
535 cmsHTRANSFORM transform
;
536 unsigned int nChannels
;
539 if (initialized
) return 0;
543 cmsSetLogErrorHandler(CMSError
);
545 if (displayProfile
== NULL
) {
546 // load display profile if it was not already loaded.
547 if (displayProfileName
== NULL
) {
548 displayProfile
= loadColorProfile("display.icc");
549 } else if (displayProfileName
->getLength() > 0) {
550 displayProfile
= loadColorProfile(displayProfileName
->getCString());
554 RGBProfile
= loadColorProfile("RGB.icc");
555 if (RGBProfile
== NULL
) {
556 /* use built in sRGB profile */
557 RGBProfile
= cmsCreate_sRGBProfile();
560 if (displayProfile
!= NULL
) {
561 displayPixelType
= getCMSColorSpaceType(cmsGetColorSpace(displayProfile
));
562 nChannels
= getCMSNChannels(cmsGetColorSpace(displayProfile
));
563 // create transform from XYZ
564 cmsHPROFILE XYZProfile
= cmsCreateXYZProfile();
565 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
567 COLORSPACE_SH(displayPixelType
) |
568 CHANNELS_SH(nChannels
) | BYTES_SH(1),
569 INTENT_RELATIVE_COLORIMETRIC
,LCMS_FLAGS
)) == 0) {
570 error(errSyntaxWarning
, -1, "Can't create Lab transform");
572 XYZ2DisplayTransform
= new GfxColorTransform(transform
, INTENT_RELATIVE_COLORIMETRIC
, PT_XYZ
, displayPixelType
);
574 cmsCloseProfile(XYZProfile
);
579 unsigned int getCMSColorSpaceType(cmsColorSpaceSignature cs
)
591 case cmsSigYCbCrData
:
615 case cmsSig2colorData
:
616 case cmsSig3colorData
:
617 case cmsSig4colorData
:
618 case cmsSig5colorData
:
619 case cmsSig6colorData
:
620 case cmsSig7colorData
:
621 case cmsSig8colorData
:
622 case cmsSig9colorData
:
623 case cmsSig10colorData
:
624 case cmsSig11colorData
:
625 case cmsSig12colorData
:
626 case cmsSig13colorData
:
627 case cmsSig14colorData
:
628 case cmsSig15colorData
:
635 unsigned int getCMSNChannels(cmsColorSpaceSignature cs
)
641 case cmsSigYCbCrData
:
647 case cmsSig3colorData
:
654 case cmsSig4colorData
:
657 case cmsSig2colorData
:
660 case cmsSig5colorData
:
663 case cmsSig6colorData
:
666 case cmsSig7colorData
:
669 case cmsSig8colorData
:
672 case cmsSig9colorData
:
675 case cmsSig10colorData
:
678 case cmsSig11colorData
:
681 case cmsSig12colorData
:
684 case cmsSig13colorData
:
687 case cmsSig14colorData
:
690 case cmsSig15colorData
:
699 //------------------------------------------------------------------------
700 // GfxDeviceGrayColorSpace
701 //------------------------------------------------------------------------
703 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
706 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
709 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
710 return new GfxDeviceGrayColorSpace();
713 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
714 *gray
= clip01(color
->c
[0]);
717 void GfxDeviceGrayColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
718 memcpy (out
, in
, length
);
721 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
722 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
725 void GfxDeviceGrayColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
729 for (i
= 0; i
< length
; i
++)
730 out
[i
] = (in
[i
] << 16) | (in
[i
] << 8) | (in
[i
] << 0);
733 void GfxDeviceGrayColorSpace::getRGBLine(Guchar
*in
, Guchar
*out
, int length
) {
734 for (int i
= 0; i
< length
; i
++) {
741 void GfxDeviceGrayColorSpace::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
) {
742 for (int i
= 0; i
< length
; i
++) {
750 void GfxDeviceGrayColorSpace::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
) {
751 for (int i
= 0; i
< length
; i
++) {
759 void GfxDeviceGrayColorSpace::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
) {
760 for (int i
= 0; i
< length
; i
++) {
761 for (int j
= 0; j
< SPOT_NCOMPS
+4; j
++)
764 out
+= (SPOT_NCOMPS
+4);
768 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
769 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
770 cmyk
->k
= clip01(gfxColorComp1
- color
->c
[0]);
773 void GfxDeviceGrayColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
774 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
776 deviceN
->c
[3] = clip01(gfxColorComp1
- color
->c
[0]);
779 void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor
*color
) {
783 //------------------------------------------------------------------------
784 // GfxCalGrayColorSpace
785 //------------------------------------------------------------------------
787 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
788 whiteX
= whiteY
= whiteZ
= 1;
789 blackX
= blackY
= blackZ
= 0;
793 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
795 if (transform
!= NULL
) {
796 if (transform
->unref() == 0) delete transform
;
801 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
802 GfxCalGrayColorSpace
*cs
;
804 cs
= new GfxCalGrayColorSpace();
813 cs
->transform
= transform
;
814 if (transform
!= NULL
) transform
->ref();
819 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
820 // Language Reference, Third Edition.
821 static const double xyzrgb
[3][3] = {
822 { 3.240449, -1.537136, -0.498531 },
823 { -0.969265, 1.876011, 0.041556 },
824 { 0.055643, -0.204026, 1.057229 }
827 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
, GfxState
*state
) {
828 GfxCalGrayColorSpace
*cs
;
829 Object obj1
, obj2
, obj3
;
832 if (!obj1
.isDict()) {
833 error(errSyntaxWarning
, -1, "Bad CalGray color space");
837 cs
= new GfxCalGrayColorSpace();
838 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
839 obj2
.arrayGetLength() == 3) {
840 obj2
.arrayGet(0, &obj3
);
841 if (likely(obj3
.isNum()))
842 cs
->whiteX
= obj3
.getNum();
844 obj2
.arrayGet(1, &obj3
);
845 if (likely(obj3
.isNum()))
846 cs
->whiteY
= obj3
.getNum();
848 obj2
.arrayGet(2, &obj3
);
849 if (likely(obj3
.isNum()))
850 cs
->whiteZ
= obj3
.getNum();
854 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
855 obj2
.arrayGetLength() == 3) {
856 obj2
.arrayGet(0, &obj3
);
857 if (likely(obj3
.isNum()))
858 cs
->blackX
= obj3
.getNum();
860 obj2
.arrayGet(1, &obj3
);
861 if (likely(obj3
.isNum()))
862 cs
->blackY
= obj3
.getNum();
864 obj2
.arrayGet(2, &obj3
);
865 if (likely(obj3
.isNum()))
866 cs
->blackZ
= obj3
.getNum();
870 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
871 cs
->gamma
= obj2
.getNum();
876 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
877 xyzrgb
[0][1] * cs
->whiteY
+
878 xyzrgb
[0][2] * cs
->whiteZ
);
879 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
880 xyzrgb
[1][1] * cs
->whiteY
+
881 xyzrgb
[1][2] * cs
->whiteZ
);
882 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
883 xyzrgb
[2][1] * cs
->whiteY
+
884 xyzrgb
[2][2] * cs
->whiteZ
);
886 cs
->transform
= (state
!= NULL
) ? state
->getXYZ2DisplayTransform() : XYZ2DisplayTransform
;
887 if (cs
->transform
!= NULL
) cs
->transform
->ref();
892 // convert CalGray to media XYZ color space
893 // (not multiply by the white point)
894 void GfxCalGrayColorSpace::getXYZ(GfxColor
*color
,
895 double *pX
, double *pY
, double *pZ
) {
896 const double A
= colToDbl(color
->c
[0]);
897 const double xyzColor
= pow(A
,gamma
);
903 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
907 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_GRAY
) {
908 Guchar out
[gfxColorMaxComps
];
909 double in
[gfxColorMaxComps
];
912 getXYZ(color
,&X
,&Y
,&Z
);
916 transform
->doTransform(in
,out
,1);
917 *gray
= byteToCol(out
[0]);
922 *gray
= clip01((GfxColorComp
)(0.299 * rgb
.r
+
924 0.114 * rgb
.b
+ 0.5));
927 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
931 getXYZ(color
,&X
,&Y
,&Z
);
933 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_RGB
) {
934 Guchar out
[gfxColorMaxComps
];
935 double in
[gfxColorMaxComps
];
940 transform
->doTransform(in
,out
,1);
941 rgb
->r
= byteToCol(out
[0]);
942 rgb
->g
= byteToCol(out
[1]);
943 rgb
->b
= byteToCol(out
[2]);
950 // convert XYZ to RGB, including gamut mapping and gamma correction
951 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
952 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
953 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
954 rgb
->r
= dblToCol(sqrt(clip01(r
* kr
)));
955 rgb
->g
= dblToCol(sqrt(clip01(g
* kg
)));
956 rgb
->b
= dblToCol(sqrt(clip01(b
* kb
)));
959 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
961 GfxColorComp c
, m
, y
, k
;
964 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
965 double in
[gfxColorMaxComps
];
966 Guchar out
[gfxColorMaxComps
];
969 getXYZ(color
,&X
,&Y
,&Z
);
974 transform
->doTransform(in
,out
,1);
975 cmyk
->c
= byteToCol(out
[0]);
976 cmyk
->m
= byteToCol(out
[1]);
977 cmyk
->y
= byteToCol(out
[2]);
978 cmyk
->k
= byteToCol(out
[3]);
983 c
= clip01(gfxColorComp1
- rgb
.r
);
984 m
= clip01(gfxColorComp1
- rgb
.g
);
985 y
= clip01(gfxColorComp1
- rgb
.b
);
999 void GfxCalGrayColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
1001 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
1003 getCMYK(color
, &cmyk
);
1004 deviceN
->c
[0] = cmyk
.c
;
1005 deviceN
->c
[1] = cmyk
.m
;
1006 deviceN
->c
[2] = cmyk
.y
;
1007 deviceN
->c
[3] = cmyk
.k
;
1010 void GfxCalGrayColorSpace::getDefaultColor(GfxColor
*color
) {
1014 //------------------------------------------------------------------------
1015 // GfxDeviceRGBColorSpace
1016 //------------------------------------------------------------------------
1018 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
1021 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
1024 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
1025 return new GfxDeviceRGBColorSpace();
1028 void GfxDeviceRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1029 *gray
= clip01((GfxColorComp
)(0.3 * color
->c
[0] +
1030 0.59 * color
->c
[1] +
1031 0.11 * color
->c
[2] + 0.5));
1034 void GfxDeviceRGBColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
1037 for (i
= 0; i
< length
; i
++) {
1039 (in
[i
* 3 + 0] * 19595 +
1040 in
[i
* 3 + 1] * 38469 +
1041 in
[i
* 3 + 2] * 7472) / 65536;
1045 void GfxDeviceRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1046 rgb
->r
= clip01(color
->c
[0]);
1047 rgb
->g
= clip01(color
->c
[1]);
1048 rgb
->b
= clip01(color
->c
[2]);
1051 void GfxDeviceRGBColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
1056 for (i
= 0, p
= in
; i
< length
; i
++, p
+= 3)
1057 out
[i
] = (p
[0] << 16) | (p
[1] << 8) | (p
[2] << 0);
1060 void GfxDeviceRGBColorSpace::getRGBLine(Guchar
*in
, Guchar
*out
, int length
) {
1061 for (int i
= 0; i
< length
; i
++) {
1068 void GfxDeviceRGBColorSpace::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
) {
1069 for (int i
= 0; i
< length
; i
++) {
1077 void GfxDeviceRGBColorSpace::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
) {
1078 GfxColorComp c
, m
, y
, k
;
1080 for (int i
= 0; i
< length
; i
++) {
1081 c
= byteToCol(255 - *in
++);
1082 m
= byteToCol(255 - *in
++);
1083 y
= byteToCol(255 - *in
++);
1091 *out
++ = colToByte(c
- k
);
1092 *out
++ = colToByte(m
- k
);
1093 *out
++ = colToByte(y
- k
);
1094 *out
++ = colToByte(k
);
1098 void GfxDeviceRGBColorSpace::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
) {
1099 GfxColorComp c
, m
, y
, k
;
1101 for (int i
= 0; i
< length
; i
++) {
1102 for (int j
= 0; j
< SPOT_NCOMPS
+4; j
++)
1104 c
= byteToCol(255 - *in
++);
1105 m
= byteToCol(255 - *in
++);
1106 y
= byteToCol(255 - *in
++);
1114 out
[0] = colToByte(c
- k
);
1115 out
[1] = colToByte(m
- k
);
1116 out
[2] = colToByte(y
- k
);
1117 out
[3] = colToByte(k
);
1118 out
+= (SPOT_NCOMPS
+4);
1122 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1123 GfxColorComp c
, m
, y
, k
;
1125 c
= clip01(gfxColorComp1
- color
->c
[0]);
1126 m
= clip01(gfxColorComp1
- color
->c
[1]);
1127 y
= clip01(gfxColorComp1
- color
->c
[2]);
1141 void GfxDeviceRGBColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
1143 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
1145 getCMYK(color
, &cmyk
);
1146 deviceN
->c
[0] = cmyk
.c
;
1147 deviceN
->c
[1] = cmyk
.m
;
1148 deviceN
->c
[2] = cmyk
.y
;
1149 deviceN
->c
[3] = cmyk
.k
;
1152 void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor
*color
) {
1158 //------------------------------------------------------------------------
1159 // GfxCalRGBColorSpace
1160 //------------------------------------------------------------------------
1162 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
1163 whiteX
= whiteY
= whiteZ
= 1;
1164 blackX
= blackY
= blackZ
= 0;
1165 gammaR
= gammaG
= gammaB
= 1;
1166 mat
[0] = 1; mat
[1] = 0; mat
[2] = 0;
1167 mat
[3] = 0; mat
[4] = 1; mat
[5] = 0;
1168 mat
[6] = 0; mat
[7] = 0; mat
[8] = 1;
1171 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
1173 if (transform
!= NULL
) {
1174 if (transform
->unref() == 0) delete transform
;
1179 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
1180 GfxCalRGBColorSpace
*cs
;
1183 cs
= new GfxCalRGBColorSpace();
1184 cs
->whiteX
= whiteX
;
1185 cs
->whiteY
= whiteY
;
1186 cs
->whiteZ
= whiteZ
;
1187 cs
->blackX
= blackX
;
1188 cs
->blackY
= blackY
;
1189 cs
->blackZ
= blackZ
;
1190 cs
->gammaR
= gammaR
;
1191 cs
->gammaG
= gammaG
;
1192 cs
->gammaB
= gammaB
;
1193 for (i
= 0; i
< 9; ++i
) {
1194 cs
->mat
[i
] = mat
[i
];
1197 cs
->transform
= transform
;
1198 if (transform
!= NULL
) transform
->ref();
1203 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
, GfxState
*state
) {
1204 GfxCalRGBColorSpace
*cs
;
1205 Object obj1
, obj2
, obj3
;
1209 if (!obj1
.isDict()) {
1210 error(errSyntaxWarning
, -1, "Bad CalRGB color space");
1214 cs
= new GfxCalRGBColorSpace();
1215 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
1216 obj2
.arrayGetLength() == 3) {
1217 obj2
.arrayGet(0, &obj3
);
1218 if (likely(obj3
.isNum()))
1219 cs
->whiteX
= obj3
.getNum();
1221 obj2
.arrayGet(1, &obj3
);
1222 if (likely(obj3
.isNum()))
1223 cs
->whiteY
= obj3
.getNum();
1225 obj2
.arrayGet(2, &obj3
);
1226 if (likely(obj3
.isNum()))
1227 cs
->whiteZ
= obj3
.getNum();
1231 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
1232 obj2
.arrayGetLength() == 3) {
1233 obj2
.arrayGet(0, &obj3
);
1234 if (likely(obj3
.isNum()))
1235 cs
->blackX
= obj3
.getNum();
1237 obj2
.arrayGet(1, &obj3
);
1238 if (likely(obj3
.isNum()))
1239 cs
->blackY
= obj3
.getNum();
1241 obj2
.arrayGet(2, &obj3
);
1242 if (likely(obj3
.isNum()))
1243 cs
->blackZ
= obj3
.getNum();
1247 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
1248 obj2
.arrayGetLength() == 3) {
1249 obj2
.arrayGet(0, &obj3
);
1250 if (likely(obj3
.isNum()))
1251 cs
->gammaR
= obj3
.getNum();
1253 obj2
.arrayGet(1, &obj3
);
1254 if (likely(obj3
.isNum()))
1255 cs
->gammaG
= obj3
.getNum();
1257 obj2
.arrayGet(2, &obj3
);
1258 if (likely(obj3
.isNum()))
1259 cs
->gammaB
= obj3
.getNum();
1263 if (obj1
.dictLookup("Matrix", &obj2
)->isArray() &&
1264 obj2
.arrayGetLength() == 9) {
1265 for (i
= 0; i
< 9; ++i
) {
1266 obj2
.arrayGet(i
, &obj3
);
1267 if (likely(obj3
.isNum()))
1268 cs
->mat
[i
] = obj3
.getNum();
1275 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
1276 xyzrgb
[0][1] * cs
->whiteY
+
1277 xyzrgb
[0][2] * cs
->whiteZ
);
1278 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
1279 xyzrgb
[1][1] * cs
->whiteY
+
1280 xyzrgb
[1][2] * cs
->whiteZ
);
1281 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
1282 xyzrgb
[2][1] * cs
->whiteY
+
1283 xyzrgb
[2][2] * cs
->whiteZ
);
1286 cs
->transform
= (state
!= NULL
) ? state
->getXYZ2DisplayTransform() : XYZ2DisplayTransform
;
1287 if (cs
->transform
!= NULL
) cs
->transform
->ref();
1292 // convert CalRGB to XYZ color space
1293 void GfxCalRGBColorSpace::getXYZ(GfxColor
*color
,
1294 double *pX
, double *pY
, double *pZ
) {
1297 A
= pow(colToDbl(color
->c
[0]), gammaR
);
1298 B
= pow(colToDbl(color
->c
[1]), gammaG
);
1299 C
= pow(colToDbl(color
->c
[2]), gammaB
);
1300 *pX
= mat
[0] * A
+ mat
[3] * B
+ mat
[6] * C
;
1301 *pY
= mat
[1] * A
+ mat
[4] * B
+ mat
[7] * C
;
1302 *pZ
= mat
[2] * A
+ mat
[5] * B
+ mat
[8] * C
;
1305 void GfxCalRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1309 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_GRAY
) {
1310 Guchar out
[gfxColorMaxComps
];
1311 double in
[gfxColorMaxComps
];
1314 getXYZ(color
,&X
,&Y
,&Z
);
1318 transform
->doTransform(in
,out
,1);
1319 *gray
= byteToCol(out
[0]);
1323 getRGB(color
, &rgb
);
1324 *gray
= clip01((GfxColorComp
)(0.299 * rgb
.r
+
1326 0.114 * rgb
.b
+ 0.5));
1329 void GfxCalRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1333 getXYZ(color
,&X
,&Y
,&Z
);
1335 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_RGB
) {
1336 Guchar out
[gfxColorMaxComps
];
1337 double in
[gfxColorMaxComps
];
1339 in
[0] = clip01(X
/whiteX
);
1340 in
[1] = clip01(Y
/whiteY
);
1341 in
[2] = clip01(Z
/whiteZ
);
1342 transform
->doTransform(in
,out
,1);
1343 rgb
->r
= byteToCol(out
[0]);
1344 rgb
->g
= byteToCol(out
[1]);
1345 rgb
->b
= byteToCol(out
[2]);
1349 // convert XYZ to RGB, including gamut mapping and gamma correction
1350 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
1351 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
1352 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
1353 rgb
->r
= dblToCol(sqrt(clip01(r
)));
1354 rgb
->g
= dblToCol(sqrt(clip01(g
)));
1355 rgb
->b
= dblToCol(sqrt(clip01(b
)));
1358 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1360 GfxColorComp c
, m
, y
, k
;
1363 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
1364 double in
[gfxColorMaxComps
];
1365 Guchar out
[gfxColorMaxComps
];
1368 getXYZ(color
,&X
,&Y
,&Z
);
1372 transform
->doTransform(in
,out
,1);
1373 cmyk
->c
= byteToCol(out
[0]);
1374 cmyk
->m
= byteToCol(out
[1]);
1375 cmyk
->y
= byteToCol(out
[2]);
1376 cmyk
->k
= byteToCol(out
[3]);
1380 getRGB(color
, &rgb
);
1381 c
= clip01(gfxColorComp1
- rgb
.r
);
1382 m
= clip01(gfxColorComp1
- rgb
.g
);
1383 y
= clip01(gfxColorComp1
- rgb
.b
);
1397 void GfxCalRGBColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
1399 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
1401 getCMYK(color
, &cmyk
);
1402 deviceN
->c
[0] = cmyk
.c
;
1403 deviceN
->c
[1] = cmyk
.m
;
1404 deviceN
->c
[2] = cmyk
.y
;
1405 deviceN
->c
[3] = cmyk
.k
;
1408 void GfxCalRGBColorSpace::getDefaultColor(GfxColor
*color
) {
1414 //------------------------------------------------------------------------
1415 // GfxDeviceCMYKColorSpace
1416 //------------------------------------------------------------------------
1418 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
1421 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
1424 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
1425 return new GfxDeviceCMYKColorSpace();
1428 void GfxDeviceCMYKColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1429 *gray
= clip01((GfxColorComp
)(gfxColorComp1
- color
->c
[3]
1431 - 0.59 * color
->c
[1]
1432 - 0.11 * color
->c
[2] + 0.5));
1435 void GfxDeviceCMYKColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1436 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
1438 c
= colToDbl(color
->c
[0]);
1439 m
= colToDbl(color
->c
[1]);
1440 y
= colToDbl(color
->c
[2]);
1441 k
= colToDbl(color
->c
[3]);
1446 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
1447 rgb
->r
= clip01(dblToCol(r
));
1448 rgb
->g
= clip01(dblToCol(g
));
1449 rgb
->b
= clip01(dblToCol(b
));
1452 static inline void GfxDeviceCMYKColorSpacegetRGBLineHelper(Guchar
*&in
, double &r
, double &g
, double &b
)
1454 double c
, m
, y
, k
, c1
, m1
, y1
, k1
;
1456 c
= byteToDbl(*in
++);
1457 m
= byteToDbl(*in
++);
1458 y
= byteToDbl(*in
++);
1459 k
= byteToDbl(*in
++);
1464 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
1467 void GfxDeviceCMYKColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
, int length
)
1470 for (int i
= 0; i
< length
; i
++) {
1471 GfxDeviceCMYKColorSpacegetRGBLineHelper(in
, r
, g
, b
);
1472 *out
++ = (dblToByte(clip01(r
)) << 16) | (dblToByte(clip01(g
)) << 8) | dblToByte(clip01(b
));
1476 void GfxDeviceCMYKColorSpace::getRGBLine(Guchar
*in
, Guchar
*out
, int length
)
1480 for (int i
= 0; i
< length
; i
++) {
1481 GfxDeviceCMYKColorSpacegetRGBLineHelper(in
, r
, g
, b
);
1482 *out
++ = dblToByte(clip01(r
));
1483 *out
++ = dblToByte(clip01(g
));
1484 *out
++ = dblToByte(clip01(b
));
1488 void GfxDeviceCMYKColorSpace::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
)
1492 for (int i
= 0; i
< length
; i
++) {
1493 GfxDeviceCMYKColorSpacegetRGBLineHelper(in
, r
, g
, b
);
1494 *out
++ = dblToByte(clip01(r
));
1495 *out
++ = dblToByte(clip01(g
));
1496 *out
++ = dblToByte(clip01(b
));
1501 void GfxDeviceCMYKColorSpace::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
)
1503 for (int i
= 0; i
< length
; i
++) {
1511 void GfxDeviceCMYKColorSpace::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
)
1513 for (int i
= 0; i
< length
; i
++) {
1514 for (int j
= 0; j
< SPOT_NCOMPS
+4; j
++)
1520 out
+= (SPOT_NCOMPS
+4);
1524 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1525 cmyk
->c
= clip01(color
->c
[0]);
1526 cmyk
->m
= clip01(color
->c
[1]);
1527 cmyk
->y
= clip01(color
->c
[2]);
1528 cmyk
->k
= clip01(color
->c
[3]);
1531 void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
1532 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
1534 deviceN
->c
[0] = clip01(color
->c
[0]);
1535 deviceN
->c
[1] = clip01(color
->c
[1]);
1536 deviceN
->c
[2] = clip01(color
->c
[2]);
1537 deviceN
->c
[3] = clip01(color
->c
[3]);
1540 void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor
*color
) {
1544 color
->c
[3] = gfxColorComp1
;
1547 //------------------------------------------------------------------------
1549 //------------------------------------------------------------------------
1551 GfxLabColorSpace::GfxLabColorSpace() {
1552 whiteX
= whiteY
= whiteZ
= 1;
1553 blackX
= blackY
= blackZ
= 0;
1558 GfxLabColorSpace::~GfxLabColorSpace() {
1560 if (transform
!= NULL
) {
1561 if (transform
->unref() == 0) delete transform
;
1566 GfxColorSpace
*GfxLabColorSpace::copy() {
1567 GfxLabColorSpace
*cs
;
1569 cs
= new GfxLabColorSpace();
1570 cs
->whiteX
= whiteX
;
1571 cs
->whiteY
= whiteY
;
1572 cs
->whiteZ
= whiteZ
;
1573 cs
->blackX
= blackX
;
1574 cs
->blackY
= blackY
;
1575 cs
->blackZ
= blackZ
;
1584 cs
->transform
= transform
;
1585 if (transform
!= NULL
) transform
->ref();
1590 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
, GfxState
*state
) {
1591 GfxLabColorSpace
*cs
;
1592 Object obj1
, obj2
, obj3
;
1595 if (!obj1
.isDict()) {
1596 error(errSyntaxWarning
, -1, "Bad Lab color space");
1600 cs
= new GfxLabColorSpace();
1601 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
1602 obj2
.arrayGetLength() == 3) {
1603 obj2
.arrayGet(0, &obj3
);
1604 cs
->whiteX
= obj3
.getNum();
1606 obj2
.arrayGet(1, &obj3
);
1607 cs
->whiteY
= obj3
.getNum();
1609 obj2
.arrayGet(2, &obj3
);
1610 cs
->whiteZ
= obj3
.getNum();
1614 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
1615 obj2
.arrayGetLength() == 3) {
1616 obj2
.arrayGet(0, &obj3
);
1617 cs
->blackX
= obj3
.getNum();
1619 obj2
.arrayGet(1, &obj3
);
1620 cs
->blackY
= obj3
.getNum();
1622 obj2
.arrayGet(2, &obj3
);
1623 cs
->blackZ
= obj3
.getNum();
1627 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
1628 obj2
.arrayGetLength() == 4) {
1629 obj2
.arrayGet(0, &obj3
);
1630 cs
->aMin
= obj3
.getNum();
1632 obj2
.arrayGet(1, &obj3
);
1633 cs
->aMax
= obj3
.getNum();
1635 obj2
.arrayGet(2, &obj3
);
1636 cs
->bMin
= obj3
.getNum();
1638 obj2
.arrayGet(3, &obj3
);
1639 cs
->bMax
= obj3
.getNum();
1645 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
1646 xyzrgb
[0][1] * cs
->whiteY
+
1647 xyzrgb
[0][2] * cs
->whiteZ
);
1648 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
1649 xyzrgb
[1][1] * cs
->whiteY
+
1650 xyzrgb
[1][2] * cs
->whiteZ
);
1651 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
1652 xyzrgb
[2][1] * cs
->whiteY
+
1653 xyzrgb
[2][2] * cs
->whiteZ
);
1656 cs
->transform
= (state
!= NULL
) ? state
->getXYZ2DisplayTransform() : XYZ2DisplayTransform
;
1657 if (cs
->transform
!= NULL
) cs
->transform
->ref();
1662 void GfxLabColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1666 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_GRAY
) {
1667 Guchar out
[gfxColorMaxComps
];
1668 double in
[gfxColorMaxComps
];
1670 getXYZ(color
, &in
[0], &in
[1], &in
[2]);
1671 transform
->doTransform(in
,out
,1);
1672 *gray
= byteToCol(out
[0]);
1676 getRGB(color
, &rgb
);
1677 *gray
= clip01((GfxColorComp
)(0.299 * rgb
.r
+
1679 0.114 * rgb
.b
+ 0.5));
1682 // convert L*a*b* to media XYZ color space
1683 // (not multiply by the white point)
1684 void GfxLabColorSpace::getXYZ(GfxColor
*color
,
1685 double *pX
, double *pY
, double *pZ
) {
1689 t1
= (colToDbl(color
->c
[0]) + 16) / 116;
1690 t2
= t1
+ colToDbl(color
->c
[1]) / 500;
1691 if (t2
>= (6.0 / 29.0)) {
1694 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
1696 if (t1
>= (6.0 / 29.0)) {
1699 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
1701 t2
= t1
- colToDbl(color
->c
[2]) / 200;
1702 if (t2
>= (6.0 / 29.0)) {
1705 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
1712 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1716 getXYZ(color
, &X
, &Y
, &Z
);
1718 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_RGB
) {
1719 Guchar out
[gfxColorMaxComps
];
1720 double in
[gfxColorMaxComps
];
1725 transform
->doTransform(in
,out
,1);
1726 rgb
->r
= byteToCol(out
[0]);
1727 rgb
->g
= byteToCol(out
[1]);
1728 rgb
->b
= byteToCol(out
[2]);
1730 } else if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
1731 Guchar out
[gfxColorMaxComps
];
1732 double in
[gfxColorMaxComps
];
1733 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
1738 transform
->doTransform(in
,out
,1);
1739 c
= byteToDbl(out
[0]);
1740 m
= byteToDbl(out
[1]);
1741 y
= byteToDbl(out
[2]);
1742 k
= byteToDbl(out
[3]);
1747 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
1748 rgb
->r
= clip01(dblToCol(r
));
1749 rgb
->g
= clip01(dblToCol(g
));
1750 rgb
->b
= clip01(dblToCol(b
));
1757 // convert XYZ to RGB, including gamut mapping and gamma correction
1758 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
1759 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
1760 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
1761 rgb
->r
= dblToCol(sqrt(clip01(r
* kr
)));
1762 rgb
->g
= dblToCol(sqrt(clip01(g
* kg
)));
1763 rgb
->b
= dblToCol(sqrt(clip01(b
* kb
)));
1766 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1768 GfxColorComp c
, m
, y
, k
;
1771 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
1772 double in
[gfxColorMaxComps
];
1773 Guchar out
[gfxColorMaxComps
];
1775 getXYZ(color
, &in
[0], &in
[1], &in
[2]);
1776 transform
->doTransform(in
,out
,1);
1777 cmyk
->c
= byteToCol(out
[0]);
1778 cmyk
->m
= byteToCol(out
[1]);
1779 cmyk
->y
= byteToCol(out
[2]);
1780 cmyk
->k
= byteToCol(out
[3]);
1784 getRGB(color
, &rgb
);
1785 c
= clip01(gfxColorComp1
- rgb
.r
);
1786 m
= clip01(gfxColorComp1
- rgb
.g
);
1787 y
= clip01(gfxColorComp1
- rgb
.b
);
1801 void GfxLabColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
1803 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
1805 getCMYK(color
, &cmyk
);
1806 deviceN
->c
[0] = cmyk
.c
;
1807 deviceN
->c
[1] = cmyk
.m
;
1808 deviceN
->c
[2] = cmyk
.y
;
1809 deviceN
->c
[3] = cmyk
.k
;
1812 void GfxLabColorSpace::getDefaultColor(GfxColor
*color
) {
1815 color
->c
[1] = dblToCol(aMin
);
1816 } else if (aMax
< 0) {
1817 color
->c
[1] = dblToCol(aMax
);
1822 color
->c
[2] = dblToCol(bMin
);
1823 } else if (bMax
< 0) {
1824 color
->c
[2] = dblToCol(bMax
);
1830 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
1833 decodeRange
[0] = 100;
1834 decodeLow
[1] = aMin
;
1835 decodeRange
[1] = aMax
- aMin
;
1836 decodeLow
[2] = bMin
;
1837 decodeRange
[2] = bMax
- bMin
;
1840 //------------------------------------------------------------------------
1841 // GfxICCBasedColorSpace
1842 //------------------------------------------------------------------------
1844 class GfxICCBasedColorSpaceKey
: public PopplerCacheKey
1847 GfxICCBasedColorSpaceKey(int numA
, int genA
) : num(numA
), gen(genA
)
1851 bool operator==(const PopplerCacheKey
&key
) const
1853 const GfxICCBasedColorSpaceKey
*k
= static_cast<const GfxICCBasedColorSpaceKey
*>(&key
);
1854 return k
->num
== num
&& k
->gen
== gen
;
1860 class GfxICCBasedColorSpaceItem
: public PopplerCacheItem
1863 GfxICCBasedColorSpaceItem(GfxICCBasedColorSpace
*csA
)
1865 cs
= static_cast<GfxICCBasedColorSpace
*>(csA
->copy());
1868 ~GfxICCBasedColorSpaceItem()
1873 GfxICCBasedColorSpace
*cs
;
1876 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA
, GfxColorSpace
*altA
,
1877 Ref
*iccProfileStreamA
) {
1880 iccProfileStream
= *iccProfileStreamA
;
1881 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
1882 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
1885 lineTransform
= NULL
;
1889 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
1892 if (transform
!= NULL
) {
1893 if (transform
->unref() == 0) delete transform
;
1895 if (lineTransform
!= NULL
) {
1896 if (lineTransform
->unref() == 0) delete lineTransform
;
1901 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
1902 GfxICCBasedColorSpace
*cs
;
1905 cs
= new GfxICCBasedColorSpace(nComps
, alt
->copy(), &iccProfileStream
);
1906 for (i
= 0; i
< 4; ++i
) {
1907 cs
->rangeMin
[i
] = rangeMin
[i
];
1908 cs
->rangeMax
[i
] = rangeMax
[i
];
1911 cs
->transform
= transform
;
1912 if (transform
!= NULL
) transform
->ref();
1913 cs
->lineTransform
= lineTransform
;
1914 if (lineTransform
!= NULL
) lineTransform
->ref();
1919 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
, OutputDev
*out
, GfxState
*state
, int recursion
) {
1920 GfxICCBasedColorSpace
*cs
;
1921 Ref iccProfileStreamA
;
1923 GfxColorSpace
*altA
;
1925 Object obj1
, obj2
, obj3
;
1928 if (arr
->getLength() < 2) {
1929 error(errSyntaxError
, -1, "Bad ICCBased color space");
1932 arr
->getNF(1, &obj1
);
1934 iccProfileStreamA
= obj1
.getRef();
1936 iccProfileStreamA
.num
= 0;
1937 iccProfileStreamA
.gen
= 0;
1942 if (out
&& iccProfileStreamA
.num
> 0) {
1943 GfxICCBasedColorSpaceKey
k(iccProfileStreamA
.num
, iccProfileStreamA
.gen
);
1944 GfxICCBasedColorSpaceItem
*item
= static_cast<GfxICCBasedColorSpaceItem
*>(out
->getIccColorSpaceCache()->lookup(k
));
1947 cs
= static_cast<GfxICCBasedColorSpace
*>(item
->cs
->copy());
1948 int transformIntent
= cs
->getIntent();
1949 int cmsIntent
= INTENT_RELATIVE_COLORIMETRIC
;
1950 if (state
!= NULL
) {
1951 const char *intent
= state
->getRenderingIntent();
1952 if (intent
!= NULL
) {
1953 if (strcmp(intent
, "AbsoluteColorimetric") == 0) {
1954 cmsIntent
= INTENT_ABSOLUTE_COLORIMETRIC
;
1955 } else if (strcmp(intent
, "Saturation") == 0) {
1956 cmsIntent
= INTENT_SATURATION
;
1957 } else if (strcmp(intent
, "Perceptual") == 0) {
1958 cmsIntent
= INTENT_PERCEPTUAL
;
1962 if (transformIntent
== cmsIntent
) {
1970 if (!obj1
.isStream()) {
1971 error(errSyntaxWarning
, -1, "Bad ICCBased color space (stream)");
1975 dict
= obj1
.streamGetDict();
1976 if (!dict
->lookup("N", &obj2
)->isInt()) {
1977 error(errSyntaxWarning
, -1, "Bad ICCBased color space (N)");
1982 nCompsA
= obj2
.getInt();
1985 error(errSyntaxError
, -1,
1986 "ICCBased color space with too many ({0:d} > 4) components",
1990 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
1991 !(altA
= GfxColorSpace::parse(NULL
, &obj2
, out
, state
, recursion
+ 1))) {
1994 altA
= new GfxDeviceGrayColorSpace();
1997 altA
= new GfxDeviceRGBColorSpace();
2000 altA
= new GfxDeviceCMYKColorSpace();
2003 error(errSyntaxWarning
, -1, "Bad ICCBased color space - invalid N");
2010 cs
= new GfxICCBasedColorSpace(nCompsA
, altA
, &iccProfileStreamA
);
2011 if (dict
->lookup("Range", &obj2
)->isArray() &&
2012 obj2
.arrayGetLength() == 2 * nCompsA
) {
2014 for (i
= 0; i
< nCompsA
; ++i
) {
2015 obj2
.arrayGet(2*i
, &obj3
);
2016 obj2
.arrayGet(2*i
+1, &obj4
);
2017 if (obj3
.isNum() && obj4
.isNum()) {
2018 cs
->rangeMin
[i
] = obj3
.getNum();
2019 cs
->rangeMax
[i
] = obj4
.getNum();
2030 dict
= obj1
.streamGetDict();
2032 Stream
*iccStream
= obj1
.getStream();
2035 profBuf
= iccStream
->toUnsignedChars(&length
, 65536, 65536);
2036 cmsHPROFILE hp
= cmsOpenProfileFromMem(profBuf
,length
);
2039 error(errSyntaxWarning
, -1, "read ICCBased color space profile error");
2041 cmsHPROFILE dhp
= (state
!= NULL
&& state
->getDisplayProfile() != NULL
) ? state
->getDisplayProfile() : displayProfile
;
2042 if (dhp
== NULL
) dhp
= RGBProfile
;
2043 unsigned int cst
= getCMSColorSpaceType(cmsGetColorSpace(hp
));
2044 unsigned int dNChannels
= getCMSNChannels(cmsGetColorSpace(dhp
));
2045 unsigned int dcst
= getCMSColorSpaceType(cmsGetColorSpace(dhp
));
2046 cmsHTRANSFORM transform
;
2048 int cmsIntent
= INTENT_RELATIVE_COLORIMETRIC
;
2049 if (state
!= NULL
) {
2050 const char *intent
= state
->getRenderingIntent();
2051 if (intent
!= NULL
) {
2052 if (strcmp(intent
, "AbsoluteColorimetric") == 0) {
2053 cmsIntent
= INTENT_ABSOLUTE_COLORIMETRIC
;
2054 } else if (strcmp(intent
, "Saturation") == 0) {
2055 cmsIntent
= INTENT_SATURATION
;
2056 } else if (strcmp(intent
, "Perceptual") == 0) {
2057 cmsIntent
= INTENT_PERCEPTUAL
;
2061 if ((transform
= cmsCreateTransform(hp
,
2062 COLORSPACE_SH(cst
) |CHANNELS_SH(nCompsA
) | BYTES_SH(1),
2064 COLORSPACE_SH(dcst
) |
2065 CHANNELS_SH(dNChannels
) | BYTES_SH(1),
2066 cmsIntent
, LCMS_FLAGS
)) == 0) {
2067 error(errSyntaxWarning
, -1, "Can't create transform");
2068 cs
->transform
= NULL
;
2070 cs
->transform
= new GfxColorTransform(transform
, cmsIntent
, cst
, dcst
);
2072 if (dcst
== PT_RGB
|| dcst
== PT_CMYK
) {
2073 // create line transform only when the display is RGB type color space
2074 if ((transform
= cmsCreateTransform(hp
,
2075 CHANNELS_SH(nCompsA
) | BYTES_SH(1),dhp
,
2076 (dcst
== PT_RGB
) ? TYPE_RGB_8
: TYPE_CMYK_8
, cmsIntent
, LCMS_FLAGS
)) == 0) {
2077 error(errSyntaxWarning
, -1, "Can't create transform");
2078 cs
->lineTransform
= NULL
;
2080 cs
->lineTransform
= new GfxColorTransform(transform
, cmsIntent
, cst
, dcst
);
2083 cmsCloseProfile(hp
);
2086 // put this colorSpace into cache
2087 if (out
&& iccProfileStreamA
.num
> 0) {
2088 GfxICCBasedColorSpaceKey
*k
= new GfxICCBasedColorSpaceKey(iccProfileStreamA
.num
, iccProfileStreamA
.gen
);
2089 GfxICCBasedColorSpaceItem
*item
= new GfxICCBasedColorSpaceItem(cs
);
2090 out
->getIccColorSpaceCache()->put(k
, item
);
2096 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
2098 if (transform
!= 0 && transform
->getTransformPixelType() == PT_GRAY
) {
2099 Guchar in
[gfxColorMaxComps
];
2100 Guchar out
[gfxColorMaxComps
];
2102 if (nComps
== 3 && transform
->getInputPixelType() == PT_Lab
) {
2103 in
[0] = colToByte(dblToCol(colToDbl(color
->c
[0]) / 100.0));
2104 in
[1] = colToByte(dblToCol((colToDbl(color
->c
[1]) + 128.0) / 255.0));
2105 in
[2] = colToByte(dblToCol((colToDbl(color
->c
[2]) + 128.0) / 255.0));
2107 for (int i
= 0;i
< nComps
;i
++) {
2108 in
[i
] = colToByte(color
->c
[i
]);
2112 unsigned int key
= 0;
2113 for (int j
= 0; j
< nComps
; j
++) {
2114 key
= (key
<< 8) + in
[j
];
2116 std::map
<unsigned int, unsigned int>::iterator it
= cmsCache
.find(key
);
2117 if (it
!= cmsCache
.end()) {
2118 unsigned int value
= it
->second
;
2119 *gray
= byteToCol(value
& 0xff);
2123 transform
->doTransform(in
,out
,1);
2124 *gray
= byteToCol(out
[0]);
2125 if (nComps
<= 4 && cmsCache
.size() <= CMSCACHE_LIMIT
) {
2126 unsigned int key
= 0;
2127 for (int j
= 0; j
< nComps
; j
++) {
2128 key
= (key
<< 8) + in
[j
];
2130 unsigned int value
= out
[0];
2131 cmsCache
.insert(std::pair
<unsigned int, unsigned int>(key
, value
));
2136 *gray
= clip01((GfxColorComp
)(0.3 * rgb
.r
+
2138 0.11 * rgb
.b
+ 0.5));
2141 alt
->getGray(color
, gray
);
2145 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
2147 if (transform
!= 0 && transform
->getTransformPixelType() == PT_RGB
) {
2148 Guchar in
[gfxColorMaxComps
];
2149 Guchar out
[gfxColorMaxComps
];
2151 if (nComps
== 3 && transform
->getInputPixelType() == PT_Lab
) {
2152 in
[0] = colToByte(dblToCol(colToDbl(color
->c
[0]) / 100.0));
2153 in
[1] = colToByte(dblToCol((colToDbl(color
->c
[1]) + 128.0) / 255.0));
2154 in
[2] = colToByte(dblToCol((colToDbl(color
->c
[2]) + 128.0) / 255.0));
2156 for (int i
= 0;i
< nComps
;i
++) {
2157 in
[i
] = colToByte(color
->c
[i
]);
2161 unsigned int key
= 0;
2162 for (int j
= 0; j
< nComps
; j
++) {
2163 key
= (key
<< 8) + in
[j
];
2165 std::map
<unsigned int, unsigned int>::iterator it
= cmsCache
.find(key
);
2166 if (it
!= cmsCache
.end()) {
2167 unsigned int value
= it
->second
;
2168 rgb
->r
= byteToCol(value
>> 16);
2169 rgb
->g
= byteToCol((value
>> 8) & 0xff);
2170 rgb
->b
= byteToCol(value
& 0xff);
2174 transform
->doTransform(in
,out
,1);
2175 rgb
->r
= byteToCol(out
[0]);
2176 rgb
->g
= byteToCol(out
[1]);
2177 rgb
->b
= byteToCol(out
[2]);
2178 if (nComps
<= 4 && cmsCache
.size() <= CMSCACHE_LIMIT
) {
2179 unsigned int key
= 0;
2180 for (int j
= 0; j
< nComps
; j
++) {
2181 key
= (key
<< 8) + in
[j
];
2183 unsigned int value
= (out
[0] << 16) + (out
[1] << 8) + out
[2];
2184 cmsCache
.insert(std::pair
<unsigned int, unsigned int>(key
, value
));
2186 } else if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
2187 Guchar in
[gfxColorMaxComps
];
2188 Guchar out
[gfxColorMaxComps
];
2189 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
2191 if (nComps
== 3 && transform
->getInputPixelType() == PT_Lab
) {
2192 in
[0] = colToByte(dblToCol(colToDbl(color
->c
[0]) / 100.0));
2193 in
[1] = colToByte(dblToCol((colToDbl(color
->c
[1]) + 128.0) / 255.0));
2194 in
[2] = colToByte(dblToCol((colToDbl(color
->c
[2]) + 128.0) / 255.0));
2196 for (int i
= 0;i
< nComps
;i
++) {
2197 in
[i
] = colToByte(color
->c
[i
]);
2201 unsigned int key
= 0;
2202 for (int j
= 0; j
< nComps
; j
++) {
2203 key
= (key
<< 8) + in
[j
];
2205 std::map
<unsigned int, unsigned int>::iterator it
= cmsCache
.find(key
);
2206 if (it
!= cmsCache
.end()) {
2207 unsigned int value
= it
->second
;
2208 rgb
->r
= byteToCol(value
>> 16);
2209 rgb
->g
= byteToCol((value
>> 8) & 0xff);
2210 rgb
->b
= byteToCol(value
& 0xff);
2214 transform
->doTransform(in
,out
,1);
2215 c
= byteToDbl(out
[0]);
2216 m
= byteToDbl(out
[1]);
2217 y
= byteToDbl(out
[2]);
2218 k
= byteToDbl(out
[3]);
2223 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
2224 rgb
->r
= clip01(dblToCol(r
));
2225 rgb
->g
= clip01(dblToCol(g
));
2226 rgb
->b
= clip01(dblToCol(b
));
2227 if (nComps
<= 4 && cmsCache
.size() <= CMSCACHE_LIMIT
) {
2228 unsigned int key
= 0;
2229 for (int j
= 0; j
< nComps
; j
++) {
2230 key
= (key
<< 8) + in
[j
];
2232 unsigned int value
= (dblToByte(r
) << 16) + (dblToByte(g
) << 8) + dblToByte(b
);
2233 cmsCache
.insert(std::pair
<unsigned int, unsigned int>(key
, value
));
2236 alt
->getRGB(color
, rgb
);
2239 alt
->getRGB(color
, rgb
);
2243 void GfxICCBasedColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
2246 if (lineTransform
!= 0 && lineTransform
->getTransformPixelType() == PT_RGB
) {
2247 Guchar
* tmp
= (Guchar
*)gmallocn(3 * length
, sizeof(Guchar
));
2248 lineTransform
->doTransform(in
, tmp
, length
);
2249 for (int i
= 0; i
< length
; ++i
) {
2250 Guchar
*current
= tmp
+ (i
* 3);
2251 out
[i
] = (current
[0] << 16) | (current
[1] << 8) | current
[2];
2255 alt
->getRGBLine(in
, out
, length
);
2258 alt
->getRGBLine(in
, out
, length
);
2262 void GfxICCBasedColorSpace::getRGBLine(Guchar
*in
, Guchar
*out
, int length
) {
2264 if (lineTransform
!= 0 && lineTransform
->getTransformPixelType() == PT_RGB
) {
2265 Guchar
* tmp
= (Guchar
*)gmallocn(3 * length
, sizeof(Guchar
));
2266 lineTransform
->doTransform(in
, tmp
, length
);
2267 Guchar
*current
= tmp
;
2268 for (int i
= 0; i
< length
; ++i
) {
2269 *out
++ = *current
++;
2270 *out
++ = *current
++;
2271 *out
++ = *current
++;
2274 } else if (lineTransform
!= NULL
&& lineTransform
->getTransformPixelType() == PT_CMYK
) {
2275 Guchar
* tmp
= (Guchar
*)gmallocn(4 * length
, sizeof(Guchar
));
2276 lineTransform
->doTransform(in
, tmp
, length
);
2277 Guchar
*current
= tmp
;
2278 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
;
2279 for (int i
= 0; i
< length
; ++i
) {
2280 c
= byteToDbl(*current
++);
2281 m
= byteToDbl(*current
++);
2282 y
= byteToDbl(*current
++);
2283 k
= byteToDbl(*current
++);
2288 cmykToRGBMatrixMultiplication(c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
);
2289 *out
++ = dblToByte(r
);
2290 *out
++ = dblToByte(g
);
2291 *out
++ = dblToByte(b
);
2295 alt
->getRGBLine(in
, out
, length
);
2298 alt
->getRGBLine(in
, out
, length
);
2302 void GfxICCBasedColorSpace::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
) {
2304 if (lineTransform
!= 0 && lineTransform
->getTransformPixelType() == PT_RGB
) {
2305 Guchar
* tmp
= (Guchar
*)gmallocn(3 * length
, sizeof(Guchar
));
2306 lineTransform
->doTransform(in
, tmp
, length
);
2307 Guchar
*current
= tmp
;
2308 for (int i
= 0; i
< length
; ++i
) {
2309 *out
++ = *current
++;
2310 *out
++ = *current
++;
2311 *out
++ = *current
++;
2316 alt
->getRGBXLine(in
, out
, length
);
2319 alt
->getRGBXLine(in
, out
, length
);
2323 void GfxICCBasedColorSpace::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
) {
2325 if (lineTransform
!= NULL
&& lineTransform
->getTransformPixelType() == PT_CMYK
) {
2326 transform
->doTransform(in
,out
,length
);
2327 } else if (lineTransform
!= NULL
&& nComps
!= 4) {
2328 GfxColorComp c
, m
, y
, k
;
2329 Guchar
* tmp
= (Guchar
*)gmallocn(3 * length
, sizeof(Guchar
));
2330 getRGBLine(in
, tmp
, length
);
2332 for (int i
= 0; i
< length
; i
++) {
2333 c
= byteToCol(255 - *p
++);
2334 m
= byteToCol(255 - *p
++);
2335 y
= byteToCol(255 - *p
++);
2343 *out
++ = colToByte(c
- k
);
2344 *out
++ = colToByte(m
- k
);
2345 *out
++ = colToByte(y
- k
);
2346 *out
++ = colToByte(k
);
2350 alt
->getCMYKLine(in
, out
, length
);
2353 alt
->getCMYKLine(in
, out
, length
);
2357 void GfxICCBasedColorSpace::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
) {
2359 if (lineTransform
!= NULL
&& lineTransform
->getTransformPixelType() == PT_CMYK
) {
2360 Guchar
* tmp
= (Guchar
*)gmallocn(4 * length
, sizeof(Guchar
));
2361 transform
->doTransform(in
,tmp
,length
);
2363 for (int i
= 0; i
< length
; i
++) {
2364 for (int j
= 0; j
< 4; j
++)
2366 for (int j
= 4; j
< SPOT_NCOMPS
+4; j
++)
2370 } else if (lineTransform
!= NULL
&& nComps
!= 4) {
2371 GfxColorComp c
, m
, y
, k
;
2372 Guchar
* tmp
= (Guchar
*)gmallocn(3 * length
, sizeof(Guchar
));
2373 getRGBLine(in
, tmp
, length
);
2375 for (int i
= 0; i
< length
; i
++) {
2376 for (int j
= 0; j
< SPOT_NCOMPS
+4; j
++)
2378 c
= byteToCol(255 - *p
++);
2379 m
= byteToCol(255 - *p
++);
2380 y
= byteToCol(255 - *p
++);
2388 out
[0] = colToByte(c
- k
);
2389 out
[1] = colToByte(m
- k
);
2390 out
[2] = colToByte(y
- k
);
2391 out
[3] = colToByte(k
);
2392 out
+= (SPOT_NCOMPS
+4);
2396 alt
->getDeviceNLine(in
, out
, length
);
2399 alt
->getDeviceNLine(in
, out
, length
);
2403 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
2405 if (transform
!= NULL
&& transform
->getTransformPixelType() == PT_CMYK
) {
2406 Guchar in
[gfxColorMaxComps
];
2407 Guchar out
[gfxColorMaxComps
];
2409 if (nComps
== 3 && transform
->getInputPixelType() == PT_Lab
) {
2410 in
[0] = colToByte(dblToCol(colToDbl(color
->c
[0]) / 100.0));
2411 in
[1] = colToByte(dblToCol((colToDbl(color
->c
[1]) + 128.0) / 255.0));
2412 in
[2] = colToByte(dblToCol((colToDbl(color
->c
[2]) + 128.0) / 255.0));
2414 for (int i
= 0;i
< nComps
;i
++) {
2415 in
[i
] = colToByte(color
->c
[i
]);
2419 unsigned int key
= 0;
2420 for (int j
= 0; j
< nComps
; j
++) {
2421 key
= (key
<< 8) + in
[j
];
2423 std::map
<unsigned int, unsigned int>::iterator it
= cmsCache
.find(key
);
2424 if (it
!= cmsCache
.end()) {
2425 unsigned int value
= it
->second
;
2426 cmyk
->c
= byteToCol(value
>> 24);
2427 cmyk
->m
= byteToCol((value
>> 16) & 0xff);
2428 cmyk
->y
= byteToCol((value
>> 8) & 0xff);
2429 cmyk
->k
= byteToCol(value
& 0xff);
2433 transform
->doTransform(in
,out
,1);
2434 cmyk
->c
= byteToCol(out
[0]);
2435 cmyk
->m
= byteToCol(out
[1]);
2436 cmyk
->y
= byteToCol(out
[2]);
2437 cmyk
->k
= byteToCol(out
[3]);
2438 if (nComps
<= 4 && cmsCache
.size() <= CMSCACHE_LIMIT
) {
2439 unsigned int key
= 0;
2440 for (int j
= 0; j
< nComps
; j
++) {
2441 key
= (key
<< 8) + in
[j
];
2443 unsigned int value
= (out
[0] << 24) + (out
[1] << 16) + (out
[2] << 8) + out
[3];
2444 cmsCache
.insert(std::pair
<unsigned int, unsigned int>(key
, value
));
2446 } else if (nComps
!= 4 && transform
!= NULL
&& transform
->getTransformPixelType() == PT_RGB
) {
2448 GfxColorComp c
, m
, y
, k
;
2451 c
= clip01(gfxColorComp1
- rgb
.r
);
2452 m
= clip01(gfxColorComp1
- rgb
.g
);
2453 y
= clip01(gfxColorComp1
- rgb
.b
);
2466 alt
->getCMYK(color
, cmyk
);
2469 alt
->getCMYK(color
, cmyk
);
2473 GBool
GfxICCBasedColorSpace::useGetRGBLine() {
2475 return lineTransform
!= NULL
|| alt
->useGetRGBLine();
2477 return alt
->useGetRGBLine();
2481 GBool
GfxICCBasedColorSpace::useGetCMYKLine() {
2483 return lineTransform
!= NULL
|| alt
->useGetCMYKLine();
2485 return alt
->useGetCMYKLine();
2489 GBool
GfxICCBasedColorSpace::useGetDeviceNLine() {
2491 return lineTransform
!= NULL
|| alt
->useGetDeviceNLine();
2493 return alt
->useGetDeviceNLine();
2497 void GfxICCBasedColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
2499 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
2501 getCMYK(color
, &cmyk
);
2502 deviceN
->c
[0] = cmyk
.c
;
2503 deviceN
->c
[1] = cmyk
.m
;
2504 deviceN
->c
[2] = cmyk
.y
;
2505 deviceN
->c
[3] = cmyk
.k
;
2508 void GfxICCBasedColorSpace::getDefaultColor(GfxColor
*color
) {
2511 for (i
= 0; i
< nComps
; ++i
) {
2512 if (rangeMin
[i
] > 0) {
2513 color
->c
[i
] = dblToCol(rangeMin
[i
]);
2514 } else if (rangeMax
[i
] < 0) {
2515 color
->c
[i
] = dblToCol(rangeMax
[i
]);
2522 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
2523 double *decodeRange
,
2525 alt
->getDefaultRanges(decodeLow
, decodeRange
, maxImgPixel
);
2528 // this is nominally correct, but some PDF files don't set the
2529 // correct ranges in the ICCBased dict
2532 for (i
= 0; i
< nComps
; ++i
) {
2533 decodeLow
[i
] = rangeMin
[i
];
2534 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
2539 //------------------------------------------------------------------------
2540 // GfxIndexedColorSpace
2541 //------------------------------------------------------------------------
2543 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*baseA
,
2546 indexHigh
= indexHighA
;
2547 lookup
= (Guchar
*)gmallocn((indexHigh
+ 1) * base
->getNComps(),
2549 overprintMask
= base
->getOverprintMask();
2552 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
2557 GfxColorSpace
*GfxIndexedColorSpace::copy() {
2558 GfxIndexedColorSpace
*cs
;
2560 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
2561 memcpy(cs
->lookup
, lookup
,
2562 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
2566 GfxColorSpace
*GfxIndexedColorSpace::parse(GfxResources
*res
, Array
*arr
, OutputDev
*out
, GfxState
*state
, int recursion
) {
2567 GfxIndexedColorSpace
*cs
;
2568 GfxColorSpace
*baseA
;
2574 if (arr
->getLength() != 4) {
2575 error(errSyntaxWarning
, -1, "Bad Indexed color space");
2579 if (!(baseA
= GfxColorSpace::parse(res
, &obj1
, out
, state
, recursion
+ 1))) {
2580 error(errSyntaxWarning
, -1, "Bad Indexed color space (base color space)");
2584 if (!arr
->get(2, &obj1
)->isInt()) {
2585 error(errSyntaxWarning
, -1, "Bad Indexed color space (hival)");
2589 indexHighA
= obj1
.getInt();
2590 if (indexHighA
< 0 || indexHighA
> 255) {
2591 // the PDF spec requires indexHigh to be in [0,255] -- allowing
2592 // values larger than 255 creates a security hole: if nComps *
2593 // indexHigh is greater than 2^31, the loop below may overwrite
2594 // past the end of the array
2595 int previousValue
= indexHighA
;
2596 if (indexHighA
< 0) indexHighA
= 0;
2597 else indexHighA
= 255;
2598 error(errSyntaxWarning
, -1, "Bad Indexed color space (invalid indexHigh value, was {0:d} using {1:d} to try to recover)", previousValue
, indexHighA
);
2601 cs
= new GfxIndexedColorSpace(baseA
, indexHighA
);
2603 n
= baseA
->getNComps();
2604 if (obj1
.isStream()) {
2606 for (i
= 0; i
<= indexHighA
; ++i
) {
2607 const int readChars
= obj1
.streamGetChars(n
, &cs
->lookup
[i
*n
]);
2608 for (j
= readChars
; j
< n
; ++j
) {
2609 error(errSyntaxWarning
, -1, "Bad Indexed color space (lookup table stream too short) padding with zeroes");
2610 cs
->lookup
[i
*n
+ j
] = 0;
2614 } else if (obj1
.isString()) {
2615 if (obj1
.getString()->getLength() < (indexHighA
+ 1) * n
) {
2616 error(errSyntaxWarning
, -1, "Bad Indexed color space (lookup table string too short)");
2619 s
= obj1
.getString()->getCString();
2620 for (i
= 0; i
<= indexHighA
; ++i
) {
2621 for (j
= 0; j
< n
; ++j
) {
2622 cs
->lookup
[i
*n
+ j
] = (Guchar
)*s
++;
2626 error(errSyntaxWarning
, -1, "Bad Indexed color space (lookup table)");
2640 GfxColor
*GfxIndexedColorSpace::mapColorToBase(GfxColor
*color
,
2641 GfxColor
*baseColor
) {
2643 double low
[gfxColorMaxComps
], range
[gfxColorMaxComps
];
2646 n
= base
->getNComps();
2647 base
->getDefaultRanges(low
, range
, indexHigh
);
2648 const int idx
= (int)(colToDbl(color
->c
[0]) + 0.5) * n
;
2649 if (likely((idx
+ n
< (indexHigh
+ 1) * base
->getNComps()) && idx
>= 0)) {
2651 for (i
= 0; i
< n
; ++i
) {
2652 baseColor
->c
[i
] = dblToCol(low
[i
] + (p
[i
] / 255.0) * range
[i
]);
2655 for (i
= 0; i
< n
; ++i
) {
2656 baseColor
->c
[i
] = 0;
2662 void GfxIndexedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
2665 base
->getGray(mapColorToBase(color
, &color2
), gray
);
2668 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
2671 base
->getRGB(mapColorToBase(color
, &color2
), rgb
);
2674 void GfxIndexedColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
, int length
) {
2678 n
= base
->getNComps();
2679 line
= (Guchar
*) gmallocn (length
, n
);
2680 for (i
= 0; i
< length
; i
++)
2681 for (j
= 0; j
< n
; j
++)
2682 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
2684 base
->getRGBLine(line
, out
, length
);
2689 void GfxIndexedColorSpace::getRGBLine(Guchar
*in
, Guchar
*out
, int length
)
2694 n
= base
->getNComps();
2695 line
= (Guchar
*) gmallocn (length
, n
);
2696 for (i
= 0; i
< length
; i
++)
2697 for (j
= 0; j
< n
; j
++)
2698 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
2700 base
->getRGBLine(line
, out
, length
);
2705 void GfxIndexedColorSpace::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
)
2710 n
= base
->getNComps();
2711 line
= (Guchar
*) gmallocn (length
, n
);
2712 for (i
= 0; i
< length
; i
++)
2713 for (j
= 0; j
< n
; j
++)
2714 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
2716 base
->getRGBXLine(line
, out
, length
);
2721 void GfxIndexedColorSpace::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
) {
2725 n
= base
->getNComps();
2726 line
= (Guchar
*) gmallocn (length
, n
);
2727 for (i
= 0; i
< length
; i
++)
2728 for (j
= 0; j
< n
; j
++)
2729 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
2731 base
->getCMYKLine(line
, out
, length
);
2736 void GfxIndexedColorSpace::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
) {
2740 n
= base
->getNComps();
2741 line
= (Guchar
*) gmallocn (length
, n
);
2742 for (i
= 0; i
< length
; i
++)
2743 for (j
= 0; j
< n
; j
++)
2744 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
2746 base
->getDeviceNLine(line
, out
, length
);
2751 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
2754 base
->getCMYK(mapColorToBase(color
, &color2
), cmyk
);
2757 void GfxIndexedColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
2760 base
->getDeviceN(mapColorToBase(color
, &color2
), deviceN
);
2763 void GfxIndexedColorSpace::getDefaultColor(GfxColor
*color
) {
2767 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
2768 double *decodeRange
,
2771 decodeRange
[0] = maxImgPixel
;
2774 //------------------------------------------------------------------------
2775 // GfxSeparationColorSpace
2776 //------------------------------------------------------------------------
2778 GfxSeparationColorSpace::GfxSeparationColorSpace(GooString
*nameA
,
2779 GfxColorSpace
*altA
,
2784 nonMarking
= !name
->cmp("None");
2785 if (!name
->cmp("Cyan")) {
2786 overprintMask
= 0x01;
2787 } else if (!name
->cmp("Magenta")) {
2788 overprintMask
= 0x02;
2789 } else if (!name
->cmp("Yellow")) {
2790 overprintMask
= 0x04;
2791 } else if (!name
->cmp("Black")) {
2792 overprintMask
= 0x08;
2793 } else if (!name
->cmp("All")) {
2794 overprintMask
= 0xffffffff;
2798 GfxSeparationColorSpace::GfxSeparationColorSpace(GooString
*nameA
,
2799 GfxColorSpace
*altA
,
2802 Guint overprintMaskA
,
2807 nonMarking
= nonMarkingA
;
2808 overprintMask
= overprintMaskA
;
2812 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
2816 if (mapping
!= NULL
)
2820 GfxColorSpace
*GfxSeparationColorSpace::copy() {
2821 int *mappingA
= NULL
;
2822 if (mapping
!= NULL
) {
2823 mappingA
= (int *) gmalloc(sizeof(int));
2824 *mappingA
= *mapping
;
2826 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy(),
2827 nonMarking
, overprintMask
, mappingA
);
2830 //~ handle the 'All' and 'None' colorants
2831 GfxColorSpace
*GfxSeparationColorSpace::parse(GfxResources
*res
, Array
*arr
, OutputDev
*out
, GfxState
*state
, int recursion
) {
2832 GfxSeparationColorSpace
*cs
;
2834 GfxColorSpace
*altA
;
2838 if (arr
->getLength() != 4) {
2839 error(errSyntaxWarning
, -1, "Bad Separation color space");
2842 if (!arr
->get(1, &obj1
)->isName()) {
2843 error(errSyntaxWarning
, -1, "Bad Separation color space (name)");
2846 nameA
= new GooString(obj1
.getName());
2849 if (!(altA
= GfxColorSpace::parse(res
, &obj1
, out
, state
, recursion
+ 1))) {
2850 error(errSyntaxWarning
, -1, "Bad Separation color space (alternate color space)");
2855 if (!(funcA
= Function::parse(&obj1
))) {
2858 if (funcA
->getInputSize() != 1) {
2859 error(errSyntaxWarning
, -1, "Bad SeparationColorSpace function");
2863 cs
= new GfxSeparationColorSpace(nameA
, altA
, funcA
);
2878 void GfxSeparationColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
2880 double c
[gfxColorMaxComps
];
2884 if (alt
->getMode() == csDeviceGray
&& name
->cmp("Black") == 0) {
2885 *gray
= clip01(gfxColorComp1
- color
->c
[0]);
2887 x
= colToDbl(color
->c
[0]);
2888 func
->transform(&x
, c
);
2889 for (i
= 0; i
< alt
->getNComps(); ++i
) {
2890 color2
.c
[i
] = dblToCol(c
[i
]);
2892 alt
->getGray(&color2
, gray
);
2896 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
2898 double c
[gfxColorMaxComps
];
2902 if (alt
->getMode() == csDeviceGray
&& name
->cmp("Black") == 0) {
2903 rgb
->r
= clip01(gfxColorComp1
- color
->c
[0]);
2904 rgb
->g
= clip01(gfxColorComp1
- color
->c
[0]);
2905 rgb
->b
= clip01(gfxColorComp1
- color
->c
[0]);
2907 x
= colToDbl(color
->c
[0]);
2908 func
->transform(&x
, c
);
2909 for (i
= 0; i
< alt
->getNComps(); ++i
) {
2910 color2
.c
[i
] = dblToCol(c
[i
]);
2912 alt
->getRGB(&color2
, rgb
);
2916 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
2918 double c
[gfxColorMaxComps
];
2922 if (name
->cmp("Black") == 0) {
2926 cmyk
->k
= color
->c
[0];
2927 } else if (name
->cmp("Cyan") == 0) {
2928 cmyk
->c
= color
->c
[0];
2932 } else if (name
->cmp("Magenta") == 0) {
2934 cmyk
->m
= color
->c
[0];
2937 } else if (name
->cmp("Yellow") == 0) {
2940 cmyk
->y
= color
->c
[0];
2943 x
= colToDbl(color
->c
[0]);
2944 func
->transform(&x
, c
);
2945 for (i
= 0; i
< alt
->getNComps(); ++i
) {
2946 color2
.c
[i
] = dblToCol(c
[i
]);
2948 alt
->getCMYK(&color2
, cmyk
);
2952 void GfxSeparationColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
2953 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
2955 if (mapping
== NULL
|| mapping
[0] == -1) {
2958 getCMYK(color
, &cmyk
);
2959 deviceN
->c
[0] = cmyk
.c
;
2960 deviceN
->c
[1] = cmyk
.m
;
2961 deviceN
->c
[2] = cmyk
.y
;
2962 deviceN
->c
[3] = cmyk
.k
;
2964 deviceN
->c
[mapping
[0]] = color
->c
[0];
2968 void GfxSeparationColorSpace::getDefaultColor(GfxColor
*color
) {
2969 color
->c
[0] = gfxColorComp1
;
2972 void GfxSeparationColorSpace::createMapping(GooList
*separationList
, int maxSepComps
) {
2975 mapping
= (int *)gmalloc(sizeof(int));
2976 switch (overprintMask
) {
2990 Guint newOverprintMask
= 0x10;
2991 for (int i
= 0; i
< separationList
->getLength(); i
++) {
2992 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(i
);
2993 if (!sepCS
->getName()->cmp(name
)) {
2994 if (sepCS
->getFunc()->hasDifferentResultSet(func
)) {
2995 error(errSyntaxWarning
, -1,
2996 "Different functions found for '{0:t}', convert immediately", name
);
3002 overprintMask
= newOverprintMask
;
3005 newOverprintMask
<<=1;
3007 if (separationList
->getLength() == maxSepComps
) {
3008 error(errSyntaxWarning
, -1,
3009 "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps
, name
);
3014 *mapping
= separationList
->getLength() + 4;
3015 separationList
->append(copy());
3016 overprintMask
= newOverprintMask
;
3021 //------------------------------------------------------------------------
3022 // GfxDeviceNColorSpace
3023 //------------------------------------------------------------------------
3025 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
3027 GfxColorSpace
*altA
,
3039 for (i
= 0; i
< nComps
; ++i
) {
3040 names
[i
] = namesA
[i
];
3041 if (names
[i
]->cmp("None")) {
3042 nonMarking
= gFalse
;
3044 if (!names
[i
]->cmp("Cyan")) {
3045 overprintMask
|= 0x01;
3046 } else if (!names
[i
]->cmp("Magenta")) {
3047 overprintMask
|= 0x02;
3048 } else if (!names
[i
]->cmp("Yellow")) {
3049 overprintMask
|= 0x04;
3050 } else if (!names
[i
]->cmp("Black")) {
3051 overprintMask
|= 0x08;
3052 } else if (!names
[i
]->cmp("All")) {
3053 overprintMask
= 0xffffffff;
3055 overprintMask
= 0x0f;
3060 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
3062 GfxColorSpace
*altA
,
3067 Guint overprintMaskA
) {
3075 nonMarking
= nonMarkingA
;
3076 overprintMask
= overprintMaskA
;
3077 for (i
= 0; i
< nComps
; ++i
) {
3078 names
[i
] = namesA
[i
]->copy();
3082 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
3085 for (i
= 0; i
< nComps
; ++i
) {
3090 deleteGooList(sepsCS
, GfxSeparationColorSpace
);
3091 if (mapping
!= NULL
)
3095 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
3097 int *mappingA
= NULL
;
3099 GooList
*sepsCSA
= new GooList(sepsCS
->getLength());
3100 for (i
= 0; i
< sepsCS
->getLength(); i
++) {
3101 GfxSeparationColorSpace
*scs
= (GfxSeparationColorSpace
*) sepsCS
->get(i
);
3102 if (likely(scs
!= NULL
)) {
3103 sepsCSA
->append(scs
->copy());
3106 if (mapping
!= NULL
) {
3107 mappingA
= (int *)gmalloc(sizeof(int) * nComps
);
3108 for (i
= 0; i
< nComps
; i
++)
3109 mappingA
[i
] = mapping
[i
];
3111 return new GfxDeviceNColorSpace(nComps
, names
, alt
->copy(), func
->copy(),
3112 sepsCSA
, mappingA
, nonMarking
, overprintMask
);
3115 //~ handle the 'None' colorant
3116 GfxColorSpace
*GfxDeviceNColorSpace::parse(GfxResources
*res
, Array
*arr
, OutputDev
*out
, GfxState
*state
, int recursion
) {
3117 GfxDeviceNColorSpace
*cs
;
3119 GooString
*namesA
[gfxColorMaxComps
];
3120 GfxColorSpace
*altA
;
3124 GooList
*separationList
= new GooList();
3126 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
3127 error(errSyntaxWarning
, -1, "Bad DeviceN color space");
3130 if (!arr
->get(1, &obj1
)->isArray()) {
3131 error(errSyntaxWarning
, -1, "Bad DeviceN color space (names)");
3134 nCompsA
= obj1
.arrayGetLength();
3135 if (nCompsA
> gfxColorMaxComps
) {
3136 error(errSyntaxWarning
, -1, "DeviceN color space with too many ({0:d} > {1:d}) components",
3137 nCompsA
, gfxColorMaxComps
);
3138 nCompsA
= gfxColorMaxComps
;
3140 for (i
= 0; i
< nCompsA
; ++i
) {
3141 if (!obj1
.arrayGet(i
, &obj2
)->isName()) {
3142 error(errSyntaxWarning
, -1, "Bad DeviceN color space (names)");
3146 namesA
[i
] = new GooString(obj2
.getName());
3151 if (!(altA
= GfxColorSpace::parse(res
, &obj1
, out
, state
, recursion
+ 1))) {
3152 error(errSyntaxWarning
, -1, "Bad DeviceN color space (alternate color space)");
3157 if (!(funcA
= Function::parse(&obj1
))) {
3161 if (arr
->getLength() == 5) {
3162 if (!arr
->get(4, &obj1
)->isDict()) {
3163 error(errSyntaxWarning
, -1, "Bad DeviceN color space (attributes)");
3166 Dict
*attribs
= obj1
.getDict();
3167 attribs
->lookup("Colorants", &obj2
);
3168 if (obj2
.isDict()) {
3169 Dict
*colorants
= obj2
.getDict();
3170 for (i
= 0; i
< colorants
->getLength(); i
++) {
3172 colorants
->getVal(i
, &obj3
);
3173 if (obj3
.isArray()) {
3174 separationList
->append(GfxSeparationColorSpace::parse(res
, obj3
.getArray(), out
, state
, recursion
));
3178 error(errSyntaxWarning
, -1, "Bad DeviceN color space (colorant value entry is not an Array)");
3187 cs
= new GfxDeviceNColorSpace(nCompsA
, namesA
, altA
, funcA
, separationList
);
3193 for (i
= 0; i
< nCompsA
; ++i
) {
3199 delete separationList
;
3203 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
3204 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
3208 for (i
= 0; i
< nComps
; ++i
) {
3209 x
[i
] = colToDbl(color
->c
[i
]);
3211 func
->transform(x
, c
);
3212 for (i
= 0; i
< alt
->getNComps(); ++i
) {
3213 color2
.c
[i
] = dblToCol(c
[i
]);
3215 alt
->getGray(&color2
, gray
);
3218 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
3219 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
3223 for (i
= 0; i
< nComps
; ++i
) {
3224 x
[i
] = colToDbl(color
->c
[i
]);
3226 func
->transform(x
, c
);
3227 for (i
= 0; i
< alt
->getNComps(); ++i
) {
3228 color2
.c
[i
] = dblToCol(c
[i
]);
3230 alt
->getRGB(&color2
, rgb
);
3233 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
3234 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
3238 for (i
= 0; i
< nComps
; ++i
) {
3239 x
[i
] = colToDbl(color
->c
[i
]);
3241 func
->transform(x
, c
);
3242 for (i
= 0; i
< alt
->getNComps(); ++i
) {
3243 color2
.c
[i
] = dblToCol(c
[i
]);
3245 alt
->getCMYK(&color2
, cmyk
);
3248 void GfxDeviceNColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
3249 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
3251 if (mapping
== NULL
) {
3254 getCMYK(color
, &cmyk
);
3255 deviceN
->c
[0] = cmyk
.c
;
3256 deviceN
->c
[1] = cmyk
.m
;
3257 deviceN
->c
[2] = cmyk
.y
;
3258 deviceN
->c
[3] = cmyk
.k
;
3260 for (int j
= 0; j
< nComps
; j
++)
3261 if (mapping
[j
] != -1)
3262 deviceN
->c
[mapping
[j
]] = color
->c
[j
];
3266 void GfxDeviceNColorSpace::getDefaultColor(GfxColor
*color
) {
3269 for (i
= 0; i
< nComps
; ++i
) {
3270 color
->c
[i
] = gfxColorComp1
;
3274 void GfxDeviceNColorSpace::createMapping(GooList
*separationList
, int maxSepComps
) {
3275 if (nonMarking
) // None
3277 mapping
= (int *)gmalloc(sizeof(int) * nComps
);
3278 Guint newOverprintMask
= 0;
3279 for (int i
= 0; i
< nComps
; i
++) {
3280 if (!names
[i
]->cmp("None")) {
3282 } else if (!names
[i
]->cmp("Cyan")) {
3283 newOverprintMask
|= 0x01;
3285 } else if (!names
[i
]->cmp("Magenta")) {
3286 newOverprintMask
|= 0x02;
3288 } else if (!names
[i
]->cmp("Yellow")) {
3289 newOverprintMask
|= 0x04;
3291 } else if (!names
[i
]->cmp("Black")) {
3292 newOverprintMask
|= 0x08;
3295 Guint startOverprintMask
= 0x10;
3296 GBool found
= gFalse
;
3297 Function
*sepFunc
= NULL
;
3301 for (int k
= 0; k
< sepsCS
->getLength(); k
++) {
3302 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)sepsCS
->get(k
);
3303 if (!sepCS
->getName()->cmp(names
[i
])) {
3304 sepFunc
= sepCS
->getFunc();
3309 for (int j
= 0; j
< separationList
->getLength(); j
++) {
3310 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)separationList
->get(j
);
3311 if (!sepCS
->getName()->cmp(names
[i
])) {
3312 if (sepFunc
!= NULL
&& sepCS
->getFunc()->hasDifferentResultSet(sepFunc
)) {
3313 error(errSyntaxWarning
, -1,
3314 "Different functions found for '{0:t}', convert immediately", names
[i
]);
3317 overprintMask
= 0xffffffff;
3321 newOverprintMask
|= startOverprintMask
;
3325 startOverprintMask
<<=1;
3328 if (separationList
->getLength() == maxSepComps
) {
3329 error(errSyntaxWarning
, -1,
3330 "Too many ({0:d}) spots, convert '{1:t}' immediately", maxSepComps
, names
[i
]);
3333 overprintMask
= 0xffffffff;
3336 mapping
[i
] = separationList
->getLength() + 4;
3337 newOverprintMask
|= startOverprintMask
;
3339 separationList
->append(new GfxSeparationColorSpace(names
[i
]->copy(),alt
->copy(), func
->copy()));
3341 for (int k
= 0; k
< sepsCS
->getLength(); k
++) {
3342 GfxSeparationColorSpace
*sepCS
= (GfxSeparationColorSpace
*)sepsCS
->get(k
);
3343 if (!sepCS
->getName()->cmp(names
[i
])) {
3345 separationList
->append(sepCS
->copy());
3350 error(errSyntaxWarning
, -1, "DeviceN has no suitable colorant");
3353 overprintMask
= 0xffffffff;
3360 overprintMask
= newOverprintMask
;
3363 //------------------------------------------------------------------------
3364 // GfxPatternColorSpace
3365 //------------------------------------------------------------------------
3367 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*underA
) {
3371 GfxPatternColorSpace::~GfxPatternColorSpace() {
3377 GfxColorSpace
*GfxPatternColorSpace::copy() {
3378 return new GfxPatternColorSpace(under
? under
->copy() :
3379 (GfxColorSpace
*)NULL
);
3382 GfxColorSpace
*GfxPatternColorSpace::parse(GfxResources
*res
, Array
*arr
, OutputDev
*out
, GfxState
*state
, int recursion
) {
3383 GfxPatternColorSpace
*cs
;
3384 GfxColorSpace
*underA
;
3387 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
3388 error(errSyntaxWarning
, -1, "Bad Pattern color space");
3392 if (arr
->getLength() == 2) {
3394 if (!(underA
= GfxColorSpace::parse(res
, &obj1
, out
, state
, recursion
+ 1))) {
3395 error(errSyntaxWarning
, -1, "Bad Pattern color space (underlying color space)");
3401 cs
= new GfxPatternColorSpace(underA
);
3405 void GfxPatternColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
3409 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
3410 rgb
->r
= rgb
->g
= rgb
->b
= 0;
3413 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
3414 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
3418 void GfxPatternColorSpace::getDeviceN(GfxColor
*color
, GfxColor
*deviceN
) {
3419 for (int i
= 0; i
< gfxColorMaxComps
; i
++)
3424 void GfxPatternColorSpace::getDefaultColor(GfxColor
*color
) {
3428 //------------------------------------------------------------------------
3430 //------------------------------------------------------------------------
3432 GfxPattern::GfxPattern(int typeA
) {
3436 GfxPattern::~GfxPattern() {
3439 GfxPattern
*GfxPattern::parse(GfxResources
*res
, Object
*obj
, OutputDev
*out
, GfxState
*state
) {
3440 GfxPattern
*pattern
;
3443 if (obj
->isDict()) {
3444 obj
->dictLookup("PatternType", &obj1
);
3445 } else if (obj
->isStream()) {
3446 obj
->streamGetDict()->lookup("PatternType", &obj1
);
3451 if (obj1
.isInt() && obj1
.getInt() == 1) {
3452 pattern
= GfxTilingPattern::parse(obj
);
3453 } else if (obj1
.isInt() && obj1
.getInt() == 2) {
3454 pattern
= GfxShadingPattern::parse(res
, obj
, out
, state
);
3460 //------------------------------------------------------------------------
3462 //------------------------------------------------------------------------
3464 GfxTilingPattern
*GfxTilingPattern::parse(Object
*patObj
) {
3465 GfxTilingPattern
*pat
;
3467 int paintTypeA
, tilingTypeA
;
3468 double bboxA
[4], matrixA
[6];
3469 double xStepA
, yStepA
;
3474 if (!patObj
->isStream()) {
3477 dict
= patObj
->streamGetDict();
3479 if (dict
->lookup("PaintType", &obj1
)->isInt()) {
3480 paintTypeA
= obj1
.getInt();
3483 error(errSyntaxWarning
, -1, "Invalid or missing PaintType in pattern");
3486 if (dict
->lookup("TilingType", &obj1
)->isInt()) {
3487 tilingTypeA
= obj1
.getInt();
3490 error(errSyntaxWarning
, -1, "Invalid or missing TilingType in pattern");
3493 bboxA
[0] = bboxA
[1] = 0;
3494 bboxA
[2] = bboxA
[3] = 1;
3495 if (dict
->lookup("BBox", &obj1
)->isArray() &&
3496 obj1
.arrayGetLength() == 4) {
3497 for (i
= 0; i
< 4; ++i
) {
3498 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
3499 bboxA
[i
] = obj2
.getNum();
3504 error(errSyntaxWarning
, -1, "Invalid or missing BBox in pattern");
3507 if (dict
->lookup("XStep", &obj1
)->isNum()) {
3508 xStepA
= obj1
.getNum();
3511 error(errSyntaxWarning
, -1, "Invalid or missing XStep in pattern");
3514 if (dict
->lookup("YStep", &obj1
)->isNum()) {
3515 yStepA
= obj1
.getNum();
3518 error(errSyntaxWarning
, -1, "Invalid or missing YStep in pattern");
3521 if (!dict
->lookup("Resources", &resDictA
)->isDict()) {
3523 resDictA
.initNull();
3524 error(errSyntaxWarning
, -1, "Invalid or missing Resources in pattern");
3526 matrixA
[0] = 1; matrixA
[1] = 0;
3527 matrixA
[2] = 0; matrixA
[3] = 1;
3528 matrixA
[4] = 0; matrixA
[5] = 0;
3529 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
3530 obj1
.arrayGetLength() == 6) {
3531 for (i
= 0; i
< 6; ++i
) {
3532 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
3533 matrixA
[i
] = obj2
.getNum();
3540 pat
= new GfxTilingPattern(paintTypeA
, tilingTypeA
, bboxA
, xStepA
, yStepA
,
3541 &resDictA
, matrixA
, patObj
);
3546 GfxTilingPattern::GfxTilingPattern(int paintTypeA
, int tilingTypeA
,
3547 double *bboxA
, double xStepA
, double yStepA
,
3548 Object
*resDictA
, double *matrixA
,
3549 Object
*contentStreamA
):
3554 paintType
= paintTypeA
;
3555 tilingType
= tilingTypeA
;
3556 for (i
= 0; i
< 4; ++i
) {
3561 resDictA
->copy(&resDict
);
3562 for (i
= 0; i
< 6; ++i
) {
3563 matrix
[i
] = matrixA
[i
];
3565 contentStreamA
->copy(&contentStream
);
3568 GfxTilingPattern::~GfxTilingPattern() {
3570 contentStream
.free();
3573 GfxPattern
*GfxTilingPattern::copy() {
3574 return new GfxTilingPattern(paintType
, tilingType
, bbox
, xStep
, yStep
,
3575 &resDict
, matrix
, &contentStream
);
3578 //------------------------------------------------------------------------
3579 // GfxShadingPattern
3580 //------------------------------------------------------------------------
3582 GfxShadingPattern
*GfxShadingPattern::parse(GfxResources
*res
, Object
*patObj
, OutputDev
*out
, GfxState
*state
) {
3584 GfxShading
*shadingA
;
3589 if (!patObj
->isDict()) {
3592 dict
= patObj
->getDict();
3594 dict
->lookup("Shading", &obj1
);
3595 shadingA
= GfxShading::parse(res
, &obj1
, out
, state
);
3601 matrixA
[0] = 1; matrixA
[1] = 0;
3602 matrixA
[2] = 0; matrixA
[3] = 1;
3603 matrixA
[4] = 0; matrixA
[5] = 0;
3604 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
3605 obj1
.arrayGetLength() == 6) {
3606 for (i
= 0; i
< 6; ++i
) {
3607 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
3608 matrixA
[i
] = obj2
.getNum();
3615 return new GfxShadingPattern(shadingA
, matrixA
);
3618 GfxShadingPattern::GfxShadingPattern(GfxShading
*shadingA
, double *matrixA
):
3624 for (i
= 0; i
< 6; ++i
) {
3625 matrix
[i
] = matrixA
[i
];
3629 GfxShadingPattern::~GfxShadingPattern() {
3633 GfxPattern
*GfxShadingPattern::copy() {
3634 return new GfxShadingPattern(shading
->copy(), matrix
);
3637 //------------------------------------------------------------------------
3639 //------------------------------------------------------------------------
3641 GfxShading::GfxShading(int typeA
) {
3646 GfxShading::GfxShading(GfxShading
*shading
) {
3649 type
= shading
->type
;
3650 colorSpace
= shading
->colorSpace
->copy();
3651 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3652 background
.c
[i
] = shading
->background
.c
[i
];
3654 hasBackground
= shading
->hasBackground
;
3655 xMin
= shading
->xMin
;
3656 yMin
= shading
->yMin
;
3657 xMax
= shading
->xMax
;
3658 yMax
= shading
->yMax
;
3659 hasBBox
= shading
->hasBBox
;
3662 GfxShading::~GfxShading() {
3668 GfxShading
*GfxShading::parse(GfxResources
*res
, Object
*obj
, OutputDev
*out
, GfxState
*state
) {
3669 GfxShading
*shading
;
3674 if (obj
->isDict()) {
3675 dict
= obj
->getDict();
3676 } else if (obj
->isStream()) {
3677 dict
= obj
->streamGetDict();
3682 if (!dict
->lookup("ShadingType", &obj1
)->isInt()) {
3683 error(errSyntaxWarning
, -1, "Invalid ShadingType in shading dictionary");
3687 typeA
= obj1
.getInt();
3692 shading
= GfxFunctionShading::parse(res
, dict
, out
, state
);
3695 shading
= GfxAxialShading::parse(res
, dict
, out
, state
);
3698 shading
= GfxRadialShading::parse(res
, dict
, out
, state
);
3701 if (obj
->isStream()) {
3702 shading
= GfxGouraudTriangleShading::parse(res
, 4, dict
, obj
->getStream(), out
, state
);
3704 error(errSyntaxWarning
, -1, "Invalid Type 4 shading object");
3709 if (obj
->isStream()) {
3710 shading
= GfxGouraudTriangleShading::parse(res
, 5, dict
, obj
->getStream(), out
, state
);
3712 error(errSyntaxWarning
, -1, "Invalid Type 5 shading object");
3717 if (obj
->isStream()) {
3718 shading
= GfxPatchMeshShading::parse(res
, 6, dict
, obj
->getStream(), out
, state
);
3720 error(errSyntaxWarning
, -1, "Invalid Type 6 shading object");
3725 if (obj
->isStream()) {
3726 shading
= GfxPatchMeshShading::parse(res
, 7, dict
, obj
->getStream(), out
, state
);
3728 error(errSyntaxWarning
, -1, "Invalid Type 7 shading object");
3733 error(errSyntaxWarning
, -1, "Unimplemented shading type {0:d}", typeA
);
3743 GBool
GfxShading::init(GfxResources
*res
, Dict
*dict
, OutputDev
*out
, GfxState
*state
) {
3747 dict
->lookup("ColorSpace", &obj1
);
3748 if (!(colorSpace
= GfxColorSpace::parse(res
, &obj1
, out
, state
))) {
3749 error(errSyntaxWarning
, -1, "Bad color space in shading dictionary");
3755 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3756 background
.c
[i
] = 0;
3758 hasBackground
= gFalse
;
3759 if (dict
->lookup("Background", &obj1
)->isArray()) {
3760 if (obj1
.arrayGetLength() == colorSpace
->getNComps()) {
3761 hasBackground
= gTrue
;
3762 for (i
= 0; i
< colorSpace
->getNComps(); ++i
) {
3763 background
.c
[i
] = dblToCol(obj1
.arrayGet(i
, &obj2
)->getNum());
3767 error(errSyntaxWarning
, -1, "Bad Background in shading dictionary");
3772 xMin
= yMin
= xMax
= yMax
= 0;
3774 if (dict
->lookup("BBox", &obj1
)->isArray()) {
3775 if (obj1
.arrayGetLength() == 4) {
3776 Object obj3
, obj4
, obj5
;
3777 obj1
.arrayGet(0, &obj2
);
3778 obj1
.arrayGet(1, &obj3
);
3779 obj1
.arrayGet(2, &obj4
);
3780 obj1
.arrayGet(3, &obj5
);
3781 if (obj2
.isNum() && obj3
.isNum() && obj4
.isNum() && obj5
.isNum())
3784 xMin
= obj2
.getNum();
3785 yMin
= obj3
.getNum();
3786 xMax
= obj4
.getNum();
3787 yMax
= obj5
.getNum();
3789 error(errSyntaxWarning
, -1, "Bad BBox in shading dictionary (Values not numbers)");
3796 error(errSyntaxWarning
, -1, "Bad BBox in shading dictionary");
3804 //------------------------------------------------------------------------
3805 // GfxFunctionShading
3806 //------------------------------------------------------------------------
3808 GfxFunctionShading::GfxFunctionShading(double x0A
, double y0A
,
3809 double x1A
, double y1A
,
3811 Function
**funcsA
, int nFuncsA
):
3820 for (i
= 0; i
< 6; ++i
) {
3821 matrix
[i
] = matrixA
[i
];
3824 for (i
= 0; i
< nFuncs
; ++i
) {
3825 funcs
[i
] = funcsA
[i
];
3829 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading
*shading
):
3838 for (i
= 0; i
< 6; ++i
) {
3839 matrix
[i
] = shading
->matrix
[i
];
3841 nFuncs
= shading
->nFuncs
;
3842 for (i
= 0; i
< nFuncs
; ++i
) {
3843 funcs
[i
] = shading
->funcs
[i
]->copy();
3847 GfxFunctionShading::~GfxFunctionShading() {
3850 for (i
= 0; i
< nFuncs
; ++i
) {
3855 GfxFunctionShading
*GfxFunctionShading::parse(GfxResources
*res
, Dict
*dict
, OutputDev
*out
, GfxState
*state
) {
3856 GfxFunctionShading
*shading
;
3857 double x0A
, y0A
, x1A
, y1A
;
3859 Function
*funcsA
[gfxColorMaxComps
];
3866 if (dict
->lookup("Domain", &obj1
)->isArray() &&
3867 obj1
.arrayGetLength() == 4) {
3868 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
3870 x1A
= obj1
.arrayGet(1, &obj2
)->getNum();
3872 y0A
= obj1
.arrayGet(2, &obj2
)->getNum();
3874 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
3879 matrixA
[0] = 1; matrixA
[1] = 0;
3880 matrixA
[2] = 0; matrixA
[3] = 1;
3881 matrixA
[4] = 0; matrixA
[5] = 0;
3882 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
3883 obj1
.arrayGetLength() == 6) {
3884 matrixA
[0] = obj1
.arrayGet(0, &obj2
)->getNum();
3886 matrixA
[1] = obj1
.arrayGet(1, &obj2
)->getNum();
3888 matrixA
[2] = obj1
.arrayGet(2, &obj2
)->getNum();
3890 matrixA
[3] = obj1
.arrayGet(3, &obj2
)->getNum();
3892 matrixA
[4] = obj1
.arrayGet(4, &obj2
)->getNum();
3894 matrixA
[5] = obj1
.arrayGet(5, &obj2
)->getNum();
3899 dict
->lookup("Function", &obj1
);
3900 if (obj1
.isArray()) {
3901 nFuncsA
= obj1
.arrayGetLength();
3902 if (nFuncsA
> gfxColorMaxComps
|| nFuncsA
<= 0) {
3903 error(errSyntaxWarning
, -1, "Invalid Function array in shading dictionary");
3906 for (i
= 0; i
< nFuncsA
; ++i
) {
3907 obj1
.arrayGet(i
, &obj2
);
3908 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
3915 if (!(funcsA
[0] = Function::parse(&obj1
))) {
3921 shading
= new GfxFunctionShading(x0A
, y0A
, x1A
, y1A
, matrixA
,
3923 if (!shading
->init(res
, dict
, out
, state
)) {
3936 GfxShading
*GfxFunctionShading::copy() {
3937 return new GfxFunctionShading(this);
3940 void GfxFunctionShading::getColor(double x
, double y
, GfxColor
*color
) {
3941 double in
[2], out
[gfxColorMaxComps
];
3944 // NB: there can be one function with n outputs or n functions with
3945 // one output each (where n = number of color components)
3946 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3951 for (i
= 0; i
< nFuncs
; ++i
) {
3952 funcs
[i
]->transform(in
, &out
[i
]);
3954 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3955 color
->c
[i
] = dblToCol(out
[i
]);
3959 //------------------------------------------------------------------------
3960 // GfxUnivariateShading
3961 //------------------------------------------------------------------------
3963 GfxUnivariateShading::GfxUnivariateShading(int typeA
,
3964 double t0A
, double t1A
,
3965 Function
**funcsA
, int nFuncsA
,
3966 GBool extend0A
, GBool extend1A
):
3974 for (i
= 0; i
< nFuncs
; ++i
) {
3975 funcs
[i
] = funcsA
[i
];
3987 GfxUnivariateShading::GfxUnivariateShading(GfxUnivariateShading
*shading
):
3994 nFuncs
= shading
->nFuncs
;
3995 for (i
= 0; i
< nFuncs
; ++i
) {
3996 funcs
[i
] = shading
->funcs
[i
]->copy();
3998 extend0
= shading
->extend0
;
3999 extend1
= shading
->extend1
;
4008 GfxUnivariateShading::~GfxUnivariateShading() {
4011 for (i
= 0; i
< nFuncs
; ++i
) {
4015 gfree (cacheBounds
);
4018 void GfxUnivariateShading::getColor(double t
, GfxColor
*color
) {
4019 double out
[gfxColorMaxComps
];
4022 // NB: there can be one function with n outputs or n functions with
4023 // one output each (where n = number of color components)
4024 nComps
= nFuncs
* funcs
[0]->getOutputSize();
4026 if (cacheSize
> 0) {
4027 double x
, ix
, *l
, *u
, *upper
;
4029 if (cacheBounds
[lastMatch
- 1] >= t
) {
4030 upper
= std::lower_bound (cacheBounds
, cacheBounds
+ lastMatch
- 1, t
);
4031 lastMatch
= upper
- cacheBounds
;
4032 lastMatch
= std::min
<int>(std::max
<int>(1, lastMatch
), cacheSize
- 1);
4033 } else if (cacheBounds
[lastMatch
] < t
) {
4034 upper
= std::lower_bound (cacheBounds
+ lastMatch
+ 1, cacheBounds
+ cacheSize
, t
);
4035 lastMatch
= upper
- cacheBounds
;
4036 lastMatch
= std::min
<int>(std::max
<int>(1, lastMatch
), cacheSize
- 1);
4039 x
= (t
- cacheBounds
[lastMatch
-1]) * cacheCoeff
[lastMatch
];
4041 u
= cacheValues
+ lastMatch
* nComps
;
4044 for (i
= 0; i
< nComps
; ++i
) {
4045 out
[i
] = ix
* l
[i
] + x
* u
[i
];
4048 for (i
= 0; i
< nComps
; ++i
) {
4051 for (i
= 0; i
< nFuncs
; ++i
) {
4052 if (funcs
[i
]->getInputSize() != 1) {
4053 error(errSyntaxWarning
, -1, "Invalid shading function (input != 1)");
4056 funcs
[i
]->transform(&t
, &out
[i
]);
4060 for (i
= 0; i
< nComps
; ++i
) {
4061 color
->c
[i
] = dblToCol(out
[i
]);
4065 void GfxUnivariateShading::setupCache(const Matrix
*ctm
,
4066 double xMin
, double yMin
,
4067 double xMax
, double yMax
) {
4068 double sMin
, sMax
, tMin
, tMax
, upperBound
;
4069 int i
, j
, nComps
, maxSize
;
4071 gfree (cacheBounds
);
4075 // NB: there can be one function with n outputs or n functions with
4076 // one output each (where n = number of color components)
4077 nComps
= nFuncs
* funcs
[0]->getOutputSize();
4079 getParameterRange(&sMin
, &sMax
, xMin
, yMin
, xMax
, yMax
);
4080 upperBound
= ctm
->norm() * getDistance(sMin
, sMax
);
4081 maxSize
= ceil(upperBound
);
4082 maxSize
= std::max
<int>(maxSize
, 2);
4087 ctm
->transform(xMin
, yMin
, &x
[0], &y
[0]);
4088 ctm
->transform(xMax
, yMin
, &x
[1], &y
[1]);
4089 ctm
->transform(xMin
, yMax
, &x
[2], &y
[2]);
4090 ctm
->transform(xMax
, yMax
, &x
[3], &y
[3]);
4094 for (i
= 1; i
< 4; i
++) {
4095 xMin
= std::min
<double>(xMin
, x
[i
]);
4096 yMin
= std::min
<double>(yMin
, y
[i
]);
4097 xMax
= std::max
<double>(xMax
, x
[i
]);
4098 yMax
= std::max
<double>(yMax
, y
[i
]);
4102 if (maxSize
> (xMax
-xMin
) * (yMax
-yMin
)) {
4107 tMin
= t0
+ sMin
* (t1
- t0
);
4108 tMax
= t0
+ sMax
* (t1
- t0
);
4110 tMin
= t0
+ sMax
* (t1
- t0
);
4111 tMax
= t0
+ sMin
* (t1
- t0
);
4114 cacheBounds
= (double *)gmallocn(maxSize
, sizeof(double) * (nComps
+ 2));
4115 cacheCoeff
= cacheBounds
+ maxSize
;
4116 cacheValues
= cacheCoeff
+ maxSize
;
4118 if (cacheSize
!= 0) {
4119 for (j
= 0; j
< cacheSize
; ++j
) {
4120 cacheCoeff
[j
] = 1 / (cacheBounds
[j
+1] - cacheBounds
[j
]);
4122 } else if (tMax
!= tMin
) {
4123 double step
= (tMax
- tMin
) / (maxSize
- 1);
4124 double coeff
= (maxSize
- 1) / (tMax
- tMin
);
4126 cacheSize
= maxSize
;
4128 for (j
= 0; j
< cacheSize
; ++j
) {
4129 cacheBounds
[j
] = tMin
+ j
* step
;
4130 cacheCoeff
[j
] = coeff
;
4132 for (i
= 0; i
< nComps
; ++i
) {
4133 cacheValues
[j
*nComps
+ i
] = 0;
4135 for (i
= 0; i
< nFuncs
; ++i
) {
4136 funcs
[i
]->transform(&cacheBounds
[j
], &cacheValues
[j
*nComps
+ i
]);
4145 //------------------------------------------------------------------------
4147 //------------------------------------------------------------------------
4149 GfxAxialShading::GfxAxialShading(double x0A
, double y0A
,
4150 double x1A
, double y1A
,
4151 double t0A
, double t1A
,
4152 Function
**funcsA
, int nFuncsA
,
4153 GBool extend0A
, GBool extend1A
):
4154 GfxUnivariateShading(2, t0A
, t1A
, funcsA
, nFuncsA
, extend0A
, extend1A
)
4162 GfxAxialShading::GfxAxialShading(GfxAxialShading
*shading
):
4163 GfxUnivariateShading(shading
)
4171 GfxAxialShading::~GfxAxialShading() {
4174 GfxAxialShading
*GfxAxialShading::parse(GfxResources
*res
, Dict
*dict
, OutputDev
*out
, GfxState
*state
) {
4175 GfxAxialShading
*shading
;
4176 double x0A
, y0A
, x1A
, y1A
;
4178 Function
*funcsA
[gfxColorMaxComps
];
4180 GBool extend0A
, extend1A
;
4184 x0A
= y0A
= x1A
= y1A
= 0;
4185 if (dict
->lookup("Coords", &obj1
)->isArray() &&
4186 obj1
.arrayGetLength() == 4) {
4187 Object obj3
, obj4
, obj5
;
4188 obj1
.arrayGet(0, &obj2
);
4189 obj1
.arrayGet(1, &obj3
);
4190 obj1
.arrayGet(2, &obj4
);
4191 obj1
.arrayGet(3, &obj5
);
4192 if (obj2
.isNum() && obj3
.isNum() && obj4
.isNum() && obj5
.isNum()) {
4193 x0A
= obj2
.getNum();
4194 y0A
= obj3
.getNum();
4195 x1A
= obj4
.getNum();
4196 y1A
= obj5
.getNum();
4203 error(errSyntaxWarning
, -1, "Missing or invalid Coords in shading dictionary");
4210 if (dict
->lookup("Domain", &obj1
)->isArray() &&
4211 obj1
.arrayGetLength() == 2) {
4213 obj1
.arrayGet(0, &obj2
);
4214 obj1
.arrayGet(1, &obj3
);
4215 if (obj2
.isNum() && obj3
.isNum()) {
4216 t0A
= obj2
.getNum();
4217 t1A
= obj3
.getNum();
4224 dict
->lookup("Function", &obj1
);
4225 if (obj1
.isArray()) {
4226 nFuncsA
= obj1
.arrayGetLength();
4227 if (nFuncsA
> gfxColorMaxComps
|| nFuncsA
== 0) {
4228 error(errSyntaxWarning
, -1, "Invalid Function array in shading dictionary");
4231 for (i
= 0; i
< nFuncsA
; ++i
) {
4232 obj1
.arrayGet(i
, &obj2
);
4233 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
4242 if (!(funcsA
[0] = Function::parse(&obj1
))) {
4249 extend0A
= extend1A
= gFalse
;
4250 if (dict
->lookup("Extend", &obj1
)->isArray() &&
4251 obj1
.arrayGetLength() == 2) {
4252 obj1
.arrayGet(0, &obj2
);
4253 if (obj2
.isBool()) {
4254 extend0A
= obj2
.getBool();
4256 error(errSyntaxWarning
, -1, "Invalid axial shading extend (0)");
4259 obj1
.arrayGet(1, &obj2
);
4260 if (obj2
.isBool()) {
4261 extend1A
= obj2
.getBool();
4263 error(errSyntaxWarning
, -1, "Invalid axial shading extend (1)");
4269 shading
= new GfxAxialShading(x0A
, y0A
, x1A
, y1A
, t0A
, t1A
,
4270 funcsA
, nFuncsA
, extend0A
, extend1A
);
4271 if (!shading
->init(res
, dict
, out
, state
)) {
4281 GfxShading
*GfxAxialShading::copy() {
4282 return new GfxAxialShading(this);
4285 double GfxAxialShading::getDistance(double sMin
, double sMax
) {
4286 double xMin
, yMin
, xMax
, yMax
;
4288 xMin
= x0
+ sMin
* (x1
- x0
);
4289 yMin
= y0
+ sMin
* (y1
- y0
);
4290 xMax
= x0
+ sMax
* (x1
- x0
);
4291 yMax
= y0
+ sMax
* (y1
- y0
);
4293 return hypot(xMax
-xMin
, yMax
-yMin
);
4296 void GfxAxialShading::getParameterRange(double *lower
, double *upper
,
4297 double xMin
, double yMin
,
4298 double xMax
, double yMax
) {
4299 double pdx
, pdy
, invsqnorm
, tdx
, tdy
, t
, range
[2];
4301 // Linear gradients are orthogonal to the line passing through their
4302 // extremes. Because of convexity, the parameter range can be
4303 // computed as the convex hull (one the real line) of the parameter
4304 // values of the 4 corners of the box.
4306 // The parameter value t for a point (x,y) can be computed as:
4308 // t = (p2 - p1) . (x,y) / |p2 - p1|^2
4310 // t0 is the t value for the top left corner
4311 // tdx is the difference between left and right corners
4312 // tdy is the difference between top and bottom corners
4316 invsqnorm
= 1.0 / (pdx
* pdx
+ pdy
* pdy
);
4320 t
= (xMin
- x0
) * pdx
+ (yMin
- y0
) * pdy
;
4321 tdx
= (xMax
- xMin
) * pdx
;
4322 tdy
= (yMax
- yMin
) * pdy
;
4324 // Because of the linearity of the t value, tdx can simply be added
4325 // the t0 to move along the top edge. After this, *lower and *upper
4326 // represent the parameter range for the top edge, so extending it
4327 // to include the whole box simply requires adding tdy to the
4330 range
[0] = range
[1] = t
;
4341 *lower
= std::max
<double>(0., std::min
<double>(1., range
[0]));
4342 *upper
= std::max
<double>(0., std::min
<double>(1., range
[1]));
4345 //------------------------------------------------------------------------
4347 //------------------------------------------------------------------------
4349 #ifndef RADIAL_EPSILON
4350 #define RADIAL_EPSILON (1. / 1024 / 1024)
4353 GfxRadialShading::GfxRadialShading(double x0A
, double y0A
, double r0A
,
4354 double x1A
, double y1A
, double r1A
,
4355 double t0A
, double t1A
,
4356 Function
**funcsA
, int nFuncsA
,
4357 GBool extend0A
, GBool extend1A
):
4358 GfxUnivariateShading(3, t0A
, t1A
, funcsA
, nFuncsA
, extend0A
, extend1A
)
4368 GfxRadialShading::GfxRadialShading(GfxRadialShading
*shading
):
4369 GfxUnivariateShading(shading
)
4379 GfxRadialShading::~GfxRadialShading() {
4382 GfxRadialShading
*GfxRadialShading::parse(GfxResources
*res
, Dict
*dict
, OutputDev
*out
, GfxState
*state
) {
4383 GfxRadialShading
*shading
;
4384 double x0A
, y0A
, r0A
, x1A
, y1A
, r1A
;
4386 Function
*funcsA
[gfxColorMaxComps
];
4388 GBool extend0A
, extend1A
;
4392 x0A
= y0A
= r0A
= x1A
= y1A
= r1A
= 0;
4393 if (dict
->lookup("Coords", &obj1
)->isArray() &&
4394 obj1
.arrayGetLength() == 6) {
4395 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
4397 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
4399 r0A
= obj1
.arrayGet(2, &obj2
)->getNum();
4401 x1A
= obj1
.arrayGet(3, &obj2
)->getNum();
4403 y1A
= obj1
.arrayGet(4, &obj2
)->getNum();
4405 r1A
= obj1
.arrayGet(5, &obj2
)->getNum();
4408 error(errSyntaxWarning
, -1, "Missing or invalid Coords in shading dictionary");
4415 if (dict
->lookup("Domain", &obj1
)->isArray() &&
4416 obj1
.arrayGetLength() == 2) {
4417 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
4419 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
4424 dict
->lookup("Function", &obj1
);
4425 if (obj1
.isArray()) {
4426 nFuncsA
= obj1
.arrayGetLength();
4427 if (nFuncsA
> gfxColorMaxComps
) {
4428 error(errSyntaxWarning
, -1, "Invalid Function array in shading dictionary");
4431 for (i
= 0; i
< nFuncsA
; ++i
) {
4432 obj1
.arrayGet(i
, &obj2
);
4433 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
4442 if (!(funcsA
[0] = Function::parse(&obj1
))) {
4449 extend0A
= extend1A
= gFalse
;
4450 if (dict
->lookup("Extend", &obj1
)->isArray() &&
4451 obj1
.arrayGetLength() == 2) {
4452 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
4454 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
4459 shading
= new GfxRadialShading(x0A
, y0A
, r0A
, x1A
, y1A
, r1A
, t0A
, t1A
,
4460 funcsA
, nFuncsA
, extend0A
, extend1A
);
4461 if (!shading
->init(res
, dict
, out
, state
)) {
4471 GfxShading
*GfxRadialShading::copy() {
4472 return new GfxRadialShading(this);
4475 double GfxRadialShading::getDistance(double sMin
, double sMax
) {
4476 double xMin
, yMin
, rMin
, xMax
, yMax
, rMax
;
4478 xMin
= x0
+ sMin
* (x1
- x0
);
4479 yMin
= y0
+ sMin
* (y1
- y0
);
4480 rMin
= r0
+ sMin
* (r1
- r0
);
4482 xMax
= x0
+ sMax
* (x1
- x0
);
4483 yMax
= y0
+ sMax
* (y1
- y0
);
4484 rMax
= r0
+ sMax
* (r1
- r0
);
4486 return hypot(xMax
-xMin
, yMax
-yMin
) + fabs(rMax
-rMin
);
4489 // extend range, adapted from cairo, radialExtendRange
4491 radialExtendRange (double range
[2], double value
, GBool valid
)
4494 range
[0] = range
[1] = value
;
4495 else if (value
< range
[0])
4497 else if (value
> range
[1])
4503 inline void radialEdge(double num
, double den
, double delta
, double lower
, double upper
,
4504 double dr
, double mindr
, GBool
&valid
, double *range
)
4506 if (fabs (den
) >= RADIAL_EPSILON
) {
4508 t_edge
= (num
) / (den
);
4509 v
= t_edge
* (delta
);
4510 if (t_edge
* dr
>= mindr
&& (lower
) <= v
&& v
<= (upper
))
4511 valid
= radialExtendRange (range
, t_edge
, valid
);
4515 inline void radialCorner1(double x
, double y
, double &b
, double dx
, double dy
, double cr
,
4516 double dr
, double mindr
, GBool
&valid
, double *range
)
4518 b
= (x
) * dx
+ (y
) * dy
+ cr
* dr
;
4519 if (fabs (b
) >= RADIAL_EPSILON
) {
4521 double x2
= (x
) * (x
);
4522 double y2
= (y
) * (y
);
4523 double cr2
= (cr
) * (cr
);
4524 double c
= x2
+ y2
- cr2
;
4526 t_corner
= 0.5 * c
/ b
;
4527 if (t_corner
* dr
>= mindr
)
4528 valid
= radialExtendRange (range
, t_corner
, valid
);
4532 inline void radialCorner2(double x
, double y
, double a
, double &b
, double &c
, double &d
, double dx
, double dy
, double cr
,
4533 double inva
, double dr
, double mindr
, GBool
&valid
, double *range
)
4535 b
= (x
) * dx
+ (y
) * dy
+ cr
* dr
;
4536 c
= (x
) * (x
) + (y
) * (y
) - cr
* cr
;
4542 t_corner
= (b
+ d
) * inva
;
4543 if (t_corner
* dr
>= mindr
)
4544 valid
= radialExtendRange (range
, t_corner
, valid
);
4545 t_corner
= (b
- d
) * inva
;
4546 if (t_corner
* dr
>= mindr
)
4547 valid
= radialExtendRange (range
, t_corner
, valid
);
4550 void GfxRadialShading::getParameterRange(double *lower
, double *upper
,
4551 double xMin
, double yMin
,
4552 double xMax
, double yMax
) {
4553 double cx
, cy
, cr
, dx
, dy
, dr
;
4554 double a
, x_focus
, y_focus
;
4555 double mindr
, minx
, miny
, maxx
, maxy
;
4559 // A radial pattern is considered degenerate if it can be
4560 // represented as a solid or clear pattern. This corresponds to one
4561 // of the two cases:
4563 // 1) The radii are both very small:
4564 // |dr| < FLT_EPSILON && min (r0, r1) < FLT_EPSILON
4566 // 2) The two circles have about the same radius and are very
4567 // close to each other (approximately a cylinder gradient that
4568 // doesn't move with the parameter):
4569 // |dr| < FLT_EPSILON && max (|dx|, |dy|) < 2 * FLT_EPSILON
4571 if (xMin
>= xMax
|| yMin
>=yMax
||
4572 (fabs (r0
- r1
) < RADIAL_EPSILON
&&
4573 (std::min
<double>(r0
, r1
) < RADIAL_EPSILON
||
4574 std::max
<double>(fabs (x0
- x1
), fabs (y0
- y1
)) < 2 * RADIAL_EPSILON
))) {
4575 *lower
= *upper
= 0;
4579 range
[0] = range
[1] = 0;
4582 x_focus
= y_focus
= 0; // silence gcc
4591 // translate by -(cx, cy) to simplify computations
4597 // enlarge boundaries slightly to avoid rounding problems in the
4598 // parameter range computation
4599 xMin
-= RADIAL_EPSILON
;
4600 yMin
-= RADIAL_EPSILON
;
4601 xMax
+= RADIAL_EPSILON
;
4602 yMax
+= RADIAL_EPSILON
;
4604 // enlarge boundaries even more to avoid rounding problems when
4605 // testing if a point belongs to the box
4606 minx
= xMin
- RADIAL_EPSILON
;
4607 miny
= yMin
- RADIAL_EPSILON
;
4608 maxx
= xMax
+ RADIAL_EPSILON
;
4609 maxy
= yMax
+ RADIAL_EPSILON
;
4611 // we dont' allow negative radiuses, so we will be checking that
4612 // t*dr >= mindr to consider t valid
4613 mindr
= -(cr
+ RADIAL_EPSILON
);
4615 // After the previous transformations, the start circle is centered
4616 // in the origin and has radius cr. A 1-unit change in the t
4617 // parameter corresponds to dx,dy,dr changes in the x,y,r of the
4618 // circle (center coordinates, radius).
4620 // To compute the minimum range needed to correctly draw the
4621 // pattern, we start with an empty range and extend it to include
4622 // the circles touching the bounding box or within it.
4624 // Focus, the point where the circle has radius == 0.
4626 // r = cr + t * dr = 0
4629 // If the radius is constant (dr == 0) there is no focus (the
4630 // gradient represents a cylinder instead of a cone).
4631 if (fabs (dr
) >= RADIAL_EPSILON
) {
4635 x_focus
= t_focus
* dx
;
4636 y_focus
= t_focus
* dy
;
4637 if (minx
<= x_focus
&& x_focus
<= maxx
&&
4638 miny
<= y_focus
&& y_focus
<= maxy
)
4640 valid
= radialExtendRange (range
, t_focus
, valid
);
4644 // Circles externally tangent to box edges.
4646 // All circles have center in (dx, dy) * t
4648 // If the circle is tangent to the line defined by the edge of the
4649 // box, then at least one of the following holds true:
4651 // (dx*t) + (cr + dr*t) == x0 (left edge)
4652 // (dx*t) - (cr + dr*t) == x1 (right edge)
4653 // (dy*t) + (cr + dr*t) == y0 (top edge)
4654 // (dy*t) - (cr + dr*t) == y1 (bottom edge)
4656 // The solution is only valid if the tangent point is actually on
4657 // the edge, i.e. if its y coordinate is in [y0,y1] for left/right
4658 // edges and if its x coordinate is in [x0,x1] for top/bottom edges.
4660 // For the first equation:
4662 // (dx + dr) * t = x0 - cr
4663 // t = (x0 - cr) / (dx + dr)
4666 // in the code this becomes:
4668 // t_edge = (num) / (den)
4669 // v = (delta) * t_edge
4671 // If the denominator in t is 0, the pattern is tangent to a line
4672 // parallel to the edge under examination. The corner-case where the
4673 // boundary line is the same as the edge is handled by the focus
4674 // point case and/or by the a==0 case.
4676 // circles tangent (externally) to left/right/top/bottom edge
4677 radialEdge(xMin
- cr
, dx
+ dr
, dy
, miny
, maxy
, dr
, mindr
, valid
, range
);
4678 radialEdge(xMax
+ cr
, dx
- dr
, dy
, miny
, maxy
, dr
, mindr
, valid
, range
);
4679 radialEdge(yMin
- cr
, dy
+ dr
, dx
, minx
, maxx
, dr
, mindr
, valid
, range
);
4680 radialEdge(yMax
+ cr
, dy
- dr
, dx
, minx
, maxx
, dr
, mindr
, valid
, range
);
4682 // Circles passing through a corner.
4684 // A circle passing through the point (x,y) satisfies:
4686 // (x-t*dx)^2 + (y-t*dy)^2 == (cr + t*dr)^2
4689 // a = dx^2 + dy^2 - dr^2
4690 // b = x*dx + y*dy + cr*dr
4691 // c = x^2 + y^2 - cr^2
4693 // a*t^2 - 2*b*t + c == 0
4695 a
= dx
* dx
+ dy
* dy
- dr
* dr
;
4696 if (fabs (a
) < RADIAL_EPSILON
* RADIAL_EPSILON
) {
4699 // Ensure that gradients with both a and dr small are
4700 // considered degenerate.
4701 // The floating point version of the degeneracy test implemented
4702 // in _radial_pattern_is_degenerate() is:
4704 // 1) The circles are practically the same size:
4705 // |dr| < RADIAL_EPSILON
4707 // 2a) The circles are both very small:
4708 // min (r0, r1) < RADIAL_EPSILON
4710 // 2b) The circles are very close to each other:
4711 // max (|dx|, |dy|) < 2 * RADIAL_EPSILON
4713 // Assuming that the gradient is not degenerate, we want to
4714 // show that |a| < RADIAL_EPSILON^2 implies |dr| >= RADIAL_EPSILON.
4716 // If the gradient is not degenerate yet it has |dr| <
4717 // RADIAL_EPSILON, (2b) is false, thus:
4719 // max (|dx|, |dy|) >= 2*RADIAL_EPSILON
4721 // 4*RADIAL_EPSILON^2 <= max (|dx|, |dy|)^2 <= dx^2 + dy^2
4723 // From the definition of a, we get:
4724 // a = dx^2 + dy^2 - dr^2 < RADIAL_EPSILON^2
4725 // dx^2 + dy^2 - RADIAL_EPSILON^2 < dr^2
4726 // 3*RADIAL_EPSILON^2 < dr^2
4728 // which is inconsistent with the hypotheses, thus |dr| <
4729 // RADIAL_EPSILON is false or the gradient is degenerate.
4731 assert (fabs (dr
) >= RADIAL_EPSILON
);
4733 // If a == 0, all the circles are tangent to a line in the
4734 // focus point. If this line is within the box extents, we
4735 // should add the circle with infinite radius, but this would
4736 // make the range unbounded. We will be limiting the range to
4737 // [0,1] anyway, so we simply add the biggest legitimate
4738 // circle (it happens for 0 or for 1).
4740 valid
= radialExtendRange (range
, 0, valid
);
4742 valid
= radialExtendRange (range
, 1, valid
);
4745 // Nondegenerate, nonlimit circles passing through the corners.
4747 // a == 0 && a*t^2 - 2*b*t + c == 0
4751 // The b == 0 case has just been handled, so we only have to
4752 // compute this if b != 0.
4754 // circles touching each corner
4755 radialCorner1(xMin
, yMin
, b
, dx
, dy
, cr
, dr
, mindr
, valid
, range
);
4756 radialCorner1(xMin
, yMax
, b
, dx
, dy
, cr
, dr
, mindr
, valid
, range
);
4757 radialCorner1(xMax
, yMin
, b
, dx
, dy
, cr
, dr
, mindr
, valid
, range
);
4758 radialCorner1(xMax
, yMax
, b
, dx
, dy
, cr
, dr
, mindr
, valid
, range
);
4760 double inva
, b
, c
, d
;
4764 // Nondegenerate, nonlimit circles passing through the corners.
4766 // a != 0 && a*t^2 - 2*b*t + c == 0
4768 // t = (b +- sqrt (b*b - a*c)) / a
4770 // If the argument of sqrt() is negative, then no circle
4771 // passes through the corner.
4773 // circles touching each corner
4774 radialCorner2(xMin
, yMin
, a
, b
, c
, d
, dx
, dy
, cr
, inva
, dr
, mindr
, valid
, range
);
4775 radialCorner2(xMin
, yMax
, a
, b
, c
, d
, dx
, dy
, cr
, inva
, dr
, mindr
, valid
, range
);
4776 radialCorner2(xMax
, yMin
, a
, b
, c
, d
, dx
, dy
, cr
, inva
, dr
, mindr
, valid
, range
);
4777 radialCorner2(xMax
, yMax
, a
, b
, c
, d
, dx
, dy
, cr
, inva
, dr
, mindr
, valid
, range
);
4780 *lower
= std::max
<double>(0., std::min
<double>(1., range
[0]));
4781 *upper
= std::max
<double>(0., std::min
<double>(1., range
[1]));
4784 //------------------------------------------------------------------------
4786 //------------------------------------------------------------------------
4788 class GfxShadingBitBuf
{
4791 GfxShadingBitBuf(Stream
*strA
);
4792 ~GfxShadingBitBuf();
4793 GBool
getBits(int n
, Guint
*val
);
4803 GfxShadingBitBuf::GfxShadingBitBuf(Stream
*strA
) {
4810 GfxShadingBitBuf::~GfxShadingBitBuf() {
4814 GBool
GfxShadingBitBuf::getBits(int n
, Guint
*val
) {
4818 x
= (bitBuf
>> (nBits
- n
)) & ((1 << n
) - 1);
4823 x
= bitBuf
& ((1 << nBits
) - 1);
4828 if ((bitBuf
= str
->getChar()) == EOF
) {
4833 x
= (x
<< 8) | bitBuf
;
4836 x
= (x
<< n
) | (bitBuf
>> (8 - n
));
4846 void GfxShadingBitBuf::flushBits() {
4851 //------------------------------------------------------------------------
4852 // GfxGouraudTriangleShading
4853 //------------------------------------------------------------------------
4855 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
4857 GfxGouraudVertex
*verticesA
, int nVerticesA
,
4858 int (*trianglesA
)[3], int nTrianglesA
,
4859 Function
**funcsA
, int nFuncsA
):
4864 vertices
= verticesA
;
4865 nVertices
= nVerticesA
;
4866 triangles
= trianglesA
;
4867 nTriangles
= nTrianglesA
;
4869 for (i
= 0; i
< nFuncs
; ++i
) {
4870 funcs
[i
] = funcsA
[i
];
4874 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
4875 GfxGouraudTriangleShading
*shading
):
4880 nVertices
= shading
->nVertices
;
4881 vertices
= (GfxGouraudVertex
*)gmallocn(nVertices
, sizeof(GfxGouraudVertex
));
4882 memcpy(vertices
, shading
->vertices
, nVertices
* sizeof(GfxGouraudVertex
));
4883 nTriangles
= shading
->nTriangles
;
4884 triangles
= (int (*)[3])gmallocn(nTriangles
* 3, sizeof(int));
4885 memcpy(triangles
, shading
->triangles
, nTriangles
* 3 * sizeof(int));
4886 nFuncs
= shading
->nFuncs
;
4887 for (i
= 0; i
< nFuncs
; ++i
) {
4888 funcs
[i
] = shading
->funcs
[i
]->copy();
4892 GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
4897 for (i
= 0; i
< nFuncs
; ++i
) {
4902 GfxGouraudTriangleShading
*GfxGouraudTriangleShading::parse(GfxResources
*res
, int typeA
,
4905 OutputDev
*out
, GfxState
*gfxState
) {
4906 GfxGouraudTriangleShading
*shading
;
4907 Function
*funcsA
[gfxColorMaxComps
];
4909 int coordBits
, compBits
, flagBits
, vertsPerRow
, nRows
;
4910 double xMin
, xMax
, yMin
, yMax
;
4911 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
4913 double cMul
[gfxColorMaxComps
];
4914 GfxGouraudVertex
*verticesA
;
4915 int (*trianglesA
)[3];
4916 int nComps
, nVerticesA
, nTrianglesA
, vertSize
, triSize
;
4918 Guint c
[gfxColorMaxComps
];
4919 GfxShadingBitBuf
*bitBuf
;
4923 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
4924 coordBits
= obj1
.getInt();
4926 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
4930 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
4931 compBits
= obj1
.getInt();
4933 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerComponent in shading dictionary");
4937 flagBits
= vertsPerRow
= 0; // make gcc happy
4939 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
4940 flagBits
= obj1
.getInt();
4942 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerFlag in shading dictionary");
4947 if (dict
->lookup("VerticesPerRow", &obj1
)->isInt()) {
4948 vertsPerRow
= obj1
.getInt();
4950 error(errSyntaxWarning
, -1, "Missing or invalid VerticesPerRow in shading dictionary");
4955 if (dict
->lookup("Decode", &obj1
)->isArray() &&
4956 obj1
.arrayGetLength() >= 6) {
4957 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
4959 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
4961 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
4962 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
4964 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
4966 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
4967 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
4968 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
4970 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
4972 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
4976 error(errSyntaxWarning
, -1, "Missing or invalid Decode array in shading dictionary");
4981 if (!dict
->lookup("Function", &obj1
)->isNull()) {
4982 if (obj1
.isArray()) {
4983 nFuncsA
= obj1
.arrayGetLength();
4984 if (nFuncsA
> gfxColorMaxComps
) {
4985 error(errSyntaxWarning
, -1, "Invalid Function array in shading dictionary");
4988 for (i
= 0; i
< nFuncsA
; ++i
) {
4989 obj1
.arrayGet(i
, &obj2
);
4990 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
4999 if (!(funcsA
[0] = Function::parse(&obj1
))) {
5009 nVerticesA
= nTrianglesA
= 0;
5012 vertSize
= triSize
= 0;
5014 flag
= 0; // make gcc happy
5015 bitBuf
= new GfxShadingBitBuf(str
);
5018 if (!bitBuf
->getBits(flagBits
, &flag
)) {
5022 if (!bitBuf
->getBits(coordBits
, &x
) ||
5023 !bitBuf
->getBits(coordBits
, &y
)) {
5026 for (i
= 0; i
< nComps
; ++i
) {
5027 if (!bitBuf
->getBits(compBits
, &c
[i
])) {
5034 if (nVerticesA
== vertSize
) {
5035 int oldVertSize
= vertSize
;
5036 vertSize
= (vertSize
== 0) ? 16 : 2 * vertSize
;
5037 verticesA
= (GfxGouraudVertex
*)
5038 greallocn(verticesA
, vertSize
, sizeof(GfxGouraudVertex
));
5039 memset(verticesA
+ oldVertSize
, 0, (vertSize
- oldVertSize
) * sizeof(GfxGouraudVertex
));
5041 verticesA
[nVerticesA
].x
= xMin
+ xMul
* (double)x
;
5042 verticesA
[nVerticesA
].y
= yMin
+ yMul
* (double)y
;
5043 for (i
= 0; i
< nComps
; ++i
) {
5044 verticesA
[nVerticesA
].color
.c
[i
] =
5045 dblToCol(cMin
[i
] + cMul
[i
] * (double)c
[i
]);
5048 bitBuf
->flushBits();
5050 if (state
== 0 || state
== 1) {
5052 } else if (state
== 2 || flag
> 0) {
5053 if (nTrianglesA
== triSize
) {
5054 triSize
= (triSize
== 0) ? 16 : 2 * triSize
;
5055 trianglesA
= (int (*)[3])
5056 greallocn(trianglesA
, triSize
* 3, sizeof(int));
5059 trianglesA
[nTrianglesA
][0] = nVerticesA
- 3;
5060 trianglesA
[nTrianglesA
][1] = nVerticesA
- 2;
5061 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
5063 } else if (flag
== 1) {
5064 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][1];
5065 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
5066 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
5067 } else { // flag == 2
5068 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][0];
5069 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
5070 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
5073 } else { // state == 3 && flag == 0
5079 if (typeA
== 5 && nVerticesA
> 0) {
5080 nRows
= nVerticesA
/ vertsPerRow
;
5081 nTrianglesA
= (nRows
- 1) * 2 * (vertsPerRow
- 1);
5082 trianglesA
= (int (*)[3])gmallocn(nTrianglesA
* 3, sizeof(int));
5084 for (i
= 0; i
< nRows
- 1; ++i
) {
5085 for (j
= 0; j
< vertsPerRow
- 1; ++j
) {
5086 trianglesA
[k
][0] = i
* vertsPerRow
+ j
;
5087 trianglesA
[k
][1] = i
* vertsPerRow
+ j
+1;
5088 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
;
5090 trianglesA
[k
][0] = i
* vertsPerRow
+ j
+1;
5091 trianglesA
[k
][1] = (i
+1) * vertsPerRow
+ j
;
5092 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
+1;
5098 shading
= new GfxGouraudTriangleShading(typeA
, verticesA
, nVerticesA
,
5099 trianglesA
, nTrianglesA
,
5101 if (!shading
->init(res
, dict
, out
, gfxState
)) {
5113 GfxShading
*GfxGouraudTriangleShading::copy() {
5114 return new GfxGouraudTriangleShading(this);
5117 void GfxGouraudTriangleShading::getTriangle(
5119 double *x0
, double *y0
, GfxColor
*color0
,
5120 double *x1
, double *y1
, GfxColor
*color1
,
5121 double *x2
, double *y2
, GfxColor
*color2
) {
5123 double out
[gfxColorMaxComps
];
5126 assert(!isParameterized());
5128 v
= triangles
[i
][0];
5129 *x0
= vertices
[v
].x
;
5130 *y0
= vertices
[v
].y
;
5132 in
= colToDbl(vertices
[v
].color
.c
[0]);
5133 for (j
= 0; j
< nFuncs
; ++j
) {
5134 funcs
[j
]->transform(&in
, &out
[j
]);
5136 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
5137 color0
->c
[j
] = dblToCol(out
[j
]);
5140 *color0
= vertices
[v
].color
;
5142 v
= triangles
[i
][1];
5143 *x1
= vertices
[v
].x
;
5144 *y1
= vertices
[v
].y
;
5146 in
= colToDbl(vertices
[v
].color
.c
[0]);
5147 for (j
= 0; j
< nFuncs
; ++j
) {
5148 funcs
[j
]->transform(&in
, &out
[j
]);
5150 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
5151 color1
->c
[j
] = dblToCol(out
[j
]);
5154 *color1
= vertices
[v
].color
;
5156 v
= triangles
[i
][2];
5157 *x2
= vertices
[v
].x
;
5158 *y2
= vertices
[v
].y
;
5160 in
= colToDbl(vertices
[v
].color
.c
[0]);
5161 for (j
= 0; j
< nFuncs
; ++j
) {
5162 funcs
[j
]->transform(&in
, &out
[j
]);
5164 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
5165 color2
->c
[j
] = dblToCol(out
[j
]);
5168 *color2
= vertices
[v
].color
;
5172 void GfxGouraudTriangleShading::getParameterizedColor(double t
, GfxColor
*color
) {
5173 double out
[gfxColorMaxComps
];
5175 for (int j
= 0; j
< nFuncs
; ++j
) {
5176 funcs
[j
]->transform(&t
, &out
[j
]);
5178 for (int j
= 0; j
< gfxColorMaxComps
; ++j
) {
5179 color
->c
[j
] = dblToCol(out
[j
]);
5183 void GfxGouraudTriangleShading::getTriangle(int i
,
5184 double *x0
, double *y0
, double *color0
,
5185 double *x1
, double *y1
, double *color1
,
5186 double *x2
, double *y2
, double *color2
) {
5189 assert(isParameterized());
5191 v
= triangles
[i
][0];
5192 if (likely(v
>= 0 && v
< nVertices
)) {
5193 *x0
= vertices
[v
].x
;
5194 *y0
= vertices
[v
].y
;
5195 *color0
= colToDbl(vertices
[v
].color
.c
[0]);
5197 v
= triangles
[i
][1];
5198 if (likely(v
>= 0 && v
< nVertices
)) {
5199 *x1
= vertices
[v
].x
;
5200 *y1
= vertices
[v
].y
;
5201 *color1
= colToDbl(vertices
[v
].color
.c
[0]);
5203 v
= triangles
[i
][2];
5204 if (likely(v
>= 0 && v
< nVertices
)) {
5205 *x2
= vertices
[v
].x
;
5206 *y2
= vertices
[v
].y
;
5207 *color2
= colToDbl(vertices
[v
].color
.c
[0]);
5211 //------------------------------------------------------------------------
5212 // GfxPatchMeshShading
5213 //------------------------------------------------------------------------
5215 GfxPatchMeshShading::GfxPatchMeshShading(int typeA
,
5216 GfxPatch
*patchesA
, int nPatchesA
,
5217 Function
**funcsA
, int nFuncsA
):
5223 nPatches
= nPatchesA
;
5225 for (i
= 0; i
< nFuncs
; ++i
) {
5226 funcs
[i
] = funcsA
[i
];
5230 GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading
*shading
):
5235 nPatches
= shading
->nPatches
;
5236 patches
= (GfxPatch
*)gmallocn(nPatches
, sizeof(GfxPatch
));
5237 memcpy(patches
, shading
->patches
, nPatches
* sizeof(GfxPatch
));
5238 nFuncs
= shading
->nFuncs
;
5239 for (i
= 0; i
< nFuncs
; ++i
) {
5240 funcs
[i
] = shading
->funcs
[i
]->copy();
5244 GfxPatchMeshShading::~GfxPatchMeshShading() {
5248 for (i
= 0; i
< nFuncs
; ++i
) {
5253 GfxPatchMeshShading
*GfxPatchMeshShading::parse(GfxResources
*res
, int typeA
, Dict
*dict
,
5254 Stream
*str
, OutputDev
*out
, GfxState
*state
) {
5255 GfxPatchMeshShading
*shading
;
5256 Function
*funcsA
[gfxColorMaxComps
];
5258 int coordBits
, compBits
, flagBits
;
5259 double xMin
, xMax
, yMin
, yMax
;
5260 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
5262 double cMul
[gfxColorMaxComps
];
5263 GfxPatch
*patchesA
, *p
;
5264 int nComps
, nPatchesA
, patchesSize
, nPts
, nColors
;
5266 double x
[16], y
[16];
5268 double c
[4][gfxColorMaxComps
];
5270 GfxShadingBitBuf
*bitBuf
;
5274 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
5275 coordBits
= obj1
.getInt();
5277 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerCoordinate in shading dictionary");
5281 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
5282 compBits
= obj1
.getInt();
5284 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerComponent in shading dictionary");
5288 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
5289 flagBits
= obj1
.getInt();
5291 error(errSyntaxWarning
, -1, "Missing or invalid BitsPerFlag in shading dictionary");
5295 if (dict
->lookup("Decode", &obj1
)->isArray() &&
5296 obj1
.arrayGetLength() >= 6) {
5297 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
5299 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
5301 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
5302 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
5304 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
5306 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
5307 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
5308 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
5310 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
5312 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
5316 error(errSyntaxWarning
, -1, "Missing or invalid Decode array in shading dictionary");
5321 if (!dict
->lookup("Function", &obj1
)->isNull()) {
5322 if (obj1
.isArray()) {
5323 nFuncsA
= obj1
.arrayGetLength();
5324 if (nFuncsA
> gfxColorMaxComps
) {
5325 error(errSyntaxWarning
, -1, "Invalid Function array in shading dictionary");
5328 for (i
= 0; i
< nFuncsA
; ++i
) {
5329 obj1
.arrayGet(i
, &obj2
);
5330 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
5339 if (!(funcsA
[0] = Function::parse(&obj1
))) {
5352 bitBuf
= new GfxShadingBitBuf(str
);
5354 if (!bitBuf
->getBits(flagBits
, &flag
)) {
5359 case 0: nPts
= 12; nColors
= 4; break;
5363 default: nPts
= 8; nColors
= 2; break;
5367 case 0: nPts
= 16; nColors
= 4; break;
5371 default: nPts
= 12; nColors
= 2; break;
5374 for (i
= 0; i
< nPts
; ++i
) {
5375 if (!bitBuf
->getBits(coordBits
, &xi
) ||
5376 !bitBuf
->getBits(coordBits
, &yi
)) {
5379 x
[i
] = xMin
+ xMul
* (double)xi
;
5380 y
[i
] = yMin
+ yMul
* (double)yi
;
5385 for (i
= 0; i
< nColors
; ++i
) {
5386 for (j
= 0; j
< nComps
; ++j
) {
5387 if (!bitBuf
->getBits(compBits
, &ci
)) {
5390 c
[i
][j
] = cMin
[j
] + cMul
[j
] * (double)ci
;
5391 if( nFuncsA
== 0 ) {
5392 // ... and colorspace values can also be stored into doubles.
5393 // They will be casted later.
5394 c
[i
][j
] = dblToCol(c
[i
][j
]);
5404 if (nPatchesA
== patchesSize
) {
5405 int oldPatchesSize
= patchesSize
;
5406 patchesSize
= (patchesSize
== 0) ? 16 : 2 * patchesSize
;
5407 patchesA
= (GfxPatch
*)greallocn(patchesA
,
5408 patchesSize
, sizeof(GfxPatch
));
5409 memset(patchesA
+ oldPatchesSize
, 0, (patchesSize
- oldPatchesSize
) * sizeof(GfxPatch
));
5411 p
= &patchesA
[nPatchesA
];
5439 for (j
= 0; j
< nComps
; ++j
) {
5440 p
->color
[0][0].c
[j
] = c
[0][j
];
5441 p
->color
[0][1].c
[j
] = c
[1][j
];
5442 p
->color
[1][1].c
[j
] = c
[2][j
];
5443 p
->color
[1][0].c
[j
] = c
[3][j
];
5447 if (nPatchesA
== 0) {
5450 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
5451 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
5452 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
5453 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
5454 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
5455 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
5456 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
5457 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
5474 for (j
= 0; j
< nComps
; ++j
) {
5475 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
5476 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
5477 p
->color
[1][1].c
[j
] = c
[0][j
];
5478 p
->color
[1][0].c
[j
] = c
[1][j
];
5482 if (nPatchesA
== 0) {
5485 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
5486 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
5487 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
5488 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
5489 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
5490 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
5491 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
5492 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
5509 for (j
= 0; j
< nComps
; ++j
) {
5510 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
5511 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
5512 p
->color
[1][1].c
[j
] = c
[0][j
];
5513 p
->color
[1][0].c
[j
] = c
[1][j
];
5517 if (nPatchesA
== 0) {
5520 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
5521 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
5522 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
5523 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
5524 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
5525 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
5526 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
5527 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
5544 for (j
= 0; j
< nComps
; ++j
) {
5545 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
5546 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
5547 p
->color
[1][1].c
[j
] = c
[0][j
];
5548 p
->color
[1][0].c
[j
] = c
[1][j
];
5587 for (j
= 0; j
< nComps
; ++j
) {
5588 p
->color
[0][0].c
[j
] = c
[0][j
];
5589 p
->color
[0][1].c
[j
] = c
[1][j
];
5590 p
->color
[1][1].c
[j
] = c
[2][j
];
5591 p
->color
[1][0].c
[j
] = c
[3][j
];
5595 if (nPatchesA
== 0) {
5598 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
5599 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
5600 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
5601 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
5602 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
5603 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
5604 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
5605 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
5630 for (j
= 0; j
< nComps
; ++j
) {
5631 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
5632 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
5633 p
->color
[1][1].c
[j
] = c
[0][j
];
5634 p
->color
[1][0].c
[j
] = c
[1][j
];
5638 if (nPatchesA
== 0) {
5641 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
5642 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
5643 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
5644 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
5645 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
5646 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
5647 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
5648 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
5673 for (j
= 0; j
< nComps
; ++j
) {
5674 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
5675 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
5676 p
->color
[1][1].c
[j
] = c
[0][j
];
5677 p
->color
[1][0].c
[j
] = c
[1][j
];
5681 if (nPatchesA
== 0) {
5684 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
5685 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
5686 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
5687 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
5688 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
5689 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
5690 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
5691 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
5716 for (j
= 0; j
< nComps
; ++j
) {
5717 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
5718 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
5719 p
->color
[1][1].c
[j
] = c
[0][j
];
5720 p
->color
[1][0].c
[j
] = c
[1][j
];
5726 bitBuf
->flushBits();
5731 for (i
= 0; i
< nPatchesA
; ++i
) {
5733 p
->x
[1][1] = (-4 * p
->x
[0][0]
5734 +6 * (p
->x
[0][1] + p
->x
[1][0])
5735 -2 * (p
->x
[0][3] + p
->x
[3][0])
5736 +3 * (p
->x
[3][1] + p
->x
[1][3])
5738 p
->y
[1][1] = (-4 * p
->y
[0][0]
5739 +6 * (p
->y
[0][1] + p
->y
[1][0])
5740 -2 * (p
->y
[0][3] + p
->y
[3][0])
5741 +3 * (p
->y
[3][1] + p
->y
[1][3])
5743 p
->x
[1][2] = (-4 * p
->x
[0][3]
5744 +6 * (p
->x
[0][2] + p
->x
[1][3])
5745 -2 * (p
->x
[0][0] + p
->x
[3][3])
5746 +3 * (p
->x
[3][2] + p
->x
[1][0])
5748 p
->y
[1][2] = (-4 * p
->y
[0][3]
5749 +6 * (p
->y
[0][2] + p
->y
[1][3])
5750 -2 * (p
->y
[0][0] + p
->y
[3][3])
5751 +3 * (p
->y
[3][2] + p
->y
[1][0])
5753 p
->x
[2][1] = (-4 * p
->x
[3][0]
5754 +6 * (p
->x
[3][1] + p
->x
[2][0])
5755 -2 * (p
->x
[3][3] + p
->x
[0][0])
5756 +3 * (p
->x
[0][1] + p
->x
[2][3])
5758 p
->y
[2][1] = (-4 * p
->y
[3][0]
5759 +6 * (p
->y
[3][1] + p
->y
[2][0])
5760 -2 * (p
->y
[3][3] + p
->y
[0][0])
5761 +3 * (p
->y
[0][1] + p
->y
[2][3])
5763 p
->x
[2][2] = (-4 * p
->x
[3][3]
5764 +6 * (p
->x
[3][2] + p
->x
[2][3])
5765 -2 * (p
->x
[3][0] + p
->x
[0][3])
5766 +3 * (p
->x
[0][2] + p
->x
[2][0])
5768 p
->y
[2][2] = (-4 * p
->y
[3][3]
5769 +6 * (p
->y
[3][2] + p
->y
[2][3])
5770 -2 * (p
->y
[3][0] + p
->y
[0][3])
5771 +3 * (p
->y
[0][2] + p
->y
[2][0])
5776 shading
= new GfxPatchMeshShading(typeA
, patchesA
, nPatchesA
,
5778 if (!shading
->init(res
, dict
, out
, state
)) {
5790 void GfxPatchMeshShading::getParameterizedColor(double t
, GfxColor
*color
) {
5791 double out
[gfxColorMaxComps
];
5793 for (int j
= 0; j
< nFuncs
; ++j
) {
5794 funcs
[j
]->transform(&t
, &out
[j
]);
5796 for (int j
= 0; j
< gfxColorMaxComps
; ++j
) {
5797 color
->c
[j
] = dblToCol(out
[j
]);
5801 GfxShading
*GfxPatchMeshShading::copy() {
5802 return new GfxPatchMeshShading(this);
5805 //------------------------------------------------------------------------
5807 //------------------------------------------------------------------------
5809 GfxImageColorMap::GfxImageColorMap(int bitsA
, Object
*decode
,
5810 GfxColorSpace
*colorSpaceA
) {
5811 GfxIndexedColorSpace
*indexedCS
;
5812 GfxSeparationColorSpace
*sepCS
;
5813 int maxPixel
, indexHigh
;
5814 Guchar
*indexedLookup
;
5817 double x
[gfxColorMaxComps
];
5818 double y
[gfxColorMaxComps
];
5821 GBool useByteLookup
;
5825 // bits per component and color space
5827 maxPixel
= (1 << bits
) - 1;
5828 colorSpace
= colorSpaceA
;
5830 // this is a hack to support 16 bits images, everywhere
5831 // we assume a component fits in 8 bits, with this hack
5832 // we treat 16 bit images as 8 bit ones until it's fixed correctly.
5833 // The hack has another part on ImageStream::getLine
5834 if (maxPixel
> 255) maxPixel
= 255;
5837 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
5844 if (decode
->isNull()) {
5845 nComps
= colorSpace
->getNComps();
5846 colorSpace
->getDefaultRanges(decodeLow
, decodeRange
, maxPixel
);
5847 } else if (decode
->isArray()) {
5848 nComps
= decode
->arrayGetLength() / 2;
5849 if (nComps
< colorSpace
->getNComps()) {
5852 if (nComps
> colorSpace
->getNComps()) {
5853 error(errSyntaxWarning
, -1, "Too many elements in Decode array");
5854 nComps
= colorSpace
->getNComps();
5856 for (i
= 0; i
< nComps
; ++i
) {
5857 decode
->arrayGet(2*i
, &obj
);
5861 decodeLow
[i
] = obj
.getNum();
5863 decode
->arrayGet(2*i
+1, &obj
);
5867 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
5874 // Construct a lookup table -- this stores pre-computed decoded
5875 // values for each component, i.e., the result of applying the
5876 // decode mapping to each possible image pixel component value.
5877 for (k
= 0; k
< nComps
; ++k
) {
5878 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
5879 sizeof(GfxColorComp
));
5880 for (i
= 0; i
<= maxPixel
; ++i
) {
5881 lookup
[k
][i
] = dblToCol(decodeLow
[k
] +
5882 (i
* decodeRange
[k
]) / maxPixel
);
5886 // Optimization: for Indexed and Separation color spaces (which have
5887 // only one component), we pre-compute a second lookup table with
5891 useByteLookup
= gFalse
;
5892 switch (colorSpace
->getMode()) {
5894 // Note that indexHigh may not be the same as maxPixel --
5895 // Distiller will remove unused palette entries, resulting in
5896 // indexHigh < maxPixel.
5897 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
5898 colorSpace2
= indexedCS
->getBase();
5899 indexHigh
= indexedCS
->getIndexHigh();
5900 nComps2
= colorSpace2
->getNComps();
5901 indexedLookup
= indexedCS
->getLookup();
5902 colorSpace2
->getDefaultRanges(x
, y
, indexHigh
);
5903 if (colorSpace2
->useGetGrayLine() || colorSpace2
->useGetRGBLine() || colorSpace2
->useGetCMYKLine() || colorSpace2
->useGetDeviceNLine()) {
5904 byte_lookup
= (Guchar
*)gmallocn ((maxPixel
+ 1), nComps2
);
5905 useByteLookup
= gTrue
;
5907 for (k
= 0; k
< nComps2
; ++k
) {
5908 lookup2
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
5909 sizeof(GfxColorComp
));
5910 for (i
= 0; i
<= maxPixel
; ++i
) {
5911 j
= (int)(decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
+ 0.5);
5914 } else if (j
> indexHigh
) {
5918 mapped
= x
[k
] + (indexedLookup
[j
*nComps2
+ k
] / 255.0) * y
[k
];
5919 lookup2
[k
][i
] = dblToCol(mapped
);
5921 byte_lookup
[i
* nComps2
+ k
] = (Guchar
) (mapped
* 255);
5926 sepCS
= (GfxSeparationColorSpace
*)colorSpace
;
5927 colorSpace2
= sepCS
->getAlt();
5928 nComps2
= colorSpace2
->getNComps();
5929 sepFunc
= sepCS
->getFunc();
5930 if (colorSpace2
->useGetGrayLine() || colorSpace2
->useGetRGBLine() || colorSpace2
->useGetCMYKLine() || colorSpace2
->useGetDeviceNLine()) {
5931 byte_lookup
= (Guchar
*)gmallocn ((maxPixel
+ 1), nComps2
);
5932 useByteLookup
= gTrue
;
5934 for (k
= 0; k
< nComps2
; ++k
) {
5935 lookup2
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
5936 sizeof(GfxColorComp
));
5937 for (i
= 0; i
<= maxPixel
; ++i
) {
5938 x
[0] = decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
;
5939 sepFunc
->transform(x
, y
);
5940 lookup2
[k
][i
] = dblToCol(y
[k
]);
5942 byte_lookup
[i
*nComps2
+ k
] = (Guchar
) (y
[k
] * 255);
5947 if (colorSpace
->useGetGrayLine() || colorSpace
->useGetRGBLine() || colorSpace
->useGetCMYKLine() || colorSpace
->useGetDeviceNLine()) {
5948 byte_lookup
= (Guchar
*)gmallocn ((maxPixel
+ 1), nComps
);
5949 useByteLookup
= gTrue
;
5951 for (k
= 0; k
< nComps
; ++k
) {
5952 lookup2
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
5953 sizeof(GfxColorComp
));
5954 for (i
= 0; i
<= maxPixel
; ++i
) {
5955 mapped
= decodeLow
[k
] + (i
* decodeRange
[k
]) / maxPixel
;
5956 lookup2
[k
][i
] = dblToCol(mapped
);
5957 if (useByteLookup
) {
5960 byte
= (int) (mapped
* 255.0 + 0.5);
5963 else if (byte
> 255)
5965 byte_lookup
[i
* nComps
+ k
] = byte
;
5979 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap
*colorMap
) {
5982 colorSpace
= colorMap
->colorSpace
->copy();
5983 bits
= colorMap
->bits
;
5984 nComps
= colorMap
->nComps
;
5985 nComps2
= colorMap
->nComps2
;
5987 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
5991 if (colorSpace
->getMode() == csIndexed
) {
5992 colorSpace2
= ((GfxIndexedColorSpace
*)colorSpace
)->getBase();
5993 for (k
= 0; k
< nComps2
; ++k
) {
5994 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
5995 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
5997 } else if (colorSpace
->getMode() == csSeparation
) {
5998 colorSpace2
= ((GfxSeparationColorSpace
*)colorSpace
)->getAlt();
5999 for (k
= 0; k
< nComps2
; ++k
) {
6000 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
6001 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
6004 for (k
= 0; k
< nComps
; ++k
) {
6005 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
6006 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
6009 if (colorMap
->byte_lookup
) {
6010 int nc
= colorSpace2
? nComps2
: nComps
;
6012 byte_lookup
= (Guchar
*)gmallocn (n
, nc
);
6013 memcpy(byte_lookup
, colorMap
->byte_lookup
, n
* nc
);
6015 for (i
= 0; i
< nComps
; ++i
) {
6016 decodeLow
[i
] = colorMap
->decodeLow
[i
];
6017 decodeRange
[i
] = colorMap
->decodeRange
[i
];
6022 GfxImageColorMap::~GfxImageColorMap() {
6026 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
6033 void GfxImageColorMap::getGray(Guchar
*x
, GfxGray
*gray
) {
6038 for (i
= 0; i
< nComps2
; ++i
) {
6039 color
.c
[i
] = lookup2
[i
][x
[0]];
6041 colorSpace2
->getGray(&color
, gray
);
6043 for (i
= 0; i
< nComps
; ++i
) {
6044 color
.c
[i
] = lookup2
[i
][x
[i
]];
6046 colorSpace
->getGray(&color
, gray
);
6050 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
6055 for (i
= 0; i
< nComps2
; ++i
) {
6056 color
.c
[i
] = lookup2
[i
][x
[0]];
6058 colorSpace2
->getRGB(&color
, rgb
);
6060 for (i
= 0; i
< nComps
; ++i
) {
6061 color
.c
[i
] = lookup2
[i
][x
[i
]];
6063 colorSpace
->getRGB(&color
, rgb
);
6067 void GfxImageColorMap::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
6069 Guchar
*inp
, *tmp_line
;
6071 if ((colorSpace2
&& !colorSpace2
->useGetGrayLine ()) ||
6072 (!colorSpace2
&& !colorSpace
->useGetGrayLine ())) {
6076 for (i
= 0; i
< length
; i
++) {
6077 getGray (inp
, &gray
);
6078 out
[i
] = colToByte(gray
);
6084 switch (colorSpace
->getMode()) {
6087 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6088 for (i
= 0; i
< length
; i
++) {
6089 for (j
= 0; j
< nComps2
; j
++) {
6090 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6093 colorSpace2
->getGrayLine(tmp_line
, out
, length
);
6099 for (j
= 0; j
< length
; j
++)
6100 for (i
= 0; i
< nComps
; i
++) {
6101 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6104 colorSpace
->getGrayLine(in
, out
, length
);
6110 void GfxImageColorMap::getRGBLine(Guchar
*in
, unsigned int *out
, int length
) {
6112 Guchar
*inp
, *tmp_line
;
6114 if (!useRGBLine()) {
6118 for (i
= 0; i
< length
; i
++) {
6121 ((int) colToByte(rgb
.r
) << 16) |
6122 ((int) colToByte(rgb
.g
) << 8) |
6123 ((int) colToByte(rgb
.b
) << 0);
6129 switch (colorSpace
->getMode()) {
6132 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6133 for (i
= 0; i
< length
; i
++) {
6134 for (j
= 0; j
< nComps2
; j
++) {
6135 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6138 colorSpace2
->getRGBLine(tmp_line
, out
, length
);
6144 for (j
= 0; j
< length
; j
++)
6145 for (i
= 0; i
< nComps
; i
++) {
6146 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6149 colorSpace
->getRGBLine(in
, out
, length
);
6155 void GfxImageColorMap::getRGBLine(Guchar
*in
, Guchar
*out
, int length
) {
6157 Guchar
*inp
, *tmp_line
;
6159 if (!useRGBLine()) {
6163 for (i
= 0; i
< length
; i
++) {
6165 *out
++ = colToByte(rgb
.r
);
6166 *out
++ = colToByte(rgb
.g
);
6167 *out
++ = colToByte(rgb
.b
);
6173 switch (colorSpace
->getMode()) {
6176 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6177 for (i
= 0; i
< length
; i
++) {
6178 for (j
= 0; j
< nComps2
; j
++) {
6179 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6182 colorSpace2
->getRGBLine(tmp_line
, out
, length
);
6188 for (j
= 0; j
< length
; j
++)
6189 for (i
= 0; i
< nComps
; i
++) {
6190 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6193 colorSpace
->getRGBLine(in
, out
, length
);
6199 void GfxImageColorMap::getRGBXLine(Guchar
*in
, Guchar
*out
, int length
) {
6201 Guchar
*inp
, *tmp_line
;
6203 if (!useRGBLine()) {
6207 for (i
= 0; i
< length
; i
++) {
6209 *out
++ = colToByte(rgb
.r
);
6210 *out
++ = colToByte(rgb
.g
);
6211 *out
++ = colToByte(rgb
.b
);
6218 switch (colorSpace
->getMode()) {
6221 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6222 for (i
= 0; i
< length
; i
++) {
6223 for (j
= 0; j
< nComps2
; j
++) {
6224 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6227 colorSpace2
->getRGBXLine(tmp_line
, out
, length
);
6233 for (j
= 0; j
< length
; j
++)
6234 for (i
= 0; i
< nComps
; i
++) {
6235 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6238 colorSpace
->getRGBXLine(in
, out
, length
);
6244 void GfxImageColorMap::getCMYKLine(Guchar
*in
, Guchar
*out
, int length
) {
6246 Guchar
*inp
, *tmp_line
;
6248 if (!useCMYKLine()) {
6252 for (i
= 0; i
< length
; i
++) {
6253 getCMYK (inp
, &cmyk
);
6254 *out
++ = colToByte(cmyk
.c
);
6255 *out
++ = colToByte(cmyk
.m
);
6256 *out
++ = colToByte(cmyk
.y
);
6257 *out
++ = colToByte(cmyk
.k
);
6263 switch (colorSpace
->getMode()) {
6266 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6267 for (i
= 0; i
< length
; i
++) {
6268 for (j
= 0; j
< nComps2
; j
++) {
6269 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6272 colorSpace2
->getCMYKLine(tmp_line
, out
, length
);
6278 for (j
= 0; j
< length
; j
++)
6279 for (i
= 0; i
< nComps
; i
++) {
6280 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6283 colorSpace
->getCMYKLine(in
, out
, length
);
6289 void GfxImageColorMap::getDeviceNLine(Guchar
*in
, Guchar
*out
, int length
) {
6291 Guchar
*inp
, *tmp_line
;
6293 if (!useDeviceNLine()) {
6297 for (i
= 0; i
< length
; i
++) {
6298 getDeviceN (inp
, &deviceN
);
6299 for (int j
= 0; j
< SPOT_NCOMPS
+4; j
++)
6300 *out
++ = deviceN
.c
[j
];
6306 switch (colorSpace
->getMode()) {
6309 tmp_line
= (Guchar
*) gmallocn (length
, nComps2
);
6310 for (i
= 0; i
< length
; i
++) {
6311 for (j
= 0; j
< nComps2
; j
++) {
6312 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
6315 colorSpace2
->getDeviceNLine(tmp_line
, out
, length
);
6321 for (j
= 0; j
< length
; j
++)
6322 for (i
= 0; i
< nComps
; i
++) {
6323 *inp
= byte_lookup
[*inp
* nComps
+ i
];
6326 colorSpace
->getDeviceNLine(in
, out
, length
);
6332 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
6337 for (i
= 0; i
< nComps2
; ++i
) {
6338 color
.c
[i
] = lookup2
[i
][x
[0]];
6340 colorSpace2
->getCMYK(&color
, cmyk
);
6342 for (i
= 0; i
< nComps
; ++i
) {
6343 color
.c
[i
] = lookup
[i
][x
[i
]];
6345 colorSpace
->getCMYK(&color
, cmyk
);
6349 void GfxImageColorMap::getDeviceN(Guchar
*x
, GfxColor
*deviceN
) {
6354 for (i
= 0; i
< nComps2
; ++i
) {
6355 color
.c
[i
] = lookup2
[i
][x
[0]];
6357 colorSpace2
->getDeviceN(&color
, deviceN
);
6359 for (i
= 0; i
< nComps
; ++i
) {
6360 color
.c
[i
] = lookup
[i
][x
[i
]];
6362 colorSpace
->getDeviceN(&color
, deviceN
);
6366 void GfxImageColorMap::getColor(Guchar
*x
, GfxColor
*color
) {
6369 maxPixel
= (1 << bits
) - 1;
6370 for (i
= 0; i
< nComps
; ++i
) {
6371 color
->c
[i
] = dblToCol(decodeLow
[i
] + (x
[i
] * decodeRange
[i
]) / maxPixel
);
6375 //------------------------------------------------------------------------
6376 // GfxSubpath and GfxPath
6377 //------------------------------------------------------------------------
6379 GfxSubpath::GfxSubpath(double x1
, double y1
) {
6381 x
= (double *)gmallocn(size
, sizeof(double));
6382 y
= (double *)gmallocn(size
, sizeof(double));
6383 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
6391 GfxSubpath::~GfxSubpath() {
6398 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
6399 size
= subpath
->size
;
6401 x
= (double *)gmallocn(size
, sizeof(double));
6402 y
= (double *)gmallocn(size
, sizeof(double));
6403 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
6404 memcpy(x
, subpath
->x
, n
* sizeof(double));
6405 memcpy(y
, subpath
->y
, n
* sizeof(double));
6406 memcpy(curve
, subpath
->curve
, n
* sizeof(GBool
));
6407 closed
= subpath
->closed
;
6410 void GfxSubpath::lineTo(double x1
, double y1
) {
6413 x
= (double *)greallocn(x
, size
, sizeof(double));
6414 y
= (double *)greallocn(y
, size
, sizeof(double));
6415 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
6423 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
6424 double x3
, double y3
) {
6427 x
= (double *)greallocn(x
, size
, sizeof(double));
6428 y
= (double *)greallocn(y
, size
, sizeof(double));
6429 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
6437 curve
[n
] = curve
[n
+1] = gTrue
;
6438 curve
[n
+2] = gFalse
;
6442 void GfxSubpath::close() {
6443 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
6449 void GfxSubpath::offset(double dx
, double dy
) {
6452 for (i
= 0; i
< n
; ++i
) {
6458 GfxPath::GfxPath() {
6462 firstX
= firstY
= 0;
6463 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
6466 GfxPath::~GfxPath() {
6469 for (i
= 0; i
< n
; ++i
)
6475 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
6476 GfxSubpath
**subpaths1
, int n1
, int size1
) {
6479 justMoved
= justMoved1
;
6484 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
6485 for (i
= 0; i
< n
; ++i
)
6486 subpaths
[i
] = subpaths1
[i
]->copy();
6489 void GfxPath::moveTo(double x
, double y
) {
6495 void GfxPath::lineTo(double x
, double y
) {
6496 if (justMoved
|| (n
> 0 && subpaths
[n
-1]->isClosed())) {
6499 subpaths
= (GfxSubpath
**)
6500 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
6503 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
6505 subpaths
[n
] = new GfxSubpath(subpaths
[n
-1]->getLastX(),
6506 subpaths
[n
-1]->getLastY());
6511 subpaths
[n
-1]->lineTo(x
, y
);
6514 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
6515 double x3
, double y3
) {
6516 if (justMoved
|| (n
> 0 && subpaths
[n
-1]->isClosed())) {
6519 subpaths
= (GfxSubpath
**)
6520 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
6523 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
6525 subpaths
[n
] = new GfxSubpath(subpaths
[n
-1]->getLastX(),
6526 subpaths
[n
-1]->getLastY());
6531 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
6534 void GfxPath::close() {
6535 // this is necessary to handle the pathological case of
6536 // moveto/closepath/clip, which defines an empty clipping region
6540 subpaths
= (GfxSubpath
**)
6541 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
6543 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
6547 subpaths
[n
-1]->close();
6550 void GfxPath::append(GfxPath
*path
) {
6553 if (n
+ path
->n
> size
) {
6555 subpaths
= (GfxSubpath
**)
6556 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
6558 for (i
= 0; i
< path
->n
; ++i
) {
6559 subpaths
[n
++] = path
->subpaths
[i
]->copy();
6564 void GfxPath::offset(double dx
, double dy
) {
6567 for (i
= 0; i
< n
; ++i
) {
6568 subpaths
[i
]->offset(dx
, dy
);
6572 //------------------------------------------------------------------------
6574 //------------------------------------------------------------------------
6575 GfxState::ReusablePathIterator::ReusablePathIterator(GfxPath
*path
)
6582 if( path
->getNumSubpaths() ) {
6583 curSubPath
= path
->getSubpath(subPathOff
);
6584 numCoords
= curSubPath
->getNumPoints();
6588 bool GfxState::ReusablePathIterator::isEnd() const {
6589 return coordOff
>= numCoords
;
6592 void GfxState::ReusablePathIterator::next() {
6594 if (coordOff
== numCoords
) {
6596 if (subPathOff
< path
->getNumSubpaths()) {
6598 curSubPath
= path
->getSubpath(subPathOff
);
6599 numCoords
= curSubPath
->getNumPoints();
6604 void GfxState::ReusablePathIterator::setCoord(double x
, double y
) {
6605 curSubPath
->setX(coordOff
, x
);
6606 curSubPath
->setY(coordOff
, y
);
6609 void GfxState::ReusablePathIterator::reset() {
6612 curSubPath
= path
->getSubpath(0);
6613 numCoords
= curSubPath
->getNumPoints();
6616 GfxState::GfxState(double hDPIA
, double vDPIA
, PDFRectangle
*pageBox
,
6617 int rotateA
, GBool upsideDown
) {
6631 ctm
[1] = upsideDown
? ky
: -ky
;
6635 ctm
[5] = ky
* (upsideDown
? -px1
: px2
);
6636 pageWidth
= kx
* (py2
- py1
);
6637 pageHeight
= ky
* (px2
- px1
);
6638 } else if (rotate
== 180) {
6642 ctm
[3] = upsideDown
? ky
: -ky
;
6644 ctm
[5] = ky
* (upsideDown
? -py1
: py2
);
6645 pageWidth
= kx
* (px2
- px1
);
6646 pageHeight
= ky
* (py2
- py1
);
6647 } else if (rotate
== 270) {
6649 ctm
[1] = upsideDown
? -ky
: ky
;
6653 ctm
[5] = ky
* (upsideDown
? px2
: -px1
);
6654 pageWidth
= kx
* (py2
- py1
);
6655 pageHeight
= ky
* (px2
- px1
);
6660 ctm
[3] = upsideDown
? -ky
: ky
;
6662 ctm
[5] = ky
* (upsideDown
? py2
: -py1
);
6663 pageWidth
= kx
* (px2
- px1
);
6664 pageHeight
= ky
* (py2
- py1
);
6667 fillColorSpace
= new GfxDeviceGrayColorSpace();
6668 strokeColorSpace
= new GfxDeviceGrayColorSpace();
6670 strokeColor
.c
[0] = 0;
6672 strokePattern
= NULL
;
6673 blendMode
= gfxBlendNormal
;
6676 fillOverprint
= gFalse
;
6677 strokeOverprint
= gFalse
;
6679 transfer
[0] = transfer
[1] = transfer
[2] = transfer
[3] = NULL
;
6689 strokeAdjust
= gFalse
;
6690 alphaIsShape
= gFalse
;
6691 textKnockout
= gFalse
;
6695 textMat
[0] = 1; textMat
[1] = 0;
6696 textMat
[2] = 0; textMat
[3] = 1;
6697 textMat
[4] = 0; textMat
[5] = 0;
6705 path
= new GfxPath();
6711 clipXMax
= pageWidth
;
6712 clipYMax
= pageHeight
;
6714 renderingIntent
[0] = 0;
6718 GfxColorSpace::setupColorProfiles();
6719 XYZ2DisplayTransformRelCol
= NULL
;
6720 XYZ2DisplayTransformAbsCol
= NULL
;
6721 XYZ2DisplayTransformSat
= NULL
;
6722 XYZ2DisplayTransformPerc
= NULL
;
6723 localDisplayProfile
= NULL
;
6724 displayProfileRef
= 0;
6728 GfxState::~GfxState() {
6731 if (fillColorSpace
) {
6732 delete fillColorSpace
;
6734 if (strokeColorSpace
) {
6735 delete strokeColorSpace
;
6740 if (strokePattern
) {
6741 delete strokePattern
;
6743 for (i
= 0; i
< 4; ++i
) {
6750 // this gets set to NULL by restore()
6757 if (XYZ2DisplayTransformRelCol
) {
6758 if (XYZ2DisplayTransformRelCol
->unref() == 0)
6759 delete XYZ2DisplayTransformRelCol
;
6761 if (XYZ2DisplayTransformAbsCol
) {
6762 if (XYZ2DisplayTransformAbsCol
->unref() == 0)
6763 delete XYZ2DisplayTransformAbsCol
;
6765 if (XYZ2DisplayTransformSat
) {
6766 if (XYZ2DisplayTransformSat
->unref() == 0)
6767 delete XYZ2DisplayTransformSat
;
6769 if (XYZ2DisplayTransformPerc
) {
6770 if (XYZ2DisplayTransformPerc
->unref() == 0)
6771 delete XYZ2DisplayTransformPerc
;
6773 if (--displayProfileRef
== 0 && localDisplayProfile
!= NULL
) {
6774 cmsCloseProfile(localDisplayProfile
);
6780 GfxState::GfxState(GfxState
*state
, GBool copyPath
) {
6783 memcpy(this, state
, sizeof(GfxState
));
6784 if (fillColorSpace
) {
6785 fillColorSpace
= state
->fillColorSpace
->copy();
6787 if (strokeColorSpace
) {
6788 strokeColorSpace
= state
->strokeColorSpace
->copy();
6791 fillPattern
= state
->fillPattern
->copy();
6793 if (strokePattern
) {
6794 strokePattern
= state
->strokePattern
->copy();
6796 for (i
= 0; i
< 4; ++i
) {
6798 transfer
[i
] = state
->transfer
[i
]->copy();
6801 if (lineDashLength
> 0) {
6802 lineDash
= (double *)gmallocn(lineDashLength
, sizeof(double));
6803 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
6809 path
= state
->path
->copy();
6813 if (XYZ2DisplayTransformRelCol
) {
6814 XYZ2DisplayTransformRelCol
->ref();
6816 if (XYZ2DisplayTransformAbsCol
) {
6817 XYZ2DisplayTransformAbsCol
->ref();
6819 if (XYZ2DisplayTransformSat
) {
6820 XYZ2DisplayTransformSat
->ref();
6822 if (XYZ2DisplayTransformPerc
) {
6823 XYZ2DisplayTransformPerc
->ref();
6825 if (localDisplayProfile
) {
6826 displayProfileRef
++;
6832 void GfxState::setDisplayProfile(cmsHPROFILE localDisplayProfileA
) {
6833 if (localDisplayProfile
!= NULL
) {
6834 cmsCloseProfile(localDisplayProfile
);
6836 localDisplayProfile
= localDisplayProfileA
;
6837 if (localDisplayProfileA
!= NULL
) {
6838 cmsHTRANSFORM transform
;
6839 unsigned int nChannels
;
6840 unsigned int localDisplayPixelType
;
6842 localDisplayPixelType
= getCMSColorSpaceType(cmsGetColorSpace(localDisplayProfile
));
6843 nChannels
= getCMSNChannels(cmsGetColorSpace(localDisplayProfile
));
6844 displayProfileRef
= 1;
6845 // create transform from XYZ
6846 cmsHPROFILE XYZProfile
= cmsCreateXYZProfile();
6847 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
6848 localDisplayProfile
,
6849 COLORSPACE_SH(localDisplayPixelType
) |
6850 CHANNELS_SH(nChannels
) | BYTES_SH(1),
6851 INTENT_RELATIVE_COLORIMETRIC
,LCMS_FLAGS
)) == 0) {
6852 error(errSyntaxWarning
, -1, "Can't create Lab transform");
6854 XYZ2DisplayTransformRelCol
= new GfxColorTransform(transform
, INTENT_RELATIVE_COLORIMETRIC
, PT_XYZ
, localDisplayPixelType
);
6856 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
6857 localDisplayProfile
,
6858 COLORSPACE_SH(localDisplayPixelType
) |
6859 CHANNELS_SH(nChannels
) | BYTES_SH(1),
6860 INTENT_ABSOLUTE_COLORIMETRIC
,LCMS_FLAGS
)) == 0) {
6861 error(errSyntaxWarning
, -1, "Can't create Lab transform");
6863 XYZ2DisplayTransformAbsCol
= new GfxColorTransform(transform
, INTENT_ABSOLUTE_COLORIMETRIC
, PT_XYZ
, localDisplayPixelType
);
6865 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
6866 localDisplayProfile
,
6867 COLORSPACE_SH(localDisplayPixelType
) |
6868 CHANNELS_SH(nChannels
) | BYTES_SH(1),
6869 INTENT_SATURATION
,LCMS_FLAGS
)) == 0) {
6870 error(errSyntaxWarning
, -1, "Can't create Lab transform");
6872 XYZ2DisplayTransformSat
= new GfxColorTransform(transform
, INTENT_SATURATION
, PT_XYZ
, localDisplayPixelType
);
6874 if ((transform
= cmsCreateTransform(XYZProfile
, TYPE_XYZ_DBL
,
6875 localDisplayProfile
,
6876 COLORSPACE_SH(localDisplayPixelType
) |
6877 CHANNELS_SH(nChannels
) | BYTES_SH(1),
6878 INTENT_PERCEPTUAL
,LCMS_FLAGS
)) == 0) {
6879 error(errSyntaxWarning
, -1, "Can't create Lab transform");
6881 XYZ2DisplayTransformPerc
= new GfxColorTransform(transform
, INTENT_PERCEPTUAL
, PT_XYZ
, localDisplayPixelType
);
6883 cmsCloseProfile(XYZProfile
);
6887 GfxColorTransform
*GfxState::getXYZ2DisplayTransform() {
6888 GfxColorTransform
*transform
;
6890 transform
= XYZ2DisplayTransformRelCol
;
6891 if (strcmp(renderingIntent
, "AbsoluteColorimetric") == 0) {
6892 transform
= XYZ2DisplayTransformAbsCol
;
6893 } else if (strcmp(renderingIntent
, "Saturation") == 0) {
6894 transform
= XYZ2DisplayTransformSat
;
6895 } else if (strcmp(renderingIntent
, "Perceptual") == 0) {
6896 transform
= XYZ2DisplayTransformPerc
;
6898 if (transform
== NULL
) {
6899 transform
= XYZ2DisplayTransform
;
6906 void GfxState::setPath(GfxPath
*pathA
) {
6911 void GfxState::getUserClipBBox(double *xMin
, double *yMin
,
6912 double *xMax
, double *yMax
) {
6914 double xMin1
, yMin1
, xMax1
, yMax1
, det
, tx
, ty
;
6917 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
6918 ictm
[0] = ctm
[3] * det
;
6919 ictm
[1] = -ctm
[1] * det
;
6920 ictm
[2] = -ctm
[2] * det
;
6921 ictm
[3] = ctm
[0] * det
;
6922 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
6923 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
6925 // transform all four corners of the clip bbox; find the min and max
6927 xMin1
= xMax1
= clipXMin
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
6928 yMin1
= yMax1
= clipXMin
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
6929 tx
= clipXMin
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
6930 ty
= clipXMin
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
6933 } else if (tx
> xMax1
) {
6938 } else if (ty
> yMax1
) {
6941 tx
= clipXMax
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
6942 ty
= clipXMax
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
6945 } else if (tx
> xMax1
) {
6950 } else if (ty
> yMax1
) {
6953 tx
= clipXMax
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
6954 ty
= clipXMax
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
6957 } else if (tx
> xMax1
) {
6962 } else if (ty
> yMax1
) {
6972 double GfxState::transformWidth(double w
) {
6975 x
= ctm
[0] + ctm
[2];
6976 y
= ctm
[1] + ctm
[3];
6977 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
6980 double GfxState::getTransformedFontSize() {
6981 double x1
, y1
, x2
, y2
;
6983 x1
= textMat
[2] * fontSize
;
6984 y1
= textMat
[3] * fontSize
;
6985 x2
= ctm
[0] * x1
+ ctm
[2] * y1
;
6986 y2
= ctm
[1] * x1
+ ctm
[3] * y1
;
6987 return sqrt(x2
* x2
+ y2
* y2
);
6990 void GfxState::getFontTransMat(double *m11
, double *m12
,
6991 double *m21
, double *m22
) {
6992 *m11
= (textMat
[0] * ctm
[0] + textMat
[1] * ctm
[2]) * fontSize
;
6993 *m12
= (textMat
[0] * ctm
[1] + textMat
[1] * ctm
[3]) * fontSize
;
6994 *m21
= (textMat
[2] * ctm
[0] + textMat
[3] * ctm
[2]) * fontSize
;
6995 *m22
= (textMat
[2] * ctm
[1] + textMat
[3] * ctm
[3]) * fontSize
;
6998 void GfxState::setCTM(double a
, double b
, double c
,
6999 double d
, double e
, double f
) {
7008 void GfxState::concatCTM(double a
, double b
, double c
,
7009 double d
, double e
, double f
) {
7015 ctm
[0] = a
* a1
+ b
* c1
;
7016 ctm
[1] = a
* b1
+ b
* d1
;
7017 ctm
[2] = c
* a1
+ d
* c1
;
7018 ctm
[3] = c
* b1
+ d
* d1
;
7019 ctm
[4] = e
* a1
+ f
* c1
+ ctm
[4];
7020 ctm
[5] = e
* b1
+ f
* d1
+ ctm
[5];
7023 void GfxState::shiftCTMAndClip(double tx
, double ty
) {
7032 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
7033 if (fillColorSpace
) {
7034 delete fillColorSpace
;
7036 fillColorSpace
= colorSpace
;
7039 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
7040 if (strokeColorSpace
) {
7041 delete strokeColorSpace
;
7043 strokeColorSpace
= colorSpace
;
7046 void GfxState::setFillPattern(GfxPattern
*pattern
) {
7050 fillPattern
= pattern
;
7053 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
7054 if (strokePattern
) {
7055 delete strokePattern
;
7057 strokePattern
= pattern
;
7060 void GfxState::setFont(GfxFont
*fontA
, double fontSizeA
) {
7065 fontSize
= fontSizeA
;
7068 void GfxState::setTransfer(Function
**funcs
) {
7071 for (i
= 0; i
< 4; ++i
) {
7075 transfer
[i
] = funcs
[i
];
7079 void GfxState::setLineDash(double *dash
, int length
, double start
) {
7083 lineDashLength
= length
;
7084 lineDashStart
= start
;
7087 void GfxState::clearPath() {
7089 path
= new GfxPath();
7092 void GfxState::clip() {
7093 double xMin
, yMin
, xMax
, yMax
, x
, y
;
7094 GfxSubpath
*subpath
;
7097 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
7098 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
7099 subpath
= path
->getSubpath(i
);
7100 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
7101 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
7102 if (i
== 0 && j
== 0) {
7108 } else if (x
> xMax
) {
7113 } else if (y
> yMax
) {
7119 if (xMin
> clipXMin
) {
7122 if (yMin
> clipYMin
) {
7125 if (xMax
< clipXMax
) {
7128 if (yMax
< clipYMax
) {
7133 void GfxState::clipToStrokePath() {
7134 double xMin
, yMin
, xMax
, yMax
, x
, y
, t0
, t1
;
7135 GfxSubpath
*subpath
;
7138 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
7139 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
7140 subpath
= path
->getSubpath(i
);
7141 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
7142 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
7143 if (i
== 0 && j
== 0) {
7149 } else if (x
> xMax
) {
7154 } else if (y
> yMax
) {
7161 // allow for the line width
7162 //~ miter joins can extend farther than this
7166 xMin
-= 0.5 * lineWidth
* t0
;
7167 xMax
+= 0.5 * lineWidth
* t0
;
7169 xMin
-= 0.5 * lineWidth
* t1
;
7170 xMax
+= 0.5 * lineWidth
* t1
;
7175 yMin
-= 0.5 * lineWidth
* t0
;
7176 yMax
+= 0.5 * lineWidth
* t0
;
7178 yMin
-= 0.5 * lineWidth
* t1
;
7179 yMax
+= 0.5 * lineWidth
* t1
;
7182 if (xMin
> clipXMin
) {
7185 if (yMin
> clipYMin
) {
7188 if (xMax
< clipXMax
) {
7191 if (yMax
< clipYMax
) {
7196 void GfxState::clipToRect(double xMin
, double yMin
, double xMax
, double yMax
) {
7197 double x
, y
, xMin1
, yMin1
, xMax1
, yMax1
;
7199 transform(xMin
, yMin
, &x
, &y
);
7202 transform(xMax
, yMin
, &x
, &y
);
7205 } else if (x
> xMax1
) {
7210 } else if (y
> yMax1
) {
7213 transform(xMax
, yMax
, &x
, &y
);
7216 } else if (x
> xMax1
) {
7221 } else if (y
> yMax1
) {
7224 transform(xMin
, yMax
, &x
, &y
);
7227 } else if (x
> xMax1
) {
7232 } else if (y
> yMax1
) {
7236 if (xMin1
> clipXMin
) {
7239 if (yMin1
> clipYMin
) {
7242 if (xMax1
< clipXMax
) {
7245 if (yMax1
< clipYMax
) {
7250 void GfxState::textShift(double tx
, double ty
) {
7253 textTransformDelta(tx
, ty
, &dx
, &dy
);
7258 void GfxState::shift(double dx
, double dy
) {
7263 GfxState
*GfxState::save() {
7267 newState
->saved
= this;
7271 GfxState
*GfxState::restore() {
7277 // these attributes aren't saved/restored by the q/Q operators
7278 oldState
->path
= path
;
7279 oldState
->curX
= curX
;
7280 oldState
->curY
= curY
;
7281 oldState
->lineX
= lineX
;
7282 oldState
->lineY
= lineY
;
7295 GBool
GfxState::parseBlendMode(Object
*obj
, GfxBlendMode
*mode
) {
7299 if (obj
->isName()) {
7300 for (i
= 0; i
< nGfxBlendModeNames
; ++i
) {
7301 if (!strcmp(obj
->getName(), gfxBlendModeNames
[i
].name
)) {
7302 *mode
= gfxBlendModeNames
[i
].mode
;
7307 } else if (obj
->isArray()) {
7308 for (i
= 0; i
< obj
->arrayGetLength(); ++i
) {
7309 obj
->arrayGet(i
, &obj2
);
7310 if (!obj2
.isName()) {
7314 for (j
= 0; j
< nGfxBlendModeNames
; ++j
) {
7315 if (!strcmp(obj2
.getName(), gfxBlendModeNames
[j
].name
)) {
7317 *mode
= gfxBlendModeNames
[j
].mode
;
7323 *mode
= gfxBlendNormal
;