testtoolsconn/stat/desktop/source/lib/src/cstatimageverify.cpp
changeset 0 3da2a79470a7
--- /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;
+}
+