added comment concerning GfxDeviceCMYKColorSpace::getRGB()
[swftools.git] / pdf2swf / xpdf / GfxState.cc
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
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"
24
25 //------------------------------------------------------------------------
26
27 static inline double clip01(double x) {
28   return (x < 0) ? 0 : ((x > 1) ? 1 : x);
29 }
30
31 //------------------------------------------------------------------------
32
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"
45 };
46
47 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
48
49 //------------------------------------------------------------------------
50 // GfxColorSpace
51 //------------------------------------------------------------------------
52
53 GfxColorSpace::GfxColorSpace() {
54 }
55
56 GfxColorSpace::~GfxColorSpace() {
57 }
58
59 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
60   GfxColorSpace *cs;
61   Object obj1;
62
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());
75     }
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");
102     }
103     obj1.free();
104   } else {
105     error(-1, "Bad color space - expected name or array");
106   }
107   return cs;
108 }
109
110 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
111                                      int maxImgPixel) {
112   int i;
113
114   for (i = 0; i < getNComps(); ++i) {
115     decodeLow[i] = 0;
116     decodeRange[i] = 1;
117   }
118 }
119
120 int GfxColorSpace::getNumColorSpaceModes() {
121   return nGfxColorSpaceModes;
122 }
123
124 char *GfxColorSpace::getColorSpaceModeName(int idx) {
125   return gfxColorSpaceModeNames[idx];
126 }
127
128 //------------------------------------------------------------------------
129 // GfxDeviceGrayColorSpace
130 //------------------------------------------------------------------------
131
132 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
133 }
134
135 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
136 }
137
138 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
139   return new GfxDeviceGrayColorSpace();
140 }
141
142 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
143   *gray = clip01(color->c[0]);
144 }
145
146 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
147   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
148 }
149
150 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
151   cmyk->c = cmyk->m = cmyk->y = 0;
152   cmyk->k = clip01(1 - color->c[0]);
153 }
154
155 //------------------------------------------------------------------------
156 // GfxCalGrayColorSpace
157 //------------------------------------------------------------------------
158
159 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
160   whiteX = whiteY = whiteZ = 1;
161   blackX = blackY = blackZ = 0;
162   gamma = 1;
163 }
164
165 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
166 }
167
168 GfxColorSpace *GfxCalGrayColorSpace::copy() {
169   GfxCalGrayColorSpace *cs;
170
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;
180 }
181
182 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
183   GfxCalGrayColorSpace *cs;
184   Object obj1, obj2, obj3;
185
186   arr->get(1, &obj1);
187   if (!obj1.isDict()) {
188     error(-1, "Bad CalGray color space");
189     obj1.free();
190     return NULL;
191   }
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();
204   }
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();
217   }
218   obj2.free();
219   if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
220     cs->gamma = obj2.getNum();
221   }
222   obj2.free();
223   obj1.free();
224   return cs;
225 }
226
227 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
228   *gray = clip01(color->c[0]);
229 }
230
231 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
232   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
233 }
234
235 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
236   cmyk->c = cmyk->m = cmyk->y = 0;
237   cmyk->k = clip01(1 - color->c[0]);
238 }
239
240 //------------------------------------------------------------------------
241 // GfxDeviceRGBColorSpace
242 //------------------------------------------------------------------------
243
244 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
245 }
246
247 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
248 }
249
250 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
251   return new GfxDeviceRGBColorSpace();
252 }
253
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]);
258 }
259
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]);
264 }
265
266 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
267   double c, m, y, k;
268
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;
275   }
276   if (y < k) {
277     k = y;
278   }
279   cmyk->c = c - k;
280   cmyk->m = m - k;
281   cmyk->y = y - k;
282   cmyk->k = k;
283 }
284
285 //------------------------------------------------------------------------
286 // GfxCalRGBColorSpace
287 //------------------------------------------------------------------------
288
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;
296 }
297
298 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
299 }
300
301 GfxColorSpace *GfxCalRGBColorSpace::copy() {
302   GfxCalRGBColorSpace *cs;
303   int i;
304
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];
317   }
318   return cs;
319 }
320
321 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
322   GfxCalRGBColorSpace *cs;
323   Object obj1, obj2, obj3;
324   int i;
325
326   arr->get(1, &obj1);
327   if (!obj1.isDict()) {
328     error(-1, "Bad CalRGB color space");
329     obj1.free();
330     return NULL;
331   }
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();
344   }
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();
357   }
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();
370   }
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();
378     }
379   }
380   obj2.free();
381   obj1.free();
382   return cs;
383 }
384
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]);
389 }
390
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]);
395 }
396
397 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
398   double c, m, y, k;
399
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;
406   }
407   if (y < k) {
408     k = y;
409   }
410   cmyk->c = c - k;
411   cmyk->m = m - k;
412   cmyk->y = y - k;
413   cmyk->k = k;
414 }
415
416 //------------------------------------------------------------------------
417 // GfxDeviceCMYKColorSpace
418 //------------------------------------------------------------------------
419
420 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
421 }
422
423 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
424 }
425
426 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
427   return new GfxDeviceCMYKColorSpace();
428 }
429
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]);
435 }
436
437 /*void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
438     double c,m,y,k,white;
439     c = color->c[0];
440     m = color->c[1];
441     y = color->c[2];
442     k = color->c[3];
443     white = 1.0 - k;
444     rgb->r = white - (c*white);
445     rgb->g = white - (m*white);
446     rgb->b = white - (y*white);
447 }*/
448 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
449   double c, m, y, aw, ac, am, ay, ar, ag, ab;
450
451   c = clip01(color->c[0] + color->c[3]);
452   m = clip01(color->c[1] + color->c[3]);
453   y = clip01(color->c[2] + color->c[3]);
454   aw = (1-c) * (1-m) * (1-y);
455   ac = c * (1-m) * (1-y);
456   am = (1-c) * m * (1-y);
457   ay = (1-c) * (1-m) * y;
458   ar = (1-c) * m * y;
459   ag = c * (1-m) * y;
460   ab = c * m * (1-y);
461   rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
462   rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
463   rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
464                   0.4863*ab);
465 }
466
467 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
468   cmyk->c = clip01(color->c[0]);
469   cmyk->m = clip01(color->c[1]);
470   cmyk->y = clip01(color->c[2]);
471   cmyk->k = clip01(color->c[3]);
472 }
473
474 //------------------------------------------------------------------------
475 // GfxLabColorSpace
476 //------------------------------------------------------------------------
477
478 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
479 // Language Reference, Third Edition.
480 static double xyzrgb[3][3] = {
481   {  3.240449, -1.537136, -0.498531 },
482   { -0.969265,  1.876011,  0.041556 },
483   {  0.055643, -0.204026,  1.057229 }
484 };
485
486 GfxLabColorSpace::GfxLabColorSpace() {
487   whiteX = whiteY = whiteZ = 1;
488   blackX = blackY = blackZ = 0;
489   aMin = bMin = -100;
490   aMax = bMax = 100;
491 }
492
493 GfxLabColorSpace::~GfxLabColorSpace() {
494 }
495
496 GfxColorSpace *GfxLabColorSpace::copy() {
497   GfxLabColorSpace *cs;
498
499   cs = new GfxLabColorSpace();
500   cs->whiteX = whiteX;
501   cs->whiteY = whiteY;
502   cs->whiteZ = whiteZ;
503   cs->blackX = blackX;
504   cs->blackY = blackY;
505   cs->blackZ = blackZ;
506   cs->aMin = aMin;
507   cs->aMax = aMax;
508   cs->bMin = bMin;
509   cs->bMax = bMax;
510   cs->kr = kr;
511   cs->kg = kg;
512   cs->kb = kb;
513   return cs;
514 }
515
516 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
517   GfxLabColorSpace *cs;
518   Object obj1, obj2, obj3;
519
520   arr->get(1, &obj1);
521   if (!obj1.isDict()) {
522     error(-1, "Bad Lab color space");
523     obj1.free();
524     return NULL;
525   }
526   cs = new GfxLabColorSpace();
527   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
528       obj2.arrayGetLength() == 3) {
529     obj2.arrayGet(0, &obj3);
530     cs->whiteX = obj3.getNum();
531     obj3.free();
532     obj2.arrayGet(1, &obj3);
533     cs->whiteY = obj3.getNum();
534     obj3.free();
535     obj2.arrayGet(2, &obj3);
536     cs->whiteZ = obj3.getNum();
537     obj3.free();
538   }
539   obj2.free();
540   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
541       obj2.arrayGetLength() == 3) {
542     obj2.arrayGet(0, &obj3);
543     cs->blackX = obj3.getNum();
544     obj3.free();
545     obj2.arrayGet(1, &obj3);
546     cs->blackY = obj3.getNum();
547     obj3.free();
548     obj2.arrayGet(2, &obj3);
549     cs->blackZ = obj3.getNum();
550     obj3.free();
551   }
552   obj2.free();
553   if (obj1.dictLookup("Range", &obj2)->isArray() &&
554       obj2.arrayGetLength() == 4) {
555     obj2.arrayGet(0, &obj3);
556     cs->aMin = obj3.getNum();
557     obj3.free();
558     obj2.arrayGet(1, &obj3);
559     cs->aMax = obj3.getNum();
560     obj3.free();
561     obj2.arrayGet(2, &obj3);
562     cs->bMin = obj3.getNum();
563     obj3.free();
564     obj2.arrayGet(3, &obj3);
565     cs->bMax = obj3.getNum();
566     obj3.free();
567   }
568   obj2.free();
569   obj1.free();
570
571   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
572                 xyzrgb[0][1] * cs->whiteY +
573                 xyzrgb[0][2] * cs->whiteZ);
574   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
575                 xyzrgb[1][1] * cs->whiteY +
576                 xyzrgb[1][2] * cs->whiteZ);
577   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
578                 xyzrgb[2][1] * cs->whiteY +
579                 xyzrgb[2][2] * cs->whiteZ);
580
581   return cs;
582 }
583
584 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
585   GfxRGB rgb;
586
587   getRGB(color, &rgb);
588   *gray = clip01(0.299 * rgb.r +
589                  0.587 * rgb.g +
590                  0.114 * rgb.b);
591 }
592
593 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
594   double X, Y, Z;
595   double t1, t2;
596   double r, g, b;
597
598   // convert L*a*b* to CIE 1931 XYZ color space
599   t1 = (color->c[0] + 16) / 116;
600   t2 = t1 + color->c[1] / 500;
601   if (t2 >= (6.0 / 29.0)) {
602     X = t2 * t2 * t2;
603   } else {
604     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
605   }
606   X *= whiteX;
607   if (t1 >= (6.0 / 29.0)) {
608     Y = t1 * t1 * t1;
609   } else {
610     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
611   }
612   Y *= whiteY;
613   t2 = t1 - color->c[2] / 200;
614   if (t2 >= (6.0 / 29.0)) {
615     Z = t2 * t2 * t2;
616   } else {
617     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
618   }
619   Z *= whiteZ;
620
621   // convert XYZ to RGB, including gamut mapping and gamma correction
622   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
623   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
624   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
625   rgb->r = pow(clip01(r * kr), 0.5);
626   rgb->g = pow(clip01(g * kg), 0.5);
627   rgb->b = pow(clip01(b * kb), 0.5);
628 }
629
630 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
631   GfxRGB rgb;
632   double c, m, y, k;
633
634   getRGB(color, &rgb);
635   c = clip01(1 - rgb.r);
636   m = clip01(1 - rgb.g);
637   y = clip01(1 - rgb.b);
638   k = c;
639   if (m < k) {
640     k = m;
641   }
642   if (y < k) {
643     k = y;
644   }
645   cmyk->c = c - k;
646   cmyk->m = m - k;
647   cmyk->y = y - k;
648   cmyk->k = k;
649 }
650
651 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
652                                         int maxImgPixel) {
653   decodeLow[0] = 0;
654   decodeRange[0] = 100;
655   decodeLow[1] = aMin;
656   decodeRange[1] = aMax - aMin;
657   decodeLow[2] = bMin;
658   decodeRange[2] = bMax - bMin;
659 }
660
661 //------------------------------------------------------------------------
662 // GfxICCBasedColorSpace
663 //------------------------------------------------------------------------
664
665 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
666                                              Ref *iccProfileStreamA) {
667   nComps = nCompsA;
668   alt = altA;
669   iccProfileStream = *iccProfileStreamA;
670   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
671   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
672 }
673
674 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
675   delete alt;
676 }
677
678 GfxColorSpace *GfxICCBasedColorSpace::copy() {
679   GfxICCBasedColorSpace *cs;
680   int i;
681
682   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
683   for (i = 0; i < 4; ++i) {
684     cs->rangeMin[i] = rangeMin[i];
685     cs->rangeMax[i] = rangeMax[i];
686   }
687   return cs;
688 }
689
690 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
691   GfxICCBasedColorSpace *cs;
692   Ref iccProfileStreamA;
693   int nCompsA;
694   GfxColorSpace *altA;
695   Dict *dict;
696   Object obj1, obj2, obj3;
697   int i;
698
699   arr->getNF(1, &obj1);
700   if (obj1.isRef()) {
701     iccProfileStreamA = obj1.getRef();
702   } else {
703     iccProfileStreamA.num = 0;
704     iccProfileStreamA.gen = 0;
705   }
706   obj1.free();
707   arr->get(1, &obj1);
708   if (!obj1.isStream()) {
709     error(-1, "Bad ICCBased color space (stream)");
710     obj1.free();
711     return NULL;
712   }
713   dict = obj1.streamGetDict();
714   if (!dict->lookup("N", &obj2)->isInt()) {
715     error(-1, "Bad ICCBased color space (N)");
716     obj2.free();
717     obj1.free();
718     return NULL;
719   }
720   nCompsA = obj2.getInt();
721   obj2.free();
722   if (dict->lookup("Alternate", &obj2)->isNull() ||
723       !(altA = GfxColorSpace::parse(&obj2))) {
724     switch (nCompsA) {
725     case 1:
726       altA = new GfxDeviceGrayColorSpace();
727       break;
728     case 3:
729       altA = new GfxDeviceRGBColorSpace();
730       break;
731     case 4:
732       altA = new GfxDeviceCMYKColorSpace();
733       break;
734     default:
735       error(-1, "Bad ICCBased color space - invalid N");
736       obj2.free();
737       obj1.free();
738       return NULL;
739     }
740   }
741   obj2.free();
742   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
743   if (dict->lookup("Range", &obj2)->isArray() &&
744       obj2.arrayGetLength() == 2 * nCompsA) {
745     for (i = 0; i < nCompsA; ++i) {
746       obj2.arrayGet(2*i, &obj3);
747       cs->rangeMin[i] = obj3.getNum();
748       obj3.free();
749       obj2.arrayGet(2*i+1, &obj3);
750       cs->rangeMax[i] = obj3.getNum();
751       obj3.free();
752     }
753   }
754   obj2.free();
755   obj1.free();
756   return cs;
757 }
758
759 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
760   alt->getGray(color, gray);
761 }
762
763 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
764   alt->getRGB(color, rgb);
765 }
766
767 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
768   alt->getCMYK(color, cmyk);
769 }
770
771 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
772                                              double *decodeRange,
773                                              int maxImgPixel) {
774   alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
775
776 #if 0
777   // this is nominally correct, but some PDF files don't set the
778   // correct ranges in the ICCBased dict
779   int i;
780
781   for (i = 0; i < nComps; ++i) {
782     decodeLow[i] = rangeMin[i];
783     decodeRange[i] = rangeMax[i] - rangeMin[i];
784   }
785 #endif
786 }
787
788 //------------------------------------------------------------------------
789 // GfxIndexedColorSpace
790 //------------------------------------------------------------------------
791
792 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
793                                            int indexHighA) {
794   base = baseA;
795   indexHigh = indexHighA;
796   lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
797                              sizeof(Guchar));
798 }
799
800 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
801   delete base;
802   gfree(lookup);
803 }
804
805 GfxColorSpace *GfxIndexedColorSpace::copy() {
806   GfxIndexedColorSpace *cs;
807
808   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
809   memcpy(cs->lookup, lookup,
810          (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
811   return cs;
812 }
813
814 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
815   GfxIndexedColorSpace *cs;
816   GfxColorSpace *baseA;
817   int indexHighA;
818   Object obj1;
819   int x;
820   char *s;
821   int n, i, j;
822
823   if (arr->getLength() != 4) {
824     error(-1, "Bad Indexed color space");
825     goto err1;
826   }
827   arr->get(1, &obj1);
828   if (!(baseA = GfxColorSpace::parse(&obj1))) {
829     error(-1, "Bad Indexed color space (base color space)");
830     goto err2;
831   }
832   obj1.free();
833   if (!arr->get(2, &obj1)->isInt()) {
834     error(-1, "Bad Indexed color space (hival)");
835     delete baseA;
836     goto err2;
837   }
838   indexHighA = obj1.getInt();
839   if (indexHighA < 0 || indexHighA > 255) {
840     // the PDF spec requires indexHigh to be in [0,255] -- allowing
841     // values larger than 255 creates a security hole: if nComps *
842     // indexHigh is greater than 2^31, the loop below may overwrite
843     // past the end of the array
844     error(-1, "Bad Indexed color space (invalid indexHigh value)");
845     delete baseA;
846     goto err2;
847   }
848   obj1.free();
849   cs = new GfxIndexedColorSpace(baseA, indexHighA);
850   arr->get(3, &obj1);
851   n = baseA->getNComps();
852   if (obj1.isStream()) {
853     obj1.streamReset();
854     for (i = 0; i <= indexHighA; ++i) {
855       for (j = 0; j < n; ++j) {
856         if ((x = obj1.streamGetChar()) == EOF) {
857           error(-1, "Bad Indexed color space (lookup table stream too short)");
858           goto err3;
859         }
860         cs->lookup[i*n + j] = (Guchar)x;
861       }
862     }
863     obj1.streamClose();
864   } else if (obj1.isString()) {
865     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
866       error(-1, "Bad Indexed color space (lookup table string too short)");
867       goto err3;
868     }
869     s = obj1.getString()->getCString();
870     for (i = 0; i <= indexHighA; ++i) {
871       for (j = 0; j < n; ++j) {
872         cs->lookup[i*n + j] = (Guchar)*s++;
873       }
874     }
875   } else {
876     error(-1, "Bad Indexed color space (lookup table)");
877     goto err3;
878   }
879   obj1.free();
880   return cs;
881
882  err3:
883   delete cs;
884  err2:
885   obj1.free();
886  err1:
887   return NULL;
888 }
889
890 GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
891                                                GfxColor *baseColor) {
892   Guchar *p;
893   double low[gfxColorMaxComps], range[gfxColorMaxComps];
894   int n, i;
895
896   n = base->getNComps();
897   base->getDefaultRanges(low, range, indexHigh);
898   p = &lookup[(int)(color->c[0] + 0.5) * n];
899   for (i = 0; i < n; ++i) {
900     baseColor->c[i] = low[i] + (p[i] / 255.0) * range[i];
901   }
902   return baseColor;
903 }
904
905 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
906   GfxColor color2;
907
908   base->getGray(mapColorToBase(color, &color2), gray);
909 }
910
911 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
912   GfxColor color2;
913
914   base->getRGB(mapColorToBase(color, &color2), rgb);
915 }
916
917 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
918   GfxColor color2;
919
920   base->getCMYK(mapColorToBase(color, &color2), cmyk);
921 }
922
923 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
924                                             double *decodeRange,
925                                             int maxImgPixel) {
926   decodeLow[0] = 0;
927   decodeRange[0] = maxImgPixel;
928 }
929
930 //------------------------------------------------------------------------
931 // GfxSeparationColorSpace
932 //------------------------------------------------------------------------
933
934 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
935                                                  GfxColorSpace *altA,
936                                                  Function *funcA) {
937   name = nameA;
938   alt = altA;
939   func = funcA;
940 }
941
942 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
943   delete name;
944   delete alt;
945   delete func;
946 }
947
948 GfxColorSpace *GfxSeparationColorSpace::copy() {
949   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
950 }
951
952 //~ handle the 'All' and 'None' colorants
953 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
954   GfxSeparationColorSpace *cs;
955   GString *nameA;
956   GfxColorSpace *altA;
957   Function *funcA;
958   Object obj1;
959
960   if (arr->getLength() != 4) {
961     error(-1, "Bad Separation color space");
962     goto err1;
963   }
964   if (!arr->get(1, &obj1)->isName()) {
965     error(-1, "Bad Separation color space (name)");
966     goto err2;
967   }
968   nameA = new GString(obj1.getName());
969   obj1.free();
970   arr->get(2, &obj1);
971   if (!(altA = GfxColorSpace::parse(&obj1))) {
972     error(-1, "Bad Separation color space (alternate color space)");
973     goto err3;
974   }
975   obj1.free();
976   arr->get(3, &obj1);
977   if (!(funcA = Function::parse(&obj1))) {
978     goto err4;
979   }
980   obj1.free();
981   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
982   return cs;
983
984  err4:
985   delete altA;
986  err3:
987   delete nameA;
988  err2:
989   obj1.free();
990  err1:
991   return NULL;
992 }
993
994 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
995   GfxColor color2;
996
997   func->transform(color->c, color2.c);
998   alt->getGray(&color2, gray);
999 }
1000
1001 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1002   GfxColor color2;
1003
1004   func->transform(color->c, color2.c);
1005   alt->getRGB(&color2, rgb);
1006 }
1007
1008 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1009   GfxColor color2;
1010
1011   func->transform(color->c, color2.c);
1012   alt->getCMYK(&color2, cmyk);
1013 }
1014
1015 //------------------------------------------------------------------------
1016 // GfxDeviceNColorSpace
1017 //------------------------------------------------------------------------
1018
1019 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1020                                            GfxColorSpace *altA,
1021                                            Function *funcA) {
1022   nComps = nCompsA;
1023   alt = altA;
1024   func = funcA;
1025 }
1026
1027 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1028   int i;
1029
1030   for (i = 0; i < nComps; ++i) {
1031     delete names[i];
1032   }
1033   delete alt;
1034   delete func;
1035 }
1036
1037 GfxColorSpace *GfxDeviceNColorSpace::copy() {
1038   GfxDeviceNColorSpace *cs;
1039   int i;
1040
1041   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
1042   for (i = 0; i < nComps; ++i) {
1043     cs->names[i] = names[i]->copy();
1044   }
1045   return cs;
1046 }
1047
1048 //~ handle the 'None' colorant
1049 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
1050   GfxDeviceNColorSpace *cs;
1051   int nCompsA;
1052   GString *namesA[gfxColorMaxComps];
1053   GfxColorSpace *altA;
1054   Function *funcA;
1055   Object obj1, obj2;
1056   int i;
1057
1058   if (arr->getLength() != 4 && arr->getLength() != 5) {
1059     error(-1, "Bad DeviceN color space");
1060     goto err1;
1061   }
1062   if (!arr->get(1, &obj1)->isArray()) {
1063     error(-1, "Bad DeviceN color space (names)");
1064     goto err2;
1065   }
1066   nCompsA = obj1.arrayGetLength();
1067   if (nCompsA > gfxColorMaxComps) {
1068     error(-1, "DeviceN color space with more than %d > %d components",
1069           nCompsA, gfxColorMaxComps);
1070     nCompsA = gfxColorMaxComps;
1071   }
1072   for (i = 0; i < nCompsA; ++i) {
1073     if (!obj1.arrayGet(i, &obj2)->isName()) {
1074       error(-1, "Bad DeviceN color space (names)");
1075       obj2.free();
1076       goto err2;
1077     }
1078     namesA[i] = new GString(obj2.getName());
1079     obj2.free();
1080   }
1081   obj1.free();
1082   arr->get(2, &obj1);
1083   if (!(altA = GfxColorSpace::parse(&obj1))) {
1084     error(-1, "Bad DeviceN color space (alternate color space)");
1085     goto err3;
1086   }
1087   obj1.free();
1088   arr->get(3, &obj1);
1089   if (!(funcA = Function::parse(&obj1))) {
1090     goto err4;
1091   }
1092   obj1.free();
1093   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1094   for (i = 0; i < nCompsA; ++i) {
1095     cs->names[i] = namesA[i];
1096   }
1097   return cs;
1098
1099  err4:
1100   delete altA;
1101  err3:
1102   for (i = 0; i < nCompsA; ++i) {
1103     delete namesA[i];
1104   }
1105  err2:
1106   obj1.free();
1107  err1:
1108   return NULL;
1109 }
1110
1111 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1112   GfxColor color2;
1113
1114   func->transform(color->c, color2.c);
1115   alt->getGray(&color2, gray);
1116 }
1117
1118 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1119   GfxColor color2;
1120
1121   func->transform(color->c, color2.c);
1122   alt->getRGB(&color2, rgb);
1123 }
1124
1125 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1126   GfxColor color2;
1127
1128   func->transform(color->c, color2.c);
1129   alt->getCMYK(&color2, cmyk);
1130 }
1131
1132 //------------------------------------------------------------------------
1133 // GfxPatternColorSpace
1134 //------------------------------------------------------------------------
1135
1136 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1137   under = underA;
1138 }
1139
1140 GfxPatternColorSpace::~GfxPatternColorSpace() {
1141   if (under) {
1142     delete under;
1143   }
1144 }
1145
1146 GfxColorSpace *GfxPatternColorSpace::copy() {
1147   return new GfxPatternColorSpace(under ? under->copy() :
1148                                           (GfxColorSpace *)NULL);
1149 }
1150
1151 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1152   GfxPatternColorSpace *cs;
1153   GfxColorSpace *underA;
1154   Object obj1;
1155
1156   if (arr->getLength() != 1 && arr->getLength() != 2) {
1157     error(-1, "Bad Pattern color space");
1158     return NULL;
1159   }
1160   underA = NULL;
1161   if (arr->getLength() == 2) {
1162     arr->get(1, &obj1);
1163     if (!(underA = GfxColorSpace::parse(&obj1))) {
1164       error(-1, "Bad Pattern color space (underlying color space)");
1165       obj1.free();
1166       return NULL;
1167     }
1168     obj1.free();
1169   }
1170   cs = new GfxPatternColorSpace(underA);
1171   return cs;
1172 }
1173
1174 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1175   *gray = 0;
1176 }
1177
1178 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1179   rgb->r = rgb->g = rgb->b = 0;
1180 }
1181
1182 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1183   cmyk->c = cmyk->m = cmyk->y = 0;
1184   cmyk->k = 1;
1185 }
1186
1187 //------------------------------------------------------------------------
1188 // Pattern
1189 //------------------------------------------------------------------------
1190
1191 GfxPattern::GfxPattern(int typeA) {
1192   type = typeA;
1193 }
1194
1195 GfxPattern::~GfxPattern() {
1196 }
1197
1198 GfxPattern *GfxPattern::parse(Object *obj) {
1199   GfxPattern *pattern;
1200   Object obj1;
1201
1202   if (obj->isDict()) {
1203     obj->dictLookup("PatternType", &obj1);
1204   } else if (obj->isStream()) {
1205     obj->streamGetDict()->lookup("PatternType", &obj1);
1206   } else {
1207     return NULL;
1208   }
1209   pattern = NULL;
1210   if (obj1.isInt() && obj1.getInt() == 1) {
1211     pattern = GfxTilingPattern::parse(obj);
1212   } else if (obj1.isInt() && obj1.getInt() == 2) {
1213     pattern = GfxShadingPattern::parse(obj);
1214   }
1215   obj1.free();
1216   return pattern;
1217 }
1218
1219 //------------------------------------------------------------------------
1220 // GfxTilingPattern
1221 //------------------------------------------------------------------------
1222
1223 GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
1224   GfxTilingPattern *pat;
1225   Dict *dict;
1226   int paintTypeA, tilingTypeA;
1227   double bboxA[4], matrixA[6];
1228   double xStepA, yStepA;
1229   Object resDictA;
1230   Object obj1, obj2;
1231   int i;
1232
1233   if (!patObj->isStream()) {
1234     return NULL;
1235   }
1236   dict = patObj->streamGetDict();
1237
1238   if (dict->lookup("PaintType", &obj1)->isInt()) {
1239     paintTypeA = obj1.getInt();
1240   } else {
1241     paintTypeA = 1;
1242     error(-1, "Invalid or missing PaintType in pattern");
1243   }
1244   obj1.free();
1245   if (dict->lookup("TilingType", &obj1)->isInt()) {
1246     tilingTypeA = obj1.getInt();
1247   } else {
1248     tilingTypeA = 1;
1249     error(-1, "Invalid or missing TilingType in pattern");
1250   }
1251   obj1.free();
1252   bboxA[0] = bboxA[1] = 0;
1253   bboxA[2] = bboxA[3] = 1;
1254   if (dict->lookup("BBox", &obj1)->isArray() &&
1255       obj1.arrayGetLength() == 4) {
1256     for (i = 0; i < 4; ++i) {
1257       if (obj1.arrayGet(i, &obj2)->isNum()) {
1258         bboxA[i] = obj2.getNum();
1259       }
1260       obj2.free();
1261     }
1262   } else {
1263     error(-1, "Invalid or missing BBox in pattern");
1264   }
1265   obj1.free();
1266   if (dict->lookup("XStep", &obj1)->isNum()) {
1267     xStepA = obj1.getNum();
1268   } else {
1269     xStepA = 1;
1270     error(-1, "Invalid or missing XStep in pattern");
1271   }
1272   obj1.free();
1273   if (dict->lookup("YStep", &obj1)->isNum()) {
1274     yStepA = obj1.getNum();
1275   } else {
1276     yStepA = 1;
1277     error(-1, "Invalid or missing YStep in pattern");
1278   }
1279   obj1.free();
1280   if (!dict->lookup("Resources", &resDictA)->isDict()) {
1281     resDictA.free();
1282     resDictA.initNull();
1283     error(-1, "Invalid or missing Resources in pattern");
1284   }
1285   matrixA[0] = 1; matrixA[1] = 0;
1286   matrixA[2] = 0; matrixA[3] = 1;
1287   matrixA[4] = 0; matrixA[5] = 0;
1288   if (dict->lookup("Matrix", &obj1)->isArray() &&
1289       obj1.arrayGetLength() == 6) {
1290     for (i = 0; i < 6; ++i) {
1291       if (obj1.arrayGet(i, &obj2)->isNum()) {
1292         matrixA[i] = obj2.getNum();
1293       }
1294       obj2.free();
1295     }
1296   }
1297   obj1.free();
1298
1299   pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1300                              &resDictA, matrixA, patObj);
1301   resDictA.free();
1302   return pat;
1303 }
1304
1305 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1306                                    double *bboxA, double xStepA, double yStepA,
1307                                    Object *resDictA, double *matrixA,
1308                                    Object *contentStreamA):
1309   GfxPattern(1)
1310 {
1311   int i;
1312
1313   paintType = paintTypeA;
1314   tilingType = tilingTypeA;
1315   for (i = 0; i < 4; ++i) {
1316     bbox[i] = bboxA[i];
1317   }
1318   xStep = xStepA;
1319   yStep = yStepA;
1320   resDictA->copy(&resDict);
1321   for (i = 0; i < 6; ++i) {
1322     matrix[i] = matrixA[i];
1323   }
1324   contentStreamA->copy(&contentStream);
1325 }
1326
1327 GfxTilingPattern::~GfxTilingPattern() {
1328   resDict.free();
1329   contentStream.free();
1330 }
1331
1332 GfxPattern *GfxTilingPattern::copy() {
1333   return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1334                               &resDict, matrix, &contentStream);
1335 }
1336
1337 //------------------------------------------------------------------------
1338 // GfxShadingPattern
1339 //------------------------------------------------------------------------
1340
1341 GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
1342   Dict *dict;
1343   GfxShading *shadingA;
1344   double matrixA[6];
1345   Object obj1, obj2;
1346   int i;
1347
1348   if (!patObj->isDict()) {
1349     return NULL;
1350   }
1351   dict = patObj->getDict();
1352
1353   dict->lookup("Shading", &obj1);
1354   shadingA = GfxShading::parse(&obj1);
1355   obj1.free();
1356   if (!shadingA) {
1357     return NULL;
1358   }
1359
1360   matrixA[0] = 1; matrixA[1] = 0;
1361   matrixA[2] = 0; matrixA[3] = 1;
1362   matrixA[4] = 0; matrixA[5] = 0;
1363   if (dict->lookup("Matrix", &obj1)->isArray() &&
1364       obj1.arrayGetLength() == 6) {
1365     for (i = 0; i < 6; ++i) {
1366       if (obj1.arrayGet(i, &obj2)->isNum()) {
1367         matrixA[i] = obj2.getNum();
1368       }
1369       obj2.free();
1370     }
1371   }
1372   obj1.free();
1373
1374   return new GfxShadingPattern(shadingA, matrixA);
1375 }
1376
1377 GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
1378   GfxPattern(2)
1379 {
1380   int i;
1381
1382   shading = shadingA;
1383   for (i = 0; i < 6; ++i) {
1384     matrix[i] = matrixA[i];
1385   }
1386 }
1387
1388 GfxShadingPattern::~GfxShadingPattern() {
1389   delete shading;
1390 }
1391
1392 GfxPattern *GfxShadingPattern::copy() {
1393   return new GfxShadingPattern(shading->copy(), matrix);
1394 }
1395
1396 //------------------------------------------------------------------------
1397 // GfxShading
1398 //------------------------------------------------------------------------
1399
1400 GfxShading::GfxShading(int typeA) {
1401   type = typeA;
1402   colorSpace = NULL;
1403 }
1404
1405 GfxShading::GfxShading(GfxShading *shading) {
1406   int i;
1407
1408   type = shading->type;
1409   colorSpace = shading->colorSpace->copy();
1410   for (i = 0; i < gfxColorMaxComps; ++i) {
1411     background.c[i] = shading->background.c[i];
1412   }
1413   hasBackground = shading->hasBackground;
1414   xMin = shading->xMin;
1415   yMin = shading->yMin;
1416   xMax = shading->xMax;
1417   yMax = shading->yMax;
1418   hasBBox = shading->hasBBox;
1419 }
1420
1421 GfxShading::~GfxShading() {
1422   if (colorSpace) {
1423     delete colorSpace;
1424   }
1425 }
1426
1427 GfxShading *GfxShading::parse(Object *obj) {
1428   GfxShading *shading;
1429   Dict *dict;
1430   int typeA;
1431   Object obj1;
1432
1433   if (obj->isDict()) {
1434     dict = obj->getDict();
1435   } else if (obj->isStream()) {
1436     dict = obj->streamGetDict();
1437   } else {
1438     return NULL;
1439   }
1440
1441   if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1442     error(-1, "Invalid ShadingType in shading dictionary");
1443     obj1.free();
1444     return NULL;
1445   }
1446   typeA = obj1.getInt();
1447   obj1.free();
1448
1449   switch (typeA) {
1450   case 1:
1451     shading = GfxFunctionShading::parse(dict);
1452     break;
1453   case 2:
1454     shading = GfxAxialShading::parse(dict);
1455     break;
1456   case 3:
1457     shading = GfxRadialShading::parse(dict);
1458     break;
1459   default:
1460     error(-1, "Unimplemented shading type %d", typeA);
1461     goto err1;
1462   }
1463
1464   return shading;
1465
1466  err1:
1467   return NULL;
1468 }
1469
1470 GBool GfxShading::init(Dict *dict) {
1471   Object obj1, obj2;
1472   int i;
1473
1474   dict->lookup("ColorSpace", &obj1);
1475   if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
1476     error(-1, "Bad color space in shading dictionary");
1477     obj1.free();
1478     return gFalse;
1479   }
1480   obj1.free();
1481
1482   for (i = 0; i < gfxColorMaxComps; ++i) {
1483     background.c[i] = 0;
1484   }
1485   hasBackground = gFalse;
1486   if (dict->lookup("Background", &obj1)->isArray()) {
1487     if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1488       hasBackground = gTrue;
1489       for (i = 0; i < colorSpace->getNComps(); ++i) {
1490         background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1491         obj2.free();
1492       }
1493     } else {
1494       error(-1, "Bad Background in shading dictionary");
1495     }
1496   }
1497   obj1.free();
1498
1499   xMin = yMin = xMax = yMax = 0;
1500   hasBBox = gFalse;
1501   if (dict->lookup("BBox", &obj1)->isArray()) {
1502     if (obj1.arrayGetLength() == 4) {
1503       hasBBox = gTrue;
1504       xMin = obj1.arrayGet(0, &obj2)->getNum();
1505       obj2.free();
1506       yMin = obj1.arrayGet(1, &obj2)->getNum();
1507       obj2.free();
1508       xMax = obj1.arrayGet(2, &obj2)->getNum();
1509       obj2.free();
1510       yMax = obj1.arrayGet(3, &obj2)->getNum();
1511       obj2.free();
1512     } else {
1513       error(-1, "Bad BBox in shading dictionary");
1514     }
1515   }
1516   obj1.free();
1517
1518   return gTrue;
1519 }
1520
1521 //------------------------------------------------------------------------
1522 // GfxFunctionShading
1523 //------------------------------------------------------------------------
1524
1525 GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
1526                                        double x1A, double y1A,
1527                                        double *matrixA,
1528                                        Function **funcsA, int nFuncsA):
1529   GfxShading(1)
1530 {
1531   int i;
1532
1533   x0 = x0A;
1534   y0 = y0A;
1535   x1 = x1A;
1536   y1 = y1A;
1537   for (i = 0; i < 6; ++i) {
1538     matrix[i] = matrixA[i];
1539   }
1540   nFuncs = nFuncsA;
1541   for (i = 0; i < nFuncs; ++i) {
1542     funcs[i] = funcsA[i];
1543   }
1544 }
1545
1546 GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
1547   GfxShading(shading)
1548 {
1549   int i;
1550
1551   x0 = shading->x0;
1552   y0 = shading->y0;
1553   x1 = shading->x1;
1554   y1 = shading->y1;
1555   for (i = 0; i < 6; ++i) {
1556     matrix[i] = shading->matrix[i];
1557   }
1558   nFuncs = shading->nFuncs;
1559   for (i = 0; i < nFuncs; ++i) {
1560     funcs[i] = shading->funcs[i]->copy();
1561   }
1562 }
1563
1564 GfxFunctionShading::~GfxFunctionShading() {
1565   int i;
1566
1567   for (i = 0; i < nFuncs; ++i) {
1568     delete funcs[i];
1569   }
1570 }
1571
1572 GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
1573   GfxFunctionShading *shading;
1574   double x0A, y0A, x1A, y1A;
1575   double matrixA[6];
1576   Function *funcsA[gfxColorMaxComps];
1577   int nFuncsA;
1578   Object obj1, obj2;
1579   int i;
1580
1581   x0A = y0A = 0;
1582   x1A = y1A = 1;
1583   if (dict->lookup("Domain", &obj1)->isArray() &&
1584       obj1.arrayGetLength() == 4) {
1585     x0A = obj1.arrayGet(0, &obj2)->getNum();
1586     obj2.free();
1587     y0A = obj1.arrayGet(1, &obj2)->getNum();
1588     obj2.free();
1589     x1A = obj1.arrayGet(2, &obj2)->getNum();
1590     obj2.free();
1591     y1A = obj1.arrayGet(3, &obj2)->getNum();
1592     obj2.free();
1593   }
1594   obj1.free();
1595
1596   matrixA[0] = 1; matrixA[1] = 0;
1597   matrixA[2] = 0; matrixA[3] = 1;
1598   matrixA[4] = 0; matrixA[5] = 0;
1599   if (dict->lookup("Matrix", &obj1)->isArray() &&
1600       obj1.arrayGetLength() == 6) {
1601     matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
1602     obj2.free();
1603     matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
1604     obj2.free();
1605     matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
1606     obj2.free();
1607     matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
1608     obj2.free();
1609     matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
1610     obj2.free();
1611     matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
1612     obj2.free();
1613   }
1614   obj1.free();
1615
1616   dict->lookup("Function", &obj1);
1617   if (obj1.isArray()) {
1618     nFuncsA = obj1.arrayGetLength();
1619     if (nFuncsA > gfxColorMaxComps) {
1620       error(-1, "Invalid Function array in shading dictionary");
1621       goto err1;
1622     }
1623     for (i = 0; i < nFuncsA; ++i) {
1624       obj1.arrayGet(i, &obj2);
1625       if (!(funcsA[i] = Function::parse(&obj2))) {
1626         goto err2;
1627       }
1628       obj2.free();
1629     }
1630   } else {
1631     nFuncsA = 1;
1632     if (!(funcsA[0] = Function::parse(&obj1))) {
1633       goto err1;
1634     }
1635   }
1636   obj1.free();
1637
1638   shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
1639                                    funcsA, nFuncsA);
1640   if (!shading->init(dict)) {
1641     delete shading;
1642     return NULL;
1643   }
1644   return shading;
1645
1646  err2:
1647   obj2.free();
1648  err1:
1649   obj1.free();
1650   return NULL;
1651 }
1652
1653 GfxShading *GfxFunctionShading::copy() {
1654   return new GfxFunctionShading(this);
1655 }
1656
1657 void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
1658   double in[2];
1659   int i;
1660
1661   in[0] = x;
1662   in[1] = y;
1663   for (i = 0; i < nFuncs; ++i) {
1664     funcs[i]->transform(in, &color->c[i]);
1665   }
1666 }
1667
1668 //------------------------------------------------------------------------
1669 // GfxAxialShading
1670 //------------------------------------------------------------------------
1671
1672 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
1673                                  double x1A, double y1A,
1674                                  double t0A, double t1A,
1675                                  Function **funcsA, int nFuncsA,
1676                                  GBool extend0A, GBool extend1A):
1677   GfxShading(2)
1678 {
1679   int i;
1680
1681   x0 = x0A;
1682   y0 = y0A;
1683   x1 = x1A;
1684   y1 = y1A;
1685   t0 = t0A;
1686   t1 = t1A;
1687   nFuncs = nFuncsA;
1688   for (i = 0; i < nFuncs; ++i) {
1689     funcs[i] = funcsA[i];
1690   }
1691   extend0 = extend0A;
1692   extend1 = extend1A;
1693 }
1694
1695 GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
1696   GfxShading(shading)
1697 {
1698   int i;
1699
1700   x0 = shading->x0;
1701   y0 = shading->y0;
1702   x1 = shading->x1;
1703   y1 = shading->y1;
1704   t0 = shading->t0;
1705   y1 = shading->t1;
1706   nFuncs = shading->nFuncs;
1707   for (i = 0; i < nFuncs; ++i) {
1708     funcs[i] = shading->funcs[i]->copy();
1709   }
1710   extend0 = shading->extend0;
1711   extend1 = shading->extend1;
1712 }
1713
1714 GfxAxialShading::~GfxAxialShading() {
1715   int i;
1716
1717   for (i = 0; i < nFuncs; ++i) {
1718     delete funcs[i];
1719   }
1720 }
1721
1722 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1723   GfxAxialShading *shading;
1724   double x0A, y0A, x1A, y1A;
1725   double t0A, t1A;
1726   Function *funcsA[gfxColorMaxComps];
1727   int nFuncsA;
1728   GBool extend0A, extend1A;
1729   Object obj1, obj2;
1730   int i;
1731
1732   x0A = y0A = x1A = y1A = 0;
1733   if (dict->lookup("Coords", &obj1)->isArray() &&
1734       obj1.arrayGetLength() == 4) {
1735     x0A = obj1.arrayGet(0, &obj2)->getNum();
1736     obj2.free();
1737     y0A = obj1.arrayGet(1, &obj2)->getNum();
1738     obj2.free();
1739     x1A = obj1.arrayGet(2, &obj2)->getNum();
1740     obj2.free();
1741     y1A = obj1.arrayGet(3, &obj2)->getNum();
1742     obj2.free();
1743   } else {
1744     error(-1, "Missing or invalid Coords in shading dictionary");
1745     goto err1;
1746   }
1747   obj1.free();
1748
1749   t0A = 0;
1750   t1A = 1;
1751   if (dict->lookup("Domain", &obj1)->isArray() &&
1752       obj1.arrayGetLength() == 2) {
1753     t0A = obj1.arrayGet(0, &obj2)->getNum();
1754     obj2.free();
1755     t1A = obj1.arrayGet(1, &obj2)->getNum();
1756     obj2.free();
1757   }
1758   obj1.free();
1759
1760   dict->lookup("Function", &obj1);
1761   if (obj1.isArray()) {
1762     nFuncsA = obj1.arrayGetLength();
1763     if (nFuncsA > gfxColorMaxComps) {
1764       error(-1, "Invalid Function array in shading dictionary");
1765       goto err1;
1766     }
1767     for (i = 0; i < nFuncsA; ++i) {
1768       obj1.arrayGet(i, &obj2);
1769       if (!(funcsA[i] = Function::parse(&obj2))) {
1770         obj1.free();
1771         obj2.free();
1772         goto err1;
1773       }
1774       obj2.free();
1775     }
1776   } else {
1777     nFuncsA = 1;
1778     if (!(funcsA[0] = Function::parse(&obj1))) {
1779       obj1.free();
1780       goto err1;
1781     }
1782   }
1783   obj1.free();
1784
1785   extend0A = extend1A = gFalse;
1786   if (dict->lookup("Extend", &obj1)->isArray() &&
1787       obj1.arrayGetLength() == 2) {
1788     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1789     obj2.free();
1790     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1791     obj2.free();
1792   }
1793   obj1.free();
1794
1795   shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1796                                 funcsA, nFuncsA, extend0A, extend1A);
1797   if (!shading->init(dict)) {
1798     delete shading;
1799     return NULL;
1800   }
1801   return shading;
1802
1803  err1:
1804   return NULL;
1805 }
1806
1807 GfxShading *GfxAxialShading::copy() {
1808   return new GfxAxialShading(this);
1809 }
1810
1811 void GfxAxialShading::getColor(double t, GfxColor *color) {
1812   int i;
1813
1814   // NB: there can be one function with n outputs or n functions with
1815   // one output each (where n = number of color components)
1816   for (i = 0; i < nFuncs; ++i) {
1817     funcs[i]->transform(&t, &color->c[i]);
1818   }
1819 }
1820
1821 //------------------------------------------------------------------------
1822 // GfxRadialShading
1823 //------------------------------------------------------------------------
1824
1825 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
1826                                    double x1A, double y1A, double r1A,
1827                                    double t0A, double t1A,
1828                                    Function **funcsA, int nFuncsA,
1829                                    GBool extend0A, GBool extend1A):
1830   GfxShading(3)
1831 {
1832   int i;
1833
1834   x0 = x0A;
1835   y0 = y0A;
1836   r0 = r0A;
1837   x1 = x1A;
1838   y1 = y1A;
1839   r1 = r1A;
1840   t0 = t0A;
1841   t1 = t1A;
1842   nFuncs = nFuncsA;
1843   for (i = 0; i < nFuncs; ++i) {
1844     funcs[i] = funcsA[i];
1845   }
1846   extend0 = extend0A;
1847   extend1 = extend1A;
1848 }
1849
1850 GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
1851   GfxShading(shading)
1852 {
1853   int i;
1854
1855   x0 = shading->x0;
1856   y0 = shading->y0;
1857   r0 = shading->r0;
1858   x1 = shading->x1;
1859   y1 = shading->y1;
1860   r1 = shading->r1;
1861   t0 = shading->t0;
1862   y1 = shading->t1;
1863   nFuncs = shading->nFuncs;
1864   for (i = 0; i < nFuncs; ++i) {
1865     funcs[i] = shading->funcs[i]->copy();
1866   }
1867   extend0 = shading->extend0;
1868   extend1 = shading->extend1;
1869 }
1870
1871 GfxRadialShading::~GfxRadialShading() {
1872   int i;
1873
1874   for (i = 0; i < nFuncs; ++i) {
1875     delete funcs[i];
1876   }
1877 }
1878
1879 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
1880   GfxRadialShading *shading;
1881   double x0A, y0A, r0A, x1A, y1A, r1A;
1882   double t0A, t1A;
1883   Function *funcsA[gfxColorMaxComps];
1884   int nFuncsA;
1885   GBool extend0A, extend1A;
1886   Object obj1, obj2;
1887   int i;
1888
1889   x0A = y0A = r0A = x1A = y1A = r1A = 0;
1890   if (dict->lookup("Coords", &obj1)->isArray() &&
1891       obj1.arrayGetLength() == 6) {
1892     x0A = obj1.arrayGet(0, &obj2)->getNum();
1893     obj2.free();
1894     y0A = obj1.arrayGet(1, &obj2)->getNum();
1895     obj2.free();
1896     r0A = obj1.arrayGet(2, &obj2)->getNum();
1897     obj2.free();
1898     x1A = obj1.arrayGet(3, &obj2)->getNum();
1899     obj2.free();
1900     y1A = obj1.arrayGet(4, &obj2)->getNum();
1901     obj2.free();
1902     r1A = obj1.arrayGet(5, &obj2)->getNum();
1903     obj2.free();
1904   } else {
1905     error(-1, "Missing or invalid Coords in shading dictionary");
1906     goto err1;
1907   }
1908   obj1.free();
1909
1910   t0A = 0;
1911   t1A = 1;
1912   if (dict->lookup("Domain", &obj1)->isArray() &&
1913       obj1.arrayGetLength() == 2) {
1914     t0A = obj1.arrayGet(0, &obj2)->getNum();
1915     obj2.free();
1916     t1A = obj1.arrayGet(1, &obj2)->getNum();
1917     obj2.free();
1918   }
1919   obj1.free();
1920
1921   dict->lookup("Function", &obj1);
1922   if (obj1.isArray()) {
1923     nFuncsA = obj1.arrayGetLength();
1924     if (nFuncsA > gfxColorMaxComps) {
1925       error(-1, "Invalid Function array in shading dictionary");
1926       goto err1;
1927     }
1928     for (i = 0; i < nFuncsA; ++i) {
1929       obj1.arrayGet(i, &obj2);
1930       if (!(funcsA[i] = Function::parse(&obj2))) {
1931         obj1.free();
1932         obj2.free();
1933         goto err1;
1934       }
1935       obj2.free();
1936     }
1937   } else {
1938     nFuncsA = 1;
1939     if (!(funcsA[0] = Function::parse(&obj1))) {
1940       obj1.free();
1941       goto err1;
1942     }
1943   }
1944   obj1.free();
1945
1946   extend0A = extend1A = gFalse;
1947   if (dict->lookup("Extend", &obj1)->isArray() &&
1948       obj1.arrayGetLength() == 2) {
1949     extend0A = obj1.arrayGet(0, &obj2)->getBool();
1950     obj2.free();
1951     extend1A = obj1.arrayGet(1, &obj2)->getBool();
1952     obj2.free();
1953   }
1954   obj1.free();
1955
1956   shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
1957                                  funcsA, nFuncsA, extend0A, extend1A);
1958   if (!shading->init(dict)) {
1959     delete shading;
1960     return NULL;
1961   }
1962   return shading;
1963
1964  err1:
1965   return NULL;
1966 }
1967
1968 GfxShading *GfxRadialShading::copy() {
1969   return new GfxRadialShading(this);
1970 }
1971
1972 void GfxRadialShading::getColor(double t, GfxColor *color) {
1973   int i;
1974
1975   // NB: there can be one function with n outputs or n functions with
1976   // one output each (where n = number of color components)
1977   for (i = 0; i < nFuncs; ++i) {
1978     funcs[i]->transform(&t, &color->c[i]);
1979   }
1980 }
1981
1982 //------------------------------------------------------------------------
1983 // GfxImageColorMap
1984 //------------------------------------------------------------------------
1985
1986 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1987                                    GfxColorSpace *colorSpaceA) {
1988   GfxIndexedColorSpace *indexedCS;
1989   GfxSeparationColorSpace *sepCS;
1990   int maxPixel, indexHigh;
1991   Guchar *lookup2;
1992   Function *sepFunc;
1993   Object obj;
1994   double x[gfxColorMaxComps];
1995   double y[gfxColorMaxComps];
1996   int i, j, k;
1997   int maxPixelForAlloc;
1998
1999   ok = gTrue;
2000
2001   // bits per component and color space
2002   bits = bitsA;
2003   maxPixel = (1 << bits) - 1;
2004   maxPixelForAlloc = (1 << (bits>8?bits:8));
2005   colorSpace = colorSpaceA;
2006
2007   // get decode map
2008   if (decode->isNull()) {
2009     nComps = colorSpace->getNComps();
2010     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2011   } else if (decode->isArray()) {
2012     nComps = decode->arrayGetLength() / 2;
2013     if (nComps != colorSpace->getNComps()) {
2014       goto err1;
2015     }
2016     for (i = 0; i < nComps; ++i) {
2017       decode->arrayGet(2*i, &obj);
2018       if (!obj.isNum()) {
2019         goto err2;
2020       }
2021       decodeLow[i] = obj.getNum();
2022       obj.free();
2023       decode->arrayGet(2*i+1, &obj);
2024       if (!obj.isNum()) {
2025         goto err2;
2026       }
2027       decodeRange[i] = obj.getNum() - decodeLow[i];
2028       obj.free();
2029     }
2030   } else {
2031     goto err1;
2032   }
2033
2034   // Construct a lookup table -- this stores pre-computed decoded
2035   // values for each component, i.e., the result of applying the
2036   // decode mapping to each possible image pixel component value.
2037   //
2038   // Optimization: for Indexed and Separation color spaces (which have
2039   // only one component), we store color values in the lookup table
2040   // rather than component values.
2041   colorSpace2 = NULL;
2042   nComps2 = 0;
2043   if (colorSpace->getMode() == csIndexed) {
2044     // Note that indexHigh may not be the same as maxPixel --
2045     // Distiller will remove unused palette entries, resulting in
2046     // indexHigh < maxPixel.
2047     indexedCS = (GfxIndexedColorSpace *)colorSpace;
2048     colorSpace2 = indexedCS->getBase();
2049     indexHigh = indexedCS->getIndexHigh();
2050     nComps2 = colorSpace2->getNComps();
2051     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2052     lookup2 = indexedCS->getLookup();
2053     colorSpace2->getDefaultRanges(x, y, indexHigh);
2054     for (i = 0; i <= maxPixel; ++i) {
2055       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
2056       if (j < 0) {
2057         j = 0;
2058       } else if (j > indexHigh) {
2059         j = indexHigh;
2060       }
2061       for (k = 0; k < nComps2; ++k) {
2062         lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k];
2063       }
2064     }
2065   } else if (colorSpace->getMode() == csSeparation) {
2066     sepCS = (GfxSeparationColorSpace *)colorSpace;
2067     colorSpace2 = sepCS->getAlt();
2068     nComps2 = colorSpace2->getNComps();
2069     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps2 * sizeof(double));
2070     sepFunc = sepCS->getFunc();
2071     for (i = 0; i <= maxPixel; ++i) {
2072       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2073       sepFunc->transform(x, y);
2074       for (k = 0; k < nComps2; ++k) {
2075         lookup[i*nComps2 + k] = y[k];
2076       }
2077     }
2078   } else {
2079     lookup = (double *)gmalloc((maxPixelForAlloc + 1) * nComps * sizeof(double));
2080     for (i = 0; i <= maxPixel; ++i) {
2081       for (k = 0; k < nComps; ++k) {
2082         lookup[i*nComps + k] = decodeLow[k] +
2083                                  (i * decodeRange[k]) / maxPixel;
2084       }
2085     }
2086   }
2087
2088   return;
2089
2090  err2:
2091   obj.free();
2092  err1:
2093   ok = gFalse;
2094 }
2095
2096 GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
2097   int n, i;
2098
2099   colorSpace = colorMap->colorSpace->copy();
2100   bits = colorMap->bits;
2101   nComps = colorMap->nComps;
2102   nComps2 = colorMap->nComps2;
2103   colorSpace2 = NULL;
2104   lookup = NULL;
2105   n = 1 << bits;
2106   if (colorSpace->getMode() == csIndexed) {
2107     colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
2108     n = n * nComps2 * sizeof(double);
2109   } else if (colorSpace->getMode() == csSeparation) {
2110     colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
2111     n = n * nComps2 * sizeof(double);
2112   } else {
2113     n = n * nComps * sizeof(double);
2114   }
2115   lookup = (double *)gmalloc(n);
2116   memcpy(lookup, colorMap->lookup, n);
2117   for (i = 0; i < nComps; ++i) {
2118     decodeLow[i] = colorMap->decodeLow[i];
2119     decodeRange[i] = colorMap->decodeRange[i];
2120   }
2121   ok = gTrue;
2122 }
2123
2124 GfxImageColorMap::~GfxImageColorMap() {
2125   delete colorSpace;
2126   gfree(lookup);
2127 }
2128
2129 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2130   GfxColor color;
2131   double *p;
2132   int i;
2133
2134   if (colorSpace2) {
2135     p = &lookup[x[0] * nComps2];
2136     for (i = 0; i < nComps2; ++i) {
2137       color.c[i] = *p++;
2138     }
2139     colorSpace2->getGray(&color, gray);
2140   } else {
2141     for (i = 0; i < nComps; ++i) {
2142       color.c[i] = lookup[x[i] * nComps + i];
2143     }
2144     colorSpace->getGray(&color, gray);
2145   }
2146 }
2147
2148 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2149   GfxColor color;
2150   double *p;
2151   int i;
2152
2153   if (colorSpace2) {
2154     p = &lookup[x[0] * nComps2];
2155     for (i = 0; i < nComps2; ++i) {
2156       color.c[i] = *p++;
2157     }
2158     colorSpace2->getRGB(&color, rgb);
2159   } else {
2160     for (i = 0; i < nComps; ++i) {
2161       color.c[i] = lookup[x[i] * nComps + i];
2162     }
2163     colorSpace->getRGB(&color, rgb);
2164   }
2165 }
2166
2167 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2168   GfxColor color;
2169   double *p;
2170   int i;
2171
2172   if (colorSpace2) {
2173     p = &lookup[x[0] * nComps2];
2174     for (i = 0; i < nComps2; ++i) {
2175       color.c[i] = *p++;
2176     }
2177     colorSpace2->getCMYK(&color, cmyk);
2178   } else {
2179     for (i = 0; i < nComps; ++i) {
2180       color.c[i] = lookup[x[i] * nComps + i];
2181     }
2182     colorSpace->getCMYK(&color, cmyk);
2183   }
2184 }
2185
2186 void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
2187   int maxPixel, i;
2188
2189   maxPixel = (1 << bits) - 1;
2190   for (i = 0; i < nComps; ++i) {
2191     color->c[i] = decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel;
2192   }
2193 }
2194
2195 //------------------------------------------------------------------------
2196 // GfxSubpath and GfxPath
2197 //------------------------------------------------------------------------
2198
2199 GfxSubpath::GfxSubpath(double x1, double y1) {
2200   size = 16;
2201   x = (double *)gmalloc(size * sizeof(double));
2202   y = (double *)gmalloc(size * sizeof(double));
2203   curve = (GBool *)gmalloc(size * sizeof(GBool));
2204   n = 1;
2205   x[0] = x1;
2206   y[0] = y1;
2207   curve[0] = gFalse;
2208   closed = gFalse;
2209 }
2210
2211 GfxSubpath::~GfxSubpath() {
2212   gfree(x);
2213   gfree(y);
2214   gfree(curve);
2215 }
2216
2217 // Used for copy().
2218 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2219   size = subpath->size;
2220   n = subpath->n;
2221   x = (double *)gmalloc(size * sizeof(double));
2222   y = (double *)gmalloc(size * sizeof(double));
2223   curve = (GBool *)gmalloc(size * sizeof(GBool));
2224   memcpy(x, subpath->x, n * sizeof(double));
2225   memcpy(y, subpath->y, n * sizeof(double));
2226   memcpy(curve, subpath->curve, n * sizeof(GBool));
2227   closed = subpath->closed;
2228 }
2229
2230 void GfxSubpath::lineTo(double x1, double y1) {
2231   if (n >= size) {
2232     size += 16;
2233     x = (double *)grealloc(x, size * sizeof(double));
2234     y = (double *)grealloc(y, size * sizeof(double));
2235     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2236   }
2237   x[n] = x1;
2238   y[n] = y1;
2239   curve[n] = gFalse;
2240   ++n;
2241 }
2242
2243 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2244                          double x3, double y3) {
2245   if (n+3 > size) {
2246     size += 16;
2247     x = (double *)grealloc(x, size * sizeof(double));
2248     y = (double *)grealloc(y, size * sizeof(double));
2249     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2250   }
2251   x[n] = x1;
2252   y[n] = y1;
2253   x[n+1] = x2;
2254   y[n+1] = y2;
2255   x[n+2] = x3;
2256   y[n+2] = y3;
2257   curve[n] = curve[n+1] = gTrue;
2258   curve[n+2] = gFalse;
2259   n += 3;
2260 }
2261
2262 void GfxSubpath::close() {
2263   if (x[n-1] != x[0] || y[n-1] != y[0]) {
2264     lineTo(x[0], y[0]);
2265   }
2266   closed = gTrue;
2267 }
2268
2269 void GfxSubpath::offset(double dx, double dy) {
2270   int i;
2271
2272   for (i = 0; i < n; ++i) {
2273     x[i] += dx;
2274     y[i] += dy;
2275   }
2276 }
2277
2278 GfxPath::GfxPath() {
2279   justMoved = gFalse;
2280   size = 16;
2281   n = 0;
2282   firstX = firstY = 0;
2283   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2284 }
2285
2286 GfxPath::~GfxPath() {
2287   int i;
2288
2289   for (i = 0; i < n; ++i)
2290     delete subpaths[i];
2291   gfree(subpaths);
2292 }
2293
2294 // Used for copy().
2295 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2296                  GfxSubpath **subpaths1, int n1, int size1) {
2297   int i;
2298
2299   justMoved = justMoved1;
2300   firstX = firstX1;
2301   firstY = firstY1;
2302   size = size1;
2303   n = n1;
2304   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2305   for (i = 0; i < n; ++i)
2306     subpaths[i] = subpaths1[i]->copy();
2307 }
2308
2309 void GfxPath::moveTo(double x, double y) {
2310   justMoved = gTrue;
2311   firstX = x;
2312   firstY = y;
2313 }
2314
2315 void GfxPath::lineTo(double x, double y) {
2316   if (justMoved) {
2317     if (n >= size) {
2318       size += 16;
2319       subpaths = (GfxSubpath **)
2320                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2321     }
2322     subpaths[n] = new GfxSubpath(firstX, firstY);
2323     ++n;
2324     justMoved = gFalse;
2325   }
2326   subpaths[n-1]->lineTo(x, y);
2327 }
2328
2329 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2330              double x3, double y3) {
2331   if (justMoved) {
2332     if (n >= size) {
2333       size += 16;
2334       subpaths = (GfxSubpath **)
2335                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2336     }
2337     subpaths[n] = new GfxSubpath(firstX, firstY);
2338     ++n;
2339     justMoved = gFalse;
2340   }
2341   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2342 }
2343
2344 void GfxPath::close() {
2345   // this is necessary to handle the pathological case of
2346   // moveto/closepath/clip, which defines an empty clipping region
2347   if (justMoved) {
2348     if (n >= size) {
2349       size += 16;
2350       subpaths = (GfxSubpath **)
2351                    grealloc(subpaths, size * sizeof(GfxSubpath *));
2352     }
2353     subpaths[n] = new GfxSubpath(firstX, firstY);
2354     ++n;
2355     justMoved = gFalse;
2356   }
2357   subpaths[n-1]->close();
2358 }
2359
2360 void GfxPath::append(GfxPath *path) {
2361   int i;
2362
2363   if (n + path->n > size) {
2364     size = n + path->n;
2365     subpaths = (GfxSubpath **)
2366                  grealloc(subpaths, size * sizeof(GfxSubpath *));
2367   }
2368   for (i = 0; i < path->n; ++i) {
2369     subpaths[n++] = path->subpaths[i]->copy();
2370   }
2371   justMoved = gFalse;
2372 }
2373
2374 void GfxPath::offset(double dx, double dy) {
2375   int i;
2376
2377   for (i = 0; i < n; ++i) {
2378     subpaths[i]->offset(dx, dy);
2379   }
2380 }
2381
2382 //------------------------------------------------------------------------
2383 // GfxState
2384 //------------------------------------------------------------------------
2385
2386 GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
2387                    int rotate, GBool upsideDown) {
2388   double kx, ky;
2389
2390   px1 = pageBox->x1;
2391   py1 = pageBox->y1;
2392   px2 = pageBox->x2;
2393   py2 = pageBox->y2;
2394   kx = hDPI / 72.0;
2395   ky = vDPI / 72.0;
2396   if (rotate == 90) {
2397     ctm[0] = 0;
2398     ctm[1] = upsideDown ? ky : -ky;
2399     ctm[2] = kx;
2400     ctm[3] = 0;
2401     ctm[4] = -kx * py1;
2402     ctm[5] = ky * (upsideDown ? -px1 : px2);
2403     pageWidth = kx * (py2 - py1);
2404     pageHeight = ky * (px2 - px1);
2405   } else if (rotate == 180) {
2406     ctm[0] = -kx;
2407     ctm[1] = 0;
2408     ctm[2] = 0;
2409     ctm[3] = upsideDown ? ky : -ky;
2410     ctm[4] = kx * px2;
2411     ctm[5] = ky * (upsideDown ? -py1 : py2);
2412     pageWidth = kx * (px2 - px1);
2413     pageHeight = ky * (py2 - py1);
2414   } else if (rotate == 270) {
2415     ctm[0] = 0;
2416     ctm[1] = upsideDown ? -ky : ky;
2417     ctm[2] = -kx;
2418     ctm[3] = 0;
2419     ctm[4] = kx * py2;
2420     ctm[5] = ky * (upsideDown ? px2 : -px1);
2421     pageWidth = kx * (py2 - py1);
2422     pageHeight = ky * (px2 - px1);
2423   } else {
2424     ctm[0] = kx;
2425     ctm[1] = 0;
2426     ctm[2] = 0;
2427     ctm[3] = upsideDown ? -ky : ky;
2428     ctm[4] = -kx * px1;
2429     ctm[5] = ky * (upsideDown ? py2 : -py1);
2430     pageWidth = kx * (px2 - px1);
2431     pageHeight = ky * (py2 - py1);
2432   }
2433
2434   fillColorSpace = new GfxDeviceGrayColorSpace();
2435   strokeColorSpace = new GfxDeviceGrayColorSpace();
2436   fillColor.c[0] = 0;
2437   strokeColor.c[0] = 0;
2438   fillPattern = NULL;
2439   strokePattern = NULL;
2440   fillOpacity = 1;
2441   strokeOpacity = 1;
2442
2443   lineWidth = 1;
2444   lineDash = NULL;
2445   lineDashLength = 0;
2446   lineDashStart = 0;
2447   flatness = 1;
2448   lineJoin = 0;
2449   lineCap = 0;
2450   miterLimit = 10;
2451
2452   font = NULL;
2453   fontSize = 0;
2454   textMat[0] = 1; textMat[1] = 0;
2455   textMat[2] = 0; textMat[3] = 1;
2456   textMat[4] = 0; textMat[5] = 0;
2457   charSpace = 0;
2458   wordSpace = 0;
2459   horizScaling = 1;
2460   leading = 0;
2461   rise = 0;
2462   render = 0;
2463
2464   path = new GfxPath();
2465   curX = curY = 0;
2466   lineX = lineY = 0;
2467
2468   clipXMin = 0;
2469   clipYMin = 0;
2470   clipXMax = pageWidth;
2471   clipYMax = pageHeight;
2472
2473   saved = NULL;
2474 }
2475
2476 GfxState::~GfxState() {
2477   if (fillColorSpace) {
2478     delete fillColorSpace;
2479   }
2480   if (strokeColorSpace) {
2481     delete strokeColorSpace;
2482   }
2483   if (fillPattern) {
2484     delete fillPattern;
2485   }
2486   if (strokePattern) {
2487     delete strokePattern;
2488   }
2489   gfree(lineDash);
2490   if (path) {
2491     // this gets set to NULL by restore()
2492     delete path;
2493   }
2494   if (saved) {
2495     delete saved;
2496   }
2497 }
2498
2499 // Used for copy();
2500 GfxState::GfxState(GfxState *state) {
2501   memcpy(this, state, sizeof(GfxState));
2502   if (fillColorSpace) {
2503     fillColorSpace = state->fillColorSpace->copy();
2504   }
2505   if (strokeColorSpace) {
2506     strokeColorSpace = state->strokeColorSpace->copy();
2507   }
2508   if (fillPattern) {
2509     fillPattern = state->fillPattern->copy();
2510   }
2511   if (strokePattern) {
2512     strokePattern = state->strokePattern->copy();
2513   }
2514   if (lineDashLength > 0) {
2515     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2516     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2517   }
2518   saved = NULL;
2519 }
2520
2521 void GfxState::setPath(GfxPath *pathA) {
2522   delete path;
2523   path = pathA;
2524 }
2525
2526 void GfxState::getUserClipBBox(double *xMin, double *yMin,
2527                                double *xMax, double *yMax) {
2528   double ictm[6];
2529   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
2530
2531   // invert the CTM
2532   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2533   ictm[0] = ctm[3] * det;
2534   ictm[1] = -ctm[1] * det;
2535   ictm[2] = -ctm[2] * det;
2536   ictm[3] = ctm[0] * det;
2537   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2538   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2539
2540   // transform all four corners of the clip bbox; find the min and max
2541   // x and y values
2542   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
2543   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
2544   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
2545   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
2546   if (tx < xMin1) {
2547     xMin1 = tx;
2548   } else if (tx > xMax1) {
2549     xMax1 = tx;
2550   }
2551   if (ty < yMin1) {
2552     yMin1 = ty;
2553   } else if (ty > yMax1) {
2554     yMax1 = ty;
2555   }
2556   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
2557   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
2558   if (tx < xMin1) {
2559     xMin1 = tx;
2560   } else if (tx > xMax1) {
2561     xMax1 = tx;
2562   }
2563   if (ty < yMin1) {
2564     yMin1 = ty;
2565   } else if (ty > yMax1) {
2566     yMax1 = ty;
2567   }
2568   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
2569   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
2570   if (tx < xMin1) {
2571     xMin1 = tx;
2572   } else if (tx > xMax1) {
2573     xMax1 = tx;
2574   }
2575   if (ty < yMin1) {
2576     yMin1 = ty;
2577   } else if (ty > yMax1) {
2578     yMax1 = ty;
2579   }
2580
2581   *xMin = xMin1;
2582   *yMin = yMin1;
2583   *xMax = xMax1;
2584   *yMax = yMax1;
2585 }
2586
2587 double GfxState::transformWidth(double w) {
2588   double x, y;
2589
2590   x = ctm[0] + ctm[2];
2591   y = ctm[1] + ctm[3];
2592   return w * sqrt(0.5 * (x * x + y * y));
2593 }
2594
2595 double GfxState::getTransformedFontSize() {
2596   double x1, y1, x2, y2;
2597
2598   x1 = textMat[2] * fontSize;
2599   y1 = textMat[3] * fontSize;
2600   x2 = ctm[0] * x1 + ctm[2] * y1;
2601   y2 = ctm[1] * x1 + ctm[3] * y1;
2602   return sqrt(x2 * x2 + y2 * y2);
2603 }
2604
2605 void GfxState::getFontTransMat(double *m11, double *m12,
2606                                double *m21, double *m22) {
2607   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
2608   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
2609   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
2610   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
2611 }
2612
2613 void GfxState::setCTM(double a, double b, double c,
2614                       double d, double e, double f) {
2615   int i;
2616
2617   ctm[0] = a;
2618   ctm[1] = b;
2619   ctm[2] = c;
2620   ctm[3] = d;
2621   ctm[4] = e;
2622   ctm[5] = f;
2623
2624   // avoid FP exceptions on badly messed up PDF files
2625   for (i = 0; i < 6; ++i) {
2626     if (ctm[i] > 1e10) {
2627       ctm[i] = 1e10;
2628     } else if (ctm[i] < -1e10) {
2629       ctm[i] = -1e10;
2630     }
2631   }
2632 }
2633
2634 void GfxState::concatCTM(double a, double b, double c,
2635                          double d, double e, double f) {
2636   double a1 = ctm[0];
2637   double b1 = ctm[1];
2638   double c1 = ctm[2];
2639   double d1 = ctm[3];
2640   int i;
2641
2642   ctm[0] = a * a1 + b * c1;
2643   ctm[1] = a * b1 + b * d1;
2644   ctm[2] = c * a1 + d * c1;
2645   ctm[3] = c * b1 + d * d1;
2646   ctm[4] = e * a1 + f * c1 + ctm[4];
2647   ctm[5] = e * b1 + f * d1 + ctm[5];
2648
2649   // avoid FP exceptions on badly messed up PDF files
2650   for (i = 0; i < 6; ++i) {
2651     if (ctm[i] > 1e10) {
2652       ctm[i] = 1e10;
2653     } else if (ctm[i] < -1e10) {
2654       ctm[i] = -1e10;
2655     }
2656   }
2657 }
2658
2659 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
2660   if (fillColorSpace) {
2661     delete fillColorSpace;
2662   }
2663   fillColorSpace = colorSpace;
2664 }
2665
2666 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
2667   if (strokeColorSpace) {
2668     delete strokeColorSpace;
2669   }
2670   strokeColorSpace = colorSpace;
2671 }
2672
2673 void GfxState::setFillPattern(GfxPattern *pattern) {
2674   if (fillPattern) {
2675     delete fillPattern;
2676   }
2677   fillPattern = pattern;
2678 }
2679
2680 void GfxState::setStrokePattern(GfxPattern *pattern) {
2681   if (strokePattern) {
2682     delete strokePattern;
2683   }
2684   strokePattern = pattern;
2685 }
2686
2687 void GfxState::setLineDash(double *dash, int length, double start) {
2688   if (lineDash)
2689     gfree(lineDash);
2690   lineDash = dash;
2691   lineDashLength = length;
2692   lineDashStart = start;
2693 }
2694
2695 void GfxState::clearPath() {
2696   delete path;
2697   path = new GfxPath();
2698 }
2699
2700 void GfxState::clip() {
2701   double xMin, yMin, xMax, yMax, x, y;
2702   GfxSubpath *subpath;
2703   int i, j;
2704
2705   xMin = xMax = yMin = yMax = 0; // make gcc happy
2706   for (i = 0; i < path->getNumSubpaths(); ++i) {
2707     subpath = path->getSubpath(i);
2708     for (j = 0; j < subpath->getNumPoints(); ++j) {
2709       transform(subpath->getX(j), subpath->getY(j), &x, &y);
2710       if (i == 0 && j == 0) {
2711         xMin = xMax = x;
2712         yMin = yMax = y;
2713       } else {
2714         if (x < xMin) {
2715           xMin = x;
2716         } else if (x > xMax) {
2717           xMax = x;
2718         }
2719         if (y < yMin) {
2720           yMin = y;
2721         } else if (y > yMax) {
2722           yMax = y;
2723         }
2724       }
2725     }
2726   }
2727   if (xMin > clipXMin) {
2728     clipXMin = xMin;
2729   }
2730   if (yMin > clipYMin) {
2731     clipYMin = yMin;
2732   }
2733   if (xMax < clipXMax) {
2734     clipXMax = xMax;
2735   }
2736   if (yMax < clipYMax) {
2737     clipYMax = yMax;
2738   }
2739 }
2740
2741 void GfxState::textShift(double tx, double ty) {
2742   double dx, dy;
2743
2744   textTransformDelta(tx, ty, &dx, &dy);
2745   curX += dx;
2746   curY += dy;
2747 }
2748
2749 void GfxState::shift(double dx, double dy) {
2750   curX += dx;
2751   curY += dy;
2752 }
2753
2754 GfxState *GfxState::save() {
2755   GfxState *newState;
2756
2757   newState = copy();
2758   newState->saved = this;
2759   return newState;
2760 }
2761
2762 GfxState *GfxState::restore() {
2763   GfxState *oldState;
2764
2765   if (saved) {
2766     oldState = saved;
2767
2768     // these attributes aren't saved/restored by the q/Q operators
2769     oldState->path = path;
2770     oldState->curX = curX;
2771     oldState->curY = curY;
2772     oldState->lineX = lineX;
2773     oldState->lineY = lineY;
2774
2775     path = NULL;
2776     saved = NULL;
2777     delete this;
2778
2779   } else {
2780     oldState = this;
2781   }
2782
2783   return oldState;
2784 }