#include "image.h"
# define BI_RGB 0
# define BI_RLE8 1
# define BI_RLE4 2
# define BI_BITFIELDS 3
static unsigned short read_word(FILE *fp);
static unsigned int read_dword(FILE *fp);
static int read_long(FILE *fp);
int
ImageReadBMP(image_t *img,
FILE *fp,
int primary,
int secondary,
int saturation,
int hue,
const ib_t *lut)
{
int offset,
info_size,
planes,
depth,
compression,
image_size,
colors_used,
colors_important,
bpp,
x, y,
color,
count,
temp,
align;
ib_t bit,
byte;
ib_t *in,
*out,
*ptr;
ib_t colormap[256][4];
(void)secondary;
getc(fp);
getc(fp);
read_dword(fp);
read_word(fp);
read_word(fp);
offset = read_dword(fp);
fprintf(stderr, "offset = %d\n", offset);
info_size = read_dword(fp);
img->xsize = read_long(fp);
img->ysize = read_long(fp);
planes = read_word(fp);
depth = read_word(fp);
compression = read_dword(fp);
image_size = read_dword(fp);
img->xppi = read_long(fp) * 0.0254 + 0.5;
img->yppi = read_long(fp) * 0.0254 + 0.5;
colors_used = read_dword(fp);
colors_important = read_dword(fp);
if (img->xppi == 0)
img->xppi = 128;
if (img->yppi == 0)
img->yppi = 128;
fprintf(stderr, "info_size = %d, xsize = %d, ysize = %d, planes = %d, depth = %d\n",
info_size, img->xsize, img->ysize, planes, depth);
fprintf(stderr, "compression = %d, image_size = %d, xppi = %d, yppi = %d\n",
compression, image_size, img->xppi, img->yppi);
fprintf(stderr, "colors_used = %d, colors_important = %d\n", colors_used,
colors_important);
if (info_size > 40)
for (info_size -= 40; info_size > 0; info_size --)
getc(fp);
if (colors_used == 0 && depth <= 8)
colors_used = 1 << depth;
fread(colormap, colors_used, 4, fp);
img->colorspace = (primary == IMAGE_RGB_CMYK) ? IMAGE_RGB : primary;
ImageSetMaxTiles(img, 0);
in = malloc(img->xsize * 3);
bpp = ImageGetDepth(img);
out = malloc(img->xsize * bpp);
color = 0;
count = 0;
align = 0;
for (y = img->ysize - 1; y >= 0; y --)
{
if (img->colorspace == IMAGE_RGB)
ptr = out;
else
ptr = in;
switch (depth)
{
case 1 :
for (x = img->xsize, bit = 128, byte = 0; x > 0; x --)
{
if (bit == 128)
byte = getc(fp);
if (byte & bit)
{
*ptr++ = colormap[1][2];
*ptr++ = colormap[1][1];
*ptr++ = colormap[1][0];
}
else
{
*ptr++ = colormap[0][2];
*ptr++ = colormap[0][1];
*ptr++ = colormap[0][0];
}
if (bit > 1)
bit >>= 1;
else
bit = 128;
}
for (temp = (img->xsize + 7) / 8; temp & 3; temp ++)
getc(fp);
break;
case 4 :
for (x = img->xsize, bit = 0xf0, temp = 0; x > 0; x --)
{
if (compression != BI_RLE4 && count == 0)
{
count = 2;
color = -1;
}
if (count == 0)
{
while (align > 0)
{
align --;
getc(fp);
}
if ((count = getc(fp)) == 0)
{
if ((count = getc(fp)) == 0)
{
x ++;
continue;
}
else if (count == 1)
{
break;
}
else if (count == 2)
{
count = getc(fp) * getc(fp) * img->xsize;
color = 0;
}
else
{
color = -1;
align = ((4 - (count & 3)) / 2) & 1;
}
}
else
color = getc(fp);
}
count --;
if (bit == 0xf0)
{
if (color < 0)
temp = getc(fp);
else
temp = color;
*ptr++ = colormap[temp >> 4][2];
*ptr++ = colormap[temp >> 4][1];
*ptr++ = colormap[temp >> 4][0];
bit = 0x0f;
}
else
{
*ptr++ = colormap[temp & 15][2];
*ptr++ = colormap[temp & 15][1];
*ptr++ = colormap[temp & 15][0];
bit = 0xf0;
}
}
break;
case 8 :
for (x = img->xsize; x > 0; x --)
{
if (compression != BI_RLE8)
{
count = 1;
color = -1;
}
if (count == 0)
{
while (align > 0)
{
align --;
getc(fp);
}
if ((count = getc(fp)) == 0)
{
if ((count = getc(fp)) == 0)
{
x ++;
continue;
}
else if (count == 1)
{
break;
}
else if (count == 2)
{
count = getc(fp) * getc(fp) * img->xsize;
color = 0;
}
else
{
color = -1;
align = (2 - (count & 1)) & 1;
}
}
else
color = getc(fp);
}
if (color < 0)
temp = getc(fp);
else
temp = color;
count --;
*ptr++ = colormap[temp][2];
*ptr++ = colormap[temp][1];
*ptr++ = colormap[temp][0];
}
break;
case 24 :
for (x = img->xsize; x > 0; x --, ptr += 3)
{
ptr[2] = getc(fp);
ptr[1] = getc(fp);
ptr[0] = getc(fp);
}
for (temp = img->xsize * 3; temp & 3; temp ++)
getc(fp);
break;
}
if (img->colorspace == IMAGE_RGB)
{
if (saturation != 100 || hue != 0)
ImageRGBAdjust(out, img->xsize, saturation, hue);
}
else
{
if (saturation != 100 || hue != 0)
ImageRGBAdjust(in, img->xsize, saturation, hue);
switch (img->colorspace)
{
case IMAGE_WHITE :
ImageRGBToWhite(in, out, img->xsize);
break;
case IMAGE_BLACK :
ImageRGBToBlack(in, out, img->xsize);
break;
case IMAGE_CMY :
ImageRGBToCMY(in, out, img->xsize);
break;
case IMAGE_CMYK :
ImageRGBToCMYK(in, out, img->xsize);
break;
}
}
if (lut)
ImageLut(out, img->xsize * bpp, lut);
ImagePutRow(img, 0, y, img->xsize, out);
}
fclose(fp);
free(in);
free(out);
return (0);
}
static unsigned short
read_word(FILE *fp)
{
unsigned char b0, b1;
b0 = getc(fp);
b1 = getc(fp);
return ((b1 << 8) | b0);
}
static unsigned int
read_dword(FILE *fp)
{
unsigned char b0, b1, b2, b3;
b0 = getc(fp);
b1 = getc(fp);
b2 = getc(fp);
b3 = getc(fp);
return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
}
static int
read_long(FILE *fp)
{
unsigned char b0, b1, b2, b3;
b0 = getc(fp);
b1 = getc(fp);
b2 = getc(fp);
b3 = getc(fp);
return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
}