IEBgps/src/IEFaceBrowser.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 files
#include <e32debug.h>
#include <e32math.h>
#include <exifmodify.h>
#include <BAUTILS.H>
#include "IEFaceBrowser.h"
#include "IEBgpsInfo.h"
#include "IEImageData.h"
#include "ImagicConsts.h"
#include "debug.h"
#include <hal.h>

// ================= MEMBER FUNCTIONS ================================ //
CFaceBrowser* CFaceBrowser::NewLC(
        RFs& aFileServer, 
        MIEFaceBrowserObserver& aFaceBrowserObserver)
    {
    DP0_IMAGIC(_L("CFaceBrowser::NewLC ++"));
    
    CFaceBrowser* self = new (ELeave) CFaceBrowser(aFileServer, aFaceBrowserObserver);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    
    DP0_IMAGIC(_L("CFaceBrowser::NewLC --"));
    
    return self;
    }

CFaceBrowser::CFaceBrowser(
        RFs& aFileServer, 
        MIEFaceBrowserObserver& aFaceBrowserObserver) :
        iUtils(iFileServer),
        iFileServer(aFileServer), 
        iFaceBrowserObserver(aFaceBrowserObserver), 
        CActive(EPriorityIdle)
    {
    
    }

CFaceBrowser::~CFaceBrowser()
    {
    DP0_IMAGIC(_L("CFaceBrowser::~CFaceBrowser ++"));
    
    if(iImageDecoder)
        {
        iImageDecoder->CancelDecoding();
        
        delete iImageDecoder;
        iImageDecoder = NULL;
        }
    
    if(iImageEncoder)
        {
        iImageEncoder->CancelEncoding();
        
        delete iImageEncoder;
        iImageEncoder = NULL;
        }
    
    if(iSymbianImageDecoder)
    {
        delete iSymbianImageDecoder;
        iSymbianImageDecoder = NULL;   
    }
    
    if(IsActive())
        Cancel();
    
#ifdef IDL_BGPS
    if(iIDLImageProcessor)
        {
        delete iIDLImageProcessor;
        iIDLImageProcessor = NULL;
        }
#endif
    
    if(iInputBuffer)
        {
        delete iInputBuffer;
        iInputBuffer = NULL;
        }
    
    if(iOutputBuffer)
        {
        delete iOutputBuffer;
        iOutputBuffer = NULL;
        }
    
    if(iFaceYuvDataArray.Count() > 0)
        {
        TCroppedFaces croppedFace;
        HBufC8* buffer = NULL;
        TInt count = iFaceYuvDataArray.Count();
        for(TInt i=0; i<count; i++)
            {
            croppedFace = iFaceYuvDataArray[0];
            buffer = croppedFace.iYuvdata;
            
            iFaceYuvDataArray.Remove(0);
            
            delete buffer;
            buffer = NULL;
            }
        }
    
    iFaceYuvDataArray.Close();
    
    if(iImageDataArray.Count() > 0)
        {
        TInt count = iImageDataArray.Count();
        for(TInt i=0; i<count; i++)
            iImageDataArray.Remove(0);
        }

    iImageDataArray.Close();
    
    iFaceCoordinates.Close();
    if (iTempFaceCoordinates)
        iTempFaceCoordinates->Close();
   
    DP0_IMAGIC(_L("CFaceBrowser::~CFaceBrowser --"));    
    }

void CFaceBrowser::ConstructL()
    {
    TInt error = KErrNone;
    
    DP0_IMAGIC(_L("CFaceBrowser::ConstructL ++"));
    
    CActiveScheduler::Add(this);
    
    iImageDecoder = CIEImageDecoder::NewL(iFileServer, *this);
    
    iImageEncoder = CIEImageEncoder::NewL(iFileServer, *this);
    
#ifdef IDLBGPS
    iIDLImageProcessor = CIDLImageProcessing::NewL(*this);
#endif
    
    iBrowsingState = EStateIdle;
    
    iNumberOfImages = 0;
    iNumberOfImagesBrowsed = 0;
    iNumberOfFacesCropped = 0;    
    iNumberOfFaces = 0;
    iTotalNumberOfFaces = 0;
      
    //RDebug::Print(_L("IDL_Engine_Create error = %d"), error);
    
    if(error != KErrNone)
        User::Leave(error);
    
    DP0_IMAGIC(_L("CFaceBrowser::ConstructL --"));    
    }

void CFaceBrowser::RunL()
    {
    DP0_IMAGIC(_L("CFaceBrowser::RunL ++"));
    
    TInt error = KErrNone;
    
    switch(iBrowsingState)
        {
        case ECreatingBitmap:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - ECreatingBitmap"));
            TInt error = iStatus.Int();
            if(iSymbianImageDecoder)
                {
                delete iSymbianImageDecoder;
                iSymbianImageDecoder = NULL;   
                }
#ifdef IDL_BGPS
            ContinueFBAfterImageConversionL();
#else
            //ExecuteFaceDetectionL();
#endif
            }
            break;
        
        case EFaceBrowsingRunning:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - EFaceBrowsingRunning"));
            
            TRAP(error, BrowseFacesL(iImageDataArray[iNumberOfImagesBrowsed]));
            
            if(error != KErrNone)
                {
                Cleanup();
                iFaceBrowserObserver.FaceBrowsingError(error);
                }                
            }
            break;
        
        case ESingleFaceBrowsingRunning:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - ESingleFaceBrowsingRunning"));
            
            //TRAP(error, BrowseFacesL(iImageDataArray[iSingleFaceBrowsingIndex]));
            TRAP(error, BrowseFacesL(iCurrentImageData));
            
            if(error != KErrNone)
                {
                Cleanup();
                iFaceBrowserObserver.FaceBrowsingError(error);
                }                
            }
            break;

        case EFaceBrowsingPaused:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - EFaceBrowsingPaused"));
            }
            break;
            
        case EFaceBrowsingStopped:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - EFaceBrowsingStopped"));
            
            Cleanup();
            }
            break;
            
        case EFaceBrowsingCompleted:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - EFaceBrowsingCompleted"));
            
            Cleanup();
            iFaceBrowserObserver.FaceBrowsingComplete();
            }
            break;
            
        case ESingleFaceBrowsingComplete:
            {
            DP0_IMAGIC(_L("CFaceBrowser::RunL() - ESingleFaceBrowsingComplete"));
            
            Cleanup2();
            iFaceBrowserObserver.FaceSingleFaceBrowsingComplete();
            }
            break;
                               
        default:
            break;
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::RunL --"));    
    }


void CFaceBrowser::CheckCroppedFaceFileNames()
    {
    DP0_IMAGIC(_L("CFaceBrowser::CheckCroppedFaceFileNames"));
    
    TInt count = iFaceYuvDataArray.Count();
    //Check that file was really cropped
    for(TInt i=0; i<count; i++)
        {
        if(BaflUtils::FileExists(iFileServer, iFaceYuvDataArray[i].iFileName))
            {
            //do nothing
            }
        else
            {
            iFaceYuvDataArray.Remove(i);
            }
        //CImageData* data = new CImageData;
        //data->iMGFilename = iFaceYuvDataArray[i].iFileName;
        //iImageDataArray.Append(data);
        }
    }
            

void CFaceBrowser::DoCancel()
    {
    DP0_IMAGIC(_L("CFaceBrowser::DoCancel ++"));
    
    iImageDecoder->CancelDecoding();
    iImageEncoder->CancelEncoding();
    
    DP0_IMAGIC(_L("CFaceBrowser::DoCancel --"));
    }

TInt CFaceBrowser::RunError(TInt aError)
    {
    DP1_IMAGIC(_L("CFaceBrowser::RunError - Error: %d"), aError);
    return aError;
    }

void CFaceBrowser::BitmapReady(TInt /*aError*/)
    {
    
    }

// =============================== PUBLIC FUNCTIONS ============================== //

