upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / GfxState.cc
blob65a1da8e411b7e8c5bfdf7b73db3bfa2391f985c
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <stddef.h>
16 #include <math.h>
17 #include <string.h> // for memcpy()
18 #include "gmem.h"
19 #include "Error.h"
20 #include "Object.h"
21 #include "Array.h"
22 #include "Page.h"
23 #include "GfxState.h"
25 //------------------------------------------------------------------------
27 static inline double clip01(double x) {
28 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
31 //------------------------------------------------------------------------
33 static char *gfxColorSpaceModeNames[] = {
34 "DeviceGray",
35 "CalGray",
36 "DeviceRGB",
37 "CalRGB",
38 "DeviceCMYK",
39 "Lab",
40 "ICCBased",
41 "Indexed",
42 "Separation",
43 "DeviceN",
44 "Pattern"
47 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
49 //------------------------------------------------------------------------
50 // GfxColorSpace
51 //------------------------------------------------------------------------
53 GfxColorSpace::GfxColorSpace() {
56 GfxColorSpace::~GfxColorSpace() {
59 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
60 GfxColorSpace *cs;
61 Object obj1;
63 cs = NULL;
64 if (csObj->isName()) {
65 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
66 cs = new GfxDeviceGrayColorSpace();
67 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
68 cs = new GfxDeviceRGBColorSpace();
69 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
70 cs = new GfxDeviceCMYKColorSpace();
71 } else if (csObj->isName("Pattern")) {
72 cs = new GfxPatternColorSpace(NULL);
73 } else {
74 error(-1, "Bad color space '%s'", csObj->getName());
76 } else if (csObj->isArray()) {
77 csObj->arrayGet(0, &obj1);
78 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
79 cs = new GfxDeviceGrayColorSpace();
80 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
81 cs = new GfxDeviceRGBColorSpace();
82 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
83 cs = new GfxDeviceCMYKColorSpace();
84 } else if (obj1.isName("CalGray")) {
85 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
86 } else if (obj1.isName("CalRGB")) {
87 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
88 } else if (obj1.isName("Lab")) {
89 cs = GfxLabColorSpace::parse(csObj->getArray());
90 } else if (obj1.isName("ICCBased")) {
91 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
92 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
93 cs = GfxIndexedColorSpace::parse(csObj->getArray());
94 } else if (obj1.isName("Separation")) {
95 cs = GfxSeparationColorSpace::parse(csObj->getArray());
96 } else if (obj1.isName("DeviceN")) {
97 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
98 } else if (obj1.isName("Pattern")) {
99 cs = GfxPatternColorSpace::parse(csObj->getArray());
100 } else {
101 error(-1, "Bad color space");
103 obj1.free();
104 } else {
105 error(-1, "Bad color space - expected name or array");
107 return cs;
110 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
111 int maxImgPixel) {
112 int i;
114 for (i = 0; i < getNComps(); ++i) {
115 decodeLow[i] = 0;
116 decodeRange[i] = 1;
120 int GfxColorSpace::getNumColorSpaceModes() {
121 return nGfxColorSpaceModes;
124 char *GfxColorSpace::getColorSpaceModeName(int idx) {
125 return gfxColorSpaceModeNames[idx];
128 //------------------------------------------------------------------------
129 // GfxDeviceGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
135 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
138 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
139 return new GfxDeviceGrayColorSpace();
142 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
143 *gray = clip01(color->c[0]);
146 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
147 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
150 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
151 cmyk->c = cmyk->m = cmyk->y = 0;
152 cmyk->k = clip01(1 - color->c[0]);
155 //------------------------------------------------------------------------
156 // GfxCalGrayColorSpace
157 //------------------------------------------------------------------------
159 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
160 whiteX = whiteY = whiteZ = 1;
161 blackX = blackY = blackZ = 0;
162 gamma = 1;
165 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
168 GfxColorSpace *GfxCalGrayColorSpace::copy() {
169 GfxCalGrayColorSpace *cs;
171 cs = new GfxCalGrayColorSpace();
172 cs->whiteX = whiteX;
173 cs->whiteY = whiteY;
174 cs->whiteZ = whiteZ;
175 cs->blackX = blackX;
176 cs->blackY = blackY;
177 cs->blackZ = blackZ;
178 cs->gamma = gamma;
179 return cs;
182 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
183 GfxCalGrayColorSpace *cs;
184 Object obj1, obj2, obj3;
186 arr->get(1, &obj1);
187 if (!obj1.isDict()) {
188 error(-1, "Bad CalGray color space");
189 obj1.free();
190 return NULL;
192 cs = new GfxCalGrayColorSpace();
193 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
194 obj2.arrayGetLength() == 3) {
195 obj2.arrayGet(0, &obj3);
196 cs->whiteX = obj3.getNum();
197 obj3.free();
198 obj2.arrayGet(1, &obj3);
199 cs->whiteY = obj3.getNum();
200 obj3.free();
201 obj2.arrayGet(2, &obj3);
202 cs->whiteZ = obj3.getNum();
203 obj3.free();
205 obj2.free();
206 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
207 obj2.arrayGetLength() == 3) {
208 obj2.arrayGet(0, &obj3);
209 cs->blackX = obj3.getNum();
210 obj3.free();
211 obj2.arrayGet(1, &obj3);
212 cs->blackY = obj3.getNum();
213 obj3.free();
214 obj2.arrayGet(2, &obj3);
215 cs->blackZ = obj3.getNum();
216 obj3.free();
218 obj2.free();
219 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
220 cs->gamma = obj2.getNum();
222 obj2.free();
223 obj1.free();
224 return cs;
227 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
228 *gray = clip01(color->c[0]);
231 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
232 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
235 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
236 cmyk->c = cmyk->m = cmyk->y = 0;
237 cmyk->k = clip01(1 - color->c[0]);
240 //------------------------------------------------------------------------
241 // GfxDeviceRGBColorSpace
242 //------------------------------------------------------------------------
244 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
247 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
250 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
251 return new GfxDeviceRGBColorSpace();
254 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
255 *gray = clip01(0.299 * color->c[0] +
256 0.587 * color->c[1] +
257 0.114 * color->c[2]);
260 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
261 rgb->r = clip01(color->c[0]);
262 rgb->g = clip01(color->c[1]);
263 rgb->b = clip01(color->c[2]);
266 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
267 double c, m, y, k;
269 c = clip01(1 - color->c[0]);
270 m = clip01(1 - color->c[1]);
271 y = clip01(1 - color->c[2]);
272 k = c;
273 if (m < k) {
274 k = m;
276 if (y < k) {
277 k = y;
279 cmyk->c = c - k;
280 cmyk->m = m - k;
281 cmyk->y = y - k;
282 cmyk->k = k;
285 //------------------------------------------------------------------------
286 // GfxCalRGBColorSpace
287 //------------------------------------------------------------------------
289 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
290 whiteX = whiteY = whiteZ = 1;
291 blackX = blackY = blackZ = 0;
292 gammaR = gammaG = gammaB = 1;
293 mat[0] = 1; mat[1] = 0; mat[2] = 0;
294 mat[3] = 0; mat[4] = 1; mat[5] = 0;
295 mat[6] = 0; mat[7] = 0; mat[8] = 1;
298 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
301 GfxColorSpace *GfxCalRGBColorSpace::copy() {
302 GfxCalRGBColorSpace *cs;
303 int i;
305 cs = new GfxCalRGBColorSpace();
306 cs->whiteX = whiteX;
307 cs->whiteY = whiteY;
308 cs->whiteZ = whiteZ;
309 cs->blackX = blackX;
310 cs->blackY = blackY;
311 cs->blackZ = blackZ;
312 cs->gammaR = gammaR;
313 cs->gammaG = gammaG;
314 cs->gammaB = gammaB;
315 for (i = 0; i < 9; ++i) {
316 cs->mat[i] = mat[i];
318 return cs;
321 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
322 GfxCalRGBColorSpace *cs;
323 Object obj1, obj2, obj3;
324 int i;
326 arr->get(1, &obj1);
327 if (!obj1.isDict()) {
328 error(-1, "Bad CalRGB color space");
329 obj1.free();
330 return NULL;
332 cs = new GfxCalRGBColorSpace();
333 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
334 obj2.arrayGetLength() == 3) {
335 obj2.arrayGet(0, &obj3);
336 cs->whiteX = obj3.getNum();
337 obj3.free();
338 obj2.arrayGet(1, &obj3);
339 cs->whiteY = obj3.getNum();
340 obj3.free();
341 obj2.arrayGet(2, &obj3);
342 cs->whiteZ = obj3.getNum();
343 obj3.free();
345 obj2.free();
346 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
347 obj2.arrayGetLength() == 3) {
348 obj2.arrayGet(0, &obj3);
349 cs->blackX = obj3.getNum();
350 obj3.free();
351 obj2.arrayGet(1, &obj3);
352 cs->blackY = obj3.getNum();
353 obj3.free();
354 obj2.arrayGet(2, &obj3);
355 cs->blackZ = obj3.getNum();
356 obj3.free();
358 obj2.free();
359 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
360 obj2.arrayGetLength() == 3) {
361 obj2.arrayGet(0, &obj3);
362 cs->gammaR = obj3.getNum();
363 obj3.free();
364 obj2.arrayGet(1, &obj3);
365 cs->gammaG = obj3.getNum();
366 obj3.free();
367 obj2.arrayGet(2, &obj3);
368 cs->gammaB = obj3.getNum();
369 obj3.free();
371 obj2.free();
372 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
373 obj2.arrayGetLength() == 9) {
374 for (i = 0; i < 9; ++i) {
375 obj2.arrayGet(i, &obj3);
376 cs->mat[i] = obj3.getNum();
377 obj3.free();
380 obj2.free();
381 obj1.free();
382 return cs;
385 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
386 *gray = clip01(0.299 * color->c[0] +
387 0.587 * color->c[1] +
388 0.114 * color->c[2]);
391 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
392 rgb->r = clip01(color->c[0]);
393 rgb->g = clip01(color->c[1]);
394 rgb->b = clip01(color->c[2]);
397 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
398 double c, m, y, k;
400 c = clip01(1 - color->c[0]);
401 m = clip01(1 - color->c[1]);
402 y = clip01(1 - color->c[2]);
403 k = c;
404 if (m < k) {
405 k = m;
407 if (y < k) {
408 k = y;
410 cmyk->c = c - k;
411 cmyk->m = m - k;
412 cmyk->y = y - k;
413 cmyk->k = k;
416 //------------------------------------------------------------------------
417 // GfxDeviceCMYKColorSpace
418 //------------------------------------------------------------------------
420 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
423 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
426 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
427 return new GfxDeviceCMYKColorSpace();
430 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
431 *gray = clip01(1 - color->c[3]
432 - 0.299 * color->c[0]
433 - 0.587 * color->c[1]
434 - 0.114 * color->c[2]);
437 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
438 double c, m, y, aw, ac, am, ay, ar, ag, ab;
440 c = clip01(color->c[0] + color->c[3]);
441 m = clip01(color->c[1] + color->c[3]);
442 y = clip01(color->c[2] + color->c[3]);
443 aw = (1-c) * (1-m) * (1-y);
444 ac = c * (1-m) * (1-y);
445 am = (1-c) * m * (1-y);
446 ay = (1-c) * (1-m) * y;
447 ar = (1-c) * m * y;
448 ag = c * (1-m) * y;
449 ab = c * m * (1-y);
450 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
451 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
452 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
453 0.4863*ab);
456 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
457 cmyk->c = clip01(color->c[0]);
458 cmyk->m = clip01(color->c[1]);
459 cmyk->y = clip01(color->c[2]);
460 cmyk->k = clip01(color->c[3]);
463 //------------------------------------------------------------------------
464 // GfxLabColorSpace
465 //------------------------------------------------------------------------
467 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
468 // Language Reference, Third Edition.
469 static double xyzrgb[3][3] = {
470 { 3.240449, -1.537136, -0.498531 },
471 { -0.969265, 1.876011, 0.041556 },
472 { 0.055643, -0.204026, 1.057229 }
475 GfxLabColorSpace::GfxLabColorSpace() {
476 whiteX = whiteY = whiteZ = 1;
477 blackX = blackY = blackZ = 0;
478 aMin = bMin = -100;
479 aMax = bMax = 100;
482 GfxLabColorSpace::~GfxLabColorSpace() {
485 GfxColorSpace *GfxLabColorSpace::copy() {
486 GfxLabColorSpace *cs;
488 cs = new GfxLabColorSpace();
489 cs->whiteX = whiteX;
490 cs->whiteY = whiteY;
491 cs->whiteZ = whiteZ;
492 cs->blackX = blackX;
493 cs->blackY = blackY;
494 cs->blackZ = blackZ;
495 cs->aMin = aMin;
496 cs->aMax = aMax;
497 cs->bMin = bMin;
498 cs->bMax = bMax;
499 cs->kr = kr;
500 cs->kg = kg;
501 cs->kb = kb;
502 return cs;
505 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
506 GfxLabColorSpace *cs;
507 Object obj1, obj2, obj3;
509 arr->get(1, &obj1);
510 if (!obj1.isDict()) {
511 error(-1, "Bad Lab color space");
512 obj1.free();
513 return NULL;
515 cs = new GfxLabColorSpace();
516 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
517 obj2.arrayGetLength() == 3) {
518 obj2.arrayGet(0, &obj3);
519 cs->whiteX = obj3.getNum();
520 obj3.free();
521 obj2.arrayGet(1, &obj3);
522 cs->whiteY = obj3.getNum();
523 obj3.free();
524 obj2.arrayGet(2, &obj3);
525 cs->whiteZ = obj3.getNum();
526 obj3.free();
528 obj2.free();
529 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
530 obj2.arrayGetLength() == 3) {
531 obj2.arrayGet(0, &obj3);
532 cs->blackX = obj3.getNum();
533 obj3.free();
534 obj2.arrayGet(1, &obj3);
535 cs->blackY = obj3.getNum();
536 obj3.free();
537 obj2.arrayGet(2, &obj3);
538 cs->blackZ = obj3.getNum();
539 obj3.free();
541 obj2.free();
542 if (obj1.dictLookup("Range", &obj2)->isArray() &&
543 obj2.arrayGetLength() == 4) {
544 obj2.arrayGet(0, &obj3);
545 cs->aMin = obj3.getNum();
546 obj3.free();
547 obj2.arrayGet(1, &obj3);
548 cs->aMax = obj3.getNum();
549 obj3.free();
550 obj2.arrayGet(2, &obj3);
551 cs->bMin = obj3.getNum();
552 obj3.free();
553 obj2.arrayGet(3, &obj3);
554 cs->bMax = obj3.getNum();
555 obj3.free();
557 obj2.free();
558 obj1.free();
560 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
561 xyzrgb[0][1] * cs->whiteY +
562 xyzrgb[0][2] * cs->whiteZ);
563 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
564 xyzrgb[1][1] * cs->whiteY +
565 xyzrgb[1][2] * cs->whiteZ);
566 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
567 xyzrgb[2][1] * cs->whiteY +
568 xyzrgb[2][2] * cs->whiteZ);
570 return cs;
573 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
574 GfxRGB rgb;
576 getRGB(color, &rgb);
577 *gray = clip01(0.299 * rgb.r +
578 0.587 * rgb.g +
579 0.114 * rgb.b);
582 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
583 double X, Y, Z;
584 double t1, t2;
585 double r, g, b;
587 // convert L*a*b* to CIE 1931 XYZ color space
588 t1 = (color->c[0] + 16) / 116;
589 t2 = t1 + color->c[1] / 500;
590 if (t2 >= (6.0 / 29.0)) {
591 X = t2 * t2 * t2;
592 } else {
593 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
595 X *= whiteX;
596 if (t1 >= (6.0 / 29.0)) {
597 Y = t1 * t1 * t1;
598 } else {
599 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
601 Y *= whiteY;
602 t2 = t1 - color->c[2] / 200;
603 if (t2 >= (6.0 / 29.0)) {
604 Z = t2 * t2 * t2;
605 } else {
606 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
608 Z *= whiteZ;
610 // convert XYZ to RGB, including gamut mapping and gamma correction
611 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
612 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
613 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
614 rgb->r = pow(clip01(r * kr), 0.5);
615 rgb->g = pow(clip01(g * kg), 0.5);
616 rgb->b = pow(clip01(b * kb), 0.5);
619 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
620 GfxRGB rgb;
621 double c, m, y, k;
623 getRGB(color, &rgb);
624 c = clip01(1 - rgb.r);
625 m = clip01(1 - rgb.g);
626 y = clip01(1 - rgb.b);
627 k = c;
628 if (m < k) {
629 k = m;
631 if (y < k) {
632 k = y;
634 cmyk->c = c - k;
635 cmyk->m = m - k;
636 cmyk->y = y - k;
637 cmyk->k = k;
640 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
641 int maxImgPixel) {
642 decodeLow[0] = 0;
643 decodeRange[0] = 100;
644 decodeLow[1] = aMin;
645 decodeRange[1] = aMax - aMin;
646 decodeLow[2] = bMin;
647 decodeRange[2] = bMax - bMin;
650 //------------------------------------------------------------------------
651 // GfxICCBasedColorSpace
652 //------------------------------------------------------------------------
654 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
655 Ref *iccProfileStreamA) {
656 nComps = nCompsA;
657 alt = altA;
658 iccProfileStream = *iccProfileStreamA;
659 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
660 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
663 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
664 delete alt;
667 GfxColorSpace *GfxICCBasedColorSpace::copy() {
668 GfxICCBasedColorSpace *cs;
669 int i;
671 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
672 for (i = 0; i < 4; ++i) {
673 cs->rangeMin[i] = rangeMin[i];
674 cs->rangeMax[i] = rangeMax[i];
676 return cs;
679 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
680 GfxICCBasedColorSpace *cs;
681 Ref iccProfileStreamA;
682 int nCompsA;
683 GfxColorSpace *altA;
684 Dict *dict;
685 Object obj1, obj2, obj3;
686 int i;
688 arr->getNF(1, &obj1);
689 if (obj1.isRef()) {
690 iccProfileStreamA = obj1.getRef();
691 } else {
692 iccProfileStreamA.num = 0;
693 iccProfileStreamA.gen = 0;
695 obj1.free();
696 arr->get(1, &obj1);
697 if (!obj1.isStream()) {
698 error(-1, "Bad ICCBased color space (stream)");
699 obj1.free();
700 return NULL;
702 dict = obj1.streamGetDict();
703 if (!dict->lookup("N", &obj2)->isInt()) {
704 error(-1, "Bad ICCBased color space (N)");
705 obj2.free();
706 obj1.free();
707 return NULL;
709 nCompsA = obj2.getInt();
710 obj2.free();
711 if (dict->lookup("Alternate", &obj2)->isNull() ||
712 !(altA = GfxColorSpace::parse(&obj2))) {
713 switch (nCompsA) {
714 case 1:
715 altA = new GfxDeviceGrayColorSpace();
716 break;
717 case 3:
718 altA = new GfxDeviceRGBColorSpace();
719 break;
720 case 4:
721 altA = new GfxDeviceCMYKColorSpace();
722 break;
723 default:
724 error(-1, "Bad ICCBased color space - invalid N");
725 obj2.free();
726 obj1.free();
727 return NULL;
730 obj2.free();
731 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
732 if (dict->lookup("Range", &obj2)->isArray() &&
733 obj2.arrayGetLength() == 2 * nCompsA) {
734 for (i = 0; i < nCompsA; ++i) {
735 obj2.arrayGet(2*i, &obj3);
736 cs->rangeMin[i] = obj3.getNum();
737 obj3.free();
738 obj2.arrayGet(2*i+1, &obj3);
739 cs->rangeMax[i] = obj3.getNum();
740 obj3.free();
743 obj2.free();
744 obj1.free();
745 return cs;
748 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
749 alt->getGray(color, gray);
752 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
753 alt->getRGB(color, rgb);
756 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
757 alt->getCMYK(color, cmyk);
760 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
761 double *decodeRange,
762 int maxImgPixel) {
763 alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
765 #if 0
766 // this is nominally correct, but some PDF files don't set the
767 // correct ranges in the ICCBased dict
768 int i;
770 for (i = 0; i < nComps; ++i) {
771 decodeLow[i] = rangeMin[i];
772 decodeRange[i] = rangeMax[i] - rangeMin[i];
774 #endif
777 //------------------------------------------------------------------------
778 // GfxIndexedColorSpace
779 //------------------------------------------------------------------------
781 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
782 int indexHighA) {
783 base = baseA;
784 indexHigh = indexHighA;
785 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
786 sizeof(Guchar));
789 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
790 delete base;
791 gfree(lookup);
794 GfxColorSpace *GfxIndexedColorSpace::copy() {
795 GfxIndexedColorSpace *cs;
797 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
798 memcpy(cs->lookup, lookup,
799 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
800 return cs;
803 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
804 GfxIndexedColorSpace *cs;
805 GfxColorSpace *baseA;
806 int indexHighA;
807 Object obj1;
808 int x;
809 char *s;
810 int n, i, j;
812 if (arr->getLength() != 4) {
813 error(-1, "Bad Indexed color space");
814 goto err1;
816 arr->get(1, &obj1);
817 if (!(baseA = GfxColorSpace::parse(&obj1))) {
818 error(-1, "Bad Indexed color space (base color space)");
819 goto err2;
821 obj1.free();
822 if (!arr->get(2, &obj1)->isInt()) {
823 error(-1, "Bad Indexed color space (hival)");
824 delete baseA;
825 goto err2;
827 indexHighA = obj1.getInt();
828 if (indexHighA < 0 || indexHighA > 255) {
829 // the PDF spec requires indexHigh to be in [0,255] -- allowing
830 // values larger than 255 creates a security hole: if nComps *
831 // indexHigh is greater than 2^31, the loop below may overwrite
832 // past the end of the array
833 error(-1, "Bad Indexed color space (invalid indexHigh value)");
834 delete baseA;
835 goto err2;
837 obj1.free();
838 cs = new GfxIndexedColorSpace(baseA, indexHighA);
839 arr->get(3, &obj1);
840 n = baseA->getNComps();
841 if (obj1.isStream()) {
842 obj1.streamReset();
843 for (i = 0; i <= indexHighA; ++i) {
844 for (j = 0; j < n; ++j) {
845 if ((x = obj1.streamGetChar()) == EOF) {
846 error(-1, "Bad Indexed color space (lookup table stream too short)");
847 goto err3;
849 cs->lookup[i*n + j] = (Guchar)x;
852 obj1.streamClose();
853 } else if (obj1.isString()) {
854 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
855 error(-1, "Bad Indexed color space (lookup table string too short)");
856 goto err3;
858 s = obj1.getString()->getCString();
859 for (i = 0; i <= indexHighA; ++i) {
860 for (j = 0; j < n; ++j) {
861 cs->lookup[i*n + j] = (Guchar)*s++;
864 } else {
865 error(-1, "Bad Indexed color space (lookup table)");
866 goto err3;
868 obj1.free();
869 return cs;
871 err3:
872 delete cs;
873 err2:
874 obj1.free();
875 err1:
876 return NULL;
879 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
880 GfxColor *baseColor) {
881 Guchar *p;
882 double low[gfxColorMaxComps], range[gfxColorMaxComps];
883 int n, i;
885 n = base->getNComps();
886 base->getDefaultRanges(low, range, indexHigh);
887 p = &lookup[(int)(color->c[0] + 0.5) * n];
888 for (i = 0; i < n; ++i) {
889 baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
891 return baseColor;
894 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
895 GfxColor color2;
897 base->getGray(mapColorToBase(color, &color2), gray);
900 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
901 GfxColor color2;
903 base->getRGB(mapColorToBase(color, &color2), rgb);
906 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
907 GfxColor color2;
909 base->getCMYK(mapColorToBase(color, &color2), cmyk);
912 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
913 double *decodeRange,
914 int maxImgPixel) {
915 decodeLow[0] = 0;
916 decodeRange[0] = maxImgPixel;
919 //------------------------------------------------------------------------
920 // GfxSeparationColorSpace
921 //------------------------------------------------------------------------
923 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
924 GfxColorSpace *altA,
925 Function *funcA) {
926 name = nameA;
927 alt = altA;
928 func = funcA;
931 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
932 delete name;
933 delete alt;
934 delete func;
937 GfxColorSpace *GfxSeparationColorSpace::copy() {
938 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
941 //~ handle the 'All' and 'None' colorants
942 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
943 GfxSeparationColorSpace *cs;
944 GString *nameA;
945 GfxColorSpace *altA;
946 Function *funcA;
947 Object obj1;
949 if (arr->getLength() != 4) {
950 error(-1, "Bad Separation color space");
951 goto err1;
953 if (!arr->get(1, &obj1)->isName()) {
954 error(-1, "Bad Separation color space (name)");
955 goto err2;
957 nameA = new GString(obj1.getName());
958 obj1.free();
959 arr->get(2, &obj1);
960 if (!(altA = GfxColorSpace::parse(&obj1))) {
961 error(-1, "Bad Separation color space (alternate color space)");
962 goto err3;
964 obj1.free();
965 arr->get(3, &obj1);
966 if (!(funcA = Function::parse(&obj1))) {
967 goto err4;
969 obj1.free();
970 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
971 return cs;
973 err4:
974 delete altA;
975 err3:
976 delete nameA;
977 err2:
978 obj1.free();
979 err1:
980 return NULL;
983 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
984 GfxColor color2;
986 func->transform(color->c, color2.c);
987 alt->getGray(&color2, gray);
990 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
991 GfxColor color2;
993 func->transform(color->c, color2.c);
994 alt->getRGB(&color2, rgb);
997 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
998 GfxColor color2;
1000 func->transform(color->c, color2.c);
1001 alt->getCMYK(&color2, cmyk);
1004 //------------------------------------------------------------------------
1005 // GfxDeviceNColorSpace
1006 //------------------------------------------------------------------------
1008 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1009 GfxColorSpace *altA,
1010 Function *funcA) {
1011 nComps = nCompsA;
1012 alt = altA;
1013 func = funcA;
1016 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1017 int i;
1019 for (i = 0; i < nComps; ++i) {
1020 delete names[i];
1022 delete alt;
1023 delete func;
1026 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1027 GfxDeviceNColorSpace *cs;
1028 int i;
1030 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1031 for (i = 0; i < nComps; ++i) {
1032 cs->names[i] = names[i]->copy();
1034 return cs;
1037 //~ handle the 'None' colorant
1038 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1039 GfxDeviceNColorSpace *cs;
1040 int nCompsA;
1041 GString *namesA[gfxColorMaxComps];
1042 GfxColorSpace *altA;
1043 Function *funcA;
1044 Object obj1, obj2;
1045 int i;
1047 if (arr->getLength() != 4 && arr->getLength() != 5) {
1048 error(-1, "Bad DeviceN color space");
1049 goto err1;
1051 if (!arr->get(1, &obj1)->isArray()) {
1052 error(-1, "Bad DeviceN color space (names)");
1053 goto err2;
1055 nCompsA = obj1.arrayGetLength();
1056 if (nCompsA > gfxColorMaxComps) {
1057 error(-1, "DeviceN color space with more than %d > %d components",
1058 nCompsA, gfxColorMaxComps);
1059 nCompsA = gfxColorMaxComps;
1061 for (i = 0; i < nCompsA; ++i) {
1062 if (!obj1.arrayGet(i, &obj2)->isName()) {
1063 error(-1, "Bad DeviceN color space (names)");
1064 obj2.free();
1065 goto err2;
1067 namesA[i] = new GString(obj2.getName());
1068 obj2.free();
1070 obj1.free();
1071 arr->get(2, &obj1);
1072 if (!(altA = GfxColorSpace::parse(&obj1))) {
1073 error(-1, "Bad DeviceN color space (alternate color space)");
1074 goto err3;
1076 obj1.free();
1077 arr->get(3, &obj1);
1078 if (!(funcA = Function::parse(&obj1))) {
1079 goto err4;
1081 obj1.free();
1082 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1083 for (i = 0; i < nCompsA; ++i) {
1084 cs->names[i] = namesA[i];
1086 return cs;
1088 err4:
1089 delete altA;
1090 err3:
1091 for (i = 0; i < nCompsA; ++i) {
1092 delete namesA[i];
1094 err2:
1095 obj1.free();
1096 err1:
1097 return NULL;
1100 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1101 GfxColor color2;
1103 func->transform(color->c, color2.c);
1104 alt->getGray(&color2, gray);
1107 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1108 GfxColor color2;
1110 func->transform(color->c, color2.c);
1111 alt->getRGB(&color2, rgb);
1114 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1115 GfxColor color2;
1117 func->transform(color->c, color2.c);
1118 alt->getCMYK(&color2, cmyk);
1121 //------------------------------------------------------------------------
1122 // GfxPatternColorSpace
1123 //------------------------------------------------------------------------
1125 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1126 under = underA;
1129 GfxPatternColorSpace::~GfxPatternColorSpace() {
1130 if (under) {
1131 delete under;
1135 GfxColorSpace *GfxPatternColorSpace::copy() {
1136 return new GfxPatternColorSpace(under ? under->copy() :
1137 (GfxColorSpace *)NULL);
1140 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1141 GfxPatternColorSpace *cs;
1142 GfxColorSpace *underA;
1143 Object obj1;
1145 if (arr->getLength() != 1 && arr->getLength() != 2) {
1146 error(-1, "Bad Pattern color space");
1147 return NULL;
1149 underA = NULL;
1150 if (arr->getLength() == 2) {
1151 arr->get(1, &obj1);
1152 if (!(underA = GfxColorSpace::parse(&obj1))) {
1153 error(-1, "Bad Pattern color space (underlying color space)");
1154 obj1.free();
1155 return NULL;
1157 obj1.free();
1159 cs = new GfxPatternColorSpace(underA);
1160 return cs;
1163 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1164 *gray = 0;
1167 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1168 rgb->r = rgb->g = rgb->b = 0;
1171 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1172 cmyk->c = cmyk->m = cmyk->y = 0;
1173 cmyk->k = 1;
1176 //------------------------------------------------------------------------
1177 // Pattern
1178 //------------------------------------------------------------------------
1180 GfxPattern::GfxPattern(int typeA) {
1181 type = typeA;
1184 GfxPattern::~GfxPattern() {
1187 GfxPattern *GfxPattern::parse(Object *obj) {
1188 GfxPattern *pattern;
1189 Object obj1;
1191 if (obj->isDict()) {
1192 obj->dictLookup("PatternType", &obj1);
1193 } else if (obj->isStream()) {
1194 obj->streamGetDict()->lookup("PatternType", &obj1);
1195 } else {
1196 return NULL;
1198 pattern = NULL;
1199 if (obj1.isInt() && obj1.getInt() == 1) {
1200 pattern = GfxTilingPattern::parse(obj);
1201 } else if (obj1.isInt() && obj1.getInt() == 2) {
1202 pattern = GfxShadingPattern::parse(obj);
1204 obj1.free();
1205 return pattern;
1208 //------------------------------------------------------------------------
1209 // GfxTilingPattern
1210 //------------------------------------------------------------------------
1212 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1213 GfxTilingPattern *pat;
1214 Dict *dict;
1215 int paintTypeA, tilingTypeA;
1216 double bboxA[4], matrixA[6];
1217 double xStepA, yStepA;
1218 Object resDictA;
1219 Object obj1, obj2;
1220 int i;
1222 if (!patObj->isStream()) {
1223 return NULL;
1225 dict = patObj->streamGetDict();
1227 if (dict->lookup("PaintType", &obj1)->isInt()) {
1228 paintTypeA = obj1.getInt();
1229 } else {
1230 paintTypeA = 1;
1231 error(-1, "Invalid or missing PaintType in pattern");
1233 obj1.free();
1234 if (dict->lookup("TilingType", &obj1)->isInt()) {
1235 tilingTypeA = obj1.getInt();
1236 } else {
1237 tilingTypeA = 1;
1238 error(-1, "Invalid or missing TilingType in pattern");
1240 obj1.free();
1241 bboxA[0] = bboxA[1] = 0;
1242 bboxA[2] = bboxA[3] = 1;
1243 if (dict->lookup("BBox", &obj1)->isArray() &&
1244 obj1.arrayGetLength() == 4) {
1245 for (i = 0; i < 4; ++i) {
1246 if (obj1.arrayGet(i, &obj2)->isNum()) {
1247 bboxA[i] = obj2.getNum();
1249 obj2.free();
1251 } else {
1252 error(-1, "Invalid or missing BBox in pattern");
1254 obj1.free();
1255 if (dict->lookup("XStep", &obj1)->isNum()) {
1256 xStepA = obj1.getNum();
1257 } else {
1258 xStepA = 1;
1259 error(-1, "Invalid or missing XStep in pattern");
1261 obj1.free();
1262 if (dict->lookup("YStep", &obj1)->isNum()) {
1263 yStepA = obj1.getNum();
1264 } else {
1265 yStepA = 1;
1266 error(-1, "Invalid or missing YStep in pattern");
1268 obj1.free();
1269 if (!dict->lookup("Resources", &resDictA)->isDict()) {
1270 resDictA.free();
1271 resDictA.initNull();
1272 error(-1, "Invalid or missing Resources in pattern");
1274 matrixA[0] = 1; matrixA[1] = 0;
1275 matrixA[2] = 0; matrixA[3] = 1;
1276 matrixA[4] = 0; matrixA[5] = 0;
1277 if (dict->lookup("Matrix", &obj1)->isArray() &&
1278 obj1.arrayGetLength() == 6) {
1279 for (i = 0; i < 6; ++i) {
1280 if (obj1.arrayGet(i, &obj2)->isNum()) {
1281 matrixA[i] = obj2.getNum();
1283 obj2.free();
1286 obj1.free();
1288 pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1289 &resDictA, matrixA, patObj);
1290 resDictA.free();
1291 return pat;
1294 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1295 double *bboxA, double xStepA, double yStepA,
1296 Object *resDictA, double *matrixA,
1297 Object *contentStreamA):
1298 GfxPattern(1)
1300 int i;
1302 paintType = paintTypeA;
1303 tilingType = tilingTypeA;
1304 for (i = 0; i < 4; ++i) {
1305 bbox[i] = bboxA[i];
1307 xStep = xStepA;
1308 yStep = yStepA;
1309 resDictA->copy(&resDict);
1310 for (i = 0; i < 6; ++i) {
1311 matrix[i] = matrixA[i];
1313 contentStreamA->copy(&contentStream);
1316 GfxTilingPattern::~GfxTilingPattern() {
1317 resDict.free();
1318 contentStream.free();
1321 GfxPattern *GfxTilingPattern::copy() {
1322 return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1323 &resDict, matrix, &contentStream);
1326 //------------------------------------------------------------------------
1327 // GfxShadingPattern
1328 //------------------------------------------------------------------------
1330 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1331 Dict *dict;
1332 GfxShading *shadingA;
1333 double matrixA[6];
1334 Object obj1, obj2;
1335 int i;
1337 if (!patObj->isDict()) {
1338 return NULL;
1340 dict = patObj->getDict();
1342 dict->lookup("Shading", &obj1);
1343 shadingA = GfxShading::parse(&obj1);
1344 obj1.free();
1345 if (!shadingA) {
1346 return NULL;
1349 matrixA[0] = 1; matrixA[1] = 0;
1350 matrixA[2] = 0; matrixA[3] = 1;
1351 matrixA[4] = 0; matrixA[5] = 0;
1352 if (dict->lookup("Matrix", &obj1)->isArray() &&
1353 obj1.arrayGetLength() == 6) {
1354 for (i = 0; i < 6; ++i) {
1355 if (obj1.arrayGet(i, &obj2)->isNum()) {
1356 matrixA[i] = obj2.getNum();
1358 obj2.free();
1361 obj1.free();
1363 return new GfxShadingPattern(shadingA, matrixA);
1366 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1367 GfxPattern(2)
1369 int i;
1371 shading = shadingA;
1372 for (i = 0; i < 6; ++i) {
1373 matrix[i] = matrixA[i];
1377 GfxShadingPattern::~GfxShadingPattern() {
1378 delete shading;
1381 GfxPattern *GfxShadingPattern::copy() {
1382 return new GfxShadingPattern(shading->copy(), matrix);
1385 //------------------------------------------------------------------------
1386 // GfxShading
1387 //------------------------------------------------------------------------
1389 GfxShading::GfxShading(int typeA) {
1390 type = typeA;
1391 colorSpace = NULL;
1394 GfxShading::GfxShading(GfxShading *shading) {
1395 int i;
1397 type = shading->type;
1398 colorSpace = shading->colorSpace->copy();
1399 for (i = 0; i < gfxColorMaxComps; ++i) {
1400 background.c[i] = shading->background.c[i];
1402 hasBackground = shading->hasBackground;
1403 xMin = shading->xMin;
1404 yMin = shading->yMin;
1405 xMax = shading->xMax;
1406 yMax = shading->yMax;
1407 hasBBox = shading->hasBBox;
1410 GfxShading::~GfxShading() {
1411 if (colorSpace) {
1412 delete colorSpace;
1416 GfxShading *GfxShading::parse(Object *obj) {
1417 GfxShading *shading;
1418 Dict *dict;
1419 int typeA;
1420 Object obj1;
1422 if (obj->isDict()) {
1423 dict = obj->getDict();
1424 } else if (obj->isStream()) {
1425 dict = obj->streamGetDict();
1426 } else {
1427 return NULL;
1430 if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1431 error(-1, "Invalid ShadingType in shading dictionary");
1432 obj1.free();
1433 return NULL;
1435 typeA = obj1.getInt();
1436 obj1.free();
1438 switch (typeA) {
1439 case 1:
1440 shading = GfxFunctionShading::parse(dict);
1441 break;
1442 case 2:
1443 shading = GfxAxialShading::parse(dict);
1444 break;
1445 case 3:
1446 shading = GfxRadialShading::parse(dict);
1447 break;
1448 default:
1449 error(-1, "Unimplemented shading type %d", typeA);
1450 goto err1;
1453 return shading;
1455 err1:
1456 return NULL;
1459 GBool GfxShading::init(Dict *dict) {
1460 Object obj1, obj2;
1461 int i;
1463 dict->lookup("ColorSpace", &obj1);
1464 if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1465 error(-1, "Bad color space in shading dictionary");
1466 obj1.free();
1467 return gFalse;
1469 obj1.free();
1471 for (i = 0; i < gfxColorMaxComps; ++i) {
1472 background.c[i] = 0;
1474 hasBackground = gFalse;
1475 if (dict->lookup("Background", &obj1)->isArray()) {
1476 if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1477 hasBackground = gTrue;
1478 for (i = 0; i < colorSpace->getNComps(); ++i) {
1479 background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1480 obj2.free();
1482 } else {
1483 error(-1, "Bad Background in shading dictionary");
1486 obj1.free();
1488 xMin = yMin = xMax = yMax = 0;
1489 hasBBox = gFalse;
1490 if (dict->lookup("BBox", &obj1)->isArray()) {
1491 if (obj1.arrayGetLength() == 4) {
1492 hasBBox = gTrue;
1493 xMin = obj1.arrayGet(0, &obj2)->getNum();
1494 obj2.free();
1495 yMin = obj1.arrayGet(1, &obj2)->getNum();
1496 obj2.free();
1497 xMax = obj1.arrayGet(2, &obj2)->getNum();
1498 obj2.free();
1499 yMax = obj1.arrayGet(3, &obj2)->getNum();
1500 obj2.free();
1501 } else {
1502 error(-1, "Bad BBox in shading dictionary");
1505 obj1.free();
1507 return gTrue;
1510 //------------------------------------------------------------------------
1511 // GfxFunctionShading
1512 //------------------------------------------------------------------------
1514 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1515 double x1A, double y1A,
1516 double *matrixA,
1517 Function **funcsA, int nFuncsA):
1518 GfxShading(1)
1520 int i;
1522 x0 = x0A;
1523 y0 = y0A;
1524 x1 = x1A;
1525 y1 = y1A;
1526 for (i = 0; i < 6; ++i) {
1527 matrix[i] = matrixA[i];
1529 nFuncs = nFuncsA;
1530 for (i = 0; i < nFuncs; ++i) {
1531 funcs[i] = funcsA[i];
1535 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1536 GfxShading(shading)
1538 int i;
1540 x0 = shading->x0;
1541 y0 = shading->y0;
1542 x1 = shading->x1;
1543 y1 = shading->y1;
1544 for (i = 0; i < 6; ++i) {
1545 matrix[i] = shading->matrix[i];
1547 nFuncs = shading->nFuncs;
1548 for (i = 0; i < nFuncs; ++i) {
1549 funcs[i] = shading->funcs[i]->copy();
1553 GfxFunctionShading::~GfxFunctionShading() {
1554 int i;
1556 for (i = 0; i < nFuncs; ++i) {
1557 delete funcs[i];
1561 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1562 GfxFunctionShading *shading;
1563 double x0A, y0A, x1A, y1A;
1564 double matrixA[6];
1565 Function *funcsA[gfxColorMaxComps];
1566 int nFuncsA;
1567 Object obj1, obj2;
1568 int i;
1570 x0A = y0A = 0;
1571 x1A = y1A = 1;
1572 if (dict->lookup("Domain", &obj1)->isArray() &&
1573 obj1.arrayGetLength() == 4) {
1574 x0A = obj1.arrayGet(0, &obj2)->getNum();
1575 obj2.free();
1576 y0A = obj1.arrayGet(1, &obj2)->getNum();
1577 obj2.free();
1578 x1A = obj1.arrayGet(2, &obj2)->getNum();
1579 obj2.free();
1580 y1A = obj1.arrayGet(3, &obj2)->getNum();
1581 obj2.free();
1583 obj1.free();
1585 matrixA[0] = 1; matrixA[1] = 0;
1586 matrixA[2] = 0; matrixA[3] = 1;
1587 matrixA[4] = 0; matrixA[5] = 0;
1588 if (dict->lookup("Matrix", &obj1)->isArray() &&
1589 obj1.arrayGetLength() == 6) {
1590 matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1591 obj2.free();
1592 matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1593 obj2.free();
1594 matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1595 obj2.free();
1596 matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1597 obj2.free();
1598 matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1599 obj2.free();
1600 matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1601 obj2.free();
1603 obj1.free();
1605 dict->lookup("Function", &obj1);
1606 if (obj1.isArray()) {
1607 nFuncsA = obj1.arrayGetLength();
1608 if (nFuncsA > gfxColorMaxComps) {
1609 error(-1, "Invalid Function array in shading dictionary");
1610 goto err1;
1612 for (i = 0; i < nFuncsA; ++i) {
1613 obj1.arrayGet(i, &obj2);
1614 if (!(funcsA[i] = Function::parse(&obj2))) {
1615 goto err2;
1617 obj2.free();
1619 } else {
1620 nFuncsA = 1;
1621 if (!(funcsA[0] = Function::parse(&obj1))) {
1622 goto err1;
1625 obj1.free();
1627 shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1628 funcsA, nFuncsA);
1629 if (!shading->init(dict)) {
1630 delete shading;
1631 return NULL;
1633 return shading;
1635 err2:
1636 obj2.free();
1637 err1:
1638 obj1.free();
1639 return NULL;
1642 GfxShading *GfxFunctionShading::copy() {
1643 return new GfxFunctionShading(this);
1646 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1647 double in[2];
1648 int i;
1650 in[0] = x;
1651 in[1] = y;
1652 for (i = 0; i < nFuncs; ++i) {
1653 funcs[i]->transform(in, &color->c[i]);
1657 //------------------------------------------------------------------------
1658 // GfxAxialShading
1659 //------------------------------------------------------------------------
1661 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1662 double x1A, double y1A,
1663 double t0A, double t1A,
1664 Function **funcsA, int nFuncsA,
1665 GBool extend0A, GBool extend1A):
1666 GfxShading(2)
1668 int i;
1670 x0 = x0A;
1671 y0 = y0A;
1672 x1 = x1A;
1673 y1 = y1A;
1674 t0 = t0A;
1675 t1 = t1A;
1676 nFuncs = nFuncsA;
1677 for (i = 0; i < nFuncs; ++i) {
1678 funcs[i] = funcsA[i];
1680 extend0 = extend0A;
1681 extend1 = extend1A;
1684 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1685 GfxShading(shading)
1687 int i;
1689 x0 = shading->x0;
1690 y0 = shading->y0;
1691 x1 = shading->x1;
1692 y1 = shading->y1;
1693 t0 = shading->t0;
1694 y1 = shading->t1;
1695 nFuncs = shading->nFuncs;
1696 for (i = 0; i < nFuncs; ++i) {
1697 funcs[i] = shading->funcs[i]->copy();
1699 extend0 = shading->extend0;
1700 extend1 = shading->extend1;
1703 GfxAxialShading::~GfxAxialShading() {
1704 int i;
1706 for (i = 0; i < nFuncs; ++i) {
1707 delete funcs[i];
1711 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1712 GfxAxialShading *shading;
1713 double x0A, y0A, x1A, y1A;
1714 double t0A, t1A;
1715 Function *funcsA[gfxColorMaxComps];
1716 int nFuncsA;
1717 GBool extend0A, extend1A;
1718 Object obj1, obj2;
1719 int i;
1721 x0A = y0A = x1A = y1A = 0;
1722 if (dict->lookup("Coords", &obj1)->isArray() &&
1723 obj1.arrayGetLength() == 4) {
1724 x0A = obj1.arrayGet(0, &obj2)->getNum();
1725 obj2.free();
1726 y0A = obj1.arrayGet(1, &obj2)->getNum();
1727 obj2.free();
1728 x1A = obj1.arrayGet(2, &obj2)->getNum();
1729 obj2.free();
1730 y1A = obj1.arrayGet(3, &obj2)->getNum();
1731 obj2.free();
1732 } else {
1733 error(-1, "Missing or invalid Coords in shading dictionary");
1734 goto err1;
1736 obj1.free();
1738 t0A = 0;
1739 t1A = 1;
1740 if (dict->lookup("Domain", &obj1)->isArray() &&
1741 obj1.arrayGetLength() == 2) {
1742 t0A = obj1.arrayGet(0, &obj2)->getNum();
1743 obj2.free();
1744 t1A = obj1.arrayGet(1, &obj2)->getNum();
1745 obj2.free();
1747 obj1.free();
1749 dict->lookup("Function", &obj1);
1750 if (obj1.isArray()) {
1751 nFuncsA = obj1.arrayGetLength();
1752 if (nFuncsA > gfxColorMaxComps) {
1753 error(-1, "Invalid Function array in shading dictionary");
1754 goto err1;
1756 for (i = 0; i < nFuncsA; ++i) {
1757 obj1.arrayGet(i, &obj2);
1758 if (!(funcsA[i] = Function::parse(&obj2))) {
1759 obj1.free();
1760 obj2.free();
1761 goto err1;
1763 obj2.free();
1765 } else {
1766 nFuncsA = 1;
1767 if (!(funcsA[0] = Function::parse(&obj1))) {
1768 obj1.free();
1769 goto err1;
1772 obj1.free();
1774 extend0A = extend1A = gFalse;
1775 if (dict->lookup("Extend", &obj1)->isArray() &&
1776 obj1.arrayGetLength() == 2) {
1777 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1778 obj2.free();
1779 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1780 obj2.free();
1782 obj1.free();
1784 shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1785 funcsA, nFuncsA, extend0A, extend1A);
1786 if (!shading->init(dict)) {
1787 delete shading;
1788 return NULL;
1790 return shading;
1792 err1:
1793 return NULL;
1796 GfxShading *GfxAxialShading::copy() {
1797 return new GfxAxialShading(this);
1800 void GfxAxialShading::getColor(double t, GfxColor *color) {
1801 int i;
1803 // NB: there can be one function with n outputs or n functions with
1804 // one output each (where n = number of color components)
1805 for (i = 0; i < nFuncs; ++i) {
1806 funcs[i]->transform(&t, &color->c[i]);
1810 //------------------------------------------------------------------------
1811 // GfxRadialShading
1812 //------------------------------------------------------------------------
1814 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1815 double x1A, double y1A, double r1A,
1816 double t0A, double t1A,
1817 Function **funcsA, int nFuncsA,
1818 GBool extend0A, GBool extend1A):
1819 GfxShading(3)
1821 int i;
1823 x0 = x0A;
1824 y0 = y0A;
1825 r0 = r0A;
1826 x1 = x1A;
1827 y1 = y1A;
1828 r1 = r1A;
1829 t0 = t0A;
1830 t1 = t1A;
1831 nFuncs = nFuncsA;
1832 for (i = 0; i < nFuncs; ++i) {
1833 funcs[i] = funcsA[i];
1835 extend0 = extend0A;
1836 extend1 = extend1A;
1839 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1840 GfxShading(shading)
1842 int i;
1844 x0 = shading->x0;
1845 y0 = shading->y0;
1846 r0 = shading->r0;
1847 x1 = shading->x1;
1848 y1 = shading->y1;
1849 r1 = shading->r1;
1850 t0 = shading->t0;
1851 y1 = shading->t1;
1852 nFuncs = shading->nFuncs;
1853 for (i = 0; i < nFuncs; ++i) {
1854 funcs[i] = shading->funcs[i]->copy();
1856 extend0 = shading->extend0;
1857 extend1 = shading->extend1;
1860 GfxRadialShading::~GfxRadialShading() {
1861 int i;
1863 for (i = 0; i < nFuncs; ++i) {
1864 delete funcs[i];
1868 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1869 GfxRadialShading *shading;
1870 double x0A, y0A, r0A, x1A, y1A, r1A;
1871 double t0A, t1A;
1872 Function *funcsA[gfxColorMaxComps];
1873 int nFuncsA;
1874 GBool extend0A, extend1A;
1875 Object obj1, obj2;
1876 int i;
1878 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1879 if (dict->lookup("Coords", &obj1)->isArray() &&
1880 obj1.arrayGetLength() == 6) {
1881 x0A = obj1.arrayGet(0, &obj2)->getNum();
1882 obj2.free();
1883 y0A = obj1.arrayGet(1, &obj2)->getNum();
1884 obj2.free();
1885 r0A = obj1.arrayGet(2, &obj2)->getNum();
1886 obj2.free();
1887 x1A = obj1.arrayGet(3, &obj2)->getNum();
1888 obj2.free();
1889 y1A = obj1.arrayGet(4, &obj2)->getNum();
1890 obj2.free();
1891 r1A = obj1.arrayGet(5, &obj2)->getNum();
1892 obj2.free();
1893 } else {
1894 error(-1, "Missing or invalid Coords in shading dictionary");
1895 goto err1;
1897 obj1.free();
1899 t0A = 0;
1900 t1A = 1;
1901 if (dict->lookup("Domain", &obj1)->isArray() &&
1902 obj1.arrayGetLength() == 2) {
1903 t0A = obj1.arrayGet(0, &obj2)->getNum();
1904 obj2.free();
1905 t1A = obj1.arrayGet(1, &obj2)->getNum();
1906 obj2.free();
1908 obj1.free();
1910 dict->lookup("Function", &obj1);
1911 if (obj1.isArray()) {
1912 nFuncsA = obj1.arrayGetLength();
1913 if (nFuncsA > gfxColorMaxComps) {
1914 error(-1, "Invalid Function array in shading dictionary");
1915 goto err1;
1917 for (i = 0; i < nFuncsA; ++i) {
1918 obj1.arrayGet(i, &obj2);
1919 if (!(funcsA[i] = Function::parse(&obj2))) {
1920 obj1.free();
1921 obj2.free();
1922 goto err1;
1924 obj2.free();
1926 } else {
1927 nFuncsA = 1;
1928 if (!(funcsA[0] = Function::parse(&obj1))) {
1929 obj1.free();
1930 goto err1;
1933 obj1.free();
1935 extend0A = extend1A = gFalse;
1936 if (dict->lookup("Extend", &obj1)->isArray() &&
1937 obj1.arrayGetLength() == 2) {
1938 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1939 obj2.free();
1940 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1941 obj2.free();
1943 obj1.free();
1945 shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1946 funcsA, nFuncsA, extend0A, extend1A);
1947 if (!shading->init(dict)) {
1948 delete shading;
1949 return NULL;
1951 return shading;
1953 err1:
1954 return NULL;
1957 GfxShading *GfxRadialShading::copy() {
1958 return new GfxRadialShading(this);
1961 void GfxRadialShading::getColor(double t, GfxColor *color) {
1962 int i;
1964 // NB: there can be one function with n outputs or n functions with
1965 // one output each (where n = number of color components)
1966 for (i = 0; i < nFuncs; ++i) {
1967 funcs[i]->transform(&t, &color->c[i]);
1971 //------------------------------------------------------------------------
1972 // GfxImageColorMap
1973 //------------------------------------------------------------------------
1975 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1976 GfxColorSpace *colorSpaceA) {
1977 GfxIndexedColorSpace *indexedCS;
1978 GfxSeparationColorSpace *sepCS;
1979 int maxPixel, indexHigh;
1980 Guchar *lookup2;
1981 Function *sepFunc;
1982 Object obj;
1983 double x[gfxColorMaxComps];
1984 double y[gfxColorMaxComps];
1985 int i, j, k;
1987 ok = gTrue;
1989 // bits per component and color space
1990 bits = bitsA;
1991 maxPixel = (1 << bits) - 1;
1992 colorSpace = colorSpaceA;
1994 // get decode map
1995 if (decode->isNull()) {
1996 nComps = colorSpace->getNComps();
1997 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1998 } else if (decode->isArray()) {
1999 nComps = decode->arrayGetLength() / 2;
2000 if (nComps != colorSpace->getNComps()) {
2001 goto err1;
2003 for (i = 0; i < nComps; ++i) {
2004 decode->arrayGet(2*i, &obj);
2005 if (!obj.isNum()) {
2006 goto err2;
2008 decodeLow[i] = obj.getNum();
2009 obj.free();
2010 decode->arrayGet(2*i+1, &obj);
2011 if (!obj.isNum()) {
2012 goto err2;
2014 decodeRange[i] = obj.getNum() - decodeLow[i];
2015 obj.free();
2017 } else {
2018 goto err1;
2021 // Construct a lookup table -- this stores pre-computed decoded
2022 // values for each component, i.e., the result of applying the
2023 // decode mapping to each possible image pixel component value.
2025 // Optimization: for Indexed and Separation color spaces (which have
2026 // only one component), we store color values in the lookup table
2027 // rather than component values.
2028 colorSpace2 = NULL;
2029 nComps2 = 0;
2030 if (colorSpace->getMode() == csIndexed) {
2031 // Note that indexHigh may not be the same as maxPixel --
2032 // Distiller will remove unused palette entries, resulting in
2033 // indexHigh < maxPixel.
2034 indexedCS = (GfxIndexedColorSpace *)colorSpace;
2035 colorSpace2 = indexedCS->getBase();
2036 indexHigh = indexedCS->getIndexHigh();
2037 nComps2 = colorSpace2->getNComps();
2038 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
2039 lookup2 = indexedCS->getLookup();
2040 colorSpace2->getDefaultRanges(x, y, indexHigh);
2041 for (i = 0; i <= maxPixel; ++i) {
2042 j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2043 if (j < 0) {
2044 j = 0;
2045 } else if (j > indexHigh) {
2046 j = indexHigh;
2048 for (k = 0; k < nComps2; ++k) {
2049 lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2052 } else if (colorSpace->getMode() == csSeparation) {
2053 sepCS = (GfxSeparationColorSpace *)colorSpace;
2054 colorSpace2 = sepCS->getAlt();
2055 nComps2 = colorSpace2->getNComps();
2056 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
2057 sepFunc = sepCS->getFunc();
2058 for (i = 0; i <= maxPixel; ++i) {
2059 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2060 sepFunc->transform(x, y);
2061 for (k = 0; k < nComps2; ++k) {
2062 lookup[i*nComps2 + k] = y[k];
2065 } else {
2066 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
2067 for (i = 0; i <= maxPixel; ++i) {
2068 for (k = 0; k < nComps; ++k) {
2069 lookup[i*nComps + k] = decodeLow[k] +
2070 (i * decodeRange[k]) / maxPixel;
2075 return;
2077 err2:
2078 obj.free();
2079 err1:
2080 ok = gFalse;
2083 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2084 int n, i;
2086 colorSpace = colorMap->colorSpace->copy();
2087 bits = colorMap->bits;
2088 nComps = colorMap->nComps;
2089 nComps2 = colorMap->nComps2;
2090 colorSpace2 = NULL;
2091 lookup = NULL;
2092 n = 1 << bits;
2093 if (colorSpace->getMode() == csIndexed) {
2094 colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2095 n = n * nComps2 * sizeof(double);
2096 } else if (colorSpace->getMode() == csSeparation) {
2097 colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2098 n = n * nComps2 * sizeof(double);
2099 } else {
2100 n = n * nComps * sizeof(double);
2102 lookup = (double *)gmalloc(n);
2103 memcpy(lookup, colorMap->lookup, n);
2104 for (i = 0; i < nComps; ++i) {
2105 decodeLow[i] = colorMap->decodeLow[i];
2106 decodeRange[i] = colorMap->decodeRange[i];
2108 ok = gTrue;
2111 GfxImageColorMap::~GfxImageColorMap() {
2112 delete colorSpace;
2113 gfree(lookup);
2116 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2117 GfxColor color;
2118 double *p;
2119 int i;
2121 if (colorSpace2) {
2122 p = &lookup[x[0] * nComps2];
2123 for (i = 0; i < nComps2; ++i) {
2124 color.c[i] = *p++;
2126 colorSpace2->getGray(&color, gray);
2127 } else {
2128 for (i = 0; i < nComps; ++i) {
2129 color.c[i] = lookup[x[i] * nComps + i];
2131 colorSpace->getGray(&color, gray);
2135 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2136 GfxColor color;
2137 double *p;
2138 int i;
2140 if (colorSpace2) {
2141 p = &lookup[x[0] * nComps2];
2142 for (i = 0; i < nComps2; ++i) {
2143 color.c[i] = *p++;
2145 colorSpace2->getRGB(&color, rgb);
2146 } else {
2147 for (i = 0; i < nComps; ++i) {
2148 color.c[i] = lookup[x[i] * nComps + i];
2150 colorSpace->getRGB(&color, rgb);
2154 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2155 GfxColor color;
2156 double *p;
2157 int i;
2159 if (colorSpace2) {
2160 p = &lookup[x[0] * nComps2];
2161 for (i = 0; i < nComps2; ++i) {
2162 color.c[i] = *p++;
2164 colorSpace2->getCMYK(&color, cmyk);
2165 } else {
2166 for (i = 0; i < nComps; ++i) {
2167 color.c[i] = lookup[x[i] * nComps + i];
2169 colorSpace->getCMYK(&color, cmyk);
2173 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2174 int maxPixel, i;
2176 maxPixel = (1 << bits) - 1;
2177 for (i = 0; i < nComps; ++i) {
2178 color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2182 //------------------------------------------------------------------------
2183 // GfxSubpath and GfxPath
2184 //------------------------------------------------------------------------
2186 GfxSubpath::GfxSubpath(double x1, double y1) {
2187 size = 16;
2188 x = (double *)gmalloc(size * sizeof(double));
2189 y = (double *)gmalloc(size * sizeof(double));
2190 curve = (GBool *)gmalloc(size * sizeof(GBool));
2191 n = 1;
2192 x[0] = x1;
2193 y[0] = y1;
2194 curve[0] = gFalse;
2195 closed = gFalse;
2198 GfxSubpath::~GfxSubpath() {
2199 gfree(x);
2200 gfree(y);
2201 gfree(curve);
2204 // Used for copy().
2205 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2206 size = subpath->size;
2207 n = subpath->n;
2208 x = (double *)gmalloc(size * sizeof(double));
2209 y = (double *)gmalloc(size * sizeof(double));
2210 curve = (GBool *)gmalloc(size * sizeof(GBool));
2211 memcpy(x, subpath->x, n * sizeof(double));
2212 memcpy(y, subpath->y, n * sizeof(double));
2213 memcpy(curve, subpath->curve, n * sizeof(GBool));
2214 closed = subpath->closed;
2217 void GfxSubpath::lineTo(double x1, double y1) {
2218 if (n >= size) {
2219 size += 16;
2220 x = (double *)grealloc(x, size * sizeof(double));
2221 y = (double *)grealloc(y, size * sizeof(double));
2222 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2224 x[n] = x1;
2225 y[n] = y1;
2226 curve[n] = gFalse;
2227 ++n;
2230 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2231 double x3, double y3) {
2232 if (n+3 > size) {
2233 size += 16;
2234 x = (double *)grealloc(x, size * sizeof(double));
2235 y = (double *)grealloc(y, size * sizeof(double));
2236 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2238 x[n] = x1;
2239 y[n] = y1;
2240 x[n+1] = x2;
2241 y[n+1] = y2;
2242 x[n+2] = x3;
2243 y[n+2] = y3;
2244 curve[n] = curve[n+1] = gTrue;
2245 curve[n+2] = gFalse;
2246 n += 3;
2249 void GfxSubpath::close() {
2250 if (x[n-1] != x[0] || y[n-1] != y[0]) {
2251 lineTo(x[0], y[0]);
2253 closed = gTrue;
2256 void GfxSubpath::offset(double dx, double dy) {
2257 int i;
2259 for (i = 0; i < n; ++i) {
2260 x[i] += dx;
2261 y[i] += dy;
2265 GfxPath::GfxPath() {
2266 justMoved = gFalse;
2267 size = 16;
2268 n = 0;
2269 firstX = firstY = 0;
2270 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2273 GfxPath::~GfxPath() {
2274 int i;
2276 for (i = 0; i < n; ++i)
2277 delete subpaths[i];
2278 gfree(subpaths);
2281 // Used for copy().
2282 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2283 GfxSubpath **subpaths1, int n1, int size1) {
2284 int i;
2286 justMoved = justMoved1;
2287 firstX = firstX1;
2288 firstY = firstY1;
2289 size = size1;
2290 n = n1;
2291 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2292 for (i = 0; i < n; ++i)
2293 subpaths[i] = subpaths1[i]->copy();
2296 void GfxPath::moveTo(double x, double y) {
2297 justMoved = gTrue;
2298 firstX = x;
2299 firstY = y;
2302 void GfxPath::lineTo(double x, double y) {
2303 if (justMoved) {
2304 if (n >= size) {
2305 size += 16;
2306 subpaths = (GfxSubpath **)
2307 grealloc(subpaths, size * sizeof(GfxSubpath *));
2309 subpaths[n] = new GfxSubpath(firstX, firstY);
2310 ++n;
2311 justMoved = gFalse;
2313 subpaths[n-1]->lineTo(x, y);
2316 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2317 double x3, double y3) {
2318 if (justMoved) {
2319 if (n >= size) {
2320 size += 16;
2321 subpaths = (GfxSubpath **)
2322 grealloc(subpaths, size * sizeof(GfxSubpath *));
2324 subpaths[n] = new GfxSubpath(firstX, firstY);
2325 ++n;
2326 justMoved = gFalse;
2328 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2331 void GfxPath::close() {
2332 // this is necessary to handle the pathological case of
2333 // moveto/closepath/clip, which defines an empty clipping region
2334 if (justMoved) {
2335 if (n >= size) {
2336 size += 16;
2337 subpaths = (GfxSubpath **)
2338 grealloc(subpaths, size * sizeof(GfxSubpath *));
2340 subpaths[n] = new GfxSubpath(firstX, firstY);
2341 ++n;
2342 justMoved = gFalse;
2344 subpaths[n-1]->close();
2347 void GfxPath::append(GfxPath *path) {
2348 int i;
2350 if (n + path->n > size) {
2351 size = n + path->n;
2352 subpaths = (GfxSubpath **)
2353 grealloc(subpaths, size * sizeof(GfxSubpath *));
2355 for (i = 0; i < path->n; ++i) {
2356 subpaths[n++] = path->subpaths[i]->copy();
2358 justMoved = gFalse;
2361 void GfxPath::offset(double dx, double dy) {
2362 int i;
2364 for (i = 0; i < n; ++i) {
2365 subpaths[i]->offset(dx, dy);
2369 //------------------------------------------------------------------------
2370 // GfxState
2371 //------------------------------------------------------------------------
2373 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2374 int rotate, GBool upsideDown) {
2375 double kx, ky;
2377 px1 = pageBox->x1;
2378 py1 = pageBox->y1;
2379 px2 = pageBox->x2;
2380 py2 = pageBox->y2;
2381 kx = hDPI / 72.0;
2382 ky = vDPI / 72.0;
2383 if (rotate == 90) {
2384 ctm[0] = 0;
2385 ctm[1] = upsideDown ? ky : -ky;
2386 ctm[2] = kx;
2387 ctm[3] = 0;
2388 ctm[4] = -kx * py1;
2389 ctm[5] = ky * (upsideDown ? -px1 : px2);
2390 pageWidth = kx * (py2 - py1);
2391 pageHeight = ky * (px2 - px1);
2392 } else if (rotate == 180) {
2393 ctm[0] = -kx;
2394 ctm[1] = 0;
2395 ctm[2] = 0;
2396 ctm[3] = upsideDown ? ky : -ky;
2397 ctm[4] = kx * px2;
2398 ctm[5] = ky * (upsideDown ? -py1 : py2);
2399 pageWidth = kx * (px2 - px1);
2400 pageHeight = ky * (py2 - py1);
2401 } else if (rotate == 270) {
2402 ctm[0] = 0;
2403 ctm[1] = upsideDown ? -ky : ky;
2404 ctm[2] = -kx;
2405 ctm[3] = 0;
2406 ctm[4] = kx * py2;
2407 ctm[5] = ky * (upsideDown ? px2 : -px1);
2408 pageWidth = kx * (py2 - py1);
2409 pageHeight = ky * (px2 - px1);
2410 } else {
2411 ctm[0] = kx;
2412 ctm[1] = 0;
2413 ctm[2] = 0;
2414 ctm[3] = upsideDown ? -ky : ky;
2415 ctm[4] = -kx * px1;
2416 ctm[5] = ky * (upsideDown ? py2 : -py1);
2417 pageWidth = kx * (px2 - px1);
2418 pageHeight = ky * (py2 - py1);
2421 fillColorSpace = new GfxDeviceGrayColorSpace();
2422 strokeColorSpace = new GfxDeviceGrayColorSpace();
2423 fillColor.c[0] = 0;
2424 strokeColor.c[0] = 0;
2425 fillPattern = NULL;
2426 strokePattern = NULL;
2427 fillOpacity = 1;
2428 strokeOpacity = 1;
2430 lineWidth = 1;
2431 lineDash = NULL;
2432 lineDashLength = 0;
2433 lineDashStart = 0;
2434 flatness = 1;
2435 lineJoin = 0;
2436 lineCap = 0;
2437 miterLimit = 10;
2439 font = NULL;
2440 fontSize = 0;
2441 textMat[0] = 1; textMat[1] = 0;
2442 textMat[2] = 0; textMat[3] = 1;
2443 textMat[4] = 0; textMat[5] = 0;
2444 charSpace = 0;
2445 wordSpace = 0;
2446 horizScaling = 1;
2447 leading = 0;
2448 rise = 0;
2449 render = 0;
2451 path = new GfxPath();
2452 curX = curY = 0;
2453 lineX = lineY = 0;
2455 clipXMin = 0;
2456 clipYMin = 0;
2457 clipXMax = pageWidth;
2458 clipYMax = pageHeight;
2460 saved = NULL;
2463 GfxState::~GfxState() {
2464 if (fillColorSpace) {
2465 delete fillColorSpace;
2467 if (strokeColorSpace) {
2468 delete strokeColorSpace;
2470 if (fillPattern) {
2471 delete fillPattern;
2473 if (strokePattern) {
2474 delete strokePattern;
2476 gfree(lineDash);
2477 if (path) {
2478 // this gets set to NULL by restore()
2479 delete path;
2481 if (saved) {
2482 delete saved;
2486 // Used for copy();
2487 GfxState::GfxState(GfxState *state) {
2488 memcpy(this, state, sizeof(GfxState));
2489 if (fillColorSpace) {
2490 fillColorSpace = state->fillColorSpace->copy();
2492 if (strokeColorSpace) {
2493 strokeColorSpace = state->strokeColorSpace->copy();
2495 if (fillPattern) {
2496 fillPattern = state->fillPattern->copy();
2498 if (strokePattern) {
2499 strokePattern = state->strokePattern->copy();
2501 if (lineDashLength > 0) {
2502 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2503 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2505 saved = NULL;
2508 void GfxState::setPath(GfxPath *pathA) {
2509 delete path;
2510 path = pathA;
2513 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2514 double *xMax, double *yMax) {
2515 double ictm[6];
2516 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2518 // invert the CTM
2519 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2520 ictm[0] = ctm[3] * det;
2521 ictm[1] = -ctm[1] * det;
2522 ictm[2] = -ctm[2] * det;
2523 ictm[3] = ctm[0] * det;
2524 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2525 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2527 // transform all four corners of the clip bbox; find the min and max
2528 // x and y values
2529 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2530 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2531 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2532 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2533 if (tx < xMin1) {
2534 xMin1 = tx;
2535 } else if (tx > xMax1) {
2536 xMax1 = tx;
2538 if (ty < yMin1) {
2539 yMin1 = ty;
2540 } else if (ty > yMax1) {
2541 yMax1 = ty;
2543 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2544 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2545 if (tx < xMin1) {
2546 xMin1 = tx;
2547 } else if (tx > xMax1) {
2548 xMax1 = tx;
2550 if (ty < yMin1) {
2551 yMin1 = ty;
2552 } else if (ty > yMax1) {
2553 yMax1 = ty;
2555 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2556 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2557 if (tx < xMin1) {
2558 xMin1 = tx;
2559 } else if (tx > xMax1) {
2560 xMax1 = tx;
2562 if (ty < yMin1) {
2563 yMin1 = ty;
2564 } else if (ty > yMax1) {
2565 yMax1 = ty;
2568 *xMin = xMin1;
2569 *yMin = yMin1;
2570 *xMax = xMax1;
2571 *yMax = yMax1;
2574 double GfxState::transformWidth(double w) {
2575 double x, y;
2577 x = ctm[0] + ctm[2];
2578 y = ctm[1] + ctm[3];
2579 return w * sqrt(0.5 * (x * x + y * y));
2582 double GfxState::getTransformedFontSize() {
2583 double x1, y1, x2, y2;
2585 x1 = textMat[2] * fontSize;
2586 y1 = textMat[3] * fontSize;
2587 x2 = ctm[0] * x1 + ctm[2] * y1;
2588 y2 = ctm[1] * x1 + ctm[3] * y1;
2589 return sqrt(x2 * x2 + y2 * y2);
2592 void GfxState::getFontTransMat(double *m11, double *m12,
2593 double *m21, double *m22) {
2594 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2595 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2596 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2597 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2600 void GfxState::setCTM(double a, double b, double c,
2601 double d, double e, double f) {
2602 int i;
2604 ctm[0] = a;
2605 ctm[1] = b;
2606 ctm[2] = c;
2607 ctm[3] = d;
2608 ctm[4] = e;
2609 ctm[5] = f;
2611 // avoid FP exceptions on badly messed up PDF files
2612 for (i = 0; i < 6; ++i) {
2613 if (ctm[i] > 1e10) {
2614 ctm[i] = 1e10;
2615 } else if (ctm[i] < -1e10) {
2616 ctm[i] = -1e10;
2621 void GfxState::concatCTM(double a, double b, double c,
2622 double d, double e, double f) {
2623 double a1 = ctm[0];
2624 double b1 = ctm[1];
2625 double c1 = ctm[2];
2626 double d1 = ctm[3];
2627 int i;
2629 ctm[0] = a * a1 + b * c1;
2630 ctm[1] = a * b1 + b * d1;
2631 ctm[2] = c * a1 + d * c1;
2632 ctm[3] = c * b1 + d * d1;
2633 ctm[4] = e * a1 + f * c1 + ctm[4];
2634 ctm[5] = e * b1 + f * d1 + ctm[5];
2636 // avoid FP exceptions on badly messed up PDF files
2637 for (i = 0; i < 6; ++i) {
2638 if (ctm[i] > 1e10) {
2639 ctm[i] = 1e10;
2640 } else if (ctm[i] < -1e10) {
2641 ctm[i] = -1e10;
2646 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2647 if (fillColorSpace) {
2648 delete fillColorSpace;
2650 fillColorSpace = colorSpace;
2653 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2654 if (strokeColorSpace) {
2655 delete strokeColorSpace;
2657 strokeColorSpace = colorSpace;
2660 void GfxState::setFillPattern(GfxPattern *pattern) {
2661 if (fillPattern) {
2662 delete fillPattern;
2664 fillPattern = pattern;
2667 void GfxState::setStrokePattern(GfxPattern *pattern) {
2668 if (strokePattern) {
2669 delete strokePattern;
2671 strokePattern = pattern;
2674 void GfxState::setLineDash(double *dash, int length, double start) {
2675 if (lineDash)
2676 gfree(lineDash);
2677 lineDash = dash;
2678 lineDashLength = length;
2679 lineDashStart = start;
2682 void GfxState::clearPath() {
2683 delete path;
2684 path = new GfxPath();
2687 void GfxState::clip() {
2688 double xMin, yMin, xMax, yMax, x, y;
2689 GfxSubpath *subpath;
2690 int i, j;
2692 xMin = xMax = yMin = yMax = 0; // make gcc happy
2693 for (i = 0; i < path->getNumSubpaths(); ++i) {
2694 subpath = path->getSubpath(i);
2695 for (j = 0; j < subpath->getNumPoints(); ++j) {
2696 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2697 if (i == 0 && j == 0) {
2698 xMin = xMax = x;
2699 yMin = yMax = y;
2700 } else {
2701 if (x < xMin) {
2702 xMin = x;
2703 } else if (x > xMax) {
2704 xMax = x;
2706 if (y < yMin) {
2707 yMin = y;
2708 } else if (y > yMax) {
2709 yMax = y;
2714 if (xMin > clipXMin) {
2715 clipXMin = xMin;
2717 if (yMin > clipYMin) {
2718 clipYMin = yMin;
2720 if (xMax < clipXMax) {
2721 clipXMax = xMax;
2723 if (yMax < clipYMax) {
2724 clipYMax = yMax;
2728 void GfxState::textShift(double tx, double ty) {
2729 double dx, dy;
2731 textTransformDelta(tx, ty, &dx, &dy);
2732 curX += dx;
2733 curY += dy;
2736 void GfxState::shift(double dx, double dy) {
2737 curX += dx;
2738 curY += dy;
2741 GfxState *GfxState::save() {
2742 GfxState *newState;
2744 newState = copy();
2745 newState->saved = this;
2746 return newState;
2749 GfxState *GfxState::restore() {
2750 GfxState *oldState;
2752 if (saved) {
2753 oldState = saved;
2755 // these attributes aren't saved/restored by the q/Q operators
2756 oldState->path = path;
2757 oldState->curX = curX;
2758 oldState->curY = curY;
2759 oldState->lineX = lineX;
2760 oldState->lineY = lineY;
2762 path = NULL;
2763 saved = NULL;
2764 delete this;
2766 } else {
2767 oldState = this;
2770 return oldState;