--- a/screengrabber/src/SGGifAnimator.cpp Fri Apr 16 14:59:17 2010 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,413 +0,0 @@
-/*
-* Copyright (c) 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 "SGGifAnimator.h"
-
-#include <s32file.h>
-#include <fbs.h>
-#include <gdi.h>
-#include <imageconversion.h>
-#include <aknenv.h>
-#include <AknGlobalProgressDialog.h>
-#include <AknQueryDialog.h>
-#include <avkon.rsg>
-
-_LIT(KSavingText, "Saving");
-
-// ---------------------------------------------------------------------------
-
-TInt CGifAnimator::CreateGifAnimation(const TDesC& aFileName, TSize aDimensions, CVideoFrameArray* aVideoFrameArray)
- {
- CGifAnimator* self = new(ELeave) CGifAnimator;
- CleanupStack::PushL(self);
- TRAPD(err, self->StartL(aFileName, aDimensions, aVideoFrameArray));
- CleanupStack::PopAndDestroy();
- return err;
- }
-
-// ---------------------------------------------------------------------------
-
-CGifAnimator::CGifAnimator() : CActive(EPriorityStandard)
- {
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::StartL(const TDesC& aFileName, const TSize& aDimensions, CVideoFrameArray* aVideoFrameArray)
- {
- __ASSERT_ALWAYS(aFileName.Length() > 0, User::Panic(_L("GifAnim"), 100));
- __ASSERT_ALWAYS(aDimensions.iHeight > 0, User::Panic(_L("GifAnim"), 101));
- __ASSERT_ALWAYS(aDimensions.iWidth > 0, User::Panic(_L("GifAnim"), 102));
- __ASSERT_ALWAYS(aVideoFrameArray != NULL, User::Panic(_L("GifAnim"), 103));
-
- CActiveScheduler::Add(this);
-
- // show a progress dialog
- iSavingProgressDialog = CSavingProgressDialog::NewL(this);
- iSavingProgressDialog->StartDisplayingL(KSavingText, aVideoFrameArray->Count()-1);
-
- // open the file for writing
- User::LeaveIfError(iFs.Connect());
- User::LeaveIfError(iOutFile.Replace(iFs, aFileName, EFileWrite));
-
- // write header
- WriteHeaderL(aDimensions);
-
- // process each frame of the animation
- for (TInt i=0; i<aVideoFrameArray->Count(); i++)
- {
- // write headers and raster block
- TVideoFrame frame = aVideoFrameArray->At(i);
- WriteGraphicControlL(frame);
- CFbsBitmap* bitmap = GetBitmapLC(frame, aDimensions);
- WriteImageDescriptorL(frame);
- WriteRasterDataL(bitmap);
- CleanupStack::PopAndDestroy(); //bitmap
-
- // update the progress bar
- iSavingProgressDialog->IncreaseProgressValueWithOne();
- }
-
- // write footer and finish
- WriteFooterL();
- FinishL();
-
- // remove the progress dialog from the screen
- iSavingProgressDialog->ProcessFinished();
- }
-
-// ---------------------------------------------------------------------------
-
-CGifAnimator::~CGifAnimator()
- {
- Cancel();
-
- if (iImageEncoder)
- delete iImageEncoder;
-
- if (iGIFImageData)
- delete iGIFImageData;
-
- delete iSavingProgressDialog;
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteHeaderL(const TSize& aDimensions)
- {
- WriteInt8L('G');
- WriteInt8L('I');
- WriteInt8L('F');
- WriteInt8L('8');
- WriteInt8L('9');
- WriteInt8L('a');
-
- WriteInt16L(aDimensions.iWidth); // width of animation
- WriteInt16L(aDimensions.iHeight); // height of animation
-
- // logical screen descriptor
- TUint8 packedFlags = 0;
- packedFlags |= 8 - 1; // size of colour table is number of bits in each color table minus one (bits 0-2)
- packedFlags |= (8 - 1) << 4; // colour resolution ie maximum size of the original colour palette (bits 4-6)
- packedFlags |= 0x80; // use global colour table (bit 7)
-
- WriteInt8L(packedFlags);
-
- WriteInt8L(TRANSPARENCY_INDEX); // background color index
-
- WriteInt8L(0); // pixel aspect ratio, 0=not used
-
- // write the Symbian default palette since that's what is used
- CPalette* palette = CPalette::NewDefaultL(EColor256);
- CleanupStack::PushL(palette);
-
- for (TInt i=0; i<palette->Entries(); i++)
- {
- TRgb entry = palette->GetEntry(i);
-
- WriteInt8L(entry.Red());
- WriteInt8L(entry.Green());
- WriteInt8L(entry.Blue());
- }
-
- CleanupStack::PopAndDestroy(); //palette
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteGraphicControlL(const TVideoFrame& aFrame)
- {
- TInt packedFlags(0);
-
- // enable transparency if needed
- if (aFrame.iEnableTransparency)
- packedFlags |= 0x01;
-
- // set disposal method:
- // 0 = disposal method not specified, 1 = do not dispose of graphic,
- // 2 = overwrite graphic with background color, 3 = overwrite graphic with previous graphic
- TInt disposalMethod = 1;
- packedFlags |= ((disposalMethod << 2) & 0x1c);
-
- WriteInt8L(0x21); // GIF extension
- WriteInt8L(0xf9); // GIF graphic control block
- WriteInt8L(0x04); // block size
- WriteInt8L(packedFlags); // packed
- WriteInt16L(aFrame.iDelay); // delay
- WriteInt8L(TRANSPARENCY_INDEX); // transparent color index
- WriteInt8L(0); // block terminator, always 0
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteImageDescriptorL(const TVideoFrame& aFrame)
- {
- WriteInt8L(0x2c); // GIF image descriptor
- WriteInt16L(aFrame.iXPos);
- WriteInt16L(aFrame.iYPos);
- WriteInt16L(aFrame.iWidth);
- WriteInt16L(aFrame.iHeight);
- WriteInt8L(0); // packed flags, none specified in this case
- }
-
-// ---------------------------------------------------------------------------
-
-CFbsBitmap* CGifAnimator::GetBitmapLC(TVideoFrame& aFrame, const TSize& aDimensions)
- {
- CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
- CleanupStack::PushL(bitmap);
-
- // read the bitmap from the temporary file
- RFile bitmapFile;
- User::LeaveIfError( bitmapFile.Open(iFs, aFrame.iFileStorePath, EFileRead) );
- RFileReadStream readStream(bitmapFile);
- bitmap->InternalizeL(readStream);
- readStream.Close();
- bitmapFile.Close();
-
- // delete the temporary file since it's not needed anymore
- iFs.Delete(aFrame.iFileStorePath);
-
- // resize the bitmap to match the video dimensions if it is a full screen one
- if (aFrame.iFillsWholeScreen && (aFrame.iWidth != aDimensions.iWidth || aFrame.iHeight != aDimensions.iHeight))
- {
- if (bitmap->Resize(aDimensions) == KErrNone)
- {
- // also update dimensions of this frame to match the dimensions of the video
- aFrame.iWidth = aDimensions.iWidth;
- aFrame.iHeight = aDimensions.iHeight;
- }
- }
-
- return bitmap;
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteRasterDataL(CFbsBitmap* aBitmap)
- {
- // reset the encoder
- if (iImageEncoder)
- {
- delete iImageEncoder;
- iImageEncoder = NULL;
- }
-
- // make sure the buffer for conversion is empty
- if (iGIFImageData)
- {
- delete iGIFImageData;
- iGIFImageData = NULL;
- }
-
- // init & convert the bitmap to GIF format
- iImageEncoder = CImageEncoder::DataNewL(iGIFImageData, CImageEncoder::EOptionNone, KImageTypeGIFUid);
- iImageEncoder->Convert( &iStatus, *aBitmap );
-
- // execute the async operation and wait till it's finished
- SetActive();
- iWait.Start();
-
- // check any erros in active object
- User::LeaveIfError( iStatus.Int() );
-
- // check if we have valid data
- if (iGIFImageData == NULL || iGIFImageData->Des().Length()<793)
- User::Leave(KErrNoMemory);
-
- // in GIF files generated by Symbian, the raster data always starts at offset 791,
- // initial code size in GIF encoding should be 8 since we have a 8bpp image,
- // also check that the second last byte is the terminator 0,
- // if this check fails in newer releases of S60, proper parsing of GIF format is probably needed
- TUint8* imagePtr = &iGIFImageData->Des()[0];
- if (imagePtr[791] != 8 || imagePtr[iGIFImageData->Des().Length()-2] != 0)
- User::Leave(KErrNotSupported);
-
- // write the raster data block to the file
- TUint writeLength = iGIFImageData->Des().Length() - 1 - 791;
- imagePtr+=791;
- TPtr8 writePtr(imagePtr, writeLength, writeLength);
- User::LeaveIfError( iOutFile.Write(writePtr) );
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteFooterL()
- {
- WriteInt8L(0x3b); // GIF trailer
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::FinishL()
- {
- iOutFile.Close();
- iFs.Close();
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteInt8L(TInt aValue)
- {
- HBufC8* buf = HBufC8::NewMaxLC(1);
-
- TUint8* ptr = &buf->Des()[0];
- ptr[0] = TUint8(aValue);
-
- User::LeaveIfError( iOutFile.Write(buf->Des()) );
-
- CleanupStack::PopAndDestroy(); // buf
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::WriteInt16L(TInt aValue)
- {
- HBufC8* buf = HBufC8::NewMaxLC(2);
-
- TUint8* ptr = &buf->Des()[0];
- ptr[0] = TUint8(aValue);
- ptr[1] = TUint8(aValue>>8);
-
- User::LeaveIfError( iOutFile.Write(buf->Des()) );
-
- CleanupStack::PopAndDestroy(); // buf
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::DoCancel()
- {
- CAknEnv::StopSchedulerWaitWithBusyMessage( iWait );
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::RunL()
- {
- CAknEnv::StopSchedulerWaitWithBusyMessage( iWait );
- }
-
-// ---------------------------------------------------------------------------
-
-void CGifAnimator::DialogDismissedL(TInt aButtonId)
- {
- // check if cancel button was pressed
- if (aButtonId == EAknSoftkeyCancel)
- {
- }
- }
-
-// ---------------------------------------------------------------------------
-
-/*************************************************************************************************/
-// a helper class to display the progress dialog on the screen
-
-CSavingProgressDialog::CSavingProgressDialog() : CActive(EPriorityLow)
- {
- CActiveScheduler::Add(this);
- }
-
-void CSavingProgressDialog::ConstructL(MDialogCallback* aDialogCallback)
- {
- iGlobalProgressDialog = CAknGlobalProgressDialog::NewL();
- iDialogCallback = aDialogCallback;
- }
-
-CSavingProgressDialog* CSavingProgressDialog::NewL(MDialogCallback* aDialogCallback)
- {
- CSavingProgressDialog* self = new(ELeave) CSavingProgressDialog();
- CleanupStack::PushL(self);
- self->ConstructL(aDialogCallback);
- CleanupStack::Pop(self);
- return self;
- }
-
-CSavingProgressDialog::~CSavingProgressDialog()
- {
- Cancel();
- delete iGlobalProgressDialog;
- }
-
-void CSavingProgressDialog::StartDisplayingL(const TDesC &aText, TInt aFinalValue)
- {
- if (!iVisible)
- {
- iFinalValue = aFinalValue;
- iCurrentValue = 0;
-
- iGlobalProgressDialog->ShowProgressDialogL(iStatus, aText, R_AVKON_SOFTKEYS_EMPTY,
- aFinalValue, CAknNoteDialog::ENoTone);
-
- iVisible = ETrue;
- SetActive();
- }
- }
-
-void CSavingProgressDialog::DoCancel()
- {
- if (iGlobalProgressDialog)
- {
- iGlobalProgressDialog->CancelProgressDialog();
- }
- iVisible = EFalse;
- }
-
-void CSavingProgressDialog::RunL()
- {
- if (iGlobalProgressDialog && iStatus.Int() == KErrNotFound)
- {
- // user dismissed the dialog
- iDialogCallback->DialogDismissedL(EAknSoftkeyCancel);
- }
- }
-
-void CSavingProgressDialog::IncreaseProgressValueWithOne()
- {
- iCurrentValue++;
- iGlobalProgressDialog->UpdateProgressDialog(iCurrentValue, iFinalValue);
- }
-
-void CSavingProgressDialog::ProcessFinished()
- {
- iGlobalProgressDialog->ProcessFinished();
- iVisible = EFalse;
- }
-
-/*************************************************************************************************/