tumble_png.c

Mon, 14 Dec 2009 16:18:21 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 14 Dec 2009 16:18:21 +0000
changeset 172
2fae6df568f6
parent 166
301f6f17c364
permissions
-rw-r--r--

remove erroneous 0.33-philpem1 tag

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