1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
16 #include <string.h> // for memcpy()
24 //------------------------------------------------------------------------
26 static inline double clip01(double x
) {
27 return (x
< 0) ? 0 : ((x
> 1) ? 1 : x
);
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 GfxColorSpace::GfxColorSpace() {
37 GfxColorSpace::~GfxColorSpace() {
40 GfxColorSpace
*GfxColorSpace::parse(Object
*csObj
) {
45 if (csObj
->isName()) {
46 if (csObj
->isName("DeviceGray") || csObj
->isName("G")) {
47 cs
= new GfxDeviceGrayColorSpace();
48 } else if (csObj
->isName("DeviceRGB") || csObj
->isName("RGB")) {
49 cs
= new GfxDeviceRGBColorSpace();
50 } else if (csObj
->isName("DeviceCMYK") || csObj
->isName("CMYK")) {
51 cs
= new GfxDeviceCMYKColorSpace();
52 } else if (csObj
->isName("Pattern")) {
53 cs
= new GfxPatternColorSpace(NULL
);
55 error(-1, "Bad color space '%s'", csObj
->getName());
57 } else if (csObj
->isArray()) {
58 csObj
->arrayGet(0, &obj1
);
59 if (obj1
.isName("DeviceGray") || obj1
.isName("G")) {
60 cs
= new GfxDeviceGrayColorSpace();
61 } else if (obj1
.isName("DeviceRGB") || obj1
.isName("RGB")) {
62 cs
= new GfxDeviceRGBColorSpace();
63 } else if (obj1
.isName("DeviceCMYK") || obj1
.isName("CMYK")) {
64 cs
= new GfxDeviceCMYKColorSpace();
65 } else if (obj1
.isName("CalGray")) {
66 cs
= GfxCalGrayColorSpace::parse(csObj
->getArray());
67 } else if (obj1
.isName("CalRGB")) {
68 cs
= GfxCalRGBColorSpace::parse(csObj
->getArray());
69 } else if (obj1
.isName("Lab")) {
70 cs
= GfxLabColorSpace::parse(csObj
->getArray());
71 } else if (obj1
.isName("ICCBased")) {
72 cs
= GfxICCBasedColorSpace::parse(csObj
->getArray());
73 } else if (obj1
.isName("Indexed") || obj1
.isName("I")) {
74 cs
= GfxIndexedColorSpace::parse(csObj
->getArray());
75 } else if (obj1
.isName("Separation")) {
76 cs
= GfxSeparationColorSpace::parse(csObj
->getArray());
77 } else if (obj1
.isName("DeviceN")) {
78 cs
= GfxDeviceNColorSpace::parse(csObj
->getArray());
79 } else if (obj1
.isName("Pattern")) {
80 cs
= GfxPatternColorSpace::parse(csObj
->getArray());
82 error(-1, "Bad color space '%s'", csObj
->getName());
86 error(-1, "Bad color space - expected name or array");
91 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
95 for (i
= 0; i
< getNComps(); ++i
) {
101 //------------------------------------------------------------------------
102 // GfxDeviceGrayColorSpace
103 //------------------------------------------------------------------------
105 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
108 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
111 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
115 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
116 *gray
= clip01(color
->c
[0]);
119 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
120 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
123 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
124 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
125 cmyk
->k
= clip01(1 - color
->c
[0]);
128 //------------------------------------------------------------------------
129 // GfxCalGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX
= whiteY
= whiteZ
= 1;
134 blackX
= blackY
= blackZ
= 0;
138 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
141 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace
*cs
;
144 cs
= new GfxCalGrayColorSpace();
155 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
) {
156 GfxCalGrayColorSpace
*cs
;
157 Object obj1
, obj2
, obj3
;
160 if (!obj1
.isDict()) {
161 error(-1, "Bad CalGray color space");
165 cs
= new GfxCalGrayColorSpace();
166 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
167 obj2
.arrayGetLength() == 3) {
168 obj2
.arrayGet(0, &obj3
);
169 cs
->whiteX
= obj3
.getNum();
171 obj2
.arrayGet(1, &obj3
);
172 cs
->whiteY
= obj3
.getNum();
174 obj2
.arrayGet(2, &obj3
);
175 cs
->whiteZ
= obj3
.getNum();
179 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
180 obj2
.arrayGetLength() == 3) {
181 obj2
.arrayGet(0, &obj3
);
182 cs
->blackX
= obj3
.getNum();
184 obj2
.arrayGet(1, &obj3
);
185 cs
->blackY
= obj3
.getNum();
187 obj2
.arrayGet(2, &obj3
);
188 cs
->blackZ
= obj3
.getNum();
192 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
193 cs
->gamma
= obj2
.getNum();
200 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
201 *gray
= clip01(color
->c
[0]);
204 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
205 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
208 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
209 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
210 cmyk
->k
= clip01(1 - color
->c
[0]);
213 //------------------------------------------------------------------------
214 // GfxDeviceRGBColorSpace
215 //------------------------------------------------------------------------
217 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
220 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
223 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
227 void GfxDeviceRGBColorSpace::getGray(GfxColor
*color
, double *gray
) {
228 *gray
= clip01(0.299 * color
->c
[0] +
229 0.587 * color
->c
[1] +
230 0.114 * color
->c
[2]);
233 void GfxDeviceRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
234 rgb
->r
= clip01(color
->c
[0]);
235 rgb
->g
= clip01(color
->c
[1]);
236 rgb
->b
= clip01(color
->c
[2]);
239 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
242 c
= clip01(1 - color
->c
[0]);
243 m
= clip01(1 - color
->c
[1]);
244 y
= clip01(1 - color
->c
[2]);
258 //------------------------------------------------------------------------
259 // GfxCalRGBColorSpace
260 //------------------------------------------------------------------------
262 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
263 whiteX
= whiteY
= whiteZ
= 1;
264 blackX
= blackY
= blackZ
= 0;
265 gammaR
= gammaG
= gammaB
= 1;
266 mat
[0] = 1; mat
[1] = 0; mat
[2] = 0;
267 mat
[3] = 0; mat
[4] = 1; mat
[5] = 0;
268 mat
[6] = 0; mat
[7] = 0; mat
[8] = 1;
271 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
274 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace
*cs
;
278 cs
= new GfxCalRGBColorSpace();
288 for (i
= 0; i
< 9; ++i
) {
294 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
) {
295 GfxCalRGBColorSpace
*cs
;
296 Object obj1
, obj2
, obj3
;
300 if (!obj1
.isDict()) {
301 error(-1, "Bad CalRGB color space");
305 cs
= new GfxCalRGBColorSpace();
306 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
307 obj2
.arrayGetLength() == 3) {
308 obj2
.arrayGet(0, &obj3
);
309 cs
->whiteX
= obj3
.getNum();
311 obj2
.arrayGet(1, &obj3
);
312 cs
->whiteY
= obj3
.getNum();
314 obj2
.arrayGet(2, &obj3
);
315 cs
->whiteZ
= obj3
.getNum();
319 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
320 obj2
.arrayGetLength() == 3) {
321 obj2
.arrayGet(0, &obj3
);
322 cs
->blackX
= obj3
.getNum();
324 obj2
.arrayGet(1, &obj3
);
325 cs
->blackY
= obj3
.getNum();
327 obj2
.arrayGet(2, &obj3
);
328 cs
->blackZ
= obj3
.getNum();
332 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
333 obj2
.arrayGetLength() == 3) {
334 obj2
.arrayGet(0, &obj3
);
335 cs
->gammaR
= obj3
.getNum();
337 obj2
.arrayGet(1, &obj3
);
338 cs
->gammaG
= obj3
.getNum();
340 obj2
.arrayGet(2, &obj3
);
341 cs
->gammaB
= obj3
.getNum();
345 if (obj1
.dictLookup("Matrix", &obj2
)->isArray() &&
346 obj2
.arrayGetLength() == 9) {
347 for (i
= 0; i
< 9; ++i
) {
348 obj2
.arrayGet(i
, &obj3
);
349 cs
->mat
[i
] = obj3
.getNum();
358 void GfxCalRGBColorSpace::getGray(GfxColor
*color
, double *gray
) {
359 *gray
= clip01(0.299 * color
->c
[0] +
360 0.587 * color
->c
[1] +
361 0.114 * color
->c
[2]);
364 void GfxCalRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
365 rgb
->r
= clip01(color
->c
[0]);
366 rgb
->g
= clip01(color
->c
[1]);
367 rgb
->b
= clip01(color
->c
[2]);
370 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
373 c
= clip01(1 - color
->c
[0]);
374 m
= clip01(1 - color
->c
[1]);
375 y
= clip01(1 - color
->c
[2]);
389 //------------------------------------------------------------------------
390 // GfxDeviceCMYKColorSpace
391 //------------------------------------------------------------------------
393 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
396 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
399 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
403 void GfxDeviceCMYKColorSpace::getGray(GfxColor
*color
, double *gray
) {
404 *gray
= clip01(1 - color
->c
[3]
405 - 0.299 * color
->c
[0]
406 - 0.587 * color
->c
[1]
407 - 0.114 * color
->c
[2]);
410 void GfxDeviceCMYKColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
411 double c
, m
, y
, aw
, ac
, am
, ay
, ar
, ag
, ab
;
413 c
= clip01(color
->c
[0] + color
->c
[3]);
414 m
= clip01(color
->c
[1] + color
->c
[3]);
415 y
= clip01(color
->c
[2] + color
->c
[3]);
416 aw
= (1-c
) * (1-m
) * (1-y
);
417 ac
= c
* (1-m
) * (1-y
);
418 am
= (1-c
) * m
* (1-y
);
419 ay
= (1-c
) * (1-m
) * y
;
423 rgb
->r
= clip01(aw
+ 0.9137*am
+ 0.9961*ay
+ 0.9882*ar
);
424 rgb
->g
= clip01(aw
+ 0.6196*ac
+ ay
+ 0.5176*ag
);
425 rgb
->b
= clip01(aw
+ 0.7804*ac
+ 0.5412*am
+ 0.0667*ar
+ 0.2118*ag
+
429 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
430 cmyk
->c
= clip01(color
->c
[0]);
431 cmyk
->m
= clip01(color
->c
[1]);
432 cmyk
->y
= clip01(color
->c
[2]);
433 cmyk
->k
= clip01(color
->c
[3]);
436 //------------------------------------------------------------------------
438 //------------------------------------------------------------------------
440 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
441 // Language Reference, Third Edition.
442 static double xyzrgb
[3][3] = {
443 { 3.240449, -1.537136, -0.498531 },
444 { -0.969265, 1.876011, 0.041556 },
445 { 0.055643, -0.204026, 1.057229 }
448 GfxLabColorSpace::GfxLabColorSpace() {
449 whiteX
= whiteY
= whiteZ
= 1;
450 blackX
= blackY
= blackZ
= 0;
455 GfxLabColorSpace::~GfxLabColorSpace() {
458 GfxColorSpace
*GfxLabColorSpace::copy() {
459 GfxLabColorSpace
*cs
;
461 cs
= new GfxLabColorSpace();
478 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
) {
479 GfxLabColorSpace
*cs
;
480 Object obj1
, obj2
, obj3
;
483 if (!obj1
.isDict()) {
484 error(-1, "Bad Lab color space");
488 cs
= new GfxLabColorSpace();
489 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
490 obj2
.arrayGetLength() == 3) {
491 obj2
.arrayGet(0, &obj3
);
492 cs
->whiteX
= obj3
.getNum();
494 obj2
.arrayGet(1, &obj3
);
495 cs
->whiteY
= obj3
.getNum();
497 obj2
.arrayGet(2, &obj3
);
498 cs
->whiteZ
= obj3
.getNum();
502 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
503 obj2
.arrayGetLength() == 3) {
504 obj2
.arrayGet(0, &obj3
);
505 cs
->blackX
= obj3
.getNum();
507 obj2
.arrayGet(1, &obj3
);
508 cs
->blackY
= obj3
.getNum();
510 obj2
.arrayGet(2, &obj3
);
511 cs
->blackZ
= obj3
.getNum();
515 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
516 obj2
.arrayGetLength() == 4) {
517 obj2
.arrayGet(0, &obj3
);
518 cs
->aMin
= obj3
.getNum();
520 obj2
.arrayGet(1, &obj3
);
521 cs
->aMax
= obj3
.getNum();
523 obj2
.arrayGet(2, &obj3
);
524 cs
->bMin
= obj3
.getNum();
526 obj2
.arrayGet(3, &obj3
);
527 cs
->bMax
= obj3
.getNum();
533 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
534 xyzrgb
[0][1] * cs
->whiteY
+
535 xyzrgb
[0][2] * cs
->whiteZ
);
536 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
537 xyzrgb
[1][1] * cs
->whiteY
+
538 xyzrgb
[1][2] * cs
->whiteZ
);
539 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
540 xyzrgb
[2][1] * cs
->whiteY
+
541 xyzrgb
[2][2] * cs
->whiteZ
);
546 void GfxLabColorSpace::getGray(GfxColor
*color
, double *gray
) {
550 *gray
= clip01(0.299 * rgb
.r
+
555 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
560 // convert L*a*b* to CIE 1931 XYZ color space
561 t1
= (color
->c
[0] + 16) / 116;
562 t2
= t1
+ color
->c
[1] / 500;
563 if (t2
>= (6.0 / 29.0)) {
566 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
569 if (t1
>= (6.0 / 29.0)) {
572 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
575 t2
= t1
- color
->c
[2] / 200;
576 if (t2
>= (6.0 / 29.0)) {
579 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
583 // convert XYZ to RGB, including gamut mapping and gamma correction
584 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
585 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
586 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
587 rgb
->r
= pow(clip01(r
* kr
), 0.5);
588 rgb
->g
= pow(clip01(g
* kg
), 0.5);
589 rgb
->b
= pow(clip01(b
* kb
), 0.5);
592 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
597 c
= clip01(1 - rgb
.r
);
598 m
= clip01(1 - rgb
.g
);
599 y
= clip01(1 - rgb
.b
);
613 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
616 decodeRange
[0] = 100;
618 decodeRange
[1] = aMax
- aMin
;
620 decodeRange
[2] = bMax
- bMin
;
623 //------------------------------------------------------------------------
624 // GfxICCBasedColorSpace
625 //------------------------------------------------------------------------
627 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA
, GfxColorSpace
*altA
,
628 Ref
*iccProfileStreamA
) {
631 iccProfileStream
= *iccProfileStreamA
;
632 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
633 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
636 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
640 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
641 GfxICCBasedColorSpace
*cs
;
644 cs
= new GfxICCBasedColorSpace(nComps
, alt
->copy(), &iccProfileStream
);
645 for (i
= 0; i
< 4; ++i
) {
646 cs
->rangeMin
[i
] = rangeMin
[i
];
647 cs
->rangeMax
[i
] = rangeMax
[i
];
652 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
) {
653 GfxICCBasedColorSpace
*cs
;
654 Ref iccProfileStreamA
;
658 Object obj1
, obj2
, obj3
;
661 arr
->getNF(1, &obj1
);
663 iccProfileStreamA
= obj1
.getRef();
665 iccProfileStreamA
.num
= 0;
666 iccProfileStreamA
.gen
= 0;
670 if (!obj1
.isStream()) {
671 error(-1, "Bad ICCBased color space (stream)");
675 dict
= obj1
.streamGetDict();
676 if (!dict
->lookup("N", &obj2
)->isInt()) {
677 error(-1, "Bad ICCBased color space (N)");
682 nCompsA
= obj2
.getInt();
684 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
685 !(altA
= GfxColorSpace::parse(&obj2
))) {
688 altA
= new GfxDeviceGrayColorSpace();
691 altA
= new GfxDeviceRGBColorSpace();
694 altA
= new GfxDeviceCMYKColorSpace();
697 error(-1, "Bad ICCBased color space - invalid N");
704 cs
= new GfxICCBasedColorSpace(nCompsA
, altA
, &iccProfileStreamA
);
705 if (dict
->lookup("Range", &obj2
)->isArray() &&
706 obj2
.arrayGetLength() == 2 * nCompsA
) {
707 for (i
= 0; i
< nCompsA
; ++i
) {
708 obj2
.arrayGet(2*i
, &obj3
);
709 cs
->rangeMin
[i
] = obj3
.getNum();
711 obj2
.arrayGet(2*i
+1, &obj3
);
712 cs
->rangeMax
[i
] = obj3
.getNum();
721 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, double *gray
) {
722 alt
->getGray(color
, gray
);
725 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
726 alt
->getRGB(color
, rgb
);
729 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
730 alt
->getCMYK(color
, cmyk
);
733 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
738 for (i
= 0; i
< nComps
; ++i
) {
739 decodeLow
[i
] = rangeMin
[i
];
740 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
744 //------------------------------------------------------------------------
745 // GfxIndexedColorSpace
746 //------------------------------------------------------------------------
748 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*baseA
,
751 indexHigh
= indexHighA
;
752 lookup
= (Guchar
*)gmalloc((indexHigh
+ 1) * base
->getNComps() *
756 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
761 GfxColorSpace
*GfxIndexedColorSpace::copy() {
762 GfxIndexedColorSpace
*cs
;
764 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
765 memcpy(cs
->lookup
, lookup
,
766 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
770 GfxColorSpace
*GfxIndexedColorSpace::parse(Array
*arr
) {
771 GfxIndexedColorSpace
*cs
;
772 GfxColorSpace
*baseA
;
779 if (arr
->getLength() != 4) {
780 error(-1, "Bad Indexed color space");
784 if (!(baseA
= GfxColorSpace::parse(&obj1
))) {
785 error(-1, "Bad Indexed color space (base color space)");
789 if (!arr
->get(2, &obj1
)->isInt()) {
790 error(-1, "Bad Indexed color space (hival)");
793 indexHighA
= obj1
.getInt();
795 cs
= new GfxIndexedColorSpace(baseA
, indexHighA
);
797 n
= baseA
->getNComps();
798 if (obj1
.isStream()) {
800 for (i
= 0; i
<= indexHighA
; ++i
) {
801 for (j
= 0; j
< n
; ++j
) {
802 if ((x
= obj1
.streamGetChar()) == EOF
) {
803 error(-1, "Bad Indexed color space (lookup table stream too short)");
806 cs
->lookup
[i
*n
+ j
] = (Guchar
)x
;
810 } else if (obj1
.isString()) {
811 if (obj1
.getString()->getLength() < (indexHighA
+ 1) * n
) {
812 error(-1, "Bad Indexed color space (lookup table string too short)");
815 s
= obj1
.getString()->getCString();
816 for (i
= 0; i
<= indexHighA
; ++i
) {
817 for (j
= 0; j
< n
; ++j
) {
818 cs
->lookup
[i
*n
+ j
] = (Guchar
)*s
++;
822 error(-1, "Bad Indexed color space (lookup table)");
836 void GfxIndexedColorSpace::getGray(GfxColor
*color
, double *gray
) {
841 n
= base
->getNComps();
842 p
= &lookup
[(int)(color
->c
[0] + 0.5) * n
];
843 for (i
= 0; i
< n
; ++i
) {
844 color2
.c
[i
] = p
[i
] / 255.0;
846 base
->getGray(&color2
, gray
);
849 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
854 n
= base
->getNComps();
855 p
= &lookup
[(int)(color
->c
[0] + 0.5) * n
];
856 for (i
= 0; i
< n
; ++i
) {
857 color2
.c
[i
] = p
[i
] / 255.0;
859 base
->getRGB(&color2
, rgb
);
862 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
867 n
= base
->getNComps();
868 p
= &lookup
[(int)(color
->c
[0] + 0.5) * n
];
869 for (i
= 0; i
< n
; ++i
) {
870 color2
.c
[i
] = p
[i
] / 255.0;
872 base
->getCMYK(&color2
, cmyk
);
875 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
879 decodeRange
[0] = maxImgPixel
;
882 //------------------------------------------------------------------------
883 // GfxSeparationColorSpace
884 //------------------------------------------------------------------------
886 GfxSeparationColorSpace::GfxSeparationColorSpace(GString
*nameA
,
894 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
900 GfxColorSpace
*GfxSeparationColorSpace::copy() {
901 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy());
904 //~ handle the 'All' and 'None' colorants
905 GfxColorSpace
*GfxSeparationColorSpace::parse(Array
*arr
) {
906 GfxSeparationColorSpace
*cs
;
912 if (arr
->getLength() != 4) {
913 error(-1, "Bad Separation color space");
916 if (!arr
->get(1, &obj1
)->isName()) {
917 error(-1, "Bad Separation color space (name)");
920 nameA
= new GString(obj1
.getName());
923 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
924 error(-1, "Bad Separation color space (alternate color space)");
929 if (!(funcA
= Function::parse(&obj1
))) {
933 cs
= new GfxSeparationColorSpace(nameA
, altA
, funcA
);
946 void GfxSeparationColorSpace::getGray(GfxColor
*color
, double *gray
) {
949 func
->transform(color
->c
, color2
.c
);
950 alt
->getGray(&color2
, gray
);
953 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
956 func
->transform(color
->c
, color2
.c
);
957 alt
->getRGB(&color2
, rgb
);
960 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
963 func
->transform(color
->c
, color2
.c
);
964 alt
->getCMYK(&color2
, cmyk
);
967 //------------------------------------------------------------------------
968 // GfxDeviceNColorSpace
969 //------------------------------------------------------------------------
971 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
979 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
982 for (i
= 0; i
< nComps
; ++i
) {
989 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
990 GfxDeviceNColorSpace
*cs
;
993 cs
= new GfxDeviceNColorSpace(nComps
, alt
->copy(), func
->copy());
994 for (i
= 0; i
< nComps
; ++i
) {
995 cs
->names
[i
] = names
[i
]->copy();
1000 //~ handle the 'None' colorant
1001 GfxColorSpace
*GfxDeviceNColorSpace::parse(Array
*arr
) {
1002 GfxDeviceNColorSpace
*cs
;
1004 GString
*namesA
[gfxColorMaxComps
];
1005 GfxColorSpace
*altA
;
1010 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
1011 error(-1, "Bad DeviceN color space");
1014 if (!arr
->get(1, &obj1
)->isArray()) {
1015 error(-1, "Bad DeviceN color space (names)");
1018 nCompsA
= obj1
.arrayGetLength();
1019 for (i
= 0; i
< nCompsA
; ++i
) {
1020 if (!obj1
.arrayGet(i
, &obj2
)->isName()) {
1021 error(-1, "Bad DeviceN color space (names)");
1025 namesA
[i
] = new GString(obj2
.getName());
1030 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1031 error(-1, "Bad DeviceN color space (alternate color space)");
1036 if (!(funcA
= Function::parse(&obj1
))) {
1040 cs
= new GfxDeviceNColorSpace(nCompsA
, altA
, funcA
);
1041 for (i
= 0; i
< nCompsA
; ++i
) {
1042 cs
->names
[i
] = namesA
[i
];
1049 for (i
= 0; i
< nCompsA
; ++i
) {
1058 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, double *gray
) {
1061 func
->transform(color
->c
, color2
.c
);
1062 alt
->getGray(&color2
, gray
);
1065 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1068 func
->transform(color
->c
, color2
.c
);
1069 alt
->getRGB(&color2
, rgb
);
1072 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1075 func
->transform(color
->c
, color2
.c
);
1076 alt
->getCMYK(&color2
, cmyk
);
1079 //------------------------------------------------------------------------
1080 // GfxPatternColorSpace
1081 //------------------------------------------------------------------------
1083 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*underA
) {
1087 GfxPatternColorSpace::~GfxPatternColorSpace() {
1093 GfxColorSpace
*GfxPatternColorSpace::copy() {
1094 return new GfxPatternColorSpace(under
? under
->copy() :
1095 (GfxColorSpace
*)NULL
);
1098 GfxColorSpace
*GfxPatternColorSpace::parse(Array
*arr
) {
1099 GfxPatternColorSpace
*cs
;
1100 GfxColorSpace
*underA
;
1103 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
1104 error(-1, "Bad Pattern color space");
1108 if (arr
->getLength() == 2) {
1110 if (!(underA
= GfxColorSpace::parse(&obj1
))) {
1111 error(-1, "Bad Pattern color space (underlying color space)");
1117 cs
= new GfxPatternColorSpace(underA
);
1121 void GfxPatternColorSpace::getGray(GfxColor
*color
, double *gray
) {
1125 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1126 rgb
->r
= rgb
->g
= rgb
->b
= 0;
1129 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1130 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
1134 //------------------------------------------------------------------------
1136 //------------------------------------------------------------------------
1138 GfxPattern::GfxPattern(int typeA
) {
1142 GfxPattern::~GfxPattern() {
1145 GfxPattern
*GfxPattern::parse(Object
*obj
) {
1146 GfxPattern
*pattern
;
1151 if (obj
->isStream()) {
1152 dict
= obj
->streamGetDict();
1153 dict
->lookup("PatternType", &obj1
);
1154 if (obj1
.isInt() && obj1
.getInt() == 1) {
1155 pattern
= new GfxTilingPattern(dict
, obj
);
1162 //------------------------------------------------------------------------
1164 //------------------------------------------------------------------------
1166 GfxTilingPattern::GfxTilingPattern(Dict
*streamDict
, Object
*stream
):
1172 if (streamDict
->lookup("PaintType", &obj1
)->isInt()) {
1173 paintType
= obj1
.getInt();
1176 error(-1, "Invalid or missing PaintType in pattern");
1179 if (streamDict
->lookup("TilingType", &obj1
)->isInt()) {
1180 tilingType
= obj1
.getInt();
1183 error(-1, "Invalid or missing TilingType in pattern");
1186 bbox
[0] = bbox
[1] = 0;
1187 bbox
[2] = bbox
[3] = 1;
1188 if (streamDict
->lookup("BBox", &obj1
)->isArray() &&
1189 obj1
.arrayGetLength() == 4) {
1190 for (i
= 0; i
< 4; ++i
) {
1191 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1192 bbox
[i
] = obj2
.getNum();
1197 error(-1, "Invalid or missing BBox in pattern");
1200 if (streamDict
->lookup("XStep", &obj1
)->isNum()) {
1201 xStep
= obj1
.getNum();
1204 error(-1, "Invalid or missing XStep in pattern");
1207 if (streamDict
->lookup("YStep", &obj1
)->isNum()) {
1208 yStep
= obj1
.getNum();
1211 error(-1, "Invalid or missing YStep in pattern");
1214 if (!streamDict
->lookup("Resources", &resDict
)->isDict()) {
1217 error(-1, "Invalid or missing Resources in pattern");
1219 matrix
[0] = 1; matrix
[1] = 0;
1220 matrix
[2] = 0; matrix
[3] = 1;
1221 matrix
[4] = 0; matrix
[5] = 0;
1222 if (streamDict
->lookup("Matrix", &obj1
)->isArray() &&
1223 obj1
.arrayGetLength() == 6) {
1224 for (i
= 0; i
< 6; ++i
) {
1225 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1226 matrix
[i
] = obj2
.getNum();
1232 stream
->copy(&contentStream
);
1235 GfxTilingPattern::~GfxTilingPattern() {
1237 contentStream
.free();
1240 GfxPattern
*GfxTilingPattern::copy() {
1241 return new GfxTilingPattern(this);
1244 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern
*pat
):
1247 memcpy(this, pat
, sizeof(GfxTilingPattern
));
1248 pat
->resDict
.copy(&resDict
);
1249 pat
->contentStream
.copy(&contentStream
);
1252 //------------------------------------------------------------------------
1254 //------------------------------------------------------------------------
1256 GfxShading::GfxShading() {
1259 GfxShading::~GfxShading() {
1263 GfxShading
*GfxShading::parse(Object
*obj
) {
1264 GfxShading
*shading
;
1266 GfxColorSpace
*colorSpaceA
;
1267 GfxColor backgroundA
;
1268 GBool hasBackgroundA
;
1269 double xMinA
, yMinA
, xMaxA
, yMaxA
;
1275 if (obj
->isDict()) {
1277 if (!obj
->dictLookup("ShadingType", &obj1
)->isInt()) {
1278 error(-1, "Invalid ShadingType in shading dictionary");
1282 typeA
= obj1
.getInt();
1285 obj
->dictLookup("ColorSpace", &obj1
);
1286 if (!(colorSpaceA
= GfxColorSpace::parse(&obj1
))) {
1287 error(-1, "Bad color space in shading dictionary");
1293 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1294 backgroundA
.c
[i
] = 0;
1296 hasBackgroundA
= gFalse
;
1297 if (obj
->dictLookup("Background", &obj1
)->isArray()) {
1298 if (obj1
.arrayGetLength() == colorSpaceA
->getNComps()) {
1299 hasBackgroundA
= gTrue
;
1300 for (i
= 0; i
< colorSpaceA
->getNComps(); ++i
) {
1301 backgroundA
.c
[i
] = obj1
.arrayGet(i
, &obj2
)->getNum();
1305 error(-1, "Bad Background in shading dictionary");
1310 xMinA
= yMinA
= xMaxA
= yMaxA
= 0;
1312 if (obj
->dictLookup("BBox", &obj1
)->isArray()) {
1313 if (obj1
.arrayGetLength() == 4) {
1315 xMinA
= obj1
.arrayGet(0, &obj2
)->getNum();
1317 yMinA
= obj1
.arrayGet(1, &obj2
)->getNum();
1319 xMaxA
= obj1
.arrayGet(2, &obj2
)->getNum();
1321 yMaxA
= obj1
.arrayGet(3, &obj2
)->getNum();
1324 error(-1, "Bad BBox in shading dictionary");
1331 shading
= GfxAxialShading::parse(obj
->getDict());
1334 shading
= GfxRadialShading::parse(obj
->getDict());
1337 error(-1, "Unimplemented shading type %d", typeA
);
1342 shading
->type
= typeA
;
1343 shading
->colorSpace
= colorSpaceA
;
1344 shading
->background
= backgroundA
;
1345 shading
->hasBackground
= hasBackgroundA
;
1346 shading
->xMin
= xMinA
;
1347 shading
->yMin
= yMinA
;
1348 shading
->xMax
= xMaxA
;
1349 shading
->yMax
= yMaxA
;
1350 shading
->hasBBox
= hasBBoxA
;
1362 //------------------------------------------------------------------------
1364 //------------------------------------------------------------------------
1366 GfxAxialShading::GfxAxialShading(double x0A
, double y0A
,
1367 double x1A
, double y1A
,
1368 double t0A
, double t1A
,
1369 Function
**funcsA
, int nFuncsA
,
1370 GBool extend0A
, GBool extend1A
) {
1380 for (i
= 0; i
< nFuncs
; ++i
) {
1381 funcs
[i
] = funcsA
[i
];
1387 GfxAxialShading::~GfxAxialShading() {
1390 for (i
= 0; i
< nFuncs
; ++i
) {
1395 GfxAxialShading
*GfxAxialShading::parse(Dict
*dict
) {
1396 double x0A
, y0A
, x1A
, y1A
;
1398 Function
*funcsA
[gfxColorMaxComps
];
1400 GBool extend0A
, extend1A
;
1404 x0A
= y0A
= x1A
= y1A
= 0;
1405 if (dict
->lookup("Coords", &obj1
)->isArray() &&
1406 obj1
.arrayGetLength() == 4) {
1407 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1409 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1411 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1413 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1416 error(-1, "Missing or invalid Coords in shading dictionary");
1423 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1424 obj1
.arrayGetLength() == 2) {
1425 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1427 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
1432 dict
->lookup("Function", &obj1
);
1433 if (obj1
.isArray()) {
1434 nFuncsA
= obj1
.arrayGetLength();
1435 for (i
= 0; i
< nFuncsA
; ++i
) {
1436 obj1
.arrayGet(i
, &obj2
);
1437 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1446 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1453 extend0A
= extend1A
= gFalse
;
1454 if (dict
->lookup("Extend", &obj1
)->isArray() &&
1455 obj1
.arrayGetLength() == 2) {
1456 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
1458 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
1463 return new GfxAxialShading(x0A
, y0A
, x1A
, y1A
, t0A
, t1A
,
1464 funcsA
, nFuncsA
, extend0A
, extend1A
);
1470 void GfxAxialShading::getColor(double t
, GfxColor
*color
) {
1473 for (i
= 0; i
< nFuncs
; ++i
) {
1474 funcs
[i
]->transform(&t
, &color
->c
[i
]);
1478 //------------------------------------------------------------------------
1480 //------------------------------------------------------------------------
1482 GfxRadialShading::GfxRadialShading(double x0A
, double y0A
, double r0A
,
1483 double x1A
, double y1A
, double r1A
,
1484 double t0A
, double t1A
,
1485 Function
**funcsA
, int nFuncsA
,
1486 GBool extend0A
, GBool extend1A
) {
1498 for (i
= 0; i
< nFuncs
; ++i
) {
1499 funcs
[i
] = funcsA
[i
];
1505 GfxRadialShading::~GfxRadialShading() {
1508 for (i
= 0; i
< nFuncs
; ++i
) {
1513 GfxRadialShading
*GfxRadialShading::parse(Dict
*dict
) {
1514 double x0A
, y0A
, r0A
, x1A
, y1A
, r1A
;
1516 Function
*funcsA
[gfxColorMaxComps
];
1518 GBool extend0A
, extend1A
;
1522 x0A
= y0A
= r0A
= x1A
= y1A
= r1A
= 0;
1523 if (dict
->lookup("Coords", &obj1
)->isArray() &&
1524 obj1
.arrayGetLength() == 6) {
1525 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1527 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1529 r0A
= obj1
.arrayGet(2, &obj2
)->getNum();
1531 x1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1533 y1A
= obj1
.arrayGet(4, &obj2
)->getNum();
1535 r1A
= obj1
.arrayGet(5, &obj2
)->getNum();
1538 error(-1, "Missing or invalid Coords in shading dictionary");
1545 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1546 obj1
.arrayGetLength() == 2) {
1547 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1549 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
1554 dict
->lookup("Function", &obj1
);
1555 if (obj1
.isArray()) {
1556 nFuncsA
= obj1
.arrayGetLength();
1557 for (i
= 0; i
< nFuncsA
; ++i
) {
1558 obj1
.arrayGet(i
, &obj2
);
1559 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1568 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1575 extend0A
= extend1A
= gFalse
;
1576 if (dict
->lookup("Extend", &obj1
)->isArray() &&
1577 obj1
.arrayGetLength() == 2) {
1578 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
1580 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
1585 return new GfxRadialShading(x0A
, y0A
, r0A
, x1A
, y1A
, r1A
, t0A
, t1A
,
1586 funcsA
, nFuncsA
, extend0A
, extend1A
);
1592 void GfxRadialShading::getColor(double t
, GfxColor
*color
) {
1595 for (i
= 0; i
< nFuncs
; ++i
) {
1596 funcs
[i
]->transform(&t
, &color
->c
[i
]);
1600 //------------------------------------------------------------------------
1602 //------------------------------------------------------------------------
1604 GfxImageColorMap::GfxImageColorMap(int bitsA
, Object
*decode
,
1605 GfxColorSpace
*colorSpaceA
) {
1606 GfxIndexedColorSpace
*indexedCS
;
1607 GfxSeparationColorSpace
*sepCS
;
1608 int maxPixel
, indexHigh
;
1612 double x
[gfxColorMaxComps
];
1613 double y
[gfxColorMaxComps
];
1615 int maxPixelForAlloc
;
1619 // bits per component and color space
1621 maxPixel
= (1 << bits
) - 1;
1622 maxPixelForAlloc
= (1 << (bits
>8?bits
:8));
1623 colorSpace
= colorSpaceA
;
1626 if (decode
->isNull()) {
1627 nComps
= colorSpace
->getNComps();
1628 colorSpace
->getDefaultRanges(decodeLow
, decodeRange
, maxPixel
);
1629 } else if (decode
->isArray()) {
1630 nComps
= decode
->arrayGetLength() / 2;
1631 if (nComps
!= colorSpace
->getNComps()) {
1634 for (i
= 0; i
< nComps
; ++i
) {
1635 decode
->arrayGet(2*i
, &obj
);
1639 decodeLow
[i
] = obj
.getNum();
1641 decode
->arrayGet(2*i
+1, &obj
);
1645 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
1652 // Construct a lookup table -- this stores pre-computed decoded
1653 // values for each component, i.e., the result of applying the
1654 // decode mapping to each possible image pixel component value.
1656 // Optimization: for Indexed and Separation color spaces (which have
1657 // only one component), we store color values in the lookup table
1658 // rather than component values.
1661 if (colorSpace
->getMode() == csIndexed
) {
1662 // Note that indexHigh may not be the same as maxPixel --
1663 // Distiller will remove unused palette entries, resulting in
1664 // indexHigh < maxPixel.
1665 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
1666 colorSpace2
= indexedCS
->getBase();
1667 indexHigh
= indexedCS
->getIndexHigh();
1668 nComps2
= colorSpace2
->getNComps();
1669 lookup
= (double *)gmalloc((maxPixelForAlloc
+ 1) * nComps2
* sizeof(double));
1670 lookup2
= indexedCS
->getLookup();
1671 for (i
= 0; i
<= indexHigh
; ++i
) {
1672 j
= (int)(decodeLow
[0] +(i
* decodeRange
[0]) / maxPixel
+ 0.5);
1673 for (k
= 0; k
< nComps2
; ++k
) {
1674 lookup
[i
*nComps2
+ k
] = lookup2
[i
*nComps2
+ k
] / 255.0;
1677 } else if (colorSpace
->getMode() == csSeparation
) {
1678 sepCS
= (GfxSeparationColorSpace
*)colorSpace
;
1679 colorSpace2
= sepCS
->getAlt();
1680 nComps2
= colorSpace2
->getNComps();
1681 lookup
= (double *)gmalloc((maxPixelForAlloc
+ 1) * nComps2
* sizeof(double));
1682 sepFunc
= sepCS
->getFunc();
1683 for (i
= 0; i
<= maxPixel
; ++i
) {
1684 x
[0] = decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
;
1685 sepFunc
->transform(x
, y
);
1686 for (k
= 0; k
< nComps2
; ++k
) {
1687 lookup
[i
*nComps2
+ k
] = y
[k
];
1691 lookup
= (double *)gmalloc((maxPixelForAlloc
+ 1) * nComps
* sizeof(double));
1692 for (i
= 0; i
<= maxPixel
; ++i
) {
1693 for (k
= 0; k
< nComps
; ++k
) {
1694 lookup
[i
*nComps
+ k
] = decodeLow
[k
] +
1695 (i
* decodeRange
[k
]) / maxPixel
;
1708 GfxImageColorMap::~GfxImageColorMap() {
1713 void GfxImageColorMap::getGray(Guchar
*x
, double *gray
) {
1719 p
= &lookup
[x
[0] * nComps2
];
1720 for (i
= 0; i
< nComps2
; ++i
) {
1723 colorSpace2
->getGray(&color
, gray
);
1725 for (i
= 0; i
< nComps
; ++i
) {
1726 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
1728 colorSpace
->getGray(&color
, gray
);
1732 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
1739 //printf("lookup[%d] bits=%d\n",x[0],bits);fflush(stdout);
1740 p
= &lookup
[x
[0] * nComps2
];
1741 for (i
= 0; i
< nComps2
; ++i
) {
1744 colorSpace2
->getRGB(&color
, rgb
);
1746 //printf("for i=0,i<%d, bits=%d\n",nComps,bits);fflush(stdout);
1747 for (i
= 0; i
< nComps
; ++i
) {
1748 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
1750 colorSpace
->getRGB(&color
, rgb
);
1754 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
1760 p
= &lookup
[x
[0] * nComps2
];
1761 for (i
= 0; i
< nComps2
; ++i
) {
1764 colorSpace2
->getCMYK(&color
, cmyk
);
1766 for (i
= 0; i
< nComps
; ++i
) {
1767 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
1769 colorSpace
->getCMYK(&color
, cmyk
);
1773 //------------------------------------------------------------------------
1774 // GfxSubpath and GfxPath
1775 //------------------------------------------------------------------------
1777 GfxSubpath::GfxSubpath(double x1
, double y1
) {
1779 x
= (double *)gmalloc(size
* sizeof(double));
1780 y
= (double *)gmalloc(size
* sizeof(double));
1781 curve
= (GBool
*)gmalloc(size
* sizeof(GBool
));
1789 GfxSubpath::~GfxSubpath() {
1796 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
1797 size
= subpath
->size
;
1799 x
= (double *)gmalloc(size
* sizeof(double));
1800 y
= (double *)gmalloc(size
* sizeof(double));
1801 curve
= (GBool
*)gmalloc(size
* sizeof(GBool
));
1802 memcpy(x
, subpath
->x
, n
* sizeof(double));
1803 memcpy(y
, subpath
->y
, n
* sizeof(double));
1804 memcpy(curve
, subpath
->curve
, n
* sizeof(GBool
));
1805 closed
= subpath
->closed
;
1808 void GfxSubpath::lineTo(double x1
, double y1
) {
1811 x
= (double *)grealloc(x
, size
* sizeof(double));
1812 y
= (double *)grealloc(y
, size
* sizeof(double));
1813 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
1821 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
1822 double x3
, double y3
) {
1825 x
= (double *)grealloc(x
, size
* sizeof(double));
1826 y
= (double *)grealloc(y
, size
* sizeof(double));
1827 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
1835 curve
[n
] = curve
[n
+1] = gTrue
;
1836 curve
[n
+2] = gFalse
;
1840 void GfxSubpath::close() {
1841 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
1847 GfxPath::GfxPath() {
1851 firstX
= firstY
= 0;
1852 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
1855 GfxPath::~GfxPath() {
1858 for (i
= 0; i
< n
; ++i
)
1864 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
1865 GfxSubpath
**subpaths1
, int n1
, int size1
) {
1868 justMoved
= justMoved1
;
1873 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
1874 for (i
= 0; i
< n
; ++i
)
1875 subpaths
[i
] = subpaths1
[i
]->copy();
1878 void GfxPath::moveTo(double x
, double y
) {
1884 void GfxPath::lineTo(double x
, double y
) {
1888 subpaths
= (GfxSubpath
**)
1889 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
1891 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
1895 subpaths
[n
-1]->lineTo(x
, y
);
1898 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
1899 double x3
, double y3
) {
1903 subpaths
= (GfxSubpath
**)
1904 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
1906 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
1910 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
1913 void GfxPath::close() {
1914 // this is necessary to handle the pathological case of
1915 // moveto/closepath/clip, which defines an empty clipping region
1919 subpaths
= (GfxSubpath
**)
1920 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
1922 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
1926 subpaths
[n
-1]->close();
1929 //------------------------------------------------------------------------
1931 //------------------------------------------------------------------------
1933 GfxState::GfxState(double dpi
, PDFRectangle
*pageBox
, int rotate
,
1944 ctm
[1] = upsideDown
? k
: -k
;
1948 ctm
[5] = k
* (upsideDown
? -px1
: px2
);
1949 pageWidth
= k
* (py2
- py1
);
1950 pageHeight
= k
* (px2
- px1
);
1951 } else if (rotate
== 180) {
1955 ctm
[3] = upsideDown
? k
: -k
;
1957 ctm
[5] = k
* (upsideDown
? -py1
: py2
);
1958 pageWidth
= k
* (px2
- px1
);
1959 pageHeight
= k
* (py2
- py1
);
1960 } else if (rotate
== 270) {
1962 ctm
[1] = upsideDown
? -k
: k
;
1966 ctm
[5] = k
* (upsideDown
? px2
: -px1
);
1967 pageWidth
= k
* (py2
- py1
);
1968 pageHeight
= k
* (px2
- px1
);
1973 ctm
[3] = upsideDown
? -k
: k
;
1975 ctm
[5] = k
* (upsideDown
? py2
: -py1
);
1976 pageWidth
= k
* (px2
- px1
);
1977 pageHeight
= k
* (py2
- py1
);
1980 fillColorSpace
= new GfxDeviceGrayColorSpace();
1981 strokeColorSpace
= new GfxDeviceGrayColorSpace();
1983 strokeColor
.c
[0] = 0;
1985 strokePattern
= NULL
;
2000 textMat
[0] = 1; textMat
[1] = 0;
2001 textMat
[2] = 0; textMat
[3] = 1;
2002 textMat
[4] = 0; textMat
[5] = 0;
2010 path
= new GfxPath();
2016 clipXMax
= pageWidth
;
2017 clipYMax
= pageHeight
;
2022 GfxState::~GfxState() {
2023 if (fillColorSpace
) {
2024 delete fillColorSpace
;
2026 if (strokeColorSpace
) {
2027 delete strokeColorSpace
;
2032 if (strokePattern
) {
2033 delete strokePattern
;
2037 // this gets set to NULL by restore()
2046 GfxState::GfxState(GfxState
*state
) {
2047 memcpy(this, state
, sizeof(GfxState
));
2048 if (fillColorSpace
) {
2049 fillColorSpace
= state
->fillColorSpace
->copy();
2051 if (strokeColorSpace
) {
2052 strokeColorSpace
= state
->strokeColorSpace
->copy();
2055 fillPattern
= state
->fillPattern
->copy();
2057 if (strokePattern
) {
2058 strokePattern
= state
->strokePattern
->copy();
2060 if (lineDashLength
> 0) {
2061 lineDash
= (double *)gmalloc(lineDashLength
* sizeof(double));
2062 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
2067 void GfxState::getUserClipBBox(double *xMin
, double *yMin
,
2068 double *xMax
, double *yMax
) {
2070 double xMin1
, yMin1
, xMax1
, yMax1
, det
, tx
, ty
;
2073 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
2074 ictm
[0] = ctm
[3] * det
;
2075 ictm
[1] = -ctm
[1] * det
;
2076 ictm
[2] = -ctm
[2] * det
;
2077 ictm
[3] = ctm
[0] * det
;
2078 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
2079 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
2081 // transform all four corners of the clip bbox; find the min and max
2083 xMin1
= xMax1
= clipXMin
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
2084 yMin1
= yMax1
= clipXMin
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
2085 tx
= clipXMin
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
2086 ty
= clipXMin
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
2089 } else if (tx
> xMax1
) {
2094 } else if (ty
> yMax1
) {
2097 tx
= clipXMax
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
2098 ty
= clipXMax
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
2101 } else if (tx
> xMax1
) {
2106 } else if (ty
> yMax1
) {
2109 tx
= clipXMax
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
2110 ty
= clipXMax
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
2113 } else if (tx
> xMax1
) {
2118 } else if (ty
> yMax1
) {
2128 double GfxState::transformWidth(double w
) {
2131 x
= ctm
[0] + ctm
[2];
2132 y
= ctm
[1] + ctm
[3];
2133 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
2136 double GfxState::getTransformedFontSize() {
2137 double x1
, y1
, x2
, y2
;
2139 x1
= textMat
[2] * fontSize
;
2140 y1
= textMat
[3] * fontSize
;
2141 x2
= ctm
[0] * x1
+ ctm
[2] * y1
;
2142 y2
= ctm
[1] * x1
+ ctm
[3] * y1
;
2143 return sqrt(x2
* x2
+ y2
* y2
);
2146 void GfxState::getFontTransMat(double *m11
, double *m12
,
2147 double *m21
, double *m22
) {
2148 *m11
= (textMat
[0] * ctm
[0] + textMat
[1] * ctm
[2]) * fontSize
;
2149 *m12
= (textMat
[0] * ctm
[1] + textMat
[1] * ctm
[3]) * fontSize
;
2150 *m21
= (textMat
[2] * ctm
[0] + textMat
[3] * ctm
[2]) * fontSize
;
2151 *m22
= (textMat
[2] * ctm
[1] + textMat
[3] * ctm
[3]) * fontSize
;
2154 void GfxState::setCTM(double a
, double b
, double c
,
2155 double d
, double e
, double f
) {
2165 // avoid FP exceptions on badly messed up PDF files
2166 for (i
= 0; i
< 6; ++i
) {
2167 if (ctm
[i
] > 1e10
) {
2169 } else if (ctm
[i
] < -1e10
) {
2175 void GfxState::concatCTM(double a
, double b
, double c
,
2176 double d
, double e
, double f
) {
2183 ctm
[0] = a
* a1
+ b
* c1
;
2184 ctm
[1] = a
* b1
+ b
* d1
;
2185 ctm
[2] = c
* a1
+ d
* c1
;
2186 ctm
[3] = c
* b1
+ d
* d1
;
2187 ctm
[4] = e
* a1
+ f
* c1
+ ctm
[4];
2188 ctm
[5] = e
* b1
+ f
* d1
+ ctm
[5];
2190 // avoid FP exceptions on badly messed up PDF files
2191 for (i
= 0; i
< 6; ++i
) {
2192 if (ctm
[i
] > 1e10
) {
2194 } else if (ctm
[i
] < -1e10
) {
2200 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
2201 if (fillColorSpace
) {
2202 delete fillColorSpace
;
2204 fillColorSpace
= colorSpace
;
2207 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
2208 if (strokeColorSpace
) {
2209 delete strokeColorSpace
;
2211 strokeColorSpace
= colorSpace
;
2214 void GfxState::setFillPattern(GfxPattern
*pattern
) {
2218 fillPattern
= pattern
;
2221 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
2222 if (strokePattern
) {
2223 delete strokePattern
;
2225 strokePattern
= pattern
;
2228 void GfxState::setLineDash(double *dash
, int length
, double start
) {
2232 lineDashLength
= length
;
2233 lineDashStart
= start
;
2236 void GfxState::clearPath() {
2238 path
= new GfxPath();
2241 void GfxState::clip() {
2242 double xMin
, yMin
, xMax
, yMax
, x
, y
;
2243 GfxSubpath
*subpath
;
2246 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
2247 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
2248 subpath
= path
->getSubpath(i
);
2249 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
2250 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
2251 if (i
== 0 && j
== 0) {
2257 } else if (x
> xMax
) {
2262 } else if (y
> yMax
) {
2268 if (xMin
> clipXMin
) {
2271 if (yMin
> clipYMin
) {
2274 if (xMax
< clipXMax
) {
2277 if (yMax
< clipYMax
) {
2282 void GfxState::textShift(double tx
, double ty
) {
2285 textTransformDelta(tx
, ty
, &dx
, &dy
);
2290 void GfxState::shift(double dx
, double dy
) {
2295 GfxState
*GfxState::save() {
2299 newState
->saved
= this;
2303 GfxState
*GfxState::restore() {
2309 // these attributes aren't saved/restored by the q/Q operators
2310 oldState
->path
= path
;
2311 oldState
->curX
= curX
;
2312 oldState
->curY
= curY
;
2313 oldState
->lineX
= lineX
;
2314 oldState
->lineY
= lineY
;