fixed windows access violation which occurs if one tries to retrieve
[swftools.git] / pdf2swf / xpdf / GfxState.cc
blobd65bbbabd7799131b5bd9b2ccc720fd260710761
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996-2002 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
13 #include <aconf.h>
14 #include <stddef.h>
15 #include <math.h>
16 #include <string.h> // for memcpy()
17 #include "gmem.h"
18 #include "Error.h"
19 #include "Object.h"
20 #include "Array.h"
21 #include "Page.h"
22 #include "GfxState.h"
24 //------------------------------------------------------------------------
26 static inline double clip01(double x) {
27 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
30 //------------------------------------------------------------------------
31 // GfxColorSpace
32 //------------------------------------------------------------------------
34 GfxColorSpace::GfxColorSpace() {
37 GfxColorSpace::~GfxColorSpace() {
40 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
41 GfxColorSpace *cs;
42 Object obj1;
44 cs = NULL;
45 if (csObj->isName()) {
46 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
47 cs = new GfxDeviceGrayColorSpace();
48 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
49 cs = new GfxDeviceRGBColorSpace();
50 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
51 cs = new GfxDeviceCMYKColorSpace();
52 } else if (csObj->isName("Pattern")) {
53 cs = new GfxPatternColorSpace(NULL);
54 } else {
55 error(-1, "Bad color space '%s'", csObj->getName());
57 } else if (csObj->isArray()) {
58 csObj->arrayGet(0, &obj1);
59 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
60 cs = new GfxDeviceGrayColorSpace();
61 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
62 cs = new GfxDeviceRGBColorSpace();
63 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
64 cs = new GfxDeviceCMYKColorSpace();
65 } else if (obj1.isName("CalGray")) {
66 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
67 } else if (obj1.isName("CalRGB")) {
68 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
69 } else if (obj1.isName("Lab")) {
70 cs = GfxLabColorSpace::parse(csObj->getArray());
71 } else if (obj1.isName("ICCBased")) {
72 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
73 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
74 cs = GfxIndexedColorSpace::parse(csObj->getArray());
75 } else if (obj1.isName("Separation")) {
76 cs = GfxSeparationColorSpace::parse(csObj->getArray());
77 } else if (obj1.isName("DeviceN")) {
78 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
79 } else if (obj1.isName("Pattern")) {
80 cs = GfxPatternColorSpace::parse(csObj->getArray());
81 } else {
82 error(-1, "Bad color space '%s'", csObj->getName());
84 obj1.free();
85 } else {
86 error(-1, "Bad color space - expected name or array");
88 return cs;
91 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
92 int maxImgPixel) {
93 int i;
95 for (i = 0; i < getNComps(); ++i) {
96 decodeLow[i] = 0;
97 decodeRange[i] = 1;
101 //------------------------------------------------------------------------
102 // GfxDeviceGrayColorSpace
103 //------------------------------------------------------------------------
105 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
108 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
111 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
115 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
116 *gray = clip01(color->c[0]);
119 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
120 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
123 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
124 cmyk->c = cmyk->m = cmyk->y = 0;
125 cmyk->k = clip01(1 - color->c[0]);
128 //------------------------------------------------------------------------
129 // GfxCalGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX = whiteY = whiteZ = 1;
134 blackX = blackY = blackZ = 0;
135 gamma = 1;
138 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
141 GfxColorSpace *GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace *cs;
144 cs = new GfxCalGrayColorSpace();
145 cs->whiteX = whiteX;
146 cs->whiteY = whiteY;
147 cs->whiteZ = whiteZ;
148 cs->blackX = blackX;
149 cs->blackY = blackY;
150 cs->blackZ = blackZ;
151 cs->gamma = gamma;
152 return cs;
155 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
156 GfxCalGrayColorSpace *cs;
157 Object obj1, obj2, obj3;
159 arr->get(1, &obj1);
160 if (!obj1.isDict()) {
161 error(-1, "Bad CalGray color space");
162 obj1.free();
163 return NULL;
165 cs = new GfxCalGrayColorSpace();
166 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
167 obj2.arrayGetLength() == 3) {
168 obj2.arrayGet(0, &obj3);
169 cs->whiteX = obj3.getNum();
170 obj3.free();
171 obj2.arrayGet(1, &obj3);
172 cs->whiteY = obj3.getNum();
173 obj3.free();
174 obj2.arrayGet(2, &obj3);
175 cs->whiteZ = obj3.getNum();
176 obj3.free();
178 obj2.free();
179 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
180 obj2.arrayGetLength() == 3) {
181 obj2.arrayGet(0, &obj3);
182 cs->blackX = obj3.getNum();
183 obj3.free();
184 obj2.arrayGet(1, &obj3);
185 cs->blackY = obj3.getNum();
186 obj3.free();
187 obj2.arrayGet(2, &obj3);
188 cs->blackZ = obj3.getNum();
189 obj3.free();
191 obj2.free();
192 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
193 cs->gamma = obj2.getNum();
195 obj2.free();
196 obj1.free();
197 return cs;
200 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
201 *gray = clip01(color->c[0]);
204 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
205 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
208 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
209 cmyk->c = cmyk->m = cmyk->y = 0;
210 cmyk->k = clip01(1 - color->c[0]);
213 //------------------------------------------------------------------------
214 // GfxDeviceRGBColorSpace
215 //------------------------------------------------------------------------
217 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
220 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
223 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
227 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
228 *gray = clip01(0.299 * color->c[0] +
229 0.587 * color->c[1] +
230 0.114 * color->c[2]);
233 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
234 rgb->r = clip01(color->c[0]);
235 rgb->g = clip01(color->c[1]);
236 rgb->b = clip01(color->c[2]);
239 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
240 double c, m, y, k;
242 c = clip01(1 - color->c[0]);
243 m = clip01(1 - color->c[1]);
244 y = clip01(1 - color->c[2]);
245 k = c;
246 if (m < k) {
247 k = m;
249 if (y < k) {
250 k = y;
252 cmyk->c = c - k;
253 cmyk->m = m - k;
254 cmyk->y = y - k;
255 cmyk->k = k;
258 //------------------------------------------------------------------------
259 // GfxCalRGBColorSpace
260 //------------------------------------------------------------------------
262 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
263 whiteX = whiteY = whiteZ = 1;
264 blackX = blackY = blackZ = 0;
265 gammaR = gammaG = gammaB = 1;
266 mat[0] = 1; mat[1] = 0; mat[2] = 0;
267 mat[3] = 0; mat[4] = 1; mat[5] = 0;
268 mat[6] = 0; mat[7] = 0; mat[8] = 1;
271 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
274 GfxColorSpace *GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace *cs;
276 int i;
278 cs = new GfxCalRGBColorSpace();
279 cs->whiteX = whiteX;
280 cs->whiteY = whiteY;
281 cs->whiteZ = whiteZ;
282 cs->blackX = blackX;
283 cs->blackY = blackY;
284 cs->blackZ = blackZ;
285 cs->gammaR = gammaR;
286 cs->gammaG = gammaG;
287 cs->gammaB = gammaB;
288 for (i = 0; i < 9; ++i) {
289 cs->mat[i] = mat[i];
291 return cs;
294 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
295 GfxCalRGBColorSpace *cs;
296 Object obj1, obj2, obj3;
297 int i;
299 arr->get(1, &obj1);
300 if (!obj1.isDict()) {
301 error(-1, "Bad CalRGB color space");
302 obj1.free();
303 return NULL;
305 cs = new GfxCalRGBColorSpace();
306 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
307 obj2.arrayGetLength() == 3) {
308 obj2.arrayGet(0, &obj3);
309 cs->whiteX = obj3.getNum();
310 obj3.free();
311 obj2.arrayGet(1, &obj3);
312 cs->whiteY = obj3.getNum();
313 obj3.free();
314 obj2.arrayGet(2, &obj3);
315 cs->whiteZ = obj3.getNum();
316 obj3.free();
318 obj2.free();
319 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
320 obj2.arrayGetLength() == 3) {
321 obj2.arrayGet(0, &obj3);
322 cs->blackX = obj3.getNum();
323 obj3.free();
324 obj2.arrayGet(1, &obj3);
325 cs->blackY = obj3.getNum();
326 obj3.free();
327 obj2.arrayGet(2, &obj3);
328 cs->blackZ = obj3.getNum();
329 obj3.free();
331 obj2.free();
332 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
333 obj2.arrayGetLength() == 3) {
334 obj2.arrayGet(0, &obj3);
335 cs->gammaR = obj3.getNum();
336 obj3.free();
337 obj2.arrayGet(1, &obj3);
338 cs->gammaG = obj3.getNum();
339 obj3.free();
340 obj2.arrayGet(2, &obj3);
341 cs->gammaB = obj3.getNum();
342 obj3.free();
344 obj2.free();
345 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
346 obj2.arrayGetLength() == 9) {
347 for (i = 0; i < 9; ++i) {
348 obj2.arrayGet(i, &obj3);
349 cs->mat[i] = obj3.getNum();
350 obj3.free();
353 obj2.free();
354 obj1.free();
355 return cs;
358 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
359 *gray = clip01(0.299 * color->c[0] +
360 0.587 * color->c[1] +
361 0.114 * color->c[2]);
364 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
365 rgb->r = clip01(color->c[0]);
366 rgb->g = clip01(color->c[1]);
367 rgb->b = clip01(color->c[2]);
370 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
371 double c, m, y, k;
373 c = clip01(1 - color->c[0]);
374 m = clip01(1 - color->c[1]);
375 y = clip01(1 - color->c[2]);
376 k = c;
377 if (m < k) {
378 k = m;
380 if (y < k) {
381 k = y;
383 cmyk->c = c - k;
384 cmyk->m = m - k;
385 cmyk->y = y - k;
386 cmyk->k = k;
389 //------------------------------------------------------------------------
390 // GfxDeviceCMYKColorSpace
391 //------------------------------------------------------------------------
393 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
396 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
399 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
403 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
404 *gray = clip01(1 - color->c[3]
405 - 0.299 * color->c[0]
406 - 0.587 * color->c[1]
407 - 0.114 * color->c[2]);
410 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
411 double c, m, y, aw, ac, am, ay, ar, ag, ab;
413 c = clip01(color->c[0] + color->c[3]);
414 m = clip01(color->c[1] + color->c[3]);
415 y = clip01(color->c[2] + color->c[3]);
416 aw = (1-c) * (1-m) * (1-y);
417 ac = c * (1-m) * (1-y);
418 am = (1-c) * m * (1-y);
419 ay = (1-c) * (1-m) * y;
420 ar = (1-c) * m * y;
421 ag = c * (1-m) * y;
422 ab = c * m * (1-y);
423 rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
424 rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
425 rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
426 0.4863*ab);
429 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
430 cmyk->c = clip01(color->c[0]);
431 cmyk->m = clip01(color->c[1]);
432 cmyk->y = clip01(color->c[2]);
433 cmyk->k = clip01(color->c[3]);
436 //------------------------------------------------------------------------
437 // GfxLabColorSpace
438 //------------------------------------------------------------------------
440 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
441 // Language Reference, Third Edition.
442 static double xyzrgb[3][3] = {
443 { 3.240449, -1.537136, -0.498531 },
444 { -0.969265, 1.876011, 0.041556 },
445 { 0.055643, -0.204026, 1.057229 }
448 GfxLabColorSpace::GfxLabColorSpace() {
449 whiteX = whiteY = whiteZ = 1;
450 blackX = blackY = blackZ = 0;
451 aMin = bMin = -100;
452 aMax = bMax = 100;
455 GfxLabColorSpace::~GfxLabColorSpace() {
458 GfxColorSpace *GfxLabColorSpace::copy() {
459 GfxLabColorSpace *cs;
461 cs = new GfxLabColorSpace();
462 cs->whiteX = whiteX;
463 cs->whiteY = whiteY;
464 cs->whiteZ = whiteZ;
465 cs->blackX = blackX;
466 cs->blackY = blackY;
467 cs->blackZ = blackZ;
468 cs->aMin = aMin;
469 cs->aMax = aMax;
470 cs->bMin = bMin;
471 cs->bMax = bMax;
472 cs->kr = kr;
473 cs->kg = kg;
474 cs->kb = kb;
475 return cs;
478 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
479 GfxLabColorSpace *cs;
480 Object obj1, obj2, obj3;
482 arr->get(1, &obj1);
483 if (!obj1.isDict()) {
484 error(-1, "Bad Lab color space");
485 obj1.free();
486 return NULL;
488 cs = new GfxLabColorSpace();
489 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
490 obj2.arrayGetLength() == 3) {
491 obj2.arrayGet(0, &obj3);
492 cs->whiteX = obj3.getNum();
493 obj3.free();
494 obj2.arrayGet(1, &obj3);
495 cs->whiteY = obj3.getNum();
496 obj3.free();
497 obj2.arrayGet(2, &obj3);
498 cs->whiteZ = obj3.getNum();
499 obj3.free();
501 obj2.free();
502 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
503 obj2.arrayGetLength() == 3) {
504 obj2.arrayGet(0, &obj3);
505 cs->blackX = obj3.getNum();
506 obj3.free();
507 obj2.arrayGet(1, &obj3);
508 cs->blackY = obj3.getNum();
509 obj3.free();
510 obj2.arrayGet(2, &obj3);
511 cs->blackZ = obj3.getNum();
512 obj3.free();
514 obj2.free();
515 if (obj1.dictLookup("Range", &obj2)->isArray() &&
516 obj2.arrayGetLength() == 4) {
517 obj2.arrayGet(0, &obj3);
518 cs->aMin = obj3.getNum();
519 obj3.free();
520 obj2.arrayGet(1, &obj3);
521 cs->aMax = obj3.getNum();
522 obj3.free();
523 obj2.arrayGet(2, &obj3);
524 cs->bMin = obj3.getNum();
525 obj3.free();
526 obj2.arrayGet(3, &obj3);
527 cs->bMax = obj3.getNum();
528 obj3.free();
530 obj2.free();
531 obj1.free();
533 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
534 xyzrgb[0][1] * cs->whiteY +
535 xyzrgb[0][2] * cs->whiteZ);
536 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
537 xyzrgb[1][1] * cs->whiteY +
538 xyzrgb[1][2] * cs->whiteZ);
539 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
540 xyzrgb[2][1] * cs->whiteY +
541 xyzrgb[2][2] * cs->whiteZ);
543 return cs;
546 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
547 GfxRGB rgb;
549 getRGB(color, &rgb);
550 *gray = clip01(0.299 * rgb.r +
551 0.587 * rgb.g +
552 0.114 * rgb.b);
555 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
556 double X, Y, Z;
557 double t1, t2;
558 double r, g, b;
560 // convert L*a*b* to CIE 1931 XYZ color space
561 t1 = (color->c[0] + 16) / 116;
562 t2 = t1 + color->c[1] / 500;
563 if (t2 >= (6.0 / 29.0)) {
564 X = t2 * t2 * t2;
565 } else {
566 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
568 X *= whiteX;
569 if (t1 >= (6.0 / 29.0)) {
570 Y = t1 * t1 * t1;
571 } else {
572 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
574 Y *= whiteY;
575 t2 = t1 - color->c[2] / 200;
576 if (t2 >= (6.0 / 29.0)) {
577 Z = t2 * t2 * t2;
578 } else {
579 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
581 Z *= whiteZ;
583 // convert XYZ to RGB, including gamut mapping and gamma correction
584 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
585 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
586 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
587 rgb->r = pow(clip01(r * kr), 0.5);
588 rgb->g = pow(clip01(g * kg), 0.5);
589 rgb->b = pow(clip01(b * kb), 0.5);
592 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
593 GfxRGB rgb;
594 double c, m, y, k;
596 getRGB(color, &rgb);
597 c = clip01(1 - rgb.r);
598 m = clip01(1 - rgb.g);
599 y = clip01(1 - rgb.b);
600 k = c;
601 if (m < k) {
602 k = m;
604 if (y < k) {
605 k = y;
607 cmyk->c = c - k;
608 cmyk->m = m - k;
609 cmyk->y = y - k;
610 cmyk->k = k;
613 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
614 int maxImgPixel) {
615 decodeLow[0] = 0;
616 decodeRange[0] = 100;
617 decodeLow[1] = aMin;
618 decodeRange[1] = aMax - aMin;
619 decodeLow[2] = bMin;
620 decodeRange[2] = bMax - bMin;
623 //------------------------------------------------------------------------
624 // GfxICCBasedColorSpace
625 //------------------------------------------------------------------------
627 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
628 Ref *iccProfileStreamA) {
629 nComps = nCompsA;
630 alt = altA;
631 iccProfileStream = *iccProfileStreamA;
632 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
633 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
636 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
637 delete alt;
640 GfxColorSpace *GfxICCBasedColorSpace::copy() {
641 GfxICCBasedColorSpace *cs;
642 int i;
644 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
645 for (i = 0; i < 4; ++i) {
646 cs->rangeMin[i] = rangeMin[i];
647 cs->rangeMax[i] = rangeMax[i];
649 return cs;
652 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
653 GfxICCBasedColorSpace *cs;
654 Ref iccProfileStreamA;
655 int nCompsA;
656 GfxColorSpace *altA;
657 Dict *dict;
658 Object obj1, obj2, obj3;
659 int i;
661 arr->getNF(1, &obj1);
662 if (obj1.isRef()) {
663 iccProfileStreamA = obj1.getRef();
664 } else {
665 iccProfileStreamA.num = 0;
666 iccProfileStreamA.gen = 0;
668 obj1.free();
669 arr->get(1, &obj1);
670 if (!obj1.isStream()) {
671 error(-1, "Bad ICCBased color space (stream)");
672 obj1.free();
673 return NULL;
675 dict = obj1.streamGetDict();
676 if (!dict->lookup("N", &obj2)->isInt()) {
677 error(-1, "Bad ICCBased color space (N)");
678 obj2.free();
679 obj1.free();
680 return NULL;
682 nCompsA = obj2.getInt();
683 obj2.free();
684 if (dict->lookup("Alternate", &obj2)->isNull() ||
685 !(altA = GfxColorSpace::parse(&obj2))) {
686 switch (nCompsA) {
687 case 1:
688 altA = new GfxDeviceGrayColorSpace();
689 break;
690 case 3:
691 altA = new GfxDeviceRGBColorSpace();
692 break;
693 case 4:
694 altA = new GfxDeviceCMYKColorSpace();
695 break;
696 default:
697 error(-1, "Bad ICCBased color space - invalid N");
698 obj2.free();
699 obj1.free();
700 return NULL;
703 obj2.free();
704 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
705 if (dict->lookup("Range", &obj2)->isArray() &&
706 obj2.arrayGetLength() == 2 * nCompsA) {
707 for (i = 0; i < nCompsA; ++i) {
708 obj2.arrayGet(2*i, &obj3);
709 cs->rangeMin[i] = obj3.getNum();
710 obj3.free();
711 obj2.arrayGet(2*i+1, &obj3);
712 cs->rangeMax[i] = obj3.getNum();
713 obj3.free();
716 obj2.free();
717 obj1.free();
718 return cs;
721 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
722 alt->getGray(color, gray);
725 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
726 alt->getRGB(color, rgb);
729 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
730 alt->getCMYK(color, cmyk);
733 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
734 double *decodeRange,
735 int maxImgPixel) {
736 int i;
738 for (i = 0; i < nComps; ++i) {
739 decodeLow[i] = rangeMin[i];
740 decodeRange[i] = rangeMax[i] - rangeMin[i];
744 //------------------------------------------------------------------------
745 // GfxIndexedColorSpace
746 //------------------------------------------------------------------------
748 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
749 int indexHighA) {
750 base = baseA;
751 indexHigh = indexHighA;
752 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
753 sizeof(Guchar));
756 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
757 delete base;
758 gfree(lookup);
761 GfxColorSpace *GfxIndexedColorSpace::copy() {
762 GfxIndexedColorSpace *cs;
764 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
765 memcpy(cs->lookup, lookup,
766 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
767 return cs;
770 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
771 GfxIndexedColorSpace *cs;
772 GfxColorSpace *baseA;
773 int indexHighA;
774 Object obj1;
775 int x;
776 char *s;
777 int n, i, j;
779 if (arr->getLength() != 4) {
780 error(-1, "Bad Indexed color space");
781 goto err1;
783 arr->get(1, &obj1);
784 if (!(baseA = GfxColorSpace::parse(&obj1))) {
785 error(-1, "Bad Indexed color space (base color space)");
786 goto err2;
788 obj1.free();
789 if (!arr->get(2, &obj1)->isInt()) {
790 error(-1, "Bad Indexed color space (hival)");
791 goto err2;
793 indexHighA = obj1.getInt();
794 obj1.free();
795 cs = new GfxIndexedColorSpace(baseA, indexHighA);
796 arr->get(3, &obj1);
797 n = baseA->getNComps();
798 if (obj1.isStream()) {
799 obj1.streamReset();
800 for (i = 0; i <= indexHighA; ++i) {
801 for (j = 0; j < n; ++j) {
802 if ((x = obj1.streamGetChar()) == EOF) {
803 error(-1, "Bad Indexed color space (lookup table stream too short)");
804 goto err3;
806 cs->lookup[i*n + j] = (Guchar)x;
809 obj1.streamClose();
810 } else if (obj1.isString()) {
811 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
812 error(-1, "Bad Indexed color space (lookup table string too short)");
813 goto err3;
815 s = obj1.getString()->getCString();
816 for (i = 0; i <= indexHighA; ++i) {
817 for (j = 0; j < n; ++j) {
818 cs->lookup[i*n + j] = (Guchar)*s++;
821 } else {
822 error(-1, "Bad Indexed color space (lookup table)");
823 goto err3;
825 obj1.free();
826 return cs;
828 err3:
829 delete cs;
830 err2:
831 obj1.free();
832 err1:
833 return NULL;
836 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
837 Guchar *p;
838 GfxColor color2;
839 int n, i;
841 n = base->getNComps();
842 p = &lookup[(int)(color->c[0] + 0.5) * n];
843 for (i = 0; i < n; ++i) {
844 color2.c[i] = p[i] / 255.0;
846 base->getGray(&color2, gray);
849 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
850 Guchar *p;
851 GfxColor color2;
852 int n, i;
854 n = base->getNComps();
855 p = &lookup[(int)(color->c[0] + 0.5) * n];
856 for (i = 0; i < n; ++i) {
857 color2.c[i] = p[i] / 255.0;
859 base->getRGB(&color2, rgb);
862 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
863 Guchar *p;
864 GfxColor color2;
865 int n, i;
867 n = base->getNComps();
868 p = &lookup[(int)(color->c[0] + 0.5) * n];
869 for (i = 0; i < n; ++i) {
870 color2.c[i] = p[i] / 255.0;
872 base->getCMYK(&color2, cmyk);
875 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
876 double *decodeRange,
877 int maxImgPixel) {
878 decodeLow[0] = 0;
879 decodeRange[0] = maxImgPixel;
882 //------------------------------------------------------------------------
883 // GfxSeparationColorSpace
884 //------------------------------------------------------------------------
886 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
887 GfxColorSpace *altA,
888 Function *funcA) {
889 name = nameA;
890 alt = altA;
891 func = funcA;
894 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
895 delete name;
896 delete alt;
897 delete func;
900 GfxColorSpace *GfxSeparationColorSpace::copy() {
901 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
904 //~ handle the 'All' and 'None' colorants
905 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
906 GfxSeparationColorSpace *cs;
907 GString *nameA;
908 GfxColorSpace *altA;
909 Function *funcA;
910 Object obj1;
912 if (arr->getLength() != 4) {
913 error(-1, "Bad Separation color space");
914 goto err1;
916 if (!arr->get(1, &obj1)->isName()) {
917 error(-1, "Bad Separation color space (name)");
918 goto err2;
920 nameA = new GString(obj1.getName());
921 obj1.free();
922 arr->get(2, &obj1);
923 if (!(altA = GfxColorSpace::parse(&obj1))) {
924 error(-1, "Bad Separation color space (alternate color space)");
925 goto err3;
927 obj1.free();
928 arr->get(3, &obj1);
929 if (!(funcA = Function::parse(&obj1))) {
930 goto err4;
932 obj1.free();
933 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
934 return cs;
936 err4:
937 delete altA;
938 err3:
939 delete nameA;
940 err2:
941 obj1.free();
942 err1:
943 return NULL;
946 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
947 GfxColor color2;
949 func->transform(color->c, color2.c);
950 alt->getGray(&color2, gray);
953 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
954 GfxColor color2;
956 func->transform(color->c, color2.c);
957 alt->getRGB(&color2, rgb);
960 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
961 GfxColor color2;
963 func->transform(color->c, color2.c);
964 alt->getCMYK(&color2, cmyk);
967 //------------------------------------------------------------------------
968 // GfxDeviceNColorSpace
969 //------------------------------------------------------------------------
971 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
972 GfxColorSpace *altA,
973 Function *funcA) {
974 nComps = nCompsA;
975 alt = altA;
976 func = funcA;
979 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
980 int i;
982 for (i = 0; i < nComps; ++i) {
983 delete names[i];
985 delete alt;
986 delete func;
989 GfxColorSpace *GfxDeviceNColorSpace::copy() {
990 GfxDeviceNColorSpace *cs;
991 int i;
993 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
994 for (i = 0; i < nComps; ++i) {
995 cs->names[i] = names[i]->copy();
997 return cs;
1000 //~ handle the 'None' colorant
1001 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1002 GfxDeviceNColorSpace *cs;
1003 int nCompsA;
1004 GString *namesA[gfxColorMaxComps];
1005 GfxColorSpace *altA;
1006 Function *funcA;
1007 Object obj1, obj2;
1008 int i;
1010 if (arr->getLength() != 4 && arr->getLength() != 5) {
1011 error(-1, "Bad DeviceN color space");
1012 goto err1;
1014 if (!arr->get(1, &obj1)->isArray()) {
1015 error(-1, "Bad DeviceN color space (names)");
1016 goto err2;
1018 nCompsA = obj1.arrayGetLength();
1019 for (i = 0; i < nCompsA; ++i) {
1020 if (!obj1.arrayGet(i, &obj2)->isName()) {
1021 error(-1, "Bad DeviceN color space (names)");
1022 obj2.free();
1023 goto err2;
1025 namesA[i] = new GString(obj2.getName());
1026 obj2.free();
1028 obj1.free();
1029 arr->get(2, &obj1);
1030 if (!(altA = GfxColorSpace::parse(&obj1))) {
1031 error(-1, "Bad DeviceN color space (alternate color space)");
1032 goto err3;
1034 obj1.free();
1035 arr->get(3, &obj1);
1036 if (!(funcA = Function::parse(&obj1))) {
1037 goto err4;
1039 obj1.free();
1040 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1041 for (i = 0; i < nCompsA; ++i) {
1042 cs->names[i] = namesA[i];
1044 return cs;
1046 err4:
1047 delete altA;
1048 err3:
1049 for (i = 0; i < nCompsA; ++i) {
1050 delete namesA[i];
1052 err2:
1053 obj1.free();
1054 err1:
1055 return NULL;
1058 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1059 GfxColor color2;
1061 func->transform(color->c, color2.c);
1062 alt->getGray(&color2, gray);
1065 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1066 GfxColor color2;
1068 func->transform(color->c, color2.c);
1069 alt->getRGB(&color2, rgb);
1072 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1073 GfxColor color2;
1075 func->transform(color->c, color2.c);
1076 alt->getCMYK(&color2, cmyk);
1079 //------------------------------------------------------------------------
1080 // GfxPatternColorSpace
1081 //------------------------------------------------------------------------
1083 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1084 under = underA;
1087 GfxPatternColorSpace::~GfxPatternColorSpace() {
1088 if (under) {
1089 delete under;
1093 GfxColorSpace *GfxPatternColorSpace::copy() {
1094 return new GfxPatternColorSpace(under ? under->copy() :
1095 (GfxColorSpace *)NULL);
1098 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1099 GfxPatternColorSpace *cs;
1100 GfxColorSpace *underA;
1101 Object obj1;
1103 if (arr->getLength() != 1 && arr->getLength() != 2) {
1104 error(-1, "Bad Pattern color space");
1105 return NULL;
1107 underA = NULL;
1108 if (arr->getLength() == 2) {
1109 arr->get(1, &obj1);
1110 if (!(underA = GfxColorSpace::parse(&obj1))) {
1111 error(-1, "Bad Pattern color space (underlying color space)");
1112 obj1.free();
1113 return NULL;
1115 obj1.free();
1117 cs = new GfxPatternColorSpace(underA);
1118 return cs;
1121 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1122 *gray = 0;
1125 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1126 rgb->r = rgb->g = rgb->b = 0;
1129 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1130 cmyk->c = cmyk->m = cmyk->y = 0;
1131 cmyk->k = 1;
1134 //------------------------------------------------------------------------
1135 // Pattern
1136 //------------------------------------------------------------------------
1138 GfxPattern::GfxPattern(int typeA) {
1139 type = typeA;
1142 GfxPattern::~GfxPattern() {
1145 GfxPattern *GfxPattern::parse(Object *obj) {
1146 GfxPattern *pattern;
1147 Dict *dict;
1148 Object obj1;
1150 pattern = NULL;
1151 if (obj->isStream()) {
1152 dict = obj->streamGetDict();
1153 dict->lookup("PatternType", &obj1);
1154 if (obj1.isInt() && obj1.getInt() == 1) {
1155 pattern = new GfxTilingPattern(dict, obj);
1157 obj1.free();
1159 return pattern;
1162 //------------------------------------------------------------------------
1163 // GfxTilingPattern
1164 //------------------------------------------------------------------------
1166 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1167 GfxPattern(1)
1169 Object obj1, obj2;
1170 int i;
1172 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1173 paintType = obj1.getInt();
1174 } else {
1175 paintType = 1;
1176 error(-1, "Invalid or missing PaintType in pattern");
1178 obj1.free();
1179 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1180 tilingType = obj1.getInt();
1181 } else {
1182 tilingType = 1;
1183 error(-1, "Invalid or missing TilingType in pattern");
1185 obj1.free();
1186 bbox[0] = bbox[1] = 0;
1187 bbox[2] = bbox[3] = 1;
1188 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1189 obj1.arrayGetLength() == 4) {
1190 for (i = 0; i < 4; ++i) {
1191 if (obj1.arrayGet(i, &obj2)->isNum()) {
1192 bbox[i] = obj2.getNum();
1194 obj2.free();
1196 } else {
1197 error(-1, "Invalid or missing BBox in pattern");
1199 obj1.free();
1200 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1201 xStep = obj1.getNum();
1202 } else {
1203 xStep = 1;
1204 error(-1, "Invalid or missing XStep in pattern");
1206 obj1.free();
1207 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1208 yStep = obj1.getNum();
1209 } else {
1210 yStep = 1;
1211 error(-1, "Invalid or missing YStep in pattern");
1213 obj1.free();
1214 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1215 resDict.free();
1216 resDict.initNull();
1217 error(-1, "Invalid or missing Resources in pattern");
1219 matrix[0] = 1; matrix[1] = 0;
1220 matrix[2] = 0; matrix[3] = 1;
1221 matrix[4] = 0; matrix[5] = 0;
1222 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1223 obj1.arrayGetLength() == 6) {
1224 for (i = 0; i < 6; ++i) {
1225 if (obj1.arrayGet(i, &obj2)->isNum()) {
1226 matrix[i] = obj2.getNum();
1228 obj2.free();
1231 obj1.free();
1232 stream->copy(&contentStream);
1235 GfxTilingPattern::~GfxTilingPattern() {
1236 resDict.free();
1237 contentStream.free();
1240 GfxPattern *GfxTilingPattern::copy() {
1241 return new GfxTilingPattern(this);
1244 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1245 GfxPattern(1)
1247 memcpy(this, pat, sizeof(GfxTilingPattern));
1248 pat->resDict.copy(&resDict);
1249 pat->contentStream.copy(&contentStream);
1252 //------------------------------------------------------------------------
1253 // GfxShading
1254 //------------------------------------------------------------------------
1256 GfxShading::GfxShading() {
1259 GfxShading::~GfxShading() {
1260 delete colorSpace;
1263 GfxShading *GfxShading::parse(Object *obj) {
1264 GfxShading *shading;
1265 int typeA;
1266 GfxColorSpace *colorSpaceA;
1267 GfxColor backgroundA;
1268 GBool hasBackgroundA;
1269 double xMinA, yMinA, xMaxA, yMaxA;
1270 GBool hasBBoxA;
1271 Object obj1, obj2;
1272 int i;
1274 shading = NULL;
1275 if (obj->isDict()) {
1277 if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1278 error(-1, "Invalid ShadingType in shading dictionary");
1279 obj1.free();
1280 goto err1;
1282 typeA = obj1.getInt();
1283 obj1.free();
1285 obj->dictLookup("ColorSpace", &obj1);
1286 if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1287 error(-1, "Bad color space in shading dictionary");
1288 obj1.free();
1289 goto err1;
1291 obj1.free();
1293 for (i = 0; i < gfxColorMaxComps; ++i) {
1294 backgroundA.c[i] = 0;
1296 hasBackgroundA = gFalse;
1297 if (obj->dictLookup("Background", &obj1)->isArray()) {
1298 if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1299 hasBackgroundA = gTrue;
1300 for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1301 backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1302 obj2.free();
1304 } else {
1305 error(-1, "Bad Background in shading dictionary");
1308 obj1.free();
1310 xMinA = yMinA = xMaxA = yMaxA = 0;
1311 hasBBoxA = gFalse;
1312 if (obj->dictLookup("BBox", &obj1)->isArray()) {
1313 if (obj1.arrayGetLength() == 4) {
1314 hasBBoxA = gTrue;
1315 xMinA = obj1.arrayGet(0, &obj2)->getNum();
1316 obj2.free();
1317 yMinA = obj1.arrayGet(1, &obj2)->getNum();
1318 obj2.free();
1319 xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1320 obj2.free();
1321 yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1322 obj2.free();
1323 } else {
1324 error(-1, "Bad BBox in shading dictionary");
1327 obj1.free();
1329 switch (typeA) {
1330 case 2:
1331 shading = GfxAxialShading::parse(obj->getDict());
1332 break;
1333 case 3:
1334 shading = GfxRadialShading::parse(obj->getDict());
1335 break;
1336 default:
1337 error(-1, "Unimplemented shading type %d", typeA);
1338 goto err1;
1341 if (shading) {
1342 shading->type = typeA;
1343 shading->colorSpace = colorSpaceA;
1344 shading->background = backgroundA;
1345 shading->hasBackground = hasBackgroundA;
1346 shading->xMin = xMinA;
1347 shading->yMin = yMinA;
1348 shading->xMax = xMaxA;
1349 shading->yMax = yMaxA;
1350 shading->hasBBox = hasBBoxA;
1351 } else {
1352 delete colorSpaceA;
1356 return shading;
1358 err1:
1359 return NULL;
1362 //------------------------------------------------------------------------
1363 // GfxAxialShading
1364 //------------------------------------------------------------------------
1366 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1367 double x1A, double y1A,
1368 double t0A, double t1A,
1369 Function **funcsA, int nFuncsA,
1370 GBool extend0A, GBool extend1A) {
1371 int i;
1373 x0 = x0A;
1374 y0 = y0A;
1375 x1 = x1A;
1376 y1 = y1A;
1377 t0 = t0A;
1378 t1 = t1A;
1379 nFuncs = nFuncsA;
1380 for (i = 0; i < nFuncs; ++i) {
1381 funcs[i] = funcsA[i];
1383 extend0 = extend0A;
1384 extend1 = extend1A;
1387 GfxAxialShading::~GfxAxialShading() {
1388 int i;
1390 for (i = 0; i < nFuncs; ++i) {
1391 delete funcs[i];
1395 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1396 double x0A, y0A, x1A, y1A;
1397 double t0A, t1A;
1398 Function *funcsA[gfxColorMaxComps];
1399 int nFuncsA;
1400 GBool extend0A, extend1A;
1401 Object obj1, obj2;
1402 int i;
1404 x0A = y0A = x1A = y1A = 0;
1405 if (dict->lookup("Coords", &obj1)->isArray() &&
1406 obj1.arrayGetLength() == 4) {
1407 x0A = obj1.arrayGet(0, &obj2)->getNum();
1408 obj2.free();
1409 y0A = obj1.arrayGet(1, &obj2)->getNum();
1410 obj2.free();
1411 x1A = obj1.arrayGet(2, &obj2)->getNum();
1412 obj2.free();
1413 y1A = obj1.arrayGet(3, &obj2)->getNum();
1414 obj2.free();
1415 } else {
1416 error(-1, "Missing or invalid Coords in shading dictionary");
1417 goto err1;
1419 obj1.free();
1421 t0A = 0;
1422 t1A = 1;
1423 if (dict->lookup("Domain", &obj1)->isArray() &&
1424 obj1.arrayGetLength() == 2) {
1425 t0A = obj1.arrayGet(0, &obj2)->getNum();
1426 obj2.free();
1427 t1A = obj1.arrayGet(1, &obj2)->getNum();
1428 obj2.free();
1430 obj1.free();
1432 dict->lookup("Function", &obj1);
1433 if (obj1.isArray()) {
1434 nFuncsA = obj1.arrayGetLength();
1435 for (i = 0; i < nFuncsA; ++i) {
1436 obj1.arrayGet(i, &obj2);
1437 if (!(funcsA[i] = Function::parse(&obj2))) {
1438 obj1.free();
1439 obj2.free();
1440 goto err1;
1442 obj2.free();
1444 } else {
1445 nFuncsA = 1;
1446 if (!(funcsA[0] = Function::parse(&obj1))) {
1447 obj1.free();
1448 goto err1;
1451 obj1.free();
1453 extend0A = extend1A = gFalse;
1454 if (dict->lookup("Extend", &obj1)->isArray() &&
1455 obj1.arrayGetLength() == 2) {
1456 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1457 obj2.free();
1458 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1459 obj2.free();
1461 obj1.free();
1463 return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1464 funcsA, nFuncsA, extend0A, extend1A);
1466 err1:
1467 return NULL;
1470 void GfxAxialShading::getColor(double t, GfxColor *color) {
1471 int i;
1473 for (i = 0; i < nFuncs; ++i) {
1474 funcs[i]->transform(&t, &color->c[i]);
1478 //------------------------------------------------------------------------
1479 // GfxRadialShading
1480 //------------------------------------------------------------------------
1482 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1483 double x1A, double y1A, double r1A,
1484 double t0A, double t1A,
1485 Function **funcsA, int nFuncsA,
1486 GBool extend0A, GBool extend1A) {
1487 int i;
1489 x0 = x0A;
1490 y0 = y0A;
1491 r0 = r0A;
1492 x1 = x1A;
1493 y1 = y1A;
1494 r1 = r1A;
1495 t0 = t0A;
1496 t1 = t1A;
1497 nFuncs = nFuncsA;
1498 for (i = 0; i < nFuncs; ++i) {
1499 funcs[i] = funcsA[i];
1501 extend0 = extend0A;
1502 extend1 = extend1A;
1505 GfxRadialShading::~GfxRadialShading() {
1506 int i;
1508 for (i = 0; i < nFuncs; ++i) {
1509 delete funcs[i];
1513 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1514 double x0A, y0A, r0A, x1A, y1A, r1A;
1515 double t0A, t1A;
1516 Function *funcsA[gfxColorMaxComps];
1517 int nFuncsA;
1518 GBool extend0A, extend1A;
1519 Object obj1, obj2;
1520 int i;
1522 x0A = y0A = r0A = x1A = y1A = r1A = 0;
1523 if (dict->lookup("Coords", &obj1)->isArray() &&
1524 obj1.arrayGetLength() == 6) {
1525 x0A = obj1.arrayGet(0, &obj2)->getNum();
1526 obj2.free();
1527 y0A = obj1.arrayGet(1, &obj2)->getNum();
1528 obj2.free();
1529 r0A = obj1.arrayGet(2, &obj2)->getNum();
1530 obj2.free();
1531 x1A = obj1.arrayGet(3, &obj2)->getNum();
1532 obj2.free();
1533 y1A = obj1.arrayGet(4, &obj2)->getNum();
1534 obj2.free();
1535 r1A = obj1.arrayGet(5, &obj2)->getNum();
1536 obj2.free();
1537 } else {
1538 error(-1, "Missing or invalid Coords in shading dictionary");
1539 goto err1;
1541 obj1.free();
1543 t0A = 0;
1544 t1A = 1;
1545 if (dict->lookup("Domain", &obj1)->isArray() &&
1546 obj1.arrayGetLength() == 2) {
1547 t0A = obj1.arrayGet(0, &obj2)->getNum();
1548 obj2.free();
1549 t1A = obj1.arrayGet(1, &obj2)->getNum();
1550 obj2.free();
1552 obj1.free();
1554 dict->lookup("Function", &obj1);
1555 if (obj1.isArray()) {
1556 nFuncsA = obj1.arrayGetLength();
1557 for (i = 0; i < nFuncsA; ++i) {
1558 obj1.arrayGet(i, &obj2);
1559 if (!(funcsA[i] = Function::parse(&obj2))) {
1560 obj1.free();
1561 obj2.free();
1562 goto err1;
1564 obj2.free();
1566 } else {
1567 nFuncsA = 1;
1568 if (!(funcsA[0] = Function::parse(&obj1))) {
1569 obj1.free();
1570 goto err1;
1573 obj1.free();
1575 extend0A = extend1A = gFalse;
1576 if (dict->lookup("Extend", &obj1)->isArray() &&
1577 obj1.arrayGetLength() == 2) {
1578 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1579 obj2.free();
1580 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1581 obj2.free();
1583 obj1.free();
1585 return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1586 funcsA, nFuncsA, extend0A, extend1A);
1588 err1:
1589 return NULL;
1592 void GfxRadialShading::getColor(double t, GfxColor *color) {
1593 int i;
1595 for (i = 0; i < nFuncs; ++i) {
1596 funcs[i]->transform(&t, &color->c[i]);
1600 //------------------------------------------------------------------------
1601 // GfxImageColorMap
1602 //------------------------------------------------------------------------
1604 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1605 GfxColorSpace *colorSpaceA) {
1606 GfxIndexedColorSpace *indexedCS;
1607 GfxSeparationColorSpace *sepCS;
1608 int maxPixel, indexHigh;
1609 Guchar *lookup2;
1610 Function *sepFunc;
1611 Object obj;
1612 double x[gfxColorMaxComps];
1613 double y[gfxColorMaxComps];
1614 int i, j, k;
1615 int maxPixelForAlloc;
1617 ok = gTrue;
1619 // bits per component and color space
1620 bits = bitsA;
1621 maxPixel = (1 << bits) - 1;
1622 maxPixelForAlloc = (1 << (bits>8?bits:8));
1623 colorSpace = colorSpaceA;
1625 // get decode map
1626 if (decode->isNull()) {
1627 nComps = colorSpace->getNComps();
1628 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1629 } else if (decode->isArray()) {
1630 nComps = decode->arrayGetLength() / 2;
1631 if (nComps != colorSpace->getNComps()) {
1632 goto err1;
1634 for (i = 0; i < nComps; ++i) {
1635 decode->arrayGet(2*i, &obj);
1636 if (!obj.isNum()) {
1637 goto err2;
1639 decodeLow[i] = obj.getNum();
1640 obj.free();
1641 decode->arrayGet(2*i+1, &obj);
1642 if (!obj.isNum()) {
1643 goto err2;
1645 decodeRange[i] = obj.getNum() - decodeLow[i];
1646 obj.free();
1648 } else {
1649 goto err1;
1652 // Construct a lookup table -- this stores pre-computed decoded
1653 // values for each component, i.e., the result of applying the
1654 // decode mapping to each possible image pixel component value.
1656 // Optimization: for Indexed and Separation color spaces (which have
1657 // only one component), we store color values in the lookup table
1658 // rather than component values.
1659 colorSpace2 = NULL;
1660 nComps2 = 0;
1661 if (colorSpace->getMode() == csIndexed) {
1662 // Note that indexHigh may not be the same as maxPixel --
1663 // Distiller will remove unused palette entries, resulting in
1664 // indexHigh < maxPixel.
1665 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1666 colorSpace2 = indexedCS->getBase();
1667 indexHigh = indexedCS->getIndexHigh();
1668 nComps2 = colorSpace2->getNComps();
1669 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
1670 lookup2 = indexedCS->getLookup();
1671 for (i = 0; i <= indexHigh; ++i) {
1672 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1673 for (k = 0; k < nComps2; ++k) {
1674 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1677 } else if (colorSpace->getMode() == csSeparation) {
1678 sepCS = (GfxSeparationColorSpace *)colorSpace;
1679 colorSpace2 = sepCS->getAlt();
1680 nComps2 = colorSpace2->getNComps();
1681 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
1682 sepFunc = sepCS->getFunc();
1683 for (i = 0; i <= maxPixel; ++i) {
1684 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1685 sepFunc->transform(x, y);
1686 for (k = 0; k < nComps2; ++k) {
1687 lookup[i*nComps2 + k] = y[k];
1690 } else {
1691 lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
1692 for (i = 0; i <= maxPixel; ++i) {
1693 for (k = 0; k < nComps; ++k) {
1694 lookup[i*nComps + k] = decodeLow[k] +
1695 (i * decodeRange[k]) / maxPixel;
1700 return;
1702 err2:
1703 obj.free();
1704 err1:
1705 ok = gFalse;
1708 GfxImageColorMap::~GfxImageColorMap() {
1709 delete colorSpace;
1710 gfree(lookup);
1713 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
1714 GfxColor color;
1715 double *p;
1716 int i;
1718 if (colorSpace2) {
1719 p = &lookup[x[0] * nComps2];
1720 for (i = 0; i < nComps2; ++i) {
1721 color.c[i] = *p++;
1723 colorSpace2->getGray(&color, gray);
1724 } else {
1725 for (i = 0; i < nComps; ++i) {
1726 color.c[i] = lookup[x[i] * nComps + i];
1728 colorSpace->getGray(&color, gray);
1732 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1734 GfxColor color;
1735 double *p;
1736 int i;
1738 if (colorSpace2) {
1739 //printf("lookup[%d] bits=%d\n",x[0],bits);fflush(stdout);
1740 p = &lookup[x[0] * nComps2];
1741 for (i = 0; i < nComps2; ++i) {
1742 color.c[i] = *p++;
1744 colorSpace2->getRGB(&color, rgb);
1745 } else {
1746 //printf("for i=0,i<%d, bits=%d\n",nComps,bits);fflush(stdout);
1747 for (i = 0; i < nComps; ++i) {
1748 color.c[i] = lookup[x[i] * nComps + i];
1750 colorSpace->getRGB(&color, rgb);
1754 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1755 GfxColor color;
1756 double *p;
1757 int i;
1759 if (colorSpace2) {
1760 p = &lookup[x[0] * nComps2];
1761 for (i = 0; i < nComps2; ++i) {
1762 color.c[i] = *p++;
1764 colorSpace2->getCMYK(&color, cmyk);
1765 } else {
1766 for (i = 0; i < nComps; ++i) {
1767 color.c[i] = lookup[x[i] * nComps + i];
1769 colorSpace->getCMYK(&color, cmyk);
1773 //------------------------------------------------------------------------
1774 // GfxSubpath and GfxPath
1775 //------------------------------------------------------------------------
1777 GfxSubpath::GfxSubpath(double x1, double y1) {
1778 size = 16;
1779 x = (double *)gmalloc(size * sizeof(double));
1780 y = (double *)gmalloc(size * sizeof(double));
1781 curve = (GBool *)gmalloc(size * sizeof(GBool));
1782 n = 1;
1783 x[0] = x1;
1784 y[0] = y1;
1785 curve[0] = gFalse;
1786 closed = gFalse;
1789 GfxSubpath::~GfxSubpath() {
1790 gfree(x);
1791 gfree(y);
1792 gfree(curve);
1795 // Used for copy().
1796 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1797 size = subpath->size;
1798 n = subpath->n;
1799 x = (double *)gmalloc(size * sizeof(double));
1800 y = (double *)gmalloc(size * sizeof(double));
1801 curve = (GBool *)gmalloc(size * sizeof(GBool));
1802 memcpy(x, subpath->x, n * sizeof(double));
1803 memcpy(y, subpath->y, n * sizeof(double));
1804 memcpy(curve, subpath->curve, n * sizeof(GBool));
1805 closed = subpath->closed;
1808 void GfxSubpath::lineTo(double x1, double y1) {
1809 if (n >= size) {
1810 size += 16;
1811 x = (double *)grealloc(x, size * sizeof(double));
1812 y = (double *)grealloc(y, size * sizeof(double));
1813 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1815 x[n] = x1;
1816 y[n] = y1;
1817 curve[n] = gFalse;
1818 ++n;
1821 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
1822 double x3, double y3) {
1823 if (n+3 > size) {
1824 size += 16;
1825 x = (double *)grealloc(x, size * sizeof(double));
1826 y = (double *)grealloc(y, size * sizeof(double));
1827 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1829 x[n] = x1;
1830 y[n] = y1;
1831 x[n+1] = x2;
1832 y[n+1] = y2;
1833 x[n+2] = x3;
1834 y[n+2] = y3;
1835 curve[n] = curve[n+1] = gTrue;
1836 curve[n+2] = gFalse;
1837 n += 3;
1840 void GfxSubpath::close() {
1841 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1842 lineTo(x[0], y[0]);
1844 closed = gTrue;
1847 GfxPath::GfxPath() {
1848 justMoved = gFalse;
1849 size = 16;
1850 n = 0;
1851 firstX = firstY = 0;
1852 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1855 GfxPath::~GfxPath() {
1856 int i;
1858 for (i = 0; i < n; ++i)
1859 delete subpaths[i];
1860 gfree(subpaths);
1863 // Used for copy().
1864 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
1865 GfxSubpath **subpaths1, int n1, int size1) {
1866 int i;
1868 justMoved = justMoved1;
1869 firstX = firstX1;
1870 firstY = firstY1;
1871 size = size1;
1872 n = n1;
1873 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1874 for (i = 0; i < n; ++i)
1875 subpaths[i] = subpaths1[i]->copy();
1878 void GfxPath::moveTo(double x, double y) {
1879 justMoved = gTrue;
1880 firstX = x;
1881 firstY = y;
1884 void GfxPath::lineTo(double x, double y) {
1885 if (justMoved) {
1886 if (n >= size) {
1887 size += 16;
1888 subpaths = (GfxSubpath **)
1889 grealloc(subpaths, size * sizeof(GfxSubpath *));
1891 subpaths[n] = new GfxSubpath(firstX, firstY);
1892 ++n;
1893 justMoved = gFalse;
1895 subpaths[n-1]->lineTo(x, y);
1898 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
1899 double x3, double y3) {
1900 if (justMoved) {
1901 if (n >= size) {
1902 size += 16;
1903 subpaths = (GfxSubpath **)
1904 grealloc(subpaths, size * sizeof(GfxSubpath *));
1906 subpaths[n] = new GfxSubpath(firstX, firstY);
1907 ++n;
1908 justMoved = gFalse;
1910 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1913 void GfxPath::close() {
1914 // this is necessary to handle the pathological case of
1915 // moveto/closepath/clip, which defines an empty clipping region
1916 if (justMoved) {
1917 if (n >= size) {
1918 size += 16;
1919 subpaths = (GfxSubpath **)
1920 grealloc(subpaths, size * sizeof(GfxSubpath *));
1922 subpaths[n] = new GfxSubpath(firstX, firstY);
1923 ++n;
1924 justMoved = gFalse;
1926 subpaths[n-1]->close();
1929 //------------------------------------------------------------------------
1930 // GfxState
1931 //------------------------------------------------------------------------
1933 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
1934 GBool upsideDown) {
1935 double k;
1937 px1 = pageBox->x1;
1938 py1 = pageBox->y1;
1939 px2 = pageBox->x2;
1940 py2 = pageBox->y2;
1941 k = dpi / 72.0;
1942 if (rotate == 90) {
1943 ctm[0] = 0;
1944 ctm[1] = upsideDown ? k : -k;
1945 ctm[2] = k;
1946 ctm[3] = 0;
1947 ctm[4] = -k * py1;
1948 ctm[5] = k * (upsideDown ? -px1 : px2);
1949 pageWidth = k * (py2 - py1);
1950 pageHeight = k * (px2 - px1);
1951 } else if (rotate == 180) {
1952 ctm[0] = -k;
1953 ctm[1] = 0;
1954 ctm[2] = 0;
1955 ctm[3] = upsideDown ? k : -k;
1956 ctm[4] = k * px2;
1957 ctm[5] = k * (upsideDown ? -py1 : py2);
1958 pageWidth = k * (px2 - px1);
1959 pageHeight = k * (py2 - py1);
1960 } else if (rotate == 270) {
1961 ctm[0] = 0;
1962 ctm[1] = upsideDown ? -k : k;
1963 ctm[2] = -k;
1964 ctm[3] = 0;
1965 ctm[4] = k * py2;
1966 ctm[5] = k * (upsideDown ? px2 : -px1);
1967 pageWidth = k * (py2 - py1);
1968 pageHeight = k * (px2 - px1);
1969 } else {
1970 ctm[0] = k;
1971 ctm[1] = 0;
1972 ctm[2] = 0;
1973 ctm[3] = upsideDown ? -k : k;
1974 ctm[4] = -k * px1;
1975 ctm[5] = k * (upsideDown ? py2 : -py1);
1976 pageWidth = k * (px2 - px1);
1977 pageHeight = k * (py2 - py1);
1980 fillColorSpace = new GfxDeviceGrayColorSpace();
1981 strokeColorSpace = new GfxDeviceGrayColorSpace();
1982 fillColor.c[0] = 0;
1983 strokeColor.c[0] = 0;
1984 fillPattern = NULL;
1985 strokePattern = NULL;
1986 fillOpacity = 1;
1987 strokeOpacity = 1;
1989 lineWidth = 1;
1990 lineDash = NULL;
1991 lineDashLength = 0;
1992 lineDashStart = 0;
1993 flatness = 0;
1994 lineJoin = 0;
1995 lineCap = 0;
1996 miterLimit = 10;
1998 font = NULL;
1999 fontSize = 0;
2000 textMat[0] = 1; textMat[1] = 0;
2001 textMat[2] = 0; textMat[3] = 1;
2002 textMat[4] = 0; textMat[5] = 0;
2003 charSpace = 0;
2004 wordSpace = 0;
2005 horizScaling = 1;
2006 leading = 0;
2007 rise = 0;
2008 render = 0;
2010 path = new GfxPath();
2011 curX = curY = 0;
2012 lineX = lineY = 0;
2014 clipXMin = 0;
2015 clipYMin = 0;
2016 clipXMax = pageWidth;
2017 clipYMax = pageHeight;
2019 saved = NULL;
2022 GfxState::~GfxState() {
2023 if (fillColorSpace) {
2024 delete fillColorSpace;
2026 if (strokeColorSpace) {
2027 delete strokeColorSpace;
2029 if (fillPattern) {
2030 delete fillPattern;
2032 if (strokePattern) {
2033 delete strokePattern;
2035 gfree(lineDash);
2036 if (path) {
2037 // this gets set to NULL by restore()
2038 delete path;
2040 if (saved) {
2041 delete saved;
2045 // Used for copy();
2046 GfxState::GfxState(GfxState *state) {
2047 memcpy(this, state, sizeof(GfxState));
2048 if (fillColorSpace) {
2049 fillColorSpace = state->fillColorSpace->copy();
2051 if (strokeColorSpace) {
2052 strokeColorSpace = state->strokeColorSpace->copy();
2054 if (fillPattern) {
2055 fillPattern = state->fillPattern->copy();
2057 if (strokePattern) {
2058 strokePattern = state->strokePattern->copy();
2060 if (lineDashLength > 0) {
2061 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2062 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2064 saved = NULL;
2067 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2068 double *xMax, double *yMax) {
2069 double ictm[6];
2070 double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2072 // invert the CTM
2073 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2074 ictm[0] = ctm[3] * det;
2075 ictm[1] = -ctm[1] * det;
2076 ictm[2] = -ctm[2] * det;
2077 ictm[3] = ctm[0] * det;
2078 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2079 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2081 // transform all four corners of the clip bbox; find the min and max
2082 // x and y values
2083 xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2084 yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2085 tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2086 ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2087 if (tx < xMin1) {
2088 xMin1 = tx;
2089 } else if (tx > xMax1) {
2090 xMax1 = tx;
2092 if (ty < yMin1) {
2093 yMin1 = ty;
2094 } else if (ty > yMax1) {
2095 yMax1 = ty;
2097 tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2098 ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2099 if (tx < xMin1) {
2100 xMin1 = tx;
2101 } else if (tx > xMax1) {
2102 xMax1 = tx;
2104 if (ty < yMin1) {
2105 yMin1 = ty;
2106 } else if (ty > yMax1) {
2107 yMax1 = ty;
2109 tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2110 ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2111 if (tx < xMin1) {
2112 xMin1 = tx;
2113 } else if (tx > xMax1) {
2114 xMax1 = tx;
2116 if (ty < yMin1) {
2117 yMin1 = ty;
2118 } else if (ty > yMax1) {
2119 yMax1 = ty;
2122 *xMin = xMin1;
2123 *yMin = yMin1;
2124 *xMax = xMax1;
2125 *yMax = yMax1;
2128 double GfxState::transformWidth(double w) {
2129 double x, y;
2131 x = ctm[0] + ctm[2];
2132 y = ctm[1] + ctm[3];
2133 return w * sqrt(0.5 * (x * x + y * y));
2136 double GfxState::getTransformedFontSize() {
2137 double x1, y1, x2, y2;
2139 x1 = textMat[2] * fontSize;
2140 y1 = textMat[3] * fontSize;
2141 x2 = ctm[0] * x1 + ctm[2] * y1;
2142 y2 = ctm[1] * x1 + ctm[3] * y1;
2143 return sqrt(x2 * x2 + y2 * y2);
2146 void GfxState::getFontTransMat(double *m11, double *m12,
2147 double *m21, double *m22) {
2148 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2149 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2150 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2151 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2154 void GfxState::setCTM(double a, double b, double c,
2155 double d, double e, double f) {
2156 int i;
2158 ctm[0] = a;
2159 ctm[1] = b;
2160 ctm[2] = c;
2161 ctm[3] = d;
2162 ctm[4] = e;
2163 ctm[5] = f;
2165 // avoid FP exceptions on badly messed up PDF files
2166 for (i = 0; i < 6; ++i) {
2167 if (ctm[i] > 1e10) {
2168 ctm[i] = 1e10;
2169 } else if (ctm[i] < -1e10) {
2170 ctm[i] = -1e10;
2175 void GfxState::concatCTM(double a, double b, double c,
2176 double d, double e, double f) {
2177 double a1 = ctm[0];
2178 double b1 = ctm[1];
2179 double c1 = ctm[2];
2180 double d1 = ctm[3];
2181 int i;
2183 ctm[0] = a * a1 + b * c1;
2184 ctm[1] = a * b1 + b * d1;
2185 ctm[2] = c * a1 + d * c1;
2186 ctm[3] = c * b1 + d * d1;
2187 ctm[4] = e * a1 + f * c1 + ctm[4];
2188 ctm[5] = e * b1 + f * d1 + ctm[5];
2190 // avoid FP exceptions on badly messed up PDF files
2191 for (i = 0; i < 6; ++i) {
2192 if (ctm[i] > 1e10) {
2193 ctm[i] = 1e10;
2194 } else if (ctm[i] < -1e10) {
2195 ctm[i] = -1e10;
2200 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2201 if (fillColorSpace) {
2202 delete fillColorSpace;
2204 fillColorSpace = colorSpace;
2207 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2208 if (strokeColorSpace) {
2209 delete strokeColorSpace;
2211 strokeColorSpace = colorSpace;
2214 void GfxState::setFillPattern(GfxPattern *pattern) {
2215 if (fillPattern) {
2216 delete fillPattern;
2218 fillPattern = pattern;
2221 void GfxState::setStrokePattern(GfxPattern *pattern) {
2222 if (strokePattern) {
2223 delete strokePattern;
2225 strokePattern = pattern;
2228 void GfxState::setLineDash(double *dash, int length, double start) {
2229 if (lineDash)
2230 gfree(lineDash);
2231 lineDash = dash;
2232 lineDashLength = length;
2233 lineDashStart = start;
2236 void GfxState::clearPath() {
2237 delete path;
2238 path = new GfxPath();
2241 void GfxState::clip() {
2242 double xMin, yMin, xMax, yMax, x, y;
2243 GfxSubpath *subpath;
2244 int i, j;
2246 xMin = xMax = yMin = yMax = 0; // make gcc happy
2247 for (i = 0; i < path->getNumSubpaths(); ++i) {
2248 subpath = path->getSubpath(i);
2249 for (j = 0; j < subpath->getNumPoints(); ++j) {
2250 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2251 if (i == 0 && j == 0) {
2252 xMin = xMax = x;
2253 yMin = yMax = y;
2254 } else {
2255 if (x < xMin) {
2256 xMin = x;
2257 } else if (x > xMax) {
2258 xMax = x;
2260 if (y < yMin) {
2261 yMin = y;
2262 } else if (y > yMax) {
2263 yMax = y;
2268 if (xMin > clipXMin) {
2269 clipXMin = xMin;
2271 if (yMin > clipYMin) {
2272 clipYMin = yMin;
2274 if (xMax < clipXMax) {
2275 clipXMax = xMax;
2277 if (yMax < clipYMax) {
2278 clipYMax = yMax;
2282 void GfxState::textShift(double tx, double ty) {
2283 double dx, dy;
2285 textTransformDelta(tx, ty, &dx, &dy);
2286 curX += dx;
2287 curY += dy;
2290 void GfxState::shift(double dx, double dy) {
2291 curX += dx;
2292 curY += dy;
2295 GfxState *GfxState::save() {
2296 GfxState *newState;
2298 newState = copy();
2299 newState->saved = this;
2300 return newState;
2303 GfxState *GfxState::restore() {
2304 GfxState *oldState;
2306 if (saved) {
2307 oldState = saved;
2309 // these attributes aren't saved/restored by the q/Q operators
2310 oldState->path = path;
2311 oldState->curX = curX;
2312 oldState->curY = curY;
2313 oldState->lineX = lineX;
2314 oldState->lineY = lineY;
2316 path = NULL;
2317 saved = NULL;
2318 delete this;
2320 } else {
2321 oldState = this;
2324 return oldState;