pdf_prim.c

Thu, 20 Mar 2003 15:26:16 +0000

author
eric
date
Thu, 20 Mar 2003 15:26:16 +0000
changeset 153
4a4a5b5fd6e5
parent 145
3ed3f7f32837
child 166
301f6f17c364
permissions
-rw-r--r--

*** empty log message ***

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;
eric@59 93 char *string;
eric@74 94 long integer;
eric@59 95 double real;
eric@59 96 struct pdf_obj *ind_ref;
eric@59 97 struct pdf_dict dict;
eric@59 98 struct pdf_array array;
eric@59 99 struct pdf_stream stream;
eric@59 100 } val;
eric@59 101 };
eric@59 102
eric@59 103
eric@59 104 struct pdf_obj *ref (struct pdf_obj *obj)
eric@59 105 {
eric@59 106 obj->ref_count++;
eric@59 107 return (obj);
eric@59 108 }
eric@59 109
eric@59 110
eric@59 111 void unref (struct pdf_obj *obj)
eric@59 112 {
eric@59 113 if ((--obj->ref_count) == 0)
eric@59 114 {
eric@59 115 /* $$$ free the object */
eric@59 116 }
eric@59 117 }
eric@59 118
eric@59 119
eric@59 120 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
eric@59 121 {
eric@59 122 pdf_assert (ind_obj->type == PT_IND_REF);
eric@59 123 return (ind_obj->val.ind_ref);
eric@59 124 }
eric@59 125
eric@59 126
eric@59 127 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
eric@59 128 {
eric@59 129 struct pdf_dict_entry *entry;
eric@59 130
eric@59 131 if (dict_obj->type == PT_IND_REF)
eric@59 132 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 133
eric@59 134 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 135
eric@59 136 /* replacing existing entry? */
eric@59 137 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 138 if (strcmp (entry->key, key) == 0)
eric@59 139 {
eric@59 140 unref (entry->val);
eric@59 141 entry->val = ref (val);
eric@59 142 return;
eric@59 143 }
eric@59 144
eric@59 145 /* new entry */
eric@67 146 entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
eric@59 147
eric@59 148 entry->next = dict_obj->val.dict.first;
eric@59 149 dict_obj->val.dict.first = entry;
eric@59 150
eric@59 151 entry->key = pdf_strdup (key);
eric@59 152 entry->val = ref (val);
eric@59 153 }
eric@59 154
eric@59 155
eric@59 156 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
eric@59 157 {
eric@59 158 struct pdf_dict_entry *entry;
eric@59 159
eric@59 160 if (dict_obj->type == PT_IND_REF)
eric@59 161 dict_obj = pdf_deref_ind_obj (dict_obj);
eric@59 162
eric@59 163 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 164
eric@59 165 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 166 if (strcmp (entry->key, key) == 0)
eric@59 167 return (entry->val);
eric@59 168
eric@59 169 return (NULL);
eric@59 170 }
eric@59 171
eric@59 172
eric@59 173 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@59 174 {
eric@67 175 struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
eric@59 176
eric@59 177 if (array_obj->type == PT_IND_REF)
eric@59 178 array_obj = pdf_deref_ind_obj (array_obj);
eric@59 179
eric@59 180 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 181
eric@59 182 elem->val = ref (val);
eric@59 183
eric@59 184 if (! array_obj->val.array.first)
eric@59 185 array_obj->val.array.first = elem;
eric@59 186 else
eric@59 187 array_obj->val.array.last->next = elem;
eric@59 188
eric@59 189 array_obj->val.array.last = elem;
eric@59 190 }
eric@59 191
eric@59 192
eric@118 193 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
eric@118 194 {
eric@118 195 struct pdf_array_elem *elem;
eric@118 196
eric@118 197 if (array_obj->type == PT_IND_REF)
eric@118 198 array_obj = pdf_deref_ind_obj (array_obj);
eric@118 199
eric@118 200 pdf_assert (array_obj->type == PT_ARRAY);
eric@118 201
eric@118 202 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@118 203 if (pdf_compare_obj (val, elem->val) == 0)
eric@118 204 return;
eric@118 205
eric@118 206 elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
eric@118 207
eric@118 208 elem->val = ref (val);
eric@118 209
eric@118 210 if (! array_obj->val.array.first)
eric@118 211 array_obj->val.array.first = elem;
eric@118 212 else
eric@118 213 array_obj->val.array.last->next = elem;
eric@118 214
eric@118 215 array_obj->val.array.last = elem;
eric@118 216 }
eric@118 217
eric@118 218
eric@59 219 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
eric@59 220 {
eric@67 221 struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
eric@59 222 obj->type = type;
eric@59 223 return (obj);
eric@59 224 }
eric@59 225
eric@59 226
eric@62 227 struct pdf_obj *pdf_new_bool (bool val)
eric@59 228 {
eric@59 229 struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
eric@62 230 obj->val.boolean = val;
eric@59 231 return (obj);
eric@59 232 }
eric@59 233
eric@59 234
eric@59 235 struct pdf_obj *pdf_new_name (char *name)
eric@59 236 {
eric@59 237 struct pdf_obj *obj = pdf_new_obj (PT_NAME);
eric@59 238 obj->val.name = pdf_strdup (name);
eric@59 239 return (obj);
eric@59 240 }
eric@59 241
eric@59 242
eric@59 243 struct pdf_obj *pdf_new_string (char *str)
eric@59 244 {
eric@59 245 struct pdf_obj *obj = pdf_new_obj (PT_STRING);
eric@59 246 obj->val.string = pdf_strdup (str);
eric@59 247 return (obj);
eric@59 248 }
eric@59 249
eric@59 250
eric@74 251 struct pdf_obj *pdf_new_integer (long val)
eric@59 252 {
eric@59 253 struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
eric@59 254 obj->val.integer = val;
eric@59 255 return (obj);
eric@59 256 }
eric@59 257
eric@59 258
eric@59 259 struct pdf_obj *pdf_new_real (double val)
eric@59 260 {
eric@59 261 struct pdf_obj *obj = pdf_new_obj (PT_REAL);
eric@59 262 obj->val.real = val;
eric@59 263 return (obj);
eric@59 264 }
eric@59 265
eric@59 266
eric@59 267 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
eric@59 268 struct pdf_obj *stream_dict,
eric@59 269 pdf_stream_write_callback callback,
eric@59 270 void *app_data)
eric@59 271 {
eric@59 272 struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
eric@59 273
eric@59 274 obj->val.stream.stream_dict = stream_dict;
eric@59 275 obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
eric@59 276 pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
eric@59 277
eric@59 278 obj->val.stream.callback = callback;
eric@59 279 obj->val.stream.app_data = app_data;
eric@59 280 return (obj);
eric@59 281 }
eric@59 282
eric@59 283
eric@59 284 /* $$$ currently limited to one filter per stream */
eric@59 285 void pdf_stream_add_filter (struct pdf_obj *stream,
eric@59 286 char *filter_name,
eric@59 287 struct pdf_obj *decode_parms)
eric@59 288 {
eric@59 289 if (stream->type == PT_IND_REF)
eric@59 290 stream = pdf_deref_ind_obj (stream);
eric@59 291
eric@59 292 pdf_assert (stream->type == PT_STREAM);
eric@59 293
eric@59 294 pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
eric@59 295 if (decode_parms)
eric@59 296 pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
eric@59 297 }
eric@59 298
eric@59 299
eric@59 300 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 301 {
eric@59 302 struct pdf_obj *ind_obj;
eric@59 303
eric@59 304 pdf_assert (obj->type != PT_IND_REF);
eric@59 305
eric@59 306 ind_obj = pdf_new_obj (PT_IND_REF);
eric@59 307
eric@59 308 ind_obj->type = PT_IND_REF;
eric@59 309 ind_obj->val.ind_ref = obj;
eric@59 310
eric@59 311 /* is there already an indirect reference to this object? */
eric@59 312 if (! obj->obj_num)
eric@59 313 {
eric@59 314 /* no, assign object number/generation and add to linked list */
eric@59 315 if (! pdf_file->first_ind_obj)
eric@59 316 {
eric@59 317 obj->obj_num = 1;
eric@59 318 pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
eric@59 319 }
eric@59 320 else
eric@59 321 {
eric@59 322 obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
eric@59 323 pdf_file->last_ind_obj->next = obj;
eric@59 324 obj->prev = pdf_file->last_ind_obj;
eric@59 325 pdf_file->last_ind_obj = obj;
eric@59 326 }
eric@59 327 }
eric@59 328
eric@59 329 return (ind_obj);
eric@59 330 }
eric@59 331
eric@59 332
eric@74 333 long pdf_get_integer (struct pdf_obj *obj)
eric@59 334 {
eric@59 335 if (obj->type == PT_IND_REF)
eric@59 336 obj = pdf_deref_ind_obj (obj);
eric@59 337
eric@59 338 pdf_assert (obj->type == PT_INTEGER);
eric@59 339
eric@59 340 return (obj->val.integer);
eric@59 341 }
eric@59 342
eric@74 343 void pdf_set_integer (struct pdf_obj *obj, long val)
eric@59 344 {
eric@59 345 if (obj->type == PT_IND_REF)
eric@59 346 obj = pdf_deref_ind_obj (obj);
eric@59 347
eric@59 348 pdf_assert (obj->type == PT_INTEGER);
eric@59 349
eric@59 350 obj->val.integer = val;
eric@59 351 }
eric@59 352
eric@59 353
eric@59 354 double pdf_get_real (struct pdf_obj *obj)
eric@59 355 {
eric@59 356 if (obj->type == PT_IND_REF)
eric@59 357 obj = pdf_deref_ind_obj (obj);
eric@59 358
eric@59 359 pdf_assert (obj->type == PT_REAL);
eric@59 360
eric@59 361 return (obj->val.real);
eric@59 362 }
eric@59 363
eric@59 364 void pdf_set_real (struct pdf_obj *obj, double val)
eric@59 365 {
eric@59 366 if (obj->type == PT_IND_REF)
eric@59 367 obj = pdf_deref_ind_obj (obj);
eric@59 368
eric@59 369 pdf_assert (obj->type == PT_REAL);
eric@59 370
eric@59 371 obj->val.real = val;
eric@59 372 }
eric@59 373
eric@59 374
eric@82 375 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
eric@82 376 {
eric@82 377 if (o1->type == PT_IND_REF)
eric@82 378 o1 = pdf_deref_ind_obj (o1);
eric@82 379
eric@82 380 if (o2->type == PT_IND_REF)
eric@82 381 o2 = pdf_deref_ind_obj (o2);
eric@82 382
eric@82 383 pdf_assert (o1->type == o2->type);
eric@82 384
eric@82 385 switch (o1->type)
eric@82 386 {
eric@82 387 case PT_INTEGER:
eric@82 388 if (o1->val.integer < o2->val.integer)
eric@82 389 return (-1);
eric@82 390 if (o1->val.integer > o2->val.integer)
eric@82 391 return (1);
eric@82 392 return (0);
eric@82 393 case PT_REAL:
eric@82 394 if (o1->val.real < o2->val.real)
eric@82 395 return (-1);
eric@82 396 if (o1->val.real > o2->val.real)
eric@82 397 return (1);
eric@82 398 return (0);
eric@82 399 case PT_STRING:
eric@82 400 return (strcmp (o1->val.string, o2->val.string));
eric@118 401 case PT_NAME:
eric@118 402 return (strcmp (o1->val.name, o2->val.name));
eric@82 403 default:
eric@82 404 pdf_fatal ("invalid object type for comparison\n");
eric@82 405 }
eric@82 406 }
eric@82 407
eric@82 408
eric@59 409 static int name_char_needs_quoting (char c)
eric@59 410 {
eric@59 411 return ((c < '!') || (c > '~') || (c == '/') || (c == '\\') ||
eric@59 412 (c == '(') || (c == ')') || (c == '<') || (c == '>') ||
eric@59 413 (c == '[') || (c == ']') || (c == '{') || (c == '}') ||
eric@59 414 (c == '%'));
eric@59 415 }
eric@59 416
eric@59 417
eric@59 418 void pdf_write_name (pdf_file_handle pdf_file, char *s)
eric@59 419 {
eric@59 420 fprintf (pdf_file->f, "/");
eric@59 421 while (*s)
eric@59 422 if (name_char_needs_quoting (*s))
eric@59 423 fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
eric@59 424 else
eric@59 425 fprintf (pdf_file->f, "%c", *(s++));
eric@59 426 fprintf (pdf_file->f, " ");
eric@59 427 }
eric@59 428
eric@59 429
eric@59 430 static int string_char_needs_quoting (char c)
eric@59 431 {
eric@59 432 return ((c < ' ') || (c > '~') || (c == '\\') ||
eric@59 433 (c == '(') || (c == ')'));
eric@59 434 }
eric@59 435
eric@59 436
eric@59 437 void pdf_write_string (pdf_file_handle pdf_file, char *s)
eric@59 438 {
eric@59 439 fprintf (pdf_file->f, "(");
eric@59 440 while (*s)
eric@59 441 if (string_char_needs_quoting (*s))
eric@59 442 fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
eric@59 443 else
eric@59 444 fprintf (pdf_file->f, "%c", *(s++));
eric@59 445 fprintf (pdf_file->f, ") ");
eric@59 446 }
eric@59 447
eric@59 448
eric@59 449 void pdf_write_real (pdf_file_handle pdf_file, double num)
eric@59 450 {
eric@59 451 /* $$$ not actually good enough, precision needs to be variable,
eric@59 452 and no exponent is allowed */
eric@59 453 fprintf (pdf_file->f, "%0f ", num);
eric@59 454 }
eric@59 455
eric@59 456
eric@59 457 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 458 {
eric@59 459 struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
eric@59 460 fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
eric@59 461 }
eric@59 462
eric@59 463
eric@59 464 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
eric@59 465 {
eric@59 466 struct pdf_array_elem *elem;
eric@59 467
eric@59 468 pdf_assert (array_obj->type == PT_ARRAY);
eric@59 469
eric@59 470 fprintf (pdf_file->f, "[ ");
eric@59 471 for (elem = array_obj->val.array.first; elem; elem = elem->next)
eric@59 472 {
eric@59 473 pdf_write_obj (pdf_file, elem->val);
eric@59 474 fprintf (pdf_file->f, " ");
eric@59 475 }
eric@59 476 fprintf (pdf_file->f, "] ");
eric@59 477 }
eric@59 478
eric@59 479
eric@59 480 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
eric@59 481 {
eric@59 482 struct pdf_dict_entry *entry;
eric@59 483
eric@59 484 pdf_assert (dict_obj->type == PT_DICTIONARY);
eric@59 485
eric@59 486 fprintf (pdf_file->f, "<<\r\n");
eric@59 487 for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
eric@59 488 {
eric@59 489 pdf_write_name (pdf_file, entry->key);
eric@59 490 fprintf (pdf_file->f, " ");
eric@59 491 pdf_write_obj (pdf_file, entry->val);
eric@59 492 fprintf (pdf_file->f, "\r\n");
eric@59 493 }
eric@59 494 fprintf (pdf_file->f, ">>\r\n");
eric@59 495 }
eric@59 496
eric@59 497
eric@59 498 void pdf_stream_write_data (pdf_file_handle pdf_file,
eric@59 499 struct pdf_obj *stream,
eric@59 500 char *data,
eric@59 501 unsigned long len)
eric@59 502 {
eric@59 503 while (len)
eric@59 504 {
eric@59 505 unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
eric@59 506 data += l2;
eric@59 507 len -= l2;
eric@59 508 if (ferror (pdf_file->f))
eric@59 509 pdf_fatal ("error writing stream data\n");
eric@59 510 }
eric@59 511 }
eric@59 512
eric@59 513
eric@66 514 void pdf_stream_printf (pdf_file_handle pdf_file,
eric@66 515 struct pdf_obj *stream,
eric@66 516 char *fmt, ...)
eric@66 517 {
eric@66 518 va_list ap;
eric@66 519
eric@66 520 va_start (ap, fmt);
eric@66 521 vfprintf (pdf_file->f, fmt, ap);
eric@66 522 va_end (ap);
eric@66 523 }
eric@66 524
eric@66 525
eric@59 526 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
eric@59 527 {
eric@59 528 unsigned long begin_pos, end_pos;
eric@59 529
eric@59 530 pdf_assert (stream->type == PT_STREAM);
eric@59 531
eric@59 532 pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
eric@59 533 fprintf (pdf_file->f, "stream\r\n");
eric@59 534 begin_pos = ftell (pdf_file->f);
eric@59 535 stream->val.stream.callback (pdf_file,
eric@59 536 stream,
eric@59 537 stream->val.stream.app_data);
eric@59 538 end_pos = ftell (pdf_file->f);
eric@145 539
eric@145 540 fprintf (pdf_file->f, "\r\nendstream\r\n");
eric@59 541
eric@59 542 pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
eric@59 543 }
eric@59 544
eric@59 545
eric@59 546 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
eric@59 547 {
eric@59 548 switch (obj->type)
eric@59 549 {
eric@59 550 case PT_NULL:
eric@59 551 fprintf (pdf_file->f, "null ");
eric@59 552 break;
eric@59 553 case PT_BOOL:
eric@62 554 if (obj->val.boolean)
eric@59 555 fprintf (pdf_file->f, "true ");
eric@59 556 else
eric@59 557 fprintf (pdf_file->f, "false ");
eric@59 558 break;
eric@59 559 case PT_NAME:
eric@59 560 pdf_write_name (pdf_file, obj->val.name);
eric@59 561 break;
eric@59 562 case PT_STRING:
eric@59 563 pdf_write_string (pdf_file, obj->val.string);
eric@59 564 break;
eric@59 565 case PT_INTEGER:
eric@59 566 fprintf (pdf_file->f, "%ld ", obj->val.integer);
eric@59 567 break;
eric@59 568 case PT_REAL:
eric@59 569 pdf_write_real (pdf_file, obj->val.real);
eric@59 570 break;
eric@59 571 case PT_IND_REF:
eric@59 572 pdf_write_ind_ref (pdf_file, obj);
eric@59 573 break;
eric@59 574 case PT_DICTIONARY:
eric@59 575 pdf_write_dict (pdf_file, obj);
eric@59 576 break;
eric@59 577 case PT_ARRAY:
eric@59 578 pdf_write_array (pdf_file, obj);
eric@59 579 break;
eric@59 580 case PT_STREAM:
eric@59 581 pdf_write_stream (pdf_file, obj);
eric@59 582 break;
eric@59 583 default:
eric@59 584 pdf_fatal ("bad object type\n");
eric@59 585 }
eric@59 586 }
eric@59 587
eric@59 588
eric@59 589 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
eric@59 590 {
eric@59 591 struct pdf_obj *obj;
eric@59 592
eric@59 593 if (ind_obj->type == PT_IND_REF)
eric@59 594 obj = pdf_deref_ind_obj (ind_obj);
eric@59 595 else
eric@59 596 obj = ind_obj;
eric@59 597
eric@59 598 obj->file_offset = ftell (pdf_file->f);
eric@59 599 fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
eric@59 600 pdf_write_obj (pdf_file, obj);
eric@59 601 fprintf (pdf_file->f, "endobj\r\n");
eric@59 602 }
eric@59 603
eric@59 604
eric@59 605 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
eric@59 606 {
eric@59 607 struct pdf_obj *ind_obj;
eric@59 608 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 609 if (! ind_obj->file_offset)
eric@59 610 pdf_write_ind_obj (pdf_file, ind_obj);
eric@59 611 }
eric@59 612
eric@59 613
eric@59 614 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
eric@59 615 {
eric@59 616 struct pdf_obj *ind_obj;
eric@59 617 pdf_file->xref_offset = ftell (pdf_file->f);
eric@59 618 fprintf (pdf_file->f, "xref\r\n");
eric@59 619 fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
eric@59 620 fprintf (pdf_file->f, "0000000000 65535 f\r\n");
eric@59 621 for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
eric@59 622 fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
eric@59 623 return (pdf_file->last_ind_obj->obj_num + 1);
eric@59 624 }
eric@59 625
eric@59 626
eric@101 627 /* this isn't really a PDF primitive data type */
eric@101 628 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
eric@101 629 {
eric@101 630 char XObject_name [4] = "Im ";
eric@101 631
eric@101 632 XObject_name [2] = ++pdf_page->last_XObject_name;
eric@101 633
eric@101 634 if (! pdf_page->XObject_dict)
eric@101 635 {
eric@101 636 pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
eric@101 637 pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
eric@101 638 }
eric@101 639
eric@101 640 pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
eric@101 641
eric@101 642 return (pdf_page->last_XObject_name);
eric@101 643 }
eric@101 644
eric@101 645