pdf_prim.c

Mon, 14 Dec 2009 16:18:21 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 16:18:21 +0000
changeset 172
2fae6df568f6
parent 166
301f6f17c364
permissions
-rw-r--r--

remove erroneous 0.33-philpem1 tag

eric@62 1 /*
eric@125 2 * tumble: build a PDF file from image files
eric@62 3 *
eric@62 4 * PDF routines
eric@145 5 * $Id: pdf_prim.c,v 1.13 2003/03/19 23:44:53 eric Exp $
eric@62 6 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
eric@62 7 *
eric@62 8 * This program is free software; you can redistribute it and/or modify
eric@62 9 * it under the terms of the GNU General Public License version 2 as
eric@62 10 * published by the Free Software Foundation. Note that permission is
eric@62 11 * not granted to redistribute this program under the terms of any
eric@62 12 * other version of the General Public License.
eric@62 13 *
eric@62 14 * This program is distributed in the hope that it will be useful,
eric@62 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
eric@62 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
eric@62 17 * GNU General Public License for more details.
eric@62 18 *
eric@62 19 * You should have received a copy of the GNU General Public License
eric@62 20 * along with this program; if not, write to the Free Software
eric@62 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
eric@62 22 */
eric@62 23
eric@62 24
eric@66 25 #include <stdarg.h>
eric@62 26 #include <stdbool.h>
eric@62 27 #include <stdint.h>
eric@59 28 #include <stdio.h>
eric@59 29 #include <stdlib.h>
eric@59 30 #include <string.h>
eric@59 31
eric@62 32 #include "bitblt.h"
eric@60 33 #include "pdf.h"
eric@60 34 #include "pdf_util.h"
eric@60 35 #include "pdf_prim.h"
eric@60 36 #include "pdf_private.h"
eric@59 37
eric@59 38
eric@59 39 struct pdf_array_elem
eric@59 40 {
eric@59 41 struct pdf_array_elem *next;
eric@59 42 struct pdf_obj *val;
eric@59 43 };
eric@59 44
eric@59 45
eric@59 46 struct pdf_array
eric@59 47 {
eric@59 48 struct pdf_array_elem *first;
eric@59 49 struct pdf_array_elem *last;
eric@59 50 };
eric@59 51
eric@59 52
eric@59 53 struct pdf_dict_entry
eric@59 54 {
eric@59 55 struct pdf_dict_entry *next;
eric@59 56 char *key;
eric@59 57 struct pdf_obj *val;
eric@59 58 };
eric@59 59
eric@59 60
eric@59 61 struct pdf_dict
eric@59 62 {
eric@59 63 struct pdf_dict_entry *first;
eric@59 64 };
eric@59 65
eric@59 66
eric@59 67 struct pdf_stream
eric@59 68 {
eric@59 69 struct pdf_obj *stream_dict;
eric@59 70 struct pdf_obj *length;
eric@59 71 pdf_stream_write_callback callback;
eric@59 72 void *app_data; /* arg to pass to callback */
eric@59 73 struct pdf_obj *filters; /* name or array of names */
eric@59 74 struct pdf_obj *decode_parms;
eric@59 75 };
eric@59 76
eric@59 77
eric@59 78 struct pdf_obj
eric@59 79 {
eric@59 80 /* these fields only apply to indirectly referenced objects */
eric@59 81 struct pdf_obj *prev;
eric@59 82 struct pdf_obj *next;
eric@59 83 unsigned long obj_num;
eric@59 84 unsigned long obj_gen;
eric@59 85 long int file_offset;
eric@59 86
eric@59 87 /* these fields apply to all objects */
eric@59 88 unsigned long ref_count;
eric@59 89 pdf_obj_type type;
eric@59 90 union {
eric@62 91 bool boolean;
eric@59 92 char *name;
philpem@166 93 struct {
philpem@166 94 char *content;
philpem@166 95 int length;
philpem@166 96 } string;
eric@74 97 long integer;
eric@59 98 double real;
eric@59 99 struct pdf_obj *ind_ref;
eric@59 100 struct pdf_dict dict;
eric@59 101 struct pdf_array array;
eric@59 102 struct pdf_stream stream;
eric@59 103 } val;
eric@59 104 };
eric@59 105
eric@59 106
eric@59 107 struct pdf_obj *ref (struct pdf_obj *obj)
eric@59 108 {
eric@59 109 obj->ref_count++;
eric@59 110 return (obj);
eric@59 111 }
eric@59 112
eric@59 113
eric@59 114 void unref (struct pdf_obj *obj)
eric@59 115 {
eric@59 116 if ((--obj->ref_count) == 0)
eric@59 117 {
eric@59 118 /* $$$ free the object */
eric@59 119 }
eric@59 120 }
eric@59 121
eric@59 122
eric@59 123 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
eric@59 124 {
eric@59 125 pdf_assert (ind_obj->type == PT_IND_REF);
eric@59 126 return (ind_obj->val.ind_ref);
eric@59 127 }
eric@59 128
eric@59 129
eric@59 130 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
eric@59 131 {
eric@59 132 struct pdf_dict_entry *entry;
eric@59 133
eric@59 134 if (dict_obj->type == PT_IND_REF)
eric@59 135 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 136
eric@59 137 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 138
eric@59 139 /* replacing existing entry? */
eric@59 140 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 141 if (strcmp (entry->key, key) == 0)
eric@59 142 {
eric@59 143 unref (entry->val);
eric@59 144 entry->val = ref (val);
eric@59 145 return;
eric@59 146 }
eric@59 147
eric@59 148 /* new entry */
eric@67 149 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
eric@59 150
eric@59 151 entry->next = dict_obj->val.dict.first;
eric@59 152 dict_obj->val.dict.first = entry;
eric@59 153
eric@59 154 entry->key = pdf_strdup (key);
eric@59 155 entry->val = ref (val);
eric@59 156 }
eric@59 157
eric@59 158
eric@59 159 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
eric@59 160 {
eric@59 161 struct pdf_dict_entry *entry;
eric@59 162
eric@59 163 if (dict_obj->type == PT_IND_REF)
eric@59 164 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 165
eric@59 166 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 167
eric@59 168 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 169 if (strcmp (entry->key, key) == 0)
eric@59 170 return (entry->val);
eric@59 171
eric@59 172 return (NULL);
eric@59 173 }
eric@59 174
eric@59 175
eric@59 176 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@59 177 {
eric@67 178 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
eric@59 179
eric@59 180 if (array_obj->type == PT_IND_REF)
eric@59 181 array_obj = pdf_deref_ind_obj (array_obj);
eric@59 182
eric@59 183 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 184
eric@59 185 elem->val = ref (val);
eric@59 186
eric@59 187 if (! array_obj->val.array.first)
eric@59 188 array_obj->val.array.first = elem;
eric@59 189 else
eric@59 190 array_obj->val.array.last->next = elem;
eric@59 191
eric@59 192 array_obj->val.array.last = elem;
eric@59 193 }
eric@59 194
eric@59 195
eric@118 196 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@118 197 {
eric@118 198 struct pdf_array_elem *elem;
eric@118 199
eric@118 200 if (array_obj->type == PT_IND_REF)
eric@118 201 array_obj = pdf_deref_ind_obj (array_obj);
eric@118 202
eric@118 203 pdf_assert (array_obj->type == PT_ARRAY);
eric@118 204
eric@118 205 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@118 206 if (pdf_compare_obj (val, elem->val) == 0)
eric@118 207 return;
eric@118 208
eric@118 209 elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
eric@118 210
eric@118 211 elem->val = ref (val);
eric@118 212
eric@118 213 if (! array_obj->val.array.first)
eric@118 214 array_obj->val.array.first = elem;
eric@118 215 else
eric@118 216 array_obj->val.array.last->next = elem;
eric@118 217
eric@118 218 array_obj->val.array.last = elem;
eric@118 219 }
eric@118 220
eric@118 221
eric@59 222 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
eric@59 223 {
eric@67 224 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
eric@59 225 obj->type = type;
eric@59 226 return (obj);
eric@59 227 }
eric@59 228
eric@59 229
eric@62 230 struct pdf_obj *pdf_new_bool (bool val)
eric@59 231 {
eric@59 232 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
eric@62 233 obj->val.boolean = val;
eric@59 234 return (obj);
eric@59 235 }
eric@59 236
eric@59 237
eric@59 238 struct pdf_obj *pdf_new_name (char *name)
eric@59 239 {
eric@59 240 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
eric@59 241 obj->val.name = pdf_strdup (name);
eric@59 242 return (obj);
eric@59 243 }
eric@59 244
eric@59 245
eric@59 246 struct pdf_obj *pdf_new_string (char *str)
eric@59 247 {
eric@59 248 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
philpem@166 249 obj->val.string.content = pdf_strdup (str);
philpem@166 250 obj->val.string.length = strlen(str);
philpem@166 251 return (obj);
philpem@166 252 }
philpem@166 253
philpem@166 254
philpem@166 255 struct pdf_obj *pdf_new_string_n (char *str, int n)
philpem@166 256 {
philpem@166 257 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
philpem@166 258 obj->val.string.length = n;
philpem@166 259 obj->val.string.content = pdf_calloc (1,n);
philpem@166 260 memcpy(obj->val.string.content, str, n);
eric@59 261 return (obj);
eric@59 262 }
eric@59 263
eric@59 264
eric@74 265 struct pdf_obj *pdf_new_integer (long val)
eric@59 266 {
eric@59 267 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
eric@59 268 obj->val.integer = val;
eric@59 269 return (obj);
eric@59 270 }
eric@59 271
eric@59 272
eric@59 273 struct pdf_obj *pdf_new_real (double val)
eric@59 274 {
eric@59 275 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
eric@59 276 obj->val.real = val;
eric@59 277 return (obj);
eric@59 278 }
eric@59 279
eric@59 280
eric@59 281 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
eric@59 282 struct pdf_obj *stream_dict,
eric@59 283 pdf_stream_write_callback callback,
eric@59 284 void *app_data)
eric@59 285 {
eric@59 286 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
eric@59 287
eric@59 288 obj->val.stream.stream_dict = stream_dict;
eric@59 289 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
eric@59 290 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
eric@59 291
eric@59 292 obj->val.stream.callback = callback;
eric@59 293 obj->val.stream.app_data = app_data;
eric@59 294 return (obj);
eric@59 295 }
eric@59 296
eric@59 297
eric@59 298 /* $$$ currently limited to one filter per stream */
eric@59 299 void pdf_stream_add_filter (struct pdf_obj *stream,
eric@59 300 char *filter_name,
eric@59 301 struct pdf_obj *decode_parms)
eric@59 302 {
eric@59 303 if (stream->type == PT_IND_REF)
eric@59 304 stream = pdf_deref_ind_obj (stream);
eric@59 305
eric@59 306 pdf_assert (stream->type == PT_STREAM);
eric@59 307
eric@59 308 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
eric@59 309 if (decode_parms)
eric@59 310 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
eric@59 311 }
eric@59 312
eric@59 313
eric@59 314 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 315 {
eric@59 316 struct pdf_obj *ind_obj;
eric@59 317
eric@59 318 pdf_assert (obj->type != PT_IND_REF);
eric@59 319
eric@59 320 ind_obj = pdf_new_obj (PT_IND_REF);
eric@59 321
eric@59 322 ind_obj->type = PT_IND_REF;
eric@59 323 ind_obj->val.ind_ref = obj;
eric@59 324
eric@59 325 /* is there already an indirect reference to this object? */
eric@59 326 if (! obj->obj_num)
eric@59 327 {
eric@59 328 /* no, assign object number/generation and add to linked list */
eric@59 329 if (! pdf_file->first_ind_obj)
eric@59 330 {
eric@59 331 obj->obj_num = 1;
eric@59 332 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
eric@59 333 }
eric@59 334 else
eric@59 335 {
eric@59 336 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
eric@59 337 pdf_file->last_ind_obj->next = obj;
eric@59 338 obj->prev = pdf_file->last_ind_obj;
eric@59 339 pdf_file->last_ind_obj = obj;
eric@59 340 }
eric@59 341 }
eric@59 342
eric@59 343 return (ind_obj);
eric@59 344 }
eric@59 345
eric@59 346
eric@74 347 long pdf_get_integer (struct pdf_obj *obj)
eric@59 348 {
eric@59 349 if (obj->type == PT_IND_REF)
eric@59 350 obj = pdf_deref_ind_obj (obj);
eric@59 351
eric@59 352 pdf_assert (obj->type == PT_INTEGER);
eric@59 353
eric@59 354 return (obj->val.integer);
eric@59 355 }
eric@59 356
eric@74 357 void pdf_set_integer (struct pdf_obj *obj, long val)
eric@59 358 {
eric@59 359 if (obj->type == PT_IND_REF)
eric@59 360 obj = pdf_deref_ind_obj (obj);
eric@59 361
eric@59 362 pdf_assert (obj->type == PT_INTEGER);
eric@59 363
eric@59 364 obj->val.integer = val;
eric@59 365 }
eric@59 366
eric@59 367
eric@59 368 double pdf_get_real (struct pdf_obj *obj)
eric@59 369 {
eric@59 370 if (obj->type == PT_IND_REF)
eric@59 371 obj = pdf_deref_ind_obj (obj);
eric@59 372
eric@59 373 pdf_assert (obj->type == PT_REAL);
eric@59 374
eric@59 375 return (obj->val.real);
eric@59 376 }
eric@59 377
eric@59 378 void pdf_set_real (struct pdf_obj *obj, double val)
eric@59 379 {
eric@59 380 if (obj->type == PT_IND_REF)
eric@59 381 obj = pdf_deref_ind_obj (obj);
eric@59 382
eric@59 383 pdf_assert (obj->type == PT_REAL);
eric@59 384
eric@59 385 obj->val.real = val;
eric@59 386 }
eric@59 387
eric@59 388
eric@82 389 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
eric@82 390 {
eric@82 391 if (o1->type == PT_IND_REF)
eric@82 392 o1 = pdf_deref_ind_obj (o1);
eric@82 393
eric@82 394 if (o2->type == PT_IND_REF)
eric@82 395 o2 = pdf_deref_ind_obj (o2);
eric@82 396
eric@82 397 pdf_assert (o1->type == o2->type);
eric@82 398
eric@82 399 switch (o1->type)
eric@82 400 {
eric@82 401 case PT_INTEGER:
eric@82 402 if (o1->val.integer < o2->val.integer)
eric@82 403 return (-1);
eric@82 404 if (o1->val.integer > o2->val.integer)
eric@82 405 return (1);
eric@82 406 return (0);
eric@82 407 case PT_REAL:
eric@82 408 if (o1->val.real < o2->val.real)
eric@82 409 return (-1);
eric@82 410 if (o1->val.real > o2->val.real)
eric@82 411 return (1);
eric@82 412 return (0);
eric@82 413 case PT_STRING:
philpem@166 414 {
philpem@166 415 int l;
philpem@166 416 l = o1->val.string.length;
philpem@166 417 if(l > o2->val.string.length)
philpem@166 418 l = o2->val.string.length;
philpem@166 419 l = memcmp (o1->val.string.content, o2->val.string.content, l);
philpem@166 420 if (l)
philpem@166 421 return l;
philpem@166 422 return o1->val.string.length - o2->val.string.length;
philpem@166 423 }
eric@118 424 case PT_NAME:
eric@118 425 return (strcmp (o1->val.name, o2->val.name));
eric@82 426 default:
eric@82 427 pdf_fatal ("invalid object type for comparison\n");
eric@82 428 }
eric@82 429 }
eric@82 430
eric@82 431
eric@59 432 static int name_char_needs_quoting (char c)
eric@59 433 {
eric@59 434 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
eric@59 435 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
eric@59 436 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
eric@59 437 (c == '%'));
eric@59 438 }
eric@59 439
eric@59 440
eric@59 441 void pdf_write_name (pdf_file_handle pdf_file, char *s)
eric@59 442 {
eric@59 443 fprintf (pdf_file->f, "/");
eric@59 444 while (*s)
eric@59 445 if (name_char_needs_quoting (*s))
eric@59 446 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
eric@59 447 else
eric@59 448 fprintf (pdf_file->f, "%c", *(s++));
eric@59 449 fprintf (pdf_file->f, " ");
eric@59 450 }
eric@59 451
eric@59 452
philpem@166 453 static int pdf_write_literal_string (pdf_file_handle pdf_file, char *s, int n)
eric@59 454 {
philpem@166 455 int i,p;
philpem@166 456 if(pdf_file) fprintf (pdf_file->f, "(");
philpem@166 457 for (i=p=0;n;n--) {
philpem@166 458 int j,k;
philpem@166 459 k=0;
philpem@166 460 switch(*s){
philpem@166 461 case '\\':
philpem@166 462 k=1;
philpem@166 463 break;
philpem@166 464 case '(':
philpem@166 465 for(j=k=1;k && j<n;j++)
philpem@166 466 k+=(s[j]=='(')?1:(s[j]==')')?-1:0;
philpem@166 467 p+=!k;
philpem@166 468 break;
philpem@166 469 case ')':
philpem@166 470 if(p)
philpem@166 471 p--;
philpem@166 472 else
philpem@166 473 k=1;
philpem@166 474 break;
philpem@166 475 }
philpem@166 476 if(k) {
philpem@166 477 i++;
philpem@166 478 if(pdf_file) fprintf (pdf_file->f, "\\");
philpem@166 479 }
philpem@166 480 i++;
philpem@166 481 if(pdf_file) fprintf (pdf_file->f, "%c", *(s++));
philpem@166 482 }
philpem@166 483 if(pdf_file) fprintf (pdf_file->f, ") ");
philpem@166 484 return i;
eric@59 485 }
eric@59 486
eric@59 487
philpem@166 488 void pdf_write_string (pdf_file_handle pdf_file, char *s, int n)
eric@59 489 {
philpem@166 490 if(pdf_write_literal_string (NULL,s,n)<2*n)
philpem@166 491 pdf_write_literal_string (pdf_file,s,n);
philpem@166 492 else {
philpem@166 493 fprintf (pdf_file->f, "<");
philpem@166 494 for(;n--;)
philpem@166 495 fprintf (pdf_file->f, "%.2X",*(s++));
philpem@166 496 fprintf (pdf_file->f, "> ");
philpem@166 497 }
eric@59 498 }
eric@59 499
eric@59 500
eric@59 501 void pdf_write_real (pdf_file_handle pdf_file, double num)
eric@59 502 {
eric@59 503 /* $$$ not actually good enough, precision needs to be variable,
eric@59 504 and no exponent is allowed */
eric@59 505 fprintf (pdf_file->f, "%0f ", num);
eric@59 506 }
eric@59 507
eric@59 508
eric@59 509 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 510 {
eric@59 511 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
eric@59 512 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
eric@59 513 }
eric@59 514
eric@59 515
eric@59 516 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
eric@59 517 {
eric@59 518 struct pdf_array_elem *elem;
eric@59 519
eric@59 520 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 521
eric@59 522 fprintf (pdf_file->f, "[ ");
eric@59 523 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@59 524 {
eric@59 525 pdf_write_obj (pdf_file, elem->val);
eric@59 526 fprintf (pdf_file->f, " ");
eric@59 527 }
eric@59 528 fprintf (pdf_file->f, "] ");
eric@59 529 }
eric@59 530
eric@59 531
eric@59 532 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
eric@59 533 {
eric@59 534 struct pdf_dict_entry *entry;
eric@59 535
eric@59 536 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 537
eric@59 538 fprintf (pdf_file->f, "<<\r\n");
eric@59 539 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 540 {
eric@59 541 pdf_write_name (pdf_file, entry->key);
eric@59 542 fprintf (pdf_file->f, " ");
eric@59 543 pdf_write_obj (pdf_file, entry->val);
eric@59 544 fprintf (pdf_file->f, "\r\n");
eric@59 545 }
eric@59 546 fprintf (pdf_file->f, ">>\r\n");
eric@59 547 }
eric@59 548
eric@59 549
eric@59 550 void pdf_stream_write_data (pdf_file_handle pdf_file,
eric@59 551 struct pdf_obj *stream,
eric@59 552 char *data,
eric@59 553 unsigned long len)
eric@59 554 {
eric@59 555 while (len)
eric@59 556 {
eric@59 557 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
eric@59 558 data += l2;
eric@59 559 len -= l2;
eric@59 560 if (ferror (pdf_file->f))
eric@59 561 pdf_fatal ("error writing stream data\n");
eric@59 562 }
eric@59 563 }
eric@59 564
eric@59 565
eric@66 566 void pdf_stream_printf (pdf_file_handle pdf_file,
eric@66 567 struct pdf_obj *stream,
eric@66 568 char *fmt, ...)
eric@66 569 {
eric@66 570 va_list ap;
eric@66 571
eric@66 572 va_start (ap, fmt);
eric@66 573 vfprintf (pdf_file->f, fmt, ap);
eric@66 574 va_end (ap);
eric@66 575 }
eric@66 576
eric@66 577
eric@59 578 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
eric@59 579 {
eric@59 580 unsigned long begin_pos, end_pos;
eric@59 581
eric@59 582 pdf_assert (stream->type == PT_STREAM);
eric@59 583
eric@59 584 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
eric@59 585 fprintf (pdf_file->f, "stream\r\n");
eric@59 586 begin_pos = ftell (pdf_file->f);
eric@59 587 stream->val.stream.callback (pdf_file,
eric@59 588 stream,
eric@59 589 stream->val.stream.app_data);
eric@59 590 end_pos = ftell (pdf_file->f);
eric@145 591
eric@145 592 fprintf (pdf_file->f, "\r\nendstream\r\n");
eric@59 593
eric@59 594 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
eric@59 595 }
eric@59 596
eric@59 597
eric@59 598 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 599 {
eric@59 600 switch (obj->type)
eric@59 601 {
eric@59 602 case PT_NULL:
eric@59 603 fprintf (pdf_file->f, "null ");
eric@59 604 break;
eric@59 605 case PT_BOOL:
eric@62 606 if (obj->val.boolean)
eric@59 607 fprintf (pdf_file->f, "true ");
eric@59 608 else
eric@59 609 fprintf (pdf_file->f, "false ");
eric@59 610 break;
eric@59 611 case PT_NAME:
eric@59 612 pdf_write_name (pdf_file, obj->val.name);
eric@59 613 break;
eric@59 614 case PT_STRING:
philpem@166 615 pdf_write_string (pdf_file, obj->val.string.content, obj->val.string.length);
eric@59 616 break;
eric@59 617 case PT_INTEGER:
eric@59 618 fprintf (pdf_file->f, "%ld ", obj->val.integer);
eric@59 619 break;
eric@59 620 case PT_REAL:
eric@59 621 pdf_write_real (pdf_file, obj->val.real);
eric@59 622 break;
eric@59 623 case PT_IND_REF:
eric@59 624 pdf_write_ind_ref (pdf_file, obj);
eric@59 625 break;
eric@59 626 case PT_DICTIONARY:
eric@59 627 pdf_write_dict (pdf_file, obj);
eric@59 628 break;
eric@59 629 case PT_ARRAY:
eric@59 630 pdf_write_array (pdf_file, obj);
eric@59 631 break;
eric@59 632 case PT_STREAM:
eric@59 633 pdf_write_stream (pdf_file, obj);
eric@59 634 break;
eric@59 635 default:
eric@59 636 pdf_fatal ("bad object type\n");
eric@59 637 }
eric@59 638 }
eric@59 639
eric@59 640
eric@59 641 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 642 {
eric@59 643 struct pdf_obj *obj;
eric@59 644
eric@59 645 if (ind_obj->type == PT_IND_REF)
eric@59 646 obj = pdf_deref_ind_obj (ind_obj);
eric@59 647 else
eric@59 648 obj = ind_obj;
eric@59 649
eric@59 650 obj->file_offset = ftell (pdf_file->f);
eric@59 651 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
eric@59 652 pdf_write_obj (pdf_file, obj);
eric@59 653 fprintf (pdf_file->f, "endobj\r\n");
eric@59 654 }
eric@59 655
eric@59 656
eric@59 657 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
eric@59 658 {
eric@59 659 struct pdf_obj *ind_obj;
eric@59 660 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 661 if (! ind_obj->file_offset)
eric@59 662 pdf_write_ind_obj (pdf_file, ind_obj);
eric@59 663 }
eric@59 664
eric@59 665
eric@59 666 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
eric@59 667 {
eric@59 668 struct pdf_obj *ind_obj;
eric@59 669 pdf_file->xref_offset = ftell (pdf_file->f);
eric@59 670 fprintf (pdf_file->f, "xref\r\n");
eric@59 671 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
eric@59 672 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
eric@59 673 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 674 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
eric@59 675 return (pdf_file->last_ind_obj->obj_num + 1);
eric@59 676 }
eric@59 677
eric@59 678
eric@101 679 /* this isn't really a PDF primitive data type */
eric@101 680 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
eric@101 681 {
eric@101 682 char XObject_name [4] = "Im ";
eric@101 683
eric@101 684 XObject_name [2] = ++pdf_page->last_XObject_name;
eric@101 685
eric@101 686 if (! pdf_page->XObject_dict)
eric@101 687 {
eric@101 688 pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
eric@101 689 pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
eric@101 690 }
eric@101 691
eric@101 692 pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
eric@101 693
eric@101 694 return (pdf_page->last_XObject_name);
eric@101 695 }
eric@101 696
eric@101 697