1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
26 //------------------------------------------------------------------------
28 static inline GfxColorComp clip01(GfxColorComp x) {
29 return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
32 static inline double clip01(double x) {
33 return (x < 0) ? 0 : (x > 1) ? 1 : x;
36 //------------------------------------------------------------------------
41 } gfxBlendModeNames[] = {
42 { "Normal", gfxBlendNormal },
43 { "Compatible", gfxBlendNormal },
44 { "Multiply", gfxBlendMultiply },
45 { "Screen", gfxBlendScreen },
46 { "Overlay", gfxBlendOverlay },
47 { "Darken", gfxBlendDarken },
48 { "Lighten", gfxBlendLighten },
49 { "ColorDodge", gfxBlendColorDodge },
50 { "ColorBurn", gfxBlendColorBurn },
51 { "HardLight", gfxBlendHardLight },
52 { "SoftLight", gfxBlendSoftLight },
53 { "Difference", gfxBlendDifference },
54 { "Exclusion", gfxBlendExclusion },
55 { "Hue", gfxBlendHue },
56 { "Saturation", gfxBlendSaturation },
57 { "Color", gfxBlendColor },
58 { "Luminosity", gfxBlendLuminosity }
61 #define nGfxBlendModeNames \
62 ((int)((sizeof(gfxBlendModeNames) / sizeof(char *))))
64 //------------------------------------------------------------------------
66 // NB: This must match the GfxColorSpaceMode enum defined in
68 static char *gfxColorSpaceModeNames[] = {
82 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
84 //------------------------------------------------------------------------
86 //------------------------------------------------------------------------
88 GfxColorSpace::GfxColorSpace() {
91 GfxColorSpace::~GfxColorSpace() {
94 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
99 if (csObj->isName()) {
100 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
101 cs = new GfxDeviceGrayColorSpace();
102 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
103 cs = new GfxDeviceRGBColorSpace();
104 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
105 cs = new GfxDeviceCMYKColorSpace();
106 } else if (csObj->isName("Pattern")) {
107 cs = new GfxPatternColorSpace(NULL);
109 error(-1, "Bad color space '%s'", csObj->getName());
111 } else if (csObj->isArray()) {
112 csObj->arrayGet(0, &obj1);
113 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
114 cs = new GfxDeviceGrayColorSpace();
115 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
116 cs = new GfxDeviceRGBColorSpace();
117 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
118 cs = new GfxDeviceCMYKColorSpace();
119 } else if (obj1.isName("CalGray")) {
120 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
121 } else if (obj1.isName("CalRGB")) {
122 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
123 } else if (obj1.isName("Lab")) {
124 cs = GfxLabColorSpace::parse(csObj->getArray());
125 } else if (obj1.isName("ICCBased")) {
126 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
127 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
128 cs = GfxIndexedColorSpace::parse(csObj->getArray());
129 } else if (obj1.isName("Separation")) {
130 cs = GfxSeparationColorSpace::parse(csObj->getArray());
131 } else if (obj1.isName("DeviceN")) {
132 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
133 } else if (obj1.isName("Pattern")) {
134 cs = GfxPatternColorSpace::parse(csObj->getArray());
136 error(-1, "Bad color space");
140 error(-1, "Bad color space - expected name or array");
145 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
149 for (i = 0; i < getNComps(); ++i) {
155 int GfxColorSpace::getNumColorSpaceModes() {
156 return nGfxColorSpaceModes;
159 char *GfxColorSpace::getColorSpaceModeName(int idx) {
160 return gfxColorSpaceModeNames[idx];
163 //------------------------------------------------------------------------
164 // GfxDeviceGrayColorSpace
165 //------------------------------------------------------------------------
167 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
170 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
173 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
174 return new GfxDeviceGrayColorSpace();
177 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
178 *gray = clip01(color->c[0]);
181 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
182 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
185 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
186 cmyk->c = cmyk->m = cmyk->y = 0;
187 cmyk->k = clip01(gfxColorComp1 - color->c[0]);
190 //------------------------------------------------------------------------
191 // GfxCalGrayColorSpace
192 //------------------------------------------------------------------------
194 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
195 whiteX = whiteY = whiteZ = 1;
196 blackX = blackY = blackZ = 0;
200 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
203 GfxColorSpace *GfxCalGrayColorSpace::copy() {
204 GfxCalGrayColorSpace *cs;
206 cs = new GfxCalGrayColorSpace();
217 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
218 GfxCalGrayColorSpace *cs;
219 Object obj1, obj2, obj3;
222 if (!obj1.isDict()) {
223 error(-1, "Bad CalGray color space");
227 cs = new GfxCalGrayColorSpace();
228 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
229 obj2.arrayGetLength() == 3) {
230 obj2.arrayGet(0, &obj3);
231 cs->whiteX = obj3.getNum();
233 obj2.arrayGet(1, &obj3);
234 cs->whiteY = obj3.getNum();
236 obj2.arrayGet(2, &obj3);
237 cs->whiteZ = obj3.getNum();
241 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
242 obj2.arrayGetLength() == 3) {
243 obj2.arrayGet(0, &obj3);
244 cs->blackX = obj3.getNum();
246 obj2.arrayGet(1, &obj3);
247 cs->blackY = obj3.getNum();
249 obj2.arrayGet(2, &obj3);
250 cs->blackZ = obj3.getNum();
254 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
255 cs->gamma = obj2.getNum();
262 void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
263 *gray = clip01(color->c[0]);
266 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
267 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
270 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
271 cmyk->c = cmyk->m = cmyk->y = 0;
272 cmyk->k = clip01(gfxColorComp1 - color->c[0]);
275 //------------------------------------------------------------------------
276 // GfxDeviceRGBColorSpace
277 //------------------------------------------------------------------------
279 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
282 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
285 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
286 return new GfxDeviceRGBColorSpace();
289 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
290 *gray = clip01((GfxColorComp)(0.3 * color->c[0] +
292 0.11 * color->c[2] + 0.5));
295 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
296 rgb->r = clip01(color->c[0]);
297 rgb->g = clip01(color->c[1]);
298 rgb->b = clip01(color->c[2]);
301 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
302 GfxColorComp c, m, y, k;
304 c = clip01(gfxColorComp1 - color->c[0]);
305 m = clip01(gfxColorComp1 - color->c[1]);
306 y = clip01(gfxColorComp1 - color->c[2]);
320 //------------------------------------------------------------------------
321 // GfxCalRGBColorSpace
322 //------------------------------------------------------------------------
324 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
325 whiteX = whiteY = whiteZ = 1;
326 blackX = blackY = blackZ = 0;
327 gammaR = gammaG = gammaB = 1;
328 mat[0] = 1; mat[1] = 0; mat[2] = 0;
329 mat[3] = 0; mat[4] = 1; mat[5] = 0;
330 mat[6] = 0; mat[7] = 0; mat[8] = 1;
333 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
336 GfxColorSpace *GfxCalRGBColorSpace::copy() {
337 GfxCalRGBColorSpace *cs;
340 cs = new GfxCalRGBColorSpace();
350 for (i = 0; i < 9; ++i) {
356 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
357 GfxCalRGBColorSpace *cs;
358 Object obj1, obj2, obj3;
362 if (!obj1.isDict()) {
363 error(-1, "Bad CalRGB color space");
367 cs = new GfxCalRGBColorSpace();
368 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
369 obj2.arrayGetLength() == 3) {
370 obj2.arrayGet(0, &obj3);
371 cs->whiteX = obj3.getNum();
373 obj2.arrayGet(1, &obj3);
374 cs->whiteY = obj3.getNum();
376 obj2.arrayGet(2, &obj3);
377 cs->whiteZ = obj3.getNum();
381 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
382 obj2.arrayGetLength() == 3) {
383 obj2.arrayGet(0, &obj3);
384 cs->blackX = obj3.getNum();
386 obj2.arrayGet(1, &obj3);
387 cs->blackY = obj3.getNum();
389 obj2.arrayGet(2, &obj3);
390 cs->blackZ = obj3.getNum();
394 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
395 obj2.arrayGetLength() == 3) {
396 obj2.arrayGet(0, &obj3);
397 cs->gammaR = obj3.getNum();
399 obj2.arrayGet(1, &obj3);
400 cs->gammaG = obj3.getNum();
402 obj2.arrayGet(2, &obj3);
403 cs->gammaB = obj3.getNum();
407 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
408 obj2.arrayGetLength() == 9) {
409 for (i = 0; i < 9; ++i) {
410 obj2.arrayGet(i, &obj3);
411 cs->mat[i] = obj3.getNum();
420 void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
421 *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
422 0.587 * color->c[1] +
423 0.114 * color->c[2] + 0.5));
426 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
427 rgb->r = clip01(color->c[0]);
428 rgb->g = clip01(color->c[1]);
429 rgb->b = clip01(color->c[2]);
432 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
433 GfxColorComp c, m, y, k;
435 c = clip01(gfxColorComp1 - color->c[0]);
436 m = clip01(gfxColorComp1 - color->c[1]);
437 y = clip01(gfxColorComp1 - color->c[2]);
451 //------------------------------------------------------------------------
452 // GfxDeviceCMYKColorSpace
453 //------------------------------------------------------------------------
455 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
458 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
461 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
462 return new GfxDeviceCMYKColorSpace();
465 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
466 *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
469 - 0.11 * color->c[2] + 0.5));
472 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
474 float c = color->c[0];
475 float m = color->c[1];
476 float y = color->c[2];
477 float k = color->c[3];
478 convert_cmyk2rgb(c,m,y,k, &r,&g,&b);
484 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
485 double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
487 c = colToDbl(color->c[0]);
488 m = colToDbl(color->c[1]);
489 y = colToDbl(color->c[2]);
490 k = colToDbl(color->c[3]);
495 // this is a matrix multiplication, unrolled for performance
497 x = c1 * m1 * y1 * k1; // 0 0 0 0
499 x = c1 * m1 * y1 * k; // 0 0 0 1
503 x = c1 * m1 * y * k1; // 0 0 1 0
506 x = c1 * m1 * y * k; // 0 0 1 1
509 x = c1 * m * y1 * k1; // 0 1 0 0
512 x = c1 * m * y1 * k; // 0 1 0 1
514 x = c1 * m * y * k1; // 0 1 1 0
518 x = c1 * m * y * k; // 0 1 1 1
520 x = c * m1 * y1 * k1; // 1 0 0 0
523 x = c * m1 * y1 * k; // 1 0 0 1
526 x = c * m1 * y * k1; // 1 0 1 0
529 x = c * m1 * y * k; // 1 0 1 1
531 x = c * m * y1 * k1; // 1 1 0 0
535 x = c * m * y1 * k; // 1 1 0 1
537 x = c * m * y * k1; // 1 1 1 0
541 rgb->r = clip01(dblToCol(r));
542 rgb->g = clip01(dblToCol(g));
543 rgb->b = clip01(dblToCol(b));
546 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
547 cmyk->c = clip01(color->c[0]);
548 cmyk->m = clip01(color->c[1]);
549 cmyk->y = clip01(color->c[2]);
550 cmyk->k = clip01(color->c[3]);
553 //------------------------------------------------------------------------
555 //------------------------------------------------------------------------
557 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
558 // Language Reference, Third Edition.
559 static double xyzrgb[3][3] = {
560 { 3.240449, -1.537136, -0.498531 },
561 { -0.969265, 1.876011, 0.041556 },
562 { 0.055643, -0.204026, 1.057229 }
565 GfxLabColorSpace::GfxLabColorSpace() {
566 whiteX = whiteY = whiteZ = 1;
567 blackX = blackY = blackZ = 0;
572 GfxLabColorSpace::~GfxLabColorSpace() {
575 GfxColorSpace *GfxLabColorSpace::copy() {
576 GfxLabColorSpace *cs;
578 cs = new GfxLabColorSpace();
595 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
596 GfxLabColorSpace *cs;
597 Object obj1, obj2, obj3;
600 if (!obj1.isDict()) {
601 error(-1, "Bad Lab color space");
605 cs = new GfxLabColorSpace();
606 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
607 obj2.arrayGetLength() == 3) {
608 obj2.arrayGet(0, &obj3);
609 cs->whiteX = obj3.getNum();
611 obj2.arrayGet(1, &obj3);
612 cs->whiteY = obj3.getNum();
614 obj2.arrayGet(2, &obj3);
615 cs->whiteZ = obj3.getNum();
619 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
620 obj2.arrayGetLength() == 3) {
621 obj2.arrayGet(0, &obj3);
622 cs->blackX = obj3.getNum();
624 obj2.arrayGet(1, &obj3);
625 cs->blackY = obj3.getNum();
627 obj2.arrayGet(2, &obj3);
628 cs->blackZ = obj3.getNum();
632 if (obj1.dictLookup("Range", &obj2)->isArray() &&
633 obj2.arrayGetLength() == 4) {
634 obj2.arrayGet(0, &obj3);
635 cs->aMin = obj3.getNum();
637 obj2.arrayGet(1, &obj3);
638 cs->aMax = obj3.getNum();
640 obj2.arrayGet(2, &obj3);
641 cs->bMin = obj3.getNum();
643 obj2.arrayGet(3, &obj3);
644 cs->bMax = obj3.getNum();
650 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
651 xyzrgb[0][1] * cs->whiteY +
652 xyzrgb[0][2] * cs->whiteZ);
653 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
654 xyzrgb[1][1] * cs->whiteY +
655 xyzrgb[1][2] * cs->whiteZ);
656 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
657 xyzrgb[2][1] * cs->whiteY +
658 xyzrgb[2][2] * cs->whiteZ);
663 void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
667 *gray = clip01((GfxColorComp)(0.299 * rgb.r +
669 0.114 * rgb.b + 0.5));
672 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
677 // convert L*a*b* to CIE 1931 XYZ color space
678 t1 = (colToDbl(color->c[0]) + 16) / 116;
679 t2 = t1 + colToDbl(color->c[1]) / 500;
680 if (t2 >= (6.0 / 29.0)) {
683 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
686 if (t1 >= (6.0 / 29.0)) {
689 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
692 t2 = t1 - colToDbl(color->c[2]) / 200;
693 if (t2 >= (6.0 / 29.0)) {
696 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
700 // convert XYZ to RGB, including gamut mapping and gamma correction
701 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
702 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
703 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
704 rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
705 rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
706 rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
709 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
711 GfxColorComp c, m, y, k;
714 c = clip01(gfxColorComp1 - rgb.r);
715 m = clip01(gfxColorComp1 - rgb.g);
716 y = clip01(gfxColorComp1 - rgb.b);
730 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
733 decodeRange[0] = 100;
735 decodeRange[1] = aMax - aMin;
737 decodeRange[2] = bMax - bMin;
740 //------------------------------------------------------------------------
741 // GfxICCBasedColorSpace
742 //------------------------------------------------------------------------
744 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
745 Ref *iccProfileStreamA) {
748 iccProfileStream = *iccProfileStreamA;
749 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
750 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
753 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
757 GfxColorSpace *GfxICCBasedColorSpace::copy() {
758 GfxICCBasedColorSpace *cs;
761 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
762 for (i = 0; i < 4; ++i) {
763 cs->rangeMin[i] = rangeMin[i];
764 cs->rangeMax[i] = rangeMax[i];
769 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
770 GfxICCBasedColorSpace *cs;
771 Ref iccProfileStreamA;
775 Object obj1, obj2, obj3;
778 arr->getNF(1, &obj1);
780 iccProfileStreamA = obj1.getRef();
782 iccProfileStreamA.num = 0;
783 iccProfileStreamA.gen = 0;
787 if (!obj1.isStream()) {
788 error(-1, "Bad ICCBased color space (stream)");
792 dict = obj1.streamGetDict();
793 if (!dict->lookup("N", &obj2)->isInt()) {
794 error(-1, "Bad ICCBased color space (N)");
799 nCompsA = obj2.getInt();
801 if (nCompsA > gfxColorMaxComps) {
802 error(-1, "ICCBased color space with too many (%d > %d) components",
803 nCompsA, gfxColorMaxComps);
804 nCompsA = gfxColorMaxComps;
806 if (dict->lookup("Alternate", &obj2)->isNull() ||
807 !(altA = GfxColorSpace::parse(&obj2))) {
810 altA = new GfxDeviceGrayColorSpace();
813 altA = new GfxDeviceRGBColorSpace();
816 altA = new GfxDeviceCMYKColorSpace();
819 error(-1, "Bad ICCBased color space - invalid N");
826 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
827 if (dict->lookup("Range", &obj2)->isArray() &&
828 obj2.arrayGetLength() == 2 * nCompsA) {
829 for (i = 0; i < nCompsA; ++i) {
830 obj2.arrayGet(2*i, &obj3);
831 cs->rangeMin[i] = obj3.getNum();
833 obj2.arrayGet(2*i+1, &obj3);
834 cs->rangeMax[i] = obj3.getNum();
843 void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
844 alt->getGray(color, gray);
847 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
848 alt->getRGB(color, rgb);
851 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
852 alt->getCMYK(color, cmyk);
855 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
858 alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
861 // this is nominally correct, but some PDF files don't set the
862 // correct ranges in the ICCBased dict
865 for (i = 0; i < nComps; ++i) {
866 decodeLow[i] = rangeMin[i];
867 decodeRange[i] = rangeMax[i] - rangeMin[i];
872 //------------------------------------------------------------------------
873 // GfxIndexedColorSpace
874 //------------------------------------------------------------------------
876 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
879 indexHigh = indexHighA;
880 lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
884 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
889 GfxColorSpace *GfxIndexedColorSpace::copy() {
890 GfxIndexedColorSpace *cs;
892 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
893 memcpy(cs->lookup, lookup,
894 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
898 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
899 GfxIndexedColorSpace *cs;
900 GfxColorSpace *baseA;
907 if (arr->getLength() != 4) {
908 error(-1, "Bad Indexed color space");
912 if (!(baseA = GfxColorSpace::parse(&obj1))) {
913 error(-1, "Bad Indexed color space (base color space)");
917 if (!arr->get(2, &obj1)->isInt()) {
918 error(-1, "Bad Indexed color space (hival)");
922 indexHighA = obj1.getInt();
923 if (indexHighA < 0 || indexHighA > 255) {
924 // the PDF spec requires indexHigh to be in [0,255] -- allowing
925 // values larger than 255 creates a security hole: if nComps *
926 // indexHigh is greater than 2^31, the loop below may overwrite
927 // past the end of the array
928 error(-1, "Bad Indexed color space (invalid indexHigh value)");
933 cs = new GfxIndexedColorSpace(baseA, indexHighA);
935 n = baseA->getNComps();
936 if (obj1.isStream()) {
938 for (i = 0; i <= indexHighA; ++i) {
939 for (j = 0; j < n; ++j) {
940 if ((x = obj1.streamGetChar()) == EOF) {
941 error(-1, "Bad Indexed color space (lookup table stream too short)");
944 cs->lookup[i*n + j] = (Guchar)x;
948 } else if (obj1.isString()) {
949 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
950 error(-1, "Bad Indexed color space (lookup table string too short)");
953 s = obj1.getString()->getCString();
954 for (i = 0; i <= indexHighA; ++i) {
955 for (j = 0; j < n; ++j) {
956 cs->lookup[i*n + j] = (Guchar)*s++;
960 error(-1, "Bad Indexed color space (lookup table)");
974 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
975 GfxColor *baseColor) {
977 double low[gfxColorMaxComps], range[gfxColorMaxComps];
980 n = base->getNComps();
981 base->getDefaultRanges(low, range, indexHigh);
982 p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n];
983 for (i = 0; i < n; ++i) {
984 baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
989 void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
992 base->getGray(mapColorToBase(color, &color2), gray);
995 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
998 base->getRGB(mapColorToBase(color, &color2), rgb);
1001 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1004 base->getCMYK(mapColorToBase(color, &color2), cmyk);
1007 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
1008 double *decodeRange,
1011 decodeRange[0] = maxImgPixel;
1014 //------------------------------------------------------------------------
1015 // GfxSeparationColorSpace
1016 //------------------------------------------------------------------------
1018 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1019 GfxColorSpace *altA,
1026 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1032 GfxColorSpace *GfxSeparationColorSpace::copy() {
1033 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
1036 //~ handle the 'All' and 'None' colorants
1037 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
1038 GfxSeparationColorSpace *cs;
1040 GfxColorSpace *altA;
1044 if (arr->getLength() != 4) {
1045 error(-1, "Bad Separation color space");
1048 if (!arr->get(1, &obj1)->isName()) {
1049 error(-1, "Bad Separation color space (name)");
1052 nameA = new GString(obj1.getName());
1055 if (!(altA = GfxColorSpace::parse(&obj1))) {
1056 error(-1, "Bad Separation color space (alternate color space)");
1061 if (!(funcA = Function::parse(&obj1))) {
1065 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1078 void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1080 double c[gfxColorMaxComps];
1084 x = colToDbl(color->c[0]);
1085 func->transform(&x, c);
1086 for (i = 0; i < alt->getNComps(); ++i) {
1087 color2.c[i] = dblToCol(c[i]);
1089 alt->getGray(&color2, gray);
1092 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1094 double c[gfxColorMaxComps];
1098 x = colToDbl(color->c[0]);
1099 func->transform(&x, c);
1100 for (i = 0; i < alt->getNComps(); ++i) {
1101 color2.c[i] = dblToCol(c[i]);
1103 alt->getRGB(&color2, rgb);
1106 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1108 double c[gfxColorMaxComps];
1112 x = colToDbl(color->c[0]);
1113 func->transform(&x, c);
1114 for (i = 0; i < alt->getNComps(); ++i) {
1115 color2.c[i] = dblToCol(c[i]);
1117 alt->getCMYK(&color2, cmyk);
1120 //------------------------------------------------------------------------
1121 // GfxDeviceNColorSpace
1122 //------------------------------------------------------------------------
1124 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1125 GfxColorSpace *altA,
1132 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1135 for (i = 0; i < nComps; ++i) {
1142 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1143 GfxDeviceNColorSpace *cs;
1146 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1147 for (i = 0; i < nComps; ++i) {
1148 cs->names[i] = names[i]->copy();
1153 //~ handle the 'None' colorant
1154 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1155 GfxDeviceNColorSpace *cs;
1157 GString *namesA[gfxColorMaxComps];
1158 GfxColorSpace *altA;
1163 if (arr->getLength() != 4 && arr->getLength() != 5) {
1164 error(-1, "Bad DeviceN color space");
1167 if (!arr->get(1, &obj1)->isArray()) {
1168 error(-1, "Bad DeviceN color space (names)");
1171 nCompsA = obj1.arrayGetLength();
1172 if (nCompsA > gfxColorMaxComps) {
1173 error(-1, "DeviceN color space with too many (%d > %d) components",
1174 nCompsA, gfxColorMaxComps);
1175 nCompsA = gfxColorMaxComps;
1177 for (i = 0; i < nCompsA; ++i) {
1178 if (!obj1.arrayGet(i, &obj2)->isName()) {
1179 error(-1, "Bad DeviceN color space (names)");
1183 namesA[i] = new GString(obj2.getName());
1188 if (!(altA = GfxColorSpace::parse(&obj1))) {
1189 error(-1, "Bad DeviceN color space (alternate color space)");
1194 if (!(funcA = Function::parse(&obj1))) {
1198 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1199 for (i = 0; i < nCompsA; ++i) {
1200 cs->names[i] = namesA[i];
1207 for (i = 0; i < nCompsA; ++i) {
1216 void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1217 double x[gfxColorMaxComps], c[gfxColorMaxComps];
1221 for (i = 0; i < nComps; ++i) {
1222 x[i] = colToDbl(color->c[i]);
1224 func->transform(x, c);
1225 for (i = 0; i < alt->getNComps(); ++i) {
1226 color2.c[i] = dblToCol(c[i]);
1228 alt->getGray(&color2, gray);
1231 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1232 double x[gfxColorMaxComps], c[gfxColorMaxComps];
1236 for (i = 0; i < nComps; ++i) {
1237 x[i] = colToDbl(color->c[i]);
1239 func->transform(x, c);
1240 for (i = 0; i < alt->getNComps(); ++i) {
1241 color2.c[i] = dblToCol(c[i]);
1243 alt->getRGB(&color2, rgb);
1246 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1247 double x[gfxColorMaxComps], c[gfxColorMaxComps];
1251 for (i = 0; i < nComps; ++i) {
1252 x[i] = colToDbl(color->c[i]);
1254 func->transform(x, c);
1255 for (i = 0; i < alt->getNComps(); ++i) {
1256 color2.c[i] = dblToCol(c[i]);
1258 alt->getCMYK(&color2, cmyk);
1261 //------------------------------------------------------------------------
1262 // GfxPatternColorSpace
1263 //------------------------------------------------------------------------
1265 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1269 GfxPatternColorSpace::~GfxPatternColorSpace() {
1275 GfxColorSpace *GfxPatternColorSpace::copy() {
1276 return new GfxPatternColorSpace(under ? under->copy() :
1277 (GfxColorSpace *)NULL);
1280 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1281 GfxPatternColorSpace *cs;
1282 GfxColorSpace *underA;
1285 if (arr->getLength() != 1 && arr->getLength() != 2) {
1286 error(-1, "Bad Pattern color space");
1290 if (arr->getLength() == 2) {
1292 if (!(underA = GfxColorSpace::parse(&obj1))) {
1293 error(-1, "Bad Pattern color space (underlying color space)");
1299 cs = new GfxPatternColorSpace(underA);
1303 void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) {
1307 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1308 rgb->r = rgb->g = rgb->b = 0;
1311 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1312 cmyk->c = cmyk->m = cmyk->y = 0;
1316 //------------------------------------------------------------------------
1318 //------------------------------------------------------------------------
1320 GfxPattern::GfxPattern(int typeA) {
1324 GfxPattern::~GfxPattern() {
1327 GfxPattern *GfxPattern::parse(Object *obj) {
1328 GfxPattern *pattern;
1331 if (obj->isDict()) {
1332 obj->dictLookup("PatternType", &obj1);
1333 } else if (obj->isStream()) {
1334 obj->streamGetDict()->lookup("PatternType", &obj1);
1339 if (obj1.isInt() && obj1.getInt() == 1) {
1340 pattern = GfxTilingPattern::parse(obj);
1341 } else if (obj1.isInt() && obj1.getInt() == 2) {
1342 pattern = GfxShadingPattern::parse(obj);
1348 //------------------------------------------------------------------------
1350 //------------------------------------------------------------------------
1352 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1353 GfxTilingPattern *pat;
1355 int paintTypeA, tilingTypeA;
1356 double bboxA[4], matrixA[6];
1357 double xStepA, yStepA;
1362 if (!patObj->isStream()) {
1365 dict = patObj->streamGetDict();
1367 if (dict->lookup("PaintType", &obj1)->isInt()) {
1368 paintTypeA = obj1.getInt();
1371 error(-1, "Invalid or missing PaintType in pattern");
1374 if (dict->lookup("TilingType", &obj1)->isInt()) {
1375 tilingTypeA = obj1.getInt();
1378 error(-1, "Invalid or missing TilingType in pattern");
1381 bboxA[0] = bboxA[1] = 0;
1382 bboxA[2] = bboxA[3] = 1;
1383 if (dict->lookup("BBox", &obj1)->isArray() &&
1384 obj1.arrayGetLength() == 4) {
1385 for (i = 0; i < 4; ++i) {
1386 if (obj1.arrayGet(i, &obj2)->isNum()) {
1387 bboxA[i] = obj2.getNum();
1392 error(-1, "Invalid or missing BBox in pattern");
1395 if (dict->lookup("XStep", &obj1)->isNum()) {
1396 xStepA = obj1.getNum();
1399 error(-1, "Invalid or missing XStep in pattern");
1402 if (dict->lookup("YStep", &obj1)->isNum()) {
1403 yStepA = obj1.getNum();
1406 error(-1, "Invalid or missing YStep in pattern");
1409 if (!dict->lookup("Resources", &resDictA)->isDict()) {
1411 resDictA.initNull();
1412 error(-1, "Invalid or missing Resources in pattern");
1414 matrixA[0] = 1; matrixA[1] = 0;
1415 matrixA[2] = 0; matrixA[3] = 1;
1416 matrixA[4] = 0; matrixA[5] = 0;
1417 if (dict->lookup("Matrix", &obj1)->isArray() &&
1418 obj1.arrayGetLength() == 6) {
1419 for (i = 0; i < 6; ++i) {
1420 if (obj1.arrayGet(i, &obj2)->isNum()) {
1421 matrixA[i] = obj2.getNum();
1428 pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1429 &resDictA, matrixA, patObj);
1434 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1435 double *bboxA, double xStepA, double yStepA,
1436 Object *resDictA, double *matrixA,
1437 Object *contentStreamA):
1442 paintType = paintTypeA;
1443 tilingType = tilingTypeA;
1444 for (i = 0; i < 4; ++i) {
1449 resDictA->copy(&resDict);
1450 for (i = 0; i < 6; ++i) {
1451 matrix[i] = matrixA[i];
1453 contentStreamA->copy(&contentStream);
1456 GfxTilingPattern::~GfxTilingPattern() {
1458 contentStream.free();
1461 GfxPattern *GfxTilingPattern::copy() {
1462 return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1463 &resDict, matrix, &contentStream);
1466 //------------------------------------------------------------------------
1467 // GfxShadingPattern
1468 //------------------------------------------------------------------------
1470 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1472 GfxShading *shadingA;
1477 if (!patObj->isDict()) {
1480 dict = patObj->getDict();
1482 dict->lookup("Shading", &obj1);
1483 shadingA = GfxShading::parse(&obj1);
1489 matrixA[0] = 1; matrixA[1] = 0;
1490 matrixA[2] = 0; matrixA[3] = 1;
1491 matrixA[4] = 0; matrixA[5] = 0;
1492 if (dict->lookup("Matrix", &obj1)->isArray() &&
1493 obj1.arrayGetLength() == 6) {
1494 for (i = 0; i < 6; ++i) {
1495 if (obj1.arrayGet(i, &obj2)->isNum()) {
1496 matrixA[i] = obj2.getNum();
1503 return new GfxShadingPattern(shadingA, matrixA);
1506 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1512 for (i = 0; i < 6; ++i) {
1513 matrix[i] = matrixA[i];
1517 GfxShadingPattern::~GfxShadingPattern() {
1521 GfxPattern *GfxShadingPattern::copy() {
1522 return new GfxShadingPattern(shading->copy(), matrix);
1525 //------------------------------------------------------------------------
1527 //------------------------------------------------------------------------
1529 GfxShading::GfxShading(int typeA) {
1534 GfxShading::GfxShading(GfxShading *shading) {
1537 type = shading->type;
1538 colorSpace = shading->colorSpace->copy();
1539 for (i = 0; i < gfxColorMaxComps; ++i) {
1540 background.c[i] = shading->background.c[i];
1542 hasBackground = shading->hasBackground;
1543 xMin = shading->xMin;
1544 yMin = shading->yMin;
1545 xMax = shading->xMax;
1546 yMax = shading->yMax;
1547 hasBBox = shading->hasBBox;
1550 GfxShading::~GfxShading() {
1556 GfxShading *GfxShading::parse(Object *obj) {
1557 GfxShading *shading;
1562 if (obj->isDict()) {
1563 dict = obj->getDict();
1564 } else if (obj->isStream()) {
1565 dict = obj->streamGetDict();
1570 if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1571 error(-1, "Invalid ShadingType in shading dictionary");
1575 typeA = obj1.getInt();
1580 shading = GfxFunctionShading::parse(dict);
1583 shading = GfxAxialShading::parse(dict);
1586 shading = GfxRadialShading::parse(dict);
1589 if (obj->isStream()) {
1590 shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream());
1592 error(-1, "Invalid Type 4 shading object");
1597 if (obj->isStream()) {
1598 shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream());
1600 error(-1, "Invalid Type 5 shading object");
1605 if (obj->isStream()) {
1606 shading = GfxPatchMeshShading::parse(6, dict, obj->getStream());
1608 error(-1, "Invalid Type 6 shading object");
1613 if (obj->isStream()) {
1614 shading = GfxPatchMeshShading::parse(7, dict, obj->getStream());
1616 error(-1, "Invalid Type 7 shading object");
1621 error(-1, "Unimplemented shading type %d", typeA);
1631 GBool GfxShading::init(Dict *dict) {
1635 dict->lookup("ColorSpace", &obj1);
1636 if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1637 error(-1, "Bad color space in shading dictionary");
1643 for (i = 0; i < gfxColorMaxComps; ++i) {
1644 background.c[i] = 0;
1646 hasBackground = gFalse;
1647 if (dict->lookup("Background", &obj1)->isArray()) {
1648 if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1649 hasBackground = gTrue;
1650 for (i = 0; i < colorSpace->getNComps(); ++i) {
1651 background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
1655 error(-1, "Bad Background in shading dictionary");
1660 xMin = yMin = xMax = yMax = 0;
1662 if (dict->lookup("BBox", &obj1)->isArray()) {
1663 if (obj1.arrayGetLength() == 4) {
1665 xMin = obj1.arrayGet(0, &obj2)->getNum();
1667 yMin = obj1.arrayGet(1, &obj2)->getNum();
1669 xMax = obj1.arrayGet(2, &obj2)->getNum();
1671 yMax = obj1.arrayGet(3, &obj2)->getNum();
1674 error(-1, "Bad BBox in shading dictionary");
1682 //------------------------------------------------------------------------
1683 // GfxFunctionShading
1684 //------------------------------------------------------------------------
1686 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1687 double x1A, double y1A,
1689 Function **funcsA, int nFuncsA):
1698 for (i = 0; i < 6; ++i) {
1699 matrix[i] = matrixA[i];
1702 for (i = 0; i < nFuncs; ++i) {
1703 funcs[i] = funcsA[i];
1707 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1716 for (i = 0; i < 6; ++i) {
1717 matrix[i] = shading->matrix[i];
1719 nFuncs = shading->nFuncs;
1720 for (i = 0; i < nFuncs; ++i) {
1721 funcs[i] = shading->funcs[i]->copy();
1725 GfxFunctionShading::~GfxFunctionShading() {
1728 for (i = 0; i < nFuncs; ++i) {
1733 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1734 GfxFunctionShading *shading;
1735 double x0A, y0A, x1A, y1A;
1737 Function *funcsA[gfxColorMaxComps];
1744 if (dict->lookup("Domain", &obj1)->isArray() &&
1745 obj1.arrayGetLength() == 4) {
1746 x0A = obj1.arrayGet(0, &obj2)->getNum();
1748 y0A = obj1.arrayGet(1, &obj2)->getNum();
1750 x1A = obj1.arrayGet(2, &obj2)->getNum();
1752 y1A = obj1.arrayGet(3, &obj2)->getNum();
1757 matrixA[0] = 1; matrixA[1] = 0;
1758 matrixA[2] = 0; matrixA[3] = 1;
1759 matrixA[4] = 0; matrixA[5] = 0;
1760 if (dict->lookup("Matrix", &obj1)->isArray() &&
1761 obj1.arrayGetLength() == 6) {
1762 matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1764 matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1766 matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1768 matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1770 matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1772 matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1777 dict->lookup("Function", &obj1);
1778 if (obj1.isArray()) {
1779 nFuncsA = obj1.arrayGetLength();
1780 if (nFuncsA > gfxColorMaxComps) {
1781 error(-1, "Invalid Function array in shading dictionary");
1784 for (i = 0; i < nFuncsA; ++i) {
1785 obj1.arrayGet(i, &obj2);
1786 if (!(funcsA[i] = Function::parse(&obj2))) {
1793 if (!(funcsA[0] = Function::parse(&obj1))) {
1799 shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1801 if (!shading->init(dict)) {
1814 GfxShading *GfxFunctionShading::copy() {
1815 return new GfxFunctionShading(this);
1818 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1819 double in[2], out[gfxColorMaxComps];
1822 // NB: there can be one function with n outputs or n functions with
1823 // one output each (where n = number of color components)
1824 for (i = 0; i < gfxColorMaxComps; ++i) {
1829 for (i = 0; i < nFuncs; ++i) {
1830 funcs[i]->transform(in, &out[i]);
1832 for (i = 0; i < gfxColorMaxComps; ++i) {
1833 color->c[i] = dblToCol(out[i]);
1837 //------------------------------------------------------------------------
1839 //------------------------------------------------------------------------
1841 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1842 double x1A, double y1A,
1843 double t0A, double t1A,
1844 Function **funcsA, int nFuncsA,
1845 GBool extend0A, GBool extend1A):
1857 for (i = 0; i < nFuncs; ++i) {
1858 funcs[i] = funcsA[i];
1864 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1875 nFuncs = shading->nFuncs;
1876 for (i = 0; i < nFuncs; ++i) {
1877 funcs[i] = shading->funcs[i]->copy();
1879 extend0 = shading->extend0;
1880 extend1 = shading->extend1;
1883 GfxAxialShading::~GfxAxialShading() {
1886 for (i = 0; i < nFuncs; ++i) {
1891 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1892 GfxAxialShading *shading;
1893 double x0A, y0A, x1A, y1A;
1895 Function *funcsA[gfxColorMaxComps];
1897 GBool extend0A, extend1A;
1901 x0A = y0A = x1A = y1A = 0;
1902 if (dict->lookup("Coords", &obj1)->isArray() &&
1903 obj1.arrayGetLength() == 4) {
1904 x0A = obj1.arrayGet(0, &obj2)->getNum();
1906 y0A = obj1.arrayGet(1, &obj2)->getNum();
1908 x1A = obj1.arrayGet(2, &obj2)->getNum();
1910 y1A = obj1.arrayGet(3, &obj2)->getNum();
1913 error(-1, "Missing or invalid Coords in shading dictionary");
1920 if (dict->lookup("Domain", &obj1)->isArray() &&
1921 obj1.arrayGetLength() == 2) {
1922 t0A = obj1.arrayGet(0, &obj2)->getNum();
1924 t1A = obj1.arrayGet(1, &obj2)->getNum();
1929 dict->lookup("Function", &obj1);
1930 if (obj1.isArray()) {
1931 nFuncsA = obj1.arrayGetLength();
1932 if (nFuncsA > gfxColorMaxComps) {
1933 error(-1, "Invalid Function array in shading dictionary");
1936 for (i = 0; i < nFuncsA; ++i) {
1937 obj1.arrayGet(i, &obj2);
1938 if (!(funcsA[i] = Function::parse(&obj2))) {
1947 if (!(funcsA[0] = Function::parse(&obj1))) {
1954 extend0A = extend1A = gFalse;
1955 if (dict->lookup("Extend", &obj1)->isArray() &&
1956 obj1.arrayGetLength() == 2) {
1957 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1959 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1964 shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1965 funcsA, nFuncsA, extend0A, extend1A);
1966 if (!shading->init(dict)) {
1976 GfxShading *GfxAxialShading::copy() {
1977 return new GfxAxialShading(this);
1980 void GfxAxialShading::getColor(double t, GfxColor *color) {
1981 double out[gfxColorMaxComps];
1984 // NB: there can be one function with n outputs or n functions with
1985 // one output each (where n = number of color components)
1986 for (i = 0; i < gfxColorMaxComps; ++i) {
1989 for (i = 0; i < nFuncs; ++i) {
1990 funcs[i]->transform(&t, &out[i]);
1992 for (i = 0; i < gfxColorMaxComps; ++i) {
1993 color->c[i] = dblToCol(out[i]);
1997 //------------------------------------------------------------------------
1999 //------------------------------------------------------------------------
2001 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
2002 double x1A, double y1A, double r1A,
2003 double t0A, double t1A,
2004 Function **funcsA, int nFuncsA,
2005 GBool extend0A, GBool extend1A):
2019 for (i = 0; i < nFuncs; ++i) {
2020 funcs[i] = funcsA[i];
2026 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
2039 nFuncs = shading->nFuncs;
2040 for (i = 0; i < nFuncs; ++i) {
2041 funcs[i] = shading->funcs[i]->copy();
2043 extend0 = shading->extend0;
2044 extend1 = shading->extend1;
2047 GfxRadialShading::~GfxRadialShading() {
2050 for (i = 0; i < nFuncs; ++i) {
2055 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
2056 GfxRadialShading *shading;
2057 double x0A, y0A, r0A, x1A, y1A, r1A;
2059 Function *funcsA[gfxColorMaxComps];
2061 GBool extend0A, extend1A;
2065 x0A = y0A = r0A = x1A = y1A = r1A = 0;
2066 if (dict->lookup("Coords", &obj1)->isArray() &&
2067 obj1.arrayGetLength() == 6) {
2068 x0A = obj1.arrayGet(0, &obj2)->getNum();
2070 y0A = obj1.arrayGet(1, &obj2)->getNum();
2072 r0A = obj1.arrayGet(2, &obj2)->getNum();
2074 x1A = obj1.arrayGet(3, &obj2)->getNum();
2076 y1A = obj1.arrayGet(4, &obj2)->getNum();
2078 r1A = obj1.arrayGet(5, &obj2)->getNum();
2081 error(-1, "Missing or invalid Coords in shading dictionary");
2088 if (dict->lookup("Domain", &obj1)->isArray() &&
2089 obj1.arrayGetLength() == 2) {
2090 t0A = obj1.arrayGet(0, &obj2)->getNum();
2092 t1A = obj1.arrayGet(1, &obj2)->getNum();
2097 dict->lookup("Function", &obj1);
2098 if (obj1.isArray()) {
2099 nFuncsA = obj1.arrayGetLength();
2100 if (nFuncsA > gfxColorMaxComps) {
2101 error(-1, "Invalid Function array in shading dictionary");
2104 for (i = 0; i < nFuncsA; ++i) {
2105 obj1.arrayGet(i, &obj2);
2106 if (!(funcsA[i] = Function::parse(&obj2))) {
2115 if (!(funcsA[0] = Function::parse(&obj1))) {
2122 extend0A = extend1A = gFalse;
2123 if (dict->lookup("Extend", &obj1)->isArray() &&
2124 obj1.arrayGetLength() == 2) {
2125 extend0A = obj1.arrayGet(0, &obj2)->getBool();
2127 extend1A = obj1.arrayGet(1, &obj2)->getBool();
2132 shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
2133 funcsA, nFuncsA, extend0A, extend1A);
2134 if (!shading->init(dict)) {
2144 GfxShading *GfxRadialShading::copy() {
2145 return new GfxRadialShading(this);
2148 void GfxRadialShading::getColor(double t, GfxColor *color) {
2149 double out[gfxColorMaxComps];
2152 // NB: there can be one function with n outputs or n functions with
2153 // one output each (where n = number of color components)
2154 for (i = 0; i < gfxColorMaxComps; ++i) {
2157 for (i = 0; i < nFuncs; ++i) {
2158 funcs[i]->transform(&t, &out[i]);
2160 for (i = 0; i < gfxColorMaxComps; ++i) {
2161 color->c[i] = dblToCol(out[i]);
2165 //------------------------------------------------------------------------
2167 //------------------------------------------------------------------------
2169 class GfxShadingBitBuf {
2172 GfxShadingBitBuf(Stream *strA);
2173 ~GfxShadingBitBuf();
2174 GBool getBits(int n, Guint *val);
2184 GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
2191 GfxShadingBitBuf::~GfxShadingBitBuf() {
2195 GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
2199 x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
2204 x = bitBuf & ((1 << nBits) - 1);
2209 if ((bitBuf = str->getChar()) == EOF) {
2214 x = (x << 8) | bitBuf;
2217 x = (x << n) | (bitBuf >> (8 - n));
2227 void GfxShadingBitBuf::flushBits() {
2232 //------------------------------------------------------------------------
2233 // GfxGouraudTriangleShading
2234 //------------------------------------------------------------------------
2236 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2238 GfxGouraudVertex *verticesA, int nVerticesA,
2239 int (*trianglesA)[3], int nTrianglesA,
2240 Function **funcsA, int nFuncsA):
2245 vertices = verticesA;
2246 nVertices = nVerticesA;
2247 triangles = trianglesA;
2248 nTriangles = nTrianglesA;
2250 for (i = 0; i < nFuncs; ++i) {
2251 funcs[i] = funcsA[i];
2255 GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2256 GfxGouraudTriangleShading *shading):
2261 nVertices = shading->nVertices;
2262 vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
2263 memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
2264 nTriangles = shading->nTriangles;
2265 triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
2266 memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
2267 nFuncs = shading->nFuncs;
2268 for (i = 0; i < nFuncs; ++i) {
2269 funcs[i] = shading->funcs[i]->copy();
2273 GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2278 for (i = 0; i < nFuncs; ++i) {
2283 GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
2286 GfxGouraudTriangleShading *shading;
2287 Function *funcsA[gfxColorMaxComps];
2289 int coordBits, compBits, flagBits, vertsPerRow, nRows;
2290 double xMin, xMax, yMin, yMax;
2291 double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2293 double cMul[gfxColorMaxComps];
2294 GfxGouraudVertex *verticesA;
2295 int (*trianglesA)[3];
2296 int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
2298 Guint c[gfxColorMaxComps];
2299 GfxShadingBitBuf *bitBuf;
2303 if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2304 coordBits = obj1.getInt();
2306 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2310 if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2311 compBits = obj1.getInt();
2313 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2317 flagBits = vertsPerRow = 0; // make gcc happy
2319 if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2320 flagBits = obj1.getInt();
2322 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2327 if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
2328 vertsPerRow = obj1.getInt();
2330 error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
2335 if (dict->lookup("Decode", &obj1)->isArray() &&
2336 obj1.arrayGetLength() >= 6) {
2337 xMin = obj1.arrayGet(0, &obj2)->getNum();
2339 xMax = obj1.arrayGet(1, &obj2)->getNum();
2341 xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
2342 yMin = obj1.arrayGet(2, &obj2)->getNum();
2344 yMax = obj1.arrayGet(3, &obj2)->getNum();
2346 yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
2347 for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
2348 cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
2350 cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
2352 cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
2356 error(-1, "Missing or invalid Decode array in shading dictionary");
2361 if (!dict->lookup("Function", &obj1)->isNull()) {
2362 if (obj1.isArray()) {
2363 nFuncsA = obj1.arrayGetLength();
2364 if (nFuncsA > gfxColorMaxComps) {
2365 error(-1, "Invalid Function array in shading dictionary");
2368 for (i = 0; i < nFuncsA; ++i) {
2369 obj1.arrayGet(i, &obj2);
2370 if (!(funcsA[i] = Function::parse(&obj2))) {
2379 if (!(funcsA[0] = Function::parse(&obj1))) {
2389 nVerticesA = nTrianglesA = 0;
2392 vertSize = triSize = 0;
2394 flag = 0; // make gcc happy
2395 bitBuf = new GfxShadingBitBuf(str);
2398 if (!bitBuf->getBits(flagBits, &flag)) {
2402 if (!bitBuf->getBits(coordBits, &x) ||
2403 !bitBuf->getBits(coordBits, &y)) {
2406 for (i = 0; i < nComps; ++i) {
2407 if (!bitBuf->getBits(compBits, &c[i])) {
2414 if (nVerticesA == vertSize) {
2415 vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
2416 verticesA = (GfxGouraudVertex *)
2417 greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
2419 verticesA[nVerticesA].x = xMin + xMul * (double)x;
2420 verticesA[nVerticesA].y = yMin + yMul * (double)y;
2421 for (i = 0; i < nComps; ++i) {
2422 verticesA[nVerticesA].color.c[i] =
2423 dblToCol(cMin[i] + cMul[i] * (double)c[i]);
2426 bitBuf->flushBits();
2428 if (state == 0 || state == 1) {
2430 } else if (state == 2 || flag > 0) {
2431 if (nTrianglesA == triSize) {
2432 triSize = (triSize == 0) ? 16 : 2 * triSize;
2433 trianglesA = (int (*)[3])
2434 greallocn(trianglesA, triSize * 3, sizeof(int));
2437 trianglesA[nTrianglesA][0] = nVerticesA - 3;
2438 trianglesA[nTrianglesA][1] = nVerticesA - 2;
2439 trianglesA[nTrianglesA][2] = nVerticesA - 1;
2441 } else if (flag == 1) {
2442 trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
2443 trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2444 trianglesA[nTrianglesA][2] = nVerticesA - 1;
2445 } else { // flag == 2
2446 trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
2447 trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2448 trianglesA[nTrianglesA][2] = nVerticesA - 1;
2451 } else { // state == 3 && flag == 0
2458 nRows = nVerticesA / vertsPerRow;
2459 nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
2460 trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
2462 for (i = 0; i < nRows - 1; ++i) {
2463 for (j = 0; j < vertsPerRow - 1; ++j) {
2464 trianglesA[k][0] = i * vertsPerRow + j;
2465 trianglesA[k][1] = i * vertsPerRow + j+1;
2466 trianglesA[k][2] = (i+1) * vertsPerRow + j;
2468 trianglesA[k][0] = i * vertsPerRow + j+1;
2469 trianglesA[k][1] = (i+1) * vertsPerRow + j;
2470 trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
2476 shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
2477 trianglesA, nTrianglesA,
2479 if (!shading->init(dict)) {
2491 GfxShading *GfxGouraudTriangleShading::copy() {
2492 return new GfxGouraudTriangleShading(this);
2495 void GfxGouraudTriangleShading::getTriangle(
2497 double *x0, double *y0, GfxColor *color0,
2498 double *x1, double *y1, GfxColor *color1,
2499 double *x2, double *y2, GfxColor *color2) {
2501 double out[gfxColorMaxComps];
2504 v = triangles[i][0];
2505 *x0 = vertices[v].x;
2506 *y0 = vertices[v].y;
2508 in = colToDbl(vertices[v].color.c[0]);
2509 for (j = 0; j < nFuncs; ++j) {
2510 funcs[j]->transform(&in, &out[j]);
2512 for (j = 0; j < gfxColorMaxComps; ++j) {
2513 color0->c[j] = dblToCol(out[j]);
2516 *color0 = vertices[v].color;
2518 v = triangles[i][1];
2519 *x1 = vertices[v].x;
2520 *y1 = vertices[v].y;
2522 in = colToDbl(vertices[v].color.c[0]);
2523 for (j = 0; j < nFuncs; ++j) {
2524 funcs[j]->transform(&in, &out[j]);
2526 for (j = 0; j < gfxColorMaxComps; ++j) {
2527 color1->c[j] = dblToCol(out[j]);
2530 *color1 = vertices[v].color;
2532 v = triangles[i][2];
2533 *x2 = vertices[v].x;
2534 *y2 = vertices[v].y;
2536 in = colToDbl(vertices[v].color.c[0]);
2537 for (j = 0; j < nFuncs; ++j) {
2538 funcs[j]->transform(&in, &out[j]);
2540 for (j = 0; j < gfxColorMaxComps; ++j) {
2541 color2->c[j] = dblToCol(out[j]);
2544 *color2 = vertices[v].color;
2548 //------------------------------------------------------------------------
2549 // GfxPatchMeshShading
2550 //------------------------------------------------------------------------
2552 GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
2553 GfxPatch *patchesA, int nPatchesA,
2554 Function **funcsA, int nFuncsA):
2560 nPatches = nPatchesA;
2562 for (i = 0; i < nFuncs; ++i) {
2563 funcs[i] = funcsA[i];
2567 GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
2572 nPatches = shading->nPatches;
2573 patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
2574 memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
2575 nFuncs = shading->nFuncs;
2576 for (i = 0; i < nFuncs; ++i) {
2577 funcs[i] = shading->funcs[i]->copy();
2581 GfxPatchMeshShading::~GfxPatchMeshShading() {
2585 for (i = 0; i < nFuncs; ++i) {
2590 GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
2592 GfxPatchMeshShading *shading;
2593 Function *funcsA[gfxColorMaxComps];
2595 int coordBits, compBits, flagBits;
2596 double xMin, xMax, yMin, yMax;
2597 double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2599 double cMul[gfxColorMaxComps];
2600 GfxPatch *patchesA, *p;
2601 int nComps, nPatchesA, patchesSize, nPts, nColors;
2603 double x[16], y[16];
2605 GfxColorComp c[4][gfxColorMaxComps];
2607 GfxShadingBitBuf *bitBuf;
2611 if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2612 coordBits = obj1.getInt();
2614 error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
2618 if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2619 compBits = obj1.getInt();
2621 error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
2625 if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2626 flagBits = obj1.getInt();
2628 error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
2632 if (dict->lookup("Decode", &obj1)->isArray() &&
2633 obj1.arrayGetLength() >= 6) {
2634 xMin = obj1.arrayGet(0, &obj2)->getNum();
2636 xMax = obj1.arrayGet(1, &obj2)->getNum();
2638 xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
2639 yMin = obj1.arrayGet(2, &obj2)->getNum();
2641 yMax = obj1.arrayGet(3, &obj2)->getNum();
2643 yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
2644 for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
2645 cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
2647 cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
2649 cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
2653 error(-1, "Missing or invalid Decode array in shading dictionary");
2658 if (!dict->lookup("Function", &obj1)->isNull()) {
2659 if (obj1.isArray()) {
2660 nFuncsA = obj1.arrayGetLength();
2661 if (nFuncsA > gfxColorMaxComps) {
2662 error(-1, "Invalid Function array in shading dictionary");
2665 for (i = 0; i < nFuncsA; ++i) {
2666 obj1.arrayGet(i, &obj2);
2667 if (!(funcsA[i] = Function::parse(&obj2))) {
2676 if (!(funcsA[0] = Function::parse(&obj1))) {
2689 bitBuf = new GfxShadingBitBuf(str);
2691 if (!bitBuf->getBits(flagBits, &flag)) {
2696 case 0: nPts = 12; nColors = 4; break;
2700 default: nPts = 8; nColors = 2; break;
2704 case 0: nPts = 16; nColors = 4; break;
2708 default: nPts = 12; nColors = 2; break;
2711 for (i = 0; i < nPts; ++i) {
2712 if (!bitBuf->getBits(coordBits, &xi) ||
2713 !bitBuf->getBits(coordBits, &yi)) {
2716 x[i] = xMin + xMul * (double)xi;
2717 y[i] = yMin + yMul * (double)yi;
2722 for (i = 0; i < nColors; ++i) {
2723 for (j = 0; j < nComps; ++j) {
2724 if (!bitBuf->getBits(compBits, &ci[j])) {
2727 c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
2736 if (nPatchesA == patchesSize) {
2737 patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
2738 patchesA = (GfxPatch *)greallocn(patchesA,
2739 patchesSize, sizeof(GfxPatch));
2741 p = &patchesA[nPatchesA];
2769 for (j = 0; j < nComps; ++j) {
2770 p->color[0][0].c[j] = c[0][j];
2771 p->color[0][1].c[j] = c[1][j];
2772 p->color[1][1].c[j] = c[2][j];
2773 p->color[1][0].c[j] = c[3][j];
2777 p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
2778 p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
2779 p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
2780 p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
2781 p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
2782 p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
2783 p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
2784 p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
2801 for (j = 0; j < nComps; ++j) {
2802 p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
2803 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2804 p->color[1][1].c[j] = c[0][j];
2805 p->color[1][0].c[j] = c[1][j];
2809 p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
2810 p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
2811 p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
2812 p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
2813 p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
2814 p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
2815 p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
2816 p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
2833 for (j = 0; j < nComps; ++j) {
2834 p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2835 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2836 p->color[1][1].c[j] = c[0][j];
2837 p->color[1][0].c[j] = c[1][j];
2841 p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
2842 p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
2843 p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
2844 p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
2845 p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
2846 p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
2847 p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
2848 p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
2865 for (j = 0; j < nComps; ++j) {
2866 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2867 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
2868 p->color[1][1].c[j] = c[0][j];
2869 p->color[1][0].c[j] = c[1][j];
2908 for (j = 0; j < nComps; ++j) {
2909 p->color[0][0].c[j] = c[0][j];
2910 p->color[0][1].c[j] = c[1][j];
2911 p->color[1][1].c[j] = c[2][j];
2912 p->color[1][0].c[j] = c[3][j];
2916 p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
2917 p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
2918 p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
2919 p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
2920 p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
2921 p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
2922 p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
2923 p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
2948 for (j = 0; j < nComps; ++j) {
2949 p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
2950 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2951 p->color[1][1].c[j] = c[0][j];
2952 p->color[1][0].c[j] = c[1][j];
2956 p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
2957 p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
2958 p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
2959 p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
2960 p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
2961 p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
2962 p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
2963 p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
2988 for (j = 0; j < nComps; ++j) {
2989 p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
2990 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
2991 p->color[1][1].c[j] = c[0][j];
2992 p->color[1][0].c[j] = c[1][j];
2996 p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
2997 p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
2998 p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
2999 p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3000 p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3001 p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3002 p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3003 p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3028 for (j = 0; j < nComps; ++j) {
3029 p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
3030 p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
3031 p->color[1][1].c[j] = c[0][j];
3032 p->color[1][0].c[j] = c[1][j];
3038 bitBuf->flushBits();
3043 for (i = 0; i < nPatchesA; ++i) {
3045 p->x[1][1] = (-4 * p->x[0][0]
3046 +6 * (p->x[0][1] + p->x[1][0])
3047 -2 * (p->x[0][3] + p->x[3][0])
3048 +3 * (p->x[3][1] + p->x[1][3])
3050 p->y[1][1] = (-4 * p->y[0][0]
3051 +6 * (p->y[0][1] + p->y[1][0])
3052 -2 * (p->y[0][3] + p->y[3][0])
3053 +3 * (p->y[3][1] + p->y[1][3])
3055 p->x[1][2] = (-4 * p->x[0][3]
3056 +6 * (p->x[0][2] + p->x[1][3])
3057 -2 * (p->x[0][0] + p->x[3][3])
3058 +3 * (p->x[3][2] + p->x[1][0])
3060 p->y[1][2] = (-4 * p->y[0][3]
3061 +6 * (p->y[0][2] + p->y[1][3])
3062 -2 * (p->y[0][0] + p->y[3][3])
3063 +3 * (p->y[3][2] + p->y[1][0])
3065 p->x[2][1] = (-4 * p->x[3][0]
3066 +6 * (p->x[3][1] + p->x[2][0])
3067 -2 * (p->x[3][3] + p->x[0][0])
3068 +3 * (p->x[0][1] + p->x[2][3])
3070 p->y[2][1] = (-4 * p->y[3][0]
3071 +6 * (p->y[3][1] + p->y[2][0])
3072 -2 * (p->y[3][3] + p->y[0][0])
3073 +3 * (p->y[0][1] + p->y[2][3])
3075 p->x[2][2] = (-4 * p->x[3][3]
3076 +6 * (p->x[3][2] + p->x[2][3])
3077 -2 * (p->x[3][0] + p->x[0][3])
3078 +3 * (p->x[0][2] + p->x[2][0])
3080 p->y[2][2] = (-4 * p->y[3][3]
3081 +6 * (p->y[3][2] + p->y[2][3])
3082 -2 * (p->y[3][0] + p->y[0][3])
3083 +3 * (p->y[0][2] + p->y[2][0])
3088 shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
3090 if (!shading->init(dict)) {
3102 GfxShading *GfxPatchMeshShading::copy() {
3103 return new GfxPatchMeshShading(this);
3106 //------------------------------------------------------------------------
3108 //------------------------------------------------------------------------
3110 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
3111 GfxColorSpace *colorSpaceA) {
3112 GfxIndexedColorSpace *indexedCS;
3113 GfxSeparationColorSpace *sepCS;
3114 int maxPixel, indexHigh;
3115 int maxPixelForAlloc;
3119 double x[gfxColorMaxComps];
3120 double y[gfxColorMaxComps];
3125 // bits per component and color space
3127 maxPixel = (1 << bits) - 1;
3128 maxPixelForAlloc = (1 << (bits>8?bits:8));
3129 colorSpace = colorSpaceA;
3132 if (decode->isNull()) {
3133 nComps = colorSpace->getNComps();
3134 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
3135 } else if (decode->isArray()) {
3136 nComps = decode->arrayGetLength() / 2;
3137 if (nComps != colorSpace->getNComps()) {
3140 for (i = 0; i < nComps; ++i) {
3141 decode->arrayGet(2*i, &obj);
3145 decodeLow[i] = obj.getNum();
3147 decode->arrayGet(2*i+1, &obj);
3151 decodeRange[i] = obj.getNum() - decodeLow[i];
3158 // Construct a lookup table -- this stores pre-computed decoded
3159 // values for each component, i.e., the result of applying the
3160 // decode mapping to each possible image pixel component value.
3162 // Optimization: for Indexed and Separation color spaces (which have
3163 // only one component), we store color values in the lookup table
3164 // rather than component values.
3165 for (k = 0; k < gfxColorMaxComps; ++k) {
3170 if (colorSpace->getMode() == csIndexed) {
3171 // Note that indexHigh may not be the same as maxPixel --
3172 // Distiller will remove unused palette entries, resulting in
3173 // indexHigh < maxPixel.
3174 indexedCS = (GfxIndexedColorSpace *)colorSpace;
3175 colorSpace2 = indexedCS->getBase();
3176 indexHigh = indexedCS->getIndexHigh();
3177 nComps2 = colorSpace2->getNComps();
3178 lookup2 = indexedCS->getLookup();
3179 colorSpace2->getDefaultRanges(x, y, indexHigh);
3180 for (k = 0; k < nComps2; ++k) {
3181 lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3182 sizeof(GfxColorComp));
3183 for (i = 0; i <= maxPixel; ++i) {
3184 j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
3187 } else if (j > indexHigh) {
3191 dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
3194 } else if (colorSpace->getMode() == csSeparation) {
3195 sepCS = (GfxSeparationColorSpace *)colorSpace;
3196 colorSpace2 = sepCS->getAlt();
3197 nComps2 = colorSpace2->getNComps();
3198 sepFunc = sepCS->getFunc();
3199 for (k = 0; k < nComps2; ++k) {
3200 lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3201 sizeof(GfxColorComp));
3202 for (i = 0; i <= maxPixel; ++i) {
3203 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
3204 sepFunc->transform(x, y);
3205 lookup[k][i] = dblToCol(y[k]);
3209 for (k = 0; k < nComps; ++k) {
3210 lookup[k] = (GfxColorComp *)gmallocn(maxPixelForAlloc + 1,
3211 sizeof(GfxColorComp));
3212 for (i = 0; i <= maxPixel; ++i) {
3213 lookup[k][i] = dblToCol(decodeLow[k] +
3214 (i * decodeRange[k]) / maxPixel);
3227 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
3230 colorSpace = colorMap->colorSpace->copy();
3231 bits = colorMap->bits;
3232 nComps = colorMap->nComps;
3233 nComps2 = colorMap->nComps2;
3235 for (k = 0; k < gfxColorMaxComps; ++k) {
3239 if (colorSpace->getMode() == csIndexed) {
3240 colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
3241 for (k = 0; k < nComps2; ++k) {
3242 lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3243 memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3245 } else if (colorSpace->getMode() == csSeparation) {
3246 colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
3247 for (k = 0; k < nComps2; ++k) {
3248 lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3249 memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3252 for (k = 0; k < nComps; ++k) {
3253 lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3254 memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3257 for (i = 0; i < nComps; ++i) {
3258 decodeLow[i] = colorMap->decodeLow[i];
3259 decodeRange[i] = colorMap->decodeRange[i];
3264 GfxImageColorMap::~GfxImageColorMap() {
3268 for (i = 0; i < gfxColorMaxComps; ++i) {
3273 void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
3278 for (i = 0; i < nComps2; ++i) {
3279 color.c[i] = lookup[i][x[0]];
3281 colorSpace2->getGray(&color, gray);
3283 for (i = 0; i < nComps; ++i) {
3284 color.c[i] = lookup[i][x[i]];
3286 colorSpace->getGray(&color, gray);
3290 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
3295 for (i = 0; i < nComps2; ++i) {
3296 color.c[i] = lookup[i][x[0]];
3298 colorSpace2->getRGB(&color, rgb);
3300 for (i = 0; i < nComps; ++i) {
3301 color.c[i] = lookup[i][x[i]];
3303 colorSpace->getRGB(&color, rgb);
3307 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
3312 for (i = 0; i < nComps2; ++i) {
3313 color.c[i] = lookup[i][x[0]];
3315 colorSpace2->getCMYK(&color, cmyk);
3317 for (i = 0; i < nComps; ++i) {
3318 color.c[i] = lookup[i][x[i]];
3320 colorSpace->getCMYK(&color, cmyk);
3324 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
3327 maxPixel = (1 << bits) - 1;
3328 for (i = 0; i < nComps; ++i) {
3329 color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
3333 //------------------------------------------------------------------------
3334 // GfxSubpath and GfxPath
3335 //------------------------------------------------------------------------
3337 GfxSubpath::GfxSubpath(double x1, double y1) {
3339 x = (double *)gmallocn(size, sizeof(double));
3340 y = (double *)gmallocn(size, sizeof(double));
3341 curve = (GBool *)gmallocn(size, sizeof(GBool));
3349 GfxSubpath::~GfxSubpath() {
3356 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
3357 size = subpath->size;
3359 x = (double *)gmallocn(size, sizeof(double));
3360 y = (double *)gmallocn(size, sizeof(double));
3361 curve = (GBool *)gmallocn(size, sizeof(GBool));
3362 memcpy(x, subpath->x, n * sizeof(double));
3363 memcpy(y, subpath->y, n * sizeof(double));
3364 memcpy(curve, subpath->curve, n * sizeof(GBool));
3365 closed = subpath->closed;
3368 void GfxSubpath::lineTo(double x1, double y1) {
3371 x = (double *)greallocn(x, size, sizeof(double));
3372 y = (double *)greallocn(y, size, sizeof(double));
3373 curve = (GBool *)greallocn(curve, size, sizeof(GBool));
3381 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
3382 double x3, double y3) {
3385 x = (double *)greallocn(x, size, sizeof(double));
3386 y = (double *)greallocn(y, size, sizeof(double));
3387 curve = (GBool *)greallocn(curve, size, sizeof(GBool));
3395 curve[n] = curve[n+1] = gTrue;
3396 curve[n+2] = gFalse;
3400 void GfxSubpath::close() {
3401 if (x[n-1] != x[0] || y[n-1] != y[0]) {
3407 void GfxSubpath::offset(double dx, double dy) {
3410 for (i = 0; i < n; ++i) {
3416 GfxPath::GfxPath() {
3420 firstX = firstY = 0;
3421 subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
3424 GfxPath::~GfxPath() {
3427 for (i = 0; i < n; ++i)
3433 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
3434 GfxSubpath **subpaths1, int n1, int size1) {
3437 justMoved = justMoved1;
3442 subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
3443 for (i = 0; i < n; ++i)
3444 subpaths[i] = subpaths1[i]->copy();
3447 void GfxPath::moveTo(double x, double y) {
3453 void GfxPath::lineTo(double x, double y) {
3457 subpaths = (GfxSubpath **)
3458 greallocn(subpaths, size, sizeof(GfxSubpath *));
3460 subpaths[n] = new GfxSubpath(firstX, firstY);
3464 subpaths[n-1]->lineTo(x, y);
3467 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
3468 double x3, double y3) {
3472 subpaths = (GfxSubpath **)
3473 greallocn(subpaths, size, sizeof(GfxSubpath *));
3475 subpaths[n] = new GfxSubpath(firstX, firstY);
3479 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
3482 void GfxPath::close() {
3483 // this is necessary to handle the pathological case of
3484 // moveto/closepath/clip, which defines an empty clipping region
3488 subpaths = (GfxSubpath **)
3489 greallocn(subpaths, size, sizeof(GfxSubpath *));
3491 subpaths[n] = new GfxSubpath(firstX, firstY);
3495 subpaths[n-1]->close();
3498 void GfxPath::append(GfxPath *path) {
3501 if (n + path->n > size) {
3503 subpaths = (GfxSubpath **)
3504 greallocn(subpaths, size, sizeof(GfxSubpath *));
3506 for (i = 0; i < path->n; ++i) {
3507 subpaths[n++] = path->subpaths[i]->copy();
3512 void GfxPath::offset(double dx, double dy) {
3515 for (i = 0; i < n; ++i) {
3516 subpaths[i]->offset(dx, dy);
3520 //------------------------------------------------------------------------
3522 //------------------------------------------------------------------------
3524 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
3525 int rotateA, GBool upsideDown) {
3537 ctm[1] = upsideDown ? ky : -ky;
3541 ctm[5] = ky * (upsideDown ? -px1 : px2);
3542 pageWidth = kx * (py2 - py1);
3543 pageHeight = ky * (px2 - px1);
3544 } else if (rotate == 180) {
3548 ctm[3] = upsideDown ? ky : -ky;
3550 ctm[5] = ky * (upsideDown ? -py1 : py2);
3551 pageWidth = kx * (px2 - px1);
3552 pageHeight = ky * (py2 - py1);
3553 } else if (rotate == 270) {
3555 ctm[1] = upsideDown ? -ky : ky;
3559 ctm[5] = ky * (upsideDown ? px2 : -px1);
3560 pageWidth = kx * (py2 - py1);
3561 pageHeight = ky * (px2 - px1);
3566 ctm[3] = upsideDown ? -ky : ky;
3568 ctm[5] = ky * (upsideDown ? py2 : -py1);
3569 pageWidth = kx * (px2 - px1);
3570 pageHeight = ky * (py2 - py1);
3573 fillColorSpace = new GfxDeviceGrayColorSpace();
3574 strokeColorSpace = new GfxDeviceGrayColorSpace();
3576 strokeColor.c[0] = 0;
3578 strokePattern = NULL;
3579 blendMode = gfxBlendNormal;
3582 fillOverprint = gFalse;
3583 strokeOverprint = gFalse;
3596 textMat[0] = 1; textMat[1] = 0;
3597 textMat[2] = 0; textMat[3] = 1;
3598 textMat[4] = 0; textMat[5] = 0;
3606 path = new GfxPath();
3612 clipXMax = pageWidth;
3613 clipYMax = pageHeight;
3618 GfxState::~GfxState() {
3619 if (fillColorSpace) {
3620 delete fillColorSpace;
3622 if (strokeColorSpace) {
3623 delete strokeColorSpace;
3628 if (strokePattern) {
3629 delete strokePattern;
3633 // this gets set to NULL by restore()
3642 GfxState::GfxState(GfxState *state) {
3643 memcpy(this, state, sizeof(GfxState));
3644 if (fillColorSpace) {
3645 fillColorSpace = state->fillColorSpace->copy();
3647 if (strokeColorSpace) {
3648 strokeColorSpace = state->strokeColorSpace->copy();
3651 fillPattern = state->fillPattern->copy();
3653 if (strokePattern) {
3654 strokePattern = state->strokePattern->copy();
3656 if (lineDashLength > 0) {
3657 lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
3658 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
3663 void GfxState::setPath(GfxPath *pathA) {
3668 void GfxState::getUserClipBBox(double *xMin, double *yMin,
3669 double *xMax, double *yMax) {
3671 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
3674 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
3675 ictm[0] = ctm[3] * det;
3676 ictm[1] = -ctm[1] * det;
3677 ictm[2] = -ctm[2] * det;
3678 ictm[3] = ctm[0] * det;
3679 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
3680 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
3682 // transform all four corners of the clip bbox; find the min and max
3684 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
3685 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
3686 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
3687 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
3690 } else if (tx > xMax1) {
3695 } else if (ty > yMax1) {
3698 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
3699 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
3702 } else if (tx > xMax1) {
3707 } else if (ty > yMax1) {
3710 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
3711 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
3714 } else if (tx > xMax1) {
3719 } else if (ty > yMax1) {
3729 double GfxState::transformWidth(double w) {
3732 x = ctm[0] + ctm[2];
3733 y = ctm[1] + ctm[3];
3734 return w * sqrt(0.5 * (x * x + y * y));
3737 double GfxState::getTransformedFontSize() {
3738 double x1, y1, x2, y2;
3740 x1 = textMat[2] * fontSize;
3741 y1 = textMat[3] * fontSize;
3742 x2 = ctm[0] * x1 + ctm[2] * y1;
3743 y2 = ctm[1] * x1 + ctm[3] * y1;
3744 return sqrt(x2 * x2 + y2 * y2);
3747 void GfxState::getFontTransMat(double *m11, double *m12,
3748 double *m21, double *m22) {
3749 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
3750 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
3751 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
3752 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
3755 void GfxState::setCTM(double a, double b, double c,
3756 double d, double e, double f) {
3766 // avoid FP exceptions on badly messed up PDF files
3767 for (i = 0; i < 6; ++i) {
3768 if (ctm[i] > 1e10) {
3770 } else if (ctm[i] < -1e10) {
3776 void GfxState::concatCTM(double a, double b, double c,
3777 double d, double e, double f) {
3784 ctm[0] = a * a1 + b * c1;
3785 ctm[1] = a * b1 + b * d1;
3786 ctm[2] = c * a1 + d * c1;
3787 ctm[3] = c * b1 + d * d1;
3788 ctm[4] = e * a1 + f * c1 + ctm[4];
3789 ctm[5] = e * b1 + f * d1 + ctm[5];
3791 // avoid FP exceptions on badly messed up PDF files
3792 for (i = 0; i < 6; ++i) {
3793 if (ctm[i] > 1e10) {
3795 } else if (ctm[i] < -1e10) {
3801 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
3802 if (fillColorSpace) {
3803 delete fillColorSpace;
3805 fillColorSpace = colorSpace;
3808 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
3809 if (strokeColorSpace) {
3810 delete strokeColorSpace;
3812 strokeColorSpace = colorSpace;
3815 void GfxState::setFillPattern(GfxPattern *pattern) {
3819 fillPattern = pattern;
3822 void GfxState::setStrokePattern(GfxPattern *pattern) {
3823 if (strokePattern) {
3824 delete strokePattern;
3826 strokePattern = pattern;
3829 void GfxState::setLineDash(double *dash, int length, double start) {
3833 lineDashLength = length;
3834 lineDashStart = start;
3837 void GfxState::clearPath() {
3839 path = new GfxPath();
3842 void GfxState::clip() {
3843 double xMin, yMin, xMax, yMax, x, y;
3844 GfxSubpath *subpath;
3847 xMin = xMax = yMin = yMax = 0; // make gcc happy
3848 for (i = 0; i < path->getNumSubpaths(); ++i) {
3849 subpath = path->getSubpath(i);
3850 for (j = 0; j < subpath->getNumPoints(); ++j) {
3851 transform(subpath->getX(j), subpath->getY(j), &x, &y);
3852 if (i == 0 && j == 0) {
3858 } else if (x > xMax) {
3863 } else if (y > yMax) {
3869 if (xMin > clipXMin) {
3872 if (yMin > clipYMin) {
3875 if (xMax < clipXMax) {
3878 if (yMax < clipYMax) {
3883 void GfxState::textShift(double tx, double ty) {
3886 textTransformDelta(tx, ty, &dx, &dy);
3891 void GfxState::shift(double dx, double dy) {
3896 GfxState *GfxState::save() {
3900 newState->saved = this;
3904 GfxState *GfxState::restore() {
3910 // these attributes aren't saved/restored by the q/Q operators
3911 oldState->path = path;
3912 oldState->curX = curX;
3913 oldState->curY = curY;
3914 oldState->lineX = lineX;
3915 oldState->lineY = lineY;
3928 GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
3932 if (obj->isName()) {
3933 for (i = 0; i < nGfxBlendModeNames; ++i) {
3934 if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
3935 *mode = gfxBlendModeNames[i].mode;
3940 } else if (obj->isArray()) {
3941 for (i = 0; i < obj->arrayGetLength(); ++i) {
3942 obj->arrayGet(i, &obj2);
3943 if (!obj2.isName()) {
3947 for (j = 0; j < nGfxBlendModeNames; ++j) {
3948 if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
3950 *mode = gfxBlendModeNames[j].mode;
3956 *mode = gfxBlendNormal;