Patched to add PNG and JP2 support.

Mon, 14 Dec 2009 15:51:53 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 15:51:53 +0000
changeset 166
301f6f17c364
parent 165
9a505be7e7fd
child 167
88aafe900928

Patched to add PNG and JP2 support.

Created-By: Daniel Gl?ckner <daniel-gl at gmx.net>


The attached patch adds PNG and JP2 support to tumble.

PNG:
As the deflated data is directly copied into the PDF, there are some
limitations to the list of supported images:
- bit depth <= 8
- no alpha channel
- no interlace

JP2:
The PDF Reference says JP2 is just a subset of the allowed JPX
format. I don't have a copy of the official standard, so I don't know
what to change to cover JPXes as well.
You'll need the Adobe Acrobat Reader 6 to display those images.
Xpdf and Ghostscript are missing the ColorSpace key in the image
dictionary, which is optional for JPXDecode and IMHO not just a matter
of a few lines of code.
One thing left to do is to change the PDF version to 1.5 if a JP2 file
has been given to tumble - maybe using the Version key in the Catalog
if seeking is not possible.
Using the resolution info in a JP2 (resc/resd boxes) is implemented but
untested. Jasper doesn't write those boxes.

I had to change the string handling to allow black in PNG palettes.
And there was a double free in tumble_input.c which happens when not
using control files.

Daniel

