📄 bmpimagereader.cpp
字号:
/* * Copyright (c) 2008, 2009, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#include "BMPImageReader.h"namespace WebCore {BMPImageReader::BMPImageReader() : m_decodedOffset(0) , m_headerOffset(0) , m_imgDataOffset(0) , m_andMaskState(None) , m_isOS21x(false) , m_isOS22x(false) , m_isTopDown(false) , m_needToProcessBitmasks(false) , m_needToProcessColorTable(false) , m_tableSizeInBytes(0) , m_seenNonZeroAlphaPixel(false) , m_seenZeroAlphaPixel(false){ m_frameBufferCache.resize(1); // Clue-in decodeBMP() that we need to detect the correct info header size. memset(&m_infoHeader, 0, sizeof(m_infoHeader));}void BMPImageReader::setData(SharedBuffer* data, bool allDataReceived){ ImageDecoder::setData(data, allDataReceived); // NOTE: This function intentionally uses frameBufferAtIndex() instead of // checking m_frameBufferCache.first() directly, so that it will do the // right thing for ICOImageDecoder, which needs to override this accessor // to support ICOs which contain PNGs. // Return quickly when we can't do any more work. if (m_failed || data->isEmpty() || (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete)) return; // Decode as much as we can. This assumes |data| starts at the beginning // of the image data, rather than containing just the latest chunk. decodeImage(data); if (m_failed) { // Handle failure before getting the framebuffer below. m_colorTable.clear(); return; } // If we got all the data but couldn't finish decoding, fail. const bool finished = (frameBufferAtIndex(0)->status() == RGBA32Buffer::FrameComplete); if (allDataReceived && !finished) m_failed = true; // Release the color table when we no longer need it. if (finished || m_failed) m_colorTable.clear();}RGBA32Buffer* BMPImageReader::frameBufferAtIndex(size_t index){ return index ? 0 : &m_frameBufferCache.first();}void BMPImageReader::decodeBMP(SharedBuffer* data){ // Calculate size of info header. if (!m_infoHeader.biSize && !getInfoHeaderSize(data)) return; // Read and process info header. if ((m_decodedOffset < (m_headerOffset + m_infoHeader.biSize)) && !processInfoHeader(data)) return; // Read and process the bitmasks, if needed. if (m_needToProcessBitmasks && !processBitmasks(data)) return; // Read and process the color table, if needed. if (m_needToProcessColorTable && !processColorTable(data)) return; // Initialize frame buffer state, if needed. if (m_frameBufferCache.first().status() == RGBA32Buffer::FrameEmpty) { m_frameBufferCache.first().setRect(IntRect(IntPoint(), size())); m_frameBufferCache.first().setStatus(RGBA32Buffer::FramePartial); if (!m_frameBufferCache.first().setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) { // Unable to allocate. m_failed = true; return; } // setSize() calls eraseARGB(), which resets the alpha flag, so we force // it back to false here. We'll set it true below in all cases where // these 0s could actually show through. m_frameBufferCache.first().setHasAlpha(false); if (!m_isTopDown) m_coord.setY(size().height() - 1); } // Decode the data. if ((m_andMaskState != Decoding) && !pastEndOfImage(0)) { if ((m_infoHeader.biCompression == RLE4) || (m_infoHeader.biCompression == RLE8) || (m_infoHeader.biCompression == RLE24)) { if (!processRLEData(data)) return; } else if (!processNonRLEData(data, false, 0)) return; } // If the image has an AND mask and there was no alpha data, process the // mask. if ((m_andMaskState == NotYetDecoded) && !m_frameBufferCache.first().hasAlpha()) { // Reset decoding coordinates to start of image. m_coord.setX(0); m_coord.setY(m_isTopDown ? 0 : (size().height() - 1)); // The AND mask is stored as 1-bit data. m_infoHeader.biBitCount = 1; m_andMaskState = Decoding; } if ((m_andMaskState == Decoding) && !processNonRLEData(data, false, 0)) return; // Done! m_frameBufferCache.first().setStatus(RGBA32Buffer::FrameComplete);}bool BMPImageReader::getInfoHeaderSize(SharedBuffer* data){ // Get size of info header. ASSERT(m_decodedOffset == m_headerOffset); if ((m_decodedOffset > data->size()) || ((data->size() - m_decodedOffset) < 4)) return false; m_infoHeader.biSize = readUint32(data, 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. if (((m_headerOffset + m_infoHeader.biSize) < m_headerOffset) || (m_imgDataOffset && (m_imgDataOffset < (m_headerOffset + m_infoHeader.biSize)))) { m_failed = true; return false; } // 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) == 0) || (m_infoHeader.biSize == 42) || (m_infoHeader.biSize == 46))) m_isOS22x = true; else m_failed = true; return !m_failed;}bool BMPImageReader::processInfoHeader(SharedBuffer* data){ // Read info header. ASSERT(m_decodedOffset == m_headerOffset); if ((m_decodedOffset > data->size()) || ((data->size() - m_decodedOffset) < m_infoHeader.biSize) || !readInfoHeader(data)) return false; m_decodedOffset += m_infoHeader.biSize; // Sanity-check header values. if (!isInfoHeaderValid()) { m_failed = true; return false; } // Make our size available to the caller. if (!setSize(m_infoHeader.biWidth, m_infoHeader.biHeight)) { m_failed = true; return false; } // For paletted images, bitmaps can set biClrUsed to 0 to mean "all // colors", so set it to the maximum number of colors for this bit depth. // Also do this for bitmaps that put too large a value here. if (m_infoHeader.biBitCount < 16) { const uint32_t maxColors = static_cast<uint32_t>(1) << m_infoHeader.biBitCount; if ((m_infoHeader.biClrUsed == 0) || (m_infoHeader.biClrUsed > maxColors)) m_infoHeader.biClrUsed = maxColors; } // For any bitmaps that set their BitCount to the wrong value, reset the // counts now that we've calculated the number of necessary colors, since // other code relies on this value being correct. if (m_infoHeader.biCompression == RLE8) m_infoHeader.biBitCount = 8; else if (m_infoHeader.biCompression == RLE4) m_infoHeader.biBitCount = 4; // Tell caller what still needs to be processed. if (m_infoHeader.biBitCount >= 16) m_needToProcessBitmasks = true; else if (m_infoHeader.biBitCount > 0) m_needToProcessColorTable = true; return true;}bool BMPImageReader::readInfoHeader(SharedBuffer* data){ // Pre-initialize some fields that not all headers set. m_infoHeader.biCompression = RGB; m_infoHeader.biClrUsed = 0; if (m_isOS21x) { m_infoHeader.biWidth = readUint16(data, 4); m_infoHeader.biHeight = readUint16(data, 6); ASSERT(m_andMaskState == None); // ICO is a Windows format, not OS/2! m_infoHeader.biBitCount = readUint16(data, 10); return true; } m_infoHeader.biWidth = readUint32(data, 4); m_infoHeader.biHeight = readUint32(data, 8); if (m_andMaskState != None) m_infoHeader.biHeight /= 2; m_infoHeader.biBitCount = readUint16(data, 14); // Read compression type, if present. if (m_infoHeader.biSize >= 20) { uint32_t biCompression = readUint32(data, 16); // Detect OS/2 2.x-specific compression types. if ((biCompression == 3) && (m_infoHeader.biBitCount == 1)) { m_infoHeader.biCompression = HUFFMAN1D;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -