*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
-
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world.
+ * But there are many bit count(bit per pixel) type in BMP format.
+ * Generally, 1,2,4,8 bit count have row risk of memory problem,
+ * so I add scale down feature only when bit count is 16 or 24 or 32 */
+ if (ie->load_opts.scale_down_by > 1)
+ {
+ if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
+ {
+ w /= ie->load_opts.scale_down_by;
+ h /= ie->load_opts.scale_down_by;
+ }
+ }
+
if (bit_count < 16)
{
if ((palette_size < 0) || (palette_size > 256)) pal_num = 256;
char hasa = 0;
int x = 0, y = 0, w = 0, h = 0, planes = 0, bit_count = 0, image_size = 0,
comp = 0, hdpi = 0, vdpi = 0, palette_size = -1, important_colors = 0;
+ int scale_ratio = 1, image_w = 0, image_h = 0;
unsigned int offset = 0, head_size = 0;
unsigned int *pal = NULL, pal_num = 0, *pix = NULL, *surface = NULL, fix,
rmask = 0, gmask = 0, bmask = 0, amask = 0;
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
-
+ /* It is not bad idea that bmp loader support scale down decoding
+ * because of memory issue in mobile world.
+ * But there are many bit count(bit per pixel) type in BMP format.
+ * Generally, 1,2,4,8 bit count have row risk of memory problem,
+ * so I add scale down feature only when bit count is 16 or 24 or 32 */
+ if(ie->load_opts.scale_down_by > 1)
+ {
+ if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
+ scale_ratio = ie->load_opts.scale_down_by;
+ }
+
+ if (scale_ratio > 1)
+ {
+ image_w = w;
+ image_h = h;
+ w /= scale_ratio;
+ h /= scale_ratio;
+
+ if ((w < 1) || (h < 1) )
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ }
+
if ((w != (int)ie->w) || (h != (int)ie->h))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
- evas_cache_image_surface_alloc(ie, w, h);
+ evas_cache_image_surface_alloc(ie, ie->w, ie->h);
surface = evas_cache_image_pixels(ie);
if (!surface)
{
}
else if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
{
+ /* Row size is rounded up to a multiple of 4bytes */
+ int row_size = 0;
+ int read_line = 0; /* total read line */
+
+ row_size = ceil((double)(image_w * bit_count) / 32) * 4;
if (comp == 0) // no compression
{
fseek(f, offset, SEEK_SET);
- buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
if (!buffer)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
- buffer_end = buffer + image_size;
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
p = buffer;
- if (fread(buffer, image_size, 1, f) != 1) goto close_file;
+ if (scale_ratio == 1)
+ {
+ if (fread(buffer, image_size, 1, f) != 1) goto close_file;
+ }
+ else
+ {
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ }
if (bit_count == 16)
{
unsigned short tmp;
-
+
pix = surface;
for (y = 0; y < h; y++)
{
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
- p += 2;
+ if (scale_ratio > 1)
+ p += 2 * scale_ratio;
+ else
+ p += 2;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
}
else if (bit_count == 24)
g = p[1];
r = p[2];
*pix = ARGB_JOIN(0xff, r, g, b);
- p += 3;
+ if (scale_ratio > 1)
+ p += 3 * scale_ratio;
+ else
+ p += 3;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
}
else if (bit_count == 32)
if (a) none_zero_alpha = 1;
if (!hasa) a = 0xff;
*pix = ARGB_JOIN(a, r, g, b);
- p += 4;
+ if (scale_ratio > 1)
+ p += 4 * scale_ratio;
+ else
+ p += 4;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
if (!none_zero_alpha)
{
if (!read_uint(f, &bmask)) goto close_file;
fseek(f, offset, SEEK_SET);
- buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+
+ if (scale_ratio == 1)
+ buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
+ else
+ buffer = malloc(row_size); // scale down is usually set because of memory issue, so read line by line
+
if (!buffer)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
- buffer_end = buffer + image_size;
+ if (scale_ratio == 1)
+ buffer_end = buffer + image_size;
+ else
+ buffer_end = buffer + row_size;
+
p = buffer;
- if (fread(buffer, image_size, 1, f) != 1) goto close_file;
+ if (scale_ratio == 1)
+ {
+ if (fread(buffer, image_size, 1, f) != 1) goto close_file;
+ }
+ else
+ {
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ }
+
if ((bit_count == 16) &&
(rmask == 0xf800) && (gmask == 0x07e0) && (bmask == 0x001f)
)
g = (tmp >> 3) & 0xfc; g |= g >> 6;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
- p += 2;
+ if (scale_ratio > 1)
+ p += 2 * scale_ratio;
+ else
+ p += 2;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
}
else if ((bit_count == 16) &&
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
- p += 2;
+ if (scale_ratio > 1)
+ p += 2 * scale_ratio;
+ else
+ p += 2;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
}
else if (bit_count == 32)
a = p[3];
if (!hasa) a = 0xff;
*pix = ARGB_JOIN(a, r, g, b);
- p += 4;
+ if (scale_ratio > 1)
+ p += 4 * scale_ratio;
+ else
+ p += 4;
if (p >= buffer_end) break;
pix++;
}
- fix = (int)(((unsigned long)p) & 0x3);
- if (fix > 0) p += 4 - fix; // align row read
- if (p >= buffer_end) break;
+ if (scale_ratio > 1)
+ {
+ read_line += scale_ratio;
+ if (read_line >= image_h) break;
+ fseek(f, row_size * (scale_ratio - 1), SEEK_CUR);
+ if (fread(buffer, row_size, 1, f) != 1) goto close_file;
+ p = buffer;
+ buffer_end = buffer + row_size;
+ }
+ else
+ {
+ fix = (int)(((unsigned long)p) & 0x3);
+ if (fix > 0) p += 4 - fix; // align row read
+ if (p >= buffer_end) break;
+ }
}
}
else
static Eina_Bool
_evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error)
{
- int w;
- int h;
- int x;
- int y;
- int i,j;
+ int w, h, x, y;
+ int i, j;
int bg;
- int r;
- int g;
- int b;
+ int r, g, b;
int alpha;
- double per;
- double per_inc;
+ double per, per_inc;
ColorMapObject *cmap;
GifRowType *rows;
+ GifRowType *tmp; /*for skip gif line */
int intoffset[] = { 0, 4, 2, 1 };
int intjump[] = { 8, 8, 4, 2 };
size_t siz;
- int cache_w;
- int cache_h;
- int cur_h;
- int cur_w;
+ int cache_w, cache_h, cur_w, cur_h;
int disposal = 0;
int bg_val = 0;
DATA32 *ptr;
Gif_Frame *gif_frame = NULL;
+ /* for scale down decoding */
+ int scale_ratio = 1;
+ int scale_w, scale_h, scale_x, scale_y;
if ((!gif) || (!frame)) return EINA_FALSE;
cache_w = ie->w;
cache_h = ie->h;
- rows = malloc(h * sizeof(GifRowType *));
+ /* if user don't set scale down, default scale_ratio is 1 */
+ if (ie->load_opts.scale_down_by > 1) scale_ratio = ie->load_opts.scale_down_by;
+ scale_w = w / scale_ratio;
+ scale_h = h / scale_ratio;
+ scale_x = x / scale_ratio;
+ scale_y = y / scale_ratio;
+
+ if (scale_ratio > 1)
+ {
+ tmp = malloc(w * sizeof(GifPixelType));
+ if (!tmp)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+ }
+
+ rows = malloc(scale_h * sizeof(GifRowType *));
+
if (!rows)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
return EINA_FALSE;
}
- for (i = 0; i < h; i++)
+
+ for (i = 0; i < scale_h; i++)
{
rows[i] = NULL;
}
- for (i = 0; i < h; i++)
+ /* alloc memory according to scaled size */
+ for (i = 0; i < scale_h; i++)
{
rows[i] = malloc(w * sizeof(GifPixelType));
if (!rows[i])
{
- for (i = 0; i < h; i++)
+ for (i = 0; i < scale_h; i++)
{
if (rows[i])
{
{
for (j = intoffset[i]; j < h; j += intjump[i])
{
- DGifGetLine(gif, rows[j], w);
+ if ((j % scale_ratio) == 0)
+ DGifGetLine(gif, rows[(j / scale_ratio)], w);
+ else
+ DGifGetLine(gif, tmp, w);
}
}
}
else
{
- for (i = 0; i < h; i++)
+ for (i = 0; i < scale_h; i++)
{
if (DGifGetLine(gif, rows[i], w) != GIF_OK)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto error;
- }
+ }
+ if (scale_ratio > 1)
+ {
+ /* we use down sample method for scale down, so skip other line */
+ for (j = 0; j < (scale_ratio - 1); j++)
+ {
+ if (DGifGetLine(gif, tmp, w) != GIF_OK)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ goto error;
+ }
+ }
+ }
}
}
alpha = gif_frame->frame_info.transparent;
if (!cmap)
{
DGifCloseFile(gif);
- for (i = 0; i < h; i++)
+ for (i = 0; i < scale_h; i++)
{
free(rows[i]);
}
bg_val = ARGB_JOIN(0xff, r, g, b);
per_inc = 100.0 / (((double)w) * h);
- cur_h = h;
- cur_w = w;
+ cur_h = scale_h;
+ cur_w = scale_w;
+
if (cur_h > cache_h) cur_h = cache_h;
if (cur_w > cache_w) cur_w = cache_w;
case 1: /* Do not dispose. need previous frame*/
memcpy(ptr, ptr_src, siz);
/* only decoding image descriptor's region */
- ptr = ptr + cache_w * y;
+ ptr = ptr + cache_w * scale_y;
for (i = 0; i < cur_h; i++)
{
- ptr = ptr + x;
+ ptr = ptr + scale_x;
for (j = 0; j < cur_w; j++)
{
- if (rows[i][j] == alpha)
+ if (rows[i][j * scale_ratio] == alpha)
{
ptr++ ;
}
else
{
- r = cmap->Colors[rows[i][j]].Red;
- g = cmap->Colors[rows[i][j]].Green;
- b = cmap->Colors[rows[i][j]].Blue;
+ r = cmap->Colors[rows[i][j * scale_ratio]].Red;
+ g = cmap->Colors[rows[i][j * scale_ratio]].Green;
+ b = cmap->Colors[rows[i][j * scale_ratio]].Blue;
*ptr++ = ARGB_JOIN(0xff, r, g, b);
}
per += per_inc;
}
- ptr = ptr + (cache_w - (x + cur_w));
+ ptr = ptr + (cache_w - (scale_x + cur_w));
}
break;
case 2: /* Restore to background color */
/* composite frames */
for (i = 0; i < cache_h; i++)
{
- if ((i < y) || (i >= (y + cur_h)))
+ if ((i < scale_y) || (i >= (scale_y + cur_h)))
{
for (j = 0; j < cache_w; j++)
{
else
{
int i1, j1;
- i1 = i -y;
+ i1 = i - scale_y;
for (j = 0; j < cache_w; j++)
{
- j1 = j - x;
- if ((j < x) || (j >= (x + cur_w)))
+ j1 = j - scale_x;
+ if ((j < scale_x) || (j >= (scale_x + cur_w)))
{
*ptr = bg_val;
ptr++;
}
else
{
- r = cmap->Colors[rows[i1][j1]].Red;
- g = cmap->Colors[rows[i1][j1]].Green;
- b = cmap->Colors[rows[i1][j1]].Blue;
+ r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
+ g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
+ b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
*ptr++ = ARGB_JOIN(0xff, r, g, b);
}
}
memset(ptr, 0, siz);
for (i = 0; i < cache_h; i++)
{
- if ((i < y) || (i >= (y + cur_h)))
+ if ((i < scale_y) || (i >= (scale_y + cur_h)))
{
for (j = 0; j < cache_w; j++)
{
else
{
int i1, j1;
- i1 = i -y;
+ i1 = i - scale_y;
for (j = 0; j < cache_w; j++)
{
- j1 = j - x;
- if ((j < x) || (j >= (x + cur_w)))
+ j1 = j - scale_x;
+ if ((j < scale_x) || (j >= (scale_x + cur_w)))
{
*ptr = bg_val;
ptr++;
}
else
{
- r = cmap->Colors[rows[i1][j1]].Red;
- g = cmap->Colors[rows[i1][j1]].Green;
- b = cmap->Colors[rows[i1][j1]].Blue;
+ r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
+ g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
+ b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
*ptr++ = ARGB_JOIN(0xff, r, g, b);
}
}
/* fill background color */
for (i = 0; i < cache_h; i++)
{
- if ((i < y) || (i >= (y + cur_h)))
+ /* the row's of logical screen not overap with frame */
+ if ((i < scale_y) || (i >= (scale_y + cur_h)))
{
for (j = 0; j < cache_w; j++)
{
else
{
int i1, j1;
- i1 = i -y;
+ i1 = i -scale_y;
for (j = 0; j < cache_w; j++)
{
- j1 = j - x;
- if ((j < x) || (j >= (x + cur_w)))
+ j1 = j - scale_x;
+ if ((j < scale_x) || (j >= (scale_x + cur_w)))
{
*ptr = bg_val;
ptr++;
}
else
{
- r = cmap->Colors[rows[i1][j1]].Red;
- g = cmap->Colors[rows[i1][j1]].Green;
- b = cmap->Colors[rows[i1][j1]].Blue;
+ r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
+ g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
+ b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
*ptr++ = ARGB_JOIN(0xff, r, g, b);
}
}
}
}
- for (i = 0; i < h; i++)
+ for (i = 0; i < scale_h; i++)
{
if (rows[i]) free(rows[i]);
}
frame->loaded = EINA_TRUE;
return EINA_TRUE;
error:
- for (i = 0; i < h; i++)
+ for (i = 0; i < scale_h; i++)
{
if (rows[i]) free(rows[i]);
}
/* check logical screen size */
w = gif->SWidth;
h = gif->SHeight;
+ /* support scale down feture in gif*/
+ if (ie->load_opts.scale_down_by > 1)
+ {
+ w /= ie->load_opts.scale_down_by;
+ h /= ie->load_opts.scale_down_by;
+ }
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
- ie->w = (int) w32;
- ie->h = (int) h32;
+ if (ie->load_opts.scale_down_by > 1)
+ {
+ ie->w = (int) w32 / ie->load_opts.scale_down_by ;
+ ie->h = (int) h32 / ie->load_opts.scale_down_by ;
+ if((ie->w < 1) || (ie->h < 1))
+ {
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ goto close_file;
+ }
+ }
+ else
+ {
+ ie->w = (int) w32;
+ ie->h = (int) h32;
+ }
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) hasa = 1;
if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) hasa = 1;
if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) hasa = 1;
unsigned char buf[PNG_BYTES_TO_CHECK];
unsigned char **lines;
char hasa;
- int i;
+ int i, j;
+ int scale_ratio = 1, image_w = 0;
+ unsigned char *tmp_line;
+ unsigned char *src_ptr, *dst_ptr;
hasa = 0;
f = E_FOPEN(file, "rb");
png_get_IHDR(png_ptr, info_ptr, (png_uint_32 *) (&w32),
(png_uint_32 *) (&h32), &bit_depth, &color_type,
&interlace_type, NULL, NULL);
+ image_w = w32;
+ if (ie->load_opts.scale_down_by > 1)
+ {
+ scale_ratio = ie->load_opts.scale_down_by;
+ w32 /= scale_ratio;
+ h32 /= scale_ratio;
+ }
evas_cache_image_surface_alloc(ie, w32, h32);
surface = (unsigned char *) evas_cache_image_pixels(ie);
if (!surface)
#endif
lines = (unsigned char **) alloca(h * sizeof(unsigned char *));
- for (i = 0; i < h; i++)
- lines[i] = surface + (i * w * sizeof(DATA32));
- png_read_image(png_ptr, lines);
- png_read_end(png_ptr, info_ptr);
+ /* we read image line by line if scale down was set */
+ if (scale_ratio == 1)
+ {
+ for (i = 0; i < h; i++)
+ lines[i] = surface + (i * w * sizeof(DATA32));
+ }
+ else
+ {
+ tmp_line = (unsigned char *) malloc(image_w * sizeof(DATA32));
+ }
+
+ if (scale_ratio == 1)
+ {
+ png_read_image(png_ptr, lines);
+ png_read_end(png_ptr, info_ptr);
+ }
+ else
+ {
+ src_ptr = surface;
+ for (i = 0; i < h; i++)
+ {
+ png_read_row(png_ptr, tmp_line, NULL);
+ dst_ptr = tmp_line;
+ for (j = 0; j < w; j++)
+ {
+ src_ptr[0] = dst_ptr[0];
+ src_ptr[1] = dst_ptr[1];
+ src_ptr[2] = dst_ptr[2];
+ src_ptr[3] = dst_ptr[3];
+ src_ptr += 4;
+ dst_ptr += scale_ratio * 4;
+ }
+ for (j = 0; j < (scale_ratio - 1); j++)
+ {
+ png_read_row(png_ptr, tmp_line, NULL);
+ }
+ }
+ if (tmp_line)
+ free(tmp_line);
+ }
+
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
E_FCLOSE(f);
evas_common_image_premul(ie);