File xv-more-bmp-formats.patch of Package xv
From e1d01328aa87af48e17947304fe5bf08a9096419 Mon Sep 17 00:00:00 2001
From: "Matthew A. Lukowicz" <matt@pancakehut>
Date: Wed, 7 Feb 2024 00:08:25 -0500
Subject: [PATCH] Add support for more PC BMP formats.
---
src/xvbmp.c | 203 ++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 151 insertions(+), 52 deletions(-)
--- src/xvbmp.c
+++ src/xvbmp.c 2024-02-07 11:41:04.894069678 +0000
@@ -26,9 +26,13 @@
#define BI_JPEG 4 /* BMP version 5 (not yet supported) */
#define BI_PNG 5 /* BMP version 5 (not yet supported) */
-#define WIN_OS2_OLD 12
-#define WIN_NEW 40
-#define OS2_NEW 64
+#define BMPV2 12
+#define BMPV3 40
+#define MS_ADOBE_V2 52 /* FIXME: Loads with corrupt colors */
+#define MS_ADOBE_V3 56 /* FIXME: Loads with corrput colors */
+#define OS2_BMPV2 64
+#define BMPV4 108
+#define BMPV5 124
#if (defined(UINT_MAX) && UINT_MAX != 0xffffffffU)
# error XV's BMP code requires 32-bit unsigned integer type, but u_int isn't
@@ -36,14 +40,14 @@
static long filesize;
-static int loadBMP1 PARM((FILE *, byte *, u_int, u_int));
-static int loadBMP4 PARM((FILE *, byte *, u_int, u_int, u_int));
-static int loadBMP8 PARM((FILE *, byte *, u_int, u_int, u_int));
-static int loadBMP16 PARM((FILE *, byte *, u_int, u_int, u_int *));
-static int loadBMP24 PARM((FILE *, byte *, u_int, u_int, u_int));
-static int loadBMP32 PARM((FILE *, byte *, u_int, u_int, u_int *));
-static u_int getshort PARM((FILE *));
-static u_int getint PARM((FILE *));
+static int loadBMP1 PARM((FILE *, byte *, u_int, u_int, int));
+static int loadBMP4 PARM((FILE *, byte *, u_int, u_int, u_int, int));
+static int loadBMP8 PARM((FILE *, byte *, u_int, u_int, u_int, int));
+static int loadBMP16 PARM((FILE *, byte *, u_int, u_int, u_int *, int));
+static int loadBMP24 PARM((FILE *, byte *, u_int, u_int, u_int, int));
+static int loadBMP32 PARM((FILE *, byte *, u_int, u_int, u_int *, int));
+static u_int getshort PARM((FILE *));
+static u_int getint PARM((FILE *));
static void putshort PARM((FILE *, int));
static void putint PARM((FILE *, int));
static void writeBMP1 PARM((FILE *, byte *, int, int));
@@ -62,11 +66,13 @@ int LoadBMP(fname, pinfo)
/*******************************************/
{
FILE *fp;
- int i, c, c1, rv, bPad;
- u_int bfSize, bfOffBits, biSize, biWidth, biHeight, biPlanes;
+ int i, c, c1, rv, bPad, rightsideup = 0;
+ u_int bfSize, bfOffBits, biSize, biWidth, biPlanes;
u_int biBitCount, biCompression, biSizeImage, biXPelsPerMeter;
u_int biYPelsPerMeter, biClrUsed, biClrImportant;
+ u_int npixels;
u_int colormask[3];
+ int biHeight;
char buf[512], rgb_bits[16];
const char *cmpstr, *bname;
byte *pic24, *pic8;
@@ -95,7 +101,8 @@ int LoadBMP(fname, pinfo)
biSize = getint(fp);
- if (biSize == WIN_NEW || biSize == OS2_NEW) {
+ if (biSize == BMPV3 || biSize == OS2_BMPV2 ||biSize == MS_ADOBE_V2 ||
+ biSize == MS_ADOBE_V3 || biSize == BMPV4 || biSize == BMPV5) {
biWidth = getint(fp);
biHeight = getint(fp);
biPlanes = getshort(fp);
@@ -121,6 +128,22 @@ int LoadBMP(fname, pinfo)
biClrUsed = biClrImportant = 0;
}
+ /* Height could be negative for uncompressed BMP files if data is
+ stored right-side-up */
+ npixels = biWidth * biHeight;
+ if (biWidth != 0 && npixels/biWidth != biHeight && biCompression == BI_RGB) {
+ u_int negHeight, npixels2;
+
+ negHeight = biHeight * -1;
+ npixels2 = biWidth * negHeight;
+
+ if (npixels2/biWidth == negHeight) {
+ biHeight = negHeight;
+ npixels = npixels2;
+ rightsideup = 1;
+ }
+ }
+
if (DEBUG>1) {
fprintf(stderr,"\nLoadBMP:\tbfSize=%d, bfOffBits=%d\n",bfSize,bfOffBits);
fprintf(stderr,"\t\tbiSize=%d, biWidth=%d, biHeight=%d, biPlanes=%d\n",
@@ -140,7 +163,6 @@ int LoadBMP(fname, pinfo)
biPlanes!=1 || biCompression>BI_PNG ||
biWidth<=0 || biHeight<=0 ||
(biClrUsed && biClrUsed > (1 << biBitCount))) {
-
sprintf(buf,
"Unsupported BMP type (%dx%d, Bits=%d, Colors=%d, Planes=%d, "
"Compr=%d)",
@@ -175,7 +197,7 @@ int LoadBMP(fname, pinfo)
bPad = 0;
- if (biSize != WIN_OS2_OLD) {
+ if (biSize != BMPV2) {
/* skip ahead to colormap, using biSize */
c = biSize - 40; /* 40 bytes read from biSize to biClrImportant */
for (i=0; i<c; i++)
@@ -191,6 +213,9 @@ int LoadBMP(fname, pinfo)
bPad -= 12;
}
+ if (biClrUsed > (1 << biBitCount))
+ biClrUsed = (1 << biBitCount);
+
/* load up colormap, if any */
if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8) {
int i, cmaplen;
@@ -200,7 +225,7 @@ int LoadBMP(fname, pinfo)
pinfo->b[i] = getc(fp);
pinfo->g[i] = getc(fp);
pinfo->r[i] = getc(fp);
- if (biSize != WIN_OS2_OLD) {
+ if (biSize != BMPV2) {
getc(fp);
bPad -= 4;
}
@@ -218,7 +243,7 @@ int LoadBMP(fname, pinfo)
}
}
- if (biSize != WIN_OS2_OLD) {
+ if (biSize != BMPV2) {
/* Waste any unused bytes between the colour map (if present)
and the start of the actual bitmap data. */
@@ -231,21 +256,18 @@ int LoadBMP(fname, pinfo)
/* create pic8 or pic24 */
if (biBitCount==16 || biBitCount==24 || biBitCount==32) {
- u_int npixels = biWidth * biHeight;
u_int count = 3 * npixels;
if (biWidth == 0 || biHeight == 0 || npixels/biWidth != biHeight ||
count/3 != npixels)
return (bmpError(bname, "image dimensions too large"));
- pic24 = (byte *) calloc((size_t) count, (size_t) 1);
+ pic24 = (byte *) calloc((size_t) (count + 1), (size_t) 1);
if (!pic24) return (bmpError(bname, "couldn't malloc 'pic24'"));
}
else {
- u_int npixels = biWidth * biHeight;
-
if (biWidth == 0 || biHeight == 0 || npixels/biWidth != biHeight)
return (bmpError(bname, "image dimensions too large"));
- pic8 = (byte *) calloc((size_t) npixels, (size_t) 1);
+ pic8 = (byte *) calloc((size_t) (npixels + 1), (size_t) 1);
if (!pic8) return(bmpError(bname, "couldn't malloc 'pic8'"));
}
@@ -254,23 +276,24 @@ int LoadBMP(fname, pinfo)
/* load up the image */
switch (biBitCount) {
case 1:
- rv = loadBMP1(fp, pic8, biWidth, biHeight);
+ rv = loadBMP1(fp, pic8, biWidth, biHeight, rightsideup);
break;
case 4:
- rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression);
+ rv = loadBMP4(fp, pic8, biWidth, biHeight, biCompression, rightsideup);
break;
case 8:
- rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression);
+ rv = loadBMP8(fp, pic8, biWidth, biHeight, biCompression, rightsideup);
break;
case 16:
rv = loadBMP16(fp, pic24, biWidth, biHeight, /* v-- BI_RGB */
- biCompression == BI_BITFIELDS? colormask : NULL);
+ biCompression == BI_BITFIELDS? colormask : NULL,
+ rightsideup);
break;
default:
if (biBitCount == 32 && biCompression == BI_BITFIELDS)
- rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask);
+ rv = loadBMP32(fp, pic24, biWidth, biHeight, colormask, rightsideup);
else /* 24 or (32 and BI_RGB) */
- rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount);
+ rv = loadBMP24(fp, pic24, biWidth, biHeight, biBitCount, rightsideup);
break;
}
@@ -314,9 +337,14 @@ int LoadBMP(fname, pinfo)
pinfo->frmType = F_BMP;
pinfo->colType = F_FULLCOLOR;
- sprintf(pinfo->fullInfo, "%sBMP, %d bit%s per pixel%s. (%ld bytes)",
- ((biSize==WIN_OS2_OLD) ? "Old OS/2 " :
- (biSize==WIN_NEW) ? "Windows " : ""),
+ sprintf(pinfo->fullInfo, "%s, %d bit%s per pixel%s. (%ld bytes)",
+ ((biSize==BMPV2) ? "Windows BMP v2 " :
+ (biSize==BMPV3) ? "Windows BMP v3 " :
+ (biSize==MS_ADOBE_V2) ? "BITMAPV2INFOHEADER " :
+ (biSize==MS_ADOBE_V3) ? "BITMAPV3INFOHEADER " :
+ (biSize==OS2_BMPV2) ? "OS/2 BMP 2.0 " :
+ (biSize==BMPV4) ? "Windows BMP v4 " :
+ (biSize==BMPV5) ? "Windows BMP v5 " : ""),
biBitCount, (biBitCount == 1) ? "" : "s",
cmpstr, filesize);
@@ -333,19 +361,31 @@ int LoadBMP(fname, pinfo)
/*******************************************/
-static int loadBMP1(fp, pic8, w, h)
+static int loadBMP1(fp, pic8, w, h, rightsideup)
FILE *fp;
byte *pic8;
u_int w,h;
+ int rightsideup;
{
- int i,j,c,bitnum,padw;
+ int i,j,c,bitnum,padw,ibegin,iend,iinc;
byte *pp = pic8 + ((h - 1) * w);
size_t l = w*h;
c = 0;
padw = ((w + 31)/32) * 32; /* 'w', padded to be a multiple of 32 */
- for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
+ if (rightsideup) {
+ ibegin = 0;
+ iend = h;
+ iinc = 1;
+ }
+ else {
+ ibegin = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+
+ for (i = ibegin; i != iend && (pp - pic8 <= l); i += iinc) {
pp = pic8 + (i * w);
if ((i&0x3f)==0) WaitCursor();
for (j=bitnum=0; j<padw; j++,bitnum++) {
@@ -368,12 +408,14 @@ static int loadBMP1(fp, pic8, w, h)
/*******************************************/
-static int loadBMP4(fp, pic8, w, h, comp)
+static int loadBMP4(fp, pic8, w, h, comp, rightsideup)
FILE *fp;
byte *pic8;
u_int w,h,comp;
+ int rightsideup;
{
int i,j,c,c1,x,y,nybnum,padw,rv;
+ int begin, end, inc;
byte *pp = pic8 + ((h - 1) * w);
size_t l = w*h;
@@ -381,9 +423,20 @@ static int loadBMP4(fp, pic8, w, h, comp
c = c1 = 0;
if (comp == BI_RGB) { /* read uncompressed data */
+ if (rightsideup) {
+ begin = 0;
+ end = h;
+ inc = 1;
+ }
+ else {
+ begin = h-1;
+ end = -1;
+ inc = -1;
+ }
+
padw = ((w + 7)/8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
- for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
+ for (i = begin; i != end && (pp - pic8 <= l); i += inc) {
pp = pic8 + (i * w);
if ((i&0x3f)==0) WaitCursor();
@@ -454,24 +507,37 @@ static int loadBMP4(fp, pic8, w, h, comp
/*******************************************/
-static int loadBMP8(fp, pic8, w, h, comp)
+static int loadBMP8(fp, pic8, w, h, comp, rightsideup)
FILE *fp;
byte *pic8;
u_int w,h,comp;
+ int rightsideup;
{
int i,j,c,c1,padw,x,y,rv;
+ int begin, end, inc;
byte *pp = pic8 + ((h - 1) * w);
size_t l = w*h;
byte *pend;
rv = 0;
- pend = pic8 + w * h;
+ pend = pic8 + l;
if (comp == BI_RGB) { /* read uncompressed data */
+ if (rightsideup) {
+ begin = 0;
+ end = h;
+ inc = 1;
+ }
+ else {
+ begin = h-1;
+ end = -1;
+ inc = -1;
+ }
+
padw = ((w + 3)/4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
- for (i=h-1; i>=0 && (pp - pic8 <= l); i--) {
+ for (i = begin; i != end && (pp - pic8 <= l); i += inc) {
pp = pic8 + (i * w);
if ((i&0x3f)==0) WaitCursor();
@@ -534,12 +600,13 @@ static int loadBMP8(fp, pic8, w, h, comp
/*******************************************/
-static int loadBMP16(fp, pic24, w, h, mask)
+static int loadBMP16(fp, pic24, w, h, mask, rightsideup)
FILE *fp;
byte *pic24;
u_int w, h, *mask;
+ int rightsideup;
{
- int x, y;
+ int x, y, ybegin, yend, yinc;
byte *pp = pic24 + ((h - 1) * w * 3);
size_t l = w*h*3;
u_int buf, colormask[6];
@@ -611,7 +678,18 @@ static int loadBMP16(fp, pic24, w, h, ma
colorbits[2], colormask[2], bitshift[2], bitshift2[2],
colormask[5], bitshift[5], bitshift2[5]);
- for (y = h-1; y >= 0 && (pp - pic24 <= l); y--) {
+ if (rightsideup) {
+ ybegin = 0;
+ yend = h;
+ yinc = 1;
+ }
+ else {
+ ybegin = h-1;
+ yend = -1;
+ yinc = -1;
+ }
+
+ for (y = ybegin; y != yend && (pp - pic24 <= l); y += yinc) {
pp = pic24 + (3 * w * y);
if ((y&0x3f)==0) WaitCursor();
@@ -638,12 +716,13 @@ static int loadBMP16(fp, pic24, w, h, ma
/*******************************************/
-static int loadBMP24(fp, pic24, w, h, bits) /* also handles 32-bit BI_RGB */
+static int loadBMP24(fp, pic24, w, h, bits, rightsideup) /* also handles 32-bit BI_RGB */
FILE *fp;
byte *pic24;
u_int w,h, bits;
+ int rightsideup;
{
- int i,j,padb,rv;
+ int i,j,padb,rv,ibegin,iend,iinc;
byte *pp = pic24 + ((h - 1) * w * 3);
size_t l = w*h*3;
@@ -652,7 +731,18 @@ static int loadBMP24(fp, pic24, w, h, bi
padb = (4 - ((w*3) % 4)) & 0x03; /* # of pad bytes to read at EOscanline */
if (bits==32) padb = 0;
- for (i=h-1; i>=0; i--) {
+ if (rightsideup) {
+ ibegin = 0;
+ iend = h;
+ iinc = 1;
+ }
+ else {
+ ibegin = h-1;
+ iend = -1;
+ iinc = -1;
+ }
+
+ for (i=ibegin; i != iend; i+=iinc) {
pp = pic24 + (i * w * 3);
if ((i&0x3f)==0) WaitCursor();
@@ -676,12 +766,13 @@ static int loadBMP24(fp, pic24, w, h, bi
/*******************************************/
-static int loadBMP32(fp, pic24, w, h, colormask) /* 32-bit BI_BITFIELDS only */
+static int loadBMP32(fp, pic24, w, h, colormask, rightsideup) /* 32-bit BI_BITFIELDS only */
FILE *fp;
byte *pic24;
u_int w, h, *colormask;
+ int rightsideup;
{
- int x, y;
+ int x, y, ybegin, yend, yinc;
byte *pp;
u_int buf;
int i, bit, bitshift[3], colorbits[3], bitshift2[3];
@@ -722,7 +813,18 @@ static int loadBMP32(fp, pic24, w, h, co
colorbits[1], colormask[1], bitshift[1], bitshift2[1],
colorbits[2], colormask[2], bitshift[2], bitshift2[2]);
- for (y = h-1; y >= 0; y--) {
+ if (rightsideup) {
+ ybegin = 0;
+ yend = h;
+ yinc = 1;
+ }
+ else {
+ ybegin = h-1;
+ yend = -1;
+ yinc = -1;
+ }
+
+ for (y = ybegin; y != yend; y += yinc) {
pp = pic24 + (3 * w * y);
if ((y&0x3f)==0) WaitCursor();
@@ -1078,6 +1180,3 @@ static int bmpError(fname, st)
SetISTR(ISTR_WARNING,"%s: %s", fname, st);
return 0;
}
-
-
-