screengrabber/src/gifanimator.cpp
branchRCL_3
changeset 22 fad26422216a
parent 21 b3cee849fa46
child 23 f8280f3bfeb7
equal deleted inserted replaced
21:b3cee849fa46 22:fad26422216a
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include "gifanimator.h"
       
    21 
       
    22 #include <s32file.h>
       
    23 #include <fbs.h>
       
    24 #include <gdi.h>
       
    25 #include <imageconversion.h>
       
    26 #include "enginewrapper.h"
       
    27 
       
    28     
       
    29 // ---------------------------------------------------------------------------
       
    30 
       
    31 TInt CGifAnimator::CreateGifAnimation(const TDesC& aFileName, TSize aDimensions, CVideoFrameArray* aVideoFrameArray, EngineWrapper& aEngineWrapper)
       
    32     {
       
    33 	CGifAnimator* self = new(ELeave) CGifAnimator;
       
    34 	CleanupStack::PushL(self);
       
    35 	TRAPD(err, self->StartL(aFileName, aDimensions, aVideoFrameArray, aEngineWrapper));
       
    36 	CleanupStack::PopAndDestroy();
       
    37 	return err;
       
    38     }
       
    39 
       
    40 // ---------------------------------------------------------------------------
       
    41 
       
    42 CGifAnimator::CGifAnimator()   
       
    43     {
       
    44     }
       
    45 
       
    46 // ---------------------------------------------------------------------------
       
    47 
       
    48 void CGifAnimator::StartL(const TDesC& aFileName, const TSize& aDimensions, CVideoFrameArray* aVideoFrameArray, EngineWrapper& aEngineWrapper)
       
    49     {
       
    50     
       
    51     __ASSERT_ALWAYS(aFileName.Length() > 0, User::Panic(_L("GifAnim"), 100));
       
    52     __ASSERT_ALWAYS(aDimensions.iHeight > 0, User::Panic(_L("GifAnim"), 101));
       
    53     __ASSERT_ALWAYS(aDimensions.iWidth > 0, User::Panic(_L("GifAnim"), 102));
       
    54     __ASSERT_ALWAYS(aVideoFrameArray != NULL, User::Panic(_L("GifAnim"), 103));
       
    55     
       
    56     
       
    57     // show a progress dialog
       
    58     aEngineWrapper.ShowProgressBar(aVideoFrameArray->Count()-1);
       
    59     
       
    60     // open the file for writing
       
    61     User::LeaveIfError(iFs.Connect());
       
    62     User::LeaveIfError(iOutFile.Replace(iFs, aFileName, EFileWrite));
       
    63     
       
    64     // write header
       
    65     WriteHeaderL(aDimensions);
       
    66     
       
    67     // process each frame of the animation
       
    68     for (TInt i=0; i<aVideoFrameArray->Count(); i++)
       
    69         {
       
    70         // write headers and raster block
       
    71         TVideoFrame frame = aVideoFrameArray->At(i);
       
    72         WriteGraphicControlL(frame);
       
    73         CFbsBitmap* bitmap = GetBitmapLC(frame, aDimensions);
       
    74         WriteImageDescriptorL(frame);
       
    75         WriteRasterDataL(bitmap);
       
    76         CleanupStack::PopAndDestroy(); //bitmap
       
    77 
       
    78         // update the progress bar
       
    79         aEngineWrapper.IncrementProgressbarValue();
       
    80         }
       
    81 
       
    82     // write footer and finish
       
    83     WriteFooterL();
       
    84     FinishL();
       
    85     
       
    86     // remove the progress dialog from the screen
       
    87     aEngineWrapper.CloseProgressbar();
       
    88     }    
       
    89 
       
    90 // ---------------------------------------------------------------------------
       
    91 
       
    92 CGifAnimator::~CGifAnimator()
       
    93     {
       
    94     
       
    95     if (iImageEncoder)
       
    96         delete iImageEncoder;
       
    97     
       
    98     if (iGIFImageData)
       
    99         delete iGIFImageData;
       
   100     
       
   101     }
       
   102 
       
   103 // ---------------------------------------------------------------------------
       
   104 
       
   105 void CGifAnimator::WriteHeaderL(const TSize& aDimensions)
       
   106     {
       
   107     WriteInt8L('G');
       
   108     WriteInt8L('I');
       
   109     WriteInt8L('F');
       
   110     WriteInt8L('8');
       
   111     WriteInt8L('9');
       
   112     WriteInt8L('a');
       
   113 
       
   114     WriteInt16L(aDimensions.iWidth);  // width of animation
       
   115     WriteInt16L(aDimensions.iHeight); // height of animation
       
   116     
       
   117     // logical screen descriptor
       
   118     TUint8 packedFlags = 0;
       
   119 	packedFlags |= 8 - 1; // size of colour table is number of bits in each color table minus one (bits 0-2)
       
   120 	packedFlags |= (8 - 1) << 4; // colour resolution ie maximum size of the original colour palette (bits 4-6)
       
   121 	packedFlags |= 0x80; // use global colour table (bit 7)
       
   122     
       
   123     WriteInt8L(packedFlags);
       
   124     
       
   125     WriteInt8L(TRANSPARENCY_INDEX); // background color index
       
   126     
       
   127     WriteInt8L(0); // pixel aspect ratio, 0=not used
       
   128     
       
   129     // write the Symbian default palette since that's what is used
       
   130     CPalette* palette = CPalette::NewDefaultL(EColor256);
       
   131     CleanupStack::PushL(palette);
       
   132     
       
   133     for (TInt i=0; i<palette->Entries(); i++)
       
   134         {
       
   135         TRgb entry = palette->GetEntry(i);
       
   136 
       
   137         WriteInt8L(entry.Red());
       
   138         WriteInt8L(entry.Green());
       
   139         WriteInt8L(entry.Blue());
       
   140         }
       
   141     
       
   142     CleanupStack::PopAndDestroy(); //palette
       
   143     }
       
   144 
       
   145 // ---------------------------------------------------------------------------
       
   146 
       
   147 void CGifAnimator::WriteGraphicControlL(const TVideoFrame& aFrame)
       
   148     {
       
   149     TInt packedFlags(0);
       
   150     
       
   151     // enable transparency if needed
       
   152     if (aFrame.iEnableTransparency)
       
   153         packedFlags |= 0x01; 
       
   154 
       
   155     // set disposal method:
       
   156     // 0 = disposal method not specified, 1 = do not dispose of graphic,
       
   157     // 2 = overwrite graphic with background color, 3 = overwrite graphic with previous graphic
       
   158     TInt disposalMethod = 1;
       
   159     packedFlags |= ((disposalMethod << 2) & 0x1c);
       
   160     
       
   161     WriteInt8L(0x21); // GIF extension
       
   162     WriteInt8L(0xf9); // GIF graphic control block
       
   163     WriteInt8L(0x04); // block size
       
   164     WriteInt8L(packedFlags); // packed
       
   165     WriteInt16L(aFrame.iDelay); // delay
       
   166     WriteInt8L(TRANSPARENCY_INDEX); // transparent color index
       
   167     WriteInt8L(0); // block terminator, always 0
       
   168     }
       
   169 
       
   170 // ---------------------------------------------------------------------------
       
   171 
       
   172 void CGifAnimator::WriteImageDescriptorL(const TVideoFrame& aFrame)
       
   173     {
       
   174     WriteInt8L(0x2c); // GIF image descriptor
       
   175     WriteInt16L(aFrame.iXPos);
       
   176     WriteInt16L(aFrame.iYPos);
       
   177     WriteInt16L(aFrame.iWidth);
       
   178     WriteInt16L(aFrame.iHeight);
       
   179     WriteInt8L(0); // packed flags, none specified in this case
       
   180     }
       
   181     
       
   182 // ---------------------------------------------------------------------------
       
   183 
       
   184 CFbsBitmap* CGifAnimator::GetBitmapLC(TVideoFrame& aFrame, const TSize& aDimensions)
       
   185     {
       
   186     CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
       
   187     CleanupStack::PushL(bitmap);
       
   188     
       
   189     // read the bitmap from the temporary file
       
   190     RFile bitmapFile;
       
   191     User::LeaveIfError( bitmapFile.Open(iFs, aFrame.iFileStorePath, EFileRead) );
       
   192     RFileReadStream readStream(bitmapFile);
       
   193     bitmap->InternalizeL(readStream);
       
   194     readStream.Close();
       
   195     bitmapFile.Close();
       
   196 
       
   197     // delete the temporary file since it's not needed anymore
       
   198     iFs.Delete(aFrame.iFileStorePath);
       
   199     
       
   200     // resize the bitmap to match the video dimensions if it is a full screen one
       
   201     if (aFrame.iFillsWholeScreen && (aFrame.iWidth != aDimensions.iWidth || aFrame.iHeight != aDimensions.iHeight))
       
   202         {
       
   203         if (bitmap->Resize(aDimensions) == KErrNone)
       
   204             {
       
   205             // also update dimensions of this frame to match the dimensions of the video            
       
   206             aFrame.iWidth = aDimensions.iWidth;
       
   207             aFrame.iHeight = aDimensions.iHeight;
       
   208             }
       
   209         }
       
   210     
       
   211     return bitmap;
       
   212     }
       
   213     
       
   214 // ---------------------------------------------------------------------------
       
   215 
       
   216 void CGifAnimator::WriteRasterDataL(CFbsBitmap* aBitmap)
       
   217     {
       
   218     // reset the encoder
       
   219     if (iImageEncoder)
       
   220         {
       
   221 	    delete iImageEncoder;
       
   222         iImageEncoder = NULL;
       
   223         }
       
   224     
       
   225     // make sure the buffer for conversion is empty    
       
   226     if (iGIFImageData)
       
   227         {
       
   228 	    delete iGIFImageData;
       
   229         iGIFImageData = NULL;
       
   230         }        
       
   231 
       
   232     
       
   233     TRequestStatus Stat = KRequestPending;
       
   234     
       
   235     // init & convert the bitmap to GIF format
       
   236     iImageEncoder = CImageEncoder::DataNewL(iGIFImageData, CImageEncoder::EOptionAlwaysThread, KImageTypeGIFUid);
       
   237     iImageEncoder->Convert( &Stat, *aBitmap );
       
   238     User::WaitForRequest(Stat);
       
   239    
       
   240    
       
   241     // check any erros in converting 
       
   242     User::LeaveIfError( Stat.Int() );
       
   243     
       
   244     // check if we have valid data
       
   245     if (iGIFImageData == NULL || iGIFImageData->Des().Length()<793)
       
   246         User::Leave(KErrNoMemory);
       
   247     
       
   248     // in GIF files generated by Symbian, the raster data always starts at offset 791,
       
   249     // initial code size in GIF encoding should be 8 since we have a 8bpp image,
       
   250     // also check that the second last byte is the terminator 0,
       
   251     // if this check fails in newer releases of S60, proper parsing of GIF format is probably needed
       
   252     TUint8* imagePtr = &iGIFImageData->Des()[0];
       
   253     if (imagePtr[791] != 8 || imagePtr[iGIFImageData->Des().Length()-2] != 0)
       
   254         User::Leave(KErrNotSupported);
       
   255     
       
   256     // write the raster data block to the file
       
   257     TUint writeLength = iGIFImageData->Des().Length() - 1 - 791;
       
   258     imagePtr+=791;
       
   259     TPtr8 writePtr(imagePtr, writeLength, writeLength);
       
   260     User::LeaveIfError( iOutFile.Write(writePtr) );
       
   261     }
       
   262 
       
   263 // ---------------------------------------------------------------------------
       
   264 
       
   265 void CGifAnimator::WriteFooterL()
       
   266     {
       
   267     WriteInt8L(0x3b); // GIF trailer
       
   268     }
       
   269     
       
   270 // ---------------------------------------------------------------------------
       
   271 
       
   272 void CGifAnimator::FinishL()
       
   273     {
       
   274     iOutFile.Close();
       
   275     iFs.Close();
       
   276     }
       
   277 
       
   278 // ---------------------------------------------------------------------------
       
   279 
       
   280 void CGifAnimator::WriteInt8L(TInt aValue)
       
   281     {
       
   282     HBufC8* buf = HBufC8::NewMaxLC(1);
       
   283 
       
   284     TUint8* ptr = &buf->Des()[0];
       
   285     ptr[0] = TUint8(aValue);
       
   286     
       
   287     User::LeaveIfError( iOutFile.Write(buf->Des()) );
       
   288     
       
   289     CleanupStack::PopAndDestroy(); // buf
       
   290     }
       
   291 
       
   292 // ---------------------------------------------------------------------------
       
   293 
       
   294 void CGifAnimator::WriteInt16L(TInt aValue)
       
   295     {
       
   296     HBufC8* buf = HBufC8::NewMaxLC(2);
       
   297 
       
   298     TUint8* ptr = &buf->Des()[0];
       
   299     ptr[0] = TUint8(aValue);
       
   300     ptr[1] = TUint8(aValue>>8);
       
   301         
       
   302     User::LeaveIfError( iOutFile.Write(buf->Des()) );
       
   303     
       
   304     CleanupStack::PopAndDestroy(); // buf
       
   305     }
       
   306 
       
   307 // ---------------------------------------------------------------------------
       
   308