evas: Support region_set for BMP image

Summary:
1) BMP loader support region decoding.
     @feature

2) Fix an issue what BMP loader can't decode an 16bit image with bit field
    @fix

Test Plan: attached sample codes

Reviewers: cedric, jpeg, jypark

Differential Revision: https://phab.enlightenment.org/D4228
This commit is contained in:
jiin.moon 2016-08-17 16:06:05 +09:00 committed by Jean-Philippe Andre
parent dc0416fade
commit a76fd7b37e
1 changed files with 95 additions and 45 deletions

View File

@ -368,6 +368,19 @@ evas_image_load_file_head_bmp(void *loader_data,
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
if (load_opts->region.w > 0 && load_opts->region.h > 0)
{
if ((load_opts->region.w + load_opts->region.x > header.width) ||
(load_opts->region.h + load_opts->region.y > header.height))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
header.width = load_opts->region.w;
header.height = load_opts->region.h;
}
/* It is not bad idea that bmp loader support scale down decoding
* because of memory issue in mobile world.*/
if (load_opts->scale_down_by > 1)
@ -465,6 +478,7 @@ evas_image_load_file_data_bmp(void *loader_data,
/* for scale decoding */
unsigned int *scale_surface = NULL, *scale_pix = NULL;
int scale_ratio = 1, image_w = 0, image_h = 0;
int region_set = 0, region_x = 0, region_y = 0, region_w, region_h;
int row_size = 0; /* Row size is rounded up to a multiple of 4bytes */
int read_line = 0; /* total read line */
@ -499,12 +513,30 @@ evas_image_load_file_data_bmp(void *loader_data,
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
image_w = region_w = header.width;
image_h = region_h = header.height;
if (opts->region.w > 0 && opts->region.h > 0)
{
if ((opts->region.w + opts->region.x > header.width) ||
(opts->region.h + opts->region.y > header.height))
{
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
region_set = 1;
region_x = opts->region.x;
region_y = image_h - (opts->region.h + opts->region.y);
region_w = opts->region.w;
region_h = opts->region.h;
header.width = opts->region.w;
header.height = opts->region.h;
}
/* It is not bad idea that bmp loader support scale down decoding
* because of memory issue in mobile world. */
if (opts->scale_down_by > 1)
scale_ratio = opts->scale_down_by;
image_w = header.width;
image_h = header.height;
if (scale_ratio > 1)
{
@ -566,7 +598,7 @@ evas_image_load_file_data_bmp(void *loader_data,
}
position = header.offset;
if ((scale_ratio == 1) || (header.comp !=0))
if ((!region_set && scale_ratio == 1) || (header.comp != 0))
{
if (image_size < (int)(fsize - position))
image_size = fsize - position;
@ -588,20 +620,20 @@ evas_image_load_file_data_bmp(void *loader_data,
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if ((scale_ratio == 1) || (header.comp !=0))
buffer_end = buffer + image_size;
else
buffer_end = buffer + row_size;
p = buffer;
if ((scale_ratio == 1) || (header.comp !=0))
if ((!region_set && scale_ratio == 1) || (header.comp != 0))
{
buffer_end = buffer + image_size;
if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
}
else
{
if (region_set)
position += row_size * region_y;
if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
buffer_end = buffer + row_size;
}
p = buffer;
if (header.bit_count == 1)
{
@ -612,7 +644,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (scale_ratio > 1) pix = scale_surface; // one line decoding
if (scale_ratio > 1 || region_set) pix = scale_surface; // one line decoding
for (x = 0; x < image_w; x++)
{
@ -653,12 +685,16 @@ evas_image_load_file_data_bmp(void *loader_data,
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
if (!right_way_up) scale_pix = surface + ((header.height - 1 - y) * header.width);
else scale_pix = surface + (y * header.width);
pix = scale_surface;
if (region_set)
pix = scale_surface + region_x;
else
pix = scale_surface;
for (x = 0; x < header.width; x++)
{
*scale_pix = *pix;
@ -693,7 +729,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (scale_ratio > 1) pix = scale_surface; // one line decoding
if (scale_ratio > 1 || region_set) pix = scale_surface; // one line decoding
for (x = 0; x < image_w; x++)
{
if ((x & 0x1) == 0x1)
@ -708,12 +744,16 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
if (!right_way_up) scale_pix = surface + ((header.height - 1 - y) * header.width);
else scale_pix = surface + (y * header.width);
pix = scale_surface;
if (region_set)
pix = scale_surface + region_x;
else
pix = scale_surface;
for (x = 0; x < header.width; x++)
{
*scale_pix = *pix;
@ -744,6 +784,8 @@ evas_image_load_file_data_bmp(void *loader_data,
Eina_Bool scale_down_line = EINA_TRUE;
pix = surface;
if (region_set && region_y > 0) scale_down_line = EINA_FALSE;
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
wpad = ((image_w + 1) / 2) * 2;
while (p < buffer_end)
@ -762,7 +804,7 @@ evas_image_load_file_data_bmp(void *loader_data,
{
if (x < header.width)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = col1;
pix++;
@ -772,7 +814,7 @@ evas_image_load_file_data_bmp(void *loader_data,
}
if (x < header.width)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = col2;
pix++;
@ -784,7 +826,7 @@ evas_image_load_file_data_bmp(void *loader_data,
}
if (p[0] & 0x1)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = col1;
pix++;
@ -804,7 +846,7 @@ evas_image_load_file_data_bmp(void *loader_data,
x = 0;
scale_x = 0;
y++;
if ((y % scale_ratio) == 0)
if (y >= region_y && (y % scale_ratio) == 0)
{
scale_y++;
scale_down_line = EINA_TRUE;
@ -852,14 +894,14 @@ evas_image_load_file_data_bmp(void *loader_data,
count /= 2;
while (count > 0)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((y >= region_y) && (x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = pal[*p >> 4];
pix++;
scale_x++;
}
x++;
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((y >= region_y) && (x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = pal[*p & 0xf];
pix++;
@ -873,7 +915,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (done & 0x1)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if (((y >= region_y) && (x >= region_x) && (x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = pal[*p >> 4];
scale_x++;
@ -901,6 +943,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += region_x;
for (x = 0; x < header.width; x++)
{
*pix = pal[*p];
@ -908,7 +951,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
@ -931,8 +974,10 @@ evas_image_load_file_data_bmp(void *loader_data,
int count = 0, done = 0;
int scale_x = 0, scale_y = 0;
Eina_Bool scale_down_line = EINA_TRUE;
pix = surface;
if (region_set && 0 < region_y)
scale_down_line = EINA_FALSE;
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
while (p < buffer_end)
@ -948,7 +993,7 @@ evas_image_load_file_data_bmp(void *loader_data,
count = p[0];
while (count > 0)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = col;
pix++;
@ -969,7 +1014,7 @@ evas_image_load_file_data_bmp(void *loader_data,
x = 0;
scale_x = 0;
y++;
if ((y % scale_ratio) == 0)
if (y >= region_y && (y % scale_ratio) == 0)
{
scale_y++;
scale_down_line = EINA_TRUE;
@ -1017,7 +1062,7 @@ evas_image_load_file_data_bmp(void *loader_data,
done = count;
while (count > 0)
{
if (((x % scale_ratio) == 0) && (scale_x < header.width))
if ((x >= region_x) && ((x % scale_ratio) == 0) && (scale_x < header.width))
{
*pix = pal[*p];
pix++;
@ -1042,7 +1087,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (header.comp == 0) // no compression
{
position = header.offset;
if (scale_ratio == 1)
if (!region_set && 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
@ -1051,18 +1096,19 @@ evas_image_load_file_data_bmp(void *loader_data,
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if (scale_ratio == 1)
if (!region_set && scale_ratio == 1)
buffer_end = buffer + image_size;
else
buffer_end = buffer + row_size;
p = buffer;
if (scale_ratio == 1)
if (!region_set && scale_ratio == 1)
{
if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
}
else
{
if (region_set) position += row_size * region_y;
if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
}
if (header.bit_count == 16)
@ -1073,6 +1119,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 2 * region_x;
for (x = 0; x < header.width; x++)
{
tmp = *((unsigned short *)(p));
@ -1087,7 +1134,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
@ -1111,6 +1158,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 3 * region_x;
for (x = 0; x < header.width; x++)
{
b = p[0];
@ -1121,7 +1169,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
@ -1146,6 +1194,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 4 * region_x;
for (x = 0; x < header.width; x++)
{
b = p[0];
@ -1160,7 +1209,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
@ -1194,12 +1243,8 @@ evas_image_load_file_data_bmp(void *loader_data,
}
else if (header.comp == 3) // bit field
{
if (!read_uint(map, fsize, &position, &header.rmask)) goto close_file;
if (!read_uint(map, fsize, &position, &header.gmask)) goto close_file;
if (!read_uint(map, fsize, &position, &header.bmask)) goto close_file;
position = header.offset;
if (scale_ratio == 1)
if (!region_set && 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
@ -1209,18 +1254,20 @@ evas_image_load_file_data_bmp(void *loader_data,
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if (scale_ratio == 1)
if (!region_set && scale_ratio == 1)
buffer_end = buffer + image_size;
else
buffer_end = buffer + row_size;
p = buffer;
if (scale_ratio == 1)
if (!region_set && scale_ratio == 1)
{
if (!read_mem(map, fsize, &position, buffer, image_size)) goto close_file;
}
else
{
if (region_set)
position += row_size * region_y;
if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
}
@ -1234,6 +1281,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 2 * region_x;
for (x = 0; x < header.width; x++)
{
tmp = *((unsigned short *)(p));
@ -1248,7 +1296,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
@ -1275,6 +1323,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 2 * region_x;
for (x = 0; x < header.width; x++)
{
tmp = *((unsigned short *)(p));
@ -1288,13 +1337,13 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;
position += row_size * (scale_ratio - 1);
if (!read_mem(map, fsize, &position, buffer_end, row_size)) goto close_file;
if (!read_mem(map, fsize, &position, buffer, row_size)) goto close_file;
p = buffer;
buffer_end = buffer + row_size;
}
@ -1312,6 +1361,7 @@ evas_image_load_file_data_bmp(void *loader_data,
for (y = 0; y < header.height; y++)
{
if (!right_way_up) pix = surface + ((header.height - 1 - y) * header.width);
if (region_set) p += 4 * region_x;
for (x = 0; x < header.width; x++)
{
b = p[0];
@ -1326,7 +1376,7 @@ evas_image_load_file_data_bmp(void *loader_data,
if (p >= buffer_end) break;
pix++;
}
if (scale_ratio > 1)
if (scale_ratio > 1 || region_set)
{
read_line += scale_ratio;
if (read_line >= image_h) break;