1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
15 #include <string.h> // for memcpy()
22 //------------------------------------------------------------------------
24 static inline double clip01(double x) {
25 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
28 //------------------------------------------------------------------------
30 //------------------------------------------------------------------------
32 GfxColorSpace::GfxColorSpace() {
35 GfxColorSpace::~GfxColorSpace() {
38 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
43 if (csObj->isName()) {
44 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
45 cs = new GfxDeviceGrayColorSpace();
46 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
47 cs = new GfxDeviceRGBColorSpace();
48 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
49 cs = new GfxDeviceCMYKColorSpace();
50 } else if (csObj->isName("Pattern")) {
51 cs = new GfxPatternColorSpace(NULL);
53 error(-1, "Bad color space '%s'", csObj->getName());
55 } else if (csObj->isArray()) {
56 csObj->arrayGet(0, &obj1);
57 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
58 cs = new GfxDeviceGrayColorSpace();
59 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
60 cs = new GfxDeviceRGBColorSpace();
61 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
62 cs = new GfxDeviceCMYKColorSpace();
63 } else if (obj1.isName("CalGray")) {
64 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
65 } else if (obj1.isName("CalRGB")) {
66 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
67 } else if (obj1.isName("Lab")) {
68 cs = GfxLabColorSpace::parse(csObj->getArray());
69 } else if (obj1.isName("ICCBased")) {
70 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
71 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
72 cs = GfxIndexedColorSpace::parse(csObj->getArray());
73 } else if (obj1.isName("Separation")) {
74 cs = GfxSeparationColorSpace::parse(csObj->getArray());
75 } else if (obj1.isName("DeviceN")) {
76 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
77 } else if (obj1.isName("Pattern")) {
78 cs = GfxPatternColorSpace::parse(csObj->getArray());
80 error(-1, "Bad color space '%s'", csObj->getName());
84 error(-1, "Bad color space - expected name or array");
89 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
93 for (i = 0; i < getNComps(); ++i) {
99 //------------------------------------------------------------------------
100 // GfxDeviceGrayColorSpace
101 //------------------------------------------------------------------------
103 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
106 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
109 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
110 return new GfxDeviceGrayColorSpace();
113 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
114 *gray = clip01(color->c[0]);
117 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
118 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
121 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
122 cmyk->c = cmyk->m = cmyk->y = 0;
123 cmyk->k = clip01(1 - color->c[0]);
126 //------------------------------------------------------------------------
127 // GfxCalGrayColorSpace
128 //------------------------------------------------------------------------
130 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
131 whiteX = whiteY = whiteZ = 1;
132 blackX = blackY = blackZ = 0;
136 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
139 GfxColorSpace *GfxCalGrayColorSpace::copy() {
140 GfxCalGrayColorSpace *cs;
142 cs = new GfxCalGrayColorSpace();
153 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
154 GfxCalGrayColorSpace *cs;
155 Object obj1, obj2, obj3;
158 if (!obj1.isDict()) {
159 error(-1, "Bad CalGray color space");
163 cs = new GfxCalGrayColorSpace();
164 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
165 obj2.arrayGetLength() == 3) {
166 obj2.arrayGet(0, &obj3);
167 cs->whiteX = obj3.getNum();
169 obj2.arrayGet(1, &obj3);
170 cs->whiteY = obj3.getNum();
172 obj2.arrayGet(2, &obj3);
173 cs->whiteZ = obj3.getNum();
177 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
178 obj2.arrayGetLength() == 3) {
179 obj2.arrayGet(0, &obj3);
180 cs->blackX = obj3.getNum();
182 obj2.arrayGet(1, &obj3);
183 cs->blackY = obj3.getNum();
185 obj2.arrayGet(2, &obj3);
186 cs->blackZ = obj3.getNum();
190 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
191 cs->gamma = obj2.getNum();
198 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
199 *gray = clip01(color->c[0]);
202 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
203 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
206 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
207 cmyk->c = cmyk->m = cmyk->y = 0;
208 cmyk->k = clip01(1 - color->c[0]);
211 //------------------------------------------------------------------------
212 // GfxDeviceRGBColorSpace
213 //------------------------------------------------------------------------
215 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
218 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
221 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
222 return new GfxDeviceRGBColorSpace();
225 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
226 *gray = clip01(0.299 * color->c[0] +
227 0.587 * color->c[1] +
228 0.114 * color->c[2]);
231 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
232 rgb->r = clip01(color->c[0]);
233 rgb->g = clip01(color->c[1]);
234 rgb->b = clip01(color->c[2]);
237 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
240 c = clip01(1 - color->c[0]);
241 m = clip01(1 - color->c[1]);
242 y = clip01(1 - color->c[2]);
256 //------------------------------------------------------------------------
257 // GfxCalRGBColorSpace
258 //------------------------------------------------------------------------
260 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
261 whiteX = whiteY = whiteZ = 1;
262 blackX = blackY = blackZ = 0;
263 gammaR = gammaG = gammaB = 1;
264 m[0] = 1; m[1] = 0; m[2] = 0;
265 m[3] = 0; m[4] = 1; m[5] = 0;
266 m[6] = 0; m[7] = 0; m[8] = 1;
269 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
272 GfxColorSpace *GfxCalRGBColorSpace::copy() {
273 GfxCalRGBColorSpace *cs;
276 cs = new GfxCalRGBColorSpace();
286 for (i = 0; i < 9; ++i) {
292 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
293 GfxCalRGBColorSpace *cs;
294 Object obj1, obj2, obj3;
298 if (!obj1.isDict()) {
299 error(-1, "Bad CalRGB color space");
303 cs = new GfxCalRGBColorSpace();
304 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
305 obj2.arrayGetLength() == 3) {
306 obj2.arrayGet(0, &obj3);
307 cs->whiteX = obj3.getNum();
309 obj2.arrayGet(1, &obj3);
310 cs->whiteY = obj3.getNum();
312 obj2.arrayGet(2, &obj3);
313 cs->whiteZ = obj3.getNum();
317 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
318 obj2.arrayGetLength() == 3) {
319 obj2.arrayGet(0, &obj3);
320 cs->blackX = obj3.getNum();
322 obj2.arrayGet(1, &obj3);
323 cs->blackY = obj3.getNum();
325 obj2.arrayGet(2, &obj3);
326 cs->blackZ = obj3.getNum();
330 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
331 obj2.arrayGetLength() == 3) {
332 obj2.arrayGet(0, &obj3);
333 cs->gammaR = obj3.getNum();
335 obj2.arrayGet(1, &obj3);
336 cs->gammaG = obj3.getNum();
338 obj2.arrayGet(2, &obj3);
339 cs->gammaB = obj3.getNum();
343 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
344 obj2.arrayGetLength() == 9) {
345 for (i = 0; i < 9; ++i) {
346 obj2.arrayGet(i, &obj3);
347 cs->m[i] = obj3.getNum();
356 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
357 *gray = clip01(0.299 * color->c[0] +
358 0.587 * color->c[1] +
359 0.114 * color->c[2]);
362 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
363 rgb->r = clip01(color->c[0]);
364 rgb->g = clip01(color->c[1]);
365 rgb->b = clip01(color->c[2]);
368 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
371 c = clip01(1 - color->c[0]);
372 m = clip01(1 - color->c[1]);
373 y = clip01(1 - color->c[2]);
387 //------------------------------------------------------------------------
388 // GfxDeviceCMYKColorSpace
389 //------------------------------------------------------------------------
391 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
394 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
397 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
398 return new GfxDeviceCMYKColorSpace();
401 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
402 *gray = clip01(1 - color->c[3]
403 - 0.299 * color->c[0]
404 - 0.587 * color->c[1]
405 - 0.114 * color->c[2]);
408 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
409 rgb->r = clip01(1 - (color->c[0] + color->c[3]));
410 rgb->g = clip01(1 - (color->c[1] + color->c[3]));
411 rgb->b = clip01(1 - (color->c[2] + color->c[3]));
414 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
415 cmyk->c = clip01(color->c[0]);
416 cmyk->m = clip01(color->c[1]);
417 cmyk->y = clip01(color->c[2]);
418 cmyk->k = clip01(color->c[3]);
421 //------------------------------------------------------------------------
423 //------------------------------------------------------------------------
425 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
426 // Language Reference, Third Edition.
427 static double xyzrgb[3][3] = {
428 { 3.240449, -1.537136, -0.498531 },
429 { -0.969265, 1.876011, 0.041556 },
430 { 0.055643, -0.204026, 1.057229 }
433 GfxLabColorSpace::GfxLabColorSpace() {
434 whiteX = whiteY = whiteZ = 1;
435 blackX = blackY = blackZ = 0;
440 GfxLabColorSpace::~GfxLabColorSpace() {
443 GfxColorSpace *GfxLabColorSpace::copy() {
444 GfxLabColorSpace *cs;
446 cs = new GfxLabColorSpace();
463 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
464 GfxLabColorSpace *cs;
465 Object obj1, obj2, obj3;
468 if (!obj1.isDict()) {
469 error(-1, "Bad Lab color space");
473 cs = new GfxLabColorSpace();
474 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
475 obj2.arrayGetLength() == 3) {
476 obj2.arrayGet(0, &obj3);
477 cs->whiteX = obj3.getNum();
479 obj2.arrayGet(1, &obj3);
480 cs->whiteY = obj3.getNum();
482 obj2.arrayGet(2, &obj3);
483 cs->whiteZ = obj3.getNum();
487 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
488 obj2.arrayGetLength() == 3) {
489 obj2.arrayGet(0, &obj3);
490 cs->blackX = obj3.getNum();
492 obj2.arrayGet(1, &obj3);
493 cs->blackY = obj3.getNum();
495 obj2.arrayGet(2, &obj3);
496 cs->blackZ = obj3.getNum();
500 if (obj1.dictLookup("Range", &obj2)->isArray() &&
501 obj2.arrayGetLength() == 4) {
502 obj2.arrayGet(0, &obj3);
503 cs->aMin = obj3.getNum();
505 obj2.arrayGet(1, &obj3);
506 cs->aMax = obj3.getNum();
508 obj2.arrayGet(2, &obj3);
509 cs->bMin = obj3.getNum();
511 obj2.arrayGet(3, &obj3);
512 cs->bMax = obj3.getNum();
518 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
519 xyzrgb[0][1] * cs->whiteY +
520 xyzrgb[0][2] * cs->whiteZ);
521 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
522 xyzrgb[1][1] * cs->whiteY +
523 xyzrgb[1][2] * cs->whiteZ);
524 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
525 xyzrgb[2][1] * cs->whiteY +
526 xyzrgb[2][2] * cs->whiteZ);
531 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
535 *gray = clip01(0.299 * rgb.r +
540 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
545 // convert L*a*b* to CIE 1931 XYZ color space
546 t1 = (color->c[0] + 16) / 116;
547 t2 = t1 + color->c[1] / 500;
548 if (t2 >= (6.0 / 29.0)) {
551 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
554 if (t1 >= (6.0 / 29.0)) {
557 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
560 t2 = t1 - color->c[2] / 200;
561 if (t2 >= (6.0 / 29.0)) {
564 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
568 // convert XYZ to RGB, including gamut mapping and gamma correction
569 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
570 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
571 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
572 rgb->r = pow(clip01(r * kr), 0.5);
573 rgb->g = pow(clip01(g * kg), 0.5);
574 rgb->b = pow(clip01(b * kb), 0.5);
577 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
582 c = clip01(1 - rgb.r);
583 m = clip01(1 - rgb.g);
584 y = clip01(1 - rgb.b);
598 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
601 decodeRange[0] = 100;
603 decodeRange[1] = aMax - aMin;
605 decodeRange[2] = bMax - bMin;
608 //------------------------------------------------------------------------
609 // GfxICCBasedColorSpace
610 //------------------------------------------------------------------------
612 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
613 Ref *iccProfileStream) {
614 this->nComps = nComps;
616 this->iccProfileStream = *iccProfileStream;
617 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
618 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
621 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
625 GfxColorSpace *GfxICCBasedColorSpace::copy() {
626 GfxICCBasedColorSpace *cs;
629 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
630 for (i = 0; i < 4; ++i) {
631 cs->rangeMin[i] = rangeMin[i];
632 cs->rangeMax[i] = rangeMax[i];
637 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
638 GfxICCBasedColorSpace *cs;
639 Ref iccProfileStream;
643 Object obj1, obj2, obj3;
646 arr->getNF(1, &obj1);
648 iccProfileStream = obj1.getRef();
650 iccProfileStream.num = 0;
651 iccProfileStream.gen = 0;
655 if (!obj1.isStream()) {
656 error(-1, "Bad ICCBased color space (stream)");
660 dict = obj1.streamGetDict();
661 if (!dict->lookup("N", &obj2)->isInt()) {
662 error(-1, "Bad ICCBased color space (N)");
667 nComps = obj2.getInt();
669 if (dict->lookup("Alternate", &obj2)->isNull() ||
670 !(alt = GfxColorSpace::parse(&obj2))) {
673 alt = new GfxDeviceGrayColorSpace();
676 alt = new GfxDeviceRGBColorSpace();
679 alt = new GfxDeviceCMYKColorSpace();
682 error(-1, "Bad ICCBased color space - invalid N");
689 cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream);
690 if (dict->lookup("Range", &obj2)->isArray() &&
691 obj2.arrayGetLength() == 2 * nComps) {
692 for (i = 0; i < nComps; ++i) {
693 obj2.arrayGet(2*i, &obj3);
694 cs->rangeMin[i] = obj3.getNum();
696 obj2.arrayGet(2*i+1, &obj3);
697 cs->rangeMax[i] = obj3.getNum();
706 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
707 alt->getGray(color, gray);
710 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
711 alt->getRGB(color, rgb);
714 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
715 alt->getCMYK(color, cmyk);
718 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
723 for (i = 0; i < nComps; ++i) {
724 decodeLow[i] = rangeMin[i];
725 decodeRange[i] = rangeMax[i] - rangeMin[i];
729 //------------------------------------------------------------------------
730 // GfxIndexedColorSpace
731 //------------------------------------------------------------------------
733 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *base,
736 this->indexHigh = indexHigh;
737 this->lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
741 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
746 GfxColorSpace *GfxIndexedColorSpace::copy() {
747 GfxIndexedColorSpace *cs;
749 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
750 memcpy(cs->lookup, lookup,
751 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
755 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
756 GfxIndexedColorSpace *cs;
764 if (arr->getLength() != 4) {
765 error(-1, "Bad Indexed color space");
769 if (!(base = GfxColorSpace::parse(&obj1))) {
770 error(-1, "Bad Indexed color space (base color space)");
774 if (!arr->get(2, &obj1)->isInt()) {
775 error(-1, "Bad Indexed color space (hival)");
778 indexHigh = obj1.getInt();
780 cs = new GfxIndexedColorSpace(base, indexHigh);
782 n = base->getNComps();
783 if (obj1.isStream()) {
785 for (i = 0; i <= indexHigh; ++i) {
786 for (j = 0; j < n; ++j) {
787 if ((x = obj1.streamGetChar()) == EOF) {
788 error(-1, "Bad Indexed color space (lookup table stream too short)");
791 cs->lookup[i*n + j] = (Guchar)x;
795 } else if (obj1.isString()) {
796 if (obj1.getString()->getLength() < (indexHigh + 1) * n) {
797 error(-1, "Bad Indexed color space (lookup table string too short)");
800 s = obj1.getString()->getCString();
801 for (i = 0; i <= indexHigh; ++i) {
802 for (j = 0; j < n; ++j) {
803 cs->lookup[i*n + j] = (Guchar)*s++;
807 error(-1, "Bad Indexed color space (lookup table)");
821 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
826 n = base->getNComps();
827 p = &lookup[(int)(color->c[0] + 0.5) * n];
828 for (i = 0; i < n; ++i) {
829 color2.c[i] = p[i] / 255.0;
831 base->getGray(&color2, gray);
834 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
839 n = base->getNComps();
840 p = &lookup[(int)(color->c[0] + 0.5) * n];
841 for (i = 0; i < n; ++i) {
842 color2.c[i] = p[i] / 255.0;
844 base->getRGB(&color2, rgb);
847 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
852 n = base->getNComps();
853 p = &lookup[(int)(color->c[0] + 0.5) * n];
854 for (i = 0; i < n; ++i) {
855 color2.c[i] = p[i] / 255.0;
857 base->getCMYK(&color2, cmyk);
860 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
864 decodeRange[0] = maxImgPixel;
867 //------------------------------------------------------------------------
868 // GfxSeparationColorSpace
869 //------------------------------------------------------------------------
871 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name,
879 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
885 GfxColorSpace *GfxSeparationColorSpace::copy() {
886 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
889 //~ handle the 'All' and 'None' colorants
890 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
891 GfxSeparationColorSpace *cs;
897 if (arr->getLength() != 4) {
898 error(-1, "Bad Separation color space");
901 if (!arr->get(1, &obj1)->isName()) {
902 error(-1, "Bad Separation color space (name)");
905 name = new GString(obj1.getName());
908 if (!(alt = GfxColorSpace::parse(&obj1))) {
909 error(-1, "Bad Separation color space (alternate color space)");
913 func = Function::parse(arr->get(3, &obj1));
918 cs = new GfxSeparationColorSpace(name, alt, func);
932 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
935 func->transform(color->c, color2.c);
936 alt->getGray(&color2, gray);
939 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
942 func->transform(color->c, color2.c);
943 alt->getRGB(&color2, rgb);
946 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
949 func->transform(color->c, color2.c);
950 alt->getCMYK(&color2, cmyk);
953 //------------------------------------------------------------------------
954 // GfxDeviceNColorSpace
955 //------------------------------------------------------------------------
957 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
960 this->nComps = nComps;
965 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
968 for (i = 0; i < nComps; ++i) {
975 GfxColorSpace *GfxDeviceNColorSpace::copy() {
976 GfxDeviceNColorSpace *cs;
979 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
980 for (i = 0; i < nComps; ++i) {
981 cs->names[i] = names[i]->copy();
986 //~ handle the 'None' colorant
987 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
988 GfxDeviceNColorSpace *cs;
990 GString *names[gfxColorMaxComps];
996 if (arr->getLength() != 4 && arr->getLength() != 5) {
997 error(-1, "Bad DeviceN color space");
1000 if (!arr->get(1, &obj1)->isArray()) {
1001 error(-1, "Bad DeviceN color space (names)");
1004 nComps = obj1.arrayGetLength();
1005 for (i = 0; i < nComps; ++i) {
1006 if (!obj1.arrayGet(i, &obj2)->isName()) {
1007 error(-1, "Bad DeviceN color space (names)");
1011 names[i] = new GString(obj2.getName());
1016 if (!(alt = GfxColorSpace::parse(&obj1))) {
1017 error(-1, "Bad DeviceN color space (alternate color space)");
1021 func = Function::parse(arr->get(3, &obj1));
1023 if (!func->isOk()) {
1026 cs = new GfxDeviceNColorSpace(nComps, alt, func);
1027 for (i = 0; i < nComps; ++i) {
1028 cs->names[i] = names[i];
1036 for (i = 0; i < nComps; ++i) {
1045 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1048 func->transform(color->c, color2.c);
1049 alt->getGray(&color2, gray);
1052 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1055 func->transform(color->c, color2.c);
1056 alt->getRGB(&color2, rgb);
1059 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1062 func->transform(color->c, color2.c);
1063 alt->getCMYK(&color2, cmyk);
1066 //------------------------------------------------------------------------
1067 // GfxPatternColorSpace
1068 //------------------------------------------------------------------------
1070 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
1071 this->under = under;
1074 GfxPatternColorSpace::~GfxPatternColorSpace() {
1080 GfxColorSpace *GfxPatternColorSpace::copy() {
1081 return new GfxPatternColorSpace(under ? under->copy() :
1082 (GfxColorSpace *)NULL);
1085 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1086 GfxPatternColorSpace *cs;
1087 GfxColorSpace *under;
1090 if (arr->getLength() != 1 && arr->getLength() != 2) {
1091 error(-1, "Bad Pattern color space");
1095 if (arr->getLength() == 2) {
1097 if (!(under = GfxColorSpace::parse(&obj1))) {
1098 error(-1, "Bad Pattern color space (underlying color space)");
1104 cs = new GfxPatternColorSpace(under);
1108 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1112 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1113 rgb->r = rgb->g = rgb->b = 0;
1116 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1117 cmyk->c = cmyk->m = cmyk->y = 0;
1121 //------------------------------------------------------------------------
1123 //------------------------------------------------------------------------
1125 GfxPattern::GfxPattern(int type) {
1129 GfxPattern::~GfxPattern() {
1132 GfxPattern *GfxPattern::parse(Object *obj) {
1133 GfxPattern *pattern;
1138 if (obj->isStream()) {
1139 dict = obj->streamGetDict();
1140 dict->lookup("PatternType", &obj1);
1141 if (obj1.isInt() && obj1.getInt() == 1) {
1142 pattern = new GfxTilingPattern(dict, obj);
1149 //------------------------------------------------------------------------
1151 //------------------------------------------------------------------------
1153 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1159 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1160 paintType = obj1.getInt();
1163 error(-1, "Invalid or missing PaintType in pattern");
1166 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1167 tilingType = obj1.getInt();
1170 error(-1, "Invalid or missing TilingType in pattern");
1173 bbox[0] = bbox[1] = 0;
1174 bbox[2] = bbox[3] = 1;
1175 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1176 obj1.arrayGetLength() == 4) {
1177 for (i = 0; i < 4; ++i) {
1178 if (obj1.arrayGet(i, &obj2)->isNum()) {
1179 bbox[i] = obj2.getNum();
1184 error(-1, "Invalid or missing BBox in pattern");
1187 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1188 xStep = obj1.getNum();
1191 error(-1, "Invalid or missing XStep in pattern");
1194 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1195 yStep = obj1.getNum();
1198 error(-1, "Invalid or missing YStep in pattern");
1201 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1204 error(-1, "Invalid or missing Resources in pattern");
1206 matrix[0] = 1; matrix[1] = 0;
1207 matrix[2] = 0; matrix[3] = 1;
1208 matrix[4] = 0; matrix[5] = 0;
1209 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1210 obj1.arrayGetLength() == 6) {
1211 for (i = 0; i < 6; ++i) {
1212 if (obj1.arrayGet(i, &obj2)->isNum()) {
1213 matrix[i] = obj2.getNum();
1219 stream->copy(&contentStream);
1222 GfxTilingPattern::~GfxTilingPattern() {
1224 contentStream.free();
1227 GfxPattern *GfxTilingPattern::copy() {
1228 return new GfxTilingPattern(this);
1231 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1234 memcpy(this, pat, sizeof(GfxTilingPattern));
1235 pat->resDict.copy(&resDict);
1236 pat->contentStream.copy(&contentStream);
1239 //------------------------------------------------------------------------
1241 //------------------------------------------------------------------------
1243 Function::Function() {
1246 Function::~Function() {
1249 Function *Function::parse(Object *funcObj) {
1255 if (funcObj->isStream()) {
1256 dict = funcObj->streamGetDict();
1257 } else if (funcObj->isDict()) {
1258 dict = funcObj->getDict();
1260 error(-1, "Expected function dictionary or stream");
1264 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
1265 error(-1, "Function type is missing or wrong type");
1269 funcType = obj1.getInt();
1272 if (funcType == 0) {
1273 func = new SampledFunction(funcObj, dict);
1274 } else if (funcType == 2) {
1275 func = new ExponentialFunction(funcObj, dict);
1277 error(-1, "Unimplemented function type");
1280 if (!func->isOk()) {
1288 GBool Function::init(Dict *dict) {
1293 if (!dict->lookup("Domain", &obj1)->isArray()) {
1294 error(-1, "Function is missing domain");
1297 m = obj1.arrayGetLength() / 2;
1298 if (m > funcMaxInputs) {
1299 error(-1, "Functions with more than %d inputs are unsupported",
1303 for (i = 0; i < m; ++i) {
1304 obj1.arrayGet(2*i, &obj2);
1305 if (!obj2.isNum()) {
1306 error(-1, "Illegal value in function domain array");
1309 domain[i][0] = obj2.getNum();
1311 obj1.arrayGet(2*i+1, &obj2);
1312 if (!obj2.isNum()) {
1313 error(-1, "Illegal value in function domain array");
1316 domain[i][1] = obj2.getNum();
1324 if (dict->lookup("Range", &obj1)->isArray()) {
1326 n = obj1.arrayGetLength() / 2;
1327 if (n > funcMaxOutputs) {
1328 error(-1, "Functions with more than %d outputs are unsupported",
1332 for (i = 0; i < n; ++i) {
1333 obj1.arrayGet(2*i, &obj2);
1334 if (!obj2.isNum()) {
1335 error(-1, "Illegal value in function range array");
1338 range[i][0] = obj2.getNum();
1340 obj1.arrayGet(2*i+1, &obj2);
1341 if (!obj2.isNum()) {
1342 error(-1, "Illegal value in function range array");
1345 range[i][1] = obj2.getNum();
1360 //------------------------------------------------------------------------
1362 //------------------------------------------------------------------------
1364 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
1366 int nSamples, sampleBits;
1377 //----- initialize the generic stuff
1382 error(-1, "Type 0 function is missing range");
1386 //----- get the stream
1387 if (!funcObj->isStream()) {
1388 error(-1, "Type 0 function isn't a stream");
1391 str = funcObj->getStream();
1394 if (!dict->lookup("Size", &obj1)->isArray() ||
1395 obj1.arrayGetLength() != m) {
1396 error(-1, "Function has missing or invalid size array");
1399 for (i = 0; i < m; ++i) {
1400 obj1.arrayGet(i, &obj2);
1401 if (!obj2.isInt()) {
1402 error(-1, "Illegal value in function size array");
1405 sampleSize[i] = obj2.getInt();
1410 //----- BitsPerSample
1411 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
1412 error(-1, "Function has missing or invalid BitsPerSample");
1415 sampleBits = obj1.getInt();
1416 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
1420 if (dict->lookup("Encode", &obj1)->isArray() &&
1421 obj1.arrayGetLength() == 2*m) {
1422 for (i = 0; i < m; ++i) {
1423 obj1.arrayGet(2*i, &obj2);
1424 if (!obj2.isNum()) {
1425 error(-1, "Illegal value in function encode array");
1428 encode[i][0] = obj2.getNum();
1430 obj1.arrayGet(2*i+1, &obj2);
1431 if (!obj2.isNum()) {
1432 error(-1, "Illegal value in function encode array");
1435 encode[i][1] = obj2.getNum();
1439 for (i = 0; i < m; ++i) {
1441 encode[i][1] = sampleSize[i] - 1;
1447 if (dict->lookup("Decode", &obj1)->isArray() &&
1448 obj1.arrayGetLength() == 2*n) {
1449 for (i = 0; i < n; ++i) {
1450 obj1.arrayGet(2*i, &obj2);
1451 if (!obj2.isNum()) {
1452 error(-1, "Illegal value in function decode array");
1455 decode[i][0] = obj2.getNum();
1457 obj1.arrayGet(2*i+1, &obj2);
1458 if (!obj2.isNum()) {
1459 error(-1, "Illegal value in function decode array");
1462 decode[i][1] = obj2.getNum();
1466 for (i = 0; i < n; ++i) {
1467 decode[i][0] = range[i][0];
1468 decode[i][1] = range[i][1];
1475 for (i = 0; i < m; ++i)
1476 nSamples *= sampleSize[i];
1477 samples = (double *)gmalloc(nSamples * sizeof(double));
1480 bitMask = (1 << sampleBits) - 1;
1482 for (i = 0; i < nSamples; ++i) {
1483 if (sampleBits == 8) {
1485 } else if (sampleBits == 16) {
1487 s = (s << 8) + str->getChar();
1488 } else if (sampleBits == 32) {
1490 s = (s << 8) + str->getChar();
1491 s = (s << 8) + str->getChar();
1492 s = (s << 8) + str->getChar();
1494 while (bits < sampleBits) {
1495 buf = (buf << 8) | (str->getChar() & 0xff);
1498 s = (buf >> (bits - sampleBits)) & bitMask;
1501 samples[i] = (double)s * sampleMul;
1516 SampledFunction::~SampledFunction() {
1522 SampledFunction::SampledFunction(SampledFunction *func) {
1525 memcpy(this, func, sizeof(SampledFunction));
1528 for (i = 0; i < m; ++i) {
1529 nSamples *= sampleSize[i];
1531 samples = (double *)gmalloc(nSamples * sizeof(double));
1532 memcpy(samples, func->samples, nSamples * sizeof(double));
1535 void SampledFunction::transform(double *in, double *out) {
1543 // map input values into sample array
1544 for (i = 0; i < m; ++i) {
1545 e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
1546 (encode[i][1] - encode[i][0]) + encode[i][0];
1549 } else if (e[i] > sampleSize[i] - 1) {
1550 e[i] = sampleSize[i] - 1;
1554 for (i = 0; i < n; ++i) {
1556 // m-linear interpolation
1557 // (only m=1 is currently supported)
1558 e0 = (int)floor(e[0]);
1559 e1 = (int)ceil(e[0]);
1561 x0 = samples[e0 * n + i];
1562 x1 = samples[e1 * n + i];
1563 s = (1 - efrac) * x0 + efrac * x1;
1565 // map output values to range
1566 out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
1567 if (out[i] < range[i][0]) {
1568 out[i] = range[i][0];
1569 } else if (out[i] > range[i][1]) {
1570 out[i] = range[i][1];
1575 //------------------------------------------------------------------------
1576 // ExponentialFunction
1577 //------------------------------------------------------------------------
1579 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
1587 //----- initialize the generic stuff
1592 error(-1, "Exponential function with more than one input");
1596 //----- default values
1597 for (i = 0; i < funcMaxOutputs; ++i) {
1603 if (dict->lookup("C0", &obj1)->isArray()) {
1605 n = obj1.arrayGetLength();
1606 } else if (obj1.arrayGetLength() != n) {
1607 error(-1, "Function's C0 array is wrong length");
1610 for (i = 0; i < n; ++i) {
1611 obj1.arrayGet(i, &obj2);
1612 if (!obj2.isNum()) {
1613 error(-1, "Illegal value in function C0 array");
1616 c0[i] = obj2.getNum();
1623 if (dict->lookup("C1", &obj1)->isArray()) {
1625 n = obj1.arrayGetLength();
1626 } else if (obj1.arrayGetLength() != n) {
1627 error(-1, "Function's C1 array is wrong length");
1630 for (i = 0; i < n; ++i) {
1631 obj1.arrayGet(i, &obj2);
1632 if (!obj2.isNum()) {
1633 error(-1, "Illegal value in function C1 array");
1636 c1[i] = obj2.getNum();
1642 //----- N (exponent)
1643 if (!dict->lookup("N", &obj1)->isNum()) {
1644 error(-1, "Function has missing or invalid N");
1661 ExponentialFunction::~ExponentialFunction() {
1664 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
1665 memcpy(this, func, sizeof(ExponentialFunction));
1668 void ExponentialFunction::transform(double *in, double *out) {
1672 if (in[0] < domain[0][0]) {
1674 } else if (in[0] > domain[0][1]) {
1679 for (i = 0; i < n; ++i) {
1680 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
1682 if (out[i] < range[i][0]) {
1683 out[i] = range[i][0];
1684 } else if (out[i] > range[i][1]) {
1685 out[i] = range[i][1];
1692 //------------------------------------------------------------------------
1694 //------------------------------------------------------------------------
1696 GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
1697 GfxColorSpace *colorSpace) {
1698 GfxIndexedColorSpace *indexedCS;
1699 GfxSeparationColorSpace *sepCS;
1700 int maxPixel, indexHigh;
1705 double y[gfxColorMaxComps];
1710 // bits per component and color space
1712 maxPixel = (1 << bits) - 1;
1713 this->colorSpace = colorSpace;
1716 if (decode->isNull()) {
1717 nComps = colorSpace->getNComps();
1718 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1719 } else if (decode->isArray()) {
1720 nComps = decode->arrayGetLength() / 2;
1721 if (nComps != colorSpace->getNComps()) {
1724 for (i = 0; i < nComps; ++i) {
1725 decode->arrayGet(2*i, &obj);
1729 decodeLow[i] = obj.getNum();
1731 decode->arrayGet(2*i+1, &obj);
1735 decodeRange[i] = obj.getNum() - decodeLow[i];
1743 // handle the case where fewer than 2^n palette entries of an n-bit
1744 // indexed color space are populated (this happens, e.g., in files
1745 // optimized by Distiller)
1746 if (colorSpace->getMode() == csIndexed) {
1747 i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
1754 // Construct a lookup table -- this stores pre-computed decoded
1755 // values for each component, i.e., the result of applying the
1756 // decode mapping to each possible image pixel component value.
1758 // Optimization: for Indexed and Separation color spaces (which have
1759 // only one component), we store color values in the lookup table
1760 // rather than component values.
1763 if (colorSpace->getMode() == csIndexed) {
1764 // Note that indexHigh may not be the same as maxPixel --
1765 // Distiller will remove unused palette entries, resulting in
1766 // indexHigh < maxPixel.
1767 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1768 colorSpace2 = indexedCS->getBase();
1769 indexHigh = indexedCS->getIndexHigh();
1770 nComps2 = colorSpace2->getNComps();
1771 lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1772 lookup2 = indexedCS->getLookup();
1773 for (i = 0; i <= indexHigh; ++i) {
1774 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1775 for (k = 0; k < nComps2; ++k) {
1776 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1779 } else if (colorSpace->getMode() == csSeparation) {
1780 sepCS = (GfxSeparationColorSpace *)colorSpace;
1781 colorSpace2 = sepCS->getAlt();
1782 nComps2 = colorSpace2->getNComps();
1783 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1784 sepFunc = sepCS->getFunc();
1785 for (i = 0; i <= maxPixel; ++i) {
1786 x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1787 sepFunc->transform(&x, y);
1788 for (k = 0; k < nComps2; ++k) {
1789 lookup[i*nComps2 + k] = y[k];
1793 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1794 for (i = 0; i <= maxPixel; ++i) {
1795 for (k = 0; k < nComps; ++k) {
1796 lookup[i*nComps + k] = decodeLow[k] +
1797 (i * decodeRange[k]) / maxPixel;
1810 GfxImageColorMap::~GfxImageColorMap() {
1815 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1821 p = &lookup[x[0] * nComps2];
1822 for (i = 0; i < nComps2; ++i) {
1825 colorSpace2->getGray(&color, gray);
1827 for (i = 0; i < nComps; ++i) {
1828 color.c[i] = lookup[x[i] * nComps + i];
1830 colorSpace->getGray(&color, gray);
1834 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1840 p = &lookup[x[0] * nComps2];
1841 for (i = 0; i < nComps2; ++i) {
1844 colorSpace2->getRGB(&color, rgb);
1846 for (i = 0; i < nComps; ++i) {
1847 color.c[i] = lookup[x[i] * nComps + i];
1849 colorSpace->getRGB(&color, rgb);
1853 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1859 p = &lookup[x[0] * nComps2];
1860 for (i = 0; i < nComps2; ++i) {
1863 colorSpace2->getCMYK(&color, cmyk);
1865 for (i = 0; i < nComps; ++i) {
1866 color.c[i] = lookup[x[i] * nComps + i];
1868 colorSpace->getCMYK(&color, cmyk);
1872 //------------------------------------------------------------------------
1873 // GfxSubpath and GfxPath
1874 //------------------------------------------------------------------------
1876 GfxSubpath::GfxSubpath(double x1, double y1) {
1878 x = (double *)gmalloc(size * sizeof(double));
1879 y = (double *)gmalloc(size * sizeof(double));
1880 curve = (GBool *)gmalloc(size * sizeof(GBool));
1888 GfxSubpath::~GfxSubpath() {
1895 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1896 size = subpath->size;
1898 x = (double *)gmalloc(size * sizeof(double));
1899 y = (double *)gmalloc(size * sizeof(double));
1900 curve = (GBool *)gmalloc(size * sizeof(GBool));
1901 memcpy(x, subpath->x, n * sizeof(double));
1902 memcpy(y, subpath->y, n * sizeof(double));
1903 memcpy(curve, subpath->curve, n * sizeof(GBool));
1904 closed = subpath->closed;
1907 void GfxSubpath::lineTo(double x1, double y1) {
1910 x = (double *)grealloc(x, size * sizeof(double));
1911 y = (double *)grealloc(y, size * sizeof(double));
1912 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1920 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1921 double x3, double y3) {
1924 x = (double *)grealloc(x, size * sizeof(double));
1925 y = (double *)grealloc(y, size * sizeof(double));
1926 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1934 curve[n] = curve[n+1] = gTrue;
1935 curve[n+2] = gFalse;
1939 void GfxSubpath::close() {
1940 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1946 GfxPath::GfxPath() {
1950 firstX = firstY = 0;
1951 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1954 GfxPath::~GfxPath() {
1957 for (i = 0; i < n; ++i)
1963 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1964 GfxSubpath **subpaths1, int n1, int size1) {
1967 justMoved = justMoved1;
1972 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1973 for (i = 0; i < n; ++i)
1974 subpaths[i] = subpaths1[i]->copy();
1977 void GfxPath::moveTo(double x, double y) {
1983 void GfxPath::lineTo(double x, double y) {
1987 subpaths = (GfxSubpath **)
1988 grealloc(subpaths, size * sizeof(GfxSubpath *));
1990 subpaths[n] = new GfxSubpath(firstX, firstY);
1994 subpaths[n-1]->lineTo(x, y);
1997 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1998 double x3, double y3) {
2002 subpaths = (GfxSubpath **)
2003 grealloc(subpaths, size * sizeof(GfxSubpath *));
2005 subpaths[n] = new GfxSubpath(firstX, firstY);
2009 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2013 //------------------------------------------------------------------------
2015 //------------------------------------------------------------------------
2017 GfxState::GfxState(double dpi, double px1a, double py1a,
2018 double px2a, double py2a, int rotate, GBool upsideDown) {
2028 ctm[1] = upsideDown ? k : -k;
2032 ctm[5] = k * (upsideDown ? -px1 : px2);
2033 pageWidth = k * (py2 - py1);
2034 pageHeight = k * (px2 - px1);
2035 } else if (rotate == 180) {
2039 ctm[3] = upsideDown ? k : -k;
2041 ctm[5] = k * (upsideDown ? -py1 : py2);
2042 pageWidth = k * (px2 - px1);
2043 pageHeight = k * (py2 - py1);
2044 } else if (rotate == 270) {
2046 ctm[1] = upsideDown ? -k : k;
2050 ctm[5] = k * (upsideDown ? px2 : -px1);
2051 pageWidth = k * (py2 - py1);
2052 pageHeight = k * (px2 - px1);
2057 ctm[3] = upsideDown ? -k : k;
2059 ctm[5] = k * (upsideDown ? py2 : -py1);
2060 pageWidth = k * (px2 - px1);
2061 pageHeight = k * (py2 - py1);
2064 fillColorSpace = new GfxDeviceGrayColorSpace();
2065 strokeColorSpace = new GfxDeviceGrayColorSpace();
2067 strokeColor.c[0] = 0;
2069 strokePattern = NULL;
2084 textMat[0] = 1; textMat[1] = 0;
2085 textMat[2] = 0; textMat[3] = 1;
2086 textMat[4] = 0; textMat[5] = 0;
2094 path = new GfxPath();
2101 GfxState::~GfxState() {
2102 if (fillColorSpace) {
2103 delete fillColorSpace;
2105 if (strokeColorSpace) {
2106 delete strokeColorSpace;
2111 if (strokePattern) {
2112 delete strokePattern;
2122 GfxState::GfxState(GfxState *state) {
2123 memcpy(this, state, sizeof(GfxState));
2124 if (fillColorSpace) {
2125 fillColorSpace = state->fillColorSpace->copy();
2127 if (strokeColorSpace) {
2128 strokeColorSpace = state->strokeColorSpace->copy();
2131 fillPattern = state->fillPattern->copy();
2133 if (strokePattern) {
2134 strokePattern = state->strokePattern->copy();
2136 if (lineDashLength > 0) {
2137 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2138 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2140 path = state->path->copy();
2144 double GfxState::transformWidth(double w) {
2147 x = ctm[0] + ctm[2];
2148 y = ctm[1] + ctm[3];
2149 return w * sqrt(0.5 * (x * x + y * y));
2152 double GfxState::getTransformedFontSize() {
2153 double x1, y1, x2, y2;
2155 x1 = textMat[2] * fontSize;
2156 y1 = textMat[3] * fontSize;
2157 x2 = ctm[0] * x1 + ctm[2] * y1;
2158 y2 = ctm[1] * x1 + ctm[3] * y1;
2159 return sqrt(x2 * x2 + y2 * y2);
2162 void GfxState::getFontTransMat(double *m11, double *m12,
2163 double *m21, double *m22) {
2164 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2165 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2166 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2167 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2170 void GfxState::setCTM(double a, double b, double c,
2171 double d, double e, double f) {
2180 void GfxState::concatCTM(double a, double b, double c,
2181 double d, double e, double f) {
2187 ctm[0] = a * a1 + b * c1;
2188 ctm[1] = a * b1 + b * d1;
2189 ctm[2] = c * a1 + d * c1;
2190 ctm[3] = c * b1 + d * d1;
2191 ctm[4] = e * a1 + f * c1 + ctm[4];
2192 ctm[5] = e * b1 + f * d1 + ctm[5];
2195 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2196 if (fillColorSpace) {
2197 delete fillColorSpace;
2199 fillColorSpace = colorSpace;
2202 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2203 if (strokeColorSpace) {
2204 delete strokeColorSpace;
2206 strokeColorSpace = colorSpace;
2209 void GfxState::setFillPattern(GfxPattern *pattern) {
2213 fillPattern = pattern;
2216 void GfxState::setStrokePattern(GfxPattern *pattern) {
2217 if (strokePattern) {
2218 delete strokePattern;
2220 strokePattern = pattern;
2223 void GfxState::setLineDash(double *dash, int length, double start) {
2227 lineDashLength = length;
2228 lineDashStart = start;
2231 void GfxState::clearPath() {
2233 path = new GfxPath();
2236 void GfxState::textShift(double tx) {
2239 textTransformDelta(tx, 0, &dx, &dy);
2244 void GfxState::textShift(double tx, double ty) {
2247 textTransformDelta(tx, ty, &dx, &dy);
2252 GfxState *GfxState::save() {
2256 newState->saved = this;
2260 GfxState *GfxState::restore() {