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;