// ImageCmp.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "ImageSimilar.h"
#include <iostream>
#include <Psapi.h>

int _tmain(int argc, _TCHAR* argv[])
{
ImageSimilar::initGdiPlus();

HANDLE h = GetCurrentProcess();
for (int i = 1; i <= 100; ++i)
{
PROCESS_MEMORY_COUNTERS mem = { 0 };
GetProcessMemoryInfo(h, &mem, sizeof(mem));
int memSize = mem.WorkingSetSize / 1024 * 1024;

auto start = std::chrono::system_clock::now();

float val = ImageSimilar::getSimilar("1.png", "2.png");

auto end = std::chrono::system_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
double cost = double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den;
std::cout << "val=" << val << " 耗时:" << cost << "秒" << " memSize=" << memSize<< std::endl;
}

ImageSimilar::unInitGdiPlus();
getchar();
return 0;
}
#include <iostream>
#include <fstream>
#include <string>
#include <chrono>
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;

namespace ImageSimilar
{
typedef struct tagIStreamBmp
{
IStream *pIStream;
Bitmap *pBitmap;
tagIStreamBmp()
{
pIStream = NULL;
}
}SIStreamBmp, *PSIStreamBmp;

GdiplusStartupInput gdiplusstartupinput;
ULONG_PTR gdiplustoken;

void initGdiPlus()
{
GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);
}

void unInitGdiPlus()
{
GdiplusShutdown(gdiplustoken);
}

bool getStreamBmp(SIStreamBmp& iStreamBmp, char* szData, int dataLen)
{
HGLOBAL hMemBmp = GlobalAlloc(GMEM_FIXED, dataLen);
if (hMemBmp == NULL) return false;
CreateStreamOnHGlobal(hMemBmp, TRUE, &iStreamBmp.pIStream);
if (iStreamBmp.pIStream == NULL)
{
return false;
}
BYTE* bData = (BYTE *)GlobalLock(hMemBmp); // 获得内存块首地址
memcpy(bData, szData, dataLen);
GlobalUnlock(hMemBmp);

iStreamBmp.pBitmap = Bitmap::FromStream(iStreamBmp.pIStream);

//GlobalFree(hMemBmp); // 需要释放吗?
return true;
}

int getFileSize(char* szFile)
{
size_t size = 0;
std::ifstream f;
f.open(szFile, std::ios::binary | std::ios::in);
if (f.is_open())
{
f.seekg(0, std::ios::end);
size = f.tellg();
f.close();
}
return size;
}

float getSimilar2(char* szData1, int dataLen1, char* szData2, int dataLen2)
{
if (szData1 == NULL || dataLen1 <= 0) return 0;
if (szData2 == NULL || dataLen2 <= 0) return 0;

SIStreamBmp sBmp1;
SIStreamBmp sBmp2;
if (!getStreamBmp(sBmp1, szData1, dataLen1)) return 0;
if (!getStreamBmp(sBmp2, szData2, dataLen2)) return 0;

if (sBmp1.pBitmap->GetWidth() != sBmp2.pBitmap->GetWidth()) return 0;
if (sBmp1.pBitmap->GetHeight() != sBmp2.pBitmap->GetHeight()) return 0;

Gdiplus::Color c1;
Gdiplus::Color c2;

// 逐个像素比较
int xMax = sBmp1.pBitmap->GetWidth();
int yMax = sBmp1.pBitmap->GetHeight();
int same = 0;
for (size_t x = 0; x < xMax; x++)
{
for (size_t y = 0; y < yMax; y++)
{
sBmp1.pBitmap->GetPixel(x, y, &c1);
sBmp2.pBitmap->GetPixel(x, y, &c2);
if (c1.GetValue() == c2.GetValue())
{
same += 1;
}
}
}

delete sBmp1.pBitmap;
delete sBmp2.pBitmap;
//::delete sBmp1.pBitmap;
//::delete sBmp2.pBitmap;
sBmp1.pIStream->Release();
sBmp2.pIStream->Release();
return float(same) / float(xMax*yMax);
}

float getSimilar(char* szFile1, char* szFile2)
{
int size1 = getFileSize(szFile1);
int size2 = getFileSize(szFile2);
if (size1 <= 0) return 0;
if (size2 <= 0) return 0;
char* szData1 = new char[size1];
char* szData2 = new char[size2];
std::ifstream f1;
std::ifstream f2;
f1.open(szFile1, std::ios::binary | std::ios::in);
f2.open(szFile2, std::ios::binary | std::ios::in);
if (f1.is_open())
{
f1.read(szData1, size1);
f1.close();
}
if (f2.is_open())
{
f2.read(szData2, size2);
f2.close();
}
float val = getSimilar2(szData1, size1, szData2, size2);
if (szData1 != NULL) delete[] szData1;
if (szData2 != NULL) delete[] szData2;
return val;
}
}