Thu, 13 Mar 2003 07:59:10 +0000
don't use page mode USE_OUTLINES if there are no outline entries.
1 /*
2 * t2p: Create a PDF file from the contents of one or more TIFF
3 * bilevel image files. The images in the resulting PDF file
4 * will be compressed using ITU-T T.6 (G4) fax encoding.
5 *
6 * PDF routines
7 * $Id: pdf_prim.c,v 1.10 2003/03/12 22:56:57 eric Exp $
8 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. Note that permission is
13 * not granted to redistribute this program under the terms of any
14 * other version of the General Public License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 */
27 #include <stdarg.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
34 #include "bitblt.h"
35 #include "pdf.h"
36 #include "pdf_util.h"
37 #include "pdf_prim.h"
38 #include "pdf_private.h"
41 struct pdf_array_elem
42 {
43 struct pdf_array_elem *next;
44 struct pdf_obj *val;
45 };
48 struct pdf_array
49 {
50 struct pdf_array_elem *first;
51 struct pdf_array_elem *last;
52 };
55 struct pdf_dict_entry
56 {
57 struct pdf_dict_entry *next;
58 char *key;
59 struct pdf_obj *val;
60 };
63 struct pdf_dict
64 {
65 struct pdf_dict_entry *first;
66 };
69 struct pdf_stream
70 {
71 struct pdf_obj *stream_dict;
72 struct pdf_obj *length;
73 pdf_stream_write_callback callback;
74 void *app_data; /* arg to pass to callback */
75 struct pdf_obj *filters; /* name or array of names */
76 struct pdf_obj *decode_parms;
77 };
80 struct pdf_obj
81 {
82 /* these fields only apply to indirectly referenced objects */
83 struct pdf_obj *prev;
84 struct pdf_obj *next;
85 unsigned long obj_num;
86 unsigned long obj_gen;
87 long int file_offset;
89 /* these fields apply to all objects */
90 unsigned long ref_count;
91 pdf_obj_type type;
92 union {
93 bool boolean;
94 char *name;
95 char *string;
96 long integer;
97 double real;
98 struct pdf_obj *ind_ref;
99 struct pdf_dict dict;
100 struct pdf_array array;
101 struct pdf_stream stream;
102 } val;
103 };
106 struct pdf_obj *ref (struct pdf_obj *obj)
107 {
108 obj->ref_count++;
109 return (obj);
110 }
113 void unref (struct pdf_obj *obj)
114 {
115 if ((--obj->ref_count) == 0)
116 {
117 /* $$$ free the object */
118 }
119 }
122 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
123 {
124 pdf_assert (ind_obj->type == PT_IND_REF);
125 return (ind_obj->val.ind_ref);
126 }
129 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
130 {
131 struct pdf_dict_entry *entry;
133 if (dict_obj->type == PT_IND_REF)
134 dict_obj = pdf_deref_ind_obj (dict_obj);
136 pdf_assert (dict_obj->type == PT_DICTIONARY);
138 /* replacing existing entry? */
139 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
140 if (strcmp (entry->key, key) == 0)
141 {
142 unref (entry->val);
143 entry->val = ref (val);
144 return;
145 }
147 /* new entry */
148 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
150 entry->next = dict_obj->val.dict.first;
151 dict_obj->val.dict.first = entry;
153 entry->key = pdf_strdup (key);
154 entry->val = ref (val);
155 }
158 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
159 {
160 struct pdf_dict_entry *entry;
162 if (dict_obj->type == PT_IND_REF)
163 dict_obj = pdf_deref_ind_obj (dict_obj);
165 pdf_assert (dict_obj->type == PT_DICTIONARY);
167 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
168 if (strcmp (entry->key, key) == 0)
169 return (entry->val);
171 return (NULL);
172 }
175 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
176 {
177 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
179 if (array_obj->type == PT_IND_REF)
180 array_obj = pdf_deref_ind_obj (array_obj);
182 pdf_assert (array_obj->type == PT_ARRAY);
184 elem->val = ref (val);
186 if (! array_obj->val.array.first)
187 array_obj->val.array.first = elem;
188 else
189 array_obj->val.array.last->next = elem;
191 array_obj->val.array.last = elem;
192 }
195 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
196 {
197 struct pdf_array_elem *elem;
199 if (array_obj->type == PT_IND_REF)
200 array_obj = pdf_deref_ind_obj (array_obj);
202 pdf_assert (array_obj->type == PT_ARRAY);
204 for (elem = array_obj->val.array.first; elem; elem = elem->next)
205 if (pdf_compare_obj (val, elem->val) == 0)
206 return;
208 elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
210 elem->val = ref (val);
212 if (! array_obj->val.array.first)
213 array_obj->val.array.first = elem;
214 else
215 array_obj->val.array.last->next = elem;
217 array_obj->val.array.last = elem;
218 }
221 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
222 {
223 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
224 obj->type = type;
225 return (obj);
226 }
229 struct pdf_obj *pdf_new_bool (bool val)
230 {
231 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
232 obj->val.boolean = val;
233 return (obj);
234 }
237 struct pdf_obj *pdf_new_name (char *name)
238 {
239 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
240 obj->val.name = pdf_strdup (name);
241 return (obj);
242 }
245 struct pdf_obj *pdf_new_string (char *str)
246 {
247 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
248 obj->val.string = pdf_strdup (str);
249 return (obj);
250 }
253 struct pdf_obj *pdf_new_integer (long val)
254 {
255 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
256 obj->val.integer = val;
257 return (obj);
258 }
261 struct pdf_obj *pdf_new_real (double val)
262 {
263 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
264 obj->val.real = val;
265 return (obj);
266 }
269 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
270 struct pdf_obj *stream_dict,
271 pdf_stream_write_callback callback,
272 void *app_data)
273 {
274 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
276 obj->val.stream.stream_dict = stream_dict;
277 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
278 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
280 obj->val.stream.callback = callback;
281 obj->val.stream.app_data = app_data;
282 return (obj);
283 }
286 /* $$$ currently limited to one filter per stream */
287 void pdf_stream_add_filter (struct pdf_obj *stream,
288 char *filter_name,
289 struct pdf_obj *decode_parms)
290 {
291 if (stream->type == PT_IND_REF)
292 stream = pdf_deref_ind_obj (stream);
294 pdf_assert (stream->type == PT_STREAM);
296 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
297 if (decode_parms)
298 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
299 }
302 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
303 {
304 struct pdf_obj *ind_obj;
306 pdf_assert (obj->type != PT_IND_REF);
308 ind_obj = pdf_new_obj (PT_IND_REF);
310 ind_obj->type = PT_IND_REF;
311 ind_obj->val.ind_ref = obj;
313 /* is there already an indirect reference to this object? */
314 if (! obj->obj_num)
315 {
316 /* no, assign object number/generation and add to linked list */
317 if (! pdf_file->first_ind_obj)
318 {
319 obj->obj_num = 1;
320 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
321 }
322 else
323 {
324 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
325 pdf_file->last_ind_obj->next = obj;
326 obj->prev = pdf_file->last_ind_obj;
327 pdf_file->last_ind_obj = obj;
328 }
329 }
331 return (ind_obj);
332 }
335 long pdf_get_integer (struct pdf_obj *obj)
336 {
337 if (obj->type == PT_IND_REF)
338 obj = pdf_deref_ind_obj (obj);
340 pdf_assert (obj->type == PT_INTEGER);
342 return (obj->val.integer);
343 }
345 void pdf_set_integer (struct pdf_obj *obj, long val)
346 {
347 if (obj->type == PT_IND_REF)
348 obj = pdf_deref_ind_obj (obj);
350 pdf_assert (obj->type == PT_INTEGER);
352 obj->val.integer = val;
353 }
356 double pdf_get_real (struct pdf_obj *obj)
357 {
358 if (obj->type == PT_IND_REF)
359 obj = pdf_deref_ind_obj (obj);
361 pdf_assert (obj->type == PT_REAL);
363 return (obj->val.real);
364 }
366 void pdf_set_real (struct pdf_obj *obj, double val)
367 {
368 if (obj->type == PT_IND_REF)
369 obj = pdf_deref_ind_obj (obj);
371 pdf_assert (obj->type == PT_REAL);
373 obj->val.real = val;
374 }
377 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
378 {
379 if (o1->type == PT_IND_REF)
380 o1 = pdf_deref_ind_obj (o1);
382 if (o2->type == PT_IND_REF)
383 o2 = pdf_deref_ind_obj (o2);
385 pdf_assert (o1->type == o2->type);
387 switch (o1->type)
388 {
389 case PT_INTEGER:
390 if (o1->val.integer < o2->val.integer)
391 return (-1);
392 if (o1->val.integer > o2->val.integer)
393 return (1);
394 return (0);
395 case PT_REAL:
396 if (o1->val.real < o2->val.real)
397 return (-1);
398 if (o1->val.real > o2->val.real)
399 return (1);
400 return (0);
401 case PT_STRING:
402 return (strcmp (o1->val.string, o2->val.string));
403 case PT_NAME:
404 return (strcmp (o1->val.name, o2->val.name));
405 default:
406 pdf_fatal ("invalid object type for comparison\n");
407 }
408 }
411 static int name_char_needs_quoting (char c)
412 {
413 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
414 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
415 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
416 (c == '%'));
417 }
420 void pdf_write_name (pdf_file_handle pdf_file, char *s)
421 {
422 fprintf (pdf_file->f, "/");
423 while (*s)
424 if (name_char_needs_quoting (*s))
425 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
426 else
427 fprintf (pdf_file->f, "%c", *(s++));
428 fprintf (pdf_file->f, " ");
429 }
432 static int string_char_needs_quoting (char c)
433 {
434 return ((c < ' ') || (c > '~') || (c == '\\') ||
435 (c == '(') || (c == ')'));
436 }
439 void pdf_write_string (pdf_file_handle pdf_file, char *s)
440 {
441 fprintf (pdf_file->f, "(");
442 while (*s)
443 if (string_char_needs_quoting (*s))
444 fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
445 else
446 fprintf (pdf_file->f, "%c", *(s++));
447 fprintf (pdf_file->f, ") ");
448 }
451 void pdf_write_real (pdf_file_handle pdf_file, double num)
452 {
453 /* $$$ not actually good enough, precision needs to be variable,
454 and no exponent is allowed */
455 fprintf (pdf_file->f, "%0f ", num);
456 }
459 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
460 {
461 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
462 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
463 }
466 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
467 {
468 struct pdf_array_elem *elem;
470 pdf_assert (array_obj->type == PT_ARRAY);
472 fprintf (pdf_file->f, "[ ");
473 for (elem = array_obj->val.array.first; elem; elem = elem->next)
474 {
475 pdf_write_obj (pdf_file, elem->val);
476 fprintf (pdf_file->f, " ");
477 }
478 fprintf (pdf_file->f, "] ");
479 }
482 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
483 {
484 struct pdf_dict_entry *entry;
486 pdf_assert (dict_obj->type == PT_DICTIONARY);
488 fprintf (pdf_file->f, "<<\r\n");
489 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
490 {
491 pdf_write_name (pdf_file, entry->key);
492 fprintf (pdf_file->f, " ");
493 pdf_write_obj (pdf_file, entry->val);
494 fprintf (pdf_file->f, "\r\n");
495 }
496 fprintf (pdf_file->f, ">>\r\n");
497 }
500 void pdf_stream_write_data (pdf_file_handle pdf_file,
501 struct pdf_obj *stream,
502 char *data,
503 unsigned long len)
504 {
505 while (len)
506 {
507 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
508 data += l2;
509 len -= l2;
510 if (ferror (pdf_file->f))
511 pdf_fatal ("error writing stream data\n");
512 }
513 }
516 void pdf_stream_printf (pdf_file_handle pdf_file,
517 struct pdf_obj *stream,
518 char *fmt, ...)
519 {
520 va_list ap;
522 va_start (ap, fmt);
523 vfprintf (pdf_file->f, fmt, ap);
524 va_end (ap);
525 }
528 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
529 {
530 unsigned long begin_pos, end_pos;
532 pdf_assert (stream->type == PT_STREAM);
534 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
535 fprintf (pdf_file->f, "stream\r\n");
536 begin_pos = ftell (pdf_file->f);
537 stream->val.stream.callback (pdf_file,
538 stream,
539 stream->val.stream.app_data);
540 end_pos = ftell (pdf_file->f);
541 fprintf (pdf_file->f, "\r\nendstream\r\n");
543 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
544 }
547 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
548 {
549 switch (obj->type)
550 {
551 case PT_NULL:
552 fprintf (pdf_file->f, "null ");
553 break;
554 case PT_BOOL:
555 if (obj->val.boolean)
556 fprintf (pdf_file->f, "true ");
557 else
558 fprintf (pdf_file->f, "false ");
559 break;
560 case PT_NAME:
561 pdf_write_name (pdf_file, obj->val.name);
562 break;
563 case PT_STRING:
564 pdf_write_string (pdf_file, obj->val.string);
565 break;
566 case PT_INTEGER:
567 fprintf (pdf_file->f, "%ld ", obj->val.integer);
568 break;
569 case PT_REAL:
570 pdf_write_real (pdf_file, obj->val.real);
571 break;
572 case PT_IND_REF:
573 pdf_write_ind_ref (pdf_file, obj);
574 break;
575 case PT_DICTIONARY:
576 pdf_write_dict (pdf_file, obj);
577 break;
578 case PT_ARRAY:
579 pdf_write_array (pdf_file, obj);
580 break;
581 case PT_STREAM:
582 pdf_write_stream (pdf_file, obj);
583 break;
584 default:
585 pdf_fatal ("bad object type\n");
586 }
587 }
590 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
591 {
592 struct pdf_obj *obj;
594 if (ind_obj->type == PT_IND_REF)
595 obj = pdf_deref_ind_obj (ind_obj);
596 else
597 obj = ind_obj;
599 obj->file_offset = ftell (pdf_file->f);
600 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
601 pdf_write_obj (pdf_file, obj);
602 fprintf (pdf_file->f, "endobj\r\n");
603 }
606 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
607 {
608 struct pdf_obj *ind_obj;
609 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
610 if (! ind_obj->file_offset)
611 pdf_write_ind_obj (pdf_file, ind_obj);
612 }
615 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
616 {
617 struct pdf_obj *ind_obj;
618 pdf_file->xref_offset = ftell (pdf_file->f);
619 fprintf (pdf_file->f, "xref\r\n");
620 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
621 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
622 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
623 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
624 return (pdf_file->last_ind_obj->obj_num + 1);
625 }
628 /* this isn't really a PDF primitive data type */
629 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
630 {
631 char XObject_name [4] = "Im ";
633 XObject_name [2] = ++pdf_page->last_XObject_name;
635 if (! pdf_page->XObject_dict)
636 {
637 pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
638 pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
639 }
641 pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
643 return (pdf_page->last_XObject_name);
644 }