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 /* FIXME ask Derek */
414 if (color->c[0] == 0.0 && color->c[1] == 0 && color->c[2] == 0) {
415 rgb->r = rgb->g = rgb->b = 1 - color->c[3];
419 c = clip01(color->c[0] + color->c[3]);
420 m = clip01(color->c[1] + color->c[3]);
421 y = clip01(color->c[2] + color->c[3]);
422 aw = (1-c) * (1-m) * (1-y);
423 ac = c * (1-m) * (1-y);
424 am = (1-c) * m * (1-y);
425 ay = (1-c) * (1-m) * y;
429 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
430 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
431 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
435 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
436 cmyk->c = clip01(color->c[0]);
437 cmyk->m = clip01(color->c[1]);
438 cmyk->y = clip01(color->c[2]);
439 cmyk->k = clip01(color->c[3]);
442 //------------------------------------------------------------------------
444 //------------------------------------------------------------------------
446 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
447 // Language Reference, Third Edition.
448 static double xyzrgb[3][3] = {
449 { 3.240449, -1.537136, -0.498531 },
450 { -0.969265, 1.876011, 0.041556 },
451 { 0.055643, -0.204026, 1.057229 }
454 GfxLabColorSpace::GfxLabColorSpace() {
455 whiteX = whiteY = whiteZ = 1;
456 blackX = blackY = blackZ = 0;
461 GfxLabColorSpace::~GfxLabColorSpace() {
464 GfxColorSpace *GfxLabColorSpace::copy() {
465 GfxLabColorSpace *cs;
467 cs = new GfxLabColorSpace();
484 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
485 GfxLabColorSpace *cs;
486 Object obj1, obj2, obj3;
489 if (!obj1.isDict()) {
490 error(-1, "Bad Lab color space");
494 cs = new GfxLabColorSpace();
495 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
496 obj2.arrayGetLength() == 3) {
497 obj2.arrayGet(0, &obj3);
498 cs->whiteX = obj3.getNum();
500 obj2.arrayGet(1, &obj3);
501 cs->whiteY = obj3.getNum();
503 obj2.arrayGet(2, &obj3);
504 cs->whiteZ = obj3.getNum();
508 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
509 obj2.arrayGetLength() == 3) {
510 obj2.arrayGet(0, &obj3);
511 cs->blackX = obj3.getNum();
513 obj2.arrayGet(1, &obj3);
514 cs->blackY = obj3.getNum();
516 obj2.arrayGet(2, &obj3);
517 cs->blackZ = obj3.getNum();
521 if (obj1.dictLookup("Range", &obj2)->isArray() &&
522 obj2.arrayGetLength() == 4) {
523 obj2.arrayGet(0, &obj3);
524 cs->aMin = obj3.getNum();
526 obj2.arrayGet(1, &obj3);
527 cs->aMax = obj3.getNum();
529 obj2.arrayGet(2, &obj3);
530 cs->bMin = obj3.getNum();
532 obj2.arrayGet(3, &obj3);
533 cs->bMax = obj3.getNum();
539 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
540 xyzrgb[0][1] * cs->whiteY +
541 xyzrgb[0][2] * cs->whiteZ);
542 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
543 xyzrgb[1][1] * cs->whiteY +
544 xyzrgb[1][2] * cs->whiteZ);
545 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
546 xyzrgb[2][1] * cs->whiteY +
547 xyzrgb[2][2] * cs->whiteZ);
552 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
556 *gray = clip01(0.299 * rgb.r +
561 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
566 // convert L*a*b* to CIE 1931 XYZ color space
567 t1 = (color->c[0] + 16) / 116;
568 t2 = t1 + color->c[1] / 500;
569 if (t2 >= (6.0 / 29.0)) {
572 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
575 if (t1 >= (6.0 / 29.0)) {
578 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
581 t2 = t1 - color->c[2] / 200;
582 if (t2 >= (6.0 / 29.0)) {
585 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
589 // convert XYZ to RGB, including gamut mapping and gamma correction
590 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
591 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
592 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
593 rgb->r = pow(clip01(r * kr), 0.5);
594 rgb->g = pow(clip01(g * kg), 0.5);
595 rgb->b = pow(clip01(b * kb), 0.5);
598 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
603 c = clip01(1 - rgb.r);
604 m = clip01(1 - rgb.g);
605 y = clip01(1 - rgb.b);
619 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
622 decodeRange[0] = 100;
624 decodeRange[1] = aMax - aMin;
626 decodeRange[2] = bMax - bMin;
629 //------------------------------------------------------------------------
630 // GfxICCBasedColorSpace
631 //------------------------------------------------------------------------
633 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
634 Ref *iccProfileStreamA) {
637 iccProfileStream = *iccProfileStreamA;
638 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
639 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
642 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
646 GfxColorSpace *GfxICCBasedColorSpace::copy() {
647 GfxICCBasedColorSpace *cs;
650 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
651 for (i = 0; i < 4; ++i) {
652 cs->rangeMin[i] = rangeMin[i];
653 cs->rangeMax[i] = rangeMax[i];
658 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
659 GfxICCBasedColorSpace *cs;
660 Ref iccProfileStreamA;
664 Object obj1, obj2, obj3;
667 arr->getNF(1, &obj1);
669 iccProfileStreamA = obj1.getRef();
671 iccProfileStreamA.num = 0;
672 iccProfileStreamA.gen = 0;
676 if (!obj1.isStream()) {
677 error(-1, "Bad ICCBased color space (stream)");
681 dict = obj1.streamGetDict();
682 if (!dict->lookup("N", &obj2)->isInt()) {
683 error(-1, "Bad ICCBased color space (N)");
688 nCompsA = obj2.getInt();
690 if (dict->lookup("Alternate", &obj2)->isNull() ||
691 !(altA = GfxColorSpace::parse(&obj2))) {
694 altA = new GfxDeviceGrayColorSpace();
697 altA = new GfxDeviceRGBColorSpace();
700 altA = new GfxDeviceCMYKColorSpace();
703 error(-1, "Bad ICCBased color space - invalid N");
710 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
711 if (dict->lookup("Range", &obj2)->isArray() &&
712 obj2.arrayGetLength() == 2 * nCompsA) {
713 for (i = 0; i < nCompsA; ++i) {
714 obj2.arrayGet(2*i, &obj3);
715 cs->rangeMin[i] = obj3.getNum();
717 obj2.arrayGet(2*i+1, &obj3);
718 cs->rangeMax[i] = obj3.getNum();
727 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
728 alt->getGray(color, gray);
731 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
732 alt->getRGB(color, rgb);
735 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
736 alt->getCMYK(color, cmyk);
739 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
744 for (i = 0; i < nComps; ++i) {
745 decodeLow[i] = rangeMin[i];
746 decodeRange[i] = rangeMax[i] - rangeMin[i];
750 //------------------------------------------------------------------------
751 // GfxIndexedColorSpace
752 //------------------------------------------------------------------------
754 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
757 indexHigh = indexHighA;
758 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
762 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
767 GfxColorSpace *GfxIndexedColorSpace::copy() {
768 GfxIndexedColorSpace *cs;
770 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
771 memcpy(cs->lookup, lookup,
772 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
776 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
777 GfxIndexedColorSpace *cs;
778 GfxColorSpace *baseA;
785 if (arr->getLength() != 4) {
786 error(-1, "Bad Indexed color space");
790 if (!(baseA = GfxColorSpace::parse(&obj1))) {
791 error(-1, "Bad Indexed color space (base color space)");
795 if (!arr->get(2, &obj1)->isInt()) {
796 error(-1, "Bad Indexed color space (hival)");
800 indexHighA = obj1.getInt();
801 if (indexHighA < 0 || indexHighA > 255) {
802 // the PDF spec requires indexHigh to be in [0,255] -- allowing
803 // values larger than 255 creates a security hole: if nComps *
804 // indexHigh is greater than 2^31, the loop below may overwrite
805 // past the end of the array
806 error(-1, "Bad Indexed color space (invalid indexHigh value)");
811 cs = new GfxIndexedColorSpace(baseA, indexHighA);
813 n = baseA->getNComps();
814 if (obj1.isStream()) {
816 for (i = 0; i <= indexHighA; ++i) {
817 for (j = 0; j < n; ++j) {
818 if ((x = obj1.streamGetChar()) == EOF) {
819 error(-1, "Bad Indexed color space (lookup table stream too short)");
822 cs->lookup[i*n + j] = (Guchar)x;
826 } else if (obj1.isString()) {
827 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
828 error(-1, "Bad Indexed color space (lookup table string too short)");
831 s = obj1.getString()->getCString();
832 for (i = 0; i <= indexHighA; ++i) {
833 for (j = 0; j < n; ++j) {
834 cs->lookup[i*n + j] = (Guchar)*s++;
838 error(-1, "Bad Indexed color space (lookup table)");
852 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
857 n = base->getNComps();
858 p = &lookup[(int)(color->c[0] + 0.5) * n];
859 for (i = 0; i < n; ++i) {
860 color2.c[i] = p[i] / 255.0;
862 base->getGray(&color2, gray);
865 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
870 n = base->getNComps();
871 p = &lookup[(int)(color->c[0] + 0.5) * n];
872 for (i = 0; i < n; ++i) {
873 color2.c[i] = p[i] / 255.0;
875 base->getRGB(&color2, rgb);
878 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
883 n = base->getNComps();
884 p = &lookup[(int)(color->c[0] + 0.5) * n];
885 for (i = 0; i < n; ++i) {
886 color2.c[i] = p[i] / 255.0;
888 base->getCMYK(&color2, cmyk);
891 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
895 decodeRange[0] = maxImgPixel;
898 //------------------------------------------------------------------------
899 // GfxSeparationColorSpace
900 //------------------------------------------------------------------------
902 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
910 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
916 GfxColorSpace *GfxSeparationColorSpace::copy() {
917 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
920 //~ handle the 'All' and 'None' colorants
921 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
922 GfxSeparationColorSpace *cs;
928 if (arr->getLength() != 4) {
929 error(-1, "Bad Separation color space");
932 if (!arr->get(1, &obj1)->isName()) {
933 error(-1, "Bad Separation color space (name)");
936 nameA = new GString(obj1.getName());
939 if (!(altA = GfxColorSpace::parse(&obj1))) {
940 error(-1, "Bad Separation color space (alternate color space)");
945 if (!(funcA = Function::parse(&obj1))) {
949 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
962 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
965 func->transform(color->c, color2.c);
966 alt->getGray(&color2, gray);
969 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
972 func->transform(color->c, color2.c);
973 alt->getRGB(&color2, rgb);
976 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
979 func->transform(color->c, color2.c);
980 alt->getCMYK(&color2, cmyk);
983 //------------------------------------------------------------------------
984 // GfxDeviceNColorSpace
985 //------------------------------------------------------------------------
987 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
995 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
998 for (i = 0; i < nComps; ++i) {
1005 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1006 GfxDeviceNColorSpace *cs;
1009 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1010 for (i = 0; i < nComps; ++i) {
1011 cs->names[i] = names[i]->copy();
1016 //~ handle the 'None' colorant
1017 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1018 GfxDeviceNColorSpace *cs;
1020 GString *namesA[gfxColorMaxComps];
1021 GfxColorSpace *altA;
1026 if (arr->getLength() != 4 && arr->getLength() != 5) {
1027 error(-1, "Bad DeviceN color space");
1030 if (!arr->get(1, &obj1)->isArray()) {
1031 error(-1, "Bad DeviceN color space (names)");
1034 nCompsA = obj1.arrayGetLength();
1035 for (i = 0; i < nCompsA; ++i) {
1036 if (!obj1.arrayGet(i, &obj2)->isName()) {
1037 error(-1, "Bad DeviceN color space (names)");
1041 namesA[i] = new GString(obj2.getName());
1046 if (!(altA = GfxColorSpace::parse(&obj1))) {
1047 error(-1, "Bad DeviceN color space (alternate color space)");
1052 if (!(funcA = Function::parse(&obj1))) {
1056 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1057 for (i = 0; i < nCompsA; ++i) {
1058 cs->names[i] = namesA[i];
1065 for (i = 0; i < nCompsA; ++i) {
1074 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1077 func->transform(color->c, color2.c);
1078 alt->getGray(&color2, gray);
1081 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1084 func->transform(color->c, color2.c);
1085 alt->getRGB(&color2, rgb);
1088 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1091 func->transform(color->c, color2.c);
1092 alt->getCMYK(&color2, cmyk);
1095 //------------------------------------------------------------------------
1096 // GfxPatternColorSpace
1097 //------------------------------------------------------------------------
1099 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1103 GfxPatternColorSpace::~GfxPatternColorSpace() {
1109 GfxColorSpace *GfxPatternColorSpace::copy() {
1110 return new GfxPatternColorSpace(under ? under->copy() :
1111 (GfxColorSpace *)NULL);
1114 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1115 GfxPatternColorSpace *cs;
1116 GfxColorSpace *underA;
1119 if (arr->getLength() != 1 && arr->getLength() != 2) {
1120 error(-1, "Bad Pattern color space");
1124 if (arr->getLength() == 2) {
1126 if (!(underA = GfxColorSpace::parse(&obj1))) {
1127 error(-1, "Bad Pattern color space (underlying color space)");
1133 cs = new GfxPatternColorSpace(underA);
1137 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1141 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1142 rgb->r = rgb->g = rgb->b = 0;
1145 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1146 cmyk->c = cmyk->m = cmyk->y = 0;
1150 //------------------------------------------------------------------------
1152 //------------------------------------------------------------------------
1154 GfxPattern::GfxPattern(int typeA) {
1158 GfxPattern::~GfxPattern() {
1161 GfxPattern *GfxPattern::parse(Object *obj) {
1162 GfxPattern *pattern;
1167 if (obj->isStream()) {
1168 dict = obj->streamGetDict();
1169 dict->lookup("PatternType", &obj1);
1170 if (obj1.isInt() && obj1.getInt() == 1) {
1171 pattern = new GfxTilingPattern(dict, obj);
1178 //------------------------------------------------------------------------
1180 //------------------------------------------------------------------------
1182 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1188 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1189 paintType = obj1.getInt();
1192 error(-1, "Invalid or missing PaintType in pattern");
1195 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1196 tilingType = obj1.getInt();
1199 error(-1, "Invalid or missing TilingType in pattern");
1202 bbox[0] = bbox[1] = 0;
1203 bbox[2] = bbox[3] = 1;
1204 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1205 obj1.arrayGetLength() == 4) {
1206 for (i = 0; i < 4; ++i) {
1207 if (obj1.arrayGet(i, &obj2)->isNum()) {
1208 bbox[i] = obj2.getNum();
1213 error(-1, "Invalid or missing BBox in pattern");
1216 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1217 xStep = obj1.getNum();
1220 error(-1, "Invalid or missing XStep in pattern");
1223 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1224 yStep = obj1.getNum();
1227 error(-1, "Invalid or missing YStep in pattern");
1230 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1233 error(-1, "Invalid or missing Resources in pattern");
1235 matrix[0] = 1; matrix[1] = 0;
1236 matrix[2] = 0; matrix[3] = 1;
1237 matrix[4] = 0; matrix[5] = 0;
1238 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1239 obj1.arrayGetLength() == 6) {
1240 for (i = 0; i < 6; ++i) {
1241 if (obj1.arrayGet(i, &obj2)->isNum()) {
1242 matrix[i] = obj2.getNum();
1248 stream->copy(&contentStream);
1251 GfxTilingPattern::~GfxTilingPattern() {
1253 contentStream.free();
1256 GfxPattern *GfxTilingPattern::copy() {
1257 return new GfxTilingPattern(this);
1260 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1263 memcpy(this, pat, sizeof(GfxTilingPattern));
1264 pat->resDict.copy(&resDict);
1265 pat->contentStream.copy(&contentStream);
1268 //------------------------------------------------------------------------
1270 //------------------------------------------------------------------------
1272 GfxShading::GfxShading() {
1275 GfxShading::~GfxShading() {
1279 GfxShading *GfxShading::parse(Object *obj) {
1280 GfxShading *shading;
1282 GfxColorSpace *colorSpaceA;
1283 GfxColor backgroundA;
1284 GBool hasBackgroundA;
1285 double xMinA, yMinA, xMaxA, yMaxA;
1291 if (obj->isDict()) {
1293 if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1294 error(-1, "Invalid ShadingType in shading dictionary");
1298 typeA = obj1.getInt();
1301 obj->dictLookup("ColorSpace", &obj1);
1302 if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1303 error(-1, "Bad color space in shading dictionary");
1309 for (i = 0; i < gfxColorMaxComps; ++i) {
1310 backgroundA.c[i] = 0;
1312 hasBackgroundA = gFalse;
1313 if (obj->dictLookup("Background", &obj1)->isArray()) {
1314 if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1315 hasBackgroundA = gTrue;
1316 for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1317 backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1321 error(-1, "Bad Background in shading dictionary");
1326 xMinA = yMinA = xMaxA = yMaxA = 0;
1328 if (obj->dictLookup("BBox", &obj1)->isArray()) {
1329 if (obj1.arrayGetLength() == 4) {
1331 xMinA = obj1.arrayGet(0, &obj2)->getNum();
1333 yMinA = obj1.arrayGet(1, &obj2)->getNum();
1335 xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1337 yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1340 error(-1, "Bad BBox in shading dictionary");
1347 shading = GfxAxialShading::parse(obj->getDict());
1350 shading = GfxRadialShading::parse(obj->getDict());
1353 error(-1, "Unimplemented shading type %d", typeA);
1358 shading->type = typeA;
1359 shading->colorSpace = colorSpaceA;
1360 shading->background = backgroundA;
1361 shading->hasBackground = hasBackgroundA;
1362 shading->xMin = xMinA;
1363 shading->yMin = yMinA;
1364 shading->xMax = xMaxA;
1365 shading->yMax = yMaxA;
1366 shading->hasBBox = hasBBoxA;
1378 //------------------------------------------------------------------------
1380 //------------------------------------------------------------------------
1382 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1383 double x1A, double y1A,
1384 double t0A, double t1A,
1385 Function **funcsA, int nFuncsA,
1386 GBool extend0A, GBool extend1A) {
1396 for (i = 0; i < nFuncs; ++i) {
1397 funcs[i] = funcsA[i];
1403 GfxAxialShading::~GfxAxialShading() {
1406 for (i = 0; i < nFuncs; ++i) {
1411 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1412 double x0A, y0A, x1A, y1A;
1414 Function *funcsA[gfxColorMaxComps];
1416 GBool extend0A, extend1A;
1420 x0A = y0A = x1A = y1A = 0;
1421 if (dict->lookup("Coords", &obj1)->isArray() &&
1422 obj1.arrayGetLength() == 4) {
1423 x0A = obj1.arrayGet(0, &obj2)->getNum();
1425 y0A = obj1.arrayGet(1, &obj2)->getNum();
1427 x1A = obj1.arrayGet(2, &obj2)->getNum();
1429 y1A = obj1.arrayGet(3, &obj2)->getNum();
1432 error(-1, "Missing or invalid Coords in shading dictionary");
1439 if (dict->lookup("Domain", &obj1)->isArray() &&
1440 obj1.arrayGetLength() == 2) {
1441 t0A = obj1.arrayGet(0, &obj2)->getNum();
1443 t1A = obj1.arrayGet(1, &obj2)->getNum();
1448 dict->lookup("Function", &obj1);
1449 if (obj1.isArray()) {
1450 nFuncsA = obj1.arrayGetLength();
1451 for (i = 0; i < nFuncsA; ++i) {
1452 obj1.arrayGet(i, &obj2);
1453 if (!(funcsA[i] = Function::parse(&obj2))) {
1462 if (!(funcsA[0] = Function::parse(&obj1))) {
1469 extend0A = extend1A = gFalse;
1470 if (dict->lookup("Extend", &obj1)->isArray() &&
1471 obj1.arrayGetLength() == 2) {
1472 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1474 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1479 return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1480 funcsA, nFuncsA, extend0A, extend1A);
1486 void GfxAxialShading::getColor(double t, GfxColor *color) {
1489 for (i = 0; i < nFuncs; ++i) {
1490 funcs[i]->transform(&t, &color->c[i]);
1494 //------------------------------------------------------------------------
1496 //------------------------------------------------------------------------
1498 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1499 double x1A, double y1A, double r1A,
1500 double t0A, double t1A,
1501 Function **funcsA, int nFuncsA,
1502 GBool extend0A, GBool extend1A) {
1514 for (i = 0; i < nFuncs; ++i) {
1515 funcs[i] = funcsA[i];
1521 GfxRadialShading::~GfxRadialShading() {
1524 for (i = 0; i < nFuncs; ++i) {
1529 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1530 double x0A, y0A, r0A, x1A, y1A, r1A;
1532 Function *funcsA[gfxColorMaxComps];
1534 GBool extend0A, extend1A;
1538 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1539 if (dict->lookup("Coords", &obj1)->isArray() &&
1540 obj1.arrayGetLength() == 6) {
1541 x0A = obj1.arrayGet(0, &obj2)->getNum();
1543 y0A = obj1.arrayGet(1, &obj2)->getNum();
1545 r0A = obj1.arrayGet(2, &obj2)->getNum();
1547 x1A = obj1.arrayGet(3, &obj2)->getNum();
1549 y1A = obj1.arrayGet(4, &obj2)->getNum();
1551 r1A = obj1.arrayGet(5, &obj2)->getNum();
1554 error(-1, "Missing or invalid Coords in shading dictionary");
1561 if (dict->lookup("Domain", &obj1)->isArray() &&
1562 obj1.arrayGetLength() == 2) {
1563 t0A = obj1.arrayGet(0, &obj2)->getNum();
1565 t1A = obj1.arrayGet(1, &obj2)->getNum();
1570 dict->lookup("Function", &obj1);
1571 if (obj1.isArray()) {
1572 nFuncsA = obj1.arrayGetLength();
1573 for (i = 0; i < nFuncsA; ++i) {
1574 obj1.arrayGet(i, &obj2);
1575 if (!(funcsA[i] = Function::parse(&obj2))) {
1584 if (!(funcsA[0] = Function::parse(&obj1))) {
1591 extend0A = extend1A = gFalse;
1592 if (dict->lookup("Extend", &obj1)->isArray() &&
1593 obj1.arrayGetLength() == 2) {
1594 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1596 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1601 return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1602 funcsA, nFuncsA, extend0A, extend1A);
1608 void GfxRadialShading::getColor(double t, GfxColor *color) {
1611 for (i = 0; i < nFuncs; ++i) {
1612 funcs[i]->transform(&t, &color->c[i]);
1616 //------------------------------------------------------------------------
1618 //------------------------------------------------------------------------
1620 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1621 GfxColorSpace *colorSpaceA) {
1622 GfxIndexedColorSpace *indexedCS;
1623 GfxSeparationColorSpace *sepCS;
1624 int maxPixel, indexHigh;
1628 double x[gfxColorMaxComps];
1629 double y[gfxColorMaxComps];
1634 // bits per component and color space
1636 maxPixel = (1 << bits) - 1;
1637 colorSpace = colorSpaceA;
1640 if (decode->isNull()) {
1641 nComps = colorSpace->getNComps();
1642 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1643 } else if (decode->isArray()) {
1644 nComps = decode->arrayGetLength() / 2;
1645 if (nComps != colorSpace->getNComps()) {
1648 for (i = 0; i < nComps; ++i) {
1649 decode->arrayGet(2*i, &obj);
1653 decodeLow[i] = obj.getNum();
1655 decode->arrayGet(2*i+1, &obj);
1659 decodeRange[i] = obj.getNum() - decodeLow[i];
1666 // Construct a lookup table -- this stores pre-computed decoded
1667 // values for each component, i.e., the result of applying the
1668 // decode mapping to each possible image pixel component value.
1670 // Optimization: for Indexed and Separation color spaces (which have
1671 // only one component), we store color values in the lookup table
1672 // rather than component values.
1675 if (colorSpace->getMode() == csIndexed) {
1676 // Note that indexHigh may not be the same as maxPixel --
1677 // Distiller will remove unused palette entries, resulting in
1678 // indexHigh < maxPixel.
1679 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1680 colorSpace2 = indexedCS->getBase();
1681 indexHigh = indexedCS->getIndexHigh();
1682 nComps2 = colorSpace2->getNComps();
1683 lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1684 lookup2 = indexedCS->getLookup();
1685 for (i = 0; i <= indexHigh; ++i) {
1686 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1687 for (k = 0; k < nComps2; ++k) {
1688 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1691 } else if (colorSpace->getMode() == csSeparation) {
1692 sepCS = (GfxSeparationColorSpace *)colorSpace;
1693 colorSpace2 = sepCS->getAlt();
1694 nComps2 = colorSpace2->getNComps();
1695 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1696 sepFunc = sepCS->getFunc();
1697 for (i = 0; i <= maxPixel; ++i) {
1698 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1699 sepFunc->transform(x, y);
1700 for (k = 0; k < nComps2; ++k) {
1701 lookup[i*nComps2 + k] = y[k];
1705 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1706 for (i = 0; i <= maxPixel; ++i) {
1707 for (k = 0; k < nComps; ++k) {
1708 lookup[i*nComps + k] = decodeLow[k] +
1709 (i * decodeRange[k]) / maxPixel;
1722 GfxImageColorMap::~GfxImageColorMap() {
1727 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1733 p = &lookup[x[0] * nComps2];
1734 for (i = 0; i < nComps2; ++i) {
1737 colorSpace2->getGray(&color, gray);
1739 for (i = 0; i < nComps; ++i) {
1740 color.c[i] = lookup[x[i] * nComps + i];
1742 colorSpace->getGray(&color, gray);
1746 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1752 p = &lookup[x[0] * nComps2];
1753 for (i = 0; i < nComps2; ++i) {
1756 colorSpace2->getRGB(&color, rgb);
1758 for (i = 0; i < nComps; ++i) {
1759 color.c[i] = lookup[x[i] * nComps + i];
1761 colorSpace->getRGB(&color, rgb);
1765 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1771 p = &lookup[x[0] * nComps2];
1772 for (i = 0; i < nComps2; ++i) {
1775 colorSpace2->getCMYK(&color, cmyk);
1777 for (i = 0; i < nComps; ++i) {
1778 color.c[i] = lookup[x[i] * nComps + i];
1780 colorSpace->getCMYK(&color, cmyk);
1784 //------------------------------------------------------------------------
1785 // GfxSubpath and GfxPath
1786 //------------------------------------------------------------------------
1788 GfxSubpath::GfxSubpath(double x1, double y1) {
1790 x = (double *)gmalloc(size * sizeof(double));
1791 y = (double *)gmalloc(size * sizeof(double));
1792 curve = (GBool *)gmalloc(size * sizeof(GBool));
1800 GfxSubpath::~GfxSubpath() {
1807 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1808 size = subpath->size;
1810 x = (double *)gmalloc(size * sizeof(double));
1811 y = (double *)gmalloc(size * sizeof(double));
1812 curve = (GBool *)gmalloc(size * sizeof(GBool));
1813 memcpy(x, subpath->x, n * sizeof(double));
1814 memcpy(y, subpath->y, n * sizeof(double));
1815 memcpy(curve, subpath->curve, n * sizeof(GBool));
1816 closed = subpath->closed;
1819 void GfxSubpath::lineTo(double x1, double y1) {
1822 x = (double *)grealloc(x, size * sizeof(double));
1823 y = (double *)grealloc(y, size * sizeof(double));
1824 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1832 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1833 double x3, double y3) {
1836 x = (double *)grealloc(x, size * sizeof(double));
1837 y = (double *)grealloc(y, size * sizeof(double));
1838 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1846 curve[n] = curve[n+1] = gTrue;
1847 curve[n+2] = gFalse;
1851 void GfxSubpath::close() {
1852 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1858 GfxPath::GfxPath() {
1862 firstX = firstY = 0;
1863 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1866 GfxPath::~GfxPath() {
1869 for (i = 0; i < n; ++i)
1875 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1876 GfxSubpath **subpaths1, int n1, int size1) {
1879 justMoved = justMoved1;
1884 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1885 for (i = 0; i < n; ++i)
1886 subpaths[i] = subpaths1[i]->copy();
1889 void GfxPath::moveTo(double x, double y) {
1895 void GfxPath::lineTo(double x, double y) {
1899 subpaths = (GfxSubpath **)
1900 grealloc(subpaths, size * sizeof(GfxSubpath *));
1902 subpaths[n] = new GfxSubpath(firstX, firstY);
1906 subpaths[n-1]->lineTo(x, y);
1909 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1910 double x3, double y3) {
1914 subpaths = (GfxSubpath **)
1915 grealloc(subpaths, size * sizeof(GfxSubpath *));
1917 subpaths[n] = new GfxSubpath(firstX, firstY);
1921 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1924 void GfxPath::close() {
1925 // this is necessary to handle the pathological case of
1926 // moveto/closepath/clip, which defines an empty clipping region
1930 subpaths = (GfxSubpath **)
1931 grealloc(subpaths, size * sizeof(GfxSubpath *));
1933 subpaths[n] = new GfxSubpath(firstX, firstY);
1937 subpaths[n-1]->close();
1940 //------------------------------------------------------------------------
1942 //------------------------------------------------------------------------
1944 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
1955 ctm[1] = upsideDown ? k : -k;
1959 ctm[5] = k * (upsideDown ? -px1 : px2);
1960 pageWidth = k * (py2 - py1);
1961 pageHeight = k * (px2 - px1);
1962 } else if (rotate == 180) {
1966 ctm[3] = upsideDown ? k : -k;
1968 ctm[5] = k * (upsideDown ? -py1 : py2);
1969 pageWidth = k * (px2 - px1);
1970 pageHeight = k * (py2 - py1);
1971 } else if (rotate == 270) {
1973 ctm[1] = upsideDown ? -k : k;
1977 ctm[5] = k * (upsideDown ? px2 : -px1);
1978 pageWidth = k * (py2 - py1);
1979 pageHeight = k * (px2 - px1);
1984 ctm[3] = upsideDown ? -k : k;
1986 ctm[5] = k * (upsideDown ? py2 : -py1);
1987 pageWidth = k * (px2 - px1);
1988 pageHeight = k * (py2 - py1);
1991 fillColorSpace = new GfxDeviceGrayColorSpace();
1992 strokeColorSpace = new GfxDeviceGrayColorSpace();
1994 strokeColor.c[0] = 0;
1996 strokePattern = NULL;
2011 textMat[0] = 1; textMat[1] = 0;
2012 textMat[2] = 0; textMat[3] = 1;
2013 textMat[4] = 0; textMat[5] = 0;
2021 path = new GfxPath();
2027 clipXMax = pageWidth;
2028 clipYMax = pageHeight;
2033 GfxState::~GfxState() {
2034 if (fillColorSpace) {
2035 delete fillColorSpace;
2037 if (strokeColorSpace) {
2038 delete strokeColorSpace;
2043 if (strokePattern) {
2044 delete strokePattern;
2048 // this gets set to NULL by restore()
2057 GfxState::GfxState(GfxState *state) {
2058 memcpy(this, state, sizeof(GfxState));
2059 if (fillColorSpace) {
2060 fillColorSpace = state->fillColorSpace->copy();
2062 if (strokeColorSpace) {
2063 strokeColorSpace = state->strokeColorSpace->copy();
2066 fillPattern = state->fillPattern->copy();
2068 if (strokePattern) {
2069 strokePattern = state->strokePattern->copy();
2071 if (lineDashLength > 0) {
2072 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2073 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2078 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2079 double *xMax, double *yMax) {
2081 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2084 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2085 ictm[0] = ctm[3] * det;
2086 ictm[1] = -ctm[1] * det;
2087 ictm[2] = -ctm[2] * det;
2088 ictm[3] = ctm[0] * det;
2089 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2090 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2092 // transform all four corners of the clip bbox; find the min and max
2094 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2095 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2096 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2097 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2100 } else if (tx > xMax1) {
2105 } else if (ty > yMax1) {
2108 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2109 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2112 } else if (tx > xMax1) {
2117 } else if (ty > yMax1) {
2120 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2121 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2124 } else if (tx > xMax1) {
2129 } else if (ty > yMax1) {
2139 double GfxState::transformWidth(double w) {
2142 x = ctm[0] + ctm[2];
2143 y = ctm[1] + ctm[3];
2144 return w * sqrt(0.5 * (x * x + y * y));
2147 double GfxState::getTransformedFontSize() {
2148 double x1, y1, x2, y2;
2150 x1 = textMat[2] * fontSize;
2151 y1 = textMat[3] * fontSize;
2152 x2 = ctm[0] * x1 + ctm[2] * y1;
2153 y2 = ctm[1] * x1 + ctm[3] * y1;
2154 return sqrt(x2 * x2 + y2 * y2);
2157 void GfxState::getFontTransMat(double *m11, double *m12,
2158 double *m21, double *m22) {
2159 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2160 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2161 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2162 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2165 void GfxState::setCTM(double a, double b, double c,
2166 double d, double e, double f) {
2176 // avoid FP exceptions on badly messed up PDF files
2177 for (i = 0; i < 6; ++i) {
2178 if (ctm[i] > 1e10) {
2180 } else if (ctm[i] < -1e10) {
2186 void GfxState::concatCTM(double a, double b, double c,
2187 double d, double e, double f) {
2194 ctm[0] = a * a1 + b * c1;
2195 ctm[1] = a * b1 + b * d1;
2196 ctm[2] = c * a1 + d * c1;
2197 ctm[3] = c * b1 + d * d1;
2198 ctm[4] = e * a1 + f * c1 + ctm[4];
2199 ctm[5] = e * b1 + f * d1 + ctm[5];
2201 // avoid FP exceptions on badly messed up PDF files
2202 for (i = 0; i < 6; ++i) {
2203 if (ctm[i] > 1e10) {
2205 } else if (ctm[i] < -1e10) {
2211 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2212 if (fillColorSpace) {
2213 delete fillColorSpace;
2215 fillColorSpace = colorSpace;
2218 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2219 if (strokeColorSpace) {
2220 delete strokeColorSpace;
2222 strokeColorSpace = colorSpace;
2225 void GfxState::setFillPattern(GfxPattern *pattern) {
2229 fillPattern = pattern;
2232 void GfxState::setStrokePattern(GfxPattern *pattern) {
2233 if (strokePattern) {
2234 delete strokePattern;
2236 strokePattern = pattern;
2239 void GfxState::setLineDash(double *dash, int length, double start) {
2243 lineDashLength = length;
2244 lineDashStart = start;
2247 void GfxState::clearPath() {
2249 path = new GfxPath();
2252 void GfxState::clip() {
2253 double xMin, yMin, xMax, yMax, x, y;
2254 GfxSubpath *subpath;
2257 xMin = xMax = yMin = yMax = 0; // make gcc happy
2258 for (i = 0; i < path->getNumSubpaths(); ++i) {
2259 subpath = path->getSubpath(i);
2260 for (j = 0; j < subpath->getNumPoints(); ++j) {
2261 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2262 if (i == 0 && j == 0) {
2268 } else if (x > xMax) {
2273 } else if (y > yMax) {
2279 if (xMin > clipXMin) {
2282 if (yMin > clipYMin) {
2285 if (xMax < clipXMax) {
2288 if (yMax < clipYMax) {
2293 void GfxState::textShift(double tx, double ty) {
2296 textTransformDelta(tx, ty, &dx, &dy);
2301 void GfxState::shift(double dx, double dy) {
2306 GfxState *GfxState::save() {
2310 newState->saved = this;
2314 GfxState *GfxState::restore() {
2320 // these attributes aren't saved/restored by the q/Q operators
2321 oldState->path = path;
2322 oldState->curX = curX;
2323 oldState->curY = curY;
2324 oldState->lineX = lineX;
2325 oldState->lineY = lineY;