comparison mupdf-source/source/pdf/pdf-op-buffer.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-2025 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 typedef struct resources_stack
27 {
28 struct resources_stack *next;
29 pdf_obj *res;
30 } resources_stack;
31
32 typedef struct
33 {
34 pdf_processor super;
35 fz_output *out;
36 int ahxencode;
37 int extgstate;
38 int newlines;
39 int balance;
40 pdf_obj *res;
41 pdf_obj *last_res;
42 resources_stack *rstack;
43 int sep;
44 } pdf_output_processor;
45
46 /* general graphics state */
47
48 static void
49 post_op(fz_context *ctx, pdf_output_processor *proc)
50 {
51 if (proc->newlines)
52 proc->sep = '\n';
53 else
54 proc->sep = 1;
55 }
56
57 static inline void separate(fz_context *ctx, pdf_output_processor *proc)
58 {
59 if (!proc->sep)
60 return;
61
62 if (proc->sep == '\n')
63 fz_write_byte(ctx, proc->out, '\n');
64 else
65 fz_write_byte(ctx, proc->out, ' ');
66 }
67
68 static void
69 pdf_out_w(fz_context *ctx, pdf_processor *proc_, float linewidth)
70 {
71 pdf_output_processor *proc = (pdf_output_processor *)proc_;
72
73 if (proc->extgstate != 0)
74 return;
75
76 separate(ctx, proc);
77 fz_write_printf(ctx, proc->out, "%g w", linewidth);
78 post_op(ctx, proc);
79 }
80
81 static void
82 pdf_out_j(fz_context *ctx, pdf_processor *proc_, int linejoin)
83 {
84 pdf_output_processor *proc = (pdf_output_processor *)proc_;
85
86 if (proc->extgstate != 0)
87 return;
88
89 separate(ctx, proc);
90 fz_write_printf(ctx, proc->out, "%d j", linejoin);
91 post_op(ctx, proc);
92 }
93
94 static void
95 pdf_out_J(fz_context *ctx, pdf_processor *proc_, int linecap)
96 {
97 pdf_output_processor *proc = (pdf_output_processor *)proc_;
98
99 if (proc->extgstate != 0)
100 return;
101
102 separate(ctx, proc);
103 fz_write_printf(ctx, proc->out, "%d J", linecap);
104 post_op(ctx, proc);
105 }
106
107 static void
108 pdf_out_M(fz_context *ctx, pdf_processor *proc_, float a)
109 {
110 pdf_output_processor *proc = (pdf_output_processor *)proc_;
111
112 if (proc->extgstate != 0)
113 return;
114
115 separate(ctx, proc);
116 fz_write_printf(ctx, proc->out, "%g M", a);
117 post_op(ctx, proc);
118 }
119
120 static void
121 pdf_out_d(fz_context *ctx, pdf_processor *proc_, pdf_obj *array, float phase)
122 {
123 pdf_output_processor *proc = (pdf_output_processor *)proc_;
124 int ahx = proc->ahxencode;
125
126 if (proc->extgstate != 0)
127 return;
128
129 pdf_print_encrypted_obj(ctx, proc->out, array, 1, ahx, NULL, 0, 0, &proc->sep);
130 separate(ctx, proc);
131 fz_write_printf(ctx, proc->out, "%g d", phase);
132 post_op(ctx, proc);
133 }
134
135 static void
136 pdf_out_ri(fz_context *ctx, pdf_processor *proc_, const char *intent)
137 {
138 pdf_output_processor *proc = (pdf_output_processor *)proc_;
139
140 if (proc->extgstate != 0)
141 return;
142
143 separate(ctx, proc);
144 fz_write_printf(ctx, proc->out, "%n ri", intent);
145 post_op(ctx, proc);
146 }
147
148 static void
149 pdf_out_i(fz_context *ctx, pdf_processor *proc_, float flatness)
150 {
151 pdf_output_processor *proc = (pdf_output_processor *)proc_;
152
153 if (proc->extgstate != 0)
154 return;
155
156 separate(ctx, proc);
157 fz_write_printf(ctx, proc->out, "%g i", flatness);
158 post_op(ctx, proc);
159 }
160
161 static void
162 pdf_out_gs_begin(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_obj *extgstate)
163 {
164 pdf_output_processor *proc = (pdf_output_processor *)proc_;
165
166 proc->extgstate = 1;
167
168 fz_write_printf(ctx, proc->out, "%n gs", name);
169 post_op(ctx, proc);
170 }
171
172 static void
173 pdf_out_gs_end(fz_context *ctx, pdf_processor *proc)
174 {
175 ((pdf_output_processor*)proc)->extgstate = 0;
176 }
177
178 /* special graphics state */
179
180 static void
181 pdf_out_q(fz_context *ctx, pdf_processor *proc_)
182 {
183 pdf_output_processor *proc = (pdf_output_processor *)proc_;
184
185 proc->balance++;
186
187 separate(ctx, proc);
188 fz_write_string(ctx, proc->out, "q");
189 post_op(ctx, proc);
190 }
191
192 static void
193 pdf_out_Q(fz_context *ctx, pdf_processor *proc_)
194 {
195 pdf_output_processor *proc = (pdf_output_processor *)proc_;
196
197 proc->balance--;
198 if (proc->balance < 0)
199 fz_warn(ctx, "gstate underflow (too many Q operators)");
200
201 separate(ctx, proc);
202 fz_write_string(ctx, proc->out, "Q");
203 post_op(ctx, proc);
204 }
205
206 static void
207 pdf_out_cm(fz_context *ctx, pdf_processor *proc_, float a, float b, float c, float d, float e, float f)
208 {
209 pdf_output_processor *proc = (pdf_output_processor *)proc_;
210
211 separate(ctx, proc);
212 fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g cm", a, b, c, d, e, f);
213 post_op(ctx, proc);
214 }
215
216 /* path construction */
217
218 static void
219 pdf_out_m(fz_context *ctx, pdf_processor *proc_, float x, float y)
220 {
221 pdf_output_processor *proc = (pdf_output_processor *)proc_;
222
223 separate(ctx, proc);
224 fz_write_printf(ctx, proc->out, "%g %g m", x, y);
225 post_op(ctx, proc);
226 }
227
228 static void
229 pdf_out_l(fz_context *ctx, pdf_processor *proc_, float x, float y)
230 {
231 pdf_output_processor *proc = (pdf_output_processor *)proc_;
232
233 separate(ctx, proc);
234 fz_write_printf(ctx, proc->out, "%g %g l", x, y);
235 post_op(ctx, proc);
236 }
237
238 static void
239 pdf_out_c(fz_context *ctx, pdf_processor *proc_, float x1, float y1, float x2, float y2, float x3, float y3)
240 {
241 pdf_output_processor *proc = (pdf_output_processor *)proc_;
242
243 separate(ctx, proc);
244 fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g c", x1, y1, x2, y2, x3, y3);
245 post_op(ctx, proc);
246 }
247
248 static void
249 pdf_out_v(fz_context *ctx, pdf_processor *proc_, float x2, float y2, float x3, float y3)
250 {
251 pdf_output_processor *proc = (pdf_output_processor *)proc_;
252
253 separate(ctx, proc);
254 fz_write_printf(ctx, proc->out, "%g %g %g %g v", x2, y2, x3, y3);
255 post_op(ctx, proc);
256 }
257
258 static void
259 pdf_out_y(fz_context *ctx, pdf_processor *proc_, float x1, float y1, float x3, float y3)
260 {
261 pdf_output_processor *proc = (pdf_output_processor *)proc_;
262
263 separate(ctx, proc);
264 fz_write_printf(ctx, proc->out, "%g %g %g %g y", x1, y1, x3, y3);
265 post_op(ctx, proc);
266 }
267
268 static void
269 pdf_out_h(fz_context *ctx, pdf_processor *proc_)
270 {
271 pdf_output_processor *proc = (pdf_output_processor *)proc_;
272
273 separate(ctx, proc);
274 fz_write_string(ctx, proc->out, "h");
275 post_op(ctx, proc);
276 }
277
278 static void
279 pdf_out_re(fz_context *ctx, pdf_processor *proc_, float x, float y, float w, float h)
280 {
281 pdf_output_processor *proc = (pdf_output_processor *)proc_;
282
283 separate(ctx, proc);
284 fz_write_printf(ctx, proc->out, "%g %g %g %g re", x, y, w, h);
285 post_op(ctx, proc);
286 }
287
288 /* path painting */
289
290 static void
291 pdf_out_S(fz_context *ctx, pdf_processor *proc_)
292 {
293 pdf_output_processor *proc = (pdf_output_processor *)proc_;
294
295 separate(ctx, proc);
296 fz_write_string(ctx, proc->out, "S");
297 post_op(ctx, proc);
298 }
299
300 static void
301 pdf_out_s(fz_context *ctx, pdf_processor *proc_)
302 {
303 pdf_output_processor *proc = (pdf_output_processor *)proc_;
304
305 separate(ctx, proc);
306 fz_write_string(ctx, proc->out, "s");
307 post_op(ctx, proc);
308 }
309
310 static void
311 pdf_out_F(fz_context *ctx, pdf_processor *proc_)
312 {
313 pdf_output_processor *proc = (pdf_output_processor *)proc_;
314
315 separate(ctx, proc);
316 fz_write_string(ctx, proc->out, "F");
317 post_op(ctx, proc);
318 }
319
320 static void
321 pdf_out_f(fz_context *ctx, pdf_processor *proc_)
322 {
323 pdf_output_processor *proc = (pdf_output_processor *)proc_;
324
325 separate(ctx, proc);
326 fz_write_string(ctx, proc->out, "f");
327 post_op(ctx, proc);
328 }
329
330 static void
331 pdf_out_fstar(fz_context *ctx, pdf_processor *proc_)
332 {
333 pdf_output_processor *proc = (pdf_output_processor *)proc_;
334
335 separate(ctx, proc);
336 fz_write_string(ctx, proc->out, "f*");
337 post_op(ctx, proc);
338 }
339
340 static void
341 pdf_out_B(fz_context *ctx, pdf_processor *proc_)
342 {
343 pdf_output_processor *proc = (pdf_output_processor *)proc_;
344
345 separate(ctx, proc);
346 fz_write_string(ctx, proc->out, "B");
347 post_op(ctx, proc);
348 }
349
350 static void
351 pdf_out_Bstar(fz_context *ctx, pdf_processor *proc_)
352 {
353 pdf_output_processor *proc = (pdf_output_processor *)proc_;
354
355 separate(ctx, proc);
356 fz_write_string(ctx, proc->out, "B*");
357 post_op(ctx, proc);
358 }
359
360 static void
361 pdf_out_b(fz_context *ctx, pdf_processor *proc_)
362 {
363 pdf_output_processor *proc = (pdf_output_processor *)proc_;
364
365 separate(ctx, proc);
366 fz_write_string(ctx, proc->out, "b");
367 post_op(ctx, proc);
368 }
369
370 static void
371 pdf_out_bstar(fz_context *ctx, pdf_processor *proc_)
372 {
373 pdf_output_processor *proc = (pdf_output_processor *)proc_;
374
375 separate(ctx, proc);
376 fz_write_string(ctx, proc->out, "b*");
377 post_op(ctx, proc);
378 }
379
380 static void
381 pdf_out_n(fz_context *ctx, pdf_processor *proc_)
382 {
383 pdf_output_processor *proc = (pdf_output_processor *)proc_;
384
385 separate(ctx, proc);
386 fz_write_string(ctx, proc->out, "n");
387 post_op(ctx, proc);
388 }
389
390 /* clipping paths */
391
392 static void
393 pdf_out_W(fz_context *ctx, pdf_processor *proc_)
394 {
395 pdf_output_processor *proc = (pdf_output_processor *)proc_;
396
397 separate(ctx, proc);
398 fz_write_string(ctx, proc->out, "W");
399 post_op(ctx, proc);
400 }
401
402 static void
403 pdf_out_Wstar(fz_context *ctx, pdf_processor *proc_)
404 {
405 pdf_output_processor *proc = (pdf_output_processor *)proc_;
406
407 separate(ctx, proc);
408 fz_write_string(ctx, proc->out, "W*");
409 post_op(ctx, proc);
410 }
411
412 /* text objects */
413
414 static void
415 pdf_out_BT(fz_context *ctx, pdf_processor *proc_)
416 {
417 pdf_output_processor *proc = (pdf_output_processor *)proc_;
418
419 separate(ctx, proc);
420 fz_write_string(ctx, proc->out, "BT");
421 post_op(ctx, proc);
422 }
423
424 static void
425 pdf_out_ET(fz_context *ctx, pdf_processor *proc_)
426 {
427 pdf_output_processor *proc = (pdf_output_processor *)proc_;
428
429 separate(ctx, proc);
430 fz_write_string(ctx, proc->out, "ET");
431 post_op(ctx, proc);
432 }
433
434 /* text state */
435
436 static void
437 pdf_out_Tc(fz_context *ctx, pdf_processor *proc_, float charspace)
438 {
439 pdf_output_processor *proc = (pdf_output_processor *)proc_;
440
441 separate(ctx, proc);
442 fz_write_printf(ctx, proc->out, "%g Tc", charspace);
443 post_op(ctx, proc);
444 }
445
446 static void
447 pdf_out_Tw(fz_context *ctx, pdf_processor *proc_, float wordspace)
448 {
449 pdf_output_processor *proc = (pdf_output_processor *)proc_;
450
451 separate(ctx, proc);
452 fz_write_printf(ctx, proc->out, "%g Tw", wordspace);
453 post_op(ctx, proc);
454 }
455
456 static void
457 pdf_out_Tz(fz_context *ctx, pdf_processor *proc_, float scale)
458 {
459 /* scale is exactly as read from the file. */
460 pdf_output_processor *proc = (pdf_output_processor *)proc_;
461
462 separate(ctx, proc);
463 fz_write_printf(ctx, proc->out, "%g Tz", scale);
464 post_op(ctx, proc);
465 }
466
467 static void
468 pdf_out_TL(fz_context *ctx, pdf_processor *proc_, float leading)
469 {
470 pdf_output_processor *proc = (pdf_output_processor *)proc_;
471
472 separate(ctx, proc);
473 fz_write_printf(ctx, proc->out, "%g TL", leading);
474 post_op(ctx, proc);
475 }
476
477 static void
478 pdf_out_Tf(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_font_desc *font, float size)
479 {
480 pdf_output_processor *proc = (pdf_output_processor *)proc_;
481
482 if (proc->extgstate != 0)
483 return;
484
485 fz_write_printf(ctx, proc->out, "%n %g Tf", name, size);
486 post_op(ctx, proc);
487 }
488
489 static void
490 pdf_out_Tr(fz_context *ctx, pdf_processor *proc_, int render)
491 {
492 pdf_output_processor *proc = (pdf_output_processor *)proc_;
493
494 separate(ctx, proc);
495 fz_write_printf(ctx, proc->out, "%d Tr", render);
496 post_op(ctx, proc);
497 }
498
499 static void
500 pdf_out_Ts(fz_context *ctx, pdf_processor *proc_, float rise)
501 {
502 pdf_output_processor *proc = (pdf_output_processor *)proc_;
503
504 separate(ctx, proc);
505 fz_write_printf(ctx, proc->out, "%g Ts", rise);
506 post_op(ctx, proc);
507 }
508
509 /* text positioning */
510
511 static void
512 pdf_out_Td(fz_context *ctx, pdf_processor *proc_, float tx, float ty)
513 {
514 pdf_output_processor *proc = (pdf_output_processor *)proc_;
515
516 separate(ctx, proc);
517 fz_write_printf(ctx, proc->out, "%g %g Td", tx, ty);
518 post_op(ctx, proc);
519 }
520
521 static void
522 pdf_out_TD(fz_context *ctx, pdf_processor *proc_, float tx, float ty)
523 {
524 pdf_output_processor *proc = (pdf_output_processor *)proc_;
525
526 separate(ctx, proc);
527 fz_write_printf(ctx, proc->out, "%g %g TD", tx, ty);
528 post_op(ctx, proc);
529 }
530
531 static void
532 pdf_out_Tm(fz_context *ctx, pdf_processor *proc_, float a, float b, float c, float d, float e, float f)
533 {
534 pdf_output_processor *proc = (pdf_output_processor *)proc_;
535
536 separate(ctx, proc);
537 fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g Tm", a, b, c, d, e, f);
538 post_op(ctx, proc);
539 }
540
541 static void
542 pdf_out_Tstar(fz_context *ctx, pdf_processor *proc_)
543 {
544 pdf_output_processor *proc = (pdf_output_processor *)proc_;
545
546 separate(ctx, proc);
547 fz_write_string(ctx, proc->out, "T*");
548 post_op(ctx, proc);
549 }
550
551 /* text showing */
552
553 static void
554 fz_write_pdf_string(fz_context *ctx, fz_output *out, const unsigned char *str, size_t len)
555 {
556 size_t i;
557
558 for (i = 0; i < len; ++i)
559 if (str[i] < 32 || str[i] >= 127)
560 break;
561
562 if (i < len)
563 {
564 fz_write_byte(ctx, out, '<');
565 for (i = 0; i < len; ++i)
566 {
567 unsigned char c = str[i];
568 fz_write_byte(ctx, out, "0123456789abcdef"[(c>>4)&15]);
569 fz_write_byte(ctx, out, "0123456789abcdef"[(c)&15]);
570 }
571 fz_write_byte(ctx, out, '>');
572 }
573 else
574 {
575 fz_write_byte(ctx, out, '(');
576 for (i = 0; i < len; ++i)
577 {
578 unsigned char c = str[i];
579 if (c == '(' || c == ')' || c == '\\')
580 fz_write_byte(ctx, out, '\\');
581 fz_write_byte(ctx, out, c);
582 }
583 fz_write_byte(ctx, out, ')');
584 }
585 }
586
587 static void
588 pdf_out_TJ(fz_context *ctx, pdf_processor *proc_, pdf_obj *array)
589 {
590 pdf_output_processor *proc = (pdf_output_processor *)proc_;
591 int ahx = proc->ahxencode;
592
593 pdf_print_encrypted_obj(ctx, proc->out, array, 1, ahx, NULL, 0, 0, &proc->sep);
594 separate(ctx, proc);
595 fz_write_string(ctx, proc->out, "TJ");
596 post_op(ctx, proc);
597 }
598
599 static void
600 pdf_out_Tj(fz_context *ctx, pdf_processor *proc_, char *str, size_t len)
601 {
602 pdf_output_processor *proc = (pdf_output_processor *)proc_;
603
604 separate(ctx, proc);
605 fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
606 fz_write_string(ctx, proc->out, "Tj");
607 post_op(ctx, proc);
608 }
609
610 static void
611 pdf_out_squote(fz_context *ctx, pdf_processor *proc_, char *str, size_t len)
612 {
613 pdf_output_processor *proc = (pdf_output_processor *)proc_;
614
615 separate(ctx, proc);
616 fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
617 fz_write_string(ctx, proc->out, "'");
618 post_op(ctx, proc);
619 }
620
621 static void
622 pdf_out_dquote(fz_context *ctx, pdf_processor *proc_, float aw, float ac, char *str, size_t len)
623 {
624 pdf_output_processor *proc = (pdf_output_processor *)proc_;
625
626 separate(ctx, proc);
627 fz_write_printf(ctx, proc->out, "%g %g ", aw, ac);
628 fz_write_pdf_string(ctx, proc->out, (const unsigned char *)str, len);
629 fz_write_string(ctx, proc->out, "\"");
630 post_op(ctx, proc);
631 }
632
633 /* type 3 fonts */
634
635 static void
636 pdf_out_d0(fz_context *ctx, pdf_processor *proc_, float wx, float wy)
637 {
638 pdf_output_processor *proc = (pdf_output_processor *)proc_;
639
640 separate(ctx, proc);
641 fz_write_printf(ctx, proc->out, "%g %g d0", wx, wy);
642 post_op(ctx, proc);
643 }
644
645 static void
646 pdf_out_d1(fz_context *ctx, pdf_processor *proc_, float wx, float wy, float llx, float lly, float urx, float ury)
647 {
648 pdf_output_processor *proc = (pdf_output_processor *)proc_;
649
650 separate(ctx, proc);
651 fz_write_printf(ctx, proc->out, "%g %g %g %g %g %g d1", wx, wy, llx, lly, urx, ury);
652 post_op(ctx, proc);
653 }
654
655 /* color */
656
657 static void
658 pdf_out_CS(fz_context *ctx, pdf_processor *proc_, const char *name, fz_colorspace *cs)
659 {
660 pdf_output_processor *proc = (pdf_output_processor *)proc_;
661
662 separate(ctx, proc);
663 fz_write_printf(ctx, proc->out, "%n CS", name);
664 post_op(ctx, proc);
665 }
666
667 static void
668 pdf_out_cs(fz_context *ctx, pdf_processor *proc_, const char *name, fz_colorspace *cs)
669 {
670 pdf_output_processor *proc = (pdf_output_processor *)proc_;
671
672 separate(ctx, proc);
673 fz_write_printf(ctx, proc->out, "%n cs", name);
674 post_op(ctx, proc);
675 }
676
677 static void
678 pdf_out_SC_pattern(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_pattern *pat, int n, float *color)
679 {
680 int i;
681 pdf_output_processor *proc = (pdf_output_processor *)proc_;
682
683 separate(ctx, proc);
684 for (i = 0; i < n; ++i)
685 fz_write_printf(ctx, proc->out, "%g ", color[i]);
686 fz_write_printf(ctx, proc->out, "%n SCN", name);
687 post_op(ctx, proc);
688 }
689
690 static void
691 pdf_out_sc_pattern(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_pattern *pat, int n, float *color)
692 {
693 int i;
694 pdf_output_processor *proc = (pdf_output_processor *)proc_;
695
696 separate(ctx, proc);
697 for (i = 0; i < n; ++i)
698 fz_write_printf(ctx, proc->out, "%g ", color[i]);
699 fz_write_printf(ctx, proc->out, "%n scn", name);
700 post_op(ctx, proc);
701 }
702
703 static void
704 pdf_out_SC_shade(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
705 {
706 pdf_output_processor *proc = (pdf_output_processor *)proc_;
707
708 separate(ctx, proc);
709 fz_write_printf(ctx, proc->out, "%n SCN", name);
710 post_op(ctx, proc);
711 }
712
713 static void
714 pdf_out_sc_shade(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
715 {
716 pdf_output_processor *proc = (pdf_output_processor *)proc_;
717
718 separate(ctx, proc);
719 fz_write_printf(ctx, proc->out, "%n scn", name);
720 post_op(ctx, proc);
721 }
722
723 static void
724 pdf_out_SC_color(fz_context *ctx, pdf_processor *proc_, int n, float *color)
725 {
726 int i;
727 pdf_output_processor *proc = (pdf_output_processor *)proc_;
728
729 separate(ctx, proc);
730 for (i = 0; i < n; ++i)
731 fz_write_printf(ctx, proc->out, "%g ", color[i]);
732 fz_write_string(ctx, proc->out, "SCN");
733 post_op(ctx, proc);
734 }
735
736 static void
737 pdf_out_sc_color(fz_context *ctx, pdf_processor *proc_, int n, float *color)
738 {
739 int i;
740 pdf_output_processor *proc = (pdf_output_processor *)proc_;
741
742 separate(ctx, proc);
743 for (i = 0; i < n; ++i)
744 fz_write_printf(ctx, proc->out, "%g ", color[i]);
745 fz_write_string(ctx, proc->out, "scn");
746 post_op(ctx, proc);
747 }
748
749 static void
750 pdf_out_G(fz_context *ctx, pdf_processor *proc_, float g)
751 {
752 pdf_output_processor *proc = (pdf_output_processor *)proc_;
753
754 separate(ctx, proc);
755 fz_write_printf(ctx, proc->out, "%g G", g);
756 post_op(ctx, proc);
757 }
758
759 static void
760 pdf_out_g(fz_context *ctx, pdf_processor *proc_, float g)
761 {
762 pdf_output_processor *proc = (pdf_output_processor *)proc_;
763
764 separate(ctx, proc);
765 fz_write_printf(ctx, proc->out, "%g g", g);
766 post_op(ctx, proc);
767 }
768
769 static void
770 pdf_out_RG(fz_context *ctx, pdf_processor *proc_, float r, float g, float b)
771 {
772 pdf_output_processor *proc = (pdf_output_processor *)proc_;
773
774 separate(ctx, proc);
775 fz_write_printf(ctx, proc->out, "%g %g %g RG", r, g, b);
776 post_op(ctx, proc);
777 }
778
779 static void
780 pdf_out_rg(fz_context *ctx, pdf_processor *proc_, float r, float g, float b)
781 {
782 pdf_output_processor *proc = (pdf_output_processor *)proc_;
783
784 separate(ctx, proc);
785 fz_write_printf(ctx, proc->out, "%g %g %g rg", r, g, b);
786 post_op(ctx, proc);
787 }
788
789 static void
790 pdf_out_K(fz_context *ctx, pdf_processor *proc_, float c, float m, float y, float k)
791 {
792 pdf_output_processor *proc = (pdf_output_processor *)proc_;
793
794 separate(ctx, proc);
795 fz_write_printf(ctx, proc->out, "%g %g %g %g K", c, m, y, k);
796 post_op(ctx, proc);
797 }
798
799 static void
800 pdf_out_k(fz_context *ctx, pdf_processor *proc_, float c, float m, float y, float k)
801 {
802 pdf_output_processor *proc = (pdf_output_processor *)proc_;
803
804 separate(ctx, proc);
805 fz_write_printf(ctx, proc->out, "%g %g %g %g k", c, m, y, k);
806 post_op(ctx, proc);
807 }
808
809 /* shadings, images, xobjects */
810
811 static void
812 pdf_out_BI(fz_context *ctx, pdf_processor *proc_, fz_image *img, const char *colorspace)
813 {
814 pdf_output_processor *proc = (pdf_output_processor *)proc_;
815 fz_output *out = proc->out;
816 int ahx = proc->ahxencode;
817 fz_compressed_buffer *cbuf;
818 fz_buffer *buf = NULL;
819 int i, w, h, bpc;
820 unsigned char *data;
821 size_t len;
822 fz_pixmap *pix = NULL;
823 fz_colorspace *cs;
824 int type;
825
826 if (img == NULL)
827 return;
828 cbuf = fz_compressed_image_buffer(ctx, img);
829 if (cbuf == NULL)
830 {
831 pix = fz_get_pixmap_from_image(ctx, img, NULL, NULL, &w, &h);
832 bpc = 8;
833 cs = pix->colorspace;
834 type = FZ_IMAGE_RAW;
835 }
836 else
837 {
838 buf = cbuf->buffer;
839 if (buf == NULL)
840 return;
841 w = img->w;
842 h = img->h;
843 bpc = img->bpc;
844 cs = img->colorspace;
845 type = cbuf->params.type;
846 }
847
848 fz_try(ctx)
849 {
850 separate(ctx, proc);
851 fz_write_string(ctx, out, "BI ");
852 fz_write_printf(ctx, out, "/W %d", w);
853 fz_write_printf(ctx, out, "/H %d", h);
854 fz_write_printf(ctx, out, "/BPC %d", bpc);
855 if (img->imagemask)
856 fz_write_string(ctx, out, "/IM true");
857 else if (cs == fz_device_gray(ctx))
858 fz_write_string(ctx, out, "/CS/G");
859 else if (cs == fz_device_rgb(ctx))
860 fz_write_string(ctx, out, "/CS/RGB");
861 else if (cs == fz_device_cmyk(ctx))
862 fz_write_string(ctx, out, "/CS/CMYK");
863 else if (cs)
864 fz_write_printf(ctx, out, "/CS%n", colorspace);
865 else
866 fz_throw(ctx, FZ_ERROR_ARGUMENT, "BI operator can only show ImageMask, Gray, RGB, or CMYK images");
867 if (img->interpolate)
868 fz_write_string(ctx, out, "/I true");
869 fz_write_string(ctx, out, "/D[");
870 for (i = 0; i < img->n * 2; ++i)
871 {
872 if (i > 0)
873 fz_write_byte(ctx, out, ' ');
874 fz_write_printf(ctx, out, "%g", img->decode[i]);
875 }
876 fz_write_string(ctx, out, "]");
877 proc->sep = 0;
878
879 switch (type)
880 {
881 default:
882 fz_throw(ctx, FZ_ERROR_ARGUMENT, "unknown compressed buffer type");
883 break;
884
885 case FZ_IMAGE_JPEG:
886 fz_write_string(ctx, out, ahx ? "/F[/AHx/DCT]" : "/F/DCT");
887 proc->sep = !ahx;
888 if (cbuf->params.u.jpeg.color_transform >= 0)
889 {
890 fz_write_printf(ctx, out, "/DP<</ColorTransform %d>>", cbuf->params.u.jpeg.color_transform);
891 proc->sep = 0;
892 }
893 if (cbuf->params.u.jpeg.invert_cmyk && img->n == 4)
894 {
895 fz_write_string(ctx, out, "/D[1 0 1 0 1 0 1 0]");
896 proc->sep = 0;
897 }
898 break;
899
900 case FZ_IMAGE_FAX:
901 fz_write_string(ctx, out, ahx ? "/F[/AHx/CCF]/DP[null<<" : "/F/CCF/DP<<");
902 fz_write_printf(ctx, out, "/K %d", cbuf->params.u.fax.k);
903 if (cbuf->params.u.fax.columns != 1728)
904 fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.fax.columns);
905 if (cbuf->params.u.fax.rows > 0)
906 fz_write_printf(ctx, out, "/Rows %d", cbuf->params.u.fax.rows);
907 if (cbuf->params.u.fax.end_of_line)
908 fz_write_string(ctx, out, "/EndOfLine true");
909 if (cbuf->params.u.fax.encoded_byte_align)
910 fz_write_string(ctx, out, "/EncodedByteAlign true");
911 if (!cbuf->params.u.fax.end_of_block)
912 fz_write_string(ctx, out, "/EndOfBlock false");
913 if (cbuf->params.u.fax.black_is_1)
914 fz_write_string(ctx, out, "/BlackIs1 true");
915 if (cbuf->params.u.fax.damaged_rows_before_error > 0)
916 fz_write_printf(ctx, out, "/DamagedRowsBeforeError %d",
917 cbuf->params.u.fax.damaged_rows_before_error);
918 fz_write_string(ctx, out, ahx ? ">>]" : ">>");
919 proc->sep = 0;
920 break;
921
922 case FZ_IMAGE_RAW:
923 if (ahx)
924 {
925 fz_write_string(ctx, out, "/F/AHx");
926 proc->sep = 1;
927 }
928 break;
929
930 case FZ_IMAGE_RLD:
931 fz_write_string(ctx, out, ahx ? "/F[/AHx/RL]" : "/F/RL");
932 proc->sep = !ahx;
933 break;
934
935 case FZ_IMAGE_FLATE:
936 fz_write_string(ctx, out, ahx ? "/F[/AHx/Fl]" : "/F/Fl");
937 proc->sep = !ahx;
938 if (cbuf->params.u.flate.predictor > 1)
939 {
940 fz_write_string(ctx, out, ahx ? "/DP[null<<" : "/DP<<");
941 fz_write_printf(ctx, out, "/Predictor %d", cbuf->params.u.flate.predictor);
942 if (cbuf->params.u.flate.columns != 1)
943 fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.flate.columns);
944 if (cbuf->params.u.flate.colors != 1)
945 fz_write_printf(ctx, out, "/Colors %d", cbuf->params.u.flate.colors);
946 if (cbuf->params.u.flate.bpc != 8)
947 fz_write_printf(ctx, out, "/BitsPerComponent %d", cbuf->params.u.flate.bpc);
948 fz_write_string(ctx, out, ahx ? ">>]" : ">>");
949 proc->sep = 0;
950 }
951 break;
952
953 case FZ_IMAGE_LZW:
954 fz_write_string(ctx, out, ahx ? "/F[/AHx/LZW]" : "/F/LZW");
955 proc->sep = !ahx;
956 if (cbuf->params.u.lzw.predictor > 1)
957 {
958 fz_write_string(ctx, out, ahx ? "/DP[null<<" : "/DP<<");
959 fz_write_printf(ctx, out, "/Predictor %d", cbuf->params.u.lzw.predictor);
960 if (cbuf->params.u.lzw.columns != 1)
961 fz_write_printf(ctx, out, "/Columns %d", cbuf->params.u.lzw.columns);
962 if (cbuf->params.u.lzw.colors != 1)
963 fz_write_printf(ctx, out, "/Colors %d", cbuf->params.u.lzw.colors);
964 if (cbuf->params.u.lzw.bpc != 8)
965 fz_write_printf(ctx, out, "/BitsPerComponent %d", cbuf->params.u.lzw.bpc);
966 if (cbuf->params.u.lzw.early_change != 1)
967 fz_write_printf(ctx, out, "/EarlyChange %d", cbuf->params.u.lzw.early_change);
968 fz_write_string(ctx, out, ahx ? ">>]" : ">>");
969 proc->sep = 0;
970 }
971 break;
972
973 case FZ_IMAGE_BROTLI:
974 fz_write_string(ctx, out, ahx ? "/F[/AHx/Br]\n" : "/F/Br\n");
975 if (cbuf->params.u.brotli.predictor > 1)
976 {
977 fz_write_string(ctx, out, ahx ? "/DP[null<<\n" : "/DP<<\n");
978 fz_write_printf(ctx, out, "/Predictor %d\n", cbuf->params.u.brotli.predictor);
979 if (cbuf->params.u.brotli.columns != 1)
980 fz_write_printf(ctx, out, "/Columns %d\n", cbuf->params.u.brotli.columns);
981 if (cbuf->params.u.brotli.colors != 1)
982 fz_write_printf(ctx, out, "/Colors %d\n", cbuf->params.u.brotli.colors);
983 if (cbuf->params.u.brotli.bpc != 8)
984 fz_write_printf(ctx, out, "/BitsPerComponent %d\n", cbuf->params.u.brotli.bpc);
985 fz_write_string(ctx, out, ahx ? ">>]\n" : ">>\n");
986 }
987 break;
988 }
989
990 separate(ctx, proc);
991 fz_write_string(ctx, out, "ID ");
992 if (buf)
993 len = fz_buffer_storage(ctx, buf, &data);
994 else
995 {
996 data = pix->samples;
997 len = ((size_t)w) * h * pix->n;
998 }
999 if (ahx)
1000 {
1001 size_t z;
1002 for (z = 0; z < len; ++z)
1003 {
1004 int c = data[z];
1005 fz_write_byte(ctx, out, "0123456789abcdef"[(c >> 4) & 0xf]);
1006 fz_write_byte(ctx, out, "0123456789abcdef"[c & 0xf]);
1007 if ((z & 31) == 31)
1008 fz_write_byte(ctx, out, '\n');
1009 }
1010 fz_write_byte(ctx, out, '>');
1011 }
1012 else
1013 {
1014 fz_write_data(ctx, out, data, len);
1015 }
1016 fz_write_string(ctx, out, " EI");
1017 proc->sep = 1;
1018 }
1019 fz_always(ctx)
1020 fz_drop_pixmap(ctx, pix);
1021 fz_catch(ctx)
1022 fz_rethrow(ctx);
1023 }
1024
1025 static void
1026 pdf_out_sh(fz_context *ctx, pdf_processor *proc_, const char *name, fz_shade *shade)
1027 {
1028 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1029
1030 separate(ctx, proc);
1031 fz_write_printf(ctx, proc->out, "%n sh", name);
1032 post_op(ctx, proc);
1033 }
1034
1035 static void
1036 pdf_out_Do_image(fz_context *ctx, pdf_processor *proc_, const char *name, fz_image *image)
1037 {
1038 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1039
1040 separate(ctx, proc);
1041 fz_write_printf(ctx, proc->out, "%n Do", name);
1042 post_op(ctx, proc);
1043 }
1044
1045 static void
1046 pdf_out_Do_form(fz_context *ctx, pdf_processor *proc_, const char *name, pdf_obj *xobj)
1047 {
1048 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1049
1050 separate(ctx, proc);
1051 fz_write_printf(ctx, proc->out, "%n Do", name);
1052 post_op(ctx, proc);
1053 }
1054
1055 /* marked content */
1056
1057 static void
1058 pdf_out_MP(fz_context *ctx, pdf_processor *proc_, const char *tag)
1059 {
1060 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1061
1062 separate(ctx, proc);
1063 fz_write_printf(ctx, proc->out, "%n MP", tag);
1064 post_op(ctx, proc);
1065 }
1066
1067 static void
1068 pdf_out_DP(fz_context *ctx, pdf_processor *proc_, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1069 {
1070 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1071 int ahx = proc->ahxencode;
1072
1073 separate(ctx, proc);
1074 fz_write_printf(ctx, proc->out, "%n", tag);
1075 proc->sep = 1;
1076 pdf_print_encrypted_obj(ctx, proc->out, raw, 1, ahx, NULL, 0, 0, &proc->sep);
1077 separate(ctx, proc);
1078 fz_write_string(ctx, proc->out, "DP");
1079 post_op(ctx, proc);
1080 }
1081
1082 static void
1083 pdf_out_BMC(fz_context *ctx, pdf_processor *proc_, const char *tag)
1084 {
1085 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1086
1087 separate(ctx, proc);
1088 fz_write_printf(ctx, proc->out, "%n BMC", tag);
1089 post_op(ctx, proc);
1090 }
1091
1092 static void
1093 pdf_out_BDC(fz_context *ctx, pdf_processor *proc_, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1094 {
1095 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1096 int ahx = proc->ahxencode;
1097
1098 separate(ctx, proc);
1099 fz_write_printf(ctx, proc->out, "%n", tag);
1100 proc->sep = 1;
1101 pdf_print_encrypted_obj(ctx, proc->out, raw, 1, ahx, NULL, 0, 0, &proc->sep);
1102 separate(ctx, proc);
1103 fz_write_string(ctx, proc->out, "BDC");
1104 post_op(ctx, proc);
1105 }
1106
1107 static void
1108 pdf_out_EMC(fz_context *ctx, pdf_processor *proc_)
1109 {
1110 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1111
1112 separate(ctx, proc);
1113 fz_write_string(ctx, proc->out, "EMC");
1114 post_op(ctx, proc);
1115 }
1116
1117 /* compatibility */
1118
1119 static void
1120 pdf_out_BX(fz_context *ctx, pdf_processor *proc_)
1121 {
1122 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1123
1124 separate(ctx, proc);
1125 fz_write_string(ctx, proc->out, "BX");
1126 post_op(ctx, proc);
1127 }
1128
1129 static void
1130 pdf_out_EX(fz_context *ctx, pdf_processor *proc_)
1131 {
1132 pdf_output_processor *proc = (pdf_output_processor *)proc_;
1133
1134 separate(ctx, proc);
1135 fz_write_string(ctx, proc->out, "EX");
1136 post_op(ctx, proc);
1137 }
1138
1139 static void
1140 pdf_close_output_processor(fz_context *ctx, pdf_processor *proc_)
1141 {
1142 pdf_output_processor *proc = (pdf_output_processor*)proc_;
1143 fz_output *out = proc->out;
1144
1145 /* Add missing 'Q' operators to get back to zero. */
1146 /* We can't prepend missing 'q' operators to guarantee we don't underflow. */
1147 while (proc->balance > 0)
1148 {
1149 proc->balance--;
1150 separate(ctx, proc);
1151 fz_write_byte(ctx, out, 'Q');
1152 post_op(ctx, proc);
1153 }
1154
1155 fz_close_output(ctx, out);
1156 }
1157
1158 static void
1159 pdf_drop_output_processor(fz_context *ctx, pdf_processor *proc)
1160 {
1161 pdf_output_processor *p = (pdf_output_processor *)proc;
1162
1163 fz_drop_output(ctx, p->out);
1164 }
1165
1166 static void
1167 pdf_reset_output_processor(fz_context *ctx, pdf_processor *proc)
1168 {
1169 pdf_output_processor *p = (pdf_output_processor *)proc;
1170
1171 fz_reset_output(ctx, p->out);
1172 }
1173
1174 static void
1175 pdf_out_push_resources(fz_context *ctx, pdf_processor *proc, pdf_obj *res)
1176 {
1177 pdf_output_processor *p = (pdf_output_processor *)proc;
1178 resources_stack *stk = fz_malloc_struct(ctx, resources_stack);
1179
1180 stk->next = p->rstack;
1181 p->rstack = stk;
1182 stk->res = pdf_keep_obj(ctx, res);
1183 }
1184
1185 static pdf_obj *
1186 pdf_out_pop_resources(fz_context *ctx, pdf_processor *proc)
1187 {
1188 pdf_output_processor *p = (pdf_output_processor *)proc;
1189 resources_stack *stk = p->rstack;
1190 pdf_obj *res = stk->res;
1191
1192 p->rstack = stk->next;
1193 fz_free(ctx, stk);
1194
1195 return res;
1196 }
1197
1198 pdf_processor *
1199 pdf_new_output_processor(fz_context *ctx, fz_output *out, int ahxencode, int newlines)
1200 {
1201 pdf_output_processor *proc = pdf_new_processor(ctx, sizeof *proc);
1202
1203 proc->super.close_processor = pdf_close_output_processor;
1204 proc->super.drop_processor = pdf_drop_output_processor;
1205 proc->super.reset_processor = pdf_reset_output_processor;
1206
1207 proc->super.push_resources = pdf_out_push_resources;
1208 proc->super.pop_resources = pdf_out_pop_resources;
1209
1210 /* general graphics state */
1211 proc->super.op_w = pdf_out_w;
1212 proc->super.op_j = pdf_out_j;
1213 proc->super.op_J = pdf_out_J;
1214 proc->super.op_M = pdf_out_M;
1215 proc->super.op_d = pdf_out_d;
1216 proc->super.op_ri = pdf_out_ri;
1217 proc->super.op_i = pdf_out_i;
1218 proc->super.op_gs_begin = pdf_out_gs_begin;
1219 proc->super.op_gs_end = pdf_out_gs_end;
1220
1221 /* transparency graphics state */
1222 proc->super.op_gs_BM = NULL;
1223 proc->super.op_gs_CA = NULL;
1224 proc->super.op_gs_ca = NULL;
1225 proc->super.op_gs_SMask = NULL;
1226
1227 /* special graphics state */
1228 proc->super.op_q = pdf_out_q;
1229 proc->super.op_Q = pdf_out_Q;
1230 proc->super.op_cm = pdf_out_cm;
1231
1232 /* path construction */
1233 proc->super.op_m = pdf_out_m;
1234 proc->super.op_l = pdf_out_l;
1235 proc->super.op_c = pdf_out_c;
1236 proc->super.op_v = pdf_out_v;
1237 proc->super.op_y = pdf_out_y;
1238 proc->super.op_h = pdf_out_h;
1239 proc->super.op_re = pdf_out_re;
1240
1241 /* path painting */
1242 proc->super.op_S = pdf_out_S;
1243 proc->super.op_s = pdf_out_s;
1244 proc->super.op_F = pdf_out_F;
1245 proc->super.op_f = pdf_out_f;
1246 proc->super.op_fstar = pdf_out_fstar;
1247 proc->super.op_B = pdf_out_B;
1248 proc->super.op_Bstar = pdf_out_Bstar;
1249 proc->super.op_b = pdf_out_b;
1250 proc->super.op_bstar = pdf_out_bstar;
1251 proc->super.op_n = pdf_out_n;
1252
1253 /* clipping paths */
1254 proc->super.op_W = pdf_out_W;
1255 proc->super.op_Wstar = pdf_out_Wstar;
1256
1257 /* text objects */
1258 proc->super.op_BT = pdf_out_BT;
1259 proc->super.op_ET = pdf_out_ET;
1260
1261 /* text state */
1262 proc->super.op_Tc = pdf_out_Tc;
1263 proc->super.op_Tw = pdf_out_Tw;
1264 proc->super.op_Tz = pdf_out_Tz;
1265 proc->super.op_TL = pdf_out_TL;
1266 proc->super.op_Tf = pdf_out_Tf;
1267 proc->super.op_Tr = pdf_out_Tr;
1268 proc->super.op_Ts = pdf_out_Ts;
1269
1270 /* text positioning */
1271 proc->super.op_Td = pdf_out_Td;
1272 proc->super.op_TD = pdf_out_TD;
1273 proc->super.op_Tm = pdf_out_Tm;
1274 proc->super.op_Tstar = pdf_out_Tstar;
1275
1276 /* text showing */
1277 proc->super.op_TJ = pdf_out_TJ;
1278 proc->super.op_Tj = pdf_out_Tj;
1279 proc->super.op_squote = pdf_out_squote;
1280 proc->super.op_dquote = pdf_out_dquote;
1281
1282 /* type 3 fonts */
1283 proc->super.op_d0 = pdf_out_d0;
1284 proc->super.op_d1 = pdf_out_d1;
1285
1286 /* color */
1287 proc->super.op_CS = pdf_out_CS;
1288 proc->super.op_cs = pdf_out_cs;
1289 proc->super.op_SC_color = pdf_out_SC_color;
1290 proc->super.op_sc_color = pdf_out_sc_color;
1291 proc->super.op_SC_pattern = pdf_out_SC_pattern;
1292 proc->super.op_sc_pattern = pdf_out_sc_pattern;
1293 proc->super.op_SC_shade = pdf_out_SC_shade;
1294 proc->super.op_sc_shade = pdf_out_sc_shade;
1295
1296 proc->super.op_G = pdf_out_G;
1297 proc->super.op_g = pdf_out_g;
1298 proc->super.op_RG = pdf_out_RG;
1299 proc->super.op_rg = pdf_out_rg;
1300 proc->super.op_K = pdf_out_K;
1301 proc->super.op_k = pdf_out_k;
1302
1303 /* shadings, images, xobjects */
1304 proc->super.op_BI = pdf_out_BI;
1305 proc->super.op_sh = pdf_out_sh;
1306 proc->super.op_Do_image = pdf_out_Do_image;
1307 proc->super.op_Do_form = pdf_out_Do_form;
1308
1309 /* marked content */
1310 proc->super.op_MP = pdf_out_MP;
1311 proc->super.op_DP = pdf_out_DP;
1312 proc->super.op_BMC = pdf_out_BMC;
1313 proc->super.op_BDC = pdf_out_BDC;
1314 proc->super.op_EMC = pdf_out_EMC;
1315
1316 /* compatibility */
1317 proc->super.op_BX = pdf_out_BX;
1318 proc->super.op_EX = pdf_out_EX;
1319
1320 /* extgstate */
1321 proc->super.op_gs_OP = NULL;
1322 proc->super.op_gs_op = NULL;
1323 proc->super.op_gs_OPM = NULL;
1324 proc->super.op_gs_UseBlackPtComp = NULL;
1325
1326 proc->out = out;
1327 proc->ahxencode = ahxencode;
1328 proc->newlines = newlines;
1329
1330 proc->super.requirements = PDF_PROCESSOR_REQUIRES_DECODED_IMAGES;
1331
1332 proc->balance = 0;
1333
1334 return (pdf_processor*)proc;
1335 }
1336
1337 pdf_processor *
1338 pdf_new_buffer_processor(fz_context *ctx, fz_buffer *buffer, int ahxencode, int newlines)
1339 {
1340 pdf_processor *proc = NULL;
1341 fz_output *out = fz_new_output_with_buffer(ctx, buffer);
1342 fz_try(ctx)
1343 {
1344 proc = pdf_new_output_processor(ctx, out, ahxencode, newlines);
1345 }
1346 fz_catch(ctx)
1347 {
1348 fz_drop_output(ctx, out);
1349 fz_rethrow(ctx);
1350 }
1351 return proc;
1352 }
1353
1354 /* Simplified processor that only counts matching q/Q pairs. */
1355
1356 typedef struct
1357 {
1358 pdf_processor super;
1359 int *balance;
1360 int *min_q;
1361 int *min_op_q;
1362 int first;
1363 int ending;
1364 } pdf_balance_processor;
1365
1366 static void
1367 pdf_balance_q(fz_context *ctx, pdf_processor *proc_)
1368 {
1369 pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1370 (*proc->balance)++;
1371 }
1372
1373 static void
1374 pdf_balance_Q(fz_context *ctx, pdf_processor *proc_)
1375 {
1376 pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1377
1378 if (proc->ending)
1379 return;
1380
1381 (*proc->balance)--;
1382 if (*proc->balance < *proc->min_q)
1383 *proc->min_q = *proc->balance;
1384 }
1385
1386 static void
1387 pdf_balance_void(fz_context *ctx, pdf_processor *proc_)
1388 {
1389 pdf_balance_processor *proc = (pdf_balance_processor*)proc_;
1390 if (*proc->balance < *proc->min_op_q)
1391 *proc->min_op_q = *proc->balance;
1392 }
1393
1394 #define BALANCE { pdf_balance_void(ctx, p); }
1395
1396 static void pdf_balance_string(fz_context *ctx, pdf_processor *p, const char *x) BALANCE
1397 static void pdf_balance_int(fz_context *ctx, pdf_processor *p, int x) BALANCE
1398 static void pdf_balance_float(fz_context *ctx, pdf_processor *p, float x) BALANCE
1399 static void pdf_balance_float2(fz_context *ctx, pdf_processor *p, float x, float y) BALANCE
1400 static void pdf_balance_float3(fz_context *ctx, pdf_processor *p, float x, float y, float z) BALANCE
1401 static void pdf_balance_float4(fz_context *ctx, pdf_processor *p, float x, float y, float z, float w) BALANCE
1402 static void pdf_balance_float6(fz_context *ctx, pdf_processor *p, float a, float b, float c, float d, float e, float f) BALANCE
1403
1404 static void pdf_balance_d(fz_context *ctx, pdf_processor *p, pdf_obj *array, float phase) BALANCE
1405 static void pdf_balance_gs_begin(fz_context *ctx, pdf_processor *p, const char *name, pdf_obj *extgstate) BALANCE
1406 static void pdf_balance_Tf(fz_context *ctx, pdf_processor *p, const char *name, pdf_font_desc *font, float size) BALANCE
1407 static void pdf_balance_TJ(fz_context *ctx, pdf_processor *p, pdf_obj *array) BALANCE
1408 static void pdf_balance_Tj(fz_context *ctx, pdf_processor *p, char *str, size_t len) BALANCE
1409 static void pdf_balance_squote(fz_context *ctx, pdf_processor *p, char *str, size_t len) BALANCE
1410 static void pdf_balance_dquote(fz_context *ctx, pdf_processor *p, float aw, float ac, char *str, size_t len) BALANCE
1411 static void pdf_balance_cs(fz_context *ctx, pdf_processor *p, const char *name, fz_colorspace *cs) BALANCE
1412 static void pdf_balance_sc_pattern(fz_context *ctx, pdf_processor *p, const char *name, pdf_pattern *pat, int n, float *color) BALANCE
1413 static void pdf_balance_sc_shade(fz_context *ctx, pdf_processor *p, const char *name, fz_shade *shade) BALANCE
1414 static void pdf_balance_sc_color(fz_context *ctx, pdf_processor *p, int n, float *color) BALANCE
1415 static void pdf_balance_BDC(fz_context *ctx, pdf_processor *p, const char *tag, pdf_obj *raw, pdf_obj *cooked) BALANCE
1416 static void pdf_balance_BI(fz_context *ctx, pdf_processor *p, fz_image *img, const char *colorspace) BALANCE
1417 static void pdf_balance_sh(fz_context *ctx, pdf_processor *p, const char *name, fz_shade *shade) BALANCE
1418 static void pdf_balance_Do_image(fz_context *ctx, pdf_processor *p, const char *name, fz_image *image) BALANCE
1419 static void pdf_balance_Do_form(fz_context *ctx, pdf_processor *p, const char *name, pdf_obj *xobj) BALANCE
1420
1421 static void pdf_balance_EOD(fz_context *ctx, pdf_processor *p)
1422 {
1423 pdf_balance_processor *proc = (pdf_balance_processor *)p;
1424
1425 proc->ending = 1;
1426 }
1427
1428 static pdf_processor *
1429 pdf_new_balance_processor(fz_context *ctx, int *balance, int *min_q, int *min_op_q)
1430 {
1431 pdf_balance_processor *proc = pdf_new_processor(ctx, sizeof *proc);
1432
1433 proc->super.op_q = pdf_balance_q;
1434 proc->super.op_Q = pdf_balance_Q;
1435
1436 /* general graphics state */
1437 proc->super.op_w = pdf_balance_float;
1438 proc->super.op_j = pdf_balance_int;
1439 proc->super.op_J = pdf_balance_int;
1440 proc->super.op_M = pdf_balance_float;
1441 proc->super.op_d = pdf_balance_d;
1442 proc->super.op_ri = pdf_balance_string;
1443 proc->super.op_i = pdf_balance_float;
1444 proc->super.op_gs_begin = pdf_balance_gs_begin;
1445
1446 /* special graphics state */
1447 proc->super.op_cm = pdf_balance_float6;
1448
1449 /* path construction */
1450 proc->super.op_m = pdf_balance_float2;
1451 proc->super.op_l = pdf_balance_float2;
1452 proc->super.op_c = pdf_balance_float6;
1453 proc->super.op_v = pdf_balance_float4;
1454 proc->super.op_y = pdf_balance_float4;
1455 proc->super.op_h = pdf_balance_void;
1456 proc->super.op_re = pdf_balance_float4;
1457
1458 /* path painting */
1459 proc->super.op_S = pdf_balance_void;
1460 proc->super.op_s = pdf_balance_void;
1461 proc->super.op_F = pdf_balance_void;
1462 proc->super.op_f = pdf_balance_void;
1463 proc->super.op_fstar = pdf_balance_void;
1464 proc->super.op_B = pdf_balance_void;
1465 proc->super.op_Bstar = pdf_balance_void;
1466 proc->super.op_b = pdf_balance_void;
1467 proc->super.op_bstar = pdf_balance_void;
1468 proc->super.op_n = pdf_balance_void;
1469
1470 /* clipping paths */
1471 proc->super.op_W = pdf_balance_void;
1472 proc->super.op_Wstar = pdf_balance_void;
1473
1474 /* text objects */
1475 proc->super.op_BT = pdf_balance_void;
1476 proc->super.op_ET = pdf_balance_void;
1477
1478 /* text state */
1479 proc->super.op_Tc = pdf_balance_float;
1480 proc->super.op_Tw = pdf_balance_float;
1481 proc->super.op_Tz = pdf_balance_float;
1482 proc->super.op_TL = pdf_balance_float;
1483 proc->super.op_Tf = pdf_balance_Tf;
1484 proc->super.op_Tr = pdf_balance_int;
1485 proc->super.op_Ts = pdf_balance_float;
1486
1487 /* text positioning */
1488 proc->super.op_Td = pdf_balance_float2;
1489 proc->super.op_TD = pdf_balance_float2;
1490 proc->super.op_Tm = pdf_balance_float6;
1491 proc->super.op_Tstar = pdf_balance_void;
1492
1493 /* text showing */
1494 proc->super.op_TJ = pdf_balance_TJ;
1495 proc->super.op_Tj = pdf_balance_Tj;
1496 proc->super.op_squote = pdf_balance_squote;
1497 proc->super.op_dquote = pdf_balance_dquote;
1498
1499 /* type 3 fonts */
1500 proc->super.op_d0 = pdf_balance_float2;
1501 proc->super.op_d1 = pdf_balance_float6;
1502
1503 /* color */
1504 proc->super.op_CS = pdf_balance_cs;
1505 proc->super.op_cs = pdf_balance_cs;
1506 proc->super.op_SC_color = pdf_balance_sc_color;
1507 proc->super.op_sc_color = pdf_balance_sc_color;
1508 proc->super.op_SC_pattern = pdf_balance_sc_pattern;
1509 proc->super.op_sc_pattern = pdf_balance_sc_pattern;
1510 proc->super.op_SC_shade = pdf_balance_sc_shade;
1511 proc->super.op_sc_shade = pdf_balance_sc_shade;
1512
1513 proc->super.op_G = pdf_balance_float;
1514 proc->super.op_g = pdf_balance_float;
1515 proc->super.op_RG = pdf_balance_float3;
1516 proc->super.op_rg = pdf_balance_float3;
1517 proc->super.op_K = pdf_balance_float4;
1518 proc->super.op_k = pdf_balance_float4;
1519
1520 /* shadings, images, xobjects */
1521 proc->super.op_BI = pdf_balance_BI;
1522 proc->super.op_sh = pdf_balance_sh;
1523 proc->super.op_Do_image = pdf_balance_Do_image;
1524 proc->super.op_Do_form = pdf_balance_Do_form;
1525
1526 /* marked content */
1527 proc->super.op_MP = pdf_balance_string;
1528 proc->super.op_DP = pdf_balance_BDC;
1529 proc->super.op_BMC = pdf_balance_string;
1530 proc->super.op_BDC = pdf_balance_BDC;
1531 proc->super.op_EMC = pdf_balance_void;
1532
1533 /* compatibility */
1534 proc->super.op_BX = pdf_balance_void;
1535 proc->super.op_EX = pdf_balance_void;
1536
1537 proc->super.op_EOD = pdf_balance_EOD;
1538
1539 proc->balance = balance;
1540 proc->min_q = min_q;
1541 proc->min_op_q = min_op_q;
1542
1543 return (pdf_processor*)proc;
1544 }
1545
1546 void
1547 pdf_count_q_balance(fz_context *ctx, pdf_document *doc, pdf_obj *res, pdf_obj *stm, int *prepend, int *append)
1548 {
1549 pdf_processor *proc;
1550
1551 int end_q = 0;
1552 int min_q = 0;
1553 int min_op_q = 1;
1554
1555 proc = pdf_new_balance_processor(ctx, &end_q, &min_q, &min_op_q);
1556 fz_try(ctx)
1557 {
1558 pdf_process_raw_contents(ctx, proc, doc, res, stm, NULL);
1559 pdf_close_processor(ctx, proc);
1560 }
1561 fz_always(ctx)
1562 pdf_drop_processor(ctx, proc);
1563 fz_catch(ctx)
1564 fz_rethrow(ctx);
1565
1566 /* normally zero, but in bad files there could be more Q than q */
1567 *prepend = -min_q;
1568
1569 /* how many Q are missing at the end */
1570 *append = end_q - min_q;
1571
1572 /* if there are unguarded operators we must add one level of q/Q around everything */
1573 if (min_op_q == min_q)
1574 {
1575 *prepend += 1;
1576 *append += 1;
1577 }
1578 }