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