为什么这段Java代码绘制图像到自身时出现类循环的重复绘制效果?
问题原因分析
你遇到的现象本质是读写同一块图像内存导致的递归覆盖问题:你直接从原图自身读取像素,同时往原图的偏移位置写入像素,整个绘制过程是逐行实时写入的,并不会先缓存整张原图的原始像素再完成绘制。当绘制到Y坐标大于100的区域时,你读取的源像素已经是前一步刚写入到偏移位置的新像素,而非原始图像素,最终就会生成一层一层往右下角偏移的重复小图,也就是你观察到的隧道效应。
逻辑复现拆解
- 初始化读取的
img内存中存储的是原始测试图的全部像素 - 执行
g.drawImage(img,100,100,null)时,绘制逻辑默认从img的左上角(0,0)读像素,依次写入到img从(100,100)开始的对应位置 - 当绘制到第101行目标像素时,此时读取的源位置第1行像素,已经是前一步刚写入的修改后像素,不再是原始图的第1行像素
- 该逻辑持续循环,就会生成不断嵌套的重复小图效果
修复方案
如果要实现仅把原图绘制一次到自身的偏移位置,需要先对原始图像素做独立拷贝,用拷贝版本作为绘制源,避免读写同一块内存。修复后的代码如下:
import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; public class Swapper{ public static void main(String[] args) throws IOException { try{ BufferedImage originalImg = ImageIO.read(new File("picture2.jpg")); // 先创建原始图像的独立拷贝,作为绘制源 BufferedImage sourceImg = new BufferedImage(originalImg.getWidth(), originalImg.getHeight(), originalImg.getType()); Graphics sourceG = sourceImg.getGraphics(); sourceG.drawImage(originalImg, 0, 0, null); sourceG.dispose(); // 用独立的源图绘制到原图上,不会出现递归覆盖问题 Graphics targetG = originalImg.getGraphics(); targetG.drawImage(sourceImg, 100, 100, null); targetG.dispose(); File file = new File("aaaimage3.png"); ImageIO.write(originalImg,"png", file); } catch(IOException e){ e.printStackTrace(); } } }
内容的提问来源于stack exchange,提问作者Crazy Thinker
相关产品推荐
相关产品推荐

