]> git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/GfxState.cxx
Import cups.org releases
[thirdparty/cups.git] / pdftops / GfxState.cxx
1 //========================================================================
2 //
3 // GfxState.cc
4 //
5 // Copyright 1996 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <math.h>
16 #include <ctype.h>
17 #include <string.h> // for memcpy()
18 #include "gmem.h"
19 #include "Error.h"
20 #include "Object.h"
21 #include "Array.h"
22 #include "GfxState.h"
23
24 //------------------------------------------------------------------------
25
26 static inline double clip01(double x) {
27 return (x < 0) ? 0 : ((x > 1) ? 1 : x);
28 }
29
30 //------------------------------------------------------------------------
31 // GfxColorSpace
32 //------------------------------------------------------------------------
33
34 GfxColorSpace::GfxColorSpace() {
35 }
36
37 GfxColorSpace::~GfxColorSpace() {
38 }
39
40 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
41 GfxColorSpace *cs;
42 Object obj1;
43
44 cs = NULL;
45 if (csObj->isName()) {
46 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
47 cs = new GfxDeviceGrayColorSpace();
48 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
49 cs = new GfxDeviceRGBColorSpace();
50 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
51 cs = new GfxDeviceCMYKColorSpace();
52 } else if (csObj->isName("Pattern")) {
53 cs = new GfxPatternColorSpace(NULL);
54 } else {
55 error(-1, "Bad color space '%s'", csObj->getName());
56 }
57 } else if (csObj->isArray()) {
58 csObj->arrayGet(0, &obj1);
59 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
60 cs = new GfxDeviceGrayColorSpace();
61 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
62 cs = new GfxDeviceRGBColorSpace();
63 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
64 cs = new GfxDeviceCMYKColorSpace();
65 } else if (obj1.isName("CalGray")) {
66 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
67 } else if (obj1.isName("CalRGB")) {
68 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
69 } else if (obj1.isName("Lab")) {
70 cs = GfxLabColorSpace::parse(csObj->getArray());
71 } else if (obj1.isName("ICCBased")) {
72 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
73 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
74 cs = GfxIndexedColorSpace::parse(csObj->getArray());
75 } else if (obj1.isName("Separation")) {
76 cs = GfxSeparationColorSpace::parse(csObj->getArray());
77 } else if (obj1.isName("DeviceN")) {
78 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
79 } else if (obj1.isName("Pattern")) {
80 cs = GfxPatternColorSpace::parse(csObj->getArray());
81 } else {
82 error(-1, "Bad color space '%s'", csObj->getName());
83 }
84 obj1.free();
85 } else {
86 error(-1, "Bad color space - expected name or array");
87 }
88 return cs;
89 }
90
91 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
92 int maxImgPixel) {
93 int i;
94
95 for (i = 0; i < getNComps(); ++i) {
96 decodeLow[i] = 0;
97 decodeRange[i] = 1;
98 }
99 }
100
101 //------------------------------------------------------------------------
102 // GfxDeviceGrayColorSpace
103 //------------------------------------------------------------------------
104
105 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
106 }
107
108 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
109 }
110
111 GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
113 }
114
115 void GfxDeviceGrayColorSpace::getGray(GfxColor *color, double *gray) {
116 *gray = clip01(color->c[0]);
117 }
118
119 void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
120 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
121 }
122
123 void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
124 cmyk->c = cmyk->m = cmyk->y = 0;
125 cmyk->k = clip01(1 - color->c[0]);
126 }
127
128 //------------------------------------------------------------------------
129 // GfxCalGrayColorSpace
130 //------------------------------------------------------------------------
131
132 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX = whiteY = whiteZ = 1;
134 blackX = blackY = blackZ = 0;
135 gamma = 1;
136 }
137
138 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
139 }
140
141 GfxColorSpace *GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace *cs;
143
144 cs = new GfxCalGrayColorSpace();
145 cs->whiteX = whiteX;
146 cs->whiteY = whiteY;
147 cs->whiteZ = whiteZ;
148 cs->blackX = blackX;
149 cs->blackY = blackY;
150 cs->blackZ = blackZ;
151 cs->gamma = gamma;
152 return cs;
153 }
154
155 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
156 GfxCalGrayColorSpace *cs;
157 Object obj1, obj2, obj3;
158
159 arr->get(1, &obj1);
160 if (!obj1.isDict()) {
161 error(-1, "Bad CalGray color space");
162 obj1.free();
163 return NULL;
164 }
165 cs = new GfxCalGrayColorSpace();
166 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
167 obj2.arrayGetLength() == 3) {
168 obj2.arrayGet(0, &obj3);
169 cs->whiteX = obj3.getNum();
170 obj3.free();
171 obj2.arrayGet(1, &obj3);
172 cs->whiteY = obj3.getNum();
173 obj3.free();
174 obj2.arrayGet(2, &obj3);
175 cs->whiteZ = obj3.getNum();
176 obj3.free();
177 }
178 obj2.free();
179 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
180 obj2.arrayGetLength() == 3) {
181 obj2.arrayGet(0, &obj3);
182 cs->blackX = obj3.getNum();
183 obj3.free();
184 obj2.arrayGet(1, &obj3);
185 cs->blackY = obj3.getNum();
186 obj3.free();
187 obj2.arrayGet(2, &obj3);
188 cs->blackZ = obj3.getNum();
189 obj3.free();
190 }
191 obj2.free();
192 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
193 cs->gamma = obj2.getNum();
194 }
195 obj2.free();
196 obj1.free();
197 return cs;
198 }
199
200 void GfxCalGrayColorSpace::getGray(GfxColor *color, double *gray) {
201 *gray = clip01(color->c[0]);
202 }
203
204 void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
205 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
206 }
207
208 void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
209 cmyk->c = cmyk->m = cmyk->y = 0;
210 cmyk->k = clip01(1 - color->c[0]);
211 }
212
213 //------------------------------------------------------------------------
214 // GfxDeviceRGBColorSpace
215 //------------------------------------------------------------------------
216
217 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
218 }
219
220 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
221 }
222
223 GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
225 }
226
227 void GfxDeviceRGBColorSpace::getGray(GfxColor *color, double *gray) {
228 *gray = clip01(0.299 * color->c[0] +
229 0.587 * color->c[1] +
230 0.114 * color->c[2]);
231 }
232
233 void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
234 rgb->r = clip01(color->c[0]);
235 rgb->g = clip01(color->c[1]);
236 rgb->b = clip01(color->c[2]);
237 }
238
239 void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
240 double c, m, y, k;
241
242 c = clip01(1 - color->c[0]);
243 m = clip01(1 - color->c[1]);
244 y = clip01(1 - color->c[2]);
245 k = c;
246 if (m < k) {
247 k = m;
248 }
249 if (y < k) {
250 k = y;
251 }
252 cmyk->c = c - k;
253 cmyk->m = m - k;
254 cmyk->y = y - k;
255 cmyk->k = k;
256 }
257
258 //------------------------------------------------------------------------
259 // GfxCalRGBColorSpace
260 //------------------------------------------------------------------------
261
262 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
263 whiteX = whiteY = whiteZ = 1;
264 blackX = blackY = blackZ = 0;
265 gammaR = gammaG = gammaB = 1;
266 m[0] = 1; m[1] = 0; m[2] = 0;
267 m[3] = 0; m[4] = 1; m[5] = 0;
268 m[6] = 0; m[7] = 0; m[8] = 1;
269 }
270
271 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
272 }
273
274 GfxColorSpace *GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace *cs;
276 int i;
277
278 cs = new GfxCalRGBColorSpace();
279 cs->whiteX = whiteX;
280 cs->whiteY = whiteY;
281 cs->whiteZ = whiteZ;
282 cs->blackX = blackX;
283 cs->blackY = blackY;
284 cs->blackZ = blackZ;
285 cs->gammaR = gammaR;
286 cs->gammaG = gammaG;
287 cs->gammaB = gammaB;
288 for (i = 0; i < 9; ++i) {
289 cs->m[i] = m[i];
290 }
291 return cs;
292 }
293
294 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
295 GfxCalRGBColorSpace *cs;
296 Object obj1, obj2, obj3;
297 int i;
298
299 arr->get(1, &obj1);
300 if (!obj1.isDict()) {
301 error(-1, "Bad CalRGB color space");
302 obj1.free();
303 return NULL;
304 }
305 cs = new GfxCalRGBColorSpace();
306 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
307 obj2.arrayGetLength() == 3) {
308 obj2.arrayGet(0, &obj3);
309 cs->whiteX = obj3.getNum();
310 obj3.free();
311 obj2.arrayGet(1, &obj3);
312 cs->whiteY = obj3.getNum();
313 obj3.free();
314 obj2.arrayGet(2, &obj3);
315 cs->whiteZ = obj3.getNum();
316 obj3.free();
317 }
318 obj2.free();
319 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
320 obj2.arrayGetLength() == 3) {
321 obj2.arrayGet(0, &obj3);
322 cs->blackX = obj3.getNum();
323 obj3.free();
324 obj2.arrayGet(1, &obj3);
325 cs->blackY = obj3.getNum();
326 obj3.free();
327 obj2.arrayGet(2, &obj3);
328 cs->blackZ = obj3.getNum();
329 obj3.free();
330 }
331 obj2.free();
332 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
333 obj2.arrayGetLength() == 3) {
334 obj2.arrayGet(0, &obj3);
335 cs->gammaR = obj3.getNum();
336 obj3.free();
337 obj2.arrayGet(1, &obj3);
338 cs->gammaG = obj3.getNum();
339 obj3.free();
340 obj2.arrayGet(2, &obj3);
341 cs->gammaB = obj3.getNum();
342 obj3.free();
343 }
344 obj2.free();
345 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
346 obj2.arrayGetLength() == 9) {
347 for (i = 0; i < 9; ++i) {
348 obj2.arrayGet(i, &obj3);
349 cs->m[i] = obj3.getNum();
350 obj3.free();
351 }
352 }
353 obj2.free();
354 obj1.free();
355 return cs;
356 }
357
358 void GfxCalRGBColorSpace::getGray(GfxColor *color, double *gray) {
359 *gray = clip01(0.299 * color->c[0] +
360 0.587 * color->c[1] +
361 0.114 * color->c[2]);
362 }
363
364 void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
365 rgb->r = clip01(color->c[0]);
366 rgb->g = clip01(color->c[1]);
367 rgb->b = clip01(color->c[2]);
368 }
369
370 void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
371 double c, m, y, k;
372
373 c = clip01(1 - color->c[0]);
374 m = clip01(1 - color->c[1]);
375 y = clip01(1 - color->c[2]);
376 k = c;
377 if (m < k) {
378 k = m;
379 }
380 if (y < k) {
381 k = y;
382 }
383 cmyk->c = c - k;
384 cmyk->m = m - k;
385 cmyk->y = y - k;
386 cmyk->k = k;
387 }
388
389 //------------------------------------------------------------------------
390 // GfxDeviceCMYKColorSpace
391 //------------------------------------------------------------------------
392
393 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
394 }
395
396 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
397 }
398
399 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
401 }
402
403 void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, double *gray) {
404 *gray = clip01(1 - color->c[3]
405 - 0.299 * color->c[0]
406 - 0.587 * color->c[1]
407 - 0.114 * color->c[2]);
408 }
409
410 void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
411 rgb->r = clip01(1 - (color->c[0] + color->c[3]));
412 rgb->g = clip01(1 - (color->c[1] + color->c[3]));
413 rgb->b = clip01(1 - (color->c[2] + color->c[3]));
414 }
415
416 void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
417 cmyk->c = clip01(color->c[0]);
418 cmyk->m = clip01(color->c[1]);
419 cmyk->y = clip01(color->c[2]);
420 cmyk->k = clip01(color->c[3]);
421 }
422
423 //------------------------------------------------------------------------
424 // GfxLabColorSpace
425 //------------------------------------------------------------------------
426
427 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
428 // Language Reference, Third Edition.
429 static double xyzrgb[3][3] = {
430 { 3.240449, -1.537136, -0.498531 },
431 { -0.969265, 1.876011, 0.041556 },
432 { 0.055643, -0.204026, 1.057229 }
433 };
434
435 GfxLabColorSpace::GfxLabColorSpace() {
436 whiteX = whiteY = whiteZ = 1;
437 blackX = blackY = blackZ = 0;
438 aMin = bMin = -100;
439 aMax = bMax = 100;
440 }
441
442 GfxLabColorSpace::~GfxLabColorSpace() {
443 }
444
445 GfxColorSpace *GfxLabColorSpace::copy() {
446 GfxLabColorSpace *cs;
447
448 cs = new GfxLabColorSpace();
449 cs->whiteX = whiteX;
450 cs->whiteY = whiteY;
451 cs->whiteZ = whiteZ;
452 cs->blackX = blackX;
453 cs->blackY = blackY;
454 cs->blackZ = blackZ;
455 cs->aMin = aMin;
456 cs->aMax = aMax;
457 cs->bMin = bMin;
458 cs->bMax = bMax;
459 cs->kr = kr;
460 cs->kg = kg;
461 cs->kb = kb;
462 return cs;
463 }
464
465 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
466 GfxLabColorSpace *cs;
467 Object obj1, obj2, obj3;
468
469 arr->get(1, &obj1);
470 if (!obj1.isDict()) {
471 error(-1, "Bad Lab color space");
472 obj1.free();
473 return NULL;
474 }
475 cs = new GfxLabColorSpace();
476 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
477 obj2.arrayGetLength() == 3) {
478 obj2.arrayGet(0, &obj3);
479 cs->whiteX = obj3.getNum();
480 obj3.free();
481 obj2.arrayGet(1, &obj3);
482 cs->whiteY = obj3.getNum();
483 obj3.free();
484 obj2.arrayGet(2, &obj3);
485 cs->whiteZ = obj3.getNum();
486 obj3.free();
487 }
488 obj2.free();
489 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
490 obj2.arrayGetLength() == 3) {
491 obj2.arrayGet(0, &obj3);
492 cs->blackX = obj3.getNum();
493 obj3.free();
494 obj2.arrayGet(1, &obj3);
495 cs->blackY = obj3.getNum();
496 obj3.free();
497 obj2.arrayGet(2, &obj3);
498 cs->blackZ = obj3.getNum();
499 obj3.free();
500 }
501 obj2.free();
502 if (obj1.dictLookup("Range", &obj2)->isArray() &&
503 obj2.arrayGetLength() == 4) {
504 obj2.arrayGet(0, &obj3);
505 cs->aMin = obj3.getNum();
506 obj3.free();
507 obj2.arrayGet(1, &obj3);
508 cs->aMax = obj3.getNum();
509 obj3.free();
510 obj2.arrayGet(2, &obj3);
511 cs->bMin = obj3.getNum();
512 obj3.free();
513 obj2.arrayGet(3, &obj3);
514 cs->bMax = obj3.getNum();
515 obj3.free();
516 }
517 obj2.free();
518 obj1.free();
519
520 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
521 xyzrgb[0][1] * cs->whiteY +
522 xyzrgb[0][2] * cs->whiteZ);
523 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
524 xyzrgb[1][1] * cs->whiteY +
525 xyzrgb[1][2] * cs->whiteZ);
526 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
527 xyzrgb[2][1] * cs->whiteY +
528 xyzrgb[2][2] * cs->whiteZ);
529
530 return cs;
531 }
532
533 void GfxLabColorSpace::getGray(GfxColor *color, double *gray) {
534 GfxRGB rgb;
535
536 getRGB(color, &rgb);
537 *gray = clip01(0.299 * rgb.r +
538 0.587 * rgb.g +
539 0.114 * rgb.b);
540 }
541
542 void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
543 double X, Y, Z;
544 double t1, t2;
545 double r, g, b;
546
547 // convert L*a*b* to CIE 1931 XYZ color space
548 t1 = (color->c[0] + 16) / 116;
549 t2 = t1 + color->c[1] / 500;
550 if (t2 >= (6.0 / 29.0)) {
551 X = t2 * t2 * t2;
552 } else {
553 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
554 }
555 X *= whiteX;
556 if (t1 >= (6.0 / 29.0)) {
557 Y = t1 * t1 * t1;
558 } else {
559 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
560 }
561 Y *= whiteY;
562 t2 = t1 - color->c[2] / 200;
563 if (t2 >= (6.0 / 29.0)) {
564 Z = t2 * t2 * t2;
565 } else {
566 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
567 }
568 Z *= whiteZ;
569
570 // convert XYZ to RGB, including gamut mapping and gamma correction
571 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
572 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
573 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
574 rgb->r = pow(clip01(r * kr), 0.5);
575 rgb->g = pow(clip01(g * kg), 0.5);
576 rgb->b = pow(clip01(b * kb), 0.5);
577 }
578
579 void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
580 GfxRGB rgb;
581 double c, m, y, k;
582
583 getRGB(color, &rgb);
584 c = clip01(1 - rgb.r);
585 m = clip01(1 - rgb.g);
586 y = clip01(1 - rgb.b);
587 k = c;
588 if (m < k) {
589 k = m;
590 }
591 if (y < k) {
592 k = y;
593 }
594 cmyk->c = c - k;
595 cmyk->m = m - k;
596 cmyk->y = y - k;
597 cmyk->k = k;
598 }
599
600 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
601 int maxImgPixel) {
602 decodeLow[0] = 0;
603 decodeRange[0] = 100;
604 decodeLow[1] = aMin;
605 decodeRange[1] = aMax - aMin;
606 decodeLow[2] = bMin;
607 decodeRange[2] = bMax - bMin;
608 }
609
610 //------------------------------------------------------------------------
611 // GfxICCBasedColorSpace
612 //------------------------------------------------------------------------
613
614 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
615 Ref *iccProfileStream) {
616 this->nComps = nComps;
617 this->alt = alt;
618 this->iccProfileStream = *iccProfileStream;
619 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
620 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
621 }
622
623 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
624 delete alt;
625 }
626
627 GfxColorSpace *GfxICCBasedColorSpace::copy() {
628 GfxICCBasedColorSpace *cs;
629 int i;
630
631 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
632 for (i = 0; i < 4; ++i) {
633 cs->rangeMin[i] = rangeMin[i];
634 cs->rangeMax[i] = rangeMax[i];
635 }
636 return cs;
637 }
638
639 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
640 GfxICCBasedColorSpace *cs;
641 Ref iccProfileStream;
642 int nComps;
643 GfxColorSpace *alt;
644 Dict *dict;
645 Object obj1, obj2, obj3;
646 int i;
647
648 arr->getNF(1, &obj1);
649 if (obj1.isRef()) {
650 iccProfileStream = obj1.getRef();
651 } else {
652 iccProfileStream.num = 0;
653 iccProfileStream.gen = 0;
654 }
655 obj1.free();
656 arr->get(1, &obj1);
657 if (!obj1.isStream()) {
658 error(-1, "Bad ICCBased color space (stream)");
659 obj1.free();
660 return NULL;
661 }
662 dict = obj1.streamGetDict();
663 if (!dict->lookup("N", &obj2)->isInt()) {
664 error(-1, "Bad ICCBased color space (N)");
665 obj2.free();
666 obj1.free();
667 return NULL;
668 }
669 nComps = obj2.getInt();
670 obj2.free();
671 if (dict->lookup("Alternate", &obj2)->isNull() ||
672 !(alt = GfxColorSpace::parse(&obj2))) {
673 switch (nComps) {
674 case 1:
675 alt = new GfxDeviceGrayColorSpace();
676 break;
677 case 3:
678 alt = new GfxDeviceRGBColorSpace();
679 break;
680 case 4:
681 alt = new GfxDeviceCMYKColorSpace();
682 break;
683 default:
684 error(-1, "Bad ICCBased color space - invalid N");
685 obj2.free();
686 obj1.free();
687 return NULL;
688 }
689 }
690 obj2.free();
691 cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream);
692 if (dict->lookup("Range", &obj2)->isArray() &&
693 obj2.arrayGetLength() == 2 * nComps) {
694 for (i = 0; i < nComps; ++i) {
695 obj2.arrayGet(2*i, &obj3);
696 cs->rangeMin[i] = obj3.getNum();
697 obj3.free();
698 obj2.arrayGet(2*i+1, &obj3);
699 cs->rangeMax[i] = obj3.getNum();
700 obj3.free();
701 }
702 }
703 obj2.free();
704 obj1.free();
705 return cs;
706 }
707
708 void GfxICCBasedColorSpace::getGray(GfxColor *color, double *gray) {
709 alt->getGray(color, gray);
710 }
711
712 void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
713 alt->getRGB(color, rgb);
714 }
715
716 void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
717 alt->getCMYK(color, cmyk);
718 }
719
720 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
721 double *decodeRange,
722 int maxImgPixel) {
723 int i;
724
725 for (i = 0; i < nComps; ++i) {
726 decodeLow[i] = rangeMin[i];
727 decodeRange[i] = rangeMax[i] - rangeMin[i];
728 }
729 }
730
731 //------------------------------------------------------------------------
732 // GfxIndexedColorSpace
733 //------------------------------------------------------------------------
734
735 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *base,
736 int indexHigh) {
737 this->base = base;
738 this->indexHigh = indexHigh;
739 this->lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
740 sizeof(Guchar));
741 }
742
743 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
744 delete base;
745 gfree(lookup);
746 }
747
748 GfxColorSpace *GfxIndexedColorSpace::copy() {
749 GfxIndexedColorSpace *cs;
750
751 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
752 memcpy(cs->lookup, lookup,
753 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
754 return cs;
755 }
756
757 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
758 GfxIndexedColorSpace *cs;
759 GfxColorSpace *base;
760 int indexHigh;
761 Object obj1;
762 int x;
763 char *s;
764 int n, i, j;
765
766 if (arr->getLength() != 4) {
767 error(-1, "Bad Indexed color space");
768 goto err1;
769 }
770 arr->get(1, &obj1);
771 if (!(base = GfxColorSpace::parse(&obj1))) {
772 error(-1, "Bad Indexed color space (base color space)");
773 goto err2;
774 }
775 obj1.free();
776 if (!arr->get(2, &obj1)->isInt()) {
777 error(-1, "Bad Indexed color space (hival)");
778 goto err2;
779 }
780 indexHigh = obj1.getInt();
781 obj1.free();
782 cs = new GfxIndexedColorSpace(base, indexHigh);
783 arr->get(3, &obj1);
784 n = base->getNComps();
785 if (obj1.isStream()) {
786 obj1.streamReset();
787 for (i = 0; i <= indexHigh; ++i) {
788 for (j = 0; j < n; ++j) {
789 if ((x = obj1.streamGetChar()) == EOF) {
790 error(-1, "Bad Indexed color space (lookup table stream too short)");
791 goto err3;
792 }
793 cs->lookup[i*n + j] = (Guchar)x;
794 }
795 }
796 obj1.streamClose();
797 } else if (obj1.isString()) {
798 if (obj1.getString()->getLength() < (indexHigh + 1) * n) {
799 error(-1, "Bad Indexed color space (lookup table string too short)");
800 goto err3;
801 }
802 s = obj1.getString()->getCString();
803 for (i = 0; i <= indexHigh; ++i) {
804 for (j = 0; j < n; ++j) {
805 cs->lookup[i*n + j] = (Guchar)*s++;
806 }
807 }
808 } else {
809 error(-1, "Bad Indexed color space (lookup table)");
810 goto err3;
811 }
812 obj1.free();
813 return cs;
814
815 err3:
816 delete cs;
817 err2:
818 obj1.free();
819 err1:
820 return NULL;
821 }
822
823 void GfxIndexedColorSpace::getGray(GfxColor *color, double *gray) {
824 Guchar *p;
825 GfxColor color2;
826 int n, i;
827
828 n = base->getNComps();
829 p = &lookup[(int)(color->c[0] + 0.5) * n];
830 for (i = 0; i < n; ++i) {
831 color2.c[i] = p[i] / 255.0;
832 }
833 base->getGray(&color2, gray);
834 }
835
836 void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
837 Guchar *p;
838 GfxColor color2;
839 int n, i;
840
841 n = base->getNComps();
842 p = &lookup[(int)(color->c[0] + 0.5) * n];
843 for (i = 0; i < n; ++i) {
844 color2.c[i] = p[i] / 255.0;
845 }
846 base->getRGB(&color2, rgb);
847 }
848
849 void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
850 Guchar *p;
851 GfxColor color2;
852 int n, i;
853
854 n = base->getNComps();
855 p = &lookup[(int)(color->c[0] + 0.5) * n];
856 for (i = 0; i < n; ++i) {
857 color2.c[i] = p[i] / 255.0;
858 }
859 base->getCMYK(&color2, cmyk);
860 }
861
862 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
863 double *decodeRange,
864 int maxImgPixel) {
865 decodeLow[0] = 0;
866 decodeRange[0] = maxImgPixel;
867 }
868
869 //------------------------------------------------------------------------
870 // GfxSeparationColorSpace
871 //------------------------------------------------------------------------
872
873 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name,
874 GfxColorSpace *alt,
875 Function *func) {
876 this->name = name;
877 this->alt = alt;
878 this->func = func;
879 }
880
881 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
882 delete name;
883 delete alt;
884 delete func;
885 }
886
887 GfxColorSpace *GfxSeparationColorSpace::copy() {
888 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
889 }
890
891 //~ handle the 'All' and 'None' colorants
892 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
893 GfxSeparationColorSpace *cs;
894 GString *name;
895 GfxColorSpace *alt;
896 Function *func;
897 Object obj1;
898
899 if (arr->getLength() != 4) {
900 error(-1, "Bad Separation color space");
901 goto err1;
902 }
903 if (!arr->get(1, &obj1)->isName()) {
904 error(-1, "Bad Separation color space (name)");
905 goto err2;
906 }
907 name = new GString(obj1.getName());
908 obj1.free();
909 arr->get(2, &obj1);
910 if (!(alt = GfxColorSpace::parse(&obj1))) {
911 error(-1, "Bad Separation color space (alternate color space)");
912 goto err3;
913 }
914 obj1.free();
915 func = Function::parse(arr->get(3, &obj1));
916 obj1.free();
917 if (!func->isOk()) {
918 goto err4;
919 }
920 cs = new GfxSeparationColorSpace(name, alt, func);
921 return cs;
922
923 err4:
924 delete func;
925 delete alt;
926 err3:
927 delete name;
928 err2:
929 obj1.free();
930 err1:
931 return NULL;
932 }
933
934 void GfxSeparationColorSpace::getGray(GfxColor *color, double *gray) {
935 GfxColor color2;
936
937 func->transform(color->c, color2.c);
938 alt->getGray(&color2, gray);
939 }
940
941 void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
942 GfxColor color2;
943
944 func->transform(color->c, color2.c);
945 alt->getRGB(&color2, rgb);
946 }
947
948 void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
949 GfxColor color2;
950
951 func->transform(color->c, color2.c);
952 alt->getCMYK(&color2, cmyk);
953 }
954
955 //------------------------------------------------------------------------
956 // GfxDeviceNColorSpace
957 //------------------------------------------------------------------------
958
959 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
960 GfxColorSpace *alt,
961 Function *func) {
962 this->nComps = nComps;
963 this->alt = alt;
964 this->func = func;
965 }
966
967 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
968 int i;
969
970 for (i = 0; i < nComps; ++i) {
971 delete names[i];
972 }
973 delete alt;
974 delete func;
975 }
976
977 GfxColorSpace *GfxDeviceNColorSpace::copy() {
978 GfxDeviceNColorSpace *cs;
979 int i;
980
981 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
982 for (i = 0; i < nComps; ++i) {
983 cs->names[i] = names[i]->copy();
984 }
985 return cs;
986 }
987
988 //~ handle the 'None' colorant
989 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
990 GfxDeviceNColorSpace *cs;
991 int nComps;
992 GString *names[gfxColorMaxComps];
993 GfxColorSpace *alt;
994 Function *func;
995 Object obj1, obj2;
996 int i;
997
998 if (arr->getLength() != 4 && arr->getLength() != 5) {
999 error(-1, "Bad DeviceN color space");
1000 goto err1;
1001 }
1002 if (!arr->get(1, &obj1)->isArray()) {
1003 error(-1, "Bad DeviceN color space (names)");
1004 goto err2;
1005 }
1006 nComps = obj1.arrayGetLength();
1007 for (i = 0; i < nComps; ++i) {
1008 if (!obj1.arrayGet(i, &obj2)->isName()) {
1009 error(-1, "Bad DeviceN color space (names)");
1010 obj2.free();
1011 goto err2;
1012 }
1013 names[i] = new GString(obj2.getName());
1014 obj2.free();
1015 }
1016 obj1.free();
1017 arr->get(2, &obj1);
1018 if (!(alt = GfxColorSpace::parse(&obj1))) {
1019 error(-1, "Bad DeviceN color space (alternate color space)");
1020 goto err3;
1021 }
1022 obj1.free();
1023 func = Function::parse(arr->get(3, &obj1));
1024 obj1.free();
1025 if (!func->isOk()) {
1026 goto err4;
1027 }
1028 cs = new GfxDeviceNColorSpace(nComps, alt, func);
1029 for (i = 0; i < nComps; ++i) {
1030 cs->names[i] = names[i];
1031 }
1032 return cs;
1033
1034 err4:
1035 delete func;
1036 delete alt;
1037 err3:
1038 for (i = 0; i < nComps; ++i) {
1039 delete names[i];
1040 }
1041 err2:
1042 obj1.free();
1043 err1:
1044 return NULL;
1045 }
1046
1047 void GfxDeviceNColorSpace::getGray(GfxColor *color, double *gray) {
1048 GfxColor color2;
1049
1050 func->transform(color->c, color2.c);
1051 alt->getGray(&color2, gray);
1052 }
1053
1054 void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1055 GfxColor color2;
1056
1057 func->transform(color->c, color2.c);
1058 alt->getRGB(&color2, rgb);
1059 }
1060
1061 void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1062 GfxColor color2;
1063
1064 func->transform(color->c, color2.c);
1065 alt->getCMYK(&color2, cmyk);
1066 }
1067
1068 //------------------------------------------------------------------------
1069 // GfxPatternColorSpace
1070 //------------------------------------------------------------------------
1071
1072 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
1073 this->under = under;
1074 }
1075
1076 GfxPatternColorSpace::~GfxPatternColorSpace() {
1077 if (under) {
1078 delete under;
1079 }
1080 }
1081
1082 GfxColorSpace *GfxPatternColorSpace::copy() {
1083 return new GfxPatternColorSpace(under ? under->copy() :
1084 (GfxColorSpace *)NULL);
1085 }
1086
1087 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1088 GfxPatternColorSpace *cs;
1089 GfxColorSpace *under;
1090 Object obj1;
1091
1092 if (arr->getLength() != 1 && arr->getLength() != 2) {
1093 error(-1, "Bad Pattern color space");
1094 return NULL;
1095 }
1096 under = NULL;
1097 if (arr->getLength() == 2) {
1098 arr->get(1, &obj1);
1099 if (!(under = GfxColorSpace::parse(&obj1))) {
1100 error(-1, "Bad Pattern color space (underlying color space)");
1101 obj1.free();
1102 return NULL;
1103 }
1104 obj1.free();
1105 }
1106 cs = new GfxPatternColorSpace(under);
1107 return cs;
1108 }
1109
1110 void GfxPatternColorSpace::getGray(GfxColor *color, double *gray) {
1111 *gray = 0;
1112 }
1113
1114 void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1115 rgb->r = rgb->g = rgb->b = 0;
1116 }
1117
1118 void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1119 cmyk->c = cmyk->m = cmyk->y = 0;
1120 cmyk->k = 1;
1121 }
1122
1123 //------------------------------------------------------------------------
1124 // Pattern
1125 //------------------------------------------------------------------------
1126
1127 GfxPattern::GfxPattern(int type) {
1128 this->type = type;
1129 }
1130
1131 GfxPattern::~GfxPattern() {
1132 }
1133
1134 GfxPattern *GfxPattern::parse(Object *obj) {
1135 GfxPattern *pattern;
1136 Dict *dict;
1137 Object obj1;
1138
1139 pattern = NULL;
1140 if (obj->isStream()) {
1141 dict = obj->streamGetDict();
1142 dict->lookup("PatternType", &obj1);
1143 if (obj1.isInt() && obj1.getInt() == 1) {
1144 pattern = new GfxTilingPattern(dict, obj);
1145 }
1146 obj1.free();
1147 }
1148 return pattern;
1149 }
1150
1151 //------------------------------------------------------------------------
1152 // GfxTilingPattern
1153 //------------------------------------------------------------------------
1154
1155 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1156 GfxPattern(1)
1157 {
1158 Object obj1, obj2;
1159 int i;
1160
1161 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1162 paintType = obj1.getInt();
1163 } else {
1164 paintType = 1;
1165 error(-1, "Invalid or missing PaintType in pattern");
1166 }
1167 obj1.free();
1168 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1169 tilingType = obj1.getInt();
1170 } else {
1171 tilingType = 1;
1172 error(-1, "Invalid or missing TilingType in pattern");
1173 }
1174 obj1.free();
1175 bbox[0] = bbox[1] = 0;
1176 bbox[2] = bbox[3] = 1;
1177 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1178 obj1.arrayGetLength() == 4) {
1179 for (i = 0; i < 4; ++i) {
1180 if (obj1.arrayGet(i, &obj2)->isNum()) {
1181 bbox[i] = obj2.getNum();
1182 }
1183 obj2.free();
1184 }
1185 } else {
1186 error(-1, "Invalid or missing BBox in pattern");
1187 }
1188 obj1.free();
1189 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1190 xStep = obj1.getNum();
1191 } else {
1192 xStep = 1;
1193 error(-1, "Invalid or missing XStep in pattern");
1194 }
1195 obj1.free();
1196 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1197 yStep = obj1.getNum();
1198 } else {
1199 yStep = 1;
1200 error(-1, "Invalid or missing YStep in pattern");
1201 }
1202 obj1.free();
1203 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1204 resDict.free();
1205 resDict.initNull();
1206 error(-1, "Invalid or missing Resources in pattern");
1207 }
1208 matrix[0] = 1; matrix[1] = 0;
1209 matrix[2] = 0; matrix[3] = 1;
1210 matrix[4] = 0; matrix[5] = 0;
1211 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1212 obj1.arrayGetLength() == 6) {
1213 for (i = 0; i < 6; ++i) {
1214 if (obj1.arrayGet(i, &obj2)->isNum()) {
1215 matrix[i] = obj2.getNum();
1216 }
1217 obj2.free();
1218 }
1219 }
1220 obj1.free();
1221 stream->copy(&contentStream);
1222 }
1223
1224 GfxTilingPattern::~GfxTilingPattern() {
1225 resDict.free();
1226 contentStream.free();
1227 }
1228
1229 GfxPattern *GfxTilingPattern::copy() {
1230 return new GfxTilingPattern(this);
1231 }
1232
1233 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1234 GfxPattern(1)
1235 {
1236 memcpy(this, pat, sizeof(GfxTilingPattern));
1237 pat->resDict.copy(&resDict);
1238 pat->contentStream.copy(&contentStream);
1239 }
1240
1241 //------------------------------------------------------------------------
1242 // Function
1243 //------------------------------------------------------------------------
1244
1245 Function::Function() {
1246 }
1247
1248 Function::~Function() {
1249 }
1250
1251 Function *Function::parse(Object *funcObj) {
1252 Function *func;
1253 Dict *dict;
1254 int funcType;
1255 Object obj1;
1256
1257 if (funcObj->isStream()) {
1258 dict = funcObj->streamGetDict();
1259 } else if (funcObj->isDict()) {
1260 dict = funcObj->getDict();
1261 } else {
1262 error(-1, "Expected function dictionary or stream");
1263 return NULL;
1264 }
1265
1266 if (!dict->lookup("FunctionType", &obj1)->isInt()) {
1267 error(-1, "Function type is missing or wrong type");
1268 obj1.free();
1269 return NULL;
1270 }
1271 funcType = obj1.getInt();
1272 obj1.free();
1273
1274 if (funcType == 0) {
1275 func = new SampledFunction(funcObj, dict);
1276 } else if (funcType == 2) {
1277 func = new ExponentialFunction(funcObj, dict);
1278 } else if (funcType == 4) {
1279 func = new PostScriptFunction(funcObj, dict);
1280 } else {
1281 error(-1, "Unimplemented function type");
1282 return NULL;
1283 }
1284 if (!func->isOk()) {
1285 delete func;
1286 return NULL;
1287 }
1288
1289 return func;
1290 }
1291
1292 GBool Function::init(Dict *dict) {
1293 Object obj1, obj2;
1294 int i;
1295
1296 //----- Domain
1297 if (!dict->lookup("Domain", &obj1)->isArray()) {
1298 error(-1, "Function is missing domain");
1299 goto err2;
1300 }
1301 m = obj1.arrayGetLength() / 2;
1302 if (m > funcMaxInputs) {
1303 error(-1, "Functions with more than %d inputs are unsupported",
1304 funcMaxInputs);
1305 goto err2;
1306 }
1307 for (i = 0; i < m; ++i) {
1308 obj1.arrayGet(2*i, &obj2);
1309 if (!obj2.isNum()) {
1310 error(-1, "Illegal value in function domain array");
1311 goto err1;
1312 }
1313 domain[i][0] = obj2.getNum();
1314 obj2.free();
1315 obj1.arrayGet(2*i+1, &obj2);
1316 if (!obj2.isNum()) {
1317 error(-1, "Illegal value in function domain array");
1318 goto err1;
1319 }
1320 domain[i][1] = obj2.getNum();
1321 obj2.free();
1322 }
1323 obj1.free();
1324
1325 //----- Range
1326 hasRange = gFalse;
1327 n = 0;
1328 if (dict->lookup("Range", &obj1)->isArray()) {
1329 hasRange = gTrue;
1330 n = obj1.arrayGetLength() / 2;
1331 if (n > funcMaxOutputs) {
1332 error(-1, "Functions with more than %d outputs are unsupported",
1333 funcMaxOutputs);
1334 goto err2;
1335 }
1336 for (i = 0; i < n; ++i) {
1337 obj1.arrayGet(2*i, &obj2);
1338 if (!obj2.isNum()) {
1339 error(-1, "Illegal value in function range array");
1340 goto err1;
1341 }
1342 range[i][0] = obj2.getNum();
1343 obj2.free();
1344 obj1.arrayGet(2*i+1, &obj2);
1345 if (!obj2.isNum()) {
1346 error(-1, "Illegal value in function range array");
1347 goto err1;
1348 }
1349 range[i][1] = obj2.getNum();
1350 obj2.free();
1351 }
1352 obj1.free();
1353 }
1354
1355 return gTrue;
1356
1357 err1:
1358 obj2.free();
1359 err2:
1360 obj1.free();
1361 return gFalse;
1362 }
1363
1364 //------------------------------------------------------------------------
1365 // SampledFunction
1366 //------------------------------------------------------------------------
1367
1368 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
1369 Stream *str;
1370 int nSamples, sampleBits;
1371 double sampleMul;
1372 Object obj1, obj2;
1373 Guint buf, bitMask;
1374 int bits;
1375 int s;
1376 int i;
1377
1378 samples = NULL;
1379 ok = gFalse;
1380
1381 //----- initialize the generic stuff
1382 if (!init(dict)) {
1383 goto err1;
1384 }
1385 if (!hasRange) {
1386 error(-1, "Type 0 function is missing range");
1387 goto err1;
1388 }
1389
1390 //----- get the stream
1391 if (!funcObj->isStream()) {
1392 error(-1, "Type 0 function isn't a stream");
1393 goto err1;
1394 }
1395 str = funcObj->getStream();
1396
1397 //----- Size
1398 if (!dict->lookup("Size", &obj1)->isArray() ||
1399 obj1.arrayGetLength() != m) {
1400 error(-1, "Function has missing or invalid size array");
1401 goto err2;
1402 }
1403 for (i = 0; i < m; ++i) {
1404 obj1.arrayGet(i, &obj2);
1405 if (!obj2.isInt()) {
1406 error(-1, "Illegal value in function size array");
1407 goto err3;
1408 }
1409 sampleSize[i] = obj2.getInt();
1410 obj2.free();
1411 }
1412 obj1.free();
1413
1414 //----- BitsPerSample
1415 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
1416 error(-1, "Function has missing or invalid BitsPerSample");
1417 goto err2;
1418 }
1419 sampleBits = obj1.getInt();
1420 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
1421 obj1.free();
1422
1423 //----- Encode
1424 if (dict->lookup("Encode", &obj1)->isArray() &&
1425 obj1.arrayGetLength() == 2*m) {
1426 for (i = 0; i < m; ++i) {
1427 obj1.arrayGet(2*i, &obj2);
1428 if (!obj2.isNum()) {
1429 error(-1, "Illegal value in function encode array");
1430 goto err3;
1431 }
1432 encode[i][0] = obj2.getNum();
1433 obj2.free();
1434 obj1.arrayGet(2*i+1, &obj2);
1435 if (!obj2.isNum()) {
1436 error(-1, "Illegal value in function encode array");
1437 goto err3;
1438 }
1439 encode[i][1] = obj2.getNum();
1440 obj2.free();
1441 }
1442 } else {
1443 for (i = 0; i < m; ++i) {
1444 encode[i][0] = 0;
1445 encode[i][1] = sampleSize[i] - 1;
1446 }
1447 }
1448 obj1.free();
1449
1450 //----- Decode
1451 if (dict->lookup("Decode", &obj1)->isArray() &&
1452 obj1.arrayGetLength() == 2*n) {
1453 for (i = 0; i < n; ++i) {
1454 obj1.arrayGet(2*i, &obj2);
1455 if (!obj2.isNum()) {
1456 error(-1, "Illegal value in function decode array");
1457 goto err3;
1458 }
1459 decode[i][0] = obj2.getNum();
1460 obj2.free();
1461 obj1.arrayGet(2*i+1, &obj2);
1462 if (!obj2.isNum()) {
1463 error(-1, "Illegal value in function decode array");
1464 goto err3;
1465 }
1466 decode[i][1] = obj2.getNum();
1467 obj2.free();
1468 }
1469 } else {
1470 for (i = 0; i < n; ++i) {
1471 decode[i][0] = range[i][0];
1472 decode[i][1] = range[i][1];
1473 }
1474 }
1475 obj1.free();
1476
1477 //----- samples
1478 nSamples = n;
1479 for (i = 0; i < m; ++i)
1480 nSamples *= sampleSize[i];
1481 samples = (double *)gmalloc(nSamples * sizeof(double));
1482 buf = 0;
1483 bits = 0;
1484 bitMask = (1 << sampleBits) - 1;
1485 str->reset();
1486 for (i = 0; i < nSamples; ++i) {
1487 if (sampleBits == 8) {
1488 s = str->getChar();
1489 } else if (sampleBits == 16) {
1490 s = str->getChar();
1491 s = (s << 8) + str->getChar();
1492 } else if (sampleBits == 32) {
1493 s = str->getChar();
1494 s = (s << 8) + str->getChar();
1495 s = (s << 8) + str->getChar();
1496 s = (s << 8) + str->getChar();
1497 } else {
1498 while (bits < sampleBits) {
1499 buf = (buf << 8) | (str->getChar() & 0xff);
1500 bits += 8;
1501 }
1502 s = (buf >> (bits - sampleBits)) & bitMask;
1503 bits -= sampleBits;
1504 }
1505 samples[i] = (double)s * sampleMul;
1506 }
1507 str->close();
1508
1509 ok = gTrue;
1510 return;
1511
1512 err3:
1513 obj2.free();
1514 err2:
1515 obj1.free();
1516 err1:
1517 return;
1518 }
1519
1520 SampledFunction::~SampledFunction() {
1521 if (samples) {
1522 gfree(samples);
1523 }
1524 }
1525
1526 SampledFunction::SampledFunction(SampledFunction *func) {
1527 int nSamples, i;
1528
1529 memcpy(this, func, sizeof(SampledFunction));
1530
1531 nSamples = n;
1532 for (i = 0; i < m; ++i) {
1533 nSamples *= sampleSize[i];
1534 }
1535 samples = (double *)gmalloc(nSamples * sizeof(double));
1536 memcpy(samples, func->samples, nSamples * sizeof(double));
1537 }
1538
1539 void SampledFunction::transform(double *in, double *out) {
1540 double e[4];
1541 double s;
1542 double x0, x1;
1543 int e0, e1;
1544 double efrac;
1545 int i;
1546
1547 // map input values into sample array
1548 for (i = 0; i < m; ++i) {
1549 e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
1550 (encode[i][1] - encode[i][0]) + encode[i][0];
1551 if (e[i] < 0) {
1552 e[i] = 0;
1553 } else if (e[i] > sampleSize[i] - 1) {
1554 e[i] = sampleSize[i] - 1;
1555 }
1556 }
1557
1558 for (i = 0; i < n; ++i) {
1559
1560 // m-linear interpolation
1561 // (only m=1 is currently supported)
1562 e0 = (int)floor(e[0]);
1563 e1 = (int)ceil(e[0]);
1564 efrac = e[0] - e0;
1565 x0 = samples[e0 * n + i];
1566 x1 = samples[e1 * n + i];
1567 s = (1 - efrac) * x0 + efrac * x1;
1568
1569 // map output values to range
1570 out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
1571 if (out[i] < range[i][0]) {
1572 out[i] = range[i][0];
1573 } else if (out[i] > range[i][1]) {
1574 out[i] = range[i][1];
1575 }
1576 }
1577 }
1578
1579 //------------------------------------------------------------------------
1580 // ExponentialFunction
1581 //------------------------------------------------------------------------
1582
1583 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
1584 Object obj1, obj2;
1585 GBool hasN;
1586 int i;
1587
1588 ok = gFalse;
1589 hasN = gFalse;
1590
1591 //----- initialize the generic stuff
1592 if (!init(dict)) {
1593 goto err1;
1594 }
1595 if (m != 1) {
1596 error(-1, "Exponential function with more than one input");
1597 goto err1;
1598 }
1599
1600 //----- default values
1601 for (i = 0; i < funcMaxOutputs; ++i) {
1602 c0[i] = 0;
1603 c1[i] = 1;
1604 }
1605
1606 //----- C0
1607 if (dict->lookup("C0", &obj1)->isArray()) {
1608 if (!hasN) {
1609 n = obj1.arrayGetLength();
1610 } else if (obj1.arrayGetLength() != n) {
1611 error(-1, "Function's C0 array is wrong length");
1612 goto err2;
1613 }
1614 for (i = 0; i < n; ++i) {
1615 obj1.arrayGet(i, &obj2);
1616 if (!obj2.isNum()) {
1617 error(-1, "Illegal value in function C0 array");
1618 goto err3;
1619 }
1620 c0[i] = obj2.getNum();
1621 obj2.free();
1622 }
1623 obj1.free();
1624 }
1625
1626 //----- C1
1627 if (dict->lookup("C1", &obj1)->isArray()) {
1628 if (!hasN) {
1629 n = obj1.arrayGetLength();
1630 } else if (obj1.arrayGetLength() != n) {
1631 error(-1, "Function's C1 array is wrong length");
1632 goto err2;
1633 }
1634 for (i = 0; i < n; ++i) {
1635 obj1.arrayGet(i, &obj2);
1636 if (!obj2.isNum()) {
1637 error(-1, "Illegal value in function C1 array");
1638 goto err3;
1639 }
1640 c1[i] = obj2.getNum();
1641 obj2.free();
1642 }
1643 obj1.free();
1644 }
1645
1646 //----- N (exponent)
1647 if (!dict->lookup("N", &obj1)->isNum()) {
1648 error(-1, "Function has missing or invalid N");
1649 goto err2;
1650 }
1651 e = obj1.getNum();
1652 obj1.free();
1653
1654 ok = gTrue;
1655 return;
1656
1657 err3:
1658 obj2.free();
1659 err2:
1660 obj1.free();
1661 err1:
1662 return;
1663 }
1664
1665 ExponentialFunction::~ExponentialFunction() {
1666 }
1667
1668 ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
1669 memcpy(this, func, sizeof(ExponentialFunction));
1670 }
1671
1672 void ExponentialFunction::transform(double *in, double *out) {
1673 double x;
1674 int i;
1675
1676 if (in[0] < domain[0][0]) {
1677 x = domain[0][0];
1678 } else if (in[0] > domain[0][1]) {
1679 x = domain[0][1];
1680 } else {
1681 x = in[0];
1682 }
1683 for (i = 0; i < n; ++i) {
1684 out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
1685 if (hasRange) {
1686 if (out[i] < range[i][0]) {
1687 out[i] = range[i][0];
1688 } else if (out[i] > range[i][1]) {
1689 out[i] = range[i][1];
1690 }
1691 }
1692 }
1693 return;
1694 }
1695
1696 //------------------------------------------------------------------------
1697 // PostScriptFunction
1698 //------------------------------------------------------------------------
1699
1700 enum PSOp {
1701 psOpAbs,
1702 psOpAdd,
1703 psOpAnd,
1704 psOpAtan,
1705 psOpBitshift,
1706 psOpCeiling,
1707 psOpCopy,
1708 psOpCos,
1709 psOpCvi,
1710 psOpCvr,
1711 psOpDiv,
1712 psOpDup,
1713 psOpEq,
1714 psOpExch,
1715 psOpExp,
1716 psOpFalse,
1717 psOpFloor,
1718 psOpGe,
1719 psOpGt,
1720 psOpIdiv,
1721 psOpIndex,
1722 psOpLe,
1723 psOpLn,
1724 psOpLog,
1725 psOpLt,
1726 psOpMod,
1727 psOpMul,
1728 psOpNe,
1729 psOpNeg,
1730 psOpNot,
1731 psOpOr,
1732 psOpPop,
1733 psOpRoll,
1734 psOpRound,
1735 psOpSin,
1736 psOpSqrt,
1737 psOpSub,
1738 psOpTrue,
1739 psOpTruncate,
1740 psOpXor,
1741 psOpIf,
1742 psOpIfelse,
1743 psOpReturn
1744 };
1745
1746 // Note: 'if' and 'ifelse' are parsed separately.
1747 // The rest are listed here in alphabetical order.
1748 // The index in this table is equivalent to the entry in PSOp.
1749 char *psOpNames[] = {
1750 "abs",
1751 "add",
1752 "and",
1753 "atan",
1754 "bitshift",
1755 "ceiling",
1756 "copy",
1757 "cos",
1758 "cvi",
1759 "cvr",
1760 "div",
1761 "dup",
1762 "eq",
1763 "exch",
1764 "exp",
1765 "false",
1766 "floor",
1767 "ge",
1768 "gt",
1769 "idiv",
1770 "index",
1771 "le",
1772 "ln",
1773 "log",
1774 "lt",
1775 "mod",
1776 "mul",
1777 "ne",
1778 "neg",
1779 "not",
1780 "or",
1781 "pop",
1782 "roll",
1783 "round",
1784 "sin",
1785 "sqrt",
1786 "sub",
1787 "true",
1788 "truncate",
1789 "xor"
1790 };
1791
1792 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
1793
1794 enum PSObjectType {
1795 psBool,
1796 psInt,
1797 psReal,
1798 psOperator,
1799 psBlock
1800 };
1801
1802 // In the code array, 'if'/'ifelse' operators take up three slots
1803 // plus space for the code in the subclause(s).
1804 //
1805 // +---------------------------------+
1806 // | psOperator: psOpIf / psOpIfelse |
1807 // +---------------------------------+
1808 // | psBlock: ptr=<A> |
1809 // +---------------------------------+
1810 // | psBlock: ptr=<B> |
1811 // +---------------------------------+
1812 // | if clause |
1813 // | ... |
1814 // | psOperator: psOpReturn |
1815 // +---------------------------------+
1816 // <A> | else clause |
1817 // | ... |
1818 // | psOperator: psOpReturn |
1819 // +---------------------------------+
1820 // <B> | ... |
1821 //
1822 // For 'if', pointer <A> is present in the code stream but unused.
1823
1824 struct PSObject {
1825 PSObjectType type;
1826 union {
1827 GBool booln; // boolean (stack only)
1828 int intg; // integer (stack and code)
1829 double real; // real (stack and code)
1830 PSOp op; // operator (code only)
1831 int blk; // if/ifelse block pointer (code only)
1832 };
1833 };
1834
1835 #define psStackSize 100
1836
1837 class PSStack {
1838 public:
1839
1840 PSStack() { sp = psStackSize; }
1841 void pushBool(GBool booln);
1842 void pushInt(int intg);
1843 void pushReal(double real);
1844 GBool popBool();
1845 int popInt();
1846 double popNum();
1847 GBool empty() { return sp == psStackSize; }
1848 GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
1849 GBool topTwoAreInts()
1850 { return sp < psStackSize - 1 &&
1851 stack[sp].type == psInt &&
1852 stack[sp+1].type == psInt; }
1853 GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
1854 GBool topTwoAreNums()
1855 { return sp < psStackSize - 1 &&
1856 (stack[sp].type == psInt || stack[sp].type == psReal) &&
1857 (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
1858 void copy(int n);
1859 void roll(int n, int j);
1860 void index(int i);
1861 void pop();
1862
1863 private:
1864
1865 GBool checkOverflow(int n = 1);
1866 GBool checkUnderflow();
1867 GBool checkType(PSObjectType t1, PSObjectType t2);
1868
1869 PSObject stack[psStackSize];
1870 int sp;
1871 };
1872
1873 GBool PSStack::checkOverflow(int n) {
1874 if (sp - n < 0) {
1875 error(-1, "Stack overflow in PostScript function");
1876 return gFalse;
1877 }
1878 return gTrue;
1879 }
1880
1881 GBool PSStack::checkUnderflow() {
1882 if (sp == psStackSize) {
1883 error(-1, "Stack underflow in PostScript function");
1884 return gFalse;
1885 }
1886 return gTrue;
1887 }
1888
1889 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
1890 if (stack[sp].type != t1 && stack[sp].type != t2) {
1891 error(-1, "Type mismatch in PostScript function");
1892 return gFalse;
1893 }
1894 return gTrue;
1895 }
1896
1897 void PSStack::pushBool(GBool booln) {
1898 if (checkOverflow()) {
1899 stack[--sp].type = psBool;
1900 stack[sp].booln = booln;
1901 }
1902 }
1903
1904 void PSStack::pushInt(int intg) {
1905 if (checkOverflow()) {
1906 stack[--sp].type = psInt;
1907 stack[sp].intg = intg;
1908 }
1909 }
1910
1911 void PSStack::pushReal(double real) {
1912 if (checkOverflow()) {
1913 stack[--sp].type = psReal;
1914 stack[sp].real = real;
1915 }
1916 }
1917
1918 GBool PSStack::popBool() {
1919 if (checkUnderflow() && checkType(psBool, psBool)) {
1920 return stack[sp++].booln;
1921 }
1922 return gFalse;
1923 }
1924
1925 int PSStack::popInt() {
1926 if (checkUnderflow() && checkType(psInt, psInt)) {
1927 return stack[sp++].intg;
1928 }
1929 return 0;
1930 }
1931
1932 double PSStack::popNum() {
1933 double ret;
1934
1935 if (checkUnderflow() && checkType(psInt, psReal)) {
1936 ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
1937 ++sp;
1938 return ret;
1939 }
1940 return 0;
1941 }
1942
1943 void PSStack::copy(int n) {
1944 int i;
1945
1946 if (!checkOverflow(n)) {
1947 return;
1948 }
1949 for (i = sp + n - 1; i <= sp; ++i) {
1950 stack[i - n] = stack[i];
1951 }
1952 sp -= n;
1953 }
1954
1955 void PSStack::roll(int n, int j) {
1956 PSObject obj;
1957 int i, k;
1958
1959 if (j >= 0) {
1960 j %= n;
1961 } else {
1962 j = -j % n;
1963 if (j != 0) {
1964 j = n - j;
1965 }
1966 }
1967 if (n <= 0 || j == 0) {
1968 return;
1969 }
1970 for (i = 0; i < j; ++i) {
1971 obj = stack[sp];
1972 for (k = sp; k < sp + n - 1; ++k) {
1973 stack[k] = stack[k+1];
1974 }
1975 stack[sp + n - 1] = obj;
1976 }
1977 }
1978
1979 void PSStack::index(int i) {
1980 if (!checkOverflow()) {
1981 return;
1982 }
1983 --sp;
1984 stack[sp] = stack[sp + 1 + i];
1985 }
1986
1987 void PSStack::pop() {
1988 if (!checkUnderflow()) {
1989 return;
1990 }
1991 ++sp;
1992 }
1993
1994 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
1995 Stream *str;
1996 int codePtr;
1997 GString *tok;
1998
1999 code = NULL;
2000 codeSize = 0;
2001 ok = gFalse;
2002
2003 //----- initialize the generic stuff
2004 if (!init(dict)) {
2005 goto err1;
2006 }
2007 if (!hasRange) {
2008 error(-1, "Type 4 function is missing range");
2009 goto err1;
2010 }
2011
2012 //----- get the stream
2013 if (!funcObj->isStream()) {
2014 error(-1, "Type 4 function isn't a stream");
2015 goto err1;
2016 }
2017 str = funcObj->getStream();
2018
2019 //----- parse the function
2020 str->reset();
2021 if (!(tok = getToken(str)) || tok->cmp("{")) {
2022 error(-1, "Expected '{' at start of PostScript function");
2023 if (tok) {
2024 delete tok;
2025 }
2026 goto err1;
2027 }
2028 delete tok;
2029 codePtr = 0;
2030 if (!parseCode(str, &codePtr)) {
2031 goto err2;
2032 }
2033 str->close();
2034
2035 ok = gTrue;
2036
2037 err2:
2038 str->close();
2039 err1:
2040 return;
2041 }
2042
2043 PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
2044 memcpy(this, func, sizeof(PostScriptFunction));
2045 code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
2046 memcpy(code, func->code, codeSize * sizeof(PSObject));
2047 }
2048
2049 PostScriptFunction::~PostScriptFunction() {
2050 gfree(code);
2051 }
2052
2053 void PostScriptFunction::transform(double *in, double *out) {
2054 PSStack *stack;
2055 int i;
2056
2057 stack = new PSStack();
2058 for (i = 0; i < m; ++i) {
2059 //~ may need to check for integers here
2060 stack->pushReal(in[i]);
2061 }
2062 exec(stack, 0);
2063 for (i = n - 1; i >= 0; --i) {
2064 out[i] = stack->popNum();
2065 if (out[i] < range[i][0]) {
2066 out[i] = range[i][0];
2067 } else if (out[i] > range[i][1]) {
2068 out[i] = range[i][1];
2069 }
2070 }
2071 // if (!stack->empty()) {
2072 // error(-1, "Extra values on stack at end of PostScript function");
2073 // }
2074 delete stack;
2075 }
2076
2077 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
2078 GString *tok;
2079 char *p;
2080 GBool isReal;
2081 int opPtr, elsePtr;
2082 int a, b, m, cmp;
2083
2084 while (1) {
2085 if (!(tok = getToken(str))) {
2086 error(-1, "Unexpected end of PostScript function stream");
2087 return gFalse;
2088 }
2089 p = tok->getCString();
2090 if (isdigit(*p) || *p == '.' || *p == '-') {
2091 isReal = gFalse;
2092 for (++p; *p; ++p) {
2093 if (*p == '.') {
2094 isReal = gTrue;
2095 break;
2096 }
2097 }
2098 resizeCode(*codePtr);
2099 if (isReal) {
2100 code[*codePtr].type = psReal;
2101 code[*codePtr].real = atof(tok->getCString());
2102 } else {
2103 code[*codePtr].type = psInt;
2104 code[*codePtr].intg = atoi(tok->getCString());
2105 }
2106 ++*codePtr;
2107 delete tok;
2108 } else if (!tok->cmp("{")) {
2109 delete tok;
2110 opPtr = *codePtr;
2111 *codePtr += 3;
2112 resizeCode(opPtr + 2);
2113 if (!parseCode(str, codePtr)) {
2114 return gFalse;
2115 }
2116 if (!(tok = getToken(str))) {
2117 error(-1, "Unexpected end of PostScript function stream");
2118 return gFalse;
2119 }
2120 if (!tok->cmp("{")) {
2121 elsePtr = *codePtr;
2122 if (!parseCode(str, codePtr)) {
2123 return gFalse;
2124 }
2125 } else {
2126 elsePtr = -1;
2127 }
2128 delete tok;
2129 if (!(tok = getToken(str))) {
2130 error(-1, "Unexpected end of PostScript function stream");
2131 return gFalse;
2132 }
2133 if (!tok->cmp("if")) {
2134 if (elsePtr >= 0) {
2135 error(-1, "Got 'if' operator with two blocks in PostScript function");
2136 return gFalse;
2137 }
2138 code[opPtr].type = psOperator;
2139 code[opPtr].op = psOpIf;
2140 code[opPtr+2].type = psBlock;
2141 code[opPtr+2].blk = *codePtr;
2142 } else if (!tok->cmp("ifelse")) {
2143 if (elsePtr < 0) {
2144 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
2145 return gFalse;
2146 }
2147 code[opPtr].type = psOperator;
2148 code[opPtr].op = psOpIfelse;
2149 code[opPtr+1].type = psBlock;
2150 code[opPtr+1].blk = elsePtr;
2151 code[opPtr+2].type = psBlock;
2152 code[opPtr+2].blk = *codePtr;
2153 } else {
2154 error(-1, "Expected if/ifelse operator in PostScript function");
2155 delete tok;
2156 return gFalse;
2157 }
2158 delete tok;
2159 } else if (!tok->cmp("}")) {
2160 delete tok;
2161 resizeCode(*codePtr);
2162 code[*codePtr].type = psOperator;
2163 code[*codePtr].op = psOpReturn;
2164 ++*codePtr;
2165 break;
2166 } else {
2167 a = -1;
2168 b = nPSOps;
2169 // invariant: psOpNames[a] < tok < psOpNames[b]
2170 while (b - a > 1) {
2171 m = (a + b) / 2;
2172 cmp = tok->cmp(psOpNames[m]);
2173 if (cmp > 0) {
2174 a = m;
2175 } else if (cmp < 0) {
2176 b = m;
2177 } else {
2178 a = b = m;
2179 }
2180 }
2181 if (cmp != 0) {
2182 error(-1, "Unknown operator '%s' in PostScript function",
2183 tok->getCString());
2184 delete tok;
2185 return gFalse;
2186 }
2187 delete tok;
2188 resizeCode(*codePtr);
2189 code[*codePtr].type = psOperator;
2190 code[*codePtr].op = (PSOp)a;
2191 ++*codePtr;
2192 }
2193 }
2194 return gTrue;
2195 }
2196
2197 GString *PostScriptFunction::getToken(Stream *str) {
2198 GString *s;
2199 int c;
2200
2201 s = new GString();
2202 do {
2203 c = str->getChar();
2204 } while (c != EOF && isspace(c));
2205 if (c == '{' || c == '}') {
2206 s->append((char)c);
2207 } else if (isdigit(c) || c == '.' || c == '-') {
2208 while (1) {
2209 s->append((char)c);
2210 c = str->lookChar();
2211 if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
2212 break;
2213 }
2214 str->getChar();
2215 }
2216 } else {
2217 while (1) {
2218 s->append((char)c);
2219 c = str->lookChar();
2220 if (c == EOF || !isalnum(c)) {
2221 break;
2222 }
2223 str->getChar();
2224 }
2225 }
2226 return s;
2227 }
2228
2229 void PostScriptFunction::resizeCode(int newSize) {
2230 if (newSize >= codeSize) {
2231 codeSize += 64;
2232 code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
2233 }
2234 }
2235
2236 void PostScriptFunction::exec(PSStack *stack, int codePtr) {
2237 int i1, i2;
2238 double r1, r2;
2239 GBool b1, b2;
2240
2241 while (1) {
2242 switch (code[codePtr].type) {
2243 case psInt:
2244 stack->pushInt(code[codePtr++].intg);
2245 break;
2246 case psReal:
2247 stack->pushReal(code[codePtr++].real);
2248 break;
2249 case psOperator:
2250 switch (code[codePtr++].op) {
2251 case psOpAbs:
2252 if (stack->topIsInt()) {
2253 stack->pushInt(abs(stack->popInt()));
2254 } else {
2255 stack->pushReal(fabs(stack->popNum()));
2256 }
2257 break;
2258 case psOpAdd:
2259 if (stack->topTwoAreInts()) {
2260 i2 = stack->popInt();
2261 i1 = stack->popInt();
2262 stack->pushInt(i1 + i2);
2263 } else {
2264 r2 = stack->popNum();
2265 r1 = stack->popNum();
2266 stack->pushReal(r1 + r2);
2267 }
2268 break;
2269 case psOpAnd:
2270 if (stack->topTwoAreInts()) {
2271 i2 = stack->popInt();
2272 i1 = stack->popInt();
2273 stack->pushInt(i1 & i2);
2274 } else {
2275 b2 = stack->popBool();
2276 b1 = stack->popBool();
2277 stack->pushReal(b1 && b2);
2278 }
2279 break;
2280 case psOpAtan:
2281 r2 = stack->popNum();
2282 r1 = stack->popNum();
2283 stack->pushReal(atan2(r1, r2));
2284 break;
2285 case psOpBitshift:
2286 i2 = stack->popInt();
2287 i1 = stack->popInt();
2288 if (i2 > 0) {
2289 stack->pushInt(i1 << i2);
2290 } else if (i2 < 0) {
2291 stack->pushInt((int)((Guint)i1 >> i2));
2292 } else {
2293 stack->pushInt(i1);
2294 }
2295 break;
2296 case psOpCeiling:
2297 if (!stack->topIsInt()) {
2298 stack->pushReal(ceil(stack->popNum()));
2299 }
2300 break;
2301 case psOpCopy:
2302 stack->copy(stack->popInt());
2303 break;
2304 case psOpCos:
2305 stack->pushReal(cos(stack->popNum()));
2306 break;
2307 case psOpCvi:
2308 if (!stack->topIsInt()) {
2309 stack->pushInt((int)stack->popNum());
2310 }
2311 break;
2312 case psOpCvr:
2313 if (!stack->topIsReal()) {
2314 stack->pushReal(stack->popNum());
2315 }
2316 break;
2317 case psOpDiv:
2318 r2 = stack->popNum();
2319 r1 = stack->popNum();
2320 stack->pushReal(r1 / r2);
2321 break;
2322 case psOpDup:
2323 stack->copy(1);
2324 break;
2325 case psOpEq:
2326 if (stack->topTwoAreInts()) {
2327 i2 = stack->popInt();
2328 i1 = stack->popInt();
2329 stack->pushBool(i1 == i2);
2330 } else if (stack->topTwoAreNums()) {
2331 r2 = stack->popNum();
2332 r1 = stack->popNum();
2333 stack->pushBool(r1 == r2);
2334 } else {
2335 b2 = stack->popBool();
2336 b1 = stack->popBool();
2337 stack->pushBool(b1 == b2);
2338 }
2339 break;
2340 case psOpExch:
2341 stack->roll(2, 1);
2342 break;
2343 case psOpExp:
2344 r2 = stack->popInt();
2345 r1 = stack->popInt();
2346 stack->pushReal(pow(r1, r2));
2347 break;
2348 case psOpFalse:
2349 stack->pushBool(gFalse);
2350 break;
2351 case psOpFloor:
2352 if (!stack->topIsInt()) {
2353 stack->pushReal(floor(stack->popNum()));
2354 }
2355 break;
2356 case psOpGe:
2357 if (stack->topTwoAreInts()) {
2358 i2 = stack->popInt();
2359 i1 = stack->popInt();
2360 stack->pushBool(i1 >= i2);
2361 } else {
2362 r2 = stack->popNum();
2363 r1 = stack->popNum();
2364 stack->pushBool(r1 >= r2);
2365 }
2366 break;
2367 case psOpGt:
2368 if (stack->topTwoAreInts()) {
2369 i2 = stack->popInt();
2370 i1 = stack->popInt();
2371 stack->pushBool(i1 > i2);
2372 } else {
2373 r2 = stack->popNum();
2374 r1 = stack->popNum();
2375 stack->pushBool(r1 > r2);
2376 }
2377 break;
2378 case psOpIdiv:
2379 i2 = stack->popInt();
2380 i1 = stack->popInt();
2381 stack->pushInt(i1 / i2);
2382 break;
2383 case psOpIndex:
2384 stack->index(stack->popInt());
2385 break;
2386 case psOpLe:
2387 if (stack->topTwoAreInts()) {
2388 i2 = stack->popInt();
2389 i1 = stack->popInt();
2390 stack->pushBool(i1 <= i2);
2391 } else {
2392 r2 = stack->popNum();
2393 r1 = stack->popNum();
2394 stack->pushBool(r1 <= r2);
2395 }
2396 break;
2397 case psOpLn:
2398 stack->pushReal(log(stack->popNum()));
2399 break;
2400 case psOpLog:
2401 stack->pushReal(log10(stack->popNum()));
2402 break;
2403 case psOpLt:
2404 if (stack->topTwoAreInts()) {
2405 i2 = stack->popInt();
2406 i1 = stack->popInt();
2407 stack->pushBool(i1 < i2);
2408 } else {
2409 r2 = stack->popNum();
2410 r1 = stack->popNum();
2411 stack->pushBool(r1 < r2);
2412 }
2413 break;
2414 case psOpMod:
2415 i2 = stack->popInt();
2416 i1 = stack->popInt();
2417 stack->pushInt(i1 % i2);
2418 break;
2419 case psOpMul:
2420 if (stack->topTwoAreInts()) {
2421 i2 = stack->popInt();
2422 i1 = stack->popInt();
2423 //~ should check for out-of-range, and push a real instead
2424 stack->pushInt(i1 * i2);
2425 } else {
2426 r2 = stack->popNum();
2427 r1 = stack->popNum();
2428 stack->pushReal(r1 * r2);
2429 }
2430 break;
2431 case psOpNe:
2432 if (stack->topTwoAreInts()) {
2433 i2 = stack->popInt();
2434 i1 = stack->popInt();
2435 stack->pushBool(i1 != i2);
2436 } else if (stack->topTwoAreNums()) {
2437 r2 = stack->popNum();
2438 r1 = stack->popNum();
2439 stack->pushBool(r1 != r2);
2440 } else {
2441 b2 = stack->popBool();
2442 b1 = stack->popBool();
2443 stack->pushBool(b1 != b2);
2444 }
2445 break;
2446 case psOpNeg:
2447 if (stack->topIsInt()) {
2448 stack->pushInt(-stack->popInt());
2449 } else {
2450 stack->pushReal(-stack->popNum());
2451 }
2452 break;
2453 case psOpNot:
2454 if (stack->topIsInt()) {
2455 stack->pushInt(~stack->popInt());
2456 } else {
2457 stack->pushReal(!stack->popBool());
2458 }
2459 break;
2460 case psOpOr:
2461 if (stack->topTwoAreInts()) {
2462 i2 = stack->popInt();
2463 i1 = stack->popInt();
2464 stack->pushInt(i1 | i2);
2465 } else {
2466 b2 = stack->popBool();
2467 b1 = stack->popBool();
2468 stack->pushReal(b1 || b2);
2469 }
2470 break;
2471 case psOpPop:
2472 stack->pop();
2473 break;
2474 case psOpRoll:
2475 i2 = stack->popInt();
2476 i1 = stack->popInt();
2477 stack->roll(i1, i2);
2478 break;
2479 case psOpRound:
2480 if (!stack->topIsInt()) {
2481 r1 = stack->popNum();
2482 stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
2483 }
2484 break;
2485 case psOpSin:
2486 stack->pushReal(cos(stack->popNum()));
2487 break;
2488 case psOpSqrt:
2489 stack->pushReal(sqrt(stack->popNum()));
2490 break;
2491 case psOpSub:
2492 if (stack->topTwoAreInts()) {
2493 i2 = stack->popInt();
2494 i1 = stack->popInt();
2495 stack->pushInt(i1 - i2);
2496 } else {
2497 r2 = stack->popNum();
2498 r1 = stack->popNum();
2499 stack->pushReal(r1 - r2);
2500 }
2501 break;
2502 case psOpTrue:
2503 stack->pushBool(gTrue);
2504 break;
2505 case psOpTruncate:
2506 if (!stack->topIsInt()) {
2507 r1 = stack->popNum();
2508 stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
2509 }
2510 break;
2511 case psOpXor:
2512 if (stack->topTwoAreInts()) {
2513 i2 = stack->popInt();
2514 i1 = stack->popInt();
2515 stack->pushInt(i1 ^ i2);
2516 } else {
2517 b2 = stack->popBool();
2518 b1 = stack->popBool();
2519 stack->pushReal(b1 ^ b2);
2520 }
2521 break;
2522 case psOpIf:
2523 b1 = stack->popBool();
2524 if (b1) {
2525 exec(stack, codePtr + 2);
2526 }
2527 codePtr = code[codePtr + 1].blk;
2528 break;
2529 case psOpIfelse:
2530 b1 = stack->popBool();
2531 if (b1) {
2532 exec(stack, codePtr + 2);
2533 } else {
2534 exec(stack, code[codePtr].blk);
2535 }
2536 codePtr = code[codePtr + 1].blk;
2537 break;
2538 case psOpReturn:
2539 return;
2540 }
2541 break;
2542 default:
2543 error(-1, "Internal: bad object in PostScript function code");
2544 break;
2545 }
2546 }
2547 }
2548 //------------------------------------------------------------------------
2549 // GfxImageColorMap
2550 //------------------------------------------------------------------------
2551
2552 GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
2553 GfxColorSpace *colorSpace) {
2554 GfxIndexedColorSpace *indexedCS;
2555 GfxSeparationColorSpace *sepCS;
2556 int maxPixel, indexHigh;
2557 Guchar *lookup2;
2558 Function *sepFunc;
2559 Object obj;
2560 double x;
2561 double y[gfxColorMaxComps];
2562 int i, j, k;
2563
2564 ok = gTrue;
2565
2566 // bits per component and color space
2567 this->bits = bits;
2568 maxPixel = (1 << bits) - 1;
2569 this->colorSpace = colorSpace;
2570
2571 // get decode map
2572 if (decode->isNull()) {
2573 nComps = colorSpace->getNComps();
2574 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
2575 } else if (decode->isArray()) {
2576 nComps = decode->arrayGetLength() / 2;
2577 if (nComps != colorSpace->getNComps()) {
2578 goto err1;
2579 }
2580 for (i = 0; i < nComps; ++i) {
2581 decode->arrayGet(2*i, &obj);
2582 if (!obj.isNum()) {
2583 goto err2;
2584 }
2585 decodeLow[i] = obj.getNum();
2586 obj.free();
2587 decode->arrayGet(2*i+1, &obj);
2588 if (!obj.isNum()) {
2589 goto err2;
2590 }
2591 decodeRange[i] = obj.getNum() - decodeLow[i];
2592 obj.free();
2593 }
2594 } else {
2595 goto err1;
2596 }
2597
2598 #if 0 //~
2599 // handle the case where fewer than 2^n palette entries of an n-bit
2600 // indexed color space are populated (this happens, e.g., in files
2601 // optimized by Distiller)
2602 if (colorSpace->getMode() == csIndexed) {
2603 i = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
2604 if (i < maxPixel) {
2605 maxPixel = i;
2606 }
2607 }
2608 #endif
2609
2610 // Construct a lookup table -- this stores pre-computed decoded
2611 // values for each component, i.e., the result of applying the
2612 // decode mapping to each possible image pixel component value.
2613 //
2614 // Optimization: for Indexed and Separation color spaces (which have
2615 // only one component), we store color values in the lookup table
2616 // rather than component values.
2617 colorSpace2 = NULL;
2618 nComps2 = 0;
2619 if (colorSpace->getMode() == csIndexed) {
2620 // Note that indexHigh may not be the same as maxPixel --
2621 // Distiller will remove unused palette entries, resulting in
2622 // indexHigh < maxPixel.
2623 indexedCS = (GfxIndexedColorSpace *)colorSpace;
2624 colorSpace2 = indexedCS->getBase();
2625 indexHigh = indexedCS->getIndexHigh();
2626 nComps2 = colorSpace2->getNComps();
2627 lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
2628 lookup2 = indexedCS->getLookup();
2629 for (i = 0; i <= indexHigh; ++i) {
2630 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
2631 for (k = 0; k < nComps2; ++k) {
2632 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
2633 }
2634 }
2635 } else if (colorSpace->getMode() == csSeparation) {
2636 sepCS = (GfxSeparationColorSpace *)colorSpace;
2637 colorSpace2 = sepCS->getAlt();
2638 nComps2 = colorSpace2->getNComps();
2639 lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
2640 sepFunc = sepCS->getFunc();
2641 for (i = 0; i <= maxPixel; ++i) {
2642 x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
2643 sepFunc->transform(&x, y);
2644 for (k = 0; k < nComps2; ++k) {
2645 lookup[i*nComps2 + k] = y[k];
2646 }
2647 }
2648 } else {
2649 lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
2650 for (i = 0; i <= maxPixel; ++i) {
2651 for (k = 0; k < nComps; ++k) {
2652 lookup[i*nComps + k] = decodeLow[k] +
2653 (i * decodeRange[k]) / maxPixel;
2654 }
2655 }
2656 }
2657
2658 return;
2659
2660 err2:
2661 obj.free();
2662 err1:
2663 ok = gFalse;
2664 }
2665
2666 GfxImageColorMap::~GfxImageColorMap() {
2667 delete colorSpace;
2668 gfree(lookup);
2669 }
2670
2671 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
2672 GfxColor color;
2673 double *p;
2674 int i;
2675
2676 if (colorSpace2) {
2677 p = &lookup[x[0] * nComps2];
2678 for (i = 0; i < nComps2; ++i) {
2679 color.c[i] = *p++;
2680 }
2681 colorSpace2->getGray(&color, gray);
2682 } else {
2683 for (i = 0; i < nComps; ++i) {
2684 color.c[i] = lookup[x[i] * nComps + i];
2685 }
2686 colorSpace->getGray(&color, gray);
2687 }
2688 }
2689
2690 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
2691 GfxColor color;
2692 double *p;
2693 int i;
2694
2695 if (colorSpace2) {
2696 p = &lookup[x[0] * nComps2];
2697 for (i = 0; i < nComps2; ++i) {
2698 color.c[i] = *p++;
2699 }
2700 colorSpace2->getRGB(&color, rgb);
2701 } else {
2702 for (i = 0; i < nComps; ++i) {
2703 color.c[i] = lookup[x[i] * nComps + i];
2704 }
2705 colorSpace->getRGB(&color, rgb);
2706 }
2707 }
2708
2709 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
2710 GfxColor color;
2711 double *p;
2712 int i;
2713
2714 if (colorSpace2) {
2715 p = &lookup[x[0] * nComps2];
2716 for (i = 0; i < nComps2; ++i) {
2717 color.c[i] = *p++;
2718 }
2719 colorSpace2->getCMYK(&color, cmyk);
2720 } else {
2721 for (i = 0; i < nComps; ++i) {
2722 color.c[i] = lookup[x[i] * nComps + i];
2723 }
2724 colorSpace->getCMYK(&color, cmyk);
2725 }
2726 }
2727
2728 //------------------------------------------------------------------------
2729 // GfxSubpath and GfxPath
2730 //------------------------------------------------------------------------
2731
2732 GfxSubpath::GfxSubpath(double x1, double y1) {
2733 size = 16;
2734 x = (double *)gmalloc(size * sizeof(double));
2735 y = (double *)gmalloc(size * sizeof(double));
2736 curve = (GBool *)gmalloc(size * sizeof(GBool));
2737 n = 1;
2738 x[0] = x1;
2739 y[0] = y1;
2740 curve[0] = gFalse;
2741 closed = gFalse;
2742 }
2743
2744 GfxSubpath::~GfxSubpath() {
2745 gfree(x);
2746 gfree(y);
2747 gfree(curve);
2748 }
2749
2750 // Used for copy().
2751 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
2752 size = subpath->size;
2753 n = subpath->n;
2754 x = (double *)gmalloc(size * sizeof(double));
2755 y = (double *)gmalloc(size * sizeof(double));
2756 curve = (GBool *)gmalloc(size * sizeof(GBool));
2757 memcpy(x, subpath->x, n * sizeof(double));
2758 memcpy(y, subpath->y, n * sizeof(double));
2759 memcpy(curve, subpath->curve, n * sizeof(GBool));
2760 closed = subpath->closed;
2761 }
2762
2763 void GfxSubpath::lineTo(double x1, double y1) {
2764 if (n >= size) {
2765 size += 16;
2766 x = (double *)grealloc(x, size * sizeof(double));
2767 y = (double *)grealloc(y, size * sizeof(double));
2768 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2769 }
2770 x[n] = x1;
2771 y[n] = y1;
2772 curve[n] = gFalse;
2773 ++n;
2774 }
2775
2776 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
2777 double x3, double y3) {
2778 if (n+3 > size) {
2779 size += 16;
2780 x = (double *)grealloc(x, size * sizeof(double));
2781 y = (double *)grealloc(y, size * sizeof(double));
2782 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
2783 }
2784 x[n] = x1;
2785 y[n] = y1;
2786 x[n+1] = x2;
2787 y[n+1] = y2;
2788 x[n+2] = x3;
2789 y[n+2] = y3;
2790 curve[n] = curve[n+1] = gTrue;
2791 curve[n+2] = gFalse;
2792 n += 3;
2793 }
2794
2795 void GfxSubpath::close() {
2796 if (x[n-1] != x[0] || y[n-1] != y[0]) {
2797 lineTo(x[0], y[0]);
2798 }
2799 closed = gTrue;
2800 }
2801
2802 GfxPath::GfxPath() {
2803 justMoved = gFalse;
2804 size = 16;
2805 n = 0;
2806 firstX = firstY = 0;
2807 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2808 }
2809
2810 GfxPath::~GfxPath() {
2811 int i;
2812
2813 for (i = 0; i < n; ++i)
2814 delete subpaths[i];
2815 gfree(subpaths);
2816 }
2817
2818 // Used for copy().
2819 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
2820 GfxSubpath **subpaths1, int n1, int size1) {
2821 int i;
2822
2823 justMoved = justMoved1;
2824 firstX = firstX1;
2825 firstY = firstY1;
2826 size = size1;
2827 n = n1;
2828 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
2829 for (i = 0; i < n; ++i)
2830 subpaths[i] = subpaths1[i]->copy();
2831 }
2832
2833 void GfxPath::moveTo(double x, double y) {
2834 justMoved = gTrue;
2835 firstX = x;
2836 firstY = y;
2837 }
2838
2839 void GfxPath::lineTo(double x, double y) {
2840 if (justMoved) {
2841 if (n >= size) {
2842 size += 16;
2843 subpaths = (GfxSubpath **)
2844 grealloc(subpaths, size * sizeof(GfxSubpath *));
2845 }
2846 subpaths[n] = new GfxSubpath(firstX, firstY);
2847 ++n;
2848 justMoved = gFalse;
2849 }
2850 subpaths[n-1]->lineTo(x, y);
2851 }
2852
2853 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
2854 double x3, double y3) {
2855 if (justMoved) {
2856 if (n >= size) {
2857 size += 16;
2858 subpaths = (GfxSubpath **)
2859 grealloc(subpaths, size * sizeof(GfxSubpath *));
2860 }
2861 subpaths[n] = new GfxSubpath(firstX, firstY);
2862 ++n;
2863 justMoved = gFalse;
2864 }
2865 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
2866 }
2867
2868
2869 //------------------------------------------------------------------------
2870 // GfxState
2871 //------------------------------------------------------------------------
2872
2873 GfxState::GfxState(double dpi, double px1a, double py1a,
2874 double px2a, double py2a, int rotate, GBool upsideDown) {
2875 double k;
2876
2877 px1 = px1a;
2878 py1 = py1a;
2879 px2 = px2a;
2880 py2 = py2a;
2881 k = dpi / 72.0;
2882 if (rotate == 90) {
2883 ctm[0] = 0;
2884 ctm[1] = upsideDown ? k : -k;
2885 ctm[2] = k;
2886 ctm[3] = 0;
2887 ctm[4] = -k * py1;
2888 ctm[5] = k * (upsideDown ? -px1 : px2);
2889 pageWidth = k * (py2 - py1);
2890 pageHeight = k * (px2 - px1);
2891 } else if (rotate == 180) {
2892 ctm[0] = -k;
2893 ctm[1] = 0;
2894 ctm[2] = 0;
2895 ctm[3] = upsideDown ? k : -k;
2896 ctm[4] = k * px2;
2897 ctm[5] = k * (upsideDown ? -py1 : py2);
2898 pageWidth = k * (px2 - px1);
2899 pageHeight = k * (py2 - py1);
2900 } else if (rotate == 270) {
2901 ctm[0] = 0;
2902 ctm[1] = upsideDown ? -k : k;
2903 ctm[2] = -k;
2904 ctm[3] = 0;
2905 ctm[4] = k * py2;
2906 ctm[5] = k * (upsideDown ? px2 : -px1);
2907 pageWidth = k * (py2 - py1);
2908 pageHeight = k * (px2 - px1);
2909 } else {
2910 ctm[0] = k;
2911 ctm[1] = 0;
2912 ctm[2] = 0;
2913 ctm[3] = upsideDown ? -k : k;
2914 ctm[4] = -k * px1;
2915 ctm[5] = k * (upsideDown ? py2 : -py1);
2916 pageWidth = k * (px2 - px1);
2917 pageHeight = k * (py2 - py1);
2918 }
2919
2920 fillColorSpace = new GfxDeviceGrayColorSpace();
2921 strokeColorSpace = new GfxDeviceGrayColorSpace();
2922 fillColor.c[0] = 0;
2923 strokeColor.c[0] = 0;
2924 fillPattern = NULL;
2925 strokePattern = NULL;
2926 fillOpacity = 1;
2927 strokeOpacity = 1;
2928
2929 lineWidth = 1;
2930 lineDash = NULL;
2931 lineDashLength = 0;
2932 lineDashStart = 0;
2933 flatness = 0;
2934 lineJoin = 0;
2935 lineCap = 0;
2936 miterLimit = 10;
2937
2938 font = NULL;
2939 fontSize = 0;
2940 textMat[0] = 1; textMat[1] = 0;
2941 textMat[2] = 0; textMat[3] = 1;
2942 textMat[4] = 0; textMat[5] = 0;
2943 charSpace = 0;
2944 wordSpace = 0;
2945 horizScaling = 1;
2946 leading = 0;
2947 rise = 0;
2948 render = 0;
2949
2950 path = new GfxPath();
2951 curX = curY = 0;
2952 lineX = lineY = 0;
2953
2954 saved = NULL;
2955 }
2956
2957 GfxState::~GfxState() {
2958 if (fillColorSpace) {
2959 delete fillColorSpace;
2960 }
2961 if (strokeColorSpace) {
2962 delete strokeColorSpace;
2963 }
2964 if (fillPattern) {
2965 delete fillPattern;
2966 }
2967 if (strokePattern) {
2968 delete strokePattern;
2969 }
2970 gfree(lineDash);
2971 delete path;
2972 if (saved) {
2973 delete saved;
2974 }
2975 }
2976
2977 // Used for copy();
2978 GfxState::GfxState(GfxState *state) {
2979 memcpy(this, state, sizeof(GfxState));
2980 if (fillColorSpace) {
2981 fillColorSpace = state->fillColorSpace->copy();
2982 }
2983 if (strokeColorSpace) {
2984 strokeColorSpace = state->strokeColorSpace->copy();
2985 }
2986 if (fillPattern) {
2987 fillPattern = state->fillPattern->copy();
2988 }
2989 if (strokePattern) {
2990 strokePattern = state->strokePattern->copy();
2991 }
2992 if (lineDashLength > 0) {
2993 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
2994 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
2995 }
2996 path = state->path->copy();
2997 saved = NULL;
2998 }
2999
3000 double GfxState::transformWidth(double w) {
3001 double x, y;
3002
3003 x = ctm[0] + ctm[2];
3004 y = ctm[1] + ctm[3];
3005 return w * sqrt(0.5 * (x * x + y * y));
3006 }
3007
3008 double GfxState::getTransformedFontSize() {
3009 double x1, y1, x2, y2;
3010
3011 x1 = textMat[2] * fontSize;
3012 y1 = textMat[3] * fontSize;
3013 x2 = ctm[0] * x1 + ctm[2] * y1;
3014 y2 = ctm[1] * x1 + ctm[3] * y1;
3015 return sqrt(x2 * x2 + y2 * y2);
3016 }
3017
3018 void GfxState::getFontTransMat(double *m11, double *m12,
3019 double *m21, double *m22) {
3020 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
3021 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
3022 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
3023 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
3024 }
3025
3026 void GfxState::setCTM(double a, double b, double c,
3027 double d, double e, double f) {
3028 ctm[0] = a;
3029 ctm[1] = b;
3030 ctm[2] = c;
3031 ctm[3] = d;
3032 ctm[4] = e;
3033 ctm[5] = f;
3034 }
3035
3036 void GfxState::concatCTM(double a, double b, double c,
3037 double d, double e, double f) {
3038 double a1 = ctm[0];
3039 double b1 = ctm[1];
3040 double c1 = ctm[2];
3041 double d1 = ctm[3];
3042
3043 ctm[0] = a * a1 + b * c1;
3044 ctm[1] = a * b1 + b * d1;
3045 ctm[2] = c * a1 + d * c1;
3046 ctm[3] = c * b1 + d * d1;
3047 ctm[4] = e * a1 + f * c1 + ctm[4];
3048 ctm[5] = e * b1 + f * d1 + ctm[5];
3049 }
3050
3051 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
3052 if (fillColorSpace) {
3053 delete fillColorSpace;
3054 }
3055 fillColorSpace = colorSpace;
3056 }
3057
3058 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
3059 if (strokeColorSpace) {
3060 delete strokeColorSpace;
3061 }
3062 strokeColorSpace = colorSpace;
3063 }
3064
3065 void GfxState::setFillPattern(GfxPattern *pattern) {
3066 if (fillPattern) {
3067 delete fillPattern;
3068 }
3069 fillPattern = pattern;
3070 }
3071
3072 void GfxState::setStrokePattern(GfxPattern *pattern) {
3073 if (strokePattern) {
3074 delete strokePattern;
3075 }
3076 strokePattern = pattern;
3077 }
3078
3079 void GfxState::setLineDash(double *dash, int length, double start) {
3080 if (lineDash)
3081 gfree(lineDash);
3082 lineDash = dash;
3083 lineDashLength = length;
3084 lineDashStart = start;
3085 }
3086
3087 void GfxState::clearPath() {
3088 delete path;
3089 path = new GfxPath();
3090 }
3091
3092 void GfxState::textShift(double tx) {
3093 double dx, dy;
3094
3095 textTransformDelta(tx, 0, &dx, &dy);
3096 curX += dx;
3097 curY += dy;
3098 }
3099
3100 void GfxState::textShift(double tx, double ty) {
3101 double dx, dy;
3102
3103 textTransformDelta(tx, ty, &dx, &dy);
3104 curX += dx;
3105 curY += dy;
3106 }
3107
3108 GfxState *GfxState::save() {
3109 GfxState *newState;
3110
3111 newState = copy();
3112 newState->saved = this;
3113 return newState;
3114 }
3115
3116 GfxState *GfxState::restore() {
3117 GfxState *oldState;
3118
3119 if (saved) {
3120 oldState = saved;
3121 saved = NULL;
3122 delete this;
3123 } else {
3124 oldState = this;
3125 }
3126 return oldState;
3127 }