void CFaceBrowser::StartFaceBrowsing(RArray<CImageData*> aImageDataArray)
    {
    DP0_IMAGIC(_L("CFaceBrowser::StartFaceBrowsing ++"));
    
    if(iBrowsingState != EStateIdle)
        iFaceBrowserObserver.FaceBrowsingError(KErrInUse); // Better error code ?
    
    if(aImageDataArray.Count() == 0)
        {
        DP0_IMAGIC(_L("ImageDataArray is empty!!!!"));
        iFaceBrowserObserver.FaceBrowsingError(KErrArgument);
        }
    else
        {
        iBrowsingState = EFaceBrowsingRunning;
        //Take local copy of imagedata array
        for(TInt i=0; i<aImageDataArray.Count(); i++)
            {
            if(!aImageDataArray[i]->iGridData.iCorrupted)
                iImageDataArray.Append(aImageDataArray[i]);
            }
        
        iNumberOfImages = iImageDataArray.Count();
        
        DP1_IMAGIC(_L("Number of images: %d"), iNumberOfImages);        
        ContinueLoop();        
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::StartFaceBrowsing --"));    
    }

//void CFaceBrowser::StartSingleFaceDetection(TInt aIndex, RArray<TRect>* aImageCoordArray)
//void CFaceBrowser::StartSingleFaceDetection(TInt aIndex, RArray<TRect>* aImageCoordArray, RArray<CImageData*> aImageDataArray)
void CFaceBrowser::StartSingleFaceBrowsing(TInt aIndex, RArray<TRect>* aImageCoordArray, CImageData* aImageData)
    {
    DP0_IMAGIC(_L("CFaceBrowser::StartSingleFaceBrowsing ++"));
    
    iCurrentImageData = aImageData;
    iSingleFaceBrowsingIndex = aIndex;
    iTempFaceCoordinates = aImageCoordArray;
    
    if(iBrowsingState != EStateIdle)
        iFaceBrowserObserver.FaceBrowsingError(KErrInUse); // Better error code ?
    
    iBrowsingState = ESingleFaceBrowsingRunning;
    
    /*//Take local copy of imagedata array
    for(TInt i=0; i<aImageDataArray.Count(); i++)//TODO, copy only one array element, not all in alrray
        {
        if(!aImageDataArray[i]->iGridData.iCorrupted)
            iImageDataArray.Append(aImageDataArray[i]);
        }
    */
    iNumberOfImages = iImageDataArray.Count();
  
    DP0_IMAGIC(_L("CFaceBrowser::StartSingleFaceBrowsing --"));
    ContinueLoop();        
    }

void CFaceBrowser::CancelFaceBrowsing()
    {
    DP0_IMAGIC(_L("CFaceBrowser::CancelFaceBrowsing ++"));
    
    Cleanup2();
    
    if(IsActive())
        Cancel();
    
    //Cleanup();//TODO, check if this is needed
    
    DP0_IMAGIC(_L("CFaceBrowser::CancelFaceBrowsing ++"));
    }

TInt CFaceBrowser::FindFaces(const TFileName a512x512TNFileName, RArray<TRect>& aCordArray)
    {
    DP1_IMAGIC(_L("CFaceBrowser::FindFaces, a512x512TNFileName = %S ++"), &a512x512TNFileName);
    
    TInt error = KErrNone;
    
    TRAP(error, iUtils.ReadFaceCoordinatesL(a512x512TNFileName, aCordArray));
    if(error != KErrNone) return error;
    
    DP0_IMAGIC(_L("CFaceBrowser::FindFaces --"));
    
    return error;    
    }

TInt CFaceBrowser::GetNumberOfFaces(const TFileName /*aFile*/)
    {
    return 0;
    }

//void CIEEngineImp::RemoveExifFaceCoordsL(const TDes& aFilename, TPoint aTlCoord, TPoint aBrCoord, TInt aFaceNumber)


TInt CFaceBrowser::RemoveFaceCoordinate(const TFileName a512x512TNFileName, RArray<TRect>& aCordArray)
    {
    DP0_IMAGIC(_L("CFaceBrowser::RemoveFaceCoordinate++"));
    
     //Read first current make note
     TInt makerNoteSize;
     HBufC8* makerNote = ReadExifMakerNoteL(a512x512TNFileName, makerNoteSize);
     
     //Read first current maker note to new array from given file
     //RArray<TRect> newCordArray;
     //ReadFaceCoordinatesL(a512x512TNFileName, newCordArray);
     
     //Allocate buffer for coords to be removed
     HBufC8* heapComment = HBufC8::NewL(100);
     TPtr8 ptrCoords = heapComment->Des();
     //Copy coords to be removed to descriptor
     for(TInt i=0; i < aCordArray.Count(); i++)
         {
         ptrCoords.AppendNum(aCordArray[i].iTl.iX);
         ptrCoords.Append(' ');
         ptrCoords.AppendNum(aCordArray[i].iTl.iY);
         ptrCoords.Append(' ');
         ptrCoords.AppendNum(aCordArray[i].iBr.iX );
         ptrCoords.Append(' ');
         ptrCoords.AppendNum(aCordArray[i].iBr.iY);
         ptrCoords.Trim();
         }
     
     //Find coordinates from maker note
     TPtr8 tmpPtr = makerNote->Des();
     TInt res = tmpPtr.Find(ptrCoords);
     
     if(res == KErrNotFound)
         return res;
         
     //Remove coordinates from maker note
     TInt l = ptrCoords.Length();
     tmpPtr.Delete(res, ptrCoords.Length()+1);
     
     //Find number of faces from maker note and update it
     _LIT8(KNumberOfFace, "#");
     res = tmpPtr.Find(KNumberOfFace);
     
     TLex8 lex(makerNote->Ptr());
     lex.SkipAndMark(res+1);
     TInt faceCount = 0;
     lex.Val(faceCount);
     
     //Check lenght of number of faces string
     TInt length = 0;
     //TInt aFaceNumber = 1;
     if(faceCount < 10)
         length = 1;
     else
         length = 2;
          
     HBufC8* numberOfFaces = HBufC8::NewL(length);
     TPtr8 FaceNroPtr = numberOfFaces->Des();
     FaceNroPtr.AppendNum(faceCount-1);
              
     tmpPtr.Replace(res+1, length, FaceNroPtr);
     //TPtr8 numberOfFaces;
     
     delete numberOfFaces;
     //numberOfFaces.Copy();
     
     
     // 1. Read JPEG image from the file to a buffer...
     RFile file;
     User::LeaveIfError( file.Open( iFileServer, a512x512TNFileName, 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::EModify );
     CleanupStack::PushL( modify );
     
     //3. Insert (Set) at least the mandatory Exif data.
     //TInt descSize = 300;
     //HBufC8* heapComment = HBufC8::NewL(descSize);
     TPtr8 ptr = makerNote->Des();
     
     modify->SetMakerNoteL(ptr);
     //modify->SetMakerNoteL(makerNote->Des());
     
     
     // 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() );
     HBufC8* newExif;
     TRAPD(err, newExif = modify->WriteDataL( jpegImage->Des() ));
     
     if(err != KErrNone)
         {
         TInt i=0;
         }
     
     //TPtr8 tmp = newExif->Des();
     
     User::LeaveIfError( file.Replace( iFileServer, a512x512TNFileName, 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("CFaceBrowser::RemoveFaceCoordinate--"));
    return KErrNone;
    }


//Writes face coordinates to Exif data if faces was found
TInt CFaceBrowser::AddFaceCoordinate(const TFileName aFilename, RArray<TRect>& aCordArray)
    {
    DP0_IMAGIC(_L("CFaceBrowser::AddFaceCoordinate++"));
    //Read first current maker note to new array from given file
    RArray<TRect> newCordArray;
    iUtils.ReadFaceCoordinatesL(aFilename, newCordArray);
     
    //Append existing coords to new coords array
    for(TInt i=0; i<newCordArray.Count(); i++)
        {
        aCordArray.Append(newCordArray[i]);
        }
              
     //Write all coords to file exif data manufactorer note
    iUtils.WriteFaceCoordinatesL(aFilename, aCordArray);
     
    newCordArray.Close();
    
    DP0_IMAGIC(_L("CFaceBrowser::AddFaceCoordinate--"));

    return KErrNone;
    }


HBufC8* CFaceBrowser::ReadExifMakerNoteL(const TDes &aFileName, TInt& aSize)
    {
    DP0_IMAGIC(_L("CFaceBrowser::ReadExifMakerNoteL++"));
    HBufC8* makerNote;
    
    // 1. Read Exif image from the file to a buffer...
    RFile file;
    User::LeaveIfError( file.Open( iFileServer, aFileName , EFileRead ) );
    CleanupClosePushL( file );
    TInt size = 65536;
        
    HBufC8* exif = HBufC8::NewL( size );
    CleanupStack::PushL( exif );
    TPtr8 bufferDes( exif->Des() ); 
    TInt err1 = file.Read( bufferDes );
    TInt length = bufferDes.Length();
    
    if(length <= 0 )
        {
        CleanupStack::Pop( exif );
        CleanupStack::PopAndDestroy();
        //return NULL;
        }
    else
        {
        CleanupStack::Pop( exif );
        CleanupStack::PopAndDestroy();
        CleanupStack::PushL( exif );
        
        // 2. Instantiate Exif reader...
        CExifRead* ExifRead;
        TInt err = 0;
        TRAP(err, ExifRead = CExifRead::NewL( exif->Des(),CExifRead::ENoJpeg ));//CExifRead::ENoTagChecking | CExifRead::ENoJpeg
        
        //HBufC8* comment = NULL;
        if(err != KErrNone)
            {
            }
        else
            {
            CleanupStack::PushL( ExifRead );
        
            // 3. Get required data from the Exif image...
            TUint32  xRes;
            TUint32  yRes;
            ExifRead->GetPixelXDimension(xRes);
            ExifRead->GetPixelYDimension(yRes);  
                    
            makerNote = ExifRead->GetMakerNoteL(); 
            
            // Delete the reader instance...
            CleanupStack::PopAndDestroy( ExifRead );
            }
       
        file.Close();
        CleanupStack::PopAndDestroy( exif );
        //DP0_IMAGIC(_L("CIEEngineImp::ReadExifData--"));
        
        if(makerNote == NULL)
            {
            User::Leave(KErrNotFound);
            }
        else
            {
            aSize = makerNote->Length();
            //return (TUint8*)makerNote->Des().Ptr();
            return makerNote;
            }
        //return comment->Des()->Ptr();
        
        }
    DP0_IMAGIC(_L("CFaceBrowser::ReadExifMakerNoteL--"));
    
    return NULL;
    }

    
// ================================ FACE BROWSING RELATED FUNCTIONS =============================== //

//This is called from RunL when face browsing is started
void CFaceBrowser::BrowseFacesL(CImageData* aImageData)
    {
    DP0_IMAGIC(_L("CFaceBrowser::BrowseFacesL++"));
    
    if(iBrowsingState != EFaceBrowsingRunning && iBrowsingState != ESingleFaceBrowsingRunning)
        User::Leave(KErrNotSupported);
    
    TBool coordnatesExists = EFalse;
    iCurrentImageData = aImageData;
    
    TFileName filename;
    iCurrentImageData->GetFileName(filename, ESize512x512);
    DP1_IMAGIC(_L("CFaceBrowser::BrowseFacesL 512x512TNFile = %S ++"), &filename);
    
    // 512x512 TN are supposed to be created in TN generation phase and should be present
    if(!iCurrentImageData->IsImageReady(ESize512x512))
        {
        Cleanup();
        User::Leave(KErrNotFound);
        }        
    else
        {
        iCurrentImageData->GetFileName(iCurrent512x512TNFileName, ESize512x512); //target file to write face coords
        }
    
    //If coordinates exist we do not process image anymore
    TRAPD(error, iUtils.ReadFaceCoordinatesL(iCurrent512x512TNFileName, iFaceCoordinates));
    if (error == KErrNone)
        {
        if(iBrowsingState == ESingleFaceBrowsingRunning)
            {
            if(iBrowsingState == ESingleFaceBrowsingRunning)
                 for(TInt i = 0; i<iFaceCoordinates.Count(); i++)
                    iTempFaceCoordinates->Append(iFaceCoordinates[i]);
            
            iBrowsingState = ESingleFaceBrowsingComplete;
            }
        else
            {
            //Increment to the next image index
            iNumberOfImagesBrowsed++;
            //Check if we are at the end of image array
            if(iNumberOfImagesBrowsed == iNumberOfImages)
                {
                iBrowsingState = EFaceBrowsingCompleted;
                }
            }
        
        //and continue to next image
        ContinueLoop();
        }
    //Here we have image which has to be processed for face detection
    else
        {
        iPrevBrowsingState = iBrowsingState;
        iBrowsingState = ECreatingBitmap;
        
        TSize size;
        if(aImageData->GetAspectRatio() > 1)
            {
            size.iWidth=320;
            size.iHeight=320/aImageData->GetAspectRatio();
            }
        else
            {
            size.iWidth=320*aImageData->GetAspectRatio();
            size.iHeight=320;
            }
        
        if(size.iWidth%2 != 0)
            size.iWidth++;
        if(size.iHeight%2 != 0)
            size.iHeight++;
        
        iBitmap = new (ELeave) CFbsBitmap();
        iBitmap->Create(size, EColor16M);
        
        iSymbianImageDecoder = CImageDecoder::FileNewL(iFileServer, iCurrent512x512TNFileName, CImageDecoder::EPreferFastDecode);
        iSymbianImageDecoder->Convert(&iStatus, *iBitmap, 0);
        
        if(!IsActive())
            SetActive();
        
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::BrowseFacesL --"));
    }

#ifdef IDLBGPS
void CFaceBrowser::ContinueFBAfterImageConversionL()
    {
    DP0_IMAGIC(_L("CFaceBrowser::ContinueFBAfterImageConversionL ++"));
    
    iBrowsingState = iPrevBrowsingState;
    
    TSize size = iBitmap->SizeInPixels();
    
    //Init IDL
    TInt value = 0;
    InitializeL(EIDLFeatureFaceDetection, size, size, &value, ETrue);
    
    // Code for the previous face detection which needed YUV input
    //TUint8* yuvArray;
    //TInt yuvDataSize = size.iHeight * size.iWidth * 3 / 2;
    //yuvArray = new TUint8 [yuvDataSize];
    //
    //ConvertRgb2Yuv(iBitmap, yuvArray, 3/*aBytesPerPixel*/, size);
    // 
    //iInputBuffer->Des().Copy(yuvArray, yuvDataSize);
    
    TInt bitmapSize = size.iHeight * size.iWidth * 3;
    
    // This is in the BGR order
    iInputBuffer->Des().Copy((TUint8 *)iBitmap->DataAddress(), bitmapSize);
    //delete yuvArray;
#if 0
    //just for testing --->
    _LIT(KTestPath, "C:\\Images\\RGB2YUV.YUV");
    TFileName temp;
    temp.Copy(KTestPath);
    
    RFile file;
    User::LeaveIfError(file.Replace(iFileServer, temp, EFileWrite));
    TInt dataSize = iInputBuffer->Size();
    file.Write(iInputBuffer->Des());
    //file.Write(yuvArray);
    file.Flush();
    file.Close();    
    //TODO, just for testing <---
#endif

#if 0
    //just for testing ---> 
    _LIT(KTestPath, "C:\\Images\\RawRGB.rgb");
    TFileName temp;
    temp.Copy(KTestPath);
        
    RFile file;
    User::LeaveIfError(file.Replace(iFileServer, temp, EFileWrite));
    TInt dataSize = iInputBuffer->Size();
    file.Write(iInputBuffer->Des());
    file.Flush();
    file.Close();    
    //just for testing <---
#endif

        
    TInt error = KErrNone;
    TRAP(error, BrowseFacesL(iCurrent512x512TNFileName, iFaceCoordinates));
    
    if(error != KErrNone)
        {
        Cleanup();
        iFaceBrowserObserver.FaceBrowsingError(error);
        }
    
#if 0
    //only for debug
    _LIT(KTestPath, "C:\\Images\\RGB2YUV.MBM");
    TFileName temp;
    temp.Copy(KTestPath);
    iBitmap->Save(temp);
#endif
    
    iBitmap->Reset();
    delete iBitmap;
    
    if(iBrowsingState == ESingleFaceBrowsingRunning)
        iBrowsingState = ESingleFaceDetectionComplete;
    
    ContinueLoop();
    
    DP0_IMAGIC(_L("CFaceBrowser::ContinueFBAfterImageConversionL --"));
    }
#endif

//http://wiki.forum.nokia.com/index.php/TSS001195_-_RGB_to_YUV_conversion
void CFaceBrowser::ConvertRgb2Yuv(CFbsBitmap* aSourceBitmap, TUint8* aYuv, TInt aBytesPerPixel, const TSize aSize)
    {
    DP0_IMAGIC(_L("CFaceBrowser::ConvertRgb2Yuv++"));
    
    // Definitions that help access each colour component in source bitmap
    #define   sR ((TInt32)(s[2]))
    #define   sG ((TInt32)(s[1]))
    #define   sB ((TInt32)(s[0]))
     
    const TInt KImageNumPixels = aSize.iHeight*aSize.iWidth;
     
    // Lock source bitmap (CFbsBitmap)
    aSourceBitmap->LockHeap(EFalse);
    TUint8* s = (TUint8*)aSourceBitmap->DataAddress();
        
    TInt i = 0;
    TInt ui = KImageNumPixels;
    TInt vi = KImageNumPixels + KImageNumPixels/4;
       
    //iYuv is an array of TUint8 values, length (KImageNumPixels*3/2)
         
    for(TInt j=0; j < aSize.iHeight; j++)
        {
        for(TInt k=0; k < aSize.iWidth; k++)
            {
            // Y value is generated for each pixel
            aYuv[i] = (TUint8)( (  66*sR + 129*sG +  25*sB + 128) >> 8 ) + 16;
              
            // U, V values are generated for every other pixel on every other scanline 
            if(0 == j%2 && 0 == k%2)
                {
                aYuv[ui++] = (TUint8)( (-38*sR - 74*sG + 112*sB + 128) >> 8 ) + 128;
                aYuv[vi++] = (TUint8)( (112*sR - 94*sG - 18*sB + 128) >> 8 ) + 128;
                }
            i++; 
            s+=aBytesPerPixel; // Number of bytes representing one pixel in source
                               // bitmap e.g. if bitmap display mode == EColor16M 
                               // (24bits/pixel), then iBytesPerPixel == 3
            }
        }
       
    aSourceBitmap->UnlockHeap(EFalse);
    // iYuv now contains the source frame converted to YUV420p format
    
    DP0_IMAGIC(_L("CFaceBrowser::ConvertRgb2Yuv--"));
    }

#ifdef IDLBGPS
//This is called after YUV data has been completed
void CFaceBrowser::BrowseFacesL(const TFileName a512x512TNFileName, RArray<TRect>& aFaceCoordinates)
    {
    DP0_IMAGIC(_L("CFaceBrowser::BrowseFacesL ++"));
    
       
    TPtr8 inBuffer = iInputBuffer->Des();
    TPtr8 outBuffer = iOutputBuffer->Des();
    
    iIDLImageProcessor->SetInOutDataL(inBuffer, outBuffer);
    iIDLImageProcessor->ProcessImageL();
    
    TInt count = aFaceCoordinates.Count();
    for(TInt i=0; i<count; i++)
        aFaceCoordinates.Remove(0);
    
    GetFaceCoordinates(iNumberOfFaces, aFaceCoordinates);
    
    //Add number of faces to image data
    iCurrentImageData->SetNumberOfFaces(iNumberOfFaces);
    
    if(iBrowsingState == ESingleFaceBrowsingRunning)
         for(TInt i = 0; i<aFaceCoordinates.Count(); i++)
            iTempFaceCoordinates->Append(aFaceCoordinates[i]);
 
    iUtils.WriteFaceCoordinatesL(a512x512TNFileName, aFaceCoordinates);
    
    if(iBrowsingState == EFaceBrowsingRunning)
        {
        if(iBrowsingState == EFaceBrowsingRunning)
            iNumberOfImagesBrowsed++;
        
        if(iNumberOfImagesBrowsed == iNumberOfImages)
            iBrowsingState = EFaceBrowsingCompleted;
        }
    else if(iBrowsingState == ESingleFaceBrowsingRunning)
        {
        iBrowsingState = ESingleFaceDetectionComplete;
        }
    
        
    DP0_IMAGIC(_L("CFaceBrowser::BrowseFacesL --"));
    }

void CFaceBrowser::GetFaceCoordinates(TInt& aNumberOfFaces, RArray<TRect>& aCordArray)
    {
    DP0_IMAGIC(_L("CFaceBrowser::GetFaceCoordinates ++"));
    
    iIDLImageProcessor->GetFacesDetected(aNumberOfFaces);
    
    if(aNumberOfFaces <= 0)
        DP0_IMAGIC(_L("No faces found!!!"));
    else
        {
        DP1_IMAGIC(_L("Number of faces found: %d"), aNumberOfFaces);
        
        // Clean up the coordinate array
        if(aCordArray.Count() > 0)
            {
            TInt count = aCordArray.Count();
            for(TInt i=0; i<count; i++)
                aCordArray.Remove(0);
            }
        
        iIDLImageProcessor->GetFaceCoordinates(aCordArray);
        aCordArray.SortSigned();
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::GetFaceCoordinates --"));
    }
#endif

// =============================== FACE CROPPING RELATED FUNCTIONS ============================ //

void CFaceBrowser::CropFacesL(CImageData* aImageData)
    {
    DP0_IMAGIC(_L("CFaceBrowser::CropFacesL ++"));
    
    TInt error = KErrNone;
    iCurrentImageData = aImageData;
    iNumberOfFacesCropped = 0;
    
    TFileName imageFileName;
    aImageData->GetFileName(imageFileName, EFullSize);
    error = MakeFacesDir(imageFileName);
    
    if(error != KErrNone && error != KErrAlreadyExists)
        User::Leave(error);
    
    // 512x512 and 320x320 TN are supposed to be created in TN generation phase and should be present
    if(!iCurrentImageData->IsImageReady(ESize512x512) || !iCurrentImageData->IsImageReady(EFullSize))
        {
        Cleanup();
        User::Leave(KErrNotFound);
        }        
    else
        {
        iCurrentImageData->GetFileName(iCurrent512x512TNFileName, ESize512x512);
        iCurrentImageData->GetFileName(iCurrentImageFileName, EFullSize);
        }
    
    // We assume that all the images were searched for faces before face cropping started
    // Hence not checking if face coordinates exists or n ot
    iUtils.ReadFaceCoordinatesL(iCurrent512x512TNFileName, iFaceCoordinates);
    
    if(iFaceCoordinates.Count() == 0)
        {
        iNumberOfImagesBrowsed++;
        
        if(iNumberOfImagesBrowsed == iNumberOfImages)
            iBrowsingState = EFaceCroppingCompleted;
                
        ContinueLoop();
        }
    else
        {
        iTotalNumberOfFaces +=  iFaceCoordinates.Count();
        DP1_IMAGIC(_L("iTotalNumberOfFaces = %d"), iTotalNumberOfFaces);
        
        iImageDecoder->GetImageSizeL(iCurrentImageFileName, iSize);
        
        if(!CheckOddSize(iSize))
            {
            TInt size = iSize.iWidth * iSize.iHeight * 3 / 2;
                    
            PrepareInOutBuffersL(ETrue, size, EFalse, 0);
            
            iImageDecoder->ConvertJpeg2YuvL(iCurrentImageFileName, *iInputBuffer);
            }
        else
            {
            iNumberOfImagesBrowsed++;
            
            if(iNumberOfImagesBrowsed == iNumberOfImages)
                iBrowsingState = EFaceCroppingCompleted;
                            
            ContinueLoop();
            }        
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::CropFacesL --"));
    }


void CFaceBrowser::CropFacesL(const TFileName /*aImageFileName*/, RArray<TRect>& aFaceCoordinates)
    {
    DP1_IMAGIC(_L("CFaceBrowser::CropFacesL++, number of faces: %d"), aFaceCoordinates.Count());

#ifdef IDLBGPS_CROP

    TRect rect(0, 0, 0, 0);
    TParse parser;
    parser.Set(aImageFileName, NULL, NULL);
        
    iNumberOfImagesBrowsed++;
    
    // Clean the face data array
    if(iFaceYuvDataArray.Count() > 0)
        {
        TCroppedFaces temp;
        HBufC8* buffer = NULL;
        TInt count  = iFaceYuvDataArray.Count();
        
        for(TInt i=0; i<count; i++)
            {
            temp = iFaceYuvDataArray[0];
            
            iFaceYuvDataArray.Remove(0);
            
            buffer = temp.iYuvdata;
            
            delete buffer;
            buffer = NULL;
            }
        }
    
    for(TInt faceIndex=0; faceIndex<aFaceCoordinates.Count(); faceIndex++)
        {
        TSize tnSize;
        TFileName thumbnailFileName;
        
        iCurrentImageData->GetFileName(thumbnailFileName, ESize32x32);
        iImageDecoder->GetImageSizeL(thumbnailFileName, tnSize);
        
        rect = GetFaceRect(iSize, tnSize, aFaceCoordinates[faceIndex]);
        
        InitializeL(EIDLFeatureCrop, iSize, rect.Size(), &rect, EFalse);
        
        TPtr8 inBuffer = iInputBuffer->Des();
        TPtr8 outBuffer = iOutputBuffer->Des();
        
        iIDLImageProcessor->SetInOutDataL(inBuffer, outBuffer);
        iIDLImageProcessor->ProcessImageL();
        
        DP1_IMAGIC(_L("Face cropped: %d"), faceIndex);
        
        TCroppedFaces croppedFace;
        croppedFace.iYuvdata = HBufC8::NewL(iOutputBuffer->Size());
        croppedFace.iYuvdata->Des().Copy(iOutputBuffer->Des());
        
        croppedFace.iFileName.Append(parser.DriveAndPath());
        croppedFace.iFileName.Append(KFaces);
        croppedFace.iFileName.Append(parser.Name());
        croppedFace.iFileName.Append(KUnderScr);
        croppedFace.iFileName.AppendNum(faceIndex);
        croppedFace.iFileName.Append(parser.Ext());
        
        croppedFace.iCroppedSize = rect.Size();        
        
        iFaceYuvDataArray.Append(croppedFace);
        iCroppedFilenames->Append(croppedFace.iFileName);
        }
#endif
    
    iBrowsingState = EEncodingFaces;
    
    DP0_IMAGIC(_L("CFaceBrowser::CropFacesL --"));
    }

TRect CFaceBrowser::GetFaceRect(const TSize aOrgImageSize, const TSize aRelImageSize, const TRect aFaceRect)
    {
    DP0_IMAGIC(_L("CFaceBrowser::GetFaceRect ++"));

    TRect faceRect(0, 0, 0, 0);
    
    faceRect.iTl = aFaceRect.iTl;
    faceRect.iBr = aFaceRect.iBr;
    
    TReal width = 0;
    TReal height = 0;
    TReal aspectRatioX = 0;
    TReal aspectRatioY = 0;
    
    //Converting the face rect to original image size
    aspectRatioX = (TReal)aOrgImageSize.iWidth / (TReal)aRelImageSize.iWidth;
    aspectRatioY = (TReal)aOrgImageSize.iHeight / (TReal)aRelImageSize.iHeight;
    
    //Make cropped rect bigger
    //faceRect.Grow(faceRect.Width()/4, (faceRect.Height()/2));
    faceRect.Grow(faceRect.Width()/2.5, (faceRect.Height()/1.5));
    //And move ract bit higher
    //faceRect.Move(0, -(faceRect.Height()/6));
    faceRect.Move(0, -(faceRect.Height()/8));
    
    if(aspectRatioX != 1.0 || aspectRatioY != 1.0)
        {
        //Scale cropping rect size to original  
        faceRect.iTl.iX *= aspectRatioX;
        faceRect.iTl.iY *= aspectRatioY;
        faceRect.iBr.iX *= aspectRatioX;
        faceRect.iBr.iY *= aspectRatioY;
        
        // Check for extreme values and negative values
        // Any invalid values will be made max valid values
        if(faceRect.iTl.iX < 0) faceRect.iTl.iX = 0;
        if(faceRect.iTl.iY < 0) faceRect.iTl.iY = 0;
        if(faceRect.iTl.iX >= aOrgImageSize.iWidth) faceRect.iBr.iX = aOrgImageSize.iWidth-1;
        if(faceRect.iTl.iY >= aOrgImageSize.iHeight) faceRect.iBr.iY = aOrgImageSize.iHeight-1;
        if(faceRect.iBr.iX > aOrgImageSize.iWidth) faceRect.iBr.iX = aOrgImageSize.iWidth;
        if(faceRect.iBr.iY > aOrgImageSize.iHeight) faceRect.iBr.iY = aOrgImageSize.iHeight;
        
        }    
    
    // Make sure that the width and height are divisible by 2, else encoder/decoder will give -10 error
    TReal remainder = 0;
    
    Math::Mod(remainder, faceRect.Size().iWidth, 2);
    
    if(remainder != 0)
        faceRect.iBr.iX--;
    
    Math::Mod(remainder, faceRect.Size().iHeight, 2);
    
    if(remainder != 0)
        faceRect.iBr.iY--;

    DP4_IMAGIC(_L("CFaceBrowser::GetFaceRect faceRect(%d, %d, %d, %d)--"), faceRect.iTl.iX, faceRect.iTl.iY, faceRect.iBr.iX, faceRect.iBr.iY);
    
    return faceRect;
    }

TInt CFaceBrowser::MakeFacesDir(const TFileName aImageName)
    {
    DP0_IMAGIC(_L("CFaceBrowser::MakeFacesDir ++"));
    
    TInt error = KErrNone;
    
    TParse parser;
    parser.Set(aImageName, NULL, NULL);
    
    TFileName faceDir = parser.DriveAndPath();
    faceDir.Append(KFaces);
    
    if(BaflUtils::PathExists(iFileServer, faceDir))
        error = KErrAlreadyExists;
    else
        {
        error = iFileServer.MkDir(faceDir);
        
        if(error == KErrNone)
            error = iFileServer.SetAtt(faceDir, KEntryAttNormal, KEntryAttNormal);
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::MakeFacesDir --"));
    
    return error;
    }

void CFaceBrowser::EncodeFaceL(const TCroppedFaces aCroppedFace)
    {
    DP0_IMAGIC(_L("CFaceBrowser::EncodeFaceL ++"));
    
    HBufC8* buffer = aCroppedFace.iYuvdata;
   
    TFileName fileName = aCroppedFace.iFileName;
    TSize size = aCroppedFace.iCroppedSize;
    
    DP1_IMAGIC(_L("Encoding Image: %S"), &fileName);
    DP2_IMAGIC(_L("Size: %dx%d"), size.iWidth, size.iHeight);
    
    iImageEncoder->ConvertYuv2JpegL(fileName, *buffer, size);
    
    DP0_IMAGIC(_L("CFaceBrowser::EncodeFaceL --"));
    }

// =============================== COMMON FUNCTIONS ============================================== //

#ifdef IDLBGPS
void CFaceBrowser::InitializeL(const TIDLFeatures aIDLFeature, const TSize aInSize, const TSize aOutSize, TAny* aValue, TBool aInBufferCreate)
    {
    DP4_IMAGIC(_L("CFaceBrowser::InitializeL, aInsize = %dx%d, aOutSize = %dx%d ++"), aInSize.iWidth, aInSize.iHeight, aOutSize.iWidth, aOutSize.iHeight);
    
//    TInt value = 0;
    TInt outputBufferSize = 0;
    //TInt inputBufferSize = (aInSize.iWidth * aInSize.iHeight * 3 / 2);
    TInt inputBufferSize = aInSize.iWidth * aInSize.iHeight * 3;
    
    iIDLImageProcessor->SetFeatureL(aIDLFeature, aValue);
    //iIDLImageProcessor->InitializeFeatureL(aInSize, 
    //                                        aOutSize, 
    //                                        EIDLFormatYUV420, 
    //                                        EIDLFormatYUV420);
    iIDLImageProcessor->InitializeFeatureL(aInSize, 
                                                aOutSize, 
                                                EIDLFormatRGB, 
                                                EIDLFormatRGB);
    
    iIDLImageProcessor->AllocateBuffersL(outputBufferSize);
    
    PrepareInOutBuffersL(aInBufferCreate, inputBufferSize, ETrue, outputBufferSize);
    
    DP0_IMAGIC(_L("CFaceBrowser::InitializeL --"));
    }
#endif

void CFaceBrowser::PrepareInOutBuffersL(TBool aInBufferCreate, const TInt aInBufSize, TBool aOutBufferCreate, const TInt aOutBufSize)
    {
    DP0_IMAGIC(_L("CFaceBrowser::PrepareInOutBuffersL ++"));
    
    if(aInBufferCreate)
        {
        if(aInBufSize <= 0)
            User::Leave(KErrArgument);
        
        if(iInputBuffer)
            {
            delete iInputBuffer;
            iInputBuffer = NULL;
            }
        
        iInputBuffer = HBufC8::NewL(aInBufSize);
        }
    
    if(aOutBufferCreate)
        {
        if(aOutBufSize <= 0)
            User::Leave(KErrArgument);
        
        if(iOutputBuffer)
            {
            delete iOutputBuffer;
            iOutputBuffer = NULL;
            }
        
        iOutputBuffer = HBufC8::NewL(aOutBufSize);
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::PrepareInOutBuffersL --"));
    }

TBool CFaceBrowser::CheckOddSize(const TSize aSize)
    {
    DP0_IMAGIC(_L("CFaceBrowser::CheckOddSize ++"));
    
    TReal remainder = 0;
    
    Math::Mod(remainder, aSize.iWidth, 2);
    
    if(remainder != 0) return ETrue;
    
    Math::Mod(remainder, aSize.iHeight, 2);
    
    if(remainder != 0) return ETrue;
    
    DP0_IMAGIC(_L("CFaceBrowser::CheckOddSize --"));
    
    return EFalse;
    }

#if 0
TFileName CFaceBrowser::MakeTNFileName(const TFileName aImageFileName, TBool a512TNFile, TBool /*a320TNFileName*/)
    {
    DP1_IMAGIC(_L("CFaceBrowser::Make512x512TNFileName, aImageFileName = %S ++"), &aImageFileName);
    
    TParse fileNameParser;
    fileNameParser.Set(aImageFileName, NULL, NULL);
    
    TFileName tnFileName;
    
    tnFileName = fileNameParser.DriveAndPath();
    
    if(a512TNFile /*&& !a320TNFileName*/)
        {
        tnFileName.Append(K512x512TNFilePath);
        tnFileName.Append(fileNameParser.Name());
        tnFileName.Append(KTNExt);
        }
/*    if(!a512TNFile && a320TNFileName)
        {
        tnFileName.Append(K320TNFilePath);
        tnFileName.Append(fileNameParser.Name());
        tnFileName.Append(K320TNFileExt);
        }*/
    
    DP1_IMAGIC(_L("CFaceBrowser::Make512x512TNFileName fileName512x512TN = %S --"), &tnFileName);
    
    return tnFileName;
    }
#endif    

void CFaceBrowser::Cleanup()
    {
    DP0_IMAGIC(_L("CFaceBrowser::Cleanup ++"));
    
    if(iImageDecoder)
            iImageDecoder->CancelDecoding();
            
    if(iImageEncoder)
        iImageEncoder->CancelEncoding();
        
    if(iFaceCoordinates.Count() > 0)
        {
        TInt count = iFaceCoordinates.Count();
        for(TInt i=0; i<count; i++)
            iFaceCoordinates.Remove(0);
        }
    
    if(iFaceYuvDataArray.Count() > 0)
        {
        TCroppedFaces croppedFaces;
        HBufC8* buffer = NULL;
        TInt count = iFaceYuvDataArray.Count();
        
        for(TInt i=0; i<count; i++)
            {
            croppedFaces = iFaceYuvDataArray[0];
            iFaceYuvDataArray.Remove(0);
            
            buffer = croppedFaces.iYuvdata;
            
            delete buffer;
            buffer = NULL;
            }
        }
/*    
    if(iImageDataArray.Count() > 0)
        {
        TInt count = iImageDataArray.Count();
        for(TInt i=0; i<count; i++)
            iImageDataArray.Remove(0);
        }
 */   
    iNumberOfFaces = 0;
    iNumberOfImages = 0;
    iNumberOfImagesBrowsed = 0;
    iNumberOfFacesCropped = 0;
    
    iCurrentImageData = NULL;
    
    iCurrentImageFileName = KEmptyString;
    iCurrent512x512TNFileName = KEmptyString;
    //iCurrent320x320TNFileName = KEmptyString;
    
    iBrowsingState = EStateIdle;
    
    DP0_IMAGIC(_L("CFaceBrowser::Cleanup --"));
    }

void CFaceBrowser::Cleanup2()
    {
    DP0_IMAGIC(_L("CFaceBrowser::Cleanup2 ++"));
    
    if(iImageDecoder)
        iImageDecoder->CancelDecoding();
        
    if(iImageEncoder)
        iImageEncoder->CancelEncoding();
    
    if(iFaceYuvDataArray.Count() > 0)
        {
        TCroppedFaces croppedFaces;
        HBufC8* buffer = NULL;
        TInt count = iFaceYuvDataArray.Count();
        
        for(TInt i=0; i<count; i++)
            {
            croppedFaces = iFaceYuvDataArray[0];
            iFaceYuvDataArray.Remove(0);
            
            buffer = croppedFaces.iYuvdata;
            
            delete buffer;
            buffer = NULL;
            }
        }

    iBrowsingState = EStateIdle;
    
    DP0_IMAGIC(_L("CFaceBrowser::Cleanup2 --"));
    }

void CFaceBrowser::ContinueLoop()
    {
    DP0_IMAGIC(_L("CFaceBrowser::ContinueLoop++"));
    
    if(!IsActive())
        {
        SetActive();
        TRequestStatus* status = &iStatus;
        User::RequestComplete(status, KErrNone);            
        }
    
    DP0_IMAGIC(_L("CFaceBrowser::ContinueLoop--"));
    }

void CFaceBrowser::WriteFaceCoordToExif(TInt numOfFaces, RArray<TRect> faceCoordinates) {
    //Add number of faces to image data
    iCurrentImageData->SetNumberOfFaces(numOfFaces);
    
    if(iBrowsingState == ESingleFaceBrowsingRunning)
         for(TInt i = 0; i<iFaceCoordinates.Count(); i++)
            iTempFaceCoordinates->Append(iFaceCoordinates[i]);
 
    iUtils.WriteFaceCoordinatesL(iCurrent512x512TNFileName, faceCoordinates);
}

// EOF