📄 pngcodec.cpp
字号:
User::Leave(KErrCorrupt);
Mem::Copy(iImageInfo.iTransparencyValue,aDataPtr,aChunkLength);
}
else if (iImageInfo.iColorType == TPngImageInformation::EGrayscale) // 0
{
if (aChunkLength < 2)
User::Leave(KErrCorrupt);
iImageInfo.iTransparentGray = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
}
else if (iImageInfo.iColorType == TPngImageInformation::EDirectColor) // 2
{
if (aChunkLength < 6)
User::Leave(KErrCorrupt);
iImageInfo.iTransparentRed = TUint16((aDataPtr[0] << 8) | aDataPtr[1]);
iImageInfo.iTransparentGreen = TUint16((aDataPtr[2] << 8) | aDataPtr[3]);
iImageInfo.iTransparentBlue = TUint16((aDataPtr[4] << 8) | aDataPtr[5]);
}
}
// Process a PNG image data
void CPngReadCodec::DoProcessDataL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
{
// Data is passed to the decompressor
TInt bytesToProcess = Min(aDataPtrLimit - aDataPtr,iChunkBytesRemaining);
iDataDes.Set(aDataPtr,bytesToProcess);
iDecompressor->SetInput(iDataDes);
while (iDecompressor->AvailIn() > 0)
iDecompressor->InflateL();
aDataPtr += bytesToProcess;
iChunkBytesRemaining -= bytesToProcess;
}
// From MEZBufferManager: manage decompressor stream
void CPngReadCodec::InitializeL(CEZZStream& aZStream)
{
aZStream.SetOutput(iDecoder->FirstBuffer());
}
void CPngReadCodec::NeedInputL(CEZZStream& /*aZStream*/)
{
}
void CPngReadCodec::NeedOutputL(CEZZStream& aZStream)
{
aZStream.SetOutput(iDecoder->DecodeL());
}
void CPngReadCodec::FinalizeL(CEZZStream& /*aZStream*/)
{
iDecoder->DecodeL();
}
//
// CPngWriteCodec: writes a PNG image
//
CPngWriteCodec::CPngWriteCodec(TInt aBpp, TBool aColor, TBool aPaletted, TInt aCompressionLevel)
: iCompressionLevel(aCompressionLevel), iCompressorPtr(NULL, 0)
{
// Set bpp
iImageInfo.iBitsPerPixel = aBpp;
switch (aBpp)
{
case 1:
iImageInfo.iBitDepth = 1;
break;
case 2:
iImageInfo.iBitDepth = 2;
break;
case 4:
iImageInfo.iBitDepth = 4;
break;
case 8:
case 24:
iImageInfo.iBitDepth = 8;
break;
default:
break;
}
// Set color type
if (aColor && aPaletted)
iImageInfo.iColorType = TPngImageInformation::EIndexedColor;
else if (aColor)
iImageInfo.iColorType = TPngImageInformation::EDirectColor;
else
iImageInfo.iColorType = TPngImageInformation::EGrayscale;
}
CPngWriteCodec::~CPngWriteCodec()
{
delete iCompressor;
delete iEncoder;
}
// Called by framework at start of conversion operation
void CPngWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
{
if (aDst.Length() == 0)
User::Leave(KErrArgument); // Not enough length for anything
SetSource(&aSource);
iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
iDestPtr = iDestStartPtr;
iDestPtrLimit = iDestPtr + aDst.MaxLength();
// Set image information
const SEpocBitmapHeader& header = aSource.Header();
iImageInfo.iSize = header.iSizeInPixels;
switch (iImageInfo.iBitDepth)
{
case 1:
case 2:
case 4:
if (iImageInfo.iColorType == TPngImageInformation::EDirectColor)
{
// Bit depths 1, 2 and 4 don't support RGB colour (color mode 2)
// Must use paletted colour or greyscale
User::Leave(KErrNotSupported);
break;
}
// fall through to case 8
case 8:
break;
default:
User::Leave(KErrNotSupported); // unsupported bit depth
break;
}
iImageInfo.iCompressionMethod = TPngImageInformation::EDeflateInflate32K;
iImageInfo.iFilterMethod = TPngImageInformation::EAdaptiveFiltering;
iImageInfo.iInterlaceMethod = TPngImageInformation::ENoInterlace;
// Create encoder
if (iEncoder)
{
delete iEncoder;
iEncoder = NULL;
}
iEncoder = CPngWriteSubCodec::NewL(iImageInfo, &aSource);
// Create compressor
if (iCompressor)
{
delete iCompressor;
iCompressor = NULL;
}
iCompressor = CEZCompressor::NewL(*this, iCompressionLevel);
// Initial encoder state
if (iImageInfo.iColorType == TPngImageInformation::EIndexedColor)
iEncoderState = EPngWritePLTE;
else
iEncoderState = EPngDeflate;
iCallAgain = ETrue; // to make sure we call DeflateL
// Write header
User::LeaveIfError(WriteHeaderChunk(aDst));
}
// Called by the framework to process frame data
TFrameState CPngWriteCodec::ProcessFrameL(TBufPtr8& aDst)
{
if (aDst.Length() == 0)
User::Leave(KErrArgument); // Not enough length for anything
TFrameState state = EFrameIncomplete;
iDestStartPtr = const_cast<TUint8*>(aDst.Ptr());
iDestPtr = iDestStartPtr;
iDestPtrLimit = iDestPtr + aDst.MaxLength();
// Set return buffer length to 0 initially
aDst.SetLength(0);
while (aDst.Length() == 0 && state != EFrameComplete)
{
// Loop round until we have some data to return or
// the image is encoded
switch (iEncoderState)
{
case EPngWritePLTE:
WritePLTEChunk(aDst);
break;
case EPngDeflate:
DeflateEncodedDataL(aDst, state);
break;
case EPngWriteIDAT:
WriteIDATChunk(aDst);
break;
case EPngFlush:
FlushCompressedDataL(aDst, state);
break;
case EPngEndChunk:
WriteEndChunk(aDst);
state = EFrameComplete;
break;
default:
break;
}
}
return state;
}
// Write a compressed image data chunk
void CPngWriteCodec::DeflateEncodedDataL(TBufPtr8& aDst, TFrameState& /*aState*/)
{
// Set ptr for compressed data
const TInt dataLength = aDst.MaxLength() - KPngChunkLengthSize - KPngChunkIdSize - KPngChunkCRCSize;
ASSERT(dataLength > 0);
iCompressorPtr.Set(iDestPtr + KPngChunkIdSize + KPngChunkLengthSize, dataLength, dataLength);
// Initialise input/output for compressor
iCompressor->SetInput(iEncoder->EncodeL(iScanline));
iScanline++;
iCompressor->SetOutput(iCompressorPtr);
while ((iEncoderState == EPngDeflate) && iCallAgain)
iCallAgain = iCompressor->DeflateL();
// Write the IDAT chunk
WriteIDATChunk(aDst);
iEncoderState = EPngFlush;
}
void CPngWriteCodec::FlushCompressedDataL(TBufPtr8& aDst, TFrameState& /*aState*/)
{
if (iCallAgain)
{
iCallAgain = iCompressor->DeflateL();
WriteIDATChunk(aDst);
}
else
{
iEncoderState = EPngEndChunk;
}
}
// Write a PLTE chunk
void CPngWriteCodec::WritePLTEChunk(TBufPtr8& aDst)
{
ASSERT(iEncoder->Palette() &&
(iImageInfo.iColorType == TPngImageInformation::EIndexedColor ||
iImageInfo.iColorType == TPngImageInformation::EDirectColor ||
iImageInfo.iColorType == TPngImageInformation::EAlphaDirectColor)); // allowed color types for PLTE chunk
// Get palette entries
CPalette* palette = iEncoder->Palette();
ASSERT(palette);
const TInt count = palette->Entries();
TUint8* ptr = iDestPtr + KPngChunkIdSize + KPngChunkLengthSize;
TInt length = count * 3;
TPtr8 data(ptr, length, length);
for (TInt i=0; i < count; i++)
{
TRgb rgb = palette->GetEntry(i);
*ptr = TUint8(rgb.Red());
ptr++;
*ptr = TUint8(rgb.Green());
ptr++;
*ptr = TUint8(rgb.Blue());
ptr++;
}
// Write PLTE chunk
WritePngChunk(iDestPtr, KPngPLTEChunkId, data, length);
ASSERT(length % 3 == 0); // length must be divisible by 3
aDst.SetLength(length);
iEncoderState = EPngDeflate;
}
// Write a data chunk
void CPngWriteCodec::WriteIDATChunk(TBufPtr8& aDst)
{
TPtrC8 ptr(iCompressor->OutputDescriptor());
if (ptr.Length())
{
TInt length = 0;
WritePngChunk(iDestPtr, KPngIDATChunkId, ptr, length);
aDst.SetLength(length);
// New output can write to the same compressor ptr
iCompressor->SetOutput(iCompressorPtr);
}
if (iCallAgain)
iEncoderState = EPngFlush;
}
// Write an END chunk
void CPngWriteCodec::WriteEndChunk(TBufPtr8& aDst)
{
// Write IEND chunk
TInt length = 0;
WritePngChunk(iDestPtr, KPngIENDChunkId, KNullDesC8, length);
aDst.SetLength(length);
}
// Write a header chunk
TInt CPngWriteCodec::WriteHeaderChunk(TBufPtr8& aDst)
{
// Write signature
Mem::Copy(iDestPtr, &KPngSignature[0], KPngFileSignatureLength);
iDestPtr += KPngFileSignatureLength;
// Write IHDR chunk
TBuf8<KPngIHDRChunkSize> buffer;
TUint8* ptr = const_cast<TUint8*>(buffer.Ptr());
// Set length of data
buffer.SetLength(KPngIHDRChunkSize);
// Chunk data
// width (4 bytes)
if ((iImageInfo.iSize.iWidth == 0) ||
(static_cast<TUint>(iImageInfo.iSize.iWidth) > KPngMaxImageSize))
{
return KErrArgument; // invalid width
}
PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iWidth);
ptr += 4;
// height (4 bytes)
if ((iImageInfo.iSize.iHeight == 0) ||
(static_cast<TUint>(iImageInfo.iSize.iHeight) > KPngMaxImageSize))
{
return KErrArgument; // invalid height
}
PtrWriteUtil::WriteBigEndianInt32(ptr, iImageInfo.iSize.iHeight);
ptr += 4;
// bit depth (1 byte)
PtrWriteUtil::WriteInt8(ptr, iImageInfo.iBitDepth);
ptr++;
// colour type (1 byte)
PtrWriteUtil::WriteInt8(ptr, iImageInfo.iColorType);
ptr++;
// compression method (1 byte)
PtrWriteUtil::WriteInt8(ptr, iImageInfo.iCompressionMethod);
ptr++;
// filter method (1 byte)
PtrWriteUtil::WriteInt8(ptr, iImageInfo.iFilterMethod);
ptr++;
// interlace method (1 byte)
PtrWriteUtil::WriteInt8(ptr, iImageInfo.iInterlaceMethod);
ptr++;
TInt length = 0;
WritePngChunk(iDestPtr, KPngIHDRChunkId, buffer, length);
aDst.SetLength(KPngFileSignatureLength + length);
return KErrNone;
}
// Chunk writing helper function
void CPngWriteCodec::WritePngChunk(TUint8*& aDestPtr, const TDesC8& aChunkId, const TDesC8& aData, TInt& aLength)
{
// Chunk length (4 bytes)
PtrWriteUtil::WriteBigEndianInt32(aDestPtr, aData.Length());
aDestPtr += KPngChunkLengthSize;
TUint8* crcPtr = aDestPtr; // start position for calculating CRC
// Chunk type (4 bytes)
Mem::Copy(aDestPtr, aChunkId.Ptr(), KPngChunkIdSize);
aDestPtr += KPngChunkIdSize;
// Chunk data (0...n bytes)
Mem::Copy(aDestPtr, aData.Ptr(), aData.Length());
aDestPtr += aData.Length();
// CRC (4 bytes)
TUint32 crc = KPngCrcMask;
GetCrc(crc, crcPtr, KPngChunkIdSize + aData.Length());
crc ^= KPngCrcMask;
PtrWriteUtil::WriteBigEndianInt32(aDestPtr, crc);
aDestPtr += KPngChunkCRCSize;
// Length of chunk
aLength = KPngChunkLengthSize + KPngChunkIdSize + aData.Length() + KPngChunkCRCSize;
}
// from MEZBufferManager, manage data compressor
void CPngWriteCodec::InitializeL(CEZZStream& /*aZStream*/)
{
}
void CPngWriteCodec::NeedInputL(CEZZStream& aZStream)
{
// Give compressor more data from encoder
aZStream.SetInput(iEncoder->EncodeL(iScanline));
if (iCompressor->AvailIn() != 0)
iScanline++;
}
void CPngWriteCodec::NeedOutputL(CEZZStream& /*aZStream*/)
{
// Signal to write an IDAT chunk
iEncoderState = EPngWriteIDAT;
}
void CPngWriteCodec::FinalizeL(CEZZStream& /*aZStream*/)
{
}
// Calculate CRC for PNG chunks
void CPngWriteCodec::GetCrc(TUint32& aCrc, const TUint8* aPtr, const TInt aLength)
{
if (!iCrcTableCalculated)
CalcCrcTable();
TUint32 code = aCrc;
for (TInt i=0; i < aLength; i++)
code = iCrcTable[(code ^ aPtr[i]) & 0xff] ^ (code >> 8);
aCrc = code;
}
void CPngWriteCodec::CalcCrcTable()
{
for (TInt i=0; i < KPngCrcTableLength; i++)
{
TUint32 code = static_cast<TUint32>(i);
for (TInt j = 0; j < 8; j++)
{
if (code & 1)
code = 0xedb88320 ^ (code >> 1);
else
code = code >> 1;
}
iCrcTable[i] = code;
}
iCrcTableCalculated = ETrue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -