1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
16 #include <string.h> // for memcpy()
24 //------------------------------------------------------------------------
26 static inline double clip01(double x) {
27 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 GfxColorSpace::GfxColorSpace() {
37 GfxColorSpace::~GfxColorSpace() {
40 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
45 if (csObj->isName()) {
46 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
47 cs = new GfxDeviceGrayColorSpace();
48 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
49 cs = new GfxDeviceRGBColorSpace();
50 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
51 cs = new GfxDeviceCMYKColorSpace();
52 } else if (csObj->isName("Pattern")) {
53 cs = new GfxPatternColorSpace(NULL);
55 error(-1, "Bad color space '%s'", csObj->getName());
57 } else if (csObj->isArray()) {
58 csObj->arrayGet(0, &obj1);
59 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
60 cs = new GfxDeviceGrayColorSpace();
61 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
62 cs = new GfxDeviceRGBColorSpace();
63 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
64 cs = new GfxDeviceCMYKColorSpace();
65 } else if (obj1.isName("CalGray")) {
66 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
67 } else if (obj1.isName("CalRGB")) {
68 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
69 } else if (obj1.isName("Lab")) {
70 cs = GfxLabColorSpace::parse(csObj->getArray());
71 } else if (obj1.isName("ICCBased")) {
72 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
73 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
74 cs = GfxIndexedColorSpace::parse(csObj->getArray());
75 } else if (obj1.isName("Separation")) {
76 cs = GfxSeparationColorSpace::parse(csObj->getArray());
77 } else if (obj1.isName("DeviceN")) {
78 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
79 } else if (obj1.isName("Pattern")) {
80 cs = GfxPatternColorSpace::parse(csObj->getArray());
82 error(-1, "Bad color space '%s'", csObj->getName());
86 error(-1, "Bad color space - expected name or array");
91 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
95 for (i = 0; i < getNComps(); ++i) {
101 //------------------------------------------------------------------------
102 // GfxDeviceGrayColorSpace
103 //------------------------------------------------------------------------
105 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
108 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
111 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
115 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
116 *gray = clip01(color->c[0]);
119 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
120 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
123 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
124 cmyk->c = cmyk->m = cmyk->y = 0;
125 cmyk->k = clip01(1 - color->c[0]);
128 //------------------------------------------------------------------------
129 // GfxCalGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX = whiteY = whiteZ = 1;
134 blackX = blackY = blackZ = 0;
138 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
141 GfxColorSpace *GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace *cs;
144 cs = new GfxCalGrayColorSpace();
155 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
156 GfxCalGrayColorSpace *cs;
157 Object obj1, obj2, obj3;
160 if (!obj1.isDict()) {
161 error(-1, "Bad CalGray color space");
165 cs = new GfxCalGrayColorSpace();
166 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
167 obj2.arrayGetLength() == 3) {
168 obj2.arrayGet(0, &obj3);
169 cs->whiteX = obj3.getNum();
171 obj2.arrayGet(1, &obj3);
172 cs->whiteY = obj3.getNum();
174 obj2.arrayGet(2, &obj3);
175 cs->whiteZ = obj3.getNum();
179 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
180 obj2.arrayGetLength() == 3) {
181 obj2.arrayGet(0, &obj3);
182 cs->blackX = obj3.getNum();
184 obj2.arrayGet(1, &obj3);
185 cs->blackY = obj3.getNum();
187 obj2.arrayGet(2, &obj3);
188 cs->blackZ = obj3.getNum();
192 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
193 cs->gamma = obj2.getNum();
200 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
201 *gray = clip01(color->c[0]);
204 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
205 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
208 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
209 cmyk->c = cmyk->m = cmyk->y = 0;
210 cmyk->k = clip01(1 - color->c[0]);
213 //------------------------------------------------------------------------
214 // GfxDeviceRGBColorSpace
215 //------------------------------------------------------------------------
217 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
220 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
223 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
227 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
228 *gray = clip01(0.299 * color->c[0] +
229 0.587 * color->c[1] +
230 0.114 * color->c[2]);
233 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
234 rgb->r = clip01(color->c[0]);
235 rgb->g = clip01(color->c[1]);
236 rgb->b = clip01(color->c[2]);
239 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
242 c = clip01(1 - color->c[0]);
243 m = clip01(1 - color->c[1]);
244 y = clip01(1 - color->c[2]);
258 //------------------------------------------------------------------------
259 // GfxCalRGBColorSpace
260 //------------------------------------------------------------------------
262 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
263 whiteX = whiteY = whiteZ = 1;
264 blackX = blackY = blackZ = 0;
265 gammaR = gammaG = gammaB = 1;
266 mat[0] = 1; mat[1] = 0; mat[2] = 0;
267 mat[3] = 0; mat[4] = 1; mat[5] = 0;
268 mat[6] = 0; mat[7] = 0; mat[8] = 1;
271 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
274 GfxColorSpace *GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace *cs;
278 cs = new GfxCalRGBColorSpace();
288 for (i = 0; i < 9; ++i) {
294 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
295 GfxCalRGBColorSpace *cs;
296 Object obj1, obj2, obj3;
300 if (!obj1.isDict()) {
301 error(-1, "Bad CalRGB color space");
305 cs = new GfxCalRGBColorSpace();
306 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
307 obj2.arrayGetLength() == 3) {
308 obj2.arrayGet(0, &obj3);
309 cs->whiteX = obj3.getNum();
311 obj2.arrayGet(1, &obj3);
312 cs->whiteY = obj3.getNum();
314 obj2.arrayGet(2, &obj3);
315 cs->whiteZ = obj3.getNum();
319 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
320 obj2.arrayGetLength() == 3) {
321 obj2.arrayGet(0, &obj3);
322 cs->blackX = obj3.getNum();
324 obj2.arrayGet(1, &obj3);
325 cs->blackY = obj3.getNum();
327 obj2.arrayGet(2, &obj3);
328 cs->blackZ = obj3.getNum();
332 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
333 obj2.arrayGetLength() == 3) {
334 obj2.arrayGet(0, &obj3);
335 cs->gammaR = obj3.getNum();
337 obj2.arrayGet(1, &obj3);
338 cs->gammaG = obj3.getNum();
340 obj2.arrayGet(2, &obj3);
341 cs->gammaB = obj3.getNum();
345 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
346 obj2.arrayGetLength() == 9) {
347 for (i = 0; i < 9; ++i) {
348 obj2.arrayGet(i, &obj3);
349 cs->mat[i] = obj3.getNum();
358 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
359 *gray = clip01(0.299 * color->c[0] +
360 0.587 * color->c[1] +
361 0.114 * color->c[2]);
364 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
365 rgb->r = clip01(color->c[0]);
366 rgb->g = clip01(color->c[1]);
367 rgb->b = clip01(color->c[2]);
370 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
373 c = clip01(1 - color->c[0]);
374 m = clip01(1 - color->c[1]);
375 y = clip01(1 - color->c[2]);
389 //------------------------------------------------------------------------
390 // GfxDeviceCMYKColorSpace
391 //------------------------------------------------------------------------
393 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
396 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
399 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
403 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
404 *gray = clip01(1 - color->c[3]
405 - 0.299 * color->c[0]
406 - 0.587 * color->c[1]
407 - 0.114 * color->c[2]);
410 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
411 double c, m, y, aw, ac, am, ay, ar, ag, ab;
413 c = clip01(color->c[0] + color->c[3]);
414 m = clip01(color->c[1] + color->c[3]);
415 y = clip01(color->c[2] + color->c[3]);
416 aw = (1-c) * (1-m) * (1-y);
417 ac = c * (1-m) * (1-y);
418 am = (1-c) * m * (1-y);
419 ay = (1-c) * (1-m) * y;
423 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
424 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
425 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
429 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
430 cmyk->c = clip01(color->c[0]);
431 cmyk->m = clip01(color->c[1]);
432 cmyk->y = clip01(color->c[2]);
433 cmyk->k = clip01(color->c[3]);
436 //------------------------------------------------------------------------
438 //------------------------------------------------------------------------
440 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
441 // Language Reference, Third Edition.
442 static double xyzrgb[3][3] = {
443 { 3.240449, -1.537136, -0.498531 },
444 { -0.969265, 1.876011, 0.041556 },
445 { 0.055643, -0.204026, 1.057229 }
448 GfxLabColorSpace::GfxLabColorSpace() {
449 whiteX = whiteY = whiteZ = 1;
450 blackX = blackY = blackZ = 0;
455 GfxLabColorSpace::~GfxLabColorSpace() {
458 GfxColorSpace *GfxLabColorSpace::copy() {
459 GfxLabColorSpace *cs;
461 cs = new GfxLabColorSpace();
478 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
479 GfxLabColorSpace *cs;
480 Object obj1, obj2, obj3;
483 if (!obj1.isDict()) {
484 error(-1, "Bad Lab color space");
488 cs = new GfxLabColorSpace();
489 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
490 obj2.arrayGetLength() == 3) {
491 obj2.arrayGet(0, &obj3);
492 cs->whiteX = obj3.getNum();
494 obj2.arrayGet(1, &obj3);
495 cs->whiteY = obj3.getNum();
497 obj2.arrayGet(2, &obj3);
498 cs->whiteZ = obj3.getNum();
502 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
503 obj2.arrayGetLength() == 3) {
504 obj2.arrayGet(0, &obj3);
505 cs->blackX = obj3.getNum();
507 obj2.arrayGet(1, &obj3);
508 cs->blackY = obj3.getNum();
510 obj2.arrayGet(2, &obj3);
511 cs->blackZ = obj3.getNum();
515 if (obj1.dictLookup("Range", &obj2)->isArray() &&
516 obj2.arrayGetLength() == 4) {
517 obj2.arrayGet(0, &obj3);
518 cs->aMin = obj3.getNum();
520 obj2.arrayGet(1, &obj3);
521 cs->aMax = obj3.getNum();
523 obj2.arrayGet(2, &obj3);
524 cs->bMin = obj3.getNum();
526 obj2.arrayGet(3, &obj3);
527 cs->bMax = obj3.getNum();
533 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
534 xyzrgb[0][1] * cs->whiteY +
535 xyzrgb[0][2] * cs->whiteZ);
536 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
537 xyzrgb[1][1] * cs->whiteY +
538 xyzrgb[1][2] * cs->whiteZ);
539 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
540 xyzrgb[2][1] * cs->whiteY +
541 xyzrgb[2][2] * cs->whiteZ);
546 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
550 *gray = clip01(0.299 * rgb.r +
555 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
560 // convert L*a*b* to CIE 1931 XYZ color space
561 t1 = (color->c[0] + 16) / 116;
562 t2 = t1 + color->c[1] / 500;
563 if (t2 >= (6.0 / 29.0)) {
566 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
569 if (t1 >= (6.0 / 29.0)) {
572 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
575 t2 = t1 - color->c[2] / 200;
576 if (t2 >= (6.0 / 29.0)) {
579 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
583 // convert XYZ to RGB, including gamut mapping and gamma correction
584 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
585 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
586 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
587 rgb->r = pow(clip01(r * kr), 0.5);
588 rgb->g = pow(clip01(g * kg), 0.5);
589 rgb->b = pow(clip01(b * kb), 0.5);
592 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
597 c = clip01(1 - rgb.r);
598 m = clip01(1 - rgb.g);
599 y = clip01(1 - rgb.b);
613 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
616 decodeRange[0] = 100;
618 decodeRange[1] = aMax - aMin;
620 decodeRange[2] = bMax - bMin;
623 //------------------------------------------------------------------------
624 // GfxICCBasedColorSpace
625 //------------------------------------------------------------------------
627 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
628 Ref *iccProfileStreamA) {
631 iccProfileStream = *iccProfileStreamA;
632 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
633 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
636 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
640 GfxColorSpace *GfxICCBasedColorSpace::copy() {
641 GfxICCBasedColorSpace *cs;
644 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
645 for (i = 0; i < 4; ++i) {
646 cs->rangeMin[i] = rangeMin[i];
647 cs->rangeMax[i] = rangeMax[i];
652 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
653 GfxICCBasedColorSpace *cs;
654 Ref iccProfileStreamA;
658 Object obj1, obj2, obj3;
661 arr->getNF(1, &obj1);
663 iccProfileStreamA = obj1.getRef();
665 iccProfileStreamA.num = 0;
666 iccProfileStreamA.gen = 0;
670 if (!obj1.isStream()) {
671 error(-1, "Bad ICCBased color space (stream)");
675 dict = obj1.streamGetDict();
676 if (!dict->lookup("N", &obj2)->isInt()) {
677 error(-1, "Bad ICCBased color space (N)");
682 nCompsA = obj2.getInt();
684 if (dict->lookup("Alternate", &obj2)->isNull() ||
685 !(altA = GfxColorSpace::parse(&obj2))) {
688 altA = new GfxDeviceGrayColorSpace();
691 altA = new GfxDeviceRGBColorSpace();
694 altA = new GfxDeviceCMYKColorSpace();
697 error(-1, "Bad ICCBased color space - invalid N");
704 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
705 if (dict->lookup("Range", &obj2)->isArray() &&
706 obj2.arrayGetLength() == 2 * nCompsA) {
707 for (i = 0; i < nCompsA; ++i) {
708 obj2.arrayGet(2*i, &obj3);
709 cs->rangeMin[i] = obj3.getNum();
711 obj2.arrayGet(2*i+1, &obj3);
712 cs->rangeMax[i] = obj3.getNum();
721 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
722 alt->getGray(color, gray);
725 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
726 alt->getRGB(color, rgb);
729 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
730 alt->getCMYK(color, cmyk);
733 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
738 for (i = 0; i < nComps; ++i) {
739 decodeLow[i] = rangeMin[i];
740 decodeRange[i] = rangeMax[i] - rangeMin[i];
744 //------------------------------------------------------------------------
745 // GfxIndexedColorSpace
746 //------------------------------------------------------------------------
748 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
751 indexHigh = indexHighA;
752 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
756 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
761 GfxColorSpace *GfxIndexedColorSpace::copy() {
762 GfxIndexedColorSpace *cs;
764 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
765 memcpy(cs->lookup, lookup,
766 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
770 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
771 GfxIndexedColorSpace *cs;
772 GfxColorSpace *baseA;
779 if (arr->getLength() != 4) {
780 error(-1, "Bad Indexed color space");
784 if (!(baseA = GfxColorSpace::parse(&obj1))) {
785 error(-1, "Bad Indexed color space (base color space)");
789 if (!arr->get(2, &obj1)->isInt()) {
790 error(-1, "Bad Indexed color space (hival)");
793 indexHighA = obj1.getInt();
795 cs = new GfxIndexedColorSpace(baseA, indexHighA);
797 n = baseA->getNComps();
798 if (obj1.isStream()) {
800 for (i = 0; i <= indexHighA; ++i) {
801 for (j = 0; j < n; ++j) {
802 if ((x = obj1.streamGetChar()) == EOF) {
803 error(-1, "Bad Indexed color space (lookup table stream too short)");
806 cs->lookup[i*n + j] = (Guchar)x;
810 } else if (obj1.isString()) {
811 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
812 error(-1, "Bad Indexed color space (lookup table string too short)");
815 s = obj1.getString()->getCString();
816 for (i = 0; i <= indexHighA; ++i) {
817 for (j = 0; j < n; ++j) {
818 cs->lookup[i*n + j] = (Guchar)*s++;
822 error(-1, "Bad Indexed color space (lookup table)");
836 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
841 n = base->getNComps();
842 p = &lookup[(int)(color->c[0] + 0.5) * n];
843 for (i = 0; i < n; ++i) {
844 color2.c[i] = p[i] / 255.0;
846 base->getGray(&color2, gray);
849 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
854 n = base->getNComps();
855 p = &lookup[(int)(color->c[0] + 0.5) * n];
856 for (i = 0; i < n; ++i) {
857 color2.c[i] = p[i] / 255.0;
859 base->getRGB(&color2, rgb);
862 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
867 n = base->getNComps();
868 p = &lookup[(int)(color->c[0] + 0.5) * n];
869 for (i = 0; i < n; ++i) {
870 color2.c[i] = p[i] / 255.0;
872 base->getCMYK(&color2, cmyk);
875 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
879 decodeRange[0] = maxImgPixel;
882 //------------------------------------------------------------------------
883 // GfxSeparationColorSpace
884 //------------------------------------------------------------------------
886 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
894 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
900 GfxColorSpace *GfxSeparationColorSpace::copy() {
901 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
904 //~ handle the 'All' and 'None' colorants
905 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
906 GfxSeparationColorSpace *cs;
912 if (arr->getLength() != 4) {
913 error(-1, "Bad Separation color space");
916 if (!arr->get(1, &obj1)->isName()) {
917 error(-1, "Bad Separation color space (name)");
920 nameA = new GString(obj1.getName());
923 if (!(altA = GfxColorSpace::parse(&obj1))) {
924 error(-1, "Bad Separation color space (alternate color space)");
929 if (!(funcA = Function::parse(&obj1))) {
933 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
946 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
949 func->transform(color->c, color2.c);
950 alt->getGray(&color2, gray);
953 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
956 func->transform(color->c, color2.c);
957 alt->getRGB(&color2, rgb);
960 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
963 func->transform(color->c, color2.c);
964 alt->getCMYK(&color2, cmyk);
967 //------------------------------------------------------------------------
968 // GfxDeviceNColorSpace
969 //------------------------------------------------------------------------
971 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
979 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
982 for (i = 0; i < nComps; ++i) {
989 GfxColorSpace *GfxDeviceNColorSpace::copy() {
990 GfxDeviceNColorSpace *cs;
993 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
994 for (i = 0; i < nComps; ++i) {
995 cs->names[i] = names[i]->copy();
1000 //~ handle the 'None' colorant
1001 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1002 GfxDeviceNColorSpace *cs;
1004 GString *namesA[gfxColorMaxComps];
1005 GfxColorSpace *altA;
1010 if (arr->getLength() != 4 && arr->getLength() != 5) {
1011 error(-1, "Bad DeviceN color space");
1014 if (!arr->get(1, &obj1)->isArray()) {
1015 error(-1, "Bad DeviceN color space (names)");
1018 nCompsA = obj1.arrayGetLength();
1019 for (i = 0; i < nCompsA; ++i) {
1020 if (!obj1.arrayGet(i, &obj2)->isName()) {
1021 error(-1, "Bad DeviceN color space (names)");
1025 namesA[i] = new GString(obj2.getName());
1030 if (!(altA = GfxColorSpace::parse(&obj1))) {
1031 error(-1, "Bad DeviceN color space (alternate color space)");
1036 if (!(funcA = Function::parse(&obj1))) {
1040 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1041 for (i = 0; i < nCompsA; ++i) {
1042 cs->names[i] = namesA[i];
1049 for (i = 0; i < nCompsA; ++i) {
1058 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1061 func->transform(color->c, color2.c);
1062 alt->getGray(&color2, gray);
1065 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1068 func->transform(color->c, color2.c);
1069 alt->getRGB(&color2, rgb);
1072 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1075 func->transform(color->c, color2.c);
1076 alt->getCMYK(&color2, cmyk);
1079 //------------------------------------------------------------------------
1080 // GfxPatternColorSpace
1081 //------------------------------------------------------------------------
1083 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1087 GfxPatternColorSpace::~GfxPatternColorSpace() {
1093 GfxColorSpace *GfxPatternColorSpace::copy() {
1094 return new GfxPatternColorSpace(under ? under->copy() :
1095 (GfxColorSpace *)NULL);
1098 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1099 GfxPatternColorSpace *cs;
1100 GfxColorSpace *underA;
1103 if (arr->getLength() != 1 && arr->getLength() != 2) {
1104 error(-1, "Bad Pattern color space");
1108 if (arr->getLength() == 2) {
1110 if (!(underA = GfxColorSpace::parse(&obj1))) {
1111 error(-1, "Bad Pattern color space (underlying color space)");
1117 cs = new GfxPatternColorSpace(underA);
1121 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1125 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1126 rgb->r = rgb->g = rgb->b = 0;
1129 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1130 cmyk->c = cmyk->m = cmyk->y = 0;
1134 //------------------------------------------------------------------------
1136 //------------------------------------------------------------------------
1138 GfxPattern::GfxPattern(int typeA) {
1142 GfxPattern::~GfxPattern() {
1145 GfxPattern *GfxPattern::parse(Object *obj) {
1146 GfxPattern *pattern;
1151 if (obj->isStream()) {
1152 dict = obj->streamGetDict();
1153 dict->lookup("PatternType", &obj1);
1154 if (obj1.isInt() && obj1.getInt() == 1) {
1155 pattern = new GfxTilingPattern(dict, obj);
1162 //------------------------------------------------------------------------
1164 //------------------------------------------------------------------------
1166 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1172 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1173 paintType = obj1.getInt();
1176 error(-1, "Invalid or missing PaintType in pattern");
1179 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1180 tilingType = obj1.getInt();
1183 error(-1, "Invalid or missing TilingType in pattern");
1186 bbox[0] = bbox[1] = 0;
1187 bbox[2] = bbox[3] = 1;
1188 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1189 obj1.arrayGetLength() == 4) {
1190 for (i = 0; i < 4; ++i) {
1191 if (obj1.arrayGet(i, &obj2)->isNum()) {
1192 bbox[i] = obj2.getNum();
1197 error(-1, "Invalid or missing BBox in pattern");
1200 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1201 xStep = obj1.getNum();
1204 error(-1, "Invalid or missing XStep in pattern");
1207 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1208 yStep = obj1.getNum();
1211 error(-1, "Invalid or missing YStep in pattern");
1214 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1217 error(-1, "Invalid or missing Resources in pattern");
1219 matrix[0] = 1; matrix[1] = 0;
1220 matrix[2] = 0; matrix[3] = 1;
1221 matrix[4] = 0; matrix[5] = 0;
1222 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1223 obj1.arrayGetLength() == 6) {
1224 for (i = 0; i < 6; ++i) {
1225 if (obj1.arrayGet(i, &obj2)->isNum()) {
1226 matrix[i] = obj2.getNum();
1232 stream->copy(&contentStream);
1235 GfxTilingPattern::~GfxTilingPattern() {
1237 contentStream.free();
1240 GfxPattern *GfxTilingPattern::copy() {
1241 return new GfxTilingPattern(this);
1244 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1247 memcpy(this, pat, sizeof(GfxTilingPattern));
1248 pat->resDict.copy(&resDict);
1249 pat->contentStream.copy(&contentStream);
1252 //------------------------------------------------------------------------
1254 //------------------------------------------------------------------------
1256 GfxShading::GfxShading() {
1259 GfxShading::~GfxShading() {
1263 GfxShading *GfxShading::parse(Object *obj) {
1264 GfxShading *shading;
1266 GfxColorSpace *colorSpaceA;
1267 GfxColor backgroundA;
1268 GBool hasBackgroundA;
1269 double xMinA, yMinA, xMaxA, yMaxA;
1275 if (obj->isDict()) {
1277 if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1278 error(-1, "Invalid ShadingType in shading dictionary");
1282 typeA = obj1.getInt();
1285 obj->dictLookup("ColorSpace", &obj1);
1286 if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1287 error(-1, "Bad color space in shading dictionary");
1293 for (i = 0; i < gfxColorMaxComps; ++i) {
1294 backgroundA.c[i] = 0;
1296 hasBackgroundA = gFalse;
1297 if (obj->dictLookup("Background", &obj1)->isArray()) {
1298 if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1299 hasBackgroundA = gTrue;
1300 for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1301 backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1305 error(-1, "Bad Background in shading dictionary");
1310 xMinA = yMinA = xMaxA = yMaxA = 0;
1312 if (obj->dictLookup("BBox", &obj1)->isArray()) {
1313 if (obj1.arrayGetLength() == 4) {
1315 xMinA = obj1.arrayGet(0, &obj2)->getNum();
1317 yMinA = obj1.arrayGet(1, &obj2)->getNum();
1319 xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1321 yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1324 error(-1, "Bad BBox in shading dictionary");
1331 shading = GfxAxialShading::parse(obj->getDict());
1334 shading = GfxRadialShading::parse(obj->getDict());
1337 error(-1, "Unimplemented shading type %d", typeA);
1342 shading->type = typeA;
1343 shading->colorSpace = colorSpaceA;
1344 shading->background = backgroundA;
1345 shading->hasBackground = hasBackgroundA;
1346 shading->xMin = xMinA;
1347 shading->yMin = yMinA;
1348 shading->xMax = xMaxA;
1349 shading->yMax = yMaxA;
1350 shading->hasBBox = hasBBoxA;
1362 //------------------------------------------------------------------------
1364 //------------------------------------------------------------------------
1366 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1367 double x1A, double y1A,
1368 double t0A, double t1A,
1369 Function **funcsA, int nFuncsA,
1370 GBool extend0A, GBool extend1A) {
1380 for (i = 0; i < nFuncs; ++i) {
1381 funcs[i] = funcsA[i];
1387 GfxAxialShading::~GfxAxialShading() {
1390 for (i = 0; i < nFuncs; ++i) {
1395 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1396 double x0A, y0A, x1A, y1A;
1398 Function *funcsA[gfxColorMaxComps];
1400 GBool extend0A, extend1A;
1404 x0A = y0A = x1A = y1A = 0;
1405 if (dict->lookup("Coords", &obj1)->isArray() &&
1406 obj1.arrayGetLength() == 4) {
1407 x0A = obj1.arrayGet(0, &obj2)->getNum();
1409 y0A = obj1.arrayGet(1, &obj2)->getNum();
1411 x1A = obj1.arrayGet(2, &obj2)->getNum();
1413 y1A = obj1.arrayGet(3, &obj2)->getNum();
1416 error(-1, "Missing or invalid Coords in shading dictionary");
1423 if (dict->lookup("Domain", &obj1)->isArray() &&
1424 obj1.arrayGetLength() == 2) {
1425 t0A = obj1.arrayGet(0, &obj2)->getNum();
1427 t1A = obj1.arrayGet(1, &obj2)->getNum();
1432 dict->lookup("Function", &obj1);
1433 if (obj1.isArray()) {
1434 nFuncsA = obj1.arrayGetLength();
1435 for (i = 0; i < nFuncsA; ++i) {
1436 obj1.arrayGet(i, &obj2);
1437 if (!(funcsA[i] = Function::parse(&obj2))) {
1446 if (!(funcsA[0] = Function::parse(&obj1))) {
1453 extend0A = extend1A = gFalse;
1454 if (dict->lookup("Extend", &obj1)->isArray() &&
1455 obj1.arrayGetLength() == 2) {
1456 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1458 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1463 return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1464 funcsA, nFuncsA, extend0A, extend1A);
1470 void GfxAxialShading::getColor(double t, GfxColor *color) {
1473 for (i = 0; i < nFuncs; ++i) {
1474 funcs[i]->transform(&t, &color->c[i]);
1478 //------------------------------------------------------------------------
1480 //------------------------------------------------------------------------
1482 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1483 double x1A, double y1A, double r1A,
1484 double t0A, double t1A,
1485 Function **funcsA, int nFuncsA,
1486 GBool extend0A, GBool extend1A) {
1498 for (i = 0; i < nFuncs; ++i) {
1499 funcs[i] = funcsA[i];
1505 GfxRadialShading::~GfxRadialShading() {
1508 for (i = 0; i < nFuncs; ++i) {
1513 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1514 double x0A, y0A, r0A, x1A, y1A, r1A;
1516 Function *funcsA[gfxColorMaxComps];
1518 GBool extend0A, extend1A;
1522 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1523 if (dict->lookup("Coords", &obj1)->isArray() &&
1524 obj1.arrayGetLength() == 6) {
1525 x0A = obj1.arrayGet(0, &obj2)->getNum();
1527 y0A = obj1.arrayGet(1, &obj2)->getNum();
1529 r0A = obj1.arrayGet(2, &obj2)->getNum();
1531 x1A = obj1.arrayGet(3, &obj2)->getNum();
1533 y1A = obj1.arrayGet(4, &obj2)->getNum();
1535 r1A = obj1.arrayGet(5, &obj2)->getNum();
1538 error(-1, "Missing or invalid Coords in shading dictionary");
1545 if (dict->lookup("Domain", &obj1)->isArray() &&
1546 obj1.arrayGetLength() == 2) {
1547 t0A = obj1.arrayGet(0, &obj2)->getNum();
1549 t1A = obj1.arrayGet(1, &obj2)->getNum();
1554 dict->lookup("Function", &obj1);
1555 if (obj1.isArray()) {
1556 nFuncsA = obj1.arrayGetLength();
1557 for (i = 0; i < nFuncsA; ++i) {
1558 obj1.arrayGet(i, &obj2);
1559 if (!(funcsA[i] = Function::parse(&obj2))) {
1568 if (!(funcsA[0] = Function::parse(&obj1))) {
1575 extend0A = extend1A = gFalse;
1576 if (dict->lookup("Extend", &obj1)->isArray() &&
1577 obj1.arrayGetLength() == 2) {
1578 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1580 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1585 return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1586 funcsA, nFuncsA, extend0A, extend1A);
1592 void GfxRadialShading::getColor(double t, GfxColor *color) {
1595 for (i = 0; i < nFuncs; ++i) {
1596 funcs[i]->transform(&t, &color->c[i]);
1600 //------------------------------------------------------------------------
1602 //------------------------------------------------------------------------
1604 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1605 GfxColorSpace *colorSpaceA) {
1606 GfxIndexedColorSpace *indexedCS;
1607 GfxSeparationColorSpace *sepCS;
1608 int maxPixel, indexHigh;
1612 double x[gfxColorMaxComps];
1613 double y[gfxColorMaxComps];
1615 int maxPixelForAlloc;
1619 // bits per component and color space
1621 maxPixel = (1 << bits) - 1;
1622 maxPixelForAlloc = (1 << (bits>8?bits:8));
1623 colorSpace = colorSpaceA;
1626 if (decode->isNull()) {
1627 nComps = colorSpace->getNComps();
1628 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1629 } else if (decode->isArray()) {
1630 nComps = decode->arrayGetLength() / 2;
1631 if (nComps != colorSpace->getNComps()) {
1634 for (i = 0; i < nComps; ++i) {
1635 decode->arrayGet(2*i, &obj);
1639 decodeLow[i] = obj.getNum();
1641 decode->arrayGet(2*i+1, &obj);
1645 decodeRange[i] = obj.getNum() - decodeLow[i];
1652 // Construct a lookup table -- this stores pre-computed decoded
1653 // values for each component, i.e., the result of applying the
1654 // decode mapping to each possible image pixel component value.
1656 // Optimization: for Indexed and Separation color spaces (which have
1657 // only one component), we store color values in the lookup table
1658 // rather than component values.
1661 if (colorSpace->getMode() == csIndexed) {
1662 // Note that indexHigh may not be the same as maxPixel --
1663 // Distiller will remove unused palette entries, resulting in
1664 // indexHigh < maxPixel.
1665 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1666 colorSpace2 = indexedCS->getBase();
1667 indexHigh = indexedCS->getIndexHigh();
1668 nComps2 = colorSpace2->getNComps();
1669 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
1670 lookup2 = indexedCS->getLookup();
1671 for (i = 0; i <= indexHigh; ++i) {
1672 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1673 for (k = 0; k < nComps2; ++k) {
1674 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1677 } else if (colorSpace->getMode() == csSeparation) {
1678 sepCS = (GfxSeparationColorSpace *)colorSpace;
1679 colorSpace2 = sepCS->getAlt();
1680 nComps2 = colorSpace2->getNComps();
1681 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
1682 sepFunc = sepCS->getFunc();
1683 for (i = 0; i <= maxPixel; ++i) {
1684 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1685 sepFunc->transform(x, y);
1686 for (k = 0; k < nComps2; ++k) {
1687 lookup[i*nComps2 + k] = y[k];
1691 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
1692 for (i = 0; i <= maxPixel; ++i) {
1693 for (k = 0; k < nComps; ++k) {
1694 lookup[i*nComps + k] = decodeLow[k] +
1695 (i * decodeRange[k]) / maxPixel;
1708 GfxImageColorMap::~GfxImageColorMap() {
1713 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1719 p = &lookup[x[0] * nComps2];
1720 for (i = 0; i < nComps2; ++i) {
1723 colorSpace2->getGray(&color, gray);
1725 for (i = 0; i < nComps; ++i) {
1726 color.c[i] = lookup[x[i] * nComps + i];
1728 colorSpace->getGray(&color, gray);
1732 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1739 //printf("lookup[%d] bits=%d\n",x[0],bits);fflush(stdout);
1740 p = &lookup[x[0] * nComps2];
1741 for (i = 0; i < nComps2; ++i) {
1744 colorSpace2->getRGB(&color, rgb);
1746 //printf("for i=0,i<%d, bits=%d\n",nComps,bits);fflush(stdout);
1747 for (i = 0; i < nComps; ++i) {
1748 color.c[i] = lookup[x[i] * nComps + i];
1750 colorSpace->getRGB(&color, rgb);
1754 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1760 p = &lookup[x[0] * nComps2];
1761 for (i = 0; i < nComps2; ++i) {
1764 colorSpace2->getCMYK(&color, cmyk);
1766 for (i = 0; i < nComps; ++i) {
1767 color.c[i] = lookup[x[i] * nComps + i];
1769 colorSpace->getCMYK(&color, cmyk);
1773 //------------------------------------------------------------------------
1774 // GfxSubpath and GfxPath
1775 //------------------------------------------------------------------------
1777 GfxSubpath::GfxSubpath(double x1, double y1) {
1779 x = (double *)gmalloc(size * sizeof(double));
1780 y = (double *)gmalloc(size * sizeof(double));
1781 curve = (GBool *)gmalloc(size * sizeof(GBool));
1789 GfxSubpath::~GfxSubpath() {
1796 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1797 size = subpath->size;
1799 x = (double *)gmalloc(size * sizeof(double));
1800 y = (double *)gmalloc(size * sizeof(double));
1801 curve = (GBool *)gmalloc(size * sizeof(GBool));
1802 memcpy(x, subpath->x, n * sizeof(double));
1803 memcpy(y, subpath->y, n * sizeof(double));
1804 memcpy(curve, subpath->curve, n * sizeof(GBool));
1805 closed = subpath->closed;
1808 void GfxSubpath::lineTo(double x1, double y1) {
1811 x = (double *)grealloc(x, size * sizeof(double));
1812 y = (double *)grealloc(y, size * sizeof(double));
1813 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1821 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1822 double x3, double y3) {
1825 x = (double *)grealloc(x, size * sizeof(double));
1826 y = (double *)grealloc(y, size * sizeof(double));
1827 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1835 curve[n] = curve[n+1] = gTrue;
1836 curve[n+2] = gFalse;
1840 void GfxSubpath::close() {
1841 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1847 GfxPath::GfxPath() {
1851 firstX = firstY = 0;
1852 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1855 GfxPath::~GfxPath() {
1858 for (i = 0; i < n; ++i)
1864 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1865 GfxSubpath **subpaths1, int n1, int size1) {
1868 justMoved = justMoved1;
1873 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1874 for (i = 0; i < n; ++i)
1875 subpaths[i] = subpaths1[i]->copy();
1878 void GfxPath::moveTo(double x, double y) {
1884 void GfxPath::lineTo(double x, double y) {
1888 subpaths = (GfxSubpath **)
1889 grealloc(subpaths, size * sizeof(GfxSubpath *));
1891 subpaths[n] = new GfxSubpath(firstX, firstY);
1895 subpaths[n-1]->lineTo(x, y);
1898 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1899 double x3, double y3) {
1903 subpaths = (GfxSubpath **)
1904 grealloc(subpaths, size * sizeof(GfxSubpath *));
1906 subpaths[n] = new GfxSubpath(firstX, firstY);
1910 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1913 void GfxPath::close() {
1914 // this is necessary to handle the pathological case of
1915 // moveto/closepath/clip, which defines an empty clipping region
1919 subpaths = (GfxSubpath **)
1920 grealloc(subpaths, size * sizeof(GfxSubpath *));
1922 subpaths[n] = new GfxSubpath(firstX, firstY);
1926 subpaths[n-1]->close();
1929 //------------------------------------------------------------------------
1931 //------------------------------------------------------------------------
1933 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
1944 ctm[1] = upsideDown ? k : -k;
1948 ctm[5] = k * (upsideDown ? -px1 : px2);
1949 pageWidth = k * (py2 - py1);
1950 pageHeight = k * (px2 - px1);
1951 } else if (rotate == 180) {
1955 ctm[3] = upsideDown ? k : -k;
1957 ctm[5] = k * (upsideDown ? -py1 : py2);
1958 pageWidth = k * (px2 - px1);
1959 pageHeight = k * (py2 - py1);
1960 } else if (rotate == 270) {
1962 ctm[1] = upsideDown ? -k : k;
1966 ctm[5] = k * (upsideDown ? px2 : -px1);
1967 pageWidth = k * (py2 - py1);
1968 pageHeight = k * (px2 - px1);
1973 ctm[3] = upsideDown ? -k : k;
1975 ctm[5] = k * (upsideDown ? py2 : -py1);
1976 pageWidth = k * (px2 - px1);
1977 pageHeight = k * (py2 - py1);
1980 fillColorSpace = new GfxDeviceGrayColorSpace();
1981 strokeColorSpace = new GfxDeviceGrayColorSpace();
1983 strokeColor.c[0] = 0;
1985 strokePattern = NULL;
2000 textMat[0] = 1; textMat[1] = 0;
2001 textMat[2] = 0; textMat[3] = 1;
2002 textMat[4] = 0; textMat[5] = 0;
2010 path = new GfxPath();
2016 clipXMax = pageWidth;
2017 clipYMax = pageHeight;
2022 GfxState::~GfxState() {
2023 if (fillColorSpace) {
2024 delete fillColorSpace;
2026 if (strokeColorSpace) {
2027 delete strokeColorSpace;
2032 if (strokePattern) {
2033 delete strokePattern;
2037 // this gets set to NULL by restore()
2046 GfxState::GfxState(GfxState *state) {
2047 memcpy(this, state, sizeof(GfxState));
2048 if (fillColorSpace) {
2049 fillColorSpace = state->fillColorSpace->copy();
2051 if (strokeColorSpace) {
2052 strokeColorSpace = state->strokeColorSpace->copy();
2055 fillPattern = state->fillPattern->copy();
2057 if (strokePattern) {
2058 strokePattern = state->strokePattern->copy();
2060 if (lineDashLength > 0) {
2061 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2062 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2067 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2068 double *xMax, double *yMax) {
2070 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2073 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2074 ictm[0] = ctm[3] * det;
2075 ictm[1] = -ctm[1] * det;
2076 ictm[2] = -ctm[2] * det;
2077 ictm[3] = ctm[0] * det;
2078 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2079 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2081 // transform all four corners of the clip bbox; find the min and max
2083 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2084 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2085 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2086 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2089 } else if (tx > xMax1) {
2094 } else if (ty > yMax1) {
2097 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2098 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2101 } else if (tx > xMax1) {
2106 } else if (ty > yMax1) {
2109 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2110 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2113 } else if (tx > xMax1) {
2118 } else if (ty > yMax1) {
2128 double GfxState::transformWidth(double w) {
2131 x = ctm[0] + ctm[2];
2132 y = ctm[1] + ctm[3];
2133 return w * sqrt(0.5 * (x * x + y * y));
2136 double GfxState::getTransformedFontSize() {
2137 double x1, y1, x2, y2;
2139 x1 = textMat[2] * fontSize;
2140 y1 = textMat[3] * fontSize;
2141 x2 = ctm[0] * x1 + ctm[2] * y1;
2142 y2 = ctm[1] * x1 + ctm[3] * y1;
2143 return sqrt(x2 * x2 + y2 * y2);
2146 void GfxState::getFontTransMat(double *m11, double *m12,
2147 double *m21, double *m22) {
2148 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2149 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2150 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2151 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2154 void GfxState::setCTM(double a, double b, double c,
2155 double d, double e, double f) {
2165 // avoid FP exceptions on badly messed up PDF files
2166 for (i = 0; i < 6; ++i) {
2167 if (ctm[i] > 1e10) {
2169 } else if (ctm[i] < -1e10) {
2175 void GfxState::concatCTM(double a, double b, double c,
2176 double d, double e, double f) {
2183 ctm[0] = a * a1 + b * c1;
2184 ctm[1] = a * b1 + b * d1;
2185 ctm[2] = c * a1 + d * c1;
2186 ctm[3] = c * b1 + d * d1;
2187 ctm[4] = e * a1 + f * c1 + ctm[4];
2188 ctm[5] = e * b1 + f * d1 + ctm[5];
2190 // avoid FP exceptions on badly messed up PDF files
2191 for (i = 0; i < 6; ++i) {
2192 if (ctm[i] > 1e10) {
2194 } else if (ctm[i] < -1e10) {
2200 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2201 if (fillColorSpace) {
2202 delete fillColorSpace;
2204 fillColorSpace = colorSpace;
2207 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2208 if (strokeColorSpace) {
2209 delete strokeColorSpace;
2211 strokeColorSpace = colorSpace;
2214 void GfxState::setFillPattern(GfxPattern *pattern) {
2218 fillPattern = pattern;
2221 void GfxState::setStrokePattern(GfxPattern *pattern) {
2222 if (strokePattern) {
2223 delete strokePattern;
2225 strokePattern = pattern;
2228 void GfxState::setLineDash(double *dash, int length, double start) {
2232 lineDashLength = length;
2233 lineDashStart = start;
2236 void GfxState::clearPath() {
2238 path = new GfxPath();
2241 void GfxState::clip() {
2242 double xMin, yMin, xMax, yMax, x, y;
2243 GfxSubpath *subpath;
2246 xMin = xMax = yMin = yMax = 0; // make gcc happy
2247 for (i = 0; i < path->getNumSubpaths(); ++i) {
2248 subpath = path->getSubpath(i);
2249 for (j = 0; j < subpath->getNumPoints(); ++j) {
2250 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2251 if (i == 0 && j == 0) {
2257 } else if (x > xMax) {
2262 } else if (y > yMax) {
2268 if (xMin > clipXMin) {
2271 if (yMin > clipYMin) {
2274 if (xMax < clipXMax) {
2277 if (yMax < clipYMax) {
2282 void GfxState::textShift(double tx, double ty) {
2285 textTransformDelta(tx, ty, &dx, &dy);
2290 void GfxState::shift(double dx, double dy) {
2295 GfxState *GfxState::save() {
2299 newState->saved = this;
2303 GfxState *GfxState::restore() {
2309 // these attributes aren't saved/restored by the q/Q operators
2310 oldState->path = path;
2311 oldState->curX = curX;
2312 oldState->curY = curY;
2313 oldState->lineX = lineX;
2314 oldState->lineY = lineY;