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