]>
git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/GfxState.cxx
1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
17 #include <string.h> // for memcpy()
24 //------------------------------------------------------------------------
26 static inline double clip01(double x
) {
27 return (x
< 0) ? 0 : ((x
> 1) ? 1 : x
);
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 GfxColorSpace::GfxColorSpace() {
37 GfxColorSpace::~GfxColorSpace() {
40 GfxColorSpace
*GfxColorSpace::parse(Object
*csObj
) {
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
);
55 error(-1, "Bad color space '%s'", csObj
->getName());
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());
82 error(-1, "Bad color space '%s'", csObj
->getName());
86 error(-1, "Bad color space - expected name or array");
91 void GfxColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
95 for (i
= 0; i
< getNComps(); ++i
) {
101 //------------------------------------------------------------------------
102 // GfxDeviceGrayColorSpace
103 //------------------------------------------------------------------------
105 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
108 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
111 GfxColorSpace
*GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
115 void GfxDeviceGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
116 *gray
= clip01(color
->c
[0]);
119 void GfxDeviceGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
120 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
123 void GfxDeviceGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
124 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
125 cmyk
->k
= clip01(1 - color
->c
[0]);
128 //------------------------------------------------------------------------
129 // GfxCalGrayColorSpace
130 //------------------------------------------------------------------------
132 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX
= whiteY
= whiteZ
= 1;
134 blackX
= blackY
= blackZ
= 0;
138 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
141 GfxColorSpace
*GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace
*cs
;
144 cs
= new GfxCalGrayColorSpace();
155 GfxColorSpace
*GfxCalGrayColorSpace::parse(Array
*arr
) {
156 GfxCalGrayColorSpace
*cs
;
157 Object obj1
, obj2
, obj3
;
160 if (!obj1
.isDict()) {
161 error(-1, "Bad CalGray color space");
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();
171 obj2
.arrayGet(1, &obj3
);
172 cs
->whiteY
= obj3
.getNum();
174 obj2
.arrayGet(2, &obj3
);
175 cs
->whiteZ
= obj3
.getNum();
179 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
180 obj2
.arrayGetLength() == 3) {
181 obj2
.arrayGet(0, &obj3
);
182 cs
->blackX
= obj3
.getNum();
184 obj2
.arrayGet(1, &obj3
);
185 cs
->blackY
= obj3
.getNum();
187 obj2
.arrayGet(2, &obj3
);
188 cs
->blackZ
= obj3
.getNum();
192 if (obj1
.dictLookup("Gamma", &obj2
)->isNum()) {
193 cs
->gamma
= obj2
.getNum();
200 void GfxCalGrayColorSpace::getGray(GfxColor
*color
, double *gray
) {
201 *gray
= clip01(color
->c
[0]);
204 void GfxCalGrayColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
205 rgb
->r
= rgb
->g
= rgb
->b
= clip01(color
->c
[0]);
208 void GfxCalGrayColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
209 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
210 cmyk
->k
= clip01(1 - color
->c
[0]);
213 //------------------------------------------------------------------------
214 // GfxDeviceRGBColorSpace
215 //------------------------------------------------------------------------
217 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
220 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
223 GfxColorSpace
*GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
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]);
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]);
239 void GfxDeviceRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
242 c
= clip01(1 - color
->c
[0]);
243 m
= clip01(1 - color
->c
[1]);
244 y
= clip01(1 - color
->c
[2]);
258 //------------------------------------------------------------------------
259 // GfxCalRGBColorSpace
260 //------------------------------------------------------------------------
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;
271 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
274 GfxColorSpace
*GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace
*cs
;
278 cs
= new GfxCalRGBColorSpace();
288 for (i
= 0; i
< 9; ++i
) {
294 GfxColorSpace
*GfxCalRGBColorSpace::parse(Array
*arr
) {
295 GfxCalRGBColorSpace
*cs
;
296 Object obj1
, obj2
, obj3
;
300 if (!obj1
.isDict()) {
301 error(-1, "Bad CalRGB color space");
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();
311 obj2
.arrayGet(1, &obj3
);
312 cs
->whiteY
= obj3
.getNum();
314 obj2
.arrayGet(2, &obj3
);
315 cs
->whiteZ
= obj3
.getNum();
319 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
320 obj2
.arrayGetLength() == 3) {
321 obj2
.arrayGet(0, &obj3
);
322 cs
->blackX
= obj3
.getNum();
324 obj2
.arrayGet(1, &obj3
);
325 cs
->blackY
= obj3
.getNum();
327 obj2
.arrayGet(2, &obj3
);
328 cs
->blackZ
= obj3
.getNum();
332 if (obj1
.dictLookup("Gamma", &obj2
)->isArray() &&
333 obj2
.arrayGetLength() == 3) {
334 obj2
.arrayGet(0, &obj3
);
335 cs
->gammaR
= obj3
.getNum();
337 obj2
.arrayGet(1, &obj3
);
338 cs
->gammaG
= obj3
.getNum();
340 obj2
.arrayGet(2, &obj3
);
341 cs
->gammaB
= obj3
.getNum();
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();
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]);
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]);
370 void GfxCalRGBColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
373 c
= clip01(1 - color
->c
[0]);
374 m
= clip01(1 - color
->c
[1]);
375 y
= clip01(1 - color
->c
[2]);
389 //------------------------------------------------------------------------
390 // GfxDeviceCMYKColorSpace
391 //------------------------------------------------------------------------
393 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
396 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
399 GfxColorSpace
*GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
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]);
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]));
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]);
423 //------------------------------------------------------------------------
425 //------------------------------------------------------------------------
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 }
435 GfxLabColorSpace::GfxLabColorSpace() {
436 whiteX
= whiteY
= whiteZ
= 1;
437 blackX
= blackY
= blackZ
= 0;
442 GfxLabColorSpace::~GfxLabColorSpace() {
445 GfxColorSpace
*GfxLabColorSpace::copy() {
446 GfxLabColorSpace
*cs
;
448 cs
= new GfxLabColorSpace();
465 GfxColorSpace
*GfxLabColorSpace::parse(Array
*arr
) {
466 GfxLabColorSpace
*cs
;
467 Object obj1
, obj2
, obj3
;
470 if (!obj1
.isDict()) {
471 error(-1, "Bad Lab color space");
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();
481 obj2
.arrayGet(1, &obj3
);
482 cs
->whiteY
= obj3
.getNum();
484 obj2
.arrayGet(2, &obj3
);
485 cs
->whiteZ
= obj3
.getNum();
489 if (obj1
.dictLookup("BlackPoint", &obj2
)->isArray() &&
490 obj2
.arrayGetLength() == 3) {
491 obj2
.arrayGet(0, &obj3
);
492 cs
->blackX
= obj3
.getNum();
494 obj2
.arrayGet(1, &obj3
);
495 cs
->blackY
= obj3
.getNum();
497 obj2
.arrayGet(2, &obj3
);
498 cs
->blackZ
= obj3
.getNum();
502 if (obj1
.dictLookup("Range", &obj2
)->isArray() &&
503 obj2
.arrayGetLength() == 4) {
504 obj2
.arrayGet(0, &obj3
);
505 cs
->aMin
= obj3
.getNum();
507 obj2
.arrayGet(1, &obj3
);
508 cs
->aMax
= obj3
.getNum();
510 obj2
.arrayGet(2, &obj3
);
511 cs
->bMin
= obj3
.getNum();
513 obj2
.arrayGet(3, &obj3
);
514 cs
->bMax
= obj3
.getNum();
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
);
533 void GfxLabColorSpace::getGray(GfxColor
*color
, double *gray
) {
537 *gray
= clip01(0.299 * rgb
.r
+
542 void GfxLabColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
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)) {
553 X
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
556 if (t1
>= (6.0 / 29.0)) {
559 Y
= (108.0 / 841.0) * (t1
- (4.0 / 29.0));
562 t2
= t1
- color
->c
[2] / 200;
563 if (t2
>= (6.0 / 29.0)) {
566 Z
= (108.0 / 841.0) * (t2
- (4.0 / 29.0));
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);
579 void GfxLabColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
584 c
= clip01(1 - rgb
.r
);
585 m
= clip01(1 - rgb
.g
);
586 y
= clip01(1 - rgb
.b
);
600 void GfxLabColorSpace::getDefaultRanges(double *decodeLow
, double *decodeRange
,
603 decodeRange
[0] = 100;
605 decodeRange
[1] = aMax
- aMin
;
607 decodeRange
[2] = bMax
- bMin
;
610 //------------------------------------------------------------------------
611 // GfxICCBasedColorSpace
612 //------------------------------------------------------------------------
614 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps
, GfxColorSpace
*alt
,
615 Ref
*iccProfileStream
) {
616 this->nComps
= nComps
;
618 this->iccProfileStream
= *iccProfileStream
;
619 rangeMin
[0] = rangeMin
[1] = rangeMin
[2] = rangeMin
[3] = 0;
620 rangeMax
[0] = rangeMax
[1] = rangeMax
[2] = rangeMax
[3] = 1;
623 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
627 GfxColorSpace
*GfxICCBasedColorSpace::copy() {
628 GfxICCBasedColorSpace
*cs
;
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
];
639 GfxColorSpace
*GfxICCBasedColorSpace::parse(Array
*arr
) {
640 GfxICCBasedColorSpace
*cs
;
641 Ref iccProfileStream
;
645 Object obj1
, obj2
, obj3
;
648 arr
->getNF(1, &obj1
);
650 iccProfileStream
= obj1
.getRef();
652 iccProfileStream
.num
= 0;
653 iccProfileStream
.gen
= 0;
657 if (!obj1
.isStream()) {
658 error(-1, "Bad ICCBased color space (stream)");
662 dict
= obj1
.streamGetDict();
663 if (!dict
->lookup("N", &obj2
)->isInt()) {
664 error(-1, "Bad ICCBased color space (N)");
669 nComps
= obj2
.getInt();
671 if (dict
->lookup("Alternate", &obj2
)->isNull() ||
672 !(alt
= GfxColorSpace::parse(&obj2
))) {
675 alt
= new GfxDeviceGrayColorSpace();
678 alt
= new GfxDeviceRGBColorSpace();
681 alt
= new GfxDeviceCMYKColorSpace();
684 error(-1, "Bad ICCBased color space - invalid N");
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();
698 obj2
.arrayGet(2*i
+1, &obj3
);
699 cs
->rangeMax
[i
] = obj3
.getNum();
708 void GfxICCBasedColorSpace::getGray(GfxColor
*color
, double *gray
) {
709 alt
->getGray(color
, gray
);
712 void GfxICCBasedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
713 alt
->getRGB(color
, rgb
);
716 void GfxICCBasedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
717 alt
->getCMYK(color
, cmyk
);
720 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow
,
725 for (i
= 0; i
< nComps
; ++i
) {
726 decodeLow
[i
] = rangeMin
[i
];
727 decodeRange
[i
] = rangeMax
[i
] - rangeMin
[i
];
731 //------------------------------------------------------------------------
732 // GfxIndexedColorSpace
733 //------------------------------------------------------------------------
735 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace
*base
,
738 this->indexHigh
= indexHigh
;
739 this->lookup
= (Guchar
*)gmalloc((indexHigh
+ 1) * base
->getNComps() *
743 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
748 GfxColorSpace
*GfxIndexedColorSpace::copy() {
749 GfxIndexedColorSpace
*cs
;
751 cs
= new GfxIndexedColorSpace(base
->copy(), indexHigh
);
752 memcpy(cs
->lookup
, lookup
,
753 (indexHigh
+ 1) * base
->getNComps() * sizeof(Guchar
));
757 GfxColorSpace
*GfxIndexedColorSpace::parse(Array
*arr
) {
758 GfxIndexedColorSpace
*cs
;
766 if (arr
->getLength() != 4) {
767 error(-1, "Bad Indexed color space");
771 if (!(base
= GfxColorSpace::parse(&obj1
))) {
772 error(-1, "Bad Indexed color space (base color space)");
776 if (!arr
->get(2, &obj1
)->isInt()) {
777 error(-1, "Bad Indexed color space (hival)");
780 indexHigh
= obj1
.getInt();
782 cs
= new GfxIndexedColorSpace(base
, indexHigh
);
784 n
= base
->getNComps();
785 if (obj1
.isStream()) {
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)");
793 cs
->lookup
[i
*n
+ j
] = (Guchar
)x
;
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)");
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
++;
809 error(-1, "Bad Indexed color space (lookup table)");
823 void GfxIndexedColorSpace::getGray(GfxColor
*color
, double *gray
) {
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;
833 base
->getGray(&color2
, gray
);
836 void GfxIndexedColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
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;
846 base
->getRGB(&color2
, rgb
);
849 void GfxIndexedColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
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;
859 base
->getCMYK(&color2
, cmyk
);
862 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow
,
866 decodeRange
[0] = maxImgPixel
;
869 //------------------------------------------------------------------------
870 // GfxSeparationColorSpace
871 //------------------------------------------------------------------------
873 GfxSeparationColorSpace::GfxSeparationColorSpace(GString
*name
,
881 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
887 GfxColorSpace
*GfxSeparationColorSpace::copy() {
888 return new GfxSeparationColorSpace(name
->copy(), alt
->copy(), func
->copy());
891 //~ handle the 'All' and 'None' colorants
892 GfxColorSpace
*GfxSeparationColorSpace::parse(Array
*arr
) {
893 GfxSeparationColorSpace
*cs
;
899 if (arr
->getLength() != 4) {
900 error(-1, "Bad Separation color space");
903 if (!arr
->get(1, &obj1
)->isName()) {
904 error(-1, "Bad Separation color space (name)");
907 name
= new GString(obj1
.getName());
910 if (!(alt
= GfxColorSpace::parse(&obj1
))) {
911 error(-1, "Bad Separation color space (alternate color space)");
915 func
= Function::parse(arr
->get(3, &obj1
));
920 cs
= new GfxSeparationColorSpace(name
, alt
, func
);
934 void GfxSeparationColorSpace::getGray(GfxColor
*color
, double *gray
) {
937 func
->transform(color
->c
, color2
.c
);
938 alt
->getGray(&color2
, gray
);
941 void GfxSeparationColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
944 func
->transform(color
->c
, color2
.c
);
945 alt
->getRGB(&color2
, rgb
);
948 void GfxSeparationColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
951 func
->transform(color
->c
, color2
.c
);
952 alt
->getCMYK(&color2
, cmyk
);
955 //------------------------------------------------------------------------
956 // GfxDeviceNColorSpace
957 //------------------------------------------------------------------------
959 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps
,
962 this->nComps
= nComps
;
967 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
970 for (i
= 0; i
< nComps
; ++i
) {
977 GfxColorSpace
*GfxDeviceNColorSpace::copy() {
978 GfxDeviceNColorSpace
*cs
;
981 cs
= new GfxDeviceNColorSpace(nComps
, alt
->copy(), func
->copy());
982 for (i
= 0; i
< nComps
; ++i
) {
983 cs
->names
[i
] = names
[i
]->copy();
988 //~ handle the 'None' colorant
989 GfxColorSpace
*GfxDeviceNColorSpace::parse(Array
*arr
) {
990 GfxDeviceNColorSpace
*cs
;
992 GString
*names
[gfxColorMaxComps
];
998 if (arr
->getLength() != 4 && arr
->getLength() != 5) {
999 error(-1, "Bad DeviceN color space");
1002 if (!arr
->get(1, &obj1
)->isArray()) {
1003 error(-1, "Bad DeviceN color space (names)");
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)");
1013 names
[i
] = new GString(obj2
.getName());
1018 if (!(alt
= GfxColorSpace::parse(&obj1
))) {
1019 error(-1, "Bad DeviceN color space (alternate color space)");
1023 func
= Function::parse(arr
->get(3, &obj1
));
1025 if (!func
->isOk()) {
1028 cs
= new GfxDeviceNColorSpace(nComps
, alt
, func
);
1029 for (i
= 0; i
< nComps
; ++i
) {
1030 cs
->names
[i
] = names
[i
];
1038 for (i
= 0; i
< nComps
; ++i
) {
1047 void GfxDeviceNColorSpace::getGray(GfxColor
*color
, double *gray
) {
1050 func
->transform(color
->c
, color2
.c
);
1051 alt
->getGray(&color2
, gray
);
1054 void GfxDeviceNColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1057 func
->transform(color
->c
, color2
.c
);
1058 alt
->getRGB(&color2
, rgb
);
1061 void GfxDeviceNColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1064 func
->transform(color
->c
, color2
.c
);
1065 alt
->getCMYK(&color2
, cmyk
);
1068 //------------------------------------------------------------------------
1069 // GfxPatternColorSpace
1070 //------------------------------------------------------------------------
1072 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace
*under
) {
1073 this->under
= under
;
1076 GfxPatternColorSpace::~GfxPatternColorSpace() {
1082 GfxColorSpace
*GfxPatternColorSpace::copy() {
1083 return new GfxPatternColorSpace(under
? under
->copy() :
1084 (GfxColorSpace
*)NULL
);
1087 GfxColorSpace
*GfxPatternColorSpace::parse(Array
*arr
) {
1088 GfxPatternColorSpace
*cs
;
1089 GfxColorSpace
*under
;
1092 if (arr
->getLength() != 1 && arr
->getLength() != 2) {
1093 error(-1, "Bad Pattern color space");
1097 if (arr
->getLength() == 2) {
1099 if (!(under
= GfxColorSpace::parse(&obj1
))) {
1100 error(-1, "Bad Pattern color space (underlying color space)");
1106 cs
= new GfxPatternColorSpace(under
);
1110 void GfxPatternColorSpace::getGray(GfxColor
*color
, double *gray
) {
1114 void GfxPatternColorSpace::getRGB(GfxColor
*color
, GfxRGB
*rgb
) {
1115 rgb
->r
= rgb
->g
= rgb
->b
= 0;
1118 void GfxPatternColorSpace::getCMYK(GfxColor
*color
, GfxCMYK
*cmyk
) {
1119 cmyk
->c
= cmyk
->m
= cmyk
->y
= 0;
1123 //------------------------------------------------------------------------
1125 //------------------------------------------------------------------------
1127 GfxPattern::GfxPattern(int type
) {
1131 GfxPattern::~GfxPattern() {
1134 GfxPattern
*GfxPattern::parse(Object
*obj
) {
1135 GfxPattern
*pattern
;
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
);
1151 //------------------------------------------------------------------------
1153 //------------------------------------------------------------------------
1155 GfxTilingPattern::GfxTilingPattern(Dict
*streamDict
, Object
*stream
):
1161 if (streamDict
->lookup("PaintType", &obj1
)->isInt()) {
1162 paintType
= obj1
.getInt();
1165 error(-1, "Invalid or missing PaintType in pattern");
1168 if (streamDict
->lookup("TilingType", &obj1
)->isInt()) {
1169 tilingType
= obj1
.getInt();
1172 error(-1, "Invalid or missing TilingType in pattern");
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();
1186 error(-1, "Invalid or missing BBox in pattern");
1189 if (streamDict
->lookup("XStep", &obj1
)->isNum()) {
1190 xStep
= obj1
.getNum();
1193 error(-1, "Invalid or missing XStep in pattern");
1196 if (streamDict
->lookup("YStep", &obj1
)->isNum()) {
1197 yStep
= obj1
.getNum();
1200 error(-1, "Invalid or missing YStep in pattern");
1203 if (!streamDict
->lookup("Resources", &resDict
)->isDict()) {
1206 error(-1, "Invalid or missing Resources in pattern");
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();
1221 stream
->copy(&contentStream
);
1224 GfxTilingPattern::~GfxTilingPattern() {
1226 contentStream
.free();
1229 GfxPattern
*GfxTilingPattern::copy() {
1230 return new GfxTilingPattern(this);
1233 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern
*pat
):
1236 memcpy(this, pat
, sizeof(GfxTilingPattern
));
1237 pat
->resDict
.copy(&resDict
);
1238 pat
->contentStream
.copy(&contentStream
);
1241 //------------------------------------------------------------------------
1243 //------------------------------------------------------------------------
1245 Function::Function() {
1248 Function::~Function() {
1251 Function
*Function::parse(Object
*funcObj
) {
1257 if (funcObj
->isStream()) {
1258 dict
= funcObj
->streamGetDict();
1259 } else if (funcObj
->isDict()) {
1260 dict
= funcObj
->getDict();
1262 error(-1, "Expected function dictionary or stream");
1266 if (!dict
->lookup("FunctionType", &obj1
)->isInt()) {
1267 error(-1, "Function type is missing or wrong type");
1271 funcType
= obj1
.getInt();
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
);
1281 error(-1, "Unimplemented function type");
1284 if (!func
->isOk()) {
1292 GBool
Function::init(Dict
*dict
) {
1297 if (!dict
->lookup("Domain", &obj1
)->isArray()) {
1298 error(-1, "Function is missing domain");
1301 m
= obj1
.arrayGetLength() / 2;
1302 if (m
> funcMaxInputs
) {
1303 error(-1, "Functions with more than %d inputs are unsupported",
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");
1313 domain
[i
][0] = obj2
.getNum();
1315 obj1
.arrayGet(2*i
+1, &obj2
);
1316 if (!obj2
.isNum()) {
1317 error(-1, "Illegal value in function domain array");
1320 domain
[i
][1] = obj2
.getNum();
1328 if (dict
->lookup("Range", &obj1
)->isArray()) {
1330 n
= obj1
.arrayGetLength() / 2;
1331 if (n
> funcMaxOutputs
) {
1332 error(-1, "Functions with more than %d outputs are unsupported",
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");
1342 range
[i
][0] = obj2
.getNum();
1344 obj1
.arrayGet(2*i
+1, &obj2
);
1345 if (!obj2
.isNum()) {
1346 error(-1, "Illegal value in function range array");
1349 range
[i
][1] = obj2
.getNum();
1364 //------------------------------------------------------------------------
1366 //------------------------------------------------------------------------
1368 SampledFunction::SampledFunction(Object
*funcObj
, Dict
*dict
) {
1370 int nSamples
, sampleBits
;
1381 //----- initialize the generic stuff
1386 error(-1, "Type 0 function is missing range");
1390 //----- get the stream
1391 if (!funcObj
->isStream()) {
1392 error(-1, "Type 0 function isn't a stream");
1395 str
= funcObj
->getStream();
1398 if (!dict
->lookup("Size", &obj1
)->isArray() ||
1399 obj1
.arrayGetLength() != m
) {
1400 error(-1, "Function has missing or invalid size array");
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");
1409 sampleSize
[i
] = obj2
.getInt();
1414 //----- BitsPerSample
1415 if (!dict
->lookup("BitsPerSample", &obj1
)->isInt()) {
1416 error(-1, "Function has missing or invalid BitsPerSample");
1419 sampleBits
= obj1
.getInt();
1420 sampleMul
= 1.0 / (double)((1 << sampleBits
) - 1);
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");
1432 encode
[i
][0] = obj2
.getNum();
1434 obj1
.arrayGet(2*i
+1, &obj2
);
1435 if (!obj2
.isNum()) {
1436 error(-1, "Illegal value in function encode array");
1439 encode
[i
][1] = obj2
.getNum();
1443 for (i
= 0; i
< m
; ++i
) {
1445 encode
[i
][1] = sampleSize
[i
] - 1;
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");
1459 decode
[i
][0] = obj2
.getNum();
1461 obj1
.arrayGet(2*i
+1, &obj2
);
1462 if (!obj2
.isNum()) {
1463 error(-1, "Illegal value in function decode array");
1466 decode
[i
][1] = obj2
.getNum();
1470 for (i
= 0; i
< n
; ++i
) {
1471 decode
[i
][0] = range
[i
][0];
1472 decode
[i
][1] = range
[i
][1];
1479 for (i
= 0; i
< m
; ++i
)
1480 nSamples
*= sampleSize
[i
];
1481 samples
= (double *)gmalloc(nSamples
* sizeof(double));
1484 bitMask
= (1 << sampleBits
) - 1;
1486 for (i
= 0; i
< nSamples
; ++i
) {
1487 if (sampleBits
== 8) {
1489 } else if (sampleBits
== 16) {
1491 s
= (s
<< 8) + str
->getChar();
1492 } else if (sampleBits
== 32) {
1494 s
= (s
<< 8) + str
->getChar();
1495 s
= (s
<< 8) + str
->getChar();
1496 s
= (s
<< 8) + str
->getChar();
1498 while (bits
< sampleBits
) {
1499 buf
= (buf
<< 8) | (str
->getChar() & 0xff);
1502 s
= (buf
>> (bits
- sampleBits
)) & bitMask
;
1505 samples
[i
] = (double)s
* sampleMul
;
1520 SampledFunction::~SampledFunction() {
1526 SampledFunction::SampledFunction(SampledFunction
*func
) {
1529 memcpy(this, func
, sizeof(SampledFunction
));
1532 for (i
= 0; i
< m
; ++i
) {
1533 nSamples
*= sampleSize
[i
];
1535 samples
= (double *)gmalloc(nSamples
* sizeof(double));
1536 memcpy(samples
, func
->samples
, nSamples
* sizeof(double));
1539 void SampledFunction::transform(double *in
, double *out
) {
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];
1553 } else if (e
[i
] > sampleSize
[i
] - 1) {
1554 e
[i
] = sampleSize
[i
] - 1;
1558 for (i
= 0; i
< n
; ++i
) {
1560 // m-linear interpolation
1561 // (only m=1 is currently supported)
1562 e0
= (int)floor(e
[0]);
1563 e1
= (int)ceil(e
[0]);
1565 x0
= samples
[e0
* n
+ i
];
1566 x1
= samples
[e1
* n
+ i
];
1567 s
= (1 - efrac
) * x0
+ efrac
* x1
;
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];
1579 //------------------------------------------------------------------------
1580 // ExponentialFunction
1581 //------------------------------------------------------------------------
1583 ExponentialFunction::ExponentialFunction(Object
*funcObj
, Dict
*dict
) {
1591 //----- initialize the generic stuff
1596 error(-1, "Exponential function with more than one input");
1600 //----- default values
1601 for (i
= 0; i
< funcMaxOutputs
; ++i
) {
1607 if (dict
->lookup("C0", &obj1
)->isArray()) {
1609 n
= obj1
.arrayGetLength();
1610 } else if (obj1
.arrayGetLength() != n
) {
1611 error(-1, "Function's C0 array is wrong length");
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");
1620 c0
[i
] = obj2
.getNum();
1627 if (dict
->lookup("C1", &obj1
)->isArray()) {
1629 n
= obj1
.arrayGetLength();
1630 } else if (obj1
.arrayGetLength() != n
) {
1631 error(-1, "Function's C1 array is wrong length");
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");
1640 c1
[i
] = obj2
.getNum();
1646 //----- N (exponent)
1647 if (!dict
->lookup("N", &obj1
)->isNum()) {
1648 error(-1, "Function has missing or invalid N");
1665 ExponentialFunction::~ExponentialFunction() {
1668 ExponentialFunction::ExponentialFunction(ExponentialFunction
*func
) {
1669 memcpy(this, func
, sizeof(ExponentialFunction
));
1672 void ExponentialFunction::transform(double *in
, double *out
) {
1676 if (in
[0] < domain
[0][0]) {
1678 } else if (in
[0] > domain
[0][1]) {
1683 for (i
= 0; i
< n
; ++i
) {
1684 out
[i
] = c0
[i
] + pow(x
, e
) * (c1
[i
] - c0
[i
]);
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];
1696 //------------------------------------------------------------------------
1697 // PostScriptFunction
1698 //------------------------------------------------------------------------
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
[] = {
1792 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
1802 // In the code array, 'if'/'ifelse' operators take up three slots
1803 // plus space for the code in the subclause(s).
1805 // +---------------------------------+
1806 // | psOperator: psOpIf / psOpIfelse |
1807 // +---------------------------------+
1808 // | psBlock: ptr=<A> |
1809 // +---------------------------------+
1810 // | psBlock: ptr=<B> |
1811 // +---------------------------------+
1814 // | psOperator: psOpReturn |
1815 // +---------------------------------+
1816 // <A> | else clause |
1818 // | psOperator: psOpReturn |
1819 // +---------------------------------+
1822 // For 'if', pointer <A> is present in the code stream but unused.
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)
1835 #define psStackSize 100
1840 PSStack() { sp
= psStackSize
; }
1841 void pushBool(GBool booln
);
1842 void pushInt(int intg
);
1843 void pushReal(double real
);
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
); }
1859 void roll(int n
, int j
);
1865 GBool
checkOverflow(int n
= 1);
1866 GBool
checkUnderflow();
1867 GBool
checkType(PSObjectType t1
, PSObjectType t2
);
1869 PSObject stack
[psStackSize
];
1873 GBool
PSStack::checkOverflow(int n
) {
1875 error(-1, "Stack overflow in PostScript function");
1881 GBool
PSStack::checkUnderflow() {
1882 if (sp
== psStackSize
) {
1883 error(-1, "Stack underflow in PostScript function");
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");
1897 void PSStack::pushBool(GBool booln
) {
1898 if (checkOverflow()) {
1899 stack
[--sp
].type
= psBool
;
1900 stack
[sp
].booln
= booln
;
1904 void PSStack::pushInt(int intg
) {
1905 if (checkOverflow()) {
1906 stack
[--sp
].type
= psInt
;
1907 stack
[sp
].intg
= intg
;
1911 void PSStack::pushReal(double real
) {
1912 if (checkOverflow()) {
1913 stack
[--sp
].type
= psReal
;
1914 stack
[sp
].real
= real
;
1918 GBool
PSStack::popBool() {
1919 if (checkUnderflow() && checkType(psBool
, psBool
)) {
1920 return stack
[sp
++].booln
;
1925 int PSStack::popInt() {
1926 if (checkUnderflow() && checkType(psInt
, psInt
)) {
1927 return stack
[sp
++].intg
;
1932 double PSStack::popNum() {
1935 if (checkUnderflow() && checkType(psInt
, psReal
)) {
1936 ret
= (stack
[sp
].type
== psInt
) ? (double)stack
[sp
].intg
: stack
[sp
].real
;
1943 void PSStack::copy(int n
) {
1946 if (!checkOverflow(n
)) {
1949 for (i
= sp
+ n
- 1; i
<= sp
; ++i
) {
1950 stack
[i
- n
] = stack
[i
];
1955 void PSStack::roll(int n
, int j
) {
1967 if (n
<= 0 || j
== 0) {
1970 for (i
= 0; i
< j
; ++i
) {
1972 for (k
= sp
; k
< sp
+ n
- 1; ++k
) {
1973 stack
[k
] = stack
[k
+1];
1975 stack
[sp
+ n
- 1] = obj
;
1979 void PSStack::index(int i
) {
1980 if (!checkOverflow()) {
1984 stack
[sp
] = stack
[sp
+ 1 + i
];
1987 void PSStack::pop() {
1988 if (!checkUnderflow()) {
1994 PostScriptFunction::PostScriptFunction(Object
*funcObj
, Dict
*dict
) {
2003 //----- initialize the generic stuff
2008 error(-1, "Type 4 function is missing range");
2012 //----- get the stream
2013 if (!funcObj
->isStream()) {
2014 error(-1, "Type 4 function isn't a stream");
2017 str
= funcObj
->getStream();
2019 //----- parse the function
2021 if (!(tok
= getToken(str
)) || tok
->cmp("{")) {
2022 error(-1, "Expected '{' at start of PostScript function");
2030 if (!parseCode(str
, &codePtr
)) {
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
));
2049 PostScriptFunction::~PostScriptFunction() {
2053 void PostScriptFunction::transform(double *in
, double *out
) {
2057 stack
= new PSStack();
2058 for (i
= 0; i
< m
; ++i
) {
2059 //~ may need to check for integers here
2060 stack
->pushReal(in
[i
]);
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];
2071 // if (!stack->empty()) {
2072 // error(-1, "Extra values on stack at end of PostScript function");
2077 GBool
PostScriptFunction::parseCode(Stream
*str
, int *codePtr
) {
2085 if (!(tok
= getToken(str
))) {
2086 error(-1, "Unexpected end of PostScript function stream");
2089 p
= tok
->getCString();
2090 if (isdigit(*p
) || *p
== '.' || *p
== '-') {
2092 for (++p
; *p
; ++p
) {
2098 resizeCode(*codePtr
);
2100 code
[*codePtr
].type
= psReal
;
2101 code
[*codePtr
].real
= atof(tok
->getCString());
2103 code
[*codePtr
].type
= psInt
;
2104 code
[*codePtr
].intg
= atoi(tok
->getCString());
2108 } else if (!tok
->cmp("{")) {
2112 resizeCode(opPtr
+ 2);
2113 if (!parseCode(str
, codePtr
)) {
2116 if (!(tok
= getToken(str
))) {
2117 error(-1, "Unexpected end of PostScript function stream");
2120 if (!tok
->cmp("{")) {
2122 if (!parseCode(str
, codePtr
)) {
2129 if (!(tok
= getToken(str
))) {
2130 error(-1, "Unexpected end of PostScript function stream");
2133 if (!tok
->cmp("if")) {
2135 error(-1, "Got 'if' operator with two blocks in PostScript function");
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")) {
2144 error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
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
;
2154 error(-1, "Expected if/ifelse operator in PostScript function");
2159 } else if (!tok
->cmp("}")) {
2161 resizeCode(*codePtr
);
2162 code
[*codePtr
].type
= psOperator
;
2163 code
[*codePtr
].op
= psOpReturn
;
2169 // invariant: psOpNames[a] < tok < psOpNames[b]
2172 cmp
= tok
->cmp(psOpNames
[m
]);
2175 } else if (cmp
< 0) {
2182 error(-1, "Unknown operator '%s' in PostScript function",
2188 resizeCode(*codePtr
);
2189 code
[*codePtr
].type
= psOperator
;
2190 code
[*codePtr
].op
= (PSOp
)a
;
2197 GString
*PostScriptFunction::getToken(Stream
*str
) {
2204 } while (c
!= EOF
&& isspace(c
));
2205 if (c
== '{' || c
== '}') {
2207 } else if (isdigit(c
) || c
== '.' || c
== '-') {
2210 c
= str
->lookChar();
2211 if (c
== EOF
|| !(isdigit(c
) || c
== '.' || c
== '-')) {
2219 c
= str
->lookChar();
2220 if (c
== EOF
|| !isalnum(c
)) {
2229 void PostScriptFunction::resizeCode(int newSize
) {
2230 if (newSize
>= codeSize
) {
2232 code
= (PSObject
*)grealloc(code
, codeSize
* sizeof(PSObject
));
2236 void PostScriptFunction::exec(PSStack
*stack
, int codePtr
) {
2242 switch (code
[codePtr
].type
) {
2244 stack
->pushInt(code
[codePtr
++].intg
);
2247 stack
->pushReal(code
[codePtr
++].real
);
2250 switch (code
[codePtr
++].op
) {
2252 if (stack
->topIsInt()) {
2253 stack
->pushInt(abs(stack
->popInt()));
2255 stack
->pushReal(fabs(stack
->popNum()));
2259 if (stack
->topTwoAreInts()) {
2260 i2
= stack
->popInt();
2261 i1
= stack
->popInt();
2262 stack
->pushInt(i1
+ i2
);
2264 r2
= stack
->popNum();
2265 r1
= stack
->popNum();
2266 stack
->pushReal(r1
+ r2
);
2270 if (stack
->topTwoAreInts()) {
2271 i2
= stack
->popInt();
2272 i1
= stack
->popInt();
2273 stack
->pushInt(i1
& i2
);
2275 b2
= stack
->popBool();
2276 b1
= stack
->popBool();
2277 stack
->pushReal(b1
&& b2
);
2281 r2
= stack
->popNum();
2282 r1
= stack
->popNum();
2283 stack
->pushReal(atan2(r1
, r2
));
2286 i2
= stack
->popInt();
2287 i1
= stack
->popInt();
2289 stack
->pushInt(i1
<< i2
);
2290 } else if (i2
< 0) {
2291 stack
->pushInt((int)((Guint
)i1
>> i2
));
2297 if (!stack
->topIsInt()) {
2298 stack
->pushReal(ceil(stack
->popNum()));
2302 stack
->copy(stack
->popInt());
2305 stack
->pushReal(cos(stack
->popNum()));
2308 if (!stack
->topIsInt()) {
2309 stack
->pushInt((int)stack
->popNum());
2313 if (!stack
->topIsReal()) {
2314 stack
->pushReal(stack
->popNum());
2318 r2
= stack
->popNum();
2319 r1
= stack
->popNum();
2320 stack
->pushReal(r1
/ r2
);
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
);
2335 b2
= stack
->popBool();
2336 b1
= stack
->popBool();
2337 stack
->pushBool(b1
== b2
);
2344 r2
= stack
->popInt();
2345 r1
= stack
->popInt();
2346 stack
->pushReal(pow(r1
, r2
));
2349 stack
->pushBool(gFalse
);
2352 if (!stack
->topIsInt()) {
2353 stack
->pushReal(floor(stack
->popNum()));
2357 if (stack
->topTwoAreInts()) {
2358 i2
= stack
->popInt();
2359 i1
= stack
->popInt();
2360 stack
->pushBool(i1
>= i2
);
2362 r2
= stack
->popNum();
2363 r1
= stack
->popNum();
2364 stack
->pushBool(r1
>= r2
);
2368 if (stack
->topTwoAreInts()) {
2369 i2
= stack
->popInt();
2370 i1
= stack
->popInt();
2371 stack
->pushBool(i1
> i2
);
2373 r2
= stack
->popNum();
2374 r1
= stack
->popNum();
2375 stack
->pushBool(r1
> r2
);
2379 i2
= stack
->popInt();
2380 i1
= stack
->popInt();
2381 stack
->pushInt(i1
/ i2
);
2384 stack
->index(stack
->popInt());
2387 if (stack
->topTwoAreInts()) {
2388 i2
= stack
->popInt();
2389 i1
= stack
->popInt();
2390 stack
->pushBool(i1
<= i2
);
2392 r2
= stack
->popNum();
2393 r1
= stack
->popNum();
2394 stack
->pushBool(r1
<= r2
);
2398 stack
->pushReal(log(stack
->popNum()));
2401 stack
->pushReal(log10(stack
->popNum()));
2404 if (stack
->topTwoAreInts()) {
2405 i2
= stack
->popInt();
2406 i1
= stack
->popInt();
2407 stack
->pushBool(i1
< i2
);
2409 r2
= stack
->popNum();
2410 r1
= stack
->popNum();
2411 stack
->pushBool(r1
< r2
);
2415 i2
= stack
->popInt();
2416 i1
= stack
->popInt();
2417 stack
->pushInt(i1
% i2
);
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
);
2426 r2
= stack
->popNum();
2427 r1
= stack
->popNum();
2428 stack
->pushReal(r1
* r2
);
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
);
2441 b2
= stack
->popBool();
2442 b1
= stack
->popBool();
2443 stack
->pushBool(b1
!= b2
);
2447 if (stack
->topIsInt()) {
2448 stack
->pushInt(-stack
->popInt());
2450 stack
->pushReal(-stack
->popNum());
2454 if (stack
->topIsInt()) {
2455 stack
->pushInt(~stack
->popInt());
2457 stack
->pushReal(!stack
->popBool());
2461 if (stack
->topTwoAreInts()) {
2462 i2
= stack
->popInt();
2463 i1
= stack
->popInt();
2464 stack
->pushInt(i1
| i2
);
2466 b2
= stack
->popBool();
2467 b1
= stack
->popBool();
2468 stack
->pushReal(b1
|| b2
);
2475 i2
= stack
->popInt();
2476 i1
= stack
->popInt();
2477 stack
->roll(i1
, i2
);
2480 if (!stack
->topIsInt()) {
2481 r1
= stack
->popNum();
2482 stack
->pushReal((r1
>= 0) ? floor(r1
+ 0.5) : ceil(r1
- 0.5));
2486 stack
->pushReal(cos(stack
->popNum()));
2489 stack
->pushReal(sqrt(stack
->popNum()));
2492 if (stack
->topTwoAreInts()) {
2493 i2
= stack
->popInt();
2494 i1
= stack
->popInt();
2495 stack
->pushInt(i1
- i2
);
2497 r2
= stack
->popNum();
2498 r1
= stack
->popNum();
2499 stack
->pushReal(r1
- r2
);
2503 stack
->pushBool(gTrue
);
2506 if (!stack
->topIsInt()) {
2507 r1
= stack
->popNum();
2508 stack
->pushReal((r1
>= 0) ? floor(r1
) : ceil(r1
));
2512 if (stack
->topTwoAreInts()) {
2513 i2
= stack
->popInt();
2514 i1
= stack
->popInt();
2515 stack
->pushInt(i1
^ i2
);
2517 b2
= stack
->popBool();
2518 b1
= stack
->popBool();
2519 stack
->pushReal(b1
^ b2
);
2523 b1
= stack
->popBool();
2525 exec(stack
, codePtr
+ 2);
2527 codePtr
= code
[codePtr
+ 1].blk
;
2530 b1
= stack
->popBool();
2532 exec(stack
, codePtr
+ 2);
2534 exec(stack
, code
[codePtr
].blk
);
2536 codePtr
= code
[codePtr
+ 1].blk
;
2543 error(-1, "Internal: bad object in PostScript function code");
2548 //------------------------------------------------------------------------
2550 //------------------------------------------------------------------------
2552 GfxImageColorMap::GfxImageColorMap(int bits
, Object
*decode
,
2553 GfxColorSpace
*colorSpace
) {
2554 GfxIndexedColorSpace
*indexedCS
;
2555 GfxSeparationColorSpace
*sepCS
;
2556 int maxPixel
, indexHigh
;
2561 double y
[gfxColorMaxComps
];
2566 // bits per component and color space
2568 maxPixel
= (1 << bits
) - 1;
2569 this->colorSpace
= colorSpace
;
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()) {
2580 for (i
= 0; i
< nComps
; ++i
) {
2581 decode
->arrayGet(2*i
, &obj
);
2585 decodeLow
[i
] = obj
.getNum();
2587 decode
->arrayGet(2*i
+1, &obj
);
2591 decodeRange
[i
] = obj
.getNum() - decodeLow
[i
];
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();
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.
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.
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;
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
];
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
;
2666 GfxImageColorMap::~GfxImageColorMap() {
2671 void GfxImageColorMap::getGray(Guchar
*x
, double *gray
) {
2677 p
= &lookup
[x
[0] * nComps2
];
2678 for (i
= 0; i
< nComps2
; ++i
) {
2681 colorSpace2
->getGray(&color
, gray
);
2683 for (i
= 0; i
< nComps
; ++i
) {
2684 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2686 colorSpace
->getGray(&color
, gray
);
2690 void GfxImageColorMap::getRGB(Guchar
*x
, GfxRGB
*rgb
) {
2696 p
= &lookup
[x
[0] * nComps2
];
2697 for (i
= 0; i
< nComps2
; ++i
) {
2700 colorSpace2
->getRGB(&color
, rgb
);
2702 for (i
= 0; i
< nComps
; ++i
) {
2703 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2705 colorSpace
->getRGB(&color
, rgb
);
2709 void GfxImageColorMap::getCMYK(Guchar
*x
, GfxCMYK
*cmyk
) {
2715 p
= &lookup
[x
[0] * nComps2
];
2716 for (i
= 0; i
< nComps2
; ++i
) {
2719 colorSpace2
->getCMYK(&color
, cmyk
);
2721 for (i
= 0; i
< nComps
; ++i
) {
2722 color
.c
[i
] = lookup
[x
[i
] * nComps
+ i
];
2724 colorSpace
->getCMYK(&color
, cmyk
);
2728 //------------------------------------------------------------------------
2729 // GfxSubpath and GfxPath
2730 //------------------------------------------------------------------------
2732 GfxSubpath::GfxSubpath(double x1
, double y1
) {
2734 x
= (double *)gmalloc(size
* sizeof(double));
2735 y
= (double *)gmalloc(size
* sizeof(double));
2736 curve
= (GBool
*)gmalloc(size
* sizeof(GBool
));
2744 GfxSubpath::~GfxSubpath() {
2751 GfxSubpath::GfxSubpath(GfxSubpath
*subpath
) {
2752 size
= subpath
->size
;
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
;
2763 void GfxSubpath::lineTo(double x1
, double y1
) {
2766 x
= (double *)grealloc(x
, size
* sizeof(double));
2767 y
= (double *)grealloc(y
, size
* sizeof(double));
2768 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
2776 void GfxSubpath::curveTo(double x1
, double y1
, double x2
, double y2
,
2777 double x3
, double y3
) {
2780 x
= (double *)grealloc(x
, size
* sizeof(double));
2781 y
= (double *)grealloc(y
, size
* sizeof(double));
2782 curve
= (GBool
*)grealloc(curve
, size
* sizeof(GBool
));
2790 curve
[n
] = curve
[n
+1] = gTrue
;
2791 curve
[n
+2] = gFalse
;
2795 void GfxSubpath::close() {
2796 if (x
[n
-1] != x
[0] || y
[n
-1] != y
[0]) {
2802 GfxPath::GfxPath() {
2806 firstX
= firstY
= 0;
2807 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
2810 GfxPath::~GfxPath() {
2813 for (i
= 0; i
< n
; ++i
)
2819 GfxPath::GfxPath(GBool justMoved1
, double firstX1
, double firstY1
,
2820 GfxSubpath
**subpaths1
, int n1
, int size1
) {
2823 justMoved
= justMoved1
;
2828 subpaths
= (GfxSubpath
**)gmalloc(size
* sizeof(GfxSubpath
*));
2829 for (i
= 0; i
< n
; ++i
)
2830 subpaths
[i
] = subpaths1
[i
]->copy();
2833 void GfxPath::moveTo(double x
, double y
) {
2839 void GfxPath::lineTo(double x
, double y
) {
2843 subpaths
= (GfxSubpath
**)
2844 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2846 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
2850 subpaths
[n
-1]->lineTo(x
, y
);
2853 void GfxPath::curveTo(double x1
, double y1
, double x2
, double y2
,
2854 double x3
, double y3
) {
2858 subpaths
= (GfxSubpath
**)
2859 grealloc(subpaths
, size
* sizeof(GfxSubpath
*));
2861 subpaths
[n
] = new GfxSubpath(firstX
, firstY
);
2865 subpaths
[n
-1]->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
2869 //------------------------------------------------------------------------
2871 //------------------------------------------------------------------------
2873 GfxState::GfxState(double dpi
, double px1a
, double py1a
,
2874 double px2a
, double py2a
, int rotate
, GBool upsideDown
) {
2884 ctm
[1] = upsideDown
? k
: -k
;
2888 ctm
[5] = k
* (upsideDown
? -px1
: px2
);
2889 pageWidth
= k
* (py2
- py1
);
2890 pageHeight
= k
* (px2
- px1
);
2891 } else if (rotate
== 180) {
2895 ctm
[3] = upsideDown
? k
: -k
;
2897 ctm
[5] = k
* (upsideDown
? -py1
: py2
);
2898 pageWidth
= k
* (px2
- px1
);
2899 pageHeight
= k
* (py2
- py1
);
2900 } else if (rotate
== 270) {
2902 ctm
[1] = upsideDown
? -k
: k
;
2906 ctm
[5] = k
* (upsideDown
? px2
: -px1
);
2907 pageWidth
= k
* (py2
- py1
);
2908 pageHeight
= k
* (px2
- px1
);
2913 ctm
[3] = upsideDown
? -k
: k
;
2915 ctm
[5] = k
* (upsideDown
? py2
: -py1
);
2916 pageWidth
= k
* (px2
- px1
);
2917 pageHeight
= k
* (py2
- py1
);
2920 fillColorSpace
= new GfxDeviceGrayColorSpace();
2921 strokeColorSpace
= new GfxDeviceGrayColorSpace();
2923 strokeColor
.c
[0] = 0;
2925 strokePattern
= NULL
;
2940 textMat
[0] = 1; textMat
[1] = 0;
2941 textMat
[2] = 0; textMat
[3] = 1;
2942 textMat
[4] = 0; textMat
[5] = 0;
2950 path
= new GfxPath();
2957 GfxState::~GfxState() {
2958 if (fillColorSpace
) {
2959 delete fillColorSpace
;
2961 if (strokeColorSpace
) {
2962 delete strokeColorSpace
;
2967 if (strokePattern
) {
2968 delete strokePattern
;
2978 GfxState::GfxState(GfxState
*state
) {
2979 memcpy(this, state
, sizeof(GfxState
));
2980 if (fillColorSpace
) {
2981 fillColorSpace
= state
->fillColorSpace
->copy();
2983 if (strokeColorSpace
) {
2984 strokeColorSpace
= state
->strokeColorSpace
->copy();
2987 fillPattern
= state
->fillPattern
->copy();
2989 if (strokePattern
) {
2990 strokePattern
= state
->strokePattern
->copy();
2992 if (lineDashLength
> 0) {
2993 lineDash
= (double *)gmalloc(lineDashLength
* sizeof(double));
2994 memcpy(lineDash
, state
->lineDash
, lineDashLength
* sizeof(double));
2996 path
= state
->path
->copy();
3000 double GfxState::transformWidth(double w
) {
3003 x
= ctm
[0] + ctm
[2];
3004 y
= ctm
[1] + ctm
[3];
3005 return w
* sqrt(0.5 * (x
* x
+ y
* y
));
3008 double GfxState::getTransformedFontSize() {
3009 double x1
, y1
, x2
, y2
;
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
);
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
;
3026 void GfxState::setCTM(double a
, double b
, double c
,
3027 double d
, double e
, double f
) {
3036 void GfxState::concatCTM(double a
, double b
, double c
,
3037 double d
, double e
, double f
) {
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];
3051 void GfxState::setFillColorSpace(GfxColorSpace
*colorSpace
) {
3052 if (fillColorSpace
) {
3053 delete fillColorSpace
;
3055 fillColorSpace
= colorSpace
;
3058 void GfxState::setStrokeColorSpace(GfxColorSpace
*colorSpace
) {
3059 if (strokeColorSpace
) {
3060 delete strokeColorSpace
;
3062 strokeColorSpace
= colorSpace
;
3065 void GfxState::setFillPattern(GfxPattern
*pattern
) {
3069 fillPattern
= pattern
;
3072 void GfxState::setStrokePattern(GfxPattern
*pattern
) {
3073 if (strokePattern
) {
3074 delete strokePattern
;
3076 strokePattern
= pattern
;
3079 void GfxState::setLineDash(double *dash
, int length
, double start
) {
3083 lineDashLength
= length
;
3084 lineDashStart
= start
;
3087 void GfxState::clearPath() {
3089 path
= new GfxPath();
3092 void GfxState::textShift(double tx
) {
3095 textTransformDelta(tx
, 0, &dx
, &dy
);
3100 void GfxState::textShift(double tx
, double ty
) {
3103 textTransformDelta(tx
, ty
, &dx
, &dy
);
3108 GfxState
*GfxState::save() {
3112 newState
->saved
= this;
3116 GfxState
*GfxState::restore() {