pdf_prim.c

Fri, 21 Feb 2003 08:49:11 +0000

author
eric
date
Fri, 21 Feb 2003 08:49:11 +0000
changeset 63
6eddf63aa517
parent 62
9bd354b83e16
child 66
6e0551b59dba
permissions
-rw-r--r--

GPL.

     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.3 2003/02/20 04:44:17 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 <stdbool.h>
    28 #include <stdint.h>
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
    33 #include "bitblt.h"
    34 #include "pdf.h"
    35 #include "pdf_util.h"
    36 #include "pdf_prim.h"
    37 #include "pdf_private.h"
    40 struct pdf_array_elem
    41 {
    42   struct pdf_array_elem *next;
    43   struct pdf_obj        *val;
    44 };
    47 struct pdf_array
    48 {
    49   struct pdf_array_elem *first;
    50   struct pdf_array_elem *last;
    51 };
    54 struct pdf_dict_entry
    55 {
    56   struct pdf_dict_entry *next;
    57   char                  *key;
    58   struct pdf_obj        *val;
    59 };
    62 struct pdf_dict
    63 {
    64   struct pdf_dict_entry *first;
    65 };
    68 struct pdf_stream
    69 {
    70   struct pdf_obj *stream_dict;
    71   struct pdf_obj *length;
    72   pdf_stream_write_callback callback;
    73   void *app_data;  /* arg to pass to callback */
    74   struct pdf_obj *filters;  /* name or array of names */
    75   struct pdf_obj *decode_parms;
    76 };
    79 struct pdf_obj
    80 {
    81   /* these fields only apply to indirectly referenced objects */
    82   struct pdf_obj      *prev;
    83   struct pdf_obj      *next;
    84   unsigned long       obj_num;
    85   unsigned long       obj_gen;
    86   long int            file_offset;
    88   /* these fields apply to all objects */
    89   unsigned long       ref_count;
    90   pdf_obj_type        type;
    91   union {
    92     bool              boolean;
    93     char              *name;
    94     char              *string;
    95     unsigned long     integer;
    96     double            real;
    97     struct pdf_obj    *ind_ref;
    98     struct pdf_dict   dict;
    99     struct pdf_array  array;
   100     struct pdf_stream stream;
   101   } val;
   102 };
   105 struct pdf_obj *ref (struct pdf_obj *obj)
   106 {
   107   obj->ref_count++;
   108   return (obj);
   109 }
   112 void unref (struct pdf_obj *obj)
   113 {
   114   if ((--obj->ref_count) == 0)
   115     {
   116       /* $$$ free the object */
   117     }
   118 }
   121 struct pdf_obj *pdf_deref_ind_obj (struct pdf_obj *ind_obj)
   122 {
   123   pdf_assert (ind_obj->type == PT_IND_REF);
   124   return (ind_obj->val.ind_ref);
   125 }
   128 void pdf_set_dict_entry (struct pdf_obj *dict_obj, char *key, struct pdf_obj *val)
   129 {
   130   struct pdf_dict_entry *entry;
   132   if (dict_obj->type == PT_IND_REF)
   133     dict_obj = pdf_deref_ind_obj (dict_obj);
   135   pdf_assert (dict_obj->type == PT_DICTIONARY);
   137   /* replacing existing entry? */
   138   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   139     if (strcmp (entry->key, key) == 0)
   140       {
   141 	unref (entry->val);
   142 	entry->val = ref (val);
   143 	return;
   144       }
   146   /* new entry */
   147   entry = pdf_calloc (sizeof (struct pdf_dict_entry));
   149   entry->next = dict_obj->val.dict.first;
   150   dict_obj->val.dict.first = entry;
   152   entry->key = pdf_strdup (key);
   153   entry->val = ref (val);
   154 }
   157 struct pdf_obj *pdf_get_dict_entry (struct pdf_obj *dict_obj, char *key)
   158 {
   159   struct pdf_dict_entry *entry;
   161   if (dict_obj->type == PT_IND_REF)
   162     dict_obj = pdf_deref_ind_obj (dict_obj);
   164   pdf_assert (dict_obj->type == PT_DICTIONARY);
   166   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   167     if (strcmp (entry->key, key) == 0)
   168       return (entry->val);
   170   return (NULL);
   171 }
   174 void pdf_add_array_elem (struct pdf_obj *array_obj, struct pdf_obj *val)
   175 {
   176   struct pdf_array_elem *elem = pdf_calloc (sizeof (struct pdf_array_elem));
   178   if (array_obj->type == PT_IND_REF)
   179     array_obj = pdf_deref_ind_obj (array_obj);
   181   pdf_assert (array_obj->type == PT_ARRAY);
   183   elem->val = ref (val);
   185   if (! array_obj->val.array.first)
   186     array_obj->val.array.first = elem;
   187   else
   188     array_obj->val.array.last->next = elem;
   190   array_obj->val.array.last = elem;
   191 }
   194 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
   195 {
   196   struct pdf_obj *obj = pdf_calloc (sizeof (struct pdf_obj));
   197   obj->type = type;
   198   return (obj);
   199 }
   202 struct pdf_obj *pdf_new_bool (bool val)
   203 {
   204   struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
   205   obj->val.boolean = val;
   206   return (obj);
   207 }
   210 struct pdf_obj *pdf_new_name (char *name)
   211 {
   212   struct pdf_obj *obj = pdf_new_obj (PT_NAME);
   213   obj->val.name = pdf_strdup (name);
   214   return (obj);
   215 }
   218 struct pdf_obj *pdf_new_string (char *str)
   219 {
   220   struct pdf_obj *obj = pdf_new_obj (PT_STRING);
   221   obj->val.string = pdf_strdup (str);
   222   return (obj);
   223 }
   226 struct pdf_obj *pdf_new_integer (unsigned long val)
   227 {
   228   struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
   229   obj->val.integer = val;
   230   return (obj);
   231 }
   234 struct pdf_obj *pdf_new_real (double val)
   235 {
   236   struct pdf_obj *obj = pdf_new_obj (PT_REAL);
   237   obj->val.real = val;
   238   return (obj);
   239 }
   242 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
   243 				struct pdf_obj *stream_dict,
   244 				pdf_stream_write_callback callback,
   245 				void *app_data)
   246 {
   247   struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
   249   obj->val.stream.stream_dict = stream_dict;
   250   obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
   251   pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
   253   obj->val.stream.callback = callback;
   254   obj->val.stream.app_data = app_data;
   255   return (obj);
   256 }
   259 /* $$$ currently limited to one filter per stream */
   260 void pdf_stream_add_filter (struct pdf_obj *stream,
   261 			    char *filter_name,
   262 			    struct pdf_obj *decode_parms)
   263 {
   264   if (stream->type == PT_IND_REF)
   265     stream = pdf_deref_ind_obj (stream);
   267   pdf_assert (stream->type == PT_STREAM);
   269   pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
   270   if (decode_parms)
   271     pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
   272 }
   275 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
   276 {
   277   struct pdf_obj *ind_obj;
   279   pdf_assert (obj->type != PT_IND_REF);
   281   ind_obj = pdf_new_obj (PT_IND_REF);
   283   ind_obj->type = PT_IND_REF;
   284   ind_obj->val.ind_ref = obj;
   286   /* is there already an indirect reference to this object? */
   287   if (! obj->obj_num)
   288     {
   289       /* no, assign object number/generation and add to linked list */
   290       if (! pdf_file->first_ind_obj)
   291 	{
   292 	  obj->obj_num = 1;
   293 	  pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
   294 	}
   295       else
   296 	{
   297 	  obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
   298 	  pdf_file->last_ind_obj->next = obj;
   299 	  obj->prev = pdf_file->last_ind_obj;
   300 	  pdf_file->last_ind_obj = obj;
   301 	}
   302     }
   304   return (ind_obj);
   305 }
   308 unsigned long pdf_get_integer (struct pdf_obj *obj)
   309 {
   310   if (obj->type == PT_IND_REF)
   311     obj = pdf_deref_ind_obj (obj);
   313   pdf_assert (obj->type == PT_INTEGER);
   315   return (obj->val.integer);
   316 }
   318 void pdf_set_integer (struct pdf_obj *obj, unsigned long val)
   319 {
   320   if (obj->type == PT_IND_REF)
   321     obj = pdf_deref_ind_obj (obj);
   323   pdf_assert (obj->type == PT_INTEGER);
   325   obj->val.integer = val;
   326 }
   329 double pdf_get_real (struct pdf_obj *obj)
   330 {
   331   if (obj->type == PT_IND_REF)
   332     obj = pdf_deref_ind_obj (obj);
   334   pdf_assert (obj->type == PT_REAL);
   336   return (obj->val.real);
   337 }
   339 void pdf_set_real (struct pdf_obj *obj, double val)
   340 {
   341   if (obj->type == PT_IND_REF)
   342     obj = pdf_deref_ind_obj (obj);
   344   pdf_assert (obj->type == PT_REAL);
   346   obj->val.real = val;
   347 }
   350 static int name_char_needs_quoting (char c)
   351 {
   352   return ((c < '!')  || (c > '~')  || (c == '/') || (c == '\\') ||
   353 	  (c == '(') || (c == ')') || (c == '<') || (c == '>')  ||
   354 	  (c == '[') || (c == ']') || (c == '{') || (c == '}')  ||
   355 	  (c == '%'));
   356 }
   359 void pdf_write_name (pdf_file_handle pdf_file, char *s)
   360 {
   361   fprintf (pdf_file->f, "/");
   362   while (*s)
   363     if (name_char_needs_quoting (*s))
   364       fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
   365     else
   366       fprintf (pdf_file->f, "%c", *(s++));
   367   fprintf (pdf_file->f, " ");
   368 }
   371 static int string_char_needs_quoting (char c)
   372 {
   373   return ((c < ' ')  || (c > '~')  || (c == '\\') ||
   374 	  (c == '(') || (c == ')'));
   375 }
   378 void pdf_write_string (pdf_file_handle pdf_file, char *s)
   379 {
   380   fprintf (pdf_file->f, "(");
   381   while (*s)
   382     if (string_char_needs_quoting (*s))
   383       fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
   384     else
   385       fprintf (pdf_file->f, "%c", *(s++));
   386   fprintf (pdf_file->f, ") ");
   387 }
   390 void pdf_write_real (pdf_file_handle pdf_file, double num)
   391 {
   392   /* $$$ not actually good enough, precision needs to be variable,
   393      and no exponent is allowed */
   394   fprintf (pdf_file->f, "%0f ", num);
   395 }
   398 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   399 {
   400   struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
   401   fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
   402 }
   405 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
   406 {
   407   struct pdf_array_elem *elem;
   409   pdf_assert (array_obj->type == PT_ARRAY);
   411   fprintf (pdf_file->f, "[ ");
   412   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   413     {
   414       pdf_write_obj (pdf_file, elem->val);
   415       fprintf (pdf_file->f, " ");
   416     }
   417   fprintf (pdf_file->f, "] ");
   418 }
   421 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
   422 {
   423   struct pdf_dict_entry *entry;
   425   pdf_assert (dict_obj->type == PT_DICTIONARY);
   427   fprintf (pdf_file->f, "<<\r\n");
   428   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   429     {
   430       pdf_write_name (pdf_file, entry->key);
   431       fprintf (pdf_file->f, " ");
   432       pdf_write_obj (pdf_file, entry->val);
   433       fprintf (pdf_file->f, "\r\n");
   434     }
   435   fprintf (pdf_file->f, ">>\r\n");
   436 }
   439 void pdf_stream_write_data (pdf_file_handle pdf_file,
   440 			    struct pdf_obj *stream,
   441 			    char *data,
   442 			    unsigned long len)
   443 {
   444   while (len)
   445     {
   446       unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
   447       data += l2;
   448       len -= l2;
   449       if (ferror (pdf_file->f))
   450 	pdf_fatal ("error writing stream data\n");
   451     }
   452 }
   455 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
   456 {
   457   unsigned long begin_pos, end_pos;
   459   pdf_assert (stream->type == PT_STREAM);
   461   pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
   462   fprintf (pdf_file->f, "stream\r\n");
   463   begin_pos = ftell (pdf_file->f);
   464   stream->val.stream.callback (pdf_file,
   465 			       stream,
   466 			       stream->val.stream.app_data);
   467   end_pos = ftell (pdf_file->f);
   468   fprintf (pdf_file->f, "\r\nendstream\r\n");
   470   pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
   471 }
   474 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
   475 {
   476   switch (obj->type)
   477     {
   478     case PT_NULL:
   479       fprintf (pdf_file->f, "null ");
   480       break;
   481     case PT_BOOL:
   482       if (obj->val.boolean)
   483 	fprintf (pdf_file->f, "true ");
   484       else
   485 	fprintf (pdf_file->f, "false ");
   486       break;
   487     case PT_NAME:
   488       pdf_write_name (pdf_file, obj->val.name);
   489       break;
   490     case PT_STRING:
   491       pdf_write_string (pdf_file, obj->val.string);
   492       break;
   493     case PT_INTEGER:
   494       fprintf (pdf_file->f, "%ld ", obj->val.integer);
   495       break;
   496     case PT_REAL:
   497       pdf_write_real (pdf_file, obj->val.real);
   498       break;
   499     case PT_IND_REF:
   500       pdf_write_ind_ref (pdf_file, obj);
   501       break;
   502     case PT_DICTIONARY:
   503       pdf_write_dict (pdf_file, obj);
   504       break;
   505     case PT_ARRAY:
   506       pdf_write_array (pdf_file, obj);
   507       break;
   508     case PT_STREAM:
   509       pdf_write_stream (pdf_file, obj);
   510       break;
   511     default:
   512       pdf_fatal ("bad object type\n");
   513     }
   514 }
   517 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   518 {
   519   struct pdf_obj *obj;
   521   if (ind_obj->type == PT_IND_REF)
   522     obj = pdf_deref_ind_obj (ind_obj);
   523   else
   524     obj = ind_obj;
   526   obj->file_offset = ftell (pdf_file->f);
   527   fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
   528   pdf_write_obj (pdf_file, obj);
   529   fprintf (pdf_file->f, "endobj\r\n");
   530 }
   533 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
   534 {
   535   struct pdf_obj *ind_obj;
   536   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   537     if (! ind_obj->file_offset)
   538       pdf_write_ind_obj (pdf_file, ind_obj);
   539 }
   542 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
   543 {
   544   struct pdf_obj *ind_obj;
   545   pdf_file->xref_offset = ftell (pdf_file->f);
   546   fprintf (pdf_file->f, "xref\r\n");
   547   fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
   548   fprintf (pdf_file->f, "0000000000 65535 f\r\n");
   549   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   550     fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
   551   return (pdf_file->last_ind_obj->obj_num + 1);
   552 }