pdf_prim.c

Thu, 13 Mar 2003 07:59:10 +0000

author
eric
date
Thu, 13 Mar 2003 07:59:10 +0000
changeset 121
e50c7f76f2f6
parent 118
c22e1c0a64fd
child 123
7b5558607c49
permissions
-rw-r--r--

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 }