Возможная ошибка в 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 помогли найти объяснение. Я выбрал ответ Фила, потому что его ответ был ближе к объяснению того, что именно произошло.)