diff -r 000000000000 -r 5d03bc08d59c fbs/fontandbitmapserver/sfbs/BITCOMP.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fbs/fontandbitmapserver/sfbs/BITCOMP.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,2233 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +#include +#include +#include "UTILS.H" +#include + +GLREF_C void Panic(TFbsPanic aPanic); + +void CBitwiseBitmap::DoInternalizeCompressedDataL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase,TBitmapfileCompression aCompression) + { + TInt destSizeInBytes = iHeader.iSizeInPixels.iHeight * iByteWidth; + TUint8* destPtr = (TUint8*)aBase; + + // try to allocate memory for the compressed bitmap + TUint8* decompressionBuffer = (TUint8*)User::Alloc(aSrceSizeInBytes); + + if (decompressionBuffer) + { + // read the compressed bitmap, then decompress + CleanupStack::PushL(decompressionBuffer); + aStream.ReadL(decompressionBuffer,aSrceSizeInBytes); + switch (aCompression) + { + case EByteRLECompression: + DoDecompressByteData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + case ETwelveBitRLECompression: + DoDecompressTwelveBitData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + case ESixteenBitRLECompression: + DoDecompressSixteenBitData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + case ETwentyFourBitRLECompression: + DoDecompressTwentyFourBitData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + case EThirtyTwoUBitRLECompression: + DoDecompressThirtyTwoUBitData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + case EThirtyTwoABitRLECompression: + DoDecompressThirtyTwoABitData(destPtr,destSizeInBytes,decompressionBuffer,aSrceSizeInBytes); + break; + default: + break; + } + CleanupStack::PopAndDestroy(); // decompressionBuffer + return; + } + + // not enough heap to pre-load the source bitmap + switch (aCompression) + { + case EByteRLECompression: + DoDecompressByteDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + case ETwelveBitRLECompression: + DoDecompressTwelveBitDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + case ESixteenBitRLECompression: + DoDecompressSixteenBitDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + case ETwentyFourBitRLECompression: + DoDecompressTwentyFourBitDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + case EThirtyTwoUBitRLECompression: + DoDecompressThirtyTwoUBitDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + case EThirtyTwoABitRLECompression: + DoDecompressThirtyTwoABitDataAltL(aStream,aSrceSizeInBytes,aBase); + break; + default: + break; + } + } + +void CBitwiseBitmap::DoDecompressByteData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + TUint8* srcePtr = aSrceBuffer; + TUint8* destPtr = aDestBuffer; + TUint8* srcePtrLimit = aSrceBuffer + aSrceSize; + TUint8* destPtrLimit = aDestBuffer + aDestSize; + + while (srcePtr < srcePtrLimit && destPtr < destPtrLimit) + { + TInt8 count = *srcePtr++; + + if (count >= 0) + { + const TInt numBytes = Min(count + 1, destPtrLimit - destPtr); + Mem::Fill(destPtr,numBytes,*srcePtr++); + destPtr += numBytes; + } + else + { + const TInt numBytes = Min(-count, destPtrLimit - destPtr); + Mem::Copy(destPtr,srcePtr,numBytes); + srcePtr += numBytes; + destPtr += numBytes; + } + } + __ASSERT_DEBUG(srcePtr == srcePtrLimit && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +void CBitwiseBitmap::DoDecompressByteDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + TInt destSizeInBytes = iHeader.iSizeInPixels.iHeight * iByteWidth; + TUint8* destPtr = (TUint8*)aBase; + TUint8* destPtrLimit = destPtr + destSizeInBytes; + + while(aSrceSizeInBytes > 0 && destPtr < destPtrLimit) + { + TInt8 count = aStream.ReadInt8L(); + aSrceSizeInBytes--; + + if (count >= 0) + { + const TInt numBytes = Min(count + 1, destPtrLimit - destPtr); + TUint8 value = aStream.ReadUint8L(); + aSrceSizeInBytes--; + Mem::Fill(destPtr,numBytes,value); + destPtr += numBytes; + } + else + { + const TInt numBytes = Min(-count, destPtrLimit - destPtr); + aStream.ReadL(destPtr,numBytes); + aSrceSizeInBytes -= numBytes; + destPtr += numBytes; + } + } + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +/** Fills the 32bit pixels into the destination pointer +This method uses the concept of Duff's Device +@param aDestPtr32 pointer to 32bit destination buffer. +@param aCount Number of 32bit pixels to be copied. +@param aValue32 32bit pixel data. */ +void CBitwiseBitmap::BitmapFill32(TUint32* aDestPtr32, TInt aCount, TUint32 aValue32) + { + __ASSERT_DEBUG(aCount > 0, Panic(EFbsBitmapDecompressionError)); + if (aCount > 0) + { // for performance loop is unrolled, using "Duff's Device" pattern + TInt blocksOf16 = aCount / 16; // number of blocks of 16 full words to write + // the first iteration writes 1 to 15 words + + switch (aCount & 0x0f) + { // note that case statements intentionally cascade + case 0: +write16dblPixels: // second and subsequent iterations always write 16 words + --blocksOf16; + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 15: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 14: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 13: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 12: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 11: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 10: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 9: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 8: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 7: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 6: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 5: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 4: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 3: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 2: + *aDestPtr32++ = aValue32; + //coverity [fallthrough] + case 1: + *aDestPtr32++ = aValue32; + } + + if (blocksOf16 > 0) + { + goto write16dblPixels; + } + } + } + +/** Fills the 16bit pixels into the destination pointer +This method uses the concept of Duff's Device +@param aDestPtr16 pointer to 16bit destination buffer. +@param aCount Number of 16bit pixels to be copied. +@param aValue16 16bit pixel data. */ +inline void CBitwiseBitmap::BitmapFill16(TUint16* aDestPtr16, TInt aCount, TUint16 aValue16) + { + // Call the 32-bit fill method if there at least 8 pixels to fill + if (aCount >= 8) + { + // first pixel is on half word address? + if (reinterpret_cast(aDestPtr16) & 2) + { + *aDestPtr16++ = aValue16; + --aCount; + } + + // destPtr16 is now full Word aligned + const TInt countDoublePixels = aCount / 2; + TUint32* destPtr32 = (TUint32*) aDestPtr16; + BitmapFill32(destPtr32, countDoublePixels, (aValue16 << 16) | aValue16); + + aCount -= countDoublePixels * 2; + if (aCount == 1) + { // last pixel is on a half-word + aDestPtr16 += countDoublePixels * 2; + *aDestPtr16++ = aValue16; + } + } + else + { // less than 8 pixels to fill + switch (aCount) + { // note that case statements intentionally cascade + case 7: + *aDestPtr16++ = aValue16; + case 6: + *aDestPtr16++ = aValue16; + case 5: + *aDestPtr16++ = aValue16; + case 4: + *aDestPtr16++ = aValue16; + case 3: + *aDestPtr16++ = aValue16; + case 2: + *aDestPtr16++ = aValue16; + case 1: + *aDestPtr16++ = aValue16; + case 0: // nothing to do + ; + } + } + } + +void CBitwiseBitmap::DoDecompressTwelveBitData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + TUint16* srcePtr = (TUint16*)aSrceBuffer; + TUint16* destPtr = (TUint16*)aDestBuffer; + TUint16* srcePtrLimit = srcePtr + (aSrceSize / 2); + TUint16* destPtrLimit = destPtr + (aDestSize / 2); + + while (srcePtr < srcePtrLimit && destPtr < destPtrLimit) + { + TUint16 value = *srcePtr++; + TInt count = Min(value >> 12, destPtrLimit - destPtr); + value &= 0x0fff; + + while (count >= 0) + { + *destPtr++ = value; + count--; + } + } + + __ASSERT_DEBUG(srcePtr == srcePtrLimit && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +void CBitwiseBitmap::DoDecompressTwelveBitDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + TInt destSizeInBytes = iHeader.iSizeInPixels.iHeight * iByteWidth; + TUint16* destPtr = (TUint16*)aBase; + TUint16* destPtrLimit = destPtr + (destSizeInBytes / 2); + + while(aSrceSizeInBytes > 0 && destPtr < destPtrLimit) + { + TUint16 value = aStream.ReadUint16L(); + TInt count = Min(value >> 12, destPtrLimit - destPtr); + value &= 0x0fff; + aSrceSizeInBytes -= 2; + + while (count >= 0) + { + *destPtr++ = value; + count--; + } + } + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +/** The function decodes 24-bit compressed buffer to the 16-bit stream with unused top bytes by using RLE compression algorithm*/ +void CBitwiseBitmap::DoDecompressSixteenBitData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + __ASSERT_DEBUG((reinterpret_cast(aDestBuffer) & 0x2)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is half-word aligned + __ASSERT_DEBUG((aDestSize & 0x2)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is half-word aligned + + TUint8* srcePtr8 = aSrceBuffer; // pointer to compressed source Byte(8-bit) stream + TUint16* destPtr16 = reinterpret_cast(aDestBuffer); //pointer to uncompressed destination HalfWord(16-bit) pixel stream + TUint8* srcePtrLimit8 = aSrceBuffer + aSrceSize; //maximum number of compressed source bytes + TUint16* destPtrLimit16 = reinterpret_cast(aDestBuffer + aDestSize); //maximum number of uncompressed destination pixel stream + const TInt KPixelSize = 2; //number of bytes of the source stream that is to be considered as one Pixel + + while (srcePtr8 < srcePtrLimit8 && destPtr16 < destPtrLimit16) + { + TInt8 count = *srcePtr8++; //number of pixels to be retrieved from the source stream + + if (count >= 0) //repeating number of pixels + { + const TInt numPixels = 1 + Min(count, (destPtrLimit16 - destPtr16)); + const TUint8 lowByte = *srcePtr8++; + const TUint8 highByte = *srcePtr8++; + const TUint16 pixel = highByte<<8 | lowByte; //Pixel buffer which needs to be stored in destPtr16 + + BitmapFill16(destPtr16, numPixels, pixel); + destPtr16 += numPixels; + } + else + { + const TInt numPixels = Min(-count, destPtrLimit16 - destPtr16); //number of pixels to be copied + const TInt numBytes = numPixels * KPixelSize; //number of bytes needs to be retrieved from the srcePtr + Mem::Copy(destPtr16, srcePtr8, numBytes); // copy bytes + srcePtr8 += numBytes; //incrementing the srcePtr by number of bytes + destPtr16 += numPixels; //incrementing the destPtr16 by number of pixels + } + } + __ASSERT_DEBUG(srcePtr8 == srcePtrLimit8 && destPtr16 == destPtrLimit16, Panic(EFbsBitmapDecompressionError)); + } + +/** The alternative decoding function which decompresses 24-bit buffer to the 16-bit stream with unused top bytes + by using RLE compression algorithm. The function is used under low memory conditions. */ +void CBitwiseBitmap::DoDecompressSixteenBitDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + __ASSERT_DEBUG((reinterpret_cast(aBase) & 0x2)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is half-word aligned + + TInt destSizeInPixels = (iHeader.iSizeInPixels.iHeight * iByteWidth); //size of destination Byte pixel buffers + destSizeInPixels >>= 1; //dividing by two, to get size of destination interms of Halfword pixel buffers + TUint16* destPtr16 = reinterpret_cast(aBase); //pointer to uncompressed destination HalfWord(16-bit) pixel stream + TUint16* destPtrLimit16 = destPtr16 + destSizeInPixels; //maximum number of compressed source bytes + const TInt KPixelSize = 2; //number of bytes of the source stream that is to be considered as one Pixel + + while(aSrceSizeInBytes > 0 && destPtr16 < destPtrLimit16) + { + TInt8 count = aStream.ReadInt8L(); //number of pixels to be retrieved from the source stream + aSrceSizeInBytes--; //One byte from source stream read, hence reduce size by one Byte + + if (count >= 0) + { + const TInt numPixels = 1 + Min(count, (destPtrLimit16 - destPtr16)); + const TUint16 pixel = aStream.ReadUint16L(); //Pixel buffer which needs to be stored in destPtr16 + aSrceSizeInBytes -= KPixelSize; //Two bytes (Halfword pixel) read, reduce size by two Bytes + + BitmapFill16(destPtr16, numPixels, pixel); + destPtr16 += numPixels; + } + else + { + const TInt numPixels = Min(-count, destPtrLimit16 - destPtr16); //number of pixels to be stored into destPtr16 + const TInt numBytes = numPixels * KPixelSize; //number of bytes needs to be retrieved from the srcePtr + aStream.ReadL(destPtr16, numPixels); //read TUint16's + aSrceSizeInBytes -= numBytes; //two-byte (halfword) pixel buffers read, reduce by number of bytes + destPtr16 += numPixels; //incrementing the destPtr16 by number of pixels + } + } + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr16 == destPtrLimit16, Panic(EFbsBitmapDecompressionError)); + } + +void CBitwiseBitmap::DoDecompressTwentyFourBitData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + TUint8* srcePtr = aSrceBuffer; + TUint8* destPtr = aDestBuffer; + TUint8* srcePtrLimit = aSrceBuffer + aSrceSize; + TUint8* destPtrLimit = aDestBuffer + aDestSize; + + while (srcePtr < srcePtrLimit && destPtr < destPtrLimit) + { + TInt8 count = *srcePtr++; + + if (count >= 0) + { + count = Min(count, (destPtrLimit - destPtr) / 3); + TUint8 component1 = *srcePtr++; + TUint8 component2 = *srcePtr++; + TUint8 component3 = *srcePtr++; + + while (count >= 0) + { + *destPtr++ = component1; + *destPtr++ = component2; + *destPtr++ = component3; + count--; + } + } + else + { + const TInt numBytes = Min(count * -3, destPtrLimit - destPtr); + Mem::Copy(destPtr,srcePtr,numBytes); + srcePtr += numBytes; + destPtr += numBytes; + } + } + __ASSERT_DEBUG(srcePtr == srcePtrLimit && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +void CBitwiseBitmap::DoDecompressTwentyFourBitDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + TInt destSizeInBytes = iHeader.iSizeInPixels.iHeight * iByteWidth; + TUint8* destPtr = (TUint8*)aBase; + TUint8* destPtrLimit = destPtr + destSizeInBytes; + + while(aSrceSizeInBytes > 0 && destPtr < destPtrLimit) + { + TInt8 count = aStream.ReadInt8L(); + aSrceSizeInBytes--; + + if (count >= 0) + { + count = Min(count, (destPtrLimit - destPtr) / 3); + TUint8 component1 = aStream.ReadUint8L(); + TUint8 component2 = aStream.ReadUint8L(); + TUint8 component3 = aStream.ReadUint8L(); + aSrceSizeInBytes -= 3; + + while (count >= 0) + { + *destPtr++ = component1; + *destPtr++ = component2; + *destPtr++ = component3; + count--; + } + } + else + { + const TInt numBytes = Min(count * -3, destPtrLimit - destPtr); + aStream.ReadL(destPtr, numBytes); + aSrceSizeInBytes -= numBytes; + destPtr += numBytes; + } + } + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr == destPtrLimit,Panic(EFbsBitmapDecompressionError)); + } + +/** The function decodes 24-bit compressed buffer to the 32-bit stream with unused top bytes by using RLE compression algorithm*/ +void CBitwiseBitmap::DoDecompressThirtyTwoUBitData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + + __ASSERT_DEBUG((reinterpret_cast(aDestBuffer) & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is word aligned + __ASSERT_DEBUG((aDestSize & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the size is whole no of pixels + + TUint8* srcePtr8 = aSrceBuffer; + TUint8* srcePtrLimit8 = aSrceBuffer + aSrceSize; + + TUint32* destPtr32 = reinterpret_cast(aDestBuffer); + TUint32* destPtrLimit32 = reinterpret_cast(aDestBuffer + aDestSize); + + while (srcePtr8 < srcePtrLimit8 && destPtr32 < destPtrLimit32) + { + + TInt8 count = *srcePtr8++; // important to read into a byte variable + + if (count >= 0) //repeating pixel buffer + { + count = Min(count, (destPtrLimit32 - destPtr32)); + const TUint8 component1 = *srcePtr8++; + const TUint8 component2 = *srcePtr8++; + const TUint8 component3 = *srcePtr8++; + + const TUint32 pixel = 0xff000000 | (component3<<16) | (component2<<8) | component1; + + // for performance loop is unrolled, using "Duff's Device" pattern + TInt blocksOf16 = (count >> 4); // number of blocks of 16 full words to write + // the first iteration writes 1 to 15 words + switch (count & 0x0f) + { // note that case statements intentionally cascade + case 15: + do { // second and subsequent iterations always write 16 words + *destPtr32++ = pixel; + case 14: + *destPtr32++ = pixel; + case 13: + *destPtr32++ = pixel; + case 12: + *destPtr32++ = pixel; + case 11: + *destPtr32++ = pixel; + case 10: + *destPtr32++ = pixel; + case 9: + *destPtr32++ = pixel; + case 8: + *destPtr32++ = pixel; + case 7: + *destPtr32++ = pixel; + case 6: + *destPtr32++ = pixel; + case 5: + *destPtr32++ = pixel; + case 4: + *destPtr32++ = pixel; + case 3: + *destPtr32++ = pixel; + case 2: + *destPtr32++ = pixel; + case 1: + *destPtr32++ = pixel; + case 0: + *destPtr32++ = pixel; + + } while(0 <= --blocksOf16); + } + } + else // negative value corresponds non repeating pixel buffer + { + const TInt numPixel = Min(-count, destPtrLimit32 - destPtr32) ; + for(TInt ii = 0; ii < numPixel; ii++) + { + TUint8 component1 = *srcePtr8++; + TUint8 component2 = *srcePtr8++; + TUint8 component3 = *srcePtr8++; + + *destPtr32++ = 0xff000000 | (component3<<16) | (component2<<8) | component1; + } + } + } + + __ASSERT_DEBUG(srcePtr8 == srcePtrLimit8 && destPtr32 == destPtrLimit32,Panic(EFbsBitmapDecompressionError)); + } + +/** The alternative decoding function which decompresses 24-bit buffer to the 32-bit stream with unused top bytes + by using RLE compression algorithm. The function is using in case of memory shortage. */ +void CBitwiseBitmap::DoDecompressThirtyTwoUBitDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + const TInt destSizeInDwords = iHeader.iSizeInPixels.iHeight * (iByteWidth>>2); + TUint32* destPtr32 = aBase; + TUint32* destPtrLimit32 = destPtr32 + destSizeInDwords; + + const TInt KMaxRLENonRepeatingPixelBufferSize = 128 * 3; + TUint8 dataBuffer[KMaxRLENonRepeatingPixelBufferSize]; + + while(aSrceSizeInBytes > 0 && destPtr32 < destPtrLimit32) + { + TInt8 count = aStream.ReadInt8L(); + aSrceSizeInBytes--; + + if (count >= 0) //repeating pixel buffer + { + count = Min(count, (destPtrLimit32 - destPtr32)); + const TUint8 component1 = aStream.ReadUint8L(); + const TUint8 component2 = aStream.ReadUint8L(); + const TUint8 component3 = aStream.ReadUint8L(); + aSrceSizeInBytes -= 3; + + const TUint32 pixel = 0xff000000 | (component3<<16) | (component2<<8) | component1; + + TInt blocksOf16 = (count >> 4); // number of blocks of 16 full words to write + // the first iteration writes 1 to 15 words + switch (count & 0x0f) + { // note that case statements intentionally cascade + case 15: + do { // second and subsequent iterations always write 16 words + *destPtr32++ = pixel; + case 14: + *destPtr32++ = pixel; + case 13: + *destPtr32++ = pixel; + case 12: + *destPtr32++ = pixel; + case 11: + *destPtr32++ = pixel; + case 10: + *destPtr32++ = pixel; + case 9: + *destPtr32++ = pixel; + case 8: + *destPtr32++ = pixel; + case 7: + *destPtr32++ = pixel; + case 6: + *destPtr32++ = pixel; + case 5: + *destPtr32++ = pixel; + case 4: + *destPtr32++ = pixel; + case 3: + *destPtr32++ = pixel; + case 2: + *destPtr32++ = pixel; + case 1: + *destPtr32++ = pixel; + case 0: + *destPtr32++ = pixel; + + } while(0 <= --blocksOf16); + } + } + else // negative value corresponds non repeating pixel buffer + { + const TInt numDestDwords = Min(-count, destPtrLimit32 - destPtr32); + const TInt numSrcBytes = numDestDwords * 3; + aStream.ReadL(&dataBuffer[0], numSrcBytes); + aSrceSizeInBytes -= numSrcBytes; + TUint8* srcPtr = dataBuffer; + const TInt& numPixel = numDestDwords; + for(TInt ii = 0; ii < numPixel; ii++) + { + const TUint8 component1 = *srcPtr++; + const TUint8 component2 = *srcPtr++; + const TUint8 component3 = *srcPtr++; + + *destPtr32++ = 0xff000000 | (component3<<16) | (component2<<8) | component1; + } + } + } + + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr32 == destPtrLimit32,Panic(EFbsBitmapDecompressionError)); + } + +/** The function decodes 32-bit compressed buffer (where top bytes are used as alpha channel) to the 32-bit stream by using RLE compression algorithm*/ +void CBitwiseBitmap::DoDecompressThirtyTwoABitData(TUint8* aDestBuffer,TInt aDestSize,TUint8* aSrceBuffer,TInt aSrceSize) + { + TUint8* srcePtr = aSrceBuffer; + TUint8* srcePtrLimit = aSrceBuffer + aSrceSize; + + TUint32* destPtr32 = reinterpret_cast(aDestBuffer); + TUint32* destPtrLimit32 = reinterpret_cast(aDestBuffer + aDestSize); + + while (srcePtr < srcePtrLimit && destPtr32 < destPtrLimit32) + { + TInt8 count = *srcePtr++; + + if (count >= 0) //repeating pixel buffer + { + count = Min(count, (destPtrLimit32 - destPtr32)); + TUint8 component1 = *srcePtr++; + TUint8 component2 = *srcePtr++; + TUint8 component3 = *srcePtr++; + TUint8 component4 = *srcePtr++; + const TUint32 pixel = (component4<<24) | (component3<<16) | (component2<<8) | component1; + + // for performance loop is unrolled, using "Duff's Device" pattern + TInt blocksOf16 = (count >> 4); // number of blocks of 16 full words to write + // the first iteration writes 1 to 15 words + switch (count & 0x0f) + { // note that case statements intentionally cascade + case 15: + do { // second and subsequent iterations always write 16 words + *destPtr32++ = pixel; + case 14: + *destPtr32++ = pixel; + case 13: + *destPtr32++ = pixel; + case 12: + *destPtr32++ = pixel; + case 11: + *destPtr32++ = pixel; + case 10: + *destPtr32++ = pixel; + case 9: + *destPtr32++ = pixel; + case 8: + *destPtr32++ = pixel; + case 7: + *destPtr32++ = pixel; + case 6: + *destPtr32++ = pixel; + case 5: + *destPtr32++ = pixel; + case 4: + *destPtr32++ = pixel; + case 3: + *destPtr32++ = pixel; + case 2: + *destPtr32++ = pixel; + case 1: + *destPtr32++ = pixel; + case 0: + *destPtr32++ = pixel; + + } while(0 <= --blocksOf16); + } + } + else // negative value corresponds non repeating pixel buffer + { + const TInt numPixel = Min(-count, destPtrLimit32 - destPtr32); + + Mem::Copy(destPtr32, srcePtr, numPixel*4); + destPtr32 += numPixel; + srcePtr += numPixel*4; + + } + } + + __ASSERT_DEBUG(srcePtr == srcePtrLimit && destPtr32 == destPtrLimit32,Panic(EFbsBitmapDecompressionError)); + } + +/** The alternative decoding function which decompresses 32-bit buffer (where top bytes are used as alpha channel) + to the 32-bit stream by using RLE compression algorithm. The function is using in case of memory shortage. */ +void CBitwiseBitmap::DoDecompressThirtyTwoABitDataAltL(RReadStream& aStream,TInt aSrceSizeInBytes,TUint32* aBase) + { + const TInt destSizeInDwords = iHeader.iSizeInPixels.iHeight * (iByteWidth>>2); + TUint32* destPtr32 = aBase; + TUint32* destPtrLimit32 = destPtr32 + destSizeInDwords; + + while(aSrceSizeInBytes > 0 && destPtr32 < destPtrLimit32) + { + TInt8 count = aStream.ReadInt8L(); + aSrceSizeInBytes--; + + if (count >= 0) //repeating pixel buffer + { + count = Min(count, (destPtrLimit32 - destPtr32)); + const TUint32 pixel = aStream.ReadUint32L(); + aSrceSizeInBytes -= 4; + + // for performance loop is unrolled, using "Duff's Device" pattern + TInt blocksOf16 = (count >> 4); // number of blocks of 16 full words to write + // the first iteration writes 1 to 15 words + switch (count & 0x0f) + { // note that case statements intentionally cascade + case 15: + do { // second and subsequent iterations always write 16 words + *destPtr32++ = pixel; + case 14: + *destPtr32++ = pixel; + case 13: + *destPtr32++ = pixel; + case 12: + *destPtr32++ = pixel; + case 11: + *destPtr32++ = pixel; + case 10: + *destPtr32++ = pixel; + case 9: + *destPtr32++ = pixel; + case 8: + *destPtr32++ = pixel; + case 7: + *destPtr32++ = pixel; + case 6: + *destPtr32++ = pixel; + case 5: + *destPtr32++ = pixel; + case 4: + *destPtr32++ = pixel; + case 3: + *destPtr32++ = pixel; + case 2: + *destPtr32++ = pixel; + case 1: + *destPtr32++ = pixel; + case 0: + *destPtr32++ = pixel; + + } while(0 <= --blocksOf16); + } + } + else // negative value corresponds non repeating pixel buffer + { + const TInt numPixels = Min(-count, destPtrLimit32 - destPtr32); + aStream.ReadL((TUint16*)destPtr32, numPixels * 2); // read TUint16's + aSrceSizeInBytes -= numPixels * 4; + destPtr32 += numPixels; + } + } + + __ASSERT_DEBUG(aSrceSizeInBytes == 0 && destPtr32 == destPtrLimit32,Panic(EFbsBitmapDecompressionError)); + } + +void CBitwiseBitmap::DoExternalizeDataCompressedL(RWriteStream& aStream,TUint8* aData,TInt aSizeInBytes) const + { + switch (iHeader.iBitsPerPixel) + { + case 1: + case 2: + case 4: + case 8: + DoExternalizeByteDataCompressedL(aStream,aData,aSizeInBytes); + break; + case 12: + DoExternalizeTwelveBitDataCompressedL(aStream,aData,aSizeInBytes); + break; + case 16: + DoExternalizeSixteenBitDataCompressedL(aStream,aData,aSizeInBytes); + break; + case 24: + DoExternalizeTwentyFourBitDataCompressedL(aStream,aData,aSizeInBytes); + break; + case 32: + __ASSERT_DEBUG(iHeader.iColor == SEpocBitmapHeader::EColor|| + iHeader.iColor == SEpocBitmapHeader::EColorAlpha|| + iHeader.iColor == SEpocBitmapHeader::EColorAlphaPM, + Panic(EFbsBitmapInvalidCompression)); + if(iHeader.iColor == SEpocBitmapHeader::EColor) + { + DoExternalizeThirtyTwoUBitDataCompressedL(aStream,aData,aSizeInBytes); + } + else + { + DoExternalizeThirtyTwoABitDataCompressedL(aStream,aData,aSizeInBytes); + } + break; + default: + break; + } + } + +void CBitwiseBitmap::DoExternalizeByteDataCompressedL(RWriteStream& aStream,TUint8* aData,TInt aSizeInBytes) const + { + TUint8* dataLimit=aData+aSizeInBytes-2; + TUint8 runPair[2]; + while(aData128) + { + aStream.WriteL(&runPair[0],2); + runLength-=128; + } + runPair[0]=TUint8(runLength-1); + aStream.WriteL(&runPair[0],2); + } + else + { + while(aData 128) + { + aStream.WriteInt8L(-128); + aStream.WriteL(runStartPtr,128); + runLength-=128; + runStartPtr+=128; + } + aStream.WriteInt8L(-runLength); + aStream.WriteL(runStartPtr,runLength); + } + } + dataLimit+=2; + if (aData 16) + { + aStream.WriteUint16L(maxLengthData); + pixelLength -= 16; + } + + if (pixelLength > 0) + aStream.WriteUint16L(value | TUint16((pixelLength - 1) << 12)); + } + } + +void CBitwiseBitmap::DoExternalizeSixteenBitDataCompressedL(RWriteStream& aStream,TUint8* aData,TInt aSizeInBytes) const + { + TUint16* srcePtr = (TUint16*)aData; + TUint16* srceLimitPtr = srcePtr + (aSizeInBytes / 2); + TUint16* srceLimitPtrMinusOne = srceLimitPtr - 1; + + while (srcePtr < srceLimitPtrMinusOne) + { + TUint16 value = *srcePtr; + TUint16* runStartPtr = srcePtr++; + + if(*srcePtr == value) + { + do + { + srcePtr++; + } + while(srcePtr < srceLimitPtr && *srcePtr == value); + + TInt pixelLength = srcePtr-runStartPtr; + while (pixelLength > 128) + { + aStream.WriteInt8L(127); + aStream.WriteUint16L(value); + pixelLength -= 128; + } + + aStream.WriteUint8L(pixelLength - 1); + aStream.WriteUint16L(value); + } + else + { + value = *srcePtr; + while (srcePtr < srceLimitPtrMinusOne && *(srcePtr + 1) != value) + { + srcePtr++; + value = *srcePtr; + } + + TInt pixelLength = srcePtr - runStartPtr; + while (pixelLength > 128) + { + aStream.WriteInt8L(-128); + aStream.WriteL(runStartPtr,128); + runStartPtr += 128; + pixelLength -= 128; + } + + aStream.WriteInt8L(-pixelLength); + aStream.WriteL(runStartPtr,pixelLength); + } + } + + TInt remainingPixels = srceLimitPtr - srcePtr; + if (remainingPixels > 0) + { + aStream.WriteInt8L(-remainingPixels); + aStream.WriteL(srcePtr,remainingPixels); + } + } + +void CBitwiseBitmap::DoExternalizeTwentyFourBitDataCompressedL(RWriteStream& aStream,TUint8* aData,TInt aSizeInBytes) const + { + TUint8* srceLimitPtr = aData + aSizeInBytes; + TUint8* srceLimitPtrMinusThree = srceLimitPtr - 3; // three bytes == one pixel + + while (aData < srceLimitPtrMinusThree) + { + TUint8* runStartPtr = aData; + TUint8 component1 = *aData++; + TUint8 component2 = *aData++; + TUint8 component3 = *aData++; + + if (TrueColorPointerCompare(aData,component1,component2,component3)) + { + do + { + aData += 3; + } + while (aData < srceLimitPtr && TrueColorPointerCompare(aData,component1,component2,component3)); + + TInt pixelLength = (aData - runStartPtr) / 3; + while (pixelLength > 128) + { + aStream.WriteInt8L(127); + aStream.WriteUint8L(component1); + aStream.WriteUint8L(component2); + aStream.WriteUint8L(component3); + pixelLength -= 128; + } + + aStream.WriteInt8L(pixelLength - 1); + aStream.WriteUint8L(component1); + aStream.WriteUint8L(component2); + aStream.WriteUint8L(component3); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + component1 = *aData++; + component2 = *aData++; + component3 = *aData++; + more = (aData < srceLimitPtr); + eqRun = more && TrueColorPointerCompare(aData,component1,component2,component3); + } + while (more && !eqRun); + if (eqRun) + aData -= 3; + TInt pixelLength = (aData - runStartPtr) / 3; + while (pixelLength > 128) + { + aStream.WriteInt8L(-128); + aStream.WriteL(runStartPtr,384); + runStartPtr += 384; + pixelLength -= 128; + } + + aStream.WriteInt8L(-pixelLength); + aStream.WriteL(runStartPtr,pixelLength * 3); + } + } + + TInt remainingPixels = srceLimitPtr - aData; + if (remainingPixels > 0) + { + TInt pixelLength = remainingPixels / 3; + aStream.WriteInt8L(-pixelLength); + aStream.WriteL(aData,remainingPixels); + } + } + +/** The function externalizes 32-bit buffer with unused top bytes to the 24-bit compressed stream by using RLE compression algorithm*/ +void CBitwiseBitmap::DoExternalizeThirtyTwoUBitDataCompressedL(RWriteStream& aStream,TUint8* aData8,TInt aSizeInBytes) const + { + + __ASSERT_DEBUG((reinterpret_cast(aData8) & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is word aligned + __ASSERT_DEBUG((aSizeInBytes & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the size is whole no of pixels + + TUint32* ptr = reinterpret_cast(aData8); + TUint32* srceLimitPtr = reinterpret_cast(aData8 + aSizeInBytes); + TUint32* srceLimitPtr2ndLast = srceLimitPtr - 1; + + while (ptr < srceLimitPtr2ndLast) + { + TUint32* runStartPtr = ptr; + TUint32 pixel = *ptr++ & 0x00ffffff; + + if ( (((*ptr)&0x00ffffff)==pixel) ) + { + do + { + ptr++; + } + while (ptr< srceLimitPtr && (((*ptr)&0x00ffffff)==pixel) ); + + TInt pixelLength = (ptr - runStartPtr); + while (pixelLength > 128) + { + aStream.WriteInt8L(127); + aStream.WriteUint8L(pixel&0x000000ff); + aStream.WriteUint8L((pixel>>8)&0x000000ff); + aStream.WriteUint8L((pixel>>16)&0x000000ff); + pixelLength -= 128; + } + + aStream.WriteInt8L(pixelLength - 1); + aStream.WriteUint8L(pixel&0x000000ff); + aStream.WriteUint8L((pixel>>8)&0x000000ff); + aStream.WriteUint8L((pixel>>16)&0x000000ff); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + pixel = *ptr++ & 0x00ffffff; + more = (ptr < srceLimitPtr); + eqRun = more && (((*ptr)&0x00ffffff)==pixel); + } while (more && !eqRun); + if (eqRun) + ptr--; + TInt pixelLength = (ptr - runStartPtr); + while (pixelLength > 128) + { + aStream.WriteInt8L(-128); + for(TInt ii = 0; ii < 128; ii++) + { + aStream.WriteL(reinterpret_cast(runStartPtr), 3); + runStartPtr++; + } + pixelLength -= 128; + } + + aStream.WriteInt8L(-pixelLength); + for(TInt kk = 0; kk < pixelLength; kk++) + { + aStream.WriteL(reinterpret_cast(runStartPtr), 3); + runStartPtr++; + } + } + } + + const TInt remainingPixels = srceLimitPtr - ptr; + if (remainingPixels > 0) + { + __ASSERT_DEBUG(remainingPixels == 1, Panic(EFbsBitmapDecompressionError)); + + aStream.WriteInt8L(-remainingPixels); + for(TInt ii = 0; ii < remainingPixels; ii++) + { + aStream.WriteL(reinterpret_cast(ptr), 3); + ptr++; + } + } + } + +/** The function externalizes 32-bit buffer with alpha channel in top byte to the 32-bit compressed stream by using RLE compression algorithm*/ +void CBitwiseBitmap::DoExternalizeThirtyTwoABitDataCompressedL(RWriteStream& aStream,TUint8* aData8,TInt aSizeInBytes) const + { + + __ASSERT_DEBUG((reinterpret_cast(aData8) & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is word aligned + __ASSERT_DEBUG((aSizeInBytes & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the size is whole no of pixels + + TUint32* ptr = reinterpret_cast(aData8); + TUint32* srceLimitPtr = reinterpret_cast(aData8 + aSizeInBytes); + TUint32* srceLimitPtr2ndLast = srceLimitPtr - 1; + + while (ptr < srceLimitPtr2ndLast) + { + TUint32* runStartPtr = ptr; + TUint32 pixel = *ptr++; + + if (*ptr==pixel) + { + do + { + ptr++; + } + while (ptr < srceLimitPtr && *ptr==pixel); + + TInt pixelLength = (ptr - runStartPtr); + while (pixelLength > 128) + { + aStream.WriteInt8L(127); + aStream.WriteUint32L(pixel); + pixelLength -= 128; + } + + aStream.WriteInt8L(pixelLength - 1); + aStream.WriteUint32L(pixel); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + pixel = *ptr++; + more = (ptr < srceLimitPtr); + eqRun = more && *ptr==pixel; + } while (more && !eqRun); + + if (eqRun) + ptr--; + + TInt pixelLength = (ptr - runStartPtr); + while (pixelLength > 128) + { + aStream.WriteInt8L(-128); + aStream.WriteL(reinterpret_cast(runStartPtr), 128*4); + runStartPtr += 128; + pixelLength -= 128; + } + + aStream.WriteInt8L(-pixelLength); + aStream.WriteL(reinterpret_cast(runStartPtr), pixelLength*4); + } + } + + const TInt remainingPixels = srceLimitPtr - ptr; + if (remainingPixels > 0) + { + __ASSERT_DEBUG(remainingPixels == 1, Panic(EFbsBitmapDecompressionError)); + + aStream.WriteInt8L(-remainingPixels); + aStream.WriteL(reinterpret_cast(ptr), remainingPixels*4); + } + } + +TInt CBitwiseBitmap::SizeOfDataCompressed(TUint8* aData,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + switch (iHeader.iBitsPerPixel) + { + case 1: + case 2: + case 4: + case 8: + return SizeOfByteDataCompressed(aData,aSizeInBytes); + case 12: + return SizeOfTwelveBitDataCompressed(aData,aSizeInBytes); + case 16: + return SizeOfSixteenBitDataCompressed(aData,aSizeInBytes); + case 24: + return SizeOfTwentyFourBitDataCompressed(aData,aSizeInBytes); + case 32: + __ASSERT_DEBUG(iHeader.iColor == SEpocBitmapHeader::EColor|| + iHeader.iColor == SEpocBitmapHeader::EColorAlpha|| + iHeader.iColor == SEpocBitmapHeader::EColorAlphaPM, + Panic(EFbsBitmapInvalidCompression)); + if(iHeader.iColor == SEpocBitmapHeader::EColor) + { + return SizeOfThirtyTwoUBitDataCompressed(aData,aSizeInBytes); + } + else + { + return SizeOfThirtyTwoABitDataCompressed(aData,aSizeInBytes); + } + default: + break; + } + + return 0; + } + +TInt CBitwiseBitmap::SizeOfByteDataCompressed(TUint8* aData,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + TInt compressedSize=0; + TUint8* dataLimit=aData+aSizeInBytes-2; + + while(aData>7) + 1) ; + } + else + { + TUint8* runStartPtr=aData; + while(aData>7) + 1; + } + } + dataLimit+=2; + if (aData>4) + 1); + } + return compressedSize; + } + +TInt CBitwiseBitmap::SizeOfSixteenBitDataCompressed(TUint8* aData,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + TInt compressedSize = 0; + TUint16* srcePtr = (TUint16*)aData; + TUint16* srceLimitPtr = srcePtr + (aSizeInBytes / 2); + TUint16* srceLimitPtrMinusOne = srceLimitPtr - 1; + + while (srcePtr < srceLimitPtrMinusOne) + { + TUint16 value = *srcePtr; + TUint16* runStartPtr = srcePtr++; + + if(*srcePtr == value) + { + do + { + srcePtr++; + } + while(srcePtr < srceLimitPtr && *srcePtr == value); + + TInt pixelLength = srcePtr-runStartPtr; + + compressedSize += 3*( ((pixelLength-1)>>7) + 1); + } + else + { + value = *srcePtr; + while (srcePtr < srceLimitPtrMinusOne && *(srcePtr + 1) != value) + { + srcePtr++; + value = *srcePtr; + } + + TInt pixelLength = srcePtr-runStartPtr; + + compressedSize += (pixelLength * 2) + ((pixelLength-1)>>7) + 1; + } + } + if (srcePtr < srceLimitPtr) + compressedSize += ((srceLimitPtr - srcePtr) * 2) + 1; + return compressedSize; + } + +TInt CBitwiseBitmap::SizeOfTwentyFourBitDataCompressed(TUint8* aData,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + TInt compressedSize = 0; + TUint8* srceLimitPtr = aData + aSizeInBytes; + TUint8* srceLimitPtrMinusThree = srceLimitPtr - 3; // three bytes == one pixel + + while (aData < srceLimitPtrMinusThree) + { + TUint8* runStartPtr = aData; + TUint8 component1 = *aData++; + TUint8 component2 = *aData++; + TUint8 component3 = *aData++; + + if (TrueColorPointerCompare(aData,component1,component2,component3)) + { + do + { + aData += 3; + } + while (aData < srceLimitPtr && TrueColorPointerCompare(aData,component1,component2,component3)); + + TInt pixelLength = (aData - runStartPtr) / 3; + + compressedSize += 4*( ((pixelLength-1)>>7) + 1); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + component1 = *aData++; + component2 = *aData++; + component3 = *aData++; + more = (aData < srceLimitPtr); + eqRun = more && TrueColorPointerCompare(aData,component1,component2,component3); + } + while (more && !eqRun); + if (eqRun) + aData -= 3; + TInt pixelLength = (aData - runStartPtr) / 3; + + compressedSize += (pixelLength * 3) + ((pixelLength-1)>>7) + 1; + } + } + + if (aData < srceLimitPtr) + compressedSize += srceLimitPtr - aData + 1; + + return compressedSize; + } + +/** The function calculates the size of 24-bit RLE compression stream which could be obtain from given 32-bit buffer, + where the top bytes are unused*/ +TInt CBitwiseBitmap::SizeOfThirtyTwoUBitDataCompressed(TUint8* aData8,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + __ASSERT_DEBUG((reinterpret_cast(aData8) & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is word aligned + __ASSERT_DEBUG((aSizeInBytes & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the size is whole no of pixels + + + TInt compressedSize = 0; + + + TUint32* ptr = reinterpret_cast(aData8); + TUint32* srceLimitPtr = reinterpret_cast(aData8 + aSizeInBytes); + TUint32* srceLimitPtr2ndLast = srceLimitPtr - 1; + while (ptr < srceLimitPtr2ndLast) + { + TUint32* runStartPtr = ptr; + TUint32 pixel = *ptr++ & 0x00ffffff; + + if ((((*ptr)&0x00ffffff)==pixel)) + { + do + { + ptr++; + } + while (ptr < srceLimitPtr && (((*ptr)&0x00ffffff)==pixel)); + + TInt pixelLength = (ptr - runStartPtr); + compressedSize += 4*( ((pixelLength-1)>>7) + 1); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + pixel = *ptr++ & 0x00ffffff; + more = (ptr < srceLimitPtr); + eqRun = more && (((*ptr)&0x00ffffff)==pixel); + } while (more && !eqRun); + + if (eqRun) + ptr--; + + TInt pixelLength = (ptr - runStartPtr) ; + compressedSize += 3*pixelLength + ((pixelLength-1)>>7) + 1; + } + } + + if (ptr < srceLimitPtr) + compressedSize += (srceLimitPtr - ptr)*3 + 1; + + return compressedSize; + } + + +TBool CBitwiseBitmap::TrueColorPointerCompare(TUint8* aColorPointer,TUint8 aComponent1,TUint8 aComponent2,TUint8 aComponent3) const + { + return (*aColorPointer == aComponent1 && *(aColorPointer + 1) == aComponent2 && *(aColorPointer + 2) == aComponent3); + } + +/** This function calculates the size of 32-bit RLE compression stream which is obtained from a given 32-bit buffer, + where the top 8 bits are used to represent the alpha channel*/ +TInt CBitwiseBitmap::SizeOfThirtyTwoABitDataCompressed(TUint8* aData8,TInt aSizeInBytes) const + { + if(aSizeInBytes<=0) + return 0; + + __ASSERT_DEBUG((reinterpret_cast(aData8) & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the start address is word aligned + __ASSERT_DEBUG((aSizeInBytes & 0x3)==0,Panic(EFbsBitmapDecompressionError)); // make sure the size is whole no of pixels + + + TInt compressedSize = 0; + + + TUint32* ptr = reinterpret_cast(aData8); + TUint32* srceLimitPtr = reinterpret_cast(aData8 + aSizeInBytes); + TUint32* srceLimitPtr2ndLast = srceLimitPtr - 1; + while (ptr < srceLimitPtr2ndLast) + { + TUint32* runStartPtr = ptr; + TUint32 pixel = *ptr++; + + if (*ptr==pixel) + { + do + { + ptr++; + } + while (ptr < srceLimitPtr && *ptr==pixel); + + TInt pixelLength = (ptr - runStartPtr); + compressedSize += 5*( ((pixelLength-1)>>7) + 1); + } + else + { + TBool more = ETrue; + TBool eqRun = EFalse; + do + { + pixel = *ptr++; + more = (ptr < srceLimitPtr); + eqRun = more && *ptr==pixel; + } while (more && !eqRun); + + if (eqRun) + ptr--; + + TInt pixelLength = (ptr - runStartPtr) ; + compressedSize += 4*pixelLength + ((pixelLength-1)>>7) + 1; + } + } + + if (ptr < srceLimitPtr) + compressedSize += (srceLimitPtr - ptr)*4 + 1; + + return compressedSize; + } + + +/* Here's a BNF description of the RLE encoding in use for all but the 12-bit compression: + + encoding := run* + run := equal-run | unequal-run + equal-run := pixel-value + unequal-run := <-runlength> pixel-value+ (i.e. pixel-value repeated times) + runlength := uint8 in 1..128 + pixelvalue := byte-pixel | 16bit-pixel | 24bit-pixel | 32bit-u-pixel | 32bit-a-pixel + byte-pixel := octet + 16bit-pixel := octet octet + 24bit-pixel := rr gg bb + 32bit-u-pixel := rr gg bb + 32bit-a-pixel := rr gg bb aa + rr := octet (red component) + gg := octet (green component) + bb := octet (blue component) + aa := octet (alpha channel) + + This scheme models runs of 2-128 equal pixels or of upto 127 unequal pixels. + Obviously a run of 0 is meaningless. A run of 1 is considered to be an 'unequal' run containing + a single pixel. + + For 12-bit compression a different encoding scheme is used. Only equal-runs are written, and the + run length is encoded into the top 4 bits of a 16 bit word. Here's a BNF for 12-bit compression: + + 12-bit-encoding := run* + run := equal-run + equal-run := high-octet low-octet + high-octet := [ rr] + low-octet := [gg bb] + runlength := 1..16 + rr := quartet (red component) + gg := quartet (green component) + bb := quartet (blue component) + +*/ + +//Palette compression additions + +/** +Attempts to compress a bitmap by reducing it to a palette + data. +If the compression fails, for any of the reasons detailed below, RLE compression will be attempted instead. +Prerequisites: +- Bitmap must not already be compressed. +- Bitmap must contain no more than 255 colors - If bitmap contains >255 colors then palette compression is unlikely to be effective. +- Bitmap must be 16, 24 or 32 (non alpha) bpp. Other modes could be implemented, but smaller bit depths will yield less compression +Small bitmaps (under 1000 pixels) will be unlikely to compress well if at all +Structure of compressed bitmap will be as follows; +size of palette[4 bytes] | palette[size * 4 bytes per entry] | data[pixels * upto 1 byte per pixel] +Bitmap data is packed into memory as efficiently as possible, according to the number of bits required. +Each line of the compressed bitmap will start on a byte boundary, but not necessarily on a word boundary. +*/ +TInt CBitwiseBitmap::PaletteCompress() + { + //Compression algorithm + //1.Iterate bitmap data, building hash of unique colours found + //2.Iterate the hash, and build linear array of the unique colours (this is the palette) + //3.Iterate the array, and set the array index of each colour back into the hash + //4.Iterate the bitmap data again, for each pixel replace with palette index found from hash + + //Bitmap must be uncompressed + if (iHeader.iCompression != ENoBitmapCompression) + return KErrNone; + + //There must be some data in the bitmap + TUint8* base = REINTERPRET_CAST(TUint8*, DataAddress()); + if (!base) + return KErrNone; + + //Get the bytes per pixel, and make sure it is a supported configuration + TUint sourceBytesPerPixel = PaletteBytesPerPixel(iHeader.iBitsPerPixel); + if (sourceBytesPerPixel == 0) + return KErrNotSupported; + + //Create a hash table and give it a decent amount of RAM to start with + RHashMap colors; + if (colors.Reserve(256) != KErrNone) + return KErrNoMemory; + + //Loop the data area of the bitmap, one pixel (sourceBytesPerPixel bytes) at a time + TInt numPixels = (iHeader.iSizeInPixels.iWidth * iHeader.iSizeInPixels.iHeight); + //we need some pixels! + if (numPixels == 0) + { + colors.Close(); + return KErrNone; + } + + TUint8* top = base + (iHeader.iSizeInPixels.iHeight * iByteWidth) ; //address of lastmost byte + TInt32 lineLengthInBytes = iHeader.iSizeInPixels.iWidth * sourceBytesPerPixel; //The actual useful data on each line + TInt32 lineLengthInBytesPadded = iByteWidth ; //the actual (aligned) length of each line + TUint8* pixelAddress; + TUint8* lineAddress; + //Loop each line of the bitmap data. Note that each line ends on a 32bit align in the source MBM data. + TUint8* lineEnd=0; + + //Separate looping for 16 & 24+ bpp. Adds a chunk of duplicated code but saves checking bpp for every pixel + if (iHeader.iBitsPerPixel < 24) + { + for (lineAddress=base;lineAddress 256) + { + colors.Close(); + return KErrNotSupported ; + } + } + } + else //>=24 bpp + { + for (lineAddress = base; lineAddress 256) + { + colors.Close(); + return KErrNotSupported; + } + } //for + }//end if + + + //Now we have enough data to build the palette by iterating all the entries in the colors hash + RArray palette(colors.Count()); + THashMapIter colorIterator(colors); + const TInt* color = colorIterator.NextKey(); + while (color) + { + if (palette.Append(*color) != KErrNone) + { + palette.Close(); + colors.Close(); + return KErrNoMemory; + } + //set the index of each entry back into the color hash for lookup later + //const cast needed as CurrentValue returns a const pointer; for no good reason? + TInt* index = CONST_CAST(TInt*, colorIterator.CurrentValue()); + *index = palette.Count() - 1; + color = colorIterator.NextKey(); + } + + //Set up some new memory for the palettised bitmap + //size is (4 bytes for palette size) + (4 bytes per palette entry) + (upto 1 byte per pixel) + //pixels are packed according to number of colors + TUint compressedBitsPerPixel = PaletteBitsPerPixel(colors.Count()); + TUint compressedPixelsPerByte = 8 / compressedBitsPerPixel; + TUint compressedLineLengthInBytesPadded = (iHeader.iSizeInPixels.iWidth + compressedPixelsPerByte - 1)/ compressedPixelsPerByte; + TInt compressedDataBytes = 4 + 4 * colors.Count() + compressedLineLengthInBytesPadded * iHeader.iSizeInPixels.iHeight; + + //add two extra ints for storing function pointers (8 bytes ) + compressedDataBytes += 8 ; + + TUint8* compressedBase = NULL; + compressedBase = iPile->Alloc(compressedDataBytes); + if (!compressedBase) + { + palette.Close(); + colors.Close(); + return KErrNoMemory; + } + iDataOffset = compressedBase - iPile->ChunkBase(); + + iHeader.iBitmapSize = sizeof(SEpocBitmapHeader) + compressedDataBytes; + iHeader.iCompression = EGenericPaletteCompression; + + //copy the palette length into the data area... + *(REINTERPRET_CAST(TInt*, compressedBase)) = palette.Count(); //let's hope we're 4 byte aligned... + compressedBase+=4; + //...then the palette itself... + for (TUint loop = 0; loop < palette.Count(); loop++) + { + *(REINTERPRET_CAST(TInt*, compressedBase)) = palette[loop]; + compressedBase +=4; + } + + //Work out, then store, the decoding functions required for packing density and colour depth. + //This saves having to do it for every scanline during decompression. + + TDecodeFunction decodeFunction = NULL; + switch (compressedPixelsPerByte) + { + case 1: + decodeFunction=CBitwiseBitmap::PaletteDecode1PixelPerByte; + break; + case 2: + decodeFunction=CBitwiseBitmap::PaletteDecode2PixelPerByte; + break; + case 4: + decodeFunction=CBitwiseBitmap::PaletteDecode4PixelPerByte; + break; + case 8: + decodeFunction=CBitwiseBitmap::PaletteDecode8PixelPerByte; + break; + default: + ::Panic(EFbsNotSupportedForCompression); + } + *(REINTERPRET_CAST(TDecodeFunction*, compressedBase)) = decodeFunction ; + compressedBase += 4 ; + + //Select the appropriate assignment function based on the bits-per-pixel of the target + TAssignFunction assignFunction = NULL; + switch (iHeader.iBitsPerPixel) + { + case 16: + assignFunction=CBitwiseBitmap::PaletteAssign16BitColor; + break; + case 24: + assignFunction=CBitwiseBitmap::PaletteAssign24BitColor; + break; + case 32: + assignFunction=CBitwiseBitmap::PaletteAssign32BitColor; + break; + default: + ::Panic(EFbsNotSupportedForCompression); + } + *(REINTERPRET_CAST(TAssignFunction*, compressedBase)) = assignFunction ; + compressedBase += 4 ; + + //...and finally the data + pixelAddress = base; + + //separate loops for 16 & 24+ bpp again + + if ( iHeader.iBitsPerPixel < 24 ) + { + for (lineAddress = base; lineAddress < top; lineAddress += lineLengthInBytesPadded) + { + //Loop each pixel within the line + pixelAddress = lineAddress; + while (pixelAddress < lineAddress + lineLengthInBytes) + { + TUint8 pack = 0; + //loop for each pixel to pack into the byte. If we run out of pixels in the line, we write out the pack byte and continue on the next line + for (TInt ii = 0; ii < compressedPixelsPerByte && pixelAddress < lineAddress + lineLengthInBytes; ii++) + { + pack <<= compressedBitsPerPixel; + //extract the color + TUint color = *pixelAddress; + color |= (*(pixelAddress+1)) << 8; + + //lookup the palette index for the color + TInt* paletteIndex = colors.Find(color); + //pack the palette index into the target byte + pack |= *paletteIndex; + //next pixel + pixelAddress += sourceBytesPerPixel; + } + //store the packed pixel data into the new compressed data area + *compressedBase = pack; + compressedBase++; + } + } + } + else //>= 24bpp + { + for (lineAddress = base; lineAddress < top; lineAddress += lineLengthInBytesPadded) + { + //Loop each pixel within the line + pixelAddress = lineAddress; + while (pixelAddress < lineAddress + lineLengthInBytes) + { + TUint8 pack = 0; + //loop for each pixel to pack into the byte. If we run out of pixels in the line, we write out the pack byte and continue on the next line + for (TInt ii = 0; ii < compressedPixelsPerByte && pixelAddress < lineAddress + lineLengthInBytes; ii++) + { + pack <<= compressedBitsPerPixel; + //extract the color + TUint color = *pixelAddress; + color |= (*(pixelAddress+1)) << 8; + color |= (*(pixelAddress+2)) << 16; + //if 32 bit, just ignore the 4th byte as it is unused for color data + + //lookup the palette index for the color + TInt* paletteIndex = colors.Find(color); + //pack the palette index into the target byte + pack |= *paletteIndex; + //next pixel + pixelAddress += sourceBytesPerPixel; + } + //store the packed pixel data into the new compressed data area + *compressedBase = pack; + compressedBase++; + } + } + }//if + + + //Set the RAM compression flag + iIsCompressedInRAM = ETrue; + + //Free the old data. + iPile->Free(base); + //Clean up + palette.Close(); + colors.Close(); + return KErrNone; + } + +/** +Create a scan line from a palette compressed bitmap. +Starting from aPixel in the bitmap pointed to be aBase, populate aDestBuffer with aLength pixels looked up in the palette. +Note this function assumes 16, 24 or 32 non alpha bit uncompressed bitmaps, compressed into 8 bit palettes (ie <256 colors) +Structure of bitmap is (4 bytes for palette size) + (4 bytes per palette entry) + (1 byte per pixel) +@param aDestBuffer Points to the destination buffer. After the call it will be filled +with the decompressed data. +@param aPixel The decompression starts from this pixel +@param aLength Length of requested decompressed data - in pixels +@param aBase Points to the beginning of compressed bitmap data +@param aLineScannngPosition Saved information about the last used position in the compressed data +*/ +void CBitwiseBitmap::GenerateLineFromPaletteCompressedData( + TUint8* aDestBuffer, + const TPoint& aPixel, + TInt aLength, + TUint32* aBase, + TLineScanningPosition& /*aLineScanningPosition*/) const + { + //At entry, aBase will point to the start of the compressed data, ie the palette size + //Each line in the bitmap will start at a byte boundary in the compressed data. + + TUint32* srcPalette = aBase + 1; //Address of the palette in the source data + TUint srcNumPaletteEntries = *aBase; //Number of entries in the palette (will be <=255) + TUint compressedBitsPerPixel = PaletteBitsPerPixel(srcNumPaletteEntries); + __ASSERT_DEBUG(compressedBitsPerPixel <= 8, Panic( EFbsBitmapDecompressionError )) ; + const TUint8 lookup[] = {0, 8, 4, 0, 2, 0, 0, 0, 1}; + //TUint compressedPixelsPerByte = 8 / compressedBitsPerPixel; + TUint compressedPixelsPerByte = lookup[compressedBitsPerPixel]; + __ASSERT_DEBUG(compressedPixelsPerByte>0, ::Panic(EFbsNotSupportedForCompression)); + + TUint8* srcData = REINTERPRET_CAST(TUint8*, srcPalette + srcNumPaletteEntries); //Address of the pixel data in the source data + + //Extract the function pointers for decoding functions. Set up decode & assign functions. + TDecodeFunction decodeFunction = NULL ; + decodeFunction = reinterpret_cast(*((TUint32*)srcData )) ; + srcData += 4 ; + TAssignFunction assignFunction = NULL; + assignFunction = reinterpret_cast(*((TUint32*)srcData )) ; + srcData += 4 ; + + //Note: The following lines have been optimised to avoid divisions. + //By way of explanation the original lines have been left as comments + + //TUint srcBytesPerLinePadded = (iHeader.iSizeInPixels.iWidth + compressedPixelsPerByte - 1) / compressedPixelsPerByte; //number of bytes occupied by each line in the compressed bitmap. + TUint srcBytesPerLinePadded = ((iHeader.iSizeInPixels.iWidth + compressedPixelsPerByte - 1) * compressedBitsPerPixel) >> 3; //number of bytes occupied by each line in the compressed bitmap. + //TUint srcStartBytesFromBase = aPixel.iY * srcBytesPerLinePadded + aPixel.iX / compressedPixelsPerByte; //Starting bytes from the start of the bitmap + TUint srcStartBytesFromBase = aPixel.iY * srcBytesPerLinePadded + ((aPixel.iX * compressedBitsPerPixel) >> 3); //Starting bytes from the start of the bitmap + //TUint srcStartPixelInByte = aPixel.iX % compressedPixelsPerByte; //starting pixel position in byte (lines start on byte boundary) + TUint srcStartPixelInByte = aPixel.iX & ((compressedPixelsPerByte)- 1); //starting pixel position in byte (lines start on byte boundary) + //TUint srcEndBytesFromBase = srcStartBytesFromBase + (aLength + compressedPixelsPerByte - 1) / compressedPixelsPerByte; //Ending bytes from the start of the bitmap + TUint srcEndBytesFromBase = srcStartBytesFromBase + (((aLength + compressedPixelsPerByte - 1) * compressedBitsPerPixel) >> 3); //Ending bytes from the start of the bitmap + //TUint srcEndPixelInByte = (aPixel.iX + aLength) % compressedPixelsPerByte; //Ending pixel position in byte + TUint srcEndPixelInByte = (aPixel.iX + aLength) & ((compressedPixelsPerByte)-1); //Ending pixel position in byte + TUint8* srcStartData = srcData + srcStartBytesFromBase; //Address of the first byte of packed pixels in the source + TUint8* srcEndData = srcData + srcEndBytesFromBase; //Address of the last+1 byte of packed pixels in the source + TUint8* destStartData = aDestBuffer + ((aPixel.iX*iHeader.iBitsPerPixel) >> 3); //Address of the first pixel in the destination + + //3 stages to the decompression: + //1. Decompress any pixels which are a subset of the first byte + //2. Loop whole bytes extracting all pixels at once + //3. Decompress any pixels which are a subset of the last byte + + TUint8* srcDataPtr = srcStartData; + + //Stage 1: Decompress any pixels which are a subset of the first byte + if (srcStartPixelInByte > 0) + PaletteDecodeAndAssignGeneric(srcDataPtr++, srcPalette, destStartData, srcStartPixelInByte, compressedPixelsPerByte-1, compressedPixelsPerByte, compressedBitsPerPixel); + + //If the last byte is only partly packed with pixels from this line, stop one byte short in the main loop + if (srcEndPixelInByte > 0) + srcEndData--; + + //Stage 2: Loop all the required pixels and call the appropriate functions + while (srcDataPtr < srcEndData) + { + __ASSERT_DEBUG(srcDataPtr <= srcEndData, ::Panic(EFbsNotSupportedForCompression)); + __ASSERT_DEBUG(destStartData <= aDestBuffer + ((aPixel.iX*iHeader.iBitsPerPixel) >> 3) + aLength * PaletteBytesPerPixel(iHeader.iBitsPerPixel), ::Panic(EFbsNotSupportedForCompression)); + (*decodeFunction)(srcDataPtr++, srcPalette, destStartData, assignFunction); + } + + //Stage 3: Decompress any pixels which are a subset of the last byte + if (srcEndPixelInByte > 0) + PaletteDecodeAndAssignGeneric(srcDataPtr++, srcPalette, destStartData, 0, srcEndPixelInByte-1, compressedPixelsPerByte, compressedBitsPerPixel); + } + +/** +This function deals with all different bit depths & color counts dynamically - smaller but slower +@param aDataPtr Address in compressed data to read from +@param aPalettePtr Address of the start of the palette in the compressed data +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aStartPixel Zero based position within the compressed byte of the first pixel to decompress +@param aEndPixel Zero based position within the compressed byte of the last pixel to decompress +@param aCompressedPixelsPerByte Number of pixels packed into each byte of the compressed data +@param aCompressedBitsPerPixel Number of bits used to express each pixel in the compressed data. Nothing to do with the color depth of the image. +*/ +void CBitwiseBitmap::PaletteDecodeAndAssignGeneric( TUint8* aDataPtr, + TUint32* aPalettePtr, + TUint8*& aDestPtr, + TUint aStartPixel, + TUint aEndPixel, + TUint aCompressedPixelsPerByte, + TUint aCompressedBitsPerPixel) const + { + __ASSERT_DEBUG(aStartPixel>= aStartPixel * aCompressedBitsPerPixel; + + TUint8 pack = *aDataPtr; //max of 8 bits for palette entry + + //Loop the pixel data from the requested start to the requested end + for (TInt ii = aStartPixel; ii <= aEndPixel; ii++) + { + //extract the bits corresponding to the required color index from the pack using the mask + TUint8 index = pack&mask; + //shift the index to the right to get true value + index >>= (aCompressedPixelsPerByte- ii - 1) * aCompressedBitsPerPixel; + //get the address of the required color value from the palette + TUint32 color = *(aPalettePtr + index); + //and copy the actual color value into the scanline buffer + *aDestPtr ++= color; + *aDestPtr ++= color >> 8; + if (iHeader.iBitsPerPixel >= 24) + *aDestPtr ++= color >> 16; + if (iHeader.iBitsPerPixel == 32) + *aDestPtr ++= 0xFF; //use 0xFF rather than 0x00 as it is more alpha friendly + + //shift the mask to get the next required bits + mask >>= aCompressedBitsPerPixel; + } + } + +/** +Specialised function for decoding pixels from a palette compressed bitmap with 1 pixel packed in each byte. +Implemented for speed, not size +@param aDataPtr Address in compressed data to read from +@param aPalettePtr Address of the start of the palette in the compressed data +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aAssignFunction Function pointer to assigment function to use to write actual pixel data to uncompressed scanline +*/ +void CBitwiseBitmap::PaletteDecode1PixelPerByte(TUint8* aDataPtr, TUint32* aPalettePtr, TUint8*& aDestPtr, TAssignFunction aAssignFunction) + { + (*aAssignFunction)(aDestPtr, *(aPalettePtr + *aDataPtr)); + } + +/** +Specialised function for decoding pixels from a palette compressed bitmap with 2 pixels packed in each byte. +Implemented for speed, not size +@param aDataPtr Address in compressed data to read from +@param aPalettePtr Address of the start of the palette in the compressed data +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aAssignFunction Function pointer to assigment function to use to write actual pixel data to uncompressed scanline +*/ +void CBitwiseBitmap::PaletteDecode2PixelPerByte(TUint8* aDataPtr, TUint32* aPalettePtr, TUint8*& aDestPtr, TAssignFunction aAssignFunction) + { + TUint8 mask = 0xF0; //binary 11110000 + TUint8 pack = *aDataPtr; + //Pixel 1 + TUint8 index = pack&mask; + index >>= 4; + TUint32 color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 4; + //Pixel 2 + index = pack&mask; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + } + +/** +Specialised function for decoding pixels from a palette compressed bitmap with 4 pixels packed in each byte. +Implemented for speed, not size +@param aDataPtr Address in compressed data to read from +@param aPalettePtr Address of the start of the palette in the compressed data +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aAssignFunction Function pointer to assigment function to use to write actual pixel data to uncompressed scanline +*/ +void CBitwiseBitmap::PaletteDecode4PixelPerByte(TUint8* aDataPtr, TUint32* aPalettePtr, TUint8*& aDestPtr, TAssignFunction aAssignFunction) + { + TUint8 mask = 0xC0; //binary 11000000 + TUint8 pack = *aDataPtr; + //Pixel 1 + TUint8 index = pack&mask; + index >>= 6; + TUint32 color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 2; + //Pixel 2 + index = pack&mask; + index >>= 4; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 2; + //Pixel 3 + index = pack&mask; + index >>= 2; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 2; + //Pixel 4 + index = pack&mask; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + } + +/** +Specialised function for decoding pixels from a palette compressed bitmap with 8 pixels packed in each byte. +Implemented for speed, not size +@param aDataPtr Address in compressed data to read from +@param aPalettePtr Address of the start of the palette in the compressed data +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aAssignFunction Function pointer to assigment function to use to write actual pixel data to uncompressed scanline +*/ +void CBitwiseBitmap::PaletteDecode8PixelPerByte(TUint8* aDataPtr, TUint32* aPalettePtr, TUint8*& aDestPtr, TAssignFunction aAssignFunction) + { + TUint8 mask = 0x80; //binary 10000000 + TUint8 pack = *aDataPtr; + //Pixel 1 + TUint8 index = pack&mask; + index >>= 7; + TUint32 color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 2 + index = pack&mask; + index >>= 6; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask>>=1; + //Pixel 3 + index = pack&mask; + index >>= 5; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 4 + index = pack&mask; + index >>= 4; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 5 + index = pack&mask; + index >>= 3; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 6 + index = pack&mask; + index >>= 2; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 7 + index = pack&mask; + index >>= 1; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + mask >>= 1; + //Pixel 8 + index = pack&mask; + color = *(aPalettePtr + index); + (*aAssignFunction)(aDestPtr, color); + } + +/** +Specialised function for assigning pixels into an uncompressed scanline of 16 bit color depth. +Implemented for speed, not size +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aColor Color info to write. +*/ +void CBitwiseBitmap::PaletteAssign16BitColor(TUint8*& aDestPtr, TUint32 aColor) + { + *aDestPtr ++= aColor; + *aDestPtr ++= aColor >> 8; + } + +/** +Specialised function for assigning pixels into an uncompressed scanline of 24 bit color depth. +Implemented for speed, not size +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aColor Color info to write. +*/ +void CBitwiseBitmap::PaletteAssign24BitColor(TUint8*& aDestPtr, TUint32 aColor) + { + *aDestPtr ++= aColor; + *aDestPtr ++= aColor >> 8; + *aDestPtr ++= aColor >> 16; + } + +/** +Specialised function for assigning pixels into an uncompressed scanline of 32 bit color depth. +Implemented for speed, not size +@param aDestPtr Address to write uncompressed data to. Will be incremented on return from function. +@param aColor Color info to write. +*/ +void CBitwiseBitmap::PaletteAssign32BitColor(TUint8*& aDestPtr, TUint32 aColor) + { + *aDestPtr ++= aColor; + *aDestPtr ++= aColor >> 8; + *aDestPtr ++= aColor >> 16; + *aDestPtr ++= 0xFF; //use 0xFF rather than 0x00 as it is more alpha friendly + } + +/** +Get the bits used per pixel when packing multiple pixels in palette compression. +The value returned is a power of 2, not always the most efficient pack, for alignment reasons, Eg + 65537 -> KMaxTInt : 32 bpp + 257 -> 65536 colors : 16 bpp + 17 -> 256 colors : 8 bpp + 5 -> 16 colors : 4 bpp + 3 -> 4 colors : 2 bpp + 0 -> 2 colors : 1 bpp +@param aNumColors The number of colors in the bitmap. This governs the size of the palette and thus +the number of bits needed to represent an index into it. +*/ +TUint CBitwiseBitmap::PaletteBitsPerPixel(TInt aNumColors) const + { + if (aNumColors <= 2) + return 1; + else if (aNumColors <= 4) + return 2; + else if (aNumColors <= 16) + return 4; + else if (aNumColors <= 256) + return 8; + else if (aNumColors <= 65536) + return 16; + else + return 32; + } + +/** +Gets the bytes used per pixel according to the bits per pixel of a bitmap. +Also used to find which bit per pixel values are supported by palette compression, hence this is not +a case of simple division by 8. +If return value is zero, the supplied bit per pixel value is not supported by palette compression. +@param aBitsPerPixel The bits per pixel value to transform into bytes +*/ +TUint CBitwiseBitmap::PaletteBytesPerPixel(TInt aBitsPerPixel) const + { + if (aBitsPerPixel == 16) + return 2; //16 bit + else if (aBitsPerPixel == 24) + return 3; //24 bit + else if (aBitsPerPixel == 32 && iHeader.iColor == SEpocBitmapHeader::EColor) + return 4; //32 bit with no alpha + else + return 0; + } +