Commit 9f66a292 authored by Peter Kasting's avatar Peter Kasting Committed by Commit Bot

Support (and add more documentation on) a variety of uncommon BMP cases.

* "Bitmap Array" files (OS/2)
* BITMAPV2HEADER info headers (Photoshop?)
* BITMAPV3HEADER info headers (Photoshop?)
* BI_ALPHABITFIELDS compression (Windows CE)
* 2bpp palettes (Windows CE)
* Top-down bitmaps with RLE compression (illegal per spec, but supported by
  Windows and Firefox)
* Truncated color palettes

This increases the number of testcases Chrome can render on
http://entropymine.com/jason/bmpsuite/bmpsuite/html/bmpsuite.html .

Bug: 552274
Change-Id: I4c86b8328d326992a2ebca2e5178727aeab3afc0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1769524
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Commit-Queue: Leon Scroggins <scroggo@chromium.org>
Reviewed-by: default avatarLeon Scroggins <scroggo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690377}
parent 5b15998c
......@@ -98,21 +98,17 @@ bool BMPImageDecoder::DecodeHelper(bool only_size) {
bool BMPImageDecoder::ProcessFileHeader(size_t& img_data_offset) {
// Read file header.
DCHECK(!decoded_offset_);
if (data_->size() < kSizeOfFileHeader)
return false;
char buffer[kSizeOfFileHeader];
FastSharedBufferReader fast_reader(data_);
const char* file_header =
fast_reader.GetConsecutiveData(0, kSizeOfFileHeader, buffer);
const uint16_t file_type =
(file_header[0] << 8) | static_cast<uint8_t>(file_header[1]);
img_data_offset = BMPImageReader::ReadUint32(&file_header[10]);
decoded_offset_ = kSizeOfFileHeader;
char buffer[kSizeOfFileHeader];
const char* file_header;
uint16_t file_type;
if (!GetFileType(fast_reader, buffer, file_header, file_type))
return false;
// See if this is a bitmap filetype we understand.
enum {
BMAP = 0x424D, // "BM"
BITMAPARRAY = 0x4241, // "BA"
// The following additional OS/2 2.x header values (see
// http://www.fileformat.info/format/os2bmp/egff.htm ) aren't widely
// decoded, and are unlikely to be in much use.
......@@ -121,10 +117,32 @@ bool BMPImageDecoder::ProcessFileHeader(size_t& img_data_offset) {
POINTER = 0x5054, // "PT"
COLORICON = 0x4349, // "CI"
COLORPOINTER = 0x4350, // "CP"
BITMAPARRAY = 0x4241, // "BA"
*/
};
return (file_type == BMAP) || SetFailed();
if (file_type == BITMAPARRAY) {
// Skip initial 14-byte header, try to read the first entry as a BMAP.
decoded_offset_ += kSizeOfFileHeader;
if (!GetFileType(fast_reader, buffer, file_header, file_type))
return false;
}
if (file_type != BMAP)
return SetFailed();
img_data_offset = BMPImageReader::ReadUint32(&file_header[10]);
decoded_offset_ += kSizeOfFileHeader;
return true;
}
bool BMPImageDecoder::GetFileType(const FastSharedBufferReader& fast_reader,
char* buffer,
const char*& file_header,
uint16_t& file_type) const {
if (data_->size() - decoded_offset_ < kSizeOfFileHeader)
return false;
file_header = fast_reader.GetConsecutiveData(decoded_offset_,
kSizeOfFileHeader, buffer);
file_type = (file_header[0] << 8) | static_cast<uint8_t>(file_header[1]);
return true;
}
} // namespace blink
......@@ -37,6 +37,7 @@
namespace blink {
class BMPImageReader;
class FastSharedBufferReader;
// This class decodes the BMP image format.
class PLATFORM_EXPORT BMPImageDecoder final : public ImageDecoder {
......@@ -72,6 +73,14 @@ class PLATFORM_EXPORT BMPImageDecoder final : public ImageDecoder {
// file header could be decoded.
bool ProcessFileHeader(size_t& img_data_offset);
// Uses |fast_reader| and |buffer| to read the file header into |file_header|.
// Computes |file_type| from the file header. Returns whether there was
// sufficient data available to read the header.
bool GetFileType(const FastSharedBufferReader& fast_reader,
char* buffer,
const char*& file_header,
uint16_t& file_type) const;
// An index into |data_| representing how much we've already decoded.
// Note that this only tracks data _this_ class decodes; once the
// BMPImageReader takes over this will not be updated further.
......
......@@ -96,6 +96,7 @@ class PLATFORM_EXPORT BMPImageReader final {
BITFIELDS = 3,
JPEG = 4,
PNG = 5,
ALPHABITFIELDS = 6, // Windows CE only
// OS/2 2.x-only
HUFFMAN1D, // Stored in file as 3
RLE24, // Stored in file as 4
......@@ -154,16 +155,29 @@ class PLATFORM_EXPORT BMPImageReader final {
// of header values from the byte stream. Returns false on error.
bool ReadInfoHeader();
// Returns true if this is a Windows V4+ BMP.
inline bool IsWindowsV4Plus() const {
// Windows V4 info header is 108 bytes. V5 is 124 bytes.
return (info_header_.bi_size == 108) || (info_header_.bi_size == 124);
// Returns true if this BMP has an alpha mask in the info header
// (BITMAPV3HEADER+). See comments in ReadInfoHeader() for more.
inline bool HasAlphaMaskInHeader() const {
// BITMAPV3HEADER is 56 bytes; this is also a valid OS/2 2.x header size, so
// exclude that case.
return (info_header_.bi_size == 56 && !is_os22x_) || // BITMAPV3HEADER
(info_header_.bi_size == 108) || // BITMAPV4HEADER
(info_header_.bi_size == 124); // BITMAPV5HEADER
}
// Returns true if this BMP has RGB masks in the info header
// (BITMAPV2HEADER+). See comments in ReadInfoHeader() for more.
inline bool HasRGBMasksInHeader() const {
// BITMAPV2HEADER is 52 bytes; this is also a valid OS/2 2.x header size, so
// exclude that case.
return (info_header_.bi_size == 52 && !is_os22x_) || // BITMAPV2HEADER
HasAlphaMaskInHeader(); // BITMAPV3HEADER+
}
// Returns false if consistency errors are found in the info header.
bool IsInfoHeaderValid() const;
// For BI_BITFIELDS images, initializes the bit_masks_[] and
// For BI_[ALPHA]BITFIELDS images, initializes the bit_masks_[] and
// bit_offsets_[] arrays. ProcessInfoHeader() will initialize these for
// other compression types where needed.
bool ProcessBitmasks();
......
......@@ -62,7 +62,7 @@ inline bool MatchesCURSignature(const char* contents) {
}
inline bool MatchesBMPSignature(const char* contents) {
return !memcmp(contents, "BM", 2);
return !memcmp(contents, "BM", 2) || !memcmp(contents, "BA", 2);
}
static constexpr size_t kLongestSignatureLength = sizeof("RIFF????WEBPVP") - 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment