确定系统剪贴板图像是否相等
我不确定我的问题是否特定于平台,但我认为不是。
因为我的经验是基于 Windows 特定的 java.awt.Toolkit 和 Windows-Clipboard。
以下示例类显示了我面临的问题。
注意:在运行程序之前,请确保系统剪贴板中没有图像。
如果系统剪贴板中没有图像,程序将向其添加新的屏幕截图。
然后我得到剪贴板数据两次!
所有 3 个图像都是相同的! - 原始屏幕截图和我从剪贴板获得的每张图像。
没问题。
但是现在第二次运行该程序。 注意:剪贴板中有旧的屏幕截图!
该程序会生成一张新的屏幕截图,并从剪贴板中获取旧的屏幕截图两次。
没有图像等于任何图像! - 第一个(新屏幕截图)应该不相等,没关系
但是我得到的每个下一个图像都不相等。
Q1:如果我得到的下一个图像不相等,为什么第一次是相等的?
Q2:更大的问题:如何比较java.awt.Image
以使下一个图像相等。
我正在寻找一种简单快速地比较两个图像的方法,或者一种简单的方法来确定剪贴板没有改变。
public class Example {
public static void main( String[] args ) throws Exception {
final Toolkit toolkit = Toolkit.getDefaultToolkit();
final Clipboard clipboard = toolkit.getSystemClipboard();
final Image origImage = new Robot().createScreenCapture( new Rectangle( toolkit.getScreenSize() ) );
if( !clipboard.isDataFlavorAvailable( DataFlavor.imageFlavor )
|| clipboard.getData( DataFlavor.imageFlavor ) == null ) {
clipboard.setContents( new ImageSelection( origImage ), null );
}
Image clipImage1 = (Image)clipboard.getData( DataFlavor.imageFlavor );
Image clipImage2 = (Image)clipboard.getData( DataFlavor.imageFlavor );
System.out.println(origImage.hashCode());
System.out.println(clipImage1.hashCode());
System.out.println(clipImage2.hashCode());
System.out.println(clipImage1.equals( clipImage2 ));
}
public static class ImageSelection implements Transferable {
private Image image;
public ImageSelection(Image image) {
this.image = image;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DataFlavor.imageFlavor};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
}
}
I am not sure if my problem is platform specific, but I think it is not.
Because my expirience is based on the Windows specific java.awt.Toolkit
and the Windows-Clipboard.
The following example class shows the problem i am faced with.
NOTE: Before running the program, make sure you have no Image in you system clipboard.
If there is no Image in the system clipboard the Program put a new screenshot to it.
Then I get the Clipboard data two times!
All 3 Images are equal! - the original Screenshot and every Image I get from the clipboard.
which is ok.
But now running the program a second time.
NOTE: There is the old screenshot in the clipboard!
The Program generates a new screenshot and get the old one from the clipboard two times.
No Images is equal to any! - The first (new screenshot) should be not equal, it is okay
But every next Image I get is not equal.
Q1: If every next Image I get is not equal, why it was equal at the first time?
Q2: The bigger Question: How can I compare a java.awt.Image
to get every next Image equal.
I am looking for an easy and fast comparison of two Images or an easy way to figure out that the clipboard doesn't has changed.
public class Example {
public static void main( String[] args ) throws Exception {
final Toolkit toolkit = Toolkit.getDefaultToolkit();
final Clipboard clipboard = toolkit.getSystemClipboard();
final Image origImage = new Robot().createScreenCapture( new Rectangle( toolkit.getScreenSize() ) );
if( !clipboard.isDataFlavorAvailable( DataFlavor.imageFlavor )
|| clipboard.getData( DataFlavor.imageFlavor ) == null ) {
clipboard.setContents( new ImageSelection( origImage ), null );
}
Image clipImage1 = (Image)clipboard.getData( DataFlavor.imageFlavor );
Image clipImage2 = (Image)clipboard.getData( DataFlavor.imageFlavor );
System.out.println(origImage.hashCode());
System.out.println(clipImage1.hashCode());
System.out.println(clipImage2.hashCode());
System.out.println(clipImage1.equals( clipImage2 ));
}
public static class ImageSelection implements Transferable {
private Image image;
public ImageSelection(Image image) {
this.image = image;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DataFlavor.imageFlavor};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return DataFlavor.imageFlavor.equals(flavor);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
if (!DataFlavor.imageFlavor.equals(flavor)) {
throw new UnsupportedFlavorException(flavor);
}
return image;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Q1:第一种情况下的对象引用是相同的。
Q2:这里有一种方法可以检查屏幕截图中的数据是否相等:
Q1: The object references were the same in the first case.
Q2: here is a way to check the data is equal in the screen shots:
除了克林特的回答之外,如果你想比较它们,你还必须将剪贴板图像转换为 BufferedImage。
使用此方法将两个图像转换为 BufferedImages 并按照 Clint 发布的方式对它们进行比较。
In addition to Clint his answer, you have to convert the clipboard Image to a BufferedImage, if you want to compare them.
Use this method to convert the two Images to BufferedImages and compare them the way Clint posted.
如果你想比较屏幕,有几种方法,
,你甚至可以将该数组保存在 pngs/jpg 中以检查逻辑有什么问题。
输出为“
如果您能进一步澄清上下文,您可能会得到更多回复”。例如,是否用于远程桌面共享等。
If you want to compare screens, there are couple of ways,
And you can even save that arrays in pngs/jpg to check what is wrong with the logic.
The output comes as
If you would have clarified the context more , you might have got more replies. For example, Is it for remote desktop sharing etc etc ..
好吧,我看了一下我们在 IDE 中使用的 JDK 背后的源代码(恰好是 IBM JDK)。
java.awt.Image
看起来像是一个抽象类,并且 equals 没有在其中定义(请检查您的 JDK 以确保)。既然是这种情况,要么子类必须实现 equals,要么我们依靠 java.lang.Object.equals(java.lang.Object),根据我们的 JDK 将equals
方法实现为返回这个==arg
。再次,请使用您的 JDK 验证这一点。但如果您的 JDK 和我们的 JDK 在实现上“匹配”,我猜测会发生以下情况。如果使用
Object
equals
,那么我猜测第一次通过你的程序时,JVM 会跟踪剪贴板上的对象并可以知道它们是相同的图像。但是当 JVM 终止然后重新启动时,它无法再知道它们是否是同一个对象。因此,它为它们分配不同的内存空间(即引用)作为不同的对象,因此它们不再相等。当然,不知道使用了哪些子类,或者您的 JDK/JVM 的实现方式是否不同,我不能完全确定这一点。但这似乎很有可能,特别是因为剪贴板在技术上位于 JVM 之外,并且是通过 JVM 访问的。如果已经存在某些东西,JVM 如何判断什么是相等的,什么是不相等的?除非有人实现一种依赖于操作系统知识的方法来判断,否则我猜它不能。
因此,这意味着您最好实施自己的解决方案,克林特似乎对此很擅长。
Well, I took a peek at the source code behind the JDK we use in our IDE (which happens to be an IBM JDK).
java.awt.Image
looks like it is an abstract class and equals is not defined in it (please check your JDK to be sure). Since this is the case, either a subclass must implementequals
, or we fall back onjava.lang.Object.equals(java.lang.Object)
, which according to our JDK implements theequals
method asreturn this == arg
.Again, please validate this with your JDK. But here is what I would surmise would happen should your JDK and ours "match" on implementation. If the
Object
equals
is used, then I'm guessing that the first time through your program, the JVM keeps track of the objects on the Clipboard and can tell that they are the same image. But when the JVM terminates and then restarts, it can no longer know if those were the same object or not. Therefore it assigns them different memory spaces (ie, references) as different objects and thus they no longer equal anymore.Of course not knowing what subclasses are used or if your JDK/JVM is implemented differently, I can't say that with full certainty. But it seems highly likely, especially since the Clipboard is technically outside of the JVM and is accessed through the JVM. How can the JVM tell what is and is not equal if there is something already there? Unless somebody implements a way to tell that relies on knowledge of the OS, I'm guessing it can't.
So that means you are best off implementing your own solution, of which Clint seems to have a good crack at it.