bool BMPImageReader::readInfoHeaderSize() { // Get size of info header. ASSERT(m_decodedOffset == m_headerOffset); if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < 4)) return false; m_infoHeader.biSize = readUint32(0); // Don't increment m_decodedOffset here, it just makes the code in // processInfoHeader() more confusing. // Don't allow the header to overflow (which would be harmless here, but // problematic or at least confusing in other places), or to overrun the // image data. const size_t headerEnd = m_headerOffset + m_infoHeader.biSize; if ((headerEnd < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < headerEnd))) return m_parent->setFailed(); // See if this is a header size we understand: // OS/2 1.x: 12 if (m_infoHeader.biSize == 12) m_isOS21x = true; // Windows V3: 40 else if ((m_infoHeader.biSize == 40) || isWindowsV4Plus()) ; // OS/2 2.x: any multiple of 4 between 16 and 64, inclusive, or 42 or 46 else if ((m_infoHeader.biSize >= 16) && (m_infoHeader.biSize <= 64) && (!(m_infoHeader.biSize & 3) || (m_infoHeader.biSize == 42) || (m_infoHeader.biSize == 46))) m_isOS22x = true; else return m_parent->setFailed(); return true; }
bool BMPImageReader::processBitmasks() { // Create m_bitMasks[] values. if (m_infoHeader.biCompression != BITFIELDS) { // The format doesn't actually use bitmasks. To simplify the decode // logic later, create bitmasks for the RGB data. For Windows V4+, // this overwrites the masks we read from the header, which are // supposed to be ignored in non-BITFIELDS cases. // 16 bits: MSB <- xRRRRRGG GGGBBBBB -> LSB // 24/32 bits: MSB <- [AAAAAAAA] RRRRRRRR GGGGGGGG BBBBBBBB -> LSB const int numBits = (m_infoHeader.biBitCount == 16) ? 5 : 8; for (int i = 0; i <= 2; ++i) m_bitMasks[i] = ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^ ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1); // For Windows V4+ 32-bit RGB, don't overwrite the alpha mask from the // header (see note in readInfoHeader()). if (m_infoHeader.biBitCount < 32) m_bitMasks[3] = 0; else if (!isWindowsV4Plus()) m_bitMasks[3] = static_cast<uint32_t>(0xff000000); } else if (!isWindowsV4Plus()) { // For Windows V4+ BITFIELDS mode bitmaps, this was already done when // we read the info header. // Fail if we don't have enough file space for the bitmasks. static const size_t SIZEOF_BITMASKS = 12; if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) return setFailed(); // Read bitmasks. if ((m_data->size() - m_decodedOffset) < SIZEOF_BITMASKS) return false; m_bitMasks[0] = readUint32(0); m_bitMasks[1] = readUint32(4); m_bitMasks[2] = readUint32(8); // No alpha in anything other than Windows V4+. m_bitMasks[3] = 0; m_decodedOffset += SIZEOF_BITMASKS; } // We've now decoded all the non-image data we care about. Skip anything // else before the actual raster data. if (m_imgDataOffset) m_decodedOffset = m_imgDataOffset; m_needToProcessBitmasks = false; // Check masks and set shift values. for (int i = 0; i < 4; ++i) { // Trim the mask to the allowed bit depth. Some Windows V4+ BMPs // specify a bogus alpha channel in bits that don't exist in the pixel // data (for example, bits 25-31 in a 24-bit RGB format). if (m_infoHeader.biBitCount < 32) m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1); // For empty masks (common on the alpha channel, especially after the // trimming above), quickly clear the shifts and continue, to avoid an // infinite loop in the counting code below. uint32_t tempMask = m_bitMasks[i]; if (!tempMask) { m_bitShiftsRight[i] = m_bitShiftsLeft[i] = 0; continue; } // Make sure bitmask does not overlap any other bitmasks. for (int j = 0; j < i; ++j) { if (tempMask & m_bitMasks[j]) return setFailed(); } // Count offset into pixel data. for (m_bitShiftsRight[i] = 0; !(tempMask & 1); tempMask >>= 1) ++m_bitShiftsRight[i]; // Count size of mask. for (m_bitShiftsLeft[i] = 8; tempMask & 1; tempMask >>= 1) --m_bitShiftsLeft[i]; // Make sure bitmask is contiguous. if (tempMask) return setFailed(); // Since RGBABuffer tops out at 8 bits per channel, adjust the shift // amounts to use the most significant 8 bits of the channel. if (m_bitShiftsLeft[i] < 0) { m_bitShiftsRight[i] -= m_bitShiftsLeft[i]; m_bitShiftsLeft[i] = 0; } } return true; }
bool BMPImageReader::readInfoHeader() { // Pre-initialize some fields that not all headers set. m_infoHeader.biCompression = RGB; m_infoHeader.biClrUsed = 0; if (m_isOS21x) { m_infoHeader.biWidth = readUint16(4); m_infoHeader.biHeight = readUint16(6); ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2! m_infoHeader.biBitCount = readUint16(10); return true; } m_infoHeader.biWidth = readUint32(4); m_infoHeader.biHeight = readUint32(8); if (m_andMaskState != None) m_infoHeader.biHeight /= 2; m_infoHeader.biBitCount = readUint16(14); // Read compression type, if present. if (m_infoHeader.biSize >= 20) { uint32_t biCompression = readUint32(16); // Detect OS/2 2.x-specific compression types. if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { m_infoHeader.biCompression = HUFFMAN1D; m_isOS22x = true; } else if ((biCompression == 4) && (m_infoHeader.biBitCount == 24)) { m_infoHeader.biCompression = RLE24; m_isOS22x = true; } else if (biCompression > 5) return setFailed(); // Some type we don't understand. else m_infoHeader.biCompression = static_cast<CompressionType>(biCompression); } // Read colors used, if present. if (m_infoHeader.biSize >= 36) m_infoHeader.biClrUsed = readUint32(32); // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do // that here. If the bit depth is less than 16, these values will be // ignored by the image data decoders. If the bit depth is at least 16 but // the compression format isn't BITFIELDS, these values will be ignored and // overwritten* in processBitmasks(). // NOTE: We allow alpha here. Microsoft doesn't really document this well, // but some BMPs appear to use it. // // For non-Windows V4+, m_bitMasks[] et. al will be initialized later // during processBitmasks(). // // *Except the alpha channel. Bizarrely, some RGB bitmaps expect decoders // to pay attention to the alpha mask here, so there's a special case in // processBitmasks() that doesn't always overwrite that value. if (isWindowsV4Plus()) { m_bitMasks[0] = readUint32(40); m_bitMasks[1] = readUint32(44); m_bitMasks[2] = readUint32(48); m_bitMasks[3] = readUint32(52); } // Detect top-down BMPs. if (m_infoHeader.biHeight < 0) { m_isTopDown = true; m_infoHeader.biHeight = -m_infoHeader.biHeight; } return true; }
bool BMPImageReader::processBitmasks() { // Create m_bitMasks[] values for R/G/B. if (m_infoHeader.biCompression != BITFIELDS) { // The format doesn't actually use bitmasks. To simplify the decode // logic later, create bitmasks for the RGB data. For Windows V4+, // this overwrites the masks we read from the header, which are // supposed to be ignored in non-BITFIELDS cases. // 16 bits: MSB <- xRRRRRGG GGGBBBBB -> LSB // 24/32 bits: MSB <- [AAAAAAAA] RRRRRRRR GGGGGGGG BBBBBBBB -> LSB const int numBits = (m_infoHeader.biBitCount == 16) ? 5 : 8; for (int i = 0; i <= 2; ++i) m_bitMasks[i] = ((static_cast<uint32_t>(1) << (numBits * (3 - i))) - 1) ^ ((static_cast<uint32_t>(1) << (numBits * (2 - i))) - 1); } else if (!isWindowsV4Plus()) { // For Windows V4+ BITFIELDS mode bitmaps, this was already done when // we read the info header. // Fail if we don't have enough file space for the bitmasks. static const size_t SIZEOF_BITMASKS = 12; if (((m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS) < (m_headerOffset + m_infoHeader.biSize)) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize + SIZEOF_BITMASKS)))) return m_parent->setFailed(); // Read bitmasks. if ((m_data->size() - m_decodedOffset) < SIZEOF_BITMASKS) return false; m_bitMasks[0] = readUint32(0); m_bitMasks[1] = readUint32(4); m_bitMasks[2] = readUint32(8); m_decodedOffset += SIZEOF_BITMASKS; } // Alpha is a poorly-documented and inconsistently-used feature. // // Windows V4+ has an alpha bitmask in the info header. Unlike the R/G/B // bitmasks, the MSDN docs don't indicate that it is only valid for the // BITFIELDS compression format, so we respect it at all times. // // To complicate things, Windows V3 BMPs, which lack this mask, can specify // 32bpp format, which to any sane reader would imply an 8-bit alpha // channel -- and for BMPs-in-ICOs, that's precisely what's intended to // happen. There also exist standalone BMPs in this format which clearly // expect the alpha channel to be respected. However, there are many other // BMPs which, for example, fill this channel with all 0s, yet clearly // expect to not be displayed as a fully-transparent rectangle. // // If these were the only two types of Windows V3, 32bpp BMPs in the wild, // we could distinguish between them by scanning the alpha channel in the // image, looking for nonzero values, and only enabling alpha if we found // some. (It turns out we have to do this anyway, because, crazily, there // are also Windows V4+ BMPs with an explicit, non-zero alpha mask, which // then zero-fill their alpha channels! See comments in // processNonRLEData().) // // Unfortunately there are also V3 BMPs -- indeed, probably more than the // number of 32bpp, V3 BMPs which intentionally use alpha -- which specify // 32bpp format, use nonzero (and non-255) alpha values, and yet expect to // be rendered fully-opaque. And other browsers do so. // // So it's impossible to display every BMP in the way its creators intended, // and we have to choose what to break. Given the paragraph above, we match // other browsers and ignore alpha in Windows V3 BMPs except inside ICO // files. if (!isWindowsV4Plus()) m_bitMasks[3] = (m_isInICO && (m_infoHeader.biCompression != BITFIELDS) && (m_infoHeader.biBitCount == 32)) ? static_cast<uint32_t>(0xff000000) : 0; // We've now decoded all the non-image data we care about. Skip anything // else before the actual raster data. if (m_imgDataOffset) m_decodedOffset = m_imgDataOffset; m_needToProcessBitmasks = false; // Check masks and set shift and LUT address values. for (int i = 0; i < 4; ++i) { // Trim the mask to the allowed bit depth. Some Windows V4+ BMPs // specify a bogus alpha channel in bits that don't exist in the pixel // data (for example, bits 25-31 in a 24-bit RGB format). if (m_infoHeader.biBitCount < 32) m_bitMasks[i] &= ((static_cast<uint32_t>(1) << m_infoHeader.biBitCount) - 1); // For empty masks (common on the alpha channel, especially after the // trimming above), quickly clear the shift and LUT address and // continue, to avoid an infinite loop in the counting code below. uint32_t tempMask = m_bitMasks[i]; if (!tempMask) { m_bitShiftsRight[i] = 0; m_lookupTableAddresses[i] = 0; continue; } // Make sure bitmask does not overlap any other bitmasks. for (int j = 0; j < i; ++j) { if (tempMask & m_bitMasks[j]) return m_parent->setFailed(); } // Count offset into pixel data. for (m_bitShiftsRight[i] = 0; !(tempMask & 1); tempMask >>= 1) ++m_bitShiftsRight[i]; // Count size of mask. size_t numBits = 0; for (; tempMask & 1; tempMask >>= 1) ++numBits; // Make sure bitmask is contiguous. if (tempMask) return m_parent->setFailed(); // Since RGBABuffer tops out at 8 bits per channel, adjust the shift // amounts to use the most significant 8 bits of the channel. if (numBits >= 8) { m_bitShiftsRight[i] += (numBits - 8); numBits = 0; } // Calculate LUT address. m_lookupTableAddresses[i] = numBits ? (nBitTo8BitlookupTable + (1 << numBits) - 2) : 0; } return true; }
bool BMPImageReader::readInfoHeader() { // Pre-initialize some fields that not all headers set. m_infoHeader.biCompression = RGB; m_infoHeader.biClrUsed = 0; if (m_isOS21x) { m_infoHeader.biWidth = readUint16(4); m_infoHeader.biHeight = readUint16(6); ASSERT(!m_isInICO); // ICO is a Windows format, not OS/2! m_infoHeader.biBitCount = readUint16(10); return true; } m_infoHeader.biWidth = readUint32(4); m_infoHeader.biHeight = readUint32(8); if (m_isInICO) m_infoHeader.biHeight /= 2; m_infoHeader.biBitCount = readUint16(14); // Read compression type, if present. if (m_infoHeader.biSize >= 20) { uint32_t biCompression = readUint32(16); // Detect OS/2 2.x-specific compression types. if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { m_infoHeader.biCompression = HUFFMAN1D; m_isOS22x = true; } else if ((biCompression == 4) && (m_infoHeader.biBitCount == 24)) { m_infoHeader.biCompression = RLE24; m_isOS22x = true; } else if (biCompression > 5) return m_parent->setFailed(); // Some type we don't understand. else m_infoHeader.biCompression = static_cast<CompressionType>(biCompression); } // Read colors used, if present. if (m_infoHeader.biSize >= 36) m_infoHeader.biClrUsed = readUint32(32); // Windows V4+ can safely read the four bitmasks from 40-56 bytes in, so do // that here. If the bit depth is less than 16, these values will be ignored // by the image data decoders. If the bit depth is at least 16 but the // compression format isn't BITFIELDS, the RGB bitmasks will be ignored and // overwritten in processBitmasks(). (The alpha bitmask will never be // overwritten: images that actually want alpha have to specify a valid // alpha mask. See comments in processBitmasks().) // // For non-Windows V4+, m_bitMasks[] et. al will be initialized later // during processBitmasks(). if (isWindowsV4Plus()) { m_bitMasks[0] = readUint32(40); m_bitMasks[1] = readUint32(44); m_bitMasks[2] = readUint32(48); m_bitMasks[3] = readUint32(52); } // Detect top-down BMPs. if (m_infoHeader.biHeight < 0) { m_isTopDown = true; m_infoHeader.biHeight = -m_infoHeader.biHeight; } return true; }