简体   繁体   中英

Comparing two images from the clipboard class

In a C# winform app. I'm writing a Clipboard log manager that logs text to a log file, (everytime a Ctrl+c/x is pressed the copied/cut text gets appended to the file) I also did the same for images, that is, if you press "prtScreen", the screen shot you took will also go to a folder.

I do that by using a timer, inside I have something which 'looks' like this:

if (Clipboard.ContainsImage())
{
  if (IsClipboardUpdated())
  {
    LogData();
    UpdateLastClipboardData();
  }
}

This is how the rest of the methods look like:

public void UpdateLastClipboardData()
{
  // ... other updates
  LastClipboardImage = Clipboard.GetImage();
}
// This is how I determine if there's a new image in the clipboard...
public bool IsClipboardUpdated()
{
  return (LastClipboardImage != Clipboard.GetImage());
}
public void LogData()
{
  Clipboard.GetImage().Save(ImagesLogFolder + "\\Image" + now_hours + "_" + now_mins + "_" + now_secs + ".jpg");  
}

The problem is: inside the update method, "LastClipboardImage != Clipboard.GetImage()" is always returning true!

I even did the following inside the update method:

Image img1 = Clipboard.GetImage();
Image img2 = Clipboard.GetImage();
Image img3 = img2;
bool b1 = img1 == img2; // this returned false. WHY??
bool b2 = img3 == img2; // this returned true. Makes sense.

Please help, the comparison isn't working... why?

A little test. Call two times the GetImage method for the same image

void Main()
{
    Image bmp1 = Clipboard.GetImage();
    Image bmp2 = Clipboard.GetImage();

    if(bmp1 != null && bmp1 == bmp2)
        Console.WriteLine("True");
    else
        Console.WriteLine("False");
}

it returns always false. So every time you call Clipboard.GetImage() you get a different image instance and thus you cannot compare then using a simple == operator

You are comparing two different instances of an Image object and of course they are not the same.

If you really want to compare the image down to the pixel level you need a more invasive (and performance hungry method) like this

bool ImagesAreDifferent(Image img1, Image img2)
{
    Bitmap bmp1 = new Bitmap(img1);
    Bitmap bmp2 = new Bitmap(img2);

    bool different = false;
    if (bmp1.Width == bmp2.Width && bmp1.Height == bmp2.Height)
    {
        for (int i = 0; i < bmp1.Width; i++)
        {
            for (int j = 0; j < bmp1.Height; j++)
            {
                Color col1 = bmp1.GetPixel(i, j);
                Color col2 = bmp2.GetPixel(i, j);
                if (col1 != col2)
                {
                    i = bmp1.Width + 1;
                    different = true;
                    break;
                }
            }
        }
    }    
    return different;
}

Notice how this is possible because the Color structure defines an Equality operator that checks if the color RGB values are the same between two colors

Image checks equality with the Object.equals , which tests for reference equality with reference types, not semantic equality. This is why img2 == img3 is true , as you have previously copied img2 's reference into img3 . However, for img1 and img2 , you called Clipboard.GetImage which constructs a new image object.

If you actually want to test if two image objects contain the same data, you will need to write your own method - perhaps an extension method if you don't want to subclass Image .

public static class ImageExtensions
{
    public static bool MyEquals(this Image x, Image y)
    {
        // compute and return your definition of equality here
    }
}

Note that the == operator will not call this method automatically, and you will have to check equality with Image.MyEquals .

I think rather than comparing images you can change the program logic to overcome this problem. How about capture event of new item added to clipboard and write in to log?

you can try code sample code from below link

http://www.codeproject.com/Tips/467361/Using-Clipboard-Csharp-4-0-Wrapper-inside

// Use the "ClipboardManager" to manage in a more comprehensive the clipboard
// I assume that "this" is a Form
ClipboardManager manager = new ClipboardManager(this);
// Use "All" to handle all kinds of objects from the clipboard
// otherwise use "Files", "Image" or "Text"
manager.Type = ClipboardManager.CheckType.All;
// Use events to manage the objects in the clipboard
manager.OnNewFilesFound += (sender, eventArg) => 
{
    foreach (String item in eventArg)
    {
        Console.WriteLine("New file found in clipboard : {0}", item);
    }
};
manager.OnNewImageFound += (sender, eventArg) =>
{
    Console.WriteLine("New image found in clipboard -> Width: {0} , Height: {1}", 
                      eventArg.Width, eventArg.Height);
};
manager.OnNewTextFound += (sender, eventArg) =>
{
    Console.WriteLine("New text found in clipboard : {0}", eventArg);
};
// Use the method "StartChecking" to start capturing objects in the clipboard
manager.StartChecking();
// Close the capturing
manager.Dispose();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM