1 //========================================================================
5 // Copyright 1996-2002 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 '%s'", csObj->getName());
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, aw, ac, am, ay, ar, ag, ab;
440 /* FIXME ask Derek */
441 if (color->c[0] == 0.0 && color->c[1] == 0 && color->c[2] == 0) {
442 rgb->r = rgb->g = rgb->b = 1 - color->c[3];
446 c = clip01(color->c[0] + color->c[3]);
447 m = clip01(color->c[1] + color->c[3]);
448 y = clip01(color->c[2] + color->c[3]);
449 aw = (1-c) * (1-m) * (1-y);
450 ac = c * (1-m) * (1-y);
451 am = (1-c) * m * (1-y);
452 ay = (1-c) * (1-m) * y;
456 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
457 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
458 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
462 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
463 cmyk->c = clip01(color->c[0]);
464 cmyk->m = clip01(color->c[1]);
465 cmyk->y = clip01(color->c[2]);
466 cmyk->k = clip01(color->c[3]);
469 //------------------------------------------------------------------------
471 //------------------------------------------------------------------------
473 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
474 // Language Reference, Third Edition.
475 static double xyzrgb[3][3] = {
476 { 3.240449, -1.537136, -0.498531 },
477 { -0.969265, 1.876011, 0.041556 },
478 { 0.055643, -0.204026, 1.057229 }
481 GfxLabColorSpace::GfxLabColorSpace() {
482 whiteX = whiteY = whiteZ = 1;
483 blackX = blackY = blackZ = 0;
488 GfxLabColorSpace::~GfxLabColorSpace() {
491 GfxColorSpace *GfxLabColorSpace::copy() {
492 GfxLabColorSpace *cs;
494 cs = new GfxLabColorSpace();
511 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
512 GfxLabColorSpace *cs;
513 Object obj1, obj2, obj3;
516 if (!obj1.isDict()) {
517 error(-1, "Bad Lab color space");
521 cs = new GfxLabColorSpace();
522 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
523 obj2.arrayGetLength() == 3) {
524 obj2.arrayGet(0, &obj3);
525 cs->whiteX = obj3.getNum();
527 obj2.arrayGet(1, &obj3);
528 cs->whiteY = obj3.getNum();
530 obj2.arrayGet(2, &obj3);
531 cs->whiteZ = obj3.getNum();
535 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
536 obj2.arrayGetLength() == 3) {
537 obj2.arrayGet(0, &obj3);
538 cs->blackX = obj3.getNum();
540 obj2.arrayGet(1, &obj3);
541 cs->blackY = obj3.getNum();
543 obj2.arrayGet(2, &obj3);
544 cs->blackZ = obj3.getNum();
548 if (obj1.dictLookup("Range", &obj2)->isArray() &&
549 obj2.arrayGetLength() == 4) {
550 obj2.arrayGet(0, &obj3);
551 cs->aMin = obj3.getNum();
553 obj2.arrayGet(1, &obj3);
554 cs->aMax = obj3.getNum();
556 obj2.arrayGet(2, &obj3);
557 cs->bMin = obj3.getNum();
559 obj2.arrayGet(3, &obj3);
560 cs->bMax = obj3.getNum();
566 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
567 xyzrgb[0][1] * cs->whiteY +
568 xyzrgb[0][2] * cs->whiteZ);
569 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
570 xyzrgb[1][1] * cs->whiteY +
571 xyzrgb[1][2] * cs->whiteZ);
572 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
573 xyzrgb[2][1] * cs->whiteY +
574 xyzrgb[2][2] * cs->whiteZ);
579 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
583 *gray = clip01(0.299 * rgb.r +
588 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
593 // convert L*a*b* to CIE 1931 XYZ color space
594 t1 = (color->c[0] + 16) / 116;
595 t2 = t1 + color->c[1] / 500;
596 if (t2 >= (6.0 / 29.0)) {
599 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
602 if (t1 >= (6.0 / 29.0)) {
605 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
608 t2 = t1 - color->c[2] / 200;
609 if (t2 >= (6.0 / 29.0)) {
612 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
616 // convert XYZ to RGB, including gamut mapping and gamma correction
617 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
618 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
619 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
620 rgb->r = pow(clip01(r * kr), 0.5);
621 rgb->g = pow(clip01(g * kg), 0.5);
622 rgb->b = pow(clip01(b * kb), 0.5);
625 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
630 c = clip01(1 - rgb.r);
631 m = clip01(1 - rgb.g);
632 y = clip01(1 - rgb.b);
646 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
649 decodeRange[0] = 100;
651 decodeRange[1] = aMax - aMin;
653 decodeRange[2] = bMax - bMin;
656 //------------------------------------------------------------------------
657 // GfxICCBasedColorSpace
658 //------------------------------------------------------------------------
660 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
661 Ref *iccProfileStreamA) {
664 iccProfileStream = *iccProfileStreamA;
665 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
666 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
669 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
673 GfxColorSpace *GfxICCBasedColorSpace::copy() {
674 GfxICCBasedColorSpace *cs;
677 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
678 for (i = 0; i < 4; ++i) {
679 cs->rangeMin[i] = rangeMin[i];
680 cs->rangeMax[i] = rangeMax[i];
685 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
686 GfxICCBasedColorSpace *cs;
687 Ref iccProfileStreamA;
691 Object obj1, obj2, obj3;
694 arr->getNF(1, &obj1);
696 iccProfileStreamA = obj1.getRef();
698 iccProfileStreamA.num = 0;
699 iccProfileStreamA.gen = 0;
703 if (!obj1.isStream()) {
704 error(-1, "Bad ICCBased color space (stream)");
708 dict = obj1.streamGetDict();
709 if (!dict->lookup("N", &obj2)->isInt()) {
710 error(-1, "Bad ICCBased color space (N)");
715 nCompsA = obj2.getInt();
717 if (dict->lookup("Alternate", &obj2)->isNull() ||
718 !(altA = GfxColorSpace::parse(&obj2))) {
721 altA = new GfxDeviceGrayColorSpace();
724 altA = new GfxDeviceRGBColorSpace();
727 altA = new GfxDeviceCMYKColorSpace();
730 error(-1, "Bad ICCBased color space - invalid N");
737 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
738 if (dict->lookup("Range", &obj2)->isArray() &&
739 obj2.arrayGetLength() == 2 * nCompsA) {
740 for (i = 0; i < nCompsA; ++i) {
741 obj2.arrayGet(2*i, &obj3);
742 cs->rangeMin[i] = obj3.getNum();
744 obj2.arrayGet(2*i+1, &obj3);
745 cs->rangeMax[i] = obj3.getNum();
754 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
755 alt->getGray(color, gray);
758 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
759 alt->getRGB(color, rgb);
762 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
763 alt->getCMYK(color, cmyk);
766 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
771 for (i = 0; i < nComps; ++i) {
772 decodeLow[i] = rangeMin[i];
773 decodeRange[i] = rangeMax[i] - rangeMin[i];
777 //------------------------------------------------------------------------
778 // GfxIndexedColorSpace
779 //------------------------------------------------------------------------
781 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
784 indexHigh = indexHighA;
785 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
789 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
794 GfxColorSpace *GfxIndexedColorSpace::copy() {
795 GfxIndexedColorSpace *cs;
797 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
798 memcpy(cs->lookup, lookup,
799 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
803 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
804 GfxIndexedColorSpace *cs;
805 GfxColorSpace *baseA;
812 if (arr->getLength() != 4) {
813 error(-1, "Bad Indexed color space");
817 if (!(baseA = GfxColorSpace::parse(&obj1))) {
818 error(-1, "Bad Indexed color space (base color space)");
822 if (!arr->get(2, &obj1)->isInt()) {
823 error(-1, "Bad Indexed color space (hival)");
827 indexHighA = obj1.getInt();
828 if (indexHighA < 0 || indexHighA > 255) {
829 // the PDF spec requires indexHigh to be in [0,255] -- allowing
830 // values larger than 255 creates a security hole: if nComps *
831 // indexHigh is greater than 2^31, the loop below may overwrite
832 // past the end of the array
833 error(-1, "Bad Indexed color space (invalid indexHigh value)");
838 cs = new GfxIndexedColorSpace(baseA, indexHighA);
840 n = baseA->getNComps();
841 if (obj1.isStream()) {
843 for (i = 0; i <= indexHighA; ++i) {
844 for (j = 0; j < n; ++j) {
845 if ((x = obj1.streamGetChar()) == EOF) {
846 error(-1, "Bad Indexed color space (lookup table stream too short)");
849 cs->lookup[i*n + j] = (Guchar)x;
853 } else if (obj1.isString()) {
854 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
855 error(-1, "Bad Indexed color space (lookup table string too short)");
858 s = obj1.getString()->getCString();
859 for (i = 0; i <= indexHighA; ++i) {
860 for (j = 0; j < n; ++j) {
861 cs->lookup[i*n + j] = (Guchar)*s++;
865 error(-1, "Bad Indexed color space (lookup table)");
879 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
880 GfxColor *baseColor) {
882 double low[gfxColorMaxComps], range[gfxColorMaxComps];
885 n = base->getNComps();
886 base->getDefaultRanges(low, range, indexHigh);
887 p = &lookup[(int)(color->c[0] + 0.5) * n];
888 for (i = 0; i < n; ++i) {
889 baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
894 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
897 base->getGray(mapColorToBase(color, &color2), gray);
900 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
903 base->getRGB(mapColorToBase(color, &color2), rgb);
906 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
909 base->getCMYK(mapColorToBase(color, &color2), cmyk);
912 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
916 decodeRange[0] = maxImgPixel;
919 //------------------------------------------------------------------------
920 // GfxSeparationColorSpace
921 //------------------------------------------------------------------------
923 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
931 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
937 GfxColorSpace *GfxSeparationColorSpace::copy() {
938 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
941 //~ handle the 'All' and 'None' colorants
942 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
943 GfxSeparationColorSpace *cs;
949 if (arr->getLength() != 4) {
950 error(-1, "Bad Separation color space");
953 if (!arr->get(1, &obj1)->isName()) {
954 error(-1, "Bad Separation color space (name)");
957 nameA = new GString(obj1.getName());
960 if (!(altA = GfxColorSpace::parse(&obj1))) {
961 error(-1, "Bad Separation color space (alternate color space)");
966 if (!(funcA = Function::parse(&obj1))) {
970 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
983 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
986 func->transform(color->c, color2.c);
987 alt->getGray(&color2, gray);
990 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
993 func->transform(color->c, color2.c);
994 alt->getRGB(&color2, rgb);
997 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1000 func->transform(color->c, color2.c);
1001 alt->getCMYK(&color2, cmyk);
1004 //------------------------------------------------------------------------
1005 // GfxDeviceNColorSpace
1006 //------------------------------------------------------------------------
1008 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1009 GfxColorSpace *altA,
1016 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1019 for (i = 0; i < nComps; ++i) {
1026 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1027 GfxDeviceNColorSpace *cs;
1030 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1031 for (i = 0; i < nComps; ++i) {
1032 cs->names[i] = names[i]->copy();
1037 //~ handle the 'None' colorant
1038 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1039 GfxDeviceNColorSpace *cs;
1041 GString *namesA[gfxColorMaxComps];
1042 GfxColorSpace *altA;
1047 if (arr->getLength() != 4 && arr->getLength() != 5) {
1048 error(-1, "Bad DeviceN color space");
1051 if (!arr->get(1, &obj1)->isArray()) {
1052 error(-1, "Bad DeviceN color space (names)");
1055 nCompsA = obj1.arrayGetLength();
1056 for (i = 0; i < nCompsA; ++i) {
1057 if (!obj1.arrayGet(i, &obj2)->isName()) {
1058 error(-1, "Bad DeviceN color space (names)");
1062 namesA[i] = new GString(obj2.getName());
1067 if (!(altA = GfxColorSpace::parse(&obj1))) {
1068 error(-1, "Bad DeviceN color space (alternate color space)");
1073 if (!(funcA = Function::parse(&obj1))) {
1077 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1078 for (i = 0; i < nCompsA; ++i) {
1079 cs->names[i] = namesA[i];
1086 for (i = 0; i < nCompsA; ++i) {
1095 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1098 func->transform(color->c, color2.c);
1099 alt->getGray(&color2, gray);
1102 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1105 func->transform(color->c, color2.c);
1106 alt->getRGB(&color2, rgb);
1109 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1112 func->transform(color->c, color2.c);
1113 alt->getCMYK(&color2, cmyk);
1116 //------------------------------------------------------------------------
1117 // GfxPatternColorSpace
1118 //------------------------------------------------------------------------
1120 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1124 GfxPatternColorSpace::~GfxPatternColorSpace() {
1130 GfxColorSpace *GfxPatternColorSpace::copy() {
1131 return new GfxPatternColorSpace(under ? under->copy() :
1132 (GfxColorSpace *)NULL);
1135 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1136 GfxPatternColorSpace *cs;
1137 GfxColorSpace *underA;
1140 if (arr->getLength() != 1 && arr->getLength() != 2) {
1141 error(-1, "Bad Pattern color space");
1145 if (arr->getLength() == 2) {
1147 if (!(underA = GfxColorSpace::parse(&obj1))) {
1148 error(-1, "Bad Pattern color space (underlying color space)");
1154 cs = new GfxPatternColorSpace(underA);
1158 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1162 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1163 rgb->r = rgb->g = rgb->b = 0;
1166 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1167 cmyk->c = cmyk->m = cmyk->y = 0;
1171 //------------------------------------------------------------------------
1173 //------------------------------------------------------------------------
1175 GfxPattern::GfxPattern(int typeA) {
1179 GfxPattern::~GfxPattern() {
1182 GfxPattern *GfxPattern::parse(Object *obj) {
1183 GfxPattern *pattern;
1188 if (obj->isStream()) {
1189 dict = obj->streamGetDict();
1190 dict->lookup("PatternType", &obj1);
1191 if (obj1.isInt() && obj1.getInt() == 1) {
1192 pattern = new GfxTilingPattern(dict, obj);
1199 //------------------------------------------------------------------------
1201 //------------------------------------------------------------------------
1203 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1209 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1210 paintType = obj1.getInt();
1213 error(-1, "Invalid or missing PaintType in pattern");
1216 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1217 tilingType = obj1.getInt();
1220 error(-1, "Invalid or missing TilingType in pattern");
1223 bbox[0] = bbox[1] = 0;
1224 bbox[2] = bbox[3] = 1;
1225 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1226 obj1.arrayGetLength() == 4) {
1227 for (i = 0; i < 4; ++i) {
1228 if (obj1.arrayGet(i, &obj2)->isNum()) {
1229 bbox[i] = obj2.getNum();
1234 error(-1, "Invalid or missing BBox in pattern");
1237 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1238 xStep = obj1.getNum();
1241 error(-1, "Invalid or missing XStep in pattern");
1244 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1245 yStep = obj1.getNum();
1248 error(-1, "Invalid or missing YStep in pattern");
1251 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1254 error(-1, "Invalid or missing Resources in pattern");
1256 matrix[0] = 1; matrix[1] = 0;
1257 matrix[2] = 0; matrix[3] = 1;
1258 matrix[4] = 0; matrix[5] = 0;
1259 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1260 obj1.arrayGetLength() == 6) {
1261 for (i = 0; i < 6; ++i) {
1262 if (obj1.arrayGet(i, &obj2)->isNum()) {
1263 matrix[i] = obj2.getNum();
1269 stream->copy(&contentStream);
1272 GfxTilingPattern::~GfxTilingPattern() {
1274 contentStream.free();
1277 GfxPattern *GfxTilingPattern::copy() {
1278 return new GfxTilingPattern(this);
1281 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1284 memcpy(this, pat, sizeof(GfxTilingPattern));
1285 pat->resDict.copy(&resDict);
1286 pat->contentStream.copy(&contentStream);
1289 //------------------------------------------------------------------------
1291 //------------------------------------------------------------------------
1293 GfxShading::GfxShading() {
1296 GfxShading::~GfxShading() {
1300 GfxShading *GfxShading::parse(Object *obj) {
1301 GfxShading *shading;
1303 GfxColorSpace *colorSpaceA;
1304 GfxColor backgroundA;
1305 GBool hasBackgroundA;
1306 double xMinA, yMinA, xMaxA, yMaxA;
1312 if (obj->isDict()) {
1314 if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1315 error(-1, "Invalid ShadingType in shading dictionary");
1319 typeA = obj1.getInt();
1322 obj->dictLookup("ColorSpace", &obj1);
1323 if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1324 error(-1, "Bad color space in shading dictionary");
1330 for (i = 0; i < gfxColorMaxComps; ++i) {
1331 backgroundA.c[i] = 0;
1333 hasBackgroundA = gFalse;
1334 if (obj->dictLookup("Background", &obj1)->isArray()) {
1335 if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1336 hasBackgroundA = gTrue;
1337 for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1338 backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1342 error(-1, "Bad Background in shading dictionary");
1347 xMinA = yMinA = xMaxA = yMaxA = 0;
1349 if (obj->dictLookup("BBox", &obj1)->isArray()) {
1350 if (obj1.arrayGetLength() == 4) {
1352 xMinA = obj1.arrayGet(0, &obj2)->getNum();
1354 yMinA = obj1.arrayGet(1, &obj2)->getNum();
1356 xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1358 yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1361 error(-1, "Bad BBox in shading dictionary");
1368 shading = GfxAxialShading::parse(obj->getDict());
1371 shading = GfxRadialShading::parse(obj->getDict());
1374 error(-1, "Unimplemented shading type %d", typeA);
1379 shading->type = typeA;
1380 shading->colorSpace = colorSpaceA;
1381 shading->background = backgroundA;
1382 shading->hasBackground = hasBackgroundA;
1383 shading->xMin = xMinA;
1384 shading->yMin = yMinA;
1385 shading->xMax = xMaxA;
1386 shading->yMax = yMaxA;
1387 shading->hasBBox = hasBBoxA;
1399 //------------------------------------------------------------------------
1401 //------------------------------------------------------------------------
1403 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1404 double x1A, double y1A,
1405 double t0A, double t1A,
1406 Function **funcsA, int nFuncsA,
1407 GBool extend0A, GBool extend1A) {
1417 for (i = 0; i < nFuncs; ++i) {
1418 funcs[i] = funcsA[i];
1424 GfxAxialShading::~GfxAxialShading() {
1427 for (i = 0; i < nFuncs; ++i) {
1432 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1433 double x0A, y0A, x1A, y1A;
1435 Function *funcsA[gfxColorMaxComps];
1437 GBool extend0A, extend1A;
1441 x0A = y0A = x1A = y1A = 0;
1442 if (dict->lookup("Coords", &obj1)->isArray() &&
1443 obj1.arrayGetLength() == 4) {
1444 x0A = obj1.arrayGet(0, &obj2)->getNum();
1446 y0A = obj1.arrayGet(1, &obj2)->getNum();
1448 x1A = obj1.arrayGet(2, &obj2)->getNum();
1450 y1A = obj1.arrayGet(3, &obj2)->getNum();
1453 error(-1, "Missing or invalid Coords in shading dictionary");
1460 if (dict->lookup("Domain", &obj1)->isArray() &&
1461 obj1.arrayGetLength() == 2) {
1462 t0A = obj1.arrayGet(0, &obj2)->getNum();
1464 t1A = obj1.arrayGet(1, &obj2)->getNum();
1469 dict->lookup("Function", &obj1);
1470 if (obj1.isArray()) {
1471 nFuncsA = obj1.arrayGetLength();
1472 for (i = 0; i < nFuncsA; ++i) {
1473 obj1.arrayGet(i, &obj2);
1474 if (!(funcsA[i] = Function::parse(&obj2))) {
1483 if (!(funcsA[0] = Function::parse(&obj1))) {
1490 extend0A = extend1A = gFalse;
1491 if (dict->lookup("Extend", &obj1)->isArray() &&
1492 obj1.arrayGetLength() == 2) {
1493 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1495 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1500 return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1501 funcsA, nFuncsA, extend0A, extend1A);
1507 void GfxAxialShading::getColor(double t, GfxColor *color) {
1510 for (i = 0; i < nFuncs; ++i) {
1511 funcs[i]->transform(&t, &color->c[i]);
1515 //------------------------------------------------------------------------
1517 //------------------------------------------------------------------------
1519 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1520 double x1A, double y1A, double r1A,
1521 double t0A, double t1A,
1522 Function **funcsA, int nFuncsA,
1523 GBool extend0A, GBool extend1A) {
1535 for (i = 0; i < nFuncs; ++i) {
1536 funcs[i] = funcsA[i];
1542 GfxRadialShading::~GfxRadialShading() {
1545 for (i = 0; i < nFuncs; ++i) {
1550 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1551 double x0A, y0A, r0A, x1A, y1A, r1A;
1553 Function *funcsA[gfxColorMaxComps];
1555 GBool extend0A, extend1A;
1559 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1560 if (dict->lookup("Coords", &obj1)->isArray() &&
1561 obj1.arrayGetLength() == 6) {
1562 x0A = obj1.arrayGet(0, &obj2)->getNum();
1564 y0A = obj1.arrayGet(1, &obj2)->getNum();
1566 r0A = obj1.arrayGet(2, &obj2)->getNum();
1568 x1A = obj1.arrayGet(3, &obj2)->getNum();
1570 y1A = obj1.arrayGet(4, &obj2)->getNum();
1572 r1A = obj1.arrayGet(5, &obj2)->getNum();
1575 error(-1, "Missing or invalid Coords in shading dictionary");
1582 if (dict->lookup("Domain", &obj1)->isArray() &&
1583 obj1.arrayGetLength() == 2) {
1584 t0A = obj1.arrayGet(0, &obj2)->getNum();
1586 t1A = obj1.arrayGet(1, &obj2)->getNum();
1591 dict->lookup("Function", &obj1);
1592 if (obj1.isArray()) {
1593 nFuncsA = obj1.arrayGetLength();
1594 for (i = 0; i < nFuncsA; ++i) {
1595 obj1.arrayGet(i, &obj2);
1596 if (!(funcsA[i] = Function::parse(&obj2))) {
1605 if (!(funcsA[0] = Function::parse(&obj1))) {
1612 extend0A = extend1A = gFalse;
1613 if (dict->lookup("Extend", &obj1)->isArray() &&
1614 obj1.arrayGetLength() == 2) {
1615 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1617 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1622 return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1623 funcsA, nFuncsA, extend0A, extend1A);
1629 void GfxRadialShading::getColor(double t, GfxColor *color) {
1632 for (i = 0; i < nFuncs; ++i) {
1633 funcs[i]->transform(&t, &color->c[i]);
1637 //------------------------------------------------------------------------
1639 //------------------------------------------------------------------------
1641 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1642 GfxColorSpace *colorSpaceA) {
1643 GfxIndexedColorSpace *indexedCS;
1644 GfxSeparationColorSpace *sepCS;
1645 int maxPixel, indexHigh;
1649 double x[gfxColorMaxComps];
1650 double y[gfxColorMaxComps];
1655 // bits per component and color space
1657 maxPixel = (1 << bits) - 1;
1658 colorSpace = colorSpaceA;
1661 if (decode->isNull()) {
1662 nComps = colorSpace->getNComps();
1663 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1664 } else if (decode->isArray()) {
1665 nComps = decode->arrayGetLength() / 2;
1666 if (nComps != colorSpace->getNComps()) {
1669 for (i = 0; i < nComps; ++i) {
1670 decode->arrayGet(2*i, &obj);
1674 decodeLow[i] = obj.getNum();
1676 decode->arrayGet(2*i+1, &obj);
1680 decodeRange[i] = obj.getNum() - decodeLow[i];
1687 // Construct a lookup table -- this stores pre-computed decoded
1688 // values for each component, i.e., the result of applying the
1689 // decode mapping to each possible image pixel component value.
1691 // Optimization: for Indexed and Separation color spaces (which have
1692 // only one component), we store color values in the lookup table
1693 // rather than component values.
1696 if (colorSpace->getMode() == csIndexed) {
1697 // Note that indexHigh may not be the same as maxPixel --
1698 // Distiller will remove unused palette entries, resulting in
1699 // indexHigh < maxPixel.
1700 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1701 colorSpace2 = indexedCS->getBase();
1702 indexHigh = indexedCS->getIndexHigh();
1703 nComps2 = colorSpace2->getNComps();
1704 lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1705 lookup2 = indexedCS->getLookup();
1706 colorSpace2->getDefaultRanges(x, y, indexHigh);
1707 for (i = 0; i <= indexHigh; ++i) {
1708 j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
1709 for (k = 0; k < nComps2; ++k) {
1710 lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k];
1713 } else if (colorSpace->getMode() == csSeparation) {
1714 sepCS = (GfxSeparationColorSpace *)colorSpace;
1715 colorSpace2 = sepCS->getAlt();
1716 nComps2 = colorSpace2->getNComps();
1717 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1718 sepFunc = sepCS->getFunc();
1719 for (i = 0; i <= maxPixel; ++i) {
1720 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1721 sepFunc->transform(x, y);
1722 for (k = 0; k < nComps2; ++k) {
1723 lookup[i*nComps2 + k] = y[k];
1727 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1728 for (i = 0; i <= maxPixel; ++i) {
1729 for (k = 0; k < nComps; ++k) {
1730 lookup[i*nComps + k] = decodeLow[k] +
1731 (i * decodeRange[k]) / maxPixel;
1744 GfxImageColorMap::~GfxImageColorMap() {
1749 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1755 p = &lookup[x[0] * nComps2];
1756 for (i = 0; i < nComps2; ++i) {
1759 colorSpace2->getGray(&color, gray);
1761 for (i = 0; i < nComps; ++i) {
1762 color.c[i] = lookup[x[i] * nComps + i];
1764 colorSpace->getGray(&color, gray);
1768 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1774 p = &lookup[x[0] * nComps2];
1775 for (i = 0; i < nComps2; ++i) {
1778 colorSpace2->getRGB(&color, rgb);
1780 for (i = 0; i < nComps; ++i) {
1781 color.c[i] = lookup[x[i] * nComps + i];
1783 colorSpace->getRGB(&color, rgb);
1787 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1793 p = &lookup[x[0] * nComps2];
1794 for (i = 0; i < nComps2; ++i) {
1797 colorSpace2->getCMYK(&color, cmyk);
1799 for (i = 0; i < nComps; ++i) {
1800 color.c[i] = lookup[x[i] * nComps + i];
1802 colorSpace->getCMYK(&color, cmyk);
1806 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
1809 maxPixel = (1 << bits) - 1;
1810 for (i = 0; i < nComps; ++i) {
1811 color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
1815 //------------------------------------------------------------------------
1816 // GfxSubpath and GfxPath
1817 //------------------------------------------------------------------------
1819 GfxSubpath::GfxSubpath(double x1, double y1) {
1821 x = (double *)gmalloc(size * sizeof(double));
1822 y = (double *)gmalloc(size * sizeof(double));
1823 curve = (GBool *)gmalloc(size * sizeof(GBool));
1831 GfxSubpath::~GfxSubpath() {
1838 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1839 size = subpath->size;
1841 x = (double *)gmalloc(size * sizeof(double));
1842 y = (double *)gmalloc(size * sizeof(double));
1843 curve = (GBool *)gmalloc(size * sizeof(GBool));
1844 memcpy(x, subpath->x, n * sizeof(double));
1845 memcpy(y, subpath->y, n * sizeof(double));
1846 memcpy(curve, subpath->curve, n * sizeof(GBool));
1847 closed = subpath->closed;
1850 void GfxSubpath::lineTo(double x1, double y1) {
1853 x = (double *)grealloc(x, size * sizeof(double));
1854 y = (double *)grealloc(y, size * sizeof(double));
1855 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1863 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1864 double x3, double y3) {
1867 x = (double *)grealloc(x, size * sizeof(double));
1868 y = (double *)grealloc(y, size * sizeof(double));
1869 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1877 curve[n] = curve[n+1] = gTrue;
1878 curve[n+2] = gFalse;
1882 void GfxSubpath::close() {
1883 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1889 GfxPath::GfxPath() {
1893 firstX = firstY = 0;
1894 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1897 GfxPath::~GfxPath() {
1900 for (i = 0; i < n; ++i)
1906 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1907 GfxSubpath **subpaths1, int n1, int size1) {
1910 justMoved = justMoved1;
1915 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1916 for (i = 0; i < n; ++i)
1917 subpaths[i] = subpaths1[i]->copy();
1920 void GfxPath::moveTo(double x, double y) {
1926 void GfxPath::lineTo(double x, double y) {
1930 subpaths = (GfxSubpath **)
1931 grealloc(subpaths, size * sizeof(GfxSubpath *));
1933 subpaths[n] = new GfxSubpath(firstX, firstY);
1937 subpaths[n-1]->lineTo(x, y);
1940 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1941 double x3, double y3) {
1945 subpaths = (GfxSubpath **)
1946 grealloc(subpaths, size * sizeof(GfxSubpath *));
1948 subpaths[n] = new GfxSubpath(firstX, firstY);
1952 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1955 void GfxPath::close() {
1956 // this is necessary to handle the pathological case of
1957 // moveto/closepath/clip, which defines an empty clipping region
1961 subpaths = (GfxSubpath **)
1962 grealloc(subpaths, size * sizeof(GfxSubpath *));
1964 subpaths[n] = new GfxSubpath(firstX, firstY);
1968 subpaths[n-1]->close();
1971 //------------------------------------------------------------------------
1973 //------------------------------------------------------------------------
1975 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
1986 ctm[1] = upsideDown ? k : -k;
1990 ctm[5] = k * (upsideDown ? -px1 : px2);
1991 pageWidth = k * (py2 - py1);
1992 pageHeight = k * (px2 - px1);
1993 } else if (rotate == 180) {
1997 ctm[3] = upsideDown ? k : -k;
1999 ctm[5] = k * (upsideDown ? -py1 : py2);
2000 pageWidth = k * (px2 - px1);
2001 pageHeight = k * (py2 - py1);
2002 } else if (rotate == 270) {
2004 ctm[1] = upsideDown ? -k : k;
2008 ctm[5] = k * (upsideDown ? px2 : -px1);
2009 pageWidth = k * (py2 - py1);
2010 pageHeight = k * (px2 - px1);
2015 ctm[3] = upsideDown ? -k : k;
2017 ctm[5] = k * (upsideDown ? py2 : -py1);
2018 pageWidth = k * (px2 - px1);
2019 pageHeight = k * (py2 - py1);
2022 fillColorSpace = new GfxDeviceGrayColorSpace();
2023 strokeColorSpace = new GfxDeviceGrayColorSpace();
2025 strokeColor.c[0] = 0;
2027 strokePattern = NULL;
2042 textMat[0] = 1; textMat[1] = 0;
2043 textMat[2] = 0; textMat[3] = 1;
2044 textMat[4] = 0; textMat[5] = 0;
2052 path = new GfxPath();
2058 clipXMax = pageWidth;
2059 clipYMax = pageHeight;
2064 GfxState::~GfxState() {
2065 if (fillColorSpace) {
2066 delete fillColorSpace;
2068 if (strokeColorSpace) {
2069 delete strokeColorSpace;
2074 if (strokePattern) {
2075 delete strokePattern;
2079 // this gets set to NULL by restore()
2088 GfxState::GfxState(GfxState *state) {
2089 memcpy(this, state, sizeof(GfxState));
2090 if (fillColorSpace) {
2091 fillColorSpace = state->fillColorSpace->copy();
2093 if (strokeColorSpace) {
2094 strokeColorSpace = state->strokeColorSpace->copy();
2097 fillPattern = state->fillPattern->copy();
2099 if (strokePattern) {
2100 strokePattern = state->strokePattern->copy();
2102 if (lineDashLength > 0) {
2103 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2104 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2109 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2110 double *xMax, double *yMax) {
2112 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2115 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2116 ictm[0] = ctm[3] * det;
2117 ictm[1] = -ctm[1] * det;
2118 ictm[2] = -ctm[2] * det;
2119 ictm[3] = ctm[0] * det;
2120 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2121 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2123 // transform all four corners of the clip bbox; find the min and max
2125 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2126 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2127 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2128 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2131 } else if (tx > xMax1) {
2136 } else if (ty > yMax1) {
2139 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2140 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2143 } else if (tx > xMax1) {
2148 } else if (ty > yMax1) {
2151 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2152 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2155 } else if (tx > xMax1) {
2160 } else if (ty > yMax1) {
2170 double GfxState::transformWidth(double w) {
2173 x = ctm[0] + ctm[2];
2174 y = ctm[1] + ctm[3];
2175 return w * sqrt(0.5 * (x * x + y * y));
2178 double GfxState::getTransformedFontSize() {
2179 double x1, y1, x2, y2;
2181 x1 = textMat[2] * fontSize;
2182 y1 = textMat[3] * fontSize;
2183 x2 = ctm[0] * x1 + ctm[2] * y1;
2184 y2 = ctm[1] * x1 + ctm[3] * y1;
2185 return sqrt(x2 * x2 + y2 * y2);
2188 void GfxState::getFontTransMat(double *m11, double *m12,
2189 double *m21, double *m22) {
2190 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2191 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2192 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2193 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2196 void GfxState::setCTM(double a, double b, double c,
2197 double d, double e, double f) {
2207 // avoid FP exceptions on badly messed up PDF files
2208 for (i = 0; i < 6; ++i) {
2209 if (ctm[i] > 1e10) {
2211 } else if (ctm[i] < -1e10) {
2217 void GfxState::concatCTM(double a, double b, double c,
2218 double d, double e, double f) {
2225 ctm[0] = a * a1 + b * c1;
2226 ctm[1] = a * b1 + b * d1;
2227 ctm[2] = c * a1 + d * c1;
2228 ctm[3] = c * b1 + d * d1;
2229 ctm[4] = e * a1 + f * c1 + ctm[4];
2230 ctm[5] = e * b1 + f * d1 + ctm[5];
2232 // avoid FP exceptions on badly messed up PDF files
2233 for (i = 0; i < 6; ++i) {
2234 if (ctm[i] > 1e10) {
2236 } else if (ctm[i] < -1e10) {
2242 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2243 if (fillColorSpace) {
2244 delete fillColorSpace;
2246 fillColorSpace = colorSpace;
2249 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2250 if (strokeColorSpace) {
2251 delete strokeColorSpace;
2253 strokeColorSpace = colorSpace;
2256 void GfxState::setFillPattern(GfxPattern *pattern) {
2260 fillPattern = pattern;
2263 void GfxState::setStrokePattern(GfxPattern *pattern) {
2264 if (strokePattern) {
2265 delete strokePattern;
2267 strokePattern = pattern;
2270 void GfxState::setLineDash(double *dash, int length, double start) {
2274 lineDashLength = length;
2275 lineDashStart = start;
2278 void GfxState::clearPath() {
2280 path = new GfxPath();
2283 void GfxState::clip() {
2284 double xMin, yMin, xMax, yMax, x, y;
2285 GfxSubpath *subpath;
2288 xMin = xMax = yMin = yMax = 0; // make gcc happy
2289 for (i = 0; i < path->getNumSubpaths(); ++i) {
2290 subpath = path->getSubpath(i);
2291 for (j = 0; j < subpath->getNumPoints(); ++j) {
2292 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2293 if (i == 0 && j == 0) {
2299 } else if (x > xMax) {
2304 } else if (y > yMax) {
2310 if (xMin > clipXMin) {
2313 if (yMin > clipYMin) {
2316 if (xMax < clipXMax) {
2319 if (yMax < clipYMax) {
2324 void GfxState::textShift(double tx, double ty) {
2327 textTransformDelta(tx, ty, &dx, &dy);
2332 void GfxState::shift(double dx, double dy) {
2337 GfxState *GfxState::save() {
2341 newState->saved = this;
2345 GfxState *GfxState::restore() {
2351 // these attributes aren't saved/restored by the q/Q operators
2352 oldState->path = path;
2353 oldState->curX = curX;
2354 oldState->curY = curY;
2355 oldState->lineX = lineX;
2356 oldState->lineY = lineY;