diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-05-09 03:19:16 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-05-09 03:19:16 +0000 |
commit | c2f873dc0560e36d181b12f450f659bfdb621b08 (patch) | |
tree | 8763f5667dd24555ec6d64e8786ae68d37cca920 | |
parent | 7a0dbb463c55783da12c0d25aaebf6f234a8e457 (diff) | |
download | netpbm-mirror-c2f873dc0560e36d181b12f450f659bfdb621b08.tar.gz netpbm-mirror-c2f873dc0560e36d181b12f450f659bfdb621b08.tar.xz netpbm-mirror-c2f873dc0560e36d181b12f450f659bfdb621b08.zip |
Fix handling of V4 and V5 Windows BMP - didn't work at all
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2770 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r-- | converter/bmp.h | 89 | ||||
-rw-r--r-- | converter/other/bmptopnm.c | 219 | ||||
-rw-r--r-- | doc/HISTORY | 2 |
3 files changed, 226 insertions, 84 deletions
diff --git a/converter/bmp.h b/converter/bmp.h index f2355929..78c469d1 100644 --- a/converter/bmp.h +++ b/converter/bmp.h @@ -83,7 +83,17 @@ #include "pm.h" /* For pm_error() */ -enum bmpClass {C_WIN, C_OS2}; +enum bmpClass { + BMP_C_OS2_1x, + BMP_C_OS2_2x, + BMP_C_WIN_V1, + BMP_C_WIN_V2, + BMP_C_WIN_V3, + BMP_C_WIN_V4, + BMP_C_WIN_V5 +}; + + static __inline__ const char * BMPClassName(enum bmpClass const class) { @@ -91,8 +101,13 @@ BMPClassName(enum bmpClass const class) { const char * name; switch (class) { - case C_OS2: name = "OS/2 (v1)"; break; - case C_WIN: name = "Windows (v1)"; break; + case BMP_C_OS2_1x: name = "OS/2 (v1)"; break; + case BMP_C_OS2_2x: name = "OS/2 (v2)"; break; + case BMP_C_WIN_V1: name = "Windows (v1)"; break; + case BMP_C_WIN_V2: name = "Windows (v2)"; break; + case BMP_C_WIN_V3: name = "Windows (v3)"; break; + case BMP_C_WIN_V4: name = "Windows (v4)"; break; + case BMP_C_WIN_V5: name = "Windows (v5)"; break; } return name; @@ -167,14 +182,66 @@ BMPleninfoheader(enum bmpClass const class) { unsigned int retval; switch (class) { - case C_WIN: retval = BMP_HDRLEN_WIN_V1; break; - case C_OS2: retval = BMP_HDRLEN_OS2_1x; break; + case BMP_C_WIN_V1: retval = BMP_HDRLEN_WIN_V1; break; + case BMP_C_WIN_V2: retval = BMP_HDRLEN_WIN_V2; break; + case BMP_C_WIN_V3: retval = BMP_HDRLEN_WIN_V3; break; + case BMP_C_WIN_V4: retval = BMP_HDRLEN_WIN_V4; break; + case BMP_C_WIN_V5: retval = BMP_HDRLEN_WIN_V5; break; + case BMP_C_OS2_1x: retval = BMP_HDRLEN_OS2_1x; break; + case BMP_C_OS2_2x: retval = BMP_HDRLEN_OS2_2x; break; } return retval; } +static __inline__ void +BMPdetermineclass(unsigned int const infoHdrLen, + enum bmpClass * const classP, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Determine the class of BMP, based on the fact that the info header is + 'infoHdrLen' bytes long. +-----------------------------------------------------------------------------*/ + switch (infoHdrLen) { + case BMP_HDRLEN_OS2_1x: *errorP = NULL; *classP = BMP_C_OS2_1x; break; + case BMP_HDRLEN_OS2_2x: *errorP = NULL; *classP = BMP_C_OS2_2x; break; + case BMP_HDRLEN_WIN_V1: *errorP = NULL; *classP = BMP_C_WIN_V1; break; + case BMP_HDRLEN_WIN_V2: *errorP = NULL; *classP = BMP_C_WIN_V2; break; + case BMP_HDRLEN_WIN_V3: *errorP = NULL; *classP = BMP_C_WIN_V3; break; + case BMP_HDRLEN_WIN_V4: *errorP = NULL; *classP = BMP_C_WIN_V4; break; + case BMP_HDRLEN_WIN_V5: *errorP = NULL; *classP = BMP_C_WIN_V5; break; + + default: + pm_asprintf(errorP, "Not one of the 7 lengths we recognize"); + } +} + + + +static __inline__ unsigned int +BMPlenrgb(enum bmpClass const class) { + + unsigned int lenrgb; + + switch (class) { + case BMP_C_OS2_1x: + case BMP_C_OS2_2x: + lenrgb = 3; + break; + case BMP_C_WIN_V1: + case BMP_C_WIN_V2: + case BMP_C_WIN_V3: + case BMP_C_WIN_V4: + case BMP_C_WIN_V5: + lenrgb = 4; + break; + } + return lenrgb; +} + + + static __inline__ unsigned int BMPlencolormap(enum bmpClass const class, unsigned int const bitcount, @@ -186,7 +253,6 @@ BMPlencolormap(enum bmpClass const class, 'cmapsize' == 0 means there is no palette. -----------------------------------------------------------------------------*/ - unsigned int lenrgb; unsigned int lencolormap; if (bitcount < 1) @@ -194,15 +260,10 @@ BMPlencolormap(enum bmpClass const class, else if (bitcount > 8) lencolormap = 0; else { - switch (class) { - case C_WIN: lenrgb = 4; break; - case C_OS2: lenrgb = 3; break; - } - - if (!cmapsize) - lencolormap = (1 << bitcount) * lenrgb; + if (cmapsize) + lencolormap = cmapsize * BMPlenrgb(class); else - lencolormap = cmapsize * lenrgb; + lencolormap = (1 << bitcount) * BMPlenrgb(class); } return lencolormap; } diff --git a/converter/other/bmptopnm.c b/converter/other/bmptopnm.c index d57bfba9..8c2b657e 100644 --- a/converter/other/bmptopnm.c +++ b/converter/other/bmptopnm.c @@ -80,6 +80,19 @@ struct pixelformat { */ }; +typedef struct { + /* These are all encodings of floating point */ + unsigned long x; + unsigned long y; + unsigned long z; +} cieXyz; + +typedef struct { + cieXyz red; + cieXyz grn; + cieXyz blu; +} cieXyzTriple; + struct bmpInfoHeader { enum rowOrder rowOrder; unsigned int cols; @@ -103,6 +116,7 @@ struct bmpInfoHeader { unsigned short cPlanes; BMPCompType compression; struct pixelformat pixelformat; + cieXyzTriple endPoints; }; @@ -208,21 +222,30 @@ GetLong(FILE * const fp) { -typedef struct { - long dummy[12]; -} cieXyzTriple; +static cieXyz +GetCieXyz(FILE * const ifP) { + + cieXyz retval; + + retval.x = GetLong(ifP); + retval.y = GetLong(ifP); + retval.z = GetLong(ifP); + + return retval; +} + + static cieXyzTriple -GetCieXyzTriple(FILE * const fp) { +GetCieXyzTriple(FILE * const ifP) { - cieXyzTriple v; - unsigned int i; + cieXyzTriple retval; - for (i = 0; i < 12; ++i) - if (pm_readlittlelong(fp, &v.dummy[i]) == -1) - pm_error(er_read, ifname); + retval.red = GetCieXyz(ifP); + retval.grn = GetCieXyz(ifP); + retval.blu = GetCieXyz(ifP); - return v; + return retval; } @@ -274,14 +297,12 @@ bmpReadfileheader(FILE * const ifP, static void -readOs2InfoHeader(FILE * const ifP, - struct bmpInfoHeader * const headerP) { +readOs2InfoHeaderRest(FILE * const ifP, + struct bmpInfoHeader * const headerP) { unsigned short colsField, rowsField; unsigned short planesField, bitCountField; - headerP->class = C_OS2; - pm_readlittleshortu(ifP, &colsField); if (colsField == 0) pm_error("Invalid BMP file: says width is zero"); @@ -317,9 +338,6 @@ readOs2InfoHeader(FILE * const ifP, headerP->cBitCount); headerP->compression = BMPCOMP_RGB; - - pm_message("OS/2 BMP, %dx%dx%d", - headerP->cols, headerP->rows, headerP->cBitCount); } @@ -367,8 +385,6 @@ readWindowsBasic40ByteInfoHeader(FILE * const ifP, int colorsused; /* ColorsUsed value from header */ unsigned short planesField, bitCountField; - headerP->class = C_WIN; - headerP->cols = GetLong(ifP); if (headerP->cols == 0) pm_error("Invalid BMP file: says width is zero"); @@ -541,7 +557,15 @@ defaultPixelformat(unsigned int const bitCount) { static void readV4InfoHeaderExtension(FILE * const ifP, - struct bmpInfoHeader * const headerP) { + struct bmpInfoHeader * const headerP, + unsigned int * const bytesReadP) { + + unsigned long redMsk, grnMsk, bluMsk, trnMsk; + + redMsk = GetLong(ifP); + grnMsk = GetLong(ifP); + bluMsk = GetLong(ifP); + trnMsk = GetLong(ifP); if (headerP->bitFields) { /* A document from Microsoft says on Windows 95 there is no @@ -549,25 +573,44 @@ readV4InfoHeaderExtension(FILE * const ifP, (5,5,5) or (5,6,5) for 16 bit and (8,8,8) for 32 bit. It calls these RGB555, RGB565, RGB888. */ - headerP->pixelformat.red = bitPositionFromMask(GetLong(ifP)); - headerP->pixelformat.grn = bitPositionFromMask(GetLong(ifP)); - headerP->pixelformat.blu = bitPositionFromMask(GetLong(ifP)); - headerP->pixelformat.trn = bitPositionFromMask(GetLong(ifP)); + headerP->pixelformat.red = bitPositionFromMask(redMsk); + headerP->pixelformat.grn = bitPositionFromMask(grnMsk); + headerP->pixelformat.blu = bitPositionFromMask(bluMsk); + headerP->pixelformat.trn = bitPositionFromMask(trnMsk); computeConventionalBgr(&headerP->pixelformat, headerP->cBitCount); } else headerP->pixelformat = defaultPixelformat(headerP->cBitCount); GetLong(ifP); /* Color space */ - GetCieXyzTriple(ifP); /* Endpoints */ + + headerP->endPoints = GetCieXyzTriple(ifP); /* 36 bytes */ + GetLong(ifP); /* GammaRed */ GetLong(ifP); /* GammaGreen */ GetLong(ifP); /* GammaBlue */ + + *bytesReadP = 68; } static void +readV5InfoHeaderExtension(FILE * const ifP, + struct bmpInfoHeader * const headerP, + unsigned int * const bytesReadP) { + + GetLong(ifP); /* Intent */ + GetLong(ifP); /* ProfileData */ + GetLong(ifP); /* ProfileSize */ + GetLong(ifP); /* Reserved */ + + *bytesReadP = 16; +} + + + +static void defaultV4InfoHeaderExtension(struct bmpInfoHeader * const headerP) { headerP->pixelformat = defaultPixelformat(headerP->cBitCount); @@ -577,9 +620,9 @@ defaultV4InfoHeaderExtension(struct bmpInfoHeader * const headerP) { static void -readWindowsInfoHeader(FILE * const ifP, - unsigned int const cInfoHeaderSize, - struct bmpInfoHeader * const headerP) { +readWindowsInfoHeaderRest(FILE * const ifP, + unsigned int const cInfoHeaderSize, + struct bmpInfoHeader * const headerP) { /* There are 3 major formats of Windows BMP, identified by the 3 info header lengths. The original @@ -587,23 +630,34 @@ readWindowsInfoHeader(FILE * const ifP, new with Windows 95 and NT 4.0. The "V5 header" is 124 bytes and was new with Windows 98 and Windows 2000. */ + unsigned int bytesRead; + readWindowsBasic40ByteInfoHeader(ifP, headerP); - if (cInfoHeaderSize >= 108) - readV4InfoHeaderExtension(ifP, headerP); - else + bytesRead = 40; + + if (cInfoHeaderSize >= BMP_HDRLEN_WIN_V4) { + unsigned int v4BytesRead; + readV4InfoHeaderExtension(ifP, headerP, &v4BytesRead); + bytesRead += v4BytesRead; + + assert(bytesRead == BMP_HDRLEN_WIN_V4); + } else defaultV4InfoHeaderExtension(headerP); - if (cInfoHeaderSize >= 124) { - /* Read off the V5 info header extension. */ - GetLong(ifP); /* Intent */ - GetLong(ifP); /* ProfileData */ - GetLong(ifP); /* ProfileSize */ - GetLong(ifP); /* Reserved */ + if (cInfoHeaderSize >= BMP_HDRLEN_WIN_V5) { + unsigned int v5BytesRead; + readV5InfoHeaderExtension(ifP, headerP, &v5BytesRead); + bytesRead += v5BytesRead; + assert(bytesRead == BMP_HDRLEN_WIN_V5); } - pm_message("Windows BMP, %dx%dx%d", - headerP->cols, headerP->rows, headerP->cBitCount); + for (; bytesRead < cInfoHeaderSize;) { + GetByte(ifP); + ++bytesRead; + } + + assert(bytesRead == cInfoHeaderSize); } @@ -611,25 +665,36 @@ readWindowsInfoHeader(FILE * const ifP, static void bmpReadinfoheader(FILE * const ifP, unsigned int * const bytesReadP, - struct bmpInfoHeader * const headerP) { + struct bmpInfoHeader * const headerP, + const char ** const errorP) { unsigned int const cInfoHeaderSize = GetLong(ifP); - switch (cInfoHeaderSize) { - case 12: - readOs2InfoHeader(ifP, headerP); - break; - case 40: - case 108: - case 124: - readWindowsInfoHeader(ifP, cInfoHeaderSize, headerP); - break; - default: - pm_error("%s: unknown Info Header size: %u bytes", - ifname, cInfoHeaderSize); - break; + const char * error; + + BMPdetermineclass(cInfoHeaderSize, &headerP->class, &error); + + if (error) { + pm_asprintf(errorP, "Cannot determine the class of BMP from the " + "info header size %u. %s", cInfoHeaderSize, error); + pm_strfree(error); + } else { + switch (headerP->class) { + case BMP_C_WIN_V1: + case BMP_C_WIN_V2: + case BMP_C_WIN_V3: + case BMP_C_WIN_V4: + case BMP_C_WIN_V5: + readWindowsInfoHeaderRest(ifP, cInfoHeaderSize, headerP); + break; + case BMP_C_OS2_1x: + case BMP_C_OS2_2x: + readOs2InfoHeaderRest(ifP, headerP); + break; + } + *errorP = NULL; + *bytesReadP = cInfoHeaderSize; } - *bytesReadP = cInfoHeaderSize; } @@ -676,11 +741,12 @@ bmpReadColormap(FILE * const ifP, bytesRead += 3; - if (class == C_WIN) { + for (i = 3; i < BMPlenrgb(class); ++i) { GetByte(ifP); bytesRead += 1; } } + *colormapP = colormap; *bytesReadP = bytesRead; } @@ -1190,19 +1256,28 @@ bmpReadraster(FILE * const ifP, static void reportHeader(struct bmpInfoHeader const header, - unsigned int const offBits) { + unsigned int const offBits, + bool const verbose) { - pm_message("BMP image header says:"); - pm_message(" Class of BMP: %s", BMPClassName(header.class)); - pm_message(" Width: %d pixels", header.cols); - pm_message(" Height: %d pixels", header.rows); - pm_message(" Depth: %d planes", header.cPlanes); - pm_message(" Row order: %s", - header.rowOrder == BOTTOMUP ? "bottom up" : "top down"); - pm_message(" Byte offset of raster within file: %u", offBits); - pm_message(" Bits per pixel in raster: %u", header.cBitCount); - pm_message(" Compression: %s", BMPCompTypeName(header.compression)); - pm_message(" Colors in color map: %u", header.cmapsize); + if (verbose) { + pm_message("BMP image header says:"); + pm_message(" Class of BMP: %s", BMPClassName(header.class)); + pm_message(" Width: %d pixels", header.cols); + pm_message(" Height: %d pixels", header.rows); + pm_message(" Depth: %d planes", header.cPlanes); + pm_message(" Row order: %s", + header.rowOrder == BOTTOMUP ? "bottom up" : "top down"); + pm_message(" Byte offset of raster within file: %u", offBits); + pm_message(" Bits per pixel in raster: %u", header.cBitCount); + pm_message(" Compression: %s", BMPCompTypeName(header.compression)); + pm_message(" Colors in color map: %u", header.cmapsize); + } else { + pm_message("%s BMP, %ux%ux%u", + BMPClassName(header.class), + header.cols, + header.rows, + header.cBitCount); + } } @@ -1340,14 +1415,18 @@ readBmp(FILE * const ifP, } { unsigned int bytesRead; - bmpReadinfoheader(ifP, &bytesRead, &bmpHeader); + const char * error; + bmpReadinfoheader(ifP, &bytesRead, &bmpHeader, &error); + if (error) + pm_error("Failed to read the BMP info header. Image may " + "not be a valid BMP. %s", error); + if (verbose) pm_message("Read %u bytes of header", bytesRead); pos += bytesRead; } - if (verbose) - reportHeader(bmpHeader, offBits); + reportHeader(bmpHeader, offBits, verbose); warnIfOffBitsWrong(bmpHeader, offBits); diff --git a/doc/HISTORY b/doc/HISTORY index 4a23ffb6..03f676ae 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -6,6 +6,8 @@ CHANGE HISTORY not yet BJH Release 10.75.00 + bmptopnm: Add ability to convert Version 4 and 5 Windows BMP. + pbmtext: remove undocumented -dump option; add 'genfontc' development tool (buildtools/ directory) to replace it. |