212 lines
4.9 KiB
C++
212 lines
4.9 KiB
C++
|
/**************************************************************************
|
||
|
*
|
||
|
* Copyright (c) 2000 Microsoft Corporation
|
||
|
*
|
||
|
* Program Name:
|
||
|
*
|
||
|
* ImgDiff
|
||
|
*
|
||
|
* ImgDiff source_file_1 source_file_2 destination_file
|
||
|
*
|
||
|
* This will difference the two source files (provided they're the same size)
|
||
|
* and output the resulting image.
|
||
|
*
|
||
|
* Technically it does:
|
||
|
*
|
||
|
* CD[i] = | S1[i] - S2[i] |
|
||
|
*
|
||
|
* where i indexes the color channels rather than the pixels.
|
||
|
* because it's an abs computation, the input source file order is unimportant.
|
||
|
*
|
||
|
*
|
||
|
* Created:
|
||
|
*
|
||
|
* 06/25/2000 asecchia
|
||
|
* Created it.
|
||
|
*
|
||
|
**************************************************************************/
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <windows.h>
|
||
|
#include <objbase.h>
|
||
|
#include <gdiplus.h>
|
||
|
|
||
|
INT AsciiToUnicodeStr(
|
||
|
const CHAR* ansiStr,
|
||
|
WCHAR* unicodeStr,
|
||
|
INT unicodeSize
|
||
|
)
|
||
|
{
|
||
|
return( MultiByteToWideChar(
|
||
|
CP_ACP,
|
||
|
0,
|
||
|
ansiStr,
|
||
|
-1,
|
||
|
unicodeStr,
|
||
|
unicodeSize
|
||
|
) > 0 );
|
||
|
}
|
||
|
|
||
|
#define Fail() goto cleanup
|
||
|
|
||
|
void _cdecl main(int argc, char **argv)
|
||
|
{
|
||
|
|
||
|
if(argc<4)
|
||
|
{
|
||
|
printf("error - need source1 and source2 and destination filename\n");
|
||
|
printf("usage: ImgDiff srcfilename srcfilename dstfilename\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
using namespace Gdiplus;
|
||
|
|
||
|
Status status;
|
||
|
WCHAR source1[1024];
|
||
|
WCHAR source2[1024];
|
||
|
WCHAR outfilename[1024];
|
||
|
AsciiToUnicodeStr(argv[1], source1, 1024);
|
||
|
AsciiToUnicodeStr(argv[2], source2, 1024);
|
||
|
AsciiToUnicodeStr(argv[3], outfilename, 1024);
|
||
|
|
||
|
|
||
|
ImageCodecInfo* codecs = NULL;
|
||
|
UINT count;
|
||
|
UINT cbCodecs;
|
||
|
|
||
|
// Open the source images
|
||
|
|
||
|
Bitmap *srcBmp1 = new Bitmap(source1);
|
||
|
Bitmap *srcBmp2 = new Bitmap(source2);
|
||
|
|
||
|
// Ask the source image for it's size.
|
||
|
|
||
|
int width = srcBmp1->GetWidth();
|
||
|
int height = srcBmp1->GetHeight();
|
||
|
|
||
|
|
||
|
if( (width != (int)srcBmp2->GetWidth()) ||
|
||
|
(height != (int)srcBmp2->GetHeight()) )
|
||
|
{
|
||
|
printf("the two input files are different sizes\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
printf("Input images are (%d x %d)\n", width, height);
|
||
|
|
||
|
// Create a destination image to draw onto
|
||
|
|
||
|
Bitmap *dstBmp = new Bitmap(
|
||
|
width,
|
||
|
height,
|
||
|
PixelFormat32bppARGB
|
||
|
);
|
||
|
|
||
|
BitmapData bdSrc1;
|
||
|
BitmapData bdSrc2;
|
||
|
BitmapData bdDst;
|
||
|
|
||
|
Rect rect(0,0,width,height);
|
||
|
|
||
|
srcBmp1->LockBits(rect, ImageLockModeRead, PixelFormat32bppARGB, &bdSrc1);
|
||
|
srcBmp2->LockBits(rect, ImageLockModeRead, PixelFormat32bppARGB, &bdSrc2);
|
||
|
dstBmp->LockBits(rect, ImageLockModeWrite, PixelFormat32bppARGB, &bdDst);
|
||
|
|
||
|
int x, y;
|
||
|
|
||
|
unsigned char *s1, *s2, *d;
|
||
|
|
||
|
for(y = 0; y < (int)bdSrc1.Height; y++)
|
||
|
{
|
||
|
for(x = 0; x < (int)bdSrc1.Width; x++)
|
||
|
{
|
||
|
s1 = (unsigned char *)((ARGB*)(bdSrc1.Scan0) + x + y * bdSrc1.Width);
|
||
|
s2 = (unsigned char *)((ARGB*)(bdSrc2.Scan0) + x + y * bdSrc2.Width);
|
||
|
d = (unsigned char *)((ARGB*)(bdDst.Scan0) + x + y * bdDst.Width);
|
||
|
|
||
|
// per channel subtract.
|
||
|
|
||
|
d[0] = (unsigned char)abs(s1[0] - s2[0]);
|
||
|
d[1] = (unsigned char)abs(s1[1] - s2[1]);
|
||
|
d[2] = (unsigned char)abs(s1[2] - s2[2]);
|
||
|
d[3] = (unsigned char)abs(s1[3] - s2[3]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
srcBmp1->UnlockBits(&bdSrc1);
|
||
|
srcBmp2->UnlockBits(&bdSrc2);
|
||
|
dstBmp->UnlockBits(&bdDst);
|
||
|
|
||
|
// Now start finding a codec to output the image.
|
||
|
|
||
|
cbCodecs = 0;
|
||
|
GetImageEncodersSize(&count, &cbCodecs);
|
||
|
|
||
|
// Allocate space for the codec list
|
||
|
|
||
|
codecs = static_cast<ImageCodecInfo *>(malloc (cbCodecs));
|
||
|
|
||
|
if (codecs == NULL)
|
||
|
{
|
||
|
printf("error: failed to allocate memory for codecs\n");
|
||
|
Fail();
|
||
|
}
|
||
|
|
||
|
// Get the list of encoders
|
||
|
|
||
|
status = GetImageEncoders(count, cbCodecs, codecs);
|
||
|
|
||
|
if (status != Ok)
|
||
|
{
|
||
|
printf("Error: GetImageEncoders returned %d\n", status);
|
||
|
Fail();
|
||
|
}
|
||
|
|
||
|
// Search the codec list for the JPEG codec.
|
||
|
// Use the Mime Type field to specify the correct codec.
|
||
|
|
||
|
for(UINT i=0; i<count; i++) {
|
||
|
if(wcscmp(codecs[i].MimeType, L"image/bmp")==0) {break;}
|
||
|
}
|
||
|
|
||
|
if(i>=count)
|
||
|
{
|
||
|
fprintf(stderr, "failed to find the codec\n");
|
||
|
Fail();
|
||
|
}
|
||
|
|
||
|
// Output the image to disk.
|
||
|
|
||
|
CLSID tempClsID;
|
||
|
tempClsID = codecs[i].Clsid;
|
||
|
|
||
|
status = dstBmp->Save(
|
||
|
outfilename,
|
||
|
&tempClsID,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (status != Ok)
|
||
|
{
|
||
|
fprintf(stderr, "SaveImage--Save() failed\n");
|
||
|
Fail();
|
||
|
}
|
||
|
|
||
|
// We're golden - everything worked.
|
||
|
|
||
|
printf("Done\n");
|
||
|
|
||
|
|
||
|
// Clean up the objects we used.
|
||
|
|
||
|
cleanup:
|
||
|
|
||
|
|
||
|
free(codecs);
|
||
|
delete dstBmp;
|
||
|
delete srcBmp1;
|
||
|
delete srcBmp2;
|
||
|
}
|
||
|
|
||
|
|