efl/legacy/evas/src/modules/loaders/bmp/evas_image_load_bmp.c

1144 lines
42 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include "evas_common.h"
#include "evas_private.h"
static Eina_Bool evas_image_load_file_head_bmp(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
static Eina_Bool evas_image_load_file_data_bmp(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
static Evas_Image_Load_Func evas_image_load_bmp_func =
{
EINA_TRUE,
evas_image_load_file_head_bmp,
evas_image_load_file_data_bmp,
NULL
};
static int
read_short(FILE *file, short *ret)
{
unsigned char b[2];
if (fread(b, sizeof(unsigned char), 2, file) != 2) return 0;
*ret = (b[1] << 8) | b[0];
return 1;
}
static int
read_ushort(FILE *file, unsigned short *ret)
{
unsigned char b[2];
if (fread(b, sizeof(unsigned char), 2, file) != 2) return 0;
*ret = (b[1] << 8) | b[0];
return 1;
}
static int
read_int(FILE *file, int *ret)
{
unsigned char b[4];
if (fread(b, sizeof(unsigned char), 4, file) != 4) return 0;
*ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
return 1;
}
static int
read_uint(FILE *file, unsigned int *ret)
{
unsigned char b[4];
if (fread(b, sizeof(unsigned char), 4, file) != 4) return 0;
*ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
return 1;
}
static Eina_Bool
evas_image_load_file_head_bmp(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
{
FILE *f;
char buf[4096];
char hasa = 0;
int w = 0, h = 0, planes = 0, bit_count = 0,
image_size = 0, comp = 0, hdpi = 0, vdpi = 0,
palette_size = -1, important_colors = 0;
unsigned int offset, head_size, rmask = 0, gmask = 0, bmask = 0, amask = 0;
unsigned int pal_num = 0;
int right_way_up = 0;
int fsize = 0;
unsigned int bmpsize;
unsigned short res1, res2;
f = fopen(file, "rb");
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize < 2) goto close_file;
if (fread(buf, 2, 1, f) != 1) goto close_file;
if (strncmp(buf, "BM", 2)) goto close_file; // magic number
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (!read_uint(f, &bmpsize)) goto close_file;
if (!read_ushort(f, &res1)) goto close_file;
if (!read_ushort(f, &res2)) goto close_file;
if (!read_uint(f, &offset)) goto close_file;
if (!read_uint(f, &head_size)) goto close_file;
if (head_size == 12) // OS/2 V1 + Windows 3.0
{
short tmp;
if (!read_short(f, &tmp)) goto close_file;
w = tmp; // width
if (!read_short(f, &tmp)) goto close_file;
h = tmp; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8 & 24
}
else if (head_size == 64) // OS/2 V2
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (fread(buf, 24, 1, f) != 1) goto close_file; // skip unused header
if (image_size == 0) image_size = fsize - offset;
}
else if (head_size == 40) // Windows 3.0 + (v3)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (image_size == 0) image_size = fsize - offset;
if ((comp == 0) && (bit_count == 32)) hasa = 1; // GIMP seems to store it this way
}
else if (head_size == 108) // Windows 95/NT4 + (v4)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (!read_int(f, &tmp2)) goto close_file;
rmask = tmp2; // red mask
if (!read_int(f, &tmp2)) goto close_file;
gmask = tmp2; // green mask
if (!read_int(f, &tmp2)) goto close_file;
bmask = tmp2; // blue mask
if (!read_int(f, &tmp2)) goto close_file;
amask = tmp2; // alpha mask
if (fread(buf, 36, 1, f) != 1) goto close_file; // skip unused cie
if (fread(buf, 12, 1, f) != 1) goto close_file; // skip unused gamma
if (image_size == 0) image_size = fsize - offset;
if ((amask) && (bit_count == 32)) hasa = 1;
}
else if (head_size == 124) // Windows 98/2000 + (v5)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (!read_int(f, &tmp2)) goto close_file;
rmask = tmp2; // red mask
if (!read_int(f, &tmp2)) goto close_file;
gmask = tmp2; // green mask
if (!read_int(f, &tmp2)) goto close_file;
bmask = tmp2; // blue mask
if (!read_int(f, &tmp2)) goto close_file;
amask = tmp2; // alpha mask
if (fread(buf, 36, 1, f) != 1) goto close_file; // skip unused cie
if (fread(buf, 12, 1, f) != 1) goto close_file; // skip unused gamma
if (fread(buf, 16, 1, f) != 1) goto close_file; // skip others
if (image_size == 0) image_size = fsize - offset;
if ((amask) && (bit_count == 32)) hasa = 1;
}
else
goto close_file;
if (h < 0)
{
h = -h;
right_way_up = 1;
}
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
{
if (IMG_TOO_BIG(w, h))
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else
*error = EVAS_LOAD_ERROR_GENERIC;
goto close_file;
}
if (bit_count < 16)
{
if ((palette_size < 0) || (palette_size > 256)) pal_num = 256;
else pal_num = palette_size;
if (bit_count == 1)
{
if (comp == 0) // no compression
{
}
else
goto close_file;
}
else if (bit_count == 4)
{
if (comp == 0) // no compression
{
}
else if (comp == 2) // rle 4bit/pixel
{
}
else
goto close_file;
}
else if (bit_count == 8)
{
if (comp == 0) // no compression
{
}
else if (comp == 1) // rle 8bit/pixel
{
}
else
goto close_file;
}
}
else if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
{
if (comp == 0) // no compression
{
// handled
}
else if (comp == 3) // bit field
{
// handled
}
else if (comp == 4) // jpeg - only printer drivers
goto close_file;
else if (comp == 3) // png - only printer drivers
goto close_file;
else
goto close_file;
}
else
goto close_file;
ie->w = w;
ie->h = h;
if (hasa) ie->flags.alpha = 1;
fclose(f);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
fclose(f);
return EINA_FALSE;
}
static Eina_Bool
evas_image_load_file_data_bmp(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
{
FILE *f;
char buf[4096];
unsigned char *buffer = NULL, *buffer_end = NULL, *p;
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;
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;
int right_way_up = 0;
unsigned char r, g, b, a;
int fsize = 0;
unsigned int bmpsize;
unsigned short res1, res2;
f = fopen(file, "rb");
if (!f)
{
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
return EINA_FALSE;
}
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
fseek(f, 0, SEEK_END);
fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize < 2) goto close_file;
if (fread(buf, 2, 1, f) != 1) goto close_file;
if (strncmp(buf, "BM", 2)) goto close_file; // magic number
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
if (!read_uint(f, &bmpsize)) goto close_file;
if (!read_ushort(f, &res1)) goto close_file;
if (!read_ushort(f, &res2)) goto close_file;
if (!read_uint(f, &offset)) goto close_file;
if (!read_uint(f, &head_size)) goto close_file;
image_size = fsize - offset;
if (image_size < 1) goto close_file;
if (head_size == 12) // OS/2 V1 + Windows 3.0
{
short tmp;
if (!read_short(f, &tmp)) goto close_file;
w = tmp; // width
if (!read_short(f, &tmp)) goto close_file;
h = tmp; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8 & 24
}
else if (head_size == 64) // OS/2 V2
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (fread(buf, 24, 1, f) != 1) goto close_file; // skip unused header
if (image_size == 0) image_size = fsize - offset;
}
else if (head_size == 40) // Windows 3.0 + (v3)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (image_size == 0) image_size = fsize - offset;
if ((comp == 0) && (bit_count == 32)) hasa = 1; // GIMP seems to store it this way
}
else if (head_size == 108) // Windows 95/NT4 + (v4)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (!read_int(f, &tmp2)) goto close_file;
rmask = tmp2; // red mask
if (!read_int(f, &tmp2)) goto close_file;
gmask = tmp2; // green mask
if (!read_int(f, &tmp2)) goto close_file;
bmask = tmp2; // blue mask
if (!read_int(f, &tmp2)) goto close_file;
amask = tmp2; // alpha mask
if (fread(buf, 36, 1, f) != 1) goto close_file; // skip unused cie
if (fread(buf, 12, 1, f) != 1) goto close_file; // skip unused gamma
if (image_size == 0) image_size = fsize - offset;
if ((amask) && (bit_count == 32)) hasa = 1;
}
else if (head_size == 124) // Windows 98/2000 + (v5)
{
short tmp;
int tmp2;
if (!read_int(f, &tmp2)) goto close_file;
w = tmp2; // width
if (!read_int(f, &tmp2)) goto close_file;
h = tmp2; // height
if (!read_short(f, &tmp)) goto close_file;
planes = tmp; // must be 1
if (!read_short(f, &tmp)) goto close_file;
bit_count = tmp; // bits per pixel: 1, 4, 8, 16, 24 & 32
if (!read_int(f, &tmp2)) goto close_file;
comp = tmp2; // compression method
if (!read_int(f, &tmp2)) goto close_file;
image_size = tmp2; // bitmap data size
if (!read_int(f, &tmp2)) goto close_file;
hdpi = (tmp2 * 254) / 10000; // horizontal pixels/meter
if (!read_int(f, &tmp2)) goto close_file;
vdpi = (tmp2 * 254) / 10000; // vertical pixles/meter
if (!read_int(f, &tmp2)) goto close_file;
palette_size = tmp2; // number of palette colors power (2^n - so 0 - 8)
if (!read_int(f, &tmp2)) goto close_file;
important_colors = tmp2; // number of important colors - 0 if all
if (!read_int(f, &tmp2)) goto close_file;
rmask = tmp2; // red mask
if (!read_int(f, &tmp2)) goto close_file;
gmask = tmp2; // green mask
if (!read_int(f, &tmp2)) goto close_file;
bmask = tmp2; // blue mask
if (!read_int(f, &tmp2)) goto close_file;
amask = tmp2; // alpha mask
if (fread(buf, 36, 1, f) != 1) goto close_file; // skip unused cie
if (fread(buf, 12, 1, f) != 1) goto close_file; // skip unused gamma
if (fread(buf, 16, 1, f) != 1) goto close_file; // skip others
if (image_size == 0) image_size = fsize - offset;
if ((amask) && (bit_count == 32)) hasa = 1;
}
else
goto close_file;
if (h < 0)
{
h = -h;
right_way_up = 1;
}
if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
IMG_TOO_BIG(w, h))
{
if (IMG_TOO_BIG(w, h))
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else
*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);
surface = evas_cache_image_pixels(ie);
if (!surface)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
if (bit_count < 16)
{
unsigned int i;
if (bit_count == 1)
{
if ((palette_size <= 0) || (palette_size > 2)) pal_num = 2;
else pal_num = palette_size;
}
else if (bit_count == 4)
{
if ((palette_size <= 0) || (palette_size > 16)) pal_num = 16;
else pal_num = palette_size;
}
else if (bit_count == 8)
{
if ((palette_size <= 0) || (palette_size > 256)) pal_num = 256;
else pal_num = palette_size;
}
pal = alloca(256 * 4);
for (i = 0; i < pal_num; i++)
{
if (fread(&b, 1, 1, f) != 1) goto close_file;
if (fread(&g, 1, 1, f) != 1) goto close_file;
if (fread(&r, 1, 1, f) != 1) goto close_file;
if ((head_size != 12) /*&& (palette_size != 0)*/)
{ // OS/2 V1 doesn't do the pad byte
if (fread(&a, 1, 1, f) != 1) goto close_file;
}
a = 0xff; // fillin a as solid for paletted images
pal[i] = ARGB_JOIN(a, r, g, b);
}
fseek(f, offset, SEEK_SET);
buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
if (!buffer)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
buffer_end = buffer + image_size;
p = buffer;
if (fread(buffer, image_size, 1, f) != 1) goto close_file;
if (bit_count == 1)
{
if (comp == 0) // no compression
{
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
if ((x & 0x7) == 0x0)
{
*pix = pal[*p >> 7];
}
else if ((x & 0x7) == 0x1)
{
*pix = pal[(*p >> 6) & 0x1];
}
else if ((x & 0x7) == 0x2)
{
*pix = pal[(*p >> 5) & 0x1];
}
else if ((x & 0x7) == 0x3)
{
*pix = pal[(*p >> 4) & 0x1];
}
else if ((x & 0x7) == 0x4)
{
*pix = pal[(*p >> 3) & 0x1];
}
else if ((x & 0x7) == 0x5)
{
*pix = pal[(*p >> 2) & 0x1];
}
else if ((x & 0x7) == 0x6)
{
*pix = pal[(*p >> 1) & 0x1];
}
else
{
*pix = pal[*p & 0x1];
p++;
}
if (p >= buffer_end) break;
pix++;
}
if ((x & 0x7) != 0) p++;
fix = (int)(((unsigned long)p) & 0x3);
if (fix > 0) p += 4 - fix; // align row read
if (p >= buffer_end) break;
}
}
else
goto close_file;
}
else if (bit_count == 4)
{
if (comp == 0) // no compression
{
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
if ((x & 0x1) == 0x1)
{
*pix = pal[*p & 0x0f];
p++;
}
else
{
*pix = pal[*p >> 4];
}
if (p >= buffer_end) break;
pix++;
}
if ((x & 0x1) != 0) p++;
fix = (int)(((unsigned long)p) & 0x3);
if (fix > 0) p += 4 - fix; // align row read
if (p >= buffer_end) break;
}
}
else if (comp == 2) // rle 4bit/pixel
{
int count = 0, done = 0, wpad;
pix = surface;
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
wpad = ((w + 1) / 2) * 2;
while (p < buffer_end)
{
if (p[0])
{
if ((x + p[0]) <= wpad)
{
unsigned int col1 = pal[p[1] >> 4];
unsigned int col2 = pal[p[1] & 0xf];
count = p[0] / 2;
while (count > 0)
{
if (x < w)
{
pix[0] = col1;
x++;
}
if (x < w)
{
pix[1] = col2;
x++;
}
pix += 2;
count--;
}
if (p[0] & 0x1)
{
*pix = col1;
x++;
pix++;
}
}
p += 2;
}
else
{
switch (p[1])
{
case 0: // EOL
x = 0;
y++;
if (!right_way_up)
pix = surface + ((h - 1 - y) * w);
else
pix = surface + (y * w);
if (y >= h)
{
p = buffer_end;
}
p += 2;
break;
case 1: // EOB
p = buffer_end;
break;
case 2: // DELTA
x += p[2];
y += p[3];
if ((x >= w) || (y >= h))
{
p = buffer_end;
}
if (!right_way_up)
pix = surface + x + ((h - 1 - y) * w);
else
pix = surface + x + (y * w);
p += 4;
break;
default:
count = p[1];
if (((p + count) > buffer_end) ||
((x + count) > w))
{
p = buffer_end;
break;
}
p += 2;
done = count;
count /= 2;
while (count > 0)
{
pix[0] = pal[*p >> 4];
pix[1] = pal[*p & 0xf];
pix += 2;
p++;
count--;
}
x += done;
if (done & 0x1)
{
*pix = pal[*p >> 4];
p++;
}
if ((done & 0x3) == 0x1)
p += 2;
else if ((done & 0x3) == 0x2)
p += 1;
break;
}
}
}
}
else
goto close_file;
}
else if (bit_count == 8)
{
if (comp == 0) // no compression
{
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
*pix = pal[*p];
p++;
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;
}
}
else if (comp == 1) // rle 8bit/pixel
{
int count = 0, done = 0;
pix = surface;
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
while (p < buffer_end)
{
if (p[0])
{
if ((x + p[0]) <= w)
{
unsigned int col = pal[p[1]];
count = p[0];
while (count > 0)
{
*pix = col;
pix++;
count--;
}
x += p[0];
}
p += 2;
}
else
{
switch (p[1])
{
case 0: // EOL
x = 0;
y++;
if (!right_way_up)
pix = surface + ((h - 1 - y) * w);
else
pix = surface + (y * w);
if (y >= h)
{
p = buffer_end;
}
p += 2;
break;
case 1: // EOB
p = buffer_end;
break;
case 2: // DELTA
x += p[2];
y += p[3];
if ((x >= w) || (y >= h))
{
p = buffer_end;
}
if (!right_way_up)
pix = surface + x + ((h - 1 - y) * w);
else
pix = surface + x + (y * w);
p += 4;
break;
default:
count = p[1];
if (((p + count) > buffer_end) ||
((x + count) > w))
{
p = buffer_end;
break;
}
p += 2;
done = count;
while (count > 0)
{
*pix = pal[*p];
pix++;
p++;
count--;
}
x += done;
if (done & 0x1) p++;
break;
}
}
}
}
else
goto close_file;
}
}
else if ((bit_count == 16) || (bit_count == 24) || (bit_count == 32))
{
if (comp == 0) // no compression
{
fseek(f, offset, SEEK_SET);
buffer = malloc(image_size + 8); // add 8 for padding to avoid checks
if (!buffer)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
buffer_end = buffer + image_size;
p = buffer;
if (fread(buffer, image_size, 1, f) != 1) goto close_file;
if (bit_count == 16)
{
unsigned short tmp;
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
tmp = *((unsigned short *)(p));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
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;
}
}
else if (bit_count == 24)
{
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
b = p[0];
g = p[1];
r = p[2];
*pix = ARGB_JOIN(0xff, r, g, b);
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;
}
}
else if (bit_count == 32)
{
int none_zero_alpha = 0;
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
b = p[0];
g = p[1];
r = p[2];
a = p[3];
if (a) none_zero_alpha = 1;
if (!hasa) a = 0xff;
*pix = ARGB_JOIN(a, r, g, b);
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 (!none_zero_alpha)
{
ie->flags.alpha = 0;
if (hasa)
{
unsigned int *pixend = surface + (w * h);
for (pix = surface; pix < pixend; pix++)
A_VAL(pix) = 0xff;
}
}
}
else
goto close_file;
}
else if (comp == 3) // bit field
{
if (!read_uint(f, &rmask)) goto close_file;
if (!read_uint(f, &gmask)) goto close_file;
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 (!buffer)
{
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
goto close_file;
}
buffer_end = buffer + image_size;
p = buffer;
if (fread(buffer, image_size, 1, f) != 1) goto close_file;
if ((bit_count == 16) &&
(rmask == 0xf800) && (gmask == 0x07e0) && (bmask == 0x001f)
)
{
unsigned short tmp;
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
tmp = *((unsigned short *)(p));
r = (tmp >> 8) & 0xf8; r |= r >> 5;
g = (tmp >> 3) & 0xfc; g |= g >> 6;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
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;
}
}
else if ((bit_count == 16) &&
(rmask == 0x7c00) && (gmask == 0x03e0) && (bmask == 0x001f)
)
{
unsigned short tmp;
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
tmp = *((unsigned short *)(p));
r = (tmp >> 7) & 0xf8; r |= r >> 5;
g = (tmp >> 2) & 0xf8; g |= g >> 5;
b = (tmp << 3) & 0xf8; b |= b >> 5;
*pix = ARGB_JOIN(0xff, r, g, b);
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;
}
}
else if (bit_count == 32)
{
pix = surface;
for (y = 0; y < h; y++)
{
if (!right_way_up) pix = surface + ((h - 1 - y) * w);
for (x = 0; x < w; x++)
{
b = p[0];
g = p[1];
r = p[2];
a = p[3];
if (!hasa) a = 0xff;
*pix = ARGB_JOIN(a, r, g, b);
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;
}
}
else
goto close_file;
}
else if (comp == 4) // jpeg - only printer drivers
{
goto close_file;
}
else if (comp == 3) // png - only printer drivers
{
goto close_file;
}
else
goto close_file;
}
else
goto close_file;
if (buffer) free(buffer);
fclose(f);
evas_common_image_premul(ie);
*error = EVAS_LOAD_ERROR_NONE;
return EINA_TRUE;
close_file:
if (buffer) free(buffer);
fclose(f);
return EINA_FALSE;
}
static int
module_open(Evas_Module *em)
{
if (!em) return 0;
em->functions = (void *)(&evas_image_load_bmp_func);
return 1;
}
static void
module_close(Evas_Module *em __UNUSED__)
{
}
static Evas_Module_Api evas_modapi =
{
EVAS_MODULE_API_VERSION,
"bmp",
"none",
{
module_open,
module_close
}
};
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, bmp);
#ifndef EVAS_STATIC_BUILD_BMP
EVAS_EINA_MODULE_DEFINE(image_loader, bmp);
#endif