【问题标题】:Possible bug in Java 8 Update 45 on Windows 8Windows 8 上的 Java 8 Update 45 中可能存在的错误
【发布时间】:2015-05-28 03:46:10
【问题描述】:

此代码获取输入图像并生成尺寸为两倍大的输出图像。内部循环中的前四行写入四个相同大小的原始副本,最后四行应该用两倍于原始大小的输入图像的一个副本覆盖小图像。

代码在 Windows 8 上的 Java 8 Update 45 上编译和运行没有错误。生成的图像与预期的不同,不是输入的大副本。输出的下半部分与预期的一样,但上半部分由循环内前两行写入的输入的两个原始大小副本组成。注释掉这两行会导致最初预期的结果,因此前两行似乎是最后执行的,而不是最先执行的,尽管在源代码中最先出现。

这是编译器错误、运行时的竞争条件还是代表我的大脑放屁?

如果需要,我会在某处提供示例。

import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
class HelloWorldApp {
    public static void main(String[] orgs) throws IOException {

        BufferedImage pic = ImageIO.read(new File("cat.jpg"));

        int w=pic.getWidth(),h=pic.getHeight();
        BufferedImage out = new BufferedImage(w+w,h+h,pic.getType());
        for (int y=0;y<h;y++) {
            for (int x=0;x<w;x++) {
                int pixel = pic.getRGB(x,y);
                // write four small copies
                out.setRGB(x    ,y    ,pixel); // these two lines apparently are
                out.setRGB(x+w  ,y    ,pixel); // executed after the remaining six
                out.setRGB(x    ,y+h  ,pixel);
                out.setRGB(x+w  ,y+h  ,pixel);
                // overwrite with one large copy
                out.setRGB(x+x  ,y+y  ,pixel);
                out.setRGB(x+x+1,y+y  ,pixel);
                out.setRGB(x+x  ,y+y+1,pixel);
                out.setRGB(x+x+1,y+y+1,pixel);
            }
        }

        ImageIO.write(out, "bmp", new File("./cat.bmp"));

    }
}

【问题讨论】:

  • 为什么不直接使用out.getGraphics().drawImage(pic, 0, 0, w * 2, h * 2, null) 而不是手动处理每个像素?
  • @BretC 我遇到了一个我不理解的可重现问题。假设我的代码是正确的,那将表明编译器存在令人担忧的问题。假设我的代码不正确,这表明我的大脑存在令人担忧的问题。另外,我计划做一些非常低级的图像处理。而且我还在学习,因为可以从类名中推断出来。 ;)

标签: java image rgb race-condition compiler-bug


【解决方案1】:

让我们尝试演示正在发生的事情。假设你的图片是:

┌───╥───┬────┐
│ ║ 0 │ 1 │
╞═══╬═══╪═══╡
│ 0 ║ A │ B │
├────╫────┼────┤
│ 1 ║ C │ D │
└────╨────┴────┘

对于 x=0,y=0,前四行之后:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ │ A │ │
├────╫────┼────┼────┼────┤
│ 1 ║ │ │ │ │
├────╫────┼────┼────┼────┤
│ 2 ║ A │ │ A │ │
├────╫────┼────┼────┼────┤
│ 3 ║ │ │ │ │
└────╨────┴────┴────┴────┘

最后四行之后:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ A │ A │ │
├────╫────┼────┼────┼────┤
│ 1 ║ A │ A │ │ │
├────╫────┼────┼────┼────┤
│ 2 ║ A │ │ A │ │
├────╫────┼────┼────┼────┤
│ 3 ║ │ │ │ │
└────╨────┴────┴────┴────┘

对于 x=1,y=0,前四行之后:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ A │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ A │ A │ │ │
├────╫────┼────┼────┼────┤
│ 2 ║ A │ B │ A │ B │
├────╫────┼────┼────┼────┤
│ 3 ║ │ │ │ │
└────╨────┴────┴────┴────┘

最后四行之后:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ A │ A │ B │ B │
├────╫────┼────┼────┼────┤
│ 2 ║ A │ B │ A │ B │
├────╫────┼────┼────┼────┤
│ 3 ║ │ │ │ │
└────╨────┴────┴────┴────┘

对于 x = 0, y = 1,前四行:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ C │ A │ C │ B │
├────╫────┼────┼────┼────┤
│ 2 ║ A │ B │ A │ B │
├────╫────┼────┼────┼────┤
│ 3 ║ C │ │ C │ │
└────╨────┴────┴────┴────┘

最后四行:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ C │ A │ C │ B │
├────╫────┼────┼────┼────┤
│ 2 ║ C │ C │ A │ B │
├────╫────┼────┼────┼────┤
│ 3 ║ C │ C │ C │ │
└────╨────┴────┴────┴────┘

对于 x=1,y=1,前四行:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ C │ D │ C │ D │
├────╫────┼────┼────┼────┤
│ 2 ║ C │ C │ A │ B │
├────╫────┼────┼────┼────┤
│ 3 ║ C │ D │ C │ D │
└────╨────┴────┴────┴────┘

最后四行:

┌───╥───┬────┬────┬───┐
│ ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├────╫────┼────┼────┼────┤
│ 1 ║ C │ D │ C │ D │
├────╫────┼────┼────┼────┤
│ 2 ║ C │ C │ D │ D │
├────╫────┼────┼────┼────┤
│ 3 ║ C │ D │ D │ D │
└────╨────┴────┴────┴────┘

这不是您预期的结果,它源于这样一个事实,即在每次迭代中,您会返回并覆盖四个像素。其中一些像素属于您的双重图像。

【讨论】:

  • 我喜欢那个文字艺术桌! =)
  • 我也是。 ;) 但是,它并没有真正解释事情。但是您的回答有助于找出确切的机制。顺便说一句,是否注意到第一行的右半部分不是 A B 而是 B B?直到在这里看到它,我才注意到我的测试图像。
  • 是的,@WolframSchmied - 底部是 CD 而不是 CC。在你的图片中也注意到了这一点?
  • 是的。您在我的回答中的视频中看不到它,但事实证明,最上面一行的右半部分是大图像的像素。
【解决方案2】:

我怕是脑子放屁。因为您在同一个循环中执行所有操作,所以在后面的迭代中执行最初的四行(小副本)最终会覆盖在早期迭代中由最后四行(大副本)写入的像素。

我不确定我的措辞是否出色,但希望你能明白我的意思。

【讨论】:

  • 这是一个简洁的陈述,表明我的(隐式)假设写入不重叠是不正确的。不过,它并没有解释到底发生了什么。
【解决方案3】:

发生的情况是,小图像从顶部和中间同时逐行写入。大图像也从顶部开始,但“移动”的速度是原来的两倍。因此,上半部分的小“慢”图像覆盖了之前写入的快速大像素,而下半部分已经写入的“小”像素被后来到达的快前沿覆盖。

我已经上传了一个 animation on YouTube 来展示这个过程。

(Phil 和 RealSkeptic 的回答都有助于找到解释。我选择了 Phil 的回答,因为他的回答更接近于解释究竟发生了什么。)

【讨论】:

    猜你喜欢
    • 2020-05-07
    • 2015-07-19
    • 1970-01-01
    • 2014-10-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 2018-01-13
    • 2012-12-06
    相关资源
    最近更新 更多