1 /* Copyright (C) 1999, 2000, 2001 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevpdfu.c,v 1.16.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /* Output utilities for PDF-writing driver */
21 #include "memory_.h"
22 #include "jpeglib_.h" /* for sdct.h */
23 #include "string_.h"
24 #include "gx.h"
25 #include "gserrors.h"
26 #include "gscdefs.h"
27 #include "gsdsrc.h"
28 #include "gsfunc.h"
29 #include "gdevpdfx.h"
30 #include "gdevpdfo.h"
31 #include "scanchar.h"
32 #include "strimpl.h"
33 #include "sa85x.h"
34 #include "scfx.h"
35 #include "sdct.h"
36 #include "slzwx.h"
37 #include "spngpx.h"
38 #include "srlx.h"
39 #include "sstring.h"
40 #include "szlibx.h"
41
42 /* Define the size of internal stream buffers. */
43 /* (This is not a limitation, it only affects performance.) */
44 #define sbuf_size 512
45
46 /* Optionally substitute other filters for FlateEncode for debugging. */
47 #if 1
48 # define compression_filter_name "FlateDecode"
49 # define compression_filter_template s_zlibE_template
50 # define compression_filter_state stream_zlib_state
51 #else
52 # include "slzwx.h"
53 # define compression_filter_name "LZWDecode"
54 # define compression_filter_template s_LZWE_template
55 # define compression_filter_state stream_LZW_state
56 #endif
57
58 /* Import procedures for writing filter parameters. */
59 extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state);
60 extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state);
61
62 #define CHECK(expr)\
63 BEGIN if ((code = (expr)) < 0) return code; END
64
65 /* GC descriptors */
66 extern_st(st_pdf_font);
67 extern_st(st_pdf_char_proc);
68 extern_st(st_pdf_font_descriptor);
69 public_st_pdf_resource();
70 private_st_pdf_x_object();
71
72 /* ---------------- Utilities ---------------- */
73
74 /* ------ Document ------ */
75
76 /* Open the document if necessary. */
77 void
pdf_open_document(gx_device_pdf * pdev)78 pdf_open_document(gx_device_pdf * pdev)
79 {
80 if (!is_in_page(pdev) && pdf_stell(pdev) == 0) {
81 stream *s = pdev->strm;
82 int level = (int)(pdev->CompatibilityLevel * 10 + 0.5);
83
84 pprintd2(s, "%%PDF-%d.%d\n", level / 10, level % 10);
85 pdev->binary_ok = !pdev->params.ASCII85EncodePages;
86 if (pdev->binary_ok)
87 stream_puts(s, "%\307\354\217\242\n");
88 }
89 /*
90 * Determine the compression method. Currently this does nothing.
91 * It also isn't clear whether the compression method can now be
92 * changed in the course of the document.
93 *
94 * The following algorithm is per an update to TN # 5151 by
95 * Adobe Developer Support.
96 */
97 if (!pdev->params.CompressPages)
98 pdev->compression = pdf_compress_none;
99 else if (pdev->CompatibilityLevel < 1.2)
100 pdev->compression = pdf_compress_LZW;
101 else if (pdev->params.UseFlateCompression)
102 pdev->compression = pdf_compress_Flate;
103 else
104 pdev->compression = pdf_compress_LZW;
105 }
106
107 /* ------ Objects ------ */
108
109 /* Allocate an object ID. */
110 private long
pdf_next_id(gx_device_pdf * pdev)111 pdf_next_id(gx_device_pdf * pdev)
112 {
113 return (pdev->next_id)++;
114 }
115
116 /*
117 * Return the current position in the output. Note that this may be in the
118 * main output file, the asides file, or the pictures file. If the current
119 * file is the pictures file, positions returned by pdf_stell must only be
120 * used locally (for computing lengths or patching), since there is no way
121 * to map them later to the eventual position in the output file.
122 */
123 long
pdf_stell(gx_device_pdf * pdev)124 pdf_stell(gx_device_pdf * pdev)
125 {
126 stream *s = pdev->strm;
127 long pos = stell(s);
128
129 if (s == pdev->asides.strm)
130 pos += ASIDES_BASE_POSITION;
131 return pos;
132 }
133
134 /* Allocate an ID for a future object. */
135 long
pdf_obj_ref(gx_device_pdf * pdev)136 pdf_obj_ref(gx_device_pdf * pdev)
137 {
138 long id = pdf_next_id(pdev);
139 long pos = pdf_stell(pdev);
140
141 fwrite(&pos, sizeof(pos), 1, pdev->xref.file);
142 return id;
143 }
144
145 /* Begin an object, optionally allocating an ID. */
146 long
pdf_open_obj(gx_device_pdf * pdev,long id)147 pdf_open_obj(gx_device_pdf * pdev, long id)
148 {
149 stream *s = pdev->strm;
150
151 if (id <= 0) {
152 id = pdf_obj_ref(pdev);
153 } else {
154 long pos = pdf_stell(pdev);
155 FILE *tfile = pdev->xref.file;
156 long tpos = ftell(tfile);
157
158 fseek(tfile, (id - pdev->FirstObjectNumber) * sizeof(pos),
159 SEEK_SET);
160 fwrite(&pos, sizeof(pos), 1, tfile);
161 fseek(tfile, tpos, SEEK_SET);
162 }
163 pprintld1(s, "%ld 0 obj\n", id);
164 return id;
165 }
166 long
pdf_begin_obj(gx_device_pdf * pdev)167 pdf_begin_obj(gx_device_pdf * pdev)
168 {
169 return pdf_open_obj(pdev, 0L);
170 }
171
172 /* End an object. */
173 int
pdf_end_obj(gx_device_pdf * pdev)174 pdf_end_obj(gx_device_pdf * pdev)
175 {
176 stream_puts(pdev->strm, "endobj\n");
177 return 0;
178 }
179
180 /* ------ Page contents ------ */
181
182 /* Handle transitions between contexts. */
183 private int
184 none_to_stream(P1(gx_device_pdf *)), stream_to_text(P1(gx_device_pdf *)),
185 string_to_text(P1(gx_device_pdf *)), text_to_stream(P1(gx_device_pdf *)),
186 stream_to_none(P1(gx_device_pdf *));
187 typedef int (*context_proc) (P1(gx_device_pdf *));
188 private const context_proc context_procs[4][4] =
189 {
190 {0, none_to_stream, none_to_stream, none_to_stream},
191 {stream_to_none, 0, stream_to_text, stream_to_text},
192 {text_to_stream, text_to_stream, 0, 0},
193 {string_to_text, string_to_text, string_to_text, 0}
194 };
195
196 /* Enter stream context. */
197 private int
none_to_stream(gx_device_pdf * pdev)198 none_to_stream(gx_device_pdf * pdev)
199 {
200 stream *s;
201
202 if (pdev->contents_id != 0)
203 return_error(gs_error_Fatal); /* only 1 contents per page */
204 pdev->contents_id = pdf_begin_obj(pdev);
205 pdev->contents_length_id = pdf_obj_ref(pdev);
206 s = pdev->strm;
207 pprintld1(s, "<</Length %ld 0 R", pdev->contents_length_id);
208 if (pdev->compression == pdf_compress_Flate)
209 pprints1(s, "/Filter /%s", compression_filter_name);
210 stream_puts(s, ">>\nstream\n");
211 pdev->contents_pos = pdf_stell(pdev);
212 if (pdev->compression == pdf_compress_Flate) { /* Set up the Flate filter. */
213 const stream_template *template = &compression_filter_template;
214 stream *es = s_alloc(pdev->pdf_memory, "PDF compression stream");
215 byte *buf = gs_alloc_bytes(pdev->pdf_memory, sbuf_size,
216 "PDF compression buffer");
217 compression_filter_state *st =
218 gs_alloc_struct(pdev->pdf_memory, compression_filter_state,
219 template->stype, "PDF compression state");
220
221 if (es == 0 || st == 0 || buf == 0)
222 return_error(gs_error_VMerror);
223 s_std_init(es, buf, sbuf_size, &s_filter_write_procs,
224 s_mode_write);
225 st->memory = pdev->pdf_memory;
226 st->template = template;
227 es->state = (stream_state *) st;
228 es->procs.process = template->process;
229 es->strm = s;
230 (*template->set_defaults) ((stream_state *) st);
231 (*template->init) ((stream_state *) st);
232 pdev->strm = s = es;
233 }
234 /*
235 * Scale the coordinate system. Use an extra level of q/Q for the
236 * sake of poorly designed PDF tools that assume that the contents
237 * stream restores the CTM.
238 */
239 pprintg2(s, "q %g 0 0 %g 0 0 cm\n",
240 72.0 / pdev->HWResolution[0], 72.0 / pdev->HWResolution[1]);
241 if (pdev->CompatibilityLevel >= 1.3) {
242 /* Set the default rendering intent. */
243 if (pdev->params.DefaultRenderingIntent != ri_Default) {
244 static const char *const ri_names[] = { psdf_ri_names };
245
246 pprints1(s, "/%s ri\n",
247 ri_names[(int)pdev->params.DefaultRenderingIntent]);
248 }
249 }
250 /* Do a level of gsave for the clipping path. */
251 stream_puts(s, "q\n");
252 return PDF_IN_STREAM;
253 }
254 /* Enter text context from stream context. */
255 private int
stream_to_text(gx_device_pdf * pdev)256 stream_to_text(gx_device_pdf * pdev)
257 {
258 /*
259 * Bizarrely enough, Acrobat Reader cares how the final font size is
260 * obtained -- the CTM (cm), text matrix (Tm), and font size (Tf)
261 * are *not* all equivalent. In particular, it seems to use the
262 * product of the text matrix and font size to decide how to
263 * anti-alias characters. Therefore, we have to temporarily patch
264 * the CTM so that the scale factors are unity. What a nuisance!
265 */
266 pprintg2(pdev->strm, "q %g 0 0 %g 0 0 cm BT\n",
267 pdev->HWResolution[0] / 72.0, pdev->HWResolution[1] / 72.0);
268 pdev->procsets |= Text;
269 gs_make_identity(&pdev->text.matrix);
270 pdev->text.line_start.x = pdev->text.line_start.y = 0;
271 pdev->text.buffer_count = 0;
272 return PDF_IN_TEXT;
273 }
274 /* Exit string context to text context. */
275 private int
string_to_text(gx_device_pdf * pdev)276 string_to_text(gx_device_pdf * pdev)
277 {
278 pdf_put_string(pdev, pdev->text.buffer, pdev->text.buffer_count);
279 stream_puts(pdev->strm, (pdev->text.use_leading ? "'\n" : "Tj\n"));
280 pdev->text.use_leading = false;
281 pdev->text.buffer_count = 0;
282 return PDF_IN_TEXT;
283 }
284 /* Exit text context to stream context. */
285 private int
text_to_stream(gx_device_pdf * pdev)286 text_to_stream(gx_device_pdf * pdev)
287 {
288 stream_puts(pdev->strm, "ET Q\n");
289 pdf_reset_text(pdev); /* because of Q */
290 return PDF_IN_STREAM;
291 }
292 /* Exit stream context. */
293 private int
stream_to_none(gx_device_pdf * pdev)294 stream_to_none(gx_device_pdf * pdev)
295 {
296 stream *s = pdev->strm;
297 long length;
298
299 /* Close the extra q/Q for poorly designed PDF tools. */
300 stream_puts(s, "Q\n");
301 if (pdev->compression == pdf_compress_Flate) { /* Terminate the Flate filter. */
302 stream *fs = s->strm;
303
304 sclose(s);
305 gs_free_object(pdev->pdf_memory, s->cbuf, "zlib buffer");
306 gs_free_object(pdev->pdf_memory, s, "zlib stream");
307 pdev->strm = s = fs;
308 }
309 length = pdf_stell(pdev) - pdev->contents_pos;
310 stream_puts(s, "endstream\n");
311 pdf_end_obj(pdev);
312 pdf_open_obj(pdev, pdev->contents_length_id);
313 pprintld1(s, "%ld\n", length);
314 pdf_end_obj(pdev);
315 return PDF_IN_NONE;
316 }
317
318 /* Begin a page contents part. */
319 int
pdf_open_contents(gx_device_pdf * pdev,pdf_context_t context)320 pdf_open_contents(gx_device_pdf * pdev, pdf_context_t context)
321 {
322 int (*proc) (P1(gx_device_pdf *));
323
324 while ((proc = context_procs[pdev->context][context]) != 0) {
325 int code = (*proc) (pdev);
326
327 if (code < 0)
328 return code;
329 pdev->context = (pdf_context_t) code;
330 }
331 pdev->context = context;
332 return 0;
333 }
334
335 /* Close the current contents part if we are in one. */
336 int
pdf_close_contents(gx_device_pdf * pdev,bool last)337 pdf_close_contents(gx_device_pdf * pdev, bool last)
338 {
339 if (pdev->context == PDF_IN_NONE)
340 return 0;
341 if (last) { /* Exit from the clipping path gsave. */
342 pdf_open_contents(pdev, PDF_IN_STREAM);
343 stream_puts(pdev->strm, "Q\n");
344 pdev->text.font = 0;
345 }
346 return pdf_open_contents(pdev, PDF_IN_NONE);
347 }
348
349 /* ------ Resources et al ------ */
350
351 /* Define the allocator descriptors for the resource types. */
352 const char *const pdf_resource_type_names[] = {
353 PDF_RESOURCE_TYPE_NAMES
354 };
355 const gs_memory_struct_type_t *const pdf_resource_type_structs[] = {
356 PDF_RESOURCE_TYPE_STRUCTS
357 };
358
359 /* Find a resource of a given type by gs_id. */
360 pdf_resource_t *
pdf_find_resource_by_gs_id(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid)361 pdf_find_resource_by_gs_id(gx_device_pdf * pdev, pdf_resource_type_t rtype,
362 gs_id rid)
363 {
364 pdf_resource_t **pchain = PDF_RESOURCE_CHAIN(pdev, rtype, rid);
365 pdf_resource_t **pprev = pchain;
366 pdf_resource_t *pres;
367
368 for (; (pres = *pprev) != 0; pprev = &pres->next)
369 if (pres->rid == rid) {
370 if (pprev != pchain) {
371 *pprev = pres->next;
372 pres->next = *pchain;
373 *pchain = pres;
374 }
375 return pres;
376 }
377 return 0;
378 }
379
380 /* Begin an object logically separate from the contents. */
381 long
pdf_open_separate(gx_device_pdf * pdev,long id)382 pdf_open_separate(gx_device_pdf * pdev, long id)
383 {
384 pdf_open_document(pdev);
385 pdev->asides.save_strm = pdev->strm;
386 pdev->strm = pdev->asides.strm;
387 return pdf_open_obj(pdev, id);
388 }
389 long
pdf_begin_separate(gx_device_pdf * pdev)390 pdf_begin_separate(gx_device_pdf * pdev)
391 {
392 return pdf_open_separate(pdev, 0L);
393 }
394
395 /* Begin an aside (resource, annotation, ...). */
396 private int
pdf_alloc_aside(gx_device_pdf * pdev,pdf_resource_t ** plist,const gs_memory_struct_type_t * pst,pdf_resource_t ** ppres,long id)397 pdf_alloc_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
398 const gs_memory_struct_type_t * pst, pdf_resource_t **ppres,
399 long id)
400 {
401 pdf_resource_t *pres;
402 cos_object_t *object;
403
404 if (pst == NULL)
405 pst = &st_pdf_resource;
406 pres = gs_alloc_struct(pdev->pdf_memory, pdf_resource_t, pst,
407 "pdf_alloc_aside(resource)");
408 object = cos_object_alloc(pdev, "pdf_alloc_aside(object)");
409 if (pres == 0 || object == 0) {
410 return_error(gs_error_VMerror);
411 }
412 if (id < 0) {
413 object->id = -1L;
414 pres->rname[0] = 0;
415 } else {
416 object->id = (id == 0 ? pdf_obj_ref(pdev) : id);
417 sprintf(pres->rname, "R%ld", object->id);
418 }
419 pres->next = *plist;
420 *plist = pres;
421 pres->prev = pdev->last_resource;
422 pdev->last_resource = pres;
423 pres->named = false;
424 pres->where_used = pdev->used_mask;
425 pres->object = object;
426 *ppres = pres;
427 return 0;
428 }
429 int
pdf_begin_aside(gx_device_pdf * pdev,pdf_resource_t ** plist,const gs_memory_struct_type_t * pst,pdf_resource_t ** ppres)430 pdf_begin_aside(gx_device_pdf * pdev, pdf_resource_t ** plist,
431 const gs_memory_struct_type_t * pst, pdf_resource_t ** ppres)
432 {
433 long id = pdf_begin_separate(pdev);
434
435 if (id < 0)
436 return (int)id;
437 return pdf_alloc_aside(pdev, plist, pst, ppres, id);
438 }
439
440 /* Begin a resource of a given type. */
441 int
pdf_begin_resource_body(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)442 pdf_begin_resource_body(gx_device_pdf * pdev, pdf_resource_type_t rtype,
443 gs_id rid, pdf_resource_t ** ppres)
444 {
445 int code = pdf_begin_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
446 pdf_resource_type_structs[rtype], ppres);
447
448 if (code >= 0)
449 (*ppres)->rid = rid;
450 return code;
451 }
452 int
pdf_begin_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres)453 pdf_begin_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
454 pdf_resource_t ** ppres)
455 {
456 int code = pdf_begin_resource_body(pdev, rtype, rid, ppres);
457
458 if (code >= 0 && pdf_resource_type_names[rtype] != 0) {
459 stream *s = pdev->strm;
460
461 pprints1(s, "<</Type%s", pdf_resource_type_names[rtype]);
462 pprintld1(s, "/Name/R%ld", (*ppres)->object->id);
463 }
464 return code;
465 }
466
467 /* Allocate a resource, but don't open the stream. */
468 int
pdf_alloc_resource(gx_device_pdf * pdev,pdf_resource_type_t rtype,gs_id rid,pdf_resource_t ** ppres,long id)469 pdf_alloc_resource(gx_device_pdf * pdev, pdf_resource_type_t rtype, gs_id rid,
470 pdf_resource_t ** ppres, long id)
471 {
472 int code = pdf_alloc_aside(pdev, PDF_RESOURCE_CHAIN(pdev, rtype, rid),
473 pdf_resource_type_structs[rtype], ppres, id);
474
475 if (code >= 0)
476 (*ppres)->rid = rid;
477 return code;
478 }
479
480 /* Get the object id of a resource. */
481 long
pdf_resource_id(const pdf_resource_t * pres)482 pdf_resource_id(const pdf_resource_t *pres)
483 {
484 return pres->object->id;
485 }
486
487 /* End an aside or other separate object. */
488 int
pdf_end_separate(gx_device_pdf * pdev)489 pdf_end_separate(gx_device_pdf * pdev)
490 {
491 int code = pdf_end_obj(pdev);
492
493 pdev->strm = pdev->asides.save_strm;
494 pdev->asides.save_strm = 0;
495 return code;
496 }
497 int
pdf_end_aside(gx_device_pdf * pdev)498 pdf_end_aside(gx_device_pdf * pdev)
499 {
500 return pdf_end_separate(pdev);
501 }
502
503 /* End a resource. */
504 int
pdf_end_resource(gx_device_pdf * pdev)505 pdf_end_resource(gx_device_pdf * pdev)
506 {
507 return pdf_end_aside(pdev);
508 }
509
510 /*
511 * Write and release the Cos objects for resources local to a content stream.
512 * We must write all the objects before freeing any of them, because
513 * they might refer to each other.
514 */
515 int
pdf_write_resource_objects(gx_device_pdf * pdev,pdf_resource_type_t rtype)516 pdf_write_resource_objects(gx_device_pdf *pdev, pdf_resource_type_t rtype)
517 {
518 int j;
519
520 /* Write objects. */
521 for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
522 pdf_resource_t *pres = pdev->resources[rtype].chains[j];
523
524 for (; pres != 0; pres = pres->next)
525 if (!pres->named && !pres->object->written)
526 cos_write_object(pres->object, pdev);
527 }
528
529 /* Free unnamed objects, which can't be used again. */
530 for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
531 pdf_resource_t **prev = &pdev->resources[rtype].chains[j];
532 pdf_resource_t *pres;
533
534 while ((pres = *prev) != 0) {
535 if (pres->named) { /* named, don't free */
536 prev = &pres->next;
537 } else {
538 cos_free(pres->object, "pdf_write_resource_objects");
539 pres->object = 0;
540 *prev = pres->next;
541 }
542 }
543 }
544
545 return 0;
546 }
547
548 /*
549 * Store the resource sets for a content stream (page or XObject).
550 * Sets page->{procsets, resource_ids[]}.
551 */
552 int
pdf_store_page_resources(gx_device_pdf * pdev,pdf_page_t * page)553 pdf_store_page_resources(gx_device_pdf *pdev, pdf_page_t *page)
554 {
555
556 /* Write out any resource dictionaries. */
557
558 {
559 int i;
560
561 for (i = 0; i <= resourceFont; ++i) {
562 stream *s = 0;
563 int j;
564
565 page->resource_ids[i] = 0;
566 for (j = 0; j < NUM_RESOURCE_CHAINS; ++j) {
567 pdf_resource_t *pres = pdev->resources[i].chains[j];
568
569 for (; pres != 0; pres = pres->next) {
570 if (pres->where_used & pdev->used_mask) {
571 long id = pres->object->id;
572
573 if (s == 0) {
574 page->resource_ids[i] = pdf_begin_separate(pdev);
575 s = pdev->strm;
576 stream_puts(s, "<<");
577 }
578 pprints1(s, "/%s\n", pres->rname);
579 pprintld1(s, "%ld 0 R", id);
580 pres->where_used -= pdev->used_mask;
581 }
582 }
583 }
584 if (s) {
585 stream_puts(s, ">>\n");
586 pdf_end_separate(pdev);
587 if (i != resourceFont)
588 pdf_write_resource_objects(pdev, i);
589 }
590 }
591 }
592
593 page->procsets = pdev->procsets;
594 return 0;
595 }
596
597 /* Copy data from a temporary file to a stream. */
598 void
pdf_copy_data(stream * s,FILE * file,long count)599 pdf_copy_data(stream *s, FILE *file, long count)
600 {
601 long left = count;
602 byte buf[sbuf_size];
603
604 while (left > 0) {
605 uint copy = min(left, sbuf_size);
606
607 fread(buf, 1, sbuf_size, file);
608 stream_write(s, buf, copy);
609 left -= copy;
610 }
611 }
612
613 /* ------ Pages ------ */
614
615 /* Get or assign the ID for a page. */
616 /* Returns 0 if the page number is out of range. */
617 long
pdf_page_id(gx_device_pdf * pdev,int page_num)618 pdf_page_id(gx_device_pdf * pdev, int page_num)
619 {
620 cos_dict_t *Page;
621
622 if (page_num < 1)
623 return 0;
624 if (page_num >= pdev->num_pages) { /* Grow the pages array. */
625 uint new_num_pages =
626 max(page_num + 10, pdev->num_pages << 1);
627 pdf_page_t *new_pages =
628 gs_resize_object(pdev->pdf_memory, pdev->pages, new_num_pages,
629 "pdf_page_id(resize pages)");
630
631 if (new_pages == 0)
632 return 0;
633 memset(&new_pages[pdev->num_pages], 0,
634 (new_num_pages - pdev->num_pages) * sizeof(pdf_page_t));
635 pdev->pages = new_pages;
636 pdev->num_pages = new_num_pages;
637 }
638 if ((Page = pdev->pages[page_num - 1].Page) == 0) {
639 pdev->pages[page_num - 1].Page = Page =
640 cos_dict_alloc(pdev, "pdf_page_id");
641 Page->id = pdf_obj_ref(pdev);
642 }
643 return Page->id;
644 }
645
646 /* Get the page structure for the current page. */
647 pdf_page_t *
pdf_current_page(gx_device_pdf * pdev)648 pdf_current_page(gx_device_pdf *pdev)
649 {
650 return &pdev->pages[pdev->next_page];
651 }
652
653 /* Get the dictionary object for the current page. */
654 cos_dict_t *
pdf_current_page_dict(gx_device_pdf * pdev)655 pdf_current_page_dict(gx_device_pdf *pdev)
656 {
657 if (pdf_page_id(pdev, pdev->next_page + 1) <= 0)
658 return 0;
659 return pdev->pages[pdev->next_page].Page;
660 }
661
662 /* Write saved page- or document-level information. */
663 int
pdf_write_saved_string(gx_device_pdf * pdev,gs_string * pstr)664 pdf_write_saved_string(gx_device_pdf * pdev, gs_string * pstr)
665 {
666 if (pstr->data != 0) {
667 stream_write(pdev->strm, pstr->data, pstr->size);
668 gs_free_string(pdev->pdf_memory, pstr->data, pstr->size,
669 "pdf_write_saved_string");
670 pstr->data = 0;
671 }
672 return 0;
673 }
674
675 /* Open a page for writing. */
676 int
pdf_open_page(gx_device_pdf * pdev,pdf_context_t context)677 pdf_open_page(gx_device_pdf * pdev, pdf_context_t context)
678 {
679 if (!is_in_page(pdev)) {
680 if (pdf_page_id(pdev, pdev->next_page + 1) == 0)
681 return_error(gs_error_VMerror);
682 pdf_open_document(pdev);
683 }
684 /* Note that context may be PDF_IN_NONE here. */
685 return pdf_open_contents(pdev, context);
686 }
687
688 /* ------ Miscellaneous output ------ */
689
690 /* Generate the default Producer string. */
691 void
pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])692 pdf_store_default_Producer(char buf[PDF_MAX_PRODUCER])
693 {
694 sprintf(buf, ((gs_revision % 100) == 0 ? "(%s %1.1f)" : "(%s %1.2f)"),
695 gs_product, gs_revision / 100.0);
696 }
697
698 /* Write matrix values. */
699 void
pdf_put_matrix(gx_device_pdf * pdev,const char * before,const gs_matrix * pmat,const char * after)700 pdf_put_matrix(gx_device_pdf * pdev, const char *before,
701 const gs_matrix * pmat, const char *after)
702 {
703 stream *s = pdev->strm;
704
705 if (before)
706 stream_puts(s, before);
707 pprintg6(s, "%g %g %g %g %g %g ",
708 pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
709 if (after)
710 stream_puts(s, after);
711 }
712
713 /*
714 * Write a name, with escapes for unusual characters. In PDF 1.1, we have
715 * no choice but to replace these characters with '?'; in PDF 1.2, we can
716 * use an escape sequence for anything except a null <00>.
717 */
718 private int
pdf_put_name_chars_1_1(stream * s,const byte * nstr,uint size)719 pdf_put_name_chars_1_1(stream *s, const byte *nstr, uint size)
720 {
721 uint i;
722
723 for (i = 0; i < size; ++i) {
724 uint c = nstr[i];
725
726 switch (c) {
727 default:
728 if (c >= 0x21 && c <= 0x7e) {
729 stream_putc(s, c);
730 break;
731 }
732 /* falls through */
733 case '%':
734 case '(': case ')':
735 case '<': case '>':
736 case '[': case ']':
737 case '{': case '}':
738 case '/':
739 case 0:
740 stream_putc(s, '?');
741 }
742 }
743 return 0;
744 }
745 private int
pdf_put_name_chars_1_2(stream * s,const byte * nstr,uint size)746 pdf_put_name_chars_1_2(stream *s, const byte *nstr, uint size)
747 {
748 uint i;
749
750 for (i = 0; i < size; ++i) {
751 uint c = nstr[i];
752 char hex[4];
753
754 switch (c) {
755 default:
756 if (c >= 0x21 && c <= 0x7e) {
757 stream_putc(s, c);
758 break;
759 }
760 /* falls through */
761 case '#':
762 case '%':
763 case '(': case ')':
764 case '<': case '>':
765 case '[': case ']':
766 case '{': case '}':
767 case '/':
768 sprintf(hex, "#%02x", c);
769 stream_puts(s, hex);
770 break;
771 case 0:
772 stream_putc(s, '?');
773 }
774 }
775 return 0;
776 }
777 pdf_put_name_chars_proc_t
pdf_put_name_chars_proc(const gx_device_pdf * pdev)778 pdf_put_name_chars_proc(const gx_device_pdf *pdev)
779 {
780 return (pdev->CompatibilityLevel >= 1.2 ? pdf_put_name_chars_1_2 :
781 pdf_put_name_chars_1_1);
782 }
783 void
pdf_put_name_chars(const gx_device_pdf * pdev,const byte * nstr,uint size)784 pdf_put_name_chars(const gx_device_pdf *pdev, const byte *nstr, uint size)
785 {
786 DISCARD(pdf_put_name_chars_proc(pdev)(pdev->strm, nstr, size));
787 }
788 void
pdf_put_name(const gx_device_pdf * pdev,const byte * nstr,uint size)789 pdf_put_name(const gx_device_pdf *pdev, const byte *nstr, uint size)
790 {
791 stream_putc(pdev->strm, '/');
792 pdf_put_name_chars(pdev, nstr, size);
793 }
794
795 /*
796 * Write a string in its shortest form ( () or <> ). Note that
797 * this form is different depending on whether binary data are allowed.
798 * We wish PDF supported ASCII85 strings ( <~ ~> ), but it doesn't.
799 */
800 void
pdf_put_string(const gx_device_pdf * pdev,const byte * str,uint size)801 pdf_put_string(const gx_device_pdf * pdev, const byte * str, uint size)
802 {
803 psdf_write_string(pdev->strm, str, size,
804 (pdev->binary_ok ? PRINT_BINARY_OK : 0));
805 }
806
807 /* Write a value, treating names specially. */
808 void
pdf_write_value(const gx_device_pdf * pdev,const byte * vstr,uint size)809 pdf_write_value(const gx_device_pdf * pdev, const byte * vstr, uint size)
810 {
811 if (size > 0 && vstr[0] == '/')
812 pdf_put_name(pdev, vstr + 1, size - 1);
813 else
814 stream_write(pdev->strm, vstr, size);
815 }
816
817 /* Store filters for a stream. */
818 /* Currently this only saves parameters for CCITTFaxDecode. */
819 int
pdf_put_filters(cos_dict_t * pcd,gx_device_pdf * pdev,stream * s,const pdf_filter_names_t * pfn)820 pdf_put_filters(cos_dict_t *pcd, gx_device_pdf *pdev, stream *s,
821 const pdf_filter_names_t *pfn)
822 {
823 const char *filter_name = 0;
824 bool binary_ok = true;
825 stream *fs = s;
826 cos_dict_t *decode_parms = 0;
827 int code;
828
829 for (; fs != 0; fs = fs->strm) {
830 const stream_state *st = fs->state;
831 const stream_template *template = st->template;
832
833 #define TEMPLATE_IS(atemp)\
834 (template->process == (atemp).process)
835 if (TEMPLATE_IS(s_A85E_template))
836 binary_ok = false;
837 else if (TEMPLATE_IS(s_CFE_template)) {
838 cos_param_list_writer_t writer;
839 stream_CF_state cfs;
840
841 decode_parms =
842 cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
843 if (decode_parms == 0)
844 return_error(gs_error_VMerror);
845 CHECK(cos_param_list_writer_init(&writer, decode_parms, 0));
846 /*
847 * If EndOfBlock is true, we mustn't write out a Rows value.
848 * This is a hack....
849 */
850 cfs = *(const stream_CF_state *)st;
851 if (cfs.EndOfBlock)
852 cfs.Rows = 0;
853 CHECK(s_CF_get_params((gs_param_list *)&writer, &cfs, false));
854 filter_name = pfn->CCITTFaxDecode;
855 } else if (TEMPLATE_IS(s_DCTE_template))
856 filter_name = pfn->DCTDecode;
857 else if (TEMPLATE_IS(s_zlibE_template))
858 filter_name = pfn->FlateDecode;
859 else if (TEMPLATE_IS(s_LZWE_template))
860 filter_name = pfn->LZWDecode;
861 else if (TEMPLATE_IS(s_PNGPE_template)) {
862 /* This is a predictor for FlateDecode or LZWEncode. */
863 const stream_PNGP_state *const ss =
864 (const stream_PNGP_state *)st;
865
866 decode_parms =
867 cos_dict_alloc(pdev, "pdf_put_image_filters(decode_parms)");
868 if (decode_parms == 0)
869 return_error(gs_error_VMerror);
870 CHECK(cos_dict_put_c_key_int(decode_parms, "/Predictor",
871 ss->Predictor));
872 CHECK(cos_dict_put_c_key_int(decode_parms, "/Columns",
873 ss->Columns));
874 if (ss->Colors != 1)
875 CHECK(cos_dict_put_c_key_int(decode_parms, "/Colors",
876 ss->Colors));
877 if (ss->BitsPerComponent != 8)
878 CHECK(cos_dict_put_c_key_int(decode_parms,
879 "/BitsPerComponent",
880 ss->BitsPerComponent));
881 } else if (TEMPLATE_IS(s_RLE_template))
882 filter_name = pfn->RunLengthDecode;
883 #undef TEMPLATE_IS
884 }
885 if (filter_name) {
886 if (binary_ok) {
887 CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, filter_name));
888 if (decode_parms)
889 CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
890 COS_OBJECT(decode_parms)));
891 } else {
892 cos_array_t *pca =
893 cos_array_alloc(pdev, "pdf_put_image_filters(Filters)");
894
895 if (pca == 0)
896 return_error(gs_error_VMerror);
897 CHECK(cos_array_add_c_string(pca, pfn->ASCII85Decode));
898 CHECK(cos_array_add_c_string(pca, filter_name));
899 CHECK(cos_dict_put_c_key_object(pcd, pfn->Filter,
900 COS_OBJECT(pca)));
901 if (decode_parms) {
902 pca = cos_array_alloc(pdev,
903 "pdf_put_image_filters(DecodeParms)");
904 if (pca == 0)
905 return_error(gs_error_VMerror);
906 CHECK(cos_array_add_c_string(pca, "null"));
907 CHECK(cos_array_add_object(pca, COS_OBJECT(decode_parms)));
908 CHECK(cos_dict_put_c_key_object(pcd, pfn->DecodeParms,
909 COS_OBJECT(pca)));
910 }
911 }
912 } else if (!binary_ok)
913 CHECK(cos_dict_put_c_strings(pcd, pfn->Filter, pfn->ASCII85Decode));
914 return 0;
915 }
916
917 /* Add a Flate compression filter to a binary writer. */
918 private int
pdf_flate_binary(gx_device_pdf * pdev,psdf_binary_writer * pbw)919 pdf_flate_binary(gx_device_pdf *pdev, psdf_binary_writer *pbw)
920 {
921 const stream_template *template = &s_zlibE_template;
922 stream_state *st = s_alloc_state(pdev->pdf_memory, template->stype,
923 "pdf_write_function");
924
925 if (st == 0)
926 return_error(gs_error_VMerror);
927 if (template->set_defaults)
928 template->set_defaults(st);
929 return psdf_encode_binary(pbw, template, st);
930 }
931
932 /*
933 * Begin a data stream. The client has opened the object and written
934 * the << and any desired dictionary keys.
935 */
936 int
pdf_begin_data_binary(gx_device_pdf * pdev,pdf_data_writer_t * pdw,bool data_is_binary)937 pdf_begin_data_binary(gx_device_pdf *pdev, pdf_data_writer_t *pdw,
938 bool data_is_binary)
939 {
940 long length_id = pdf_obj_ref(pdev);
941 stream *s = pdev->strm;
942 #define USE_ASCII85 1
943 #define USE_FLATE 2
944 static const char *const fnames[4] = {
945 "", "/Filter/ASCII85Decode", "/Filter/FlateDecode",
946 "/Filter[/ASCII85Decode/FlateDecode]"
947 };
948 int filters = 0;
949 int code;
950
951 if (pdev->CompatibilityLevel >= 1.2) {
952 filters |= USE_FLATE;
953 data_is_binary = true;
954 }
955 if (data_is_binary && !pdev->binary_ok)
956 filters |= USE_ASCII85;
957 stream_puts(s, fnames[filters]);
958 pprintld1(s, "/Length %ld 0 R>>stream\n", length_id);
959 code = psdf_begin_binary((gx_device_psdf *)pdev, &pdw->binary);
960 if (code < 0)
961 return code;
962 pdw->start = stell(s);
963 pdw->length_id = length_id;
964 if (filters & USE_FLATE)
965 code = pdf_flate_binary(pdev, &pdw->binary);
966 return code;
967 #undef USE_ASCII85
968 #undef USE_FLATE
969 }
970
971 /* End a data stream. */
972 int
pdf_end_data(pdf_data_writer_t * pdw)973 pdf_end_data(pdf_data_writer_t *pdw)
974 {
975 gx_device_pdf *pdev = (gx_device_pdf *)pdw->binary.dev;
976 int code = psdf_end_binary(&pdw->binary);
977 long length = stell(pdev->strm) - pdw->start;
978
979 if (code < 0)
980 return code;
981 stream_puts(pdev->strm, "\nendstream\n");
982 pdf_end_separate(pdev);
983 pdf_open_separate(pdev, pdw->length_id);
984 pprintld1(pdev->strm, "%ld\n", length);
985 return pdf_end_separate(pdev);
986 }
987
988 /* Create a Function object. */
989 int
pdf_function(gx_device_pdf * pdev,const gs_function_t * pfn,cos_value_t * pvalue)990 pdf_function(gx_device_pdf *pdev, const gs_function_t *pfn,
991 cos_value_t *pvalue)
992 {
993 gs_function_info_t info;
994 cos_param_list_writer_t rlist;
995 pdf_resource_t *pres;
996 cos_object_t *pcfn;
997 cos_dict_t *pcd;
998 cos_value_t v;
999 int code = pdf_alloc_resource(pdev, resourceFunction, gs_no_id, &pres, 0L);
1000
1001 if (code < 0)
1002 return code;
1003 pcfn = pres->object;
1004 gs_function_get_info(pfn, &info);
1005 if (info.DataSource != 0) {
1006 psdf_binary_writer writer;
1007 stream *save = pdev->strm;
1008 cos_stream_t *pcos;
1009 stream *s;
1010
1011 cos_become(pcfn, cos_type_stream);
1012 pcos = (cos_stream_t *)pcfn;
1013 pcd = cos_stream_dict(pcos);
1014 s = cos_write_stream_alloc(pcos, pdev, "pdf_function");
1015 if (s == 0)
1016 return_error(gs_error_VMerror);
1017 pdev->strm = s;
1018 code = psdf_begin_binary((gx_device_psdf *)pdev, &writer);
1019 if (code >= 0 && info.data_size > 30 && /* 30 is arbitrary */
1020 pdev->CompatibilityLevel >= 1.2
1021 )
1022 code = pdf_flate_binary(pdev, &writer);
1023 if (code >= 0) {
1024 static const pdf_filter_names_t fnames = {
1025 PDF_FILTER_NAMES
1026 };
1027
1028 code = pdf_put_filters(pcd, pdev, writer.strm, &fnames);
1029 }
1030 if (code >= 0) {
1031 byte buf[100]; /* arbitrary */
1032 ulong pos;
1033 uint count;
1034 const byte *ptr;
1035
1036 for (pos = 0; pos < info.data_size; pos += count) {
1037 count = min(sizeof(buf), info.data_size - pos);
1038 data_source_access_only(info.DataSource, pos, count, buf,
1039 &ptr);
1040 stream_write(writer.strm, ptr, count);
1041 }
1042 code = psdf_end_binary(&writer);
1043 sclose(s);
1044 }
1045 pdev->strm = save;
1046 if (code < 0)
1047 return code;
1048 } else {
1049 cos_become(pcfn, cos_type_dict);
1050 pcd = (cos_dict_t *)pcfn;
1051 }
1052 if (info.Functions != 0) {
1053 int i;
1054 cos_array_t *functions =
1055 cos_array_alloc(pdev, "pdf_function(Functions)");
1056
1057 if (functions == 0)
1058 return_error(gs_error_VMerror);
1059 for (i = 0; i < info.num_Functions; ++i) {
1060 if ((code = pdf_function(pdev, info.Functions[i], &v)) < 0 ||
1061 (code = cos_array_add(functions, &v)) < 0
1062 ) {
1063 COS_FREE(functions, "pdf_function(Functions)");
1064 return code;
1065 }
1066 }
1067 code = cos_dict_put_c_key(pcd, "/Functions",
1068 COS_OBJECT_VALUE(&v, functions));
1069 if (code < 0) {
1070 COS_FREE(functions, "pdf_function(Functions)");
1071 return code;
1072 }
1073 }
1074 code = cos_param_list_writer_init(&rlist, pcd, PRINT_BINARY_OK);
1075 if (code < 0)
1076 return code;
1077 code = gs_function_get_params(pfn, (gs_param_list *)&rlist);
1078 if (code < 0)
1079 return code;
1080 COS_OBJECT_VALUE(pvalue, pcd);
1081 return 0;
1082 }
1083
1084 /* Write a Function object. */
1085 int
pdf_write_function(gx_device_pdf * pdev,const gs_function_t * pfn,long * pid)1086 pdf_write_function(gx_device_pdf *pdev, const gs_function_t *pfn, long *pid)
1087 {
1088 cos_value_t value;
1089 int code = pdf_function(pdev, pfn, &value);
1090
1091 if (code < 0)
1092 return code;
1093 *pid = value.contents.object->id;
1094 return 0;
1095 }
1096