w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

GfxState.cc
Go to the documentation of this file.
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996-2016 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>
18 #include "gmem.h"
19 #include "gmempp.h"
20 #include "Error.h"
21 #include "GlobalParams.h"
22 #include "Object.h"
23 #include "Array.h"
24 #include "Page.h"
25 #include "XRef.h"
26 #include "GfxState.h"
27 
28 //------------------------------------------------------------------------
29 
30 // Max depth of nested color spaces. This is used to catch infinite
31 // loops in the color space object structure.
32 #define colorSpaceRecursionLimit 8
33 
34 
35 //------------------------------------------------------------------------
36 
38  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
39 }
40 
41 static inline double clip01(double x) {
42  return (x < 0) ? 0 : (x > 1) ? 1 : x;
43 }
44 
45 //------------------------------------------------------------------------
46 
48  const char *name;
50 };
51 
53  { "Normal", gfxBlendNormal },
54  { "Compatible", gfxBlendNormal },
55  { "Multiply", gfxBlendMultiply },
56  { "Screen", gfxBlendScreen },
57  { "Overlay", gfxBlendOverlay },
58  { "Darken", gfxBlendDarken },
59  { "Lighten", gfxBlendLighten },
60  { "ColorDodge", gfxBlendColorDodge },
61  { "ColorBurn", gfxBlendColorBurn },
62  { "HardLight", gfxBlendHardLight },
63  { "SoftLight", gfxBlendSoftLight },
64  { "Difference", gfxBlendDifference },
65  { "Exclusion", gfxBlendExclusion },
66  { "Hue", gfxBlendHue },
67  { "Saturation", gfxBlendSaturation },
68  { "Color", gfxBlendColor },
69  { "Luminosity", gfxBlendLuminosity }
70 };
71 
72 #define nGfxBlendModeNames \
73  ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
74 
75 //------------------------------------------------------------------------
76 
77 // NB: This must match the GfxColorSpaceMode enum defined in
78 // GfxState.h
79 static const char *gfxColorSpaceModeNames[] = {
80  "DeviceGray",
81  "CalGray",
82  "DeviceRGB",
83  "CalRGB",
84  "DeviceCMYK",
85  "Lab",
86  "ICCBased",
87  "Indexed",
88  "Separation",
89  "DeviceN",
90  "Pattern"
91 };
92 
93 #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
94 
95 
96 
97 
98 //------------------------------------------------------------------------
99 // GfxColorSpace
100 //------------------------------------------------------------------------
101 
103  overprintMask = 0x0f;
105 }
106 
108 }
109 
111  int recursion) {
112  GfxColorSpace *cs;
113  Object obj1;
114 
115  if (recursion > colorSpaceRecursionLimit) {
116  error(errSyntaxError, -1, "Loop detected in color space objects");
117  return NULL;
118  }
119  cs = NULL;
120  if (csObj->isName()) {
121  if (csObj->isName("DeviceGray") || csObj->isName("G")) {
123  } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
125  } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
127  } else if (csObj->isName("Pattern")) {
129  } else {
130  error(errSyntaxError, -1, "Bad color space '{0:s}'", csObj->getName());
131  }
132  } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
133  csObj->arrayGet(0, &obj1);
134  if (obj1.isName("DeviceGray") || obj1.isName("G")) {
136  } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
138  } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
140  } else if (obj1.isName("CalGray")) {
141  cs = GfxCalGrayColorSpace::parse(csObj->getArray(), recursion);
142  } else if (obj1.isName("CalRGB")) {
143  cs = GfxCalRGBColorSpace::parse(csObj->getArray(), recursion);
144  } else if (obj1.isName("Lab")) {
145  cs = GfxLabColorSpace::parse(csObj->getArray(), recursion);
146  } else if (obj1.isName("ICCBased")) {
148  recursion);
149  } else if (obj1.isName("Indexed") || obj1.isName("I")) {
151  recursion);
152  } else if (obj1.isName("Separation")) {
154  recursion);
155  } else if (obj1.isName("DeviceN")) {
157  recursion);
158  } else if (obj1.isName("Pattern")) {
160  recursion);
161  } else {
162  error(errSyntaxError, -1, "Bad color space");
163  }
164  obj1.free();
165  } else {
166  error(errSyntaxError, -1, "Bad color space - expected name or array");
167  }
168  return cs;
169 }
170 
172  GfxColorSpace *cs;
173 
174  cs = NULL;
175  if (mode == csDeviceGray) {
176  cs = new GfxDeviceGrayColorSpace();
177  } else if (mode == csDeviceRGB) {
178  cs = new GfxDeviceRGBColorSpace();
179  } else if (mode == csDeviceCMYK) {
180  cs = new GfxDeviceCMYKColorSpace();
181  }
182  return cs;
183 }
184 
185 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
186  int maxImgPixel) {
187  int i;
188 
189  for (i = 0; i < getNComps(); ++i) {
190  decodeLow[i] = 0;
191  decodeRange[i] = 1;
192  }
193 }
194 
196  return nGfxColorSpaceModes;
197 }
198 
200  return gfxColorSpaceModeNames[idx];
201 }
202 
203 //------------------------------------------------------------------------
204 // GfxDeviceGrayColorSpace
205 //------------------------------------------------------------------------
206 
208 }
209 
211 }
212 
215 
216  cs = new GfxDeviceGrayColorSpace();
217  return cs;
218 }
219 
220 
222  GfxRenderingIntent ri) {
223  *gray = clip01(color->c[0]);
224 }
225 
227  GfxRenderingIntent ri) {
228  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
229 }
230 
232  GfxRenderingIntent ri) {
233  cmyk->c = cmyk->m = cmyk->y = 0;
234  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
235 }
236 
237 
238 
240  color->c[0] = 0;
241 }
242 
243 //------------------------------------------------------------------------
244 // GfxCalGrayColorSpace
245 //------------------------------------------------------------------------
246 
248  whiteX = whiteY = whiteZ = 1;
249  blackX = blackY = blackZ = 0;
250  gamma = 1;
251 }
252 
254 }
255 
258 
259  cs = new GfxCalGrayColorSpace();
260  cs->whiteX = whiteX;
261  cs->whiteY = whiteY;
262  cs->whiteZ = whiteZ;
263  cs->blackX = blackX;
264  cs->blackY = blackY;
265  cs->blackZ = blackZ;
266  cs->gamma = gamma;
267  return cs;
268 }
269 
270 
273  Object obj1, obj2, obj3;
274 
275  if (arr->getLength() < 2) {
276  error(errSyntaxError, -1, "Bad CalGray color space");
277  return NULL;
278  }
279  arr->get(1, &obj1);
280  if (!obj1.isDict()) {
281  error(errSyntaxError, -1, "Bad CalGray color space");
282  obj1.free();
283  return NULL;
284  }
285  cs = new GfxCalGrayColorSpace();
286  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
287  obj2.arrayGetLength() == 3) {
288  obj2.arrayGet(0, &obj3);
289  cs->whiteX = obj3.getNum();
290  obj3.free();
291  obj2.arrayGet(1, &obj3);
292  cs->whiteY = obj3.getNum();
293  obj3.free();
294  obj2.arrayGet(2, &obj3);
295  cs->whiteZ = obj3.getNum();
296  obj3.free();
297  }
298  obj2.free();
299  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
300  obj2.arrayGetLength() == 3) {
301  obj2.arrayGet(0, &obj3);
302  cs->blackX = obj3.getNum();
303  obj3.free();
304  obj2.arrayGet(1, &obj3);
305  cs->blackY = obj3.getNum();
306  obj3.free();
307  obj2.arrayGet(2, &obj3);
308  cs->blackZ = obj3.getNum();
309  obj3.free();
310  }
311  obj2.free();
312  if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
313  cs->gamma = obj2.getNum();
314  }
315  obj2.free();
316  obj1.free();
317  return cs;
318 }
319 
321  GfxRenderingIntent ri) {
322  *gray = clip01(color->c[0]);
323 }
324 
326  GfxRenderingIntent ri) {
327  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
328 }
329 
331  GfxRenderingIntent ri) {
332  cmyk->c = cmyk->m = cmyk->y = 0;
333  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
334 }
335 
336 
337 
339  color->c[0] = 0;
340 }
341 
342 //------------------------------------------------------------------------
343 // GfxDeviceRGBColorSpace
344 //------------------------------------------------------------------------
345 
347 }
348 
350 }
351 
354 
355  cs = new GfxDeviceRGBColorSpace();
356  return cs;
357 }
358 
359 
361  GfxRenderingIntent ri) {
362  *gray = clip01((GfxColorComp)(0.3 * color->c[0] +
363  0.59 * color->c[1] +
364  0.11 * color->c[2] + 0.5));
365 }
366 
368  GfxRenderingIntent ri) {
369  rgb->r = clip01(color->c[0]);
370  rgb->g = clip01(color->c[1]);
371  rgb->b = clip01(color->c[2]);
372 }
373 
375  GfxRenderingIntent ri) {
376  GfxColorComp c, m, y, k;
377 
378  c = clip01(gfxColorComp1 - color->c[0]);
379  m = clip01(gfxColorComp1 - color->c[1]);
380  y = clip01(gfxColorComp1 - color->c[2]);
381  k = c;
382  if (m < k) {
383  k = m;
384  }
385  if (y < k) {
386  k = y;
387  }
388  cmyk->c = c - k;
389  cmyk->m = m - k;
390  cmyk->y = y - k;
391  cmyk->k = k;
392 }
393 
394 
395 
397  color->c[0] = 0;
398  color->c[1] = 0;
399  color->c[2] = 0;
400 }
401 
402 //------------------------------------------------------------------------
403 // GfxCalRGBColorSpace
404 //------------------------------------------------------------------------
405 
407  whiteX = whiteY = whiteZ = 1;
408  blackX = blackY = blackZ = 0;
409  gammaR = gammaG = gammaB = 1;
410  mat[0] = 1; mat[1] = 0; mat[2] = 0;
411  mat[3] = 0; mat[4] = 1; mat[5] = 0;
412  mat[6] = 0; mat[7] = 0; mat[8] = 1;
413 }
414 
416 }
417 
420  int i;
421 
422  cs = new GfxCalRGBColorSpace();
423  cs->whiteX = whiteX;
424  cs->whiteY = whiteY;
425  cs->whiteZ = whiteZ;
426  cs->blackX = blackX;
427  cs->blackY = blackY;
428  cs->blackZ = blackZ;
429  cs->gammaR = gammaR;
430  cs->gammaG = gammaG;
431  cs->gammaB = gammaB;
432  for (i = 0; i < 9; ++i) {
433  cs->mat[i] = mat[i];
434  }
435  return cs;
436 }
437 
440  Object obj1, obj2, obj3;
441  int i;
442 
443  if (arr->getLength() < 2) {
444  error(errSyntaxError, -1, "Bad CalRGB color space");
445  return NULL;
446  }
447  arr->get(1, &obj1);
448  if (!obj1.isDict()) {
449  error(errSyntaxError, -1, "Bad CalRGB color space");
450  obj1.free();
451  return NULL;
452  }
453  cs = new GfxCalRGBColorSpace();
454  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
455  obj2.arrayGetLength() == 3) {
456  obj2.arrayGet(0, &obj3);
457  cs->whiteX = obj3.getNum();
458  obj3.free();
459  obj2.arrayGet(1, &obj3);
460  cs->whiteY = obj3.getNum();
461  obj3.free();
462  obj2.arrayGet(2, &obj3);
463  cs->whiteZ = obj3.getNum();
464  obj3.free();
465  }
466  obj2.free();
467  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
468  obj2.arrayGetLength() == 3) {
469  obj2.arrayGet(0, &obj3);
470  cs->blackX = obj3.getNum();
471  obj3.free();
472  obj2.arrayGet(1, &obj3);
473  cs->blackY = obj3.getNum();
474  obj3.free();
475  obj2.arrayGet(2, &obj3);
476  cs->blackZ = obj3.getNum();
477  obj3.free();
478  }
479  obj2.free();
480  if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
481  obj2.arrayGetLength() == 3) {
482  obj2.arrayGet(0, &obj3);
483  cs->gammaR = obj3.getNum();
484  obj3.free();
485  obj2.arrayGet(1, &obj3);
486  cs->gammaG = obj3.getNum();
487  obj3.free();
488  obj2.arrayGet(2, &obj3);
489  cs->gammaB = obj3.getNum();
490  obj3.free();
491  }
492  obj2.free();
493  if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
494  obj2.arrayGetLength() == 9) {
495  for (i = 0; i < 9; ++i) {
496  obj2.arrayGet(i, &obj3);
497  cs->mat[i] = obj3.getNum();
498  obj3.free();
499  }
500  }
501  obj2.free();
502  obj1.free();
503  return cs;
504 }
505 
506 
508  GfxRenderingIntent ri) {
509  *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
510  0.587 * color->c[1] +
511  0.114 * color->c[2] + 0.5));
512 }
513 
515  GfxRenderingIntent ri) {
516  rgb->r = clip01(color->c[0]);
517  rgb->g = clip01(color->c[1]);
518  rgb->b = clip01(color->c[2]);
519 }
520 
522  GfxRenderingIntent ri) {
523  GfxColorComp c, m, y, k;
524 
525  c = clip01(gfxColorComp1 - color->c[0]);
526  m = clip01(gfxColorComp1 - color->c[1]);
527  y = clip01(gfxColorComp1 - color->c[2]);
528  k = c;
529  if (m < k) {
530  k = m;
531  }
532  if (y < k) {
533  k = y;
534  }
535  cmyk->c = c - k;
536  cmyk->m = m - k;
537  cmyk->y = y - k;
538  cmyk->k = k;
539 }
540 
541 
542 
544  color->c[0] = 0;
545  color->c[1] = 0;
546  color->c[2] = 0;
547 }
548 
549 //------------------------------------------------------------------------
550 // GfxDeviceCMYKColorSpace
551 //------------------------------------------------------------------------
552 
554 }
555 
557 }
558 
561 
562  cs = new GfxDeviceCMYKColorSpace();
563  return cs;
564 }
565 
566 
568  GfxRenderingIntent ri) {
570  - 0.3 * color->c[0]
571  - 0.59 * color->c[1]
572  - 0.11 * color->c[2] + 0.5));
573 }
574 
576  GfxRenderingIntent ri) {
577  double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
578 
579  c = colToDbl(color->c[0]);
580  m = colToDbl(color->c[1]);
581  y = colToDbl(color->c[2]);
582  k = colToDbl(color->c[3]);
583  c1 = 1 - c;
584  m1 = 1 - m;
585  y1 = 1 - y;
586  k1 = 1 - k;
587  // this is a matrix multiplication, unrolled for performance
588  // C M Y K
589  x = c1 * m1 * y1 * k1; // 0 0 0 0
590  r = g = b = x;
591  x = c1 * m1 * y1 * k; // 0 0 0 1
592  r += 0.1373 * x;
593  g += 0.1216 * x;
594  b += 0.1255 * x;
595  x = c1 * m1 * y * k1; // 0 0 1 0
596  r += x;
597  g += 0.9490 * x;
598  x = c1 * m1 * y * k; // 0 0 1 1
599  r += 0.1098 * x;
600  g += 0.1020 * x;
601  x = c1 * m * y1 * k1; // 0 1 0 0
602  r += 0.9255 * x;
603  b += 0.5490 * x;
604  x = c1 * m * y1 * k; // 0 1 0 1
605  r += 0.1412 * x;
606  x = c1 * m * y * k1; // 0 1 1 0
607  r += 0.9294 * x;
608  g += 0.1098 * x;
609  b += 0.1412 * x;
610  x = c1 * m * y * k; // 0 1 1 1
611  r += 0.1333 * x;
612  x = c * m1 * y1 * k1; // 1 0 0 0
613  g += 0.6784 * x;
614  b += 0.9373 * x;
615  x = c * m1 * y1 * k; // 1 0 0 1
616  g += 0.0588 * x;
617  b += 0.1412 * x;
618  x = c * m1 * y * k1; // 1 0 1 0
619  g += 0.6510 * x;
620  b += 0.3137 * x;
621  x = c * m1 * y * k; // 1 0 1 1
622  g += 0.0745 * x;
623  x = c * m * y1 * k1; // 1 1 0 0
624  r += 0.1804 * x;
625  g += 0.1922 * x;
626  b += 0.5725 * x;
627  x = c * m * y1 * k; // 1 1 0 1
628  b += 0.0078 * x;
629  x = c * m * y * k1; // 1 1 1 0
630  r += 0.2118 * x;
631  g += 0.2119 * x;
632  b += 0.2235 * x;
633  rgb->r = clip01(dblToCol(r));
634  rgb->g = clip01(dblToCol(g));
635  rgb->b = clip01(dblToCol(b));
636 }
637 
639  GfxRenderingIntent ri) {
640  cmyk->c = clip01(color->c[0]);
641  cmyk->m = clip01(color->c[1]);
642  cmyk->y = clip01(color->c[2]);
643  cmyk->k = clip01(color->c[3]);
644 }
645 
646 
647 
649  color->c[0] = 0;
650  color->c[1] = 0;
651  color->c[2] = 0;
652  color->c[3] = gfxColorComp1;
653 }
654 
655 
656 //------------------------------------------------------------------------
657 // GfxLabColorSpace
658 //------------------------------------------------------------------------
659 
660 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
661 // Language Reference, Third Edition.
662 static double xyzrgb[3][3] = {
663  { 3.240449, -1.537136, -0.498531 },
664  { -0.969265, 1.876011, 0.041556 },
665  { 0.055643, -0.204026, 1.057229 }
666 };
667 
669  whiteX = whiteY = whiteZ = 1;
670  blackX = blackY = blackZ = 0;
671  aMin = bMin = -100;
672  aMax = bMax = 100;
673 }
674 
676 }
677 
680 
681  cs = new GfxLabColorSpace();
682  cs->whiteX = whiteX;
683  cs->whiteY = whiteY;
684  cs->whiteZ = whiteZ;
685  cs->blackX = blackX;
686  cs->blackY = blackY;
687  cs->blackZ = blackZ;
688  cs->aMin = aMin;
689  cs->aMax = aMax;
690  cs->bMin = bMin;
691  cs->bMax = bMax;
692  cs->kr = kr;
693  cs->kg = kg;
694  cs->kb = kb;
695  return cs;
696 }
697 
700  Object obj1, obj2, obj3;
701 
702  if (arr->getLength() < 2) {
703  error(errSyntaxError, -1, "Bad Lab color space");
704  return NULL;
705  }
706  arr->get(1, &obj1);
707  if (!obj1.isDict()) {
708  error(errSyntaxError, -1, "Bad Lab color space");
709  obj1.free();
710  return NULL;
711  }
712  cs = new GfxLabColorSpace();
713  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
714  obj2.arrayGetLength() == 3) {
715  obj2.arrayGet(0, &obj3);
716  cs->whiteX = obj3.getNum();
717  obj3.free();
718  obj2.arrayGet(1, &obj3);
719  cs->whiteY = obj3.getNum();
720  obj3.free();
721  obj2.arrayGet(2, &obj3);
722  cs->whiteZ = obj3.getNum();
723  obj3.free();
724  }
725  obj2.free();
726  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
727  obj2.arrayGetLength() == 3) {
728  obj2.arrayGet(0, &obj3);
729  cs->blackX = obj3.getNum();
730  obj3.free();
731  obj2.arrayGet(1, &obj3);
732  cs->blackY = obj3.getNum();
733  obj3.free();
734  obj2.arrayGet(2, &obj3);
735  cs->blackZ = obj3.getNum();
736  obj3.free();
737  }
738  obj2.free();
739  if (obj1.dictLookup("Range", &obj2)->isArray() &&
740  obj2.arrayGetLength() == 4) {
741  obj2.arrayGet(0, &obj3);
742  cs->aMin = obj3.getNum();
743  obj3.free();
744  obj2.arrayGet(1, &obj3);
745  cs->aMax = obj3.getNum();
746  obj3.free();
747  obj2.arrayGet(2, &obj3);
748  cs->bMin = obj3.getNum();
749  obj3.free();
750  obj2.arrayGet(3, &obj3);
751  cs->bMax = obj3.getNum();
752  obj3.free();
753  }
754  obj2.free();
755  obj1.free();
756 
757  cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
758  xyzrgb[0][1] * cs->whiteY +
759  xyzrgb[0][2] * cs->whiteZ);
760  cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
761  xyzrgb[1][1] * cs->whiteY +
762  xyzrgb[1][2] * cs->whiteZ);
763  cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
764  xyzrgb[2][1] * cs->whiteY +
765  xyzrgb[2][2] * cs->whiteZ);
766 
767  return cs;
768 }
769 
770 
772  GfxRenderingIntent ri) {
773  GfxRGB rgb;
774 
775  getRGB(color, &rgb, ri);
776  *gray = clip01((GfxColorComp)(0.299 * rgb.r +
777  0.587 * rgb.g +
778  0.114 * rgb.b + 0.5));
779 }
780 
782  GfxRenderingIntent ri) {
783  double X, Y, Z;
784  double t1, t2;
785  double r, g, b;
786 
787 
788  // convert L*a*b* to CIE 1931 XYZ color space
789  t1 = (colToDbl(color->c[0]) + 16) / 116;
790  t2 = t1 + colToDbl(color->c[1]) / 500;
791  if (t2 >= (6.0 / 29.0)) {
792  X = t2 * t2 * t2;
793  } else {
794  X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
795  }
796  X *= whiteX;
797  if (t1 >= (6.0 / 29.0)) {
798  Y = t1 * t1 * t1;
799  } else {
800  Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
801  }
802  Y *= whiteY;
803  t2 = t1 - colToDbl(color->c[2]) / 200;
804  if (t2 >= (6.0 / 29.0)) {
805  Z = t2 * t2 * t2;
806  } else {
807  Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
808  }
809  Z *= whiteZ;
810 
811  // convert XYZ to RGB, including gamut mapping and gamma correction
812  r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
813  g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
814  b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
815  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
816  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
817  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
818 }
819 
821  GfxRenderingIntent ri) {
822  GfxRGB rgb;
823  GfxColorComp c, m, y, k;
824 
825 
826  getRGB(color, &rgb, ri);
827  c = clip01(gfxColorComp1 - rgb.r);
828  m = clip01(gfxColorComp1 - rgb.g);
829  y = clip01(gfxColorComp1 - rgb.b);
830  k = c;
831  if (m < k) {
832  k = m;
833  }
834  if (y < k) {
835  k = y;
836  }
837  cmyk->c = c - k;
838  cmyk->m = m - k;
839  cmyk->y = y - k;
840  cmyk->k = k;
841 }
842 
843 
844 
846  color->c[0] = 0;
847  if (aMin > 0) {
848  color->c[1] = dblToCol(aMin);
849  } else if (aMax < 0) {
850  color->c[1] = dblToCol(aMax);
851  } else {
852  color->c[1] = 0;
853  }
854  if (bMin > 0) {
855  color->c[2] = dblToCol(bMin);
856  } else if (bMax < 0) {
857  color->c[2] = dblToCol(bMax);
858  } else {
859  color->c[2] = 0;
860  }
861 }
862 
863 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
864  int maxImgPixel) {
865  decodeLow[0] = 0;
866  decodeRange[0] = 100;
867  decodeLow[1] = aMin;
868  decodeRange[1] = aMax - aMin;
869  decodeLow[2] = bMin;
870  decodeRange[2] = bMax - bMin;
871 }
872 
873 //------------------------------------------------------------------------
874 // GfxICCBasedColorSpace
875 //------------------------------------------------------------------------
876 
878  Ref *iccProfileStreamA) {
879  nComps = nCompsA;
880  alt = altA;
881  iccProfileStream = *iccProfileStreamA;
882  rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
883  rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
884 }
885 
887  delete alt;
888 }
889 
892  int i;
893 
895  for (i = 0; i < 4; ++i) {
896  cs->rangeMin[i] = rangeMin[i];
897  cs->rangeMax[i] = rangeMax[i];
898  }
899  return cs;
900 }
901 
903  int recursion) {
905  Ref iccProfileStreamA;
906  int nCompsA;
907  GfxColorSpace *altA;
908  Dict *dict;
909  Object obj1, obj2, obj3;
910  int i;
911 
912  if (arr->getLength() < 2) {
913  error(errSyntaxError, -1, "Bad ICCBased color space");
914  return NULL;
915  }
916  arr->getNF(1, &obj1);
917  if (obj1.isRef()) {
918  iccProfileStreamA = obj1.getRef();
919  } else {
920  iccProfileStreamA.num = 0;
921  iccProfileStreamA.gen = 0;
922  }
923  obj1.free();
924  arr->get(1, &obj1);
925  if (!obj1.isStream()) {
926  error(errSyntaxError, -1, "Bad ICCBased color space (stream)");
927  obj1.free();
928  return NULL;
929  }
930  dict = obj1.streamGetDict();
931  if (!dict->lookup("N", &obj2)->isInt()) {
932  error(errSyntaxError, -1, "Bad ICCBased color space (N)");
933  obj2.free();
934  obj1.free();
935  return NULL;
936  }
937  nCompsA = obj2.getInt();
938  obj2.free();
939  if (nCompsA > 4) {
940  error(errSyntaxError, -1,
941  "ICCBased color space with too many ({0:d} > 4) components",
942  nCompsA);
943  nCompsA = 4;
944  }
945  if (dict->lookup("Alternate", &obj2)->isNull() ||
946  !(altA = GfxColorSpace::parse(&obj2,
947  recursion + 1))) {
948  switch (nCompsA) {
949  case 1:
951  break;
952  case 3:
954  break;
955  case 4:
957  break;
958  default:
959  error(errSyntaxError, -1, "Bad ICCBased color space - invalid N");
960  obj2.free();
961  obj1.free();
962  return NULL;
963  }
964  }
965  obj2.free();
966  cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
967  if (dict->lookup("Range", &obj2)->isArray() &&
968  obj2.arrayGetLength() == 2 * nCompsA) {
969  for (i = 0; i < nCompsA; ++i) {
970  obj2.arrayGet(2*i, &obj3);
971  cs->rangeMin[i] = obj3.getNum();
972  obj3.free();
973  obj2.arrayGet(2*i+1, &obj3);
974  cs->rangeMax[i] = obj3.getNum();
975  obj3.free();
976  }
977  }
978  obj2.free();
979  obj1.free();
980  return cs;
981 }
982 
983 
985  GfxRenderingIntent ri) {
986  alt->getGray(color, gray, ri);
987 }
988 
990  GfxRenderingIntent ri) {
991  alt->getRGB(color, rgb, ri);
992 }
993 
995  GfxRenderingIntent ri) {
996  alt->getCMYK(color, cmyk, ri);
997 }
998 
999 
1000 
1002  int i;
1003 
1004  for (i = 0; i < nComps; ++i) {
1005  if (rangeMin[i] > 0) {
1006  color->c[i] = dblToCol(rangeMin[i]);
1007  } else if (rangeMax[i] < 0) {
1008  color->c[i] = dblToCol(rangeMax[i]);
1009  } else {
1010  color->c[i] = 0;
1011  }
1012  }
1013 }
1014 
1016  double *decodeRange,
1017  int maxImgPixel) {
1018  alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
1019 
1020 #if 0
1021  // this is nominally correct, but some PDF files don't set the
1022  // correct ranges in the ICCBased dict
1023  int i;
1024 
1025  for (i = 0; i < nComps; ++i) {
1026  decodeLow[i] = rangeMin[i];
1027  decodeRange[i] = rangeMax[i] - rangeMin[i];
1028  }
1029 #endif
1030 }
1031 
1032 
1033 //------------------------------------------------------------------------
1034 // GfxIndexedColorSpace
1035 //------------------------------------------------------------------------
1036 
1038  int indexHighA) {
1039  base = baseA;
1040  indexHigh = indexHighA;
1041  lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
1042  sizeof(Guchar));
1044 }
1045 
1047  delete base;
1048  gfree(lookup);
1049 }
1050 
1053 
1055  memcpy(cs->lookup, lookup,
1056  (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
1057  return cs;
1058 }
1059 
1061  int recursion) {
1063  GfxColorSpace *baseA;
1064  int indexHighA;
1065  Object obj1;
1066  int x;
1067  char *s;
1068  int n, i, j;
1069 
1070  if (arr->getLength() != 4) {
1071  error(errSyntaxError, -1, "Bad Indexed color space");
1072  goto err1;
1073  }
1074  arr->get(1, &obj1);
1075  if (!(baseA = GfxColorSpace::parse(&obj1,
1076  recursion + 1))) {
1077  error(errSyntaxError, -1, "Bad Indexed color space (base color space)");
1078  goto err2;
1079  }
1080  obj1.free();
1081  if (!arr->get(2, &obj1)->isInt()) {
1082  error(errSyntaxError, -1, "Bad Indexed color space (hival)");
1083  delete baseA;
1084  goto err2;
1085  }
1086  indexHighA = obj1.getInt();
1087  if (indexHighA < 0 || indexHighA > 255) {
1088  // the PDF spec requires indexHigh to be in [0,255] -- allowing
1089  // values larger than 255 creates a security hole: if nComps *
1090  // indexHigh is greater than 2^31, the loop below may overwrite
1091  // past the end of the array
1092  error(errSyntaxError, -1,
1093  "Bad Indexed color space (invalid indexHigh value)");
1094  delete baseA;
1095  goto err2;
1096  }
1097  obj1.free();
1098  cs = new GfxIndexedColorSpace(baseA, indexHighA);
1099  arr->get(3, &obj1);
1100  n = baseA->getNComps();
1101  if (obj1.isStream()) {
1102  obj1.streamReset();
1103  for (i = 0; i <= indexHighA; ++i) {
1104  for (j = 0; j < n; ++j) {
1105  if ((x = obj1.streamGetChar()) == EOF) {
1106  error(errSyntaxError, -1,
1107  "Bad Indexed color space (lookup table stream too short)");
1108  cs->indexHigh = indexHighA = i - 1;
1109  if (cs->indexHigh < 0) {
1110  goto err3;
1111  }
1112  }
1113  cs->lookup[i*n + j] = (Guchar)x;
1114  }
1115  }
1116  obj1.streamClose();
1117  } else if (obj1.isString()) {
1118  if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
1119  error(errSyntaxError, -1,
1120  "Bad Indexed color space (lookup table string too short)");
1121  cs->indexHigh = indexHighA = obj1.getString()->getLength() / n - 1;
1122  if (cs->indexHigh < 0) {
1123  goto err3;
1124  }
1125  }
1126  s = obj1.getString()->getCString();
1127  for (i = 0; i <= indexHighA; ++i) {
1128  for (j = 0; j < n; ++j) {
1129  cs->lookup[i*n + j] = (Guchar)*s++;
1130  }
1131  }
1132  } else {
1133  error(errSyntaxError, -1, "Bad Indexed color space (lookup table)");
1134  goto err3;
1135  }
1136  obj1.free();
1137  return cs;
1138 
1139  err3:
1140  delete cs;
1141  err2:
1142  obj1.free();
1143  err1:
1144  return NULL;
1145 }
1146 
1147 
1149  GfxColor *baseColor) {
1150  Guchar *p;
1152  int n, i, k;
1153 
1154  n = base->getNComps();
1156  k = (int)(colToDbl(color->c[0]) + 0.5);
1157  if (k < 0) {
1158  k = 0;
1159  } else if (k > indexHigh) {
1160  k = indexHigh;
1161  }
1162  p = &lookup[k * n];
1163  for (i = 0; i < n; ++i) {
1164  baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
1165  }
1166  return baseColor;
1167 }
1168 
1170  GfxRenderingIntent ri) {
1171  GfxColor color2;
1172 
1173  base->getGray(mapColorToBase(color, &color2), gray, ri);
1174 }
1175 
1177  GfxRenderingIntent ri) {
1178  GfxColor color2;
1179 
1180  base->getRGB(mapColorToBase(color, &color2), rgb, ri);
1181 }
1182 
1184  GfxRenderingIntent ri) {
1185  GfxColor color2;
1186 
1187  base->getCMYK(mapColorToBase(color, &color2), cmyk, ri);
1188 }
1189 
1190 
1191 
1193  color->c[0] = 0;
1194 }
1195 
1197  double *decodeRange,
1198  int maxImgPixel) {
1199  decodeLow[0] = 0;
1200  decodeRange[0] = maxImgPixel;
1201 }
1202 
1203 //------------------------------------------------------------------------
1204 // GfxSeparationColorSpace
1205 //------------------------------------------------------------------------
1206 
1208  GfxColorSpace *altA,
1209  Function *funcA) {
1210  name = nameA;
1211  alt = altA;
1212  func = funcA;
1213  nonMarking = !name->cmp("None");
1214  if (!name->cmp("Cyan")) {
1215  overprintMask = 0x01;
1216  } else if (!name->cmp("Magenta")) {
1217  overprintMask = 0x02;
1218  } else if (!name->cmp("Yellow")) {
1219  overprintMask = 0x04;
1220  } else if (!name->cmp("Black")) {
1221  overprintMask = 0x08;
1222  }
1223 }
1224 
1226  GfxColorSpace *altA,
1227  Function *funcA,
1228  GBool nonMarkingA,
1229  Guint overprintMaskA) {
1230  name = nameA;
1231  alt = altA;
1232  func = funcA;
1233  nonMarking = nonMarkingA;
1234  overprintMask = overprintMaskA;
1235 }
1236 
1238  delete name;
1239  delete alt;
1240  delete func;
1241 }
1242 
1245 
1246  cs = new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
1248  return cs;
1249 }
1250 
1252  int recursion) {
1254  GString *nameA;
1255  GfxColorSpace *altA;
1256  Function *funcA;
1257  Object obj1, obj2;
1258 
1259  if (arr->getLength() != 4) {
1260  error(errSyntaxError, -1, "Bad Separation color space");
1261  goto err1;
1262  }
1263  if (!arr->get(1, &obj1)->isName()) {
1264  error(errSyntaxError, -1, "Bad Separation color space (name)");
1265  goto err2;
1266  }
1267  nameA = new GString(obj1.getName());
1268  obj1.free();
1269  arr->get(2, &obj1);
1270  // some PDF generators use an ICC profile stream here; Adobe
1271  // apparently looks at the /Alternate entry in the stream dictionary
1272  if (obj1.isStream() &&
1273  !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1274  obj1.free();
1275  obj1 = obj2;
1276  }
1277  if (!(altA = GfxColorSpace::parse(&obj1,
1278  recursion + 1))) {
1279  error(errSyntaxError, -1,
1280  "Bad Separation color space (alternate color space)");
1281  goto err3;
1282  }
1283  obj1.free();
1284  arr->get(3, &obj1);
1285  if (!(funcA = Function::parse(&obj1, 1, altA->getNComps()))) {
1286  goto err4;
1287  }
1288  obj1.free();
1289  cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1290  return cs;
1291 
1292  err4:
1293  delete altA;
1294  err3:
1295  delete nameA;
1296  err2:
1297  obj1.free();
1298  err1:
1299  return NULL;
1300 }
1301 
1302 
1304  GfxRenderingIntent ri) {
1305  double x;
1306  double c[gfxColorMaxComps];
1307  GfxColor color2;
1308  int i;
1309 
1310  x = colToDbl(color->c[0]);
1311  func->transform(&x, c);
1312  for (i = 0; i < alt->getNComps(); ++i) {
1313  color2.c[i] = dblToCol(c[i]);
1314  }
1315  alt->getGray(&color2, gray, ri);
1316 }
1317 
1319  GfxRenderingIntent ri) {
1320  double x;
1321  double c[gfxColorMaxComps];
1322  GfxColor color2;
1323  int i;
1324 
1325  x = colToDbl(color->c[0]);
1326  func->transform(&x, c);
1327  for (i = 0; i < alt->getNComps(); ++i) {
1328  color2.c[i] = dblToCol(c[i]);
1329  }
1330  alt->getRGB(&color2, rgb, ri);
1331 }
1332 
1334  GfxRenderingIntent ri) {
1335  double x;
1336  double c[gfxColorMaxComps];
1337  GfxColor color2;
1338  int i;
1339 
1340  x = colToDbl(color->c[0]);
1341  func->transform(&x, c);
1342  for (i = 0; i < alt->getNComps(); ++i) {
1343  color2.c[i] = dblToCol(c[i]);
1344  }
1345  alt->getCMYK(&color2, cmyk, ri);
1346 }
1347 
1348 
1349 
1351  color->c[0] = gfxColorComp1;
1352 }
1353 
1354 //------------------------------------------------------------------------
1355 // GfxDeviceNColorSpace
1356 //------------------------------------------------------------------------
1357 
1359  GString **namesA,
1360  GfxColorSpace *altA,
1361  Function *funcA,
1362  Object *attrsA) {
1363  int i;
1364 
1365  nComps = nCompsA;
1366  alt = altA;
1367  func = funcA;
1368  attrsA->copy(&attrs);
1369  nonMarking = gTrue;
1370  overprintMask = 0;
1371  for (i = 0; i < nComps; ++i) {
1372  names[i] = namesA[i];
1373  if (names[i]->cmp("None")) {
1374  nonMarking = gFalse;
1375  }
1376  if (!names[i]->cmp("Cyan")) {
1377  overprintMask |= 0x01;
1378  } else if (!names[i]->cmp("Magenta")) {
1379  overprintMask |= 0x02;
1380  } else if (!names[i]->cmp("Yellow")) {
1381  overprintMask |= 0x04;
1382  } else if (!names[i]->cmp("Black")) {
1383  overprintMask |= 0x08;
1384  } else {
1385  overprintMask = 0x0f;
1386  }
1387  }
1388 }
1389 
1391  GString **namesA,
1392  GfxColorSpace *altA,
1393  Function *funcA,
1394  Object *attrsA,
1395  GBool nonMarkingA,
1396  Guint overprintMaskA) {
1397  int i;
1398 
1399  nComps = nCompsA;
1400  alt = altA;
1401  func = funcA;
1402  attrsA->copy(&attrs);
1403  nonMarking = nonMarkingA;
1404  overprintMask = overprintMaskA;
1405  for (i = 0; i < nComps; ++i) {
1406  names[i] = namesA[i]->copy();
1407  }
1408 }
1409 
1411  int i;
1412 
1413  for (i = 0; i < nComps; ++i) {
1414  delete names[i];
1415  }
1416  delete alt;
1417  delete func;
1418  attrs.free();
1419 }
1420 
1423 
1426  return cs;
1427 }
1428 
1430  int recursion) {
1432  int nCompsA;
1433  GString *namesA[gfxColorMaxComps];
1434  GfxColorSpace *altA;
1435  Function *funcA;
1436  Object attrsA, obj1, obj2;
1437  int i;
1438 
1439  if (arr->getLength() != 4 && arr->getLength() != 5) {
1440  error(errSyntaxError, -1, "Bad DeviceN color space");
1441  goto err1;
1442  }
1443  if (!arr->get(1, &obj1)->isArray()) {
1444  error(errSyntaxError, -1, "Bad DeviceN color space (names)");
1445  goto err2;
1446  }
1447  nCompsA = obj1.arrayGetLength();
1448  if (nCompsA > gfxColorMaxComps) {
1449  error(errSyntaxError, -1,
1450  "DeviceN color space with too many ({0:d} > {1:d}) components",
1451  nCompsA, gfxColorMaxComps);
1452  nCompsA = gfxColorMaxComps;
1453  }
1454  for (i = 0; i < nCompsA; ++i) {
1455  if (!obj1.arrayGet(i, &obj2)->isName()) {
1456  error(errSyntaxError, -1, "Bad DeviceN color space (names)");
1457  obj2.free();
1458  goto err2;
1459  }
1460  namesA[i] = new GString(obj2.getName());
1461  obj2.free();
1462  }
1463  obj1.free();
1464  arr->get(2, &obj1);
1465  // some PDF generators use an ICC profile stream here; Adobe
1466  // apparently looks at the /Alternate entry in the stream dictionary
1467  if (obj1.isStream() &&
1468  !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1469  obj1.free();
1470  obj1 = obj2;
1471  }
1472  if (!(altA = GfxColorSpace::parse(&obj1,
1473  recursion + 1))) {
1474  error(errSyntaxError, -1,
1475  "Bad DeviceN color space (alternate color space)");
1476  goto err3;
1477  }
1478  obj1.free();
1479  arr->get(3, &obj1);
1480  if (!(funcA = Function::parse(&obj1, nCompsA, altA->getNComps()))) {
1481  goto err4;
1482  }
1483  obj1.free();
1484  if (arr->getLength() == 5) {
1485  arr->get(4, &attrsA);
1486  } else {
1487  attrsA.initNull();
1488  }
1489  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, &attrsA);
1490  attrsA.free();
1491  return cs;
1492 
1493  err4:
1494  delete altA;
1495  err3:
1496  for (i = 0; i < nCompsA; ++i) {
1497  delete namesA[i];
1498  }
1499  err2:
1500  obj1.free();
1501  err1:
1502  return NULL;
1503 }
1504 
1505 
1507  GfxRenderingIntent ri) {
1509  GfxColor color2;
1510  int i;
1511 
1512  for (i = 0; i < nComps; ++i) {
1513  x[i] = colToDbl(color->c[i]);
1514  }
1515  func->transform(x, c);
1516  for (i = 0; i < alt->getNComps(); ++i) {
1517  color2.c[i] = dblToCol(c[i]);
1518  }
1519  alt->getGray(&color2, gray, ri);
1520 }
1521 
1523  GfxRenderingIntent ri) {
1525  GfxColor color2;
1526  int i;
1527 
1528  for (i = 0; i < nComps; ++i) {
1529  x[i] = colToDbl(color->c[i]);
1530  }
1531  func->transform(x, c);
1532  for (i = 0; i < alt->getNComps(); ++i) {
1533  color2.c[i] = dblToCol(c[i]);
1534  }
1535  alt->getRGB(&color2, rgb, ri);
1536 }
1537 
1539  GfxRenderingIntent ri) {
1541  GfxColor color2;
1542  int i;
1543 
1544  for (i = 0; i < nComps; ++i) {
1545  x[i] = colToDbl(color->c[i]);
1546  }
1547  func->transform(x, c);
1548  for (i = 0; i < alt->getNComps(); ++i) {
1549  color2.c[i] = dblToCol(c[i]);
1550  }
1551  alt->getCMYK(&color2, cmyk, ri);
1552 }
1553 
1554 
1555 
1557  int i;
1558 
1559  for (i = 0; i < nComps; ++i) {
1560  color->c[i] = gfxColorComp1;
1561  }
1562 }
1563 
1564 //------------------------------------------------------------------------
1565 // GfxPatternColorSpace
1566 //------------------------------------------------------------------------
1567 
1569  under = underA;
1570 }
1571 
1573  if (under) {
1574  delete under;
1575  }
1576 }
1577 
1580 
1581  cs = new GfxPatternColorSpace(under ? under->copy() :
1582  (GfxColorSpace *)NULL);
1583  return cs;
1584 }
1585 
1587  int recursion) {
1589  GfxColorSpace *underA;
1590  Object obj1;
1591 
1592  if (arr->getLength() != 1 && arr->getLength() != 2) {
1593  error(errSyntaxError, -1, "Bad Pattern color space");
1594  return NULL;
1595  }
1596  underA = NULL;
1597  if (arr->getLength() == 2) {
1598  arr->get(1, &obj1);
1599  if (!(underA = GfxColorSpace::parse(&obj1,
1600  recursion + 1))) {
1601  error(errSyntaxError, -1,
1602  "Bad Pattern color space (underlying color space)");
1603  obj1.free();
1604  return NULL;
1605  }
1606  obj1.free();
1607  }
1608  cs = new GfxPatternColorSpace(underA);
1609  return cs;
1610 }
1611 
1612 
1614  GfxRenderingIntent ri) {
1615  *gray = 0;
1616 }
1617 
1619  GfxRenderingIntent ri) {
1620  rgb->r = rgb->g = rgb->b = 0;
1621 }
1622 
1624  GfxRenderingIntent ri) {
1625  cmyk->c = cmyk->m = cmyk->y = 0;
1626  cmyk->k = 1;
1627 }
1628 
1629 
1630 
1632  // not used
1633 }
1634 
1635 //------------------------------------------------------------------------
1636 // Pattern
1637 //------------------------------------------------------------------------
1638 
1640  type = typeA;
1641 }
1642 
1644 }
1645 
1647  ) {
1649  Object typeObj;
1650 
1651  if (obj->isDict()) {
1652  obj->dictLookup("PatternType", &typeObj);
1653  } else if (obj->isStream()) {
1654  obj->streamGetDict()->lookup("PatternType", &typeObj);
1655  } else {
1656  return NULL;
1657  }
1658  pattern = NULL;
1659  if (typeObj.isInt() && typeObj.getInt() == 1) {
1661  } else if (typeObj.isInt() && typeObj.getInt() == 2) {
1663  );
1664  }
1665  typeObj.free();
1666  return pattern;
1667 }
1668 
1669 //------------------------------------------------------------------------
1670 // GfxTilingPattern
1671 //------------------------------------------------------------------------
1672 
1675  Dict *dict;
1676  int paintTypeA, tilingTypeA;
1677  double bboxA[4], matrixA[6];
1678  double xStepA, yStepA;
1679  Object resDictA;
1680  Object obj1, obj2;
1681  int i;
1682 
1683  if (!patObj->isStream()) {
1684  return NULL;
1685  }
1686  dict = patObj->streamGetDict();
1687 
1688  if (dict->lookup("PaintType", &obj1)->isInt()) {
1689  paintTypeA = obj1.getInt();
1690  } else {
1691  paintTypeA = 1;
1692  error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
1693  }
1694  obj1.free();
1695  if (dict->lookup("TilingType", &obj1)->isInt()) {
1696  tilingTypeA = obj1.getInt();
1697  } else {
1698  tilingTypeA = 1;
1699  error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
1700  }
1701  obj1.free();
1702  bboxA[0] = bboxA[1] = 0;
1703  bboxA[2] = bboxA[3] = 1;
1704  if (dict->lookup("BBox", &obj1)->isArray() &&
1705  obj1.arrayGetLength() == 4) {
1706  for (i = 0; i < 4; ++i) {
1707  if (obj1.arrayGet(i, &obj2)->isNum()) {
1708  bboxA[i] = obj2.getNum();
1709  }
1710  obj2.free();
1711  }
1712  } else {
1713  error(errSyntaxError, -1, "Invalid or missing BBox in pattern");
1714  }
1715  obj1.free();
1716  if (dict->lookup("XStep", &obj1)->isNum()) {
1717  xStepA = obj1.getNum();
1718  } else {
1719  xStepA = 1;
1720  error(errSyntaxError, -1, "Invalid or missing XStep in pattern");
1721  }
1722  obj1.free();
1723  if (dict->lookup("YStep", &obj1)->isNum()) {
1724  yStepA = obj1.getNum();
1725  } else {
1726  yStepA = 1;
1727  error(errSyntaxError, -1, "Invalid or missing YStep in pattern");
1728  }
1729  obj1.free();
1730  if (!dict->lookup("Resources", &resDictA)->isDict()) {
1731  resDictA.free();
1732  resDictA.initNull();
1733  error(errSyntaxError, -1, "Invalid or missing Resources in pattern");
1734  }
1735  matrixA[0] = 1; matrixA[1] = 0;
1736  matrixA[2] = 0; matrixA[3] = 1;
1737  matrixA[4] = 0; matrixA[5] = 0;
1738  if (dict->lookup("Matrix", &obj1)->isArray() &&
1739  obj1.arrayGetLength() == 6) {
1740  for (i = 0; i < 6; ++i) {
1741  if (obj1.arrayGet(i, &obj2)->isNum()) {
1742  matrixA[i] = obj2.getNum();
1743  }
1744  obj2.free();
1745  }
1746  }
1747  obj1.free();
1748 
1749  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1750  &resDictA, matrixA, patObjRef);
1751  resDictA.free();
1752  return pat;
1753 }
1754 
1755 GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1756  double *bboxA, double xStepA, double yStepA,
1757  Object *resDictA, double *matrixA,
1758  Object *contentStreamRefA):
1759  GfxPattern(1)
1760 {
1761  int i;
1762 
1763  paintType = paintTypeA;
1764  tilingType = tilingTypeA;
1765  for (i = 0; i < 4; ++i) {
1766  bbox[i] = bboxA[i];
1767  }
1768  xStep = xStepA;
1769  yStep = yStepA;
1770  resDictA->copy(&resDict);
1771  for (i = 0; i < 6; ++i) {
1772  matrix[i] = matrixA[i];
1773  }
1774  contentStreamRefA->copy(&contentStreamRef);
1775 }
1776 
1778  resDict.free();
1780 }
1781 
1785 }
1786 
1787 //------------------------------------------------------------------------
1788 // GfxShadingPattern
1789 //------------------------------------------------------------------------
1790 
1792  ) {
1793  Dict *dict;
1794  GfxShading *shadingA;
1795  double matrixA[6];
1796  Object obj1, obj2;
1797  int i;
1798 
1799  if (!patObj->isDict()) {
1800  return NULL;
1801  }
1802  dict = patObj->getDict();
1803 
1804  dict->lookup("Shading", &obj1);
1805  shadingA = GfxShading::parse(&obj1
1806  );
1807  obj1.free();
1808  if (!shadingA) {
1809  return NULL;
1810  }
1811 
1812  matrixA[0] = 1; matrixA[1] = 0;
1813  matrixA[2] = 0; matrixA[3] = 1;
1814  matrixA[4] = 0; matrixA[5] = 0;
1815  if (dict->lookup("Matrix", &obj1)->isArray() &&
1816  obj1.arrayGetLength() == 6) {
1817  for (i = 0; i < 6; ++i) {
1818  if (obj1.arrayGet(i, &obj2)->isNum()) {
1819  matrixA[i] = obj2.getNum();
1820  }
1821  obj2.free();
1822  }
1823  }
1824  obj1.free();
1825 
1826  return new GfxShadingPattern(shadingA, matrixA);
1827 }
1828 
1830  GfxPattern(2)
1831 {
1832  int i;
1833 
1834  shading = shadingA;
1835  for (i = 0; i < 6; ++i) {
1836  matrix[i] = matrixA[i];
1837  }
1838 }
1839 
1841  delete shading;
1842 }
1843 
1845  return new GfxShadingPattern(shading->copy(), matrix);
1846 }
1847 
1848 //------------------------------------------------------------------------
1849 // GfxShading
1850 //------------------------------------------------------------------------
1851 
1853  type = typeA;
1854  colorSpace = NULL;
1855 }
1856 
1858  int i;
1859 
1860  type = shading->type;
1861  colorSpace = shading->colorSpace->copy();
1862  for (i = 0; i < gfxColorMaxComps; ++i) {
1863  background.c[i] = shading->background.c[i];
1864  }
1865  hasBackground = shading->hasBackground;
1866  xMin = shading->xMin;
1867  yMin = shading->yMin;
1868  xMax = shading->xMax;
1869  yMax = shading->yMax;
1870  hasBBox = shading->hasBBox;
1871 }
1872 
1874  if (colorSpace) {
1875  delete colorSpace;
1876  }
1877 }
1878 
1880  ) {
1881  GfxShading *shading;
1882  Dict *dict;
1883  int typeA;
1884  Object obj1;
1885 
1886  if (obj->isDict()) {
1887  dict = obj->getDict();
1888  } else if (obj->isStream()) {
1889  dict = obj->streamGetDict();
1890  } else {
1891  return NULL;
1892  }
1893 
1894  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
1895  error(errSyntaxError, -1, "Invalid ShadingType in shading dictionary");
1896  obj1.free();
1897  return NULL;
1898  }
1899  typeA = obj1.getInt();
1900  obj1.free();
1901 
1902  switch (typeA) {
1903  case 1:
1904  shading = GfxFunctionShading::parse(dict
1905  );
1906  break;
1907  case 2:
1908  shading = GfxAxialShading::parse(dict
1909  );
1910  break;
1911  case 3:
1912  shading = GfxRadialShading::parse(dict
1913  );
1914  break;
1915  case 4:
1916  if (obj->isStream()) {
1917  shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()
1918  );
1919  } else {
1920  error(errSyntaxError, -1, "Invalid Type 4 shading object");
1921  goto err1;
1922  }
1923  break;
1924  case 5:
1925  if (obj->isStream()) {
1926  shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()
1927  );
1928  } else {
1929  error(errSyntaxError, -1, "Invalid Type 5 shading object");
1930  goto err1;
1931  }
1932  break;
1933  case 6:
1934  if (obj->isStream()) {
1935  shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()
1936  );
1937  } else {
1938  error(errSyntaxError, -1, "Invalid Type 6 shading object");
1939  goto err1;
1940  }
1941  break;
1942  case 7:
1943  if (obj->isStream()) {
1944  shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()
1945  );
1946  } else {
1947  error(errSyntaxError, -1, "Invalid Type 7 shading object");
1948  goto err1;
1949  }
1950  break;
1951  default:
1952  error(errSyntaxError, -1, "Unknown shading type {0:d}", typeA);
1953  goto err1;
1954  }
1955 
1956  return shading;
1957 
1958  err1:
1959  return NULL;
1960 }
1961 
1963  ) {
1964  Object obj1, obj2;
1965  int i;
1966 
1967  dict->lookup("ColorSpace", &obj1);
1968  if (!(colorSpace = GfxColorSpace::parse(&obj1
1969  ))) {
1970  error(errSyntaxError, -1, "Bad color space in shading dictionary");
1971  obj1.free();
1972  return gFalse;
1973  }
1974  obj1.free();
1975 
1976  for (i = 0; i < gfxColorMaxComps; ++i) {
1977  background.c[i] = 0;
1978  }
1980  if (dict->lookup("Background", &obj1)->isArray()) {
1981  if (obj1.arrayGetLength() == colorSpace->getNComps()) {
1982  hasBackground = gTrue;
1983  for (i = 0; i < colorSpace->getNComps(); ++i) {
1984  background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
1985  obj2.free();
1986  }
1987  } else {
1988  error(errSyntaxError, -1, "Bad Background in shading dictionary");
1989  }
1990  }
1991  obj1.free();
1992 
1993  xMin = yMin = xMax = yMax = 0;
1994  hasBBox = gFalse;
1995  if (dict->lookup("BBox", &obj1)->isArray()) {
1996  if (obj1.arrayGetLength() == 4) {
1997  hasBBox = gTrue;
1998  xMin = obj1.arrayGet(0, &obj2)->getNum();
1999  obj2.free();
2000  yMin = obj1.arrayGet(1, &obj2)->getNum();
2001  obj2.free();
2002  xMax = obj1.arrayGet(2, &obj2)->getNum();
2003  obj2.free();
2004  yMax = obj1.arrayGet(3, &obj2)->getNum();
2005  obj2.free();
2006  } else {
2007  error(errSyntaxError, -1, "Bad BBox in shading dictionary");
2008  }
2009  }
2010  obj1.free();
2011 
2012  return gTrue;
2013 }
2014 
2015 //------------------------------------------------------------------------
2016 // GfxFunctionShading
2017 //------------------------------------------------------------------------
2018 
2020  double x1A, double y1A,
2021  double *matrixA,
2022  Function **funcsA, int nFuncsA):
2023  GfxShading(1)
2024 {
2025  int i;
2026 
2027  x0 = x0A;
2028  y0 = y0A;
2029  x1 = x1A;
2030  y1 = y1A;
2031  for (i = 0; i < 6; ++i) {
2032  matrix[i] = matrixA[i];
2033  }
2034  nFuncs = nFuncsA;
2035  for (i = 0; i < nFuncs; ++i) {
2036  funcs[i] = funcsA[i];
2037  }
2038 }
2039 
2041  GfxShading(shading)
2042 {
2043  int i;
2044 
2045  x0 = shading->x0;
2046  y0 = shading->y0;
2047  x1 = shading->x1;
2048  y1 = shading->y1;
2049  for (i = 0; i < 6; ++i) {
2050  matrix[i] = shading->matrix[i];
2051  }
2052  nFuncs = shading->nFuncs;
2053  for (i = 0; i < nFuncs; ++i) {
2054  funcs[i] = shading->funcs[i]->copy();
2055  }
2056 }
2057 
2059  int i;
2060 
2061  for (i = 0; i < nFuncs; ++i) {
2062  delete funcs[i];
2063  }
2064 }
2065 
2067  ) {
2068  GfxFunctionShading *shading;
2069  double x0A, y0A, x1A, y1A;
2070  double matrixA[6];
2071  Function *funcsA[gfxColorMaxComps];
2072  int nFuncsA;
2073  Object obj1, obj2;
2074  int i;
2075 
2076  x0A = y0A = 0;
2077  x1A = y1A = 1;
2078  if (dict->lookup("Domain", &obj1)->isArray() &&
2079  obj1.arrayGetLength() == 4) {
2080  x0A = obj1.arrayGet(0, &obj2)->getNum();
2081  obj2.free();
2082  x1A = obj1.arrayGet(1, &obj2)->getNum();
2083  obj2.free();
2084  y0A = obj1.arrayGet(2, &obj2)->getNum();
2085  obj2.free();
2086  y1A = obj1.arrayGet(3, &obj2)->getNum();
2087  obj2.free();
2088  }
2089  obj1.free();
2090 
2091  matrixA[0] = 1; matrixA[1] = 0;
2092  matrixA[2] = 0; matrixA[3] = 1;
2093  matrixA[4] = 0; matrixA[5] = 0;
2094  if (dict->lookup("Matrix", &obj1)->isArray() &&
2095  obj1.arrayGetLength() == 6) {
2096  matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
2097  obj2.free();
2098  matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
2099  obj2.free();
2100  matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
2101  obj2.free();
2102  matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
2103  obj2.free();
2104  matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
2105  obj2.free();
2106  matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
2107  obj2.free();
2108  }
2109  obj1.free();
2110 
2111  dict->lookup("Function", &obj1);
2112  if (obj1.isArray()) {
2113  nFuncsA = obj1.arrayGetLength();
2114  if (nFuncsA > gfxColorMaxComps) {
2115  error(errSyntaxError, -1,
2116  "Invalid Function array in shading dictionary");
2117  goto err1;
2118  }
2119  for (i = 0; i < nFuncsA; ++i) {
2120  obj1.arrayGet(i, &obj2);
2121  if (!(funcsA[i] = Function::parse(&obj2, 2, 1))) {
2122  goto err2;
2123  }
2124  obj2.free();
2125  }
2126  } else {
2127  nFuncsA = 1;
2128  if (!(funcsA[0] = Function::parse(&obj1, 2, -1))) {
2129  goto err1;
2130  }
2131  }
2132  obj1.free();
2133 
2134  shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
2135  funcsA, nFuncsA);
2136  if (!shading->init(dict
2137  )) {
2138  delete shading;
2139  return NULL;
2140  }
2141 
2142  for (i = 0; i < shading->nFuncs; ++i) {
2143  if (shading->funcs[i]->getOutputSize()
2144  != shading->getColorSpace()->getNComps()) {
2145  error(errSyntaxError, -1, "Invalid function in shading dictionary");
2146  delete shading;
2147  return NULL;
2148  }
2149  }
2150 
2151  return shading;
2152 
2153  err2:
2154  obj2.free();
2155  err1:
2156  obj1.free();
2157  return NULL;
2158 }
2159 
2161  return new GfxFunctionShading(this);
2162 }
2163 
2165  double in[2], out[gfxColorMaxComps];
2166  int i;
2167 
2168  // NB: there can be one function with n outputs or n functions with
2169  // one output each (where n = number of color components)
2170  for (i = 0; i < gfxColorMaxComps; ++i) {
2171  out[i] = 0;
2172  }
2173  in[0] = x;
2174  in[1] = y;
2175  for (i = 0; i < nFuncs; ++i) {
2176  funcs[i]->transform(in, &out[i]);
2177  }
2178  for (i = 0; i < gfxColorMaxComps; ++i) {
2179  color->c[i] = dblToCol(out[i]);
2180  }
2181 }
2182 
2183 //------------------------------------------------------------------------
2184 // GfxAxialShading
2185 //------------------------------------------------------------------------
2186 
2187 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
2188  double x1A, double y1A,
2189  double t0A, double t1A,
2190  Function **funcsA, int nFuncsA,
2191  GBool extend0A, GBool extend1A):
2192  GfxShading(2)
2193 {
2194  int i;
2195 
2196  x0 = x0A;
2197  y0 = y0A;
2198  x1 = x1A;
2199  y1 = y1A;
2200  t0 = t0A;
2201  t1 = t1A;
2202  nFuncs = nFuncsA;
2203  for (i = 0; i < nFuncs; ++i) {
2204  funcs[i] = funcsA[i];
2205  }
2206  extend0 = extend0A;
2207  extend1 = extend1A;
2208 }
2209 
2211  GfxShading(shading)
2212 {
2213  int i;
2214 
2215  x0 = shading->x0;
2216  y0 = shading->y0;
2217  x1 = shading->x1;
2218  y1 = shading->y1;
2219  t0 = shading->t0;
2220  t1 = shading->t1;
2221  nFuncs = shading->nFuncs;
2222  for (i = 0; i < nFuncs; ++i) {
2223  funcs[i] = shading->funcs[i]->copy();
2224  }
2225  extend0 = shading->extend0;
2226  extend1 = shading->extend1;
2227 }
2228 
2230  int i;
2231 
2232  for (i = 0; i < nFuncs; ++i) {
2233  delete funcs[i];
2234  }
2235 }
2236 
2238  ) {
2239  GfxAxialShading *shading;
2240  double x0A, y0A, x1A, y1A;
2241  double t0A, t1A;
2242  Function *funcsA[gfxColorMaxComps];
2243  int nFuncsA;
2244  GBool extend0A, extend1A;
2245  Object obj1, obj2;
2246  int i;
2247 
2248  x0A = y0A = x1A = y1A = 0;
2249  if (dict->lookup("Coords", &obj1)->isArray() &&
2250  obj1.arrayGetLength() == 4) {
2251  x0A = obj1.arrayGet(0, &obj2)->getNum();
2252  obj2.free();
2253  y0A = obj1.arrayGet(1, &obj2)->getNum();
2254  obj2.free();
2255  x1A = obj1.arrayGet(2, &obj2)->getNum();
2256  obj2.free();
2257  y1A = obj1.arrayGet(3, &obj2)->getNum();
2258  obj2.free();
2259  } else {
2260  error(errSyntaxError, -1,
2261  "Missing or invalid Coords in shading dictionary");
2262  obj1.free();
2263  goto err1;
2264  }
2265  obj1.free();
2266 
2267  t0A = 0;
2268  t1A = 1;
2269  if (dict->lookup("Domain", &obj1)->isArray() &&
2270  obj1.arrayGetLength() == 2) {
2271  t0A = obj1.arrayGet(0, &obj2)->getNum();
2272  obj2.free();
2273  t1A = obj1.arrayGet(1, &obj2)->getNum();
2274  obj2.free();
2275  }
2276  obj1.free();
2277 
2278  dict->lookup("Function", &obj1);
2279  if (obj1.isArray()) {
2280  nFuncsA = obj1.arrayGetLength();
2281  if (nFuncsA > gfxColorMaxComps) {
2282  error(errSyntaxError, -1,
2283  "Invalid Function array in shading dictionary");
2284  goto err1;
2285  }
2286  for (i = 0; i < nFuncsA; ++i) {
2287  obj1.arrayGet(i, &obj2);
2288  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
2289  obj1.free();
2290  obj2.free();
2291  goto err1;
2292  }
2293  obj2.free();
2294  }
2295  } else {
2296  nFuncsA = 1;
2297  if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2298  obj1.free();
2299  goto err1;
2300  }
2301  }
2302  obj1.free();
2303 
2304  extend0A = extend1A = gFalse;
2305  if (dict->lookup("Extend", &obj1)->isArray() &&
2306  obj1.arrayGetLength() == 2) {
2307  extend0A = obj1.arrayGet(0, &obj2)->getBool();
2308  obj2.free();
2309  extend1A = obj1.arrayGet(1, &obj2)->getBool();
2310  obj2.free();
2311  }
2312  obj1.free();
2313 
2314  shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
2315  funcsA, nFuncsA, extend0A, extend1A);
2316  if (!shading->init(dict
2317  )) {
2318  delete shading;
2319  return NULL;
2320  }
2321 
2322  for (i = 0; i < shading->nFuncs; ++i) {
2323  if (shading->funcs[i]->getOutputSize()
2324  != shading->getColorSpace()->getNComps()) {
2325  error(errSyntaxError, -1, "Invalid function in shading dictionary");
2326  delete shading;
2327  return NULL;
2328  }
2329  }
2330 
2331  return shading;
2332 
2333  err1:
2334  return NULL;
2335 }
2336 
2338  return new GfxAxialShading(this);
2339 }
2340 
2342  double out[gfxColorMaxComps];
2343  int i;
2344 
2345  // NB: there can be one function with n outputs or n functions with
2346  // one output each (where n = number of color components)
2347  for (i = 0; i < gfxColorMaxComps; ++i) {
2348  out[i] = 0;
2349  }
2350  for (i = 0; i < nFuncs; ++i) {
2351  funcs[i]->transform(&t, &out[i]);
2352  }
2353  for (i = 0; i < gfxColorMaxComps; ++i) {
2354  color->c[i] = dblToCol(out[i]);
2355  }
2356 }
2357 
2358 //------------------------------------------------------------------------
2359 // GfxRadialShading
2360 //------------------------------------------------------------------------
2361 
2362 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
2363  double x1A, double y1A, double r1A,
2364  double t0A, double t1A,
2365  Function **funcsA, int nFuncsA,
2366  GBool extend0A, GBool extend1A):
2367  GfxShading(3)
2368 {
2369  int i;
2370 
2371  x0 = x0A;
2372  y0 = y0A;
2373  r0 = r0A;
2374  x1 = x1A;
2375  y1 = y1A;
2376  r1 = r1A;
2377  t0 = t0A;
2378  t1 = t1A;
2379  nFuncs = nFuncsA;
2380  for (i = 0; i < nFuncs; ++i) {
2381  funcs[i] = funcsA[i];
2382  }
2383  extend0 = extend0A;
2384  extend1 = extend1A;
2385 }
2386 
2388  GfxShading(shading)
2389 {
2390  int i;
2391 
2392  x0 = shading->x0;
2393  y0 = shading->y0;
2394  r0 = shading->r0;
2395  x1 = shading->x1;
2396  y1 = shading->y1;
2397  r1 = shading->r1;
2398  t0 = shading->t0;
2399  t1 = shading->t1;
2400  nFuncs = shading->nFuncs;
2401  for (i = 0; i < nFuncs; ++i) {
2402  funcs[i] = shading->funcs[i]->copy();
2403  }
2404  extend0 = shading->extend0;
2405  extend1 = shading->extend1;
2406 }
2407 
2409  int i;
2410 
2411  for (i = 0; i < nFuncs; ++i) {
2412  delete funcs[i];
2413  }
2414 }
2415 
2417  ) {
2418  GfxRadialShading *shading;
2419  double x0A, y0A, r0A, x1A, y1A, r1A;
2420  double t0A, t1A;
2421  Function *funcsA[gfxColorMaxComps];
2422  int nFuncsA;
2423  GBool extend0A, extend1A;
2424  Object obj1, obj2;
2425  int i;
2426 
2427  x0A = y0A = r0A = x1A = y1A = r1A = 0;
2428  if (dict->lookup("Coords", &obj1)->isArray() &&
2429  obj1.arrayGetLength() == 6) {
2430  x0A = obj1.arrayGet(0, &obj2)->getNum();
2431  obj2.free();
2432  y0A = obj1.arrayGet(1, &obj2)->getNum();
2433  obj2.free();
2434  r0A = obj1.arrayGet(2, &obj2)->getNum();
2435  obj2.free();
2436  x1A = obj1.arrayGet(3, &obj2)->getNum();
2437  obj2.free();
2438  y1A = obj1.arrayGet(4, &obj2)->getNum();
2439  obj2.free();
2440  r1A = obj1.arrayGet(5, &obj2)->getNum();
2441  obj2.free();
2442  } else {
2443  error(errSyntaxError, -1,
2444  "Missing or invalid Coords in shading dictionary");
2445  goto err1;
2446  }
2447  obj1.free();
2448 
2449  t0A = 0;
2450  t1A = 1;
2451  if (dict->lookup("Domain", &obj1)->isArray() &&
2452  obj1.arrayGetLength() == 2) {
2453  t0A = obj1.arrayGet(0, &obj2)->getNum();
2454  obj2.free();
2455  t1A = obj1.arrayGet(1, &obj2)->getNum();
2456  obj2.free();
2457  }
2458  obj1.free();
2459 
2460  dict->lookup("Function", &obj1);
2461  if (obj1.isArray()) {
2462  nFuncsA = obj1.arrayGetLength();
2463  if (nFuncsA > gfxColorMaxComps) {
2464  error(errSyntaxError, -1,
2465  "Invalid Function array in shading dictionary");
2466  goto err1;
2467  }
2468  for (i = 0; i < nFuncsA; ++i) {
2469  obj1.arrayGet(i, &obj2);
2470  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
2471  obj1.free();
2472  obj2.free();
2473  goto err1;
2474  }
2475  obj2.free();
2476  }
2477  } else {
2478  nFuncsA = 1;
2479  if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2480  obj1.free();
2481  goto err1;
2482  }
2483  }
2484  obj1.free();
2485 
2486  extend0A = extend1A = gFalse;
2487  if (dict->lookup("Extend", &obj1)->isArray() &&
2488  obj1.arrayGetLength() == 2) {
2489  extend0A = obj1.arrayGet(0, &obj2)->getBool();
2490  obj2.free();
2491  extend1A = obj1.arrayGet(1, &obj2)->getBool();
2492  obj2.free();
2493  }
2494  obj1.free();
2495 
2496  shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
2497  funcsA, nFuncsA, extend0A, extend1A);
2498  if (!shading->init(dict
2499  )) {
2500  delete shading;
2501  return NULL;
2502  }
2503 
2504  for (i = 0; i < shading->nFuncs; ++i) {
2505  if (shading->funcs[i]->getOutputSize()
2506  != shading->getColorSpace()->getNComps()) {
2507  error(errSyntaxError, -1, "Invalid function in shading dictionary");
2508  delete shading;
2509  return NULL;
2510  }
2511  }
2512 
2513  return shading;
2514 
2515  err1:
2516  return NULL;
2517 }
2518 
2520  return new GfxRadialShading(this);
2521 }
2522 
2524  double out[gfxColorMaxComps];
2525  int i;
2526 
2527  // NB: there can be one function with n outputs or n functions with
2528  // one output each (where n = number of color components)
2529  for (i = 0; i < gfxColorMaxComps; ++i) {
2530  out[i] = 0;
2531  }
2532  for (i = 0; i < nFuncs; ++i) {
2533  funcs[i]->transform(&t, &out[i]);
2534  }
2535  for (i = 0; i < gfxColorMaxComps; ++i) {
2536  color->c[i] = dblToCol(out[i]);
2537  }
2538 }
2539 
2540 //------------------------------------------------------------------------
2541 // GfxShadingBitBuf
2542 //------------------------------------------------------------------------
2543 
2545 public:
2546 
2547  GfxShadingBitBuf(Stream *strA);
2549  GBool getBits(int n, Guint *val);
2550  void flushBits();
2551 
2552 private:
2553 
2555  int bitBuf;
2556  int nBits;
2557 };
2558 
2560  str = strA;
2561  str->reset();
2562  bitBuf = 0;
2563  nBits = 0;
2564 }
2565 
2567  str->close();
2568 }
2569 
2571  int x;
2572 
2573  if (nBits >= n) {
2574  x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
2575  nBits -= n;
2576  } else {
2577  x = 0;
2578  if (nBits > 0) {
2579  x = bitBuf & ((1 << nBits) - 1);
2580  n -= nBits;
2581  nBits = 0;
2582  }
2583  while (n > 0) {
2584  if ((bitBuf = str->getChar()) == EOF) {
2585  nBits = 0;
2586  return gFalse;
2587  }
2588  if (n >= 8) {
2589  x = (x << 8) | bitBuf;
2590  n -= 8;
2591  } else {
2592  x = (x << n) | (bitBuf >> (8 - n));
2593  nBits = 8 - n;
2594  n = 0;
2595  }
2596  }
2597  }
2598  *val = x;
2599  return gTrue;
2600 }
2601 
2603  bitBuf = 0;
2604  nBits = 0;
2605 }
2606 
2607 //------------------------------------------------------------------------
2608 // GfxGouraudTriangleShading
2609 //------------------------------------------------------------------------
2610 
2612  int typeA,
2613  GfxGouraudVertex *verticesA, int nVerticesA,
2614  int (*trianglesA)[3], int nTrianglesA,
2615  int nCompsA, Function **funcsA, int nFuncsA):
2616  GfxShading(typeA)
2617 {
2618  int i;
2619 
2620  vertices = verticesA;
2621  nVertices = nVerticesA;
2622  triangles = trianglesA;
2623  nTriangles = nTrianglesA;
2624  nComps = nCompsA;
2625  nFuncs = nFuncsA;
2626  for (i = 0; i < nFuncs; ++i) {
2627  funcs[i] = funcsA[i];
2628  }
2629 }
2630 
2632  GfxGouraudTriangleShading *shading):
2633  GfxShading(shading)
2634 {
2635  int i;
2636 
2637  nVertices = shading->nVertices;
2639  memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
2640  nTriangles = shading->nTriangles;
2641  triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
2642  memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
2643  nComps = shading->nComps;
2644  nFuncs = shading->nFuncs;
2645  for (i = 0; i < nFuncs; ++i) {
2646  funcs[i] = shading->funcs[i]->copy();
2647  }
2648 }
2649 
2651  int i;
2652 
2653  gfree(vertices);
2654  gfree(triangles);
2655  for (i = 0; i < nFuncs; ++i) {
2656  delete funcs[i];
2657  }
2658 }
2659 
2661  int typeA, Dict *dict, Stream *str
2662  ) {
2663  GfxGouraudTriangleShading *shading;
2664  Function *funcsA[gfxColorMaxComps];
2665  int nFuncsA;
2666  int coordBits, compBits, flagBits, vertsPerRow, nRows;
2667  double xMin, xMax, yMin, yMax;
2668  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2669  double xMul, yMul;
2670  double cMul[gfxColorMaxComps];
2671  GfxGouraudVertex *verticesA;
2672  int (*trianglesA)[3];
2673  int nCompsA, nVerticesA, nTrianglesA, vertSize, triSize;
2674  Guint x, y, flag;
2676  GfxShadingBitBuf *bitBuf;
2677  Object obj1, obj2;
2678  int i, j, k, state;
2679 
2680  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2681  coordBits = obj1.getInt();
2682  } else {
2683  error(errSyntaxError, -1,
2684  "Missing or invalid BitsPerCoordinate in shading dictionary");
2685  goto err2;
2686  }
2687  if (coordBits <= 0 || coordBits > 32) {
2688  error(errSyntaxError, -1,
2689  "Invalid BitsPerCoordinate in shading dictionary");
2690  goto err2;
2691  }
2692  obj1.free();
2693  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2694  compBits = obj1.getInt();
2695  } else {
2696  error(errSyntaxError, -1,
2697  "Missing or invalid BitsPerComponent in shading dictionary");
2698  goto err2;
2699  }
2700  if (compBits <= 0 || compBits > 16) {
2701  error(errSyntaxError, -1,
2702  "Invalid BitsPerComponent in shading dictionary");
2703  goto err2;
2704  }
2705  obj1.free();
2706  flagBits = vertsPerRow = 0; // make gcc happy
2707  if (typeA == 4) {
2708  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2709  flagBits = obj1.getInt();
2710  } else {
2711  error(errSyntaxError, -1,
2712  "Missing or invalid BitsPerFlag in shading dictionary");
2713  goto err2;
2714  }
2715  if (flagBits < 2 || flagBits > 8) {
2716  error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
2717  goto err2;
2718  }
2719  obj1.free();
2720  } else {
2721  if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
2722  vertsPerRow = obj1.getInt();
2723  } else {
2724  error(errSyntaxError, -1,
2725  "Missing or invalid VerticesPerRow in shading dictionary");
2726  goto err2;
2727  }
2728  obj1.free();
2729  if (vertsPerRow < 2) {
2730  error(errSyntaxError, -1,
2731  "Invalid VerticesPerRow in shading dictionary");
2732  goto err2;
2733  }
2734  }
2735  if (dict->lookup("Decode", &obj1)->isArray() &&
2736  obj1.arrayGetLength() >= 6) {
2737  xMin = obj1.arrayGet(0, &obj2)->getNum();
2738  obj2.free();
2739  xMax = obj1.arrayGet(1, &obj2)->getNum();
2740  obj2.free();
2741  xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
2742  yMin = obj1.arrayGet(2, &obj2)->getNum();
2743  obj2.free();
2744  yMax = obj1.arrayGet(3, &obj2)->getNum();
2745  obj2.free();
2746  yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
2747  for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
2748  cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
2749  obj2.free();
2750  cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
2751  obj2.free();
2752  cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
2753  }
2754  nCompsA = i;
2755  } else {
2756  error(errSyntaxError, -1,
2757  "Missing or invalid Decode array in shading dictionary");
2758  goto err2;
2759  }
2760  obj1.free();
2761 
2762  if (!dict->lookup("Function", &obj1)->isNull()) {
2763  if (obj1.isArray()) {
2764  nFuncsA = obj1.arrayGetLength();
2765  if (nFuncsA > gfxColorMaxComps) {
2766  error(errSyntaxError, -1,
2767  "Invalid Function array in shading dictionary");
2768  goto err1;
2769  }
2770  for (i = 0; i < nFuncsA; ++i) {
2771  obj1.arrayGet(i, &obj2);
2772  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
2773  obj1.free();
2774  obj2.free();
2775  goto err1;
2776  }
2777  obj2.free();
2778  }
2779  } else {
2780  nFuncsA = 1;
2781  if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2782  obj1.free();
2783  goto err1;
2784  }
2785  }
2786  } else {
2787  nFuncsA = 0;
2788  }
2789  obj1.free();
2790 
2791  nVerticesA = nTrianglesA = 0;
2792  verticesA = NULL;
2793  trianglesA = NULL;
2794  vertSize = triSize = 0;
2795  state = 0;
2796  flag = 0; // make gcc happy
2797  bitBuf = new GfxShadingBitBuf(str);
2798  while (1) {
2799  if (typeA == 4) {
2800  if (!bitBuf->getBits(flagBits, &flag)) {
2801  break;
2802  }
2803  }
2804  if (!bitBuf->getBits(coordBits, &x) ||
2805  !bitBuf->getBits(coordBits, &y)) {
2806  break;
2807  }
2808  for (i = 0; i < nCompsA; ++i) {
2809  if (!bitBuf->getBits(compBits, &c[i])) {
2810  break;
2811  }
2812  }
2813  if (i < nCompsA) {
2814  break;
2815  }
2816  if (nVerticesA == vertSize) {
2817  vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
2818  verticesA = (GfxGouraudVertex *)
2819  greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
2820  }
2821  verticesA[nVerticesA].x = xMin + xMul * (double)x;
2822  verticesA[nVerticesA].y = yMin + yMul * (double)y;
2823  for (i = 0; i < nCompsA; ++i) {
2824  verticesA[nVerticesA].color[i] = cMin[i] + cMul[i] * (double)c[i];
2825  }
2826  ++nVerticesA;
2827  bitBuf->flushBits();
2828  if (typeA == 4) {
2829  if (state == 0 || state == 1) {
2830  ++state;
2831  } else if (state == 2 || flag > 0) {
2832  if (nTrianglesA == triSize) {
2833  triSize = (triSize == 0) ? 16 : 2 * triSize;
2834  trianglesA = (int (*)[3])
2835  greallocn(trianglesA, triSize * 3, sizeof(int));
2836  }
2837  if (state == 2) {
2838  trianglesA[nTrianglesA][0] = nVerticesA - 3;
2839  trianglesA[nTrianglesA][1] = nVerticesA - 2;
2840  trianglesA[nTrianglesA][2] = nVerticesA - 1;
2841  ++state;
2842  } else if (flag == 1) {
2843  trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
2844  trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2845  trianglesA[nTrianglesA][2] = nVerticesA - 1;
2846  } else { // flag == 2
2847  trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
2848  trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
2849  trianglesA[nTrianglesA][2] = nVerticesA - 1;
2850  }
2851  ++nTrianglesA;
2852  } else { // state == 3 && flag == 0
2853  state = 1;
2854  }
2855  }
2856  }
2857  delete bitBuf;
2858  if (typeA == 5) {
2859  nRows = nVerticesA / vertsPerRow;
2860  nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
2861  trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
2862  k = 0;
2863  for (i = 0; i < nRows - 1; ++i) {
2864  for (j = 0; j < vertsPerRow - 1; ++j) {
2865  trianglesA[k][0] = i * vertsPerRow + j;
2866  trianglesA[k][1] = i * vertsPerRow + j+1;
2867  trianglesA[k][2] = (i+1) * vertsPerRow + j;
2868  ++k;
2869  trianglesA[k][0] = i * vertsPerRow + j+1;
2870  trianglesA[k][1] = (i+1) * vertsPerRow + j;
2871  trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
2872  ++k;
2873  }
2874  }
2875  }
2876 
2877  shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
2878  trianglesA, nTrianglesA,
2879  nCompsA, funcsA, nFuncsA);
2880  if (!shading->init(dict
2881  )) {
2882  delete shading;
2883  return NULL;
2884  }
2885 
2886  for (i = 0; i < shading->nFuncs; ++i) {
2887  if (shading->funcs[i]->getOutputSize()
2888  != shading->getColorSpace()->getNComps()) {
2889  error(errSyntaxError, -1, "Invalid function in shading dictionary");
2890  delete shading;
2891  return NULL;
2892  }
2893  }
2894 
2895  return shading;
2896 
2897  err2:
2898  obj1.free();
2899  err1:
2900  return NULL;
2901 }
2902 
2904  return new GfxGouraudTriangleShading(this);
2905 }
2906 
2908  int i,
2909  double *x0, double *y0, double *color0,
2910  double *x1, double *y1, double *color1,
2911  double *x2, double *y2, double *color2) {
2912  int v, j;
2913 
2914  v = triangles[i][0];
2915  *x0 = vertices[v].x;
2916  *y0 = vertices[v].y;
2917  for (j = 0; j < nComps; ++j) {
2918  color0[j] = vertices[v].color[j];
2919  }
2920  v = triangles[i][1];
2921  *x1 = vertices[v].x;
2922  *y1 = vertices[v].y;
2923  for (j = 0; j < nComps; ++j) {
2924  color1[j] = vertices[v].color[j];
2925  }
2926  v = triangles[i][2];
2927  *x2 = vertices[v].x;
2928  *y2 = vertices[v].y;
2929  for (j = 0; j < nComps; ++j) {
2930  color2[j] = vertices[v].color[j];
2931  }
2932 }
2933 
2934 void GfxGouraudTriangleShading::getBBox(double *xMin, double *yMin,
2935  double *xMax, double *yMax) {
2936  double xxMin = 0;
2937  double yyMin = 0;
2938  double xxMax = 0;
2939  double yyMax = 0;
2940  if (nVertices > 0) {
2941  xxMin = xxMax = vertices[0].x;
2942  yyMin = yyMax = vertices[0].y;
2943  }
2944  for (int i = 1; i < nVertices; ++i) {
2945  if (vertices[i].x < xxMin) {
2946  xxMin = vertices[i].x;
2947  } else if (vertices[i].x > xxMax) {
2948  xxMax = vertices[i].x;
2949  }
2950  if (vertices[i].y < yyMin) {
2951  yyMin = vertices[i].y;
2952  } else if (vertices[i].y > yyMax) {
2953  yyMax = vertices[i].y;
2954  }
2955  }
2956  *xMin = xxMin;
2957  *yMin = yyMin;
2958  *xMax = xxMax;
2959  *yMax = yyMax;
2960 }
2961 
2963  double c[gfxColorMaxComps];
2964  int i;
2965 
2966  if (nFuncs > 0) {
2967  for (i = 0; i < nFuncs; ++i) {
2968  funcs[i]->transform(in, &c[i]);
2969  }
2970  for (i = 0; i < colorSpace->getNComps(); ++i) {
2971  out->c[i] = dblToCol(c[i]);
2972  }
2973  } else {
2974  for (i = 0; i < nComps; ++i) {
2975  out->c[i] = dblToCol(in[i]);
2976  }
2977  }
2978 }
2979 
2980 //------------------------------------------------------------------------
2981 // GfxPatchMeshShading
2982 //------------------------------------------------------------------------
2983 
2985  GfxPatch *patchesA, int nPatchesA,
2986  int nCompsA,
2987  Function **funcsA, int nFuncsA):
2988  GfxShading(typeA)
2989 {
2990  int i;
2991 
2992  patches = patchesA;
2993  nPatches = nPatchesA;
2994  nComps = nCompsA;
2995  nFuncs = nFuncsA;
2996  for (i = 0; i < nFuncs; ++i) {
2997  funcs[i] = funcsA[i];
2998  }
2999 }
3000 
3002  GfxShading(shading)
3003 {
3004  int i;
3005 
3006  nPatches = shading->nPatches;
3007  patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
3008  memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
3009  nComps = shading->nComps;
3010  nFuncs = shading->nFuncs;
3011  for (i = 0; i < nFuncs; ++i) {
3012  funcs[i] = shading->funcs[i]->copy();
3013  }
3014 }
3015 
3017  int i;
3018 
3019  gfree(patches);
3020  for (i = 0; i < nFuncs; ++i) {
3021  delete funcs[i];
3022  }
3023 }
3024 
3026  Stream *str
3027  ) {
3028  GfxPatchMeshShading *shading;
3029  Function *funcsA[gfxColorMaxComps];
3030  int nFuncsA;
3031  int coordBits, compBits, flagBits;
3032  double xMin, xMax, yMin, yMax;
3033  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
3034  double xMul, yMul;
3035  double cMul[gfxColorMaxComps];
3036  GfxPatch *patchesA, *p;
3037  int nCompsA, nPatchesA, patchesSize, nPts, nColors;
3038  Guint flag;
3039  double x[16], y[16];
3040  Guint xi, yi;
3041  double c[4][gfxColorMaxComps];
3042  Guint ci;
3043  GfxShadingBitBuf *bitBuf;
3044  Object obj1, obj2;
3045  int i, j;
3046 
3047  nPatchesA = 0;
3048  patchesA = NULL;
3049  patchesSize = 0;
3050 
3051  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
3052  coordBits = obj1.getInt();
3053  } else {
3054  error(errSyntaxError, -1,
3055  "Missing or invalid BitsPerCoordinate in shading dictionary");
3056  goto err2;
3057  }
3058  if (coordBits <= 0 || coordBits > 32) {
3059  error(errSyntaxError, -1,
3060  "Invalid BitsPerCoordinate in shading dictionary");
3061  goto err2;
3062  }
3063  obj1.free();
3064  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
3065  compBits = obj1.getInt();
3066  } else {
3067  error(errSyntaxError, -1,
3068  "Missing or invalid BitsPerComponent in shading dictionary");
3069  goto err2;
3070  }
3071  if (compBits <= 0 || compBits > 16) {
3072  error(errSyntaxError, -1,
3073  "Invalid BitsPerComponent in shading dictionary");
3074  goto err2;
3075  }
3076  obj1.free();
3077  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
3078  flagBits = obj1.getInt();
3079  } else {
3080  error(errSyntaxError, -1,
3081  "Missing or invalid BitsPerFlag in shading dictionary");
3082  goto err2;
3083  }
3084  if (flagBits < 2 || flagBits > 8) {
3085  error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
3086  goto err2;
3087  }
3088  obj1.free();
3089  if (dict->lookup("Decode", &obj1)->isArray() &&
3090  obj1.arrayGetLength() >= 6) {
3091  xMin = obj1.arrayGet(0, &obj2)->getNum();
3092  obj2.free();
3093  xMax = obj1.arrayGet(1, &obj2)->getNum();
3094  obj2.free();
3095  xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
3096  yMin = obj1.arrayGet(2, &obj2)->getNum();
3097  obj2.free();
3098  yMax = obj1.arrayGet(3, &obj2)->getNum();
3099  obj2.free();
3100  yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
3101  for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
3102  cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
3103  obj2.free();
3104  cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
3105  obj2.free();
3106  cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
3107  }
3108  nCompsA = i;
3109  } else {
3110  error(errSyntaxError, -1,
3111  "Missing or invalid Decode array in shading dictionary");
3112  goto err2;
3113  }
3114  obj1.free();
3115 
3116  if (!dict->lookup("Function", &obj1)->isNull()) {
3117  if (obj1.isArray()) {
3118  nFuncsA = obj1.arrayGetLength();
3119  if (nFuncsA > gfxColorMaxComps) {
3120  error(errSyntaxError, -1,
3121  "Invalid Function array in shading dictionary");
3122  goto err1;
3123  }
3124  for (i = 0; i < nFuncsA; ++i) {
3125  obj1.arrayGet(i, &obj2);
3126  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
3127  obj1.free();
3128  obj2.free();
3129  goto err1;
3130  }
3131  obj2.free();
3132  }
3133  } else {
3134  nFuncsA = 1;
3135  if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
3136  obj1.free();
3137  goto err1;
3138  }
3139  }
3140  } else {
3141  nFuncsA = 0;
3142  }
3143  obj1.free();
3144 
3145  bitBuf = new GfxShadingBitBuf(str);
3146  while (1) {
3147  if (!bitBuf->getBits(flagBits, &flag)) {
3148  break;
3149  }
3150  flag &= 3;
3151  if (flag != 0 && nPatchesA == 0) {
3152  error(errSyntaxError, -1, "Invalid patch in patch mesh shading");
3153  delete bitBuf;
3154  goto err1;
3155  }
3156  if (typeA == 6) {
3157  switch (flag) {
3158  case 0: nPts = 12; nColors = 4; break;
3159  case 1:
3160  case 2:
3161  case 3:
3162  default: nPts = 8; nColors = 2; break;
3163  }
3164  } else {
3165  switch (flag) {
3166  case 0: nPts = 16; nColors = 4; break;
3167  case 1:
3168  case 2:
3169  case 3:
3170  default: nPts = 12; nColors = 2; break;
3171  }
3172  }
3173  for (i = 0; i < nPts; ++i) {
3174  if (!bitBuf->getBits(coordBits, &xi) ||
3175  !bitBuf->getBits(coordBits, &yi)) {
3176  break;
3177  }
3178  x[i] = xMin + xMul * (double)xi;
3179  y[i] = yMin + yMul * (double)yi;
3180  }
3181  if (i < nPts) {
3182  break;
3183  }
3184  for (i = 0; i < nColors; ++i) {
3185  for (j = 0; j < nCompsA; ++j) {
3186  if (!bitBuf->getBits(compBits, &ci)) {
3187  break;
3188  }
3189  c[i][j] = cMin[j] + cMul[j] * (double)ci;
3190  }
3191  if (j < nCompsA) {
3192  break;
3193  }
3194  }
3195  if (i < nColors) {
3196  break;
3197  }
3198  if (nPatchesA == patchesSize) {
3199  patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
3200  patchesA = (GfxPatch *)greallocn(patchesA,
3201  patchesSize, sizeof(GfxPatch));
3202  }
3203  p = &patchesA[nPatchesA];
3204  if (typeA == 6) {
3205  switch (flag) {
3206  case 0:
3207  p->x[0][0] = x[0];
3208  p->y[0][0] = y[0];
3209  p->x[0][1] = x[1];
3210  p->y[0][1] = y[1];
3211  p->x[0][2] = x[2];
3212  p->y[0][2] = y[2];
3213  p->x[0][3] = x[3];
3214  p->y[0][3] = y[3];
3215  p->x[1][3] = x[4];
3216  p->y[1][3] = y[4];
3217  p->x[2][3] = x[5];
3218  p->y[2][3] = y[5];
3219  p->x[3][3] = x[6];
3220  p->y[3][3] = y[6];
3221  p->x[3][2] = x[7];
3222  p->y[3][2] = y[7];
3223  p->x[3][1] = x[8];
3224  p->y[3][1] = y[8];
3225  p->x[3][0] = x[9];
3226  p->y[3][0] = y[9];
3227  p->x[2][0] = x[10];
3228  p->y[2][0] = y[10];
3229  p->x[1][0] = x[11];
3230  p->y[1][0] = y[11];
3231  for (j = 0; j < nCompsA; ++j) {
3232  p->color[0][0][j] = c[0][j];
3233  p->color[0][1][j] = c[1][j];
3234  p->color[1][1][j] = c[2][j];
3235  p->color[1][0][j] = c[3][j];
3236  }
3237  break;
3238  case 1:
3239  p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
3240  p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
3241  p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
3242  p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
3243  p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
3244  p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
3245  p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
3246  p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
3247  p->x[1][3] = x[0];
3248  p->y[1][3] = y[0];
3249  p->x[2][3] = x[1];
3250  p->y[2][3] = y[1];
3251  p->x[3][3] = x[2];
3252  p->y[3][3] = y[2];
3253  p->x[3][2] = x[3];
3254  p->y[3][2] = y[3];
3255  p->x[3][1] = x[4];
3256  p->y[3][1] = y[4];
3257  p->x[3][0] = x[5];
3258  p->y[3][0] = y[5];
3259  p->x[2][0] = x[6];
3260  p->y[2][0] = y[6];
3261  p->x[1][0] = x[7];
3262  p->y[1][0] = y[7];
3263  for (j = 0; j < nCompsA; ++j) {
3264  p->color[0][0][j] = patchesA[nPatchesA-1].color[0][1][j];
3265  p->color[0][1][j] = patchesA[nPatchesA-1].color[1][1][j];
3266  p->color[1][1][j] = c[0][j];
3267  p->color[1][0][j] = c[1][j];
3268  }
3269  break;
3270  case 2:
3271  p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
3272  p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
3273  p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
3274  p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
3275  p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
3276  p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
3277  p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
3278  p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
3279  p->x[1][3] = x[0];
3280  p->y[1][3] = y[0];
3281  p->x[2][3] = x[1];
3282  p->y[2][3] = y[1];
3283  p->x[3][3] = x[2];
3284  p->y[3][3] = y[2];
3285  p->x[3][2] = x[3];
3286  p->y[3][2] = y[3];
3287  p->x[3][1] = x[4];
3288  p->y[3][1] = y[4];
3289  p->x[3][0] = x[5];
3290  p->y[3][0] = y[5];
3291  p->x[2][0] = x[6];
3292  p->y[2][0] = y[6];
3293  p->x[1][0] = x[7];
3294  p->y[1][0] = y[7];
3295  for (j = 0; j < nCompsA; ++j) {
3296  p->color[0][0][j] = patchesA[nPatchesA-1].color[1][1][j];
3297  p->color[0][1][j] = patchesA[nPatchesA-1].color[1][0][j];
3298  p->color[1][1][j] = c[0][j];
3299  p->color[1][0][j] = c[1][j];
3300  }
3301  break;
3302  case 3:
3303  p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
3304  p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
3305  p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
3306  p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3307  p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3308  p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3309  p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3310  p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3311  p->x[1][3] = x[0];
3312  p->y[1][3] = y[0];
3313  p->x[2][3] = x[1];
3314  p->y[2][3] = y[1];
3315  p->x[3][3] = x[2];
3316  p->y[3][3] = y[2];
3317  p->x[3][2] = x[3];
3318  p->y[3][2] = y[3];
3319  p->x[3][1] = x[4];
3320  p->y[3][1] = y[4];
3321  p->x[3][0] = x[5];
3322  p->y[3][0] = y[5];
3323  p->x[2][0] = x[6];
3324  p->y[2][0] = y[6];
3325  p->x[1][0] = x[7];
3326  p->y[1][0] = y[7];
3327  for (j = 0; j < nCompsA; ++j) {
3328  p->color[0][0][j] = patchesA[nPatchesA-1].color[1][0][j];
3329  p->color[0][1][j] = patchesA[nPatchesA-1].color[0][0][j];
3330  p->color[1][1][j] = c[0][j];
3331  p->color[1][0][j] = c[1][j];
3332  }
3333  break;
3334  }
3335  } else {
3336  switch (flag) {
3337  case 0:
3338  p->x[0][0] = x[0];
3339  p->y[0][0] = y[0];
3340  p->x[0][1] = x[1];
3341  p->y[0][1] = y[1];
3342  p->x[0][2] = x[2];
3343  p->y[0][2] = y[2];
3344  p->x[0][3] = x[3];
3345  p->y[0][3] = y[3];
3346  p->x[1][3] = x[4];
3347  p->y[1][3] = y[4];
3348  p->x[2][3] = x[5];
3349  p->y[2][3] = y[5];
3350  p->x[3][3] = x[6];
3351  p->y[3][3] = y[6];
3352  p->x[3][2] = x[7];
3353  p->y[3][2] = y[7];
3354  p->x[3][1] = x[8];
3355  p->y[3][1] = y[8];
3356  p->x[3][0] = x[9];
3357  p->y[3][0] = y[9];
3358  p->x[2][0] = x[10];
3359  p->y[2][0] = y[10];
3360  p->x[1][0] = x[11];
3361  p->y[1][0] = y[11];
3362  p->x[1][1] = x[12];
3363  p->y[1][1] = y[12];
3364  p->x[1][2] = x[13];
3365  p->y[1][2] = y[13];
3366  p->x[2][2] = x[14];
3367  p->y[2][2] = y[14];
3368  p->x[2][1] = x[15];
3369  p->y[2][1] = y[15];
3370  for (j = 0; j < nCompsA; ++j) {
3371  p->color[0][0][j] = c[0][j];
3372  p->color[0][1][j] = c[1][j];
3373  p->color[1][1][j] = c[2][j];
3374  p->color[1][0][j] = c[3][j];
3375  }
3376  break;
3377  case 1:
3378  p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
3379  p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
3380  p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
3381  p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
3382  p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
3383  p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
3384  p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
3385  p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
3386  p->x[1][3] = x[0];
3387  p->y[1][3] = y[0];
3388  p->x[2][3] = x[1];
3389  p->y[2][3] = y[1];
3390  p->x[3][3] = x[2];
3391  p->y[3][3] = y[2];
3392  p->x[3][2] = x[3];
3393  p->y[3][2] = y[3];
3394  p->x[3][1] = x[4];
3395  p->y[3][1] = y[4];
3396  p->x[3][0] = x[5];
3397  p->y[3][0] = y[5];
3398  p->x[2][0] = x[6];
3399  p->y[2][0] = y[6];
3400  p->x[1][0] = x[7];
3401  p->y[1][0] = y[7];
3402  p->x[1][1] = x[8];
3403  p->y[1][1] = y[8];
3404  p->x[1][2] = x[9];
3405  p->y[1][2] = y[9];
3406  p->x[2][2] = x[10];
3407  p->y[2][2] = y[10];
3408  p->x[2][1] = x[11];
3409  p->y[2][1] = y[11];
3410  for (j = 0; j < nCompsA; ++j) {
3411  p->color[0][0][j] = patchesA[nPatchesA-1].color[0][1][j];
3412  p->color[0][1][j] = patchesA[nPatchesA-1].color[1][1][j];
3413  p->color[1][1][j] = c[0][j];
3414  p->color[1][0][j] = c[1][j];
3415  }
3416  break;
3417  case 2:
3418  p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
3419  p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
3420  p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
3421  p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
3422  p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
3423  p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
3424  p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
3425  p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
3426  p->x[1][3] = x[0];
3427  p->y[1][3] = y[0];
3428  p->x[2][3] = x[1];
3429  p->y[2][3] = y[1];
3430  p->x[3][3] = x[2];
3431  p->y[3][3] = y[2];
3432  p->x[3][2] = x[3];
3433  p->y[3][2] = y[3];
3434  p->x[3][1] = x[4];
3435  p->y[3][1] = y[4];
3436  p->x[3][0] = x[5];
3437  p->y[3][0] = y[5];
3438  p->x[2][0] = x[6];
3439  p->y[2][0] = y[6];
3440  p->x[1][0] = x[7];
3441  p->y[1][0] = y[7];
3442  p->x[1][1] = x[8];
3443  p->y[1][1] = y[8];
3444  p->x[1][2] = x[9];
3445  p->y[1][2] = y[9];
3446  p->x[2][2] = x[10];
3447  p->y[2][2] = y[10];
3448  p->x[2][1] = x[11];
3449  p->y[2][1] = y[11];
3450  for (j = 0; j < nCompsA; ++j) {
3451  p->color[0][0][j] = patchesA[nPatchesA-1].color[1][1][j];
3452  p->color[0][1][j] = patchesA[nPatchesA-1].color[1][0][j];
3453  p->color[1][1][j] = c[0][j];
3454  p->color[1][0][j] = c[1][j];
3455  }
3456  break;
3457  case 3:
3458  p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
3459  p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
3460  p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
3461  p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3462  p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3463  p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3464  p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3465  p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3466  p->x[1][3] = x[0];
3467  p->y[1][3] = y[0];
3468  p->x[2][3] = x[1];
3469  p->y[2][3] = y[1];
3470  p->x[3][3] = x[2];
3471  p->y[3][3] = y[2];
3472  p->x[3][2] = x[3];
3473  p->y[3][2] = y[3];
3474  p->x[3][1] = x[4];
3475  p->y[3][1] = y[4];
3476  p->x[3][0] = x[5];
3477  p->y[3][0] = y[5];
3478  p->x[2][0] = x[6];
3479  p->y[2][0] = y[6];
3480  p->x[1][0] = x[7];
3481  p->y[1][0] = y[7];
3482  p->x[1][1] = x[8];
3483  p->y[1][1] = y[8];
3484  p->x[1][2] = x[9];
3485  p->y[1][2] = y[9];
3486  p->x[2][2] = x[10];
3487  p->y[2][2] = y[10];
3488  p->x[2][1] = x[11];
3489  p->y[2][1] = y[11];
3490  for (j = 0; j < nCompsA; ++j) {
3491  p->color[0][0][j] = patchesA[nPatchesA-1].color[1][0][j];
3492  p->color[0][1][j] = patchesA[nPatchesA-1].color[0][0][j];
3493  p->color[1][1][j] = c[0][j];
3494  p->color[1][0][j] = c[1][j];
3495  }
3496  break;
3497  }
3498  }
3499  ++nPatchesA;
3500  bitBuf->flushBits();
3501  }
3502  delete bitBuf;
3503 
3504  if (typeA == 6) {
3505  for (i = 0; i < nPatchesA; ++i) {
3506  p = &patchesA[i];
3507  p->x[1][1] = (-4 * p->x[0][0]
3508  +6 * (p->x[0][1] + p->x[1][0])
3509  -2 * (p->x[0][3] + p->x[3][0])
3510  +3 * (p->x[3][1] + p->x[1][3])
3511  - p->x[3][3]) / 9;
3512  p->y[1][1] = (-4 * p->y[0][0]
3513  +6 * (p->y[0][1] + p->y[1][0])
3514  -2 * (p->y[0][3] + p->y[3][0])
3515  +3 * (p->y[3][1] + p->y[1][3])
3516  - p->y[3][3]) / 9;
3517  p->x[1][2] = (-4 * p->x[0][3]
3518  +6 * (p->x[0][2] + p->x[1][3])
3519  -2 * (p->x[0][0] + p->x[3][3])
3520  +3 * (p->x[3][2] + p->x[1][0])
3521  - p->x[3][0]) / 9;
3522  p->y[1][2] = (-4 * p->y[0][3]
3523  +6 * (p->y[0][2] + p->y[1][3])
3524  -2 * (p->y[0][0] + p->y[3][3])
3525  +3 * (p->y[3][2] + p->y[1][0])
3526  - p->y[3][0]) / 9;
3527  p->x[2][1] = (-4 * p->x[3][0]
3528  +6 * (p->x[3][1] + p->x[2][0])
3529  -2 * (p->x[3][3] + p->x[0][0])
3530  +3 * (p->x[0][1] + p->x[2][3])
3531  - p->x[0][3]) / 9;
3532  p->y[2][1] = (-4 * p->y[3][0]
3533  +6 * (p->y[3][1] + p->y[2][0])
3534  -2 * (p->y[3][3] + p->y[0][0])
3535  +3 * (p->y[0][1] + p->y[2][3])
3536  - p->y[0][3]) / 9;
3537  p->x[2][2] = (-4 * p->x[3][3]
3538  +6 * (p->x[3][2] + p->x[2][3])
3539  -2 * (p->x[3][0] + p->x[0][3])
3540  +3 * (p->x[0][2] + p->x[2][0])
3541  - p->x[0][0]) / 9;
3542  p->y[2][2] = (-4 * p->y[3][3]
3543  +6 * (p->y[3][2] + p->y[2][3])
3544  -2 * (p->y[3][0] + p->y[0][3])
3545  +3 * (p->y[0][2] + p->y[2][0])
3546  - p->y[0][0]) / 9;
3547  }
3548  }
3549 
3550  shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
3551  nCompsA, funcsA, nFuncsA);
3552  if (!shading->init(dict
3553  )) {
3554  delete shading;
3555  return NULL;
3556  }
3557 
3558  for (i = 0; i < shading->nFuncs; ++i) {
3559  if (shading->funcs[i]->getOutputSize()
3560  != shading->getColorSpace()->getNComps()) {
3561  error(errSyntaxError, -1, "Invalid function in shading dictionary");
3562  delete shading;
3563  return NULL;
3564  }
3565  }
3566 
3567  return shading;
3568 
3569  err2:
3570  obj1.free();
3571  err1:
3572  if (patchesA) {
3573  gfree(patchesA);
3574  }
3575  return NULL;
3576 }
3577 
3579  return new GfxPatchMeshShading(this);
3580 }
3581 
3582 void GfxPatchMeshShading::getBBox(double *xMin, double *yMin,
3583  double *xMax, double *yMax) {
3584  double xxMin = 0;
3585  double yyMin = 0;
3586  double xxMax = 0;
3587  double yyMax = 0;
3588  if (nPatches > 0) {
3589  xxMin = patches[0].x[0][0];
3590  yyMin = patches[0].y[0][0];
3591  }
3592  for (int i = 0; i < nPatches; ++i) {
3593  for (int j = 0; j < 4; ++j) {
3594  for (int k = 0; k < 4; ++k) {
3595  if (patches[i].x[j][k] < xxMin) {
3596  xxMin = patches[i].x[j][k];
3597  } else if (patches[i].x[j][k] > xxMax) {
3598  xxMax = patches[i].x[j][k];
3599  }
3600  if (patches[i].y[j][k] < yyMin) {
3601  yyMin = patches[i].y[j][k];
3602  } else if (patches[i].y[j][k] > yyMax) {
3603  yyMax = patches[i].y[j][k];
3604  }
3605  }
3606  }
3607  }
3608  *xMin = xxMin;
3609  *yMin = yyMin;
3610  *xMax = xxMax;
3611  *yMax = yyMax;
3612 }
3613 
3615  double c[gfxColorMaxComps];
3616  int i;
3617 
3618  if (nFuncs > 0) {
3619  for (i = 0; i < nFuncs; ++i) {
3620  funcs[i]->transform(in, &c[i]);
3621  }
3622  for (i = 0; i < colorSpace->getNComps(); ++i) {
3623  out->c[i] = dblToCol(c[i]);
3624  }
3625  } else {
3626  for (i = 0; i < nComps; ++i) {
3627  out->c[i] = dblToCol(in[i]);
3628  }
3629  }
3630 }
3631 
3632 //------------------------------------------------------------------------
3633 // GfxImageColorMap
3634 //------------------------------------------------------------------------
3635 
3637  GfxColorSpace *colorSpaceA,
3638  int maxAllowedBits) {
3639  GfxIndexedColorSpace *indexedCS;
3640  GfxSeparationColorSpace *sepCS;
3641  int maxPixel, indexHigh;
3642  Guchar *indexedLookup;
3643  Function *sepFunc;
3644  Object obj;
3645  double defaultLow[gfxColorMaxComps], defaultRange[gfxColorMaxComps];
3647  int i, j, k;
3648 
3649  ok = gTrue;
3650 
3651  // bits per component and color space
3652  bits = bitsA;
3653  if (bits <= maxAllowedBits) {
3654  maxPixel = (1 << bits) - 1;
3655  } else {
3656  maxPixel = (1 << maxAllowedBits) - 1;
3657  }
3658  colorSpace = colorSpaceA;
3659 
3660  // initialize
3661  for (k = 0; k < gfxColorMaxComps; ++k) {
3662  lookup[k] = NULL;
3663  lookup2[k] = NULL;
3664  }
3665 
3666  // get decode map
3667  colorSpace->getDefaultRanges(defaultLow, defaultRange, maxPixel);
3668  if (decode->isNull()) {
3670  for (i = 0; i < nComps; ++i) {
3671  decodeLow[i] = defaultLow[i];
3672  decodeRange[i] = defaultRange[i];
3673  }
3674  } else if (decode->isArray()) {
3675  nComps = decode->arrayGetLength() / 2;
3676  if (nComps < colorSpace->getNComps()) {
3677  goto err1;
3678  }
3679  if (nComps > colorSpace->getNComps()) {
3680  error(errSyntaxWarning, -1, "Too many elements in Decode array");
3682  }
3683  for (i = 0; i < nComps; ++i) {
3684  decode->arrayGet(2*i, &obj);
3685  if (!obj.isNum()) {
3686  goto err2;
3687  }
3688  decodeLow[i] = obj.getNum();
3689  obj.free();
3690  decode->arrayGet(2*i+1, &obj);
3691  if (!obj.isNum()) {
3692  goto err2;
3693  }
3694  decodeRange[i] = obj.getNum() - decodeLow[i];
3695  obj.free();
3696  }
3697  } else {
3698  goto err1;
3699  }
3700 
3701  // Construct a lookup table -- this stores pre-computed decoded
3702  // values for each component, i.e., the result of applying the
3703  // decode mapping to each possible image pixel component value.
3704  for (k = 0; k < nComps; ++k) {
3705  lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
3706  sizeof(GfxColorComp));
3707  for (i = 0; i <= maxPixel; ++i) {
3708  double t = decodeLow[k] + (i * decodeRange[k]) / maxPixel;
3709  if (t < defaultLow[k]) {
3710  t = defaultLow[k];
3711  } else if (t > defaultLow[k] + defaultRange[k]) {
3712  t = defaultLow[k] + defaultRange[k];
3713  }
3714  lookup[k][i] = dblToCol(t);
3715  }
3716  }
3717 
3718  // Optimization: for Indexed and Separation color spaces (which have
3719  // only one component), we pre-compute a second lookup table with
3720  // color values
3721  colorSpace2 = NULL;
3722  nComps2 = 0;
3723  if (colorSpace->getMode() == csIndexed) {
3724  // Note that indexHigh may not be the same as maxPixel --
3725  // Distiller will remove unused palette entries, resulting in
3726  // indexHigh < maxPixel.
3727  indexedCS = (GfxIndexedColorSpace *)colorSpace;
3728  colorSpace2 = indexedCS->getBase();
3729  indexHigh = indexedCS->getIndexHigh();
3731  indexedLookup = indexedCS->getLookup();
3732  colorSpace2->getDefaultRanges(x, y, indexHigh);
3733  for (k = 0; k < nComps2; ++k) {
3734  lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
3735  sizeof(GfxColorComp));
3736  }
3737  for (i = 0; i <= maxPixel; ++i) {
3738  j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
3739  if (j < 0) {
3740  j = 0;
3741  } else if (j > indexHigh) {
3742  j = indexHigh;
3743  }
3744  for (k = 0; k < nComps2; ++k) {
3745  lookup2[k][i] =
3746  dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]);
3747  }
3748  }
3749  } else if (colorSpace->getMode() == csSeparation) {
3751  colorSpace2 = sepCS->getAlt();
3753  sepFunc = sepCS->getFunc();
3754  for (k = 0; k < nComps2; ++k) {
3755  lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
3756  sizeof(GfxColorComp));
3757  }
3758  for (i = 0; i <= maxPixel; ++i) {
3759  double t = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
3760  if (t < defaultLow[0]) {
3761  t = defaultLow[0];
3762  } else if (t > defaultLow[0] + defaultRange[0]) {
3763  t = defaultLow[0] + defaultRange[0];
3764  }
3765  x[0] = t;
3766  sepFunc->transform(x, y);
3767  for (k = 0; k < nComps2; ++k) {
3768  lookup2[k][i] = dblToCol(y[k]);
3769  }
3770  }
3771  }
3772 
3773  return;
3774 
3775  err2:
3776  obj.free();
3777  err1:
3778  ok = gFalse;
3779 }
3780 
3782  int n, i, k;
3783 
3784  colorSpace = colorMap->colorSpace->copy();
3785  bits = colorMap->bits;
3786  nComps = colorMap->nComps;
3787  nComps2 = colorMap->nComps2;
3788  colorSpace2 = NULL;
3789  for (k = 0; k < gfxColorMaxComps; ++k) {
3790  lookup[k] = NULL;
3791  lookup2[k] = NULL;
3792  }
3793  if (bits <= 8) {
3794  n = 1 << bits;
3795  } else {
3796  n = 256;
3797  }
3798  for (k = 0; k < nComps; ++k) {
3799  lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3800  memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
3801  }
3802  if (colorSpace->getMode() == csIndexed) {
3803  colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
3804  for (k = 0; k < nComps2; ++k) {
3805  lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3806  memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
3807  }
3808  } else if (colorSpace->getMode() == csSeparation) {
3810  for (k = 0; k < nComps2; ++k) {
3811  lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
3812  memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
3813  }
3814  }
3815  for (i = 0; i < nComps; ++i) {
3816  decodeLow[i] = colorMap->decodeLow[i];
3817  decodeRange[i] = colorMap->decodeRange[i];
3818  }
3819  ok = gTrue;
3820 }
3821 
3823  int i;
3824 
3825  delete colorSpace;
3826  for (i = 0; i < gfxColorMaxComps; ++i) {
3827  gfree(lookup[i]);
3828  gfree(lookup2[i]);
3829  }
3830 }
3831 
3833  GfxRenderingIntent ri) {
3834  GfxColor color;
3835  int i;
3836 
3837  if (colorSpace2) {
3838  for (i = 0; i < nComps2; ++i) {
3839  color.c[i] = lookup2[i][x[0]];
3840  }
3841  colorSpace2->getGray(&color, gray, ri);
3842  } else {
3843  for (i = 0; i < nComps; ++i) {
3844  color.c[i] = lookup[i][x[i]];
3845  }
3846  colorSpace->getGray(&color, gray, ri);
3847  }
3848 }
3849 
3851  GfxColor color;
3852  int i;
3853 
3854  if (colorSpace2) {
3855  for (i = 0; i < nComps2; ++i) {
3856  color.c[i] = lookup2[i][x[0]];
3857  }
3858  colorSpace2->getRGB(&color, rgb, ri);
3859  } else {
3860  for (i = 0; i < nComps; ++i) {
3861  color.c[i] = lookup[i][x[i]];
3862  }
3863  colorSpace->getRGB(&color, rgb, ri);
3864  }
3865 }
3866 
3868  GfxRenderingIntent ri) {
3869  GfxColor color;
3870  int i;
3871 
3872  if (colorSpace2) {
3873  for (i = 0; i < nComps2; ++i) {
3874  color.c[i] = lookup2[i][x[0]];
3875  }
3876  colorSpace2->getCMYK(&color, cmyk, ri);
3877  } else {
3878  for (i = 0; i < nComps; ++i) {
3879  color.c[i] = lookup[i][x[i]];
3880  }
3881  colorSpace->getCMYK(&color, cmyk, ri);
3882  }
3883 }
3884 
3885 
3887  int i;
3888 
3889  for (i = 0; i < nComps; ++i) {
3890  color->c[i] = lookup[i][x[i]];
3891  }
3892 }
3893 
3895  GfxRenderingIntent ri) {
3896  GfxColor color;
3897  GfxGray gray;
3898  int i, j;
3899 
3900  if (colorSpace2) {
3901  for (j = 0; j < n; ++j) {
3902  for (i = 0; i < nComps2; ++i) {
3903  color.c[i] = lookup2[i][in[j]];
3904  }
3905  colorSpace2->getGray(&color, &gray, ri);
3906  out[j] = colToByte(gray);
3907  }
3908  } else {
3909  for (j = 0; j < n; ++j) {
3910  for (i = 0; i < nComps; ++i) {
3911  color.c[i] = lookup[i][in[j * nComps + i]];
3912  }
3913  colorSpace->getGray(&color, &gray, ri);
3914  out[j] = colToByte(gray);
3915  }
3916  }
3917 }
3918 
3920  GfxRenderingIntent ri) {
3921  GfxColor color;
3922  GfxRGB rgb;
3923  int i, j;
3924 
3925  if (colorSpace2) {
3926  for (j = 0; j < n; ++j) {
3927  for (i = 0; i < nComps2; ++i) {
3928  color.c[i] = lookup2[i][in[j]];
3929  }
3930  colorSpace2->getRGB(&color, &rgb, ri);
3931  out[j*3] = colToByte(rgb.r);
3932  out[j*3 + 1] = colToByte(rgb.g);
3933  out[j*3 + 2] = colToByte(rgb.b);
3934  }
3935  } else {
3936  for (j = 0; j < n; ++j) {
3937  for (i = 0; i < nComps; ++i) {
3938  color.c[i] = lookup[i][in[j * nComps + i]];
3939  }
3940  colorSpace->getRGB(&color, &rgb, ri);
3941  out[j*3] = colToByte(rgb.r);
3942  out[j*3 + 1] = colToByte(rgb.g);
3943  out[j*3 + 2] = colToByte(rgb.b);
3944  }
3945  }
3946 }
3947 
3949  GfxRenderingIntent ri) {
3950  GfxColor color;
3951  GfxCMYK cmyk;
3952  int i, j;
3953 
3954  if (colorSpace2) {
3955  for (j = 0; j < n; ++j) {
3956  for (i = 0; i < nComps2; ++i) {
3957  color.c[i] = lookup2[i][in[j]];
3958  }
3959  colorSpace2->getCMYK(&color, &cmyk, ri);
3960  out[j*4] = colToByte(cmyk.c);
3961  out[j*4 + 1] = colToByte(cmyk.m);
3962  out[j*4 + 2] = colToByte(cmyk.y);
3963  out[j*4 + 3] = colToByte(cmyk.k);
3964  }
3965  } else {
3966  for (j = 0; j < n; ++j) {
3967  for (i = 0; i < nComps; ++i) {
3968  color.c[i] = lookup[i][in[j * nComps + i]];
3969  }
3970  colorSpace->getCMYK(&color, &cmyk, ri);
3971  out[j*4] = colToByte(cmyk.c);
3972  out[j*4 + 1] = colToByte(cmyk.m);
3973  out[j*4 + 2] = colToByte(cmyk.y);
3974  out[j*4 + 3] = colToByte(cmyk.k);
3975  }
3976  }
3977 }
3978 
3979 
3980 //------------------------------------------------------------------------
3981 // GfxSubpath and GfxPath
3982 //------------------------------------------------------------------------
3983 
3984 GfxSubpath::GfxSubpath(double x1, double y1) {
3985  size = 16;
3986  x = (double *)gmallocn(size, sizeof(double));
3987  y = (double *)gmallocn(size, sizeof(double));
3988  curve = (GBool *)gmallocn(size, sizeof(GBool));
3989  n = 1;
3990  x[0] = x1;
3991  y[0] = y1;
3992  curve[0] = gFalse;
3993  closed = gFalse;
3994 }
3995 
3997  gfree(x);
3998  gfree(y);
3999  gfree(curve);
4000 }
4001 
4002 // Used for copy().
4004  size = subpath->size;
4005  n = subpath->n;
4006  x = (double *)gmallocn(size, sizeof(double));
4007  y = (double *)gmallocn(size, sizeof(double));
4008  curve = (GBool *)gmallocn(size, sizeof(GBool));
4009  memcpy(x, subpath->x, n * sizeof(double));
4010  memcpy(y, subpath->y, n * sizeof(double));
4011  memcpy(curve, subpath->curve, n * sizeof(GBool));
4012  closed = subpath->closed;
4013 }
4014 
4015 void GfxSubpath::lineTo(double x1, double y1) {
4016  if (n >= size) {
4017  size *= 2;
4018  x = (double *)greallocn(x, size, sizeof(double));
4019  y = (double *)greallocn(y, size, sizeof(double));
4020  curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4021  }
4022  x[n] = x1;
4023  y[n] = y1;
4024  curve[n] = gFalse;
4025  ++n;
4026 }
4027 
4028 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
4029  double x3, double y3) {
4030  if (n+3 > size) {
4031  size *= 2;
4032  x = (double *)greallocn(x, size, sizeof(double));
4033  y = (double *)greallocn(y, size, sizeof(double));
4034  curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4035  }
4036  x[n] = x1;
4037  y[n] = y1;
4038  x[n+1] = x2;
4039  y[n+1] = y2;
4040  x[n+2] = x3;
4041  y[n+2] = y3;
4042  curve[n] = curve[n+1] = gTrue;
4043  curve[n+2] = gFalse;
4044  n += 3;
4045 }
4046 
4048  if (x[n-1] != x[0] || y[n-1] != y[0]) {
4049  lineTo(x[0], y[0]);
4050  }
4051  closed = gTrue;
4052 }
4053 
4054 void GfxSubpath::offset(double dx, double dy) {
4055  int i;
4056 
4057  for (i = 0; i < n; ++i) {
4058  x[i] += dx;
4059  y[i] += dy;
4060  }
4061 }
4062 
4064  justMoved = gFalse;
4065  size = 16;
4066  n = 0;
4067  firstX = firstY = 0;
4068  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4069 }
4070 
4072  int i;
4073 
4074  for (i = 0; i < n; ++i)
4075  delete subpaths[i];
4076  gfree(subpaths);
4077 }
4078 
4079 // Used for copy().
4080 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
4081  GfxSubpath **subpaths1, int n1, int size1) {
4082  int i;
4083 
4084  justMoved = justMoved1;
4085  firstX = firstX1;
4086  firstY = firstY1;
4087  size = size1;
4088  n = n1;
4089  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4090  for (i = 0; i < n; ++i)
4091  subpaths[i] = subpaths1[i]->copy();
4092 }
4093 
4094 void GfxPath::moveTo(double x, double y) {
4095  justMoved = gTrue;
4096  firstX = x;
4097  firstY = y;
4098 }
4099 
4100 void GfxPath::lineTo(double x, double y) {
4101  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4102  if (n >= size) {
4103  size *= 2;
4104  subpaths = (GfxSubpath **)
4105  greallocn(subpaths, size, sizeof(GfxSubpath *));
4106  }
4107  if (justMoved) {
4108  subpaths[n] = new GfxSubpath(firstX, firstY);
4109  } else {
4110  subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4111  subpaths[n-1]->getLastY());
4112  }
4113  ++n;
4114  justMoved = gFalse;
4115  }
4116  subpaths[n-1]->lineTo(x, y);
4117 }
4118 
4119 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
4120  double x3, double y3) {
4121  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4122  if (n >= size) {
4123  size *= 2;
4124  subpaths = (GfxSubpath **)
4125  greallocn(subpaths, size, sizeof(GfxSubpath *));
4126  }
4127  if (justMoved) {
4128  subpaths[n] = new GfxSubpath(firstX, firstY);
4129  } else {
4130  subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4131  subpaths[n-1]->getLastY());
4132  }
4133  ++n;
4134  justMoved = gFalse;
4135  }
4136  subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
4137 }
4138 
4140  // this is necessary to handle the pathological case of
4141  // moveto/closepath/clip, which defines an empty clipping region
4142  if (justMoved) {
4143  if (n >= size) {
4144  size *= 2;
4145  subpaths = (GfxSubpath **)
4146  greallocn(subpaths, size, sizeof(GfxSubpath *));
4147  }
4148  subpaths[n] = new GfxSubpath(firstX, firstY);
4149  ++n;
4150  justMoved = gFalse;
4151  }
4152  subpaths[n-1]->close();
4153 }
4154 
4156  int i;
4157 
4158  if (n + path->n > size) {
4159  size = n + path->n;
4160  subpaths = (GfxSubpath **)
4161  greallocn(subpaths, size, sizeof(GfxSubpath *));
4162  }
4163  for (i = 0; i < path->n; ++i) {
4164  subpaths[n++] = path->subpaths[i]->copy();
4165  }
4166  justMoved = gFalse;
4167 }
4168 
4169 void GfxPath::offset(double dx, double dy) {
4170  int i;
4171 
4172  for (i = 0; i < n; ++i) {
4173  subpaths[i]->offset(dx, dy);
4174  }
4175 }
4176 
4177 //------------------------------------------------------------------------
4178 // GfxState
4179 //------------------------------------------------------------------------
4180 
4181 GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
4182  int rotateA, GBool upsideDown
4183  ) {
4184  double kx, ky;
4185 
4186  hDPI = hDPIA;
4187  vDPI = vDPIA;
4188  rotate = rotateA;
4189  px1 = pageBox->x1;
4190  py1 = pageBox->y1;
4191  px2 = pageBox->x2;
4192  py2 = pageBox->y2;
4193  kx = hDPI / 72.0;
4194  ky = vDPI / 72.0;
4195  if (rotate == 90) {
4196  ctm[0] = 0;
4197  ctm[1] = upsideDown ? ky : -ky;
4198  ctm[2] = kx;
4199  ctm[3] = 0;
4200  ctm[4] = -kx * py1;
4201  ctm[5] = ky * (upsideDown ? -px1 : px2);
4202  pageWidth = kx * (py2 - py1);
4203  pageHeight = ky * (px2 - px1);
4204  } else if (rotate == 180) {
4205  ctm[0] = -kx;
4206  ctm[1] = 0;
4207  ctm[2] = 0;
4208  ctm[3] = upsideDown ? ky : -ky;
4209  ctm[4] = kx * px2;
4210  ctm[5] = ky * (upsideDown ? -py1 : py2);
4211  pageWidth = kx * (px2 - px1);
4212  pageHeight = ky * (py2 - py1);
4213  } else if (rotate == 270) {
4214  ctm[0] = 0;
4215  ctm[1] = upsideDown ? -ky : ky;
4216  ctm[2] = -kx;
4217  ctm[3] = 0;
4218  ctm[4] = kx * py2;
4219  ctm[5] = ky * (upsideDown ? px2 : -px1);
4220  pageWidth = kx * (py2 - py1);
4221  pageHeight = ky * (px2 - px1);
4222  } else {
4223  ctm[0] = kx;
4224  ctm[1] = 0;
4225  ctm[2] = 0;
4226  ctm[3] = upsideDown ? -ky : ky;
4227  ctm[4] = -kx * px1;
4228  ctm[5] = ky * (upsideDown ? py2 : -py1);
4229  pageWidth = kx * (px2 - px1);
4230  pageHeight = ky * (py2 - py1);
4231  }
4232 
4235  fillColor.c[0] = 0;
4236  strokeColor.c[0] = 0;
4237  fillPattern = NULL;
4238  strokePattern = NULL;
4240  fillOpacity = 1;
4241  strokeOpacity = 1;
4245  overprintMode = 0;
4246  transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
4247 
4248  lineWidth = 1;
4249  lineDash = NULL;
4250  lineDashLength = 0;
4251  lineDashStart = 0;
4252  flatness = 1;
4253  lineJoin = 0;
4254  lineCap = 0;
4255  miterLimit = 10;
4256  strokeAdjust = gFalse;
4257 
4258  font = NULL;
4259  fontSize = 0;
4260  textMat[0] = 1; textMat[1] = 0;
4261  textMat[2] = 0; textMat[3] = 1;
4262  textMat[4] = 0; textMat[5] = 0;
4263  charSpace = 0;
4264  wordSpace = 0;
4265  horizScaling = 1;
4266  leading = 0;
4267  rise = 0;
4268  render = 0;
4269 
4270  path = new GfxPath();
4271  curX = curY = 0;
4272  lineX = lineY = 0;
4273 
4274  clipXMin = 0;
4275  clipYMin = 0;
4276  clipXMax =