pdf_prim.c

Fri, 21 Feb 2003 09:25:47 +0000

author
eric
date
Fri, 21 Feb 2003 09:25:47 +0000
changeset 66
6e0551b59dba
parent 62
9bd354b83e16
child 67
7add7411c1c2
permissions
-rw-r--r--

implemented ImageMask fill color arguments to pdf_write_g4_fax_image().

     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.4 2003/02/21 01:25:47 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     unsigned 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 (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 (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 struct pdf_obj *pdf_new_obj (pdf_obj_type type)
   196 {
   197   struct pdf_obj *obj = pdf_calloc (sizeof (struct pdf_obj));
   198   obj->type = type;
   199   return (obj);
   200 }
   203 struct pdf_obj *pdf_new_bool (bool val)
   204 {
   205   struct pdf_obj *obj = pdf_new_obj (PT_BOOL);
   206   obj->val.boolean = val;
   207   return (obj);
   208 }
   211 struct pdf_obj *pdf_new_name (char *name)
   212 {
   213   struct pdf_obj *obj = pdf_new_obj (PT_NAME);
   214   obj->val.name = pdf_strdup (name);
   215   return (obj);
   216 }
   219 struct pdf_obj *pdf_new_string (char *str)
   220 {
   221   struct pdf_obj *obj = pdf_new_obj (PT_STRING);
   222   obj->val.string = pdf_strdup (str);
   223   return (obj);
   224 }
   227 struct pdf_obj *pdf_new_integer (unsigned long val)
   228 {
   229   struct pdf_obj *obj = pdf_new_obj (PT_INTEGER);
   230   obj->val.integer = val;
   231   return (obj);
   232 }
   235 struct pdf_obj *pdf_new_real (double val)
   236 {
   237   struct pdf_obj *obj = pdf_new_obj (PT_REAL);
   238   obj->val.real = val;
   239   return (obj);
   240 }
   243 struct pdf_obj *pdf_new_stream (pdf_file_handle pdf_file,
   244 				struct pdf_obj *stream_dict,
   245 				pdf_stream_write_callback callback,
   246 				void *app_data)
   247 {
   248   struct pdf_obj *obj = pdf_new_obj (PT_STREAM);
   250   obj->val.stream.stream_dict = stream_dict;
   251   obj->val.stream.length = pdf_new_ind_ref (pdf_file, pdf_new_integer (0));
   252   pdf_set_dict_entry (obj->val.stream.stream_dict, "Length", obj->val.stream.length);
   254   obj->val.stream.callback = callback;
   255   obj->val.stream.app_data = app_data;
   256   return (obj);
   257 }
   260 /* $$$ currently limited to one filter per stream */
   261 void pdf_stream_add_filter (struct pdf_obj *stream,
   262 			    char *filter_name,
   263 			    struct pdf_obj *decode_parms)
   264 {
   265   if (stream->type == PT_IND_REF)
   266     stream = pdf_deref_ind_obj (stream);
   268   pdf_assert (stream->type == PT_STREAM);
   270   pdf_set_dict_entry (stream->val.stream.stream_dict, "Filter", pdf_new_name (filter_name));
   271   if (decode_parms)
   272     pdf_set_dict_entry (stream->val.stream.stream_dict, "DecodeParms", decode_parms);
   273 }
   276 struct pdf_obj *pdf_new_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *obj)
   277 {
   278   struct pdf_obj *ind_obj;
   280   pdf_assert (obj->type != PT_IND_REF);
   282   ind_obj = pdf_new_obj (PT_IND_REF);
   284   ind_obj->type = PT_IND_REF;
   285   ind_obj->val.ind_ref = obj;
   287   /* is there already an indirect reference to this object? */
   288   if (! obj->obj_num)
   289     {
   290       /* no, assign object number/generation and add to linked list */
   291       if (! pdf_file->first_ind_obj)
   292 	{
   293 	  obj->obj_num = 1;
   294 	  pdf_file->first_ind_obj = pdf_file->last_ind_obj = obj;
   295 	}
   296       else
   297 	{
   298 	  obj->obj_num = pdf_file->last_ind_obj->obj_num + 1;
   299 	  pdf_file->last_ind_obj->next = obj;
   300 	  obj->prev = pdf_file->last_ind_obj;
   301 	  pdf_file->last_ind_obj = obj;
   302 	}
   303     }
   305   return (ind_obj);
   306 }
   309 unsigned long pdf_get_integer (struct pdf_obj *obj)
   310 {
   311   if (obj->type == PT_IND_REF)
   312     obj = pdf_deref_ind_obj (obj);
   314   pdf_assert (obj->type == PT_INTEGER);
   316   return (obj->val.integer);
   317 }
   319 void pdf_set_integer (struct pdf_obj *obj, unsigned long val)
   320 {
   321   if (obj->type == PT_IND_REF)
   322     obj = pdf_deref_ind_obj (obj);
   324   pdf_assert (obj->type == PT_INTEGER);
   326   obj->val.integer = val;
   327 }
   330 double pdf_get_real (struct pdf_obj *obj)
   331 {
   332   if (obj->type == PT_IND_REF)
   333     obj = pdf_deref_ind_obj (obj);
   335   pdf_assert (obj->type == PT_REAL);
   337   return (obj->val.real);
   338 }
   340 void pdf_set_real (struct pdf_obj *obj, double val)
   341 {
   342   if (obj->type == PT_IND_REF)
   343     obj = pdf_deref_ind_obj (obj);
   345   pdf_assert (obj->type == PT_REAL);
   347   obj->val.real = val;
   348 }
   351 static int name_char_needs_quoting (char c)
   352 {
   353   return ((c < '!')  || (c > '~')  || (c == '/') || (c == '\\') ||
   354 	  (c == '(') || (c == ')') || (c == '<') || (c == '>')  ||
   355 	  (c == '[') || (c == ']') || (c == '{') || (c == '}')  ||
   356 	  (c == '%'));
   357 }
   360 void pdf_write_name (pdf_file_handle pdf_file, char *s)
   361 {
   362   fprintf (pdf_file->f, "/");
   363   while (*s)
   364     if (name_char_needs_quoting (*s))
   365       fprintf (pdf_file->f, "#%02x", 0xff & *(s++));
   366     else
   367       fprintf (pdf_file->f, "%c", *(s++));
   368   fprintf (pdf_file->f, " ");
   369 }
   372 static int string_char_needs_quoting (char c)
   373 {
   374   return ((c < ' ')  || (c > '~')  || (c == '\\') ||
   375 	  (c == '(') || (c == ')'));
   376 }
   379 void pdf_write_string (pdf_file_handle pdf_file, char *s)
   380 {
   381   fprintf (pdf_file->f, "(");
   382   while (*s)
   383     if (string_char_needs_quoting (*s))
   384       fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
   385     else
   386       fprintf (pdf_file->f, "%c", *(s++));
   387   fprintf (pdf_file->f, ") ");
   388 }
   391 void pdf_write_real (pdf_file_handle pdf_file, double num)
   392 {
   393   /* $$$ not actually good enough, precision needs to be variable,
   394      and no exponent is allowed */
   395   fprintf (pdf_file->f, "%0f ", num);
   396 }
   399 void pdf_write_ind_ref (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   400 {
   401   struct pdf_obj *obj = pdf_deref_ind_obj (ind_obj);
   402   fprintf (pdf_file->f, "%ld %ld R ", obj->obj_num, obj->obj_gen);
   403 }
   406 void pdf_write_array (pdf_file_handle pdf_file, struct pdf_obj *array_obj)
   407 {
   408   struct pdf_array_elem *elem;
   410   pdf_assert (array_obj->type == PT_ARRAY);
   412   fprintf (pdf_file->f, "[ ");
   413   for (elem = array_obj->val.array.first; elem; elem = elem->next)
   414     {
   415       pdf_write_obj (pdf_file, elem->val);
   416       fprintf (pdf_file->f, " ");
   417     }
   418   fprintf (pdf_file->f, "] ");
   419 }
   422 void pdf_write_dict (pdf_file_handle pdf_file, struct pdf_obj *dict_obj)
   423 {
   424   struct pdf_dict_entry *entry;
   426   pdf_assert (dict_obj->type == PT_DICTIONARY);
   428   fprintf (pdf_file->f, "<<\r\n");
   429   for (entry = dict_obj->val.dict.first; entry; entry = entry->next)
   430     {
   431       pdf_write_name (pdf_file, entry->key);
   432       fprintf (pdf_file->f, " ");
   433       pdf_write_obj (pdf_file, entry->val);
   434       fprintf (pdf_file->f, "\r\n");
   435     }
   436   fprintf (pdf_file->f, ">>\r\n");
   437 }
   440 void pdf_stream_write_data (pdf_file_handle pdf_file,
   441 			    struct pdf_obj *stream,
   442 			    char *data,
   443 			    unsigned long len)
   444 {
   445   while (len)
   446     {
   447       unsigned long l2 = fwrite (data, 1, len, pdf_file->f);
   448       data += l2;
   449       len -= l2;
   450       if (ferror (pdf_file->f))
   451 	pdf_fatal ("error writing stream data\n");
   452     }
   453 }
   456 void pdf_stream_printf (pdf_file_handle pdf_file,
   457 			struct pdf_obj *stream,
   458 			char *fmt, ...)
   459 {
   460   va_list ap;
   462   va_start (ap, fmt);
   463   vfprintf (pdf_file->f, fmt, ap);
   464   va_end (ap);
   465 }
   468 void pdf_write_stream (pdf_file_handle pdf_file, struct pdf_obj *stream)
   469 {
   470   unsigned long begin_pos, end_pos;
   472   pdf_assert (stream->type == PT_STREAM);
   474   pdf_write_dict (pdf_file, stream->val.stream.stream_dict);
   475   fprintf (pdf_file->f, "stream\r\n");
   476   begin_pos = ftell (pdf_file->f);
   477   stream->val.stream.callback (pdf_file,
   478 			       stream,
   479 			       stream->val.stream.app_data);
   480   end_pos = ftell (pdf_file->f);
   481   fprintf (pdf_file->f, "\r\nendstream\r\n");
   483   pdf_set_integer (stream->val.stream.length, end_pos - begin_pos);
   484 }
   487 void pdf_write_obj (pdf_file_handle pdf_file, struct pdf_obj *obj)
   488 {
   489   switch (obj->type)
   490     {
   491     case PT_NULL:
   492       fprintf (pdf_file->f, "null ");
   493       break;
   494     case PT_BOOL:
   495       if (obj->val.boolean)
   496 	fprintf (pdf_file->f, "true ");
   497       else
   498 	fprintf (pdf_file->f, "false ");
   499       break;
   500     case PT_NAME:
   501       pdf_write_name (pdf_file, obj->val.name);
   502       break;
   503     case PT_STRING:
   504       pdf_write_string (pdf_file, obj->val.string);
   505       break;
   506     case PT_INTEGER:
   507       fprintf (pdf_file->f, "%ld ", obj->val.integer);
   508       break;
   509     case PT_REAL:
   510       pdf_write_real (pdf_file, obj->val.real);
   511       break;
   512     case PT_IND_REF:
   513       pdf_write_ind_ref (pdf_file, obj);
   514       break;
   515     case PT_DICTIONARY:
   516       pdf_write_dict (pdf_file, obj);
   517       break;
   518     case PT_ARRAY:
   519       pdf_write_array (pdf_file, obj);
   520       break;
   521     case PT_STREAM:
   522       pdf_write_stream (pdf_file, obj);
   523       break;
   524     default:
   525       pdf_fatal ("bad object type\n");
   526     }
   527 }
   530 void pdf_write_ind_obj (pdf_file_handle pdf_file, struct pdf_obj *ind_obj)
   531 {
   532   struct pdf_obj *obj;
   534   if (ind_obj->type == PT_IND_REF)
   535     obj = pdf_deref_ind_obj (ind_obj);
   536   else
   537     obj = ind_obj;
   539   obj->file_offset = ftell (pdf_file->f);
   540   fprintf (pdf_file->f, "%ld %ld obj\r\n", obj->obj_num, obj->obj_gen);
   541   pdf_write_obj (pdf_file, obj);
   542   fprintf (pdf_file->f, "endobj\r\n");
   543 }
   546 void pdf_write_all_ind_obj (pdf_file_handle pdf_file)
   547 {
   548   struct pdf_obj *ind_obj;
   549   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   550     if (! ind_obj->file_offset)
   551       pdf_write_ind_obj (pdf_file, ind_obj);
   552 }
   555 unsigned long pdf_write_xref (pdf_file_handle pdf_file)
   556 {
   557   struct pdf_obj *ind_obj;
   558   pdf_file->xref_offset = ftell (pdf_file->f);
   559   fprintf (pdf_file->f, "xref\r\n");
   560   fprintf (pdf_file->f, "0 %ld\r\n", pdf_file->last_ind_obj->obj_num + 1);
   561   fprintf (pdf_file->f, "0000000000 65535 f\r\n");
   562   for (ind_obj = pdf_file->first_ind_obj; ind_obj; ind_obj = ind_obj->next)
   563     fprintf (pdf_file->f, "%010ld 00000 n\r\n", ind_obj->file_offset);
   564   return (pdf_file->last_ind_obj->obj_num + 1);
   565 }