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));
915 if (!func || !func->isOk()) {
918 cs = new GfxSeparationColorSpace(name, alt, func);
933 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
936 func->transform(color->c, color2.c);
937 alt->getGray(&color2, gray);
940 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
943 func->transform(color->c, color2.c);
944 alt->getRGB(&color2, rgb);
947 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
950 func->transform(color->c, color2.c);
951 alt->getCMYK(&color2, cmyk);
954 //------------------------------------------------------------------------
955 // GfxDeviceNColorSpace
956 //------------------------------------------------------------------------
958 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
961 this->nComps = nComps;
966 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
969 for (i = 0; i < nComps; ++i) {
976 GfxColorSpace *GfxDeviceNColorSpace::copy() {
977 GfxDeviceNColorSpace *cs;
980 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
981 for (i = 0; i < nComps; ++i) {
982 cs->names[i] = names[i]->copy();
987 //~ handle the 'None' colorant
988 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
989 GfxDeviceNColorSpace *cs;
991 GString *names[gfxColorMaxComps];
997 if (arr->getLength() != 4 && arr->getLength() != 5) {
998 error(-1, "Bad DeviceN color space");
1001 if (!arr->get(1, &obj1)->isArray()) {
1002 error(-1, "Bad DeviceN color space (names)");
1005 nComps = obj1.arrayGetLength();
1006 for (i = 0; i < nComps; ++i) {
1007 if (!obj1.arrayGet(i, &obj2)->isName()) {
1008 error(-1, "Bad DeviceN color space (names)");
1012 names[i] = new GString(obj2.getName());
1017 if (!(alt = GfxColorSpace::parse(&obj1))) {
1018 error(-1, "Bad DeviceN color space (alternate color space)");
1022 func = Function::parse(arr->get(3, &obj1));
1024 if (!func->isOk()) {
1027 cs = new GfxDeviceNColorSpace(nComps, alt, func);
1028 for (i = 0; i < nComps; ++i) {
1029 cs->names[i] = names[i];
1037 for (i = 0; i < nComps; ++i) {
1046 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1049 func->transform(color->c, color2.c);
1050 alt->getGray(&color2, gray);
1053 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1056 func->transform(color->c, color2.c);
1057 alt->getRGB(&color2, rgb);
1060 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1063 func->transform(color->c, color2.c);
1064 alt->getCMYK(&color2, cmyk);
1067 //------------------------------------------------------------------------
1068 // GfxPatternColorSpace
1069 //------------------------------------------------------------------------
1071 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
1072 this->under = under;
1075 GfxPatternColorSpace::~GfxPatternColorSpace() {
1081 GfxColorSpace *GfxPatternColorSpace::copy() {
1082 return new GfxPatternColorSpace(under ? under->copy() :
1083 (GfxColorSpace *)NULL);
1086 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1087 GfxPatternColorSpace *cs;
1088 GfxColorSpace *under;
1091 if (arr->getLength() != 1 && arr->getLength() != 2) {
1092 error(-1, "Bad Pattern color space");
1096 if (arr->getLength() == 2) {
1098 if (!(under = GfxColorSpace::parse(&obj1))) {
1099 error(-1, "Bad Pattern color space (underlying color space)");
1105 cs = new GfxPatternColorSpace(under);
1109 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1113 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1114 rgb->r = rgb->g = rgb->b = 0;
1117 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1118 cmyk->c = cmyk->m = cmyk->y = 0;
1122 //------------------------------------------------------------------------
1124 //------------------------------------------------------------------------
1126 GfxPattern::GfxPattern(int type) {
1130 GfxPattern::~GfxPattern() {
1133 GfxPattern *GfxPattern::parse(Object *obj) {
1134 GfxPattern *pattern;
1139 if (obj->isStream()) {
1140 dict = obj->streamGetDict();
1141 dict->lookup("PatternType", &obj1);
1142 if (obj1.isInt() && obj1.getInt() == 1) {
1143 pattern = new GfxTilingPattern(dict, obj);
1150 //------------------------------------------------------------------------
1152 //------------------------------------------------------------------------
1154 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1160 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1161 paintType = obj1.getInt();
1164 error(-1, "Invalid or missing PaintType in pattern");
1167 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1168 tilingType = obj1.getInt();
1171 error(-1, "Invalid or missing TilingType in pattern");
1174 bbox[0] = bbox[1] = 0;
1175 bbox[2] = bbox[3] = 1;
1176 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1177 obj1.arrayGetLength() == 4) {
1178 for (i = 0; i < 4; ++i) {
1179 if (obj1.arrayGet(i, &obj2)->isNum()) {
1180 bbox[i] = obj2.getNum();
1185 error(-1, "Invalid or missing BBox in pattern");
1188 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1189 xStep = obj1.getNum();
1192 error(-1, "Invalid or missing XStep in pattern");
1195 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1196 yStep = obj1.getNum();
1199 error(-1, "Invalid or missing YStep in pattern");
1202 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1205 error(-1, "Invalid or missing Resources in pattern");
1207 matrix[0] = 1; matrix[1] = 0;
1208 matrix[2] = 0; matrix[3] = 1;
1209 matrix[4] = 0; matrix[5] = 0;
1210 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1211 obj1.arrayGetLength() == 6) {
1212 for (i = 0; i < 6; ++i) {
1213 if (obj1.arrayGet(i, &obj2)->isNum()) {
1214 matrix[i] = obj2.getNum();
1220 stream->copy(&contentStream);
1223 GfxTilingPattern::~GfxTilingPattern() {
1225 contentStream.free();
1228 GfxPattern *GfxTilingPattern::copy() {
1229 return new GfxTilingPattern(this);
1232 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1235 memcpy(this, pat, sizeof(GfxTilingPattern));
1236 pat->resDict.copy(&resDict);
1237 pat->contentStream.copy(&contentStream);
1240 //------------------------------------------------------------------------
1242 //------------------------------------------------------------------------
1244 Function::Function() {
1247 Function::~Function() {
1250 Function *Function::parse(Object *funcObj) {
1256 if (funcObj->isStream()) {
1257 dict = funcObj->streamGetDict();
1258 } else if (funcObj->isDict()) {
1259 dict = funcObj->getDict();
1261 error(-1, "Expected function dictionary or stream");
1265 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
1266 error(-1, "Function type is missing or wrong type");
1270 funcType = obj1.getInt();
1273 if (funcType == 0) {
1274 func = new SampledFunction(funcObj, dict);
1275 } else if (funcType == 2) {
1276 func = new ExponentialFunction(funcObj, dict);
1278 error(-1, "Unimplemented function type");
1281 if (!func->isOk()) {
1289 GBool Function::init(Dict *dict) {
1294 if (!dict->lookup("Domain", &obj1)->isArray()) {
1295 error(-1, "Function is missing domain");
1298 m = obj1.arrayGetLength() / 2;
1299 if (m > funcMaxInputs) {
1300 error(-1, "Functions with more than %d inputs are unsupported",
1304 for (i = 0; i < m; ++i) {
1305 obj1.arrayGet(2*i, &obj2);
1306 if (!obj2.isNum()) {
1307 error(-1, "Illegal value in function domain array");
1310 domain[i][0] = obj2.getNum();
1312 obj1.arrayGet(2*i+1, &obj2);
1313 if (!obj2.isNum()) {
1314 error(-1, "Illegal value in function domain array");
1317 domain[i][1] = obj2.getNum();
1325 if (dict->lookup("Range", &obj1)->isArray()) {
1327 n = obj1.arrayGetLength() / 2;
1328 if (n > funcMaxOutputs) {
1329 error(-1, "Functions with more than %d outputs are unsupported",
1333 for (i = 0; i < n; ++i) {
1334 obj1.arrayGet(2*i, &obj2);
1335 if (!obj2.isNum()) {
1336 error(-1, "Illegal value in function range array");
1339 range[i][0] = obj2.getNum();
1341 obj1.arrayGet(2*i+1, &obj2);
1342 if (!obj2.isNum()) {
1343 error(-1, "Illegal value in function range array");
1346 range[i][1] = obj2.getNum();
1361 //------------------------------------------------------------------------
1363 //------------------------------------------------------------------------
1365 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
1367 int nSamples, sampleBits;
1378 //----- initialize the generic stuff
1383 error(-1, "Type 0 function is missing range");
1387 //----- get the stream
1388 if (!funcObj->isStream()) {
1389 error(-1, "Type 0 function isn't a stream");
1392 str = funcObj->getStream();
1395 if (!dict->lookup("Size", &obj1)->isArray() ||
1396 obj1.arrayGetLength() != m) {
1397 error(-1, "Function has missing or invalid size array");
1400 for (i = 0; i < m; ++i) {
1401 obj1.arrayGet(i, &obj2);
1402 if (!obj2.isInt()) {
1403 error(-1, "Illegal value in function size array");
1406 sampleSize[i] = obj2.getInt();
1411 //----- BitsPerSample
1412 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
1413 error(-1, "Function has missing or invalid BitsPerSample");
1416 sampleBits = obj1.getInt();
1417 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
1421 if (dict->lookup("Encode", &obj1)->isArray() &&
1422 obj1.arrayGetLength() == 2*m) {
1423 for (i = 0; i < m; ++i) {
1424 obj1.arrayGet(2*i, &obj2);
1425 if (!obj2.isNum()) {
1426 error(-1, "Illegal value in function encode array");
1429 encode[i][0] = obj2.getNum();
1431 obj1.arrayGet(2*i+1, &obj2);
1432 if (!obj2.isNum()) {
1433 error(-1, "Illegal value in function encode array");
1436 encode[i][1] = obj2.getNum();
1440 for (i = 0; i < m; ++i) {
1442 encode[i][1] = sampleSize[i] - 1;
1448 if (dict->lookup("Decode", &obj1)->isArray() &&
1449 obj1.arrayGetLength() == 2*n) {
1450 for (i = 0; i < n; ++i) {
1451 obj1.arrayGet(2*i, &obj2);
1452 if (!obj2.isNum()) {
1453 error(-1, "Illegal value in function decode array");
1456 decode[i][0] = obj2.getNum();
1458 obj1.arrayGet(2*i+1, &obj2);
1459 if (!obj2.isNum()) {
1460 error(-1, "Illegal value in function decode array");
1463 decode[i][1] = obj2.getNum();
1467 for (i = 0; i < n; ++i) {
1468 decode[i][0] = range[i][0];
1469 decode[i][1] = range[i][1];
1476 for (i = 0; i < m; ++i)
1477 nSamples *= sampleSize[i];
1478 samples = (double *)gmalloc(nSamples * sizeof(double));
1481 bitMask = (1 << sampleBits) - 1;
1483 for (i = 0; i < nSamples; ++i) {
1484 if (sampleBits == 8) {
1486 } else if (sampleBits == 16) {
1488 s = (s << 8) + str->getChar();
1489 } else if (sampleBits == 32) {
1491 s = (s << 8) + str->getChar();
1492 s = (s << 8) + str->getChar();
1493 s = (s << 8) + str->getChar();
1495 while (bits < sampleBits) {
1496 buf = (buf << 8) | (str->getChar() & 0xff);
1499 s = (buf >> (bits - sampleBits)) & bitMask;
1502 samples[i] = (double)s * sampleMul;
1517 SampledFunction::~SampledFunction() {
1523 SampledFunction::SampledFunction(SampledFunction *func) {
1526 memcpy(this, func, sizeof(SampledFunction));
1529 for (i = 0; i < m; ++i) {
1530 nSamples *= sampleSize[i];
1532 samples = (double *)gmalloc(nSamples * sizeof(double));
1533 memcpy(samples, func->samples, nSamples * sizeof(double));
1536 void SampledFunction::transform(double *in, double *out) {
1544 // map input values into sample array
1545 for (i = 0; i < m; ++i) {
1546 e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
1547 (encode[i][1] - encode[i][0]) + encode[i][0];
1550 } else if (e[i] > sampleSize[i] - 1) {
1551 e[i] = sampleSize[i] - 1;
1555 for (i = 0; i < n; ++i) {
1557 // m-linear interpolation
1558 // (only m=1 is currently supported)
1559 e0 = (int)floor(e[0]);
1560 e1 = (int)ceil(e[0]);
1562 x0 = samples[e0 * n + i];
1563 x1 = samples[e1 * n + i];
1564 s = (1 - efrac) * x0 + efrac * x1;
1566 // map output values to range
1567 out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
1568 if (out[i] < range[i][0]) {
1569 out[i] = range[i][0];
1570 } else if (out[i] > range[i][1]) {
1571 out[i] = range[i][1];
1576 //------------------------------------------------------------------------
1577 // ExponentialFunction
1578 //------------------------------------------------------------------------
1580 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
1588 //----- initialize the generic stuff
1593 error(-1, "Exponential function with more than one input");
1597 //----- default values
1598 for (i = 0; i < funcMaxOutputs; ++i) {
1604 if (dict->lookup("C0", &obj1)->isArray()) {
1606 n = obj1.arrayGetLength();
1607 } else if (obj1.arrayGetLength() != n) {
1608 error(-1, "Function's C0 array is wrong length");
1611 for (i = 0; i < n; ++i) {
1612 obj1.arrayGet(i, &obj2);
1613 if (!obj2.isNum()) {
1614 error(-1, "Illegal value in function C0 array");
1617 c0[i] = obj2.getNum();
1624 if (dict->lookup("C1", &obj1)->isArray()) {
1626 n = obj1.arrayGetLength();
1627 } else if (obj1.arrayGetLength() != n) {
1628 error(-1, "Function's C1 array is wrong length");
1631 for (i = 0; i < n; ++i) {
1632 obj1.arrayGet(i, &obj2);
1633 if (!obj2.isNum()) {
1634 error(-1, "Illegal value in function C1 array");
1637 c1[i] = obj2.getNum();
1643 //----- N (exponent)
1644 if (!dict->lookup("N", &obj1)->isNum()) {
1645 error(-1, "Function has missing or invalid N");
1662 ExponentialFunction::~ExponentialFunction() {
1665 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
1666 memcpy(this, func, sizeof(ExponentialFunction));
1669 void ExponentialFunction::transform(double *in, double *out) {
1673 if (in[0] < domain[0][0]) {
1675 } else if (in[0] > domain[0][1]) {
1680 for (i = 0; i < n; ++i) {
1681 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
1683 if (out[i] < range[i][0]) {
1684 out[i] = range[i][0];
1685 } else if (out[i] > range[i][1]) {
1686 out[i] = range[i][1];
1693 //------------------------------------------------------------------------
1695 //------------------------------------------------------------------------
1697 GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
1698 GfxColorSpace *colorSpace) {
1699 GfxIndexedColorSpace *indexedCS;
1700 GfxSeparationColorSpace *sepCS;
1701 int maxPixel, indexHigh;
1706 double y[gfxColorMaxComps];
1711 // bits per component and color space
1713 maxPixel = (1 << bits) - 1;
1714 this->colorSpace = colorSpace;
1717 if (decode->isNull()) {
1718 nComps = colorSpace->getNComps();
1719 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1720 } else if (decode->isArray()) {
1721 nComps = decode->arrayGetLength() / 2;
1722 if (nComps != colorSpace->getNComps()) {
1725 for (i = 0; i < nComps; ++i) {
1726 decode->arrayGet(2*i, &obj);
1730 decodeLow[i] = obj.getNum();
1732 decode->arrayGet(2*i+1, &obj);
1736 decodeRange[i] = obj.getNum() - decodeLow[i];
1744 // handle the case where fewer than 2^n palette entries of an n-bit
1745 // indexed color space are populated (this happens, e.g., in files
1746 // optimized by Distiller)
1747 if (colorSpace->getMode() == csIndexed) {
1748 i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
1755 // Construct a lookup table -- this stores pre-computed decoded
1756 // values for each component, i.e., the result of applying the
1757 // decode mapping to each possible image pixel component value.
1759 // Optimization: for Indexed and Separation color spaces (which have
1760 // only one component), we store color values in the lookup table
1761 // rather than component values.
1764 if (colorSpace->getMode() == csIndexed) {
1765 // Note that indexHigh may not be the same as maxPixel --
1766 // Distiller will remove unused palette entries, resulting in
1767 // indexHigh < maxPixel.
1768 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1769 colorSpace2 = indexedCS->getBase();
1770 indexHigh = indexedCS->getIndexHigh();
1771 nComps2 = colorSpace2->getNComps();
1772 lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
1773 lookup2 = indexedCS->getLookup();
1774 for (i = 0; i <= indexHigh; ++i) {
1775 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1776 for (k = 0; k < nComps2; ++k) {
1777 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1780 } else if (colorSpace->getMode() == csSeparation) {
1781 sepCS = (GfxSeparationColorSpace *)colorSpace;
1782 colorSpace2 = sepCS->getAlt();
1783 nComps2 = colorSpace2->getNComps();
1784 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
1785 sepFunc = sepCS->getFunc();
1786 for (i = 0; i <= maxPixel; ++i) {
1787 x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1788 sepFunc->transform(&x, y);
1789 for (k = 0; k < nComps2; ++k) {
1790 lookup[i*nComps2 + k] = y[k];
1794 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
1795 for (i = 0; i <= maxPixel; ++i) {
1796 for (k = 0; k < nComps; ++k) {
1797 lookup[i*nComps + k] = decodeLow[k] +
1798 (i * decodeRange[k]) / maxPixel;
1811 GfxImageColorMap::~GfxImageColorMap() {
1816 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1822 p = &lookup[x[0] * nComps2];
1823 for (i = 0; i < nComps2; ++i) {
1826 colorSpace2->getGray(&color, gray);
1828 for (i = 0; i < nComps; ++i) {
1829 color.c[i] = lookup[x[i] * nComps + i];
1831 colorSpace->getGray(&color, gray);
1835 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1841 p = &lookup[x[0] * nComps2];
1842 for (i = 0; i < nComps2; ++i) {
1845 colorSpace2->getRGB(&color, rgb);
1847 for (i = 0; i < nComps; ++i) {
1848 color.c[i] = lookup[x[i] * nComps + i];
1850 colorSpace->getRGB(&color, rgb);
1854 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1860 p = &lookup[x[0] * nComps2];
1861 for (i = 0; i < nComps2; ++i) {
1864 colorSpace2->getCMYK(&color, cmyk);
1866 for (i = 0; i < nComps; ++i) {
1867 color.c[i] = lookup[x[i] * nComps + i];
1869 colorSpace->getCMYK(&color, cmyk);
1873 //------------------------------------------------------------------------
1874 // GfxSubpath and GfxPath
1875 //------------------------------------------------------------------------
1877 GfxSubpath::GfxSubpath(double x1, double y1) {
1879 x = (double *)gmalloc(size * sizeof(double));
1880 y = (double *)gmalloc(size * sizeof(double));
1881 curve = (GBool *)gmalloc(size * sizeof(GBool));
1889 GfxSubpath::~GfxSubpath() {
1896 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1897 size = subpath->size;
1899 x = (double *)gmalloc(size * sizeof(double));
1900 y = (double *)gmalloc(size * sizeof(double));
1901 curve = (GBool *)gmalloc(size * sizeof(GBool));
1902 memcpy(x, subpath->x, n * sizeof(double));
1903 memcpy(y, subpath->y, n * sizeof(double));
1904 memcpy(curve, subpath->curve, n * sizeof(GBool));
1905 closed = subpath->closed;
1908 void GfxSubpath::lineTo(double x1, double y1) {
1911 x = (double *)grealloc(x, size * sizeof(double));
1912 y = (double *)grealloc(y, size * sizeof(double));
1913 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1921 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1922 double x3, double y3) {
1925 x = (double *)grealloc(x, size * sizeof(double));
1926 y = (double *)grealloc(y, size * sizeof(double));
1927 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1935 curve[n] = curve[n+1] = gTrue;
1936 curve[n+2] = gFalse;
1940 void GfxSubpath::close() {
1941 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1947 GfxPath::GfxPath() {
1951 firstX = firstY = 0;
1952 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1955 GfxPath::~GfxPath() {
1958 for (i = 0; i < n; ++i)
1964 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1965 GfxSubpath **subpaths1, int n1, int size1) {
1968 justMoved = justMoved1;
1973 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1974 for (i = 0; i < n; ++i)
1975 subpaths[i] = subpaths1[i]->copy();
1978 void GfxPath::moveTo(double x, double y) {
1984 void GfxPath::lineTo(double x, double y) {
1988 subpaths = (GfxSubpath **)
1989 grealloc(subpaths, size * sizeof(GfxSubpath *));
1991 subpaths[n] = new GfxSubpath(firstX, firstY);
1995 subpaths[n-1]->lineTo(x, y);
1998 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1999 double x3, double y3) {
2003 subpaths = (GfxSubpath **)
2004 grealloc(subpaths, size * sizeof(GfxSubpath *));
2006 subpaths[n] = new GfxSubpath(firstX, firstY);
2010 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2014 //------------------------------------------------------------------------
2016 //------------------------------------------------------------------------
2018 GfxState::GfxState(double dpi, double px1a, double py1a,
2019 double px2a, double py2a, int rotate, GBool upsideDown) {
2029 ctm[1] = upsideDown ? k : -k;
2033 ctm[5] = k * (upsideDown ? -px1 : px2);
2034 pageWidth = k * (py2 - py1);
2035 pageHeight = k * (px2 - px1);
2036 } else if (rotate == 180) {
2040 ctm[3] = upsideDown ? k : -k;
2042 ctm[5] = k * (upsideDown ? -py1 : py2);
2043 pageWidth = k * (px2 - px1);
2044 pageHeight = k * (py2 - py1);
2045 } else if (rotate == 270) {
2047 ctm[1] = upsideDown ? -k : k;
2051 ctm[5] = k * (upsideDown ? px2 : -px1);
2052 pageWidth = k * (py2 - py1);
2053 pageHeight = k * (px2 - px1);
2058 ctm[3] = upsideDown ? -k : k;
2060 ctm[5] = k * (upsideDown ? py2 : -py1);
2061 pageWidth = k * (px2 - px1);
2062 pageHeight = k * (py2 - py1);
2065 fillColorSpace = new GfxDeviceGrayColorSpace();
2066 strokeColorSpace = new GfxDeviceGrayColorSpace();
2068 strokeColor.c[0] = 0;
2070 strokePattern = NULL;
2085 textMat[0] = 1; textMat[1] = 0;
2086 textMat[2] = 0; textMat[3] = 1;
2087 textMat[4] = 0; textMat[5] = 0;
2095 path = new GfxPath();
2102 GfxState::~GfxState() {
2103 if (fillColorSpace) {
2104 delete fillColorSpace;
2106 if (strokeColorSpace) {
2107 delete strokeColorSpace;
2112 if (strokePattern) {
2113 delete strokePattern;
2123 GfxState::GfxState(GfxState *state) {
2124 memcpy(this, state, sizeof(GfxState));
2125 if (fillColorSpace) {
2126 fillColorSpace = state->fillColorSpace->copy();
2128 if (strokeColorSpace) {
2129 strokeColorSpace = state->strokeColorSpace->copy();
2132 fillPattern = state->fillPattern->copy();
2134 if (strokePattern) {
2135 strokePattern = state->strokePattern->copy();
2137 if (lineDashLength > 0) {
2138 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2139 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2141 path = state->path->copy();
2145 double GfxState::transformWidth(double w) {
2148 x = ctm[0] + ctm[2];
2149 y = ctm[1] + ctm[3];
2150 return w * sqrt(0.5 * (x * x + y * y));
2153 double GfxState::getTransformedFontSize() {
2154 double x1, y1, x2, y2;
2156 x1 = textMat[2] * fontSize;
2157 y1 = textMat[3] * fontSize;
2158 x2 = ctm[0] * x1 + ctm[2] * y1;
2159 y2 = ctm[1] * x1 + ctm[3] * y1;
2160 return sqrt(x2 * x2 + y2 * y2);
2163 void GfxState::getFontTransMat(double *m11, double *m12,
2164 double *m21, double *m22) {
2165 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2166 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2167 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2168 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2171 void GfxState::setCTM(double a, double b, double c,
2172 double d, double e, double f) {
2181 void GfxState::concatCTM(double a, double b, double c,
2182 double d, double e, double f) {
2188 ctm[0] = a * a1 + b * c1;
2189 ctm[1] = a * b1 + b * d1;
2190 ctm[2] = c * a1 + d * c1;
2191 ctm[3] = c * b1 + d * d1;
2192 ctm[4] = e * a1 + f * c1 + ctm[4];
2193 ctm[5] = e * b1 + f * d1 + ctm[5];
2196 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2197 if (fillColorSpace) {
2198 delete fillColorSpace;
2200 fillColorSpace = colorSpace;
2203 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2204 if (strokeColorSpace) {
2205 delete strokeColorSpace;
2207 strokeColorSpace = colorSpace;
2210 void GfxState::setFillPattern(GfxPattern *pattern) {
2214 fillPattern = pattern;
2217 void GfxState::setStrokePattern(GfxPattern *pattern) {
2218 if (strokePattern) {
2219 delete strokePattern;
2221 strokePattern = pattern;
2224 void GfxState::setLineDash(double *dash, int length, double start) {
2228 lineDashLength = length;
2229 lineDashStart = start;
2232 void GfxState::clearPath() {
2234 path = new GfxPath();
2237 void GfxState::textShift(double tx) {
2240 textTransformDelta(tx, 0, &dx, &dy);
2245 void GfxState::textShift(double tx, double ty) {
2248 textTransformDelta(tx, ty, &dx, &dy);
2253 GfxState *GfxState::save() {
2257 newState->saved = this;
2261 GfxState *GfxState::restore() {