Mon, 14 Dec 2009 16:16:03 +0000
Added tag V0_33_philpem1 for changeset ad0b9a8990ac
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 }