Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/GfxState.cc') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/GfxState.cc | 2097 |
1 files changed, 2097 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/GfxState.cc b/noncore/unsupported/qpdf/xpdf/GfxState.cc new file mode 100644 index 0000000..af4e0d4 --- a/dev/null +++ b/noncore/unsupported/qpdf/xpdf/GfxState.cc | |||
@@ -0,0 +1,2097 @@ | |||
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 <aconf.h> | ||
14 | #include <stddef.h> | ||
15 | #include <math.h> | ||
16 | #include <string.h> // for memcpy() | ||
17 | #include "gmem.h" | ||
18 | #include "Error.h" | ||
19 | #include "Object.h" | ||
20 | #include "Array.h" | ||
21 | #include "Page.h" | ||
22 | #include "GfxState.h" | ||
23 | |||
24 | //------------------------------------------------------------------------ | ||
25 | |||
26 | static inline fouble clip01(fouble x) { | ||
27 | return (x < 0) ? fouble(0) : ((x > 1) ? fouble(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(fouble *decodeLow, fouble *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, fouble *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, fouble *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, fouble *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 | fouble 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 | mat[0] = 1; mat[1] = 0; mat[2] = 0; | ||
267 | mat[3] = 0; mat[4] = 1; mat[5] = 0; | ||
268 | mat[6] = 0; mat[7] = 0; mat[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->mat[i] = mat[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->mat[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, fouble *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 | fouble 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, fouble *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 fouble 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, fouble *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 | fouble X, Y, Z; | ||
544 | fouble t1, t2; | ||
545 | fouble 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 | fouble 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(fouble *decodeLow, fouble *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 nCompsA, GfxColorSpace *altA, | ||
615 | Ref *iccProfileStreamA) { | ||
616 | nComps = nCompsA; | ||
617 | alt = altA; | ||
618 | iccProfileStream = *iccProfileStreamA; | ||
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 iccProfileStreamA; | ||
642 | int nCompsA; | ||
643 | GfxColorSpace *altA; | ||
644 | Dict *dict; | ||
645 | Object obj1, obj2, obj3; | ||
646 | int i; | ||
647 | |||
648 | arr->getNF(1, &obj1); | ||
649 | if (obj1.isRef()) { | ||
650 | iccProfileStreamA = obj1.getRef(); | ||
651 | } else { | ||
652 | iccProfileStreamA.num = 0; | ||
653 | iccProfileStreamA.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 | nCompsA = obj2.getInt(); | ||
670 | obj2.free(); | ||
671 | if (dict->lookup("Alternate", &obj2)->isNull() || | ||
672 | !(altA = GfxColorSpace::parse(&obj2))) { | ||
673 | switch (nCompsA) { | ||
674 | case 1: | ||
675 | altA = new GfxDeviceGrayColorSpace(); | ||
676 | break; | ||
677 | case 3: | ||
678 | altA = new GfxDeviceRGBColorSpace(); | ||
679 | break; | ||
680 | case 4: | ||
681 | altA = 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(nCompsA, altA, &iccProfileStreamA); | ||
692 | if (dict->lookup("Range", &obj2)->isArray() && | ||
693 | obj2.arrayGetLength() == 2 * nCompsA) { | ||
694 | for (i = 0; i < nCompsA; ++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, fouble *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(fouble *decodeLow, | ||
721 | fouble *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 *baseA, | ||
736 | int indexHighA) { | ||
737 | base = baseA; | ||
738 | indexHigh = indexHighA; | ||
739 | 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 *baseA; | ||
760 | int indexHighA; | ||
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 (!(baseA = 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 | indexHighA = obj1.getInt(); | ||
781 | obj1.free(); | ||
782 | cs = new GfxIndexedColorSpace(baseA, indexHighA); | ||
783 | arr->get(3, &obj1); | ||
784 | n = baseA->getNComps(); | ||
785 | if (obj1.isStream()) { | ||
786 | obj1.streamReset(); | ||
787 | for (i = 0; i <= indexHighA; ++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() < (indexHighA + 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 <= indexHighA; ++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, fouble *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(fouble *decodeLow, | ||
863 | fouble *decodeRange, | ||
864 | int maxImgPixel) { | ||
865 | decodeLow[0] = 0; | ||
866 | decodeRange[0] = maxImgPixel; | ||
867 | } | ||
868 | |||
869 | //------------------------------------------------------------------------ | ||
870 | // GfxSeparationColorSpace | ||
871 | //------------------------------------------------------------------------ | ||
872 | |||
873 | GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, | ||
874 | GfxColorSpace *altA, | ||
875 | Function *funcA) { | ||
876 | name = nameA; | ||
877 | alt = altA; | ||
878 | func = funcA; | ||
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 *nameA; | ||
895 | GfxColorSpace *altA; | ||
896 | Function *funcA; | ||
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 | nameA = new GString(obj1.getName()); | ||
908 | obj1.free(); | ||
909 | arr->get(2, &obj1); | ||
910 | if (!(altA = GfxColorSpace::parse(&obj1))) { | ||
911 | error(-1, "Bad Separation color space (alternate color space)"); | ||
912 | goto err3; | ||
913 | } | ||
914 | obj1.free(); | ||
915 | arr->get(3, &obj1); | ||
916 | if (!(funcA = Function::parse(&obj1))) { | ||
917 | goto err4; | ||
918 | } | ||
919 | obj1.free(); | ||
920 | cs = new GfxSeparationColorSpace(nameA, altA, funcA); | ||
921 | return cs; | ||
922 | |||
923 | err4: | ||
924 | delete altA; | ||
925 | err3: | ||
926 | delete nameA; | ||
927 | err2: | ||
928 | obj1.free(); | ||
929 | err1: | ||
930 | return NULL; | ||
931 | } | ||
932 | |||
933 | void GfxSeparationColorSpace::getGray(GfxColor *color, fouble *gray) { | ||
934 | GfxColor color2; | ||
935 | |||
936 | func->transform(color->c, color2.c); | ||
937 | alt->getGray(&color2, gray); | ||
938 | } | ||
939 | |||
940 | void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { | ||
941 | GfxColor color2; | ||
942 | |||
943 | func->transform(color->c, color2.c); | ||
944 | alt->getRGB(&color2, rgb); | ||
945 | } | ||
946 | |||
947 | void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { | ||
948 | GfxColor color2; | ||
949 | |||
950 | func->transform(color->c, color2.c); | ||
951 | alt->getCMYK(&color2, cmyk); | ||
952 | } | ||
953 | |||
954 | //------------------------------------------------------------------------ | ||
955 | // GfxDeviceNColorSpace | ||
956 | //------------------------------------------------------------------------ | ||
957 | |||
958 | GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, | ||
959 | GfxColorSpace *altA, | ||
960 | Function *funcA) { | ||
961 | nComps = nCompsA; | ||
962 | alt = altA; | ||
963 | func = funcA; | ||
964 | } | ||
965 | |||
966 | GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { | ||
967 | int i; | ||
968 | |||
969 | for (i = 0; i < nComps; ++i) { | ||
970 | delete names[i]; | ||
971 | } | ||
972 | delete alt; | ||
973 | delete func; | ||
974 | } | ||
975 | |||
976 | GfxColorSpace *GfxDeviceNColorSpace::copy() { | ||
977 | GfxDeviceNColorSpace *cs; | ||
978 | int i; | ||
979 | |||
980 | cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy()); | ||
981 | for (i = 0; i < nComps; ++i) { | ||
982 | cs->names[i] = names[i]->copy(); | ||
983 | } | ||
984 | return cs; | ||
985 | } | ||
986 | |||
987 | //~ handle the 'None' colorant | ||
988 | GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { | ||
989 | GfxDeviceNColorSpace *cs; | ||
990 | int nCompsA; | ||
991 | GString *namesA[gfxColorMaxComps]; | ||
992 | GfxColorSpace *altA; | ||
993 | Function *funcA; | ||
994 | Object obj1, obj2; | ||
995 | int i; | ||
996 | |||
997 | if (arr->getLength() != 4 && arr->getLength() != 5) { | ||
998 | error(-1, "Bad DeviceN color space"); | ||
999 | goto err1; | ||
1000 | } | ||
1001 | if (!arr->get(1, &obj1)->isArray()) { | ||
1002 | error(-1, "Bad DeviceN color space (names)"); | ||
1003 | goto err2; | ||
1004 | } | ||
1005 | nCompsA = obj1.arrayGetLength(); | ||
1006 | for (i = 0; i < nCompsA; ++i) { | ||
1007 | if (!obj1.arrayGet(i, &obj2)->isName()) { | ||
1008 | error(-1, "Bad DeviceN color space (names)"); | ||
1009 | obj2.free(); | ||
1010 | goto err2; | ||
1011 | } | ||
1012 | namesA[i] = new GString(obj2.getName()); | ||
1013 | obj2.free(); | ||
1014 | } | ||
1015 | obj1.free(); | ||
1016 | arr->get(2, &obj1); | ||
1017 | if (!(altA = GfxColorSpace::parse(&obj1))) { | ||
1018 | error(-1, "Bad DeviceN color space (alternate color space)"); | ||
1019 | goto err3; | ||
1020 | } | ||
1021 | obj1.free(); | ||
1022 | arr->get(3, &obj1); | ||
1023 | if (!(funcA = Function::parse(&obj1))) { | ||
1024 | goto err4; | ||
1025 | } | ||
1026 | obj1.free(); | ||
1027 | cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA); | ||
1028 | for (i = 0; i < nCompsA; ++i) { | ||
1029 | cs->names[i] = namesA[i]; | ||
1030 | } | ||
1031 | return cs; | ||
1032 | |||
1033 | err4: | ||
1034 | delete altA; | ||
1035 | err3: | ||
1036 | for (i = 0; i < nCompsA; ++i) { | ||
1037 | delete namesA[i]; | ||
1038 | } | ||
1039 | err2: | ||
1040 | obj1.free(); | ||
1041 | err1: | ||
1042 | return NULL; | ||
1043 | } | ||
1044 | |||
1045 | void GfxDeviceNColorSpace::getGray(GfxColor *color, fouble *gray) { | ||
1046 | GfxColor color2; | ||
1047 | |||
1048 | func->transform(color->c, color2.c); | ||
1049 | alt->getGray(&color2, gray); | ||
1050 | } | ||
1051 | |||
1052 | void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { | ||
1053 | GfxColor color2; | ||
1054 | |||
1055 | func->transform(color->c, color2.c); | ||
1056 | alt->getRGB(&color2, rgb); | ||
1057 | } | ||
1058 | |||
1059 | void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { | ||
1060 | GfxColor color2; | ||
1061 | |||
1062 | func->transform(color->c, color2.c); | ||
1063 | alt->getCMYK(&color2, cmyk); | ||
1064 | } | ||
1065 | |||
1066 | //------------------------------------------------------------------------ | ||
1067 | // GfxPatternColorSpace | ||
1068 | //------------------------------------------------------------------------ | ||
1069 | |||
1070 | GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { | ||
1071 | under = underA; | ||
1072 | } | ||
1073 | |||
1074 | GfxPatternColorSpace::~GfxPatternColorSpace() { | ||
1075 | if (under) { | ||
1076 | delete under; | ||
1077 | } | ||
1078 | } | ||
1079 | |||
1080 | GfxColorSpace *GfxPatternColorSpace::copy() { | ||
1081 | return new GfxPatternColorSpace(under ? under->copy() : | ||
1082 | (GfxColorSpace *)NULL); | ||
1083 | } | ||
1084 | |||
1085 | GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) { | ||
1086 | GfxPatternColorSpace *cs; | ||
1087 | GfxColorSpace *underA; | ||
1088 | Object obj1; | ||
1089 | |||
1090 | if (arr->getLength() != 1 && arr->getLength() != 2) { | ||
1091 | error(-1, "Bad Pattern color space"); | ||
1092 | return NULL; | ||
1093 | } | ||
1094 | underA = NULL; | ||
1095 | if (arr->getLength() == 2) { | ||
1096 | arr->get(1, &obj1); | ||
1097 | if (!(underA = GfxColorSpace::parse(&obj1))) { | ||
1098 | error(-1, "Bad Pattern color space (underlying color space)"); | ||
1099 | obj1.free(); | ||
1100 | return NULL; | ||
1101 | } | ||
1102 | obj1.free(); | ||
1103 | } | ||
1104 | cs = new GfxPatternColorSpace(underA); | ||
1105 | return cs; | ||
1106 | } | ||
1107 | |||
1108 | void GfxPatternColorSpace::getGray(GfxColor *color, fouble *gray) { | ||
1109 | *gray = 0; | ||
1110 | } | ||
1111 | |||
1112 | void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { | ||
1113 | rgb->r = rgb->g = rgb->b = 0; | ||
1114 | } | ||
1115 | |||
1116 | void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { | ||
1117 | cmyk->c = cmyk->m = cmyk->y = 0; | ||
1118 | cmyk->k = 1; | ||
1119 | } | ||
1120 | |||
1121 | //------------------------------------------------------------------------ | ||
1122 | // Pattern | ||
1123 | //------------------------------------------------------------------------ | ||
1124 | |||
1125 | GfxPattern::GfxPattern(int typeA) { | ||
1126 | type = typeA; | ||
1127 | } | ||
1128 | |||
1129 | GfxPattern::~GfxPattern() { | ||
1130 | } | ||
1131 | |||
1132 | GfxPattern *GfxPattern::parse(Object *obj) { | ||
1133 | GfxPattern *pattern; | ||
1134 | Dict *dict; | ||
1135 | Object obj1; | ||
1136 | |||
1137 | pattern = NULL; | ||
1138 | if (obj->isStream()) { | ||
1139 | dict = obj->streamGetDict(); | ||
1140 | dict->lookup("PatternType", &obj1); | ||
1141 | if (obj1.isInt() && obj1.getInt() == 1) { | ||
1142 | pattern = new GfxTilingPattern(dict, obj); | ||
1143 | } | ||
1144 | obj1.free(); | ||
1145 | } | ||
1146 | return pattern; | ||
1147 | } | ||
1148 | |||
1149 | //------------------------------------------------------------------------ | ||
1150 | // GfxTilingPattern | ||
1151 | //------------------------------------------------------------------------ | ||
1152 | |||
1153 | GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream): | ||
1154 | GfxPattern(1) | ||
1155 | { | ||
1156 | Object obj1, obj2; | ||
1157 | int i; | ||
1158 | |||
1159 | if (streamDict->lookup("PaintType", &obj1)->isInt()) { | ||
1160 | paintType = obj1.getInt(); | ||
1161 | } else { | ||
1162 | paintType = 1; | ||
1163 | error(-1, "Invalid or missing PaintType in pattern"); | ||
1164 | } | ||
1165 | obj1.free(); | ||
1166 | if (streamDict->lookup("TilingType", &obj1)->isInt()) { | ||
1167 | tilingType = obj1.getInt(); | ||
1168 | } else { | ||
1169 | tilingType = 1; | ||
1170 | error(-1, "Invalid or missing TilingType in pattern"); | ||
1171 | } | ||
1172 | obj1.free(); | ||
1173 | bbox[0] = bbox[1] = 0; | ||
1174 | bbox[2] = bbox[3] = 1; | ||
1175 | if (streamDict->lookup("BBox", &obj1)->isArray() && | ||
1176 | obj1.arrayGetLength() == 4) { | ||
1177 | for (i = 0; i < 4; ++i) { | ||
1178 | if (obj1.arrayGet(i, &obj2)->isNum()) { | ||
1179 | bbox[i] = obj2.getNum(); | ||
1180 | } | ||
1181 | obj2.free(); | ||
1182 | } | ||
1183 | } else { | ||
1184 | error(-1, "Invalid or missing BBox in pattern"); | ||
1185 | } | ||
1186 | obj1.free(); | ||
1187 | if (streamDict->lookup("XStep", &obj1)->isNum()) { | ||
1188 | xStep = obj1.getNum(); | ||
1189 | } else { | ||
1190 | xStep = 1; | ||
1191 | error(-1, "Invalid or missing XStep in pattern"); | ||
1192 | } | ||
1193 | obj1.free(); | ||
1194 | if (streamDict->lookup("YStep", &obj1)->isNum()) { | ||
1195 | yStep = obj1.getNum(); | ||
1196 | } else { | ||
1197 | yStep = 1; | ||
1198 | error(-1, "Invalid or missing YStep in pattern"); | ||
1199 | } | ||
1200 | obj1.free(); | ||
1201 | if (!streamDict->lookup("Resources", &resDict)->isDict()) { | ||
1202 | resDict.free(); | ||
1203 | resDict.initNull(); | ||
1204 | error(-1, "Invalid or missing Resources in pattern"); | ||
1205 | } | ||
1206 | matrix[0] = 1; matrix[1] = 0; | ||
1207 | matrix[2] = 0; matrix[3] = 1; | ||
1208 | matrix[4] = 0; matrix[5] = 0; | ||
1209 | if (streamDict->lookup("Matrix", &obj1)->isArray() && | ||
1210 | obj1.arrayGetLength() == 6) { | ||
1211 | for (i = 0; i < 6; ++i) { | ||
1212 | if (obj1.arrayGet(i, &obj2)->isNum()) { | ||
1213 | matrix[i] = obj2.getNum(); | ||
1214 | } | ||
1215 | obj2.free(); | ||
1216 | } | ||
1217 | } | ||
1218 | obj1.free(); | ||
1219 | stream->copy(&contentStream); | ||
1220 | } | ||
1221 | |||
1222 | GfxTilingPattern::~GfxTilingPattern() { | ||
1223 | resDict.free(); | ||
1224 | contentStream.free(); | ||
1225 | } | ||
1226 | |||
1227 | GfxPattern *GfxTilingPattern::copy() { | ||
1228 | return new GfxTilingPattern(this); | ||
1229 | } | ||
1230 | |||
1231 | GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat): | ||
1232 | GfxPattern(1) | ||
1233 | { | ||
1234 | memcpy(this, pat, sizeof(GfxTilingPattern)); | ||
1235 | pat->resDict.copy(&resDict); | ||
1236 | pat->contentStream.copy(&contentStream); | ||
1237 | } | ||
1238 | |||
1239 | //------------------------------------------------------------------------ | ||
1240 | // GfxShading | ||
1241 | //------------------------------------------------------------------------ | ||
1242 | |||
1243 | GfxShading::GfxShading() { | ||
1244 | } | ||
1245 | |||
1246 | GfxShading::~GfxShading() { | ||
1247 | delete colorSpace; | ||
1248 | } | ||
1249 | |||
1250 | GfxShading *GfxShading::parse(Object *obj) { | ||
1251 | GfxShading *shading; | ||
1252 | int typeA; | ||
1253 | GfxColorSpace *colorSpaceA; | ||
1254 | GfxColor backgroundA; | ||
1255 | GBool hasBackgroundA; | ||
1256 | fouble xMinA, yMinA, xMaxA, yMaxA; | ||
1257 | GBool hasBBoxA; | ||
1258 | Object obj1, obj2; | ||
1259 | int i; | ||
1260 | |||
1261 | shading = NULL; | ||
1262 | if (obj->isDict()) { | ||
1263 | |||
1264 | if (!obj->dictLookup("ShadingType", &obj1)->isInt()) { | ||
1265 | error(-1, "Invalid ShadingType in shading dictionary"); | ||
1266 | obj1.free(); | ||
1267 | goto err1; | ||
1268 | } | ||
1269 | typeA = obj1.getInt(); | ||
1270 | obj1.free(); | ||
1271 | if (typeA != 2) { | ||
1272 | error(-1, "Unimplemented shading type %d", typeA); | ||
1273 | goto err1; | ||
1274 | } | ||
1275 | |||
1276 | obj->dictLookup("ColorSpace", &obj1); | ||
1277 | if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) { | ||
1278 | error(-1, "Bad color space in shading dictionary"); | ||
1279 | obj1.free(); | ||
1280 | goto err1; | ||
1281 | } | ||
1282 | obj1.free(); | ||
1283 | |||
1284 | for (i = 0; i < gfxColorMaxComps; ++i) { | ||
1285 | backgroundA.c[i] = 0; | ||
1286 | } | ||
1287 | hasBackgroundA = gFalse; | ||
1288 | if (obj->dictLookup("Background", &obj1)->isArray()) { | ||
1289 | if (obj1.arrayGetLength() == colorSpaceA->getNComps()) { | ||
1290 | hasBackgroundA = gTrue; | ||
1291 | for (i = 0; i < colorSpaceA->getNComps(); ++i) { | ||
1292 | backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum(); | ||
1293 | obj2.free(); | ||
1294 | } | ||
1295 | } else { | ||
1296 | error(-1, "Bad Background in shading dictionary"); | ||
1297 | } | ||
1298 | } | ||
1299 | obj1.free(); | ||
1300 | |||
1301 | xMinA = yMinA = xMaxA = yMaxA = 0; | ||
1302 | hasBBoxA = gFalse; | ||
1303 | if (obj->dictLookup("BBox", &obj1)->isArray()) { | ||
1304 | if (obj1.arrayGetLength() == 4) { | ||
1305 | hasBBoxA = gTrue; | ||
1306 | xMinA = obj1.arrayGet(0, &obj2)->getNum(); | ||
1307 | obj2.free(); | ||
1308 | yMinA = obj1.arrayGet(1, &obj2)->getNum(); | ||
1309 | obj2.free(); | ||
1310 | xMaxA = obj1.arrayGet(2, &obj2)->getNum(); | ||
1311 | obj2.free(); | ||
1312 | yMaxA = obj1.arrayGet(3, &obj2)->getNum(); | ||
1313 | obj2.free(); | ||
1314 | } else { | ||
1315 | error(-1, "Bad BBox in shading dictionary"); | ||
1316 | } | ||
1317 | } | ||
1318 | obj1.free(); | ||
1319 | |||
1320 | shading = GfxAxialShading::parse(obj->getDict()); | ||
1321 | |||
1322 | if (shading) { | ||
1323 | shading->type = typeA; | ||
1324 | shading->colorSpace = colorSpaceA; | ||
1325 | shading->background = backgroundA; | ||
1326 | shading->hasBackground = hasBackgroundA; | ||
1327 | shading->xMin = xMinA; | ||
1328 | shading->yMin = yMinA; | ||
1329 | shading->xMax = xMaxA; | ||
1330 | shading->yMax = yMaxA; | ||
1331 | shading->hasBBox = hasBBoxA; | ||
1332 | } else { | ||
1333 | delete colorSpaceA; | ||
1334 | } | ||
1335 | } | ||
1336 | |||
1337 | return shading; | ||
1338 | |||
1339 | err1: | ||
1340 | return NULL; | ||
1341 | } | ||
1342 | |||
1343 | //------------------------------------------------------------------------ | ||
1344 | // GfxAxialShading | ||
1345 | //------------------------------------------------------------------------ | ||
1346 | |||
1347 | GfxAxialShading::GfxAxialShading(fouble x0A, fouble y0A, | ||
1348 | fouble x1A, fouble y1A, | ||
1349 | fouble t0A, fouble t1A, | ||
1350 | Function **funcsA, int nFuncsA, | ||
1351 | GBool extend0A, GBool extend1A) { | ||
1352 | int i; | ||
1353 | |||
1354 | x0 = x0A; | ||
1355 | y0 = y0A; | ||
1356 | x1 = x1A; | ||
1357 | y1 = y1A; | ||
1358 | t0 = t0A; | ||
1359 | t1 = t1A; | ||
1360 | nFuncs = nFuncsA; | ||
1361 | for (i = 0; i < nFuncs; ++i) { | ||
1362 | funcs[i] = funcsA[i]; | ||
1363 | } | ||
1364 | extend0 = extend0A; | ||
1365 | extend1 = extend1A; | ||
1366 | } | ||
1367 | |||
1368 | GfxAxialShading::~GfxAxialShading() { | ||
1369 | int i; | ||
1370 | |||
1371 | for (i = 0; i < nFuncs; ++i) { | ||
1372 | delete funcs[i]; | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1376 | GfxAxialShading *GfxAxialShading::parse(Dict *dict) { | ||
1377 | fouble x0A, y0A, x1A, y1A; | ||
1378 | fouble t0A, t1A; | ||
1379 | Function *funcsA[gfxColorMaxComps]; | ||
1380 | int nFuncsA; | ||
1381 | GBool extend0A, extend1A; | ||
1382 | Object obj1, obj2; | ||
1383 | int i; | ||
1384 | |||
1385 | x0A = y0A = x1A = y1A = 0; | ||
1386 | if (dict->lookup("Coords", &obj1)->isArray() && | ||
1387 | obj1.arrayGetLength() == 4) { | ||
1388 | x0A = obj1.arrayGet(0, &obj2)->getNum(); | ||
1389 | obj2.free(); | ||
1390 | y0A = obj1.arrayGet(1, &obj2)->getNum(); | ||
1391 | obj2.free(); | ||
1392 | x1A = obj1.arrayGet(2, &obj2)->getNum(); | ||
1393 | obj2.free(); | ||
1394 | y1A = obj1.arrayGet(3, &obj2)->getNum(); | ||
1395 | obj2.free(); | ||
1396 | } else { | ||
1397 | error(-1, "Missing or invalid Coords in shading dictionary"); | ||
1398 | goto err1; | ||
1399 | } | ||
1400 | obj1.free(); | ||
1401 | |||
1402 | t0A = 0; | ||
1403 | t1A = 1; | ||
1404 | if (dict->lookup("Domain", &obj1)->isArray() && | ||
1405 | obj1.arrayGetLength() == 2) { | ||
1406 | t0A = obj1.arrayGet(0, &obj2)->getNum(); | ||
1407 | obj2.free(); | ||
1408 | t1A = obj1.arrayGet(1, &obj2)->getNum(); | ||
1409 | obj2.free(); | ||
1410 | } | ||
1411 | obj1.free(); | ||
1412 | |||
1413 | dict->lookup("Function", &obj1); | ||
1414 | if (obj1.isArray()) { | ||
1415 | nFuncsA = obj1.arrayGetLength(); | ||
1416 | for (i = 0; i < nFuncsA; ++i) { | ||
1417 | obj1.arrayGet(i, &obj2); | ||
1418 | if (!(funcsA[i] = Function::parse(&obj2))) { | ||
1419 | obj1.free(); | ||
1420 | obj2.free(); | ||
1421 | goto err1; | ||
1422 | } | ||
1423 | obj2.free(); | ||
1424 | } | ||
1425 | } else { | ||
1426 | nFuncsA = 1; | ||
1427 | if (!(funcsA[0] = Function::parse(&obj1))) { | ||
1428 | obj1.free(); | ||
1429 | goto err1; | ||
1430 | } | ||
1431 | } | ||
1432 | obj1.free(); | ||
1433 | |||
1434 | extend0A = extend1A = gFalse; | ||
1435 | if (dict->lookup("Extend", &obj1)->isArray() && | ||
1436 | obj1.arrayGetLength() == 2) { | ||
1437 | extend0A = obj1.arrayGet(0, &obj2)->getBool(); | ||
1438 | obj2.free(); | ||
1439 | extend1A = obj1.arrayGet(1, &obj2)->getBool(); | ||
1440 | obj2.free(); | ||
1441 | } | ||
1442 | obj1.free(); | ||
1443 | |||
1444 | return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, | ||
1445 | funcsA, nFuncsA, extend0A, extend1A); | ||
1446 | |||
1447 | err1: | ||
1448 | return NULL; | ||
1449 | } | ||
1450 | |||
1451 | void GfxAxialShading::getColor(fouble t, GfxColor *color) { | ||
1452 | int i; | ||
1453 | |||
1454 | for (i = 0; i < nFuncs; ++i) { | ||
1455 | funcs[i]->transform(&t, &color->c[i]); | ||
1456 | } | ||
1457 | } | ||
1458 | |||
1459 | //------------------------------------------------------------------------ | ||
1460 | // GfxImageColorMap | ||
1461 | //------------------------------------------------------------------------ | ||
1462 | |||
1463 | GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, | ||
1464 | GfxColorSpace *colorSpaceA) { | ||
1465 | GfxIndexedColorSpace *indexedCS; | ||
1466 | GfxSeparationColorSpace *sepCS; | ||
1467 | int maxPixel, indexHigh; | ||
1468 | Guchar *lookup2; | ||
1469 | Function *sepFunc; | ||
1470 | Object obj; | ||
1471 | fouble x[gfxColorMaxComps]; | ||
1472 | fouble y[gfxColorMaxComps]; | ||
1473 | int i, j, k; | ||
1474 | |||
1475 | ok = gTrue; | ||
1476 | |||
1477 | // bits per component and color space | ||
1478 | bits = bitsA; | ||
1479 | maxPixel = (1 << bits) - 1; | ||
1480 | colorSpace = colorSpaceA; | ||
1481 | |||
1482 | // get decode map | ||
1483 | if (decode->isNull()) { | ||
1484 | nComps = colorSpace->getNComps(); | ||
1485 | colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); | ||
1486 | } else if (decode->isArray()) { | ||
1487 | nComps = decode->arrayGetLength() / 2; | ||
1488 | if (nComps != colorSpace->getNComps()) { | ||
1489 | goto err1; | ||
1490 | } | ||
1491 | for (i = 0; i < nComps; ++i) { | ||
1492 | decode->arrayGet(2*i, &obj); | ||
1493 | if (!obj.isNum()) { | ||
1494 | goto err2; | ||
1495 | } | ||
1496 | decodeLow[i] = obj.getNum(); | ||
1497 | obj.free(); | ||
1498 | decode->arrayGet(2*i+1, &obj); | ||
1499 | if (!obj.isNum()) { | ||
1500 | goto err2; | ||
1501 | } | ||
1502 | decodeRange[i] = obj.getNum() - decodeLow[i]; | ||
1503 | obj.free(); | ||
1504 | } | ||
1505 | } else { | ||
1506 | goto err1; | ||
1507 | } | ||
1508 | |||
1509 | // Construct a lookup table -- this stores pre-computed decoded | ||
1510 | // values for each component, i.e., the result of applying the | ||
1511 | // decode mapping to each possible image pixel component value. | ||
1512 | // | ||
1513 | // Optimization: for Indexed and Separation color spaces (which have | ||
1514 | // only one component), we store color values in the lookup table | ||
1515 | // rather than component values. | ||
1516 | colorSpace2 = NULL; | ||
1517 | nComps2 = 0; | ||
1518 | if (colorSpace->getMode() == csIndexed) { | ||
1519 | // Note that indexHigh may not be the same as maxPixel -- | ||
1520 | // Distiller will remove unused palette entries, resulting in | ||
1521 | // indexHigh < maxPixel. | ||
1522 | indexedCS = (GfxIndexedColorSpace *)colorSpace; | ||
1523 | colorSpace2 = indexedCS->getBase(); | ||
1524 | indexHigh = indexedCS->getIndexHigh(); | ||
1525 | nComps2 = colorSpace2->getNComps(); | ||
1526 | lookup = (fouble *)gmalloc((indexHigh + 1) * nComps2 * sizeof(fouble)); | ||
1527 | lookup2 = indexedCS->getLookup(); | ||
1528 | for (i = 0; i <= indexHigh; ++i) { | ||
1529 | j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5); | ||
1530 | for (k = 0; k < nComps2; ++k) { | ||
1531 | lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0; | ||
1532 | } | ||
1533 | } | ||
1534 | } else if (colorSpace->getMode() == csSeparation) { | ||
1535 | sepCS = (GfxSeparationColorSpace *)colorSpace; | ||
1536 | colorSpace2 = sepCS->getAlt(); | ||
1537 | nComps2 = colorSpace2->getNComps(); | ||
1538 | lookup = (fouble *)gmalloc((maxPixel + 1) * nComps2 * sizeof(fouble)); | ||
1539 | sepFunc = sepCS->getFunc(); | ||
1540 | for (i = 0; i <= maxPixel; ++i) { | ||
1541 | x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; | ||
1542 | sepFunc->transform(x, y); | ||
1543 | for (k = 0; k < nComps2; ++k) { | ||
1544 | lookup[i*nComps2 + k] = y[k]; | ||
1545 | } | ||
1546 | } | ||
1547 | } else { | ||
1548 | lookup = (fouble *)gmalloc((maxPixel + 1) * nComps * sizeof(fouble)); | ||
1549 | for (i = 0; i <= maxPixel; ++i) { | ||
1550 | for (k = 0; k < nComps; ++k) { | ||
1551 | lookup[i*nComps + k] = decodeLow[k] + | ||
1552 | (i * decodeRange[k]) / maxPixel; | ||
1553 | } | ||
1554 | } | ||
1555 | } | ||
1556 | |||
1557 | return; | ||
1558 | |||
1559 | err2: | ||
1560 | obj.free(); | ||
1561 | err1: | ||
1562 | ok = gFalse; | ||
1563 | } | ||
1564 | |||
1565 | GfxImageColorMap::~GfxImageColorMap() { | ||
1566 | delete colorSpace; | ||
1567 | gfree(lookup); | ||
1568 | } | ||
1569 | |||
1570 | void GfxImageColorMap::getGray(Guchar *x, fouble *gray) { | ||
1571 | GfxColor color; | ||
1572 | fouble *p; | ||
1573 | int i; | ||
1574 | |||
1575 | if (colorSpace2) { | ||
1576 | p = &lookup[x[0] * nComps2]; | ||
1577 | for (i = 0; i < nComps2; ++i) { | ||
1578 | color.c[i] = *p++; | ||
1579 | } | ||
1580 | colorSpace2->getGray(&color, gray); | ||
1581 | } else { | ||
1582 | for (i = 0; i < nComps; ++i) { | ||
1583 | color.c[i] = lookup[x[i] * nComps + i]; | ||
1584 | } | ||
1585 | colorSpace->getGray(&color, gray); | ||
1586 | } | ||
1587 | } | ||
1588 | |||
1589 | void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { | ||
1590 | GfxColor color; | ||
1591 | fouble *p; | ||
1592 | int i; | ||
1593 | |||
1594 | if (colorSpace2) { | ||
1595 | p = &lookup[x[0] * nComps2]; | ||
1596 | for (i = 0; i < nComps2; ++i) { | ||
1597 | color.c[i] = *p++; | ||
1598 | } | ||
1599 | colorSpace2->getRGB(&color, rgb); | ||
1600 | } else { | ||
1601 | for (i = 0; i < nComps; ++i) { | ||
1602 | color.c[i] = lookup[x[i] * nComps + i]; | ||
1603 | } | ||
1604 | colorSpace->getRGB(&color, rgb); | ||
1605 | } | ||
1606 | } | ||
1607 | |||
1608 | void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { | ||
1609 | GfxColor color; | ||
1610 | fouble *p; | ||
1611 | int i; | ||
1612 | |||
1613 | if (colorSpace2) { | ||
1614 | p = &lookup[x[0] * nComps2]; | ||
1615 | for (i = 0; i < nComps2; ++i) { | ||
1616 | color.c[i] = *p++; | ||
1617 | } | ||
1618 | colorSpace2->getCMYK(&color, cmyk); | ||
1619 | } else { | ||
1620 | for (i = 0; i < nComps; ++i) { | ||
1621 | color.c[i] = lookup[x[i] * nComps + i]; | ||
1622 | } | ||
1623 | colorSpace->getCMYK(&color, cmyk); | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | //------------------------------------------------------------------------ | ||
1628 | // GfxSubpath and GfxPath | ||
1629 | //------------------------------------------------------------------------ | ||
1630 | |||
1631 | GfxSubpath::GfxSubpath(fouble x1, fouble y1) { | ||
1632 | size = 16; | ||
1633 | x = (fouble *)gmalloc(size * sizeof(fouble)); | ||
1634 | y = (fouble *)gmalloc(size * sizeof(fouble)); | ||
1635 | curve = (GBool *)gmalloc(size * sizeof(GBool)); | ||
1636 | n = 1; | ||
1637 | x[0] = x1; | ||
1638 | y[0] = y1; | ||
1639 | curve[0] = gFalse; | ||
1640 | closed = gFalse; | ||
1641 | } | ||
1642 | |||
1643 | GfxSubpath::~GfxSubpath() { | ||
1644 | gfree(x); | ||
1645 | gfree(y); | ||
1646 | gfree(curve); | ||
1647 | } | ||
1648 | |||
1649 | // Used for copy(). | ||
1650 | GfxSubpath::GfxSubpath(GfxSubpath *subpath) { | ||
1651 | size = subpath->size; | ||
1652 | n = subpath->n; | ||
1653 | x = (fouble *)gmalloc(size * sizeof(fouble)); | ||
1654 | y = (fouble *)gmalloc(size * sizeof(fouble)); | ||
1655 | curve = (GBool *)gmalloc(size * sizeof(GBool)); | ||
1656 | memcpy(x, subpath->x, n * sizeof(fouble)); | ||
1657 | memcpy(y, subpath->y, n * sizeof(fouble)); | ||
1658 | memcpy(curve, subpath->curve, n * sizeof(GBool)); | ||
1659 | closed = subpath->closed; | ||
1660 | } | ||
1661 | |||
1662 | void GfxSubpath::lineTo(fouble x1, fouble y1) { | ||
1663 | if (n >= size) { | ||
1664 | size += 16; | ||
1665 | x = (fouble *)grealloc(x, size * sizeof(fouble)); | ||
1666 | y = (fouble *)grealloc(y, size * sizeof(fouble)); | ||
1667 | curve = (GBool *)grealloc(curve, size * sizeof(GBool)); | ||
1668 | } | ||
1669 | x[n] = x1; | ||
1670 | y[n] = y1; | ||
1671 | curve[n] = gFalse; | ||
1672 | ++n; | ||
1673 | } | ||
1674 | |||
1675 | void GfxSubpath::curveTo(fouble x1, fouble y1, fouble x2, fouble y2, | ||
1676 | fouble x3, fouble y3) { | ||
1677 | if (n+3 > size) { | ||
1678 | size += 16; | ||
1679 | x = (fouble *)grealloc(x, size * sizeof(fouble)); | ||
1680 | y = (fouble *)grealloc(y, size * sizeof(fouble)); | ||
1681 | curve = (GBool *)grealloc(curve, size * sizeof(GBool)); | ||
1682 | } | ||
1683 | x[n] = x1; | ||
1684 | y[n] = y1; | ||
1685 | x[n+1] = x2; | ||
1686 | y[n+1] = y2; | ||
1687 | x[n+2] = x3; | ||
1688 | y[n+2] = y3; | ||
1689 | curve[n] = curve[n+1] = gTrue; | ||
1690 | curve[n+2] = gFalse; | ||
1691 | n += 3; | ||
1692 | } | ||
1693 | |||
1694 | void GfxSubpath::close() { | ||
1695 | if (x[n-1] != x[0] || y[n-1] != y[0]) { | ||
1696 | lineTo(x[0], y[0]); | ||
1697 | } | ||
1698 | closed = gTrue; | ||
1699 | } | ||
1700 | |||
1701 | GfxPath::GfxPath() { | ||
1702 | justMoved = gFalse; | ||
1703 | size = 16; | ||
1704 | n = 0; | ||
1705 | firstX = firstY = 0; | ||
1706 | subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *)); | ||
1707 | } | ||
1708 | |||
1709 | GfxPath::~GfxPath() { | ||
1710 | int i; | ||
1711 | |||
1712 | for (i = 0; i < n; ++i) | ||
1713 | delete subpaths[i]; | ||
1714 | gfree(subpaths); | ||
1715 | } | ||
1716 | |||
1717 | // Used for copy(). | ||
1718 | GfxPath::GfxPath(GBool justMoved1, fouble firstX1, fouble firstY1, | ||
1719 | GfxSubpath **subpaths1, int n1, int size1) { | ||
1720 | int i; | ||
1721 | |||
1722 | justMoved = justMoved1; | ||
1723 | firstX = firstX1; | ||
1724 | firstY = firstY1; | ||
1725 | size = size1; | ||
1726 | n = n1; | ||
1727 | subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *)); | ||
1728 | for (i = 0; i < n; ++i) | ||
1729 | subpaths[i] = subpaths1[i]->copy(); | ||
1730 | } | ||
1731 | |||
1732 | void GfxPath::moveTo(fouble x, fouble y) { | ||
1733 | justMoved = gTrue; | ||
1734 | firstX = x; | ||
1735 | firstY = y; | ||
1736 | } | ||
1737 | |||
1738 | void GfxPath::lineTo(fouble x, fouble y) { | ||
1739 | if (justMoved) { | ||
1740 | if (n >= size) { | ||
1741 | size += 16; | ||
1742 | subpaths = (GfxSubpath **) | ||
1743 | grealloc(subpaths, size * sizeof(GfxSubpath *)); | ||
1744 | } | ||
1745 | subpaths[n] = new GfxSubpath(firstX, firstY); | ||
1746 | ++n; | ||
1747 | justMoved = gFalse; | ||
1748 | } | ||
1749 | subpaths[n-1]->lineTo(x, y); | ||
1750 | } | ||
1751 | |||
1752 | void GfxPath::curveTo(fouble x1, fouble y1, fouble x2, fouble y2, | ||
1753 | fouble x3, fouble y3) { | ||
1754 | if (justMoved) { | ||
1755 | if (n >= size) { | ||
1756 | size += 16; | ||
1757 | subpaths = (GfxSubpath **) | ||
1758 | grealloc(subpaths, size * sizeof(GfxSubpath *)); | ||
1759 | } | ||
1760 | subpaths[n] = new GfxSubpath(firstX, firstY); | ||
1761 | ++n; | ||
1762 | justMoved = gFalse; | ||
1763 | } | ||
1764 | subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); | ||
1765 | } | ||
1766 | |||
1767 | void GfxPath::close() { | ||
1768 | // this is necessary to handle the pathological case of | ||
1769 | // moveto/closepath/clip, which defines an empty clipping region | ||
1770 | if (justMoved) { | ||
1771 | if (n >= size) { | ||
1772 | size += 16; | ||
1773 | subpaths = (GfxSubpath **) | ||
1774 | grealloc(subpaths, size * sizeof(GfxSubpath *)); | ||
1775 | } | ||
1776 | subpaths[n] = new GfxSubpath(firstX, firstY); | ||
1777 | ++n; | ||
1778 | justMoved = gFalse; | ||
1779 | } | ||
1780 | subpaths[n-1]->close(); | ||
1781 | } | ||
1782 | |||
1783 | //------------------------------------------------------------------------ | ||
1784 | // GfxState | ||
1785 | //------------------------------------------------------------------------ | ||
1786 | |||
1787 | GfxState::GfxState(fouble dpi, PDFRectangle *pageBox, int rotate, | ||
1788 | GBool upsideDown) { | ||
1789 | fouble k; | ||
1790 | |||
1791 | px1 = pageBox->x1; | ||
1792 | py1 = pageBox->y1; | ||
1793 | px2 = pageBox->x2; | ||
1794 | py2 = pageBox->y2; | ||
1795 | k = dpi / 72.0; | ||
1796 | if (rotate == 90) { | ||
1797 | ctm[0] = 0; | ||
1798 | ctm[1] = upsideDown ? k : -k; | ||
1799 | ctm[2] = k; | ||
1800 | ctm[3] = 0; | ||
1801 | ctm[4] = -k * py1; | ||
1802 | ctm[5] = k * (upsideDown ? -px1 : px2); | ||
1803 | pageWidth = k * (py2 - py1); | ||
1804 | pageHeight = k * (px2 - px1); | ||
1805 | } else if (rotate == 180) { | ||
1806 | ctm[0] = -k; | ||
1807 | ctm[1] = 0; | ||
1808 | ctm[2] = 0; | ||
1809 | ctm[3] = upsideDown ? k : -k; | ||
1810 | ctm[4] = k * px2; | ||
1811 | ctm[5] = k * (upsideDown ? -py1 : py2); | ||
1812 | pageWidth = k * (px2 - px1); | ||
1813 | pageHeight = k * (py2 - py1); | ||
1814 | } else if (rotate == 270) { | ||
1815 | ctm[0] = 0; | ||
1816 | ctm[1] = upsideDown ? -k : k; | ||
1817 | ctm[2] = -k; | ||
1818 | ctm[3] = 0; | ||
1819 | ctm[4] = k * py2; | ||
1820 | ctm[5] = k * (upsideDown ? px2 : -px1); | ||
1821 | pageWidth = k * (py2 - py1); | ||
1822 | pageHeight = k * (px2 - px1); | ||
1823 | } else { | ||
1824 | ctm[0] = k; | ||
1825 | ctm[1] = 0; | ||
1826 | ctm[2] = 0; | ||
1827 | ctm[3] = upsideDown ? -k : k; | ||
1828 | ctm[4] = -k * px1; | ||
1829 | ctm[5] = k * (upsideDown ? py2 : -py1); | ||
1830 | pageWidth = k * (px2 - px1); | ||
1831 | pageHeight = k * (py2 - py1); | ||
1832 | } | ||
1833 | |||
1834 | fillColorSpace = new GfxDeviceGrayColorSpace(); | ||
1835 | strokeColorSpace = new GfxDeviceGrayColorSpace(); | ||
1836 | fillColor.c[0] = 0; | ||
1837 | strokeColor.c[0] = 0; | ||
1838 | fillPattern = NULL; | ||
1839 | strokePattern = NULL; | ||
1840 | fillOpacity = 1; | ||
1841 | strokeOpacity = 1; | ||
1842 | |||
1843 | lineWidth = 1; | ||
1844 | lineDash = NULL; | ||
1845 | lineDashLength = 0; | ||
1846 | lineDashStart = 0; | ||
1847 | flatness = 0; | ||
1848 | lineJoin = 0; | ||
1849 | lineCap = 0; | ||
1850 | miterLimit = 10; | ||
1851 | |||
1852 | font = NULL; | ||
1853 | fontSize = 0; | ||
1854 | textMat[0] = 1; textMat[1] = 0; | ||
1855 | textMat[2] = 0; textMat[3] = 1; | ||
1856 | textMat[4] = 0; textMat[5] = 0; | ||
1857 | charSpace = 0; | ||
1858 | wordSpace = 0; | ||
1859 | horizScaling = 1; | ||
1860 | leading = 0; | ||
1861 | rise = 0; | ||
1862 | render = 0; | ||
1863 | |||
1864 | path = new GfxPath(); | ||
1865 | curX = curY = 0; | ||
1866 | lineX = lineY = 0; | ||
1867 | |||
1868 | clipXMin = 0; | ||
1869 | clipYMin = 0; | ||
1870 | clipXMax = pageWidth; | ||
1871 | clipYMax = pageHeight; | ||
1872 | |||
1873 | saved = NULL; | ||
1874 | } | ||
1875 | |||
1876 | GfxState::~GfxState() { | ||
1877 | if (fillColorSpace) { | ||
1878 | delete fillColorSpace; | ||
1879 | } | ||
1880 | if (strokeColorSpace) { | ||
1881 | delete strokeColorSpace; | ||
1882 | } | ||
1883 | if (fillPattern) { | ||
1884 | delete fillPattern; | ||
1885 | } | ||
1886 | if (strokePattern) { | ||
1887 | delete strokePattern; | ||
1888 | } | ||
1889 | gfree(lineDash); | ||
1890 | if (path) { | ||
1891 | // this gets set to NULL by restore() | ||
1892 | delete path; | ||
1893 | } | ||
1894 | if (saved) { | ||
1895 | delete saved; | ||
1896 | } | ||
1897 | } | ||
1898 | |||
1899 | // Used for copy(); | ||
1900 | GfxState::GfxState(GfxState *state) { | ||
1901 | memcpy(this, state, sizeof(GfxState)); | ||
1902 | if (fillColorSpace) { | ||
1903 | fillColorSpace = state->fillColorSpace->copy(); | ||
1904 | } | ||
1905 | if (strokeColorSpace) { | ||
1906 | strokeColorSpace = state->strokeColorSpace->copy(); | ||
1907 | } | ||
1908 | if (fillPattern) { | ||
1909 | fillPattern = state->fillPattern->copy(); | ||
1910 | } | ||
1911 | if (strokePattern) { | ||
1912 | strokePattern = state->strokePattern->copy(); | ||
1913 | } | ||
1914 | if (lineDashLength > 0) { | ||
1915 | lineDash = (fouble *)gmalloc(lineDashLength * sizeof(fouble)); | ||
1916 | memcpy(lineDash, state->lineDash, lineDashLength * sizeof(fouble)); | ||
1917 | } | ||
1918 | saved = NULL; | ||
1919 | } | ||
1920 | |||
1921 | fouble GfxState::transformWidth(fouble w) { | ||
1922 | fouble x, y; | ||
1923 | |||
1924 | x = ctm[0] + ctm[2]; | ||
1925 | y = ctm[1] + ctm[3]; | ||
1926 | return w * sqrt(0.5 * (x * x + y * y)); | ||
1927 | } | ||
1928 | |||
1929 | fouble GfxState::getTransformedFontSize() { | ||
1930 | fouble x1, y1, x2, y2; | ||
1931 | |||
1932 | x1 = textMat[2] * fontSize; | ||
1933 | y1 = textMat[3] * fontSize; | ||
1934 | x2 = ctm[0] * x1 + ctm[2] * y1; | ||
1935 | y2 = ctm[1] * x1 + ctm[3] * y1; | ||
1936 | return sqrt(x2 * x2 + y2 * y2); | ||
1937 | } | ||
1938 | |||
1939 | void GfxState::getFontTransMat(fouble *m11, fouble *m12, | ||
1940 | fouble *m21, fouble *m22) { | ||
1941 | *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; | ||
1942 | *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; | ||
1943 | *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; | ||
1944 | *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; | ||
1945 | } | ||
1946 | |||
1947 | void GfxState::setCTM(fouble a, fouble b, fouble c, | ||
1948 | fouble d, fouble e, fouble f) { | ||
1949 | ctm[0] = a; | ||
1950 | ctm[1] = b; | ||
1951 | ctm[2] = c; | ||
1952 | ctm[3] = d; | ||
1953 | ctm[4] = e; | ||
1954 | ctm[5] = f; | ||
1955 | } | ||
1956 | |||
1957 | void GfxState::concatCTM(fouble a, fouble b, fouble c, | ||
1958 | fouble d, fouble e, fouble f) { | ||
1959 | fouble a1 = ctm[0]; | ||
1960 | fouble b1 = ctm[1]; | ||
1961 | fouble c1 = ctm[2]; | ||
1962 | fouble d1 = ctm[3]; | ||
1963 | |||
1964 | ctm[0] = a * a1 + b * c1; | ||
1965 | ctm[1] = a * b1 + b * d1; | ||
1966 | ctm[2] = c * a1 + d * c1; | ||
1967 | ctm[3] = c * b1 + d * d1; | ||
1968 | ctm[4] = e * a1 + f * c1 + ctm[4]; | ||
1969 | ctm[5] = e * b1 + f * d1 + ctm[5]; | ||
1970 | } | ||
1971 | |||
1972 | void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { | ||
1973 | if (fillColorSpace) { | ||
1974 | delete fillColorSpace; | ||
1975 | } | ||
1976 | fillColorSpace = colorSpace; | ||
1977 | } | ||
1978 | |||
1979 | void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { | ||
1980 | if (strokeColorSpace) { | ||
1981 | delete strokeColorSpace; | ||
1982 | } | ||
1983 | strokeColorSpace = colorSpace; | ||
1984 | } | ||
1985 | |||
1986 | void GfxState::setFillPattern(GfxPattern *pattern) { | ||
1987 | if (fillPattern) { | ||
1988 | delete fillPattern; | ||
1989 | } | ||
1990 | fillPattern = pattern; | ||
1991 | } | ||
1992 | |||
1993 | void GfxState::setStrokePattern(GfxPattern *pattern) { | ||
1994 | if (strokePattern) { | ||
1995 | delete strokePattern; | ||
1996 | } | ||
1997 | strokePattern = pattern; | ||
1998 | } | ||
1999 | |||
2000 | void GfxState::setLineDash(fouble *dash, int length, fouble start) { | ||
2001 | if (lineDash) | ||
2002 | gfree(lineDash); | ||
2003 | lineDash = dash; | ||
2004 | lineDashLength = length; | ||
2005 | lineDashStart = start; | ||
2006 | } | ||
2007 | |||
2008 | void GfxState::clearPath() { | ||
2009 | delete path; | ||
2010 | path = new GfxPath(); | ||
2011 | } | ||
2012 | |||
2013 | void GfxState::clip() { | ||
2014 | fouble xMin, yMin, xMax, yMax, x, y; | ||
2015 | GfxSubpath *subpath; | ||
2016 | int i, j; | ||
2017 | |||
2018 | xMin = xMax = yMin = yMax = 0; // make gcc happy | ||
2019 | for (i = 0; i < path->getNumSubpaths(); ++i) { | ||
2020 | subpath = path->getSubpath(i); | ||
2021 | for (j = 0; j < subpath->getNumPoints(); ++j) { | ||
2022 | transform(subpath->getX(j), subpath->getY(j), &x, &y); | ||
2023 | if (i == 0 && j == 0) { | ||
2024 | xMin = xMax = x; | ||
2025 | yMin = yMax = y; | ||
2026 | } else { | ||
2027 | if (x < xMin) { | ||
2028 | xMin = x; | ||
2029 | } else if (x > xMax) { | ||
2030 | xMax = x; | ||
2031 | } | ||
2032 | if (y < yMin) { | ||
2033 | yMin = y; | ||
2034 | } else if (y > yMax) { | ||
2035 | yMax = y; | ||
2036 | } | ||
2037 | } | ||
2038 | } | ||
2039 | } | ||
2040 | if (xMin > clipXMin) { | ||
2041 | clipXMin = xMin; | ||
2042 | } | ||
2043 | if (yMin > clipYMin) { | ||
2044 | clipYMin = yMin; | ||
2045 | } | ||
2046 | if (xMax < clipXMax) { | ||
2047 | clipXMax = xMax; | ||
2048 | } | ||
2049 | if (yMax < clipYMax) { | ||
2050 | clipYMax = yMax; | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | void GfxState::textShift(fouble tx) { | ||
2055 | fouble dx, dy; | ||
2056 | |||
2057 | textTransformDelta(tx, 0, &dx, &dy); | ||
2058 | curX += dx; | ||
2059 | curY += dy; | ||
2060 | } | ||
2061 | |||
2062 | void GfxState::shift(fouble dx, fouble dy) { | ||
2063 | curX += dx; | ||
2064 | curY += dy; | ||
2065 | } | ||
2066 | |||
2067 | GfxState *GfxState::save() { | ||
2068 | GfxState *newState; | ||
2069 | |||
2070 | newState = copy(); | ||
2071 | newState->saved = this; | ||
2072 | return newState; | ||
2073 | } | ||
2074 | |||
2075 | GfxState *GfxState::restore() { | ||
2076 | GfxState *oldState; | ||
2077 | |||
2078 | if (saved) { | ||
2079 | oldState = saved; | ||
2080 | |||
2081 | // these attributes aren't saved/restored by the q/Q operators | ||
2082 | oldState->path = path; | ||
2083 | oldState->curX = curX; | ||
2084 | oldState->curY = curY; | ||
2085 | oldState->lineX = lineX; | ||
2086 | oldState->lineY = lineY; | ||
2087 | |||
2088 | path = NULL; | ||
2089 | saved = NULL; | ||
2090 | delete this; | ||
2091 | |||
2092 | } else { | ||
2093 | oldState = this; | ||
2094 | } | ||
2095 | |||
2096 | return oldState; | ||
2097 | } | ||