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