aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/loaders/png/evas_image_load_png.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/modules/loaders/png/evas_image_load_png.c')
-rw-r--r--libraries/evas/src/modules/loaders/png/evas_image_load_png.c328
1 files changed, 328 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/loaders/png/evas_image_load_png.c b/libraries/evas/src/modules/loaders/png/evas_image_load_png.c
new file mode 100644
index 0000000..a1480ae
--- /dev/null
+++ b/libraries/evas/src/modules/loaders/png/evas_image_load_png.c
@@ -0,0 +1,328 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <png.h>
7#include <setjmp.h>
8
9#ifdef HAVE_EVIL
10# include <Evil.h>
11#endif
12
13#ifdef _WIN32_WCE
14# define E_FOPEN(file, mode) evil_fopen_native((file), (mode))
15# define E_FREAD(buffer, size, count, stream) evil_fread_native(buffer, size, count, stream)
16# define E_FCLOSE(stream) evil_fclose_native(stream)
17#else
18# define E_FOPEN(file, mode) fopen((file), (mode))
19# define E_FREAD(buffer, size, count, stream) fread(buffer, size, count, stream)
20# define E_FCLOSE(stream) fclose(stream)
21#endif
22
23#include "evas_common.h"
24#include "evas_private.h"
25
26
27#define PNG_BYTES_TO_CHECK 4
28
29
30static Eina_Bool evas_image_load_file_head_png(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
31static Eina_Bool evas_image_load_file_data_png(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
32
33static Evas_Image_Load_Func evas_image_load_png_func =
34{
35 EINA_TRUE,
36 evas_image_load_file_head_png,
37 evas_image_load_file_data_png,
38 NULL
39};
40
41static Eina_Bool
42evas_image_load_file_head_png(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
43{
44 png_uint_32 w32, h32;
45 FILE *f;
46 png_structp png_ptr = NULL;
47 png_infop info_ptr = NULL;
48 int bit_depth, color_type, interlace_type;
49 unsigned char buf[PNG_BYTES_TO_CHECK];
50 char hasa;
51
52 hasa = 0;
53 f = E_FOPEN(file, "rb");
54 if (!f)
55 {
56 ERR("File: '%s' does not exist\n", file);
57 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
58 return EINA_FALSE;
59 }
60
61 /* if we havent read the header before, set the header data */
62 if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
63 {
64 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
65 goto close_file;
66 }
67
68 if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
69 {
70 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
71 goto close_file;
72 }
73
74 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
75 if (!png_ptr)
76 {
77 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
78 goto close_file;
79 }
80
81 info_ptr = png_create_info_struct(png_ptr);
82 if (!info_ptr)
83 {
84 png_destroy_read_struct(&png_ptr, NULL, NULL);
85 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
86 goto close_file;
87 }
88 if (setjmp(png_jmpbuf(png_ptr)))
89 {
90 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
91 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
92 goto close_file;
93 }
94 png_init_io(png_ptr, f);
95 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
96 png_read_info(png_ptr, info_ptr);
97 png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
98 (png_uint_32 *) (&h32), &bit_depth, &color_type,
99 &interlace_type, NULL, NULL);
100 if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) ||
101 IMG_TOO_BIG(w32, h32))
102 {
103 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
104 if (IMG_TOO_BIG(w32, h32))
105 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
106 else
107 *error = EVAS_LOAD_ERROR_GENERIC;
108 goto close_file;
109 }
110 if (ie->load_opts.scale_down_by > 1)
111 {
112 ie->w = (int) w32 / ie->load_opts.scale_down_by;
113 ie->h = (int) h32 / ie->load_opts.scale_down_by;
114 if ((ie->w < 1) || (ie->h < 1))
115 {
116 *error = EVAS_LOAD_ERROR_GENERIC;
117 goto close_file;
118 }
119 }
120 else
121 {
122 ie->w = (int) w32;
123 ie->h = (int) h32;
124 }
125 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
126 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
127 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
128 if (hasa) ie->flags.alpha = 1;
129 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
130 E_FCLOSE(f);
131
132 *error = EVAS_LOAD_ERROR_NONE;
133 return EINA_TRUE;
134
135 close_file:
136 E_FCLOSE(f);
137 return EINA_FALSE;
138}
139
140static Eina_Bool
141evas_image_load_file_data_png(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
142{
143 unsigned char *surface;
144 png_uint_32 w32, h32;
145 int w, h;
146 FILE *f;
147 png_structp png_ptr = NULL;
148 png_infop info_ptr = NULL;
149 int bit_depth, color_type, interlace_type;
150 unsigned char buf[PNG_BYTES_TO_CHECK];
151 unsigned char **lines;
152 char hasa;
153 int i, j;
154 int scale_ratio = 1, image_w = 0;
155 unsigned char *tmp_line;
156 DATA32 *src_ptr, *dst_ptr;
157
158 hasa = 0;
159 f = E_FOPEN(file, "rb");
160 if (!f)
161 {
162 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
163 return EINA_FALSE;
164 }
165
166 /* if we havent read the header before, set the header data */
167 if (E_FREAD(buf, PNG_BYTES_TO_CHECK, 1, f) != 1)
168 {
169 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
170 goto close_file;
171 }
172 if (png_sig_cmp(buf, 0, PNG_BYTES_TO_CHECK))
173 {
174 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
175 goto close_file;
176 }
177 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
178 if (!png_ptr)
179 {
180 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
181 goto close_file;
182 }
183
184 info_ptr = png_create_info_struct(png_ptr);
185 if (!info_ptr)
186 {
187 png_destroy_read_struct(&png_ptr, NULL, NULL);
188 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
189 goto close_file;
190 }
191 if (setjmp(png_jmpbuf(png_ptr)))
192 {
193 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
194 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
195 goto close_file;
196 }
197 png_init_io(png_ptr, f);
198 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
199 png_read_info(png_ptr, info_ptr);
200 png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
201 (png_uint_32 *) (&h32), &bit_depth, &color_type,
202 &interlace_type, NULL, NULL);
203 image_w = w32;
204 if (ie->load_opts.scale_down_by > 1)
205 {
206 scale_ratio = ie->load_opts.scale_down_by;
207 w32 /= scale_ratio;
208 h32 /= scale_ratio;
209 }
210 evas_cache_image_surface_alloc(ie, w32, h32);
211 surface = (unsigned char *) evas_cache_image_pixels(ie);
212 if (!surface)
213 {
214 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
215 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
216 goto close_file;
217 }
218 if ((w32 != ie->w) || (h32 != ie->h))
219 {
220 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
221 *error = EVAS_LOAD_ERROR_GENERIC;
222 goto close_file;
223 }
224 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
225 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
226 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
227 if (hasa) ie->flags.alpha = 1;
228
229 /* Prep for transformations... ultimately we want ARGB */
230 /* expand palette -> RGB if necessary */
231 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr);
232 /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
233 if ((color_type == PNG_COLOR_TYPE_GRAY) ||
234 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
235 {
236 png_set_gray_to_rgb(png_ptr);
237 if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
238 }
239 /* expand transparency entry -> alpha channel if present */
240 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
241 png_set_tRNS_to_alpha(png_ptr);
242 /* reduce 16bit color -> 8bit color if necessary */
243 if (bit_depth > 8) png_set_strip_16(png_ptr);
244 /* pack all pixels to byte boundaries */
245 png_set_packing(png_ptr);
246
247 w = ie->w;
248 h = ie->h;
249 /* we want ARGB */
250#ifdef WORDS_BIGENDIAN
251 png_set_swap_alpha(png_ptr);
252 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE);
253#else
254 png_set_bgr(png_ptr);
255 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
256#endif
257
258 /* we read image line by line if scale down was set */
259 if (scale_ratio == 1)
260 {
261 lines = (unsigned char **) alloca(h * sizeof(unsigned char *));
262 for (i = 0; i < h; i++)
263 lines[i] = surface + (i * w * sizeof(DATA32));
264 png_read_image(png_ptr, lines);
265 png_read_end(png_ptr, info_ptr);
266 }
267 else
268 {
269 tmp_line = (unsigned char *) alloca(image_w * sizeof(DATA32));
270 dst_ptr = (DATA32 *)surface;
271 for (i = 0; i < h; i++)
272 {
273 png_read_row(png_ptr, tmp_line, NULL);
274 src_ptr = (DATA32 *)tmp_line;
275 for (j = 0; j < w; j++)
276 {
277 *dst_ptr = *src_ptr;
278 dst_ptr++;
279 src_ptr += scale_ratio;
280 }
281 for (j = 0; j < (scale_ratio - 1); j++)
282 {
283 png_read_row(png_ptr, tmp_line, NULL);
284 }
285 }
286 }
287
288 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
289 E_FCLOSE(f);
290 evas_common_image_premul(ie);
291
292 *error = EVAS_LOAD_ERROR_NONE;
293 return EINA_TRUE;
294
295 close_file:
296 E_FCLOSE(f);
297 return EINA_FALSE;
298}
299
300static int
301module_open(Evas_Module *em)
302{
303 if (!em) return 0;
304 em->functions = (void *)(&evas_image_load_png_func);
305 return 1;
306}
307
308static void
309module_close(Evas_Module *em __UNUSED__)
310{
311}
312
313static Evas_Module_Api evas_modapi =
314{
315 EVAS_MODULE_API_VERSION,
316 "png",
317 "none",
318 {
319 module_open,
320 module_close
321 }
322};
323
324EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, png);
325
326#ifndef EVAS_STATIC_BUILD_PNG
327EVAS_EINA_MODULE_DEFINE(image_loader, png);
328#endif