diff -r 000000000000 -r 40261b775718 mmplugins/imagingplugins/codecs/ImageProcessor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mmplugins/imagingplugins/codecs/ImageProcessor.cpp Tue Feb 02 01:56:55 2010 +0200 @@ -0,0 +1,2532 @@ +// Copyright (c) 1999-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 "ImageProcessorPriv.h" +#include "ImageUtils.h" +#include "ImageClientMain.h" + +//Size of dynamically allocated buffers used by CPixelWriter & CMonochromePixelWriter +const TInt KPixelWriterBufferSize = 1024; +const TInt KPixelWriterBufferThreeQuarter = 768; + +/** +Constructor for this class. +*/ +EXPORT_C CImageProcessorExtension::CImageProcessorExtension() +:iOperation(EDecodeNormal) + { + } + +/** +Destructor for this class. +*/ +EXPORT_C CImageProcessorExtension::~CImageProcessorExtension() + { + } + +/** +Sets the area of interest of the image to be decoded. + +@param aRect + A reference to a TRect that specifies the location and size of the region to be decoded. + +*/ +EXPORT_C void CImageProcessorExtension::SetClippingRect(const TRect& aRect) + { + iClippingRect = aRect; + } + +/** +Sets the scaling coefficient for the decode. + +@param aScalingCoeff + The scaling coefficient. + +@see TImageConvScaler::SetScalingL +*/ +EXPORT_C void CImageProcessorExtension::SetScaling(TInt aScalingCoeff) + { + iScalingCoeff = aScalingCoeff; + } + +/** +Sets the desired size of the destination image for the decode. + +@param aDesiredSize + The desired size of the destination image. + +@see TImageConvScaler::SetScalingL +*/ +EXPORT_C void CImageProcessorExtension::SetScaling(const TSize& aDesiredSize) + { + iDesiredSize = aDesiredSize; + } + +/** +Sets the operation to be applied to the image. + +@param aOperation + The operation to apply to the image. + +@see TImageConvScaler::SetScalingL +*/ +EXPORT_C void CImageProcessorExtension::SetOperation(TTransformOptions aOperation) + { + iOperation = aOperation; + } + +/** +Sets an initial one-off number of scanlines to be skipped. +This must be called prior to calling SetYPosIncrement(), +if it is to be used. + +@param aNumberOfScanlines + The number of scanlines to skip. + +@see CImageProcessor::SetYPosIncrement() +*/ +EXPORT_C void CImageProcessorExtension::SetInitialScanlineSkipPadding(TInt aNumberOfScanlines) + { + iNumberOfScanlinesToSkip = aNumberOfScanlines; + } + +// +// ImageProcessorUtility +// + +// +// CColorImageProcessor +// + +/** + * @see CImageProcessor. + * @internalComponent + */ +void CColorImageProcessor::CreateBlockBufferL(TInt aBlockArea) + { + delete[] iBlockBuffer; + iBlockBuffer = NULL; + + if(aBlockArea) + iBlockBuffer = new (ELeave) TRgb[aBlockArea]; + + iBlockArea = aBlockArea; + } + +/** + * Destructor. + * @see CImageProcessor. + * @internalComponent + */ +CColorImageProcessor::~CColorImageProcessor() + { + delete[] iBlockBuffer; + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetPixelRun(TRgb aColor,TInt aCount) + { + TBool returnValue = EFalse; + + while(aCount--) + returnValue |= SetPixel(aColor); + + return returnValue; + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetPixels(TRgb* aColorBuffer,TInt aBufferLength) + { + TBool returnValue = EFalse; + + while(aBufferLength--) + returnValue |= SetPixel(*aColorBuffer++); + + return returnValue; + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetMonoPixel(TInt aGray256) + { + return SetPixel(TRgb(aGray256,aGray256,aGray256)); + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetMonoPixelRun(TInt aGray256,TInt aCount) + { + return SetPixelRun(TRgb(aGray256,aGray256,aGray256),aCount); + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetMonoPixels(TUint32* aGray256Buffer,TInt aBufferLength) + { + TBool returnValue = EFalse; + + while(aBufferLength--) + { + TUint32 gray256 = *aGray256Buffer++; + returnValue = SetPixel(TRgb(gray256,gray256,gray256)); + } + return returnValue; + } + +/** + * @see CImageProcessor. + * @internalComponent + */ +TBool CColorImageProcessor::SetMonoPixelBlock(TUint32* aGray256Buffer) + { + ASSERT(iBlockBuffer); + + TRgb* blockBufferPtr = iBlockBuffer; + TRgb* blockBufferPtrLimit = blockBufferPtr+iBlockArea; + + while(blockBufferPtr=0); + iLineRepeat = aLineRepeat; + } + +/** + * + * @see CImageProcessor. + */ +void CPixelWriter::SetPixelPadding(TInt aNumberOfPixels) + { + iPixelPadding = aNumberOfPixels; + } + +/** + * + * @see CImageProcessor. + */ +TBool CPixelWriter::SetPixel(TRgb aColor) + { + *iRgbBufferPtr++ = aColor; + + if (iRgbBufferPtr == iRgbBufferPtrLimit) + return FlushPixels(); + + return EFalse; + } + +/** + * + * @see CImageProcessor. + */ +TBool CPixelWriter::SetPixelRun(TRgb aColor,TInt aCount) + { + while(aCount) + { + TRgb* ptr = iRgbBufferPtr; + TRgb* limit = ptr+aCount; + if(limit>iRgbBufferPtrLimit) + limit = iRgbBufferPtrLimit; + + TInt n = limit-ptr; + aCount -= n; + + if(n&1) + *ptr++ = aColor; + if(n&2) + { + *ptr++ = aColor; + *ptr++ = aColor; + } + if(n&4) + { + *ptr++ = aColor; + *ptr++ = aColor; + *ptr++ = aColor; + *ptr++ = aColor; + } + while(ptr= KPixelWriterBufferThreeQuarter) + { + TRgb* rgbBuffer = iRgbBuffer; + + if (iRgbBufferPtr != rgbBuffer) + { + // flush rest of the pixels + if(FlushPixels()) + { + return ETrue; + } + } + + // use external buffer without copying data + TBool rValue = EFalse; + + while (aBufferLength && !rValue) + { + TInt bufferLength = (aBufferLength>KPixelWriterBufferSize)?KPixelWriterBufferSize:aBufferLength; + iRgbBuffer = aColorBuffer; + iRgbBufferPtr = aColorBuffer+bufferLength; + iRgbBufferPtrLimit = aColorBuffer+bufferLength; + + rValue = FlushPixels(); + aBufferLength -= bufferLength; + aColorBuffer += bufferLength; + } + + // restore pointers to inner buffer + iRgbBuffer = rgbBuffer; + iRgbBufferPtr = rgbBuffer; + iRgbBufferPtrLimit = rgbBuffer+KPixelWriterBufferSize; + + return rValue; + } + + while(aBufferLength) + { + TRgb* ptr = iRgbBufferPtr; + TRgb* limit = ptr+aBufferLength; + if(limit>iRgbBufferPtrLimit) + limit = iRgbBufferPtrLimit; + + TInt n = limit-ptr; + aBufferLength -= n; + + if(n&1) + *ptr++ = *aColorBuffer++; + if(n&2) + { + *ptr++ = *aColorBuffer++; + *ptr++ = *aColorBuffer++; + } + while(ptr(aColorBuffer); + } + else + { + SetPixelBlockIndex(aColorBuffer); + } + + TInt ySkip = 0; + if(iNumberOfScanlinesToSkip > 0) + { + ySkip = iNumberOfScanlinesToSkip * iBlockSize.iWidth; + indexBufferPtr += ySkip; + ySkip = iNumberOfScanlinesToSkip; + iNumberOfScanlinesToSkip = 0; // Only call this conditional once. + } + + TInt imageWidth = iImageRegion.iBr.iX; + TInt imageHeight = iImageRegion.iBr.iY; + TInt endOfImage = iDrawBottomUp ? -1 : imageHeight; + + // The minimum number of pixels to render horizontally + TInt minWidth = Min(iBlockSize.iWidth, imageWidth - iPos.iX); + + // The next vertical position. Note that this is usually the height of the block, but + // in the case of the first block when clipping is required, this will be reduced by ySkip. + TInt nextYPos = iDrawBottomUp ? (iPos.iY - iBlockSize.iHeight) + ySkip : + (iPos.iY + iBlockSize.iHeight) - ySkip; + + TInt endPosition = iDrawBottomUp ? Max(nextYPos, endOfImage) : Min(nextYPos, endOfImage); + + // Once the first block has been processed, iYInc is set to block height + iYInc = iDrawBottomUp ? -iBlockSize.iHeight + ySkip : iBlockSize.iHeight - ySkip; + + // Skip unnecessary pixels (for cropping, or padding when rotated) + indexBufferPtr += iPixelPadding; + + TPoint pos(iPos); + iUtil.Begin(); + for(;iDrawBottomUp ? pos.iY > endPosition : pos.iY < endPosition; iDrawBottomUp ? pos.iY-- : pos.iY++) + { + iUtil.SetPos(pos); + iUtil.SetPixels(indexBufferPtr, minWidth); + indexBufferPtr += iBlockSize.iWidth; // next line in block + } + iUtil.End(); + + iPos.iX += iBlockSize.iWidth; + + if (iPos.iX >= imageWidth) + { + return NewLine(); + } + + return EFalse; + } + +/** + * + * @see CImageProcessor. + */ +TBool CPixelWriter::FlushPixels() + { + TRgb* rgbBufferPtrLimit = iRgbBufferPtr; + iRgbBufferPtr = iRgbBuffer; + + if(iPos.iY < iImageRegion.iTl.iY || iPos.iY >= iImageRegion.iBr.iY) + return ETrue; + + iUtil.Begin(); + + TBool finished = EFalse; + for (TRgb* rgbBufferPtr = iRgbBuffer; rgbBufferPtr < rgbBufferPtrLimit; ) + { + TInt pixelsToSkip = Min(rgbBufferPtrLimit - rgbBufferPtr,iPixelsToSkip); + rgbBufferPtr += pixelsToSkip; + iPixelsToSkip -= pixelsToSkip; + + if(iPixelsToSkip) + break; + + TInt pixelsToFlush = Min(rgbBufferPtrLimit - rgbBufferPtr,iImageRegion.iBr.iX - iPos.iX); + + if(!pixelsToFlush) + break; + + SetPixelBufferIndex(rgbBufferPtr,pixelsToFlush); + rgbBufferPtr += pixelsToFlush; + + TBool fillDown = iYInc > 0; + TPoint pos(iPos); + TInt posYLimit; + if(fillDown) + posYLimit = Min(pos.iY + iLineRepeat + 1 ,iImageRegion.iBr.iY); + else + posYLimit = Max(pos.iY - iLineRepeat - 1 ,iImageRegion.iTl.iY-1); + + for(;fillDown ? pos.iY < posYLimit : pos.iY > posYLimit; fillDown ? pos.iY++ : pos.iY--) + { + if(!iUtil.SetPos(pos-iImageRegion.iTl)) + { + iUtil.End(); + return ETrue; + } + iUtil.SetPixels(iIndexBuffer,pixelsToFlush); + } + + iPos.iX += pixelsToFlush; + if (iPos.iX >= iImageRegion.iBr.iX) + { + finished = NewLine(); + if(finished) + break; + } + } + + iUtil.End(); + + return finished; + } + +/** + * + * @see CImageProcessor. + */ +TBool CPixelWriter::SetPos(const TPoint& aPosition) + { + if(iImageRegion.Contains(aPosition)) + { + FlushPixels(); + iPixelsToSkip = 0; + iPos = aPosition; + return ETrue; + } + + return EFalse; + } + +void CPixelWriter::Reset() + { + delete iColorConv; + iColorConv = NULL; + + delete[] iRgbBuffer; + iRgbBuffer = NULL; + + delete[] iIndexBuffer; + iIndexBuffer = NULL; + + iPos.SetXY(0,0); + iPixelsToSkip = 0; + iImageRegion.SetRect(0,0,0,0); + iBlockSize.SetSize(0,0); + + iDrawBottomUp = EFalse; + } + +void CPixelWriter::DoPrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize* aBlockSize) + { + if( (aImageRect.iTl.iX<0) || (aImageRect.iTl.iY<0) || (aImageRect.Size().iWidth>aBitmap.SizeInPixels().iWidth) || (aImageRect.Size().iHeight>aBitmap.SizeInPixels().iHeight) ) + { + User::Leave(KErrArgument); + } + + Reset(); + + iDisplayMode = aBitmap.DisplayMode(); + + iImageRegion = aImageRect; + + ASSERT(iColorConv==NULL); + iColorConv = TColorConvertor::NewL(aBitmap.DisplayMode()); + iUtil.SetBitmapL(&aBitmap); + + if (aBlockSize) + { + if (aBlockSize->iWidth <= 0 || aBlockSize->iHeight <= 0) + { + User::Leave(KErrArgument); + } + + iBlockSize = *aBlockSize; + iBlockArea = iBlockSize.iWidth * iBlockSize.iHeight; + + ASSERT(iIndexBuffer == NULL); + iIndexBuffer = new(ELeave) TUint32[iBlockArea]; + + iIndexBufferPtrLimit = iIndexBuffer + iBlockArea; + CreateBlockBufferL(iBlockArea); + + switch(iOperation) + { + case EDecodeRotate180: + case EDecodeRotate270: + case EDecodeHorizontalFlip: + case EDecodeVerticalFlipRotate90: + iDrawBottomUp = ETrue; + break; + default: + iDrawBottomUp = EFalse; + } + + iYInc = iDrawBottomUp ? -iBlockSize.iHeight : iBlockSize.iHeight; + iStartPosition.SetXY(iImageRegion.iTl.iX, iDrawBottomUp ? iImageRegion.iBr.iY - 1 : 0); + iEndPosition.SetXY(iImageRegion.iBr.iX, iDrawBottomUp ? + iImageRegion.iTl.iY - 1 : iImageRegion.iBr.iY); + iPos = iStartPosition; + } + else + { + iPos = iImageRegion.iTl; + iStartPosition = iPos; + iEndPosition = aImageRect.iBr; + + ASSERT(iRgbBuffer == NULL); + iRgbBuffer = new(ELeave) TRgb[KPixelWriterBufferSize]; + + iRgbBufferPtr = iRgbBuffer; + iRgbBufferPtrLimit = iRgbBuffer + KPixelWriterBufferSize; + + ASSERT(iIndexBuffer == NULL); + iIndexBuffer = new(ELeave) TUint32[KPixelWriterBufferSize]; + + iIndexBufferPtrLimit = iIndexBuffer + KPixelWriterBufferSize; + } + } + +TBool CPixelWriter::NewLine() + { + iPos.iX = iStartPosition.iX; + iPos.iY += iYInc; + + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + + iPixelsToSkip = iPixelPadding; + return EFalse; + } + +void CPixelWriter::SetPixelBufferIndex(TRgb* aColorBuffer,TInt aCount) + { + iColorConv->ColorToIndex(REINTERPRET_CAST(TInt*,iIndexBuffer),aColorBuffer,aCount); + } + +void CPixelWriter::SetPixelBlockIndex(TRgb* aColorBuffer) + { + iColorConv->ColorToIndex(REINTERPRET_CAST(TInt*,iIndexBuffer),aColorBuffer,iIndexBufferPtrLimit-iIndexBuffer); + } + +// +// CMonochromePixelWriter +// + +/** + * + * Static factory function to create CMonochromePixelWriter objects. + * + * @return Pointer to a fully constructed CMonochromePixelWriter object. + */ +CMonochromePixelWriter* CMonochromePixelWriter::NewL() + { + return new(ELeave) CMonochromePixelWriter; + } + +/** + * + * Default constructor for this class. + */ +CMonochromePixelWriter::CMonochromePixelWriter(): + iYInc(1) + {} + +/** + * + * Destructor + */ +CMonochromePixelWriter::~CMonochromePixelWriter() + { + Reset(); + } + +/** + * + * @see CImageProcessor + */ +void CMonochromePixelWriter::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect) + { + DoPrepareL(aBitmap,aImageRect,NULL); + } + +/** + * + * @see CImageProcessor + */ +void CMonochromePixelWriter::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize& aRgbBlockSize) + { + DoPrepareL(aBitmap,aImageRect,&aRgbBlockSize); + } + +/** + * + * @see CImageProcessor. + */ +void CMonochromePixelWriter::SetYPosIncrement(TInt aYInc) + { + iYInc = aYInc - iNumberOfScanlinesToSkip; + } + +/** + * + * @see CImageProcessor. + */ +void CMonochromePixelWriter::SetPixelPadding(TInt aNumberOfPixels) + { + iPixelPadding = aNumberOfPixels; + } + +/** + * + * @see CImageProcessor. + */ +void CMonochromePixelWriter::SetLineRepeat(TInt aLineRepeat) + { + ASSERT(aLineRepeat>=0); + iLineRepeat = aLineRepeat; + } + +/** + * + * @see CImageProcessor. + */ +TBool CMonochromePixelWriter::SetMonoPixel(TInt aGray256) + { + *iGray256BufferPtr++ = aGray256; + + if (iGray256BufferPtr != iGray256BufferPtrLimit) + return EFalse; + + return FlushPixels(); + } + +/** + * + * @see CImageProcessor. + */ +TBool CMonochromePixelWriter::SetMonoPixelRun(TInt aGray256,TInt aCount) + { + while(aCount) + { + TUint32* ptr = iGray256BufferPtr; + TUint32* limit = ptr+aCount; + if(limit>iGray256BufferPtrLimit) + limit = iGray256BufferPtrLimit; + + TInt n = limit-ptr; + aCount -= n; + + if(n&1) + *ptr++ = aGray256; + if(n&2) + { + *ptr++ = aGray256; + *ptr++ = aGray256; + } + if(n&4) + { + *ptr++ = aGray256; + *ptr++ = aGray256; + *ptr++ = aGray256; + *ptr++ = aGray256; + } + while(ptr= KPixelWriterBufferThreeQuarter) + { + TUint32* gray256Buffer = iGray256Buffer; + + if (iGray256BufferPtr != gray256Buffer) + { + // flush rest of the pixels + if(FlushPixels()) + { + return ETrue; + } + } + + // use external buffer without copying data + TBool rValue = EFalse; + + while (aBufferLength && !rValue) + { + TInt bufferLength = (aBufferLength>KPixelWriterBufferSize)?KPixelWriterBufferSize:aBufferLength; + iGray256Buffer = aGray256Buffer; + iGray256BufferPtr = aGray256Buffer+bufferLength; + iGray256BufferPtrLimit = aGray256Buffer+bufferLength; + + rValue = FlushPixels(); + aBufferLength -= bufferLength; + aGray256Buffer += bufferLength; + } + + // restore pointers to inner buffer + iGray256Buffer = gray256Buffer; + iGray256BufferPtr = gray256Buffer; + iGray256BufferPtrLimit = gray256Buffer+KPixelWriterBufferSize; + + return rValue; + } + + while(aBufferLength) + { + TUint32* ptr = iGray256BufferPtr; + TUint32* limit = ptr+aBufferLength; + if(limit>iGray256BufferPtrLimit) + limit = iGray256BufferPtrLimit; + + TInt n = limit-ptr; + aBufferLength -= n; + + if(n&1) + *ptr++ = *aGray256Buffer++; + if(n&2) + { + *ptr++ = *aGray256Buffer++; + *ptr++ = *aGray256Buffer++; + } + while(ptr 0) + { + ySkip = iNumberOfScanlinesToSkip * iBlockSize.iWidth; + indexBufferPtr += ySkip; + ySkip = iNumberOfScanlinesToSkip; + iNumberOfScanlinesToSkip = 0; // Only call this conditional once. + } + + TInt imageWidth = iImageRegion.iBr.iX; + TInt imageHeight = iImageRegion.iBr.iY; + TInt endOfImage = iDrawBottomUp ? -1 : imageHeight; + + // The minimum number of pixels to render horizontally + TInt minWidth = Min(iBlockSize.iWidth, imageWidth - iPos.iX); + + // The next vertical position. Note that this is usually the height of the block, but + // in the case of the first block when clipping is required, this will be reduced by ySkip. + TInt nextYPos = iDrawBottomUp ? (iPos.iY - iBlockSize.iHeight) + ySkip : + (iPos.iY + iBlockSize.iHeight) - ySkip; + + TInt endPosition = iDrawBottomUp ? Max(nextYPos, endOfImage) : Min(nextYPos, endOfImage); + + // Once the first block has been processed, iYInc is set to block height + iYInc = iDrawBottomUp ? -iBlockSize.iHeight + ySkip : iBlockSize.iHeight - ySkip; + + // Skip unnecessary pixels (for cropping, or padding when rotated) + indexBufferPtr += iPixelPadding; + + TPoint pos(iPos); + iUtil.Begin(); + for(;iDrawBottomUp ? pos.iY > endPosition : pos.iY < endPosition; iDrawBottomUp ? pos.iY-- : pos.iY++) + { + iUtil.SetPos(pos); + iUtil.SetPixels(indexBufferPtr, minWidth); + indexBufferPtr += iBlockSize.iWidth; // next line in block + } + iUtil.End(); + + iPos.iX += iBlockSize.iWidth; + + if (iPos.iX >= imageWidth) + { + return NewLine(); + } + + return EFalse; + } + +/** + * + * @see CImageProcessor. + */ +TBool CMonochromePixelWriter::FlushPixels() + { + TUint32* gray256BufferPtrLimit = iGray256BufferPtr; + iGray256BufferPtr = iGray256Buffer; + + if(iPos.iY < iImageRegion.iTl.iY || iPos.iY >= iImageRegion.iBr.iY) + return ETrue; + + iUtil.Begin(); + + TBool finished = EFalse; + for (TUint32* gray256BufferPtr = iGray256Buffer; gray256BufferPtr < gray256BufferPtrLimit; ) + { + TInt pixelsToSkip = Min(gray256BufferPtrLimit - gray256BufferPtr,iPixelsToSkip); + gray256BufferPtr += pixelsToSkip; + iPixelsToSkip -= pixelsToSkip; + + if(iPixelsToSkip) + break; + + TInt pixelsToFlush = Min(gray256BufferPtrLimit - gray256BufferPtr,iImageRegion.iBr.iX - iPos.iX); + + if(!pixelsToFlush) + break; + + SetPixelBufferIndex(gray256BufferPtr,pixelsToFlush); + gray256BufferPtr += pixelsToFlush; + + TBool fillDown = iYInc > 0; + TPoint pos(iPos); + TInt posYLimit; + if(fillDown) + posYLimit = Min(pos.iY + iLineRepeat + 1 ,iImageRegion.iBr.iY); + else + posYLimit = Max(pos.iY - iLineRepeat - 1 ,iImageRegion.iTl.iY-1); + + for(;fillDown ? pos.iY < posYLimit : pos.iY > posYLimit; fillDown ? pos.iY++ : pos.iY--) + { + if(!iUtil.SetPos(pos-iImageRegion.iTl)) + { + iUtil.End(); + return ETrue; + } + iUtil.SetPixels(iIndexBuffer,pixelsToFlush); + } + + iPos.iX += pixelsToFlush; + if (iPos.iX >= iImageRegion.iBr.iX) + { + finished = NewLine(); + if(finished) + break; + } + } + + iUtil.End(); + + return finished; + } + +/** + * + * @see CImageProcessor. + */ +TBool CMonochromePixelWriter::SetPos(const TPoint& aPosition) + { + if(iImageRegion.Contains(aPosition)) + { + FlushPixels(); + iPixelsToSkip = 0; + iPos = aPosition; + return ETrue; + } + + return EFalse; + } + +void CMonochromePixelWriter::Reset() + { + delete iColorConv; + iColorConv = NULL; + + delete[] iGray256Buffer; + iGray256Buffer = NULL; + + delete[] iIndexBuffer; + iIndexBuffer = NULL; + + iPos.SetXY(0,0); + iPixelsToSkip = 0; + iImageRegion.SetRect(0,0,0,0); + iBlockSize.SetSize(0,0); + + iDrawBottomUp = EFalse; + } + +void CMonochromePixelWriter::DoPrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize* aBlockSize) + { + if( (aImageRect.iTl.iX<0) || (aImageRect.iTl.iY<0) || (aImageRect.Size().iWidth>aBitmap.SizeInPixels().iWidth) || (aImageRect.Size().iHeight>aBitmap.SizeInPixels().iHeight) ) + { + User::Leave(KErrArgument); + } + + Reset(); + + iImageRegion = aImageRect; + + iColorConv = TColorConvertor::NewL(aBitmap.DisplayMode()); + iUtil.SetBitmapL(&aBitmap); + + if (aBlockSize) + { + if (aBlockSize->iWidth <= 0 || aBlockSize->iHeight <= 0) + { + User::Leave(KErrArgument); + } + + iBlockSize = *aBlockSize; + iBlockArea = iBlockSize.iWidth * iBlockSize.iHeight; + + ASSERT(iIndexBuffer == NULL); + iIndexBuffer = new(ELeave) TUint32[iBlockArea]; + + iIndexBufferPtrLimit = iIndexBuffer + iBlockArea; + CreateBlockBufferL(iBlockArea); + + switch(iOperation) + { + case EDecodeRotate180: + case EDecodeRotate270: + case EDecodeHorizontalFlip: + case EDecodeVerticalFlipRotate90: + iDrawBottomUp = ETrue; + break; + default: + iDrawBottomUp = EFalse; + } + + iYInc = iDrawBottomUp ? -iBlockSize.iHeight : iBlockSize.iHeight; + iStartPosition.SetXY(iImageRegion.iTl.iX, iDrawBottomUp ? iImageRegion.iBr.iY - 1 : 0); + iEndPosition.SetXY(iImageRegion.iBr.iX, iDrawBottomUp ? + iImageRegion.iTl.iY - 1 : iImageRegion.iBr.iY); + iPos = iStartPosition; + } + else + { + iPos = iImageRegion.iTl; + iStartPosition = iPos; + iEndPosition = aImageRect.iBr; + + ASSERT(iGray256Buffer == NULL); + iGray256Buffer = new(ELeave) TUint32[KPixelWriterBufferSize]; + + iGray256BufferPtr = iGray256Buffer; + iGray256BufferPtrLimit = iGray256Buffer + KPixelWriterBufferSize; + + ASSERT(iIndexBuffer == NULL); + iIndexBuffer = new(ELeave) TUint32[KPixelWriterBufferSize]; + + iIndexBufferPtrLimit = iIndexBuffer + KPixelWriterBufferSize; + } + + for(TInt i=0; i<256; i++) + { + iIndexLookup[i] = iColorConv->ColorIndex(TRgb(i,i,i)); + } + } + +TBool CMonochromePixelWriter::NewLine() + { + iPos.iX = iStartPosition.iX; + iPos.iY += iYInc; + + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + + iPixelsToSkip = iPixelPadding; + return EFalse; + } + +void CMonochromePixelWriter::SetPixelBlockIndex(TUint32* aGray256Buffer) + { + CMonochromePixelWriter::SetPixelBufferIndex(aGray256Buffer,iBlockArea); + } + +void CMonochromePixelWriter::SetPixelBufferIndex(TUint32* aGray256Buffer,TInt aCount) + { + TUint32* indexBufferPtr = iIndexBuffer; + TUint32* indexBufferPtrLimit = indexBufferPtr+aCount; + TUint32* indexLookup = iIndexLookup; + + if(aCount&1) + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + if(aCount&2) + { + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + } + while (indexBufferPtr < indexBufferPtrLimit) + { + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + *indexBufferPtr++ = indexLookup[*aGray256Buffer++]; + } + } + +// +// CErrorDiffuser::TColorError +// + +inline CErrorDiffuser::TColorError::TColorError(): + iRedError(0), + iGreenError(0), + iBlueError(0) + {} + +inline CErrorDiffuser::TColorError::TColorError(TInt aRedError,TInt aGreenError,TInt aBlueError): + iRedError(aRedError), + iGreenError(aGreenError), + iBlueError(aBlueError) + {} + +inline void CErrorDiffuser::TColorError::AdjustColor(TRgb& aColor) const + { + TInt red = ColorCcomponent::ClampColorComponent((iRedError >> 4) + aColor.Red()); + TInt green = ColorCcomponent::ClampColorComponent((iGreenError >> 4) + aColor.Green()); + TInt blue = ColorCcomponent::ClampColorComponent((iBlueError >> 4) + aColor.Blue()); + aColor = TRgb(red,green,blue); + } + +inline void CErrorDiffuser::TColorError::SetError(TRgb aIdealColor,TRgb aActualColor) + { + iRedError = aIdealColor.Red() - aActualColor.Red(); + iGreenError = aIdealColor.Green() - aActualColor.Green(); + iBlueError = aIdealColor.Blue() - aActualColor.Blue(); + } + +inline CErrorDiffuser::TColorError CErrorDiffuser::TColorError::operator+(const TColorError& aColorError) const + { + TInt redError = iRedError + aColorError.iRedError; + TInt greenError = iGreenError + aColorError.iGreenError; + TInt blueError = iBlueError + aColorError.iBlueError; + return TColorError(redError,greenError,blueError); + } + +inline CErrorDiffuser::TColorError CErrorDiffuser::TColorError::operator-(const TColorError& aColorError) const + { + TInt redError = iRedError - aColorError.iRedError; + TInt greenError = iGreenError - aColorError.iGreenError; + TInt blueError = iBlueError - aColorError.iBlueError; + return TColorError(redError,greenError,blueError); + } + +inline CErrorDiffuser::TColorError CErrorDiffuser::TColorError::operator<<(TInt aShift) const + { + TInt redError = iRedError << aShift; + TInt greenError = iGreenError << aShift; + TInt blueError = iBlueError << aShift; + return TColorError(redError,greenError,blueError); + } + +inline CErrorDiffuser::TColorError& CErrorDiffuser::TColorError::operator+=(const TColorError& aColorError) + { + iRedError += aColorError.iRedError; + iGreenError += aColorError.iGreenError; + iBlueError += aColorError.iBlueError; + return *this; + } + +CErrorDiffuser::CErrorDiffuser() + { + } + +CErrorDiffuser::~CErrorDiffuser() + { + Reset(); + } + +void CErrorDiffuser::DoPrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize* aBlockSize) + { + CPixelWriter::DoPrepareL(aBitmap,aImageRect,aBlockSize); + + TInt scanlineErrorBufferLength = iImageRegion.iBr.iX+2; + + if (iBlockArea > 0) + { + ASSERT(iEdgeErrorBuffer == NULL); + iEdgeErrorBuffer = new(ELeave) TColorError[iBlockSize.iHeight]; + + scanlineErrorBufferLength += iBlockSize.iWidth; + } + + ASSERT(iScanlineErrorBuffer == NULL); + iScanlineErrorBuffer = new(ELeave) TColorError[scanlineErrorBufferLength]; + + if (iDisplayMode == EColor64K) + { + ASSERT(iRedErrorLookupTable == NULL); + iRedErrorLookupTable = new(ELeave) TInt8[256]; + ASSERT(iGreenErrorLookupTable == NULL); + iGreenErrorLookupTable = new(ELeave) TInt8[256]; + + for (TInt i=0;i<256;i++) + { + TInt tmp = i & 0xf8; + iRedErrorLookupTable[i] = i - (tmp | (tmp >> 5)); + tmp = i & 0xfc; + iGreenErrorLookupTable[i] = i - (tmp | (tmp >> 6)); + } + } + } + +void CErrorDiffuser::SetPixelBufferIndex(TRgb* aColorBuffer,TInt aCount) + { + // use optimized function for EColor64K mode + if (iDisplayMode == EColor64K) + { + SetPixelBufferColor64KIndex(aColorBuffer, aCount); + return; + } + + TInt clearX = iPos.iX; + + TInt yDiff = iPos.iY - iLastPos.iY; + if(yDiff != 0) // On a new line? + { + new(&iNextError) TColorError; + clearX = iImageRegion.iBr.iX; // To clear to end of line + + if(yDiff == -1 || yDiff == 1) // Now on ajacent line? + { + clearX -= iLastPos.iX; // Clear end of previous line + if(clearX) + { + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TColorError)); + } + clearX = iPos.iX; // To clear up to current position + } + iLastPos.iX = iImageRegion.iTl.iX; // Start of this line + } + + clearX -= iLastPos.iX; + if(clearX > 0) // Treat any skipped pixels as if they produced no error + { + new(&iNextError) TColorError; + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TColorError)); + } + + iLastPos.iY = iPos.iY; + iLastPos.iX = iPos.iX+aCount; + + TUint32* indexBufferPtr = iIndexBuffer; + TUint32* indexBufferPtrLimit = indexBufferPtr+aCount; + TColorError* scanlineErrorBufferPtr = iScanlineErrorBuffer + iPos.iX; + TColorError error; + TRgb color; + + while(indexBufferPtrColorIndex(color); + *indexBufferPtr++ = index; + + error.SetError(color, iColorConv->Color(index)); + + iNextError = (error << 3) - error; // Set right error for this pixel + + *scanlineErrorBufferPtr++ += error + (error << 1); // Set left-down error for this pixel + + *scanlineErrorBufferPtr += error + (error << 2); // Set down error for this pixel + + iNextError += *(scanlineErrorBufferPtr+1); + + *(scanlineErrorBufferPtr+1) = error; // Set right-down error for this pixel + } + } + +// faster function (see listing) then Bitmap Util ClampColorComponent +inline TInt CErrorDiffuser::ClipColorComponent(TInt value) + { + if (TUint(value) > 0xFF) + { + value = value < 0 ? 0 : 0xFF; + } + return value; + } + +void CErrorDiffuser::SetPixelBufferColor64KIndex(TRgb* aColorBuffer,TInt aCount) + { + TInt clearX = iPos.iX; + + TInt yDiff = iPos.iY - iLastPos.iY; + if(yDiff != 0) // On a new line? + { + iNextRedError = 0; + iNextGreenError = 0; + iNextBlueError = 0; + clearX = iImageRegion.iBr.iX; // To clear to end of line + + if(yDiff == -1 || yDiff == 1) // Now on ajacent line? + { + clearX -= iLastPos.iX; // Clear end of previous line + if(clearX > 0) + { + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TColorError)); + } + clearX = iPos.iX; // To clear up to current position + } + iLastPos.iX = iImageRegion.iTl.iX; // Start of this line + } + + clearX -= iLastPos.iX; + if(clearX > 0) // Treat any skipped pixels as if they produced no error + { + iNextRedError = 0; + iNextGreenError = 0; + iNextBlueError = 0; + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TColorError)); + } + + iLastPos.iY = iPos.iY; + iLastPos.iX = iPos.iX+aCount; + + TUint32* indexBufferPtr = iIndexBuffer; + TUint32* indexBufferPtrLimit = indexBufferPtr+aCount; + + TColorError* scanlineErrorBufferPtr = iScanlineErrorBuffer + iPos.iX; + + TInt redError = iNextRedError; + TInt greenError = iNextGreenError; + TInt blueError = iNextBlueError; + + while(indexBufferPtrRed(); + red = ClipColorComponent(red + (redError >> 4)); + + register TInt error = iRedErrorLookupTable[red]; + + // Set right error for red component + scanlineErrorBufferPtr->iRedError += error + (error << 1); // Set left-down error for this pixel + (scanlineErrorBufferPtr+1)->iRedError += error + (error << 2); // Set down error for this pixel + redError = (scanlineErrorBufferPtr+2)->iRedError + (error << 3) - error; // Set right error for this pixel + (scanlineErrorBufferPtr+2)->iRedError = error; // Set right-down error for this pixel + + // green + register TInt green = aColorBuffer->Green(); + + green = ClipColorComponent(green + (greenError >> 4)); + + error = iGreenErrorLookupTable[green]; + + // Set right error for green component + scanlineErrorBufferPtr->iGreenError += error + (error << 1); // Set left-down error for this pixel + (scanlineErrorBufferPtr+1)->iGreenError += error + (error << 2); // Set down error for this pixel + greenError = (scanlineErrorBufferPtr+2)->iGreenError + (error << 3) - error; // Set right error for this pixel + (scanlineErrorBufferPtr+2)->iGreenError = error; // Set right-down error for this pixel + + // blue + register TInt blue = aColorBuffer->Blue(); + + blue = ClipColorComponent(blue + (blueError >> 4)); + + *indexBufferPtr++ = ((red & 0xf8) << 8) | ((green & 0xfc) << 3) | ((blue & 0xf8) >> 3); + + error = iRedErrorLookupTable[blue];// use the same lookup table for blue color + + // Set right error for blue component + scanlineErrorBufferPtr->iBlueError += error + (error << 1); // Set left-down error for this pixel + (scanlineErrorBufferPtr+1)->iBlueError += error + (error << 2); // Set down error for this pixel + blueError = (scanlineErrorBufferPtr+2)->iBlueError + (error << 3) - error; // Set right error for this pixel + (scanlineErrorBufferPtr+2)->iBlueError = error; // Set right-down error for this pixel + + scanlineErrorBufferPtr++; + aColorBuffer++; + } + + iNextRedError = redError; + iNextGreenError = greenError; + iNextBlueError = blueError; + + + } + +void CErrorDiffuser::SetPixelBlockIndex(TRgb* aColorBuffer) + { + if(iPos.iY!=iLastPos.iY) + { + Mem::FillZ(iEdgeErrorBuffer,sizeof(TColorError) * iBlockSize.iHeight); + } + + TUint32* indexBufferPtr = iIndexBuffer; + + TColorError error; + TColorError* edgeErrorBuffer = iEdgeErrorBuffer; + + for (TInt row = 0; row < iBlockSize.iHeight; row++) + { + TColorError* errorValue = iScanlineErrorBuffer + iPos.iX; + TColorError nextError = *edgeErrorBuffer + *errorValue; + *edgeErrorBuffer = error; + + for (TInt col = 0; col < iBlockSize.iWidth; col++) + { + TRgb bufferColor = *aColorBuffer++; + nextError.AdjustColor(bufferColor); + + TUint32 index = iColorConv->ColorIndex(bufferColor); + *indexBufferPtr++ = index; + + error.SetError(bufferColor,iColorConv->Color(index)); + + if (col > 0) + *(errorValue - 1) += error + (error << 1); // Set left-down error for this pixel + else + *errorValue = error + (error << 1); + + *errorValue += error + (error << 2); // Set down error for this pixel + errorValue++; + + nextError = (error << 3) - error; // Set right error for this pixel + + if (col < iBlockSize.iWidth) + { + nextError += *errorValue; + *errorValue = error; // Set right-down error for this pixel + } + + } + + *edgeErrorBuffer++ += nextError; + } + + iLastPos.iY = iPos.iY; + iLastPos.iX = iPos.iX+iBlockSize.iWidth; + } + +void CErrorDiffuser::Reset() + { + CPixelWriter::Reset(); + + delete[] iScanlineErrorBuffer; + iScanlineErrorBuffer = NULL; + + delete[] iEdgeErrorBuffer; + iEdgeErrorBuffer = NULL; + + delete iRedErrorLookupTable; + iRedErrorLookupTable = NULL; + + delete iGreenErrorLookupTable; + iGreenErrorLookupTable = NULL; + + } + +// +// CMonochromeErrorDiffuser +// + + +/** + * + * Static factory function to create CMonochromeErrorDiffuser objects. + * + * @return Pointer to a fully constructed CMonochromeErrorDiffuser object. + */ +CMonochromeErrorDiffuser* CMonochromeErrorDiffuser::NewL() + { + return new(ELeave) CMonochromeErrorDiffuser; + } + +CMonochromeErrorDiffuser::CMonochromeErrorDiffuser() + {} + +CMonochromeErrorDiffuser::~CMonochromeErrorDiffuser() + { + Reset(); + } + +void CMonochromeErrorDiffuser::DoPrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize* aBlockSize) + { + CMonochromePixelWriter::DoPrepareL(aBitmap,aImageRect,aBlockSize); + + TInt scanlineErrorBufferLength = iImageRegion.iBr.iX+2; + + if (iBlockArea > 0) + { + ASSERT(iEdgeErrorBuffer == NULL); + iEdgeErrorBuffer = new(ELeave) TInt[iBlockSize.iHeight]; + + Mem::FillZ(iEdgeErrorBuffer,sizeof(TInt) * iBlockSize.iHeight); + scanlineErrorBufferLength += iBlockSize.iWidth; + } + + ASSERT(iScanlineErrorBuffer == NULL); + iScanlineErrorBuffer = new(ELeave) TInt[scanlineErrorBufferLength]; + + Mem::FillZ(iScanlineErrorBuffer,sizeof(TInt) * scanlineErrorBufferLength); + } + +void CMonochromeErrorDiffuser::SetPixelBufferIndex(TUint32* aGray256Buffer,TInt aCount) + { + TInt clearX = iPos.iX; + + TInt yDiff = iPos.iY - iLastPos.iY; + if(yDiff != 0) // On a new line? + { + iNextError = 0; + clearX = iImageRegion.iBr.iX; // To clear to end of line + + if(yDiff == -1 || yDiff == 1) // Now on ajacent line? + { + clearX -= iLastPos.iX; // Clear end of previous line + if(clearX) + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TInt)); + clearX = iPos.iX; // To clear up to current position + } + iLastPos.iX = iImageRegion.iTl.iX; // Start of this line + } + + clearX -= iLastPos.iX; + if(clearX > 0) // Treat any skipped pixels as if they produced no error + { + iNextError = 0; + Mem::FillZ(iScanlineErrorBuffer + iLastPos.iX + 2, clearX * sizeof(TInt)); + } + + iLastPos.iY = iPos.iY; + iLastPos.iX = iPos.iX+aCount; + + TUint32* indexBufferPtr = iIndexBuffer; + TUint32* indexBufferPtrLimit = indexBufferPtr+aCount; + + TInt* scanlineErrorBufferPtr = iScanlineErrorBuffer + iPos.iX; + TInt nextError = iNextError; + + while(indexBufferPtr> 4); + TUint32 index = iIndexLookup[ColorCcomponent::ClampColorComponent(error)]; + *indexBufferPtr++ = index; + + error -= TColorConvertor::RgbToMonochrome(iColorConv->Color(index)); + + nextError = (error << 3) - error; // Set right error for this pixel + + *scanlineErrorBufferPtr++ += error + (error << 1); // Set left-down error for this pixel + + *scanlineErrorBufferPtr += error + (error << 2); // Set down error for this pixel + + nextError += *(scanlineErrorBufferPtr+1); + + *(scanlineErrorBufferPtr+1) = error; // Set right-down error for this pixel + } + + iNextError = nextError; + } + +void CMonochromeErrorDiffuser::SetPixelBlockIndex(TUint32* aGray256Buffer) + { + if(iPos.iY!=iLastPos.iY) + { + Mem::FillZ(iEdgeErrorBuffer,sizeof(TInt) * iBlockSize.iHeight); + } + + TUint32* indexBufferPtr = iIndexBuffer; + + TInt error = 0; + TInt* edgeErrorBuffer = iEdgeErrorBuffer; + + for (TInt row = 0; row < iBlockSize.iHeight; row++) + { + TInt* errorValue = iScanlineErrorBuffer + iPos.iX; + TInt nextError = *edgeErrorBuffer + *errorValue; + *edgeErrorBuffer = error; + + for (TInt col = 0; col < iBlockSize.iWidth; col++) + { + TInt gray256 = *aGray256Buffer++; + + error = gray256 + (nextError >> 4); // Same as /16 + + TUint32 index = iIndexLookup[ColorCcomponent::ClampColorComponent(error)]; + *indexBufferPtr++ = index; + + error -= TColorConvertor::RgbToMonochrome(iColorConv->Color(index)); + + if (col > 0) + *(errorValue - 1) += error + (error << 1); // Set left-down error for this pixel + else + *errorValue = error + (error << 1); + + *errorValue += error + (error << 2); // Set down error for this pixel + errorValue++; + + nextError = (error << 3) - error; // Set right error for this pixel + + if (col < iBlockSize.iWidth) + { + nextError += *errorValue; + *errorValue = error; // Set right-down error for this pixel + } + } + + *edgeErrorBuffer++ += nextError; + } + + iLastPos.iY = iPos.iY; + iLastPos.iX = iPos.iX+iBlockSize.iWidth; + } + +void CMonochromeErrorDiffuser::Reset() + { + CMonochromePixelWriter::Reset(); + + delete[] iScanlineErrorBuffer; + iScanlineErrorBuffer = NULL; + + delete[] iEdgeErrorBuffer; + iEdgeErrorBuffer = NULL; + } + +// +// CThumbnailProcessor +// + +/** + * + * Static factory function to create CThumbnailProcessor objects. + * + * @param "aImageProc" + * A pointer to an externally constructed CImageProcessorExtension object. + * This will be deleted when the CThumbnailProcessor object is deleted. + * @param "aReductionFactor" + * The reduction factor to use. + * @return Pointer to a fully constructed CThumbnailProcessor object. + */ +CThumbnailProcessor* CThumbnailProcessor::NewL(CImageProcessorExtension* aImageProc,TInt aReductionFactor) + { + return new(ELeave) CThumbnailProcessor(aImageProc,aReductionFactor); + } + +CThumbnailProcessor::CThumbnailProcessor(CImageProcessorExtension* aImageProc,TInt aReductionFactor): + iImageProc(aImageProc), + iYInc(1), + iReductionFactor(aReductionFactor) + {} + +CThumbnailProcessor::~CThumbnailProcessor() + { + delete iImageProc; + delete[] iReducedPixelBuffer; + delete[] iReducedSumBuffer; + } + +void CThumbnailProcessor::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect) + { + PrepareCommonL(aImageRect); + iYInc = 1; + + TInt bufferSize = (iImageRegion.iBr.iX + (1<> iReductionFactor; + + ASSERT(iReducedSumBuffer == NULL); + iReducedSumBuffer = new(ELeave) TColorSum[bufferSize]; + Mem::FillZ(iReducedSumBuffer,bufferSize * sizeof(TColorSum)); + + iImageProc->PrepareL(aBitmap,iReducedImageRegion); + + ASSERT(iReducedPixelBuffer == NULL); + iReducedPixelBuffer = new(ELeave) TRgb[iReducedImageRegion.iBr.iX]; + } + +void CThumbnailProcessor::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize& aRgbBlockSize) + { + PrepareCommonL(aImageRect); + + CreateBlockBufferL(aRgbBlockSize.iWidth*aRgbBlockSize.iHeight); + + iOriginalBlockSize = aRgbBlockSize; + iYInc = iDrawBottomUp ? -iOriginalBlockSize.iHeight : iOriginalBlockSize.iHeight; + + iReducedBlockSize = aRgbBlockSize; + iReducedBlockSize.iWidth >>= iReductionFactor; + iReducedBlockSize.iHeight >>= iReductionFactor; + + iImageProc->SetInitialScanlineSkipPadding(iNumberOfScanlinesToSkip >> iReductionFactor); + iImageProc->SetPixelPadding(iPixelPadding >> iReductionFactor); + iImageProc->PrepareL(aBitmap,iReducedImageRegion,iReducedBlockSize); + + ASSERT(iReducedPixelBuffer == NULL); + iReducedPixelBuffer = new(ELeave) TRgb[iReducedBlockSize.iWidth * iReducedBlockSize.iHeight]; + } + +void CThumbnailProcessor::PrepareCommonL(const TRect& aImageRect) + { + ASSERT(iReductionFactor > 0); + iImageRegion = aImageRect; + + TInt roundUp = (1<> iReductionFactor; + iReducedImageRegion.iTl.iY = aImageRect.iTl.iY >> iReductionFactor; + + TSize size = aImageRect.Size(); + size.iWidth = (size.iWidth + roundUp) >> iReductionFactor; + size.iHeight = (size.iHeight + roundUp) >> iReductionFactor; + iReducedImageRegion.iBr = iReducedImageRegion.iTl + size; + + switch(iOperation) + { + case EDecodeRotate180: + case EDecodeRotate270: + case EDecodeHorizontalFlip: + case EDecodeVerticalFlipRotate90: + iDrawBottomUp = ETrue; + iImageProc->SetOperation(iOperation); + break; + default: + iDrawBottomUp = EFalse; + } + iStartPosition.SetXY(iImageRegion.iTl.iX, iDrawBottomUp ? aImageRect.iBr.iY - 1 : 0); + iEndPosition.SetXY(aImageRect.iBr.iX, iDrawBottomUp ? aImageRect.iTl.iY - 1 : aImageRect.iBr.iY); + iPos = iStartPosition; + + iPositionChanged = ETrue; + + iEndOfLineX = iEndPosition.iX + iPixelPadding; + + delete[] iReducedPixelBuffer; + iReducedPixelBuffer = NULL; + + delete[] iReducedSumBuffer; + iReducedSumBuffer = NULL; + } + +TBool CThumbnailProcessor::SetPixel(TRgb aColor) + { + TInt x = iPos.iX; + + if (x < iImageRegion.iBr.iX) + { + TColorSum* sumPtr = iReducedSumBuffer + (x >> iReductionFactor); + sumPtr->iRed += aColor.Red(); + sumPtr->iGreen += aColor.Green(); + sumPtr->iBlue += aColor.Blue(); + sumPtr->iCount++; + } + + x++; + iPos.iX = x; + + if (x == iEndOfLineX) + return NewLine(); + + return EFalse; + } + +TBool CThumbnailProcessor::NewLine() + { + TInt newY = iPos.iY + iYInc; + + TBool finished = (newY < iStartPosition.iY || newY >= iEndPosition.iY); + TBool outsideOfBuffer = ((newY ^ iPos.iY) >> iReductionFactor) != 0; + + if(finished || outsideOfBuffer) + { + DoFlushPixels(); + } + + iPos.iX = iStartPosition.iX; + iPos.iY = newY; + + if(iPositionChanged && outsideOfBuffer) + { + iImageProc->SetPos(TPoint(iPos.iX >> iReductionFactor,iPos.iY >> iReductionFactor)); + iPositionChanged = EFalse; + } + + return finished; + } + +TBool CThumbnailProcessor::SetPixelBlock(TRgb* aColorBuffer) + { + if ((iPos.iX >> iReductionFactor) < iReducedImageRegion.iBr.iX) + { + ASSERT(aColorBuffer); + + if(iPositionChanged) + { + iImageProc->SetPos(TPoint(iPos.iX >> iReductionFactor,iPos.iY >> iReductionFactor)); + iPositionChanged = EFalse; + } + + TInt xOuterStop = iReducedBlockSize.iWidth<>= divisionFactor; + green >>= divisionFactor; + blue >>= divisionFactor; + + *reducedPixelBuffer++ = TRgb(red,green,blue); + } + } + + iImageProc->SetPixelBlock(iReducedPixelBuffer); + } + + iPos.iX += iOriginalBlockSize.iWidth; + if (iPos.iX >= iEndOfLineX) + { + iPos.iX = iStartPosition.iX; + iPos.iY += iYInc; + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + } + + return EFalse; + + } + +TBool CThumbnailProcessor::FlushPixels() + { + DoFlushPixels(); + iImageProc->FlushPixels(); + + iPositionChanged = ETrue; + + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + + return EFalse; + } + +void CThumbnailProcessor::DoFlushPixels() + { + if(!iReducedSumBuffer) + return; + + TColorSum* reducedSumPtr = iReducedSumBuffer + iReducedImageRegion.iTl.iX; + TColorSum* reducedSumPtrLimit = iReducedSumBuffer + iReducedImageRegion.iBr.iX; + + while(reducedSumPtr < reducedSumPtrLimit) + { + + while(reducedSumPtr->iCount==0) + { + reducedSumPtr++; + if(reducedSumPtr==reducedSumPtrLimit) + return; + } + + if(iPositionChanged) + iImageProc->SetPos(TPoint(reducedSumPtr - iReducedSumBuffer,iPos.iY >> iReductionFactor)); + + TRgb* reducedPixelBufferPtr = iReducedPixelBuffer; + TInt fullCountFactor = 2*iReductionFactor; + + while(reducedSumPtr < reducedSumPtrLimit) + { + TInt count = reducedSumPtr->iCount; + TUint32 red; + TUint32 green; + TUint32 blue; + + if(count == (1<iRed >> fullCountFactor; + green = reducedSumPtr->iGreen >> fullCountFactor; + blue = reducedSumPtr->iBlue >> fullCountFactor; + } + else if(count!=0) + { + red = reducedSumPtr->iRed / count; + green = reducedSumPtr->iGreen / count; + blue = reducedSumPtr->iBlue / count; + } + else + break; + + *reducedPixelBufferPtr++ = TRgb(red,green,blue); + + reducedSumPtr++; + } + + TInt numPixels = reducedPixelBufferPtr-iReducedPixelBuffer; + iImageProc->SetPixels(iReducedPixelBuffer,numPixels); + + Mem::FillZ(reducedSumPtr-numPixels,numPixels * sizeof(TColorSum)); + } + + } + +TBool CThumbnailProcessor::SetPos(const TPoint& aPosition) + { + if(iImageRegion.Contains(aPosition)==EFalse) + return EFalse; + + if((aPosition.iY ^ iPos.iY) >> iReductionFactor) + DoFlushPixels(); + + iPositionChanged = ETrue; + iPos = aPosition; + + return ETrue; + } + +void CThumbnailProcessor::SetYPosIncrement(TInt aYInc) + { + iYInc = aYInc; + + TInt reducedYInc = aYInc >> iReductionFactor; + if(reducedYInc==0) + reducedYInc = 1; + + iImageProc->SetYPosIncrement(reducedYInc); + } + +void CThumbnailProcessor::SetLineRepeat(TInt aLineRepeat) + { + TInt reducedLineRepeat = aLineRepeat >> iReductionFactor; + iImageProc->SetLineRepeat(reducedLineRepeat); + } + +void CThumbnailProcessor::SetPixelPadding(TInt aNumberOfPixels) + { + iPixelPadding = aNumberOfPixels; + iEndOfLineX = iEndPosition.iX + iPixelPadding; + } + +// +// CMonochromeThumbnailProcessor +// + +/** + * + * Static factory function to create CMonochromeThumbnailProcessor objects. + * + * @param "aImageProc" + * A pointer to an externally constructed CImageProcessorExtension object. + * This will be deleted when the CMonochromeThumbnailProcessor object is deleted. + * @param aReductionFactor" + * The reduction factor to use. + * @return Pointer to a fully constructed CMonochromeThumbnailProcessor object. + */ +CMonochromeThumbnailProcessor* CMonochromeThumbnailProcessor::NewL(CImageProcessorExtension* aImageProc,TInt aReductionFactor) + { + return new(ELeave) CMonochromeThumbnailProcessor(aImageProc,aReductionFactor); + } + +CMonochromeThumbnailProcessor::CMonochromeThumbnailProcessor(CImageProcessorExtension* aImageProc,TInt aReductionFactor): + iImageProc(aImageProc), + iYInc(1), + iReductionFactor(aReductionFactor) + {} + +CMonochromeThumbnailProcessor::~CMonochromeThumbnailProcessor() + { + delete iImageProc; + delete[] iReducedPixelBuffer; + delete[] iReducedSumBuffer; + } + +void CMonochromeThumbnailProcessor::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect) + { + PrepareCommonL(aImageRect); + iYInc = 1; + + TInt bufferSize = (iImageRegion.iBr.iX + (1<> iReductionFactor; + + ASSERT(iReducedSumBuffer == NULL); + iReducedSumBuffer = new(ELeave) TMonochromeSum[bufferSize]; + Mem::FillZ(iReducedSumBuffer,bufferSize * sizeof(TMonochromeSum)); + + iImageProc->PrepareL(aBitmap,iReducedImageRegion); + + ASSERT(iReducedPixelBuffer == NULL); + iReducedPixelBuffer = new(ELeave) TUint32[iReducedImageRegion.iBr.iX]; + } + +void CMonochromeThumbnailProcessor::PrepareL(CFbsBitmap& aBitmap,const TRect& aImageRect,const TSize& aRgbBlockSize) + { + PrepareCommonL(aImageRect); + + CreateBlockBufferL(aRgbBlockSize.iWidth*aRgbBlockSize.iHeight); + + iOriginalBlockSize = aRgbBlockSize; + iYInc = iDrawBottomUp ? -iOriginalBlockSize.iHeight : iOriginalBlockSize.iHeight; + + + iReducedBlockSize = aRgbBlockSize; + iReducedBlockSize.iWidth >>= iReductionFactor; + iReducedBlockSize.iHeight >>= iReductionFactor; + + iImageProc->SetInitialScanlineSkipPadding(iNumberOfScanlinesToSkip >> iReductionFactor); + iImageProc->SetPixelPadding(iPixelPadding >> iReductionFactor); + iImageProc->PrepareL(aBitmap,iReducedImageRegion,iReducedBlockSize); + + ASSERT(iReducedPixelBuffer == NULL); + iReducedPixelBuffer = new(ELeave) TUint32[iReducedBlockSize.iWidth * iReducedBlockSize.iHeight]; + } + +void CMonochromeThumbnailProcessor::PrepareCommonL(const TRect& aImageRect) + { + ASSERT(iReductionFactor > 0); + iImageRegion = aImageRect; + + TInt roundUp = (1<> iReductionFactor; + iReducedImageRegion.iTl.iY = aImageRect.iTl.iY >> iReductionFactor; + + TSize size = aImageRect.Size(); + size.iWidth = (size.iWidth + roundUp) >> iReductionFactor; + size.iHeight = (size.iHeight + roundUp) >> iReductionFactor; + iReducedImageRegion.iBr = iReducedImageRegion.iTl + size; + + switch(iOperation) + { + case EDecodeRotate180: + case EDecodeRotate270: + case EDecodeHorizontalFlip: + case EDecodeVerticalFlipRotate90: + iDrawBottomUp = ETrue; + iImageProc->SetOperation(iOperation); + break; + default: + iDrawBottomUp = EFalse; + } + iStartPosition.SetXY(iImageRegion.iTl.iX, iDrawBottomUp ? aImageRect.iBr.iY - 1 : 0); + iEndPosition.SetXY(aImageRect.iBr.iX, iDrawBottomUp ? aImageRect.iTl.iY - 1 : aImageRect.iBr.iY); + iPos = iStartPosition; + + iPositionChanged = ETrue; + + iEndOfLineX = iEndPosition.iX + iPixelPadding; + + delete[] iReducedPixelBuffer; + iReducedPixelBuffer = NULL; + + delete iReducedSumBuffer; + iReducedSumBuffer = NULL; + } + +TBool CMonochromeThumbnailProcessor::SetMonoPixel(TInt aGray256) + { + TInt x = iPos.iX; + + if (x < iImageRegion.iBr.iX) + { + TMonochromeSum* sumPtr = iReducedSumBuffer + (x >> iReductionFactor); + sumPtr->iLevel += aGray256; + sumPtr->iCount++; + } + + x++; + iPos.iX = x; + + if (x == iEndOfLineX) + return NewLine(); + + return EFalse; + } + +TBool CMonochromeThumbnailProcessor::SetMonoPixelRun(TInt aGray256,TInt aCount) + { + while (aCount != 0) + { + TInt x = iPos.iX; + TInt xLimit = x+aCount; + + iPos.iX = xLimit; + + if (xLimit > iImageRegion.iBr.iX) + xLimit = iImageRegion.iBr.iX; + + if (xLimit > x) + { + TInt numPixels = xLimit-x; + + TInt reductionFactor = iReductionFactor; + TInt reductionCount = 1<> reductionFactor); + + TInt n = reductionCount-(x&(reductionCount-1)); //number of pixels to complete current TMonochromeSum + + if(numPixels > n) + { + sumPtr->iCount += n; //Complete first TMonochromeSum in run + sumPtr->iLevel += n * aGray256; + sumPtr++; + numPixels -= n; + + while(numPixels > reductionCount) //Complete middle TMonochromeSum(s) in run + { + sumPtr->iCount += reductionCount; + sumPtr->iLevel += aGray256 << reductionFactor; + sumPtr++; + numPixels -= reductionCount; + } + } + + sumPtr->iCount += numPixels; //Update last/only TMonochromeSum in run + sumPtr->iLevel += numPixels * aGray256; + } + + if (iPos.iX < iEndOfLineX) + break; + + aCount = iPos.iX - iEndOfLineX; + + if(NewLine()) + return ETrue; + } + + return EFalse; + } + +TBool CMonochromeThumbnailProcessor::NewLine() + { + TInt newY = iPos.iY + iYInc; + + TBool finished = (newY < iStartPosition.iY || newY >= iEndPosition.iY); + TBool outsideOfBuffer = ((newY ^ iPos.iY) >> iReductionFactor) != 0; + + if(finished || outsideOfBuffer) + { + DoFlushPixels(); + } + + iPos.iX = iStartPosition.iX; + iPos.iY = newY; + + if(iPositionChanged && outsideOfBuffer) + { + iImageProc->SetPos(TPoint(iPos.iX >> iReductionFactor,iPos.iY >> iReductionFactor)); + iPositionChanged = EFalse; + } + + return finished; + } + +TBool CMonochromeThumbnailProcessor::SetMonoPixelBlock(TUint32* aGray256Buffer) + { + if ((iPos.iX >> iReductionFactor) < iReducedImageRegion.iBr.iX) + { + ASSERT(aGray256Buffer); + + if(iPositionChanged) + { + iImageProc->SetPos(TPoint(iPos.iX >> iReductionFactor,iPos.iY >> iReductionFactor)); + iPositionChanged = EFalse; + } + + TInt xOuterStop = iReducedBlockSize.iWidth<>= divisionFactor; + *reducedPixelBuffer++ = level; + } + } + + iImageProc->SetMonoPixelBlock(iReducedPixelBuffer); + } + + iPos.iX += iOriginalBlockSize.iWidth; + if (iPos.iX >= iEndOfLineX) + { + iPos.iX = iStartPosition.iX; + iPos.iY += iYInc; + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + } + + return EFalse; + + } + +TBool CMonochromeThumbnailProcessor::FlushPixels() + { + DoFlushPixels(); + iImageProc->FlushPixels(); + + iPositionChanged = ETrue; + + if(iPos.iY < iStartPosition.iY || iPos.iY >= iEndPosition.iY) + { + return ETrue; + } + + return EFalse; + } + +void CMonochromeThumbnailProcessor::DoFlushPixels() + { + if(!iReducedSumBuffer) + return; + + TMonochromeSum* reducedSumPtr = iReducedSumBuffer + iReducedImageRegion.iTl.iX; + TMonochromeSum* reducedSumPtrLimit = iReducedSumBuffer + iReducedImageRegion.iBr.iX; + + while(reducedSumPtr < reducedSumPtrLimit) + { + + while(reducedSumPtr->iCount==0) + { + reducedSumPtr++; + if(reducedSumPtr==reducedSumPtrLimit) + return; + } + + if(iPositionChanged) + iImageProc->SetPos(TPoint(reducedSumPtr - iReducedSumBuffer,iPos.iY >> iReductionFactor)); + + TUint32* reducedPixelBufferPtr = iReducedPixelBuffer; + TInt fullCountFactor = 2*iReductionFactor; + TInt fullCount = 1<iLevel; + TInt count = reducedSumPtr->iCount; + + if(count==fullCount) + level >>= fullCountFactor; + else if(count!=0) + level /= count; + else + break; + + *reducedPixelBufferPtr++ = level; + + reducedSumPtr++; + } + while(reducedSumPtr < reducedSumPtrLimit); + + TInt numPixels = reducedPixelBufferPtr-iReducedPixelBuffer; + iImageProc->SetMonoPixels(iReducedPixelBuffer,numPixels); + + Mem::FillZ(reducedSumPtr-numPixels,numPixels * sizeof(TMonochromeSum)); + } + + } + +TBool CMonochromeThumbnailProcessor::SetPos(const TPoint& aPosition) + { + if(iImageRegion.Contains(aPosition)==EFalse) + return EFalse; + + if((aPosition.iY ^ iPos.iY) >> iReductionFactor) + DoFlushPixels(); + + iPositionChanged = ETrue; + iPos = aPosition; + + return ETrue; + } + +void CMonochromeThumbnailProcessor::SetYPosIncrement(TInt aYInc) + { + iYInc = aYInc; + + TInt reducedYInc = aYInc >> iReductionFactor; + if(reducedYInc==0) + reducedYInc = 1; + + iImageProc->SetYPosIncrement(reducedYInc); + } + +void CMonochromeThumbnailProcessor::SetLineRepeat(TInt aLineRepeat) + { + TInt reducedLineRepeat = aLineRepeat >> iReductionFactor; + iImageProc->SetLineRepeat(reducedLineRepeat); + } + +void CMonochromeThumbnailProcessor::SetPixelPadding(TInt aNumberOfPixels) + { + iPixelPadding = aNumberOfPixels; + iEndOfLineX = iEndPosition.iX + iPixelPadding; + } +