1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
17 #include <string.h> // for memcpy()
25 //------------------------------------------------------------------------
27 static inline double clip01(double x
) {
28 return (x
< 0) ? 0 : ((x
> 1) ? 1 : x
);
31 //------------------------------------------------------------------------
33 static char *gfxColorSpaceModeNames
[] = {
47 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
49 //------------------------------------------------------------------------
51 //------------------------------------------------------------------------
53 GfxColorSpace::GfxColorSpace() {
56 GfxColorSpace::~GfxColorSpace() {
59 GfxColorSpace
*GfxColorSpace::parse(Object
*csObj
) {
64 if (csObj
->isName()) {
65 if (csObj
->isName("DeviceGray") || csObj
->isName("G")) {
66 cs
= new GfxDeviceGrayColorSpace();
67 } else if (csObj
->isName("DeviceRGB") || csObj
->isName("RGB")) {
68 cs
= new GfxDeviceRGBColorSpace();
69 } else if (csObj
->isName("DeviceCMYK") || csObj
->isName("CMYK")) {
70 cs
= new GfxDeviceCMYKColorSpace();
71 } else if (csObj
->isName("Pattern")) {
72 cs
= new GfxPatternColorSpace(NULL
);
74 error(-1, "Bad color space '%s'", csObj
->getName());
76 } else if (csObj
->isArray()) {
77 csObj
->arrayGet(0, &obj1
);
78 if (obj1
.isName("DeviceGray") || obj1
.isName("G")) {
79 cs
= new GfxDeviceGrayColorSpace();
80 } else if (obj1
.isName("DeviceRGB") || obj1
.isName("RGB")) {
81 cs
= new GfxDeviceRGBColorSpace();
82 } else if (obj1
.isName("DeviceCMYK") || obj1
.isName("CMYK")) {
83 cs
= new GfxDeviceCMYKColorSpace();
84 } else if (obj1
.isName("CalGray")) {
85 cs
= GfxCalGrayColorSpace::parse(csObj
->getArray());
86 } else if (obj1
.isName("CalRGB")) {
87 cs
= GfxCalRGBColorSpace::parse(csObj
->getArray());
88 } else if (obj1
.isName("Lab")) {
89 cs
= GfxLabColorSpace::parse(csObj
->getArray());
90 } else if (obj1
.isName("ICCBased")) {
91 cs
= GfxICCBasedColorSpace::parse(csObj
->getArray());
92 } else if (obj1
.isName("Indexed") || obj1
.isName("I")) {
93 cs
= GfxIndexedColorSpace::parse(csObj
->getArray());
94 } else if (obj1
.isName("Separation")) {
95 cs
= GfxSeparationColorSpace::parse(csObj
->getArray());
96 } else if (obj1
.isName("DeviceN")) {
97 cs
= GfxDeviceNColorSpace::parse(csObj
->getArray());
98 } else if (obj1
.isName("Pattern")) {
99 cs
= GfxPatternColorSpace::parse(csObj
->getArray());
101 error(-1, "Bad color space");
105 error(-1, "Bad color space - expected name or array");
110 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
114 for (i
= 0; i
< getNComps(); ++i
) {
120 int GfxColorSpace::getNumColorSpaceModes() {
121 return nGfxColorSpaceModes
;
124 char *GfxColorSpace::getColorSpaceModeName(int idx
) {
125 return gfxColorSpaceModeNames
[idx
];
128 //------------------------------------------------------------------------
129 // GfxDeviceGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
135 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
138 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
139 return new GfxDeviceGrayColorSpace();
142 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
143 *gray
= clip01(color
->c
[0]);
146 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
147 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
150 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
151 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
152 cmyk
->k
= clip01(1 - color
->c
[0]);
155 //------------------------------------------------------------------------
156 // GfxCalGrayColorSpace
157 //------------------------------------------------------------------------
159 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
160 whiteX
= whiteY
= whiteZ
= 1;
161 blackX
= blackY
= blackZ
= 0;
165 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
168 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
169 GfxCalGrayColorSpace
*cs
;
171 cs
= new GfxCalGrayColorSpace();
182 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
) {
183 GfxCalGrayColorSpace
*cs
;
184 Object obj1
, obj2
, obj3
;
187 if (!obj1
.isDict()) {
188 error(-1, "Bad CalGray color space");
192 cs
= new GfxCalGrayColorSpace();
193 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
194 obj2
.arrayGetLength() == 3) {
195 obj2
.arrayGet(0, &obj3
);
196 cs
->whiteX
= obj3
.getNum();
198 obj2
.arrayGet(1, &obj3
);
199 cs
->whiteY
= obj3
.getNum();
201 obj2
.arrayGet(2, &obj3
);
202 cs
->whiteZ
= obj3
.getNum();
206 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
207 obj2
.arrayGetLength() == 3) {
208 obj2
.arrayGet(0, &obj3
);
209 cs
->blackX
= obj3
.getNum();
211 obj2
.arrayGet(1, &obj3
);
212 cs
->blackY
= obj3
.getNum();
214 obj2
.arrayGet(2, &obj3
);
215 cs
->blackZ
= obj3
.getNum();
219 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
220 cs
->gamma
= obj2
.getNum();
227 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
228 *gray
= clip01(color
->c
[0]);
231 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
232 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
235 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
236 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
237 cmyk
->k
= clip01(1 - color
->c
[0]);
240 //------------------------------------------------------------------------
241 // GfxDeviceRGBColorSpace
242 //------------------------------------------------------------------------
244 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
247 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
250 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
251 return new GfxDeviceRGBColorSpace();
254 void GfxDeviceRGBColorSpace::getGray(GfxColor
*color
, double *gray
) {
255 *gray
= clip01(0.299 * color
->c
[0] +
256 0.587 * color
->c
[1] +
257 0.114 * color
->c
[2]);
260 void GfxDeviceRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
261 rgb
->r
= clip01(color
->c
[0]);
262 rgb
->g
= clip01(color
->c
[1]);
263 rgb
->b
= clip01(color
->c
[2]);
266 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
269 c
= clip01(1 - color
->c
[0]);
270 m
= clip01(1 - color
->c
[1]);
271 y
= clip01(1 - color
->c
[2]);
285 //------------------------------------------------------------------------
286 // GfxCalRGBColorSpace
287 //------------------------------------------------------------------------
289 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
290 whiteX
= whiteY
= whiteZ
= 1;
291 blackX
= blackY
= blackZ
= 0;
292 gammaR
= gammaG
= gammaB
= 1;
293 mat
[0] = 1; mat
[1] = 0; mat
[2] = 0;
294 mat
[3] = 0; mat
[4] = 1; mat
[5] = 0;
295 mat
[6] = 0; mat
[7] = 0; mat
[8] = 1;
298 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
301 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
302 GfxCalRGBColorSpace
*cs
;
305 cs
= new GfxCalRGBColorSpace();
315 for (i
= 0; i
< 9; ++i
) {
321 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
) {
322 GfxCalRGBColorSpace
*cs
;
323 Object obj1
, obj2
, obj3
;
327 if (!obj1
.isDict()) {
328 error(-1, "Bad CalRGB color space");
332 cs
= new GfxCalRGBColorSpace();
333 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
334 obj2
.arrayGetLength() == 3) {
335 obj2
.arrayGet(0, &obj3
);
336 cs
->whiteX
= obj3
.getNum();
338 obj2
.arrayGet(1, &obj3
);
339 cs
->whiteY
= obj3
.getNum();
341 obj2
.arrayGet(2, &obj3
);
342 cs
->whiteZ
= obj3
.getNum();
346 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
347 obj2
.arrayGetLength() == 3) {
348 obj2
.arrayGet(0, &obj3
);
349 cs
->blackX
= obj3
.getNum();
351 obj2
.arrayGet(1, &obj3
);
352 cs
->blackY
= obj3
.getNum();
354 obj2
.arrayGet(2, &obj3
);
355 cs
->blackZ
= obj3
.getNum();
359 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
360 obj2
.arrayGetLength() == 3) {
361 obj2
.arrayGet(0, &obj3
);
362 cs
->gammaR
= obj3
.getNum();
364 obj2
.arrayGet(1, &obj3
);
365 cs
->gammaG
= obj3
.getNum();
367 obj2
.arrayGet(2, &obj3
);
368 cs
->gammaB
= obj3
.getNum();
372 if (obj1
.dictLookup("Matrix", &obj2
)->isArray() &&
373 obj2
.arrayGetLength() == 9) {
374 for (i
= 0; i
< 9; ++i
) {
375 obj2
.arrayGet(i
, &obj3
);
376 cs
->mat
[i
] = obj3
.getNum();
385 void GfxCalRGBColorSpace::getGray(GfxColor
*color
, double *gray
) {
386 *gray
= clip01(0.299 * color
->c
[0] +
387 0.587 * color
->c
[1] +
388 0.114 * color
->c
[2]);
391 void GfxCalRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
392 rgb
->r
= clip01(color
->c
[0]);
393 rgb
->g
= clip01(color
->c
[1]);
394 rgb
->b
= clip01(color
->c
[2]);
397 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
400 c
= clip01(1 - color
->c
[0]);
401 m
= clip01(1 - color
->c
[1]);
402 y
= clip01(1 - color
->c
[2]);
416 //------------------------------------------------------------------------
417 // GfxDeviceCMYKColorSpace
418 //------------------------------------------------------------------------
420 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
423 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
426 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
427 return new GfxDeviceCMYKColorSpace();
430 void GfxDeviceCMYKColorSpace::getGray(GfxColor
*color
, double *gray
) {
431 *gray
= clip01(1 - color
->c
[3]
432 - 0.299 * color
->c
[0]
433 - 0.587 * color
->c
[1]
434 - 0.114 * color
->c
[2]);
437 void GfxDeviceCMYKColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
438 double c
, m
, y
, aw
, ac
, am
, ay
, ar
, ag
, ab
;
440 c
= clip01(color
->c
[0] + color
->c
[3]);
441 m
= clip01(color
->c
[1] + color
->c
[3]);
442 y
= clip01(color
->c
[2] + color
->c
[3]);
443 aw
= (1-c
) * (1-m
) * (1-y
);
444 ac
= c
* (1-m
) * (1-y
);
445 am
= (1-c
) * m
* (1-y
);
446 ay
= (1-c
) * (1-m
) * y
;
450 rgb
->r
= clip01(aw
+ 0.9137*am
+ 0.9961*ay
+ 0.9882*ar
);
451 rgb
->g
= clip01(aw
+ 0.6196*ac
+ ay
+ 0.5176*ag
);
452 rgb
->b
= clip01(aw
+ 0.7804*ac
+ 0.5412*am
+ 0.0667*ar
+ 0.2118*ag
+
456 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
457 cmyk
->c
= clip01(color
->c
[0]);
458 cmyk
->m
= clip01(color
->c
[1]);
459 cmyk
->y
= clip01(color
->c
[2]);
460 cmyk
->k
= clip01(color
->c
[3]);
463 //------------------------------------------------------------------------
465 //------------------------------------------------------------------------
467 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
468 // Language Reference, Third Edition.
469 static double xyzrgb
[3][3] = {
470 { 3.240449, -1.537136, -0.498531 },
471 { -0.969265, 1.876011, 0.041556 },
472 { 0.055643, -0.204026, 1.057229 }
475 GfxLabColorSpace::GfxLabColorSpace() {
476 whiteX
= whiteY
= whiteZ
= 1;
477 blackX
= blackY
= blackZ
= 0;
482 GfxLabColorSpace::~GfxLabColorSpace() {
485 GfxColorSpace
*GfxLabColorSpace::copy() {
486 GfxLabColorSpace
*cs
;
488 cs
= new GfxLabColorSpace();
505 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
) {
506 GfxLabColorSpace
*cs
;
507 Object obj1
, obj2
, obj3
;
510 if (!obj1
.isDict()) {
511 error(-1, "Bad Lab color space");
515 cs
= new GfxLabColorSpace();
516 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
517 obj2
.arrayGetLength() == 3) {
518 obj2
.arrayGet(0, &obj3
);
519 cs
->whiteX
= obj3
.getNum();
521 obj2
.arrayGet(1, &obj3
);
522 cs
->whiteY
= obj3
.getNum();
524 obj2
.arrayGet(2, &obj3
);
525 cs
->whiteZ
= obj3
.getNum();
529 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
530 obj2
.arrayGetLength() == 3) {
531 obj2
.arrayGet(0, &obj3
);
532 cs
->blackX
= obj3
.getNum();
534 obj2
.arrayGet(1, &obj3
);
535 cs
->blackY
= obj3
.getNum();
537 obj2
.arrayGet(2, &obj3
);
538 cs
->blackZ
= obj3
.getNum();
542 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
543 obj2
.arrayGetLength() == 4) {
544 obj2
.arrayGet(0, &obj3
);
545 cs
->aMin
= obj3
.getNum();
547 obj2
.arrayGet(1, &obj3
);
548 cs
->aMax
= obj3
.getNum();
550 obj2
.arrayGet(2, &obj3
);
551 cs
->bMin
= obj3
.getNum();
553 obj2
.arrayGet(3, &obj3
);
554 cs
->bMax
= obj3
.getNum();
560 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
561 xyzrgb
[0][1] * cs
->whiteY
+
562 xyzrgb
[0][2] * cs
->whiteZ
);
563 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
564 xyzrgb
[1][1] * cs
->whiteY
+
565 xyzrgb
[1][2] * cs
->whiteZ
);
566 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
567 xyzrgb
[2][1] * cs
->whiteY
+
568 xyzrgb
[2][2] * cs
->whiteZ
);
573 void GfxLabColorSpace::getGray(GfxColor
*color
, double *gray
) {
577 *gray
= clip01(0.299 * rgb
.r
+
582 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
587 // convert L*a*b* to CIE 1931 XYZ color space
588 t1
= (color
->c
[0] + 16) / 116;
589 t2
= t1
+ color
->c
[1] / 500;
590 if (t2
>= (6.0 / 29.0)) {
593 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
596 if (t1
>= (6.0 / 29.0)) {
599 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
602 t2
= t1
- color
->c
[2] / 200;
603 if (t2
>= (6.0 / 29.0)) {
606 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
610 // convert XYZ to RGB, including gamut mapping and gamma correction
611 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
612 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
613 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
614 rgb
->r
= pow(clip01(r
* kr
), 0.5);
615 rgb
->g
= pow(clip01(g
* kg
), 0.5);
616 rgb
->b
= pow(clip01(b
* kb
), 0.5);
619 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
624 c
= clip01(1 - rgb
.r
);
625 m
= clip01(1 - rgb
.g
);
626 y
= clip01(1 - rgb
.b
);
640 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
643 decodeRange
[0] = 100;
645 decodeRange
[1] = aMax
- aMin
;
647 decodeRange
[2] = bMax
- bMin
;
650 //------------------------------------------------------------------------
651 // GfxICCBasedColorSpace
652 //------------------------------------------------------------------------
654 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA
, GfxColorSpace
*altA
,
655 Ref
*iccProfileStreamA
) {
658 iccProfileStream
= *iccProfileStreamA
;
659 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
660 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
663 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
667 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
668 GfxICCBasedColorSpace
*cs
;
671 cs
= new GfxICCBasedColorSpace(nComps
, alt
->copy(), &iccProfileStream
);
672 for (i
= 0; i
< 4; ++i
) {
673 cs
->rangeMin
[i
] = rangeMin
[i
];
674 cs
->rangeMax
[i
] = rangeMax
[i
];
679 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
) {
680 GfxICCBasedColorSpace
*cs
;
681 Ref iccProfileStreamA
;
685 Object obj1
, obj2
, obj3
;
688 arr
->getNF(1, &obj1
);
690 iccProfileStreamA
= obj1
.getRef();
692 iccProfileStreamA
.num
= 0;
693 iccProfileStreamA
.gen
= 0;
697 if (!obj1
.isStream()) {
698 error(-1, "Bad ICCBased color space (stream)");
702 dict
= obj1
.streamGetDict();
703 if (!dict
->lookup("N", &obj2
)->isInt()) {
704 error(-1, "Bad ICCBased color space (N)");
709 nCompsA
= obj2
.getInt();
711 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
712 !(altA
= GfxColorSpace::parse(&obj2
))) {
715 altA
= new GfxDeviceGrayColorSpace();
718 altA
= new GfxDeviceRGBColorSpace();
721 altA
= new GfxDeviceCMYKColorSpace();
724 error(-1, "Bad ICCBased color space - invalid N");
731 cs
= new GfxICCBasedColorSpace(nCompsA
, altA
, &iccProfileStreamA
);
732 if (dict
->lookup("Range", &obj2
)->isArray() &&
733 obj2
.arrayGetLength() == 2 * nCompsA
) {
734 for (i
= 0; i
< nCompsA
; ++i
) {
735 obj2
.arrayGet(2*i
, &obj3
);
736 cs
->rangeMin
[i
] = obj3
.getNum();
738 obj2
.arrayGet(2*i
+1, &obj3
);
739 cs
->rangeMax
[i
] = obj3
.getNum();
748 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, double *gray
) {
749 alt
->getGray(color
, gray
);
752 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
753 alt
->getRGB(color
, rgb
);
756 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
757 alt
->getCMYK(color
, cmyk
);
760 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
763 alt
->getDefaultRanges(decodeLow
, decodeRange
, maxImgPixel
);
766 // this is nominally correct, but some PDF files don't set the
767 // correct ranges in the ICCBased dict
770 for (i
= 0; i
< nComps
; ++i
) {
771 decodeLow
[i
] = rangeMin
[i
];
772 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
777 //------------------------------------------------------------------------
778 // GfxIndexedColorSpace
779 //------------------------------------------------------------------------
781 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*baseA
,
784 indexHigh
= indexHighA
;
785 lookup
= (Guchar
*)gmalloc((indexHigh
+ 1) * base
->getNComps() *
789 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
794 GfxColorSpace
*GfxIndexedColorSpace::copy() {
795 GfxIndexedColorSpace
*cs
;
797 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
798 memcpy(cs
->lookup
, lookup
,
799 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
803 GfxColorSpace
*GfxIndexedColorSpace::parse(Array
*arr
) {
804 GfxIndexedColorSpace
*cs
;
805 GfxColorSpace
*baseA
;
812 if (arr
->getLength() != 4) {
813 error(-1, "Bad Indexed color space");
817 if (!(baseA
= GfxColorSpace::parse(&obj1
))) {
818 error(-1, "Bad Indexed color space (base color space)");
822 if (!arr
->get(2, &obj1
)->isInt()) {
823 error(-1, "Bad Indexed color space (hival)");
827 indexHighA
= obj1
.getInt();
828 if (indexHighA
< 0 || indexHighA
> 255) {
829 // the PDF spec requires indexHigh to be in [0,255] -- allowing
830 // values larger than 255 creates a security hole: if nComps *
831 // indexHigh is greater than 2^31, the loop below may overwrite
832 // past the end of the array
833 error(-1, "Bad Indexed color space (invalid indexHigh value)");
838 cs
= new GfxIndexedColorSpace(baseA
, indexHighA
);
840 n
= baseA
->getNComps();
841 if (obj1
.isStream()) {
843 for (i
= 0; i
<= indexHighA
; ++i
) {
844 for (j
= 0; j
< n
; ++j
) {
845 if ((x
= obj1
.streamGetChar()) == EOF
) {
846 error(-1, "Bad Indexed color space (lookup table stream too short)");
849 cs
->lookup
[i
*n
+ j
] = (Guchar
)x
;
853 } else if (obj1
.isString()) {
854 if (obj1
.getString()->getLength() < (indexHighA
+ 1) * n
) {
855 error(-1, "Bad Indexed color space (lookup table string too short)");
858 s
= obj1
.getString()->getCString();
859 for (i
= 0; i
<= indexHighA
; ++i
) {
860 for (j
= 0; j
< n
; ++j
) {
861 cs
->lookup
[i
*n
+ j
] = (Guchar
)*s
++;
865 error(-1, "Bad Indexed color space (lookup table)");
879 GfxColor
*GfxIndexedColorSpace::mapColorToBase(GfxColor
*color
,
880 GfxColor
*baseColor
) {
882 double low
[gfxColorMaxComps
], range
[gfxColorMaxComps
];
885 n
= base
->getNComps();
886 base
->getDefaultRanges(low
, range
, indexHigh
);
887 p
= &lookup
[(int)(color
->c
[0] + 0.5) * n
];
888 for (i
= 0; i
< n
; ++i
) {
889 baseColor
->c
[i
] = low
[i
] + (p
[i
] / 255.0) * range
[i
];
894 void GfxIndexedColorSpace::getGray(GfxColor
*color
, double *gray
) {
897 base
->getGray(mapColorToBase(color
, &color2
), gray
);
900 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
903 base
->getRGB(mapColorToBase(color
, &color2
), rgb
);
906 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
909 base
->getCMYK(mapColorToBase(color
, &color2
), cmyk
);
912 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
916 decodeRange
[0] = maxImgPixel
;
919 //------------------------------------------------------------------------
920 // GfxSeparationColorSpace
921 //------------------------------------------------------------------------
923 GfxSeparationColorSpace::GfxSeparationColorSpace(GString
*nameA
,
931 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
937 GfxColorSpace
*GfxSeparationColorSpace::copy() {
938 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy());
941 //~ handle the 'All' and 'None' colorants
942 GfxColorSpace
*GfxSeparationColorSpace::parse(Array
*arr
) {
943 GfxSeparationColorSpace
*cs
;
949 if (arr
->getLength() != 4) {
950 error(-1, "Bad Separation color space");
953 if (!arr
->get(1, &obj1
)->isName()) {
954 error(-1, "Bad Separation color space (name)");
957 nameA
= new GString(obj1
.getName());
960 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
961 error(-1, "Bad Separation color space (alternate color space)");
966 if (!(funcA
= Function::parse(&obj1
))) {
970 cs
= new GfxSeparationColorSpace(nameA
, altA
, funcA
);
983 void GfxSeparationColorSpace::getGray(GfxColor
*color
, double *gray
) {
986 func
->transform(color
->c
, color2
.c
);
987 alt
->getGray(&color2
, gray
);
990 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
993 func
->transform(color
->c
, color2
.c
);
994 alt
->getRGB(&color2
, rgb
);
997 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1000 func
->transform(color
->c
, color2
.c
);
1001 alt
->getCMYK(&color2
, cmyk
);
1004 //------------------------------------------------------------------------
1005 // GfxDeviceNColorSpace
1006 //------------------------------------------------------------------------
1008 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
1009 GfxColorSpace
*altA
,
1016 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1019 for (i
= 0; i
< nComps
; ++i
) {
1026 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
1027 GfxDeviceNColorSpace
*cs
;
1030 cs
= new GfxDeviceNColorSpace(nComps
, alt
->copy(), func
->copy());
1031 for (i
= 0; i
< nComps
; ++i
) {
1032 cs
->names
[i
] = names
[i
]->copy();
1037 //~ handle the 'None' colorant
1038 GfxColorSpace
*GfxDeviceNColorSpace::parse(Array
*arr
) {
1039 GfxDeviceNColorSpace
*cs
;
1041 GString
*namesA
[gfxColorMaxComps
];
1042 GfxColorSpace
*altA
;
1047 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
1048 error(-1, "Bad DeviceN color space");
1051 if (!arr
->get(1, &obj1
)->isArray()) {
1052 error(-1, "Bad DeviceN color space (names)");
1055 nCompsA
= obj1
.arrayGetLength();
1056 if (nCompsA
> gfxColorMaxComps
) {
1057 error(-1, "DeviceN color space with more than %d > %d components",
1058 nCompsA
, gfxColorMaxComps
);
1059 nCompsA
= gfxColorMaxComps
;
1061 for (i
= 0; i
< nCompsA
; ++i
) {
1062 if (!obj1
.arrayGet(i
, &obj2
)->isName()) {
1063 error(-1, "Bad DeviceN color space (names)");
1067 namesA
[i
] = new GString(obj2
.getName());
1072 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1073 error(-1, "Bad DeviceN color space (alternate color space)");
1078 if (!(funcA
= Function::parse(&obj1
))) {
1082 cs
= new GfxDeviceNColorSpace(nCompsA
, altA
, funcA
);
1083 for (i
= 0; i
< nCompsA
; ++i
) {
1084 cs
->names
[i
] = namesA
[i
];
1091 for (i
= 0; i
< nCompsA
; ++i
) {
1100 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, double *gray
) {
1103 func
->transform(color
->c
, color2
.c
);
1104 alt
->getGray(&color2
, gray
);
1107 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1110 func
->transform(color
->c
, color2
.c
);
1111 alt
->getRGB(&color2
, rgb
);
1114 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1117 func
->transform(color
->c
, color2
.c
);
1118 alt
->getCMYK(&color2
, cmyk
);
1121 //------------------------------------------------------------------------
1122 // GfxPatternColorSpace
1123 //------------------------------------------------------------------------
1125 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*underA
) {
1129 GfxPatternColorSpace::~GfxPatternColorSpace() {
1135 GfxColorSpace
*GfxPatternColorSpace::copy() {
1136 return new GfxPatternColorSpace(under
? under
->copy() :
1137 (GfxColorSpace
*)NULL
);
1140 GfxColorSpace
*GfxPatternColorSpace::parse(Array
*arr
) {
1141 GfxPatternColorSpace
*cs
;
1142 GfxColorSpace
*underA
;
1145 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
1146 error(-1, "Bad Pattern color space");
1150 if (arr
->getLength() == 2) {
1152 if (!(underA
= GfxColorSpace::parse(&obj1
))) {
1153 error(-1, "Bad Pattern color space (underlying color space)");
1159 cs
= new GfxPatternColorSpace(underA
);
1163 void GfxPatternColorSpace::getGray(GfxColor
*color
, double *gray
) {
1167 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1168 rgb
->r
= rgb
->g
= rgb
->b
= 0;
1171 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1172 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
1176 //------------------------------------------------------------------------
1178 //------------------------------------------------------------------------
1180 GfxPattern::GfxPattern(int typeA
) {
1184 GfxPattern::~GfxPattern() {
1187 GfxPattern
*GfxPattern::parse(Object
*obj
) {
1188 GfxPattern
*pattern
;
1191 if (obj
->isDict()) {
1192 obj
->dictLookup("PatternType", &obj1
);
1193 } else if (obj
->isStream()) {
1194 obj
->streamGetDict()->lookup("PatternType", &obj1
);
1199 if (obj1
.isInt() && obj1
.getInt() == 1) {
1200 pattern
= GfxTilingPattern::parse(obj
);
1201 } else if (obj1
.isInt() && obj1
.getInt() == 2) {
1202 pattern
= GfxShadingPattern::parse(obj
);
1208 //------------------------------------------------------------------------
1210 //------------------------------------------------------------------------
1212 GfxTilingPattern
*GfxTilingPattern::parse(Object
*patObj
) {
1213 GfxTilingPattern
*pat
;
1215 int paintTypeA
, tilingTypeA
;
1216 double bboxA
[4], matrixA
[6];
1217 double xStepA
, yStepA
;
1222 if (!patObj
->isStream()) {
1225 dict
= patObj
->streamGetDict();
1227 if (dict
->lookup("PaintType", &obj1
)->isInt()) {
1228 paintTypeA
= obj1
.getInt();
1231 error(-1, "Invalid or missing PaintType in pattern");
1234 if (dict
->lookup("TilingType", &obj1
)->isInt()) {
1235 tilingTypeA
= obj1
.getInt();
1238 error(-1, "Invalid or missing TilingType in pattern");
1241 bboxA
[0] = bboxA
[1] = 0;
1242 bboxA
[2] = bboxA
[3] = 1;
1243 if (dict
->lookup("BBox", &obj1
)->isArray() &&
1244 obj1
.arrayGetLength() == 4) {
1245 for (i
= 0; i
< 4; ++i
) {
1246 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1247 bboxA
[i
] = obj2
.getNum();
1252 error(-1, "Invalid or missing BBox in pattern");
1255 if (dict
->lookup("XStep", &obj1
)->isNum()) {
1256 xStepA
= obj1
.getNum();
1259 error(-1, "Invalid or missing XStep in pattern");
1262 if (dict
->lookup("YStep", &obj1
)->isNum()) {
1263 yStepA
= obj1
.getNum();
1266 error(-1, "Invalid or missing YStep in pattern");
1269 if (!dict
->lookup("Resources", &resDictA
)->isDict()) {
1271 resDictA
.initNull();
1272 error(-1, "Invalid or missing Resources in pattern");
1274 matrixA
[0] = 1; matrixA
[1] = 0;
1275 matrixA
[2] = 0; matrixA
[3] = 1;
1276 matrixA
[4] = 0; matrixA
[5] = 0;
1277 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1278 obj1
.arrayGetLength() == 6) {
1279 for (i
= 0; i
< 6; ++i
) {
1280 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1281 matrixA
[i
] = obj2
.getNum();
1288 pat
= new GfxTilingPattern(paintTypeA
, tilingTypeA
, bboxA
, xStepA
, yStepA
,
1289 &resDictA
, matrixA
, patObj
);
1294 GfxTilingPattern::GfxTilingPattern(int paintTypeA
, int tilingTypeA
,
1295 double *bboxA
, double xStepA
, double yStepA
,
1296 Object
*resDictA
, double *matrixA
,
1297 Object
*contentStreamA
):
1302 paintType
= paintTypeA
;
1303 tilingType
= tilingTypeA
;
1304 for (i
= 0; i
< 4; ++i
) {
1309 resDictA
->copy(&resDict
);
1310 for (i
= 0; i
< 6; ++i
) {
1311 matrix
[i
] = matrixA
[i
];
1313 contentStreamA
->copy(&contentStream
);
1316 GfxTilingPattern::~GfxTilingPattern() {
1318 contentStream
.free();
1321 GfxPattern
*GfxTilingPattern::copy() {
1322 return new GfxTilingPattern(paintType
, tilingType
, bbox
, xStep
, yStep
,
1323 &resDict
, matrix
, &contentStream
);
1326 //------------------------------------------------------------------------
1327 // GfxShadingPattern
1328 //------------------------------------------------------------------------
1330 GfxShadingPattern
*GfxShadingPattern::parse(Object
*patObj
) {
1332 GfxShading
*shadingA
;
1337 if (!patObj
->isDict()) {
1340 dict
= patObj
->getDict();
1342 dict
->lookup("Shading", &obj1
);
1343 shadingA
= GfxShading::parse(&obj1
);
1349 matrixA
[0] = 1; matrixA
[1] = 0;
1350 matrixA
[2] = 0; matrixA
[3] = 1;
1351 matrixA
[4] = 0; matrixA
[5] = 0;
1352 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1353 obj1
.arrayGetLength() == 6) {
1354 for (i
= 0; i
< 6; ++i
) {
1355 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1356 matrixA
[i
] = obj2
.getNum();
1363 return new GfxShadingPattern(shadingA
, matrixA
);
1366 GfxShadingPattern::GfxShadingPattern(GfxShading
*shadingA
, double *matrixA
):
1372 for (i
= 0; i
< 6; ++i
) {
1373 matrix
[i
] = matrixA
[i
];
1377 GfxShadingPattern::~GfxShadingPattern() {
1381 GfxPattern
*GfxShadingPattern::copy() {
1382 return new GfxShadingPattern(shading
->copy(), matrix
);
1385 //------------------------------------------------------------------------
1387 //------------------------------------------------------------------------
1389 GfxShading::GfxShading(int typeA
) {
1394 GfxShading::GfxShading(GfxShading
*shading
) {
1397 type
= shading
->type
;
1398 colorSpace
= shading
->colorSpace
->copy();
1399 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1400 background
.c
[i
] = shading
->background
.c
[i
];
1402 hasBackground
= shading
->hasBackground
;
1403 xMin
= shading
->xMin
;
1404 yMin
= shading
->yMin
;
1405 xMax
= shading
->xMax
;
1406 yMax
= shading
->yMax
;
1407 hasBBox
= shading
->hasBBox
;
1410 GfxShading::~GfxShading() {
1416 GfxShading
*GfxShading::parse(Object
*obj
) {
1417 GfxShading
*shading
;
1422 if (obj
->isDict()) {
1423 dict
= obj
->getDict();
1424 } else if (obj
->isStream()) {
1425 dict
= obj
->streamGetDict();
1430 if (!dict
->lookup("ShadingType", &obj1
)->isInt()) {
1431 error(-1, "Invalid ShadingType in shading dictionary");
1435 typeA
= obj1
.getInt();
1440 shading
= GfxFunctionShading::parse(dict
);
1443 shading
= GfxAxialShading::parse(dict
);
1446 shading
= GfxRadialShading::parse(dict
);
1449 error(-1, "Unimplemented shading type %d", typeA
);
1459 GBool
GfxShading::init(Dict
*dict
) {
1463 dict
->lookup("ColorSpace", &obj1
);
1464 if (!(colorSpace
= GfxColorSpace::parse(&obj1
))) {
1465 error(-1, "Bad color space in shading dictionary");
1471 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1472 background
.c
[i
] = 0;
1474 hasBackground
= gFalse
;
1475 if (dict
->lookup("Background", &obj1
)->isArray()) {
1476 if (obj1
.arrayGetLength() == colorSpace
->getNComps()) {
1477 hasBackground
= gTrue
;
1478 for (i
= 0; i
< colorSpace
->getNComps(); ++i
) {
1479 background
.c
[i
] = obj1
.arrayGet(i
, &obj2
)->getNum();
1483 error(-1, "Bad Background in shading dictionary");
1488 xMin
= yMin
= xMax
= yMax
= 0;
1490 if (dict
->lookup("BBox", &obj1
)->isArray()) {
1491 if (obj1
.arrayGetLength() == 4) {
1493 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
1495 yMin
= obj1
.arrayGet(1, &obj2
)->getNum();
1497 xMax
= obj1
.arrayGet(2, &obj2
)->getNum();
1499 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
1502 error(-1, "Bad BBox in shading dictionary");
1510 //------------------------------------------------------------------------
1511 // GfxFunctionShading
1512 //------------------------------------------------------------------------
1514 GfxFunctionShading::GfxFunctionShading(double x0A
, double y0A
,
1515 double x1A
, double y1A
,
1517 Function
**funcsA
, int nFuncsA
):
1526 for (i
= 0; i
< 6; ++i
) {
1527 matrix
[i
] = matrixA
[i
];
1530 for (i
= 0; i
< nFuncs
; ++i
) {
1531 funcs
[i
] = funcsA
[i
];
1535 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading
*shading
):
1544 for (i
= 0; i
< 6; ++i
) {
1545 matrix
[i
] = shading
->matrix
[i
];
1547 nFuncs
= shading
->nFuncs
;
1548 for (i
= 0; i
< nFuncs
; ++i
) {
1549 funcs
[i
] = shading
->funcs
[i
]->copy();
1553 GfxFunctionShading::~GfxFunctionShading() {
1556 for (i
= 0; i
< nFuncs
; ++i
) {
1561 GfxFunctionShading
*GfxFunctionShading::parse(Dict
*dict
) {
1562 GfxFunctionShading
*shading
;
1563 double x0A
, y0A
, x1A
, y1A
;
1565 Function
*funcsA
[gfxColorMaxComps
];
1572 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1573 obj1
.arrayGetLength() == 4) {
1574 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1576 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1578 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1580 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1585 matrixA
[0] = 1; matrixA
[1] = 0;
1586 matrixA
[2] = 0; matrixA
[3] = 1;
1587 matrixA
[4] = 0; matrixA
[5] = 0;
1588 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1589 obj1
.arrayGetLength() == 6) {
1590 matrixA
[0] = obj1
.arrayGet(0, &obj2
)->getNum();
1592 matrixA
[1] = obj1
.arrayGet(1, &obj2
)->getNum();
1594 matrixA
[2] = obj1
.arrayGet(2, &obj2
)->getNum();
1596 matrixA
[3] = obj1
.arrayGet(3, &obj2
)->getNum();
1598 matrixA
[4] = obj1
.arrayGet(4, &obj2
)->getNum();
1600 matrixA
[5] = obj1
.arrayGet(5, &obj2
)->getNum();
1605 dict
->lookup("Function", &obj1
);
1606 if (obj1
.isArray()) {
1607 nFuncsA
= obj1
.arrayGetLength();
1608 if (nFuncsA
> gfxColorMaxComps
) {
1609 error(-1, "Invalid Function array in shading dictionary");
1612 for (i
= 0; i
< nFuncsA
; ++i
) {
1613 obj1
.arrayGet(i
, &obj2
);
1614 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1621 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1627 shading
= new GfxFunctionShading(x0A
, y0A
, x1A
, y1A
, matrixA
,
1629 if (!shading
->init(dict
)) {
1642 GfxShading
*GfxFunctionShading::copy() {
1643 return new GfxFunctionShading(this);
1646 void GfxFunctionShading::getColor(double x
, double y
, GfxColor
*color
) {
1652 for (i
= 0; i
< nFuncs
; ++i
) {
1653 funcs
[i
]->transform(in
, &color
->c
[i
]);
1657 //------------------------------------------------------------------------
1659 //------------------------------------------------------------------------
1661 GfxAxialShading::GfxAxialShading(double x0A
, double y0A
,
1662 double x1A
, double y1A
,
1663 double t0A
, double t1A
,
1664 Function
**funcsA
, int nFuncsA
,
1665 GBool extend0A
, GBool extend1A
):
1677 for (i
= 0; i
< nFuncs
; ++i
) {
1678 funcs
[i
] = funcsA
[i
];
1684 GfxAxialShading::GfxAxialShading(GfxAxialShading
*shading
):
1695 nFuncs
= shading
->nFuncs
;
1696 for (i
= 0; i
< nFuncs
; ++i
) {
1697 funcs
[i
] = shading
->funcs
[i
]->copy();
1699 extend0
= shading
->extend0
;
1700 extend1
= shading
->extend1
;
1703 GfxAxialShading::~GfxAxialShading() {
1706 for (i
= 0; i
< nFuncs
; ++i
) {
1711 GfxAxialShading
*GfxAxialShading::parse(Dict
*dict
) {
1712 GfxAxialShading
*shading
;
1713 double x0A
, y0A
, x1A
, y1A
;
1715 Function
*funcsA
[gfxColorMaxComps
];
1717 GBool extend0A
, extend1A
;
1721 x0A
= y0A
= x1A
= y1A
= 0;
1722 if (dict
->lookup("Coords", &obj1
)->isArray() &&
1723 obj1
.arrayGetLength() == 4) {
1724 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1726 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1728 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1730 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1733 error(-1, "Missing or invalid Coords in shading dictionary");
1740 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1741 obj1
.arrayGetLength() == 2) {
1742 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1744 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
1749 dict
->lookup("Function", &obj1
);
1750 if (obj1
.isArray()) {
1751 nFuncsA
= obj1
.arrayGetLength();
1752 if (nFuncsA
> gfxColorMaxComps
) {
1753 error(-1, "Invalid Function array in shading dictionary");
1756 for (i
= 0; i
< nFuncsA
; ++i
) {
1757 obj1
.arrayGet(i
, &obj2
);
1758 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1767 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1774 extend0A
= extend1A
= gFalse
;
1775 if (dict
->lookup("Extend", &obj1
)->isArray() &&
1776 obj1
.arrayGetLength() == 2) {
1777 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
1779 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
1784 shading
= new GfxAxialShading(x0A
, y0A
, x1A
, y1A
, t0A
, t1A
,
1785 funcsA
, nFuncsA
, extend0A
, extend1A
);
1786 if (!shading
->init(dict
)) {
1796 GfxShading
*GfxAxialShading::copy() {
1797 return new GfxAxialShading(this);
1800 void GfxAxialShading::getColor(double t
, GfxColor
*color
) {
1803 // NB: there can be one function with n outputs or n functions with
1804 // one output each (where n = number of color components)
1805 for (i
= 0; i
< nFuncs
; ++i
) {
1806 funcs
[i
]->transform(&t
, &color
->c
[i
]);
1810 //------------------------------------------------------------------------
1812 //------------------------------------------------------------------------
1814 GfxRadialShading::GfxRadialShading(double x0A
, double y0A
, double r0A
,
1815 double x1A
, double y1A
, double r1A
,
1816 double t0A
, double t1A
,
1817 Function
**funcsA
, int nFuncsA
,
1818 GBool extend0A
, GBool extend1A
):
1832 for (i
= 0; i
< nFuncs
; ++i
) {
1833 funcs
[i
] = funcsA
[i
];
1839 GfxRadialShading::GfxRadialShading(GfxRadialShading
*shading
):
1852 nFuncs
= shading
->nFuncs
;
1853 for (i
= 0; i
< nFuncs
; ++i
) {
1854 funcs
[i
] = shading
->funcs
[i
]->copy();
1856 extend0
= shading
->extend0
;
1857 extend1
= shading
->extend1
;
1860 GfxRadialShading::~GfxRadialShading() {
1863 for (i
= 0; i
< nFuncs
; ++i
) {
1868 GfxRadialShading
*GfxRadialShading::parse(Dict
*dict
) {
1869 GfxRadialShading
*shading
;
1870 double x0A
, y0A
, r0A
, x1A
, y1A
, r1A
;
1872 Function
*funcsA
[gfxColorMaxComps
];
1874 GBool extend0A
, extend1A
;
1878 x0A
= y0A
= r0A
= x1A
= y1A
= r1A
= 0;
1879 if (dict
->lookup("Coords", &obj1
)->isArray() &&
1880 obj1
.arrayGetLength() == 6) {
1881 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1883 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1885 r0A
= obj1
.arrayGet(2, &obj2
)->getNum();
1887 x1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1889 y1A
= obj1
.arrayGet(4, &obj2
)->getNum();
1891 r1A
= obj1
.arrayGet(5, &obj2
)->getNum();
1894 error(-1, "Missing or invalid Coords in shading dictionary");
1901 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1902 obj1
.arrayGetLength() == 2) {
1903 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1905 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
1910 dict
->lookup("Function", &obj1
);
1911 if (obj1
.isArray()) {
1912 nFuncsA
= obj1
.arrayGetLength();
1913 if (nFuncsA
> gfxColorMaxComps
) {
1914 error(-1, "Invalid Function array in shading dictionary");
1917 for (i
= 0; i
< nFuncsA
; ++i
) {
1918 obj1
.arrayGet(i
, &obj2
);
1919 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1928 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1935 extend0A
= extend1A
= gFalse
;
1936 if (dict
->lookup("Extend", &obj1
)->isArray() &&
1937 obj1
.arrayGetLength() == 2) {
1938 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
1940 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
1945 shading
= new GfxRadialShading(x0A
, y0A
, r0A
, x1A
, y1A
, r1A
, t0A
, t1A
,
1946 funcsA
, nFuncsA
, extend0A
, extend1A
);
1947 if (!shading
->init(dict
)) {
1957 GfxShading
*GfxRadialShading::copy() {
1958 return new GfxRadialShading(this);
1961 void GfxRadialShading::getColor(double t
, GfxColor
*color
) {
1964 // NB: there can be one function with n outputs or n functions with
1965 // one output each (where n = number of color components)
1966 for (i
= 0; i
< nFuncs
; ++i
) {
1967 funcs
[i
]->transform(&t
, &color
->c
[i
]);
1971 //------------------------------------------------------------------------
1973 //------------------------------------------------------------------------
1975 GfxImageColorMap::GfxImageColorMap(int bitsA
, Object
*decode
,
1976 GfxColorSpace
*colorSpaceA
) {
1977 GfxIndexedColorSpace
*indexedCS
;
1978 GfxSeparationColorSpace
*sepCS
;
1979 int maxPixel
, indexHigh
;
1983 double x
[gfxColorMaxComps
];
1984 double y
[gfxColorMaxComps
];
1989 // bits per component and color space
1991 maxPixel
= (1 << bits
) - 1;
1992 colorSpace
= colorSpaceA
;
1995 if (decode
->isNull()) {
1996 nComps
= colorSpace
->getNComps();
1997 colorSpace
->getDefaultRanges(decodeLow
, decodeRange
, maxPixel
);
1998 } else if (decode
->isArray()) {
1999 nComps
= decode
->arrayGetLength() / 2;
2000 if (nComps
!= colorSpace
->getNComps()) {
2003 for (i
= 0; i
< nComps
; ++i
) {
2004 decode
->arrayGet(2*i
, &obj
);
2008 decodeLow
[i
] = obj
.getNum();
2010 decode
->arrayGet(2*i
+1, &obj
);
2014 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
2021 // Construct a lookup table -- this stores pre-computed decoded
2022 // values for each component, i.e., the result of applying the
2023 // decode mapping to each possible image pixel component value.
2025 // Optimization: for Indexed and Separation color spaces (which have
2026 // only one component), we store color values in the lookup table
2027 // rather than component values.
2030 if (colorSpace
->getMode() == csIndexed
) {
2031 // Note that indexHigh may not be the same as maxPixel --
2032 // Distiller will remove unused palette entries, resulting in
2033 // indexHigh < maxPixel.
2034 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
2035 colorSpace2
= indexedCS
->getBase();
2036 indexHigh
= indexedCS
->getIndexHigh();
2037 nComps2
= colorSpace2
->getNComps();
2038 lookup
= (double *)gmalloc((maxPixel
+ 1) * nComps2
* sizeof(double));
2039 lookup2
= indexedCS
->getLookup();
2040 colorSpace2
->getDefaultRanges(x
, y
, indexHigh
);
2041 for (i
= 0; i
<= maxPixel
; ++i
) {
2042 j
= (int)(decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
+ 0.5);
2045 } else if (j
> indexHigh
) {
2048 for (k
= 0; k
< nComps2
; ++k
) {
2049 lookup
[i
*nComps2
+ k
] = x
[k
] + (lookup2
[j
*nComps2
+ k
] / 255.0) * y
[k
];
2052 } else if (colorSpace
->getMode() == csSeparation
) {
2053 sepCS
= (GfxSeparationColorSpace
*)colorSpace
;
2054 colorSpace2
= sepCS
->getAlt();
2055 nComps2
= colorSpace2
->getNComps();
2056 lookup
= (double *)gmalloc((maxPixel
+ 1) * nComps2
* sizeof(double));
2057 sepFunc
= sepCS
->getFunc();
2058 for (i
= 0; i
<= maxPixel
; ++i
) {
2059 x
[0] = decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
;
2060 sepFunc
->transform(x
, y
);
2061 for (k
= 0; k
< nComps2
; ++k
) {
2062 lookup
[i
*nComps2
+ k
] = y
[k
];
2066 lookup
= (double *)gmalloc((maxPixel
+ 1) * nComps
* sizeof(double));
2067 for (i
= 0; i
<= maxPixel
; ++i
) {
2068 for (k
= 0; k
< nComps
; ++k
) {
2069 lookup
[i
*nComps
+ k
] = decodeLow
[k
] +
2070 (i
* decodeRange
[k
]) / maxPixel
;
2083 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap
*colorMap
) {
2086 colorSpace
= colorMap
->colorSpace
->copy();
2087 bits
= colorMap
->bits
;
2088 nComps
= colorMap
->nComps
;
2089 nComps2
= colorMap
->nComps2
;
2093 if (colorSpace
->getMode() == csIndexed
) {
2094 colorSpace2
= ((GfxIndexedColorSpace
*)colorSpace
)->getBase();
2095 n
= n
* nComps2
* sizeof(double);
2096 } else if (colorSpace
->getMode() == csSeparation
) {
2097 colorSpace2
= ((GfxSeparationColorSpace
*)colorSpace
)->getAlt();
2098 n
= n
* nComps2
* sizeof(double);
2100 n
= n
* nComps
* sizeof(double);
2102 lookup
= (double *)gmalloc(n
);
2103 memcpy(lookup
, colorMap
->lookup
, n
);
2104 for (i
= 0; i
< nComps
; ++i
) {
2105 decodeLow
[i
] = colorMap
->decodeLow
[i
];
2106 decodeRange
[i
] = colorMap
->decodeRange
[i
];
2111 GfxImageColorMap::~GfxImageColorMap() {
2116 void GfxImageColorMap::getGray(Guchar
*x
, double *gray
) {
2122 p
= &lookup
[x
[0] * nComps2
];
2123 for (i
= 0; i
< nComps2
; ++i
) {
2126 colorSpace2
->getGray(&color
, gray
);
2128 for (i
= 0; i
< nComps
; ++i
) {
2129 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2131 colorSpace
->getGray(&color
, gray
);
2135 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
2141 p
= &lookup
[x
[0] * nComps2
];
2142 for (i
= 0; i
< nComps2
; ++i
) {
2145 colorSpace2
->getRGB(&color
, rgb
);
2147 for (i
= 0; i
< nComps
; ++i
) {
2148 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2150 colorSpace
->getRGB(&color
, rgb
);
2154 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
2160 p
= &lookup
[x
[0] * nComps2
];
2161 for (i
= 0; i
< nComps2
; ++i
) {
2164 colorSpace2
->getCMYK(&color
, cmyk
);
2166 for (i
= 0; i
< nComps
; ++i
) {
2167 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2169 colorSpace
->getCMYK(&color
, cmyk
);
2173 void GfxImageColorMap::getColor(Guchar
*x
, GfxColor
*color
) {
2176 maxPixel
= (1 << bits
) - 1;
2177 for (i
= 0; i
< nComps
; ++i
) {
2178 color
->c
[i
] = decodeLow
[i
] + (x
[i
] * decodeRange
[i
]) / maxPixel
;
2182 //------------------------------------------------------------------------
2183 // GfxSubpath and GfxPath
2184 //------------------------------------------------------------------------
2186 GfxSubpath::GfxSubpath(double x1
, double y1
) {
2188 x
= (double *)gmalloc(size
* sizeof(double));
2189 y
= (double *)gmalloc(size
* sizeof(double));
2190 curve
= (GBool
*)gmalloc(size
* sizeof(GBool
));
2198 GfxSubpath::~GfxSubpath() {
2205 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
2206 size
= subpath
->size
;
2208 x
= (double *)gmalloc(size
* sizeof(double));
2209 y
= (double *)gmalloc(size
* sizeof(double));
2210 curve
= (GBool
*)gmalloc(size
* sizeof(GBool
));
2211 memcpy(x
, subpath
->x
, n
* sizeof(double));
2212 memcpy(y
, subpath
->y
, n
* sizeof(double));
2213 memcpy(curve
, subpath
->curve
, n
* sizeof(GBool
));
2214 closed
= subpath
->closed
;
2217 void GfxSubpath::lineTo(double x1
, double y1
) {
2220 x
= (double *)grealloc(x
, size
* sizeof(double));
2221 y
= (double *)grealloc(y
, size
* sizeof(double));
2222 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
2230 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
2231 double x3
, double y3
) {
2234 x
= (double *)grealloc(x
, size
* sizeof(double));
2235 y
= (double *)grealloc(y
, size
* sizeof(double));
2236 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
2244 curve
[n
] = curve
[n
+1] = gTrue
;
2245 curve
[n
+2] = gFalse
;
2249 void GfxSubpath::close() {
2250 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
2256 void GfxSubpath::offset(double dx
, double dy
) {
2259 for (i
= 0; i
< n
; ++i
) {
2265 GfxPath::GfxPath() {
2269 firstX
= firstY
= 0;
2270 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
2273 GfxPath::~GfxPath() {
2276 for (i
= 0; i
< n
; ++i
)
2282 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
2283 GfxSubpath
**subpaths1
, int n1
, int size1
) {
2286 justMoved
= justMoved1
;
2291 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
2292 for (i
= 0; i
< n
; ++i
)
2293 subpaths
[i
] = subpaths1
[i
]->copy();
2296 void GfxPath::moveTo(double x
, double y
) {
2302 void GfxPath::lineTo(double x
, double y
) {
2306 subpaths
= (GfxSubpath
**)
2307 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2309 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
2313 subpaths
[n
-1]->lineTo(x
, y
);
2316 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
2317 double x3
, double y3
) {
2321 subpaths
= (GfxSubpath
**)
2322 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2324 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
2328 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
2331 void GfxPath::close() {
2332 // this is necessary to handle the pathological case of
2333 // moveto/closepath/clip, which defines an empty clipping region
2337 subpaths
= (GfxSubpath
**)
2338 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2340 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
2344 subpaths
[n
-1]->close();
2347 void GfxPath::append(GfxPath
*path
) {
2350 if (n
+ path
->n
> size
) {
2352 subpaths
= (GfxSubpath
**)
2353 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2355 for (i
= 0; i
< path
->n
; ++i
) {
2356 subpaths
[n
++] = path
->subpaths
[i
]->copy();
2361 void GfxPath::offset(double dx
, double dy
) {
2364 for (i
= 0; i
< n
; ++i
) {
2365 subpaths
[i
]->offset(dx
, dy
);
2369 //------------------------------------------------------------------------
2371 //------------------------------------------------------------------------
2373 GfxState::GfxState(double hDPI
, double vDPI
, PDFRectangle
*pageBox
,
2374 int rotate
, GBool upsideDown
) {
2385 ctm
[1] = upsideDown
? ky
: -ky
;
2389 ctm
[5] = ky
* (upsideDown
? -px1
: px2
);
2390 pageWidth
= kx
* (py2
- py1
);
2391 pageHeight
= ky
* (px2
- px1
);
2392 } else if (rotate
== 180) {
2396 ctm
[3] = upsideDown
? ky
: -ky
;
2398 ctm
[5] = ky
* (upsideDown
? -py1
: py2
);
2399 pageWidth
= kx
* (px2
- px1
);
2400 pageHeight
= ky
* (py2
- py1
);
2401 } else if (rotate
== 270) {
2403 ctm
[1] = upsideDown
? -ky
: ky
;
2407 ctm
[5] = ky
* (upsideDown
? px2
: -px1
);
2408 pageWidth
= kx
* (py2
- py1
);
2409 pageHeight
= ky
* (px2
- px1
);
2414 ctm
[3] = upsideDown
? -ky
: ky
;
2416 ctm
[5] = ky
* (upsideDown
? py2
: -py1
);
2417 pageWidth
= kx
* (px2
- px1
);
2418 pageHeight
= ky
* (py2
- py1
);
2421 fillColorSpace
= new GfxDeviceGrayColorSpace();
2422 strokeColorSpace
= new GfxDeviceGrayColorSpace();
2424 strokeColor
.c
[0] = 0;
2426 strokePattern
= NULL
;
2441 textMat
[0] = 1; textMat
[1] = 0;
2442 textMat
[2] = 0; textMat
[3] = 1;
2443 textMat
[4] = 0; textMat
[5] = 0;
2451 path
= new GfxPath();
2457 clipXMax
= pageWidth
;
2458 clipYMax
= pageHeight
;
2463 GfxState::~GfxState() {
2464 if (fillColorSpace
) {
2465 delete fillColorSpace
;
2467 if (strokeColorSpace
) {
2468 delete strokeColorSpace
;
2473 if (strokePattern
) {
2474 delete strokePattern
;
2478 // this gets set to NULL by restore()
2487 GfxState::GfxState(GfxState
*state
) {
2488 memcpy(this, state
, sizeof(GfxState
));
2489 if (fillColorSpace
) {
2490 fillColorSpace
= state
->fillColorSpace
->copy();
2492 if (strokeColorSpace
) {
2493 strokeColorSpace
= state
->strokeColorSpace
->copy();
2496 fillPattern
= state
->fillPattern
->copy();
2498 if (strokePattern
) {
2499 strokePattern
= state
->strokePattern
->copy();
2501 if (lineDashLength
> 0) {
2502 lineDash
= (double *)gmalloc(lineDashLength
* sizeof(double));
2503 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
2508 void GfxState::setPath(GfxPath
*pathA
) {
2513 void GfxState::getUserClipBBox(double *xMin
, double *yMin
,
2514 double *xMax
, double *yMax
) {
2516 double xMin1
, yMin1
, xMax1
, yMax1
, det
, tx
, ty
;
2519 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
2520 ictm
[0] = ctm
[3] * det
;
2521 ictm
[1] = -ctm
[1] * det
;
2522 ictm
[2] = -ctm
[2] * det
;
2523 ictm
[3] = ctm
[0] * det
;
2524 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
2525 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
2527 // transform all four corners of the clip bbox; find the min and max
2529 xMin1
= xMax1
= clipXMin
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
2530 yMin1
= yMax1
= clipXMin
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
2531 tx
= clipXMin
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
2532 ty
= clipXMin
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
2535 } else if (tx
> xMax1
) {
2540 } else if (ty
> yMax1
) {
2543 tx
= clipXMax
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
2544 ty
= clipXMax
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
2547 } else if (tx
> xMax1
) {
2552 } else if (ty
> yMax1
) {
2555 tx
= clipXMax
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
2556 ty
= clipXMax
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
2559 } else if (tx
> xMax1
) {
2564 } else if (ty
> yMax1
) {
2574 double GfxState::transformWidth(double w
) {
2577 x
= ctm
[0] + ctm
[2];
2578 y
= ctm
[1] + ctm
[3];
2579 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
2582 double GfxState::getTransformedFontSize() {
2583 double x1
, y1
, x2
, y2
;
2585 x1
= textMat
[2] * fontSize
;
2586 y1
= textMat
[3] * fontSize
;
2587 x2
= ctm
[0] * x1
+ ctm
[2] * y1
;
2588 y2
= ctm
[1] * x1
+ ctm
[3] * y1
;
2589 return sqrt(x2
* x2
+ y2
* y2
);
2592 void GfxState::getFontTransMat(double *m11
, double *m12
,
2593 double *m21
, double *m22
) {
2594 *m11
= (textMat
[0] * ctm
[0] + textMat
[1] * ctm
[2]) * fontSize
;
2595 *m12
= (textMat
[0] * ctm
[1] + textMat
[1] * ctm
[3]) * fontSize
;
2596 *m21
= (textMat
[2] * ctm
[0] + textMat
[3] * ctm
[2]) * fontSize
;
2597 *m22
= (textMat
[2] * ctm
[1] + textMat
[3] * ctm
[3]) * fontSize
;
2600 void GfxState::setCTM(double a
, double b
, double c
,
2601 double d
, double e
, double f
) {
2611 // avoid FP exceptions on badly messed up PDF files
2612 for (i
= 0; i
< 6; ++i
) {
2613 if (ctm
[i
] > 1e10
) {
2615 } else if (ctm
[i
] < -1e10
) {
2621 void GfxState::concatCTM(double a
, double b
, double c
,
2622 double d
, double e
, double f
) {
2629 ctm
[0] = a
* a1
+ b
* c1
;
2630 ctm
[1] = a
* b1
+ b
* d1
;
2631 ctm
[2] = c
* a1
+ d
* c1
;
2632 ctm
[3] = c
* b1
+ d
* d1
;
2633 ctm
[4] = e
* a1
+ f
* c1
+ ctm
[4];
2634 ctm
[5] = e
* b1
+ f
* d1
+ ctm
[5];
2636 // avoid FP exceptions on badly messed up PDF files
2637 for (i
= 0; i
< 6; ++i
) {
2638 if (ctm
[i
] > 1e10
) {
2640 } else if (ctm
[i
] < -1e10
) {
2646 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
2647 if (fillColorSpace
) {
2648 delete fillColorSpace
;
2650 fillColorSpace
= colorSpace
;
2653 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
2654 if (strokeColorSpace
) {
2655 delete strokeColorSpace
;
2657 strokeColorSpace
= colorSpace
;
2660 void GfxState::setFillPattern(GfxPattern
*pattern
) {
2664 fillPattern
= pattern
;
2667 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
2668 if (strokePattern
) {
2669 delete strokePattern
;
2671 strokePattern
= pattern
;
2674 void GfxState::setLineDash(double *dash
, int length
, double start
) {
2678 lineDashLength
= length
;
2679 lineDashStart
= start
;
2682 void GfxState::clearPath() {
2684 path
= new GfxPath();
2687 void GfxState::clip() {
2688 double xMin
, yMin
, xMax
, yMax
, x
, y
;
2689 GfxSubpath
*subpath
;
2692 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
2693 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
2694 subpath
= path
->getSubpath(i
);
2695 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
2696 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
2697 if (i
== 0 && j
== 0) {
2703 } else if (x
> xMax
) {
2708 } else if (y
> yMax
) {
2714 if (xMin
> clipXMin
) {
2717 if (yMin
> clipYMin
) {
2720 if (xMax
< clipXMax
) {
2723 if (yMax
< clipYMax
) {
2728 void GfxState::textShift(double tx
, double ty
) {
2731 textTransformDelta(tx
, ty
, &dx
, &dy
);
2736 void GfxState::shift(double dx
, double dy
) {
2741 GfxState
*GfxState::save() {
2745 newState
->saved
= this;
2749 GfxState
*GfxState::restore() {
2755 // these attributes aren't saved/restored by the q/Q operators
2756 oldState
->path
= path
;
2757 oldState
->curX
= curX
;
2758 oldState
->curY
= curY
;
2759 oldState
->lineX
= lineX
;
2760 oldState
->lineY
= lineY
;