--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/testtoolsconn/stat/desktop/source/lib/src/cstatimageverify.cpp Mon Mar 08 15:04:18 2010 +0800
@@ -0,0 +1,678 @@
+/*
+* Copyright (c) 2005-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 "stdafx.h"
+#include <STATCommon.h>
+#include "CSTATImageVerify.h"
+
+//----------------------------------------------------------------------------
+//standard constructor
+CSTATImageVerify::CSTATImageVerify(CSTATLogFile *pLog)
+: iImageCount(0), margin(0), lastrefimageloaded(0), pLogFile(pLog),
+ m_pDib(NULL), m_pDib2(NULL), m_pDibBits(NULL), m_pDibBits2(NULL),
+ m_pBIH(NULL), m_pBIH2(NULL), m_pPalette(NULL), m_pPalette2(NULL),
+ m_dwDibSize(0), m_dwDibSize2(0), m_nPaletteEntries(0), m_nPaletteEntries2(0)
+{
+}
+
+//----------------------------------------------------------------------------
+//destructor
+CSTATImageVerify::~CSTATImageVerify()
+{
+ if (m_pDib)
+ {
+ delete [] m_pDib;
+ m_pDib = NULL;
+ }
+
+ if (m_pDib2)
+ {
+ delete [] m_pDib2;
+ m_pDib2 = NULL;
+ }
+}
+
+//----------------------------------------------------------------------------
+
+//image verification function (loading + blitting)
+int CSTATImageVerify::VerifyImage(CString& lastscreenshot)
+{
+ TCHAR buffer[70];
+ _stprintf(buffer, _T("User set margin of error (percentage) : %ld"), margin);
+
+ pLogFile->Set(START_VERIFICATION, buffer);
+
+ // make sure we've got at least 1 image left
+ if(ImagesRemaining())
+ {
+ if(LoadRefImage())
+ pLogFile->Set(REFIMAGELOAD_OK, refimagearray[lastrefimageloaded++].completefilenamepath);
+ else
+ return pLogFile->Set(REFIMAGELOAD_FAILURE);
+
+ Sleep(500);
+
+ if(LoadNewImage(lastscreenshot))
+ pLogFile->Set(NEWIMAGELOAD_OK);
+ else
+ return pLogFile->Set(NEWIMAGELOAD_FAILURE);
+ }
+ else
+ return pLogFile->Set(REFIMAGELOAD_FAILURE_LIMIT); //run out of reference images
+
+ //compare images and decide if difference is greater than margin value set earlier
+
+ // If we have not data we can't draw.
+ if (!m_pDib2)
+ return pLogFile->Set(VERIFICATION_FAILURE);
+
+ //set width and height of images
+ int nWidth = m_pBIH2 -> biWidth;
+ int nHeight = m_pBIH2 -> biHeight;
+
+ HDC hdc, hMaskDC, hImageDC;
+ HBITMAP hMaskBitmap, hImageBitmap;
+
+ hdc = GetDC(NULL);
+
+ //---------------------
+
+ hMaskDC = CreateCompatibleDC(hdc);
+ hImageDC = CreateCompatibleDC(hdc);
+
+ hMaskBitmap = CreateCompatibleBitmap(hdc, nWidth, nHeight);
+
+ SelectObject(hMaskDC, hMaskBitmap);
+ SetTextColor(hMaskDC, RGB(0, 0, 255));
+
+ //---------------------
+
+ hImageBitmap = CreateCompatibleBitmap(hdc, nWidth, nHeight);
+
+ // release the object now we're finished with it
+ ReleaseDC(NULL, hdc);
+
+ SelectObject(hImageDC, hImageBitmap);
+ SetTextColor(hImageDC, RGB(0, 0, 255));
+
+ //---------------------
+
+ //set MaskBitmap pixel data to that of the original DIB
+ SetDIBits(hMaskDC, hMaskBitmap, 0L, nHeight, m_pDibBits, (BITMAPINFO *)m_pBIH, (DWORD)DIB_RGB_COLORS);
+
+ //create a new DIB using second image data
+ SetDIBits(hImageDC, hImageBitmap, 0L, nHeight, m_pDibBits2, (BITMAPINFO *)m_pBIH2, (DWORD)DIB_RGB_COLORS);
+
+ //XOR new image with original image (so new pic on top of pic 2)
+ BitBlt(hMaskDC, 0, 0, nWidth, nHeight, hImageDC, 0, 0, SRCINVERT);
+
+ //***************************************************
+
+ //now work on percentage difference in images
+
+ //need to use 'new' otherwise you get a stack overflow with anything big like this (1MB+)
+ COLORREF (*pixelcoord) [480];
+ pixelcoord = new COLORREF [640][480];
+ if (!pixelcoord)
+ return pLogFile->Set(VERIFICATION_FAILURE);
+
+ int x, y, myheight, mywidth;
+ float totalpixelarea;
+
+ x = 0;
+ y = 0;
+ int difference = 0;
+ float finalpercentage = 0;
+ totalpixelarea = 0;
+ myheight = 0;
+ mywidth = 0;
+
+ mywidth = m_pBIH -> biWidth;
+ myheight = m_pBIH -> biHeight;
+
+ // convert total to float for later % calculation
+ totalpixelarea = (float)(mywidth * myheight);
+
+ //initialisation
+ for(y = 0; y < 480; y++)
+ {
+ //go across picture left to right at each line
+ for(x = 0; x < 640; x++)
+ {
+ //get colorref value from coordinates
+ pixelcoord[x][y] = 0;
+ }
+ }
+
+ //check pixels - start at line 0
+ for(y = 0; y < myheight; y++)
+ {
+ //go across picture left to right at each line
+ for(x = 0; x < mywidth; x++)
+ {
+ //get colorref value from coordinates
+ pixelcoord[x][y] = GetPixel(hMaskDC, x, y);
+
+ //if not a black pixel then increment counter
+ if(pixelcoord[x][y] != 0)
+ {
+ difference++;
+ }
+ }
+ }
+
+ // release resources
+ delete [] pixelcoord;
+ DeleteDC(hMaskDC);
+ DeleteDC(hImageDC);
+ DeleteObject(hMaskBitmap);
+ DeleteObject(hImageBitmap);
+
+ if (m_pDib)
+ {
+ delete [] m_pDib;
+ m_pDib = NULL;
+ }
+
+ if (m_pDib2)
+ {
+ delete [] m_pDib2;
+ m_pDib2 = NULL;
+ }
+
+ //now calculate percentage of pic that is not black
+ finalpercentage = ((difference / totalpixelarea) * 100);
+
+ // write conversion info to file
+
+
+ CString cBuffer;
+ cBuffer.Format(_T("Margin %ld : Difference %f"), margin, finalpercentage);
+ pLogFile->Set(cBuffer);
+
+ if(finalpercentage > margin)
+ return pLogFile->Set(VERIFICATION_FAILURE);
+
+ return pLogFile->Set(VERIFICATION_PASS);
+}
+
+
+//----------------------------------------------------------------------------
+//image loading for current new image
+bool CSTATImageVerify::LoadNewImage(CString& newimage)
+{
+ CFile cf;
+
+ // Attempt to open the Dib file for reading.
+ if(!cf.Open(newimage, CFile::modeRead))
+ return false;
+
+ // Get the size of the file and store
+ // in a local variable. Subtract the
+ // size of the BITMAPFILEHEADER structure
+ // since we won't keep that in memory.
+ DWORD dwDibSize;
+ dwDibSize = cf.GetLength() - sizeof( BITMAPFILEHEADER );
+
+ // Attempt to allocate the Dib memory.
+ unsigned char *pDib;
+ pDib = new unsigned char [dwDibSize];
+ if(!pDib)
+ {
+ cf.Close();
+ return false;
+ }
+
+ BITMAPFILEHEADER BFH;
+
+ // Read in the Dib header and data.
+ try
+ {
+ // Did we read in the entire BITMAPFILEHEADER?
+ if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )
+ != sizeof( BITMAPFILEHEADER ) ||
+
+ // Is the type 'MB'?
+ BFH.bfType != 'MB' ||
+
+ // Did we read in the remaining data?
+ cf.Read( pDib, dwDibSize ) != dwDibSize )
+ {
+
+ // Delete the memory if we had any
+ // errors and return FALSE.
+ delete [] pDib;
+ cf.Close();
+ return false;
+ }
+ }
+
+ // If we catch an exception, delete the
+ // exception, the temporary Dib memory,
+ // and return FALSE.
+ catch( CFileException *e )
+ {
+ e->Delete();
+ delete [] pDib;
+ cf.Close();
+ return( FALSE );
+ }
+
+ // If we got to this point, the Dib has been
+ // loaded. If a Dib was already loaded into
+ // this class, we must now delete it.
+ if (m_pDib2)
+ {
+ delete [] m_pDib2;
+ m_pDib2 = NULL;
+ }
+
+ // Store the local Dib data pointer and
+ // Dib size variables in the class member
+ // variables.
+ m_pDib2 = pDib;
+ m_dwDibSize2 = dwDibSize;
+
+ // Pointer our BITMAPINFOHEADER and RGBQUAD
+ // variables to the correct place in the Dib data.
+ m_pBIH2 = (BITMAPINFOHEADER *) m_pDib2;
+ m_pPalette2 =
+ (RGBQUAD *) &m_pDib2[sizeof(BITMAPINFOHEADER)];
+
+ // Calculate the number of palette entries.
+ m_nPaletteEntries = 1 << m_pBIH2->biBitCount;
+ if( m_pBIH2->biBitCount > 8 )
+ m_nPaletteEntries = 0;
+ else if( m_pBIH2->biClrUsed != 0 )
+ m_nPaletteEntries = m_pBIH2->biClrUsed;
+
+ // Point m_pDib2Bits to the actual Dib bits data.
+ m_pDibBits2 =
+ &m_pDib2[sizeof(BITMAPINFOHEADER)+
+ m_nPaletteEntries*sizeof(RGBQUAD)];
+
+ // If we have a valid palette, delete it.
+ if( m_Palette.GetSafeHandle() != NULL )
+ m_Palette.DeleteObject();
+
+ // If there are palette entries, we'll need
+ // to create a LOGPALETTE then create the
+ // CPalette palette.
+ if( m_nPaletteEntries != 0 )
+ {
+ // Allocate the LOGPALETTE structure.
+ LOGPALETTE *pLogPal = (LOGPALETTE *) new char [sizeof(LOGPALETTE) + m_nPaletteEntries*sizeof(PALETTEENTRY)];
+ if (pLogPal)
+ {
+ // Set the LOGPALETTE to version 0x300
+ // and store the number of palette
+ // entries.
+ pLogPal->palVersion = 0x300;
+ pLogPal->palNumEntries = (WORD)m_nPaletteEntries;
+
+ // Store the RGB values into each
+ // PALETTEENTRY element.
+ for( int i=0; i<m_nPaletteEntries; i++ )
+ {
+ pLogPal->palPalEntry[i].peRed =
+ m_pPalette2[i].rgbRed;
+ pLogPal->palPalEntry[i].peGreen =
+ m_pPalette2[i].rgbGreen;
+ pLogPal->palPalEntry[i].peBlue =
+ m_pPalette2[i].rgbBlue;
+ }
+
+ // Create the CPalette object and
+ // delete the LOGPALETTE memory.
+ m_Palette.CreatePalette( pLogPal );
+ delete [] pLogPal;
+ }
+ else
+ return false;
+ }
+
+ cf.Close();
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+//image loading for current reference image
+bool CSTATImageVerify::LoadRefImage()
+{
+ CFile cf;
+ if( !cf.Open(refimagearray[lastrefimageloaded].completefilenamepath, CFile::modeRead ) )
+ return false;
+
+ // Get the size of the file and store
+ // in a local variable. Subtract the
+ // size of the BITMAPFILEHEADER structure
+ // since we won't keep that in memory.
+ DWORD dwDibSize;
+ dwDibSize = cf.GetLength() - sizeof( BITMAPFILEHEADER );
+
+ // Attempt to allocate the Dib memory.
+ unsigned char *pDib;
+ pDib = new unsigned char [dwDibSize];
+ if(!pDib)
+ {
+ cf.Close();
+ return false;
+ }
+
+ BITMAPFILEHEADER BFH;
+
+ // Read in the Dib header and data.
+ try
+ {
+
+ // Did we read in the entire BITMAPFILEHEADER?
+ if( cf.Read( &BFH, sizeof( BITMAPFILEHEADER ) )
+ != sizeof( BITMAPFILEHEADER ) ||
+
+ // Is the type 'MB'?
+ BFH.bfType != 'MB' ||
+
+ // Did we read in the remaining data?
+ cf.Read( pDib, dwDibSize ) != dwDibSize )
+ {
+
+ // Delete the memory if we had any
+ // errors and return FALSE.
+ delete [] pDib;
+ cf.Close();
+ return false;
+ }
+ }
+
+ // If we catch an exception, delete the
+ // exception, the temporary Dib memory,
+ // and return FALSE.
+ catch( CFileException *e )
+ {
+ e->Delete();
+ delete [] pDib;
+ cf.Close();
+ return false;
+ }
+
+ // If we got to this point, the Dib has been
+ // loaded. If a Dib was already loaded into
+ // this class, we must now delete it.
+ if(m_pDib)
+ {
+ delete m_pDib;
+ m_pDib = NULL;
+ }
+
+ // Store the local Dib data pointer and
+ // Dib size variables in the class member
+ // variables.
+ m_pDib = pDib;
+ m_dwDibSize = dwDibSize;
+
+ // Pointer our BITMAPINFOHEADER and RGBQUAD
+ // variables to the correct place in the Dib data.
+ m_pBIH = (BITMAPINFOHEADER *) m_pDib;
+ m_pPalette =
+ (RGBQUAD *) &m_pDib[sizeof(BITMAPINFOHEADER)];
+
+ // Calculate the number of palette entries.
+ m_nPaletteEntries = 1 << m_pBIH->biBitCount;
+ if( m_pBIH->biBitCount > 8 )
+ m_nPaletteEntries = 0;
+ else if( m_pBIH->biClrUsed != 0 )
+ m_nPaletteEntries = m_pBIH->biClrUsed;
+
+ // Point m_pDibBits to the actual Dib bits data.
+ m_pDibBits =
+ &m_pDib[sizeof(BITMAPINFOHEADER)+
+ m_nPaletteEntries*sizeof(RGBQUAD)];
+
+ // If we have a valid palette, delete it.
+ if (m_Palette.GetSafeHandle())
+ m_Palette.DeleteObject();
+
+ // If there are palette entries, we'll need
+ // to create a LOGPALETTE then create the
+ // CPalette palette.
+ if( m_nPaletteEntries != 0 )
+ {
+ // Allocate the LOGPALETTE structure.
+ LOGPALETTE *pLogPal = (LOGPALETTE *) new char
+ [sizeof(LOGPALETTE)+
+ m_nPaletteEntries*sizeof(PALETTEENTRY)];
+
+ if(pLogPal)
+ {
+
+ // Set the LOGPALETTE to version 0x300
+ // and store the number of palette
+ // entries.
+ pLogPal->palVersion = 0x300;
+ pLogPal->palNumEntries = (WORD)m_nPaletteEntries;
+
+ // Store the RGB values into each
+ // PALETTEENTRY element.
+ for( int i=0; i<m_nPaletteEntries; i++ )
+ {
+ pLogPal->palPalEntry[i].peRed =
+ m_pPalette[i].rgbRed;
+ pLogPal->palPalEntry[i].peGreen =
+ m_pPalette[i].rgbGreen;
+ pLogPal->palPalEntry[i].peBlue =
+ m_pPalette[i].rgbBlue;
+ }
+
+ // Create the CPalette object and
+ // delete the LOGPALETTE memory.
+ m_Palette.CreatePalette( pLogPal );
+ delete [] pLogPal;
+ }
+ else
+ return false;
+ }
+
+ cf.Close();
+
+ return true;
+}
+
+//----------------------------------------------------------------------------
+int CSTATImageVerify::EnableVerification(int fudge)
+{
+ // temp variable
+ FILETIME creationtime;
+ creationtime.dwLowDateTime = 0;
+ creationtime.dwHighDateTime = 0;
+
+ // initialise settings
+ iImageCount = 0;
+ lastrefimageloaded = 0;
+ margin = fudge;
+
+ // check limits
+ if (margin < 0)
+ margin = 0;
+ if (margin > 100)
+ margin = 100;
+
+ // populate our array with images
+ CFileFind refimagefinder;
+ if (refimagefinder.FindFile(referenceimagedir + _T("\\*.bmp"), 0))
+ {
+ int i = 0;
+ int iMoreFiles = true;
+ for (i=0;i<VERIFY_MAX_IMAGES;i++)
+ {
+ if (iMoreFiles)
+ {
+ iMoreFiles = refimagefinder.FindNextFile();
+ refimagearray[i].completefilenamepath = refimagefinder.GetFilePath(); //store filename into array string variable
+ refimagefinder.GetLastWriteTime(&creationtime); //store corresponding modification time
+ refimagearray[i].lCreationTime = (((ULONGLONG) creationtime.dwHighDateTime) << 32) + creationtime.dwLowDateTime;
+ iImageCount++;
+ }
+ else
+ {
+ refimagearray[i].completefilenamepath = _T("");
+ refimagearray[i].lCreationTime = 0;
+ }
+ }
+
+ refimagefinder.Close();
+ }
+
+ // now sort into date/time order
+ if (iImageCount)
+ {
+ CSTATReferenceImages temp;
+ bool bNotFinished = true;
+ int i = 0;
+ while (bNotFinished)
+ {
+ bNotFinished = false;
+ for (i=0;i<iImageCount;i++)
+ {
+ if ((i + 1) < iImageCount &&
+ refimagearray[i+1].lCreationTime < refimagearray[i].lCreationTime)
+ {
+ temp = refimagearray[i];
+ refimagearray[i]= refimagearray[i+1];
+ refimagearray[i+1]= temp;
+ bNotFinished = true;
+ }
+ }
+ }
+ }
+
+ return iImageCount;
+}
+//----------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Get the local reference image directory from the registry
+int CSTATImageVerify::Initialise(const CString& path)
+{
+ int ret = ERROR_REGISTRY;
+ TCHAR szFullPath[256 + 1];
+
+
+ _tcsncpy(szFullPath, path.operator LPCTSTR(), path.GetLength() + 1);
+
+ //append ref images directory to the stat installation directory as found in registry
+ _tcscat(szFullPath, _T("\\Reference Images"));
+ referenceimagedir = szFullPath;
+
+ // try to create in case it doesn't exist
+ CreateDirectory(referenceimagedir, NULL);
+
+ // there may be old files to delete...
+ _tcscat(szFullPath, _T("\\*.*"));
+ CFileFind finder;
+ if (finder.FindFile(szFullPath, 0))
+ {
+ int iWorking = 1;
+ int filecount = 0;
+ while (iWorking)
+ {
+ iWorking = finder.FindNextFile();
+
+ // skip . and .. files
+ if (finder.IsDots())
+ continue;
+
+ filecount++;
+ }
+
+ finder.Close();
+
+ if (filecount)
+ ret = REFDIR_FOUND;
+ else
+ ret = ITS_OK;
+ }
+ else
+ ret = LOG_DIR_CREATE_FAILURE;
+
+
+
+ return ret;
+}
+
+//----------------------------------------------------------------------------
+//reference images copied over to local machine
+int CSTATImageVerify::CopyReferenceImages(LPTSTR refimagelocation)
+{
+ int ret = GENERAL_FAILURE;
+
+ // need to copy into null terminated string to have 2 nulls at end as required
+ TCHAR szFrom[MAX_PATH + 1] = {0};
+ _tcscpy(szFrom, refimagelocation);
+ _tcscat(szFrom, _T("\\*.bmp"));
+
+ // need to copy into null terminated string to have 2 nulls at end as required
+ TCHAR szTo[MAX_PATH + 1] = {0};
+ _tcscpy(szTo, referenceimagedir);
+
+ //new file structure for copying files
+ SHFILEOPSTRUCT fo = {0};
+ fo.wFunc = FO_COPY;
+ fo.pFrom = szFrom;
+ fo.pTo = szTo;
+ fo.fFlags = FOF_NOCONFIRMATION | FOF_SILENT;
+
+ //copy new images across
+ if(::SHFileOperation(&fo) != 0) //if fail file operation
+ return ERR_FILE_COPY_FAILED;
+
+ // check that at least 1 bitmap image got copied across
+ _tcscat(szTo, _T("\\*.bmp"));
+ CFileFind finder;
+ ret = finder.FindFile(szTo, 0);
+ finder.Close();
+ if (!ret)
+ return NO_BITMAPS;
+
+ return ITS_OK;
+}
+
+//----------------------------------------------------------------------------
+//local reference images deleted from local machine
+int CSTATImageVerify::DeleteReferenceImages()
+{
+ // need to copy into null terminated string to have 2 nulls at end as required
+ TCHAR szImages[MAX_PATH + 1] = {0};
+ _tcscpy(szImages, referenceimagedir);
+ _tcscat(szImages, _T("\\*.*"));
+
+ //new file structure for deleting files
+ SHFILEOPSTRUCT fo2 = {0};
+ fo2.wFunc = FO_DELETE;
+ fo2.pFrom = szImages;
+ fo2.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_FILESONLY | FOF_NOERRORUI;
+
+ //delete
+ if(::SHFileOperation(&fo2) != 0) //if fail file deletion
+ return DELETEIMAGES_FAILURE;
+
+ return ITS_OK;
+}
+