tumble_png.c

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
permissions
-rw-r--r--

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

     1 /*
     2  * tumble: build a PDF file from image files
     3  *
     4  * Copyright 2004 Daniel Gloeckner
     5  * 
     6  * Derived from tumble_jpeg.c written 2003 by Eric Smith <eric at brouhaha.com>
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License version 2 as
    10  * published by the Free Software Foundation.  Note that permission is
    11  * not granted to redistribute this program under the terms of any
    12  * other version of the General Public License.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  *
    19  * You should have received a copy of the GNU General Public License
    20  * along with this program; if not, write to the Free Software
    21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
    22  */
    25 #include <stdbool.h>
    26 #include <stdint.h>
    27 #include <stdio.h>
    28 #include <strings.h>  /* strcasecmp() is a BSDism */
    31 #include "semantics.h"
    32 #include "tumble.h"
    33 #include "bitblt.h"
    34 #include "pdf.h"
    35 #include "tumble_input.h"
    38 static FILE *png_f;
    40 static struct {
    41   uint32_t palent;
    42   uint8_t bpp;
    43   uint8_t color;
    44   char pal[256*3];
    45 } cinfo;
    48 static bool match_png_suffix (char *suffix)
    49 {
    50   return (strcasecmp (suffix, ".png") == 0);
    51 }
    53 static bool close_png_input_file (void)
    54 {
    55   return (1);
    56 }
    58 #define BENUM(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
    60 static bool open_png_input_file (FILE *f, char *name)
    61 {
    62   const char sig [8]="\211PNG\r\n\032\n";
    63   uint8_t buf [8];
    64   int l;
    66   l = fread (buf, 1, sizeof (sig), f);
    67   if (l != sizeof (sig) || memcmp(buf,sig,sizeof(sig))) {
    68     rewind(f);
    69     return 0;
    70   }
    72   png_f = f;
    74   return 1;
    75 }
    78 static bool last_png_input_page (void)
    79 {
    80   return 1;
    81 }
    84 static bool get_png_image_info (int image,
    85 				 input_attributes_t input_attributes,
    86 				 image_info_t *image_info)
    87 {
    88   uint8_t buf [20], unit;
    89   uint32_t width,height,xppu,yppu;
    90   size_t l;
    91   bool seen_IHDR,seen_PLTE,seen_pHYs;
    93   seen_IHDR=seen_PLTE=seen_pHYs=false;
    94   memset(&cinfo,0,sizeof(cinfo));
    95   unit=0;
    96   xppu=yppu=1;
    98   for(;;)
    99   {
   100     l = fread (buf, 1, 8, png_f);
   101     if(l != 8)
   102       return 0;
   103     l=BENUM(buf);
   104     if(!memcmp(buf+4,"IHDR",4)) {
   105       if(seen_IHDR || l!=13)
   106 	return 0;
   107       seen_IHDR=true;
   108       l = fread (buf, 1, 17, png_f);
   109       if(l!=17)
   110 	return 0;
   111       width=BENUM(buf);
   112       height=BENUM(buf+4);
   113       cinfo.bpp=buf[8];
   114       cinfo.color=buf[9];
   115       if(buf[8]>8 || buf[10] || buf[11] || buf[12])
   116 	return 0;
   117       continue;
   118     }
   119     if(!seen_IHDR)
   120       return 0;
   121     if(!memcmp(buf+4,"PLTE",4)) {
   122       size_t i;
   123       if(seen_PLTE || l>256*3 || l%3 || !cinfo.color)
   124 	return 0;
   125       seen_PLTE=true;
   126       i = fread (cinfo.pal, 1, l, png_f);
   127       if(i != l)
   128 	return 0;
   129       cinfo.palent=l/3;
   130       fseek(png_f,4,SEEK_CUR);
   131     } else if(!memcmp(buf+4,"pHYs",4)) {
   132       if(seen_pHYs || l!=9)
   133 	return 0;
   134       seen_pHYs=true;
   135       l = fread (buf, 1, 13, png_f);
   136       if(l != 13)
   137 	return 0;
   138       xppu=BENUM(buf);
   139       yppu=BENUM(buf+4);
   140       unit=buf[8];
   141     } else if(!memcmp(buf+4,"IDAT",4)) {
   142       fseek(png_f,-8,SEEK_CUR);
   143       break;
   144     } else {
   145       fseek(png_f,l+4,SEEK_CUR);
   146     }
   147   }
   148   if(cinfo.color==3 && !seen_PLTE)
   149     return 0;
   151 #ifdef DEBUG_JPEG
   152   printf ("color type: %d\n", cinfo.color);
   153   printf ("bit depth: %d\n", cinfo.bpp);
   154   printf ("density unit: %d\n", unit);
   155   printf ("x density: %d\n", xppu);
   156   printf ("y density: %d\n", yppu);
   157   printf ("width: %d\n", width);
   158   printf ("height: %d\n", height);
   159 #endif
   161   switch (cinfo.color)
   162     {
   163     case 0:
   164       image_info->color = 0;
   165       break;
   166     case 2:
   167     case 3:
   168       image_info->color = 1;
   169       break;
   170     default:
   171       fprintf (stderr, "PNG color type %d not supported\n", cinfo.color);
   172       return (0);
   173     }
   174   image_info->width_samples = width;
   175   image_info->height_samples = height;
   177   switch (unit==1)
   178   {
   179     case 1:
   180       image_info->width_points = ((image_info->width_samples * POINTS_PER_INCH) /
   181 				  (xppu * 0.0254));
   182       image_info->height_points = ((image_info->height_samples * POINTS_PER_INCH) /
   183 				   (yppu * 0.0254));
   184       break;
   185     case 0:
   186       /* assume 300 DPI - not great, but what else can we do? */
   187       image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
   188       image_info->height_points = ((double) yppu * image_info->height_samples * POINTS_PER_INCH) / ( 300.0 * xppu);
   189       break;
   190     default:
   191       fprintf (stderr, "PNG pHYs unit %d not supported\n", unit);
   192   }
   194   return 1;
   195 }
   198 static bool process_png_image (int image,  /* range 1 .. n */
   199 				input_attributes_t input_attributes,
   200 				image_info_t *image_info,
   201 				pdf_page_handle page)
   202 {
   203   pdf_write_png_image (page,
   204 			0, 0,  /* x, y */
   205 			image_info->width_points,
   206 			image_info->height_points,
   207 			cinfo.color,
   208 			cinfo.color==3?cinfo.pal:NULL,
   209 			cinfo.palent,
   210 			cinfo.bpp,
   211 			image_info->width_samples,
   212 			image_info->height_samples,
   213 			png_f);
   215   return (1);
   216 }
   219 input_handler_t png_handler =
   220   {
   221     match_png_suffix,
   222     open_png_input_file,
   223     close_png_input_file,
   224     last_png_input_page,
   225     get_png_image_info,
   226     process_png_image
   227   };
   230 void init_png_handler (void)
   231 {
   232   install_input_handler (& png_handler);
   233 }