1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
17 #include <string.h> // for memcpy()
26 //------------------------------------------------------------------------
28 static inline double clip01(double x) {
29 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
32 //------------------------------------------------------------------------
34 static char *gfxColorSpaceModeNames[] = {
48 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
50 //------------------------------------------------------------------------
52 //------------------------------------------------------------------------
54 GfxColorSpace::GfxColorSpace() {
57 GfxColorSpace::~GfxColorSpace() {
60 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
65 if (csObj->isName()) {
66 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
67 cs = new GfxDeviceGrayColorSpace();
68 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
69 cs = new GfxDeviceRGBColorSpace();
70 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
71 cs = new GfxDeviceCMYKColorSpace();
72 } else if (csObj->isName("Pattern")) {
73 cs = new GfxPatternColorSpace(NULL);
75 error(-1, "Bad color space '%s'", csObj->getName());
77 } else if (csObj->isArray()) {
78 csObj->arrayGet(0, &obj1);
79 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
80 cs = new GfxDeviceGrayColorSpace();
81 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
82 cs = new GfxDeviceRGBColorSpace();
83 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
84 cs = new GfxDeviceCMYKColorSpace();
85 } else if (obj1.isName("CalGray")) {
86 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
87 } else if (obj1.isName("CalRGB")) {
88 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
89 } else if (obj1.isName("Lab")) {
90 cs = GfxLabColorSpace::parse(csObj->getArray());
91 } else if (obj1.isName("ICCBased")) {
92 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
93 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
94 cs = GfxIndexedColorSpace::parse(csObj->getArray());
95 } else if (obj1.isName("Separation")) {
96 cs = GfxSeparationColorSpace::parse(csObj->getArray());
97 } else if (obj1.isName("DeviceN")) {
98 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
99 } else if (obj1.isName("Pattern")) {
100 cs = GfxPatternColorSpace::parse(csObj->getArray());
102 error(-1, "Bad color space");
106 error(-1, "Bad color space - expected name or array");
111 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
115 for (i = 0; i < getNComps(); ++i) {
121 int GfxColorSpace::getNumColorSpaceModes() {
122 return nGfxColorSpaceModes;
125 char *GfxColorSpace::getColorSpaceModeName(int idx) {
126 return gfxColorSpaceModeNames[idx];
129 //------------------------------------------------------------------------
130 // GfxDeviceGrayColorSpace
131 //------------------------------------------------------------------------
133 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
136 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
139 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
140 return new GfxDeviceGrayColorSpace();
143 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
144 *gray = clip01(color->c[0]);
147 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
148 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
151 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
152 cmyk->c = cmyk->m = cmyk->y = 0;
153 cmyk->k = clip01(1 - color->c[0]);
156 //------------------------------------------------------------------------
157 // GfxCalGrayColorSpace
158 //------------------------------------------------------------------------
160 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
161 whiteX = whiteY = whiteZ = 1;
162 blackX = blackY = blackZ = 0;
166 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
169 GfxColorSpace *GfxCalGrayColorSpace::copy() {
170 GfxCalGrayColorSpace *cs;
172 cs = new GfxCalGrayColorSpace();
183 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
184 GfxCalGrayColorSpace *cs;
185 Object obj1, obj2, obj3;
188 if (!obj1.isDict()) {
189 error(-1, "Bad CalGray color space");
193 cs = new GfxCalGrayColorSpace();
194 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
195 obj2.arrayGetLength() == 3) {
196 obj2.arrayGet(0, &obj3);
197 cs->whiteX = obj3.getNum();
199 obj2.arrayGet(1, &obj3);
200 cs->whiteY = obj3.getNum();
202 obj2.arrayGet(2, &obj3);
203 cs->whiteZ = obj3.getNum();
207 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
208 obj2.arrayGetLength() == 3) {
209 obj2.arrayGet(0, &obj3);
210 cs->blackX = obj3.getNum();
212 obj2.arrayGet(1, &obj3);
213 cs->blackY = obj3.getNum();
215 obj2.arrayGet(2, &obj3);
216 cs->blackZ = obj3.getNum();
220 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
221 cs->gamma = obj2.getNum();
228 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
229 *gray = clip01(color->c[0]);
232 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
233 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
236 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
237 cmyk->c = cmyk->m = cmyk->y = 0;
238 cmyk->k = clip01(1 - color->c[0]);
241 //------------------------------------------------------------------------
242 // GfxDeviceRGBColorSpace
243 //------------------------------------------------------------------------
245 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
248 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
251 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
252 return new GfxDeviceRGBColorSpace();
255 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
256 *gray = clip01(0.299 * color->c[0] +
257 0.587 * color->c[1] +
258 0.114 * color->c[2]);
261 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
262 rgb->r = clip01(color->c[0]);
263 rgb->g = clip01(color->c[1]);
264 rgb->b = clip01(color->c[2]);
267 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
270 c = clip01(1 - color->c[0]);
271 m = clip01(1 - color->c[1]);
272 y = clip01(1 - color->c[2]);
286 //------------------------------------------------------------------------
287 // GfxCalRGBColorSpace
288 //------------------------------------------------------------------------
290 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
291 whiteX = whiteY = whiteZ = 1;
292 blackX = blackY = blackZ = 0;
293 gammaR = gammaG = gammaB = 1;
294 mat[0] = 1; mat[1] = 0; mat[2] = 0;
295 mat[3] = 0; mat[4] = 1; mat[5] = 0;
296 mat[6] = 0; mat[7] = 0; mat[8] = 1;
299 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
302 GfxColorSpace *GfxCalRGBColorSpace::copy() {
303 GfxCalRGBColorSpace *cs;
306 cs = new GfxCalRGBColorSpace();
316 for (i = 0; i < 9; ++i) {
322 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
323 GfxCalRGBColorSpace *cs;
324 Object obj1, obj2, obj3;
328 if (!obj1.isDict()) {
329 error(-1, "Bad CalRGB color space");
333 cs = new GfxCalRGBColorSpace();
334 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
335 obj2.arrayGetLength() == 3) {
336 obj2.arrayGet(0, &obj3);
337 cs->whiteX = obj3.getNum();
339 obj2.arrayGet(1, &obj3);
340 cs->whiteY = obj3.getNum();
342 obj2.arrayGet(2, &obj3);
343 cs->whiteZ = obj3.getNum();
347 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
348 obj2.arrayGetLength() == 3) {
349 obj2.arrayGet(0, &obj3);
350 cs->blackX = obj3.getNum();
352 obj2.arrayGet(1, &obj3);
353 cs->blackY = obj3.getNum();
355 obj2.arrayGet(2, &obj3);
356 cs->blackZ = obj3.getNum();
360 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
361 obj2.arrayGetLength() == 3) {
362 obj2.arrayGet(0, &obj3);
363 cs->gammaR = obj3.getNum();
365 obj2.arrayGet(1, &obj3);
366 cs->gammaG = obj3.getNum();
368 obj2.arrayGet(2, &obj3);
369 cs->gammaB = obj3.getNum();
373 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
374 obj2.arrayGetLength() == 9) {
375 for (i = 0; i < 9; ++i) {
376 obj2.arrayGet(i, &obj3);
377 cs->mat[i] = obj3.getNum();
386 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
387 *gray = clip01(0.299 * color->c[0] +
388 0.587 * color->c[1] +
389 0.114 * color->c[2]);
392 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
393 rgb->r = clip01(color->c[0]);
394 rgb->g = clip01(color->c[1]);
395 rgb->b = clip01(color->c[2]);
398 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
401 c = clip01(1 - color->c[0]);
402 m = clip01(1 - color->c[1]);
403 y = clip01(1 - color->c[2]);
417 //------------------------------------------------------------------------
418 // GfxDeviceCMYKColorSpace
419 //------------------------------------------------------------------------
421 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
424 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
427 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
428 return new GfxDeviceCMYKColorSpace();
431 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
432 *gray = clip01(1 - color->c[3]
433 - 0.299 * color->c[0]
434 - 0.587 * color->c[1]
435 - 0.114 * color->c[2]);
438 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
439 double c,m,y,k,white;
445 rgb->r = white - (c*white);
446 rgb->g = white - (m*white);
447 rgb->b = white - (y*white);
449 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
450 double c, m, y, aw, ac, am, ay, ar, ag, ab;
452 c = clip01(color->c[0] + color->c[3]);
453 m = clip01(color->c[1] + color->c[3]);
454 y = clip01(color->c[2] + color->c[3]);
455 aw = (1-c) * (1-m) * (1-y);
456 ac = c * (1-m) * (1-y);
457 am = (1-c) * m * (1-y);
458 ay = (1-c) * (1-m) * y;
462 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
463 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
464 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag + 0.4863*ab);
466 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
468 float c = color->c[0];
469 float m = color->c[1];
470 float y = color->c[2];
471 float k = color->c[3];
472 convert_cmyk2rgb(c,m,y,k, &r,&g,&b);
478 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
479 cmyk->c = clip01(color->c[0]);
480 cmyk->m = clip01(color->c[1]);
481 cmyk->y = clip01(color->c[2]);
482 cmyk->k = clip01(color->c[3]);
485 //------------------------------------------------------------------------
487 //------------------------------------------------------------------------
489 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
490 // Language Reference, Third Edition.
491 static double xyzrgb[3][3] = {
492 { 3.240449, -1.537136, -0.498531 },
493 { -0.969265, 1.876011, 0.041556 },
494 { 0.055643, -0.204026, 1.057229 }
497 GfxLabColorSpace::GfxLabColorSpace() {
498 whiteX = whiteY = whiteZ = 1;
499 blackX = blackY = blackZ = 0;
504 GfxLabColorSpace::~GfxLabColorSpace() {
507 GfxColorSpace *GfxLabColorSpace::copy() {
508 GfxLabColorSpace *cs;
510 cs = new GfxLabColorSpace();
527 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
528 GfxLabColorSpace *cs;
529 Object obj1, obj2, obj3;
532 if (!obj1.isDict()) {
533 error(-1, "Bad Lab color space");
537 cs = new GfxLabColorSpace();
538 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
539 obj2.arrayGetLength() == 3) {
540 obj2.arrayGet(0, &obj3);
541 cs->whiteX = obj3.getNum();
543 obj2.arrayGet(1, &obj3);
544 cs->whiteY = obj3.getNum();
546 obj2.arrayGet(2, &obj3);
547 cs->whiteZ = obj3.getNum();
551 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
552 obj2.arrayGetLength() == 3) {
553 obj2.arrayGet(0, &obj3);
554 cs->blackX = obj3.getNum();
556 obj2.arrayGet(1, &obj3);
557 cs->blackY = obj3.getNum();
559 obj2.arrayGet(2, &obj3);
560 cs->blackZ = obj3.getNum();
564 if (obj1.dictLookup("Range", &obj2)->isArray() &&
565 obj2.arrayGetLength() == 4) {
566 obj2.arrayGet(0, &obj3);
567 cs->aMin = obj3.getNum();
569 obj2.arrayGet(1, &obj3);
570 cs->aMax = obj3.getNum();
572 obj2.arrayGet(2, &obj3);
573 cs->bMin = obj3.getNum();
575 obj2.arrayGet(3, &obj3);
576 cs->bMax = obj3.getNum();
582 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
583 xyzrgb[0][1] * cs->whiteY +
584 xyzrgb[0][2] * cs->whiteZ);
585 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
586 xyzrgb[1][1] * cs->whiteY +
587 xyzrgb[1][2] * cs->whiteZ);
588 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
589 xyzrgb[2][1] * cs->whiteY +
590 xyzrgb[2][2] * cs->whiteZ);
595 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
599 *gray = clip01(0.299 * rgb.r +
604 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
609 // convert L*a*b* to CIE 1931 XYZ color space
610 t1 = (color->c[0] + 16) / 116;
611 t2 = t1 + color->c[1] / 500;
612 if (t2 >= (6.0 / 29.0)) {
615 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
618 if (t1 >= (6.0 / 29.0)) {
621 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
624 t2 = t1 - color->c[2] / 200;
625 if (t2 >= (6.0 / 29.0)) {
628 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
632 // convert XYZ to RGB, including gamut mapping and gamma correction
633 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
634 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
635 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
636 rgb->r = pow(clip01(r * kr), 0.5);
637 rgb->g = pow(clip01(g * kg), 0.5);
638 rgb->b = pow(clip01(b * kb), 0.5);
641 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
646 c = clip01(1 - rgb.r);
647 m = clip01(1 - rgb.g);
648 y = clip01(1 - rgb.b);
662 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
665 decodeRange[0] = 100;
667 decodeRange[1] = aMax - aMin;
669 decodeRange[2] = bMax - bMin;
672 //------------------------------------------------------------------------
673 // GfxICCBasedColorSpace
674 //------------------------------------------------------------------------
676 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
677 Ref *iccProfileStreamA) {
680 iccProfileStream = *iccProfileStreamA;
681 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
682 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
685 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
689 GfxColorSpace *GfxICCBasedColorSpace::copy() {
690 GfxICCBasedColorSpace *cs;
693 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
694 for (i = 0; i < 4; ++i) {
695 cs->rangeMin[i] = rangeMin[i];
696 cs->rangeMax[i] = rangeMax[i];
701 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
702 GfxICCBasedColorSpace *cs;
703 Ref iccProfileStreamA;
707 Object obj1, obj2, obj3;
710 arr->getNF(1, &obj1);
712 iccProfileStreamA = obj1.getRef();
714 iccProfileStreamA.num = 0;
715 iccProfileStreamA.gen = 0;
719 if (!obj1.isStream()) {
720 error(-1, "Bad ICCBased color space (stream)");
724 dict = obj1.streamGetDict();
725 if (!dict->lookup("N", &obj2)->isInt()) {
726 error(-1, "Bad ICCBased color space (N)");
731 nCompsA = obj2.getInt();
733 if (dict->lookup("Alternate", &obj2)->isNull() ||
734 !(altA = GfxColorSpace::parse(&obj2))) {
737 altA = new GfxDeviceGrayColorSpace();
740 altA = new GfxDeviceRGBColorSpace();
743 altA = new GfxDeviceCMYKColorSpace();
746 error(-1, "Bad ICCBased color space - invalid N");
753 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
754 if (dict->lookup("Range", &obj2)->isArray() &&
755 obj2.arrayGetLength() == 2 * nCompsA) {
756 for (i = 0; i < nCompsA; ++i) {
757 obj2.arrayGet(2*i, &obj3);
758 cs->rangeMin[i] = obj3.getNum();
760 obj2.arrayGet(2*i+1, &obj3);
761 cs->rangeMax[i] = obj3.getNum();
770 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
771 alt->getGray(color, gray);
774 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
775 alt->getRGB(color, rgb);
778 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
779 alt->getCMYK(color, cmyk);
782 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
785 alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
788 // this is nominally correct, but some PDF files don't set the
789 // correct ranges in the ICCBased dict
792 for (i = 0; i < nComps; ++i) {
793 decodeLow[i] = rangeMin[i];
794 decodeRange[i] = rangeMax[i] - rangeMin[i];
799 //------------------------------------------------------------------------
800 // GfxIndexedColorSpace
801 //------------------------------------------------------------------------
803 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
806 indexHigh = indexHighA;
807 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
811 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
816 GfxColorSpace *GfxIndexedColorSpace::copy() {
817 GfxIndexedColorSpace *cs;
819 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
820 memcpy(cs->lookup, lookup,
821 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
825 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
826 GfxIndexedColorSpace *cs;
827 GfxColorSpace *baseA;
834 if (arr->getLength() != 4) {
835 error(-1, "Bad Indexed color space");
839 if (!(baseA = GfxColorSpace::parse(&obj1))) {
840 error(-1, "Bad Indexed color space (base color space)");
844 if (!arr->get(2, &obj1)->isInt()) {
845 error(-1, "Bad Indexed color space (hival)");
849 indexHighA = obj1.getInt();
850 if (indexHighA < 0 || indexHighA > 255) {
851 // the PDF spec requires indexHigh to be in [0,255] -- allowing
852 // values larger than 255 creates a security hole: if nComps *
853 // indexHigh is greater than 2^31, the loop below may overwrite
854 // past the end of the array
855 error(-1, "Bad Indexed color space (invalid indexHigh value)");
860 cs = new GfxIndexedColorSpace(baseA, indexHighA);
862 n = baseA->getNComps();
863 if (obj1.isStream()) {
865 for (i = 0; i <= indexHighA; ++i) {
866 for (j = 0; j < n; ++j) {
867 if ((x = obj1.streamGetChar()) == EOF) {
868 error(-1, "Bad Indexed color space (lookup table stream too short)");
871 cs->lookup[i*n + j] = (Guchar)x;
875 } else if (obj1.isString()) {
876 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
877 error(-1, "Bad Indexed color space (lookup table string too short)");
880 s = obj1.getString()->getCString();
881 for (i = 0; i <= indexHighA; ++i) {
882 for (j = 0; j < n; ++j) {
883 cs->lookup[i*n + j] = (Guchar)*s++;
887 error(-1, "Bad Indexed color space (lookup table)");
901 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
902 GfxColor *baseColor) {
904 double low[gfxColorMaxComps], range[gfxColorMaxComps];
907 n = base->getNComps();
908 base->getDefaultRanges(low, range, indexHigh);
909 p = &lookup[(int)(color->c[0] + 0.5) * n];
910 for (i = 0; i < n; ++i) {
911 baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
916 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
919 base->getGray(mapColorToBase(color, &color2), gray);
922 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
925 base->getRGB(mapColorToBase(color, &color2), rgb);
928 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
931 base->getCMYK(mapColorToBase(color, &color2), cmyk);
934 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
938 decodeRange[0] = maxImgPixel;
941 //------------------------------------------------------------------------
942 // GfxSeparationColorSpace
943 //------------------------------------------------------------------------
945 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
953 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
959 GfxColorSpace *GfxSeparationColorSpace::copy() {
960 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
963 //~ handle the 'All' and 'None' colorants
964 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
965 GfxSeparationColorSpace *cs;
971 if (arr->getLength() != 4) {
972 error(-1, "Bad Separation color space");
975 if (!arr->get(1, &obj1)->isName()) {
976 error(-1, "Bad Separation color space (name)");
979 nameA = new GString(obj1.getName());
982 if (!(altA = GfxColorSpace::parse(&obj1))) {
983 error(-1, "Bad Separation color space (alternate color space)");
988 if (!(funcA = Function::parse(&obj1))) {
992 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1005 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
1008 func->transform(color->c, color2.c);
1009 alt->getGray(&color2, gray);
1012 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1015 func->transform(color->c, color2.c);
1016 alt->getRGB(&color2, rgb);
1019 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1022 func->transform(color->c, color2.c);
1023 alt->getCMYK(&color2, cmyk);
1026 //------------------------------------------------------------------------
1027 // GfxDeviceNColorSpace
1028 //------------------------------------------------------------------------
1030 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1031 GfxColorSpace *altA,
1038 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1041 for (i = 0; i < nComps; ++i) {
1048 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1049 GfxDeviceNColorSpace *cs;
1052 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1053 for (i = 0; i < nComps; ++i) {
1054 cs->names[i] = names[i]->copy();
1059 //~ handle the 'None' colorant
1060 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1061 GfxDeviceNColorSpace *cs;
1063 GString *namesA[gfxColorMaxComps];
1064 GfxColorSpace *altA;
1069 if (arr->getLength() != 4 && arr->getLength() != 5) {
1070 error(-1, "Bad DeviceN color space");
1073 if (!arr->get(1, &obj1)->isArray()) {
1074 error(-1, "Bad DeviceN color space (names)");
1077 nCompsA = obj1.arrayGetLength();
1078 if (nCompsA > gfxColorMaxComps) {
1079 error(-1, "DeviceN color space with more than %d > %d components",
1080 nCompsA, gfxColorMaxComps);
1081 nCompsA = gfxColorMaxComps;
1083 for (i = 0; i < nCompsA; ++i) {
1084 if (!obj1.arrayGet(i, &obj2)->isName()) {
1085 error(-1, "Bad DeviceN color space (names)");
1089 namesA[i] = new GString(obj2.getName());
1094 if (!(altA = GfxColorSpace::parse(&obj1))) {
1095 error(-1, "Bad DeviceN color space (alternate color space)");
1100 if (!(funcA = Function::parse(&obj1))) {
1104 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1105 for (i = 0; i < nCompsA; ++i) {
1106 cs->names[i] = namesA[i];
1113 for (i = 0; i < nCompsA; ++i) {
1122 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1125 func->transform(color->c, color2.c);
1126 alt->getGray(&color2, gray);
1129 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1132 func->transform(color->c, color2.c);
1133 alt->getRGB(&color2, rgb);
1136 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1139 func->transform(color->c, color2.c);
1140 alt->getCMYK(&color2, cmyk);
1143 //------------------------------------------------------------------------
1144 // GfxPatternColorSpace
1145 //------------------------------------------------------------------------
1147 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1151 GfxPatternColorSpace::~GfxPatternColorSpace() {
1157 GfxColorSpace *GfxPatternColorSpace::copy() {
1158 return new GfxPatternColorSpace(under ? under->copy() :
1159 (GfxColorSpace *)NULL);
1162 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1163 GfxPatternColorSpace *cs;
1164 GfxColorSpace *underA;
1167 if (arr->getLength() != 1 && arr->getLength() != 2) {
1168 error(-1, "Bad Pattern color space");
1172 if (arr->getLength() == 2) {
1174 if (!(underA = GfxColorSpace::parse(&obj1))) {
1175 error(-1, "Bad Pattern color space (underlying color space)");
1181 cs = new GfxPatternColorSpace(underA);
1185 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1189 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1190 rgb->r = rgb->g = rgb->b = 0;
1193 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1194 cmyk->c = cmyk->m = cmyk->y = 0;
1198 //------------------------------------------------------------------------
1200 //------------------------------------------------------------------------
1202 GfxPattern::GfxPattern(int typeA) {
1206 GfxPattern::~GfxPattern() {
1209 GfxPattern *GfxPattern::parse(Object *obj) {
1210 GfxPattern *pattern;
1213 if (obj->isDict()) {
1214 obj->dictLookup("PatternType", &obj1);
1215 } else if (obj->isStream()) {
1216 obj->streamGetDict()->lookup("PatternType", &obj1);
1221 if (obj1.isInt() && obj1.getInt() == 1) {
1222 pattern = GfxTilingPattern::parse(obj);
1223 } else if (obj1.isInt() && obj1.getInt() == 2) {
1224 pattern = GfxShadingPattern::parse(obj);
1230 //------------------------------------------------------------------------
1232 //------------------------------------------------------------------------
1234 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1235 GfxTilingPattern *pat;
1237 int paintTypeA, tilingTypeA;
1238 double bboxA[4], matrixA[6];
1239 double xStepA, yStepA;
1244 if (!patObj->isStream()) {
1247 dict = patObj->streamGetDict();
1249 if (dict->lookup("PaintType", &obj1)->isInt()) {
1250 paintTypeA = obj1.getInt();
1253 error(-1, "Invalid or missing PaintType in pattern");
1256 if (dict->lookup("TilingType", &obj1)->isInt()) {
1257 tilingTypeA = obj1.getInt();
1260 error(-1, "Invalid or missing TilingType in pattern");
1263 bboxA[0] = bboxA[1] = 0;
1264 bboxA[2] = bboxA[3] = 1;
1265 if (dict->lookup("BBox", &obj1)->isArray() &&
1266 obj1.arrayGetLength() == 4) {
1267 for (i = 0; i < 4; ++i) {
1268 if (obj1.arrayGet(i, &obj2)->isNum()) {
1269 bboxA[i] = obj2.getNum();
1274 error(-1, "Invalid or missing BBox in pattern");
1277 if (dict->lookup("XStep", &obj1)->isNum()) {
1278 xStepA = obj1.getNum();
1281 error(-1, "Invalid or missing XStep in pattern");
1284 if (dict->lookup("YStep", &obj1)->isNum()) {
1285 yStepA = obj1.getNum();
1288 error(-1, "Invalid or missing YStep in pattern");
1291 if (!dict->lookup("Resources", &resDictA)->isDict()) {
1293 resDictA.initNull();
1294 error(-1, "Invalid or missing Resources in pattern");
1296 matrixA[0] = 1; matrixA[1] = 0;
1297 matrixA[2] = 0; matrixA[3] = 1;
1298 matrixA[4] = 0; matrixA[5] = 0;
1299 if (dict->lookup("Matrix", &obj1)->isArray() &&
1300 obj1.arrayGetLength() == 6) {
1301 for (i = 0; i < 6; ++i) {
1302 if (obj1.arrayGet(i, &obj2)->isNum()) {
1303 matrixA[i] = obj2.getNum();
1310 pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1311 &resDictA, matrixA, patObj);
1316 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1317 double *bboxA, double xStepA, double yStepA,
1318 Object *resDictA, double *matrixA,
1319 Object *contentStreamA):
1324 paintType = paintTypeA;
1325 tilingType = tilingTypeA;
1326 for (i = 0; i < 4; ++i) {
1331 resDictA->copy(&resDict);
1332 for (i = 0; i < 6; ++i) {
1333 matrix[i] = matrixA[i];
1335 contentStreamA->copy(&contentStream);
1338 GfxTilingPattern::~GfxTilingPattern() {
1340 contentStream.free();
1343 GfxPattern *GfxTilingPattern::copy() {
1344 return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1345 &resDict, matrix, &contentStream);
1348 //------------------------------------------------------------------------
1349 // GfxShadingPattern
1350 //------------------------------------------------------------------------
1352 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1354 GfxShading *shadingA;
1359 if (!patObj->isDict()) {
1362 dict = patObj->getDict();
1364 dict->lookup("Shading", &obj1);
1365 shadingA = GfxShading::parse(&obj1);
1371 matrixA[0] = 1; matrixA[1] = 0;
1372 matrixA[2] = 0; matrixA[3] = 1;
1373 matrixA[4] = 0; matrixA[5] = 0;
1374 if (dict->lookup("Matrix", &obj1)->isArray() &&
1375 obj1.arrayGetLength() == 6) {
1376 for (i = 0; i < 6; ++i) {
1377 if (obj1.arrayGet(i, &obj2)->isNum()) {
1378 matrixA[i] = obj2.getNum();
1385 return new GfxShadingPattern(shadingA, matrixA);
1388 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1394 for (i = 0; i < 6; ++i) {
1395 matrix[i] = matrixA[i];
1399 GfxShadingPattern::~GfxShadingPattern() {
1403 GfxPattern *GfxShadingPattern::copy() {
1404 return new GfxShadingPattern(shading->copy(), matrix);
1407 //------------------------------------------------------------------------
1409 //------------------------------------------------------------------------
1411 GfxShading::GfxShading(int typeA) {
1416 GfxShading::GfxShading(GfxShading *shading) {
1419 type = shading->type;
1420 colorSpace = shading->colorSpace->copy();
1421 for (i = 0; i < gfxColorMaxComps; ++i) {
1422 background.c[i] = shading->background.c[i];
1424 hasBackground = shading->hasBackground;
1425 xMin = shading->xMin;
1426 yMin = shading->yMin;
1427 xMax = shading->xMax;
1428 yMax = shading->yMax;
1429 hasBBox = shading->hasBBox;
1432 GfxShading::~GfxShading() {
1438 GfxShading *GfxShading::parse(Object *obj) {
1439 GfxShading *shading;
1444 if (obj->isDict()) {
1445 dict = obj->getDict();
1446 } else if (obj->isStream()) {
1447 dict = obj->streamGetDict();
1452 if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1453 error(-1, "Invalid ShadingType in shading dictionary");
1457 typeA = obj1.getInt();
1462 shading = GfxFunctionShading::parse(dict);
1465 shading = GfxAxialShading::parse(dict);
1468 shading = GfxRadialShading::parse(dict);
1471 error(-1, "Unimplemented shading type %d", typeA);
1481 GBool GfxShading::init(Dict *dict) {
1485 dict->lookup("ColorSpace", &obj1);
1486 if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1487 error(-1, "Bad color space in shading dictionary");
1493 for (i = 0; i < gfxColorMaxComps; ++i) {
1494 background.c[i] = 0;
1496 hasBackground = gFalse;
1497 if (dict->lookup("Background", &obj1)->isArray()) {
1498 if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1499 hasBackground = gTrue;
1500 for (i = 0; i < colorSpace->getNComps(); ++i) {
1501 background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1505 error(-1, "Bad Background in shading dictionary");
1510 xMin = yMin = xMax = yMax = 0;
1512 if (dict->lookup("BBox", &obj1)->isArray()) {
1513 if (obj1.arrayGetLength() == 4) {
1515 xMin = obj1.arrayGet(0, &obj2)->getNum();
1517 yMin = obj1.arrayGet(1, &obj2)->getNum();
1519 xMax = obj1.arrayGet(2, &obj2)->getNum();
1521 yMax = obj1.arrayGet(3, &obj2)->getNum();
1524 error(-1, "Bad BBox in shading dictionary");
1532 //------------------------------------------------------------------------
1533 // GfxFunctionShading
1534 //------------------------------------------------------------------------
1536 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1537 double x1A, double y1A,
1539 Function **funcsA, int nFuncsA):
1548 for (i = 0; i < 6; ++i) {
1549 matrix[i] = matrixA[i];
1552 for (i = 0; i < nFuncs; ++i) {
1553 funcs[i] = funcsA[i];
1557 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1566 for (i = 0; i < 6; ++i) {
1567 matrix[i] = shading->matrix[i];
1569 nFuncs = shading->nFuncs;
1570 for (i = 0; i < nFuncs; ++i) {
1571 funcs[i] = shading->funcs[i]->copy();
1575 GfxFunctionShading::~GfxFunctionShading() {
1578 for (i = 0; i < nFuncs; ++i) {
1583 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1584 GfxFunctionShading *shading;
1585 double x0A, y0A, x1A, y1A;
1587 Function *funcsA[gfxColorMaxComps];
1594 if (dict->lookup("Domain", &obj1)->isArray() &&
1595 obj1.arrayGetLength() == 4) {
1596 x0A = obj1.arrayGet(0, &obj2)->getNum();
1598 y0A = obj1.arrayGet(1, &obj2)->getNum();
1600 x1A = obj1.arrayGet(2, &obj2)->getNum();
1602 y1A = obj1.arrayGet(3, &obj2)->getNum();
1607 matrixA[0] = 1; matrixA[1] = 0;
1608 matrixA[2] = 0; matrixA[3] = 1;
1609 matrixA[4] = 0; matrixA[5] = 0;
1610 if (dict->lookup("Matrix", &obj1)->isArray() &&
1611 obj1.arrayGetLength() == 6) {
1612 matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1614 matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1616 matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1618 matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1620 matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1622 matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1627 dict->lookup("Function", &obj1);
1628 if (obj1.isArray()) {
1629 nFuncsA = obj1.arrayGetLength();
1630 if (nFuncsA > gfxColorMaxComps) {
1631 error(-1, "Invalid Function array in shading dictionary");
1634 for (i = 0; i < nFuncsA; ++i) {
1635 obj1.arrayGet(i, &obj2);
1636 if (!(funcsA[i] = Function::parse(&obj2))) {
1643 if (!(funcsA[0] = Function::parse(&obj1))) {
1649 shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1651 if (!shading->init(dict)) {
1664 GfxShading *GfxFunctionShading::copy() {
1665 return new GfxFunctionShading(this);
1668 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1674 for (i = 0; i < nFuncs; ++i) {
1675 funcs[i]->transform(in, &color->c[i]);
1679 //------------------------------------------------------------------------
1681 //------------------------------------------------------------------------
1683 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1684 double x1A, double y1A,
1685 double t0A, double t1A,
1686 Function **funcsA, int nFuncsA,
1687 GBool extend0A, GBool extend1A):
1699 for (i = 0; i < nFuncs; ++i) {
1700 funcs[i] = funcsA[i];
1706 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1717 nFuncs = shading->nFuncs;
1718 for (i = 0; i < nFuncs; ++i) {
1719 funcs[i] = shading->funcs[i]->copy();
1721 extend0 = shading->extend0;
1722 extend1 = shading->extend1;
1725 GfxAxialShading::~GfxAxialShading() {
1728 for (i = 0; i < nFuncs; ++i) {
1733 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1734 GfxAxialShading *shading;
1735 double x0A, y0A, x1A, y1A;
1737 Function *funcsA[gfxColorMaxComps];
1739 GBool extend0A, extend1A;
1743 x0A = y0A = x1A = y1A = 0;
1744 if (dict->lookup("Coords", &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();
1755 error(-1, "Missing or invalid Coords in shading dictionary");
1762 if (dict->lookup("Domain", &obj1)->isArray() &&
1763 obj1.arrayGetLength() == 2) {
1764 t0A = obj1.arrayGet(0, &obj2)->getNum();
1766 t1A = obj1.arrayGet(1, &obj2)->getNum();
1771 dict->lookup("Function", &obj1);
1772 if (obj1.isArray()) {
1773 nFuncsA = obj1.arrayGetLength();
1774 if (nFuncsA > gfxColorMaxComps) {
1775 error(-1, "Invalid Function array in shading dictionary");
1778 for (i = 0; i < nFuncsA; ++i) {
1779 obj1.arrayGet(i, &obj2);
1780 if (!(funcsA[i] = Function::parse(&obj2))) {
1789 if (!(funcsA[0] = Function::parse(&obj1))) {
1796 extend0A = extend1A = gFalse;
1797 if (dict->lookup("Extend", &obj1)->isArray() &&
1798 obj1.arrayGetLength() == 2) {
1799 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1801 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1806 shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1807 funcsA, nFuncsA, extend0A, extend1A);
1808 if (!shading->init(dict)) {
1818 GfxShading *GfxAxialShading::copy() {
1819 return new GfxAxialShading(this);
1822 void GfxAxialShading::getColor(double t, GfxColor *color) {
1825 // NB: there can be one function with n outputs or n functions with
1826 // one output each (where n = number of color components)
1827 for (i = 0; i < nFuncs; ++i) {
1828 funcs[i]->transform(&t, &color->c[i]);
1832 //------------------------------------------------------------------------
1834 //------------------------------------------------------------------------
1836 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1837 double x1A, double y1A, double r1A,
1838 double t0A, double t1A,
1839 Function **funcsA, int nFuncsA,
1840 GBool extend0A, GBool extend1A):
1854 for (i = 0; i < nFuncs; ++i) {
1855 funcs[i] = funcsA[i];
1861 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1874 nFuncs = shading->nFuncs;
1875 for (i = 0; i < nFuncs; ++i) {
1876 funcs[i] = shading->funcs[i]->copy();
1878 extend0 = shading->extend0;
1879 extend1 = shading->extend1;
1882 GfxRadialShading::~GfxRadialShading() {
1885 for (i = 0; i < nFuncs; ++i) {
1890 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1891 GfxRadialShading *shading;
1892 double x0A, y0A, r0A, x1A, y1A, r1A;
1894 Function *funcsA[gfxColorMaxComps];
1896 GBool extend0A, extend1A;
1900 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1901 if (dict->lookup("Coords", &obj1)->isArray() &&
1902 obj1.arrayGetLength() == 6) {
1903 x0A = obj1.arrayGet(0, &obj2)->getNum();
1905 y0A = obj1.arrayGet(1, &obj2)->getNum();
1907 r0A = obj1.arrayGet(2, &obj2)->getNum();
1909 x1A = obj1.arrayGet(3, &obj2)->getNum();
1911 y1A = obj1.arrayGet(4, &obj2)->getNum();
1913 r1A = obj1.arrayGet(5, &obj2)->getNum();
1916 error(-1, "Missing or invalid Coords in shading dictionary");
1923 if (dict->lookup("Domain", &obj1)->isArray() &&
1924 obj1.arrayGetLength() == 2) {
1925 t0A = obj1.arrayGet(0, &obj2)->getNum();
1927 t1A = obj1.arrayGet(1, &obj2)->getNum();
1932 dict->lookup("Function", &obj1);
1933 if (obj1.isArray()) {
1934 nFuncsA = obj1.arrayGetLength();
1935 if (nFuncsA > gfxColorMaxComps) {
1936 error(-1, "Invalid Function array in shading dictionary");
1939 for (i = 0; i < nFuncsA; ++i) {
1940 obj1.arrayGet(i, &obj2);
1941 if (!(funcsA[i] = Function::parse(&obj2))) {
1950 if (!(funcsA[0] = Function::parse(&obj1))) {
1957 extend0A = extend1A = gFalse;
1958 if (dict->lookup("Extend", &obj1)->isArray() &&
1959 obj1.arrayGetLength() == 2) {
1960 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1962 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1967 shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1968 funcsA, nFuncsA, extend0A, extend1A);
1969 if (!shading->init(dict)) {
1979 GfxShading *GfxRadialShading::copy() {
1980 return new GfxRadialShading(this);
1983 void GfxRadialShading::getColor(double t, GfxColor *color) {
1986 // NB: there can be one function with n outputs or n functions with
1987 // one output each (where n = number of color components)
1988 for (i = 0; i < nFuncs; ++i) {
1989 funcs[i]->transform(&t, &color->c[i]);
1993 //------------------------------------------------------------------------
1995 //------------------------------------------------------------------------
1997 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1998 GfxColorSpace *colorSpaceA) {
1999 GfxIndexedColorSpace *indexedCS;
2000 GfxSeparationColorSpace *sepCS;
2001 int maxPixel, indexHigh;
2005 double x[gfxColorMaxComps];
2006 double y[gfxColorMaxComps];
2008 int maxPixelForAlloc;
2012 // bits per component and color space
2014 maxPixel = (1 << bits) - 1;
2015 maxPixelForAlloc = (1 << (bits>8?bits:8));
2016 colorSpace = colorSpaceA;
2019 if (decode->isNull()) {
2020 nComps = colorSpace->getNComps();
2021 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2022 } else if (decode->isArray()) {
2023 nComps = decode->arrayGetLength() / 2;
2024 if (nComps != colorSpace->getNComps()) {
2027 for (i = 0; i < nComps; ++i) {
2028 decode->arrayGet(2*i, &obj);
2032 decodeLow[i] = obj.getNum();
2034 decode->arrayGet(2*i+1, &obj);
2038 decodeRange[i] = obj.getNum() - decodeLow[i];
2045 // Construct a lookup table -- this stores pre-computed decoded
2046 // values for each component, i.e., the result of applying the
2047 // decode mapping to each possible image pixel component value.
2049 // Optimization: for Indexed and Separation color spaces (which have
2050 // only one component), we store color values in the lookup table
2051 // rather than component values.
2054 if (colorSpace->getMode() == csIndexed) {
2055 // Note that indexHigh may not be the same as maxPixel --
2056 // Distiller will remove unused palette entries, resulting in
2057 // indexHigh < maxPixel.
2058 indexedCS = (GfxIndexedColorSpace *)colorSpace;
2059 colorSpace2 = indexedCS->getBase();
2060 indexHigh = indexedCS->getIndexHigh();
2061 nComps2 = colorSpace2->getNComps();
2062 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2063 lookup2 = indexedCS->getLookup();
2064 colorSpace2->getDefaultRanges(x, y, indexHigh);
2065 for (i = 0; i <= maxPixel; ++i) {
2066 j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2069 } else if (j > indexHigh) {
2072 for (k = 0; k < nComps2; ++k) {
2073 lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2076 } else if (colorSpace->getMode() == csSeparation) {
2077 sepCS = (GfxSeparationColorSpace *)colorSpace;
2078 colorSpace2 = sepCS->getAlt();
2079 nComps2 = colorSpace2->getNComps();
2080 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2081 sepFunc = sepCS->getFunc();
2082 for (i = 0; i <= maxPixel; ++i) {
2083 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2084 sepFunc->transform(x, y);
2085 for (k = 0; k < nComps2; ++k) {
2086 lookup[i*nComps2 + k] = y[k];
2090 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
2091 for (i = 0; i <= maxPixel; ++i) {
2092 for (k = 0; k < nComps; ++k) {
2093 lookup[i*nComps + k] = decodeLow[k] +
2094 (i * decodeRange[k]) / maxPixel;
2107 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2110 colorSpace = colorMap->colorSpace->copy();
2111 bits = colorMap->bits;
2112 nComps = colorMap->nComps;
2113 nComps2 = colorMap->nComps2;
2117 if (colorSpace->getMode() == csIndexed) {
2118 colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2119 n = n * nComps2 * sizeof(double);
2120 } else if (colorSpace->getMode() == csSeparation) {
2121 colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2122 n = n * nComps2 * sizeof(double);
2124 n = n * nComps * sizeof(double);
2126 lookup = (double *)gmalloc(n);
2127 memcpy(lookup, colorMap->lookup, n);
2128 for (i = 0; i < nComps; ++i) {
2129 decodeLow[i] = colorMap->decodeLow[i];
2130 decodeRange[i] = colorMap->decodeRange[i];
2135 GfxImageColorMap::~GfxImageColorMap() {
2140 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2146 p = &lookup[x[0] * nComps2];
2147 for (i = 0; i < nComps2; ++i) {
2150 colorSpace2->getGray(&color, gray);
2152 for (i = 0; i < nComps; ++i) {
2153 color.c[i] = lookup[x[i] * nComps + i];
2155 colorSpace->getGray(&color, gray);
2159 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2165 p = &lookup[x[0] * nComps2];
2166 for (i = 0; i < nComps2; ++i) {
2169 colorSpace2->getRGB(&color, rgb);
2171 for (i = 0; i < nComps; ++i) {
2172 color.c[i] = lookup[x[i] * nComps + i];
2174 colorSpace->getRGB(&color, rgb);
2178 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2184 p = &lookup[x[0] * nComps2];
2185 for (i = 0; i < nComps2; ++i) {
2188 colorSpace2->getCMYK(&color, cmyk);
2190 for (i = 0; i < nComps; ++i) {
2191 color.c[i] = lookup[x[i] * nComps + i];
2193 colorSpace->getCMYK(&color, cmyk);
2197 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2200 maxPixel = (1 << bits) - 1;
2201 for (i = 0; i < nComps; ++i) {
2202 color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2206 //------------------------------------------------------------------------
2207 // GfxSubpath and GfxPath
2208 //------------------------------------------------------------------------
2210 GfxSubpath::GfxSubpath(double x1, double y1) {
2212 x = (double *)gmalloc(size * sizeof(double));
2213 y = (double *)gmalloc(size * sizeof(double));
2214 curve = (GBool *)gmalloc(size * sizeof(GBool));
2222 GfxSubpath::~GfxSubpath() {
2229 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2230 size = subpath->size;
2232 x = (double *)gmalloc(size * sizeof(double));
2233 y = (double *)gmalloc(size * sizeof(double));
2234 curve = (GBool *)gmalloc(size * sizeof(GBool));
2235 memcpy(x, subpath->x, n * sizeof(double));
2236 memcpy(y, subpath->y, n * sizeof(double));
2237 memcpy(curve, subpath->curve, n * sizeof(GBool));
2238 closed = subpath->closed;
2241 void GfxSubpath::lineTo(double x1, double y1) {
2244 x = (double *)grealloc(x, size * sizeof(double));
2245 y = (double *)grealloc(y, size * sizeof(double));
2246 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2254 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2255 double x3, double y3) {
2258 x = (double *)grealloc(x, size * sizeof(double));
2259 y = (double *)grealloc(y, size * sizeof(double));
2260 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2268 curve[n] = curve[n+1] = gTrue;
2269 curve[n+2] = gFalse;
2273 void GfxSubpath::close() {
2274 if (x[n-1] != x[0] || y[n-1] != y[0]) {
2280 void GfxSubpath::offset(double dx, double dy) {
2283 for (i = 0; i < n; ++i) {
2289 GfxPath::GfxPath() {
2293 firstX = firstY = 0;
2294 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2297 GfxPath::~GfxPath() {
2300 for (i = 0; i < n; ++i)
2306 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2307 GfxSubpath **subpaths1, int n1, int size1) {
2310 justMoved = justMoved1;
2315 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2316 for (i = 0; i < n; ++i)
2317 subpaths[i] = subpaths1[i]->copy();
2320 void GfxPath::moveTo(double x, double y) {
2326 void GfxPath::lineTo(double x, double y) {
2330 subpaths = (GfxSubpath **)
2331 grealloc(subpaths, size * sizeof(GfxSubpath *));
2333 subpaths[n] = new GfxSubpath(firstX, firstY);
2337 subpaths[n-1]->lineTo(x, y);
2340 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2341 double x3, double y3) {
2345 subpaths = (GfxSubpath **)
2346 grealloc(subpaths, size * sizeof(GfxSubpath *));
2348 subpaths[n] = new GfxSubpath(firstX, firstY);
2352 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2355 void GfxPath::close() {
2356 // this is necessary to handle the pathological case of
2357 // moveto/closepath/clip, which defines an empty clipping region
2361 subpaths = (GfxSubpath **)
2362 grealloc(subpaths, size * sizeof(GfxSubpath *));
2364 subpaths[n] = new GfxSubpath(firstX, firstY);
2368 subpaths[n-1]->close();
2371 void GfxPath::append(GfxPath *path) {
2374 if (n + path->n > size) {
2376 subpaths = (GfxSubpath **)
2377 grealloc(subpaths, size * sizeof(GfxSubpath *));
2379 for (i = 0; i < path->n; ++i) {
2380 subpaths[n++] = path->subpaths[i]->copy();
2385 void GfxPath::offset(double dx, double dy) {
2388 for (i = 0; i < n; ++i) {
2389 subpaths[i]->offset(dx, dy);
2393 //------------------------------------------------------------------------
2395 //------------------------------------------------------------------------
2397 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2398 int rotate, GBool upsideDown) {
2409 ctm[1] = upsideDown ? ky : -ky;
2413 ctm[5] = ky * (upsideDown ? -px1 : px2);
2414 pageWidth = kx * (py2 - py1);
2415 pageHeight = ky * (px2 - px1);
2416 } else if (rotate == 180) {
2420 ctm[3] = upsideDown ? ky : -ky;
2422 ctm[5] = ky * (upsideDown ? -py1 : py2);
2423 pageWidth = kx * (px2 - px1);
2424 pageHeight = ky * (py2 - py1);
2425 } else if (rotate == 270) {
2427 ctm[1] = upsideDown ? -ky : ky;
2431 ctm[5] = ky * (upsideDown ? px2 : -px1);
2432 pageWidth = kx * (py2 - py1);
2433 pageHeight = ky * (px2 - px1);
2438 ctm[3] = upsideDown ? -ky : ky;
2440 ctm[5] = ky * (upsideDown ? py2 : -py1);
2441 pageWidth = kx * (px2 - px1);
2442 pageHeight = ky * (py2 - py1);
2445 fillColorSpace = new GfxDeviceGrayColorSpace();
2446 strokeColorSpace = new GfxDeviceGrayColorSpace();
2448 strokeColor.c[0] = 0;
2450 strokePattern = NULL;
2465 textMat[0] = 1; textMat[1] = 0;
2466 textMat[2] = 0; textMat[3] = 1;
2467 textMat[4] = 0; textMat[5] = 0;
2475 path = new GfxPath();
2481 clipXMax = pageWidth;
2482 clipYMax = pageHeight;
2487 GfxState::~GfxState() {
2488 if (fillColorSpace) {
2489 delete fillColorSpace;
2491 if (strokeColorSpace) {
2492 delete strokeColorSpace;
2497 if (strokePattern) {
2498 delete strokePattern;
2502 // this gets set to NULL by restore()
2511 GfxState::GfxState(GfxState *state) {
2512 memcpy(this, state, sizeof(GfxState));
2513 if (fillColorSpace) {
2514 fillColorSpace = state->fillColorSpace->copy();
2516 if (strokeColorSpace) {
2517 strokeColorSpace = state->strokeColorSpace->copy();
2520 fillPattern = state->fillPattern->copy();
2522 if (strokePattern) {
2523 strokePattern = state->strokePattern->copy();
2525 if (lineDashLength > 0) {
2526 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2527 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2532 void GfxState::setPath(GfxPath *pathA) {
2537 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2538 double *xMax, double *yMax) {
2540 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2543 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2544 ictm[0] = ctm[3] * det;
2545 ictm[1] = -ctm[1] * det;
2546 ictm[2] = -ctm[2] * det;
2547 ictm[3] = ctm[0] * det;
2548 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2549 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2551 // transform all four corners of the clip bbox; find the min and max
2553 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2554 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2555 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2556 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2559 } else if (tx > xMax1) {
2564 } else if (ty > yMax1) {
2567 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2568 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2571 } else if (tx > xMax1) {
2576 } else if (ty > yMax1) {
2579 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2580 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2583 } else if (tx > xMax1) {
2588 } else if (ty > yMax1) {
2598 double GfxState::transformWidth(double w) {
2601 x = ctm[0] + ctm[2];
2602 y = ctm[1] + ctm[3];
2603 return w * sqrt(0.5 * (x * x + y * y));
2606 double GfxState::getTransformedFontSize() {
2607 double x1, y1, x2, y2;
2609 x1 = textMat[2] * fontSize;
2610 y1 = textMat[3] * fontSize;
2611 x2 = ctm[0] * x1 + ctm[2] * y1;
2612 y2 = ctm[1] * x1 + ctm[3] * y1;
2613 return sqrt(x2 * x2 + y2 * y2);
2616 void GfxState::getFontTransMat(double *m11, double *m12,
2617 double *m21, double *m22) {
2618 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2619 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2620 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2621 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2624 void GfxState::setCTM(double a, double b, double c,
2625 double d, double e, double f) {
2635 // avoid FP exceptions on badly messed up PDF files
2636 for (i = 0; i < 6; ++i) {
2637 if (ctm[i] > 1e10) {
2639 } else if (ctm[i] < -1e10) {
2645 void GfxState::concatCTM(double a, double b, double c,
2646 double d, double e, double f) {
2653 ctm[0] = a * a1 + b * c1;
2654 ctm[1] = a * b1 + b * d1;
2655 ctm[2] = c * a1 + d * c1;
2656 ctm[3] = c * b1 + d * d1;
2657 ctm[4] = e * a1 + f * c1 + ctm[4];
2658 ctm[5] = e * b1 + f * d1 + ctm[5];
2660 // avoid FP exceptions on badly messed up PDF files
2661 for (i = 0; i < 6; ++i) {
2662 if (ctm[i] > 1e10) {
2664 } else if (ctm[i] < -1e10) {
2670 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2671 if (fillColorSpace) {
2672 delete fillColorSpace;
2674 fillColorSpace = colorSpace;
2677 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2678 if (strokeColorSpace) {
2679 delete strokeColorSpace;
2681 strokeColorSpace = colorSpace;
2684 void GfxState::setFillPattern(GfxPattern *pattern) {
2688 fillPattern = pattern;
2691 void GfxState::setStrokePattern(GfxPattern *pattern) {
2692 if (strokePattern) {
2693 delete strokePattern;
2695 strokePattern = pattern;
2698 void GfxState::setLineDash(double *dash, int length, double start) {
2702 lineDashLength = length;
2703 lineDashStart = start;
2706 void GfxState::clearPath() {
2708 path = new GfxPath();
2711 void GfxState::clip() {
2712 double xMin, yMin, xMax, yMax, x, y;
2713 GfxSubpath *subpath;
2716 xMin = xMax = yMin = yMax = 0; // make gcc happy
2717 for (i = 0; i < path->getNumSubpaths(); ++i) {
2718 subpath = path->getSubpath(i);
2719 for (j = 0; j < subpath->getNumPoints(); ++j) {
2720 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2721 if (i == 0 && j == 0) {
2727 } else if (x > xMax) {
2732 } else if (y > yMax) {
2738 if (xMin > clipXMin) {
2741 if (yMin > clipYMin) {
2744 if (xMax < clipXMax) {
2747 if (yMax < clipYMax) {
2752 void GfxState::textShift(double tx, double ty) {
2755 textTransformDelta(tx, ty, &dx, &dy);
2760 void GfxState::shift(double dx, double dy) {
2765 GfxState *GfxState::save() {
2769 newState->saved = this;
2773 GfxState *GfxState::restore() {
2779 // these attributes aren't saved/restored by the q/Q operators
2780 oldState->path = path;
2781 oldState->curX = curX;
2782 oldState->curY = curY;
2783 oldState->lineX = lineX;
2784 oldState->lineY = lineY;