Makefile file | annotate | diff | revisions
pdf.h file | annotate | diff | revisions
pdf_jp2.c file | annotate | diff | revisions
pdf_png.c file | annotate | diff | revisions
pdf_prim.c file | annotate | diff | revisions
pdf_prim.h file | annotate | diff | revisions
tumble.c file | annotate | diff | revisions
tumble_input.c file | annotate | diff | revisions
tumble_input.h file | annotate | diff | revisions
tumble_jp2.c file | annotate | diff | revisions
tumble_png.c file | annotate | diff | revisions
     1.1 --- a/Makefile	Mon Dec 14 15:44:55 2009 +0000
     1.2 +++ b/Makefile	Mon Dec 14 15:51:53 2009 +0000
     1.3 @@ -65,11 +65,12 @@
     1.4  TARGETS = tumble
     1.5  
     1.6  CSRCS = tumble.c semantics.c \
     1.7 -	tumble_input.c tumble_tiff.c tumble_jpeg.c tumble_pbm.c \
     1.8 +	tumble_input.c tumble_tiff.c tumble_jpeg.c \
     1.9 +	tumble_pbm.c tumble_png.c tumble_jp2.c \
    1.10  	bitblt.c bitblt_table_gen.c bitblt_g4.c g4_table_gen.c \
    1.11  	pdf.c pdf_util.c pdf_prim.c pdf_name_tree.c \
    1.12  	pdf_bookmark.c pdf_page_label.c \
    1.13 -	pdf_text.c pdf_g4.c pdf_jpeg.c
    1.14 +	pdf_text.c pdf_g4.c pdf_jpeg.c pdf_png.c pdf_jp2.c
    1.15  OSRCS = scanner.l parser.y
    1.16  HDRS = tumble.h tumble_input.h semantics.h bitblt.h bitblt_tables.h \
    1.17  	pdf.h pdf_private.h pdf_util.h pdf_prim.h pdf_name_tree.h
    1.18 @@ -107,11 +108,12 @@
    1.19  
    1.20  
    1.21  TUMBLE_OBJS = tumble.o semantics.o \
    1.22 -		tumble_input.o tumble_tiff.o tumble_jpeg.o tumble_pbm.o \
    1.23 +		tumble_input.o tumble_tiff.o tumble_jpeg.o \
    1.24 +		tumble_pbm.o tumble_png.o tumble_jp2.o \
    1.25  		bitblt.o bitblt_g4.o bitblt_tables.o g4_tables.o \
    1.26  		pdf.o pdf_util.o pdf_prim.o pdf_name_tree.o \
    1.27  		pdf_bookmark.o pdf_page_label.o \
    1.28 -		pdf_text.o pdf_g4.o pdf_jpeg.o
    1.29 +		pdf_text.o pdf_g4.o pdf_jpeg.o pdf_png.o pdf_jp2.o
    1.30  
    1.31  ifdef CTL_LANG
    1.32  TUMBLE_OBJS += scanner.o parser.tab.o
     2.1 --- a/pdf.h	Mon Dec 14 15:44:55 2009 +0000
     2.2 +++ b/pdf.h	Mon Dec 14 15:51:53 2009 +0000
     2.3 @@ -92,6 +92,27 @@
     2.4  			   uint32_t height_samples,
     2.5  			   FILE *f);
     2.6  
     2.7 +void pdf_write_png_image (pdf_page_handle pdf_page,
     2.8 +			   double x,
     2.9 +			   double y,
    2.10 +			   double width,
    2.11 +			   double height,
    2.12 +			   int color,
    2.13 +			   char *pal,
    2.14 +			   int palent,
    2.15 +			   int bpp,
    2.16 +			   uint32_t width_samples,
    2.17 +			   uint32_t height_samples,
    2.18 +			   FILE *f);
    2.19 +
    2.20 +void pdf_write_jp2_image (pdf_page_handle pdf_page,
    2.21 +			   double x,
    2.22 +			   double y,
    2.23 +			   double width,
    2.24 +			   double height,
    2.25 +			   uint32_t width_samples,
    2.26 +			   uint32_t height_samples,
    2.27 +			   FILE *f);
    2.28  
    2.29  void pdf_set_page_number (pdf_page_handle pdf_page, char *page_number);
    2.30  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/pdf_jp2.c	Mon Dec 14 15:51:53 2009 +0000
     3.3 @@ -0,0 +1,161 @@
     3.4 +/*
     3.5 + * tumble: build a PDF file from image files
     3.6 + *
     3.7 + * PDF routines
     3.8 + * Copyright 2004 Daniel Gloeckner
     3.9 + *
    3.10 + * Derived from pdf_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
    3.11 + *
    3.12 + * This program is free software; you can redistribute it and/or modify
    3.13 + * it under the terms of the GNU General Public License version 2 as
    3.14 + * published by the Free Software Foundation.  Note that permission is
    3.15 + * not granted to redistribute this program under the terms of any
    3.16 + * other version of the General Public License.
    3.17 + *
    3.18 + * This program is distributed in the hope that it will be useful,
    3.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.21 + * GNU General Public License for more details.
    3.22 + *
    3.23 + * You should have received a copy of the GNU General Public License
    3.24 + * along with this program; if not, write to the Free Software
    3.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    3.26 + */
    3.27 +
    3.28 +
    3.29 +#include <stdbool.h>
    3.30 +#include <stdint.h>
    3.31 +#include <stdio.h>
    3.32 +#include <stdlib.h>
    3.33 +#include <string.h>
    3.34 +
    3.35 +
    3.36 +#include "bitblt.h"
    3.37 +#include "pdf.h"
    3.38 +#include "pdf_util.h"
    3.39 +#include "pdf_prim.h"
    3.40 +#include "pdf_private.h"
    3.41 +
    3.42 +
    3.43 +struct pdf_jp2_image
    3.44 +{
    3.45 +  double width, height;
    3.46 +  double x, y;
    3.47 +  uint32_t width_samples, height_samples;
    3.48 +  FILE *f;
    3.49 +  char XObject_name [4];
    3.50 +};
    3.51 +
    3.52 +
    3.53 +static void pdf_write_jp2_content_callback (pdf_file_handle pdf_file,
    3.54 +					     struct pdf_obj *stream,
    3.55 +					     void *app_data)
    3.56 +{
    3.57 +  struct pdf_jp2_image *image = app_data;
    3.58 +
    3.59 +  /* transformation matrix is: width 0 0 height x y cm */
    3.60 +  pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
    3.61 +		     image->width, image->height,
    3.62 +		     image->x, image->y);
    3.63 +  pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
    3.64 +		     image->XObject_name);
    3.65 +}
    3.66 +
    3.67 +
    3.68 +#define JPEG_BUFFER_SIZE 8192
    3.69 +
    3.70 +static void pdf_write_jp2_image_callback (pdf_file_handle pdf_file,
    3.71 +					   struct pdf_obj *stream,
    3.72 +					   void *app_data)
    3.73 +{
    3.74 +  struct pdf_jp2_image *image = app_data;
    3.75 +  int rlen, wlen;
    3.76 +  uint8_t *wp;
    3.77 +  uint8_t buffer [8192];
    3.78 +
    3.79 +  while (! feof (image->f))
    3.80 +    {
    3.81 +      rlen = fread (& buffer [0], 1, JPEG_BUFFER_SIZE, image->f);
    3.82 +      wp = & buffer [0];
    3.83 +      while (rlen)
    3.84 +	{
    3.85 +	  wlen = fwrite (wp, 1, rlen, pdf_file->f);
    3.86 +	  if (feof (pdf_file->f))
    3.87 +	    pdf_fatal ("unexpected EOF on output file\n");
    3.88 +	  if (ferror (pdf_file->f))
    3.89 +	    pdf_fatal ("error on output file\n");
    3.90 +	  rlen -= wlen;
    3.91 +	  wp += wlen;
    3.92 +	}
    3.93 +      if (ferror (image->f))
    3.94 +	pdf_fatal ("error on input file\n");
    3.95 +    }
    3.96 +}
    3.97 +
    3.98 +
    3.99 +void pdf_write_jp2_image (pdf_page_handle pdf_page,
   3.100 +			   double x,
   3.101 +			   double y,
   3.102 +			   double width,
   3.103 +			   double height,
   3.104 +			   uint32_t width_samples,
   3.105 +			   uint32_t height_samples,
   3.106 +			   FILE *f)
   3.107 +{
   3.108 +  struct pdf_jp2_image *image;
   3.109 +
   3.110 +  struct pdf_obj *stream;
   3.111 +  struct pdf_obj *stream_dict;
   3.112 +
   3.113 +  struct pdf_obj *content_stream;
   3.114 +
   3.115 +  image = pdf_calloc (1, sizeof (struct pdf_jp2_image));
   3.116 +
   3.117 +  image->width = width;
   3.118 +  image->height = height;
   3.119 +  image->x = x;
   3.120 +  image->y = y;
   3.121 +
   3.122 +  image->f = f;
   3.123 +
   3.124 +  image->width_samples = width_samples;
   3.125 +  image->height_samples = height_samples;
   3.126 +
   3.127 +  stream_dict = pdf_new_obj (PT_DICTIONARY);
   3.128 +
   3.129 +  stream = pdf_new_ind_ref (pdf_page->pdf_file,
   3.130 +			    pdf_new_stream (pdf_page->pdf_file,
   3.131 +					    stream_dict,
   3.132 +					    & pdf_write_jp2_image_callback,
   3.133 +					    image));
   3.134 +
   3.135 +  strcpy (& image->XObject_name [0], "Im ");
   3.136 +  image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
   3.137 +
   3.138 +  pdf_set_dict_entry (stream_dict, "Type",    pdf_new_name ("XObject"));
   3.139 +  pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
   3.140 +// Name is required in PDF 1.0 but obsoleted in later PDF versions
   3.141 +//  pdf_set_dict_entry (stream_dict, "Name",    pdf_new_name (& image->XObject_name [0]));
   3.142 +  pdf_set_dict_entry (stream_dict, "Width",   pdf_new_integer (image->width_samples));
   3.143 +  pdf_set_dict_entry (stream_dict, "Height",  pdf_new_integer (image->height_samples));
   3.144 +
   3.145 +  // not required for JPXDecode, but 
   3.146 +  pdf_set_dict_entry (stream_dict, "BitsPerComponent",  pdf_new_integer (8));
   3.147 +
   3.148 +  pdf_stream_add_filter (stream, "JPXDecode", NULL);
   3.149 +
   3.150 +  /* the following will write the stream, using our callback function to
   3.151 +     get the actual data */
   3.152 +  pdf_write_ind_obj (pdf_page->pdf_file, stream);
   3.153 +
   3.154 +  content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
   3.155 +				    pdf_new_stream (pdf_page->pdf_file,
   3.156 +						    pdf_new_obj (PT_DICTIONARY),
   3.157 +						    & pdf_write_jp2_content_callback,
   3.158 +						    image));
   3.159 +
   3.160 +  pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
   3.161 +
   3.162 +  pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
   3.163 +
   3.164 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pdf_png.c	Mon Dec 14 15:51:53 2009 +0000
     4.3 @@ -0,0 +1,200 @@
     4.4 +/*
     4.5 + * tumble: build a PDF file from image files
     4.6 + *
     4.7 + * PDF routines
     4.8 + * Copyright 2004 Daniel Gloeckner
     4.9 + *
    4.10 + * Derived from pdf_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
    4.11 + *
    4.12 + * This program is free software; you can redistribute it and/or modify
    4.13 + * it under the terms of the GNU General Public License version 2 as
    4.14 + * published by the Free Software Foundation.  Note that permission is
    4.15 + * not granted to redistribute this program under the terms of any
    4.16 + * other version of the General Public License.
    4.17 + *
    4.18 + * This program is distributed in the hope that it will be useful,
    4.19 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.20 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.21 + * GNU General Public License for more details.
    4.22 + *
    4.23 + * You should have received a copy of the GNU General Public License
    4.24 + * along with this program; if not, write to the Free Software
    4.25 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    4.26 + */
    4.27 +
    4.28 +
    4.29 +#include <stdbool.h>
    4.30 +#include <stdint.h>
    4.31 +#include <stdio.h>
    4.32 +#include <stdlib.h>
    4.33 +#include <string.h>
    4.34 +
    4.35 +
    4.36 +#include "bitblt.h"
    4.37 +#include "pdf.h"
    4.38 +#include "pdf_util.h"
    4.39 +#include "pdf_prim.h"
    4.40 +#include "pdf_private.h"
    4.41 +
    4.42 +
    4.43 +struct pdf_png_image
    4.44 +{
    4.45 +  double width, height;
    4.46 +  double x, y;
    4.47 +  bool color;  /* false for grayscale */
    4.48 +  uint32_t width_samples, height_samples;
    4.49 +  FILE *f;
    4.50 +  char XObject_name [4];
    4.51 +};
    4.52 +
    4.53 +
    4.54 +static void pdf_write_png_content_callback (pdf_file_handle pdf_file,
    4.55 +					     struct pdf_obj *stream,
    4.56 +					     void *app_data)
    4.57 +{
    4.58 +  struct pdf_png_image *image = app_data;
    4.59 +
    4.60 +  /* transformation matrix is: width 0 0 height x y cm */
    4.61 +  pdf_stream_printf (pdf_file, stream, "q %g 0 0 %g %g %g cm ",
    4.62 +		     image->width, image->height,
    4.63 +		     image->x, image->y);
    4.64 +  pdf_stream_printf (pdf_file, stream, "/%s Do Q\r\n",
    4.65 +		     image->XObject_name);
    4.66 +}
    4.67 +
    4.68 +
    4.69 +static void pdf_write_png_image_callback (pdf_file_handle pdf_file,
    4.70 +					   struct pdf_obj *stream,
    4.71 +					   void *app_data)
    4.72 +{
    4.73 +  struct pdf_png_image *image = app_data;
    4.74 +  int rlen, wlen;
    4.75 +  uint8_t *wp;
    4.76 +  uint8_t buffer [8192];
    4.77 +
    4.78 +  while (! feof (image->f))
    4.79 +    {
    4.80 +      uint32_t clen;
    4.81 +      rlen = fread (buffer, 1, 8, image->f);
    4.82 +      if (rlen != 8)
    4.83 +	pdf_fatal ("unexpected EOF on input file\n");
    4.84 +      clen=(buffer[0]<<24)+(buffer[1]<<16)+(buffer[2]<<8)+buffer[3];
    4.85 +      if (!memcmp(buffer+4,"IEND",4))
    4.86 +	break;
    4.87 +      if (memcmp(buffer+4,"IDAT",4)) {
    4.88 +	fseek(image->f, clen+4, SEEK_CUR);
    4.89 +	continue;
    4.90 +      }
    4.91 +      while (clen)
    4.92 +      {
    4.93 +	rlen = fread (buffer, 1, (clen<sizeof(buffer))?clen:sizeof(buffer), image->f);
    4.94 +	if(!rlen)
    4.95 +	  pdf_fatal ("unexpected EOF on input file\n");
    4.96 +	clen -= rlen;
    4.97 +        wp = buffer;
    4.98 +        while (rlen)
    4.99 +	{
   4.100 +	  wlen = fwrite (wp, 1, rlen, pdf_file->f);
   4.101 +	  if (feof (pdf_file->f))
   4.102 +	    pdf_fatal ("unexpected EOF on output file\n");
   4.103 +	  if (ferror (pdf_file->f))
   4.104 +	    pdf_fatal ("error on output file\n");
   4.105 +	  rlen -= wlen;
   4.106 +	  wp += wlen;
   4.107 +	}
   4.108 +        if (ferror (image->f))
   4.109 +	  pdf_fatal ("error on input file\n");
   4.110 +      }
   4.111 +      fseek(image->f, 4, SEEK_CUR);
   4.112 +    }
   4.113 +}
   4.114 +
   4.115 +
   4.116 +void pdf_write_png_image (pdf_page_handle pdf_page,
   4.117 +			   double x,
   4.118 +			   double y,
   4.119 +			   double width,
   4.120 +			   double height,
   4.121 +			   int color,
   4.122 +			   char *indexed,
   4.123 +			   int palent,
   4.124 +			   int bpp,
   4.125 +			   uint32_t width_samples,
   4.126 +			   uint32_t height_samples,
   4.127 +			   FILE *f)
   4.128 +{
   4.129 +  struct pdf_png_image *image;
   4.130 +
   4.131 +  struct pdf_obj *stream;
   4.132 +  struct pdf_obj *stream_dict;
   4.133 +  struct pdf_obj *flateparams;
   4.134 +
   4.135 +  struct pdf_obj *content_stream;
   4.136 +
   4.137 +  image = pdf_calloc (1, sizeof (struct pdf_png_image));
   4.138 +
   4.139 +  image->width = width;
   4.140 +  image->height = height;
   4.141 +  image->x = x;
   4.142 +  image->y = y;
   4.143 +
   4.144 +  image->f = f;
   4.145 +
   4.146 +  image->color = color;
   4.147 +  image->width_samples = width_samples;
   4.148 +  image->height_samples = height_samples;
   4.149 +
   4.150 +  pdf_add_array_elem_unique (pdf_page->procset,
   4.151 +			     pdf_new_name (palent ? "ImageI" : image->color ? "ImageC" : "ImageB"));
   4.152 +
   4.153 +  stream_dict = pdf_new_obj (PT_DICTIONARY);
   4.154 +
   4.155 +  stream = pdf_new_ind_ref (pdf_page->pdf_file,
   4.156 +			    pdf_new_stream (pdf_page->pdf_file,
   4.157 +					    stream_dict,
   4.158 +					    & pdf_write_png_image_callback,
   4.159 +					    image));
   4.160 +
   4.161 +  strcpy (& image->XObject_name [0], "Im ");
   4.162 +  image->XObject_name [2] = pdf_new_XObject (pdf_page, stream);
   4.163 +
   4.164 +  flateparams = pdf_new_obj (PT_DICTIONARY);
   4.165 +  
   4.166 +  pdf_set_dict_entry (stream_dict, "Type",    pdf_new_name ("XObject"));
   4.167 +  pdf_set_dict_entry (stream_dict, "Subtype", pdf_new_name ("Image"));
   4.168 +// Name is required in PDF 1.0 but obsoleted in later PDF versions
   4.169 +//  pdf_set_dict_entry (stream_dict, "Name",    pdf_new_name (& image->XObject_name [0]));
   4.170 +  pdf_set_dict_entry (stream_dict, "Width",   pdf_new_integer (image->width_samples));
   4.171 +  pdf_set_dict_entry (flateparams, "Columns",   pdf_new_integer (image->width_samples));
   4.172 +  pdf_set_dict_entry (stream_dict, "Height",  pdf_new_integer (image->height_samples));
   4.173 +  if(palent) {
   4.174 +    struct pdf_obj *space;
   4.175 +    space = pdf_new_obj (PT_ARRAY);
   4.176 +    pdf_add_array_elem (space, pdf_new_name ("Indexed"));
   4.177 +    pdf_add_array_elem (space, pdf_new_name ("DeviceRGB"));
   4.178 +    pdf_add_array_elem (space, pdf_new_integer (palent-1));
   4.179 +    pdf_add_array_elem (space, pdf_new_string_n (indexed,3*palent));
   4.180 +    pdf_set_dict_entry (stream_dict, "ColorSpace", space);
   4.181 +  } else
   4.182 +    pdf_set_dict_entry (stream_dict, "ColorSpace", pdf_new_name (image->color ? "DeviceRGB" : "DeviceGray"));
   4.183 +  pdf_set_dict_entry (flateparams, "Colors", pdf_new_integer ((!indexed && image->color) ? 3 : 1));
   4.184 +  pdf_set_dict_entry (stream_dict, "BitsPerComponent", pdf_new_integer (bpp));
   4.185 +  pdf_set_dict_entry (flateparams, "BitsPerComponent", pdf_new_integer (bpp));
   4.186 +  pdf_set_dict_entry (flateparams, "Predictor", pdf_new_integer (15));
   4.187 +
   4.188 +  pdf_stream_add_filter (stream, "FlateDecode", flateparams);
   4.189 +
   4.190 +  /* the following will write the stream, using our callback function to
   4.191 +     get the actual data */
   4.192 +  pdf_write_ind_obj (pdf_page->pdf_file, stream);
   4.193 +
   4.194 +  content_stream = pdf_new_ind_ref (pdf_page->pdf_file,
   4.195 +				    pdf_new_stream (pdf_page->pdf_file,
   4.196 +						    pdf_new_obj (PT_DICTIONARY),
   4.197 +						    & pdf_write_png_content_callback,
   4.198 +						    image));
   4.199 +
   4.200 +  pdf_set_dict_entry (pdf_page->page_dict, "Contents", content_stream);
   4.201 +
   4.202 +  pdf_write_ind_obj (pdf_page->pdf_file, content_stream);
   4.203 +}
     5.1 --- a/pdf_prim.c	Mon Dec 14 15:44:55 2009 +0000
     5.2 +++ b/pdf_prim.c	Mon Dec 14 15:51:53 2009 +0000
     5.3 @@ -90,7 +90,10 @@
     5.4    union {
     5.5      bool              boolean;
     5.6      char              *name;
     5.7 -    char              *string;
     5.8 +    struct {
     5.9 +      char            *content;
    5.10 +      int             length;
    5.11 +    }                 string;
    5.12      long              integer;
    5.13      double            real;
    5.14      struct pdf_obj    *ind_ref;
    5.15 @@ -243,7 +246,18 @@
    5.16  struct pdf_obj *pdf_new_string (char *str)
    5.17  {
    5.18    struct pdf_obj *obj = pdf_new_obj (PT_STRING);
    5.19 -  obj->val.string = pdf_strdup (str);
    5.20 +  obj->val.string.content = pdf_strdup (str);
    5.21 +  obj->val.string.length = strlen(str);
    5.22 +  return (obj);
    5.23 +}
    5.24 +
    5.25 +
    5.26 +struct pdf_obj *pdf_new_string_n (char *str, int n)
    5.27 +{
    5.28 +  struct pdf_obj *obj = pdf_new_obj (PT_STRING);
    5.29 +  obj->val.string.length = n;
    5.30 +  obj->val.string.content = pdf_calloc (1,n);
    5.31 +  memcpy(obj->val.string.content, str, n);
    5.32    return (obj);
    5.33  }
    5.34  
    5.35 @@ -397,7 +411,16 @@
    5.36  	return (1);
    5.37        return (0);
    5.38      case PT_STRING:
    5.39 -      return (strcmp (o1->val.string, o2->val.string));
    5.40 +      {
    5.41 +	int l;
    5.42 +	l = o1->val.string.length;
    5.43 +	if(l > o2->val.string.length)
    5.44 +	  l = o2->val.string.length;
    5.45 +	l = memcmp (o1->val.string.content, o2->val.string.content, l);
    5.46 +        if (l)
    5.47 +	  return l;
    5.48 +	return o1->val.string.length - o2->val.string.length;
    5.49 +      }
    5.50      case PT_NAME:
    5.51        return (strcmp (o1->val.name, o2->val.name));
    5.52      default:
    5.53 @@ -427,22 +450,51 @@
    5.54  }
    5.55  
    5.56  
    5.57 -static int string_char_needs_quoting (char c)
    5.58 +static int pdf_write_literal_string (pdf_file_handle pdf_file, char *s, int n)
    5.59  {
    5.60 -  return ((c < ' ')  || (c > '~')  || (c == '\\') ||
    5.61 -	  (c == '(') || (c == ')'));
    5.62 +  int i,p;
    5.63 +  if(pdf_file) fprintf (pdf_file->f, "(");
    5.64 +  for (i=p=0;n;n--) {
    5.65 +    int j,k;
    5.66 +    k=0;
    5.67 +    switch(*s){
    5.68 +      case '\\':
    5.69 +	k=1;
    5.70 +	break;
    5.71 +      case '(':
    5.72 +	for(j=k=1;k && j<n;j++)
    5.73 +	  k+=(s[j]=='(')?1:(s[j]==')')?-1:0;
    5.74 +	p+=!k;
    5.75 +	break;
    5.76 +      case ')':
    5.77 +	if(p)
    5.78 +	  p--;
    5.79 +	else
    5.80 +	  k=1;
    5.81 +	break;
    5.82 +    }
    5.83 +    if(k) {
    5.84 +      i++;
    5.85 +      if(pdf_file) fprintf (pdf_file->f, "\\");
    5.86 +    }
    5.87 +    i++;
    5.88 +    if(pdf_file) fprintf (pdf_file->f, "%c", *(s++));
    5.89 +  }
    5.90 +  if(pdf_file) fprintf (pdf_file->f, ") ");
    5.91 +  return i;
    5.92  }
    5.93  
    5.94  
    5.95 -void pdf_write_string (pdf_file_handle pdf_file, char *s)
    5.96 +void pdf_write_string (pdf_file_handle pdf_file, char *s, int n)
    5.97  {
    5.98 -  fprintf (pdf_file->f, "(");
    5.99 -  while (*s)
   5.100 -    if (string_char_needs_quoting (*s))
   5.101 -      fprintf (pdf_file->f, "\\%03o", 0xff & *(s++));
   5.102 -    else
   5.103 -      fprintf (pdf_file->f, "%c", *(s++));
   5.104 -  fprintf (pdf_file->f, ") ");
   5.105 +  if(pdf_write_literal_string (NULL,s,n)<2*n)
   5.106 +    pdf_write_literal_string (pdf_file,s,n);
   5.107 +  else {
   5.108 +    fprintf (pdf_file->f, "<");
   5.109 +    for(;n--;)
   5.110 +      fprintf (pdf_file->f, "%.2X",*(s++));
   5.111 +    fprintf (pdf_file->f, "> ");
   5.112 +  }
   5.113  }
   5.114  
   5.115  
   5.116 @@ -560,7 +612,7 @@
   5.117        pdf_write_name (pdf_file, obj->val.name);
   5.118        break;
   5.119      case PT_STRING:
   5.120 -      pdf_write_string (pdf_file, obj->val.string);
   5.121 +      pdf_write_string (pdf_file, obj->val.string.content, obj->val.string.length);
   5.122        break;
   5.123      case PT_INTEGER:
   5.124        fprintf (pdf_file->f, "%ld ", obj->val.integer);
     6.1 --- a/pdf_prim.h	Mon Dec 14 15:44:55 2009 +0000
     6.2 +++ b/pdf_prim.h	Mon Dec 14 15:51:53 2009 +0000
     6.3 @@ -79,6 +79,8 @@
     6.4  
     6.5  struct pdf_obj *pdf_new_string (char *str);
     6.6  
     6.7 +struct pdf_obj *pdf_new_string_n (char *str, int n);
     6.8 +
     6.9  struct pdf_obj *pdf_new_integer (long val);
    6.10  
    6.11  struct pdf_obj *pdf_new_real (double val);
     7.1 --- a/tumble.c	Mon Dec 14 15:44:55 2009 +0000
     7.2 +++ b/tumble.c	Mon Dec 14 15:51:53 2009 +0000
     7.3 @@ -381,6 +381,8 @@
     7.4    init_tiff_handler ();
     7.5    init_jpeg_handler ();
     7.6    init_pbm_handler ();
     7.7 +  init_png_handler ();
     7.8 +  init_jp2_handler ();
     7.9  
    7.10    while (--argc)
    7.11      {
     8.1 --- a/tumble_input.c	Mon Dec 14 15:44:55 2009 +0000
     8.2 +++ b/tumble_input.c	Mon Dec 14 15:51:53 2009 +0000
     8.3 @@ -117,8 +117,10 @@
     8.4        result = current_input_handler->close_input_file ();
     8.5        current_input_handler = NULL;
     8.6      }
     8.7 -  if (in_filename)
     8.8 +  if (in_filename) {
     8.9      free (in_filename);
    8.10 +    in_filename = NULL;
    8.11 +  }
    8.12    if (in)
    8.13      {
    8.14        fclose (in);
     9.1 --- a/tumble_input.h	Mon Dec 14 15:44:55 2009 +0000
     9.2 +++ b/tumble_input.h	Mon Dec 14 15:51:53 2009 +0000
     9.3 @@ -65,3 +65,5 @@
     9.4  void init_tiff_handler (void);
     9.5  void init_jpeg_handler (void);
     9.6  void init_pbm_handler  (void);
     9.7 +void init_png_handler  (void);
     9.8 +void init_jp2_handler  (void);
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tumble_jp2.c	Mon Dec 14 15:51:53 2009 +0000
    10.3 @@ -0,0 +1,275 @@
    10.4 +/*
    10.5 + * tumble: build a PDF file from image files
    10.6 + *
    10.7 + * Copyright 2004 Daniel Gloeckner
    10.8 + *
    10.9 + * Derived from tumble_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
   10.10 + *
   10.11 + * This program is free software; you can redistribute it and/or modify
   10.12 + * it under the terms of the GNU General Public License version 2 as
   10.13 + * published by the Free Software Foundation.  Note that permission is
   10.14 + * not granted to redistribute this program under the terms of any
   10.15 + * other version of the General Public License.
   10.16 + *
   10.17 + * This program is distributed in the hope that it will be useful,
   10.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10.20 + * GNU General Public License for more details.
   10.21 + *
   10.22 + * You should have received a copy of the GNU General Public License
   10.23 + * along with this program; if not, write to the Free Software
   10.24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   10.25 + */
   10.26 +
   10.27 +
   10.28 +#include <stdbool.h>
   10.29 +#include <stdint.h>
   10.30 +#include <stdio.h>
   10.31 +#include <math.h>
   10.32 +#include <strings.h>  /* strcasecmp() is a BSDism */
   10.33 +
   10.34 +
   10.35 +#include "semantics.h"
   10.36 +#include "tumble.h"
   10.37 +#include "bitblt.h"
   10.38 +#include "pdf.h"
   10.39 +#include "tumble_input.h"
   10.40 +
   10.41 +
   10.42 +static bool match_jp2_suffix (char *suffix)
   10.43 +{
   10.44 +  return (strcasecmp (suffix, ".jp2") == 0);
   10.45 +}
   10.46 +
   10.47 +static bool close_jp2_input_file (void)
   10.48 +{
   10.49 +  return (1);
   10.50 +}
   10.51 +
   10.52 +static struct {
   10.53 +  FILE *f;
   10.54 +  uint32_t width,height;
   10.55 +  struct {
   10.56 +    double VR,HR;
   10.57 +  } res[2];
   10.58 +} jp2info;
   10.59 +
   10.60 +struct box {
   10.61 +  char TBox[4];
   10.62 +  bool (*func)(uint64_t size, void *cparam);
   10.63 +  void *cparam;
   10.64 +};
   10.65 +
   10.66 +#define BE32(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
   10.67 +#define BE16(p) (((p)[2]<<8)+(p)[3])
   10.68 +
   10.69 +static bool skipbox(uint64_t size, void *cparam)
   10.70 +{
   10.71 +  if(size==~0)
   10.72 +    fseek(jp2info.f,0,SEEK_END);
   10.73 +  else {
   10.74 +    if(cparam)
   10.75 +      size-=*(int *)cparam;
   10.76 +    fseek(jp2info.f,size,SEEK_CUR); /*FIXME: size is 64bit*/
   10.77 +  }
   10.78 +  return 1;
   10.79 +}
   10.80 +
   10.81 +static bool read_res(uint64_t size, void *cparam)
   10.82 +{
   10.83 +  int read=0;
   10.84 +  bool ret=1;
   10.85 +  if(size>=10) {
   10.86 +    int i;
   10.87 +    unsigned char buf[10];
   10.88 +
   10.89 +    ret=0;
   10.90 +    i=(int)cparam;
   10.91 +    read=fread(buf,1,10,jp2info.f);
   10.92 +    if(read==10) {
   10.93 +      uint16_t vrn,vrd,hrn,hrd;
   10.94 +      int8_t vre,hre;
   10.95 +      vrn=BE16(buf);
   10.96 +      vrd=BE16(buf+2);
   10.97 +      hrn=BE16(buf+4);
   10.98 +      hrd=BE16(buf+6);
   10.99 +      vre=((signed char *)buf)[8];
  10.100 +      hre=((signed char *)buf)[9];
  10.101 +      if(vrn && vrd && hrn && hrd) {
  10.102 +	jp2info.res[i].VR=vrn*pow(10.0,vre)/vrd;
  10.103 +	jp2info.res[i].HR=hrn*pow(10.0,hre)/hrd;
  10.104 +	ret=1;
  10.105 +      }
  10.106 +    }
  10.107 +  }
  10.108 +  skipbox(size,&read);
  10.109 +  return ret;
  10.110 +}
  10.111 +
  10.112 +static bool read_ihdr(uint64_t size, void *cparam)
  10.113 +{
  10.114 +  int read=0;
  10.115 +  bool ret=1;
  10.116 +  if(size>=8) {
  10.117 +    unsigned char buf[8];
  10.118 +    read=fread(buf,1,8,jp2info.f);
  10.119 +    if(read==8) {
  10.120 +      jp2info.height=BE32(buf);
  10.121 +      jp2info.width=BE32(buf+4);
  10.122 +    } else
  10.123 +      ret=0;
  10.124 +  }
  10.125 +  skipbox(size,&read);
  10.126 +  return ret;
  10.127 +}
  10.128 +
  10.129 +static bool superbox(uint64_t size, void *cparam)
  10.130 +{ 
  10.131 +  while(size>=8) {
  10.132 +    static unsigned char buf[12];
  10.133 +    int r;
  10.134 +    uint64_t s;
  10.135 +    struct box *l;
  10.136 +
  10.137 +    r=fread(buf+4,1,8,jp2info.f);
  10.138 +    if(r<8)
  10.139 +      return (size==~0 && r==0);
  10.140 + 
  10.141 +    s=BE32(buf+4);
  10.142 +    if(s==1 && size>=16) {
  10.143 +      r=fread(buf,1,8,jp2info.f);
  10.144 +      if(r<8)
  10.145 +        return 0;
  10.146 +      s=((uint64_t)BE32(buf)<<32)+BE32(buf+4);
  10.147 +    }
  10.148 +    if(s && s<8)
  10.149 +      return 0;
  10.150 +    if(size!=~0) {
  10.151 +      if(!s)
  10.152 +        return 0;
  10.153 +      size-=s;
  10.154 +    } else if(!s)
  10.155 +      size=0;
  10.156 +    s=s?s-8:~0;
  10.157 +
  10.158 +    for(l=(struct box *)cparam;l->func;l++)
  10.159 +      if(!memcmp(l->TBox,buf+8,4))
  10.160 +        break;
  10.161 +    if(l->func) {
  10.162 +      if(!l->func(s,l->cparam))
  10.163 +	return 0;
  10.164 +    }else
  10.165 +      if(!skipbox(s,NULL))
  10.166 +	return 0;
  10.167 +  }
  10.168 +  
  10.169 +  return size==0;
  10.170 +}
  10.171 +
  10.172 +static const struct box res_boxes[]={
  10.173 +  {"resc",read_res,(void *)0},
  10.174 +  {"resd",read_res,(void *)1},
  10.175 +  {"",NULL,NULL}
  10.176 +};
  10.177 +
  10.178 +static const struct box jp2h_boxes[]={
  10.179 +  {"ihdr",read_ihdr,NULL},
  10.180 +  {"res ",superbox,(void *)res_boxes},
  10.181 +  {"",NULL,NULL}
  10.182 +};
  10.183 +
  10.184 +static const struct box root[]={
  10.185 +  {"jp2h",superbox,(void *)jp2h_boxes},
  10.186 +  {"",NULL,NULL}
  10.187 +};
  10.188 +
  10.189 +static bool open_jp2_input_file (FILE *f, char *name)
  10.190 +{
  10.191 +  int s;
  10.192 +  const char sig[12]="\0\0\0\xCjP  \r\n\x87\n";
  10.193 +  char buf[12];
  10.194 +
  10.195 +  memset(&jp2info,0,sizeof(jp2info));
  10.196 +  jp2info.f=f;
  10.197 +  
  10.198 +  s=fread(buf,1,12,f);
  10.199 +  rewind(f);
  10.200 +  return (s==12 && !memcmp(buf,sig,12));
  10.201 +}
  10.202 +
  10.203 +
  10.204 +static bool last_jp2_input_page (void)
  10.205 +{
  10.206 +  return 1;
  10.207 +}
  10.208 +
  10.209 +
  10.210 +static bool get_jp2_image_info (int image,
  10.211 +				 input_attributes_t input_attributes,
  10.212 +				 image_info_t *image_info)
  10.213 +{
  10.214 +  int i;
  10.215 +
  10.216 +  if(!superbox(~0,(void *)root))
  10.217 +    return 0;
  10.218 +  rewind(jp2info.f);
  10.219 +  
  10.220 +#ifdef DEBUG_JPEG
  10.221 +  printf ("capture x density: %d pixel/m\n", jp2info.res[0].HR);
  10.222 +  printf ("capture y density: %d pixel/m\n", jp2info.res[0].VR);
  10.223 +  printf ("display x density: %d pixel/m\n", jp2info.res[1].HR);
  10.224 +  printf ("display y density: %d pixel/m\n", jp2info.res[1].VR);
  10.225 +  printf ("width: %d\n", jp2info.width);
  10.226 +  printf ("height: %d\n", jp2info.height);
  10.227 +#endif
  10.228 +
  10.229 +  image_info->color = 1;
  10.230 +  image_info->width_samples = jp2info.width;
  10.231 +  image_info->height_samples = jp2info.height;
  10.232 +
  10.233 +  image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
  10.234 +  image_info->height_points = (image_info->height_samples * POINTS_PER_INCH) / 300.0;
  10.235 +
  10.236 +  for(i=2;i--;)
  10.237 +    if(jp2info.res[i].VR > 0.0 && jp2info.res[i].HR > 0.0) {
  10.238 +      image_info->width_points = (image_info->width_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].HR * 254);
  10.239 +      image_info->height_points = (image_info->height_samples * POINTS_PER_INCH * 10000)/(jp2info.res[i].VR * 254);
  10.240 +      break;
  10.241 +    }
  10.242 +
  10.243 +  return 1;
  10.244 +}
  10.245 +
  10.246 +
  10.247 +static bool process_jp2_image (int image,  /* range 1 .. n */
  10.248 +				input_attributes_t input_attributes,
  10.249 +				image_info_t *image_info,
  10.250 +				pdf_page_handle page)
  10.251 +{
  10.252 +  pdf_write_jp2_image (page,
  10.253 +			0, 0,  /* x, y */
  10.254 +			image_info->width_points,
  10.255 +			image_info->height_points,
  10.256 +			image_info->width_samples,
  10.257 +			image_info->height_samples,
  10.258 +			jp2info.f);
  10.259 +
  10.260 +  return (1);
  10.261 +}
  10.262 +
  10.263 +
  10.264 +input_handler_t jp2_handler =
  10.265 +  {
  10.266 +    match_jp2_suffix,
  10.267 +    open_jp2_input_file,
  10.268 +    close_jp2_input_file,
  10.269 +    last_jp2_input_page,
  10.270 +    get_jp2_image_info,
  10.271 +    process_jp2_image
  10.272 +  };
  10.273 +
  10.274 +
  10.275 +void init_jp2_handler (void)
  10.276 +{
  10.277 +  install_input_handler (& jp2_handler);
  10.278 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tumble_png.c	Mon Dec 14 15:51:53 2009 +0000
    11.3 @@ -0,0 +1,233 @@
    11.4 +/*
    11.5 + * tumble: build a PDF file from image files
    11.6 + *
    11.7 + * Copyright 2004 Daniel Gloeckner
    11.8 + * 
    11.9 + * Derived from tumble_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
   11.10 + *
   11.11 + * This program is free software; you can redistribute it and/or modify
   11.12 + * it under the terms of the GNU General Public License version 2 as
   11.13 + * published by the Free Software Foundation.  Note that permission is
   11.14 + * not granted to redistribute this program under the terms of any
   11.15 + * other version of the General Public License.
   11.16 + *
   11.17 + * This program is distributed in the hope that it will be useful,
   11.18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11.19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11.20 + * GNU General Public License for more details.
   11.21 + *
   11.22 + * You should have received a copy of the GNU General Public License
   11.23 + * along with this program; if not, write to the Free Software
   11.24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
   11.25 + */
   11.26 +
   11.27 +
   11.28 +#include <stdbool.h>
   11.29 +#include <stdint.h>
   11.30 +#include <stdio.h>
   11.31 +#include <strings.h>  /* strcasecmp() is a BSDism */
   11.32 +
   11.33 +
   11.34 +#include "semantics.h"
   11.35 +#include "tumble.h"
   11.36 +#include "bitblt.h"
   11.37 +#include "pdf.h"
   11.38 +#include "tumble_input.h"
   11.39 +
   11.40 +
   11.41 +static FILE *png_f;
   11.42 +
   11.43 +static struct {
   11.44 +  uint32_t palent;
   11.45 +  uint8_t bpp;
   11.46 +  uint8_t color;
   11.47 +  char pal[256*3];
   11.48 +} cinfo;
   11.49 +
   11.50 +
   11.51 +static bool match_png_suffix (char *suffix)
   11.52 +{
   11.53 +  return (strcasecmp (suffix, ".png") == 0);
   11.54 +}
   11.55 +
   11.56 +static bool close_png_input_file (void)
   11.57 +{
   11.58 +  return (1);
   11.59 +}
   11.60 +
   11.61 +#define BENUM(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
   11.62 +
   11.63 +static bool open_png_input_file (FILE *f, char *name)
   11.64 +{
   11.65 +  const char sig [8]="\211PNG\r\n\032\n";
   11.66 +  uint8_t buf [8];
   11.67 +  int l;
   11.68 +
   11.69 +  l = fread (buf, 1, sizeof (sig), f);
   11.70 +  if (l != sizeof (sig) || memcmp(buf,sig,sizeof(sig))) {
   11.71 +    rewind(f);
   11.72 +    return 0;
   11.73 +  }
   11.74 +
   11.75 +  png_f = f;
   11.76 +  
   11.77 +  return 1;
   11.78 +}
   11.79 +
   11.80 +
   11.81 +static bool last_png_input_page (void)
   11.82 +{
   11.83 +  return 1;
   11.84 +}
   11.85 +
   11.86 +
   11.87 +static bool get_png_image_info (int image,
   11.88 +				 input_attributes_t input_attributes,
   11.89 +				 image_info_t *image_info)
   11.90 +{
   11.91 +  uint8_t buf [20], unit;
   11.92 +  uint32_t width,height,xppu,yppu;
   11.93 +  size_t l;
   11.94 +  bool seen_IHDR,seen_PLTE,seen_pHYs;
   11.95 +
   11.96 +  seen_IHDR=seen_PLTE=seen_pHYs=false;
   11.97 +  memset(&cinfo,0,sizeof(cinfo));
   11.98 +  unit=0;
   11.99 +  xppu=yppu=1;
  11.100 +  
  11.101 +  for(;;)
  11.102 +  {
  11.103 +    l = fread (buf, 1, 8, png_f);
  11.104 +    if(l != 8)
  11.105 +      return 0;
  11.106 +    l=BENUM(buf);
  11.107 +    if(!memcmp(buf+4,"IHDR",4)) {
  11.108 +      if(seen_IHDR || l!=13)
  11.109 +	return 0;
  11.110 +      seen_IHDR=true;
  11.111 +      l = fread (buf, 1, 17, png_f);
  11.112 +      if(l!=17)
  11.113 +	return 0;
  11.114 +      width=BENUM(buf);
  11.115 +      height=BENUM(buf+4);
  11.116 +      cinfo.bpp=buf[8];
  11.117 +      cinfo.color=buf[9];
  11.118 +      if(buf[8]>8 || buf[10] || buf[11] || buf[12])
  11.119 +	return 0;
  11.120 +      continue;
  11.121 +    }
  11.122 +    if(!seen_IHDR)
  11.123 +      return 0;
  11.124 +    if(!memcmp(buf+4,"PLTE",4)) {
  11.125 +      size_t i;
  11.126 +      if(seen_PLTE || l>256*3 || l%3 || !cinfo.color)
  11.127 +	return 0;
  11.128 +      seen_PLTE=true;
  11.129 +      i = fread (cinfo.pal, 1, l, png_f);
  11.130 +      if(i != l)
  11.131 +	return 0;
  11.132 +      cinfo.palent=l/3;
  11.133 +      fseek(png_f,4,SEEK_CUR);
  11.134 +    } else if(!memcmp(buf+4,"pHYs",4)) {
  11.135 +      if(seen_pHYs || l!=9)
  11.136 +	return 0;
  11.137 +      seen_pHYs=true;
  11.138 +      l = fread (buf, 1, 13, png_f);
  11.139 +      if(l != 13)
  11.140 +	return 0;
  11.141 +      xppu=BENUM(buf);
  11.142 +      yppu=BENUM(buf+4);
  11.143 +      unit=buf[8];
  11.144 +    } else if(!memcmp(buf+4,"IDAT",4)) {
  11.145 +      fseek(png_f,-8,SEEK_CUR);
  11.146 +      break;
  11.147 +    } else {
  11.148 +      fseek(png_f,l+4,SEEK_CUR);
  11.149 +    }
  11.150 +  }
  11.151 +  if(cinfo.color==3 && !seen_PLTE)
  11.152 +    return 0;
  11.153 +
  11.154 +#ifdef DEBUG_JPEG
  11.155 +  printf ("color type: %d\n", cinfo.color);
  11.156 +  printf ("bit depth: %d\n", cinfo.bpp);
  11.157 +  printf ("density unit: %d\n", unit);
  11.158 +  printf ("x density: %d\n", xppu);
  11.159 +  printf ("y density: %d\n", yppu);
  11.160 +  printf ("width: %d\n", width);
  11.161 +  printf ("height: %d\n", height);
  11.162 +#endif
  11.163 +
  11.164 +  switch (cinfo.color)
  11.165 +    {
  11.166 +    case 0:
  11.167 +      image_info->color = 0;
  11.168 +      break;
  11.169 +    case 2:
  11.170 +    case 3:
  11.171 +      image_info->color = 1;
  11.172 +      break;
  11.173 +    default:
  11.174 +      fprintf (stderr, "PNG color type %d not supported\n", cinfo.color);
  11.175 +      return (0);
  11.176 +    }
  11.177 +  image_info->width_samples = width;
  11.178 +  image_info->height_samples = height;
  11.179 +
  11.180 +  switch (unit==1)
  11.181 +  {
  11.182 +    case 1:
  11.183 +      image_info->width_points = ((image_info->width_samples * POINTS_PER_INCH) /
  11.184 +				  (xppu * 0.0254));
  11.185 +      image_info->height_points = ((image_info->height_samples * POINTS_PER_INCH) /
  11.186 +				   (yppu * 0.0254));
  11.187 +      break;
  11.188 +    case 0:
  11.189 +      /* assume 300 DPI - not great, but what else can we do? */
  11.190 +      image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
  11.191 +      image_info->height_points = ((double) yppu * image_info->height_samples * POINTS_PER_INCH) / ( 300.0 * xppu);
  11.192 +      break;
  11.193 +    default:
  11.194 +      fprintf (stderr, "PNG pHYs unit %d not supported\n", unit);
  11.195 +  }
  11.196 +
  11.197 +  return 1;
  11.198 +}
  11.199 +
  11.200 +
  11.201 +static bool process_png_image (int image,  /* range 1 .. n */
  11.202 +				input_attributes_t input_attributes,
  11.203 +				image_info_t *image_info,
  11.204 +				pdf_page_handle page)
  11.205 +{
  11.206 +  pdf_write_png_image (page,
  11.207 +			0, 0,  /* x, y */
  11.208 +			image_info->width_points,
  11.209 +			image_info->height_points,
  11.210 +			cinfo.color,
  11.211 +			cinfo.color==3?cinfo.pal:NULL,
  11.212 +			cinfo.palent,
  11.213 +			cinfo.bpp,
  11.214 +			image_info->width_samples,
  11.215 +			image_info->height_samples,
  11.216 +			png_f);
  11.217 +
  11.218 +  return (1);
  11.219 +}
  11.220 +
  11.221 +
  11.222 +input_handler_t png_handler =
  11.223 +  {
  11.224 +    match_png_suffix,
  11.225 +    open_png_input_file,
  11.226 +    close_png_input_file,
  11.227 +    last_png_input_page,
  11.228 +    get_png_image_info,
  11.229 +    process_png_image
  11.230 +  };
  11.231 +
  11.232 +
  11.233 +void init_png_handler (void)
  11.234 +{
  11.235 +  install_input_handler (& png_handler);
  11.236 +}