skip to Main Content

Using VS2022, C#, Blazor and jquery the code first loads a "C:ImagesdefaultImage.png" into a canvas region in the page:

 <canvas id="CanvasId" @ref="canvasElement"></canvas>

 await JS.InvokeVoidAsync("loadImageOnCanvas", "CanvasId", "/scripts/defaultImage.png");

Then at certain point, I need to know if the image in the canvas is still the same as the one first loaded (the defaultImage,png) meaning it has not been modified by the user.
NOTE: It is a simple image in black and white and only 27KB size 241px x 154px.

To check it, I use the code below but when both are compared
they are never equal. The one from the canvas is always a bit bigger in size, around 1k.

// Retrieve the image that was loaded on canvas
var canvasImage = await JS.InvokeAsync<string>("captureCanvasImage", "CanvasId");
canvasImage = canvasImage.Replace("data:image/png;base64,", String.Empty);
               
// byte[27980]
byte[] imageOnCanvas_Bytes = Convert.FromBase64String(canvasImage);
    
// byte[26978]
byte[] defaultImage_Bytes = File.ReadAllBytes("wwwroot/scripts/defaultImage.png");
                    
// Compare as string returns FALSE  
var result = canvasImage == Convert.ToBase64String(defaultImage_Bytes);
                     
// Compare byte arrays returns FALSE
var result2 = imageOnCanvas_Bytes.SequenceEqual(defaultImage_Bytes);

2

Answers


  1. Comparing two images in this context can be tricky and maybe it can get complex overtime.

    If you are handling the modification events (uploading a new image to the canvas, click or drag event, etc…), you can workaround all of this by defining a history of changes, meaning each event you’re concerned to handle should add a new element to a List<string> ChangeHistory for example. Thus, an image is edited in the canvas only if ChangeHistory has elements.

    this separates the concern of "what has been modified" from "it has been modified", and also (slightly for your situation) improves the overall performance without needing to make comparisons.

    Visual Studio itself uses a similar approach for determining if it should show you the (*) on your class name tab if it’s been modified. for example, if you type in a character in your code, VS automatically shows the asterisk, the asterisk won’t go away if you simply delete the character but only if you click in Undo (or ctrl+Z). That’s because the VS does not compare, but holds a history of modification events.

    HTH.

    Login or Signup to reply.
  2. If you want to compare pixel values you probably want to extract the actual pixel data, and not just compare the file-bytes. Image files may change if it is resaved, even if the pixels is identical. Not sure if this is your actual problem, but it might be worth a try.

    To get the pixel data you should be able to use something like this:

    var decoder = new PngBitmapDecoder(
        myStream,
        BitmapCreateOptions.PreservePixelFormat,
        BitmapCacheOption.OnLoad);
    var frame = decoder.Frames[0];
    var width = frame.PixelWidth;
    var height = frame.PixelHeight;
    
    var bytesPerPixel = frame.Format.BitsPerPixel / 8;
    var stride = bytesPerPixel * width;
    while (stride % 4 != 0) stride++; // Make stride an even multiple of four
    var data = new byte[stride * height];
    frame.CopyPixels(data, stride, 0);
    

    Where myStream is either a file stream or memory stream containing the bytes for the file.

    This should handle any changes to metadata in the file, but will not handle any change to the actual pixels. If you need to handle changes things will quickly get complicated. There are several possible similarity metrics, but it is nor really possible to recommend anything without understanding the type of changes you need to handle.

    A possibly better approach is to attach some kind of versioning data to the image to track changes, but I don’t know enough about Blazor, nor your use case, to recommend anything specific.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search