1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 #include "UGooString.h"
27 //------------------------------------------------------------------------
29 static inline GfxColorComp
clip01(GfxColorComp x
) {
30 return (x
< 0) ? 0 : (x
> gfxColorComp1
) ? gfxColorComp1
: x
;
33 static inline double clip01(double x
) {
34 return (x
< 0) ? 0 : (x
> 1) ? 1 : x
;
37 GBool
Matrix::invertTo(Matrix
*other
)
41 det
= 1 / (m
[0] * m
[3] - m
[1] * m
[2]);
42 other
->m
[0] = m
[3] * det
;
43 other
->m
[1] = -m
[1] * det
;
44 other
->m
[2] = -m
[2] * det
;
45 other
->m
[3] = m
[0] * det
;
46 other
->m
[4] = (m
[2] * m
[5] - m
[3] * m
[4]) * det
;
47 other
->m
[5] = (m
[1] * m
[4] - m
[0] * m
[5]) * det
;
52 void Matrix::transform(double x
, double y
, double *tx
, double *ty
)
54 double temp_x
, temp_y
;
56 temp_x
= m
[0] * x
+ m
[2] * y
+ m
[4];
57 temp_y
= m
[1] * x
+ m
[3] * y
+ m
[5];
63 //------------------------------------------------------------------------
65 struct gfxBlendModeName
{
70 static gfxBlendModeName gfxBlendModeNames
[] = {
71 { "Normal", gfxBlendNormal
},
72 { "Compatible", gfxBlendNormal
},
73 { "Multiply", gfxBlendMultiply
},
74 { "Screen", gfxBlendScreen
},
75 { "Overlay", gfxBlendOverlay
},
76 { "Darken", gfxBlendDarken
},
77 { "Lighten", gfxBlendLighten
},
78 { "ColorDodge", gfxBlendColorDodge
},
79 { "ColorBurn", gfxBlendColorBurn
},
80 { "HardLight", gfxBlendHardLight
},
81 { "SoftLight", gfxBlendSoftLight
},
82 { "Difference", gfxBlendDifference
},
83 { "Exclusion", gfxBlendExclusion
},
84 { "Hue", gfxBlendHue
},
85 { "Saturation", gfxBlendSaturation
},
86 { "Color", gfxBlendColor
},
87 { "Luminosity", gfxBlendLuminosity
}
90 #define nGfxBlendModeNames \
91 ((int)((sizeof(gfxBlendModeNames) / sizeof(gfxBlendModeName))))
93 //------------------------------------------------------------------------
95 // NB: This must match the GfxColorSpaceMode enum defined in
97 static char *gfxColorSpaceModeNames
[] = {
111 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
113 //------------------------------------------------------------------------
115 //------------------------------------------------------------------------
117 GfxColorSpace::GfxColorSpace() {
120 GfxColorSpace::~GfxColorSpace() {
123 GfxColorSpace
*GfxColorSpace::parse(Object
*csObj
) {
128 if (csObj
->isName()) {
129 if (csObj
->isName("DeviceGray") || csObj
->isName("G")) {
130 cs
= new GfxDeviceGrayColorSpace();
131 } else if (csObj
->isName("DeviceRGB") || csObj
->isName("RGB")) {
132 cs
= new GfxDeviceRGBColorSpace();
133 } else if (csObj
->isName("DeviceCMYK") || csObj
->isName("CMYK")) {
134 cs
= new GfxDeviceCMYKColorSpace();
135 } else if (csObj
->isName("Pattern")) {
136 cs
= new GfxPatternColorSpace(NULL
);
138 error(-1, "Bad color space '%s'", csObj
->getNameC());
140 } else if (csObj
->isArray()) {
141 csObj
->arrayGet(0, &obj1
);
142 if (obj1
.isName("DeviceGray") || obj1
.isName("G")) {
143 cs
= new GfxDeviceGrayColorSpace();
144 } else if (obj1
.isName("DeviceRGB") || obj1
.isName("RGB")) {
145 cs
= new GfxDeviceRGBColorSpace();
146 } else if (obj1
.isName("DeviceCMYK") || obj1
.isName("CMYK")) {
147 cs
= new GfxDeviceCMYKColorSpace();
148 } else if (obj1
.isName("CalGray")) {
149 cs
= GfxCalGrayColorSpace::parse(csObj
->getArray());
150 } else if (obj1
.isName("CalRGB")) {
151 cs
= GfxCalRGBColorSpace::parse(csObj
->getArray());
152 } else if (obj1
.isName("Lab")) {
153 cs
= GfxLabColorSpace::parse(csObj
->getArray());
154 } else if (obj1
.isName("ICCBased")) {
155 cs
= GfxICCBasedColorSpace::parse(csObj
->getArray());
156 } else if (obj1
.isName("Indexed") || obj1
.isName("I")) {
157 cs
= GfxIndexedColorSpace::parse(csObj
->getArray());
158 } else if (obj1
.isName("Separation")) {
159 cs
= GfxSeparationColorSpace::parse(csObj
->getArray());
160 } else if (obj1
.isName("DeviceN")) {
161 cs
= GfxDeviceNColorSpace::parse(csObj
->getArray());
162 } else if (obj1
.isName("Pattern")) {
163 cs
= GfxPatternColorSpace::parse(csObj
->getArray());
165 error(-1, "Bad color space");
169 error(-1, "Bad color space - expected name or array");
174 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
178 for (i
= 0; i
< getNComps(); ++i
) {
184 int GfxColorSpace::getNumColorSpaceModes() {
185 return nGfxColorSpaceModes
;
188 char *GfxColorSpace::getColorSpaceModeName(int idx
) {
189 return gfxColorSpaceModeNames
[idx
];
192 void GfxColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
, int length
) {
198 for (i
= 0; i
< length
; i
++) {
200 for (j
= 0; j
< n
; j
++)
201 color
.c
[j
] = in
[i
* n
+ j
] * 256;
203 getRGB (&color
, &rgb
);
205 ((int) colToByte(rgb
.r
) << 16) |
206 ((int) colToByte(rgb
.g
) << 8) |
207 ((int) colToByte(rgb
.b
) << 0);
211 void GfxColorSpace::getGrayLine(Guchar
*in
, unsigned char *out
, int length
) {
217 for (i
= 0; i
< length
; i
++) {
219 for (j
= 0; j
< n
; j
++)
220 color
.c
[j
] = in
[i
* n
+ j
] * 256;
222 getGray (&color
, &gray
);
223 out
[i
] = colToByte(gray
);
228 //------------------------------------------------------------------------
229 // GfxDeviceGrayColorSpace
230 //------------------------------------------------------------------------
232 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
235 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
238 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
239 return new GfxDeviceGrayColorSpace();
242 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
243 *gray
= clip01(color
->c
[0]);
246 void GfxDeviceGrayColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
247 memcpy (out
, in
, length
);
250 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
251 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
254 void GfxDeviceGrayColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
258 for (i
= 0; i
< length
; i
++)
259 out
[i
] = (in
[i
] << 16) | (in
[i
] << 8) | (in
[i
] << 0);
262 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
263 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
264 cmyk
->k
= clip01(gfxColorComp1
- color
->c
[0]);
267 //------------------------------------------------------------------------
268 // GfxCalGrayColorSpace
269 //------------------------------------------------------------------------
271 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
272 whiteX
= whiteY
= whiteZ
= 1;
273 blackX
= blackY
= blackZ
= 0;
277 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
280 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
281 GfxCalGrayColorSpace
*cs
;
283 cs
= new GfxCalGrayColorSpace();
294 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
) {
295 GfxCalGrayColorSpace
*cs
;
296 Object obj1
, obj2
, obj3
;
299 if (!obj1
.isDict()) {
300 error(-1, "Bad CalGray color space");
304 cs
= new GfxCalGrayColorSpace();
305 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
306 obj2
.arrayGetLength() == 3) {
307 obj2
.arrayGet(0, &obj3
);
308 cs
->whiteX
= obj3
.getNum();
310 obj2
.arrayGet(1, &obj3
);
311 cs
->whiteY
= obj3
.getNum();
313 obj2
.arrayGet(2, &obj3
);
314 cs
->whiteZ
= obj3
.getNum();
318 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
319 obj2
.arrayGetLength() == 3) {
320 obj2
.arrayGet(0, &obj3
);
321 cs
->blackX
= obj3
.getNum();
323 obj2
.arrayGet(1, &obj3
);
324 cs
->blackY
= obj3
.getNum();
326 obj2
.arrayGet(2, &obj3
);
327 cs
->blackZ
= obj3
.getNum();
331 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
332 cs
->gamma
= obj2
.getNum();
339 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
340 *gray
= clip01(color
->c
[0]);
343 void GfxCalGrayColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
344 memcpy (out
, in
, length
);
347 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
348 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
351 void GfxCalGrayColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
355 for (i
= 0; i
< length
; i
++)
356 out
[i
] = (in
[i
] << 16) | (in
[i
] << 8) | (in
[i
] << 0);
359 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
360 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
361 cmyk
->k
= clip01(gfxColorComp1
- color
->c
[0]);
364 //------------------------------------------------------------------------
365 // GfxDeviceRGBColorSpace
366 //------------------------------------------------------------------------
368 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
371 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
374 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
375 return new GfxDeviceRGBColorSpace();
378 void GfxDeviceRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
379 *gray
= clip01((GfxColorComp
)(0.3 * color
->c
[0] +
381 0.11 * color
->c
[2] + 0.5));
384 void GfxDeviceRGBColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
387 for (i
= 0; i
< length
; i
++) {
389 (in
[i
* 3 + 0] * 19595 +
390 in
[i
* 3 + 1] * 38469 +
391 in
[i
* 3 + 2] * 7472) / 65536;
395 void GfxDeviceRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
396 rgb
->r
= clip01(color
->c
[0]);
397 rgb
->g
= clip01(color
->c
[1]);
398 rgb
->b
= clip01(color
->c
[2]);
401 void GfxDeviceRGBColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
406 for (i
= 0, p
= in
; i
< length
; i
++, p
+= 3)
407 out
[i
] = (p
[0] << 16) | (p
[1] << 8) | (p
[2] << 0);
410 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
411 GfxColorComp c
, m
, y
, k
;
413 c
= clip01(gfxColorComp1
- color
->c
[0]);
414 m
= clip01(gfxColorComp1
- color
->c
[1]);
415 y
= clip01(gfxColorComp1
- color
->c
[2]);
429 //------------------------------------------------------------------------
430 // GfxCalRGBColorSpace
431 //------------------------------------------------------------------------
433 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
434 whiteX
= whiteY
= whiteZ
= 1;
435 blackX
= blackY
= blackZ
= 0;
436 gammaR
= gammaG
= gammaB
= 1;
437 mat
[0] = 1; mat
[1] = 0; mat
[2] = 0;
438 mat
[3] = 0; mat
[4] = 1; mat
[5] = 0;
439 mat
[6] = 0; mat
[7] = 0; mat
[8] = 1;
442 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
445 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
446 GfxCalRGBColorSpace
*cs
;
449 cs
= new GfxCalRGBColorSpace();
459 for (i
= 0; i
< 9; ++i
) {
465 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
) {
466 GfxCalRGBColorSpace
*cs
;
467 Object obj1
, obj2
, obj3
;
471 if (!obj1
.isDict()) {
472 error(-1, "Bad CalRGB color space");
476 cs
= new GfxCalRGBColorSpace();
477 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
478 obj2
.arrayGetLength() == 3) {
479 obj2
.arrayGet(0, &obj3
);
480 cs
->whiteX
= obj3
.getNum();
482 obj2
.arrayGet(1, &obj3
);
483 cs
->whiteY
= obj3
.getNum();
485 obj2
.arrayGet(2, &obj3
);
486 cs
->whiteZ
= obj3
.getNum();
490 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
491 obj2
.arrayGetLength() == 3) {
492 obj2
.arrayGet(0, &obj3
);
493 cs
->blackX
= obj3
.getNum();
495 obj2
.arrayGet(1, &obj3
);
496 cs
->blackY
= obj3
.getNum();
498 obj2
.arrayGet(2, &obj3
);
499 cs
->blackZ
= obj3
.getNum();
503 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
504 obj2
.arrayGetLength() == 3) {
505 obj2
.arrayGet(0, &obj3
);
506 cs
->gammaR
= obj3
.getNum();
508 obj2
.arrayGet(1, &obj3
);
509 cs
->gammaG
= obj3
.getNum();
511 obj2
.arrayGet(2, &obj3
);
512 cs
->gammaB
= obj3
.getNum();
516 if (obj1
.dictLookup("Matrix", &obj2
)->isArray() &&
517 obj2
.arrayGetLength() == 9) {
518 for (i
= 0; i
< 9; ++i
) {
519 obj2
.arrayGet(i
, &obj3
);
520 cs
->mat
[i
] = obj3
.getNum();
529 void GfxCalRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
530 *gray
= clip01((GfxColorComp
)(0.299 * color
->c
[0] +
531 0.587 * color
->c
[1] +
532 0.114 * color
->c
[2] + 0.5));
535 void GfxCalRGBColorSpace::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
538 for (i
= 0; i
< length
; i
++) {
540 (in
[i
* 3 + 0] * 19595 +
541 in
[i
* 3 + 1] * 38469 +
542 in
[i
* 3 + 2] * 7472) / 65536;
546 void GfxCalRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
547 rgb
->r
= clip01(color
->c
[0]);
548 rgb
->g
= clip01(color
->c
[1]);
549 rgb
->b
= clip01(color
->c
[2]);
552 void GfxCalRGBColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
557 for (i
= 0, p
= in
; i
< length
; i
++, p
+= 3)
558 out
[i
] = (p
[0] << 16) | (p
[1] << 8) | (p
[2] << 0);
561 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
562 GfxColorComp c
, m
, y
, k
;
564 c
= clip01(gfxColorComp1
- color
->c
[0]);
565 m
= clip01(gfxColorComp1
- color
->c
[1]);
566 y
= clip01(gfxColorComp1
- color
->c
[2]);
580 //------------------------------------------------------------------------
581 // GfxDeviceCMYKColorSpace
582 //------------------------------------------------------------------------
584 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
587 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
590 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
591 return new GfxDeviceCMYKColorSpace();
594 void GfxDeviceCMYKColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
595 *gray
= clip01((GfxColorComp
)(gfxColorComp1
- color
->c
[3]
598 - 0.11 * color
->c
[2] + 0.5));
601 void GfxDeviceCMYKColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
602 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
, x
;
604 c
= colToDbl(color
->c
[0]);
605 m
= colToDbl(color
->c
[1]);
606 y
= colToDbl(color
->c
[2]);
607 k
= colToDbl(color
->c
[3]);
612 // this is a matrix multiplication, unrolled for performance
614 x
= c1
* m1
* y1
* k1
; // 0 0 0 0
616 x
= c1
* m1
* y1
* k
; // 0 0 0 1
620 x
= c1
* m1
* y
* k1
; // 0 0 1 0
623 x
= c1
* m1
* y
* k
; // 0 0 1 1
626 x
= c1
* m
* y1
* k1
; // 0 1 0 0
629 x
= c1
* m
* y1
* k
; // 0 1 0 1
631 x
= c1
* m
* y
* k1
; // 0 1 1 0
635 x
= c1
* m
* y
* k
; // 0 1 1 1
637 x
= c
* m1
* y1
* k1
; // 1 0 0 0
640 x
= c
* m1
* y1
* k
; // 1 0 0 1
643 x
= c
* m1
* y
* k1
; // 1 0 1 0
646 x
= c
* m1
* y
* k
; // 1 0 1 1
648 x
= c
* m
* y1
* k1
; // 1 1 0 0
652 x
= c
* m
* y1
* k
; // 1 1 0 1
654 x
= c
* m
* y
* k1
; // 1 1 1 0
658 rgb
->r
= clip01(dblToCol(r
));
659 rgb
->g
= clip01(dblToCol(g
));
660 rgb
->b
= clip01(dblToCol(b
));
663 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
664 cmyk
->c
= clip01(color
->c
[0]);
665 cmyk
->m
= clip01(color
->c
[1]);
666 cmyk
->y
= clip01(color
->c
[2]);
667 cmyk
->k
= clip01(color
->c
[3]);
670 //------------------------------------------------------------------------
672 //------------------------------------------------------------------------
674 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
675 // Language Reference, Third Edition.
676 static double xyzrgb
[3][3] = {
677 { 3.240449, -1.537136, -0.498531 },
678 { -0.969265, 1.876011, 0.041556 },
679 { 0.055643, -0.204026, 1.057229 }
682 GfxLabColorSpace::GfxLabColorSpace() {
683 whiteX
= whiteY
= whiteZ
= 1;
684 blackX
= blackY
= blackZ
= 0;
689 GfxLabColorSpace::~GfxLabColorSpace() {
692 GfxColorSpace
*GfxLabColorSpace::copy() {
693 GfxLabColorSpace
*cs
;
695 cs
= new GfxLabColorSpace();
712 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
) {
713 GfxLabColorSpace
*cs
;
714 Object obj1
, obj2
, obj3
;
717 if (!obj1
.isDict()) {
718 error(-1, "Bad Lab color space");
722 cs
= new GfxLabColorSpace();
723 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
724 obj2
.arrayGetLength() == 3) {
725 obj2
.arrayGet(0, &obj3
);
726 cs
->whiteX
= obj3
.getNum();
728 obj2
.arrayGet(1, &obj3
);
729 cs
->whiteY
= obj3
.getNum();
731 obj2
.arrayGet(2, &obj3
);
732 cs
->whiteZ
= obj3
.getNum();
736 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
737 obj2
.arrayGetLength() == 3) {
738 obj2
.arrayGet(0, &obj3
);
739 cs
->blackX
= obj3
.getNum();
741 obj2
.arrayGet(1, &obj3
);
742 cs
->blackY
= obj3
.getNum();
744 obj2
.arrayGet(2, &obj3
);
745 cs
->blackZ
= obj3
.getNum();
749 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
750 obj2
.arrayGetLength() == 4) {
751 obj2
.arrayGet(0, &obj3
);
752 cs
->aMin
= obj3
.getNum();
754 obj2
.arrayGet(1, &obj3
);
755 cs
->aMax
= obj3
.getNum();
757 obj2
.arrayGet(2, &obj3
);
758 cs
->bMin
= obj3
.getNum();
760 obj2
.arrayGet(3, &obj3
);
761 cs
->bMax
= obj3
.getNum();
767 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
768 xyzrgb
[0][1] * cs
->whiteY
+
769 xyzrgb
[0][2] * cs
->whiteZ
);
770 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
771 xyzrgb
[1][1] * cs
->whiteY
+
772 xyzrgb
[1][2] * cs
->whiteZ
);
773 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
774 xyzrgb
[2][1] * cs
->whiteY
+
775 xyzrgb
[2][2] * cs
->whiteZ
);
780 void GfxLabColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
784 *gray
= clip01((GfxColorComp
)(0.299 * rgb
.r
+
786 0.114 * rgb
.b
+ 0.5));
789 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
794 // convert L*a*b* to CIE 1931 XYZ color space
795 t1
= (colToDbl(color
->c
[0]) + 16) / 116;
796 t2
= t1
+ colToDbl(color
->c
[1]) / 500;
797 if (t2
>= (6.0 / 29.0)) {
800 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
803 if (t1
>= (6.0 / 29.0)) {
806 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
809 t2
= t1
- colToDbl(color
->c
[2]) / 200;
810 if (t2
>= (6.0 / 29.0)) {
813 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
817 // convert XYZ to RGB, including gamut mapping and gamma correction
818 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
819 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
820 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
821 rgb
->r
= dblToCol(pow(clip01(r
* kr
), 0.5));
822 rgb
->g
= dblToCol(pow(clip01(g
* kg
), 0.5));
823 rgb
->b
= dblToCol(pow(clip01(b
* kb
), 0.5));
826 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
828 GfxColorComp c
, m
, y
, k
;
831 c
= clip01(gfxColorComp1
- rgb
.r
);
832 m
= clip01(gfxColorComp1
- rgb
.g
);
833 y
= clip01(gfxColorComp1
- rgb
.b
);
847 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
850 decodeRange
[0] = 100;
852 decodeRange
[1] = aMax
- aMin
;
854 decodeRange
[2] = bMax
- bMin
;
857 //------------------------------------------------------------------------
858 // GfxICCBasedColorSpace
859 //------------------------------------------------------------------------
861 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA
, GfxColorSpace
*altA
,
862 Ref
*iccProfileStreamA
) {
865 iccProfileStream
= *iccProfileStreamA
;
866 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
867 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
870 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
874 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
875 GfxICCBasedColorSpace
*cs
;
878 cs
= new GfxICCBasedColorSpace(nComps
, alt
->copy(), &iccProfileStream
);
879 for (i
= 0; i
< 4; ++i
) {
880 cs
->rangeMin
[i
] = rangeMin
[i
];
881 cs
->rangeMax
[i
] = rangeMax
[i
];
886 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
) {
887 GfxICCBasedColorSpace
*cs
;
888 Ref iccProfileStreamA
;
892 Object obj1
, obj2
, obj3
;
895 arr
->getNF(1, &obj1
);
897 iccProfileStreamA
= obj1
.getRef();
899 iccProfileStreamA
.num
= 0;
900 iccProfileStreamA
.gen
= 0;
904 if (!obj1
.isStream()) {
905 error(-1, "Bad ICCBased color space (stream)");
909 dict
= obj1
.streamGetDict();
910 if (!dict
->lookup("N", &obj2
)->isInt()) {
911 error(-1, "Bad ICCBased color space (N)");
916 nCompsA
= obj2
.getInt();
918 if (nCompsA
> gfxColorMaxComps
) {
919 error(-1, "ICCBased color space with too many (%d > %d) components",
920 nCompsA
, gfxColorMaxComps
);
921 nCompsA
= gfxColorMaxComps
;
923 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
924 !(altA
= GfxColorSpace::parse(&obj2
))) {
927 altA
= new GfxDeviceGrayColorSpace();
930 altA
= new GfxDeviceRGBColorSpace();
933 altA
= new GfxDeviceCMYKColorSpace();
936 error(-1, "Bad ICCBased color space - invalid N");
943 cs
= new GfxICCBasedColorSpace(nCompsA
, altA
, &iccProfileStreamA
);
944 if (dict
->lookup("Range", &obj2
)->isArray() &&
945 obj2
.arrayGetLength() == 2 * nCompsA
) {
946 for (i
= 0; i
< nCompsA
; ++i
) {
947 obj2
.arrayGet(2*i
, &obj3
);
948 cs
->rangeMin
[i
] = obj3
.getNum();
950 obj2
.arrayGet(2*i
+1, &obj3
);
951 cs
->rangeMax
[i
] = obj3
.getNum();
960 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
961 alt
->getGray(color
, gray
);
964 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
965 alt
->getRGB(color
, rgb
);
968 void GfxICCBasedColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
,
970 alt
->getRGBLine(in
, out
, length
);
973 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
974 alt
->getCMYK(color
, cmyk
);
977 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
980 alt
->getDefaultRanges(decodeLow
, decodeRange
, maxImgPixel
);
983 // this is nominally correct, but some PDF files don't set the
984 // correct ranges in the ICCBased dict
987 for (i
= 0; i
< nComps
; ++i
) {
988 decodeLow
[i
] = rangeMin
[i
];
989 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
994 //------------------------------------------------------------------------
995 // GfxIndexedColorSpace
996 //------------------------------------------------------------------------
998 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*baseA
,
1001 indexHigh
= indexHighA
;
1002 lookup
= (Guchar
*)gmallocn((indexHigh
+ 1) * base
->getNComps(),
1006 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
1011 GfxColorSpace
*GfxIndexedColorSpace::copy() {
1012 GfxIndexedColorSpace
*cs
;
1014 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
1015 memcpy(cs
->lookup
, lookup
,
1016 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
1020 GfxColorSpace
*GfxIndexedColorSpace::parse(Array
*arr
) {
1021 GfxIndexedColorSpace
*cs
;
1022 GfxColorSpace
*baseA
;
1029 if (arr
->getLength() != 4) {
1030 error(-1, "Bad Indexed color space");
1034 if (!(baseA
= GfxColorSpace::parse(&obj1
))) {
1035 error(-1, "Bad Indexed color space (base color space)");
1039 if (!arr
->get(2, &obj1
)->isInt()) {
1040 error(-1, "Bad Indexed color space (hival)");
1044 indexHighA
= obj1
.getInt();
1045 if (indexHighA
< 0 || indexHighA
> 255) {
1046 // the PDF spec requires indexHigh to be in [0,255] -- allowing
1047 // values larger than 255 creates a security hole: if nComps *
1048 // indexHigh is greater than 2^31, the loop below may overwrite
1049 // past the end of the array
1050 error(-1, "Bad Indexed color space (invalid indexHigh value)");
1055 cs
= new GfxIndexedColorSpace(baseA
, indexHighA
);
1057 n
= baseA
->getNComps();
1058 if (obj1
.isStream()) {
1060 for (i
= 0; i
<= indexHighA
; ++i
) {
1061 for (j
= 0; j
< n
; ++j
) {
1062 if ((x
= obj1
.streamGetChar()) == EOF
) {
1063 error(-1, "Bad Indexed color space (lookup table stream too short)");
1066 cs
->lookup
[i
*n
+ j
] = (Guchar
)x
;
1070 } else if (obj1
.isString()) {
1071 if (obj1
.getString()->getLength() < (indexHighA
+ 1) * n
) {
1072 error(-1, "Bad Indexed color space (lookup table string too short)");
1075 s
= obj1
.getString()->getCString();
1076 for (i
= 0; i
<= indexHighA
; ++i
) {
1077 for (j
= 0; j
< n
; ++j
) {
1078 cs
->lookup
[i
*n
+ j
] = (Guchar
)*s
++;
1082 error(-1, "Bad Indexed color space (lookup table)");
1096 GfxColor
*GfxIndexedColorSpace::mapColorToBase(GfxColor
*color
,
1097 GfxColor
*baseColor
) {
1099 double low
[gfxColorMaxComps
], range
[gfxColorMaxComps
];
1102 n
= base
->getNComps();
1103 base
->getDefaultRanges(low
, range
, indexHigh
);
1104 p
= &lookup
[(int)(colToDbl(color
->c
[0]) + 0.5) * n
];
1105 for (i
= 0; i
< n
; ++i
) {
1106 baseColor
->c
[i
] = dblToCol(low
[i
] + (p
[i
] / 255.0) * range
[i
]);
1111 void GfxIndexedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1114 base
->getGray(mapColorToBase(color
, &color2
), gray
);
1117 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1120 base
->getRGB(mapColorToBase(color
, &color2
), rgb
);
1123 void GfxIndexedColorSpace::getRGBLine(Guchar
*in
, unsigned int *out
, int length
) {
1127 n
= base
->getNComps();
1128 line
= (Guchar
*) gmalloc (length
* n
);
1129 for (i
= 0; i
< length
; i
++)
1130 for (j
= 0; j
< n
; j
++)
1131 line
[i
* n
+ j
] = lookup
[in
[i
] * n
+ j
];
1133 base
->getRGBLine(line
, out
, length
);
1138 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1141 base
->getCMYK(mapColorToBase(color
, &color2
), cmyk
);
1144 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
1145 double *decodeRange
,
1148 decodeRange
[0] = maxImgPixel
;
1151 //------------------------------------------------------------------------
1152 // GfxSeparationColorSpace
1153 //------------------------------------------------------------------------
1155 GfxSeparationColorSpace::GfxSeparationColorSpace(GooString
*nameA
,
1156 GfxColorSpace
*altA
,
1163 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1169 GfxColorSpace
*GfxSeparationColorSpace::copy() {
1170 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy());
1173 //~ handle the 'All' and 'None' colorants
1174 GfxColorSpace
*GfxSeparationColorSpace::parse(Array
*arr
) {
1175 GfxSeparationColorSpace
*cs
;
1177 GfxColorSpace
*altA
;
1181 if (arr
->getLength() != 4) {
1182 error(-1, "Bad Separation color space");
1185 if (!arr
->get(1, &obj1
)->isName()) {
1186 error(-1, "Bad Separation color space (name)");
1189 nameA
= new GooString(obj1
.getName());
1192 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1193 error(-1, "Bad Separation color space (alternate color space)");
1198 if (!(funcA
= Function::parse(&obj1
))) {
1202 cs
= new GfxSeparationColorSpace(nameA
, altA
, funcA
);
1215 void GfxSeparationColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1217 double c
[gfxColorMaxComps
];
1221 x
= colToDbl(color
->c
[0]);
1222 func
->transform(&x
, c
);
1223 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1224 color2
.c
[i
] = dblToCol(c
[i
]);
1226 alt
->getGray(&color2
, gray
);
1229 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1231 double c
[gfxColorMaxComps
];
1235 x
= colToDbl(color
->c
[0]);
1236 func
->transform(&x
, c
);
1237 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1238 color2
.c
[i
] = dblToCol(c
[i
]);
1240 alt
->getRGB(&color2
, rgb
);
1243 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1245 double c
[gfxColorMaxComps
];
1249 x
= colToDbl(color
->c
[0]);
1250 func
->transform(&x
, c
);
1251 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1252 color2
.c
[i
] = dblToCol(c
[i
]);
1254 alt
->getCMYK(&color2
, cmyk
);
1257 //------------------------------------------------------------------------
1258 // GfxDeviceNColorSpace
1259 //------------------------------------------------------------------------
1261 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
1262 GfxColorSpace
*altA
,
1269 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1272 for (i
= 0; i
< nComps
; ++i
) {
1279 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
1280 GfxDeviceNColorSpace
*cs
;
1283 cs
= new GfxDeviceNColorSpace(nComps
, alt
->copy(), func
->copy());
1284 for (i
= 0; i
< nComps
; ++i
) {
1285 cs
->names
[i
] = names
[i
]->copy();
1290 //~ handle the 'None' colorant
1291 GfxColorSpace
*GfxDeviceNColorSpace::parse(Array
*arr
) {
1292 GfxDeviceNColorSpace
*cs
;
1294 GooString
*namesA
[gfxColorMaxComps
];
1295 GfxColorSpace
*altA
;
1300 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
1301 error(-1, "Bad DeviceN color space");
1304 if (!arr
->get(1, &obj1
)->isArray()) {
1305 error(-1, "Bad DeviceN color space (names)");
1308 nCompsA
= obj1
.arrayGetLength();
1309 if (nCompsA
> gfxColorMaxComps
) {
1310 error(-1, "DeviceN color space with too many (%d > %d) components",
1311 nCompsA
, gfxColorMaxComps
);
1312 nCompsA
= gfxColorMaxComps
;
1314 for (i
= 0; i
< nCompsA
; ++i
) {
1315 if (!obj1
.arrayGet(i
, &obj2
)->isName()) {
1316 error(-1, "Bad DeviceN color space (names)");
1320 namesA
[i
] = new GooString(obj2
.getName());
1325 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1326 error(-1, "Bad DeviceN color space (alternate color space)");
1331 if (!(funcA
= Function::parse(&obj1
))) {
1335 cs
= new GfxDeviceNColorSpace(nCompsA
, altA
, funcA
);
1336 for (i
= 0; i
< nCompsA
; ++i
) {
1337 cs
->names
[i
] = namesA
[i
];
1344 for (i
= 0; i
< nCompsA
; ++i
) {
1353 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1354 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1358 for (i
= 0; i
< nComps
; ++i
) {
1359 x
[i
] = colToDbl(color
->c
[i
]);
1361 func
->transform(x
, c
);
1362 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1363 color2
.c
[i
] = dblToCol(c
[i
]);
1365 alt
->getGray(&color2
, gray
);
1368 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1369 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1373 for (i
= 0; i
< nComps
; ++i
) {
1374 x
[i
] = colToDbl(color
->c
[i
]);
1376 func
->transform(x
, c
);
1377 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1378 color2
.c
[i
] = dblToCol(c
[i
]);
1380 alt
->getRGB(&color2
, rgb
);
1383 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1384 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1388 for (i
= 0; i
< nComps
; ++i
) {
1389 x
[i
] = colToDbl(color
->c
[i
]);
1391 func
->transform(x
, c
);
1392 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1393 color2
.c
[i
] = dblToCol(c
[i
]);
1395 alt
->getCMYK(&color2
, cmyk
);
1398 //------------------------------------------------------------------------
1399 // GfxPatternColorSpace
1400 //------------------------------------------------------------------------
1402 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*underA
) {
1406 GfxPatternColorSpace::~GfxPatternColorSpace() {
1412 GfxColorSpace
*GfxPatternColorSpace::copy() {
1413 return new GfxPatternColorSpace(under
? under
->copy() :
1414 (GfxColorSpace
*)NULL
);
1417 GfxColorSpace
*GfxPatternColorSpace::parse(Array
*arr
) {
1418 GfxPatternColorSpace
*cs
;
1419 GfxColorSpace
*underA
;
1422 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
1423 error(-1, "Bad Pattern color space");
1427 if (arr
->getLength() == 2) {
1429 if (!(underA
= GfxColorSpace::parse(&obj1
))) {
1430 error(-1, "Bad Pattern color space (underlying color space)");
1436 cs
= new GfxPatternColorSpace(underA
);
1440 void GfxPatternColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1444 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1445 rgb
->r
= rgb
->g
= rgb
->b
= 0;
1448 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1449 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
1453 //------------------------------------------------------------------------
1455 //------------------------------------------------------------------------
1457 GfxPattern::GfxPattern(int typeA
) {
1461 GfxPattern::~GfxPattern() {
1464 GfxPattern
*GfxPattern::parse(Object
*obj
) {
1465 GfxPattern
*pattern
;
1468 if (obj
->isDict()) {
1469 obj
->dictLookup("PatternType", &obj1
);
1470 } else if (obj
->isStream()) {
1471 obj
->streamGetDict()->lookup("PatternType", &obj1
);
1476 if (obj1
.isInt() && obj1
.getInt() == 1) {
1477 pattern
= GfxTilingPattern::parse(obj
);
1478 } else if (obj1
.isInt() && obj1
.getInt() == 2) {
1479 pattern
= GfxShadingPattern::parse(obj
);
1485 //------------------------------------------------------------------------
1487 //------------------------------------------------------------------------
1489 GfxTilingPattern
*GfxTilingPattern::parse(Object
*patObj
) {
1490 GfxTilingPattern
*pat
;
1492 int paintTypeA
, tilingTypeA
;
1493 double bboxA
[4], matrixA
[6];
1494 double xStepA
, yStepA
;
1499 if (!patObj
->isStream()) {
1502 dict
= patObj
->streamGetDict();
1504 if (dict
->lookup("PaintType", &obj1
)->isInt()) {
1505 paintTypeA
= obj1
.getInt();
1508 error(-1, "Invalid or missing PaintType in pattern");
1511 if (dict
->lookup("TilingType", &obj1
)->isInt()) {
1512 tilingTypeA
= obj1
.getInt();
1515 error(-1, "Invalid or missing TilingType in pattern");
1518 bboxA
[0] = bboxA
[1] = 0;
1519 bboxA
[2] = bboxA
[3] = 1;
1520 if (dict
->lookup("BBox", &obj1
)->isArray() &&
1521 obj1
.arrayGetLength() == 4) {
1522 for (i
= 0; i
< 4; ++i
) {
1523 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1524 bboxA
[i
] = obj2
.getNum();
1529 error(-1, "Invalid or missing BBox in pattern");
1532 if (dict
->lookup("XStep", &obj1
)->isNum()) {
1533 xStepA
= obj1
.getNum();
1536 error(-1, "Invalid or missing XStep in pattern");
1539 if (dict
->lookup("YStep", &obj1
)->isNum()) {
1540 yStepA
= obj1
.getNum();
1543 error(-1, "Invalid or missing YStep in pattern");
1546 if (!dict
->lookup("Resources", &resDictA
)->isDict()) {
1548 resDictA
.initNull();
1549 error(-1, "Invalid or missing Resources in pattern");
1551 matrixA
[0] = 1; matrixA
[1] = 0;
1552 matrixA
[2] = 0; matrixA
[3] = 1;
1553 matrixA
[4] = 0; matrixA
[5] = 0;
1554 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1555 obj1
.arrayGetLength() == 6) {
1556 for (i
= 0; i
< 6; ++i
) {
1557 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1558 matrixA
[i
] = obj2
.getNum();
1565 pat
= new GfxTilingPattern(paintTypeA
, tilingTypeA
, bboxA
, xStepA
, yStepA
,
1566 &resDictA
, matrixA
, patObj
);
1571 GfxTilingPattern::GfxTilingPattern(int paintTypeA
, int tilingTypeA
,
1572 double *bboxA
, double xStepA
, double yStepA
,
1573 Object
*resDictA
, double *matrixA
,
1574 Object
*contentStreamA
):
1579 paintType
= paintTypeA
;
1580 tilingType
= tilingTypeA
;
1581 for (i
= 0; i
< 4; ++i
) {
1586 resDictA
->copy(&resDict
);
1587 for (i
= 0; i
< 6; ++i
) {
1588 matrix
[i
] = matrixA
[i
];
1590 contentStreamA
->copy(&contentStream
);
1593 GfxTilingPattern::~GfxTilingPattern() {
1595 contentStream
.free();
1598 GfxPattern
*GfxTilingPattern::copy() {
1599 return new GfxTilingPattern(paintType
, tilingType
, bbox
, xStep
, yStep
,
1600 &resDict
, matrix
, &contentStream
);
1603 //------------------------------------------------------------------------
1604 // GfxShadingPattern
1605 //------------------------------------------------------------------------
1607 GfxShadingPattern
*GfxShadingPattern::parse(Object
*patObj
) {
1609 GfxShading
*shadingA
;
1614 if (!patObj
->isDict()) {
1617 dict
= patObj
->getDict();
1619 dict
->lookup("Shading", &obj1
);
1620 shadingA
= GfxShading::parse(&obj1
);
1626 matrixA
[0] = 1; matrixA
[1] = 0;
1627 matrixA
[2] = 0; matrixA
[3] = 1;
1628 matrixA
[4] = 0; matrixA
[5] = 0;
1629 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1630 obj1
.arrayGetLength() == 6) {
1631 for (i
= 0; i
< 6; ++i
) {
1632 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1633 matrixA
[i
] = obj2
.getNum();
1640 return new GfxShadingPattern(shadingA
, matrixA
);
1643 GfxShadingPattern::GfxShadingPattern(GfxShading
*shadingA
, double *matrixA
):
1649 for (i
= 0; i
< 6; ++i
) {
1650 matrix
[i
] = matrixA
[i
];
1654 GfxShadingPattern::~GfxShadingPattern() {
1658 GfxPattern
*GfxShadingPattern::copy() {
1659 return new GfxShadingPattern(shading
->copy(), matrix
);
1662 //------------------------------------------------------------------------
1664 //------------------------------------------------------------------------
1666 GfxShading::GfxShading(int typeA
) {
1671 GfxShading::GfxShading(GfxShading
*shading
) {
1674 type
= shading
->type
;
1675 colorSpace
= shading
->colorSpace
->copy();
1676 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1677 background
.c
[i
] = shading
->background
.c
[i
];
1679 hasBackground
= shading
->hasBackground
;
1680 xMin
= shading
->xMin
;
1681 yMin
= shading
->yMin
;
1682 xMax
= shading
->xMax
;
1683 yMax
= shading
->yMax
;
1684 hasBBox
= shading
->hasBBox
;
1687 GfxShading::~GfxShading() {
1693 GfxShading
*GfxShading::parse(Object
*obj
) {
1694 GfxShading
*shading
;
1699 if (obj
->isDict()) {
1700 dict
= obj
->getDict();
1701 } else if (obj
->isStream()) {
1702 dict
= obj
->streamGetDict();
1707 if (!dict
->lookup("ShadingType", &obj1
)->isInt()) {
1708 error(-1, "Invalid ShadingType in shading dictionary");
1712 typeA
= obj1
.getInt();
1717 shading
= GfxFunctionShading::parse(dict
);
1720 shading
= GfxAxialShading::parse(dict
);
1723 shading
= GfxRadialShading::parse(dict
);
1726 if (obj
->isStream()) {
1727 shading
= GfxGouraudTriangleShading::parse(4, dict
, obj
->getStream());
1729 error(-1, "Invalid Type 4 shading object");
1734 if (obj
->isStream()) {
1735 shading
= GfxGouraudTriangleShading::parse(5, dict
, obj
->getStream());
1737 error(-1, "Invalid Type 5 shading object");
1742 if (obj
->isStream()) {
1743 shading
= GfxPatchMeshShading::parse(6, dict
, obj
->getStream());
1745 error(-1, "Invalid Type 6 shading object");
1750 if (obj
->isStream()) {
1751 shading
= GfxPatchMeshShading::parse(7, dict
, obj
->getStream());
1753 error(-1, "Invalid Type 7 shading object");
1758 error(-1, "Unimplemented shading type %d", typeA
);
1768 GBool
GfxShading::init(Dict
*dict
) {
1772 dict
->lookup("ColorSpace", &obj1
);
1773 if (!(colorSpace
= GfxColorSpace::parse(&obj1
))) {
1774 error(-1, "Bad color space in shading dictionary");
1780 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1781 background
.c
[i
] = 0;
1783 hasBackground
= gFalse
;
1784 if (dict
->lookup("Background", &obj1
)->isArray()) {
1785 if (obj1
.arrayGetLength() == colorSpace
->getNComps()) {
1786 hasBackground
= gTrue
;
1787 for (i
= 0; i
< colorSpace
->getNComps(); ++i
) {
1788 background
.c
[i
] = dblToCol(obj1
.arrayGet(i
, &obj2
)->getNum());
1792 error(-1, "Bad Background in shading dictionary");
1797 xMin
= yMin
= xMax
= yMax
= 0;
1799 if (dict
->lookup("BBox", &obj1
)->isArray()) {
1800 if (obj1
.arrayGetLength() == 4) {
1802 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
1804 yMin
= obj1
.arrayGet(1, &obj2
)->getNum();
1806 xMax
= obj1
.arrayGet(2, &obj2
)->getNum();
1808 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
1811 error(-1, "Bad BBox in shading dictionary");
1819 //------------------------------------------------------------------------
1820 // GfxFunctionShading
1821 //------------------------------------------------------------------------
1823 GfxFunctionShading::GfxFunctionShading(double x0A
, double y0A
,
1824 double x1A
, double y1A
,
1826 Function
**funcsA
, int nFuncsA
):
1835 for (i
= 0; i
< 6; ++i
) {
1836 matrix
[i
] = matrixA
[i
];
1839 for (i
= 0; i
< nFuncs
; ++i
) {
1840 funcs
[i
] = funcsA
[i
];
1844 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading
*shading
):
1853 for (i
= 0; i
< 6; ++i
) {
1854 matrix
[i
] = shading
->matrix
[i
];
1856 nFuncs
= shading
->nFuncs
;
1857 for (i
= 0; i
< nFuncs
; ++i
) {
1858 funcs
[i
] = shading
->funcs
[i
]->copy();
1862 GfxFunctionShading::~GfxFunctionShading() {
1865 for (i
= 0; i
< nFuncs
; ++i
) {
1870 GfxFunctionShading
*GfxFunctionShading::parse(Dict
*dict
) {
1871 GfxFunctionShading
*shading
;
1872 double x0A
, y0A
, x1A
, y1A
;
1874 Function
*funcsA
[gfxColorMaxComps
];
1881 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1882 obj1
.arrayGetLength() == 4) {
1883 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1885 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1887 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1889 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1894 matrixA
[0] = 1; matrixA
[1] = 0;
1895 matrixA
[2] = 0; matrixA
[3] = 1;
1896 matrixA
[4] = 0; matrixA
[5] = 0;
1897 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1898 obj1
.arrayGetLength() == 6) {
1899 matrixA
[0] = obj1
.arrayGet(0, &obj2
)->getNum();
1901 matrixA
[1] = obj1
.arrayGet(1, &obj2
)->getNum();
1903 matrixA
[2] = obj1
.arrayGet(2, &obj2
)->getNum();
1905 matrixA
[3] = obj1
.arrayGet(3, &obj2
)->getNum();
1907 matrixA
[4] = obj1
.arrayGet(4, &obj2
)->getNum();
1909 matrixA
[5] = obj1
.arrayGet(5, &obj2
)->getNum();
1914 dict
->lookup("Function", &obj1
);
1915 if (obj1
.isArray()) {
1916 nFuncsA
= obj1
.arrayGetLength();
1917 if (nFuncsA
> gfxColorMaxComps
) {
1918 error(-1, "Invalid Function array in shading dictionary");
1921 for (i
= 0; i
< nFuncsA
; ++i
) {
1922 obj1
.arrayGet(i
, &obj2
);
1923 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1930 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1936 shading
= new GfxFunctionShading(x0A
, y0A
, x1A
, y1A
, matrixA
,
1938 if (!shading
->init(dict
)) {
1951 GfxShading
*GfxFunctionShading::copy() {
1952 return new GfxFunctionShading(this);
1955 void GfxFunctionShading::getColor(double x
, double y
, GfxColor
*color
) {
1956 double in
[2], out
[gfxColorMaxComps
];
1959 // NB: there can be one function with n outputs or n functions with
1960 // one output each (where n = number of color components)
1961 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1966 for (i
= 0; i
< nFuncs
; ++i
) {
1967 funcs
[i
]->transform(in
, &out
[i
]);
1969 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1970 color
->c
[i
] = dblToCol(out
[i
]);
1974 //------------------------------------------------------------------------
1976 //------------------------------------------------------------------------
1978 GfxAxialShading::GfxAxialShading(double x0A
, double y0A
,
1979 double x1A
, double y1A
,
1980 double t0A
, double t1A
,
1981 Function
**funcsA
, int nFuncsA
,
1982 GBool extend0A
, GBool extend1A
):
1994 for (i
= 0; i
< nFuncs
; ++i
) {
1995 funcs
[i
] = funcsA
[i
];
2001 GfxAxialShading::GfxAxialShading(GfxAxialShading
*shading
):
2012 nFuncs
= shading
->nFuncs
;
2013 for (i
= 0; i
< nFuncs
; ++i
) {
2014 funcs
[i
] = shading
->funcs
[i
]->copy();
2016 extend0
= shading
->extend0
;
2017 extend1
= shading
->extend1
;
2020 GfxAxialShading::~GfxAxialShading() {
2023 for (i
= 0; i
< nFuncs
; ++i
) {
2028 GfxAxialShading
*GfxAxialShading::parse(Dict
*dict
) {
2029 GfxAxialShading
*shading
;
2030 double x0A
, y0A
, x1A
, y1A
;
2032 Function
*funcsA
[gfxColorMaxComps
];
2034 GBool extend0A
, extend1A
;
2038 x0A
= y0A
= x1A
= y1A
= 0;
2039 if (dict
->lookup("Coords", &obj1
)->isArray() &&
2040 obj1
.arrayGetLength() == 4) {
2041 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2043 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
2045 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
2047 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
2050 error(-1, "Missing or invalid Coords in shading dictionary");
2057 if (dict
->lookup("Domain", &obj1
)->isArray() &&
2058 obj1
.arrayGetLength() == 2) {
2059 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2061 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
2066 dict
->lookup("Function", &obj1
);
2067 if (obj1
.isArray()) {
2068 nFuncsA
= obj1
.arrayGetLength();
2069 if (nFuncsA
> gfxColorMaxComps
) {
2070 error(-1, "Invalid Function array in shading dictionary");
2073 for (i
= 0; i
< nFuncsA
; ++i
) {
2074 obj1
.arrayGet(i
, &obj2
);
2075 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2084 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2091 extend0A
= extend1A
= gFalse
;
2092 if (dict
->lookup("Extend", &obj1
)->isArray() &&
2093 obj1
.arrayGetLength() == 2) {
2094 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
2096 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
2101 shading
= new GfxAxialShading(x0A
, y0A
, x1A
, y1A
, t0A
, t1A
,
2102 funcsA
, nFuncsA
, extend0A
, extend1A
);
2103 if (!shading
->init(dict
)) {
2113 GfxShading
*GfxAxialShading::copy() {
2114 return new GfxAxialShading(this);
2117 void GfxAxialShading::getColor(double t
, GfxColor
*color
) {
2118 double out
[gfxColorMaxComps
];
2121 // NB: there can be one function with n outputs or n functions with
2122 // one output each (where n = number of color components)
2123 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2126 for (i
= 0; i
< nFuncs
; ++i
) {
2127 funcs
[i
]->transform(&t
, &out
[i
]);
2129 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2130 color
->c
[i
] = dblToCol(out
[i
]);
2134 //------------------------------------------------------------------------
2136 //------------------------------------------------------------------------
2138 GfxRadialShading::GfxRadialShading(double x0A
, double y0A
, double r0A
,
2139 double x1A
, double y1A
, double r1A
,
2140 double t0A
, double t1A
,
2141 Function
**funcsA
, int nFuncsA
,
2142 GBool extend0A
, GBool extend1A
):
2156 for (i
= 0; i
< nFuncs
; ++i
) {
2157 funcs
[i
] = funcsA
[i
];
2163 GfxRadialShading::GfxRadialShading(GfxRadialShading
*shading
):
2176 nFuncs
= shading
->nFuncs
;
2177 for (i
= 0; i
< nFuncs
; ++i
) {
2178 funcs
[i
] = shading
->funcs
[i
]->copy();
2180 extend0
= shading
->extend0
;
2181 extend1
= shading
->extend1
;
2184 GfxRadialShading::~GfxRadialShading() {
2187 for (i
= 0; i
< nFuncs
; ++i
) {
2192 GfxRadialShading
*GfxRadialShading::parse(Dict
*dict
) {
2193 GfxRadialShading
*shading
;
2194 double x0A
, y0A
, r0A
, x1A
, y1A
, r1A
;
2196 Function
*funcsA
[gfxColorMaxComps
];
2198 GBool extend0A
, extend1A
;
2202 x0A
= y0A
= r0A
= x1A
= y1A
= r1A
= 0;
2203 if (dict
->lookup("Coords", &obj1
)->isArray() &&
2204 obj1
.arrayGetLength() == 6) {
2205 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2207 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
2209 r0A
= obj1
.arrayGet(2, &obj2
)->getNum();
2211 x1A
= obj1
.arrayGet(3, &obj2
)->getNum();
2213 y1A
= obj1
.arrayGet(4, &obj2
)->getNum();
2215 r1A
= obj1
.arrayGet(5, &obj2
)->getNum();
2218 error(-1, "Missing or invalid Coords in shading dictionary");
2225 if (dict
->lookup("Domain", &obj1
)->isArray() &&
2226 obj1
.arrayGetLength() == 2) {
2227 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2229 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
2234 dict
->lookup("Function", &obj1
);
2235 if (obj1
.isArray()) {
2236 nFuncsA
= obj1
.arrayGetLength();
2237 if (nFuncsA
> gfxColorMaxComps
) {
2238 error(-1, "Invalid Function array in shading dictionary");
2241 for (i
= 0; i
< nFuncsA
; ++i
) {
2242 obj1
.arrayGet(i
, &obj2
);
2243 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2252 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2259 extend0A
= extend1A
= gFalse
;
2260 if (dict
->lookup("Extend", &obj1
)->isArray() &&
2261 obj1
.arrayGetLength() == 2) {
2262 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
2264 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
2269 shading
= new GfxRadialShading(x0A
, y0A
, r0A
, x1A
, y1A
, r1A
, t0A
, t1A
,
2270 funcsA
, nFuncsA
, extend0A
, extend1A
);
2271 if (!shading
->init(dict
)) {
2281 GfxShading
*GfxRadialShading::copy() {
2282 return new GfxRadialShading(this);
2285 void GfxRadialShading::getColor(double t
, GfxColor
*color
) {
2286 double out
[gfxColorMaxComps
];
2289 // NB: there can be one function with n outputs or n functions with
2290 // one output each (where n = number of color components)
2291 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2294 for (i
= 0; i
< nFuncs
; ++i
) {
2295 funcs
[i
]->transform(&t
, &out
[i
]);
2297 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2298 color
->c
[i
] = dblToCol(out
[i
]);
2302 //------------------------------------------------------------------------
2304 //------------------------------------------------------------------------
2306 class GfxShadingBitBuf
{
2309 GfxShadingBitBuf(Stream
*strA
);
2310 ~GfxShadingBitBuf();
2311 GBool
getBits(int n
, Guint
*val
);
2321 GfxShadingBitBuf::GfxShadingBitBuf(Stream
*strA
) {
2328 GfxShadingBitBuf::~GfxShadingBitBuf() {
2332 GBool
GfxShadingBitBuf::getBits(int n
, Guint
*val
) {
2336 x
= (bitBuf
>> (nBits
- n
)) & ((1 << n
) - 1);
2341 x
= bitBuf
& ((1 << nBits
) - 1);
2346 if ((bitBuf
= str
->getChar()) == EOF
) {
2351 x
= (x
<< 8) | bitBuf
;
2354 x
= (x
<< n
) | (bitBuf
>> (8 - n
));
2364 void GfxShadingBitBuf::flushBits() {
2369 //------------------------------------------------------------------------
2370 // GfxGouraudTriangleShading
2371 //------------------------------------------------------------------------
2373 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2375 GfxGouraudVertex
*verticesA
, int nVerticesA
,
2376 int (*trianglesA
)[3], int nTrianglesA
,
2377 Function
**funcsA
, int nFuncsA
):
2382 vertices
= verticesA
;
2383 nVertices
= nVerticesA
;
2384 triangles
= trianglesA
;
2385 nTriangles
= nTrianglesA
;
2387 for (i
= 0; i
< nFuncs
; ++i
) {
2388 funcs
[i
] = funcsA
[i
];
2392 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2393 GfxGouraudTriangleShading
*shading
):
2398 nVertices
= shading
->nVertices
;
2399 vertices
= (GfxGouraudVertex
*)gmallocn(nVertices
, sizeof(GfxGouraudVertex
));
2400 memcpy(vertices
, shading
->vertices
, nVertices
* sizeof(GfxGouraudVertex
));
2401 nTriangles
= shading
->nTriangles
;
2402 triangles
= (int (*)[3])gmallocn(nTriangles
* 3, sizeof(int));
2403 memcpy(triangles
, shading
->triangles
, nTriangles
* 3 * sizeof(int));
2404 nFuncs
= shading
->nFuncs
;
2405 for (i
= 0; i
< nFuncs
; ++i
) {
2406 funcs
[i
] = shading
->funcs
[i
]->copy();
2410 GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2415 for (i
= 0; i
< nFuncs
; ++i
) {
2420 GfxGouraudTriangleShading
*GfxGouraudTriangleShading::parse(int typeA
,
2423 GfxGouraudTriangleShading
*shading
;
2424 Function
*funcsA
[gfxColorMaxComps
];
2426 int coordBits
, compBits
, flagBits
, vertsPerRow
, nRows
;
2427 double xMin
, xMax
, yMin
, yMax
;
2428 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
2430 double cMul
[gfxColorMaxComps
];
2431 GfxGouraudVertex
*verticesA
;
2432 int (*trianglesA
)[3];
2433 int nComps
, nVerticesA
, nTrianglesA
, vertSize
, triSize
;
2435 Guint c
[gfxColorMaxComps
];
2436 GfxShadingBitBuf
*bitBuf
;
2440 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
2441 coordBits
= obj1
.getInt();
2443 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2447 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
2448 compBits
= obj1
.getInt();
2450 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2454 flagBits
= vertsPerRow
= 0; // make gcc happy
2456 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
2457 flagBits
= obj1
.getInt();
2459 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2464 if (dict
->lookup("VerticesPerRow", &obj1
)->isInt()) {
2465 vertsPerRow
= obj1
.getInt();
2467 error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
2472 if (dict
->lookup("Decode", &obj1
)->isArray() &&
2473 obj1
.arrayGetLength() >= 6) {
2474 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
2476 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
2478 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
2479 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
2481 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
2483 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
2484 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
2485 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
2487 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
2489 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
2493 error(-1, "Missing or invalid Decode array in shading dictionary");
2498 if (!dict
->lookup("Function", &obj1
)->isNull()) {
2499 if (obj1
.isArray()) {
2500 nFuncsA
= obj1
.arrayGetLength();
2501 if (nFuncsA
> gfxColorMaxComps
) {
2502 error(-1, "Invalid Function array in shading dictionary");
2505 for (i
= 0; i
< nFuncsA
; ++i
) {
2506 obj1
.arrayGet(i
, &obj2
);
2507 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2516 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2526 nVerticesA
= nTrianglesA
= 0;
2529 vertSize
= triSize
= 0;
2531 flag
= 0; // make gcc happy
2532 bitBuf
= new GfxShadingBitBuf(str
);
2535 if (!bitBuf
->getBits(flagBits
, &flag
)) {
2539 if (!bitBuf
->getBits(coordBits
, &x
) ||
2540 !bitBuf
->getBits(coordBits
, &y
)) {
2543 for (i
= 0; i
< nComps
; ++i
) {
2544 if (!bitBuf
->getBits(compBits
, &c
[i
])) {
2551 if (nVerticesA
== vertSize
) {
2552 vertSize
= (vertSize
== 0) ? 16 : 2 * vertSize
;
2553 verticesA
= (GfxGouraudVertex
*)
2554 greallocn(verticesA
, vertSize
, sizeof(GfxGouraudVertex
));
2556 verticesA
[nVerticesA
].x
= xMin
+ xMul
* (double)x
;
2557 verticesA
[nVerticesA
].y
= yMin
+ yMul
* (double)y
;
2558 for (i
= 0; i
< nComps
; ++i
) {
2559 verticesA
[nVerticesA
].color
.c
[i
] =
2560 dblToCol(cMin
[i
] + cMul
[i
] * (double)c
[i
]);
2563 bitBuf
->flushBits();
2565 if (state
== 0 || state
== 1) {
2567 } else if (state
== 2 || flag
> 0) {
2568 if (nTrianglesA
== triSize
) {
2569 triSize
= (triSize
== 0) ? 16 : 2 * triSize
;
2570 trianglesA
= (int (*)[3])
2571 greallocn(trianglesA
, triSize
* 3, sizeof(int));
2574 trianglesA
[nTrianglesA
][0] = nVerticesA
- 3;
2575 trianglesA
[nTrianglesA
][1] = nVerticesA
- 2;
2576 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2578 } else if (flag
== 1) {
2579 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][1];
2580 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
2581 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2582 } else { // flag == 2
2583 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][0];
2584 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
2585 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2588 } else { // state == 3 && flag == 0
2595 nRows
= nVerticesA
/ vertsPerRow
;
2596 nTrianglesA
= (nRows
- 1) * 2 * (vertsPerRow
- 1);
2597 trianglesA
= (int (*)[3])gmallocn(nTrianglesA
* 3, sizeof(int));
2599 for (i
= 0; i
< nRows
- 1; ++i
) {
2600 for (j
= 0; j
< vertsPerRow
- 1; ++j
) {
2601 trianglesA
[k
][0] = i
* vertsPerRow
+ j
;
2602 trianglesA
[k
][1] = i
* vertsPerRow
+ j
+1;
2603 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
;
2605 trianglesA
[k
][0] = i
* vertsPerRow
+ j
+1;
2606 trianglesA
[k
][1] = (i
+1) * vertsPerRow
+ j
;
2607 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
+1;
2613 shading
= new GfxGouraudTriangleShading(typeA
, verticesA
, nVerticesA
,
2614 trianglesA
, nTrianglesA
,
2616 if (!shading
->init(dict
)) {
2628 GfxShading
*GfxGouraudTriangleShading::copy() {
2629 return new GfxGouraudTriangleShading(this);
2632 void GfxGouraudTriangleShading::getTriangle(
2634 double *x0
, double *y0
, GfxColor
*color0
,
2635 double *x1
, double *y1
, GfxColor
*color1
,
2636 double *x2
, double *y2
, GfxColor
*color2
) {
2638 double out
[gfxColorMaxComps
];
2641 v
= triangles
[i
][0];
2642 *x0
= vertices
[v
].x
;
2643 *y0
= vertices
[v
].y
;
2645 in
= colToDbl(vertices
[v
].color
.c
[0]);
2646 for (j
= 0; j
< nFuncs
; ++j
) {
2647 funcs
[j
]->transform(&in
, &out
[j
]);
2649 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2650 color0
->c
[j
] = dblToCol(out
[j
]);
2653 *color0
= vertices
[v
].color
;
2655 v
= triangles
[i
][1];
2656 *x1
= vertices
[v
].x
;
2657 *y1
= vertices
[v
].y
;
2659 in
= colToDbl(vertices
[v
].color
.c
[0]);
2660 for (j
= 0; j
< nFuncs
; ++j
) {
2661 funcs
[j
]->transform(&in
, &out
[j
]);
2663 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2664 color1
->c
[j
] = dblToCol(out
[j
]);
2667 *color1
= vertices
[v
].color
;
2669 v
= triangles
[i
][2];
2670 *x2
= vertices
[v
].x
;
2671 *y2
= vertices
[v
].y
;
2673 in
= colToDbl(vertices
[v
].color
.c
[0]);
2674 for (j
= 0; j
< nFuncs
; ++j
) {
2675 funcs
[j
]->transform(&in
, &out
[j
]);
2677 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2678 color2
->c
[j
] = dblToCol(out
[j
]);
2681 *color2
= vertices
[v
].color
;
2685 //------------------------------------------------------------------------
2686 // GfxPatchMeshShading
2687 //------------------------------------------------------------------------
2689 GfxPatchMeshShading::GfxPatchMeshShading(int typeA
,
2690 GfxPatch
*patchesA
, int nPatchesA
,
2691 Function
**funcsA
, int nFuncsA
):
2697 nPatches
= nPatchesA
;
2699 for (i
= 0; i
< nFuncs
; ++i
) {
2700 funcs
[i
] = funcsA
[i
];
2704 GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading
*shading
):
2709 nPatches
= shading
->nPatches
;
2710 patches
= (GfxPatch
*)gmallocn(nPatches
, sizeof(GfxPatch
));
2711 memcpy(patches
, shading
->patches
, nPatches
* sizeof(GfxPatch
));
2712 nFuncs
= shading
->nFuncs
;
2713 for (i
= 0; i
< nFuncs
; ++i
) {
2714 funcs
[i
] = shading
->funcs
[i
]->copy();
2718 GfxPatchMeshShading::~GfxPatchMeshShading() {
2722 for (i
= 0; i
< nFuncs
; ++i
) {
2727 GfxPatchMeshShading
*GfxPatchMeshShading::parse(int typeA
, Dict
*dict
,
2729 GfxPatchMeshShading
*shading
;
2730 Function
*funcsA
[gfxColorMaxComps
];
2732 int coordBits
, compBits
, flagBits
;
2733 double xMin
, xMax
, yMin
, yMax
;
2734 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
2736 double cMul
[gfxColorMaxComps
];
2737 GfxPatch
*patchesA
, *p
;
2738 int nComps
, nPatchesA
, patchesSize
, nPts
, nColors
;
2740 double x
[16], y
[16];
2742 GfxColorComp c
[4][gfxColorMaxComps
];
2744 GfxShadingBitBuf
*bitBuf
;
2748 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
2749 coordBits
= obj1
.getInt();
2751 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2755 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
2756 compBits
= obj1
.getInt();
2758 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2762 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
2763 flagBits
= obj1
.getInt();
2765 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2769 if (dict
->lookup("Decode", &obj1
)->isArray() &&
2770 obj1
.arrayGetLength() >= 6) {
2771 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
2773 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
2775 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
2776 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
2778 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
2780 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
2781 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
2782 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
2784 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
2786 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
2790 error(-1, "Missing or invalid Decode array in shading dictionary");
2795 if (!dict
->lookup("Function", &obj1
)->isNull()) {
2796 if (obj1
.isArray()) {
2797 nFuncsA
= obj1
.arrayGetLength();
2798 if (nFuncsA
> gfxColorMaxComps
) {
2799 error(-1, "Invalid Function array in shading dictionary");
2802 for (i
= 0; i
< nFuncsA
; ++i
) {
2803 obj1
.arrayGet(i
, &obj2
);
2804 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2813 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2826 bitBuf
= new GfxShadingBitBuf(str
);
2828 if (!bitBuf
->getBits(flagBits
, &flag
)) {
2833 case 0: nPts
= 12; nColors
= 4; break;
2837 default: nPts
= 8; nColors
= 2; break;
2841 case 0: nPts
= 16; nColors
= 4; break;
2845 default: nPts
= 12; nColors
= 2; break;
2848 for (i
= 0; i
< nPts
; ++i
) {
2849 if (!bitBuf
->getBits(coordBits
, &xi
) ||
2850 !bitBuf
->getBits(coordBits
, &yi
)) {
2853 x
[i
] = xMin
+ xMul
* (double)xi
;
2854 y
[i
] = yMin
+ yMul
* (double)yi
;
2859 for (i
= 0; i
< nColors
; ++i
) {
2860 for (j
= 0; j
< nComps
; ++j
) {
2861 if (!bitBuf
->getBits(compBits
, &ci
[j
])) {
2864 c
[i
][j
] = dblToCol(cMin
[j
] + cMul
[j
] * (double)ci
[j
]);
2873 if (nPatchesA
== patchesSize
) {
2874 patchesSize
= (patchesSize
== 0) ? 16 : 2 * patchesSize
;
2875 patchesA
= (GfxPatch
*)greallocn(patchesA
,
2876 patchesSize
, sizeof(GfxPatch
));
2878 p
= &patchesA
[nPatchesA
];
2906 for (j
= 0; j
< nComps
; ++j
) {
2907 p
->color
[0][0].c
[j
] = c
[0][j
];
2908 p
->color
[0][1].c
[j
] = c
[1][j
];
2909 p
->color
[1][1].c
[j
] = c
[2][j
];
2910 p
->color
[1][0].c
[j
] = c
[3][j
];
2914 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
2915 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
2916 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
2917 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
2918 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
2919 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
2920 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
2921 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
2938 for (j
= 0; j
< nComps
; ++j
) {
2939 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
2940 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2941 p
->color
[1][1].c
[j
] = c
[0][j
];
2942 p
->color
[1][0].c
[j
] = c
[1][j
];
2946 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
2947 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
2948 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
2949 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
2950 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
2951 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
2952 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
2953 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
2970 for (j
= 0; j
< nComps
; ++j
) {
2971 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2972 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
2973 p
->color
[1][1].c
[j
] = c
[0][j
];
2974 p
->color
[1][0].c
[j
] = c
[1][j
];
2978 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
2979 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
2980 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
2981 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
2982 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
2983 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
2984 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
2985 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
3002 for (j
= 0; j
< nComps
; ++j
) {
3003 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
3004 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
3005 p
->color
[1][1].c
[j
] = c
[0][j
];
3006 p
->color
[1][0].c
[j
] = c
[1][j
];
3045 for (j
= 0; j
< nComps
; ++j
) {
3046 p
->color
[0][0].c
[j
] = c
[0][j
];
3047 p
->color
[0][1].c
[j
] = c
[1][j
];
3048 p
->color
[1][1].c
[j
] = c
[2][j
];
3049 p
->color
[1][0].c
[j
] = c
[3][j
];
3053 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
3054 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
3055 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
3056 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
3057 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
3058 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
3059 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
3060 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
3085 for (j
= 0; j
< nComps
; ++j
) {
3086 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
3087 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
3088 p
->color
[1][1].c
[j
] = c
[0][j
];
3089 p
->color
[1][0].c
[j
] = c
[1][j
];
3093 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
3094 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
3095 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
3096 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
3097 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
3098 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
3099 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
3100 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
3125 for (j
= 0; j
< nComps
; ++j
) {
3126 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
3127 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
3128 p
->color
[1][1].c
[j
] = c
[0][j
];
3129 p
->color
[1][0].c
[j
] = c
[1][j
];
3133 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
3134 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
3135 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
3136 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
3137 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
3138 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
3139 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
3140 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
3165 for (j
= 0; j
< nComps
; ++j
) {
3166 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
3167 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
3168 p
->color
[1][1].c
[j
] = c
[0][j
];
3169 p
->color
[1][0].c
[j
] = c
[1][j
];
3175 bitBuf
->flushBits();
3180 for (i
= 0; i
< nPatchesA
; ++i
) {
3182 p
->x
[1][1] = (-4 * p
->x
[0][0]
3183 +6 * (p
->x
[0][1] + p
->x
[1][0])
3184 -2 * (p
->x
[0][3] + p
->x
[3][0])
3185 +3 * (p
->x
[3][1] + p
->x
[1][3])
3187 p
->y
[1][1] = (-4 * p
->y
[0][0]
3188 +6 * (p
->y
[0][1] + p
->y
[1][0])
3189 -2 * (p
->y
[0][3] + p
->y
[3][0])
3190 +3 * (p
->y
[3][1] + p
->y
[1][3])
3192 p
->x
[1][2] = (-4 * p
->x
[0][3]
3193 +6 * (p
->x
[0][2] + p
->x
[1][3])
3194 -2 * (p
->x
[0][0] + p
->x
[3][3])
3195 +3 * (p
->x
[3][2] + p
->x
[1][0])
3197 p
->y
[1][2] = (-4 * p
->y
[0][3]
3198 +6 * (p
->y
[0][2] + p
->y
[1][3])
3199 -2 * (p
->y
[0][0] + p
->y
[3][3])
3200 +3 * (p
->y
[3][2] + p
->y
[1][0])
3202 p
->x
[2][1] = (-4 * p
->x
[3][0]
3203 +6 * (p
->x
[3][1] + p
->x
[2][0])
3204 -2 * (p
->x
[3][3] + p
->x
[0][0])
3205 +3 * (p
->x
[0][1] + p
->x
[2][3])
3207 p
->y
[2][1] = (-4 * p
->y
[3][0]
3208 +6 * (p
->y
[3][1] + p
->y
[2][0])
3209 -2 * (p
->y
[3][3] + p
->y
[0][0])
3210 +3 * (p
->y
[0][1] + p
->y
[2][3])
3212 p
->x
[2][2] = (-4 * p
->x
[3][3]
3213 +6 * (p
->x
[3][2] + p
->x
[2][3])
3214 -2 * (p
->x
[3][0] + p
->x
[0][3])
3215 +3 * (p
->x
[0][2] + p
->x
[2][0])
3217 p
->y
[2][2] = (-4 * p
->y
[3][3]
3218 +6 * (p
->y
[3][2] + p
->y
[2][3])
3219 -2 * (p
->y
[3][0] + p
->y
[0][3])
3220 +3 * (p
->y
[0][2] + p
->y
[2][0])
3225 shading
= new GfxPatchMeshShading(typeA
, patchesA
, nPatchesA
,
3227 if (!shading
->init(dict
)) {
3239 GfxShading
*GfxPatchMeshShading::copy() {
3240 return new GfxPatchMeshShading(this);
3243 //------------------------------------------------------------------------
3245 //------------------------------------------------------------------------
3247 GfxImageColorMap::GfxImageColorMap(int bitsA
, Object
*decode
,
3248 GfxColorSpace
*colorSpaceA
) {
3249 GfxIndexedColorSpace
*indexedCS
;
3250 GfxSeparationColorSpace
*sepCS
;
3251 int maxPixel
, indexHigh
;
3255 double x
[gfxColorMaxComps
];
3256 double y
[gfxColorMaxComps
];
3262 // bits per component and color space
3264 maxPixel
= (1 << bits
) - 1;
3265 colorSpace
= colorSpaceA
;
3268 if (decode
->isNull()) {
3269 nComps
= colorSpace
->getNComps();
3270 colorSpace
->getDefaultRanges(decodeLow
, decodeRange
, maxPixel
);
3271 } else if (decode
->isArray()) {
3272 nComps
= decode
->arrayGetLength() / 2;
3273 if (nComps
!= colorSpace
->getNComps()) {
3276 for (i
= 0; i
< nComps
; ++i
) {
3277 decode
->arrayGet(2*i
, &obj
);
3281 decodeLow
[i
] = obj
.getNum();
3283 decode
->arrayGet(2*i
+1, &obj
);
3287 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
3294 // Construct a lookup table -- this stores pre-computed decoded
3295 // values for each component, i.e., the result of applying the
3296 // decode mapping to each possible image pixel component value.
3298 // Optimization: for Indexed and Separation color spaces (which have
3299 // only one component), we store color values in the lookup table
3300 // rather than component values.
3301 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
3306 if (colorSpace
->getMode() == csIndexed
) {
3307 // Note that indexHigh may not be the same as maxPixel --
3308 // Distiller will remove unused palette entries, resulting in
3309 // indexHigh < maxPixel.
3310 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
3311 colorSpace2
= indexedCS
->getBase();
3312 indexHigh
= indexedCS
->getIndexHigh();
3313 nComps2
= colorSpace2
->getNComps();
3314 lookup2
= indexedCS
->getLookup();
3315 colorSpace2
->getDefaultRanges(x
, y
, indexHigh
);
3316 byte_lookup
= (Guchar
*)gmalloc ((maxPixel
+ 1) * nComps2
);
3317 for (k
= 0; k
< nComps2
; ++k
) {
3318 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3319 sizeof(GfxColorComp
));
3320 for (i
= 0; i
<= maxPixel
; ++i
) {
3321 j
= (int)(decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
+ 0.5);
3324 } else if (j
> indexHigh
) {
3328 mapped
= x
[k
] + (lookup2
[j
*nComps2
+ k
] / 255.0) * y
[k
];
3329 lookup
[k
][i
] = dblToCol(mapped
);
3330 byte_lookup
[i
* nComps2
+ k
] = (Guchar
) (mapped
* 255);
3333 } else if (colorSpace
->getMode() == csSeparation
) {
3334 sepCS
= (GfxSeparationColorSpace
*)colorSpace
;
3335 colorSpace2
= sepCS
->getAlt();
3336 nComps2
= colorSpace2
->getNComps();
3337 sepFunc
= sepCS
->getFunc();
3338 byte_lookup
= (Guchar
*)gmallocn ((maxPixel
+ 1), nComps2
);
3339 for (k
= 0; k
< nComps2
; ++k
) {
3340 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3341 sizeof(GfxColorComp
));
3342 for (i
= 0; i
<= maxPixel
; ++i
) {
3343 x
[0] = decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
;
3344 sepFunc
->transform(x
, y
);
3345 lookup
[k
][i
] = dblToCol(y
[k
]);
3346 byte_lookup
[i
*nComps2
+ k
] = (Guchar
) (y
[k
] * 255);
3350 byte_lookup
= (Guchar
*)gmallocn ((maxPixel
+ 1), nComps
);
3351 for (k
= 0; k
< nComps
; ++k
) {
3352 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3353 sizeof(GfxColorComp
));
3354 for (i
= 0; i
<= maxPixel
; ++i
) {
3355 mapped
= decodeLow
[k
] + (i
* decodeRange
[k
]) / maxPixel
;
3356 lookup
[k
][i
] = dblToCol(mapped
);
3357 byte
= (int) (mapped
* 255.0 + 0.5);
3360 else if (byte
> 255)
3362 byte_lookup
[i
* nComps
+ k
] = byte
;
3373 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
3379 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap
*colorMap
) {
3382 colorSpace
= colorMap
->colorSpace
->copy();
3383 bits
= colorMap
->bits
;
3384 nComps
= colorMap
->nComps
;
3385 nComps2
= colorMap
->nComps2
;
3387 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
3391 if (colorSpace
->getMode() == csIndexed
) {
3392 colorSpace2
= ((GfxIndexedColorSpace
*)colorSpace
)->getBase();
3393 for (k
= 0; k
< nComps2
; ++k
) {
3394 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3395 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3397 } else if (colorSpace
->getMode() == csSeparation
) {
3398 colorSpace2
= ((GfxSeparationColorSpace
*)colorSpace
)->getAlt();
3399 for (k
= 0; k
< nComps2
; ++k
) {
3400 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3401 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3404 for (k
= 0; k
< nComps
; ++k
) {
3405 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3406 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3409 for (i
= 0; i
< nComps
; ++i
) {
3410 decodeLow
[i
] = colorMap
->decodeLow
[i
];
3411 decodeRange
[i
] = colorMap
->decodeRange
[i
];
3416 GfxImageColorMap::~GfxImageColorMap() {
3420 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3426 void GfxImageColorMap::getGray(Guchar
*x
, GfxGray
*gray
) {
3431 for (i
= 0; i
< nComps2
; ++i
) {
3432 color
.c
[i
] = lookup
[i
][x
[0]];
3434 colorSpace2
->getGray(&color
, gray
);
3436 for (i
= 0; i
< nComps
; ++i
) {
3437 color
.c
[i
] = lookup
[i
][x
[i
]];
3439 colorSpace
->getGray(&color
, gray
);
3443 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
3448 for (i
= 0; i
< nComps2
; ++i
) {
3449 color
.c
[i
] = lookup
[i
][x
[0]];
3451 colorSpace2
->getRGB(&color
, rgb
);
3453 for (i
= 0; i
< nComps
; ++i
) {
3454 color
.c
[i
] = lookup
[i
][x
[i
]];
3456 colorSpace
->getRGB(&color
, rgb
);
3460 void GfxImageColorMap::getGrayLine(Guchar
*in
, Guchar
*out
, int length
) {
3462 Guchar
*inp
, *tmp_line
;
3464 switch (colorSpace
->getMode()) {
3467 tmp_line
= (Guchar
*) gmalloc (length
* nComps2
);
3468 for (i
= 0; i
< length
; i
++) {
3469 for (j
= 0; j
< nComps2
; j
++) {
3470 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
3473 colorSpace2
->getGrayLine(tmp_line
, out
, length
);
3479 for (j
= 0; j
< length
; j
++)
3480 for (i
= 0; i
< nComps
; i
++) {
3481 *inp
= byte_lookup
[*inp
* nComps
+ i
];
3484 colorSpace
->getGrayLine(in
, out
, length
);
3489 void GfxImageColorMap::getRGBLine(Guchar
*in
, unsigned int *out
, int length
) {
3491 Guchar
*inp
, *tmp_line
;
3493 switch (colorSpace
->getMode()) {
3496 tmp_line
= (Guchar
*) gmalloc (length
* nComps2
);
3497 for (i
= 0; i
< length
; i
++) {
3498 for (j
= 0; j
< nComps2
; j
++) {
3499 tmp_line
[i
* nComps2
+ j
] = byte_lookup
[in
[i
] * nComps2
+ j
];
3502 colorSpace2
->getRGBLine(tmp_line
, out
, length
);
3508 for (j
= 0; j
< length
; j
++)
3509 for (i
= 0; i
< nComps
; i
++) {
3510 *inp
= byte_lookup
[*inp
* nComps
+ i
];
3513 colorSpace
->getRGBLine(in
, out
, length
);
3519 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
3524 for (i
= 0; i
< nComps2
; ++i
) {
3525 color
.c
[i
] = lookup
[i
][x
[0]];
3527 colorSpace2
->getCMYK(&color
, cmyk
);
3529 for (i
= 0; i
< nComps
; ++i
) {
3530 color
.c
[i
] = lookup
[i
][x
[i
]];
3532 colorSpace
->getCMYK(&color
, cmyk
);
3536 void GfxImageColorMap::getColor(Guchar
*x
, GfxColor
*color
) {
3539 maxPixel
= (1 << bits
) - 1;
3540 for (i
= 0; i
< nComps
; ++i
) {
3541 color
->c
[i
] = dblToCol(decodeLow
[i
] + (x
[i
] * decodeRange
[i
]) / maxPixel
);
3545 //------------------------------------------------------------------------
3546 // GfxSubpath and GfxPath
3547 //------------------------------------------------------------------------
3549 GfxSubpath::GfxSubpath(double x1
, double y1
) {
3551 x
= (double *)gmallocn(size
, sizeof(double));
3552 y
= (double *)gmallocn(size
, sizeof(double));
3553 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
3561 GfxSubpath::~GfxSubpath() {
3568 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
3569 size
= subpath
->size
;
3571 x
= (double *)gmallocn(size
, sizeof(double));
3572 y
= (double *)gmallocn(size
, sizeof(double));
3573 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
3574 memcpy(x
, subpath
->x
, n
* sizeof(double));
3575 memcpy(y
, subpath
->y
, n
* sizeof(double));
3576 memcpy(curve
, subpath
->curve
, n
* sizeof(GBool
));
3577 closed
= subpath
->closed
;
3580 void GfxSubpath::lineTo(double x1
, double y1
) {
3583 x
= (double *)greallocn(x
, size
, sizeof(double));
3584 y
= (double *)greallocn(y
, size
, sizeof(double));
3585 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
3593 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
3594 double x3
, double y3
) {
3597 x
= (double *)greallocn(x
, size
, sizeof(double));
3598 y
= (double *)greallocn(y
, size
, sizeof(double));
3599 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
3607 curve
[n
] = curve
[n
+1] = gTrue
;
3608 curve
[n
+2] = gFalse
;
3612 void GfxSubpath::close() {
3613 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
3619 void GfxSubpath::offset(double dx
, double dy
) {
3622 for (i
= 0; i
< n
; ++i
) {
3628 GfxPath::GfxPath() {
3632 firstX
= firstY
= 0;
3633 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
3636 GfxPath::~GfxPath() {
3639 for (i
= 0; i
< n
; ++i
)
3645 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
3646 GfxSubpath
**subpaths1
, int n1
, int size1
) {
3649 justMoved
= justMoved1
;
3654 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
3655 for (i
= 0; i
< n
; ++i
)
3656 subpaths
[i
] = subpaths1
[i
]->copy();
3659 void GfxPath::moveTo(double x
, double y
) {
3665 void GfxPath::lineTo(double x
, double y
) {
3669 subpaths
= (GfxSubpath
**)
3670 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3672 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3676 subpaths
[n
-1]->lineTo(x
, y
);
3679 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
3680 double x3
, double y3
) {
3684 subpaths
= (GfxSubpath
**)
3685 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3687 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3691 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
3694 void GfxPath::close() {
3695 // this is necessary to handle the pathological case of
3696 // moveto/closepath/clip, which defines an empty clipping region
3700 subpaths
= (GfxSubpath
**)
3701 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3703 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3707 subpaths
[n
-1]->close();
3710 void GfxPath::append(GfxPath
*path
) {
3713 if (n
+ path
->n
> size
) {
3715 subpaths
= (GfxSubpath
**)
3716 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3718 for (i
= 0; i
< path
->n
; ++i
) {
3719 subpaths
[n
++] = path
->subpaths
[i
]->copy();
3724 void GfxPath::offset(double dx
, double dy
) {
3727 for (i
= 0; i
< n
; ++i
) {
3728 subpaths
[i
]->offset(dx
, dy
);
3732 //------------------------------------------------------------------------
3734 //------------------------------------------------------------------------
3736 GfxState::GfxState(double hDPI
, double vDPI
, PDFRectangle
*pageBox
,
3737 int rotateA
, GBool upsideDown
) {
3749 ctm
[1] = upsideDown
? ky
: -ky
;
3753 ctm
[5] = ky
* (upsideDown
? -px1
: px2
);
3754 pageWidth
= kx
* (py2
- py1
);
3755 pageHeight
= ky
* (px2
- px1
);
3756 } else if (rotate
== 180) {
3760 ctm
[3] = upsideDown
? ky
: -ky
;
3762 ctm
[5] = ky
* (upsideDown
? -py1
: py2
);
3763 pageWidth
= kx
* (px2
- px1
);
3764 pageHeight
= ky
* (py2
- py1
);
3765 } else if (rotate
== 270) {
3767 ctm
[1] = upsideDown
? -ky
: ky
;
3771 ctm
[5] = ky
* (upsideDown
? px2
: -px1
);
3772 pageWidth
= kx
* (py2
- py1
);
3773 pageHeight
= ky
* (px2
- px1
);
3778 ctm
[3] = upsideDown
? -ky
: ky
;
3780 ctm
[5] = ky
* (upsideDown
? py2
: -py1
);
3781 pageWidth
= kx
* (px2
- px1
);
3782 pageHeight
= ky
* (py2
- py1
);
3785 fillColorSpace
= new GfxDeviceGrayColorSpace();
3786 strokeColorSpace
= new GfxDeviceGrayColorSpace();
3788 strokeColor
.c
[0] = 0;
3790 strokePattern
= NULL
;
3791 blendMode
= gfxBlendNormal
;
3794 fillOverprint
= gFalse
;
3795 strokeOverprint
= gFalse
;
3808 textMat
[0] = 1; textMat
[1] = 0;
3809 textMat
[2] = 0; textMat
[3] = 1;
3810 textMat
[4] = 0; textMat
[5] = 0;
3818 path
= new GfxPath();
3824 clipXMax
= pageWidth
;
3825 clipYMax
= pageHeight
;
3830 GfxState::~GfxState() {
3831 if (fillColorSpace
) {
3832 delete fillColorSpace
;
3834 if (strokeColorSpace
) {
3835 delete strokeColorSpace
;
3840 if (strokePattern
) {
3841 delete strokePattern
;
3845 // this gets set to NULL by restore()
3857 GfxState::GfxState(GfxState
*state
) {
3858 memcpy(this, state
, sizeof(GfxState
));
3859 if (fillColorSpace
) {
3860 fillColorSpace
= state
->fillColorSpace
->copy();
3862 if (strokeColorSpace
) {
3863 strokeColorSpace
= state
->strokeColorSpace
->copy();
3866 fillPattern
= state
->fillPattern
->copy();
3868 if (strokePattern
) {
3869 strokePattern
= state
->strokePattern
->copy();
3871 if (lineDashLength
> 0) {
3872 lineDash
= (double *)gmallocn(lineDashLength
, sizeof(double));
3873 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
3881 void GfxState::setPath(GfxPath
*pathA
) {
3886 void GfxState::getUserClipBBox(double *xMin
, double *yMin
,
3887 double *xMax
, double *yMax
) {
3889 double xMin1
, yMin1
, xMax1
, yMax1
, det
, tx
, ty
;
3892 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
3893 ictm
[0] = ctm
[3] * det
;
3894 ictm
[1] = -ctm
[1] * det
;
3895 ictm
[2] = -ctm
[2] * det
;
3896 ictm
[3] = ctm
[0] * det
;
3897 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
3898 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
3900 // transform all four corners of the clip bbox; find the min and max
3902 xMin1
= xMax1
= clipXMin
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
3903 yMin1
= yMax1
= clipXMin
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
3904 tx
= clipXMin
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
3905 ty
= clipXMin
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
3908 } else if (tx
> xMax1
) {
3913 } else if (ty
> yMax1
) {
3916 tx
= clipXMax
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
3917 ty
= clipXMax
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
3920 } else if (tx
> xMax1
) {
3925 } else if (ty
> yMax1
) {
3928 tx
= clipXMax
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
3929 ty
= clipXMax
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
3932 } else if (tx
> xMax1
) {
3937 } else if (ty
> yMax1
) {
3947 double GfxState::transformWidth(double w
) {
3950 x
= ctm
[0] + ctm
[2];
3951 y
= ctm
[1] + ctm
[3];
3952 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
3955 double GfxState::getTransformedFontSize() {
3956 double x1
, y1
, x2
, y2
;
3958 x1
= textMat
[2] * fontSize
;
3959 y1
= textMat
[3] * fontSize
;
3960 x2
= ctm
[0] * x1
+ ctm
[2] * y1
;
3961 y2
= ctm
[1] * x1
+ ctm
[3] * y1
;
3962 return sqrt(x2
* x2
+ y2
* y2
);
3965 void GfxState::getFontTransMat(double *m11
, double *m12
,
3966 double *m21
, double *m22
) {
3967 *m11
= (textMat
[0] * ctm
[0] + textMat
[1] * ctm
[2]) * fontSize
;
3968 *m12
= (textMat
[0] * ctm
[1] + textMat
[1] * ctm
[3]) * fontSize
;
3969 *m21
= (textMat
[2] * ctm
[0] + textMat
[3] * ctm
[2]) * fontSize
;
3970 *m22
= (textMat
[2] * ctm
[1] + textMat
[3] * ctm
[3]) * fontSize
;
3973 void GfxState::setCTM(double a
, double b
, double c
,
3974 double d
, double e
, double f
) {
3984 // avoid FP exceptions on badly messed up PDF files
3985 for (i
= 0; i
< 6; ++i
) {
3986 if (ctm
[i
] > 1e10
) {
3988 } else if (ctm
[i
] < -1e10
) {
3994 void GfxState::concatCTM(double a
, double b
, double c
,
3995 double d
, double e
, double f
) {
4002 ctm
[0] = a
* a1
+ b
* c1
;
4003 ctm
[1] = a
* b1
+ b
* d1
;
4004 ctm
[2] = c
* a1
+ d
* c1
;
4005 ctm
[3] = c
* b1
+ d
* d1
;
4006 ctm
[4] = e
* a1
+ f
* c1
+ ctm
[4];
4007 ctm
[5] = e
* b1
+ f
* d1
+ ctm
[5];
4009 // avoid FP exceptions on badly messed up PDF files
4010 for (i
= 0; i
< 6; ++i
) {
4011 if (ctm
[i
] > 1e10
) {
4013 } else if (ctm
[i
] < -1e10
) {
4019 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
4020 if (fillColorSpace
) {
4021 delete fillColorSpace
;
4023 fillColorSpace
= colorSpace
;
4026 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
4027 if (strokeColorSpace
) {
4028 delete strokeColorSpace
;
4030 strokeColorSpace
= colorSpace
;
4033 void GfxState::setFillPattern(GfxPattern
*pattern
) {
4037 fillPattern
= pattern
;
4040 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
4041 if (strokePattern
) {
4042 delete strokePattern
;
4044 strokePattern
= pattern
;
4047 void GfxState::setFont(GfxFont
*fontA
, double fontSizeA
) {
4052 fontSize
= fontSizeA
;
4055 void GfxState::setLineDash(double *dash
, int length
, double start
) {
4059 lineDashLength
= length
;
4060 lineDashStart
= start
;
4063 void GfxState::clearPath() {
4065 path
= new GfxPath();
4068 void GfxState::clip() {
4069 double xMin
, yMin
, xMax
, yMax
, x
, y
;
4070 GfxSubpath
*subpath
;
4073 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
4074 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
4075 subpath
= path
->getSubpath(i
);
4076 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
4077 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
4078 if (i
== 0 && j
== 0) {
4084 } else if (x
> xMax
) {
4089 } else if (y
> yMax
) {
4095 if (xMin
> clipXMin
) {
4098 if (yMin
> clipYMin
) {
4101 if (xMax
< clipXMax
) {
4104 if (yMax
< clipYMax
) {
4109 void GfxState::textShift(double tx
, double ty
) {
4112 textTransformDelta(tx
, ty
, &dx
, &dy
);
4117 void GfxState::shift(double dx
, double dy
) {
4122 GfxState
*GfxState::save() {
4126 newState
->saved
= this;
4130 GfxState
*GfxState::restore() {
4136 // these attributes aren't saved/restored by the q/Q operators
4137 oldState
->path
= path
;
4138 oldState
->curX
= curX
;
4139 oldState
->curY
= curY
;
4140 oldState
->lineX
= lineX
;
4141 oldState
->lineY
= lineY
;
4154 GBool
GfxState::parseBlendMode(Object
*obj
, GfxBlendMode
*mode
) {
4158 if (obj
->isName()) {
4159 for (i
= 0; i
< nGfxBlendModeNames
; ++i
) {
4160 if (!strcmp(obj
->getNameC(), gfxBlendModeNames
[i
].name
)) {
4161 *mode
= gfxBlendModeNames
[i
].mode
;
4166 } else if (obj
->isArray()) {
4167 for (i
= 0; i
< obj
->arrayGetLength(); ++i
) {
4168 obj
->arrayGet(i
, &obj2
);
4169 if (!obj2
.isName()) {
4173 for (j
= 0; j
< nGfxBlendModeNames
; ++j
) {
4174 if (!strcmp(obj2
.getNameC(), gfxBlendModeNames
[j
].name
)) {
4176 *mode
= gfxBlendModeNames
[j
].mode
;
4182 *mode
= gfxBlendNormal
;