pdf_prim.c

Fri, 14 Mar 2003 08:24:37 +0000

author
eric
date
Fri, 14 Mar 2003 08:24:37 +0000
changeset 131
4b8c80d77f76
parent 125
e2ef1c2f9eca
child 145
3ed3f7f32837
permissions
-rw-r--r--

finished implementing page labels.

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * PDF routines
     5  * $Id: pdf_prim.c,v 1.12 2003/03/13 00:57:05 eric Exp $
     6  * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdarg.h>
    26 #include <stdbool.h>
    27 #include <stdint.h>
    28 #include <stdio.h>
    29 #include <stdlib.h>
    30 #include <string.h>
    32 #include "bitblt.h"
    33 #include "pdf.h"
    34 #include "pdf_util.h"
    35 #include "pdf_prim.h"
    36 #include "pdf_private.h"
    39 struct pdf_array_elem
    40 {
    41   struct pdf_array_elem *next;
    42   struct pdf_obj        *val;
    43 };
    46 struct pdf_array
    47 {
    48   struct pdf_array_elem *first;
    49   struct pdf_array_elem *last;
    50 };
    53 struct pdf_dict_entry
    54 {
    55   struct pdf_dict_entry *next;
    56   char                  *key;
    57   struct pdf_obj        *val;
    58 };
    61 struct pdf_dict
    62 {
    63   struct pdf_dict_entry *first;
    64 };
    67 struct pdf_stream
    68 {
    69   struct pdf_obj *stream_dict;
    70   struct pdf_obj *length;
    71   pdf_stream_write_callback callback;
    72   void *app_data;  /* arg to pass to callback */
    73   struct pdf_obj *filters;  /* name or array of names */
    74   struct pdf_obj *decode_parms;
    75 };
    78 struct pdf_obj
    79 {
    80   /* these fields only apply to indirectly referenced objects */
    81   struct pdf_obj      *prev;
    82   struct pdf_obj      *next;
    83   unsigned long       obj_num;
    84   unsigned long       obj_gen;
    85   long int            file_offset;
    87   /* these fields apply to all objects */
    88   unsigned long       ref_count;
    89   pdf_obj_type        type;
    90   union {
    91     bool              boolean;
    92     char              *name;
    93     char              *string;
    94     long              integer;
    95     double            real;
    96     struct pdf_obj    *ind_ref;
    97     struct pdf_dict   dict;
    98     struct pdf_array  array;
    99     struct pdf_stream stream;
   100   } val;
   101 };
   104 struct pdf_obj *ref (struct pdf_obj *obj)
   105 {
   106   obj->ref_count++;
   107   return (obj);
   108 }
   111 void unref (struct pdf_obj *obj)
   112 {
   113   if ((--obj->ref_count) == 0)
   114     {
   115       /* $$$ free the object */
   116     }
   117 }
   120 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
   121 {
   122   pdf_assert (ind_obj->type == PT_IND_REF);
   123   return (ind_obj->val.ind_ref);
   124 }
   127 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
   128 {
   129   struct pdf_dict_entry *entry;
   131   if (dict_obj->type == PT_IND_REF)
   132     dict_obj = pdf_deref_ind_obj (dict_obj);
   134   pdf_assert (dict_obj->type == PT_DICTIONARY);
   136   /* replacing existing entry? */
   137   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   138     if (strcmp (entry->key, key) == 0)
   139       {
   140 	unref (entry->val);
   141 	entry->val = ref (val);
   142 	return;
   143       }
   145   /* new entry */
   146   entry = pdf_calloc (1, sizeof (struct pdf_dict_entry));
   148   entry->next = dict_obj->val.dict.first;
   149   dict_obj->val.dict.first = entry;
   151   entry->key = pdf_strdup (key);
   152   entry->val = ref (val);
   153 }
   156 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
   157 {
   158   struct pdf_dict_entry *entry;
   160   if (dict_obj->type == PT_IND_REF)
   161     dict_obj = pdf_deref_ind_obj (dict_obj);
   163   pdf_assert (dict_obj->type == PT_DICTIONARY);
   165   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   166     if (strcmp (entry->key, key) == 0)
   167       return (entry->val);
   169   return (NULL);
   170 }
   173 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
   174 {
   175   struct pdf_array_elem *elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
   177   if (array_obj->type == PT_IND_REF)
   178     array_obj = pdf_deref_ind_obj (array_obj);
   180   pdf_assert (array_obj->type == PT_ARRAY);
   182   elem->val = ref (val);
   184   if (! array_obj->val.array.first)
   185     array_obj->val.array.first = elem;
   186   else
   187     array_obj->val.array.last->next = elem;
   189   array_obj->val.array.last = elem;
   190 }
   193 void pdf_add_array_elem_unique (struct pdf_obj *array_obj, struct pdf_obj *val)
   194 {
   195   struct pdf_array_elem *elem;
   197   if (array_obj->type == PT_IND_REF)
   198     array_obj = pdf_deref_ind_obj (array_obj);
   200   pdf_assert (array_obj->type == PT_ARRAY);
   202   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   203     if (pdf_compare_obj (val, elem->val) == 0)
   204       return;
   206   elem = pdf_calloc (1, sizeof (struct pdf_array_elem));
   208   elem->val = ref (val);
   210   if (! array_obj->val.array.first)
   211     array_obj->val.array.first = elem;
   212   else
   213     array_obj->val.array.last->next = elem;
   215   array_obj->val.array.last = elem;
   216 }
   219 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
   220 {
   221   struct pdf_obj *obj = pdf_calloc (1, sizeof (struct pdf_obj));
   222   obj->type = type;
   223   return (obj);
   224 }
   227 struct pdf_obj *pdf_new_bool (bool val)
   228 {
   229   struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
   230   obj->val.boolean = val;
   231   return (obj);
   232 }
   235 struct pdf_obj *pdf_new_name (char *name)
   236 {
   237   struct pdf_obj *obj = pdf_new_obj (PT_NAME);
   238   obj->val.name = pdf_strdup (name);
   239   return (obj);
   240 }
   243 struct pdf_obj *pdf_new_string (char *str)
   244 {
   245   struct pdf_obj *obj = pdf_new_obj (PT_STRING);
   246   obj->val.string = pdf_strdup (str);
   247   return (obj);
   248 }
   251 struct pdf_obj *pdf_new_integer (long val)
   252 {
   253   struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
   254   obj->val.integer = val;
   255   return (obj);
   256 }
   259 struct pdf_obj *pdf_new_real (double val)
   260 {
   261   struct pdf_obj *obj = pdf_new_obj (PT_REAL);
   262   obj->val.real = val;
   263   return (obj);
   264 }
   267 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
   268 				struct pdf_obj *stream_dict,
   269 				pdf_stream_write_callback callback,
   270 				void *app_data)
   271 {
   272   struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
   274   obj->val.stream.stream_dict = stream_dict;
   275   obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
   276   pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
   278   obj->val.stream.callback = callback;
   279   obj->val.stream.app_data = app_data;
   280   return (obj);
   281 }
   284 /* $$$ currently limited to one filter per stream */
   285 void pdf_stream_add_filter (struct pdf_obj *stream,
   286 			    char *filter_name,
   287 			    struct pdf_obj *decode_parms)
   288 {
   289   if (stream->type == PT_IND_REF)
   290     stream = pdf_deref_ind_obj (stream);
   292   pdf_assert (stream->type == PT_STREAM);
   294   pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
   295   if (decode_parms)
   296     pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
   297 }
   300 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
   301 {
   302   struct pdf_obj *ind_obj;
   304   pdf_assert (obj->type != PT_IND_REF);
   306   ind_obj = pdf_new_obj (PT_IND_REF);
   308   ind_obj->type = PT_IND_REF;
   309   ind_obj->val.ind_ref = obj;
   311   /* is there already an indirect reference to this object? */
   312   if (! obj->obj_num)
   313     {
   314       /* no, assign object number/generation and add to linked list */
   315       if (! pdf_file->first_ind_obj)
   316 	{
   317 	  obj->obj_num = 1;
   318 	  pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
   319 	}
   320       else
   321 	{
   322 	  obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
   323 	  pdf_file->last_ind_obj->next = obj;
   324 	  obj->prev = pdf_file->last_ind_obj;
   325 	  pdf_file->last_ind_obj = obj;
   326 	}
   327     }
   329   return (ind_obj);
   330 }
   333 long pdf_get_integer (struct pdf_obj *obj)
   334 {
   335   if (obj->type == PT_IND_REF)
   336     obj = pdf_deref_ind_obj (obj);
   338   pdf_assert (obj->type == PT_INTEGER);
   340   return (obj->val.integer);
   341 }
   343 void pdf_set_integer (struct pdf_obj *obj, long val)
   344 {
   345   if (obj->type == PT_IND_REF)
   346     obj = pdf_deref_ind_obj (obj);
   348   pdf_assert (obj->type == PT_INTEGER);
   350   obj->val.integer = val;
   351 }
   354 double pdf_get_real (struct pdf_obj *obj)
   355 {
   356   if (obj->type == PT_IND_REF)
   357     obj = pdf_deref_ind_obj (obj);
   359   pdf_assert (obj->type == PT_REAL);
   361   return (obj->val.real);
   362 }
   364 void pdf_set_real (struct pdf_obj *obj, double val)
   365 {
   366   if (obj->type == PT_IND_REF)
   367     obj = pdf_deref_ind_obj (obj);
   369   pdf_assert (obj->type == PT_REAL);
   371   obj->val.real = val;
   372 }
   375 int pdf_compare_obj (struct pdf_obj *o1, struct pdf_obj *o2)
   376 {
   377   if (o1->type == PT_IND_REF)
   378     o1 = pdf_deref_ind_obj (o1);
   380   if (o2->type == PT_IND_REF)
   381     o2 = pdf_deref_ind_obj (o2);
   383   pdf_assert (o1->type == o2->type);
   385   switch (o1->type)
   386     {
   387     case PT_INTEGER:
   388       if (o1->val.integer < o2->val.integer)
   389 	return (-1);
   390       if (o1->val.integer > o2->val.integer)
   391 	return (1);
   392       return (0);
   393     case PT_REAL:
   394       if (o1->val.real < o2->val.real)
   395 	return (-1);
   396       if (o1->val.real > o2->val.real)
   397 	return (1);
   398       return (0);
   399     case PT_STRING:
   400       return (strcmp (o1->val.string, o2->val.string));
   401     case PT_NAME:
   402       return (strcmp (o1->val.name, o2->val.name));
   403     default:
   404       pdf_fatal ("invalid object type for comparison\n");
   405     }
   406 }
   409 static int name_char_needs_quoting (char c)
   410 {
   411   return ((c < '!')  || (c > '~')  || (c == '/') || (c == '\\') ||
   412 	  (c == '(') || (c == ')') || (c == '<') || (c == '>')  ||
   413 	  (c == '[') || (c == ']') || (c == '{') || (c == '}')  ||
   414 	  (c == '%'));
   415 }
   418 void pdf_write_name (pdf_file_handle pdf_file, char *s)
   419 {
   420   fprintf (pdf_file->f, "/");
   421   while (*s)
   422     if (name_char_needs_quoting (*s))
   423       fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
   424     else
   425       fprintf (pdf_file->f, "%c", *(s++));
   426   fprintf (pdf_file->f, " ");
   427 }
   430 static int string_char_needs_quoting (char c)
   431 {
   432   return ((c < ' ')  || (c > '~')  || (c == '\\') ||
   433 	  (c == '(') || (c == ')'));
   434 }
   437 void pdf_write_string (pdf_file_handle pdf_file, char *s)
   438 {
   439   fprintf (pdf_file->f, "(");
   440   while (*s)
   441     if (string_char_needs_quoting (*s))
   442       fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
   443     else
   444       fprintf (pdf_file->f, "%c", *(s++));
   445   fprintf (pdf_file->f, ") ");
   446 }
   449 void pdf_write_real (pdf_file_handle pdf_file, double num)
   450 {
   451   /* $$$ not actually good enough, precision needs to be variable,
   452      and no exponent is allowed */
   453   fprintf (pdf_file->f, "%0f ", num);
   454 }
   457 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   458 {
   459   struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
   460   fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
   461 }
   464 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
   465 {
   466   struct pdf_array_elem *elem;
   468   pdf_assert (array_obj->type == PT_ARRAY);
   470   fprintf (pdf_file->f, "[ ");
   471   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   472     {
   473       pdf_write_obj (pdf_file, elem->val);
   474       fprintf (pdf_file->f, " ");
   475     }
   476   fprintf (pdf_file->f, "] ");
   477 }
   480 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
   481 {
   482   struct pdf_dict_entry *entry;
   484   pdf_assert (dict_obj->type == PT_DICTIONARY);
   486   fprintf (pdf_file->f, "<<\r\n");
   487   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   488     {
   489       pdf_write_name (pdf_file, entry->key);
   490       fprintf (pdf_file->f, " ");
   491       pdf_write_obj (pdf_file, entry->val);
   492       fprintf (pdf_file->f, "\r\n");
   493     }
   494   fprintf (pdf_file->f, ">>\r\n");
   495 }
   498 void pdf_stream_write_data (pdf_file_handle pdf_file,
   499 			    struct pdf_obj *stream,
   500 			    char *data,
   501 			    unsigned long len)
   502 {
   503   while (len)
   504     {
   505       unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
   506       data += l2;
   507       len -= l2;
   508       if (ferror (pdf_file->f))
   509 	pdf_fatal ("error writing stream data\n");
   510     }
   511 }
   514 void pdf_stream_printf (pdf_file_handle pdf_file,
   515 			struct pdf_obj *stream,
   516 			char *fmt, ...)
   517 {
   518   va_list ap;
   520   va_start (ap, fmt);
   521   vfprintf (pdf_file->f, fmt, ap);
   522   va_end (ap);
   523 }
   526 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
   527 {
   528   unsigned long begin_pos, end_pos;
   530   pdf_assert (stream->type == PT_STREAM);
   532   pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
   533   fprintf (pdf_file->f, "stream\r\n");
   534   begin_pos = ftell (pdf_file->f);
   535   stream->val.stream.callback (pdf_file,
   536 			       stream,
   537 			       stream->val.stream.app_data);
   538   end_pos = ftell (pdf_file->f);
   539   fprintf (pdf_file->f, "endstream\r\n");
   541   pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
   542 }
   545 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
   546 {
   547   switch (obj->type)
   548     {
   549     case PT_NULL:
   550       fprintf (pdf_file->f, "null ");
   551       break;
   552     case PT_BOOL:
   553       if (obj->val.boolean)
   554 	fprintf (pdf_file->f, "true ");
   555       else
   556 	fprintf (pdf_file->f, "false ");
   557       break;
   558     case PT_NAME:
   559       pdf_write_name (pdf_file, obj->val.name);
   560       break;
   561     case PT_STRING:
   562       pdf_write_string (pdf_file, obj->val.string);
   563       break;
   564     case PT_INTEGER:
   565       fprintf (pdf_file->f, "%ld ", obj->val.integer);
   566       break;
   567     case PT_REAL:
   568       pdf_write_real (pdf_file, obj->val.real);
   569       break;
   570     case PT_IND_REF:
   571       pdf_write_ind_ref (pdf_file, obj);
   572       break;
   573     case PT_DICTIONARY:
   574       pdf_write_dict (pdf_file, obj);
   575       break;
   576     case PT_ARRAY:
   577       pdf_write_array (pdf_file, obj);
   578       break;
   579     case PT_STREAM:
   580       pdf_write_stream (pdf_file, obj);
   581       break;
   582     default:
   583       pdf_fatal ("bad object type\n");
   584     }
   585 }
   588 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   589 {
   590   struct pdf_obj *obj;
   592   if (ind_obj->type == PT_IND_REF)
   593     obj = pdf_deref_ind_obj (ind_obj);
   594   else
   595     obj = ind_obj;
   597   obj->file_offset = ftell (pdf_file->f);
   598   fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
   599   pdf_write_obj (pdf_file, obj);
   600   fprintf (pdf_file->f, "endobj\r\n");
   601 }
   604 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
   605 {
   606   struct pdf_obj *ind_obj;
   607   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   608     if (! ind_obj->file_offset)
   609       pdf_write_ind_obj (pdf_file, ind_obj);
   610 }
   613 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
   614 {
   615   struct pdf_obj *ind_obj;
   616   pdf_file->xref_offset = ftell (pdf_file->f);
   617   fprintf (pdf_file->f, "xref\r\n");
   618   fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
   619   fprintf (pdf_file->f, "0000000000 65535 f\r\n");
   620   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   621     fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
   622   return (pdf_file->last_ind_obj->obj_num + 1);
   623 }
   626 /* this isn't really a PDF primitive data type */
   627 char pdf_new_XObject (pdf_page_handle pdf_page, struct pdf_obj *ind_ref)
   628 {
   629   char XObject_name [4] = "Im ";
   631   XObject_name [2] = ++pdf_page->last_XObject_name;
   633   if (! pdf_page->XObject_dict)
   634     {
   635       pdf_page->XObject_dict = pdf_new_obj (PT_DICTIONARY);
   636       pdf_set_dict_entry (pdf_page->resources, "XObject", pdf_page->XObject_dict);
   637     }
   639   pdf_set_dict_entry (pdf_page->XObject_dict, & XObject_name [0], ind_ref);
   641   return (pdf_page->last_XObject_name);
   642 }