mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-04 19:33:18 +00:00
Bug 108271 Support RLE compression and bitfields for the BMP Decoder
patch by neil@parkwaycc.co.uk initial work by jdunn@netscape.com r=biesi sr=tor
This commit is contained in:
parent
0dffa137af
commit
db33edea08
@ -20,6 +20,7 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Neil Rashbrook <neil@parkwaycc.co.uk>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
@ -36,13 +37,11 @@
|
||||
* ----- END LICENSE BLOCK ----- */
|
||||
/* I got the format description from http://www.daubnet.com/formats/BMP.html */
|
||||
|
||||
/* This does not yet work in this version:
|
||||
* o) Compressed Bitmaps
|
||||
* This decoder was tested on Windows, Linux and Mac. */
|
||||
|
||||
/* This is a Cross-Platform BMP Decoder, which should work everywhere, including
|
||||
* Big-Endian machines like the PowerPC. */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nsBMPDecoder.h"
|
||||
|
||||
#include "nsIInputStream.h"
|
||||
@ -65,11 +64,16 @@ nsBMPDecoder::nsBMPDecoder()
|
||||
NS_INIT_ISUPPORTS();
|
||||
mColors = nsnull;
|
||||
mRow = nsnull;
|
||||
mPos = mNumColors = mRowBytes = mCurLine = 0;
|
||||
mPos = mNumColors = mRowBytes = 0;
|
||||
mCurLine = 1; // Otherwise decoder will never start
|
||||
mState = eRLEStateInitial;
|
||||
mStateData = 0;
|
||||
mAlpha = mAlphaPtr = mDecoded = mDecoding = nsnull;
|
||||
}
|
||||
|
||||
nsBMPDecoder::~nsBMPDecoder()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBMPDecoder::Init(imgILoad *aLoad)
|
||||
@ -103,7 +107,16 @@ NS_IMETHODIMP nsBMPDecoder::Close()
|
||||
delete[] mRow;
|
||||
mRow = nsnull;
|
||||
mRowBytes = 0;
|
||||
mCurLine = 0;
|
||||
mCurLine = 1;
|
||||
if (mAlpha)
|
||||
free(mAlpha);
|
||||
mAlpha = nsnull;
|
||||
if (mDecoded)
|
||||
free(mDecoded);
|
||||
mDecoded = nsnull;
|
||||
|
||||
mState = eRLEStateInitial;
|
||||
mStateData = 0;
|
||||
|
||||
if (mObserver) {
|
||||
mObserver->OnStopContainer(nsnull, nsnull, mImage);
|
||||
@ -140,16 +153,16 @@ NS_IMETHODIMP nsBMPDecoder::WriteFrom(nsIInputStream *aInStr, PRUint32 aCount, P
|
||||
// Actual Data Processing
|
||||
// ----------------------------------------
|
||||
|
||||
nsresult nsBMPDecoder::SetData(PRUint8* aData)
|
||||
nsresult nsBMPDecoder::SetData()
|
||||
{
|
||||
PRUint32 bpr;
|
||||
nsresult rv;
|
||||
PRUint32 bpr;
|
||||
|
||||
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 line = (mBIH.height < 0) ? (-mBIH.height - mCurLine - 1) : mCurLine;
|
||||
rv = mFrame->SetImageData(aData, bpr, line * bpr);
|
||||
PRInt32 line = (mBIH.height < 0) ? (-mBIH.height - mCurLine--) : --mCurLine;
|
||||
rv = mFrame->SetImageData(mDecoded, bpr, line * bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRect r(0, line, mBIH.width, 1);
|
||||
@ -159,6 +172,43 @@ nsresult nsBMPDecoder::SetData(PRUint8* aData)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsBMPDecoder::WriteRLERows(PRUint32 rows)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 bpr, alpha, cnt, line;
|
||||
PRUint8 byte, bit;
|
||||
PRUint8* pos = mAlpha;
|
||||
|
||||
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// First pack the alpha data
|
||||
rv = mFrame->GetAlphaBytesPerRow(&alpha);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
for (cnt = 0; cnt < alpha; cnt++) {
|
||||
byte = 0;
|
||||
for (bit = 128; bit; bit >>= 1)
|
||||
byte |= *pos++ & bit;
|
||||
mAlpha[cnt] = byte;
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < rows; cnt++) {
|
||||
line = (mBIH.height < 0) ? (-mBIH.height - mCurLine--) : --mCurLine;
|
||||
rv = mFrame->SetAlphaData(mAlpha, alpha, line * alpha);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mFrame->SetImageData(mDecoded, bpr, line * bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (cnt == 0) {
|
||||
memset(mAlpha, 0, mBIH.width);
|
||||
memset(mDecoded, 0, bpr);
|
||||
}
|
||||
}
|
||||
|
||||
line = (mBIH.height < 0) ? (-mBIH.height - mCurLine - rows) : mCurLine;
|
||||
nsRect r(0, line, mBIH.width, rows);
|
||||
return mObserver->OnDataAvailable(nsnull, nsnull, mFrame, &r);
|
||||
}
|
||||
|
||||
static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
|
||||
{
|
||||
// find the rightmost 1
|
||||
@ -197,7 +247,7 @@ NS_METHOD nsBMPDecoder::CalcBitShift()
|
||||
|
||||
NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
{
|
||||
if (!aCount || (mCurLine < 0)) // aCount=0 means EOF, mCurLine < 0 means we're past end of image
|
||||
if (!aCount || !mCurLine) // aCount=0 means EOF, mCurLine=0 means we're past end of image
|
||||
return NS_OK;
|
||||
|
||||
nsresult rv;
|
||||
@ -232,10 +282,6 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
ProcessInfoHeader();
|
||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP image is %lix%lix%lu. compression=%lu\n",
|
||||
mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
|
||||
if (mBIH.compression && mBIH.compression != BI_BITFIELDS) {
|
||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("Don't yet support compressed BMPs\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mBIH.bpp <= 8) {
|
||||
switch (mBIH.bpp) {
|
||||
@ -274,7 +320,7 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mObserver->OnStartContainer(nsnull, nsnull, mImage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mCurLine = real_height - 1;
|
||||
mCurLine = real_height;
|
||||
|
||||
mRow = new PRUint8[(mBIH.width * mBIH.bpp)/8 + 4];
|
||||
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
||||
@ -283,7 +329,11 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
if (!mRow) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
rv = mFrame->Init(0, 0, mBIH.width, real_height, BMP_GFXFORMAT, 24);
|
||||
if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||
rv = mFrame->Init(0, 0, mBIH.width, real_height, RLE_GFXFORMAT_ALPHA, 24);
|
||||
} else {
|
||||
rv = mFrame->Init(0, 0, mBIH.width, real_height, BMP_GFXFORMAT, 24);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mImage->AppendFrame(mFrame);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -354,61 +404,61 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
mRowBytes += toCopy;
|
||||
}
|
||||
if ((rowSize - mRowBytes) == 0) {
|
||||
PRUint32 bpr;
|
||||
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
PRUint8* decoded = new PRUint8[bpr];
|
||||
if (!decoded)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (!mDecoded) {
|
||||
PRUint32 bpr;
|
||||
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mDecoded = (PRUint8*)malloc(bpr);
|
||||
if (!mDecoded)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
PRUint8* p = mRow;
|
||||
PRUint8* d = decoded;
|
||||
PRUint32 lpos = 0;
|
||||
PRUint8* d = mDecoded;
|
||||
PRUint32 lpos = mBIH.width;
|
||||
switch (mBIH.bpp) {
|
||||
case 1:
|
||||
while (lpos < mBIH.width) {
|
||||
while (lpos > 0) {
|
||||
PRInt8 bit;
|
||||
PRUint8 idx;
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
if (lpos >= mBIH.width)
|
||||
break;
|
||||
for (bit = 7; bit >= 0 && lpos > 0; bit--) {
|
||||
idx = (*p >> bit) & 1;
|
||||
SetPixel(d, idx, mColors);
|
||||
++lpos;
|
||||
--lpos;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
while (lpos < mBIH.width) {
|
||||
Set4BitPixel(d, *p, lpos, mBIH.width, mColors);
|
||||
while (lpos > 0) {
|
||||
Set4BitPixel(d, *p, lpos, mColors);
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
while (lpos < mBIH.width) {
|
||||
while (lpos > 0) {
|
||||
SetPixel(d, *p, mColors);
|
||||
++lpos;
|
||||
--lpos;
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
while (lpos < mBIH.width) {
|
||||
while (lpos > 0) {
|
||||
PRUint16 val = LITTLE_TO_NATIVE16(*(PRUint16*)p);
|
||||
SetPixel(d,
|
||||
(val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
|
||||
(val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
|
||||
(val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
|
||||
++lpos;
|
||||
--lpos;
|
||||
p+=2;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
case 24:
|
||||
while (lpos < mBIH.width) {
|
||||
while (lpos > 0) {
|
||||
SetPixel(d, p[2], p[1], p[0]);
|
||||
p += 2;
|
||||
++lpos;
|
||||
--lpos;
|
||||
if (mBIH.bpp == 32)
|
||||
p++; // Padding byte
|
||||
++p;
|
||||
@ -419,17 +469,193 @@ NS_METHOD nsBMPDecoder::ProcessData(const char* aBuffer, PRUint32 aCount)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = SetData(decoded);
|
||||
delete[] decoded;
|
||||
nsresult rv = SetData();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mCurLine == 0) { // Finished last line
|
||||
return mObserver->OnStopFrame(nsnull, nsnull, mFrame);
|
||||
}
|
||||
mCurLine--; mRowBytes = 0;
|
||||
mRowBytes = 0;
|
||||
|
||||
}
|
||||
} while (aCount > 0);
|
||||
}
|
||||
else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
|
||||
if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8))
|
||||
|| ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
|
||||
PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mAlpha) {
|
||||
PRUint32 alpha;
|
||||
rv = mFrame->GetAlphaBytesPerRow(&alpha);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Allocate an unpacked buffer
|
||||
mAlpha = (PRUint8*)calloc(alpha, 8);
|
||||
if (!mAlpha)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mAlphaPtr = mAlpha;
|
||||
}
|
||||
|
||||
if (!mDecoded) {
|
||||
PRUint32 bpr;
|
||||
rv = mFrame->GetImageBytesPerRow(&bpr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mDecoded = (PRUint8*)calloc(bpr, 1);
|
||||
if (!mDecoded)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mDecoding = mDecoded;
|
||||
}
|
||||
|
||||
while (aCount > 0) {
|
||||
PRUint8 byte;
|
||||
|
||||
switch(mState) {
|
||||
case eRLEStateInitial:
|
||||
mStateData = (PRUint8)*aBuffer++;
|
||||
aCount--;
|
||||
|
||||
mState = eRLEStateNeedSecondEscapeByte;
|
||||
continue;
|
||||
|
||||
case eRLEStateNeedSecondEscapeByte:
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
if (mStateData != RLE_ESCAPE) { // encoded mode
|
||||
// Encoded mode consists of two bytes:
|
||||
// the first byte (mStateData) specifies the
|
||||
// number of consecutive pixels to be drawn
|
||||
// using the color index contained in
|
||||
// the second byte
|
||||
// Work around bitmaps that specify too many pixels
|
||||
if (mAlphaPtr + mStateData > mAlpha + mBIH.width)
|
||||
mStateData = (PRUint32)(mAlpha + mBIH.width - mAlphaPtr);
|
||||
memset(mAlphaPtr, 0xFF, mStateData);
|
||||
mAlphaPtr += mStateData;
|
||||
if (mBIH.compression == BI_RLE8) {
|
||||
while (mStateData > 0) {
|
||||
SetPixel(mDecoding, byte, mColors);
|
||||
mStateData--;
|
||||
}
|
||||
} else {
|
||||
while (mStateData > 0) {
|
||||
Set4BitPixel(mDecoding, byte, mStateData, mColors);
|
||||
}
|
||||
}
|
||||
|
||||
mState = eRLEStateInitial;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(byte) {
|
||||
case RLE_ESCAPE_EOL:
|
||||
// End of Line: Write out current row
|
||||
// and reset our row buffer
|
||||
rv = WriteRLERows(1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mAlphaPtr = mAlpha;
|
||||
mDecoding = mDecoded;
|
||||
|
||||
mState = eRLEStateInitial;
|
||||
break;
|
||||
|
||||
case RLE_ESCAPE_EOF: // EndOfFile
|
||||
rv = WriteRLERows(mCurLine);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
|
||||
case RLE_ESCAPE_DELTA:
|
||||
mState = eRLEStateNeedXDelta;
|
||||
continue;
|
||||
|
||||
default : // absolute mode
|
||||
// Save the number of pixels to read
|
||||
mStateData = byte;
|
||||
if (mAlphaPtr + mStateData > mAlpha + mBIH.width) {
|
||||
// We can work around bitmaps that specify one
|
||||
// pixel too many, but only if their width is odd.
|
||||
mStateData -= mBIH.width & 1;
|
||||
if (mAlphaPtr + mStateData > mAlpha + mBIH.width)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
memset(mAlphaPtr, 0xFF, mStateData);
|
||||
mAlphaPtr += mStateData;
|
||||
|
||||
mState = eRLEStateAbsoluteMode;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case eRLEStateNeedXDelta:
|
||||
// Handle the XDelta and proceed to get Y Delta
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
mAlphaPtr += byte;
|
||||
mDecoding += byte * GFXBYTESPERPIXEL;
|
||||
|
||||
mState = eRLEStateNeedYDelta;
|
||||
continue;
|
||||
|
||||
case eRLEStateNeedYDelta:
|
||||
// Get the Y Delta and then "handle" the move
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
mState = eRLEStateInitial;
|
||||
if (byte == 0)
|
||||
continue; // Nothing more to do
|
||||
|
||||
rv = WriteRLERows(PR_MIN(byte, mCurLine));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
|
||||
case eRLEStateAbsoluteMode: // Absolute Mode
|
||||
// In absolute mode, the second byte (mStateData)
|
||||
// represents the number of pixels
|
||||
// that follow, each of which contains
|
||||
// the color index of a single pixel.
|
||||
if (mBIH.compression == BI_RLE8) {
|
||||
while (aCount > 0 && mStateData > 0) {
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
SetPixel(mDecoding, byte, mColors);
|
||||
mStateData--;
|
||||
}
|
||||
} else {
|
||||
while (aCount > 0 && mStateData > 0) {
|
||||
byte = *aBuffer++;
|
||||
aCount--;
|
||||
Set4BitPixel(mDecoding, byte, mStateData, mColors);
|
||||
}
|
||||
}
|
||||
|
||||
if (mStateData == 0) {
|
||||
// In absolute mode, each run must
|
||||
// be aligned on a word boundary
|
||||
|
||||
if ((((size_t)aBuffer) & 1) == 0) { // Word Aligned
|
||||
mState = eRLEStateInitial;
|
||||
} else if (aCount > 0) { // Not word Aligned
|
||||
// "next" byte is just a padding byte
|
||||
// so "move" past it and we can continue
|
||||
aBuffer++;
|
||||
aCount--;
|
||||
mState = eRLEStateInitial;
|
||||
}
|
||||
}
|
||||
// else state is still eRLEStateAbsoluteMode
|
||||
continue;
|
||||
|
||||
default :
|
||||
NS_NOTREACHED("BMP RLE decompression: unknown state!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Because of the use of the continue statement
|
||||
// we only get here for eol, eof or y delta
|
||||
if (mCurLine == 0) { // Finished last line
|
||||
return mObserver->OnStopFrame(nsnull, nsnull, mFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,15 +107,39 @@ struct bitFields {
|
||||
|
||||
#if defined(XP_PC) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
|
||||
#define BMP_GFXFORMAT gfxIFormats::BGR
|
||||
#define RLE_GFXFORMAT_ALPHA gfxIFormats::BGR_A1
|
||||
#else
|
||||
#define USE_RGB
|
||||
#define BMP_GFXFORMAT gfxIFormats::RGB
|
||||
#define RLE_GFXFORMAT_ALPHA gfxIFormats::RGB_A1
|
||||
#endif
|
||||
|
||||
#if defined(XP_MAC) || defined(XP_MACOSX)
|
||||
#define GFXBYTESPERPIXEL 4
|
||||
#else
|
||||
#define GFXBYTESPERPIXEL 3
|
||||
#endif
|
||||
|
||||
// BMPINFOHEADER.compression defines
|
||||
#define BI_RLE8 1
|
||||
#define BI_RLE4 2
|
||||
#define BI_BITFIELDS 3
|
||||
|
||||
// RLE Escape codes
|
||||
#define RLE_ESCAPE 0
|
||||
#define RLE_ESCAPE_EOL 0
|
||||
#define RLE_ESCAPE_EOF 1
|
||||
#define RLE_ESCAPE_DELTA 2
|
||||
|
||||
// enums for mState
|
||||
enum ERLEState {
|
||||
eRLEStateInitial,
|
||||
eRLEStateNeedSecondEscapeByte,
|
||||
eRLEStateNeedXDelta,
|
||||
eRLEStateNeedYDelta, // mStateData will hold x delta
|
||||
eRLEStateAbsoluteMode // mStateData will hold count of existing data to read
|
||||
};
|
||||
|
||||
class nsBMPDecoder : public imgIDecoder
|
||||
{
|
||||
public:
|
||||
@ -140,10 +164,15 @@ private:
|
||||
* the bitmasks from mBitFields */
|
||||
NS_METHOD CalcBitShift();
|
||||
|
||||
/** Sets the image data at specified position. mCurLine is used
|
||||
* to get the row
|
||||
* @param aData The data */
|
||||
nsresult SetData(PRUint8* aData);
|
||||
/** Sets the image data. mCurLine is used to get the row,
|
||||
* mDecoded is used to get the data */
|
||||
nsresult SetData();
|
||||
|
||||
/** Sets the rle data. mCurLine is used to get the row,
|
||||
* mDecoded is used to get the data for the first row,
|
||||
* all subsequent rows are blank.
|
||||
* @param rows Number of rows of data to set */
|
||||
nsresult WriteRLERows(PRUint32 rows);
|
||||
|
||||
nsCOMPtr<imgIDecoderObserver> mObserver;
|
||||
|
||||
@ -166,6 +195,13 @@ private:
|
||||
PRUint8 *mRow; // Holds one raw line of the image
|
||||
PRUint32 mRowBytes; // How many bytes of the row were already received
|
||||
PRInt32 mCurLine;
|
||||
PRUint8 *mAlpha; // Holds one line of unpacked alpha data
|
||||
PRUint8 *mAlphaPtr; // Pointer within unpacked alpha data
|
||||
PRUint8 *mDecoded; // Holds one line of color image data
|
||||
PRUint8 *mDecoding; // Pointer within image data
|
||||
|
||||
ERLEState mState; // Maintains the current state of the RLE decoding
|
||||
PRUint32 mStateData;// Decoding information that is needed depending on mState
|
||||
|
||||
void ProcessFileHeader();
|
||||
void ProcessInfoHeader();
|
||||
@ -173,7 +209,7 @@ private:
|
||||
|
||||
/** Sets the pixel data in aDecoded to the given values.
|
||||
* The variable passed in as aDecoded will be moved on 3 bytes! */
|
||||
inline nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue)
|
||||
inline void SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUint8 aBlue)
|
||||
{
|
||||
#if defined(XP_MAC) || defined(XP_MACOSX)
|
||||
*aDecoded++ = 0; // Mac needs this padding byte
|
||||
@ -187,37 +223,32 @@ inline nsresult SetPixel(PRUint8*& aDecoded, PRUint8 aRed, PRUint8 aGreen, PRUin
|
||||
*aDecoded++ = aGreen;
|
||||
*aDecoded++ = aRed;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult SetPixel(PRUint8*& aDecoded, PRUint8 idx, colorTable* aColors)
|
||||
inline void SetPixel(PRUint8*& aDecoded, PRUint8 idx, colorTable* aColors)
|
||||
{
|
||||
PRUint8 red, green, blue;
|
||||
red = aColors[idx].red;
|
||||
green = aColors[idx].green;
|
||||
blue = aColors[idx].blue;
|
||||
return SetPixel(aDecoded, red, green, blue);
|
||||
SetPixel(aDecoded, red, green, blue);
|
||||
}
|
||||
|
||||
/** Sets one or two pixels; it is ensured that aPos is <= mBIH.width
|
||||
/** Sets two (or one if aCount = 1) pixels
|
||||
* @param aDecoded where the data is stored. Will be moved 3 or 6 bytes,
|
||||
* depending on whether one or two pixels are written.
|
||||
* @param aData The values for the two pixels
|
||||
* @param aPos Current position. Is incremented by one or two. */
|
||||
inline nsresult Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData,
|
||||
PRUint32& aPos, PRUint32 aMaxWidth, colorTable* aColors)
|
||||
* @param aCount Current count. Is decremented by one or two. */
|
||||
inline void Set4BitPixel(PRUint8*& aDecoded, PRUint8 aData,
|
||||
PRUint32& aCount, colorTable* aColors)
|
||||
{
|
||||
PRUint8 idx = aData >> 4;
|
||||
nsresult rv = SetPixel(aDecoded, idx, aColors);
|
||||
if ((++aPos >= aMaxWidth) || NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
idx = aData & 0xF;
|
||||
rv = SetPixel(aDecoded, idx, aColors);
|
||||
++aPos;
|
||||
return rv;
|
||||
SetPixel(aDecoded, idx, aColors);
|
||||
if (--aCount > 0) {
|
||||
idx = aData & 0xF;
|
||||
SetPixel(aDecoded, idx, aColors);
|
||||
--aCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -121,7 +121,8 @@ PRUint32 nsICODecoder::CalcAlphaRowSize()
|
||||
nsICODecoder::nsICODecoder()
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
mPos = mNumColors = mCurLine = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
|
||||
mPos = mNumColors = mRowBytes = mImageOffset = mCurrIcon = mNumIcons = 0;
|
||||
mCurLine = 1; // Otherwise decoder will never start
|
||||
mColors = nsnull;
|
||||
mRow = nsnull;
|
||||
mDecodingAndMask = PR_FALSE;
|
||||
@ -295,7 +296,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
rv = mObserver->OnStartContainer(nsnull, nsnull, mImage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurLine = (mDirEntry.mHeight - 1);
|
||||
mCurLine = mDirEntry.mHeight;
|
||||
mRow = new PRUint8[(mDirEntry.mWidth * mBIH.bpp)/8 + 4];
|
||||
// +4 because the line is padded to a 4 bit boundary, but I don't want
|
||||
// to make exact calculations here, that's unnecessary.
|
||||
@ -365,59 +366,54 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
mRowBytes += toCopy;
|
||||
}
|
||||
if (rowSize == mRowBytes) {
|
||||
#if defined(XP_MAC) || defined(XP_MACOSX)
|
||||
PRUint8* decoded = mDecodedBuffer+(mCurLine*mDirEntry.mWidth*4);
|
||||
#else
|
||||
PRUint8* decoded = mDecodedBuffer+(mCurLine*mDirEntry.mWidth*3);
|
||||
#endif
|
||||
mCurLine--;
|
||||
PRUint8* decoded = mDecodedBuffer + (mCurLine * mDirEntry.mWidth * GFXBYTESPERPIXEL);
|
||||
PRUint8* p = mRow;
|
||||
PRUint8* d = decoded;
|
||||
PRUint32 lpos = 0;
|
||||
PRUint32 lpos = mDirEntry.mWidth;
|
||||
switch (mBIH.bpp) {
|
||||
case 1:
|
||||
while (lpos < mDirEntry.mWidth) {
|
||||
while (lpos > 0) {
|
||||
PRInt8 bit;
|
||||
PRUint8 idx;
|
||||
for (bit = 7; bit >= 0; bit--) {
|
||||
if (lpos >= mDirEntry.mWidth)
|
||||
break;
|
||||
for (bit = 7; bit >= 0 && lpos > 0; bit--) {
|
||||
idx = (*p >> bit) & 1;
|
||||
SetPixel(d, idx, mColors);
|
||||
++lpos;
|
||||
--lpos;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
while (lpos < mDirEntry.mWidth) {
|
||||
Set4BitPixel(d, *p, lpos, mDirEntry.mWidth, mColors);
|
||||
while (lpos > 0) {
|
||||
Set4BitPixel(d, *p, lpos, mColors);
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
while (lpos < mDirEntry.mWidth) {
|
||||
while (lpos > 0) {
|
||||
SetPixel(d, *p, mColors);
|
||||
++lpos;
|
||||
--lpos;
|
||||
++p;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
while (lpos < mDirEntry.mWidth) {
|
||||
while (lpos > 0) {
|
||||
SetPixel(d,
|
||||
(p[1] & 124) << 1,
|
||||
((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
|
||||
(p[0] & 31) << 3);
|
||||
|
||||
++lpos;
|
||||
--lpos;
|
||||
p+=2;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
case 24:
|
||||
while (lpos < mDirEntry.mWidth) {
|
||||
while (lpos > 0) {
|
||||
SetPixel(d, p[2], p[1], p[0]);
|
||||
p += 2;
|
||||
++lpos;
|
||||
--lpos;
|
||||
if (mBIH.bpp == 32)
|
||||
p++; // Padding byte
|
||||
++p;
|
||||
@ -431,7 +427,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
if (mCurLine == 0)
|
||||
mDecodingAndMask = PR_TRUE;
|
||||
|
||||
mCurLine--; mRowBytes = 0;
|
||||
mRowBytes = 0;
|
||||
}
|
||||
} while (!mDecodingAndMask && aCount > 0);
|
||||
}
|
||||
@ -442,7 +438,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
|
||||
mPos++;
|
||||
mRowBytes = 0;
|
||||
mCurLine = (mDirEntry.mHeight - 1);
|
||||
mCurLine = mDirEntry.mHeight;
|
||||
delete []mRow;
|
||||
mRow = new PRUint8[rowSize];
|
||||
mAlphaBuffer = new PRUint8[mDirEntry.mHeight*rowSize];
|
||||
@ -461,6 +457,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
mRowBytes += toCopy;
|
||||
}
|
||||
if ((rowSize - mRowBytes) == 0) {
|
||||
mCurLine--;
|
||||
PRUint8* decoded = mAlphaBuffer+(mCurLine*rowSize);
|
||||
PRUint8* p = mRow;
|
||||
PRUint32 lpos = 0;
|
||||
@ -477,7 +474,7 @@ nsresult nsICODecoder::ProcessData(const char* aBuffer, PRUint32 aCount) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCurLine--; mRowBytes = 0;
|
||||
mRowBytes = 0;
|
||||
}
|
||||
} while (aCount > 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user