using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Tango.ScreenCapture { public class ImageComparer { unsafe public Bitmap CreateDifferenceBitmap(Bitmap previousImage, Bitmap currentImage, Color matchColor) { if (previousImage == null | currentImage == null) throw new InvalidOperationException("Cannot compare image. They are the same instance"); if (previousImage.Height != currentImage.Height || previousImage.Width != currentImage.Width) throw new InvalidOperationException("Cannot compare image of different size."); Bitmap diffImage = currentImage.Clone() as Bitmap; int height = previousImage.Height; int width = previousImage.Width; BitmapData data1 = previousImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData data2 = currentImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData diffData = diffImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); byte* data1Ptr = (byte*)data1.Scan0; byte* data2Ptr = (byte*)data2.Scan0; byte* diffPtr = (byte*)diffData.Scan0; byte[] swapColor = new byte[4]; swapColor[0] = matchColor.B; swapColor[1] = matchColor.G; swapColor[2] = matchColor.R; swapColor[3] = matchColor.A; int rowPadding = data1.Stride - (previousImage.Width * 4); // iterate over height (rows) for (int i = 0; i < height; i++) { // iterate over width (columns) for (int j = 0; j < width; j++) { int same = 0; byte[] tmp = new byte[4]; // compare pixels and copy new values into temporary array for (int x = 0; x < 4; x++) { tmp[x] = data2Ptr[0]; if (data1Ptr[0] == data2Ptr[0]) { same++; } data1Ptr++; // advance image1 ptr data2Ptr++; // advance image2 ptr } // swap color or add new values for (int x = 0; x < 4; x++) { diffPtr[0] = (same == 4) ? swapColor[x] : tmp[x]; diffPtr++; // advance diff image ptr } } // at the end of each column, skip extra padding if (rowPadding > 0) { data1Ptr += rowPadding; data2Ptr += rowPadding; diffPtr += rowPadding; } } previousImage.UnlockBits(data1); currentImage.UnlockBits(data2); diffImage.UnlockBits(diffData); return diffImage; } unsafe public VectorDifferenceImage CreateDifferenceVector(Bitmap previousImage, Bitmap currentImage) { VectorDifferenceImage vector = new VectorDifferenceImage(previousImage.Width, previousImage.Height); if (previousImage == null | currentImage == null) throw new InvalidOperationException("Cannot compare image. They are the same instance"); if (previousImage.Height != currentImage.Height || previousImage.Width != currentImage.Width) throw new InvalidOperationException("Cannot compare image of different size."); int height = previousImage.Height; int width = previousImage.Width; BitmapData data1 = previousImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData data2 = currentImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte* data1Ptr = (byte*)data1.Scan0; byte* data2Ptr = (byte*)data2.Scan0; int rowPadding = data1.Stride - (previousImage.Width * 4); // iterate over height (rows) for (int i = 0; i < height; i++) { // iterate over width (columns) for (int j = 0; j < width; j++) { int same = 0; byte[] tmp = new byte[4]; // compare pixels and copy new values into temporary array for (int x = 0; x < 4; x++) { tmp[x] = data2Ptr[0]; if (data1Ptr[0] == data2Ptr[0]) { same++; } data1Ptr++; // advance image1 ptr data2Ptr++; // advance image2 ptr } if (same != 4) { vector.Pixels.Add(new VectorImagePixel() { X = (ushort)j, Y = (ushort)i, B = tmp[0], G = tmp[1], R = tmp[2], }); } } // at the end of each column, skip extra padding if (rowPadding > 0) { data1Ptr += rowPadding; data2Ptr += rowPadding; } } previousImage.UnlockBits(data1); currentImage.UnlockBits(data2); return vector; } } }