Support various kinds of BMP headers (incl reading bmp with alpha)

This commit is contained in:
rdb 2016-02-03 13:36:38 +01:00
parent 2c61260c5f
commit 623d81db6b
2 changed files with 76 additions and 44 deletions

View File

@ -32,6 +32,10 @@ static unsigned long BMPoffbits(int classv, unsigned long bitcount);
#define C_WIN 1 #define C_WIN 1
#define C_OS2 2 #define C_OS2 2
#define C_WINV2 3
#define C_WINV3 4
#define C_WINV4 5
#define C_WINV5 6
static char er_internal[] = "%s: internal error!"; static char er_internal[] = "%s: internal error!";
@ -41,8 +45,12 @@ BMPlenfileheader(int classv)
switch (classv) switch (classv)
{ {
case C_WIN: case C_WIN:
return 14;
case C_OS2: case C_OS2:
case C_WINV2:
case C_WINV3:
case C_WINV4:
case C_WINV5:
return 14;
return 14; return 14;
default: default:
pm_error(er_internal, "BMPlenfileheader"); pm_error(er_internal, "BMPlenfileheader");
@ -59,6 +67,14 @@ BMPleninfoheader(int classv)
return 40; return 40;
case C_OS2: case C_OS2:
return 12; return 12;
case C_WINV2:
return 52;
case C_WINV3:
return 56;
case C_WINV4:
return 108;
case C_WINV5:
return 124;
default: default:
pm_error(er_internal, "BMPleninfoheader"); pm_error(er_internal, "BMPleninfoheader");
return 0; return 0;
@ -107,17 +123,6 @@ BMPlenline(int classv, unsigned long bitcount, unsigned long x)
{ {
unsigned long bitsperline; unsigned long bitsperline;
switch (classv)
{
case C_WIN:
break;
case C_OS2:
break;
default:
pm_error(er_internal, "BMPlenline");
return 0;
}
bitsperline = x * bitcount; bitsperline = x * bitcount;
/* /*

View File

@ -191,39 +191,47 @@ BMPreadinfoheader(
{ {
case 12: case 12:
classv = C_OS2; classv = C_OS2;
cx = GetShort(fp);
cy = GetShort(fp);
cPlanes = GetShort(fp);
cBitCount = GetShort(fp);
break; break;
case 40: case 40: // BITMAPINFOHEADER
classv = C_WIN; classv = C_WIN;
break;
cx = GetLong(fp); case 52: // BITMAPV2INFOHEADER
cy = GetLong(fp); classv = C_WINV2;
cPlanes = GetShort(fp); break;
cBitCount = GetShort(fp); case 56: // BITMAPV3INFOHEADER
classv = C_WINV3;
/* break;
* We've read 16 bytes so far, need to read 24 more case 108: // BITMAPV4HEADER
* for the required total of 40. classv = C_WINV4;
*/ break;
case 124: // BITMAPV5HEADER
GetLong(fp); classv = C_WINV5;
GetLong(fp);
GetLong(fp);
GetLong(fp);
GetLong(fp);
GetLong(fp);
break; break;
default: default:
pm_error("%s: unknown cbFix: %d", ifname, cbFix); pm_error("%s: unknown cbFix: %d", ifname, cbFix);
break; break;
} }
if (classv == C_OS2) {
cx = GetShort(fp);
cy = GetShort(fp);
} else {
cx = GetLong(fp);
cy = GetLong(fp);
}
cPlanes = GetShort(fp);
cBitCount = GetShort(fp);
/*
* We've read 16 bytes so far, need to read more
* for the required total.
*/
if (classv != C_OS2) {
for (int i = 0; i < cbFix - 16; i += 4) {
GetLong(fp);
}
}
if (cPlanes != 1) if (cPlanes != 1)
{ {
pm_error("%s: don't know how to handle cPlanes = %d" pm_error("%s: don't know how to handle cPlanes = %d"
@ -239,6 +247,16 @@ BMPreadinfoheader(
,cy ,cy
,cBitCount); ,cBitCount);
break; break;
case C_WINV2:
case C_WINV3:
case C_WINV4:
case C_WINV5:
pm_message("Windows BMP V%d, %dx%dx%d"
,(classv - C_WINV2 + 2)
,cx
,cy
,cBitCount);
break;
case C_OS2: case C_OS2:
pm_message("OS/2 BMP, %dx%dx%d" pm_message("OS/2 BMP, %dx%dx%d"
,cx ,cx
@ -288,7 +306,7 @@ BMPreadrgbtable(
R[i] = (pixval) GetByte(fp); R[i] = (pixval) GetByte(fp);
nbyte += 3; nbyte += 3;
if (classv == C_WIN) if (classv != C_OS2)
{ {
(void) GetByte(fp); (void) GetByte(fp);
nbyte++; nbyte++;
@ -307,6 +325,7 @@ BMPreadrow(
istream *fp, istream *fp,
unsigned long *ppos, /* number of bytes read from fp */ unsigned long *ppos, /* number of bytes read from fp */
pixel *row, pixel *row,
xelval *alpha_row,
unsigned long cx, unsigned long cx,
unsigned short cBitCount, unsigned short cBitCount,
int indexed, int indexed,
@ -335,6 +354,10 @@ BMPreadrow(
b = GetByte(fp); b = GetByte(fp);
g = GetByte(fp); g = GetByte(fp);
r = GetByte(fp); r = GetByte(fp);
if (cBitCount > 24) {
*(alpha_row++) = GetByte(fp);
++nbyte;
}
nbyte += 3; nbyte += 3;
PPM_ASSIGN(*row, r, g, b); PPM_ASSIGN(*row, r, g, b);
} else { } else {
@ -369,7 +392,7 @@ BMPreadrow(
} }
static void static void
BMPreadbits(xel *array, BMPreadbits(xel *array, xelval *alpha_array,
istream *fp, istream *fp,
unsigned long *ppos, /* number of bytes read from fp */ unsigned long *ppos, /* number of bytes read from fp */
unsigned long offBits, unsigned long offBits,
@ -386,7 +409,7 @@ BMPreadbits(xel *array,
readto(fp, ppos, offBits); readto(fp, ppos, offBits);
if(cBitCount > 24) if(cBitCount > 24 && cBitCount != 32)
{ {
pm_error("%s: cannot handle cBitCount: %d" pm_error("%s: cannot handle cBitCount: %d"
,ifname ,ifname
@ -400,7 +423,7 @@ BMPreadbits(xel *array,
for (y = (long)cy - 1; y >= 0; y--) for (y = (long)cy - 1; y >= 0; y--)
{ {
int rc; int rc;
rc = BMPreadrow(fp, ppos, array + y*cx, cx, cBitCount, indexed, R, G, B); rc = BMPreadrow(fp, ppos, array + y*cx, alpha_array + y*cx, cx, cBitCount, indexed, R, G, B);
if(rc == -1) if(rc == -1)
{ {
pm_error("%s: couldn't read row %d" pm_error("%s: couldn't read row %d"
@ -472,7 +495,11 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
} }
} }
_num_channels = 3; if (cBitCount > 24) {
_num_channels = 4;
} else {
_num_channels = 3;
}
_x_size = (int)cx; _x_size = (int)cx;
_y_size = (int)cy; _y_size = (int)cy;
_maxval = 255; _maxval = 255;
@ -498,8 +525,8 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
// below. // below.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
int PNMFileTypeBMP::Reader:: int PNMFileTypeBMP::Reader::
read_data(xel *array, xelval *) { read_data(xel *array, xelval *alpha_array) {
BMPreadbits(array, _file, &pos, offBits, _x_size, _y_size, BMPreadbits(array, alpha_array, _file, &pos, offBits, _x_size, _y_size,
cBitCount, classv, indexed, R, G, B); cBitCount, classv, indexed, R, G, B);
if (pos != BMPlenfile(classv, cBitCount, _x_size, _y_size)) { if (pos != BMPlenfile(classv, cBitCount, _x_size, _y_size)) {