1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
17 #include <string.h> // for memcpy()
25 //------------------------------------------------------------------------
27 static inline double clip01(double x) {
28 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
31 //------------------------------------------------------------------------
33 static char *gfxColorSpaceModeNames[] = {
47 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
49 //------------------------------------------------------------------------
51 //------------------------------------------------------------------------
53 GfxColorSpace::GfxColorSpace() {
56 GfxColorSpace::~GfxColorSpace() {
59 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
64 if (csObj->isName()) {
65 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
66 cs = new GfxDeviceGrayColorSpace();
67 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
68 cs = new GfxDeviceRGBColorSpace();
69 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
70 cs = new GfxDeviceCMYKColorSpace();
71 } else if (csObj->isName("Pattern")) {
72 cs = new GfxPatternColorSpace(NULL);
74 error(-1, "Bad color space '%s'", csObj->getName());
76 } else if (csObj->isArray()) {
77 csObj->arrayGet(0, &obj1);
78 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
79 cs = new GfxDeviceGrayColorSpace();
80 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
81 cs = new GfxDeviceRGBColorSpace();
82 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
83 cs = new GfxDeviceCMYKColorSpace();
84 } else if (obj1.isName("CalGray")) {
85 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
86 } else if (obj1.isName("CalRGB")) {
87 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
88 } else if (obj1.isName("Lab")) {
89 cs = GfxLabColorSpace::parse(csObj->getArray());
90 } else if (obj1.isName("ICCBased")) {
91 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
92 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
93 cs = GfxIndexedColorSpace::parse(csObj->getArray());
94 } else if (obj1.isName("Separation")) {
95 cs = GfxSeparationColorSpace::parse(csObj->getArray());
96 } else if (obj1.isName("DeviceN")) {
97 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
98 } else if (obj1.isName("Pattern")) {
99 cs = GfxPatternColorSpace::parse(csObj->getArray());
101 error(-1, "Bad color space");
105 error(-1, "Bad color space - expected name or array");
110 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
114 for (i = 0; i < getNComps(); ++i) {
120 int GfxColorSpace::getNumColorSpaceModes() {
121 return nGfxColorSpaceModes;
124 char *GfxColorSpace::getColorSpaceModeName(int idx) {
125 return gfxColorSpaceModeNames[idx];
128 //------------------------------------------------------------------------
129 // GfxDeviceGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
135 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
138 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
139 return new GfxDeviceGrayColorSpace();
142 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
143 *gray = clip01(color->c[0]);
146 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
147 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
150 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
151 cmyk->c = cmyk->m = cmyk->y = 0;
152 cmyk->k = clip01(1 - color->c[0]);
155 //------------------------------------------------------------------------
156 // GfxCalGrayColorSpace
157 //------------------------------------------------------------------------
159 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
160 whiteX = whiteY = whiteZ = 1;
161 blackX = blackY = blackZ = 0;
165 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
168 GfxColorSpace *GfxCalGrayColorSpace::copy() {
169 GfxCalGrayColorSpace *cs;
171 cs = new GfxCalGrayColorSpace();
182 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
183 GfxCalGrayColorSpace *cs;
184 Object obj1, obj2, obj3;
187 if (!obj1.isDict()) {
188 error(-1, "Bad CalGray color space");
192 cs = new GfxCalGrayColorSpace();
193 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
194 obj2.arrayGetLength() == 3) {
195 obj2.arrayGet(0, &obj3);
196 cs->whiteX = obj3.getNum();
198 obj2.arrayGet(1, &obj3);
199 cs->whiteY = obj3.getNum();
201 obj2.arrayGet(2, &obj3);
202 cs->whiteZ = obj3.getNum();
206 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
207 obj2.arrayGetLength() == 3) {
208 obj2.arrayGet(0, &obj3);
209 cs->blackX = obj3.getNum();
211 obj2.arrayGet(1, &obj3);
212 cs->blackY = obj3.getNum();
214 obj2.arrayGet(2, &obj3);
215 cs->blackZ = obj3.getNum();
219 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
220 cs->gamma = obj2.getNum();
227 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
228 *gray = clip01(color->c[0]);
231 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
232 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
235 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
236 cmyk->c = cmyk->m = cmyk->y = 0;
237 cmyk->k = clip01(1 - color->c[0]);
240 //------------------------------------------------------------------------
241 // GfxDeviceRGBColorSpace
242 //------------------------------------------------------------------------
244 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
247 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
250 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
251 return new GfxDeviceRGBColorSpace();
254 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
255 *gray = clip01(0.299 * color->c[0] +
256 0.587 * color->c[1] +
257 0.114 * color->c[2]);
260 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
261 rgb->r = clip01(color->c[0]);
262 rgb->g = clip01(color->c[1]);
263 rgb->b = clip01(color->c[2]);
266 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
269 c = clip01(1 - color->c[0]);
270 m = clip01(1 - color->c[1]);
271 y = clip01(1 - color->c[2]);
285 //------------------------------------------------------------------------
286 // GfxCalRGBColorSpace
287 //------------------------------------------------------------------------
289 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
290 whiteX = whiteY = whiteZ = 1;
291 blackX = blackY = blackZ = 0;
292 gammaR = gammaG = gammaB = 1;
293 mat[0] = 1; mat[1] = 0; mat[2] = 0;
294 mat[3] = 0; mat[4] = 1; mat[5] = 0;
295 mat[6] = 0; mat[7] = 0; mat[8] = 1;
298 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
301 GfxColorSpace *GfxCalRGBColorSpace::copy() {
302 GfxCalRGBColorSpace *cs;
305 cs = new GfxCalRGBColorSpace();
315 for (i = 0; i < 9; ++i) {
321 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
322 GfxCalRGBColorSpace *cs;
323 Object obj1, obj2, obj3;
327 if (!obj1.isDict()) {
328 error(-1, "Bad CalRGB color space");
332 cs = new GfxCalRGBColorSpace();
333 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
334 obj2.arrayGetLength() == 3) {
335 obj2.arrayGet(0, &obj3);
336 cs->whiteX = obj3.getNum();
338 obj2.arrayGet(1, &obj3);
339 cs->whiteY = obj3.getNum();
341 obj2.arrayGet(2, &obj3);
342 cs->whiteZ = obj3.getNum();
346 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
347 obj2.arrayGetLength() == 3) {
348 obj2.arrayGet(0, &obj3);
349 cs->blackX = obj3.getNum();
351 obj2.arrayGet(1, &obj3);
352 cs->blackY = obj3.getNum();
354 obj2.arrayGet(2, &obj3);
355 cs->blackZ = obj3.getNum();
359 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
360 obj2.arrayGetLength() == 3) {
361 obj2.arrayGet(0, &obj3);
362 cs->gammaR = obj3.getNum();
364 obj2.arrayGet(1, &obj3);
365 cs->gammaG = obj3.getNum();
367 obj2.arrayGet(2, &obj3);
368 cs->gammaB = obj3.getNum();
372 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
373 obj2.arrayGetLength() == 9) {
374 for (i = 0; i < 9; ++i) {
375 obj2.arrayGet(i, &obj3);
376 cs->mat[i] = obj3.getNum();
385 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
386 *gray = clip01(0.299 * color->c[0] +
387 0.587 * color->c[1] +
388 0.114 * color->c[2]);
391 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
392 rgb->r = clip01(color->c[0]);
393 rgb->g = clip01(color->c[1]);
394 rgb->b = clip01(color->c[2]);
397 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
400 c = clip01(1 - color->c[0]);
401 m = clip01(1 - color->c[1]);
402 y = clip01(1 - color->c[2]);
416 //------------------------------------------------------------------------
417 // GfxDeviceCMYKColorSpace
418 //------------------------------------------------------------------------
420 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
423 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
426 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
427 return new GfxDeviceCMYKColorSpace();
430 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
431 *gray = clip01(1 - color->c[3]
432 - 0.299 * color->c[0]
433 - 0.587 * color->c[1]
434 - 0.114 * color->c[2]);
437 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
438 double c,m,y,k,white;
444 rgb->r = white - (c*white);
445 rgb->g = white - (m*white);
446 rgb->b = white - (y*white);
448 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
449 double c, m, y, aw, ac, am, ay, ar, ag, ab;
451 c = clip01(color->c[0] + color->c[3]);
452 m = clip01(color->c[1] + color->c[3]);
453 y = clip01(color->c[2] + color->c[3]);
454 aw = (1-c) * (1-m) * (1-y);
455 ac = c * (1-m) * (1-y);
456 am = (1-c) * m * (1-y);
457 ay = (1-c) * (1-m) * y;
461 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
462 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
463 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
467 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
468 cmyk->c = clip01(color->c[0]);
469 cmyk->m = clip01(color->c[1]);
470 cmyk->y = clip01(color->c[2]);
471 cmyk->k = clip01(color->c[3]);
474 //------------------------------------------------------------------------
476 //------------------------------------------------------------------------
478 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
479 // Language Reference, Third Edition.
480 static double xyzrgb[3][3] = {
481 { 3.240449, -1.537136, -0.498531 },
482 { -0.969265, 1.876011, 0.041556 },
483 { 0.055643, -0.204026, 1.057229 }
486 GfxLabColorSpace::GfxLabColorSpace() {
487 whiteX = whiteY = whiteZ = 1;
488 blackX = blackY = blackZ = 0;
493 GfxLabColorSpace::~GfxLabColorSpace() {
496 GfxColorSpace *GfxLabColorSpace::copy() {
497 GfxLabColorSpace *cs;
499 cs = new GfxLabColorSpace();
516 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
517 GfxLabColorSpace *cs;
518 Object obj1, obj2, obj3;
521 if (!obj1.isDict()) {
522 error(-1, "Bad Lab color space");
526 cs = new GfxLabColorSpace();
527 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
528 obj2.arrayGetLength() == 3) {
529 obj2.arrayGet(0, &obj3);
530 cs->whiteX = obj3.getNum();
532 obj2.arrayGet(1, &obj3);
533 cs->whiteY = obj3.getNum();
535 obj2.arrayGet(2, &obj3);
536 cs->whiteZ = obj3.getNum();
540 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
541 obj2.arrayGetLength() == 3) {
542 obj2.arrayGet(0, &obj3);
543 cs->blackX = obj3.getNum();
545 obj2.arrayGet(1, &obj3);
546 cs->blackY = obj3.getNum();
548 obj2.arrayGet(2, &obj3);
549 cs->blackZ = obj3.getNum();
553 if (obj1.dictLookup("Range", &obj2)->isArray() &&
554 obj2.arrayGetLength() == 4) {
555 obj2.arrayGet(0, &obj3);
556 cs->aMin = obj3.getNum();
558 obj2.arrayGet(1, &obj3);
559 cs->aMax = obj3.getNum();
561 obj2.arrayGet(2, &obj3);
562 cs->bMin = obj3.getNum();
564 obj2.arrayGet(3, &obj3);
565 cs->bMax = obj3.getNum();
571 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
572 xyzrgb[0][1] * cs->whiteY +
573 xyzrgb[0][2] * cs->whiteZ);
574 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
575 xyzrgb[1][1] * cs->whiteY +
576 xyzrgb[1][2] * cs->whiteZ);
577 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
578 xyzrgb[2][1] * cs->whiteY +
579 xyzrgb[2][2] * cs->whiteZ);
584 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
588 *gray = clip01(0.299 * rgb.r +
593 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
598 // convert L*a*b* to CIE 1931 XYZ color space
599 t1 = (color->c[0] + 16) / 116;
600 t2 = t1 + color->c[1] / 500;
601 if (t2 >= (6.0 / 29.0)) {
604 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
607 if (t1 >= (6.0 / 29.0)) {
610 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
613 t2 = t1 - color->c[2] / 200;
614 if (t2 >= (6.0 / 29.0)) {
617 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
621 // convert XYZ to RGB, including gamut mapping and gamma correction
622 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
623 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
624 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
625 rgb->r = pow(clip01(r * kr), 0.5);
626 rgb->g = pow(clip01(g * kg), 0.5);
627 rgb->b = pow(clip01(b * kb), 0.5);
630 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
635 c = clip01(1 - rgb.r);
636 m = clip01(1 - rgb.g);
637 y = clip01(1 - rgb.b);
651 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
654 decodeRange[0] = 100;
656 decodeRange[1] = aMax - aMin;
658 decodeRange[2] = bMax - bMin;
661 //------------------------------------------------------------------------
662 // GfxICCBasedColorSpace
663 //------------------------------------------------------------------------
665 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
666 Ref *iccProfileStreamA) {
669 iccProfileStream = *iccProfileStreamA;
670 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
671 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
674 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
678 GfxColorSpace *GfxICCBasedColorSpace::copy() {
679 GfxICCBasedColorSpace *cs;
682 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
683 for (i = 0; i < 4; ++i) {
684 cs->rangeMin[i] = rangeMin[i];
685 cs->rangeMax[i] = rangeMax[i];
690 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
691 GfxICCBasedColorSpace *cs;
692 Ref iccProfileStreamA;
696 Object obj1, obj2, obj3;
699 arr->getNF(1, &obj1);
701 iccProfileStreamA = obj1.getRef();
703 iccProfileStreamA.num = 0;
704 iccProfileStreamA.gen = 0;
708 if (!obj1.isStream()) {
709 error(-1, "Bad ICCBased color space (stream)");
713 dict = obj1.streamGetDict();
714 if (!dict->lookup("N", &obj2)->isInt()) {
715 error(-1, "Bad ICCBased color space (N)");
720 nCompsA = obj2.getInt();
722 if (dict->lookup("Alternate", &obj2)->isNull() ||
723 !(altA = GfxColorSpace::parse(&obj2))) {
726 altA = new GfxDeviceGrayColorSpace();
729 altA = new GfxDeviceRGBColorSpace();
732 altA = new GfxDeviceCMYKColorSpace();
735 error(-1, "Bad ICCBased color space - invalid N");
742 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
743 if (dict->lookup("Range", &obj2)->isArray() &&
744 obj2.arrayGetLength() == 2 * nCompsA) {
745 for (i = 0; i < nCompsA; ++i) {
746 obj2.arrayGet(2*i, &obj3);
747 cs->rangeMin[i] = obj3.getNum();
749 obj2.arrayGet(2*i+1, &obj3);
750 cs->rangeMax[i] = obj3.getNum();
759 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
760 alt->getGray(color, gray);
763 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
764 alt->getRGB(color, rgb);
767 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
768 alt->getCMYK(color, cmyk);
771 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
774 alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
777 // this is nominally correct, but some PDF files don't set the
778 // correct ranges in the ICCBased dict
781 for (i = 0; i < nComps; ++i) {
782 decodeLow[i] = rangeMin[i];
783 decodeRange[i] = rangeMax[i] - rangeMin[i];
788 //------------------------------------------------------------------------
789 // GfxIndexedColorSpace
790 //------------------------------------------------------------------------
792 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
795 indexHigh = indexHighA;
796 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
800 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
805 GfxColorSpace *GfxIndexedColorSpace::copy() {
806 GfxIndexedColorSpace *cs;
808 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
809 memcpy(cs->lookup, lookup,
810 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
814 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
815 GfxIndexedColorSpace *cs;
816 GfxColorSpace *baseA;
823 if (arr->getLength() != 4) {
824 error(-1, "Bad Indexed color space");
828 if (!(baseA = GfxColorSpace::parse(&obj1))) {
829 error(-1, "Bad Indexed color space (base color space)");
833 if (!arr->get(2, &obj1)->isInt()) {
834 error(-1, "Bad Indexed color space (hival)");
838 indexHighA = obj1.getInt();
839 if (indexHighA < 0 || indexHighA > 255) {
840 // the PDF spec requires indexHigh to be in [0,255] -- allowing
841 // values larger than 255 creates a security hole: if nComps *
842 // indexHigh is greater than 2^31, the loop below may overwrite
843 // past the end of the array
844 error(-1, "Bad Indexed color space (invalid indexHigh value)");
849 cs = new GfxIndexedColorSpace(baseA, indexHighA);
851 n = baseA->getNComps();
852 if (obj1.isStream()) {
854 for (i = 0; i <= indexHighA; ++i) {
855 for (j = 0; j < n; ++j) {
856 if ((x = obj1.streamGetChar()) == EOF) {
857 error(-1, "Bad Indexed color space (lookup table stream too short)");
860 cs->lookup[i*n + j] = (Guchar)x;
864 } else if (obj1.isString()) {
865 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
866 error(-1, "Bad Indexed color space (lookup table string too short)");
869 s = obj1.getString()->getCString();
870 for (i = 0; i <= indexHighA; ++i) {
871 for (j = 0; j < n; ++j) {
872 cs->lookup[i*n + j] = (Guchar)*s++;
876 error(-1, "Bad Indexed color space (lookup table)");
890 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
891 GfxColor *baseColor) {
893 double low[gfxColorMaxComps], range[gfxColorMaxComps];
896 n = base->getNComps();
897 base->getDefaultRanges(low, range, indexHigh);
898 p = &lookup[(int)(color->c[0] + 0.5) * n];
899 for (i = 0; i < n; ++i) {
900 baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
905 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
908 base->getGray(mapColorToBase(color, &color2), gray);
911 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
914 base->getRGB(mapColorToBase(color, &color2), rgb);
917 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
920 base->getCMYK(mapColorToBase(color, &color2), cmyk);
923 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
927 decodeRange[0] = maxImgPixel;
930 //------------------------------------------------------------------------
931 // GfxSeparationColorSpace
932 //------------------------------------------------------------------------
934 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
942 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
948 GfxColorSpace *GfxSeparationColorSpace::copy() {
949 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
952 //~ handle the 'All' and 'None' colorants
953 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
954 GfxSeparationColorSpace *cs;
960 if (arr->getLength() != 4) {
961 error(-1, "Bad Separation color space");
964 if (!arr->get(1, &obj1)->isName()) {
965 error(-1, "Bad Separation color space (name)");
968 nameA = new GString(obj1.getName());
971 if (!(altA = GfxColorSpace::parse(&obj1))) {
972 error(-1, "Bad Separation color space (alternate color space)");
977 if (!(funcA = Function::parse(&obj1))) {
981 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
994 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
997 func->transform(color->c, color2.c);
998 alt->getGray(&color2, gray);
1001 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1004 func->transform(color->c, color2.c);
1005 alt->getRGB(&color2, rgb);
1008 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1011 func->transform(color->c, color2.c);
1012 alt->getCMYK(&color2, cmyk);
1015 //------------------------------------------------------------------------
1016 // GfxDeviceNColorSpace
1017 //------------------------------------------------------------------------
1019 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1020 GfxColorSpace *altA,
1027 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1030 for (i = 0; i < nComps; ++i) {
1037 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1038 GfxDeviceNColorSpace *cs;
1041 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1042 for (i = 0; i < nComps; ++i) {
1043 cs->names[i] = names[i]->copy();
1048 //~ handle the 'None' colorant
1049 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1050 GfxDeviceNColorSpace *cs;
1052 GString *namesA[gfxColorMaxComps];
1053 GfxColorSpace *altA;
1058 if (arr->getLength() != 4 && arr->getLength() != 5) {
1059 error(-1, "Bad DeviceN color space");
1062 if (!arr->get(1, &obj1)->isArray()) {
1063 error(-1, "Bad DeviceN color space (names)");
1066 nCompsA = obj1.arrayGetLength();
1067 if (nCompsA > gfxColorMaxComps) {
1068 error(-1, "DeviceN color space with more than %d > %d components",
1069 nCompsA, gfxColorMaxComps);
1070 nCompsA = gfxColorMaxComps;
1072 for (i = 0; i < nCompsA; ++i) {
1073 if (!obj1.arrayGet(i, &obj2)->isName()) {
1074 error(-1, "Bad DeviceN color space (names)");
1078 namesA[i] = new GString(obj2.getName());
1083 if (!(altA = GfxColorSpace::parse(&obj1))) {
1084 error(-1, "Bad DeviceN color space (alternate color space)");
1089 if (!(funcA = Function::parse(&obj1))) {
1093 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1094 for (i = 0; i < nCompsA; ++i) {
1095 cs->names[i] = namesA[i];
1102 for (i = 0; i < nCompsA; ++i) {
1111 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1114 func->transform(color->c, color2.c);
1115 alt->getGray(&color2, gray);
1118 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1121 func->transform(color->c, color2.c);
1122 alt->getRGB(&color2, rgb);
1125 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1128 func->transform(color->c, color2.c);
1129 alt->getCMYK(&color2, cmyk);
1132 //------------------------------------------------------------------------
1133 // GfxPatternColorSpace
1134 //------------------------------------------------------------------------
1136 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1140 GfxPatternColorSpace::~GfxPatternColorSpace() {
1146 GfxColorSpace *GfxPatternColorSpace::copy() {
1147 return new GfxPatternColorSpace(under ? under->copy() :
1148 (GfxColorSpace *)NULL);
1151 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1152 GfxPatternColorSpace *cs;
1153 GfxColorSpace *underA;
1156 if (arr->getLength() != 1 && arr->getLength() != 2) {
1157 error(-1, "Bad Pattern color space");
1161 if (arr->getLength() == 2) {
1163 if (!(underA = GfxColorSpace::parse(&obj1))) {
1164 error(-1, "Bad Pattern color space (underlying color space)");
1170 cs = new GfxPatternColorSpace(underA);
1174 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1178 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1179 rgb->r = rgb->g = rgb->b = 0;
1182 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1183 cmyk->c = cmyk->m = cmyk->y = 0;
1187 //------------------------------------------------------------------------
1189 //------------------------------------------------------------------------
1191 GfxPattern::GfxPattern(int typeA) {
1195 GfxPattern::~GfxPattern() {
1198 GfxPattern *GfxPattern::parse(Object *obj) {
1199 GfxPattern *pattern;
1202 if (obj->isDict()) {
1203 obj->dictLookup("PatternType", &obj1);
1204 } else if (obj->isStream()) {
1205 obj->streamGetDict()->lookup("PatternType", &obj1);
1210 if (obj1.isInt() && obj1.getInt() == 1) {
1211 pattern = GfxTilingPattern::parse(obj);
1212 } else if (obj1.isInt() && obj1.getInt() == 2) {
1213 pattern = GfxShadingPattern::parse(obj);
1219 //------------------------------------------------------------------------
1221 //------------------------------------------------------------------------
1223 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1224 GfxTilingPattern *pat;
1226 int paintTypeA, tilingTypeA;
1227 double bboxA[4], matrixA[6];
1228 double xStepA, yStepA;
1233 if (!patObj->isStream()) {
1236 dict = patObj->streamGetDict();
1238 if (dict->lookup("PaintType", &obj1)->isInt()) {
1239 paintTypeA = obj1.getInt();
1242 error(-1, "Invalid or missing PaintType in pattern");
1245 if (dict->lookup("TilingType", &obj1)->isInt()) {
1246 tilingTypeA = obj1.getInt();
1249 error(-1, "Invalid or missing TilingType in pattern");
1252 bboxA[0] = bboxA[1] = 0;
1253 bboxA[2] = bboxA[3] = 1;
1254 if (dict->lookup("BBox", &obj1)->isArray() &&
1255 obj1.arrayGetLength() == 4) {
1256 for (i = 0; i < 4; ++i) {
1257 if (obj1.arrayGet(i, &obj2)->isNum()) {
1258 bboxA[i] = obj2.getNum();
1263 error(-1, "Invalid or missing BBox in pattern");
1266 if (dict->lookup("XStep", &obj1)->isNum()) {
1267 xStepA = obj1.getNum();
1270 error(-1, "Invalid or missing XStep in pattern");
1273 if (dict->lookup("YStep", &obj1)->isNum()) {
1274 yStepA = obj1.getNum();
1277 error(-1, "Invalid or missing YStep in pattern");
1280 if (!dict->lookup("Resources", &resDictA)->isDict()) {
1282 resDictA.initNull();
1283 error(-1, "Invalid or missing Resources in pattern");
1285 matrixA[0] = 1; matrixA[1] = 0;
1286 matrixA[2] = 0; matrixA[3] = 1;
1287 matrixA[4] = 0; matrixA[5] = 0;
1288 if (dict->lookup("Matrix", &obj1)->isArray() &&
1289 obj1.arrayGetLength() == 6) {
1290 for (i = 0; i < 6; ++i) {
1291 if (obj1.arrayGet(i, &obj2)->isNum()) {
1292 matrixA[i] = obj2.getNum();
1299 pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1300 &resDictA, matrixA, patObj);
1305 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1306 double *bboxA, double xStepA, double yStepA,
1307 Object *resDictA, double *matrixA,
1308 Object *contentStreamA):
1313 paintType = paintTypeA;
1314 tilingType = tilingTypeA;
1315 for (i = 0; i < 4; ++i) {
1320 resDictA->copy(&resDict);
1321 for (i = 0; i < 6; ++i) {
1322 matrix[i] = matrixA[i];
1324 contentStreamA->copy(&contentStream);
1327 GfxTilingPattern::~GfxTilingPattern() {
1329 contentStream.free();
1332 GfxPattern *GfxTilingPattern::copy() {
1333 return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1334 &resDict, matrix, &contentStream);
1337 //------------------------------------------------------------------------
1338 // GfxShadingPattern
1339 //------------------------------------------------------------------------
1341 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1343 GfxShading *shadingA;
1348 if (!patObj->isDict()) {
1351 dict = patObj->getDict();
1353 dict->lookup("Shading", &obj1);
1354 shadingA = GfxShading::parse(&obj1);
1360 matrixA[0] = 1; matrixA[1] = 0;
1361 matrixA[2] = 0; matrixA[3] = 1;
1362 matrixA[4] = 0; matrixA[5] = 0;
1363 if (dict->lookup("Matrix", &obj1)->isArray() &&
1364 obj1.arrayGetLength() == 6) {
1365 for (i = 0; i < 6; ++i) {
1366 if (obj1.arrayGet(i, &obj2)->isNum()) {
1367 matrixA[i] = obj2.getNum();
1374 return new GfxShadingPattern(shadingA, matrixA);
1377 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1383 for (i = 0; i < 6; ++i) {
1384 matrix[i] = matrixA[i];
1388 GfxShadingPattern::~GfxShadingPattern() {
1392 GfxPattern *GfxShadingPattern::copy() {
1393 return new GfxShadingPattern(shading->copy(), matrix);
1396 //------------------------------------------------------------------------
1398 //------------------------------------------------------------------------
1400 GfxShading::GfxShading(int typeA) {
1405 GfxShading::GfxShading(GfxShading *shading) {
1408 type = shading->type;
1409 colorSpace = shading->colorSpace->copy();
1410 for (i = 0; i < gfxColorMaxComps; ++i) {
1411 background.c[i] = shading->background.c[i];
1413 hasBackground = shading->hasBackground;
1414 xMin = shading->xMin;
1415 yMin = shading->yMin;
1416 xMax = shading->xMax;
1417 yMax = shading->yMax;
1418 hasBBox = shading->hasBBox;
1421 GfxShading::~GfxShading() {
1427 GfxShading *GfxShading::parse(Object *obj) {
1428 GfxShading *shading;
1433 if (obj->isDict()) {
1434 dict = obj->getDict();
1435 } else if (obj->isStream()) {
1436 dict = obj->streamGetDict();
1441 if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1442 error(-1, "Invalid ShadingType in shading dictionary");
1446 typeA = obj1.getInt();
1451 shading = GfxFunctionShading::parse(dict);
1454 shading = GfxAxialShading::parse(dict);
1457 shading = GfxRadialShading::parse(dict);
1460 error(-1, "Unimplemented shading type %d", typeA);
1470 GBool GfxShading::init(Dict *dict) {
1474 dict->lookup("ColorSpace", &obj1);
1475 if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1476 error(-1, "Bad color space in shading dictionary");
1482 for (i = 0; i < gfxColorMaxComps; ++i) {
1483 background.c[i] = 0;
1485 hasBackground = gFalse;
1486 if (dict->lookup("Background", &obj1)->isArray()) {
1487 if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1488 hasBackground = gTrue;
1489 for (i = 0; i < colorSpace->getNComps(); ++i) {
1490 background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1494 error(-1, "Bad Background in shading dictionary");
1499 xMin = yMin = xMax = yMax = 0;
1501 if (dict->lookup("BBox", &obj1)->isArray()) {
1502 if (obj1.arrayGetLength() == 4) {
1504 xMin = obj1.arrayGet(0, &obj2)->getNum();
1506 yMin = obj1.arrayGet(1, &obj2)->getNum();
1508 xMax = obj1.arrayGet(2, &obj2)->getNum();
1510 yMax = obj1.arrayGet(3, &obj2)->getNum();
1513 error(-1, "Bad BBox in shading dictionary");
1521 //------------------------------------------------------------------------
1522 // GfxFunctionShading
1523 //------------------------------------------------------------------------
1525 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1526 double x1A, double y1A,
1528 Function **funcsA, int nFuncsA):
1537 for (i = 0; i < 6; ++i) {
1538 matrix[i] = matrixA[i];
1541 for (i = 0; i < nFuncs; ++i) {
1542 funcs[i] = funcsA[i];
1546 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1555 for (i = 0; i < 6; ++i) {
1556 matrix[i] = shading->matrix[i];
1558 nFuncs = shading->nFuncs;
1559 for (i = 0; i < nFuncs; ++i) {
1560 funcs[i] = shading->funcs[i]->copy();
1564 GfxFunctionShading::~GfxFunctionShading() {
1567 for (i = 0; i < nFuncs; ++i) {
1572 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1573 GfxFunctionShading *shading;
1574 double x0A, y0A, x1A, y1A;
1576 Function *funcsA[gfxColorMaxComps];
1583 if (dict->lookup("Domain", &obj1)->isArray() &&
1584 obj1.arrayGetLength() == 4) {
1585 x0A = obj1.arrayGet(0, &obj2)->getNum();
1587 y0A = obj1.arrayGet(1, &obj2)->getNum();
1589 x1A = obj1.arrayGet(2, &obj2)->getNum();
1591 y1A = obj1.arrayGet(3, &obj2)->getNum();
1596 matrixA[0] = 1; matrixA[1] = 0;
1597 matrixA[2] = 0; matrixA[3] = 1;
1598 matrixA[4] = 0; matrixA[5] = 0;
1599 if (dict->lookup("Matrix", &obj1)->isArray() &&
1600 obj1.arrayGetLength() == 6) {
1601 matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1603 matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1605 matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1607 matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1609 matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1611 matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1616 dict->lookup("Function", &obj1);
1617 if (obj1.isArray()) {
1618 nFuncsA = obj1.arrayGetLength();
1619 if (nFuncsA > gfxColorMaxComps) {
1620 error(-1, "Invalid Function array in shading dictionary");
1623 for (i = 0; i < nFuncsA; ++i) {
1624 obj1.arrayGet(i, &obj2);
1625 if (!(funcsA[i] = Function::parse(&obj2))) {
1632 if (!(funcsA[0] = Function::parse(&obj1))) {
1638 shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1640 if (!shading->init(dict)) {
1653 GfxShading *GfxFunctionShading::copy() {
1654 return new GfxFunctionShading(this);
1657 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1663 for (i = 0; i < nFuncs; ++i) {
1664 funcs[i]->transform(in, &color->c[i]);
1668 //------------------------------------------------------------------------
1670 //------------------------------------------------------------------------
1672 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1673 double x1A, double y1A,
1674 double t0A, double t1A,
1675 Function **funcsA, int nFuncsA,
1676 GBool extend0A, GBool extend1A):
1688 for (i = 0; i < nFuncs; ++i) {
1689 funcs[i] = funcsA[i];
1695 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1706 nFuncs = shading->nFuncs;
1707 for (i = 0; i < nFuncs; ++i) {
1708 funcs[i] = shading->funcs[i]->copy();
1710 extend0 = shading->extend0;
1711 extend1 = shading->extend1;
1714 GfxAxialShading::~GfxAxialShading() {
1717 for (i = 0; i < nFuncs; ++i) {
1722 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1723 GfxAxialShading *shading;
1724 double x0A, y0A, x1A, y1A;
1726 Function *funcsA[gfxColorMaxComps];
1728 GBool extend0A, extend1A;
1732 x0A = y0A = x1A = y1A = 0;
1733 if (dict->lookup("Coords", &obj1)->isArray() &&
1734 obj1.arrayGetLength() == 4) {
1735 x0A = obj1.arrayGet(0, &obj2)->getNum();
1737 y0A = obj1.arrayGet(1, &obj2)->getNum();
1739 x1A = obj1.arrayGet(2, &obj2)->getNum();
1741 y1A = obj1.arrayGet(3, &obj2)->getNum();
1744 error(-1, "Missing or invalid Coords in shading dictionary");
1751 if (dict->lookup("Domain", &obj1)->isArray() &&
1752 obj1.arrayGetLength() == 2) {
1753 t0A = obj1.arrayGet(0, &obj2)->getNum();
1755 t1A = obj1.arrayGet(1, &obj2)->getNum();
1760 dict->lookup("Function", &obj1);
1761 if (obj1.isArray()) {
1762 nFuncsA = obj1.arrayGetLength();
1763 if (nFuncsA > gfxColorMaxComps) {
1764 error(-1, "Invalid Function array in shading dictionary");
1767 for (i = 0; i < nFuncsA; ++i) {
1768 obj1.arrayGet(i, &obj2);
1769 if (!(funcsA[i] = Function::parse(&obj2))) {
1778 if (!(funcsA[0] = Function::parse(&obj1))) {
1785 extend0A = extend1A = gFalse;
1786 if (dict->lookup("Extend", &obj1)->isArray() &&
1787 obj1.arrayGetLength() == 2) {
1788 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1790 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1795 shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1796 funcsA, nFuncsA, extend0A, extend1A);
1797 if (!shading->init(dict)) {
1807 GfxShading *GfxAxialShading::copy() {
1808 return new GfxAxialShading(this);
1811 void GfxAxialShading::getColor(double t, GfxColor *color) {
1814 // NB: there can be one function with n outputs or n functions with
1815 // one output each (where n = number of color components)
1816 for (i = 0; i < nFuncs; ++i) {
1817 funcs[i]->transform(&t, &color->c[i]);
1821 //------------------------------------------------------------------------
1823 //------------------------------------------------------------------------
1825 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1826 double x1A, double y1A, double r1A,
1827 double t0A, double t1A,
1828 Function **funcsA, int nFuncsA,
1829 GBool extend0A, GBool extend1A):
1843 for (i = 0; i < nFuncs; ++i) {
1844 funcs[i] = funcsA[i];
1850 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1863 nFuncs = shading->nFuncs;
1864 for (i = 0; i < nFuncs; ++i) {
1865 funcs[i] = shading->funcs[i]->copy();
1867 extend0 = shading->extend0;
1868 extend1 = shading->extend1;
1871 GfxRadialShading::~GfxRadialShading() {
1874 for (i = 0; i < nFuncs; ++i) {
1879 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1880 GfxRadialShading *shading;
1881 double x0A, y0A, r0A, x1A, y1A, r1A;
1883 Function *funcsA[gfxColorMaxComps];
1885 GBool extend0A, extend1A;
1889 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1890 if (dict->lookup("Coords", &obj1)->isArray() &&
1891 obj1.arrayGetLength() == 6) {
1892 x0A = obj1.arrayGet(0, &obj2)->getNum();
1894 y0A = obj1.arrayGet(1, &obj2)->getNum();
1896 r0A = obj1.arrayGet(2, &obj2)->getNum();
1898 x1A = obj1.arrayGet(3, &obj2)->getNum();
1900 y1A = obj1.arrayGet(4, &obj2)->getNum();
1902 r1A = obj1.arrayGet(5, &obj2)->getNum();
1905 error(-1, "Missing or invalid Coords in shading dictionary");
1912 if (dict->lookup("Domain", &obj1)->isArray() &&
1913 obj1.arrayGetLength() == 2) {
1914 t0A = obj1.arrayGet(0, &obj2)->getNum();
1916 t1A = obj1.arrayGet(1, &obj2)->getNum();
1921 dict->lookup("Function", &obj1);
1922 if (obj1.isArray()) {
1923 nFuncsA = obj1.arrayGetLength();
1924 if (nFuncsA > gfxColorMaxComps) {
1925 error(-1, "Invalid Function array in shading dictionary");
1928 for (i = 0; i < nFuncsA; ++i) {
1929 obj1.arrayGet(i, &obj2);
1930 if (!(funcsA[i] = Function::parse(&obj2))) {
1939 if (!(funcsA[0] = Function::parse(&obj1))) {
1946 extend0A = extend1A = gFalse;
1947 if (dict->lookup("Extend", &obj1)->isArray() &&
1948 obj1.arrayGetLength() == 2) {
1949 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1951 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1956 shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1957 funcsA, nFuncsA, extend0A, extend1A);
1958 if (!shading->init(dict)) {
1968 GfxShading *GfxRadialShading::copy() {
1969 return new GfxRadialShading(this);
1972 void GfxRadialShading::getColor(double t, GfxColor *color) {
1975 // NB: there can be one function with n outputs or n functions with
1976 // one output each (where n = number of color components)
1977 for (i = 0; i < nFuncs; ++i) {
1978 funcs[i]->transform(&t, &color->c[i]);
1982 //------------------------------------------------------------------------
1984 //------------------------------------------------------------------------
1986 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1987 GfxColorSpace *colorSpaceA) {
1988 GfxIndexedColorSpace *indexedCS;
1989 GfxSeparationColorSpace *sepCS;
1990 int maxPixel, indexHigh;
1994 double x[gfxColorMaxComps];
1995 double y[gfxColorMaxComps];
1997 int maxPixelForAlloc;
2001 // bits per component and color space
2003 maxPixel = (1 << bits) - 1;
2004 maxPixelForAlloc = (1 << (bits>8?bits:8));
2005 colorSpace = colorSpaceA;
2008 if (decode->isNull()) {
2009 nComps = colorSpace->getNComps();
2010 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2011 } else if (decode->isArray()) {
2012 nComps = decode->arrayGetLength() / 2;
2013 if (nComps != colorSpace->getNComps()) {
2016 for (i = 0; i < nComps; ++i) {
2017 decode->arrayGet(2*i, &obj);
2021 decodeLow[i] = obj.getNum();
2023 decode->arrayGet(2*i+1, &obj);
2027 decodeRange[i] = obj.getNum() - decodeLow[i];
2034 // Construct a lookup table -- this stores pre-computed decoded
2035 // values for each component, i.e., the result of applying the
2036 // decode mapping to each possible image pixel component value.
2038 // Optimization: for Indexed and Separation color spaces (which have
2039 // only one component), we store color values in the lookup table
2040 // rather than component values.
2043 if (colorSpace->getMode() == csIndexed) {
2044 // Note that indexHigh may not be the same as maxPixel --
2045 // Distiller will remove unused palette entries, resulting in
2046 // indexHigh < maxPixel.
2047 indexedCS = (GfxIndexedColorSpace *)colorSpace;
2048 colorSpace2 = indexedCS->getBase();
2049 indexHigh = indexedCS->getIndexHigh();
2050 nComps2 = colorSpace2->getNComps();
2051 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2052 lookup2 = indexedCS->getLookup();
2053 colorSpace2->getDefaultRanges(x, y, indexHigh);
2054 for (i = 0; i <= maxPixel; ++i) {
2055 j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2058 } else if (j > indexHigh) {
2061 for (k = 0; k < nComps2; ++k) {
2062 lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2065 } else if (colorSpace->getMode() == csSeparation) {
2066 sepCS = (GfxSeparationColorSpace *)colorSpace;
2067 colorSpace2 = sepCS->getAlt();
2068 nComps2 = colorSpace2->getNComps();
2069 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2070 sepFunc = sepCS->getFunc();
2071 for (i = 0; i <= maxPixel; ++i) {
2072 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2073 sepFunc->transform(x, y);
2074 for (k = 0; k < nComps2; ++k) {
2075 lookup[i*nComps2 + k] = y[k];
2079 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
2080 for (i = 0; i <= maxPixel; ++i) {
2081 for (k = 0; k < nComps; ++k) {
2082 lookup[i*nComps + k] = decodeLow[k] +
2083 (i * decodeRange[k]) / maxPixel;
2096 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2099 colorSpace = colorMap->colorSpace->copy();
2100 bits = colorMap->bits;
2101 nComps = colorMap->nComps;
2102 nComps2 = colorMap->nComps2;
2106 if (colorSpace->getMode() == csIndexed) {
2107 colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2108 n = n * nComps2 * sizeof(double);
2109 } else if (colorSpace->getMode() == csSeparation) {
2110 colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2111 n = n * nComps2 * sizeof(double);
2113 n = n * nComps * sizeof(double);
2115 lookup = (double *)gmalloc(n);
2116 memcpy(lookup, colorMap->lookup, n);
2117 for (i = 0; i < nComps; ++i) {
2118 decodeLow[i] = colorMap->decodeLow[i];
2119 decodeRange[i] = colorMap->decodeRange[i];
2124 GfxImageColorMap::~GfxImageColorMap() {
2129 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2135 p = &lookup[x[0] * nComps2];
2136 for (i = 0; i < nComps2; ++i) {
2139 colorSpace2->getGray(&color, gray);
2141 for (i = 0; i < nComps; ++i) {
2142 color.c[i] = lookup[x[i] * nComps + i];
2144 colorSpace->getGray(&color, gray);
2148 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2154 p = &lookup[x[0] * nComps2];
2155 for (i = 0; i < nComps2; ++i) {
2158 colorSpace2->getRGB(&color, rgb);
2160 for (i = 0; i < nComps; ++i) {
2161 color.c[i] = lookup[x[i] * nComps + i];
2163 colorSpace->getRGB(&color, rgb);
2167 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2173 p = &lookup[x[0] * nComps2];
2174 for (i = 0; i < nComps2; ++i) {
2177 colorSpace2->getCMYK(&color, cmyk);
2179 for (i = 0; i < nComps; ++i) {
2180 color.c[i] = lookup[x[i] * nComps + i];
2182 colorSpace->getCMYK(&color, cmyk);
2186 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2189 maxPixel = (1 << bits) - 1;
2190 for (i = 0; i < nComps; ++i) {
2191 color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2195 //------------------------------------------------------------------------
2196 // GfxSubpath and GfxPath
2197 //------------------------------------------------------------------------
2199 GfxSubpath::GfxSubpath(double x1, double y1) {
2201 x = (double *)gmalloc(size * sizeof(double));
2202 y = (double *)gmalloc(size * sizeof(double));
2203 curve = (GBool *)gmalloc(size * sizeof(GBool));
2211 GfxSubpath::~GfxSubpath() {
2218 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2219 size = subpath->size;
2221 x = (double *)gmalloc(size * sizeof(double));
2222 y = (double *)gmalloc(size * sizeof(double));
2223 curve = (GBool *)gmalloc(size * sizeof(GBool));
2224 memcpy(x, subpath->x, n * sizeof(double));
2225 memcpy(y, subpath->y, n * sizeof(double));
2226 memcpy(curve, subpath->curve, n * sizeof(GBool));
2227 closed = subpath->closed;
2230 void GfxSubpath::lineTo(double x1, double y1) {
2233 x = (double *)grealloc(x, size * sizeof(double));
2234 y = (double *)grealloc(y, size * sizeof(double));
2235 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2243 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2244 double x3, double y3) {
2247 x = (double *)grealloc(x, size * sizeof(double));
2248 y = (double *)grealloc(y, size * sizeof(double));
2249 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2257 curve[n] = curve[n+1] = gTrue;
2258 curve[n+2] = gFalse;
2262 void GfxSubpath::close() {
2263 if (x[n-1] != x[0] || y[n-1] != y[0]) {
2269 void GfxSubpath::offset(double dx, double dy) {
2272 for (i = 0; i < n; ++i) {
2278 GfxPath::GfxPath() {
2282 firstX = firstY = 0;
2283 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2286 GfxPath::~GfxPath() {
2289 for (i = 0; i < n; ++i)
2295 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2296 GfxSubpath **subpaths1, int n1, int size1) {
2299 justMoved = justMoved1;
2304 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2305 for (i = 0; i < n; ++i)
2306 subpaths[i] = subpaths1[i]->copy();
2309 void GfxPath::moveTo(double x, double y) {
2315 void GfxPath::lineTo(double x, double y) {
2319 subpaths = (GfxSubpath **)
2320 grealloc(subpaths, size * sizeof(GfxSubpath *));
2322 subpaths[n] = new GfxSubpath(firstX, firstY);
2326 subpaths[n-1]->lineTo(x, y);
2329 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2330 double x3, double y3) {
2334 subpaths = (GfxSubpath **)
2335 grealloc(subpaths, size * sizeof(GfxSubpath *));
2337 subpaths[n] = new GfxSubpath(firstX, firstY);
2341 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2344 void GfxPath::close() {
2345 // this is necessary to handle the pathological case of
2346 // moveto/closepath/clip, which defines an empty clipping region
2350 subpaths = (GfxSubpath **)
2351 grealloc(subpaths, size * sizeof(GfxSubpath *));
2353 subpaths[n] = new GfxSubpath(firstX, firstY);
2357 subpaths[n-1]->close();
2360 void GfxPath::append(GfxPath *path) {
2363 if (n + path->n > size) {
2365 subpaths = (GfxSubpath **)
2366 grealloc(subpaths, size * sizeof(GfxSubpath *));
2368 for (i = 0; i < path->n; ++i) {
2369 subpaths[n++] = path->subpaths[i]->copy();
2374 void GfxPath::offset(double dx, double dy) {
2377 for (i = 0; i < n; ++i) {
2378 subpaths[i]->offset(dx, dy);
2382 //------------------------------------------------------------------------
2384 //------------------------------------------------------------------------
2386 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2387 int rotate, GBool upsideDown) {
2398 ctm[1] = upsideDown ? ky : -ky;
2402 ctm[5] = ky * (upsideDown ? -px1 : px2);
2403 pageWidth = kx * (py2 - py1);
2404 pageHeight = ky * (px2 - px1);
2405 } else if (rotate == 180) {
2409 ctm[3] = upsideDown ? ky : -ky;
2411 ctm[5] = ky * (upsideDown ? -py1 : py2);
2412 pageWidth = kx * (px2 - px1);
2413 pageHeight = ky * (py2 - py1);
2414 } else if (rotate == 270) {
2416 ctm[1] = upsideDown ? -ky : ky;
2420 ctm[5] = ky * (upsideDown ? px2 : -px1);
2421 pageWidth = kx * (py2 - py1);
2422 pageHeight = ky * (px2 - px1);
2427 ctm[3] = upsideDown ? -ky : ky;
2429 ctm[5] = ky * (upsideDown ? py2 : -py1);
2430 pageWidth = kx * (px2 - px1);
2431 pageHeight = ky * (py2 - py1);
2434 fillColorSpace = new GfxDeviceGrayColorSpace();
2435 strokeColorSpace = new GfxDeviceGrayColorSpace();
2437 strokeColor.c[0] = 0;
2439 strokePattern = NULL;
2454 textMat[0] = 1; textMat[1] = 0;
2455 textMat[2] = 0; textMat[3] = 1;
2456 textMat[4] = 0; textMat[5] = 0;
2464 path = new GfxPath();
2470 clipXMax = pageWidth;
2471 clipYMax = pageHeight;
2476 GfxState::~GfxState() {
2477 if (fillColorSpace) {
2478 delete fillColorSpace;
2480 if (strokeColorSpace) {
2481 delete strokeColorSpace;
2486 if (strokePattern) {
2487 delete strokePattern;
2491 // this gets set to NULL by restore()
2500 GfxState::GfxState(GfxState *state) {
2501 memcpy(this, state, sizeof(GfxState));
2502 if (fillColorSpace) {
2503 fillColorSpace = state->fillColorSpace->copy();
2505 if (strokeColorSpace) {
2506 strokeColorSpace = state->strokeColorSpace->copy();
2509 fillPattern = state->fillPattern->copy();
2511 if (strokePattern) {
2512 strokePattern = state->strokePattern->copy();
2514 if (lineDashLength > 0) {
2515 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2516 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2521 void GfxState::setPath(GfxPath *pathA) {
2526 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2527 double *xMax, double *yMax) {
2529 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2532 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2533 ictm[0] = ctm[3] * det;
2534 ictm[1] = -ctm[1] * det;
2535 ictm[2] = -ctm[2] * det;
2536 ictm[3] = ctm[0] * det;
2537 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2538 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2540 // transform all four corners of the clip bbox; find the min and max
2542 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2543 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2544 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2545 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2548 } else if (tx > xMax1) {
2553 } else if (ty > yMax1) {
2556 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2557 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2560 } else if (tx > xMax1) {
2565 } else if (ty > yMax1) {
2568 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2569 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2572 } else if (tx > xMax1) {
2577 } else if (ty > yMax1) {
2587 double GfxState::transformWidth(double w) {
2590 x = ctm[0] + ctm[2];
2591 y = ctm[1] + ctm[3];
2592 return w * sqrt(0.5 * (x * x + y * y));
2595 double GfxState::getTransformedFontSize() {
2596 double x1, y1, x2, y2;
2598 x1 = textMat[2] * fontSize;
2599 y1 = textMat[3] * fontSize;
2600 x2 = ctm[0] * x1 + ctm[2] * y1;
2601 y2 = ctm[1] * x1 + ctm[3] * y1;
2602 return sqrt(x2 * x2 + y2 * y2);
2605 void GfxState::getFontTransMat(double *m11, double *m12,
2606 double *m21, double *m22) {
2607 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2608 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2609 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2610 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2613 void GfxState::setCTM(double a, double b, double c,
2614 double d, double e, double f) {
2624 // avoid FP exceptions on badly messed up PDF files
2625 for (i = 0; i < 6; ++i) {
2626 if (ctm[i] > 1e10) {
2628 } else if (ctm[i] < -1e10) {
2634 void GfxState::concatCTM(double a, double b, double c,
2635 double d, double e, double f) {
2642 ctm[0] = a * a1 + b * c1;
2643 ctm[1] = a * b1 + b * d1;
2644 ctm[2] = c * a1 + d * c1;
2645 ctm[3] = c * b1 + d * d1;
2646 ctm[4] = e * a1 + f * c1 + ctm[4];
2647 ctm[5] = e * b1 + f * d1 + ctm[5];
2649 // avoid FP exceptions on badly messed up PDF files
2650 for (i = 0; i < 6; ++i) {
2651 if (ctm[i] > 1e10) {
2653 } else if (ctm[i] < -1e10) {
2659 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2660 if (fillColorSpace) {
2661 delete fillColorSpace;
2663 fillColorSpace = colorSpace;
2666 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2667 if (strokeColorSpace) {
2668 delete strokeColorSpace;
2670 strokeColorSpace = colorSpace;
2673 void GfxState::setFillPattern(GfxPattern *pattern) {
2677 fillPattern = pattern;
2680 void GfxState::setStrokePattern(GfxPattern *pattern) {
2681 if (strokePattern) {
2682 delete strokePattern;
2684 strokePattern = pattern;
2687 void GfxState::setLineDash(double *dash, int length, double start) {
2691 lineDashLength = length;
2692 lineDashStart = start;
2695 void GfxState::clearPath() {
2697 path = new GfxPath();
2700 void GfxState::clip() {
2701 double xMin, yMin, xMax, yMax, x, y;
2702 GfxSubpath *subpath;
2705 xMin = xMax = yMin = yMax = 0; // make gcc happy
2706 for (i = 0; i < path->getNumSubpaths(); ++i) {
2707 subpath = path->getSubpath(i);
2708 for (j = 0; j < subpath->getNumPoints(); ++j) {
2709 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2710 if (i == 0 && j == 0) {
2716 } else if (x > xMax) {
2721 } else if (y > yMax) {
2727 if (xMin > clipXMin) {
2730 if (yMin > clipYMin) {
2733 if (xMax < clipXMax) {
2736 if (yMax < clipYMax) {
2741 void GfxState::textShift(double tx, double ty) {
2744 textTransformDelta(tx, ty, &dx, &dy);
2749 void GfxState::shift(double dx, double dy) {
2754 GfxState *GfxState::save() {
2758 newState->saved = this;
2762 GfxState *GfxState::restore() {
2768 // these attributes aren't saved/restored by the q/Q operators
2769 oldState->path = path;
2770 oldState->curX = curX;
2771 oldState->curY = curY;
2772 oldState->lineX = lineX;
2773 oldState->lineY = lineY;