summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorCedric BAIL <cedric.bail@free.fr>2019-06-13 15:35:48 -0700
committerCedric BAIL <cedric.bail@free.fr>2019-07-12 09:54:18 -0700
commit382c58018272c6773a5e83ec4ee9f14b1318eab7 (patch)
tree640d631694d2ed5599638713c21e6cd6dcf39ba7 /src/modules
parent6a93e2ef3da17c8548d149535f2f39faf18fa46c (diff)
evas: add support for .9.png file to PNG loader.
This support Android 9 patch file format. Only black is a recognized color for both the stretch area and the content area. All other color are associated with being "white". Reviewed-by: Hermet Park <hermetpark@gmail.com> Differential Revision: https://phab.enlightenment.org/D9103
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/evas/image_loaders/png/evas_image_load_png.c625
1 files changed, 461 insertions, 164 deletions
diff --git a/src/modules/evas/image_loaders/png/evas_image_load_png.c b/src/modules/evas/image_loaders/png/evas_image_load_png.c
index 1460cc783d..4ffd5643c6 100644
--- a/src/modules/evas/image_loaders/png/evas_image_load_png.c
+++ b/src/modules/evas/image_loaders/png/evas_image_load_png.c
@@ -10,6 +10,8 @@
10#include "evas_private.h" 10#include "evas_private.h"
11 11
12#define PNG_BYTES_TO_CHECK 4 12#define PNG_BYTES_TO_CHECK 4
13#define WHITE 0xFFFFFFFF
14#define BLACK 0xFF000000
13 15
14typedef struct _Evas_PNG_Info Evas_PNG_Info; 16typedef struct _Evas_PNG_Info Evas_PNG_Info;
15struct _Evas_PNG_Info 17struct _Evas_PNG_Info
@@ -17,6 +19,13 @@ struct _Evas_PNG_Info
17 unsigned char *map; 19 unsigned char *map;
18 size_t length; 20 size_t length;
19 size_t position; 21 size_t position;
22
23 png_structp png_ptr;
24 png_infop info_ptr;
25 png_uint_32 w32, h32;
26 int bit_depth, color_type, interlace_type;
27
28 volatile Eina_Bool hasa;
20}; 29};
21 30
22typedef struct _Evas_Loader_Internal Evas_Loader_Internal; 31typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
@@ -37,6 +46,34 @@ static const Evas_Colorspace cspace_grey_alpha[2] = {
37}; 46};
38 47
39static void 48static void
49_evas_image_png_update_x_content(Eina_Rectangle *r, int index)
50{
51 if (r->x == 0)
52 {
53 r->x = index;
54 r->w = 1;
55 }
56 else
57 {
58 r->w = index - r->x;
59 }
60}
61
62static void
63_evas_image_png_update_y_content(Eina_Rectangle *r, int index)
64{
65 if (r->y == 0)
66 {
67 r->y = index;
68 r->h = 1;
69 }
70 else
71 {
72 r->h = index - r->y;
73 }
74}
75
76static void
40_evas_image_png_read(png_structp png_ptr, png_bytep out, png_size_t count) 77_evas_image_png_read(png_structp png_ptr, png_bytep out, png_size_t count)
41{ 78{
42 Evas_PNG_Info *epi = png_get_io_ptr(png_ptr); 79 Evas_PNG_Info *epi = png_get_io_ptr(png_ptr);
@@ -76,77 +113,65 @@ evas_image_load_file_close_png(void *loader_data)
76} 113}
77 114
78static Eina_Bool 115static Eina_Bool
79evas_image_load_file_head_png(void *loader_data, 116_evas_image_load_file_internal_head_png(Evas_Loader_Internal *loader,
80 Emile_Image_Property *prop, 117 Evas_Image_Property *prop,
81 int *error) 118 Evas_PNG_Info *epi,
119 int *error, Eina_Bool close_file)
82{ 120{
83 Evas_Loader_Internal *loader = loader_data; 121 Evas_Image_Load_Opts *opts = loader->opts;
84 Evas_Image_Load_Opts *opts; 122 Eina_File *f = loader->f;
85 Eina_File *f;
86
87 Evas_PNG_Info epi;
88 png_structp png_ptr = NULL;
89 png_infop info_ptr = NULL;
90 png_uint_32 w32, h32;
91 int bit_depth, color_type, interlace_type;
92 volatile char hasa;
93 volatile Eina_Bool r = EINA_FALSE; 123 volatile Eina_Bool r = EINA_FALSE;
94 124
95 opts = loader->opts; 125 *error = EVAS_LOAD_ERROR_NONE;
96 f = loader->f;
97 126
98 hasa = 0; 127 epi->hasa = 0;
99 epi.map = eina_file_map_all(f, EINA_FILE_RANDOM); 128 epi->map = eina_file_map_all(f, EINA_FILE_RANDOM);
100 if (!epi.map) 129 if (!epi->map)
101 { 130 {
102 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 131 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
103 goto close_file; 132 goto close_file;
104 } 133 }
105 epi.length = eina_file_size_get(f); 134 epi->length = eina_file_size_get(f);
106 epi.position = 0; 135 epi->position = 0;
107 136
108 if (epi.length < PNG_BYTES_TO_CHECK) 137 if (epi->length < PNG_BYTES_TO_CHECK)
109 { 138 {
110 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 139 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
111 goto close_file; 140 goto close_file;
112 } 141 }
113 142 if (png_sig_cmp(epi->map, 0, PNG_BYTES_TO_CHECK))
114 if (png_sig_cmp(epi.map, 0, PNG_BYTES_TO_CHECK))
115 { 143 {
116 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 144 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
117 goto close_file; 145 goto close_file;
118 } 146 }
119 147 epi->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
120 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 148 if (!epi->png_ptr)
121 if (!png_ptr)
122 { 149 {
123 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; 150 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
124 goto close_file; 151 goto close_file;
125 } 152 }
126 153 epi->info_ptr = png_create_info_struct(epi->png_ptr);
127 info_ptr = png_create_info_struct(png_ptr); 154 if (!epi->info_ptr)
128 if (!info_ptr)
129 { 155 {
130 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; 156 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
131 goto close_file; 157 goto close_file;
132 } 158 }
133 159 png_set_read_fn(epi->png_ptr, epi, _evas_image_png_read);
134 png_set_read_fn(png_ptr, &epi, _evas_image_png_read); 160 if (setjmp(png_jmpbuf(epi->png_ptr)))
135
136 if (setjmp(png_jmpbuf(png_ptr)))
137 { 161 {
138 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 162 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
139 goto close_file; 163 goto close_file;
140 } 164 }
141 165
142 png_read_info(png_ptr, info_ptr); 166 png_read_info(epi->png_ptr, epi->info_ptr);
143 png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), 167 png_get_IHDR(epi->png_ptr, epi->info_ptr, (png_uint_32 *) (&epi->w32),
144 (png_uint_32 *) (&h32), &bit_depth, &color_type, 168 (png_uint_32 *) (&epi->h32), &epi->bit_depth, &epi->color_type,
145 &interlace_type, NULL, NULL); 169 &epi->interlace_type, NULL, NULL);
146 if ((w32 < 1) || (h32 < 1) || (w32 > IMG_MAX_SIZE) || (h32 > IMG_MAX_SIZE) || 170 if ((epi->w32 < 1) || (epi->h32 < 1) ||
147 IMG_TOO_BIG(w32, h32)) 171 (epi->w32 > IMG_MAX_SIZE) || (epi->h32 > IMG_MAX_SIZE) ||
172 IMG_TOO_BIG(epi->w32, epi->h32))
148 { 173 {
149 if (IMG_TOO_BIG(w32, h32)) 174 if (IMG_TOO_BIG(epi->w32, epi->h32))
150 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; 175 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
151 else 176 else
152 *error = EVAS_LOAD_ERROR_GENERIC; 177 *error = EVAS_LOAD_ERROR_GENERIC;
@@ -155,28 +180,28 @@ evas_image_load_file_head_png(void *loader_data,
155 180
156 if (opts->emile.region.w > 0 && opts->emile.region.h > 0) 181 if (opts->emile.region.w > 0 && opts->emile.region.h > 0)
157 { 182 {
158 if (((int) w32 < opts->emile.region.x + opts->emile.region.w) || 183 if (((int) epi->w32 < opts->emile.region.x + opts->emile.region.w) ||
159 ((int) h32 < opts->emile.region.y + opts->emile.region.h)) 184 ((int) epi->h32 < opts->emile.region.y + opts->emile.region.h))
160 { 185 {
161 *error = EVAS_LOAD_ERROR_GENERIC; 186 *error = EVAS_LOAD_ERROR_GENERIC;
162 goto close_file; 187 goto close_file;
163 } 188 }
164 if(opts->emile.scale_down_by > 1) 189 if(opts->emile.scale_down_by > 1)
165 { 190 {
166 prop->w = opts->emile.region.w / opts->emile.scale_down_by; 191 prop->info.w = opts->emile.region.w / opts->emile.scale_down_by;
167 prop->h = opts->emile.region.h / opts->emile.scale_down_by; 192 prop->info.h = opts->emile.region.h / opts->emile.scale_down_by;
168 } 193 }
169 else 194 else
170 { 195 {
171 prop->w = opts->emile.region.w; 196 prop->info.w = opts->emile.region.w;
172 prop->h = opts->emile.region.h; 197 prop->info.h = opts->emile.region.h;
173 } 198 }
174 } 199 }
175 else if (opts->emile.scale_down_by > 1) 200 else if (opts->emile.scale_down_by > 1)
176 { 201 {
177 prop->w = (int) w32 / opts->emile.scale_down_by; 202 prop->info.w = (int) epi->w32 / opts->emile.scale_down_by;
178 prop->h = (int) h32 / opts->emile.scale_down_by; 203 prop->info.h = (int) epi->h32 / opts->emile.scale_down_by;
179 if ((prop->w < 1) || (prop->h < 1)) 204 if ((prop->info.w < 1) || (prop->info.h < 1))
180 { 205 {
181 *error = EVAS_LOAD_ERROR_GENERIC; 206 *error = EVAS_LOAD_ERROR_GENERIC;
182 goto close_file; 207 goto close_file;
@@ -184,191 +209,462 @@ evas_image_load_file_head_png(void *loader_data,
184 } 209 }
185 else 210 else
186 { 211 {
187 prop->w = (int) w32; 212 prop->info.w = (int) epi->w32;
188 prop->h = (int) h32; 213 prop->info.h = (int) epi->h32;
189 } 214 }
190 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1; 215 if (png_get_valid(epi->png_ptr, epi->info_ptr, PNG_INFO_tRNS)) epi->hasa = 1;
191 switch (color_type) 216 switch (epi->color_type)
192 { 217 {
193 case PNG_COLOR_TYPE_RGB_ALPHA: 218 case PNG_COLOR_TYPE_RGB_ALPHA:
194 hasa = 1; 219 epi->hasa = 1;
195 break; 220 break;
196 case PNG_COLOR_TYPE_GRAY_ALPHA: 221 case PNG_COLOR_TYPE_GRAY_ALPHA:
197 hasa = 1; 222 epi->hasa = 1;
198 prop->cspaces = cspace_grey_alpha; 223 prop->info.cspaces = cspace_grey_alpha;
199 break; 224 break;
200 case PNG_COLOR_TYPE_GRAY: 225 case PNG_COLOR_TYPE_GRAY:
201 if (!hasa) prop->cspaces = cspace_grey; 226 if (!epi->hasa) prop->info.cspaces = cspace_grey;
202 break; 227 break;
203 } 228 }
204 if (hasa) prop->alpha = 1; 229 if (epi->hasa) prop->info.alpha = 1;
230
231 prop->need_data = eina_str_has_extension(eina_file_filename_get(f), ".9.png");
232 if (prop->need_data)
233 {
234 // Adjust size to take into account the 9 patch pixels information
235 prop->info.w -= 2;
236 prop->info.h -= 2;
237 }
205 238
206 *error = EVAS_LOAD_ERROR_NONE;
207 r = EINA_TRUE; 239 r = EINA_TRUE;
208 240
241 if (!close_file) return r;
242
209 close_file: 243 close_file:
210 if (png_ptr) png_destroy_read_struct(&png_ptr, 244 if (epi->png_ptr) png_destroy_read_struct(&epi->png_ptr,
211 info_ptr ? &info_ptr : NULL, 245 epi->info_ptr ? &epi->info_ptr : NULL,
212 NULL); 246 NULL);
213 if (epi.map) eina_file_map_free(f, epi. map); 247 if (epi->map) eina_file_map_free(f, epi->map);
248 memset(epi, 0, sizeof (Evas_PNG_Info));
214 249
215 return r; 250 return r;
216} 251}
217 252
218static Eina_Bool 253static Eina_Bool
219evas_image_load_file_data_png(void *loader_data, 254evas_image_load_file_head_png(void *loader_data,
220 Emile_Image_Property *prop, 255 Evas_Image_Property *prop,
221 void *pixels,
222 int *error) 256 int *error)
223{ 257{
224 Evas_Loader_Internal *loader = loader_data; 258 Evas_Loader_Internal *loader = loader_data;
259 Evas_PNG_Info epi;
260
261 memset(&epi, 0, sizeof (Evas_PNG_Info));
262
263 if (!_evas_image_load_file_internal_head_png(loader, prop, &epi, error, EINA_TRUE))
264 return EINA_FALSE;
265
266 return EINA_TRUE;
267}
268
269static inline Eina_Bool
270_is_black(DATA32 *ptr)
271{
272 if (*ptr == BLACK) return EINA_TRUE;
273 return EINA_FALSE;
274}
275
276static Eina_Bool
277evas_image_load_file_head_with_data_png(void *loader_data,
278 Evas_Image_Property *prop,
279 void *pixels,
280 int *error)
281{
282 Evas_Loader_Internal *loader = loader_data;
225 Evas_Image_Load_Opts *opts; 283 Evas_Image_Load_Opts *opts;
226 Eina_File *f; 284 Eina_File *f;
227 285
286 unsigned char *src_ptr;
287 unsigned char *pixels2;
228 unsigned char *surface; 288 unsigned char *surface;
229 png_structp png_ptr = NULL;
230 png_infop info_ptr = NULL;
231 Evas_PNG_Info epi; 289 Evas_PNG_Info epi;
232 png_uint_32 w32, h32; 290 Eina_Rectangle region;
233 unsigned int pack_offset; 291 unsigned int pack_offset;
234 int w, h; 292 int w, h;
235 int bit_depth, color_type, interlace_type;
236 volatile char hasa;
237 char passes; 293 char passes;
238 int i, j, p, k; 294 int i, j, p, k;
239 volatile int scale_ratio = 1; 295 volatile int scale_ratio = 1;
240 volatile int region_set = 0;
241 int image_w = 0, image_h = 0; 296 int image_w = 0, image_h = 0;
242 volatile Eina_Bool r = EINA_FALSE; 297 volatile Eina_Bool r = EINA_FALSE;
298 Eina_Bool nine_patch = EINA_FALSE;
243 299
244 opts = loader->opts; 300 opts = loader->opts;
245 f = loader->f; 301 f = loader->f;
246 302
247 hasa = 0; 303 memset(&epi, 0, sizeof (Evas_PNG_Info));
304 region = opts->emile.region;
305
306 if (!_evas_image_load_file_internal_head_png(loader, prop, &epi, error, EINA_FALSE))
307 return EINA_FALSE;
308
309 image_w = epi.w32;
310 image_h = epi.h32;
248 311
249 epi.map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); 312 // We are leveragging region code to not load the border information pixels
250 if (!epi.map) 313 // from 9patch files into the surface used by Evas
314 if (prop->need_data)
251 { 315 {
252 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 316 nine_patch = EINA_TRUE;
253 goto close_file; 317
318 region.x += 1;
319 region.y += 1;
320
321 if (region.w > 0 && region.h > 0)
322 {
323 if (region.x + region.w + 1 < image_w) region.w += 1;
324 else region.w = image_w - region.x - 1;
325 if (region.y + region.h + 1 < image_h) region.h += 1;
326 else region.h = image_h - region.y - 1;
327 }
328 else
329 {
330 region.w = image_w - region.x - 1;
331 region.h = image_h - region.y - 1;
332 }
254 } 333 }
255 epi.length = eina_file_size_get(f);
256 epi.position = 0;
257 334
258 if (epi.length < PNG_BYTES_TO_CHECK) 335 surface = pixels;
336
337 /* Prep for transformations... ultimately we want ARGB */
338 /* expand palette -> RGB if necessary */
339 if (epi.color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(epi.png_ptr);
340 /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
341 if ((epi.color_type == PNG_COLOR_TYPE_GRAY) ||
342 (epi.color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
259 { 343 {
260 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 344 if (prop->info.cspace == EVAS_COLORSPACE_ARGB8888)
345 png_set_gray_to_rgb(epi.png_ptr);
346 if (epi.bit_depth < 8) png_set_expand_gray_1_2_4_to_8(epi.png_ptr);
347 }
348 /* reduce 16bit color -> 8bit color if necessary */
349 if (epi.bit_depth > 8) png_set_strip_16(epi.png_ptr);
350 /* pack all pixels to byte boundaries */
351 png_set_packing(epi.png_ptr);
352
353 w = prop->info.w;
354 h = prop->info.h;
355
356 switch (prop->info.cspace)
357 {
358 case EVAS_COLORSPACE_ARGB8888:
359 /* we want ARGB */
360#ifdef WORDS_BIGENDIAN
361 png_set_swap_alpha(epi.png_ptr);
362 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_BEFORE);
363#else
364 png_set_bgr(epi.png_ptr);
365 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_AFTER);
366#endif
367 pack_offset = sizeof(DATA32);
368 break;
369 case EVAS_COLORSPACE_AGRY88:
370 /* we want AGRY */
371#ifdef WORDS_BIGENDIAN
372 png_set_swap_alpha(epi.png_ptr);
373 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_BEFORE);
374#else
375 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_AFTER);
376#endif
377 pack_offset = sizeof(DATA16);
378 break;
379 case EVAS_COLORSPACE_GRY8: pack_offset = sizeof(DATA8); break;
380 default: abort();
381 }
382
383 passes = png_set_interlace_handling(epi.png_ptr);
384
385 /* we read image line by line in all case because of .9.png */
386 pixels2 = malloc(image_w * image_h * pack_offset);
387 if (!pixels2)
388 {
389 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
261 goto close_file; 390 goto close_file;
262 } 391 }
263 392
264 /* if we havent read the header before, set the header data */ 393 for (p = 0; p < passes; p++)
265 if (png_sig_cmp(epi.map, 0, PNG_BYTES_TO_CHECK))
266 { 394 {
267 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 395 for (i = 0; i < image_h; i++)
268 goto close_file; 396 png_read_row(epi.png_ptr, pixels2 + (i * image_w * pack_offset), NULL);
269 } 397 }
270 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 398 png_read_end(epi.png_ptr, epi.info_ptr);
271 if (!png_ptr) 399
400 if (nine_patch && pack_offset != sizeof (DATA32))
272 { 401 {
273 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; 402 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
274 goto close_file; 403 goto close_file;
275 } 404 }
276 405
277 info_ptr = png_create_info_struct(png_ptr); 406 if (nine_patch)
278 if (!info_ptr)
279 { 407 {
280 png_destroy_read_struct(&png_ptr, NULL, NULL); 408 DATA32 *src_ptr1;
281 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; 409 DATA32 *src_ptr2;
282 goto close_file; 410 Eina_Bool stretchable = EINA_FALSE;
411 Eina_Rectangle optional_content = { 0 };
412 uint8_t current = 0;
413
414 memset(&prop->content, 0, sizeof (Eina_Rectangle));
415
416 // Top line of the image
417 src_ptr1 = (DATA32*) pixels2 + 1;
418 // Bottom line of the image
419 src_ptr2 = src_ptr1 + (image_h - 1) * image_w;
420
421 // Extract top stretch zone and horizontal content area
422 for (i = 1; i < image_w - 1;
423 i++, src_ptr1++, src_ptr2++)
424 {
425 Eina_Bool bp1 = _is_black(src_ptr1);
426 Eina_Bool bp2 = _is_black(src_ptr2);
427
428 // Updating horizontal area where content can be located
429 if (bp2)
430 _evas_image_png_update_x_content(&prop->content, i);
431
432 // In case no content area is provided, let's make it up
433 if (bp1)
434 _evas_image_png_update_x_content(&optional_content, i);
435
436 // Switching from a non stretchable to a stretchable zone or the opposite
437 if (!((stretchable && (bp1)) ||
438 (!stretchable && (!bp1))))
439 {
440 evas_loader_helper_stretch_region_push(&prop->stretch.horizontal.region,
441 &current, stretchable);
442 stretchable = !stretchable;
443 }
444
445 // Keep counting in the area we are in
446 current++;
447
448 if (current != 0x7F) continue;
449
450 // The bucket is full
451 evas_loader_helper_stretch_region_push(&prop->stretch.horizontal.region,
452 &current, stretchable);
453 }
454
455 current = 0;
456
457 // Left border of the image
458 src_ptr1 = (DATA32*) pixels2 + image_w;
459 // Right border of the image
460 src_ptr2 = src_ptr1 + (image_w - 1);
461
462 for (i = 1; i < image_h - 1;
463 i++, src_ptr1 += image_w, src_ptr2 += image_w)
464 {
465 Eina_Bool bp1 = _is_black(src_ptr1);
466 Eina_Bool bp2 = _is_black(src_ptr2);
467
468 // Updating vertical area where content can be located
469 if (bp2)
470 _evas_image_png_update_y_content(&prop->content, i);
471
472 // In case no content area is provided, let's make it up
473 if (bp1)
474 _evas_image_png_update_y_content(&optional_content, i);
475
476 // Switching from a non stretchable to a stretchable zone or the opposite
477 if (!((stretchable && (bp1)) ||
478 (!stretchable && (!bp1))))
479 {
480 evas_loader_helper_stretch_region_push(&prop->stretch.vertical.region,
481 &current, stretchable);
482 stretchable = !stretchable;
483 }
484
485 // Keep counting in the area we are in
486 current++;
487
488 if (current != 0x7F) continue;
489
490 // The bucket is full
491 evas_loader_helper_stretch_region_push(&prop->stretch.vertical.region,
492 &current, stretchable);
493 }
494
495 // Content zone is optional, if not provided, we should use the one we guessed
496 if (prop->content.x == 0 || prop->content.y == 0)
497 memcpy(&prop->content, &optional_content, sizeof (Eina_Rectangle));
498
499 // Check that the limit of our content zone are correct
500 // This could be handled as an incorrect file completly,
501 // but let's try to recover
502 if (prop->content.x == 0 || prop->content.y == 0)
503 {
504 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
505 goto close_file;
506 }
507 if ((prop->content.x + prop->content.w >= image_w - 1) &&
508 (prop->content.y + prop->content.h >= image_h - 1))
509 {
510 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
511 goto close_file;
512 }
513
514 // Correct the work space to be the same as the image one for intersection
515 // with region and correct back afterward.
516 prop->content.x++;
517 prop->content.y++;
518 if (eina_rectangle_intersection(&prop->content, &region))
519 {
520 prop->content.x--;
521 prop->content.y--;
522 }
283 } 523 }
284 524
285 png_set_read_fn(png_ptr, &epi, _evas_image_png_read); 525 src_ptr = pixels2 + (region.y * image_w * pack_offset) + region.x * pack_offset;
286 526
287 if (setjmp(png_jmpbuf(png_ptr))) 527 //general case: 4 bytes pixel.
528 if (pack_offset == sizeof(DATA32))
288 { 529 {
289 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); 530 DATA32 *dst_ptr = (DATA32 *) surface;
290 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 531 DATA32 *src_ptr2 = (DATA32 *) src_ptr;
291 goto close_file; 532
533 for (i = 0; i < h; i++)
534 {
535 for (j = 0; j < w; j++)
536 {
537 *dst_ptr = *src_ptr2;
538 ++dst_ptr;
539 src_ptr2 += scale_ratio;
540 }
541 src_ptr2 += scale_ratio * (image_w - w);
542 }
292 } 543 }
544 else
545 {
546 unsigned char *dst_ptr = surface;
547
548 for (i = 0; i < h; i++)
549 {
550 for (j = 0; j < w; j++)
551 {
552 for (k = 0; k < (int)pack_offset; k++)
553 dst_ptr[k] = src_ptr[k + scale_ratio * j * pack_offset];
554 dst_ptr += pack_offset;
555 }
556 src_ptr += scale_ratio * (image_w - w) * pack_offset;
557 }
558 }
559 free(pixels2);
560
561 prop->info.premul = EINA_TRUE;
562
563 *error = EVAS_LOAD_ERROR_NONE;
564 r = EINA_TRUE;
565
566 close_file:
567 if (epi.png_ptr) png_destroy_read_struct(&epi.png_ptr,
568 epi.info_ptr ? &epi.info_ptr : NULL,
569 NULL);
570 if (epi.map) eina_file_map_free(f, epi.map);
571 return r;
572}
573
574static Eina_Bool
575evas_image_load_file_data_png(void *loader_data,
576 Evas_Image_Property *prop,
577 void *pixels,
578 int *error)
579{
580 Evas_Loader_Internal *loader = loader_data;
581 Evas_Image_Load_Opts *opts;
582 Eina_File *f;
293 583
294 png_read_info(png_ptr, info_ptr); 584 unsigned char *surface;
295 png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32), 585 Evas_PNG_Info epi;
296 (png_uint_32 *) (&h32), &bit_depth, &color_type, 586 unsigned int pack_offset;
297 &interlace_type, NULL, NULL); 587 int w, h;
298 image_w = w32; 588 char passes;
299 image_h = h32; 589 int i, j, p, k;
590 volatile int scale_ratio = 1;
591 volatile int region_set = 0;
592 int image_w = 0, image_h = 0;
593 volatile Eina_Bool r = EINA_FALSE;
594
595 opts = loader->opts;
596 f = loader->f;
597
598 memset(&epi, 0, sizeof (Evas_PNG_Info));
599
600 if (!_evas_image_load_file_internal_head_png(loader, prop, &epi, error, EINA_FALSE))
601 return EINA_FALSE;
602
603 image_w = epi.w32;
604 image_h = epi.h32;
300 if (opts->emile.scale_down_by > 1) 605 if (opts->emile.scale_down_by > 1)
301 { 606 {
302 scale_ratio = opts->emile.scale_down_by; 607 scale_ratio = opts->emile.scale_down_by;
303 w32 /= scale_ratio; 608 epi.w32 /= scale_ratio;
304 h32 /= scale_ratio; 609 epi.h32 /= scale_ratio;
305 } 610 }
306 611
307 if ((opts->emile.region.w > 0 && opts->emile.region.h > 0) && 612 if ((opts->emile.region.w > 0 && opts->emile.region.h > 0) &&
308 (opts->emile.region.w != image_w || opts->emile.region.h != image_h)) 613 (opts->emile.region.w != image_w || opts->emile.region.h != image_h))
309 { 614 {
310 w32 = opts->emile.region.w / scale_ratio; 615 epi.w32 = opts->emile.region.w / scale_ratio;
311 h32 = opts->emile.region.h / scale_ratio; 616 epi.h32 = opts->emile.region.h / scale_ratio;
312 region_set = 1; 617 region_set = 1;
313 } 618 }
314 619
315 if (prop->w != w32 || 620 if (prop->info.w != epi.w32 ||
316 prop->h != h32) 621 prop->info.h != epi.h32)
317 { 622 {
318 *error = EVAS_LOAD_ERROR_GENERIC; 623 *error = EVAS_LOAD_ERROR_GENERIC;
319 goto close_file; 624 goto close_file;
320 } 625 }
321 626
322 surface = pixels; 627 surface = pixels;
323 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
324 {
325 /* expand transparency entry -> alpha channel if present */
326 png_set_tRNS_to_alpha(png_ptr);
327 hasa = 1;
328 }
329 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
330 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
331 if (hasa) prop->alpha = 1;
332 628
333 /* Prep for transformations... ultimately we want ARGB */ 629 /* Prep for transformations... ultimately we want ARGB */
334 /* expand palette -> RGB if necessary */ 630 /* expand palette -> RGB if necessary */
335 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png_ptr); 631 if (epi.color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(epi.png_ptr);
336 /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */ 632 /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
337 if ((color_type == PNG_COLOR_TYPE_GRAY) || 633 if ((epi.color_type == PNG_COLOR_TYPE_GRAY) ||
338 (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) 634 (epi.color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
339 { 635 {
340 if (prop->cspace == EVAS_COLORSPACE_ARGB8888) 636 if (prop->info.cspace == EVAS_COLORSPACE_ARGB8888)
341 png_set_gray_to_rgb(png_ptr); 637 png_set_gray_to_rgb(epi.png_ptr);
342 if (bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); 638 if (epi.bit_depth < 8) png_set_expand_gray_1_2_4_to_8(epi.png_ptr);
343 } 639 }
344 /* reduce 16bit color -> 8bit color if necessary */ 640 /* reduce 16bit color -> 8bit color if necessary */
345 if (bit_depth > 8) png_set_strip_16(png_ptr); 641 if (epi.bit_depth > 8) png_set_strip_16(epi.png_ptr);
346 /* pack all pixels to byte boundaries */ 642 /* pack all pixels to byte boundaries */
347 png_set_packing(png_ptr); 643 png_set_packing(epi.png_ptr);
348 644
349 w = w32; 645 w = epi.w32;
350 h = h32; 646 h = epi.h32;
351 647
352 switch (prop->cspace) 648 switch (prop->info.cspace)
353 { 649 {
354 case EVAS_COLORSPACE_ARGB8888: 650 case EVAS_COLORSPACE_ARGB8888:
355 /* we want ARGB */ 651 /* we want ARGB */
356#ifdef WORDS_BIGENDIAN 652#ifdef WORDS_BIGENDIAN
357 png_set_swap_alpha(png_ptr); 653 png_set_swap_alpha(epi.png_ptr);
358 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); 654 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_BEFORE);
359#else 655#else
360 png_set_bgr(png_ptr); 656 png_set_bgr(epi.png_ptr);
361 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 657 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_AFTER);
362#endif 658#endif
363 pack_offset = sizeof(DATA32); 659 pack_offset = sizeof(DATA32);
364 break; 660 break;
365 case EVAS_COLORSPACE_AGRY88: 661 case EVAS_COLORSPACE_AGRY88:
366 /* we want AGRY */ 662 /* we want AGRY */
367#ifdef WORDS_BIGENDIAN 663#ifdef WORDS_BIGENDIAN
368 png_set_swap_alpha(png_ptr); 664 png_set_swap_alpha(epi.png_ptr);
369 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_BEFORE); 665 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_BEFORE);
370#else 666#else
371 if (!hasa) png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 667 if (!epi.hasa) png_set_filler(epi.png_ptr, 0xff, PNG_FILLER_AFTER);
372#endif 668#endif
373 pack_offset = sizeof(DATA16); 669 pack_offset = sizeof(DATA16);
374 break; 670 break;
@@ -376,7 +672,7 @@ evas_image_load_file_data_png(void *loader_data,
376 default: abort(); 672 default: abort();
377 } 673 }
378 674
379 passes = png_set_interlace_handling(png_ptr); 675 passes = png_set_interlace_handling(epi.png_ptr);
380 676
381 /* we read image line by line if scale down was set */ 677 /* we read image line by line if scale down was set */
382 if (scale_ratio == 1 && region_set == 0) 678 if (scale_ratio == 1 && region_set == 0)
@@ -384,9 +680,9 @@ evas_image_load_file_data_png(void *loader_data,
384 for (p = 0; p < passes; p++) 680 for (p = 0; p < passes; p++)
385 { 681 {
386 for (i = 0; i < h; i++) 682 for (i = 0; i < h; i++)
387 png_read_row(png_ptr, surface + (i * w * pack_offset), NULL); 683 png_read_row(epi.png_ptr, surface + (i * w * pack_offset), NULL);
388 } 684 }
389 png_read_end(png_ptr, info_ptr); 685 png_read_end(epi.png_ptr, epi.info_ptr);
390 } 686 }
391 else 687 else
392 { 688 {
@@ -409,9 +705,9 @@ evas_image_load_file_data_png(void *loader_data,
409 unsigned short *pbuf; 705 unsigned short *pbuf;
410 706
411 for (skip_row = 0; skip_row < region_y; skip_row++) 707 for (skip_row = 0; skip_row < region_y; skip_row++)
412 png_read_row(png_ptr, tmp_line, NULL); 708 png_read_row(epi.png_ptr, tmp_line, NULL);
413 709
414 png_read_row(png_ptr, tmp_line, NULL); 710 png_read_row(epi.png_ptr, tmp_line, NULL);
415 src_ptr = tmp_line + (region_x * pack_offset); 711 src_ptr = tmp_line + (region_x * pack_offset);
416 712
417 //The first pixel, of the first line 713 //The first pixel, of the first line
@@ -450,7 +746,7 @@ evas_image_load_file_data_png(void *loader_data,
450 //vertical interpolation. 746 //vertical interpolation.
451 for (j = 0; j < scale_ratio; j++) 747 for (j = 0; j < scale_ratio; j++)
452 { 748 {
453 png_read_row(png_ptr, tmp_line, NULL); 749 png_read_row(epi.png_ptr, tmp_line, NULL);
454 src_ptr = tmp_line + (region_x * pack_offset); 750 src_ptr = tmp_line + (region_x * pack_offset);
455 751
456 for (p = 0; p < line_size; ++p) 752 for (p = 0; p < line_size; ++p)
@@ -486,7 +782,7 @@ evas_image_load_file_data_png(void *loader_data,
486 } 782 }
487 783
488 for (skip_row = region_y + h * scale_ratio; skip_row < image_h; skip_row++) 784 for (skip_row = region_y + h * scale_ratio; skip_row < image_h; skip_row++)
489 png_read_row(png_ptr, tmp_line, NULL); 785 png_read_row(epi.png_ptr, tmp_line, NULL);
490 } 786 }
491 else 787 else
492 { 788 {
@@ -499,8 +795,9 @@ evas_image_load_file_data_png(void *loader_data,
499 for (p = 0; p < passes; p++) 795 for (p = 0; p < passes; p++)
500 { 796 {
501 for (i = 0; i < image_h; i++) 797 for (i = 0; i < image_h; i++)
502 png_read_row(png_ptr, pixels2 + (i * image_w * pack_offset), NULL); 798 png_read_row(epi.png_ptr, pixels2 + (i * image_w * pack_offset), NULL);
503 } 799 }
800 png_read_end(epi.png_ptr, epi.info_ptr);
504 801
505 src_ptr = pixels2 + (region_y * image_w * pack_offset) + region_x * pack_offset; 802 src_ptr = pixels2 + (region_y * image_w * pack_offset) + region_x * pack_offset;
506 803
@@ -541,15 +838,15 @@ evas_image_load_file_data_png(void *loader_data,
541 } 838 }
542 } 839 }
543 840
544 prop->premul = EINA_TRUE; 841 prop->info.premul = EINA_TRUE;
545 842
546 *error = EVAS_LOAD_ERROR_NONE; 843 *error = EVAS_LOAD_ERROR_NONE;
547 r = EINA_TRUE; 844 r = EINA_TRUE;
548 845
549 close_file: 846 close_file:
550 if (png_ptr) png_destroy_read_struct(&png_ptr, 847 if (epi.png_ptr) png_destroy_read_struct(&epi.png_ptr,
551 info_ptr ? &info_ptr : NULL, 848 epi.info_ptr ? &epi.info_ptr : NULL,
552 NULL); 849 NULL);
553 if (epi.map) eina_file_map_free(f, epi.map); 850 if (epi.map) eina_file_map_free(f, epi.map);
554 return r; 851 return r;
555} 852}
@@ -559,9 +856,9 @@ static Evas_Image_Load_Func evas_image_load_png_func =
559 EVAS_IMAGE_LOAD_VERSION, 856 EVAS_IMAGE_LOAD_VERSION,
560 evas_image_load_file_open_png, 857 evas_image_load_file_open_png,
561 evas_image_load_file_close_png, 858 evas_image_load_file_close_png,
562 (void*) evas_image_load_file_head_png, 859 evas_image_load_file_head_png,
563 NULL, 860 evas_image_load_file_head_with_data_png,
564 (void*) evas_image_load_file_data_png, 861 evas_image_load_file_data_png,
565 NULL, 862 NULL,
566 EINA_TRUE, 863 EINA_TRUE,
567 EINA_FALSE 864 EINA_FALSE