1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 //------------------------------------------------------------------------
27 static inline GfxColorComp
clip01(GfxColorComp x
) {
28 return (x
< 0) ? 0 : (x
> gfxColorComp1
) ? gfxColorComp1
: x
;
31 static inline double clip01(double x
) {
32 return (x
< 0) ? 0 : (x
> 1) ? 1 : x
;
35 //------------------------------------------------------------------------
40 } gfxBlendModeNames
[] = {
41 { "Normal", gfxBlendNormal
},
42 { "Compatible", gfxBlendNormal
},
43 { "Multiply", gfxBlendMultiply
},
44 { "Screen", gfxBlendScreen
},
45 { "Overlay", gfxBlendOverlay
},
46 { "Darken", gfxBlendDarken
},
47 { "Lighten", gfxBlendLighten
},
48 { "ColorDodge", gfxBlendColorDodge
},
49 { "ColorBurn", gfxBlendColorBurn
},
50 { "HardLight", gfxBlendHardLight
},
51 { "SoftLight", gfxBlendSoftLight
},
52 { "Difference", gfxBlendDifference
},
53 { "Exclusion", gfxBlendExclusion
},
54 { "Hue", gfxBlendHue
},
55 { "Saturation", gfxBlendSaturation
},
56 { "Color", gfxBlendColor
},
57 { "Luminosity", gfxBlendLuminosity
}
60 #define nGfxBlendModeNames \
61 ((int)((sizeof(gfxBlendModeNames) / sizeof(char *))))
63 //------------------------------------------------------------------------
65 // NB: This must match the GfxColorSpaceMode enum defined in
67 static char *gfxColorSpaceModeNames
[] = {
81 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
83 //------------------------------------------------------------------------
85 //------------------------------------------------------------------------
87 GfxColorSpace::GfxColorSpace() {
90 GfxColorSpace::~GfxColorSpace() {
93 GfxColorSpace
*GfxColorSpace::parse(Object
*csObj
) {
98 if (csObj
->isName()) {
99 if (csObj
->isName("DeviceGray") || csObj
->isName("G")) {
100 cs
= new GfxDeviceGrayColorSpace();
101 } else if (csObj
->isName("DeviceRGB") || csObj
->isName("RGB")) {
102 cs
= new GfxDeviceRGBColorSpace();
103 } else if (csObj
->isName("DeviceCMYK") || csObj
->isName("CMYK")) {
104 cs
= new GfxDeviceCMYKColorSpace();
105 } else if (csObj
->isName("Pattern")) {
106 cs
= new GfxPatternColorSpace(NULL
);
108 error(-1, "Bad color space '%s'", csObj
->getName());
110 } else if (csObj
->isArray()) {
111 csObj
->arrayGet(0, &obj1
);
112 if (obj1
.isName("DeviceGray") || obj1
.isName("G")) {
113 cs
= new GfxDeviceGrayColorSpace();
114 } else if (obj1
.isName("DeviceRGB") || obj1
.isName("RGB")) {
115 cs
= new GfxDeviceRGBColorSpace();
116 } else if (obj1
.isName("DeviceCMYK") || obj1
.isName("CMYK")) {
117 cs
= new GfxDeviceCMYKColorSpace();
118 } else if (obj1
.isName("CalGray")) {
119 cs
= GfxCalGrayColorSpace::parse(csObj
->getArray());
120 } else if (obj1
.isName("CalRGB")) {
121 cs
= GfxCalRGBColorSpace::parse(csObj
->getArray());
122 } else if (obj1
.isName("Lab")) {
123 cs
= GfxLabColorSpace::parse(csObj
->getArray());
124 } else if (obj1
.isName("ICCBased")) {
125 cs
= GfxICCBasedColorSpace::parse(csObj
->getArray());
126 } else if (obj1
.isName("Indexed") || obj1
.isName("I")) {
127 cs
= GfxIndexedColorSpace::parse(csObj
->getArray());
128 } else if (obj1
.isName("Separation")) {
129 cs
= GfxSeparationColorSpace::parse(csObj
->getArray());
130 } else if (obj1
.isName("DeviceN")) {
131 cs
= GfxDeviceNColorSpace::parse(csObj
->getArray());
132 } else if (obj1
.isName("Pattern")) {
133 cs
= GfxPatternColorSpace::parse(csObj
->getArray());
135 error(-1, "Bad color space");
139 error(-1, "Bad color space - expected name or array");
144 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
148 for (i
= 0; i
< getNComps(); ++i
) {
154 int GfxColorSpace::getNumColorSpaceModes() {
155 return nGfxColorSpaceModes
;
158 char *GfxColorSpace::getColorSpaceModeName(int idx
) {
159 return gfxColorSpaceModeNames
[idx
];
162 //------------------------------------------------------------------------
163 // GfxDeviceGrayColorSpace
164 //------------------------------------------------------------------------
166 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
169 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
172 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
173 return new GfxDeviceGrayColorSpace();
176 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
177 *gray
= clip01(color
->c
[0]);
180 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
181 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
184 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
185 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
186 cmyk
->k
= clip01(gfxColorComp1
- color
->c
[0]);
189 //------------------------------------------------------------------------
190 // GfxCalGrayColorSpace
191 //------------------------------------------------------------------------
193 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
194 whiteX
= whiteY
= whiteZ
= 1;
195 blackX
= blackY
= blackZ
= 0;
199 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
202 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
203 GfxCalGrayColorSpace
*cs
;
205 cs
= new GfxCalGrayColorSpace();
216 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
) {
217 GfxCalGrayColorSpace
*cs
;
218 Object obj1
, obj2
, obj3
;
221 if (!obj1
.isDict()) {
222 error(-1, "Bad CalGray color space");
226 cs
= new GfxCalGrayColorSpace();
227 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
228 obj2
.arrayGetLength() == 3) {
229 obj2
.arrayGet(0, &obj3
);
230 cs
->whiteX
= obj3
.getNum();
232 obj2
.arrayGet(1, &obj3
);
233 cs
->whiteY
= obj3
.getNum();
235 obj2
.arrayGet(2, &obj3
);
236 cs
->whiteZ
= obj3
.getNum();
240 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
241 obj2
.arrayGetLength() == 3) {
242 obj2
.arrayGet(0, &obj3
);
243 cs
->blackX
= obj3
.getNum();
245 obj2
.arrayGet(1, &obj3
);
246 cs
->blackY
= obj3
.getNum();
248 obj2
.arrayGet(2, &obj3
);
249 cs
->blackZ
= obj3
.getNum();
253 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
254 cs
->gamma
= obj2
.getNum();
261 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
262 *gray
= clip01(color
->c
[0]);
265 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
266 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
269 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
270 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
271 cmyk
->k
= clip01(gfxColorComp1
- color
->c
[0]);
274 //------------------------------------------------------------------------
275 // GfxDeviceRGBColorSpace
276 //------------------------------------------------------------------------
278 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
281 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
284 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
285 return new GfxDeviceRGBColorSpace();
288 void GfxDeviceRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
289 *gray
= clip01((GfxColorComp
)(0.3 * color
->c
[0] +
291 0.11 * color
->c
[2] + 0.5));
294 void GfxDeviceRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
295 rgb
->r
= clip01(color
->c
[0]);
296 rgb
->g
= clip01(color
->c
[1]);
297 rgb
->b
= clip01(color
->c
[2]);
300 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
301 GfxColorComp c
, m
, y
, k
;
303 c
= clip01(gfxColorComp1
- color
->c
[0]);
304 m
= clip01(gfxColorComp1
- color
->c
[1]);
305 y
= clip01(gfxColorComp1
- color
->c
[2]);
319 //------------------------------------------------------------------------
320 // GfxCalRGBColorSpace
321 //------------------------------------------------------------------------
323 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
324 whiteX
= whiteY
= whiteZ
= 1;
325 blackX
= blackY
= blackZ
= 0;
326 gammaR
= gammaG
= gammaB
= 1;
327 mat
[0] = 1; mat
[1] = 0; mat
[2] = 0;
328 mat
[3] = 0; mat
[4] = 1; mat
[5] = 0;
329 mat
[6] = 0; mat
[7] = 0; mat
[8] = 1;
332 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
335 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
336 GfxCalRGBColorSpace
*cs
;
339 cs
= new GfxCalRGBColorSpace();
349 for (i
= 0; i
< 9; ++i
) {
355 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
) {
356 GfxCalRGBColorSpace
*cs
;
357 Object obj1
, obj2
, obj3
;
361 if (!obj1
.isDict()) {
362 error(-1, "Bad CalRGB color space");
366 cs
= new GfxCalRGBColorSpace();
367 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
368 obj2
.arrayGetLength() == 3) {
369 obj2
.arrayGet(0, &obj3
);
370 cs
->whiteX
= obj3
.getNum();
372 obj2
.arrayGet(1, &obj3
);
373 cs
->whiteY
= obj3
.getNum();
375 obj2
.arrayGet(2, &obj3
);
376 cs
->whiteZ
= obj3
.getNum();
380 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
381 obj2
.arrayGetLength() == 3) {
382 obj2
.arrayGet(0, &obj3
);
383 cs
->blackX
= obj3
.getNum();
385 obj2
.arrayGet(1, &obj3
);
386 cs
->blackY
= obj3
.getNum();
388 obj2
.arrayGet(2, &obj3
);
389 cs
->blackZ
= obj3
.getNum();
393 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
394 obj2
.arrayGetLength() == 3) {
395 obj2
.arrayGet(0, &obj3
);
396 cs
->gammaR
= obj3
.getNum();
398 obj2
.arrayGet(1, &obj3
);
399 cs
->gammaG
= obj3
.getNum();
401 obj2
.arrayGet(2, &obj3
);
402 cs
->gammaB
= obj3
.getNum();
406 if (obj1
.dictLookup("Matrix", &obj2
)->isArray() &&
407 obj2
.arrayGetLength() == 9) {
408 for (i
= 0; i
< 9; ++i
) {
409 obj2
.arrayGet(i
, &obj3
);
410 cs
->mat
[i
] = obj3
.getNum();
419 void GfxCalRGBColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
420 *gray
= clip01((GfxColorComp
)(0.299 * color
->c
[0] +
421 0.587 * color
->c
[1] +
422 0.114 * color
->c
[2] + 0.5));
425 void GfxCalRGBColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
426 rgb
->r
= clip01(color
->c
[0]);
427 rgb
->g
= clip01(color
->c
[1]);
428 rgb
->b
= clip01(color
->c
[2]);
431 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
432 GfxColorComp c
, m
, y
, k
;
434 c
= clip01(gfxColorComp1
- color
->c
[0]);
435 m
= clip01(gfxColorComp1
- color
->c
[1]);
436 y
= clip01(gfxColorComp1
- color
->c
[2]);
450 //------------------------------------------------------------------------
451 // GfxDeviceCMYKColorSpace
452 //------------------------------------------------------------------------
454 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
457 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
460 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
461 return new GfxDeviceCMYKColorSpace();
464 void GfxDeviceCMYKColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
465 *gray
= clip01((GfxColorComp
)(gfxColorComp1
- color
->c
[3]
468 - 0.11 * color
->c
[2] + 0.5));
471 void GfxDeviceCMYKColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
472 double c
, m
, y
, k
, c1
, m1
, y1
, k1
, r
, g
, b
, x
;
474 c
= colToDbl(color
->c
[0]);
475 m
= colToDbl(color
->c
[1]);
476 y
= colToDbl(color
->c
[2]);
477 k
= colToDbl(color
->c
[3]);
482 // this is a matrix multiplication, unrolled for performance
484 x
= c1
* m1
* y1
* k1
; // 0 0 0 0
486 x
= c1
* m1
* y1
* k
; // 0 0 0 1
490 x
= c1
* m1
* y
* k1
; // 0 0 1 0
493 x
= c1
* m1
* y
* k
; // 0 0 1 1
496 x
= c1
* m
* y1
* k1
; // 0 1 0 0
499 x
= c1
* m
* y1
* k
; // 0 1 0 1
501 x
= c1
* m
* y
* k1
; // 0 1 1 0
505 x
= c1
* m
* y
* k
; // 0 1 1 1
507 x
= c
* m1
* y1
* k1
; // 1 0 0 0
510 x
= c
* m1
* y1
* k
; // 1 0 0 1
513 x
= c
* m1
* y
* k1
; // 1 0 1 0
516 x
= c
* m1
* y
* k
; // 1 0 1 1
518 x
= c
* m
* y1
* k1
; // 1 1 0 0
522 x
= c
* m
* y1
* k
; // 1 1 0 1
524 x
= c
* m
* y
* k1
; // 1 1 1 0
528 rgb
->r
= clip01(dblToCol(r
));
529 rgb
->g
= clip01(dblToCol(g
));
530 rgb
->b
= clip01(dblToCol(b
));
533 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
534 cmyk
->c
= clip01(color
->c
[0]);
535 cmyk
->m
= clip01(color
->c
[1]);
536 cmyk
->y
= clip01(color
->c
[2]);
537 cmyk
->k
= clip01(color
->c
[3]);
540 //------------------------------------------------------------------------
542 //------------------------------------------------------------------------
544 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
545 // Language Reference, Third Edition.
546 static double xyzrgb
[3][3] = {
547 { 3.240449, -1.537136, -0.498531 },
548 { -0.969265, 1.876011, 0.041556 },
549 { 0.055643, -0.204026, 1.057229 }
552 GfxLabColorSpace::GfxLabColorSpace() {
553 whiteX
= whiteY
= whiteZ
= 1;
554 blackX
= blackY
= blackZ
= 0;
559 GfxLabColorSpace::~GfxLabColorSpace() {
562 GfxColorSpace
*GfxLabColorSpace::copy() {
563 GfxLabColorSpace
*cs
;
565 cs
= new GfxLabColorSpace();
582 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
) {
583 GfxLabColorSpace
*cs
;
584 Object obj1
, obj2
, obj3
;
587 if (!obj1
.isDict()) {
588 error(-1, "Bad Lab color space");
592 cs
= new GfxLabColorSpace();
593 if (obj1
.dictLookup("WhitePoint", &obj2
)->isArray() &&
594 obj2
.arrayGetLength() == 3) {
595 obj2
.arrayGet(0, &obj3
);
596 cs
->whiteX
= obj3
.getNum();
598 obj2
.arrayGet(1, &obj3
);
599 cs
->whiteY
= obj3
.getNum();
601 obj2
.arrayGet(2, &obj3
);
602 cs
->whiteZ
= obj3
.getNum();
606 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
607 obj2
.arrayGetLength() == 3) {
608 obj2
.arrayGet(0, &obj3
);
609 cs
->blackX
= obj3
.getNum();
611 obj2
.arrayGet(1, &obj3
);
612 cs
->blackY
= obj3
.getNum();
614 obj2
.arrayGet(2, &obj3
);
615 cs
->blackZ
= obj3
.getNum();
619 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
620 obj2
.arrayGetLength() == 4) {
621 obj2
.arrayGet(0, &obj3
);
622 cs
->aMin
= obj3
.getNum();
624 obj2
.arrayGet(1, &obj3
);
625 cs
->aMax
= obj3
.getNum();
627 obj2
.arrayGet(2, &obj3
);
628 cs
->bMin
= obj3
.getNum();
630 obj2
.arrayGet(3, &obj3
);
631 cs
->bMax
= obj3
.getNum();
637 cs
->kr
= 1 / (xyzrgb
[0][0] * cs
->whiteX
+
638 xyzrgb
[0][1] * cs
->whiteY
+
639 xyzrgb
[0][2] * cs
->whiteZ
);
640 cs
->kg
= 1 / (xyzrgb
[1][0] * cs
->whiteX
+
641 xyzrgb
[1][1] * cs
->whiteY
+
642 xyzrgb
[1][2] * cs
->whiteZ
);
643 cs
->kb
= 1 / (xyzrgb
[2][0] * cs
->whiteX
+
644 xyzrgb
[2][1] * cs
->whiteY
+
645 xyzrgb
[2][2] * cs
->whiteZ
);
650 void GfxLabColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
654 *gray
= clip01((GfxColorComp
)(0.299 * rgb
.r
+
656 0.114 * rgb
.b
+ 0.5));
659 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
664 // convert L*a*b* to CIE 1931 XYZ color space
665 t1
= (colToDbl(color
->c
[0]) + 16) / 116;
666 t2
= t1
+ colToDbl(color
->c
[1]) / 500;
667 if (t2
>= (6.0 / 29.0)) {
670 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
673 if (t1
>= (6.0 / 29.0)) {
676 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
679 t2
= t1
- colToDbl(color
->c
[2]) / 200;
680 if (t2
>= (6.0 / 29.0)) {
683 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
687 // convert XYZ to RGB, including gamut mapping and gamma correction
688 r
= xyzrgb
[0][0] * X
+ xyzrgb
[0][1] * Y
+ xyzrgb
[0][2] * Z
;
689 g
= xyzrgb
[1][0] * X
+ xyzrgb
[1][1] * Y
+ xyzrgb
[1][2] * Z
;
690 b
= xyzrgb
[2][0] * X
+ xyzrgb
[2][1] * Y
+ xyzrgb
[2][2] * Z
;
691 rgb
->r
= dblToCol(pow(clip01(r
* kr
), 0.5));
692 rgb
->g
= dblToCol(pow(clip01(g
* kg
), 0.5));
693 rgb
->b
= dblToCol(pow(clip01(b
* kb
), 0.5));
696 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
698 GfxColorComp c
, m
, y
, k
;
701 c
= clip01(gfxColorComp1
- rgb
.r
);
702 m
= clip01(gfxColorComp1
- rgb
.g
);
703 y
= clip01(gfxColorComp1
- rgb
.b
);
717 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
720 decodeRange
[0] = 100;
722 decodeRange
[1] = aMax
- aMin
;
724 decodeRange
[2] = bMax
- bMin
;
727 //------------------------------------------------------------------------
728 // GfxICCBasedColorSpace
729 //------------------------------------------------------------------------
731 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA
, GfxColorSpace
*altA
,
732 Ref
*iccProfileStreamA
) {
735 iccProfileStream
= *iccProfileStreamA
;
736 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
737 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
740 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
744 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
745 GfxICCBasedColorSpace
*cs
;
748 cs
= new GfxICCBasedColorSpace(nComps
, alt
->copy(), &iccProfileStream
);
749 for (i
= 0; i
< 4; ++i
) {
750 cs
->rangeMin
[i
] = rangeMin
[i
];
751 cs
->rangeMax
[i
] = rangeMax
[i
];
756 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
) {
757 GfxICCBasedColorSpace
*cs
;
758 Ref iccProfileStreamA
;
762 Object obj1
, obj2
, obj3
;
765 arr
->getNF(1, &obj1
);
767 iccProfileStreamA
= obj1
.getRef();
769 iccProfileStreamA
.num
= 0;
770 iccProfileStreamA
.gen
= 0;
774 if (!obj1
.isStream()) {
775 error(-1, "Bad ICCBased color space (stream)");
779 dict
= obj1
.streamGetDict();
780 if (!dict
->lookup("N", &obj2
)->isInt()) {
781 error(-1, "Bad ICCBased color space (N)");
786 nCompsA
= obj2
.getInt();
788 if (nCompsA
> gfxColorMaxComps
) {
789 error(-1, "ICCBased color space with too many (%d > %d) components",
790 nCompsA
, gfxColorMaxComps
);
791 nCompsA
= gfxColorMaxComps
;
793 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
794 !(altA
= GfxColorSpace::parse(&obj2
))) {
797 altA
= new GfxDeviceGrayColorSpace();
800 altA
= new GfxDeviceRGBColorSpace();
803 altA
= new GfxDeviceCMYKColorSpace();
806 error(-1, "Bad ICCBased color space - invalid N");
813 cs
= new GfxICCBasedColorSpace(nCompsA
, altA
, &iccProfileStreamA
);
814 if (dict
->lookup("Range", &obj2
)->isArray() &&
815 obj2
.arrayGetLength() == 2 * nCompsA
) {
816 for (i
= 0; i
< nCompsA
; ++i
) {
817 obj2
.arrayGet(2*i
, &obj3
);
818 cs
->rangeMin
[i
] = obj3
.getNum();
820 obj2
.arrayGet(2*i
+1, &obj3
);
821 cs
->rangeMax
[i
] = obj3
.getNum();
830 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
831 alt
->getGray(color
, gray
);
834 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
835 alt
->getRGB(color
, rgb
);
838 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
839 alt
->getCMYK(color
, cmyk
);
842 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
845 alt
->getDefaultRanges(decodeLow
, decodeRange
, maxImgPixel
);
848 // this is nominally correct, but some PDF files don't set the
849 // correct ranges in the ICCBased dict
852 for (i
= 0; i
< nComps
; ++i
) {
853 decodeLow
[i
] = rangeMin
[i
];
854 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
859 //------------------------------------------------------------------------
860 // GfxIndexedColorSpace
861 //------------------------------------------------------------------------
863 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*baseA
,
866 indexHigh
= indexHighA
;
867 lookup
= (Guchar
*)gmallocn((indexHigh
+ 1) * base
->getNComps(),
871 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
876 GfxColorSpace
*GfxIndexedColorSpace::copy() {
877 GfxIndexedColorSpace
*cs
;
879 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
880 memcpy(cs
->lookup
, lookup
,
881 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
885 GfxColorSpace
*GfxIndexedColorSpace::parse(Array
*arr
) {
886 GfxIndexedColorSpace
*cs
;
887 GfxColorSpace
*baseA
;
894 if (arr
->getLength() != 4) {
895 error(-1, "Bad Indexed color space");
899 if (!(baseA
= GfxColorSpace::parse(&obj1
))) {
900 error(-1, "Bad Indexed color space (base color space)");
904 if (!arr
->get(2, &obj1
)->isInt()) {
905 error(-1, "Bad Indexed color space (hival)");
909 indexHighA
= obj1
.getInt();
910 if (indexHighA
< 0 || indexHighA
> 255) {
911 // the PDF spec requires indexHigh to be in [0,255] -- allowing
912 // values larger than 255 creates a security hole: if nComps *
913 // indexHigh is greater than 2^31, the loop below may overwrite
914 // past the end of the array
915 error(-1, "Bad Indexed color space (invalid indexHigh value)");
920 cs
= new GfxIndexedColorSpace(baseA
, indexHighA
);
922 n
= baseA
->getNComps();
923 if (obj1
.isStream()) {
925 for (i
= 0; i
<= indexHighA
; ++i
) {
926 for (j
= 0; j
< n
; ++j
) {
927 if ((x
= obj1
.streamGetChar()) == EOF
) {
928 error(-1, "Bad Indexed color space (lookup table stream too short)");
931 cs
->lookup
[i
*n
+ j
] = (Guchar
)x
;
935 } else if (obj1
.isString()) {
936 if (obj1
.getString()->getLength() < (indexHighA
+ 1) * n
) {
937 error(-1, "Bad Indexed color space (lookup table string too short)");
940 s
= obj1
.getString()->getCString();
941 for (i
= 0; i
<= indexHighA
; ++i
) {
942 for (j
= 0; j
< n
; ++j
) {
943 cs
->lookup
[i
*n
+ j
] = (Guchar
)*s
++;
947 error(-1, "Bad Indexed color space (lookup table)");
961 GfxColor
*GfxIndexedColorSpace::mapColorToBase(GfxColor
*color
,
962 GfxColor
*baseColor
) {
964 double low
[gfxColorMaxComps
], range
[gfxColorMaxComps
];
967 n
= base
->getNComps();
968 base
->getDefaultRanges(low
, range
, indexHigh
);
969 p
= &lookup
[(int)(colToDbl(color
->c
[0]) + 0.5) * n
];
970 for (i
= 0; i
< n
; ++i
) {
971 baseColor
->c
[i
] = dblToCol(low
[i
] + (p
[i
] / 255.0) * range
[i
]);
976 void GfxIndexedColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
979 base
->getGray(mapColorToBase(color
, &color2
), gray
);
982 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
985 base
->getRGB(mapColorToBase(color
, &color2
), rgb
);
988 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
991 base
->getCMYK(mapColorToBase(color
, &color2
), cmyk
);
994 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
998 decodeRange
[0] = maxImgPixel
;
1001 //------------------------------------------------------------------------
1002 // GfxSeparationColorSpace
1003 //------------------------------------------------------------------------
1005 GfxSeparationColorSpace::GfxSeparationColorSpace(GString
*nameA
,
1006 GfxColorSpace
*altA
,
1013 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1019 GfxColorSpace
*GfxSeparationColorSpace::copy() {
1020 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy());
1023 //~ handle the 'All' and 'None' colorants
1024 GfxColorSpace
*GfxSeparationColorSpace::parse(Array
*arr
) {
1025 GfxSeparationColorSpace
*cs
;
1027 GfxColorSpace
*altA
;
1031 if (arr
->getLength() != 4) {
1032 error(-1, "Bad Separation color space");
1035 if (!arr
->get(1, &obj1
)->isName()) {
1036 error(-1, "Bad Separation color space (name)");
1039 nameA
= new GString(obj1
.getName());
1042 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1043 error(-1, "Bad Separation color space (alternate color space)");
1048 if (!(funcA
= Function::parse(&obj1
))) {
1052 cs
= new GfxSeparationColorSpace(nameA
, altA
, funcA
);
1065 void GfxSeparationColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1067 double c
[gfxColorMaxComps
];
1071 x
= colToDbl(color
->c
[0]);
1072 func
->transform(&x
, c
);
1073 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1074 color2
.c
[i
] = dblToCol(c
[i
]);
1076 alt
->getGray(&color2
, gray
);
1079 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1081 double c
[gfxColorMaxComps
];
1085 x
= colToDbl(color
->c
[0]);
1086 func
->transform(&x
, c
);
1087 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1088 color2
.c
[i
] = dblToCol(c
[i
]);
1090 alt
->getRGB(&color2
, rgb
);
1093 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1095 double c
[gfxColorMaxComps
];
1099 x
= colToDbl(color
->c
[0]);
1100 func
->transform(&x
, c
);
1101 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1102 color2
.c
[i
] = dblToCol(c
[i
]);
1104 alt
->getCMYK(&color2
, cmyk
);
1107 //------------------------------------------------------------------------
1108 // GfxDeviceNColorSpace
1109 //------------------------------------------------------------------------
1111 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA
,
1112 GfxColorSpace
*altA
,
1119 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1122 for (i
= 0; i
< nComps
; ++i
) {
1129 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
1130 GfxDeviceNColorSpace
*cs
;
1133 cs
= new GfxDeviceNColorSpace(nComps
, alt
->copy(), func
->copy());
1134 for (i
= 0; i
< nComps
; ++i
) {
1135 cs
->names
[i
] = names
[i
]->copy();
1140 //~ handle the 'None' colorant
1141 GfxColorSpace
*GfxDeviceNColorSpace::parse(Array
*arr
) {
1142 GfxDeviceNColorSpace
*cs
;
1144 GString
*namesA
[gfxColorMaxComps
];
1145 GfxColorSpace
*altA
;
1150 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
1151 error(-1, "Bad DeviceN color space");
1154 if (!arr
->get(1, &obj1
)->isArray()) {
1155 error(-1, "Bad DeviceN color space (names)");
1158 nCompsA
= obj1
.arrayGetLength();
1159 if (nCompsA
> gfxColorMaxComps
) {
1160 error(-1, "DeviceN color space with too many (%d > %d) components",
1161 nCompsA
, gfxColorMaxComps
);
1162 nCompsA
= gfxColorMaxComps
;
1164 for (i
= 0; i
< nCompsA
; ++i
) {
1165 if (!obj1
.arrayGet(i
, &obj2
)->isName()) {
1166 error(-1, "Bad DeviceN color space (names)");
1170 namesA
[i
] = new GString(obj2
.getName());
1175 if (!(altA
= GfxColorSpace::parse(&obj1
))) {
1176 error(-1, "Bad DeviceN color space (alternate color space)");
1181 if (!(funcA
= Function::parse(&obj1
))) {
1185 cs
= new GfxDeviceNColorSpace(nCompsA
, altA
, funcA
);
1186 for (i
= 0; i
< nCompsA
; ++i
) {
1187 cs
->names
[i
] = namesA
[i
];
1194 for (i
= 0; i
< nCompsA
; ++i
) {
1203 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1204 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1208 for (i
= 0; i
< nComps
; ++i
) {
1209 x
[i
] = colToDbl(color
->c
[i
]);
1211 func
->transform(x
, c
);
1212 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1213 color2
.c
[i
] = dblToCol(c
[i
]);
1215 alt
->getGray(&color2
, gray
);
1218 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1219 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1223 for (i
= 0; i
< nComps
; ++i
) {
1224 x
[i
] = colToDbl(color
->c
[i
]);
1226 func
->transform(x
, c
);
1227 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1228 color2
.c
[i
] = dblToCol(c
[i
]);
1230 alt
->getRGB(&color2
, rgb
);
1233 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1234 double x
[gfxColorMaxComps
], c
[gfxColorMaxComps
];
1238 for (i
= 0; i
< nComps
; ++i
) {
1239 x
[i
] = colToDbl(color
->c
[i
]);
1241 func
->transform(x
, c
);
1242 for (i
= 0; i
< alt
->getNComps(); ++i
) {
1243 color2
.c
[i
] = dblToCol(c
[i
]);
1245 alt
->getCMYK(&color2
, cmyk
);
1248 //------------------------------------------------------------------------
1249 // GfxPatternColorSpace
1250 //------------------------------------------------------------------------
1252 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*underA
) {
1256 GfxPatternColorSpace::~GfxPatternColorSpace() {
1262 GfxColorSpace
*GfxPatternColorSpace::copy() {
1263 return new GfxPatternColorSpace(under
? under
->copy() :
1264 (GfxColorSpace
*)NULL
);
1267 GfxColorSpace
*GfxPatternColorSpace::parse(Array
*arr
) {
1268 GfxPatternColorSpace
*cs
;
1269 GfxColorSpace
*underA
;
1272 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
1273 error(-1, "Bad Pattern color space");
1277 if (arr
->getLength() == 2) {
1279 if (!(underA
= GfxColorSpace::parse(&obj1
))) {
1280 error(-1, "Bad Pattern color space (underlying color space)");
1286 cs
= new GfxPatternColorSpace(underA
);
1290 void GfxPatternColorSpace::getGray(GfxColor
*color
, GfxGray
*gray
) {
1294 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1295 rgb
->r
= rgb
->g
= rgb
->b
= 0;
1298 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1299 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
1303 //------------------------------------------------------------------------
1305 //------------------------------------------------------------------------
1307 GfxPattern::GfxPattern(int typeA
) {
1311 GfxPattern::~GfxPattern() {
1314 GfxPattern
*GfxPattern::parse(Object
*obj
) {
1315 GfxPattern
*pattern
;
1318 if (obj
->isDict()) {
1319 obj
->dictLookup("PatternType", &obj1
);
1320 } else if (obj
->isStream()) {
1321 obj
->streamGetDict()->lookup("PatternType", &obj1
);
1326 if (obj1
.isInt() && obj1
.getInt() == 1) {
1327 pattern
= GfxTilingPattern::parse(obj
);
1328 } else if (obj1
.isInt() && obj1
.getInt() == 2) {
1329 pattern
= GfxShadingPattern::parse(obj
);
1335 //------------------------------------------------------------------------
1337 //------------------------------------------------------------------------
1339 GfxTilingPattern
*GfxTilingPattern::parse(Object
*patObj
) {
1340 GfxTilingPattern
*pat
;
1342 int paintTypeA
, tilingTypeA
;
1343 double bboxA
[4], matrixA
[6];
1344 double xStepA
, yStepA
;
1349 if (!patObj
->isStream()) {
1352 dict
= patObj
->streamGetDict();
1354 if (dict
->lookup("PaintType", &obj1
)->isInt()) {
1355 paintTypeA
= obj1
.getInt();
1358 error(-1, "Invalid or missing PaintType in pattern");
1361 if (dict
->lookup("TilingType", &obj1
)->isInt()) {
1362 tilingTypeA
= obj1
.getInt();
1365 error(-1, "Invalid or missing TilingType in pattern");
1368 bboxA
[0] = bboxA
[1] = 0;
1369 bboxA
[2] = bboxA
[3] = 1;
1370 if (dict
->lookup("BBox", &obj1
)->isArray() &&
1371 obj1
.arrayGetLength() == 4) {
1372 for (i
= 0; i
< 4; ++i
) {
1373 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1374 bboxA
[i
] = obj2
.getNum();
1379 error(-1, "Invalid or missing BBox in pattern");
1382 if (dict
->lookup("XStep", &obj1
)->isNum()) {
1383 xStepA
= obj1
.getNum();
1386 error(-1, "Invalid or missing XStep in pattern");
1389 if (dict
->lookup("YStep", &obj1
)->isNum()) {
1390 yStepA
= obj1
.getNum();
1393 error(-1, "Invalid or missing YStep in pattern");
1396 if (!dict
->lookup("Resources", &resDictA
)->isDict()) {
1398 resDictA
.initNull();
1399 error(-1, "Invalid or missing Resources in pattern");
1401 matrixA
[0] = 1; matrixA
[1] = 0;
1402 matrixA
[2] = 0; matrixA
[3] = 1;
1403 matrixA
[4] = 0; matrixA
[5] = 0;
1404 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1405 obj1
.arrayGetLength() == 6) {
1406 for (i
= 0; i
< 6; ++i
) {
1407 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1408 matrixA
[i
] = obj2
.getNum();
1415 pat
= new GfxTilingPattern(paintTypeA
, tilingTypeA
, bboxA
, xStepA
, yStepA
,
1416 &resDictA
, matrixA
, patObj
);
1421 GfxTilingPattern::GfxTilingPattern(int paintTypeA
, int tilingTypeA
,
1422 double *bboxA
, double xStepA
, double yStepA
,
1423 Object
*resDictA
, double *matrixA
,
1424 Object
*contentStreamA
):
1429 paintType
= paintTypeA
;
1430 tilingType
= tilingTypeA
;
1431 for (i
= 0; i
< 4; ++i
) {
1436 resDictA
->copy(&resDict
);
1437 for (i
= 0; i
< 6; ++i
) {
1438 matrix
[i
] = matrixA
[i
];
1440 contentStreamA
->copy(&contentStream
);
1443 GfxTilingPattern::~GfxTilingPattern() {
1445 contentStream
.free();
1448 GfxPattern
*GfxTilingPattern::copy() {
1449 return new GfxTilingPattern(paintType
, tilingType
, bbox
, xStep
, yStep
,
1450 &resDict
, matrix
, &contentStream
);
1453 //------------------------------------------------------------------------
1454 // GfxShadingPattern
1455 //------------------------------------------------------------------------
1457 GfxShadingPattern
*GfxShadingPattern::parse(Object
*patObj
) {
1459 GfxShading
*shadingA
;
1464 if (!patObj
->isDict()) {
1467 dict
= patObj
->getDict();
1469 dict
->lookup("Shading", &obj1
);
1470 shadingA
= GfxShading::parse(&obj1
);
1476 matrixA
[0] = 1; matrixA
[1] = 0;
1477 matrixA
[2] = 0; matrixA
[3] = 1;
1478 matrixA
[4] = 0; matrixA
[5] = 0;
1479 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1480 obj1
.arrayGetLength() == 6) {
1481 for (i
= 0; i
< 6; ++i
) {
1482 if (obj1
.arrayGet(i
, &obj2
)->isNum()) {
1483 matrixA
[i
] = obj2
.getNum();
1490 return new GfxShadingPattern(shadingA
, matrixA
);
1493 GfxShadingPattern::GfxShadingPattern(GfxShading
*shadingA
, double *matrixA
):
1499 for (i
= 0; i
< 6; ++i
) {
1500 matrix
[i
] = matrixA
[i
];
1504 GfxShadingPattern::~GfxShadingPattern() {
1508 GfxPattern
*GfxShadingPattern::copy() {
1509 return new GfxShadingPattern(shading
->copy(), matrix
);
1512 //------------------------------------------------------------------------
1514 //------------------------------------------------------------------------
1516 GfxShading::GfxShading(int typeA
) {
1521 GfxShading::GfxShading(GfxShading
*shading
) {
1524 type
= shading
->type
;
1525 colorSpace
= shading
->colorSpace
->copy();
1526 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1527 background
.c
[i
] = shading
->background
.c
[i
];
1529 hasBackground
= shading
->hasBackground
;
1530 xMin
= shading
->xMin
;
1531 yMin
= shading
->yMin
;
1532 xMax
= shading
->xMax
;
1533 yMax
= shading
->yMax
;
1534 hasBBox
= shading
->hasBBox
;
1537 GfxShading::~GfxShading() {
1543 GfxShading
*GfxShading::parse(Object
*obj
) {
1544 GfxShading
*shading
;
1549 if (obj
->isDict()) {
1550 dict
= obj
->getDict();
1551 } else if (obj
->isStream()) {
1552 dict
= obj
->streamGetDict();
1557 if (!dict
->lookup("ShadingType", &obj1
)->isInt()) {
1558 error(-1, "Invalid ShadingType in shading dictionary");
1562 typeA
= obj1
.getInt();
1567 shading
= GfxFunctionShading::parse(dict
);
1570 shading
= GfxAxialShading::parse(dict
);
1573 shading
= GfxRadialShading::parse(dict
);
1576 if (obj
->isStream()) {
1577 shading
= GfxGouraudTriangleShading::parse(4, dict
, obj
->getStream());
1579 error(-1, "Invalid Type 4 shading object");
1584 if (obj
->isStream()) {
1585 shading
= GfxGouraudTriangleShading::parse(5, dict
, obj
->getStream());
1587 error(-1, "Invalid Type 5 shading object");
1592 if (obj
->isStream()) {
1593 shading
= GfxPatchMeshShading::parse(6, dict
, obj
->getStream());
1595 error(-1, "Invalid Type 6 shading object");
1600 if (obj
->isStream()) {
1601 shading
= GfxPatchMeshShading::parse(7, dict
, obj
->getStream());
1603 error(-1, "Invalid Type 7 shading object");
1608 error(-1, "Unimplemented shading type %d", typeA
);
1618 GBool
GfxShading::init(Dict
*dict
) {
1622 dict
->lookup("ColorSpace", &obj1
);
1623 if (!(colorSpace
= GfxColorSpace::parse(&obj1
))) {
1624 error(-1, "Bad color space in shading dictionary");
1630 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1631 background
.c
[i
] = 0;
1633 hasBackground
= gFalse
;
1634 if (dict
->lookup("Background", &obj1
)->isArray()) {
1635 if (obj1
.arrayGetLength() == colorSpace
->getNComps()) {
1636 hasBackground
= gTrue
;
1637 for (i
= 0; i
< colorSpace
->getNComps(); ++i
) {
1638 background
.c
[i
] = dblToCol(obj1
.arrayGet(i
, &obj2
)->getNum());
1642 error(-1, "Bad Background in shading dictionary");
1647 xMin
= yMin
= xMax
= yMax
= 0;
1649 if (dict
->lookup("BBox", &obj1
)->isArray()) {
1650 if (obj1
.arrayGetLength() == 4) {
1652 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
1654 yMin
= obj1
.arrayGet(1, &obj2
)->getNum();
1656 xMax
= obj1
.arrayGet(2, &obj2
)->getNum();
1658 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
1661 error(-1, "Bad BBox in shading dictionary");
1669 //------------------------------------------------------------------------
1670 // GfxFunctionShading
1671 //------------------------------------------------------------------------
1673 GfxFunctionShading::GfxFunctionShading(double x0A
, double y0A
,
1674 double x1A
, double y1A
,
1676 Function
**funcsA
, int nFuncsA
):
1685 for (i
= 0; i
< 6; ++i
) {
1686 matrix
[i
] = matrixA
[i
];
1689 for (i
= 0; i
< nFuncs
; ++i
) {
1690 funcs
[i
] = funcsA
[i
];
1694 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading
*shading
):
1703 for (i
= 0; i
< 6; ++i
) {
1704 matrix
[i
] = shading
->matrix
[i
];
1706 nFuncs
= shading
->nFuncs
;
1707 for (i
= 0; i
< nFuncs
; ++i
) {
1708 funcs
[i
] = shading
->funcs
[i
]->copy();
1712 GfxFunctionShading::~GfxFunctionShading() {
1715 for (i
= 0; i
< nFuncs
; ++i
) {
1720 GfxFunctionShading
*GfxFunctionShading::parse(Dict
*dict
) {
1721 GfxFunctionShading
*shading
;
1722 double x0A
, y0A
, x1A
, y1A
;
1724 Function
*funcsA
[gfxColorMaxComps
];
1731 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1732 obj1
.arrayGetLength() == 4) {
1733 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1735 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1737 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1739 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1744 matrixA
[0] = 1; matrixA
[1] = 0;
1745 matrixA
[2] = 0; matrixA
[3] = 1;
1746 matrixA
[4] = 0; matrixA
[5] = 0;
1747 if (dict
->lookup("Matrix", &obj1
)->isArray() &&
1748 obj1
.arrayGetLength() == 6) {
1749 matrixA
[0] = obj1
.arrayGet(0, &obj2
)->getNum();
1751 matrixA
[1] = obj1
.arrayGet(1, &obj2
)->getNum();
1753 matrixA
[2] = obj1
.arrayGet(2, &obj2
)->getNum();
1755 matrixA
[3] = obj1
.arrayGet(3, &obj2
)->getNum();
1757 matrixA
[4] = obj1
.arrayGet(4, &obj2
)->getNum();
1759 matrixA
[5] = obj1
.arrayGet(5, &obj2
)->getNum();
1764 dict
->lookup("Function", &obj1
);
1765 if (obj1
.isArray()) {
1766 nFuncsA
= obj1
.arrayGetLength();
1767 if (nFuncsA
> gfxColorMaxComps
) {
1768 error(-1, "Invalid Function array in shading dictionary");
1771 for (i
= 0; i
< nFuncsA
; ++i
) {
1772 obj1
.arrayGet(i
, &obj2
);
1773 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1780 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1786 shading
= new GfxFunctionShading(x0A
, y0A
, x1A
, y1A
, matrixA
,
1788 if (!shading
->init(dict
)) {
1801 GfxShading
*GfxFunctionShading::copy() {
1802 return new GfxFunctionShading(this);
1805 void GfxFunctionShading::getColor(double x
, double y
, GfxColor
*color
) {
1806 double in
[2], out
[gfxColorMaxComps
];
1809 // NB: there can be one function with n outputs or n functions with
1810 // one output each (where n = number of color components)
1811 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1816 for (i
= 0; i
< nFuncs
; ++i
) {
1817 funcs
[i
]->transform(in
, &out
[i
]);
1819 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1820 color
->c
[i
] = dblToCol(out
[i
]);
1824 //------------------------------------------------------------------------
1826 //------------------------------------------------------------------------
1828 GfxAxialShading::GfxAxialShading(double x0A
, double y0A
,
1829 double x1A
, double y1A
,
1830 double t0A
, double t1A
,
1831 Function
**funcsA
, int nFuncsA
,
1832 GBool extend0A
, GBool extend1A
):
1844 for (i
= 0; i
< nFuncs
; ++i
) {
1845 funcs
[i
] = funcsA
[i
];
1851 GfxAxialShading::GfxAxialShading(GfxAxialShading
*shading
):
1862 nFuncs
= shading
->nFuncs
;
1863 for (i
= 0; i
< nFuncs
; ++i
) {
1864 funcs
[i
] = shading
->funcs
[i
]->copy();
1866 extend0
= shading
->extend0
;
1867 extend1
= shading
->extend1
;
1870 GfxAxialShading::~GfxAxialShading() {
1873 for (i
= 0; i
< nFuncs
; ++i
) {
1878 GfxAxialShading
*GfxAxialShading::parse(Dict
*dict
) {
1879 GfxAxialShading
*shading
;
1880 double x0A
, y0A
, x1A
, y1A
;
1882 Function
*funcsA
[gfxColorMaxComps
];
1884 GBool extend0A
, extend1A
;
1888 x0A
= y0A
= x1A
= y1A
= 0;
1889 if (dict
->lookup("Coords", &obj1
)->isArray() &&
1890 obj1
.arrayGetLength() == 4) {
1891 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1893 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
1895 x1A
= obj1
.arrayGet(2, &obj2
)->getNum();
1897 y1A
= obj1
.arrayGet(3, &obj2
)->getNum();
1900 error(-1, "Missing or invalid Coords in shading dictionary");
1907 if (dict
->lookup("Domain", &obj1
)->isArray() &&
1908 obj1
.arrayGetLength() == 2) {
1909 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
1911 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
1916 dict
->lookup("Function", &obj1
);
1917 if (obj1
.isArray()) {
1918 nFuncsA
= obj1
.arrayGetLength();
1919 if (nFuncsA
> gfxColorMaxComps
) {
1920 error(-1, "Invalid Function array in shading dictionary");
1923 for (i
= 0; i
< nFuncsA
; ++i
) {
1924 obj1
.arrayGet(i
, &obj2
);
1925 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
1934 if (!(funcsA
[0] = Function::parse(&obj1
))) {
1941 extend0A
= extend1A
= gFalse
;
1942 if (dict
->lookup("Extend", &obj1
)->isArray() &&
1943 obj1
.arrayGetLength() == 2) {
1944 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
1946 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
1951 shading
= new GfxAxialShading(x0A
, y0A
, x1A
, y1A
, t0A
, t1A
,
1952 funcsA
, nFuncsA
, extend0A
, extend1A
);
1953 if (!shading
->init(dict
)) {
1963 GfxShading
*GfxAxialShading::copy() {
1964 return new GfxAxialShading(this);
1967 void GfxAxialShading::getColor(double t
, GfxColor
*color
) {
1968 double out
[gfxColorMaxComps
];
1971 // NB: there can be one function with n outputs or n functions with
1972 // one output each (where n = number of color components)
1973 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1976 for (i
= 0; i
< nFuncs
; ++i
) {
1977 funcs
[i
]->transform(&t
, &out
[i
]);
1979 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
1980 color
->c
[i
] = dblToCol(out
[i
]);
1984 //------------------------------------------------------------------------
1986 //------------------------------------------------------------------------
1988 GfxRadialShading::GfxRadialShading(double x0A
, double y0A
, double r0A
,
1989 double x1A
, double y1A
, double r1A
,
1990 double t0A
, double t1A
,
1991 Function
**funcsA
, int nFuncsA
,
1992 GBool extend0A
, GBool extend1A
):
2006 for (i
= 0; i
< nFuncs
; ++i
) {
2007 funcs
[i
] = funcsA
[i
];
2013 GfxRadialShading::GfxRadialShading(GfxRadialShading
*shading
):
2026 nFuncs
= shading
->nFuncs
;
2027 for (i
= 0; i
< nFuncs
; ++i
) {
2028 funcs
[i
] = shading
->funcs
[i
]->copy();
2030 extend0
= shading
->extend0
;
2031 extend1
= shading
->extend1
;
2034 GfxRadialShading::~GfxRadialShading() {
2037 for (i
= 0; i
< nFuncs
; ++i
) {
2042 GfxRadialShading
*GfxRadialShading::parse(Dict
*dict
) {
2043 GfxRadialShading
*shading
;
2044 double x0A
, y0A
, r0A
, x1A
, y1A
, r1A
;
2046 Function
*funcsA
[gfxColorMaxComps
];
2048 GBool extend0A
, extend1A
;
2052 x0A
= y0A
= r0A
= x1A
= y1A
= r1A
= 0;
2053 if (dict
->lookup("Coords", &obj1
)->isArray() &&
2054 obj1
.arrayGetLength() == 6) {
2055 x0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2057 y0A
= obj1
.arrayGet(1, &obj2
)->getNum();
2059 r0A
= obj1
.arrayGet(2, &obj2
)->getNum();
2061 x1A
= obj1
.arrayGet(3, &obj2
)->getNum();
2063 y1A
= obj1
.arrayGet(4, &obj2
)->getNum();
2065 r1A
= obj1
.arrayGet(5, &obj2
)->getNum();
2068 error(-1, "Missing or invalid Coords in shading dictionary");
2075 if (dict
->lookup("Domain", &obj1
)->isArray() &&
2076 obj1
.arrayGetLength() == 2) {
2077 t0A
= obj1
.arrayGet(0, &obj2
)->getNum();
2079 t1A
= obj1
.arrayGet(1, &obj2
)->getNum();
2084 dict
->lookup("Function", &obj1
);
2085 if (obj1
.isArray()) {
2086 nFuncsA
= obj1
.arrayGetLength();
2087 if (nFuncsA
> gfxColorMaxComps
) {
2088 error(-1, "Invalid Function array in shading dictionary");
2091 for (i
= 0; i
< nFuncsA
; ++i
) {
2092 obj1
.arrayGet(i
, &obj2
);
2093 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2102 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2109 extend0A
= extend1A
= gFalse
;
2110 if (dict
->lookup("Extend", &obj1
)->isArray() &&
2111 obj1
.arrayGetLength() == 2) {
2112 extend0A
= obj1
.arrayGet(0, &obj2
)->getBool();
2114 extend1A
= obj1
.arrayGet(1, &obj2
)->getBool();
2119 shading
= new GfxRadialShading(x0A
, y0A
, r0A
, x1A
, y1A
, r1A
, t0A
, t1A
,
2120 funcsA
, nFuncsA
, extend0A
, extend1A
);
2121 if (!shading
->init(dict
)) {
2131 GfxShading
*GfxRadialShading::copy() {
2132 return new GfxRadialShading(this);
2135 void GfxRadialShading::getColor(double t
, GfxColor
*color
) {
2136 double out
[gfxColorMaxComps
];
2139 // NB: there can be one function with n outputs or n functions with
2140 // one output each (where n = number of color components)
2141 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2144 for (i
= 0; i
< nFuncs
; ++i
) {
2145 funcs
[i
]->transform(&t
, &out
[i
]);
2147 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
2148 color
->c
[i
] = dblToCol(out
[i
]);
2152 //------------------------------------------------------------------------
2154 //------------------------------------------------------------------------
2156 class GfxShadingBitBuf
{
2159 GfxShadingBitBuf(Stream
*strA
);
2160 ~GfxShadingBitBuf();
2161 GBool
getBits(int n
, Guint
*val
);
2171 GfxShadingBitBuf::GfxShadingBitBuf(Stream
*strA
) {
2178 GfxShadingBitBuf::~GfxShadingBitBuf() {
2182 GBool
GfxShadingBitBuf::getBits(int n
, Guint
*val
) {
2186 x
= (bitBuf
>> (nBits
- n
)) & ((1 << n
) - 1);
2191 x
= bitBuf
& ((1 << nBits
) - 1);
2196 if ((bitBuf
= str
->getChar()) == EOF
) {
2201 x
= (x
<< 8) | bitBuf
;
2204 x
= (x
<< n
) | (bitBuf
>> (8 - n
));
2214 void GfxShadingBitBuf::flushBits() {
2219 //------------------------------------------------------------------------
2220 // GfxGouraudTriangleShading
2221 //------------------------------------------------------------------------
2223 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2225 GfxGouraudVertex
*verticesA
, int nVerticesA
,
2226 int (*trianglesA
)[3], int nTrianglesA
,
2227 Function
**funcsA
, int nFuncsA
):
2232 vertices
= verticesA
;
2233 nVertices
= nVerticesA
;
2234 triangles
= trianglesA
;
2235 nTriangles
= nTrianglesA
;
2237 for (i
= 0; i
< nFuncs
; ++i
) {
2238 funcs
[i
] = funcsA
[i
];
2242 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2243 GfxGouraudTriangleShading
*shading
):
2248 nVertices
= shading
->nVertices
;
2249 vertices
= (GfxGouraudVertex
*)gmallocn(nVertices
, sizeof(GfxGouraudVertex
));
2250 memcpy(vertices
, shading
->vertices
, nVertices
* sizeof(GfxGouraudVertex
));
2251 nTriangles
= shading
->nTriangles
;
2252 triangles
= (int (*)[3])gmallocn(nTriangles
* 3, sizeof(int));
2253 memcpy(triangles
, shading
->triangles
, nTriangles
* 3 * sizeof(int));
2254 nFuncs
= shading
->nFuncs
;
2255 for (i
= 0; i
< nFuncs
; ++i
) {
2256 funcs
[i
] = shading
->funcs
[i
]->copy();
2260 GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2265 for (i
= 0; i
< nFuncs
; ++i
) {
2270 GfxGouraudTriangleShading
*GfxGouraudTriangleShading::parse(int typeA
,
2273 GfxGouraudTriangleShading
*shading
;
2274 Function
*funcsA
[gfxColorMaxComps
];
2276 int coordBits
, compBits
, flagBits
, vertsPerRow
, nRows
;
2277 double xMin
, xMax
, yMin
, yMax
;
2278 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
2280 double cMul
[gfxColorMaxComps
];
2281 GfxGouraudVertex
*verticesA
;
2282 int (*trianglesA
)[3];
2283 int nComps
, nVerticesA
, nTrianglesA
, vertSize
, triSize
;
2285 Guint c
[gfxColorMaxComps
];
2286 GfxShadingBitBuf
*bitBuf
;
2290 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
2291 coordBits
= obj1
.getInt();
2293 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2297 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
2298 compBits
= obj1
.getInt();
2300 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2304 flagBits
= vertsPerRow
= 0; // make gcc happy
2306 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
2307 flagBits
= obj1
.getInt();
2309 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2314 if (dict
->lookup("VerticesPerRow", &obj1
)->isInt()) {
2315 vertsPerRow
= obj1
.getInt();
2317 error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
2322 if (dict
->lookup("Decode", &obj1
)->isArray() &&
2323 obj1
.arrayGetLength() >= 6) {
2324 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
2326 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
2328 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
2329 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
2331 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
2333 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
2334 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
2335 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
2337 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
2339 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
2343 error(-1, "Missing or invalid Decode array in shading dictionary");
2348 if (!dict
->lookup("Function", &obj1
)->isNull()) {
2349 if (obj1
.isArray()) {
2350 nFuncsA
= obj1
.arrayGetLength();
2351 if (nFuncsA
> gfxColorMaxComps
) {
2352 error(-1, "Invalid Function array in shading dictionary");
2355 for (i
= 0; i
< nFuncsA
; ++i
) {
2356 obj1
.arrayGet(i
, &obj2
);
2357 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2366 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2376 nVerticesA
= nTrianglesA
= 0;
2379 vertSize
= triSize
= 0;
2381 flag
= 0; // make gcc happy
2382 bitBuf
= new GfxShadingBitBuf(str
);
2385 if (!bitBuf
->getBits(flagBits
, &flag
)) {
2389 if (!bitBuf
->getBits(coordBits
, &x
) ||
2390 !bitBuf
->getBits(coordBits
, &y
)) {
2393 for (i
= 0; i
< nComps
; ++i
) {
2394 if (!bitBuf
->getBits(compBits
, &c
[i
])) {
2401 if (nVerticesA
== vertSize
) {
2402 vertSize
= (vertSize
== 0) ? 16 : 2 * vertSize
;
2403 verticesA
= (GfxGouraudVertex
*)
2404 greallocn(verticesA
, vertSize
, sizeof(GfxGouraudVertex
));
2406 verticesA
[nVerticesA
].x
= xMin
+ xMul
* (double)x
;
2407 verticesA
[nVerticesA
].y
= yMin
+ yMul
* (double)y
;
2408 for (i
= 0; i
< nComps
; ++i
) {
2409 verticesA
[nVerticesA
].color
.c
[i
] =
2410 dblToCol(cMin
[i
] + cMul
[i
] * (double)c
[i
]);
2413 bitBuf
->flushBits();
2415 if (state
== 0 || state
== 1) {
2417 } else if (state
== 2 || flag
> 0) {
2418 if (nTrianglesA
== triSize
) {
2419 triSize
= (triSize
== 0) ? 16 : 2 * triSize
;
2420 trianglesA
= (int (*)[3])
2421 greallocn(trianglesA
, triSize
* 3, sizeof(int));
2424 trianglesA
[nTrianglesA
][0] = nVerticesA
- 3;
2425 trianglesA
[nTrianglesA
][1] = nVerticesA
- 2;
2426 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2428 } else if (flag
== 1) {
2429 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][1];
2430 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
2431 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2432 } else { // flag == 2
2433 trianglesA
[nTrianglesA
][0] = trianglesA
[nTrianglesA
- 1][0];
2434 trianglesA
[nTrianglesA
][1] = trianglesA
[nTrianglesA
- 1][2];
2435 trianglesA
[nTrianglesA
][2] = nVerticesA
- 1;
2438 } else { // state == 3 && flag == 0
2445 nRows
= nVerticesA
/ vertsPerRow
;
2446 nTrianglesA
= (nRows
- 1) * 2 * (vertsPerRow
- 1);
2447 trianglesA
= (int (*)[3])gmallocn(nTrianglesA
* 3, sizeof(int));
2449 for (i
= 0; i
< nRows
- 1; ++i
) {
2450 for (j
= 0; j
< vertsPerRow
- 1; ++j
) {
2451 trianglesA
[k
][0] = i
* vertsPerRow
+ j
;
2452 trianglesA
[k
][1] = i
* vertsPerRow
+ j
+1;
2453 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
;
2455 trianglesA
[k
][0] = i
* vertsPerRow
+ j
+1;
2456 trianglesA
[k
][1] = (i
+1) * vertsPerRow
+ j
;
2457 trianglesA
[k
][2] = (i
+1) * vertsPerRow
+ j
+1;
2463 shading
= new GfxGouraudTriangleShading(typeA
, verticesA
, nVerticesA
,
2464 trianglesA
, nTrianglesA
,
2466 if (!shading
->init(dict
)) {
2478 GfxShading
*GfxGouraudTriangleShading::copy() {
2479 return new GfxGouraudTriangleShading(this);
2482 void GfxGouraudTriangleShading::getTriangle(
2484 double *x0
, double *y0
, GfxColor
*color0
,
2485 double *x1
, double *y1
, GfxColor
*color1
,
2486 double *x2
, double *y2
, GfxColor
*color2
) {
2488 double out
[gfxColorMaxComps
];
2491 v
= triangles
[i
][0];
2492 *x0
= vertices
[v
].x
;
2493 *y0
= vertices
[v
].y
;
2495 in
= colToDbl(vertices
[v
].color
.c
[0]);
2496 for (j
= 0; j
< nFuncs
; ++j
) {
2497 funcs
[j
]->transform(&in
, &out
[j
]);
2499 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2500 color0
->c
[j
] = dblToCol(out
[j
]);
2503 *color0
= vertices
[v
].color
;
2505 v
= triangles
[i
][1];
2506 *x1
= vertices
[v
].x
;
2507 *y1
= vertices
[v
].y
;
2509 in
= colToDbl(vertices
[v
].color
.c
[0]);
2510 for (j
= 0; j
< nFuncs
; ++j
) {
2511 funcs
[j
]->transform(&in
, &out
[j
]);
2513 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2514 color1
->c
[j
] = dblToCol(out
[j
]);
2517 *color1
= vertices
[v
].color
;
2519 v
= triangles
[i
][2];
2520 *x2
= vertices
[v
].x
;
2521 *y2
= vertices
[v
].y
;
2523 in
= colToDbl(vertices
[v
].color
.c
[0]);
2524 for (j
= 0; j
< nFuncs
; ++j
) {
2525 funcs
[j
]->transform(&in
, &out
[j
]);
2527 for (j
= 0; j
< gfxColorMaxComps
; ++j
) {
2528 color2
->c
[j
] = dblToCol(out
[j
]);
2531 *color2
= vertices
[v
].color
;
2535 //------------------------------------------------------------------------
2536 // GfxPatchMeshShading
2537 //------------------------------------------------------------------------
2539 GfxPatchMeshShading::GfxPatchMeshShading(int typeA
,
2540 GfxPatch
*patchesA
, int nPatchesA
,
2541 Function
**funcsA
, int nFuncsA
):
2547 nPatches
= nPatchesA
;
2549 for (i
= 0; i
< nFuncs
; ++i
) {
2550 funcs
[i
] = funcsA
[i
];
2554 GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading
*shading
):
2559 nPatches
= shading
->nPatches
;
2560 patches
= (GfxPatch
*)gmallocn(nPatches
, sizeof(GfxPatch
));
2561 memcpy(patches
, shading
->patches
, nPatches
* sizeof(GfxPatch
));
2562 nFuncs
= shading
->nFuncs
;
2563 for (i
= 0; i
< nFuncs
; ++i
) {
2564 funcs
[i
] = shading
->funcs
[i
]->copy();
2568 GfxPatchMeshShading::~GfxPatchMeshShading() {
2572 for (i
= 0; i
< nFuncs
; ++i
) {
2577 GfxPatchMeshShading
*GfxPatchMeshShading::parse(int typeA
, Dict
*dict
,
2579 GfxPatchMeshShading
*shading
;
2580 Function
*funcsA
[gfxColorMaxComps
];
2582 int coordBits
, compBits
, flagBits
;
2583 double xMin
, xMax
, yMin
, yMax
;
2584 double cMin
[gfxColorMaxComps
], cMax
[gfxColorMaxComps
];
2586 double cMul
[gfxColorMaxComps
];
2587 GfxPatch
*patchesA
, *p
;
2588 int nComps
, nPatchesA
, patchesSize
, nPts
, nColors
;
2590 double x
[16], y
[16];
2592 GfxColorComp c
[4][gfxColorMaxComps
];
2594 GfxShadingBitBuf
*bitBuf
;
2598 if (dict
->lookup("BitsPerCoordinate", &obj1
)->isInt()) {
2599 coordBits
= obj1
.getInt();
2601 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2605 if (dict
->lookup("BitsPerComponent", &obj1
)->isInt()) {
2606 compBits
= obj1
.getInt();
2608 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2612 if (dict
->lookup("BitsPerFlag", &obj1
)->isInt()) {
2613 flagBits
= obj1
.getInt();
2615 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2619 if (dict
->lookup("Decode", &obj1
)->isArray() &&
2620 obj1
.arrayGetLength() >= 6) {
2621 xMin
= obj1
.arrayGet(0, &obj2
)->getNum();
2623 xMax
= obj1
.arrayGet(1, &obj2
)->getNum();
2625 xMul
= (xMax
- xMin
) / (pow(2.0, coordBits
) - 1);
2626 yMin
= obj1
.arrayGet(2, &obj2
)->getNum();
2628 yMax
= obj1
.arrayGet(3, &obj2
)->getNum();
2630 yMul
= (yMax
- yMin
) / (pow(2.0, coordBits
) - 1);
2631 for (i
= 0; 5 + 2*i
< obj1
.arrayGetLength() && i
< gfxColorMaxComps
; ++i
) {
2632 cMin
[i
] = obj1
.arrayGet(4 + 2*i
, &obj2
)->getNum();
2634 cMax
[i
] = obj1
.arrayGet(5 + 2*i
, &obj2
)->getNum();
2636 cMul
[i
] = (cMax
[i
] - cMin
[i
]) / (double)((1 << compBits
) - 1);
2640 error(-1, "Missing or invalid Decode array in shading dictionary");
2645 if (!dict
->lookup("Function", &obj1
)->isNull()) {
2646 if (obj1
.isArray()) {
2647 nFuncsA
= obj1
.arrayGetLength();
2648 if (nFuncsA
> gfxColorMaxComps
) {
2649 error(-1, "Invalid Function array in shading dictionary");
2652 for (i
= 0; i
< nFuncsA
; ++i
) {
2653 obj1
.arrayGet(i
, &obj2
);
2654 if (!(funcsA
[i
] = Function::parse(&obj2
))) {
2663 if (!(funcsA
[0] = Function::parse(&obj1
))) {
2676 bitBuf
= new GfxShadingBitBuf(str
);
2678 if (!bitBuf
->getBits(flagBits
, &flag
)) {
2683 case 0: nPts
= 12; nColors
= 4; break;
2687 default: nPts
= 8; nColors
= 2; break;
2691 case 0: nPts
= 16; nColors
= 4; break;
2695 default: nPts
= 12; nColors
= 2; break;
2698 for (i
= 0; i
< nPts
; ++i
) {
2699 if (!bitBuf
->getBits(coordBits
, &xi
) ||
2700 !bitBuf
->getBits(coordBits
, &yi
)) {
2703 x
[i
] = xMin
+ xMul
* (double)xi
;
2704 y
[i
] = yMin
+ yMul
* (double)yi
;
2709 for (i
= 0; i
< nColors
; ++i
) {
2710 for (j
= 0; j
< nComps
; ++j
) {
2711 if (!bitBuf
->getBits(compBits
, &ci
[j
])) {
2714 c
[i
][j
] = dblToCol(cMin
[j
] + cMul
[j
] * (double)ci
[j
]);
2723 if (nPatchesA
== patchesSize
) {
2724 patchesSize
= (patchesSize
== 0) ? 16 : 2 * patchesSize
;
2725 patchesA
= (GfxPatch
*)greallocn(patchesA
,
2726 patchesSize
, sizeof(GfxPatch
));
2728 p
= &patchesA
[nPatchesA
];
2756 for (j
= 0; j
< nComps
; ++j
) {
2757 p
->color
[0][0].c
[j
] = c
[0][j
];
2758 p
->color
[0][1].c
[j
] = c
[1][j
];
2759 p
->color
[1][1].c
[j
] = c
[2][j
];
2760 p
->color
[1][0].c
[j
] = c
[3][j
];
2764 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
2765 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
2766 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
2767 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
2768 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
2769 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
2770 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
2771 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
2788 for (j
= 0; j
< nComps
; ++j
) {
2789 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
2790 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2791 p
->color
[1][1].c
[j
] = c
[0][j
];
2792 p
->color
[1][0].c
[j
] = c
[1][j
];
2796 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
2797 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
2798 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
2799 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
2800 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
2801 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
2802 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
2803 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
2820 for (j
= 0; j
< nComps
; ++j
) {
2821 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2822 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
2823 p
->color
[1][1].c
[j
] = c
[0][j
];
2824 p
->color
[1][0].c
[j
] = c
[1][j
];
2828 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
2829 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
2830 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
2831 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
2832 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
2833 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
2834 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
2835 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
2852 for (j
= 0; j
< nComps
; ++j
) {
2853 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
2854 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
2855 p
->color
[1][1].c
[j
] = c
[0][j
];
2856 p
->color
[1][0].c
[j
] = c
[1][j
];
2895 for (j
= 0; j
< nComps
; ++j
) {
2896 p
->color
[0][0].c
[j
] = c
[0][j
];
2897 p
->color
[0][1].c
[j
] = c
[1][j
];
2898 p
->color
[1][1].c
[j
] = c
[2][j
];
2899 p
->color
[1][0].c
[j
] = c
[3][j
];
2903 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[0][3];
2904 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[0][3];
2905 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[1][3];
2906 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[1][3];
2907 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[2][3];
2908 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[2][3];
2909 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][3];
2910 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][3];
2935 for (j
= 0; j
< nComps
; ++j
) {
2936 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[0][1].c
[j
];
2937 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2938 p
->color
[1][1].c
[j
] = c
[0][j
];
2939 p
->color
[1][0].c
[j
] = c
[1][j
];
2943 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][3];
2944 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][3];
2945 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[3][2];
2946 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[3][2];
2947 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[3][1];
2948 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[3][1];
2949 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[3][0];
2950 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[3][0];
2975 for (j
= 0; j
< nComps
; ++j
) {
2976 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][1].c
[j
];
2977 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
2978 p
->color
[1][1].c
[j
] = c
[0][j
];
2979 p
->color
[1][0].c
[j
] = c
[1][j
];
2983 p
->x
[0][0] = patchesA
[nPatchesA
-1].x
[3][0];
2984 p
->y
[0][0] = patchesA
[nPatchesA
-1].y
[3][0];
2985 p
->x
[0][1] = patchesA
[nPatchesA
-1].x
[2][0];
2986 p
->y
[0][1] = patchesA
[nPatchesA
-1].y
[2][0];
2987 p
->x
[0][2] = patchesA
[nPatchesA
-1].x
[1][0];
2988 p
->y
[0][2] = patchesA
[nPatchesA
-1].y
[1][0];
2989 p
->x
[0][3] = patchesA
[nPatchesA
-1].x
[0][0];
2990 p
->y
[0][3] = patchesA
[nPatchesA
-1].y
[0][0];
3015 for (j
= 0; j
< nComps
; ++j
) {
3016 p
->color
[0][0].c
[j
] = patchesA
[nPatchesA
-1].color
[1][0].c
[j
];
3017 p
->color
[0][1].c
[j
] = patchesA
[nPatchesA
-1].color
[0][0].c
[j
];
3018 p
->color
[1][1].c
[j
] = c
[0][j
];
3019 p
->color
[1][0].c
[j
] = c
[1][j
];
3025 bitBuf
->flushBits();
3030 for (i
= 0; i
< nPatchesA
; ++i
) {
3032 p
->x
[1][1] = (-4 * p
->x
[0][0]
3033 +6 * (p
->x
[0][1] + p
->x
[1][0])
3034 -2 * (p
->x
[0][3] + p
->x
[3][0])
3035 +3 * (p
->x
[3][1] + p
->x
[1][3])
3037 p
->y
[1][1] = (-4 * p
->y
[0][0]
3038 +6 * (p
->y
[0][1] + p
->y
[1][0])
3039 -2 * (p
->y
[0][3] + p
->y
[3][0])
3040 +3 * (p
->y
[3][1] + p
->y
[1][3])
3042 p
->x
[1][2] = (-4 * p
->x
[0][3]
3043 +6 * (p
->x
[0][2] + p
->x
[1][3])
3044 -2 * (p
->x
[0][0] + p
->x
[3][3])
3045 +3 * (p
->x
[3][2] + p
->x
[1][0])
3047 p
->y
[1][2] = (-4 * p
->y
[0][3]
3048 +6 * (p
->y
[0][2] + p
->y
[1][3])
3049 -2 * (p
->y
[0][0] + p
->y
[3][3])
3050 +3 * (p
->y
[3][2] + p
->y
[1][0])
3052 p
->x
[2][1] = (-4 * p
->x
[3][0]
3053 +6 * (p
->x
[3][1] + p
->x
[2][0])
3054 -2 * (p
->x
[3][3] + p
->x
[0][0])
3055 +3 * (p
->x
[0][1] + p
->x
[2][3])
3057 p
->y
[2][1] = (-4 * p
->y
[3][0]
3058 +6 * (p
->y
[3][1] + p
->y
[2][0])
3059 -2 * (p
->y
[3][3] + p
->y
[0][0])
3060 +3 * (p
->y
[0][1] + p
->y
[2][3])
3062 p
->x
[2][2] = (-4 * p
->x
[3][3]
3063 +6 * (p
->x
[3][2] + p
->x
[2][3])
3064 -2 * (p
->x
[3][0] + p
->x
[0][3])
3065 +3 * (p
->x
[0][2] + p
->x
[2][0])
3067 p
->y
[2][2] = (-4 * p
->y
[3][3]
3068 +6 * (p
->y
[3][2] + p
->y
[2][3])
3069 -2 * (p
->y
[3][0] + p
->y
[0][3])
3070 +3 * (p
->y
[0][2] + p
->y
[2][0])
3075 shading
= new GfxPatchMeshShading(typeA
, patchesA
, nPatchesA
,
3077 if (!shading
->init(dict
)) {
3089 GfxShading
*GfxPatchMeshShading::copy() {
3090 return new GfxPatchMeshShading(this);
3093 //------------------------------------------------------------------------
3095 //------------------------------------------------------------------------
3097 GfxImageColorMap::GfxImageColorMap(int bitsA
, Object
*decode
,
3098 GfxColorSpace
*colorSpaceA
) {
3099 GfxIndexedColorSpace
*indexedCS
;
3100 GfxSeparationColorSpace
*sepCS
;
3101 int maxPixel
, indexHigh
;
3105 double x
[gfxColorMaxComps
];
3106 double y
[gfxColorMaxComps
];
3111 // bits per component and color space
3113 maxPixel
= (1 << bits
) - 1;
3114 colorSpace
= colorSpaceA
;
3117 if (decode
->isNull()) {
3118 nComps
= colorSpace
->getNComps();
3119 colorSpace
->getDefaultRanges(decodeLow
, decodeRange
, maxPixel
);
3120 } else if (decode
->isArray()) {
3121 nComps
= decode
->arrayGetLength() / 2;
3122 if (nComps
!= colorSpace
->getNComps()) {
3125 for (i
= 0; i
< nComps
; ++i
) {
3126 decode
->arrayGet(2*i
, &obj
);
3130 decodeLow
[i
] = obj
.getNum();
3132 decode
->arrayGet(2*i
+1, &obj
);
3136 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
3143 // Construct a lookup table -- this stores pre-computed decoded
3144 // values for each component, i.e., the result of applying the
3145 // decode mapping to each possible image pixel component value.
3147 // Optimization: for Indexed and Separation color spaces (which have
3148 // only one component), we store color values in the lookup table
3149 // rather than component values.
3150 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
3155 if (colorSpace
->getMode() == csIndexed
) {
3156 // Note that indexHigh may not be the same as maxPixel --
3157 // Distiller will remove unused palette entries, resulting in
3158 // indexHigh < maxPixel.
3159 indexedCS
= (GfxIndexedColorSpace
*)colorSpace
;
3160 colorSpace2
= indexedCS
->getBase();
3161 indexHigh
= indexedCS
->getIndexHigh();
3162 nComps2
= colorSpace2
->getNComps();
3163 lookup2
= indexedCS
->getLookup();
3164 colorSpace2
->getDefaultRanges(x
, y
, indexHigh
);
3165 for (k
= 0; k
< nComps2
; ++k
) {
3166 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3167 sizeof(GfxColorComp
));
3168 for (i
= 0; i
<= maxPixel
; ++i
) {
3169 j
= (int)(decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
+ 0.5);
3172 } else if (j
> indexHigh
) {
3176 dblToCol(x
[k
] + (lookup2
[j
*nComps2
+ k
] / 255.0) * y
[k
]);
3179 } else if (colorSpace
->getMode() == csSeparation
) {
3180 sepCS
= (GfxSeparationColorSpace
*)colorSpace
;
3181 colorSpace2
= sepCS
->getAlt();
3182 nComps2
= colorSpace2
->getNComps();
3183 sepFunc
= sepCS
->getFunc();
3184 for (k
= 0; k
< nComps2
; ++k
) {
3185 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3186 sizeof(GfxColorComp
));
3187 for (i
= 0; i
<= maxPixel
; ++i
) {
3188 x
[0] = decodeLow
[0] + (i
* decodeRange
[0]) / maxPixel
;
3189 sepFunc
->transform(x
, y
);
3190 lookup
[k
][i
] = dblToCol(y
[k
]);
3194 for (k
= 0; k
< nComps
; ++k
) {
3195 lookup
[k
] = (GfxColorComp
*)gmallocn(maxPixel
+ 1,
3196 sizeof(GfxColorComp
));
3197 for (i
= 0; i
<= maxPixel
; ++i
) {
3198 lookup
[k
][i
] = dblToCol(decodeLow
[k
] +
3199 (i
* decodeRange
[k
]) / maxPixel
);
3212 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap
*colorMap
) {
3215 colorSpace
= colorMap
->colorSpace
->copy();
3216 bits
= colorMap
->bits
;
3217 nComps
= colorMap
->nComps
;
3218 nComps2
= colorMap
->nComps2
;
3220 for (k
= 0; k
< gfxColorMaxComps
; ++k
) {
3224 if (colorSpace
->getMode() == csIndexed
) {
3225 colorSpace2
= ((GfxIndexedColorSpace
*)colorSpace
)->getBase();
3226 for (k
= 0; k
< nComps2
; ++k
) {
3227 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3228 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3230 } else if (colorSpace
->getMode() == csSeparation
) {
3231 colorSpace2
= ((GfxSeparationColorSpace
*)colorSpace
)->getAlt();
3232 for (k
= 0; k
< nComps2
; ++k
) {
3233 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3234 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3237 for (k
= 0; k
< nComps
; ++k
) {
3238 lookup
[k
] = (GfxColorComp
*)gmallocn(n
, sizeof(GfxColorComp
));
3239 memcpy(lookup
[k
], colorMap
->lookup
[k
], n
* sizeof(GfxColorComp
));
3242 for (i
= 0; i
< nComps
; ++i
) {
3243 decodeLow
[i
] = colorMap
->decodeLow
[i
];
3244 decodeRange
[i
] = colorMap
->decodeRange
[i
];
3249 GfxImageColorMap::~GfxImageColorMap() {
3253 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
3258 void GfxImageColorMap::getGray(Guchar
*x
, GfxGray
*gray
) {
3263 for (i
= 0; i
< nComps2
; ++i
) {
3264 color
.c
[i
] = lookup
[i
][x
[0]];
3266 colorSpace2
->getGray(&color
, gray
);
3268 for (i
= 0; i
< nComps
; ++i
) {
3269 color
.c
[i
] = lookup
[i
][x
[i
]];
3271 colorSpace
->getGray(&color
, gray
);
3275 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
3280 for (i
= 0; i
< nComps2
; ++i
) {
3281 color
.c
[i
] = lookup
[i
][x
[0]];
3283 colorSpace2
->getRGB(&color
, rgb
);
3285 for (i
= 0; i
< nComps
; ++i
) {
3286 color
.c
[i
] = lookup
[i
][x
[i
]];
3288 colorSpace
->getRGB(&color
, rgb
);
3292 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
3297 for (i
= 0; i
< nComps2
; ++i
) {
3298 color
.c
[i
] = lookup
[i
][x
[0]];
3300 colorSpace2
->getCMYK(&color
, cmyk
);
3302 for (i
= 0; i
< nComps
; ++i
) {
3303 color
.c
[i
] = lookup
[i
][x
[i
]];
3305 colorSpace
->getCMYK(&color
, cmyk
);
3309 void GfxImageColorMap::getColor(Guchar
*x
, GfxColor
*color
) {
3312 maxPixel
= (1 << bits
) - 1;
3313 for (i
= 0; i
< nComps
; ++i
) {
3314 color
->c
[i
] = dblToCol(decodeLow
[i
] + (x
[i
] * decodeRange
[i
]) / maxPixel
);
3318 //------------------------------------------------------------------------
3319 // GfxSubpath and GfxPath
3320 //------------------------------------------------------------------------
3322 GfxSubpath::GfxSubpath(double x1
, double y1
) {
3324 x
= (double *)gmallocn(size
, sizeof(double));
3325 y
= (double *)gmallocn(size
, sizeof(double));
3326 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
3334 GfxSubpath::~GfxSubpath() {
3341 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
3342 size
= subpath
->size
;
3344 x
= (double *)gmallocn(size
, sizeof(double));
3345 y
= (double *)gmallocn(size
, sizeof(double));
3346 curve
= (GBool
*)gmallocn(size
, sizeof(GBool
));
3347 memcpy(x
, subpath
->x
, n
* sizeof(double));
3348 memcpy(y
, subpath
->y
, n
* sizeof(double));
3349 memcpy(curve
, subpath
->curve
, n
* sizeof(GBool
));
3350 closed
= subpath
->closed
;
3353 void GfxSubpath::lineTo(double x1
, double y1
) {
3356 x
= (double *)greallocn(x
, size
, sizeof(double));
3357 y
= (double *)greallocn(y
, size
, sizeof(double));
3358 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
3366 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
3367 double x3
, double y3
) {
3370 x
= (double *)greallocn(x
, size
, sizeof(double));
3371 y
= (double *)greallocn(y
, size
, sizeof(double));
3372 curve
= (GBool
*)greallocn(curve
, size
, sizeof(GBool
));
3380 curve
[n
] = curve
[n
+1] = gTrue
;
3381 curve
[n
+2] = gFalse
;
3385 void GfxSubpath::close() {
3386 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
3392 void GfxSubpath::offset(double dx
, double dy
) {
3395 for (i
= 0; i
< n
; ++i
) {
3401 GfxPath::GfxPath() {
3405 firstX
= firstY
= 0;
3406 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
3409 GfxPath::~GfxPath() {
3412 for (i
= 0; i
< n
; ++i
)
3418 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
3419 GfxSubpath
**subpaths1
, int n1
, int size1
) {
3422 justMoved
= justMoved1
;
3427 subpaths
= (GfxSubpath
**)gmallocn(size
, sizeof(GfxSubpath
*));
3428 for (i
= 0; i
< n
; ++i
)
3429 subpaths
[i
] = subpaths1
[i
]->copy();
3432 void GfxPath::moveTo(double x
, double y
) {
3438 void GfxPath::lineTo(double x
, double y
) {
3442 subpaths
= (GfxSubpath
**)
3443 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3445 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3449 subpaths
[n
-1]->lineTo(x
, y
);
3452 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
3453 double x3
, double y3
) {
3457 subpaths
= (GfxSubpath
**)
3458 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3460 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3464 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
3467 void GfxPath::close() {
3468 // this is necessary to handle the pathological case of
3469 // moveto/closepath/clip, which defines an empty clipping region
3473 subpaths
= (GfxSubpath
**)
3474 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3476 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
3480 subpaths
[n
-1]->close();
3483 void GfxPath::append(GfxPath
*path
) {
3486 if (n
+ path
->n
> size
) {
3488 subpaths
= (GfxSubpath
**)
3489 greallocn(subpaths
, size
, sizeof(GfxSubpath
*));
3491 for (i
= 0; i
< path
->n
; ++i
) {
3492 subpaths
[n
++] = path
->subpaths
[i
]->copy();
3497 void GfxPath::offset(double dx
, double dy
) {
3500 for (i
= 0; i
< n
; ++i
) {
3501 subpaths
[i
]->offset(dx
, dy
);
3505 //------------------------------------------------------------------------
3507 //------------------------------------------------------------------------
3509 GfxState::GfxState(double hDPI
, double vDPI
, PDFRectangle
*pageBox
,
3510 int rotateA
, GBool upsideDown
) {
3522 ctm
[1] = upsideDown
? ky
: -ky
;
3526 ctm
[5] = ky
* (upsideDown
? -px1
: px2
);
3527 pageWidth
= kx
* (py2
- py1
);
3528 pageHeight
= ky
* (px2
- px1
);
3529 } else if (rotate
== 180) {
3533 ctm
[3] = upsideDown
? ky
: -ky
;
3535 ctm
[5] = ky
* (upsideDown
? -py1
: py2
);
3536 pageWidth
= kx
* (px2
- px1
);
3537 pageHeight
= ky
* (py2
- py1
);
3538 } else if (rotate
== 270) {
3540 ctm
[1] = upsideDown
? -ky
: ky
;
3544 ctm
[5] = ky
* (upsideDown
? px2
: -px1
);
3545 pageWidth
= kx
* (py2
- py1
);
3546 pageHeight
= ky
* (px2
- px1
);
3551 ctm
[3] = upsideDown
? -ky
: ky
;
3553 ctm
[5] = ky
* (upsideDown
? py2
: -py1
);
3554 pageWidth
= kx
* (px2
- px1
);
3555 pageHeight
= ky
* (py2
- py1
);
3558 fillColorSpace
= new GfxDeviceGrayColorSpace();
3559 strokeColorSpace
= new GfxDeviceGrayColorSpace();
3561 strokeColor
.c
[0] = 0;
3563 strokePattern
= NULL
;
3564 blendMode
= gfxBlendNormal
;
3567 fillOverprint
= gFalse
;
3568 strokeOverprint
= gFalse
;
3581 textMat
[0] = 1; textMat
[1] = 0;
3582 textMat
[2] = 0; textMat
[3] = 1;
3583 textMat
[4] = 0; textMat
[5] = 0;
3591 path
= new GfxPath();
3597 clipXMax
= pageWidth
;
3598 clipYMax
= pageHeight
;
3603 GfxState::~GfxState() {
3604 if (fillColorSpace
) {
3605 delete fillColorSpace
;
3607 if (strokeColorSpace
) {
3608 delete strokeColorSpace
;
3613 if (strokePattern
) {
3614 delete strokePattern
;
3618 // this gets set to NULL by restore()
3627 GfxState::GfxState(GfxState
*state
) {
3628 memcpy(this, state
, sizeof(GfxState
));
3629 if (fillColorSpace
) {
3630 fillColorSpace
= state
->fillColorSpace
->copy();
3632 if (strokeColorSpace
) {
3633 strokeColorSpace
= state
->strokeColorSpace
->copy();
3636 fillPattern
= state
->fillPattern
->copy();
3638 if (strokePattern
) {
3639 strokePattern
= state
->strokePattern
->copy();
3641 if (lineDashLength
> 0) {
3642 lineDash
= (double *)gmallocn(lineDashLength
, sizeof(double));
3643 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
3648 void GfxState::setPath(GfxPath
*pathA
) {
3653 void GfxState::getUserClipBBox(double *xMin
, double *yMin
,
3654 double *xMax
, double *yMax
) {
3656 double xMin1
, yMin1
, xMax1
, yMax1
, det
, tx
, ty
;
3659 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
3660 ictm
[0] = ctm
[3] * det
;
3661 ictm
[1] = -ctm
[1] * det
;
3662 ictm
[2] = -ctm
[2] * det
;
3663 ictm
[3] = ctm
[0] * det
;
3664 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
3665 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
3667 // transform all four corners of the clip bbox; find the min and max
3669 xMin1
= xMax1
= clipXMin
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
3670 yMin1
= yMax1
= clipXMin
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
3671 tx
= clipXMin
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
3672 ty
= clipXMin
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
3675 } else if (tx
> xMax1
) {
3680 } else if (ty
> yMax1
) {
3683 tx
= clipXMax
* ictm
[0] + clipYMin
* ictm
[2] + ictm
[4];
3684 ty
= clipXMax
* ictm
[1] + clipYMin
* ictm
[3] + ictm
[5];
3687 } else if (tx
> xMax1
) {
3692 } else if (ty
> yMax1
) {
3695 tx
= clipXMax
* ictm
[0] + clipYMax
* ictm
[2] + ictm
[4];
3696 ty
= clipXMax
* ictm
[1] + clipYMax
* ictm
[3] + ictm
[5];
3699 } else if (tx
> xMax1
) {
3704 } else if (ty
> yMax1
) {
3714 double GfxState::transformWidth(double w
) {
3717 x
= ctm
[0] + ctm
[2];
3718 y
= ctm
[1] + ctm
[3];
3719 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
3722 double GfxState::getTransformedFontSize() {
3723 double x1
, y1
, x2
, y2
;
3725 x1
= textMat
[2] * fontSize
;
3726 y1
= textMat
[3] * fontSize
;
3727 x2
= ctm
[0] * x1
+ ctm
[2] * y1
;
3728 y2
= ctm
[1] * x1
+ ctm
[3] * y1
;
3729 return sqrt(x2
* x2
+ y2
* y2
);
3732 void GfxState::getFontTransMat(double *m11
, double *m12
,
3733 double *m21
, double *m22
) {
3734 *m11
= (textMat
[0] * ctm
[0] + textMat
[1] * ctm
[2]) * fontSize
;
3735 *m12
= (textMat
[0] * ctm
[1] + textMat
[1] * ctm
[3]) * fontSize
;
3736 *m21
= (textMat
[2] * ctm
[0] + textMat
[3] * ctm
[2]) * fontSize
;
3737 *m22
= (textMat
[2] * ctm
[1] + textMat
[3] * ctm
[3]) * fontSize
;
3740 void GfxState::setCTM(double a
, double b
, double c
,
3741 double d
, double e
, double f
) {
3751 // avoid FP exceptions on badly messed up PDF files
3752 for (i
= 0; i
< 6; ++i
) {
3753 if (ctm
[i
] > 1e10
) {
3755 } else if (ctm
[i
] < -1e10
) {
3761 void GfxState::concatCTM(double a
, double b
, double c
,
3762 double d
, double e
, double f
) {
3769 ctm
[0] = a
* a1
+ b
* c1
;
3770 ctm
[1] = a
* b1
+ b
* d1
;
3771 ctm
[2] = c
* a1
+ d
* c1
;
3772 ctm
[3] = c
* b1
+ d
* d1
;
3773 ctm
[4] = e
* a1
+ f
* c1
+ ctm
[4];
3774 ctm
[5] = e
* b1
+ f
* d1
+ ctm
[5];
3776 // avoid FP exceptions on badly messed up PDF files
3777 for (i
= 0; i
< 6; ++i
) {
3778 if (ctm
[i
] > 1e10
) {
3780 } else if (ctm
[i
] < -1e10
) {
3786 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
3787 if (fillColorSpace
) {
3788 delete fillColorSpace
;
3790 fillColorSpace
= colorSpace
;
3793 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
3794 if (strokeColorSpace
) {
3795 delete strokeColorSpace
;
3797 strokeColorSpace
= colorSpace
;
3800 void GfxState::setFillPattern(GfxPattern
*pattern
) {
3804 fillPattern
= pattern
;
3807 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
3808 if (strokePattern
) {
3809 delete strokePattern
;
3811 strokePattern
= pattern
;
3814 void GfxState::setLineDash(double *dash
, int length
, double start
) {
3818 lineDashLength
= length
;
3819 lineDashStart
= start
;
3822 void GfxState::clearPath() {
3824 path
= new GfxPath();
3827 void GfxState::clip() {
3828 double xMin
, yMin
, xMax
, yMax
, x
, y
;
3829 GfxSubpath
*subpath
;
3832 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
3833 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
3834 subpath
= path
->getSubpath(i
);
3835 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
3836 transform(subpath
->getX(j
), subpath
->getY(j
), &x
, &y
);
3837 if (i
== 0 && j
== 0) {
3843 } else if (x
> xMax
) {
3848 } else if (y
> yMax
) {
3854 if (xMin
> clipXMin
) {
3857 if (yMin
> clipYMin
) {
3860 if (xMax
< clipXMax
) {
3863 if (yMax
< clipYMax
) {
3868 void GfxState::textShift(double tx
, double ty
) {
3871 textTransformDelta(tx
, ty
, &dx
, &dy
);
3876 void GfxState::shift(double dx
, double dy
) {
3881 GfxState
*GfxState::save() {
3885 newState
->saved
= this;
3889 GfxState
*GfxState::restore() {
3895 // these attributes aren't saved/restored by the q/Q operators
3896 oldState
->path
= path
;
3897 oldState
->curX
= curX
;
3898 oldState
->curY
= curY
;
3899 oldState
->lineX
= lineX
;
3900 oldState
->lineY
= lineY
;
3913 GBool
GfxState::parseBlendMode(Object
*obj
, GfxBlendMode
*mode
) {
3917 if (obj
->isName()) {
3918 for (i
= 0; i
< nGfxBlendModeNames
; ++i
) {
3919 if (!strcmp(obj
->getName(), gfxBlendModeNames
[i
].name
)) {
3920 *mode
= gfxBlendModeNames
[i
].mode
;
3925 } else if (obj
->isArray()) {
3926 for (i
= 0; i
< obj
->arrayGetLength(); ++i
) {
3927 obj
->arrayGet(i
, &obj2
);
3928 if (!obj2
.isName()) {
3932 for (j
= 0; j
< nGfxBlendModeNames
; ++j
) {
3933 if (!strcmp(obj2
.getName(), gfxBlendModeNames
[j
].name
)) {
3935 *mode
= gfxBlendModeNames
[j
].mode
;
3941 *mode
= gfxBlendNormal
;