This source file includes following definitions.
- ReadleShort
- ReadleLong
- WriteleByte
- WriteleShort
- WriteleLong
- load
- save
- formats
#include "loader_common.h"
#include <sys/stat.h>
typedef struct tagRGBQUAD {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
#define BI_RGB 0
#define BI_RLE8 1
#define BI_RLE4 2
#define BI_BITFIELDS 3
enum {
RLE_NEXT = 0,
RLE_END = 1,
RLE_MOVE = 2
};
static int
ReadleShort(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
ReadleLong(FILE * file, unsigned long *ret)
{
unsigned char b[4];
if (fread(b, sizeof(unsigned char), 4, file) != 4)
return 0;
*ret = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
return 1;
}
static int
WriteleByte(FILE * file, unsigned char val)
{
int rc;
rc = fputc((int)val & 0xff, file);
if (rc == EOF)
return 0;
return 1;
}
static int
WriteleShort(FILE * file, unsigned short val)
{
int rc;
rc = fputc((int)(val & 0xff), file);
if (rc == EOF)
return 0;
rc = fputc((int)((val >> 8) & 0xff), file);
if (rc == EOF)
return 0;
return 1;
}
static int
WriteleLong(FILE * file, unsigned long val)
{
int rc;
rc = fputc((int)(val & 0xff), file);
if (rc == EOF)
return 0;
rc = fputc((int)((val >> 8) & 0xff), file);
if (rc == EOF)
return 0;
rc = fputc((int)((val >> 16) & 0xff), file);
if (rc == EOF)
return 0;
rc = fputc((int)((val >> 24) & 0xff), file);
if (rc == EOF)
return 0;
return 1;
}
char
load(ImlibImage * im, ImlibProgressFunction progress,
char progress_granularity, char immediate_load)
{
FILE *f;
char pper = 0;
int pl = 0;
char type[2];
unsigned long size, offset, headSize, comp, imgsize, j, k, l;
unsigned short tmpShort, planes, bitcount, ncols, skip;
unsigned char byte = 0, g, b, r;
unsigned long i, w, h;
unsigned short x, y;
DATA32 *ptr, *data_end;
unsigned char *buffer_ptr, *buffer, *buffer_end;
RGBQUAD rgbQuads[256];
unsigned long rmask = 0xff, gmask = 0xff, bmask = 0xff;
unsigned long rshift = 0, gshift = 0, bshift = 0;
unsigned long rleftshift = 0, gleftshift = 0, bleftshift = 0;
unsigned char byte1, byte2;
if (im->data)
return 0;
f = fopen(im->real_file, "rb");
if (!f)
return 0;
{
struct stat statbuf;
if (stat(im->real_file, &statbuf) == -1)
{
fclose(f);
return 0;
}
size = statbuf.st_size;
if (fread(type, 1, 2, f) != 2)
{
fclose(f);
return 0;
}
if (strncmp(type, "BM", 2))
{
fclose(f);
return 0;
}
fseek(f, 8, SEEK_CUR);
ReadleLong(f, &offset);
ReadleLong(f, &headSize);
if (offset >= size)
{
fclose(f);
return 0;
}
if (headSize == 12)
{
ReadleShort(f, &tmpShort);
w = tmpShort;
ReadleShort(f, &tmpShort);
h = tmpShort;
ReadleShort(f, &planes);
ReadleShort(f, &bitcount);
imgsize = size - offset;
comp = BI_RGB;
}
else if (headSize == 40)
{
ReadleLong(f, &w);
ReadleLong(f, &h);
ReadleShort(f, &planes);
ReadleShort(f, &bitcount);
ReadleLong(f, &comp);
ReadleLong(f, &imgsize);
imgsize = size - offset;
fseek(f, 16, SEEK_CUR);
}
else
{
fclose(f);
return 0;
}
if (!IMAGE_DIMENSIONS_OK(w, h))
{
fclose(f);
return 0;
}
if (bitcount < 16)
{
ncols = (offset - headSize - 14);
if (headSize == 12)
{
ncols /= 3;
if (ncols > 256)
ncols = 256;
for (i = 0; i < ncols; i++)
fread(&rgbQuads[i], 3, 1, f);
}
else
{
ncols /= 4;
if (ncols > 256)
ncols = 256;
fread(rgbQuads, 4, ncols, f);
}
}
else if (bitcount == 16 || bitcount == 32)
{
if (comp == BI_BITFIELDS)
{
int bit;
ReadleLong(f, &rmask);
ReadleLong(f, &gmask);
ReadleLong(f, &bmask);
for (bit = bitcount - 1; bit >= 0; bit--)
{
if (bmask & (1 << bit))
bshift = bit;
if (gmask & (1 << bit))
gshift = bit;
if (rmask & (1 << bit))
rshift = bit;
}
while (((((0xffffL & bmask) >> bshift) << bleftshift) & 0x80) ==
0)
{
bleftshift++;
}
while (((((0xffffL & gmask) >> gshift) << gleftshift) & 0x80) ==
0)
{
gleftshift++;
}
while (((((0xffffL & rmask) >> rshift) << rleftshift) & 0x80) ==
0)
{
rleftshift++;
}
}
else if (bitcount == 16)
{
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
rshift = 10;
gshift = 5;
bshift = 0;
rleftshift = gleftshift = bleftshift = 3;
}
else if (bitcount == 32)
{
rmask = 0x00FF0000;
gmask = 0x0000FF00;
bmask = 0x000000FF;
rshift = 16;
gshift = 8;
bshift = 0;
}
}
im->w = w;
im->h = h;
if (!im->format)
{
UNSET_FLAG(im->flags, F_HAS_ALPHA);
im->format = strdup("bmp");
}
}
if (((!im->data) && (im->loader)) || (immediate_load) || (progress))
{
fseek(f, offset, SEEK_SET);
buffer = malloc(imgsize);
if (!buffer)
{
fclose(f);
return 0;
}
im->data = malloc(w * h * sizeof(DATA32));
if (!im->data)
{
fclose(f);
free(buffer);
return 0;
}
fread(buffer, imgsize, 1, f);
fclose(f);
buffer_ptr = buffer;
buffer_end = buffer + imgsize;
data_end = im->data + w * h;
ptr = im->data + ((h - 1) * w);
if (bitcount == 1)
{
if (comp == BI_RGB)
{
skip = ((((w + 31) / 32) * 32) - w) / 8;
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end; x++)
{
if ((x & 7) == 0)
byte = *(buffer_ptr++);
k = (byte >> 7) & 1;
*ptr++ = 0xff000000 |
(rgbQuads[k].rgbRed << 16) |
(rgbQuads[k].rgbGreen << 8) |
rgbQuads[k].rgbBlue;
byte <<= 1;
}
buffer_ptr += skip;
ptr -= w * 2;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
}
if (bitcount == 4)
{
if (comp == BI_RLE4)
{
unsigned char *buffer_end_minus_1 = buffer_end - 1;
x = 0;
y = 0;
for (i = 0; i < imgsize && buffer_ptr < buffer_end_minus_1;
i++)
{
byte1 = buffer_ptr[0];
byte2 = buffer_ptr[1];
buffer_ptr += 2;
if (byte1)
{
DATA32 t1, t2;
l = byte1;
if (l + x > w)
goto _bail;
t1 = 0xff000000 |
(rgbQuads[byte2 >> 4].rgbRed << 16) |
(rgbQuads[byte2 >> 4].rgbGreen << 8) |
(rgbQuads[byte2 >> 4].rgbBlue);
t2 = 0xff000000 |
(rgbQuads[byte2 & 0xF].rgbRed << 16) |
(rgbQuads[byte2 & 0xF].rgbGreen << 8) |
(rgbQuads[byte2 & 0xF].rgbBlue);
for (j = l / 2; j; j--)
{
ptr[0] = t1;
ptr[1] = t2;
ptr += 2;
}
if (l & 1)
*ptr++ = t1;
x += l;
}
else
{
switch (byte2)
{
case RLE_NEXT:
x = 0;
if (++y >= h)
goto _bail;
ptr = im->data + (h - y - 1) * w;
break;
case RLE_END:
goto _bail;
case RLE_MOVE:
if (buffer_ptr >= buffer_end_minus_1)
goto _bail;
x += buffer_ptr[0];
y += buffer_ptr[1];
buffer_ptr += 2;
if (x >= w)
goto _bail;
if (y >= h)
goto _bail;
ptr = im->data + (h - y - 1) * w + x;
break;
default:
l = byte2;
if (l + x > w)
goto _bail;
if (buffer_ptr + (l >> 1) + (l & 1) >
buffer_end)
goto _bail;
for (j = l / 2; j; j--)
{
byte = *buffer_ptr++;
ptr[0] =
0xff000000 |
(rgbQuads[byte >> 4].rgbRed << 16) |
(rgbQuads[byte >> 4].rgbGreen << 8) |
(rgbQuads[byte >> 4].rgbBlue);
ptr[1] =
0xff000000 |
(rgbQuads[byte & 0xF].rgbRed << 16) |
(rgbQuads[byte & 0xF].rgbGreen << 8) |
(rgbQuads[byte & 0xF].rgbBlue);
ptr += 2;
}
if (l & 1)
{
byte = *buffer_ptr++;
*ptr++ =
0xff000000 |
(rgbQuads[byte >> 4].rgbRed << 16) |
(rgbQuads[byte >> 4].rgbGreen << 8) |
(rgbQuads[byte >> 4].rgbBlue);
}
x += l;
if ((l & 3) == 1)
buffer_ptr += 2;
else if ((l & 3) == 2)
buffer_ptr++;
break;
}
}
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
else if (comp == BI_RGB)
{
skip = ((((w + 7) / 8) * 8) - w) / 2;
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end; x++)
{
if ((x & 1) == 0)
byte = *(buffer_ptr++);
k = (byte & 0xF0) >> 4;
*ptr++ = 0xff000000 |
(rgbQuads[k].rgbRed << 16) |
(rgbQuads[k].rgbGreen << 8) |
rgbQuads[k].rgbBlue;
byte <<= 4;
}
buffer_ptr += skip;
ptr -= w * 2;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
}
if (bitcount == 8)
{
if (comp == BI_RLE8)
{
unsigned char *buffer_end_minus_1 = buffer_end - 1;
x = 0;
y = 0;
for (i = 0; i < imgsize && buffer_ptr < buffer_end_minus_1;
i++)
{
byte1 = buffer_ptr[0];
byte2 = buffer_ptr[1];
buffer_ptr += 2;
if (byte1)
{
DATA32 pix =
0xff000000 | (rgbQuads[byte2].rgbRed << 16) |
(rgbQuads[byte2].rgbGreen << 8) |
(rgbQuads[byte2].rgbBlue);
l = byte1;
if (x + l > w)
goto _bail;
for (j = l; j; j--)
*ptr++ = pix;
x += l;
}
else
{
switch (byte2)
{
case RLE_NEXT:
x = 0;
if (++y >= h)
goto _bail;
ptr = im->data + ((h - y - 1) * w) + x;
break;
case RLE_END:
goto _bail;
case RLE_MOVE:
if (buffer_ptr >= buffer_end_minus_1)
goto _bail;
x += buffer_ptr[0];
y += buffer_ptr[1];
buffer_ptr += 2;
if (x >= w)
goto _bail;
if (y >= h)
goto _bail;
ptr = im->data + ((h - y - 1) * w) + x;
break;
default:
l = byte2;
if (x + l > w)
goto _bail;
if (buffer_ptr + l > buffer_end)
goto _bail;
for (j = 0; j < l; j++)
{
byte = *(buffer_ptr++);
*ptr++ = 0xff000000 |
(rgbQuads[byte].rgbRed << 16) |
(rgbQuads[byte].rgbGreen << 8) |
rgbQuads[byte].rgbBlue;
}
x += l;
if (l & 1)
buffer_ptr++;
break;
}
}
}
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
else if (comp == BI_RGB)
{
skip = (((w + 3) / 4) * 4) - w;
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end; x++)
{
byte = *(buffer_ptr++);
*ptr++ = 0xff000000 |
(rgbQuads[byte].rgbRed << 16) |
(rgbQuads[byte].rgbGreen << 8) |
rgbQuads[byte].rgbBlue;
}
ptr -= w * 2;
buffer_ptr += skip;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
}
else if (bitcount == 16)
{
unsigned char *buffer_end_minus_1 = buffer_end - 1;
skip = (((w * 16 + 31) / 32) * 4) - (w * 2);
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end_minus_1; x++)
{
unsigned short pix = *(unsigned short *)buffer_ptr;
*ptr++ =
0xff000000 |
((((pix & rmask) >> rshift) << rleftshift) << 16) |
((((pix & gmask) >> gshift) << gleftshift) << 8) |
((((pix & bmask) >> bshift) << bleftshift));
buffer_ptr += 2;
}
ptr -= w * 2;
buffer_ptr += skip;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
else if (bitcount == 24)
{
unsigned char *buffer_end_minus_2 = buffer_end - 2;
skip = (4 - ((w * 3) % 4)) & 3;
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end_minus_2; x++)
{
b = *(buffer_ptr++);
g = *(buffer_ptr++);
r = *(buffer_ptr++);
*ptr++ = 0xff000000 | (r << 16) | (g << 8) | b;
}
ptr -= w * 2;
buffer_ptr += skip;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
else if (bitcount == 32)
{
unsigned char *buffer_end_minus_3 = buffer_end_minus_3;
skip = (((w * 32 + 31) / 32) * 4) - (w * 4);
for (y = 0; y < h; y++)
{
for (x = 0; x < w && buffer_ptr < buffer_end_minus_3; x++)
{
DATA32 pix = *(unsigned int *)buffer_ptr;
*ptr++ = 0xff000000 | (((pix & rmask) >> rshift) << 16) |
(((pix & gmask) >> gshift) << 8) |
(((pix & bmask) >> bshift));
buffer_ptr += 4;
}
ptr -= w * 2;
buffer_ptr += skip;
if (progress)
{
char per;
int l;
per = (char)((100 * y) / im->h);
if (((per - pper) >= progress_granularity) ||
(y == (im->h - 1)))
{
l = y - pl;
if (!progress
(im, per, 0, im->h - y - 1, im->w,
im->h - y + l))
{
free(buffer);
return 2;
}
pper = per;
pl = y;
}
}
}
}
_bail:
free(buffer);
}
return 1;
}
char
save(ImlibImage * im, ImlibProgressFunction progress, char progress_granularity)
{
FILE *f;
Imlib_Color pixel_color;
unsigned long i, j, pad;
if (!im->data)
return 0;
f = fopen(im->real_file, "wb");
if (!f)
return 0;
pad = (4 - ((im->w * 3) % 4)) & 0x03;
WriteleShort(f, 0x4d42);
WriteleLong(f, 54 + 3 * im->w * im->h);
WriteleShort(f, 0x0000);
WriteleShort(f, 0x0000);
WriteleLong(f, 54);
WriteleLong(f, 40);
WriteleLong(f, im->w);
WriteleLong(f, im->h);
WriteleShort(f, 1);
WriteleShort(f, 24);
WriteleLong(f, 0);
WriteleLong(f, 3 * im->w * im->h);
for (i = 0; i < 4; i++)
WriteleLong(f, 0x0000);
for (i = 0; i < im->h; i++)
{
for (j = 0; j < im->w; j++)
{
imlib_image_query_pixel(j, im->h - i - 1, &pixel_color);
WriteleByte(f, pixel_color.blue);
WriteleByte(f, pixel_color.green);
WriteleByte(f, pixel_color.red);
}
for (j = 0; j < pad; j++)
WriteleByte(f, 0);
}
fclose(f);
return 1;
}
void
formats(ImlibLoader * l)
{
char *list_formats[] = { "bmp" };
{
int i;
l->num_formats = (sizeof(list_formats) / sizeof(char *));
l->formats = malloc(sizeof(char *) * l->num_formats);
for (i = 0; i < l->num_formats; i++)
l->formats[i] = strdup(list_formats[i]);
}
}