IEBgps/src/IETNGenerator.cpp
author jkauppin
Fri, 15 Oct 2010 10:18:29 +0900
changeset 3 93fff7023be8
permissions -rw-r--r--
Initial version

/*
* 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: Juha Kauppinen, Mika Hokkanen
* 
* Description: Photo Browser
*
*/

#include <ImageConversion.h> //CImageDecoder
#include <FBS.H> //CFbsBitmap
#include <BAUTILS.H>
//#include <IEBGPSTrace.h>

#include "IETNGenerator.h"
#include "IEBgpServerSession.h" 
#include <hal.h> 
#include "ImagicConsts.h"
#include "ieengineutils.h" 

_LIT8(KMimeJpeg, "image/jpeg");
_LIT8(KMimePng, "image/png");

#define DO_NOT_USE_SCALING



CIETNGeneratorAO* CIETNGeneratorAO::NewL(RFs& aFileServer, MIEThumbNailObserver &aObserver)
{
	CIETNGeneratorAO* self = new (ELeave) CIETNGeneratorAO(aFileServer, aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop();
	return self;
}

CIETNGeneratorAO::~CIETNGeneratorAO()
{
    DP0_IMAGIC((_L("CIETNGeneratorAO::~CIETNGeneratorAO ++")));
 	if(IsActive())
		Cancel();
 	
	 CancelOutStaningRequests();
	 DeleteObjects();
	 
	 DP0_IMAGIC((_L("CIETNGeneratorAO::~CIETNGeneratorAO --")));
}

//EPriorityIdle, EPriorityLow, EPriorityStandard, EPriorityUserInput, EPriorityHigh
CIETNGeneratorAO::CIETNGeneratorAO(RFs& aFileServer, MIEThumbNailObserver &aObserver)
: iFileServer(aFileServer),
  iThumbnailObserver(aObserver),
  CActive(EPriorityStandard)
{
	
}

void CIETNGeneratorAO::ConstructL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::ConstructL ++")));

	CActiveScheduler::Add(this);
	iError = KErrNone;
	decoderUid = CIEEngineUtils::GetImageDecoderUid();
	//i512x512TnBitmap = new (ELeave) CFbsBitmap();
	
	DP0_IMAGIC((_L("CIETNGeneratorAO::ConstructL --")));
    }

void CIETNGeneratorAO::RunL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::RunL ++")));
    iError = iStatus.Int();
	
#ifdef _IMAGIC_DEBUG
    TInt mem = 0;
	TInt ret = HAL::Get(HALData::EMemoryRAMFree, mem);
	DP1_IMAGIC(_L("CIETNGeneratorAO::RunL - mem: %d"),mem);
#endif
	
	if(iError != KErrNone)
	    {
	    DeleteObjects();
        
        iConvertStatus = ENone;
        
        // inform to higher layer... and delete thumbnails we tried to create
        DP1_IMAGIC(_L("CIETNGeneratorAO::RunL - Something wrong %d"), iError);      
        iThumbnailObserver.ThumbNailGenerationCompleted(iError);
	    }
	
	switch (iConvertStatus)
	    {
	    case EDecoding:
	        {
	        DP0_IMAGIC((_L("CIETNGeneratorAO::RunL - EDecoding")));
	        TRAPD(err, DecodeL()); // TODO handle errors
	        if (err != KErrNone) 
	            {
	            DP1_IMAGIC((_L("CIETNGeneratorAO::RunL - EDecoding error: %d")), err);
	            iThumbnailObserver.ThumbNailGenerationCompleted(err); //ASSERT(0);
	            iConvertStatus = ENone;
	            }
	        else
	            {
#ifdef DO_NOT_USE_SCALING
	            iConvertStatus = EEncoding;
#else
	            iConvertStatus = EScaling;
#endif
                SetActive();
	            }
	        }
	        break;
		
	    case EScaling:
	        {
	        DP0_IMAGIC((_L("CIETNGeneratorAO::RunL - EScaling")));
	        TRAPD(err, ScaleL());
            if (err != KErrNone) 
                {
                DP1_IMAGIC((_L("CIETNGeneratorAO::RunL - EScaling error: %d")), err);
                iThumbnailObserver.ThumbNailGenerationCompleted(err); //ASSERT(0);
                iConvertStatus = ENone;
                }
            else
                {
                iConvertStatus = EEncoding;
                SetActive();
                }
	        }
	        break;
        	
	    case EEncoding:
	        {
	        DP0_IMAGIC((_L("CIETNGeneratorAO::RunL - EEncoding")));
	        TRAPD(err, EncodeL()); // TODO handle errors
	        if (err != KErrNone)
	            {
	            DP1_IMAGIC((_L("CIETNGeneratorAO::RunL - EEncoding error: %d")), err);
                iThumbnailObserver.ThumbNailGenerationCompleted(err); //ASSERT(0);
                iConvertStatus = ENone;
	            }
	        else
	            {
	            iConvertStatus = EReady;

#ifdef USE_BITMAPS_TNS
	            if(!IsJPEG(iThumbnailSize))
	                {
	                //When saving TN as bitmap we need to complete request immeadtely 
	                //because bitmap saving is handled by CFbsBitmap class instead of image encoder
	                SetActive();
	                TRequestStatus* status = &iStatus;
	                User::RequestComplete( status, KErrNone );
	                }
	            else
	                {
	                SetActive();
	                }
#else
	            SetActive();        
#endif
	            }
	        }
	        break;
        
	    case EReady:
	        {
	        DP0_IMAGIC((_L("CIETNGeneratorAO::RunL - EReady")));
   		
	        // use same image for generating smaller thumbnails
	        if (IsLargeThumbnail(iThumbnailSize))
	            {
                /*DP0_IMAGIC((_L("CIETNGeneratorAO::RunL - EScaling")));
                TRAPD(err, ScaleL());
                if (err != KErrNone)
                    ASSERT(0);// TODO handle errors   
                iConvertStatus = EEncoding;
                SetActive();*/ 
   		    }
   		
	        if( iImageEncoder )
	            {
	            delete iImageEncoder;
	            iImageEncoder = NULL;
	            }
        
	        if( iBitmap )
	            {
	            iBitmap->Reset();
	            delete iBitmap;
	            iBitmap = NULL;
	            }
	        
#ifdef DECODE_FROM_BUFFER    
	        if(iSourceData) 
	            {
	            delete iSourceData;
	            iSourceData = NULL;
	            }
#endif
	        
	        iConvertStatus = ENone;
        
#ifndef USE_BITMAPS_TNS
	        WriteExifData(iThumbnailFileName, iResolutionSize);
#else
	        if(IsJPEG(iThumbnailSize))
	            {
	            TRAPD(err, WriteExifDataL(iThumbnailFileName, iThumbnailSize));
	            }
#endif
            
            iFileServer.SetModified(iThumbnailFileName, iSourceTime);
            iThumbnailObserver.ThumbNailGenerationCompleted(KErrNone);
            }
	        break;
        }
	
    DP0_IMAGIC(_L("CIETNGeneratorAO::RunL --"));
    }

TBool CIETNGeneratorAO::IsJPEG(const TSize& aResolution) const
    {
#ifdef USE_64X64_BITMAP_TN
    return (aResolution.iWidth >= 512 || aResolution.iHeight >= 512);
#else
    return (aResolution.iWidth >= 128 || aResolution.iHeight >= 128);    
#endif
    }

TBool CIETNGeneratorAO::IsLargeThumbnail(const TSize& aResolution) const
    {
    return (aResolution.iHeight >= 512);
    }

void CIETNGeneratorAO::ScaleL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::Scale++")));
   
    if ( iImageDecoder )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    
    if (iBitmapScaler )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
   
    iBitmapScaler = CBitmapScaler::NewL();
    iBitmapScaler->UseLowMemoryAlgorithm(ETrue);
   
    TSize tgtBitmapize;
   
    // If we want to create high resolution thumbnail, we use 512x512 resolution
    // for low resolution TN we use size set in iResolutionSize
    if(IsLargeThumbnail(iThumbnailSize))
        {
        tgtBitmapize.iWidth = 512;
        tgtBitmapize.iHeight = 512;
       
        if(iSourceSize.iWidth > iSourceSize.iHeight)
            {
            // If we have wide panorama, use higher resolution to width
            if((iSourceSize.iWidth / iSourceSize.iHeight) > 1.6)
                tgtBitmapize.iWidth = 1024;
            }
        else
            {
            // If we have wide panorama, use higher resolution to height
            if((iSourceSize.iHeight / iSourceSize.iWidth) > 1.6)
                tgtBitmapize.iHeight = 1024;
            }
        }
    else
        {
        tgtBitmapize = iThumbnailSize;
        }
   
    // Use max quality
    iBitmapScaler->SetQualityAlgorithm(CBitmapScaler::EMaximumQuality);
    //iBitmapScaler->SetQualityAlgorithm(CBitmapScaler::EMediumQuality);
    //iBitmapScaler->SetQualityAlgorithm(CBitmapScaler::EMinimumQuality);
   
    DP2_IMAGIC(_L("CIETNGeneratorAO::Scale to %dx%d"), tgtBitmapize.iWidth, tgtBitmapize.iHeight);
      
    iBitmapScaler->Scale(&iStatus, *iBitmap, tgtBitmapize, EFalse);
       
    DP0_IMAGIC((_L("CIETNGeneratorAO::Scale--")));
    }

void CIETNGeneratorAO::EncodeL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::Encode++")));
   
    if (iImageDecoder )
        {
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    if( iBitmapScaler )
        {
        delete iBitmapScaler;
        iBitmapScaler = NULL;
        }
    if( iImageEncoder )
        {
        delete iImageEncoder;
        iImageEncoder = NULL;
        }

    TParse parser;
    parser.Set(iThumbnailFileName, NULL, NULL );
    TFileName tnPath = parser.DriveAndPath();
    CIEEngineUtils::CreateTNFolder(iFileServer, tnPath);
      
#ifdef USE_BITMAPS_TNS
    // Save Bitmap thumbnails if resolution is 128x128 or smaller
    if(!IsJPEG(iThumbnailSize))
        {
        iBitmap->Save(iThumbnailFileName);
        }
    else //if bigger than then save jpg thumbnails
#endif
        {
#if 0
        //If we had 512x512 resolution bitmap we make copy of it
        if(iBitmap->SizeInPixels().iWidth == 512 && iBitmap->SizeInPixels().iHeight == 512)
            {
            i512x512TnBitmap->Reset();
            TInt error = i512x512TnBitmap->Create(iBitmap->SizeInPixels(), EColor16M);
            
            TUint8* dstData = (TUint8 *)i512x512TnBitmap->DataAddress();
            TUint8* srcData = (TUint8 *)iBitmap->DataAddress();
            TInt dataSize = iBitmap->SizeInPixels().iWidth * iBitmap->SizeInPixels().iHeight;
            dataSize*=3;
            
            //Copy bitmap
            for(TInt i=0; i<dataSize; i++)
                {
                dstData[i] = srcData[i];
                }
            }
#endif       
        
        SetJpegImageDataL();
        DP1_IMAGIC(_L("CIETNGeneratorAO::Encode - iThumbnailFileName: %S"), &iThumbnailFileName);
        iMimeString = KMimeJpeg;
        iImageEncoder = CImageEncoder::FileNewL( iFileServer, iThumbnailFileName, iMimeString );
        iImageEncoder->Convert(&iStatus, *iBitmap, iFrameImageData);
        }
   
    TEntry entry;
    User::LeaveIfError(iFileServer.Entry(iThumbnailFileName, entry));
    // Remember the modified time of the source file
    iSourceTime = entry.iModified;
   
    DP0_IMAGIC((_L("CIETNGeneratorAO::Encode--")));
    }

void CIETNGeneratorAO::DecodeL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::Decode++")));
    
    if(iImageDecoder)
        {
        delete iImageDecoder;
        iImageDecoder = NULL;   
        }
    
    DP1_IMAGIC((_L("CIETNGeneratorAO::Decode - Creating decoder... with filename: %S")),&iSourceFileName);
#ifdef USE_EXT_JPEG_DEC
    iImageDecoder = CExtJpegDecoder::FileNewL(iFileServer, iSourceFileName);
#else
    
#ifdef DECODE_FROM_BUFFER    
    if(iSourceData) {
        delete iSourceData;
        iSourceData = NULL;
    }
    
    RFile jpgFile;
    TInt fileSize;
    
    User::LeaveIfError(jpgFile.Open(iFileServer, iSourceFileName, EFileRead));
    jpgFile.Size(fileSize);
    iSourceData = HBufC8::NewL(fileSize);
    
    TPtr8 buffer = iSourceData->Des();
    
    jpgFile.Read(buffer, fileSize);
    
    jpgFile.Close();
    
    iImageDecoder = CImageDecoder::DataNewL(
            iFileServer, 
            *iSourceData, 
            CImageDecoder::EOptionNone, 
            KNullUid, 
            KNullUid, 
            decoderUid);
    
    
#else    
    iImageDecoder = CImageDecoder::FileNewL(
                                        iFileServer, 
                                        iSourceFileName, 
                                        CImageDecoder::EOptionNone, 
                                        KNullUid, 
                                        KNullUid, 
                                        decoderUid);
#endif

#endif
    
    
    iMimeString = KMimeJpeg;
#ifdef DECODE_FROM_BUFFER
    CImageDecoder::GetMimeTypeDataL( *iSourceData, iMimeString );    
#else
    CImageDecoder::GetMimeTypeFileL( iFileServer, iSourceFileName, iMimeString );
#endif
    
    iSourceSize = iImageDecoder->FrameInfo().iOverallSizeInPixels;
    
    DP2_IMAGIC((_L("CIETNGeneratorAO::Decode - image %dx%d")), iSourceSize.iWidth, iSourceSize.iHeight );
        
    iBitmap = new (ELeave) CFbsBitmap();
    
    TargetDecodingSize(iThumbnailSize, iSourceSize);
   
#ifdef DO_NOT_USE_SCALING
    if(IsLargeThumbnail(iThumbnailSize))
        {
        iSourceSize.iHeight=512;
        iSourceSize.iWidth=512;
        }
#endif
  
    TInt error = iBitmap->Create(iSourceSize, EColor16M);
    
    iImageDecoder->Convert(&iStatus, *iBitmap, 0);
    
    DP0_IMAGIC((_L("CIETNGeneratorAO::Decode - convert bitmap... OK")));
    DP0_IMAGIC((_L("CIETNGeneratorAO::Decode--")));
    }

void CIETNGeneratorAO::TargetDecodingSize(const TSize aTgtSize, TSize& aSrcSize)
    {
    DP0_IMAGIC(_L("CIETNGeneratorAO::TargetDecodingSize++"));
    
    DP2_IMAGIC(_L("CIETNGeneratorAO::TargetDecodingSize - Tgt %dx%d"),aTgtSize.iHeight, aTgtSize.iWidth);
    DP2_IMAGIC(_L("CIETNGeneratorAO::TargetDecodingSize - Src %dx%d"),aSrcSize.iHeight, aSrcSize.iWidth);
    
    // up to 32 times downscale in scaler
    for (TInt i = 0;i < 5;i++)
        {
        if (aSrcSize.iWidth < aTgtSize.iWidth * 2 ||
            aSrcSize.iHeight < aTgtSize.iHeight * 2) 
            {
            break;
            }
            
            aSrcSize.iWidth >>= 1;
            aSrcSize.iHeight >>= 1;
        }
    
    // Check that we do not create odd resolution size thumbnail
    if(aSrcSize.iHeight & 1)
        aSrcSize.iHeight++;
    if(aSrcSize.iWidth & 1)
        aSrcSize.iWidth++;
    
    DP2_IMAGIC(_L("CIETNGeneratorAO::TargetDecodingSize - New Src %dx%d"), aSrcSize.iHeight, aSrcSize.iWidth);
    DP0_IMAGIC((_L("CIETNGeneratorAO::TargetDecodingSize--")));
    }

