comparison mupdf-source/source/pdf/pdf-op-color.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2024 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24 #include "mupdf/pdf.h"
25
26 #include <string.h>
27
28 enum {
29 UNMARKED_STROKE = 1,
30 UNMARKED_FILL = 2
31 };
32
33 typedef struct gstate_stack
34 {
35 struct gstate_stack *next;
36 pdf_obj *cs_stroke;
37 pdf_obj *cs_fill;
38 int unmarked;
39 fz_matrix ctm;
40 } gstate_stack;
41
42 typedef struct resources_stack
43 {
44 struct resources_stack *next;
45 pdf_obj *old_rdb;
46 pdf_obj *new_rdb;
47 } resources_stack;
48
49 typedef struct
50 {
51 pdf_obj *cs;
52 float color[FZ_MAX_COLORS];
53 } cs_color;
54
55 #define MAX_REWRITTEN_NAME 32
56
57 typedef struct
58 {
59 pdf_obj *im_obj;
60 fz_image *after;
61 char name[MAX_REWRITTEN_NAME];
62 } rewritten_image;
63
64 typedef struct
65 {
66 int max;
67 int len;
68 rewritten_image *res;
69 } rewritten_images;
70
71 typedef struct
72 {
73 pdf_obj *before;
74 fz_shade *after;
75 char name[MAX_REWRITTEN_NAME];
76 } rewritten_shade;
77
78 typedef struct
79 {
80 int max;
81 int len;
82 rewritten_shade *res;
83 } rewritten_shades;
84
85 typedef struct
86 {
87 pdf_processor super;
88 pdf_document *doc;
89 int structparents;
90 pdf_processor *chain;
91 pdf_filter_options *global_options;
92 pdf_color_filter_options *options;
93 resources_stack *rstack;
94 gstate_stack *gstate;
95 cs_color *stroke;
96 cs_color *fill;
97 rewritten_images images;
98 rewritten_shades shades;
99 } pdf_color_processor;
100
101 static void
102 push_rewritten_image(fz_context *ctx, pdf_color_processor *p, pdf_obj *im_obj, fz_image *after, char *name)
103 {
104 rewritten_images *list = &p->images;
105
106 if (list->max == list->len)
107 {
108 int new_max = list->max * 2;
109 if (new_max == 0)
110 new_max = 32;
111 list->res = fz_realloc(ctx, list->res, sizeof(*list->res) * new_max);
112 list->max = new_max;
113 }
114 list->res[list->len].im_obj = pdf_keep_obj(ctx, im_obj);
115 list->res[list->len].after = fz_keep_image(ctx, after);
116 memcpy(list->res[list->len].name, name, MAX_REWRITTEN_NAME);
117 list->len++;
118 }
119
120 static fz_image *
121 find_rewritten_image(fz_context *ctx, pdf_color_processor *p, pdf_obj *im_obj, char *name)
122 {
123 rewritten_images *list = &p->images;
124 int i;
125
126 for (i = 0; i < list->len; i++)
127 if (list->res[i].im_obj == im_obj)
128 {
129 memcpy(name, list->res[i].name, MAX_REWRITTEN_NAME);
130 return list->res[i].after;
131 }
132
133 return NULL;
134 }
135
136 static void
137 drop_rewritten_images(fz_context *ctx, pdf_color_processor *p)
138 {
139 rewritten_images *list = &p->images;
140 int i;
141
142 for (i = 0; i < list->len; i++)
143 {
144 pdf_drop_obj(ctx, list->res[i].im_obj);
145 fz_drop_image(ctx, list->res[i].after);
146 }
147 fz_free(ctx, list->res);
148 list->res = NULL;
149 list->len = 0;
150 list->max = 0;
151 }
152
153 static void
154 push_rewritten_shade(fz_context *ctx, pdf_color_processor *p, pdf_obj *before, fz_shade *after, char *name)
155 {
156 rewritten_shades *list = &p->shades;
157
158 if (list->max == list->len)
159 {
160 int new_max = list->max * 2;
161 if (new_max == 0)
162 new_max = 32;
163 list->res = fz_realloc(ctx, list->res, sizeof(*list->res) * new_max);
164 list->max = new_max;
165 }
166 list->res[list->len].before = pdf_keep_obj(ctx, before);
167 list->res[list->len].after = fz_keep_shade(ctx, after);
168 memcpy(list->res[list->len].name, name, MAX_REWRITTEN_NAME);
169 list->len++;
170 }
171
172 static fz_shade *
173 find_rewritten_shade(fz_context *ctx, pdf_color_processor *p, pdf_obj *before, char *name)
174 {
175 rewritten_shades *list = &p->shades;
176 int i;
177
178 for (i = 0; i < list->len; i++)
179 if (list->res[i].before == before)
180 {
181 memcpy(name, list->res[i].name, MAX_REWRITTEN_NAME);
182 return list->res[i].after;
183 }
184
185 return NULL;
186 }
187
188 static void
189 drop_rewritten_shades(fz_context *ctx, pdf_color_processor *p)
190 {
191 rewritten_shades *list = &p->shades;
192 int i;
193
194 for (i = 0; i < list->len; i++)
195 {
196 pdf_drop_obj(ctx, list->res[i].before);
197 fz_drop_shade(ctx, list->res[i].after);
198 }
199 fz_free(ctx, list->res);
200 list->res = NULL;
201 list->len = 0;
202 list->max = 0;
203 }
204
205 static void
206 make_resource_instance(fz_context *ctx, pdf_color_processor *p, pdf_obj *key, const char *prefix, char *buf, int len, pdf_obj *target)
207 {
208 int i;
209
210 /* key gives us our category. Make sure we have such a category. */
211 pdf_obj *res = pdf_dict_get(ctx, p->rstack->new_rdb, key);
212 if (!res)
213 res = pdf_dict_put_dict(ctx, p->rstack->new_rdb, key, 8);
214
215 /* Now check through the category for each possible prefixed name
216 * in turn. */
217 for (i = 1; i < 65536; ++i)
218 {
219 pdf_obj *obj;
220 fz_snprintf(buf, len, "%s%d", prefix, i);
221
222 obj = pdf_dict_gets(ctx, res, buf);
223 if (!obj)
224 {
225 /* We've run out of names. At least that means we haven't
226 * previously added one ourselves. So add it now. */
227 pdf_dict_puts(ctx, res, buf, target);
228 return;
229 }
230 if (pdf_objcmp_resolve(ctx, obj, target) == 0)
231 {
232 /* We've found this one before! */
233 return;
234 }
235 }
236 fz_throw(ctx, FZ_ERROR_LIMIT, "Cannot create unique resource name");
237 }
238
239 static void
240 rewrite_cs(fz_context *ctx, pdf_color_processor *p, pdf_obj *cs_obj, int n, float *color, int stroking)
241 {
242 char new_name[MAX_REWRITTEN_NAME];
243 fz_colorspace *cs = NULL;
244 pdf_pattern *pat = NULL;
245 fz_shade *shade = NULL;
246 int type;
247
248 if (stroking)
249 p->gstate->unmarked &= ~UNMARKED_STROKE;
250 else
251 p->gstate->unmarked &= ~UNMARKED_FILL;
252
253 /* Otherwise, if it's a name, look it up as a colorspace. */
254 if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceGray)) ||
255 pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceCMYK)) ||
256 pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceRGB)) ||
257 pdf_name_eq(ctx, cs_obj, PDF_NAME(Pattern)))
258 {
259 /* These names should not be looked up. */
260 }
261 else if (pdf_is_name(ctx, cs_obj))
262 {
263 /* Any other names should be looked up in the resource dict,
264 * because our rewrite function doesn't have access to that. */
265 cs_obj = pdf_dict_get(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(ColorSpace)), cs_obj);
266 }
267
268 /* Until now, cs_obj has been a borrowed reference. Make it a real one. */
269 pdf_keep_obj(ctx, cs_obj);
270
271 /* Whatever happens, from here on in, we must drop cs_obj. */
272 fz_var(cs);
273 fz_var(pat);
274 fz_var(shade);
275
276 fz_try(ctx)
277 {
278 /* Our gstate always has to contain colorspaces BEFORE rewriting.
279 * Consider the case where we are given a separation space, and
280 * we rewrite it to be RGB. Then we change the 'amount' of that
281 * separation; we can't do that with the RGB value. */
282 if (stroking)
283 {
284 pdf_drop_obj(ctx, p->gstate->cs_stroke);
285 p->gstate->cs_stroke = pdf_keep_obj(ctx, cs_obj);
286 }
287 else
288 {
289 pdf_drop_obj(ctx, p->gstate->cs_fill);
290 p->gstate->cs_fill = pdf_keep_obj(ctx, cs_obj);
291 }
292 /* Now, do any rewriting. This might drop the reference to cs_obj and
293 * return with a different one. */
294 if (p->options->color_rewrite)
295 p->options->color_rewrite(ctx, p->options->opaque, &cs_obj, &n, color);
296
297 /* If we've rewritten it to be a simple name, great! */
298 if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceGray)))
299 {
300 if (stroking)
301 {
302 if (n == 1)
303 p->chain->op_G(ctx, p->chain, color[0]);
304 else
305 p->chain->op_CS(ctx, p->chain, "DeviceGray", fz_device_gray(ctx));
306 }
307 else
308 {
309 if (n == 1)
310 p->chain->op_g(ctx, p->chain, color[0]);
311 else
312 p->chain->op_cs(ctx, p->chain, "DeviceGray", fz_device_gray(ctx));
313 }
314 break;
315 }
316
317 if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceRGB)))
318 {
319 if (stroking)
320 {
321 if (n == 3)
322 p->chain->op_RG(ctx, p->chain, color[0], color[1], color[2]);
323 else
324 p->chain->op_CS(ctx, p->chain, "DeviceRGB", fz_device_rgb(ctx));
325 }
326 else
327 {
328 if (n == 3)
329 p->chain->op_rg(ctx, p->chain, color[0], color[1], color[2]);
330 else
331 p->chain->op_cs(ctx, p->chain, "DeviceRGB", fz_device_rgb(ctx));
332 }
333 break;
334 }
335
336 if (pdf_name_eq(ctx, cs_obj, PDF_NAME(DeviceCMYK)))
337 {
338 if (stroking)
339 {
340 if (n == 4)
341 p->chain->op_K(ctx, p->chain, color[0], color[1], color[2], color[3]);
342 else
343 p->chain->op_CS(ctx, p->chain, "DeviceCMYK", fz_device_cmyk(ctx));
344 }
345 else
346 {
347 if (n == 4)
348 p->chain->op_k(ctx, p->chain, color[0], color[1], color[2], color[3]);
349 else
350 p->chain->op_cs(ctx, p->chain, "DeviceCMYK", fz_device_cmyk(ctx));
351 }
352 break;
353 }
354
355 /* Accept both /Pattern and [ /Pattern ] */
356 if (pdf_name_eq(ctx, cs_obj, PDF_NAME(Pattern)) ||
357 (pdf_array_len(ctx, cs_obj) == 1 && pdf_name_eq(ctx, pdf_array_get(ctx, cs_obj, 0), PDF_NAME(Pattern))))
358 {
359 assert(n == 0);
360 if (stroking)
361 p->chain->op_CS(ctx, p->chain, "Pattern", NULL);
362 else
363 p->chain->op_cs(ctx, p->chain, "Pattern", NULL);
364 break;
365 }
366
367 /* Has it been rewritten to be an array? */
368 if (pdf_is_array(ctx, cs_obj))
369 {
370 /* Make a new entry (or find an existing one), and send that. */
371 make_resource_instance(ctx, p, PDF_NAME(ColorSpace), "CS", new_name, sizeof(new_name), cs_obj);
372
373 cs = pdf_load_colorspace(ctx, cs_obj);
374 if (stroking)
375 p->chain->op_CS(ctx, p->chain, new_name, cs);
376 else
377 p->chain->op_cs(ctx, p->chain, new_name, cs);
378
379 if (n > 0)
380 {
381 if (stroking)
382 p->chain->op_SC_color(ctx, p->chain, n, color);
383 else
384 p->chain->op_sc_color(ctx, p->chain, n, color);
385 }
386 break;
387 }
388
389 /* Has it been rewritten to be a pattern? */
390 type = pdf_dict_get_int(ctx, cs_obj, PDF_NAME(PatternType));
391 if (type < 1 || type > 2)
392 fz_throw(ctx, FZ_ERROR_FORMAT, "Bad PatternType");
393
394 /* Make a new entry (or find an existing one), and send that. */
395 make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), cs_obj);
396
397 if (type == 1)
398 {
399 pat = pdf_load_pattern(ctx, p->doc, cs_obj);
400 if (stroking)
401 p->chain->op_SC_pattern(ctx, p->chain, new_name, pat, n, color);
402 else
403 p->chain->op_sc_pattern(ctx, p->chain, new_name, pat, n, color);
404 break;
405 }
406 else if (type == 2)
407 {
408 shade = pdf_load_shading(ctx, p->doc, cs_obj);
409 if (stroking)
410 p->chain->op_SC_shade(ctx, p->chain, new_name, shade);
411 else
412 p->chain->op_sc_shade(ctx, p->chain, new_name, shade);
413 break;
414 }
415
416 fz_throw(ctx, FZ_ERROR_FORMAT, "Illegal rewritten colorspace");
417 }
418 fz_always(ctx)
419 {
420 fz_drop_shade(ctx, shade);
421 fz_drop_colorspace(ctx, cs);
422 pdf_drop_pattern(ctx, pat);
423 pdf_drop_obj(ctx, cs_obj);
424 }
425 fz_catch(ctx)
426 fz_rethrow(ctx);
427 }
428
429 static void
430 mark_stroke(fz_context *ctx, pdf_color_processor *p)
431 {
432 float zero[FZ_MAX_COLORS] = { 0 };
433
434 rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, zero, 1);
435
436 p->gstate->unmarked &= ~UNMARKED_STROKE;
437 }
438
439 static void
440 mark_fill(fz_context *ctx, pdf_color_processor *p)
441 {
442 float zero[FZ_MAX_COLORS] = { 0 };
443
444 rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, zero, 0);
445
446 p->gstate->unmarked &= ~UNMARKED_FILL;
447 }
448
449 /* general graphics state */
450
451 static void
452 pdf_color_w(fz_context *ctx, pdf_processor *proc, float linewidth)
453 {
454 pdf_color_processor *p = (pdf_color_processor*)proc;
455
456 if (p->chain->op_w)
457 p->chain->op_w(ctx, p->chain, linewidth);
458 }
459
460 static void
461 pdf_color_j(fz_context *ctx, pdf_processor *proc, int linejoin)
462 {
463 pdf_color_processor *p = (pdf_color_processor*)proc;
464
465 if (p->chain->op_j)
466 p->chain->op_j(ctx, p->chain, linejoin);
467 }
468
469 static void
470 pdf_color_J(fz_context *ctx, pdf_processor *proc, int linecap)
471 {
472 pdf_color_processor *p = (pdf_color_processor*)proc;
473
474 if (p->chain->op_J)
475 p->chain->op_J(ctx, p->chain, linecap);
476 }
477
478 static void
479 pdf_color_M(fz_context *ctx, pdf_processor *proc, float miterlimit)
480 {
481 pdf_color_processor *p = (pdf_color_processor*)proc;
482
483 if (p->chain->op_M)
484 p->chain->op_M(ctx, p->chain, miterlimit);
485 }
486
487 static void
488 pdf_color_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase)
489 {
490 pdf_color_processor *p = (pdf_color_processor*)proc;
491
492 if (p->chain->op_d)
493 p->chain->op_d(ctx, p->chain, array, phase);
494 }
495
496 static void
497 pdf_color_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
498 {
499 pdf_color_processor *p = (pdf_color_processor*)proc;
500
501 if (p->chain->op_ri)
502 p->chain->op_ri(ctx, p->chain, intent);
503 }
504
505 static void
506 pdf_color_gs_OP(fz_context *ctx, pdf_processor *proc, int b)
507 {
508 pdf_color_processor *p = (pdf_color_processor*)proc;
509
510 if (p->chain->op_gs_OP)
511 p->chain->op_gs_OP(ctx, p->chain, b);
512 }
513
514 static void
515 pdf_color_gs_op(fz_context *ctx, pdf_processor *proc, int b)
516 {
517 pdf_color_processor *p = (pdf_color_processor*)proc;
518
519 if (p->chain->op_gs_op)
520 p->chain->op_gs_op(ctx, p->chain, b);
521 }
522
523 static void
524 pdf_color_gs_OPM(fz_context *ctx, pdf_processor *proc, int i)
525 {
526 pdf_color_processor *p = (pdf_color_processor*)proc;
527
528 if (p->chain->op_gs_OPM)
529 p->chain->op_gs_OPM(ctx, p->chain, i);
530 }
531
532 static void
533 pdf_color_gs_UseBlackPtComp(fz_context *ctx, pdf_processor *proc, pdf_obj *name)
534 {
535 pdf_color_processor *p = (pdf_color_processor*)proc;
536
537 if (p->chain->op_gs_UseBlackPtComp)
538 p->chain->op_gs_UseBlackPtComp(ctx, p->chain, name);
539 }
540
541 static void
542 pdf_color_i(fz_context *ctx, pdf_processor *proc, float flatness)
543 {
544 pdf_color_processor *p = (pdf_color_processor*)proc;
545
546 if (p->chain->op_i)
547 p->chain->op_i(ctx, p->chain, flatness);
548 }
549
550 static void
551 pdf_color_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
552 {
553 pdf_color_processor *p = (pdf_color_processor*)proc;
554
555 if (p->chain->op_gs_begin)
556 p->chain->op_gs_begin(ctx, p->chain, name, extgstate);
557 }
558
559 static void
560 pdf_color_gs_BM(fz_context *ctx, pdf_processor *proc, const char *blendmode)
561 {
562 pdf_color_processor *p = (pdf_color_processor*)proc;
563
564 if (p->chain->op_gs_BM)
565 p->chain->op_gs_BM(ctx, p->chain, blendmode);
566 }
567
568 static void
569 pdf_color_gs_CA(fz_context *ctx, pdf_processor *proc, float alpha)
570 {
571 pdf_color_processor *p = (pdf_color_processor*)proc;
572
573 if (p->chain->op_gs_CA)
574 p->chain->op_gs_CA(ctx, p->chain, alpha);
575 }
576
577 static void
578 pdf_color_gs_ca(fz_context *ctx, pdf_processor *proc, float alpha)
579 {
580 pdf_color_processor *p = (pdf_color_processor*)proc;
581
582 if (p->chain->op_gs_ca)
583 p->chain->op_gs_ca(ctx, p->chain, alpha);
584 }
585
586 static void
587 pdf_color_gs_SMask(fz_context *ctx, pdf_processor *proc, pdf_obj *smask, fz_colorspace *smask_cs, float *bc, int luminosity, pdf_obj *tr)
588 {
589 pdf_color_processor *p = (pdf_color_processor*)proc;
590
591 if (p->chain->op_gs_SMask)
592 p->chain->op_gs_SMask(ctx, p->chain, smask, smask_cs, bc, luminosity, tr);
593 }
594
595 static void
596 pdf_color_gs_end(fz_context *ctx, pdf_processor *proc)
597 {
598 pdf_color_processor *p = (pdf_color_processor*)proc;
599
600 if (p->chain->op_gs_end)
601 p->chain->op_gs_end(ctx, p->chain);
602 }
603
604 /* special graphics state */
605
606 static void
607 pdf_color_q(fz_context *ctx, pdf_processor *proc)
608 {
609 pdf_color_processor *p = (pdf_color_processor*)proc;
610 gstate_stack *gs = fz_malloc_struct(ctx, gstate_stack);
611
612 gs->next = p->gstate;
613 gs->cs_fill = pdf_keep_obj(ctx, p->gstate->cs_fill);
614 gs->cs_stroke = pdf_keep_obj(ctx, p->gstate->cs_stroke);
615 gs->unmarked = p->gstate->unmarked;
616 gs->ctm = p->gstate->ctm;
617 p->gstate = gs;
618
619 if (p->chain->op_q)
620 p->chain->op_q(ctx, p->chain);
621 }
622
623 static void
624 pdf_color_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
625 {
626 pdf_color_processor *p = (pdf_color_processor*)proc;
627 fz_matrix m;
628
629 m.a = a;
630 m.b = b;
631 m.c = c;
632 m.d = d;
633 m.e = e;
634 m.f = f;
635
636 p->gstate->ctm = fz_concat(m, p->gstate->ctm);
637
638 if (p->chain->op_cm)
639 p->chain->op_cm(ctx, p->chain, a, b, c, d, e, f);
640 }
641
642 /* path construction */
643
644 static void
645 pdf_color_m(fz_context *ctx, pdf_processor *proc, float x, float y)
646 {
647 pdf_color_processor *p = (pdf_color_processor*)proc;
648
649 if (p->chain->op_m)
650 p->chain->op_m(ctx, p->chain, x, y);
651 }
652
653 static void
654 pdf_color_l(fz_context *ctx, pdf_processor *proc, float x, float y)
655 {
656 pdf_color_processor *p = (pdf_color_processor*)proc;
657
658 if (p->chain->op_l)
659 p->chain->op_l(ctx, p->chain, x, y);
660 }
661
662 static void
663 pdf_color_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3)
664 {
665 pdf_color_processor *p = (pdf_color_processor*)proc;
666
667 if (p->chain->op_c)
668 p->chain->op_c(ctx, p->chain, x1, y1, x2, y2, x3, y3);
669 }
670
671 static void
672 pdf_color_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3)
673 {
674 pdf_color_processor *p = (pdf_color_processor*)proc;
675
676 if (p->chain->op_v)
677 p->chain->op_v(ctx, p->chain, x2, y2, x3, y3);
678 }
679
680 static void
681 pdf_color_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3)
682 {
683 pdf_color_processor *p = (pdf_color_processor*)proc;
684
685 if (p->chain->op_y)
686 p->chain->op_y(ctx, p->chain, x1, y1, x3, y3);
687 }
688
689 static void
690 pdf_color_h(fz_context *ctx, pdf_processor *proc)
691 {
692 pdf_color_processor *p = (pdf_color_processor*)proc;
693
694 if (p->chain->op_h)
695 p->chain->op_h(ctx, p->chain);
696 }
697
698 static void
699 pdf_color_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
700 {
701 pdf_color_processor *p = (pdf_color_processor*)proc;
702
703 if (p->chain->op_re)
704 p->chain->op_re(ctx, p->chain, x, y, w, h);
705 }
706
707 /* path painting */
708
709 static void
710 pdf_color_S(fz_context *ctx, pdf_processor *proc)
711 {
712 pdf_color_processor *p = (pdf_color_processor*)proc;
713
714 if (p->gstate->unmarked & UNMARKED_STROKE)
715 mark_stroke(ctx, p);
716
717 if (p->chain->op_S)
718 p->chain->op_S(ctx, p->chain);
719 }
720
721 static void
722 pdf_color_s(fz_context *ctx, pdf_processor *proc)
723 {
724 pdf_color_processor *p = (pdf_color_processor*)proc;
725
726 if (p->gstate->unmarked & UNMARKED_FILL)
727 mark_fill(ctx, p);
728
729 if (p->chain->op_s)
730 p->chain->op_s(ctx, p->chain);
731 }
732
733 static void
734 pdf_color_F(fz_context *ctx, pdf_processor *proc)
735 {
736 pdf_color_processor *p = (pdf_color_processor*)proc;
737
738 if (p->gstate->unmarked & UNMARKED_FILL)
739 mark_fill(ctx, p);
740
741 if (p->chain->op_F)
742 p->chain->op_F(ctx, p->chain);
743 }
744
745 static void
746 pdf_color_f(fz_context *ctx, pdf_processor *proc)
747 {
748 pdf_color_processor *p = (pdf_color_processor*)proc;
749
750 if (p->gstate->unmarked & UNMARKED_FILL)
751 mark_fill(ctx, p);
752
753 if (p->chain->op_f)
754 p->chain->op_f(ctx, p->chain);
755 }
756
757 static void
758 pdf_color_fstar(fz_context *ctx, pdf_processor *proc)
759 {
760 pdf_color_processor *p = (pdf_color_processor*)proc;
761
762 if (p->gstate->unmarked & UNMARKED_FILL)
763 mark_fill(ctx, p);
764
765 if (p->chain->op_fstar)
766 p->chain->op_fstar(ctx, p->chain);
767 }
768
769 static void
770 pdf_color_B(fz_context *ctx, pdf_processor *proc)
771 {
772 pdf_color_processor *p = (pdf_color_processor*)proc;
773
774 if (p->gstate->unmarked & UNMARKED_STROKE)
775 mark_stroke(ctx, p);
776 if (p->gstate->unmarked & UNMARKED_FILL)
777 mark_fill(ctx, p);
778
779 if (p->chain->op_B)
780 p->chain->op_B(ctx, p->chain);
781 }
782
783 static void
784 pdf_color_Bstar(fz_context *ctx, pdf_processor *proc)
785 {
786 pdf_color_processor *p = (pdf_color_processor*)proc;
787
788 if (p->gstate->unmarked & UNMARKED_STROKE)
789 mark_stroke(ctx, p);
790 if (p->gstate->unmarked & UNMARKED_FILL)
791 mark_fill(ctx, p);
792
793 if (p->chain->op_Bstar)
794 p->chain->op_Bstar(ctx, p->chain);
795 }
796
797 static void
798 pdf_color_b(fz_context *ctx, pdf_processor *proc)
799 {
800 pdf_color_processor *p = (pdf_color_processor*)proc;
801
802 if (p->gstate->unmarked & UNMARKED_STROKE)
803 mark_stroke(ctx, p);
804 if (p->gstate->unmarked & UNMARKED_FILL)
805 mark_fill(ctx, p);
806
807 if (p->chain->op_b)
808 p->chain->op_b(ctx, p->chain);
809 }
810
811 static void
812 pdf_color_bstar(fz_context *ctx, pdf_processor *proc)
813 {
814 pdf_color_processor *p = (pdf_color_processor*)proc;
815
816 if (p->gstate->unmarked & UNMARKED_STROKE)
817 mark_stroke(ctx, p);
818 if (p->gstate->unmarked & UNMARKED_FILL)
819 mark_fill(ctx, p);
820
821 if (p->chain->op_bstar)
822 p->chain->op_bstar(ctx, p->chain);
823 }
824
825 static void
826 pdf_color_n(fz_context *ctx, pdf_processor *proc)
827 {
828 pdf_color_processor *p = (pdf_color_processor*)proc;
829
830 if (p->chain->op_n)
831 p->chain->op_n(ctx, p->chain);
832 }
833
834 /* clipping paths */
835
836 static void
837 pdf_color_W(fz_context *ctx, pdf_processor *proc)
838 {
839 pdf_color_processor *p = (pdf_color_processor*)proc;
840
841 if (p->chain->op_W)
842 p->chain->op_W(ctx, p->chain);
843 }
844
845 static void
846 pdf_color_Wstar(fz_context *ctx, pdf_processor *proc)
847 {
848 pdf_color_processor *p = (pdf_color_processor*)proc;
849
850 if (p->chain->op_Wstar)
851 p->chain->op_Wstar(ctx, p->chain);
852 }
853
854 /* text objects */
855
856 static void
857 pdf_color_BT(fz_context *ctx, pdf_processor *proc)
858 {
859 pdf_color_processor *p = (pdf_color_processor*)proc;
860
861 if (p->chain->op_BT)
862 p->chain->op_BT(ctx, p->chain);
863 }
864
865 static void
866 pdf_color_ET(fz_context *ctx, pdf_processor *proc)
867 {
868 pdf_color_processor *p = (pdf_color_processor*)proc;
869
870 if (p->chain->op_ET)
871 p->chain->op_ET(ctx, p->chain);
872 }
873
874 static void
875 pdf_color_Q(fz_context *ctx, pdf_processor *proc)
876 {
877 pdf_color_processor *p = (pdf_color_processor*)proc;
878 gstate_stack *gs = p->gstate;
879
880 p->gstate = gs->next;
881 pdf_drop_obj(ctx, gs->cs_fill);
882 pdf_drop_obj(ctx, gs->cs_stroke);
883
884 fz_try(ctx)
885 if (p->chain->op_Q)
886 p->chain->op_Q(ctx, p->chain);
887 fz_always(ctx)
888 fz_free(ctx, gs);
889 fz_catch(ctx)
890 fz_rethrow(ctx);
891 }
892
893 /* text state */
894
895 static void
896 pdf_color_Tc(fz_context *ctx, pdf_processor *proc, float charspace)
897 {
898 pdf_color_processor *p = (pdf_color_processor*)proc;
899
900 if (p->chain->op_Tc)
901 p->chain->op_Tc(ctx, p->chain, charspace);
902 }
903
904 static void
905 pdf_color_Tw(fz_context *ctx, pdf_processor *proc, float wordspace)
906 {
907 pdf_color_processor *p = (pdf_color_processor*)proc;
908
909 if (p->chain->op_Tw)
910 p->chain->op_Tw(ctx, p->chain, wordspace);
911 }
912
913 static void
914 pdf_color_Tz(fz_context *ctx, pdf_processor *proc, float scale)
915 {
916 pdf_color_processor *p = (pdf_color_processor*)proc;
917
918 if (p->chain->op_Tz)
919 p->chain->op_Tz(ctx, p->chain, scale);
920 }
921
922 static void
923 pdf_color_TL(fz_context *ctx, pdf_processor *proc, float leading)
924 {
925 pdf_color_processor *p = (pdf_color_processor*)proc;
926
927 if (p->chain->op_TL)
928 p->chain->op_TL(ctx, p->chain, leading);
929 }
930
931 static void
932 pdf_color_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size)
933 {
934 pdf_color_processor *p = (pdf_color_processor*)proc;
935
936 if (p->chain->op_Tf)
937 p->chain->op_Tf(ctx, p->chain, name, font, size);
938 }
939
940 static void
941 pdf_color_Tr(fz_context *ctx, pdf_processor *proc, int render)
942 {
943 pdf_color_processor *p = (pdf_color_processor*)proc;
944
945 if (p->chain->op_Tr)
946 p->chain->op_Tr(ctx, p->chain, render);
947 }
948
949 static void
950 pdf_color_Ts(fz_context *ctx, pdf_processor *proc, float rise)
951 {
952 pdf_color_processor *p = (pdf_color_processor*)proc;
953
954 if (p->chain->op_Ts)
955 p->chain->op_Ts(ctx, p->chain, rise);
956 }
957
958 /* text positioning */
959
960 static void
961 pdf_color_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty)
962 {
963 pdf_color_processor *p = (pdf_color_processor*)proc;
964
965 if (p->chain->op_Td)
966 p->chain->op_Td(ctx, p->chain, tx, ty);
967 }
968
969 static void
970 pdf_color_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty)
971 {
972 pdf_color_processor *p = (pdf_color_processor*)proc;
973
974 if (p->chain->op_TD)
975 p->chain->op_TD(ctx, p->chain, tx, ty);
976 }
977
978 static void
979 pdf_color_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
980 {
981 pdf_color_processor *p = (pdf_color_processor*)proc;
982
983 if (p->chain->op_Tm)
984 p->chain->op_Tm(ctx, p->chain, a, b, c, d, e, f);
985 }
986
987 static void
988 pdf_color_Tstar(fz_context *ctx, pdf_processor *proc)
989 {
990 pdf_color_processor *p = (pdf_color_processor*)proc;
991
992 if (p->chain->op_Tstar)
993 p->chain->op_Tstar(ctx, p->chain);
994 }
995
996 /* text showing */
997
998 static void
999 pdf_color_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array)
1000 {
1001 pdf_color_processor *p = (pdf_color_processor*)proc;
1002
1003 /* FIXME: We could optimise this if we knew the Tr, maybe. */
1004 if (p->gstate->unmarked & UNMARKED_STROKE)
1005 mark_stroke(ctx, p);
1006 if (p->gstate->unmarked & UNMARKED_FILL)
1007 mark_fill(ctx, p);
1008
1009 if (p->chain->op_TJ)
1010 p->chain->op_TJ(ctx, p->chain, array);
1011 }
1012
1013 static void
1014 pdf_color_Tj(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1015 {
1016 pdf_color_processor *p = (pdf_color_processor*)proc;
1017
1018 /* FIXME: We could optimise this if we knew the Tr, maybe. */
1019 if (p->gstate->unmarked & UNMARKED_STROKE)
1020 mark_stroke(ctx, p);
1021 if (p->gstate->unmarked & UNMARKED_FILL)
1022 mark_fill(ctx, p);
1023
1024 if (p->chain->op_Tj)
1025 p->chain->op_Tj(ctx, p->chain, str, len);
1026 }
1027
1028 static void
1029 pdf_color_squote(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1030 {
1031 pdf_color_processor *p = (pdf_color_processor*)proc;
1032
1033 /* FIXME: We could optimise this if we knew the Tr, maybe. */
1034 if (p->gstate->unmarked & UNMARKED_STROKE)
1035 mark_stroke(ctx, p);
1036 if (p->gstate->unmarked & UNMARKED_FILL)
1037 mark_fill(ctx, p);
1038
1039 if (p->chain->op_squote)
1040 p->chain->op_squote(ctx, p->chain, str, len);
1041 }
1042
1043 static void
1044 pdf_color_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, size_t len)
1045 {
1046 pdf_color_processor *p = (pdf_color_processor*)proc;
1047
1048 /* FIXME: We could optimise this if we knew the Tr, maybe. */
1049 if (p->gstate->unmarked & UNMARKED_STROKE)
1050 mark_stroke(ctx, p);
1051 if (p->gstate->unmarked & UNMARKED_FILL)
1052 mark_fill(ctx, p);
1053
1054 if (p->chain->op_dquote)
1055 p->chain->op_dquote(ctx, p->chain, aw, ac, str, len);
1056 }
1057
1058 /* type 3 fonts */
1059
1060 static void
1061 pdf_color_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy)
1062 {
1063 pdf_color_processor *p = (pdf_color_processor*)proc;
1064
1065 if (p->chain->op_d0)
1066 p->chain->op_d0(ctx, p->chain, wx, wy);
1067 }
1068
1069 static void
1070 pdf_color_d1(fz_context *ctx, pdf_processor *proc, float wx, float wy, float llx, float lly, float urx, float ury)
1071 {
1072 pdf_color_processor *p = (pdf_color_processor*)proc;
1073
1074 if (p->chain->op_d1)
1075 p->chain->op_d1(ctx, p->chain, wx, wy, llx, lly, urx, ury);
1076 }
1077
1078 /* color */
1079
1080 static void
1081 pdf_color_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1082 {
1083 pdf_color_processor *p = (pdf_color_processor *)proc;
1084 pdf_obj *cs_obj = pdf_new_name(ctx, name);
1085 float color[FZ_MAX_COLORS] = { 1 };
1086
1087 fz_try(ctx)
1088 rewrite_cs(ctx, p, cs_obj, 0, color, 1);
1089 fz_always(ctx)
1090 pdf_drop_obj(ctx, cs_obj);
1091 fz_catch(ctx)
1092 fz_rethrow(ctx);
1093 }
1094
1095 static void
1096 pdf_color_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1097 {
1098 pdf_color_processor *p = (pdf_color_processor*)proc;
1099 pdf_obj *cs_obj = pdf_new_name(ctx, name);
1100 float color[FZ_MAX_COLORS] = { 1 };
1101
1102 fz_try(ctx)
1103 rewrite_cs(ctx, p, cs_obj, 0, color, 0);
1104 fz_always(ctx)
1105 pdf_drop_obj(ctx, cs_obj);
1106 fz_catch(ctx)
1107 fz_rethrow(ctx);
1108 }
1109
1110 static void
1111 pdf_color_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1112 {
1113 pdf_color_processor *p = (pdf_color_processor*)proc;
1114 float local_color[FZ_MAX_COLORS] = { 0 };
1115 pdf_obj *cs_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name);
1116
1117 memcpy(local_color, color, sizeof(float) * n);
1118 rewrite_cs(ctx, p, cs_obj, n, local_color, 1);
1119 }
1120
1121 static void
1122 pdf_color_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1123 {
1124 pdf_color_processor *p = (pdf_color_processor*)proc;
1125 float local_color[FZ_MAX_COLORS] = { 0 };
1126 pdf_obj *cs_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name);
1127
1128 memcpy(local_color, color, sizeof(float) * n);
1129 rewrite_cs(ctx, p, cs_obj, n, local_color, 0);
1130 }
1131
1132 static void
1133 pdf_color_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1134 {
1135 pdf_color_processor *p = (pdf_color_processor*)proc;
1136 pdf_obj *orig;
1137 pdf_obj *dict = NULL;
1138 pdf_obj *dict2 = NULL;
1139 char new_name[MAX_REWRITTEN_NAME];
1140 pdf_obj *rewritten;
1141 fz_shade *new_shade = NULL;
1142
1143 if (p->options->shade_rewrite == NULL)
1144 {
1145 /* Must copy shading over to new resources dict. */
1146 pdf_obj *old_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name);
1147 pdf_obj *new_shading_dict = pdf_dict_get(ctx, p->rstack->new_rdb, PDF_NAME(Shading));
1148 if (new_shading_dict == NULL)
1149 pdf_dict_put_drop(ctx, p->rstack->new_rdb, PDF_NAME(Shading), new_shading_dict = pdf_new_dict(ctx, p->doc, 4));
1150 pdf_dict_puts(ctx, new_shading_dict, name, old_obj);
1151
1152 if (p->chain->op_SC_shade)
1153 p->chain->op_SC_shade(ctx, p->chain, name, shade);
1154 return;
1155 }
1156
1157 orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name);
1158 orig = pdf_dict_get(ctx, orig, PDF_NAME(Shading));
1159
1160 new_shade = find_rewritten_shade(ctx, p, orig, new_name);
1161 if (new_shade)
1162 {
1163 /* Must copy shading over to new resources dict. */
1164 pdf_obj *old_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name);
1165 pdf_obj *new_shading_dict = pdf_dict_get(ctx, p->rstack->new_rdb, PDF_NAME(Shading));
1166 if (new_shading_dict == NULL)
1167 pdf_dict_put_drop(ctx, p->rstack->new_rdb, PDF_NAME(Shading), new_shading_dict = pdf_new_dict(ctx, p->doc, 4));
1168 pdf_dict_puts(ctx, new_shading_dict, name, old_obj);
1169
1170 if (p->chain->op_SC_shade)
1171 p->chain->op_SC_shade(ctx, p->chain, new_name, new_shade);
1172 return;
1173 }
1174
1175 rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque);
1176
1177 fz_var(new_shade);
1178 fz_var(dict);
1179 fz_var(dict2);
1180
1181 fz_try(ctx)
1182 {
1183 dict = pdf_new_dict(ctx, p->doc, 1);
1184 pdf_dict_put_int(ctx, dict, PDF_NAME(PatternType), 2);
1185 pdf_dict_put(ctx, dict, PDF_NAME(Shading), rewritten);
1186 dict2 = pdf_add_object(ctx, p->doc, dict);
1187 make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), dict2);
1188
1189 new_shade = pdf_load_shading(ctx, p->doc, rewritten);
1190
1191 /* Remember that we've done this one before. */
1192 push_rewritten_shade(ctx, p, orig, new_shade, new_name);
1193
1194 if (p->chain->op_sh)
1195 p->chain->op_SC_shade(ctx, p->chain, new_name, new_shade);
1196 }
1197 fz_always(ctx)
1198 {
1199 fz_drop_shade(ctx, new_shade);
1200 pdf_drop_obj(ctx, rewritten);
1201 pdf_drop_obj(ctx, dict);
1202 pdf_drop_obj(ctx, dict2);
1203 }
1204 fz_catch(ctx)
1205 fz_rethrow(ctx);
1206 }
1207
1208 static void
1209 pdf_color_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1210 {
1211 pdf_color_processor *p = (pdf_color_processor*)proc;
1212 pdf_obj *orig;
1213 pdf_obj *dict = NULL;
1214 pdf_obj *dict2 = NULL;
1215 char new_name[MAX_REWRITTEN_NAME];
1216 pdf_obj *rewritten;
1217 fz_shade *new_shade = NULL;
1218
1219 if (p->options->shade_rewrite == NULL)
1220 {
1221 /* Must copy shading over to new resources dict. */
1222 pdf_obj *old_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name);
1223 pdf_obj *new_shading_dict = pdf_dict_get(ctx, p->rstack->new_rdb, PDF_NAME(Shading));
1224 if (new_shading_dict == NULL)
1225 pdf_dict_put_drop(ctx, p->rstack->new_rdb, PDF_NAME(Shading), new_shading_dict = pdf_new_dict(ctx, p->doc, 4));
1226 pdf_dict_puts(ctx, new_shading_dict, name, old_obj);
1227
1228 if (p->chain->op_sc_shade)
1229 p->chain->op_sc_shade(ctx, p->chain, name, shade);
1230 return;
1231 }
1232
1233 orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Pattern)), name);
1234 orig = pdf_dict_get(ctx, orig, PDF_NAME(Shading));
1235
1236 new_shade = find_rewritten_shade(ctx, p, orig, new_name);
1237 if (new_shade)
1238 {
1239 if (p->chain->op_sc_shade)
1240 p->chain->op_sc_shade(ctx, p->chain, new_name, new_shade);
1241 return;
1242 }
1243
1244 rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque);
1245
1246 fz_var(new_shade);
1247 fz_var(dict);
1248 fz_var(dict2);
1249
1250 fz_try(ctx)
1251 {
1252 dict = pdf_new_dict(ctx, p->doc, 1);
1253 pdf_dict_put_int(ctx, dict, PDF_NAME(PatternType), 2);
1254 pdf_dict_put(ctx, dict, PDF_NAME(Shading), rewritten);
1255 dict2 = pdf_add_object(ctx, p->doc, dict);
1256 make_resource_instance(ctx, p, PDF_NAME(Pattern), "Pa", new_name, sizeof(new_name), dict2);
1257
1258 new_shade = pdf_load_shading(ctx, p->doc, rewritten);
1259
1260 /* Remember that we've done this one before. */
1261 push_rewritten_shade(ctx, p, orig, new_shade, new_name);
1262
1263 if (p->chain->op_sh)
1264 p->chain->op_sc_shade(ctx, p->chain, new_name, new_shade);
1265 }
1266 fz_always(ctx)
1267 {
1268 fz_drop_shade(ctx, new_shade);
1269 pdf_drop_obj(ctx, rewritten);
1270 pdf_drop_obj(ctx, dict);
1271 pdf_drop_obj(ctx, dict2);
1272 }
1273 fz_catch(ctx)
1274 fz_rethrow(ctx);
1275 }
1276
1277 static void
1278 pdf_color_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1279 {
1280 pdf_color_processor *p = (pdf_color_processor*)proc;
1281 float local_color[FZ_MAX_COLORS] = { 0 };
1282 pdf_obj *cs_obj = p->gstate->cs_stroke;
1283
1284 memcpy(local_color, color, sizeof(float) * n);
1285 rewrite_cs(ctx, p, cs_obj, n, local_color, 1);
1286 }
1287
1288 static void
1289 pdf_color_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1290 {
1291 pdf_color_processor *p = (pdf_color_processor*)proc;
1292 float local_color[FZ_MAX_COLORS] = { 0 };
1293 pdf_obj *cs_obj = p->gstate->cs_fill;
1294
1295 memcpy(local_color, color, sizeof(float) * n);
1296 rewrite_cs(ctx, p, cs_obj, n, local_color, 0);
1297 }
1298
1299 static void
1300 pdf_color_G(fz_context *ctx, pdf_processor *proc, float g)
1301 {
1302 pdf_color_processor *p = (pdf_color_processor*)proc;
1303 float local_color[FZ_MAX_COLORS] = { g };
1304
1305 rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, local_color, 1);
1306 }
1307
1308 static void
1309 pdf_color_g(fz_context *ctx, pdf_processor *proc, float g)
1310 {
1311 pdf_color_processor *p = (pdf_color_processor*)proc;
1312 float local_color[FZ_MAX_COLORS] = { g };
1313
1314 rewrite_cs(ctx, p, PDF_NAME(DeviceGray), 1, local_color, 0);
1315 }
1316
1317 static void
1318 pdf_color_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1319 {
1320 pdf_color_processor *p = (pdf_color_processor*)proc;
1321 float local_color[FZ_MAX_COLORS] = { r, g, b };
1322
1323 rewrite_cs(ctx, p, PDF_NAME(DeviceRGB), 3, local_color, 1);
1324 }
1325
1326 static void
1327 pdf_color_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1328 {
1329 pdf_color_processor *p = (pdf_color_processor*)proc;
1330 float local_color[FZ_MAX_COLORS] = { r, g, b };
1331
1332 rewrite_cs(ctx, p, PDF_NAME(DeviceRGB), 3, local_color, 0);
1333 }
1334
1335 static void
1336 pdf_color_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1337 {
1338 pdf_color_processor *p = (pdf_color_processor*)proc;
1339 float local_color[FZ_MAX_COLORS] = { c, m, y, k };
1340
1341 rewrite_cs(ctx, p, PDF_NAME(DeviceCMYK), 4, local_color, 1);
1342 }
1343
1344 static void
1345 pdf_color_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1346 {
1347 pdf_color_processor *p = (pdf_color_processor*)proc;
1348
1349 float local_color[FZ_MAX_COLORS] = { c, m, y, k };
1350
1351 rewrite_cs(ctx, p, PDF_NAME(DeviceCMYK), 4, local_color, 0);
1352 }
1353
1354 /* shadings, images, xobjects */
1355
1356 static void
1357 pdf_color_BI(fz_context *ctx, pdf_processor *proc, fz_image *image, const char *colorspace)
1358 {
1359 pdf_color_processor *p = (pdf_color_processor*)proc;
1360
1361 if (image->imagemask)
1362 {
1363 /* Imagemasks require the color to have been set. */
1364 if (p->gstate->unmarked & UNMARKED_FILL)
1365 mark_fill(ctx, p);
1366 }
1367
1368 fz_keep_image(ctx, image);
1369 if (p->options->image_rewrite)
1370 p->options->image_rewrite(ctx, p->options->opaque, &image, p->gstate->ctm, NULL);
1371
1372 if (p->chain->op_BI)
1373 p->chain->op_BI(ctx, p->chain, image, colorspace);
1374 fz_drop_image(ctx, image);
1375 }
1376
1377 static void
1378 pdf_color_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1379 {
1380 pdf_color_processor *p = (pdf_color_processor*)proc;
1381 pdf_obj *orig;
1382 char new_name[MAX_REWRITTEN_NAME];
1383 pdf_obj *rewritten;
1384 fz_shade *new_shade = NULL;
1385
1386 if (p->options->shade_rewrite == NULL)
1387 {
1388 /* Must copy shading over to new resources dict. */
1389 pdf_obj *old_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name);
1390 pdf_obj *new_shading_dict = pdf_dict_get(ctx, p->rstack->new_rdb, PDF_NAME(Shading));
1391 if (new_shading_dict == NULL)
1392 pdf_dict_put_drop(ctx, p->rstack->new_rdb, PDF_NAME(Shading), new_shading_dict = pdf_new_dict(ctx, p->doc, 4));
1393 pdf_dict_puts(ctx, new_shading_dict, name, old_obj);
1394
1395 if (p->chain->op_sh)
1396 p->chain->op_sh(ctx, p->chain, name, shade);
1397 return;
1398 }
1399
1400 orig = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(Shading)), name);
1401
1402 new_shade = find_rewritten_shade(ctx, p, orig, new_name);
1403 if (new_shade)
1404 {
1405 if (p->chain->op_sh)
1406 p->chain->op_sh(ctx, p->chain, new_name, new_shade);
1407 return;
1408 }
1409
1410 rewritten = pdf_recolor_shade(ctx, orig, p->options->shade_rewrite, p->options->opaque);
1411
1412 fz_var(new_shade);
1413
1414 fz_try(ctx)
1415 {
1416 make_resource_instance(ctx, p, PDF_NAME(Shading), "Sh", new_name, sizeof(new_name), rewritten);
1417
1418 new_shade = pdf_load_shading(ctx, p->doc, rewritten);
1419
1420 /* Remember that we've done this one before. */
1421 push_rewritten_shade(ctx, p, orig, new_shade, new_name);
1422
1423 if (p->chain->op_sh)
1424 p->chain->op_sh(ctx, p->chain, new_name, new_shade);
1425 }
1426 fz_always(ctx)
1427 {
1428 fz_drop_shade(ctx, new_shade);
1429 pdf_drop_obj(ctx, rewritten);
1430 }
1431 fz_catch(ctx)
1432 fz_rethrow(ctx);
1433 }
1434
1435 static void
1436 pdf_color_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image)
1437 {
1438 pdf_color_processor *p = (pdf_color_processor*)proc;
1439 fz_image *orig = image;
1440 char new_name[MAX_REWRITTEN_NAME];
1441 pdf_obj *im_obj = pdf_dict_gets(ctx, pdf_dict_get(ctx, p->rstack->old_rdb, PDF_NAME(XObject)), name);
1442
1443 /* Have we done this one before? */
1444 if (!p->options->repeated_image_rewrite)
1445 {
1446 image = find_rewritten_image(ctx, p, im_obj, new_name);
1447 if (image)
1448 {
1449 if (p->chain->op_Do_image)
1450 p->chain->op_Do_image(ctx, p->chain, new_name, image);
1451 return;
1452 }
1453 }
1454
1455 image = orig;
1456 fz_keep_image(ctx, image);
1457 pdf_keep_obj(ctx, im_obj);
1458
1459 fz_var(im_obj);
1460 fz_try(ctx)
1461 {
1462
1463 if (image->imagemask)
1464 {
1465 /* Imagemasks require the color to have been set. */
1466 if (p->gstate->unmarked & UNMARKED_FILL)
1467 mark_fill(ctx, p);
1468 }
1469 else
1470 {
1471 if (p->options->image_rewrite)
1472 p->options->image_rewrite(ctx, p->options->opaque, &image, p->gstate->ctm, im_obj);
1473 }
1474
1475 /* If it's been rewritten add the new one, otherwise copy the old one across. */
1476 if (image != orig)
1477 {
1478 pdf_drop_obj(ctx, im_obj);
1479 im_obj = NULL;
1480 im_obj = pdf_add_image(ctx, p->doc, image);
1481 }
1482
1483 make_resource_instance(ctx, p, PDF_NAME(XObject), "Im", new_name, sizeof(new_name), im_obj);
1484
1485 if (!p->options->repeated_image_rewrite)
1486 {
1487 /* Remember that we've done this one before. */
1488 push_rewritten_image(ctx, p, im_obj, image, new_name);
1489 }
1490
1491 if (p->chain->op_Do_image)
1492 p->chain->op_Do_image(ctx, p->chain, new_name, image);
1493 }
1494 fz_always(ctx)
1495 {
1496 pdf_drop_obj(ctx, im_obj);
1497 fz_drop_image(ctx, image);
1498 }
1499 fz_catch(ctx)
1500 fz_rethrow(ctx);
1501 }
1502
1503 static void
1504 pdf_color_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj)
1505 {
1506 pdf_color_processor *p = (pdf_color_processor*)proc;
1507 char new_name[MAX_REWRITTEN_NAME];
1508 pdf_obj *xres;
1509 pdf_obj *new_xres = NULL;
1510
1511 fz_var(new_xres);
1512
1513 /* FIXME: Ideally we'd look at p->global_options->instance_forms here
1514 * to avoid flattening all the XObjects. This is non-trivial, and
1515 * currently incomplete, hence disabled. We have to find some way to
1516 * tell the underlying filters (in particular the output filter) that
1517 * we are in a new XObject (so the output filter can start a new buffer).
1518 * Maybe it could look at p->global_options->instance_forms too on a
1519 * push/pop of the resources? For now, let's just leave it disabled. */
1520 if (0 && p->global_options->instance_forms)
1521 {
1522 make_resource_instance(ctx, p, PDF_NAME(XObject), "Xo", new_name, sizeof(new_name), xobj);
1523
1524 xres = pdf_xobject_resources(ctx, xobj);
1525 fz_try(ctx)
1526 pdf_process_contents(ctx, (pdf_processor *)p, p->doc, xres, xobj, NULL, &new_xres);
1527 fz_catch(ctx)
1528 {
1529 pdf_drop_obj(ctx, new_xres);
1530 fz_rethrow(ctx);
1531 }
1532
1533 pdf_dict_put_drop(ctx, xobj, PDF_NAME(Resources), new_xres);
1534
1535 if (p->chain->op_Do_form)
1536 p->chain->op_Do_form(ctx, p->chain, new_name, xobj);
1537 }
1538 else
1539 {
1540 /* In this case, we just copy the XObject across (renaming it). Our caller will arrange to
1541 * filter it. */
1542 make_resource_instance(ctx, p, PDF_NAME(XObject), "Xo", new_name, sizeof(new_name), xobj);
1543 if (p->chain->op_Do_form)
1544 p->chain->op_Do_form(ctx, p->chain, new_name, xobj);
1545 }
1546 }
1547
1548 /* marked content */
1549
1550 static void
1551 pdf_color_MP(fz_context *ctx, pdf_processor *proc, const char *tag)
1552 {
1553 pdf_color_processor *p = (pdf_color_processor*)proc;
1554
1555 if (p->chain->op_MP)
1556 p->chain->op_MP(ctx, p->chain, tag);
1557 }
1558
1559 static void
1560 pdf_color_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1561 {
1562 pdf_color_processor *p = (pdf_color_processor*)proc;
1563
1564 if (p->chain->op_DP)
1565 p->chain->op_DP(ctx, p->chain, tag, raw, cooked);
1566 }
1567
1568 static void
1569 pdf_color_BMC(fz_context *ctx, pdf_processor *proc, const char *tag)
1570 {
1571 pdf_color_processor *p = (pdf_color_processor*)proc;
1572
1573 if (p->chain->op_BMC)
1574 p->chain->op_BMC(ctx, p->chain, tag);
1575 }
1576
1577 static void
1578 pdf_color_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1579 {
1580 pdf_color_processor *p = (pdf_color_processor*)proc;
1581
1582 if (p->chain->op_BDC)
1583 p->chain->op_BDC(ctx, p->chain, tag, raw, cooked);
1584 }
1585
1586 static void
1587 pdf_color_EMC(fz_context *ctx, pdf_processor *proc)
1588 {
1589 pdf_color_processor *p = (pdf_color_processor*)proc;
1590
1591 if (p->chain->op_EMC)
1592 p->chain->op_EMC(ctx, p->chain);
1593 }
1594
1595 /* compatibility */
1596
1597 static void
1598 pdf_color_BX(fz_context *ctx, pdf_processor *proc)
1599 {
1600 pdf_color_processor *p = (pdf_color_processor*)proc;
1601
1602 if (p->chain->op_BX)
1603 p->chain->op_BX(ctx, p->chain);
1604 }
1605
1606 static void
1607 pdf_color_EX(fz_context *ctx, pdf_processor *proc)
1608 {
1609 pdf_color_processor *p = (pdf_color_processor*)proc;
1610
1611 if (p->chain->op_EX)
1612 p->chain->op_EX(ctx, p->chain);
1613 }
1614
1615 static void
1616 pdf_color_END(fz_context *ctx, pdf_processor *proc)
1617 {
1618 pdf_color_processor *p = (pdf_color_processor*)proc;
1619
1620 if (p->chain->op_END)
1621 p->chain->op_END(ctx, p->chain);
1622 }
1623
1624 static void
1625 pdf_close_color_processor(fz_context *ctx, pdf_processor *proc)
1626 {
1627 pdf_color_processor *p = (pdf_color_processor*)proc;
1628
1629 pdf_close_processor(ctx, p->chain);
1630 }
1631
1632 static void
1633 pdf_drop_color_processor(fz_context *ctx, pdf_processor *proc)
1634 {
1635 pdf_color_processor *p = (pdf_color_processor*)proc;
1636 gstate_stack *gs = p->gstate;
1637
1638 while (gs)
1639 {
1640 gstate_stack *gs_next = gs->next;
1641
1642 pdf_drop_obj(ctx, gs->cs_fill);
1643 pdf_drop_obj(ctx, gs->cs_stroke);
1644 fz_free(ctx, gs);
1645 gs = gs_next;
1646 }
1647 drop_rewritten_images(ctx, p);
1648 drop_rewritten_shades(ctx, p);
1649
1650 pdf_drop_document(ctx, p->doc);
1651 }
1652
1653 static void
1654 pdf_color_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res)
1655 {
1656 pdf_color_processor *p = (pdf_color_processor*)proc;
1657 resources_stack *stk = fz_malloc_struct(ctx, resources_stack);
1658 pdf_obj *obj;
1659
1660 p->gstate->unmarked = UNMARKED_STROKE | UNMARKED_FILL;
1661
1662 stk->next = p->rstack;
1663 p->rstack = stk;
1664 fz_try(ctx)
1665 {
1666 stk->old_rdb = pdf_keep_obj(ctx, res);
1667 /* At the moment we know that we'll always be flattening XObjects.
1668 * So only the top level 'push' makes a new resource dict. Any
1669 * subsequent one will share the previous levels one. */
1670 if (stk->next)
1671 stk->new_rdb = pdf_keep_obj(ctx, stk->next->new_rdb);
1672 else
1673 stk->new_rdb = pdf_new_dict(ctx, p->doc, 1);
1674
1675 obj = pdf_dict_get(ctx, res, PDF_NAME(Properties));
1676 if (obj)
1677 pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(Properties), obj);
1678 obj = pdf_dict_get(ctx, res, PDF_NAME(ExtGState));
1679 if (obj)
1680 pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(ExtGState), obj);
1681 obj = pdf_dict_get(ctx, res, PDF_NAME(Font));
1682 if (obj)
1683 pdf_dict_put(ctx, stk->new_rdb, PDF_NAME(Font), obj);
1684
1685 pdf_processor_push_resources(ctx, p->chain, stk->new_rdb);
1686 }
1687 fz_catch(ctx)
1688 {
1689 pdf_drop_obj(ctx, stk->old_rdb);
1690 pdf_drop_obj(ctx, stk->new_rdb);
1691 fz_free(ctx, stk);
1692 p->rstack = stk->next;
1693 fz_rethrow(ctx);
1694 }
1695 }
1696
1697 static pdf_obj *
1698 pdf_color_pop_resources(fz_context *ctx, pdf_processor *proc)
1699 {
1700 pdf_color_processor *p = (pdf_color_processor*)proc;
1701 resources_stack *stk = p->rstack;
1702
1703 p->rstack = stk->next;
1704 pdf_drop_obj(ctx, stk->old_rdb);
1705 pdf_drop_obj(ctx, stk->new_rdb);
1706 fz_free(ctx, stk);
1707
1708 return pdf_processor_pop_resources(ctx, p->chain);
1709 }
1710
1711 static void
1712 pdf_reset_color_processor(fz_context *ctx, pdf_processor *proc)
1713 {
1714 pdf_color_processor *p = (pdf_color_processor*)proc;
1715
1716 pdf_reset_processor(ctx, p->chain);
1717 }
1718
1719 pdf_processor *
1720 pdf_new_color_filter(
1721 fz_context *ctx,
1722 pdf_document *doc,
1723 pdf_processor *chain,
1724 int struct_parents,
1725 fz_matrix transform,
1726 pdf_filter_options *global_options,
1727 void *options_)
1728 {
1729 pdf_color_processor *proc = pdf_new_processor(ctx, sizeof * proc);
1730 pdf_color_filter_options *options = (pdf_color_filter_options *)options_;
1731
1732 proc->super.close_processor = pdf_close_color_processor;
1733 proc->super.drop_processor = pdf_drop_color_processor;
1734 proc->super.reset_processor = pdf_reset_color_processor;
1735
1736 proc->super.push_resources = pdf_color_push_resources;
1737 proc->super.pop_resources = pdf_color_pop_resources;
1738
1739 /* general graphics state */
1740 proc->super.op_w = pdf_color_w;
1741 proc->super.op_j = pdf_color_j;
1742 proc->super.op_J = pdf_color_J;
1743 proc->super.op_M = pdf_color_M;
1744 proc->super.op_d = pdf_color_d;
1745 proc->super.op_ri = pdf_color_ri;
1746 proc->super.op_i = pdf_color_i;
1747 proc->super.op_gs_begin = pdf_color_gs_begin;
1748 proc->super.op_gs_end = pdf_color_gs_end;
1749
1750 /* transparency graphics state */
1751 proc->super.op_gs_BM = pdf_color_gs_BM;
1752 proc->super.op_gs_CA = pdf_color_gs_CA;
1753 proc->super.op_gs_ca = pdf_color_gs_ca;
1754 proc->super.op_gs_SMask = pdf_color_gs_SMask;
1755
1756 /* special graphics state */
1757 proc->super.op_q = pdf_color_q;
1758 proc->super.op_Q = pdf_color_Q;
1759 proc->super.op_cm = pdf_color_cm;
1760
1761 /* path construction */
1762 proc->super.op_m = pdf_color_m;
1763 proc->super.op_l = pdf_color_l;
1764 proc->super.op_c = pdf_color_c;
1765 proc->super.op_v = pdf_color_v;
1766 proc->super.op_y = pdf_color_y;
1767 proc->super.op_h = pdf_color_h;
1768 proc->super.op_re = pdf_color_re;
1769
1770 /* path painting */
1771 proc->super.op_S = pdf_color_S;
1772 proc->super.op_s = pdf_color_s;
1773 proc->super.op_F = pdf_color_F;
1774 proc->super.op_f = pdf_color_f;
1775 proc->super.op_fstar = pdf_color_fstar;
1776 proc->super.op_B = pdf_color_B;
1777 proc->super.op_Bstar = pdf_color_Bstar;
1778 proc->super.op_b = pdf_color_b;
1779 proc->super.op_bstar = pdf_color_bstar;
1780 proc->super.op_n = pdf_color_n;
1781
1782 /* clipping paths */
1783 proc->super.op_W = pdf_color_W;
1784 proc->super.op_Wstar = pdf_color_Wstar;
1785
1786 /* text objects */
1787 proc->super.op_BT = pdf_color_BT;
1788 proc->super.op_ET = pdf_color_ET;
1789
1790 /* text state */
1791 proc->super.op_Tc = pdf_color_Tc;
1792 proc->super.op_Tw = pdf_color_Tw;
1793 proc->super.op_Tz = pdf_color_Tz;
1794 proc->super.op_TL = pdf_color_TL;
1795 proc->super.op_Tf = pdf_color_Tf;
1796 proc->super.op_Tr = pdf_color_Tr;
1797 proc->super.op_Ts = pdf_color_Ts;
1798
1799 /* text positioning */
1800 proc->super.op_Td = pdf_color_Td;
1801 proc->super.op_TD = pdf_color_TD;
1802 proc->super.op_Tm = pdf_color_Tm;
1803 proc->super.op_Tstar = pdf_color_Tstar;
1804
1805 /* text showing */
1806 proc->super.op_TJ = pdf_color_TJ;
1807 proc->super.op_Tj = pdf_color_Tj;
1808 proc->super.op_squote = pdf_color_squote;
1809 proc->super.op_dquote = pdf_color_dquote;
1810
1811 /* type 3 fonts */
1812 proc->super.op_d0 = pdf_color_d0;
1813 proc->super.op_d1 = pdf_color_d1;
1814
1815 /* color */
1816 proc->super.op_CS = pdf_color_CS;
1817 proc->super.op_cs = pdf_color_cs;
1818 proc->super.op_SC_color = pdf_color_SC_color;
1819 proc->super.op_sc_color = pdf_color_sc_color;
1820 proc->super.op_SC_pattern = pdf_color_SC_pattern;
1821 proc->super.op_sc_pattern = pdf_color_sc_pattern;
1822 proc->super.op_SC_shade = pdf_color_SC_shade;
1823 proc->super.op_sc_shade = pdf_color_sc_shade;
1824
1825 proc->super.op_G = pdf_color_G;
1826 proc->super.op_g = pdf_color_g;
1827 proc->super.op_RG = pdf_color_RG;
1828 proc->super.op_rg = pdf_color_rg;
1829 proc->super.op_K = pdf_color_K;
1830 proc->super.op_k = pdf_color_k;
1831
1832 /* shadings, images, xobjects */
1833 proc->super.op_BI = pdf_color_BI;
1834 proc->super.op_sh = pdf_color_sh;
1835 proc->super.op_Do_image = pdf_color_Do_image;
1836 proc->super.op_Do_form = pdf_color_Do_form;
1837
1838 /* marked content */
1839 proc->super.op_MP = pdf_color_MP;
1840 proc->super.op_DP = pdf_color_DP;
1841 proc->super.op_BMC = pdf_color_BMC;
1842 proc->super.op_BDC = pdf_color_BDC;
1843 proc->super.op_EMC = pdf_color_EMC;
1844
1845 /* compatibility */
1846 proc->super.op_BX = pdf_color_BX;
1847 proc->super.op_EX = pdf_color_EX;
1848
1849 /* extgstate */
1850 proc->super.op_gs_OP = pdf_color_gs_OP;
1851 proc->super.op_gs_op = pdf_color_gs_op;
1852 proc->super.op_gs_OPM = pdf_color_gs_OPM;
1853 proc->super.op_gs_UseBlackPtComp = pdf_color_gs_UseBlackPtComp;
1854
1855 proc->super.op_END = pdf_color_END;
1856
1857 fz_try(ctx)
1858 proc->gstate = fz_malloc_struct(ctx, gstate_stack);
1859 fz_catch(ctx)
1860 {
1861 fz_free(ctx, proc);
1862 fz_rethrow(ctx);
1863 }
1864 proc->gstate->ctm = fz_identity;
1865
1866 proc->doc = pdf_keep_document(ctx, doc);
1867 proc->chain = chain;
1868 proc->global_options = global_options;
1869 proc->options = options;
1870
1871 proc->super.requirements = PDF_PROCESSOR_REQUIRES_DECODED_IMAGES | proc->chain->requirements;
1872
1873 return (pdf_processor*)proc;
1874 }