Coverage Report

Created: 2026-06-30 07:15

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