Exemple #1
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}