void CIETNGeneratorAO::WriteExifDataL(const TDes &aFilename, TSize aSize)
     {
     DP0_IMAGIC(_L("CIETNGeneratorAO::WriteExifData++"));
     
     // 1. Read JPEG image from the file to a buffer...
     RFile file;
     User::LeaveIfError( file.Open( iFileServer, aFilename, EFileWrite ) );
     CleanupClosePushL( file );
     TInt size = 0;
     file.Size(size);
     HBufC8* jpegImage = HBufC8::NewL( size );
     CleanupStack::PushL( jpegImage );
     TPtr8 bufferDes( jpegImage->Des() );
     User::LeaveIfError( file.Read( bufferDes ) );
     CleanupStack::Pop( jpegImage );
     CleanupStack::PopAndDestroy();
     CleanupStack::PushL( jpegImage );
     
     file.Close();
     
     // 2. Instantiate Exif modifier in ECreate mode...
     CExifModify* modify = CExifModify::NewL( jpegImage->Des(), CExifModify::ECreate );
     CleanupStack::PushL( modify );
     
     // 3. Insert (Set) at least the mandatory Exif data...
     modify->SetXResolutionL( aSize.iWidth, 1 ); 
     modify->SetYResolutionL( aSize.iHeight, 1 ); 
     modify->SetResolutionUnitL( 2 );
     modify->SetYCbCrPositioningL( 1 );
     modify->SetComponentsConfigurationL( 1, 2, 3, 0 );
     modify->SetColorSpaceL( 1 );
     modify->SetPixelXDimensionL( aSize.iWidth );
     modify->SetPixelYDimensionL( aSize.iHeight );
     
     // 4. Get the new Exif image...
     // If zero length descriptor is given instead of jpeg->Des(), then only the
     // Exif meta data is returned.
     HBufC8* newExif = modify->WriteDataL( jpegImage->Des() );
     TPtr8 tmp = newExif->Des();
     
     User::LeaveIfError( file.Replace( iFileServer, aFilename, EFileWrite ) );
     //Write Exif and jpeg image back to jpeg file
     User::LeaveIfError(file.Write(*newExif));
     
     /* Process the new Exif data */
     delete newExif;
     newExif = NULL;
     
     // 5. Delete the modifier instance...
     CleanupStack::PopAndDestroy( modify );
     CleanupStack::PopAndDestroy( jpegImage );
     
     file.Close();
     
     DP0_IMAGIC(_L("CIETNGeneratorAO::WriteExifData--"));
     }


//Set JPEG image quality for encoding
void CIETNGeneratorAO::SetJpegImageDataL()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::SetJpegImageDataL++")));
    
    TJpegImageData* jpegImageData;
    jpegImageData = new (ELeave) TJpegImageData;
    jpegImageData->iSampleScheme = TJpegImageData::EColor420;
    jpegImageData->iQualityFactor = 80;
    
    if (iFrameImageData)
        {
        delete iFrameImageData;
        iFrameImageData = NULL;
        }
    
    iFrameImageData = CFrameImageData::NewL();
    
    //Ownership of jpegImageData lies with CFrameImageData
    User::LeaveIfError(iFrameImageData->AppendImageData(jpegImageData));
    
    DP0_IMAGIC((_L("CIETNGeneratorAO::SetJpegImageDataL--")));
    }

void CIETNGeneratorAO::DoCancel()
    {	
    }

TInt CIETNGeneratorAO::RunError(TInt /*aError*/)
    {
	return KErrNone;
    }
 
/* Set Image arrary received from Client.*/ 
void CIETNGeneratorAO::SetImageArray(RArray<CImageData*> aImageArray)
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::SetImageArray ++")));
    
    iImageArray = aImageArray;
    
    DP0_IMAGIC((_L("CIETNGeneratorAO::SetImageArray --")));
    }
 
void CIETNGeneratorAO::CreateThumbnailL(
        const TDes& aSourceFile, 
        const TDes& aThumbnailFile, 
        const TSize &aSize)
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::CreateThumbnailL ++")));

	iSourceFileName.Copy(aSourceFile);
	iThumbnailFileName.Copy(aThumbnailFile);
	iThumbnailSize = aSize;
 
 	iConvertStatus = EDecoding;
 	if(!IsActive())
 	    {
 	    SetActive();
 	    TRequestStatus* status = &iStatus;
 	    User::RequestComplete( status, KErrNone );
 	    }
 	
 	DP0_IMAGIC((_L("CIETNGeneratorAO::CreateThumbnailL --")));
    }
	

void CIETNGeneratorAO::CreateThumbnailL(
        const TDes& aSourceFile, 
        const TDes& aThumbnailFile, 
        const TSize &aSize,
        CFbsBitmap* /*a512x512TnBitmap*/)
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::CreateThumbnailL ++")));

    iSourceFileName.Copy(aSourceFile);
    iThumbnailFileName.Copy(aThumbnailFile);
    iThumbnailSize = aSize;
 
    iConvertStatus = EDecoding;
    if(!IsActive())
        {
        SetActive();
        TRequestStatus* status = &iStatus;
        User::RequestComplete( status, KErrNone );
        }
    
    DP0_IMAGIC((_L("CIETNGeneratorAO::CreateThumbnailL --")));
    }

void CIETNGeneratorAO::CancelOutStaningRequests()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::CancelOutStaningRequests ++")));
    
    if(iError != KErrNone)
        {
        if(BaflUtils::FileExists(iFileServer, iThumbnailFileName))
            {
            TInt err = BaflUtils::DeleteFile(iFileServer, iThumbnailFileName);
            DP2_IMAGIC(_L("CIETNGeneratorAO::CancelOutStaningRequests - DeleteCorruptedThumbNailFile - file found: %S, err:%d"), &iThumbnailFileName, err);
            }
        }
        
    DeleteObjects();
    
    DP0_IMAGIC((_L("CIETNGeneratorAO::CancelOutStaningRequests --")));
    }
 
void CIETNGeneratorAO::DeleteObjects()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::DeleteObjects ++")));
	
    if(iImageDecoder)
		{
		delete iImageDecoder;
		iImageDecoder = NULL;	
		}

	if( iBitmapScaler )
		{
		delete iBitmapScaler;
		iBitmapScaler = NULL;
		}
	
	if( iBitmap )
		{
		delete iBitmap;
		iBitmap = NULL;
		}
	
	if( iImageEncoder )
		{
		delete iImageEncoder;
		iImageEncoder = NULL;
		}	
	
    if (iFrameImageData)
        {
        delete iFrameImageData;
        iFrameImageData = NULL;
        }
	
#ifdef DECODE_FROM_BUFFER    
    if(iSourceData) 
        {
        delete iSourceData;
        iSourceData = NULL;
        }
#endif
    //delete i512x512TnBitmap;
    
	DP0_IMAGIC((_L("CIETNGeneratorAO::DeleteObjects --")));
    }

void CIETNGeneratorAO::CancelRequestsAndDeleteObjects()
    {
    DP0_IMAGIC((_L("CIETNGeneratorAO::CancelRequestsAndDeleteObjects ++")));
    
	CancelOutStaningRequests();
	DeleteObjects();
	
	DP0_IMAGIC((_L("CIETNGeneratorAO::CancelRequestsAndDeleteObjects --")));
    }