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 <spacewar@gmail.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 *
23 * 2009-03-13 [JDB] New module to add PNG image support.
24 */
25
26
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <strings.h> /* strcasecmp() is a BSDism */
32
33
34 #include "semantics.h"
35 #include "tumble.h"
36 #include "bitblt.h"
37 #include "pdf.h"
38 #include "tumble_input.h"
39
40
41 static FILE *png_f;
42
43 static struct {
44 uint32_t palent;
45 uint8_t bpp;
46 uint8_t color;
47 char pal[256*3];
48 } cinfo;
49
50
match_png_suffix(char * suffix)51 static bool match_png_suffix (char *suffix)
52 {
53 return (strcasecmp (suffix, ".png") == 0);
54 }
55
close_png_input_file(void)56 static bool close_png_input_file (void)
57 {
58 return (1);
59 }
60
61 #define BENUM(p) (((p)[0]<<24)+((p)[1]<<16)+((p)[2]<<8)+(p)[3])
62
open_png_input_file(FILE * f,char * name)63 static bool open_png_input_file (FILE *f, char *name)
64 {
65 const char sig [8]="\211PNG\r\n\032\n";
66 uint8_t buf [8];
67 int l;
68
69 l = fread (buf, 1, sizeof (sig), f);
70 if (l != sizeof (sig) || memcmp(buf,sig,sizeof(sig))) {
71 rewind(f);
72 return 0;
73 }
74
75 png_f = f;
76
77 return 1;
78 }
79
80
last_png_input_page(void)81 static bool last_png_input_page (void)
82 {
83 return 1;
84 }
85
86
get_png_image_info(int image,input_attributes_t input_attributes,image_info_t * image_info)87 static bool get_png_image_info (int image,
88 input_attributes_t input_attributes,
89 image_info_t *image_info)
90 {
91 uint8_t buf [20], unit;
92 uint32_t width,height,xppu,yppu;
93 size_t l;
94 bool seen_IHDR,seen_PLTE,seen_pHYs;
95
96 seen_IHDR=seen_PLTE=seen_pHYs=false;
97 memset(&cinfo,0,sizeof(cinfo));
98 unit=0;
99 xppu=yppu=1;
100
101 for(;;)
102 {
103 l = fread (buf, 1, 8, png_f);
104 if(l != 8)
105 return 0;
106 l=BENUM(buf);
107 if(!memcmp(buf+4,"IHDR",4)) {
108 if(seen_IHDR || l!=13)
109 return 0;
110 seen_IHDR=true;
111 l = fread (buf, 1, 17, png_f);
112 if(l!=17)
113 return 0;
114 width=BENUM(buf);
115 height=BENUM(buf+4);
116 cinfo.bpp=buf[8];
117 cinfo.color=buf[9];
118 if(buf[8]>8 || buf[10] || buf[11] || buf[12])
119 return 0;
120 continue;
121 }
122 if(!seen_IHDR)
123 return 0;
124 if(!memcmp(buf+4,"PLTE",4)) {
125 size_t i;
126 if(seen_PLTE || l>256*3 || l%3 || !cinfo.color)
127 return 0;
128 seen_PLTE=true;
129 i = fread (cinfo.pal, 1, l, png_f);
130 if(i != l)
131 return 0;
132 cinfo.palent=l/3;
133 fseek(png_f,4,SEEK_CUR);
134 } else if(!memcmp(buf+4,"pHYs",4)) {
135 if(seen_pHYs || l!=9)
136 return 0;
137 seen_pHYs=true;
138 l = fread (buf, 1, 13, png_f);
139 if(l != 13)
140 return 0;
141 xppu=BENUM(buf);
142 yppu=BENUM(buf+4);
143 unit=buf[8];
144 } else if(!memcmp(buf+4,"IDAT",4)) {
145 fseek(png_f,-8,SEEK_CUR);
146 break;
147 } else {
148 fseek(png_f,l+4,SEEK_CUR);
149 }
150 }
151 if(cinfo.color==3 && !seen_PLTE)
152 return 0;
153
154 #ifdef DEBUG_JPEG
155 printf ("color type: %d\n", cinfo.color);
156 printf ("bit depth: %d\n", cinfo.bpp);
157 printf ("density unit: %d\n", unit);
158 printf ("x density: %d\n", xppu);
159 printf ("y density: %d\n", yppu);
160 printf ("width: %d\n", width);
161 printf ("height: %d\n", height);
162 #endif
163
164 switch (cinfo.color)
165 {
166 case 0:
167 image_info->color = 0;
168 break;
169 case 2:
170 case 3:
171 image_info->color = 1;
172 break;
173 default:
174 fprintf (stderr, "PNG color type %d not supported\n", cinfo.color);
175 return (0);
176 }
177 image_info->width_samples = width;
178 image_info->height_samples = height;
179
180 switch (unit==1)
181 {
182 case 1:
183 image_info->width_points = ((image_info->width_samples * POINTS_PER_INCH) /
184 (xppu * 0.0254));
185 image_info->height_points = ((image_info->height_samples * POINTS_PER_INCH) /
186 (yppu * 0.0254));
187 break;
188 case 0:
189 /* assume 300 DPI - not great, but what else can we do? */
190 image_info->width_points = (image_info->width_samples * POINTS_PER_INCH) / 300.0;
191 image_info->height_points = ((double) yppu * image_info->height_samples * POINTS_PER_INCH) / ( 300.0 * xppu);
192 break;
193 default:
194 fprintf (stderr, "PNG pHYs unit %d not supported\n", unit);
195 }
196
197 return 1;
198 }
199
200
process_png_image(int image,input_attributes_t input_attributes,image_info_t * image_info,pdf_page_handle page,position_t position)201 static bool process_png_image (int image, /* range 1 .. n */
202 input_attributes_t input_attributes,
203 image_info_t *image_info,
204 pdf_page_handle page,
205 position_t position)
206 {
207 pdf_write_png_image (page,
208 position.x, position.y,
209 image_info->width_points,
210 image_info->height_points,
211 cinfo.color,
212 cinfo.color==3?cinfo.pal:NULL,
213 cinfo.palent,
214 cinfo.bpp,
215 image_info->width_samples,
216 image_info->height_samples,
217 input_attributes.transparency,
218 png_f);
219
220 return (1);
221 }
222
223
224 input_handler_t png_handler =
225 {
226 match_png_suffix,
227 open_png_input_file,
228 close_png_input_file,
229 last_png_input_page,
230 get_png_image_info,
231 process_png_image
232 };
233
234
init_png_handler(void)235 void init_png_handler (void)
236 {
237 install_input_handler (& png_handler);
238 }
239