diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/evas/src/modules/loaders/png/evas_image_load_png.c | 328 |
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 | |||
30 | static 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); | ||
31 | static 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 | |||
33 | static 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 | |||
41 | static Eina_Bool | ||
42 | evas_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 | |||
140 | static Eina_Bool | ||
141 | evas_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 | |||
300 | static int | ||
301 | module_open(Evas_Module *em) | ||
302 | { | ||
303 | if (!em) return 0; | ||
304 | em->functions = (void *)(&evas_image_load_png_func); | ||
305 | return 1; | ||
306 | } | ||
307 | |||
308 | static void | ||
309 | module_close(Evas_Module *em __UNUSED__) | ||
310 | { | ||
311 | } | ||
312 | |||
313 | static 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 | |||
324 | EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, png); | ||
325 | |||
326 | #ifndef EVAS_STATIC_BUILD_PNG | ||
327 | EVAS_EINA_MODULE_DEFINE(image_loader, png); | ||
328 | #endif | ||