如何解决批量图片叠加代码遍历全部图片时的NullPointerException?
问题:图片叠加遍历中出现NullPointerException
需要将bottom文件夹(含12张图片)内的每张底图与top文件夹(含10张图片)内的每张顶图叠加,命名逻辑可行,但代码遍历top文件夹前3张后就抛出NullPointerException,底图可正常遍历完成。
最初尝试的代码
package images; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; public class overlay_images { public static void main(String[] args) throws IOException,NullPointerException { File bottom = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\bottom"); File top = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\top_lantern_blocks"); int x = bottom.listFiles().length; int y = top.listFiles().length; BufferedImage[][] imgs = new BufferedImage[x*y][2]; BufferedImage[] newImgs = new BufferedImage[x*y]; String newFileName = ""; for(int n=0;n<x*y;n++) { imgs[n] = new BufferedImage[] {ImageIO.read(bottom.listFiles()[n%x]), ImageIO.read(top.listFiles()[n/x])}; newImgs[n] = new BufferedImage(16,16,BufferedImage.TYPE_4BYTE_ABGR); for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { int ptop = ImageIO.read(top.listFiles()[n/x]).getRGB(i,j); int pbttm = ImageIO.read(bottom.listFiles()[n%x]).getRGB(i,j); if(ptop/(2^24)==0) {newImgs[n].setRGB(i,j,pbttm);} else {newImgs[n].setRGB(i,j,ptop);} } } newImgs[n].setRGB(8,15,imgs[n%x][0].getRGB(8,15)); newFileName = "C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\lantern_blocks\\"; newFileName+= top.listFiles()[n/x].getName().replace(".png","") + "_"; newFileName+= bottom.listFiles()[n%x].getName(); newFileName = newFileName.replace("bulb", "lantern"); newFileName = newFileName.replace("_off", "_block"); ImageIO.write(newImgs[n],"png",new File(newFileName)); } } }
VSCode提示错误出现在第21行:int ptop = ImageIO.read(top.listFiles()[n/x]).getRGB(i,j);
修改后遍历文件的代码
改为直接遍历文件后仍出现相同错误,异常位置在第17行:
package images; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; public class overlay_images { public static void main(String[] args) throws IOException,NullPointerException { File bottom = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\bottom"); File top = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\top_lantern_blocks"); BufferedImage newImg = new BufferedImage(16,16,BufferedImage.TYPE_4BYTE_ABGR); String newFileName = ""; for(File m:bottom.listFiles()) { for(File n:top.listFiles()) { newImg=new BufferedImage(16,16,BufferedImage.TYPE_4BYTE_ABGR); for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { int ptop = ImageIO.read(n).getRGB(i,j); int pbttm = ImageIO.read(m).getRGB(i,j); if(ptop/(2^24)==0) {newImg.setRGB(i,j,pbttm);} else {newImg.setRGB(i,j,ptop);} } } newImg.setRGB(8,15,ImageIO.read(m).getRGB(8,15)); newFileName = "C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\lantern_blocks\\"; newFileName+= n.getName().replace(".png","") + "_"; newFileName+= m.getName(); newFileName = newFileName.replace("bulb", "lantern"); newFileName = newFileName.replace("_off", "_block"); ImageIO.write(newImg,"png",new File(newFileName)); } } } }
问题原因与修复方案
核心问题
- 重复读取图片耗尽文件流:嵌套循环中反复调用
ImageIO.read()读取同一文件,多次读取后流无法正常获取图片,返回null,调用getRGB()触发空指针。 - 位运算逻辑错误:
2^24是异或运算,不是幂运算,无法正确判断Alpha通道值。 - 路径转义不规范:原代码路径使用
\未转义,Java中需用\\或/。
修复后的代码
package images; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; public class overlay_images { public static void main(String[] args) throws IOException { // 修正路径转义 File bottomDir = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\bottom"); File topDir = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\top_lantern_blocks"); File outputDir = new File("C:\\Users\\mymsa\\Documents\\Mathmatical Docs\\Java Math\\images\\all_img\\lantern_blocks"); // 确保输出目录存在 if (!outputDir.exists()) { outputDir.mkdirs(); } // 遍历底图文件 for (File bottomFile : bottomDir.listFiles()) { if (!bottomFile.isFile() || !bottomFile.getName().endsWith(".png")) continue; BufferedImage bottomImg = ImageIO.read(bottomFile); if (bottomImg == null) continue; // 跳过无法读取的图片 // 遍历顶图文件 for (File topFile : topDir.listFiles()) { if (!topFile.isFile() || !topFile.getName().endsWith(".png")) continue; BufferedImage topImg = ImageIO.read(topFile); if (topImg == null) continue; // 跳过无法读取的图片 // 创建新图片 BufferedImage newImg = new BufferedImage(16, 16, BufferedImage.TYPE_4BYTE_ABGR); // 像素叠加逻辑 for (int i = 0; i < 16; i++) { for (int j = 0; j < 16; j++) { int topPixel = topImg.getRGB(i, j); int bottomPixel = bottomImg.getRGB(i, j); // 正确判断Alpha通道:Alpha为0时用底图,否则用顶图 if (((topPixel >> 24) & 0xFF) == 0) { newImg.setRGB(i, j, bottomPixel); } else { newImg.setRGB(i, j, topPixel); } } } // 额外设置指定像素 newImg.setRGB(8, 15, bottomImg.getRGB(8, 15)); // 生成文件名 String topName = topFile.getName().replace(".png", ""); String bottomName = bottomFile.getName(); String fileName = topName + "_" + bottomName; fileName = fileName.replace("bulb", "lantern").replace("_off", "_block"); File outputFile = new File(outputDir, fileName); // 写入图片 ImageIO.write(newImg, "png", outputFile); } } } }
关键修复点
- 提前读取每张图片到
BufferedImage对象,避免循环中重复读取文件流。 - 修正Alpha通道判断逻辑,用
>>移位和& 0xFF准确获取Alpha值。 - 添加文件有效性检查,跳过非PNG文件和无法读取的图片。
- 确保输出目录存在,避免写入失败。
- 规范路径转义字符,避免路径解析错误。
内容的提问来源于stack exchange,提问作者ItsErtHere
相关产品推荐
相关产品推荐

