using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media.Imaging; using Tango.RemoteDesktop.Frames; namespace Tango.RemoteDesktop.Comparers { /// /// Represents a vector comparer which will compare and return a difference. /// /// public class VectorBitmapComparer : IBitmapComparer { /// /// When max number of differences reached, the comparer will immediately return the current difference frame. /// This should enforce the screen capture engine to report 'No Difference Available'. /// public long? MaxDifferencesThrow { get; set; } /// /// Creates the difference as . /// /// The previous bitmap. /// The current bitmap. /// /// /// Cannot compare image. They are the same instance /// or /// Cannot compare image of different size. /// public unsafe BitmapComparerResult CreateDifference(Bitmap previousBitmap, Bitmap currentBitmap) { VectorFrame vector = new VectorFrame(previousBitmap.Width, previousBitmap.Height); uint count = 0; if (previousBitmap == null | currentBitmap == null) throw new InvalidOperationException("Cannot compare image. They are the same instance"); if (previousBitmap.Height != currentBitmap.Height || previousBitmap.Width != currentBitmap.Width) throw new InvalidOperationException("Cannot compare image of different size."); int height = previousBitmap.Height; int width = previousBitmap.Width; BitmapData data1 = previousBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData data2 = currentBitmap.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 - (previousBitmap.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) { int colorIndex = vector.Colors.Count; VectorFrameColor color = new VectorFrameColor() { B = tmp[0], G = tmp[1], R = tmp[2], Index = colorIndex }; VectorFrameColor existingColor; if (vector.Colors.TryGetValue(color.ToInt32(), out existingColor)) { colorIndex = existingColor.Index; } else { vector.Colors.Add(color.ToInt32(), color); } vector.Pixels.Add(new VectorFramePixel() { X = j, Y = i, ColorIndex = colorIndex, Color = color }); count++; if (MaxDifferencesThrow != null && count > MaxDifferencesThrow.Value) { previousBitmap.UnlockBits(data1); currentBitmap.UnlockBits(data2); throw new MaxDifferencesReachedException(); } } } // at the end of each column, skip extra padding if (rowPadding > 0) { data1Ptr += rowPadding; data2Ptr += rowPadding; } } previousBitmap.UnlockBits(data1); currentBitmap.UnlockBits(data2); return new BitmapComparerResult() { Frame = vector, DifferenceCount = count }; } } }