Возможная ошибка в Java 8 Обновление 45 в Windows 8

Этот код берет входное изображение и создает выходное изображение, размер которого в два раза больше. Первые четыре строки во внутреннем цикле записывают четыре копии оригинала одинакового размера, последние четыре строки должны перезаписывать маленькие изображения одной копией входного изображения, в два раза превышающей оригинал.

Код компилируется и выполняется без ошибок в Java 8 Update 45 в Windows 8. Полученный образ не является, как ожидается, одной большой копией входных данных. Нижняя половина выходных данных соответствует ожидаемой, но верхняя половина состоит из двух копий исходного размера, записанных в первых двух строках цикла. Комментирование этих двух строк приводит к изначально ожидаемому результату, поэтому кажется, что первые две строки выполняются последними, а не первыми, несмотря на то, что они появляются первыми в исходном коде.

Это ошибка компилятора, состояние гонки во время выполнения или мозговой пердеть от моего имени?

Если потребуется, я выложу примеры где-нибудь.

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"));

    }
}

3 ответа

Решение

Боюсь, это мозговой пердеть. Поскольку вы выполняете все в одном цикле, выполнение начальных четырех строк (маленьких копий) на более поздних итерациях приводит к перезаписи пикселей, которые были записаны последними четырьмя строками (большая копия) на более ранних итерациях.

Я не уверен, что сформулировал это блестяще, но надеюсь, вы поймете, что я имею в виду.

Давайте попробуем продемонстрировать, что происходит. Предположим, ваше изображение:

┌───╥───┬───┐
║ ║ 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 │
└───╨───┴───┴───┴───┘

Это не тот результат, который вы ожидали, а тот факт, что на каждой итерации вы возвращаетесь и перезаписываете четыре пикселя. Некоторые из этих пикселей принадлежат вашему двойному изображению.

Что происходит, так это то, что маленькие изображения пишутся построчно, начиная сверху и из середины одновременно. Большое изображение также начинается сверху, но "движется" вдвое быстрее. Таким образом, маленькие "медленные" изображения в верхней половине перезаписывают быстрые большие пиксели, написанные ранее, в то время как в нижней половине уже записанные "маленькие" пиксели перезаписываются быстрым фронтом, появляющимся позже.

Я загрузил на YouTube анимацию, показывающую процесс.

(Ответы Фила и RealSkeptic помогли найти объяснение. Я выбрал ответ Фила, потому что его ответ был ближе к объяснению того, что именно произошло.)

Другие вопросы по тегам