ImageIO.write无法写入bmp文件

16

我试图将图像保存为bmp格式,但没有创建任何文件。 如果我使用“png”代替,一切正常。 有任何想法吗?

//This works fine:
ImageIO.write(bi, "png", new File("D:\\MyImage.png"));

//This does not work:
ImageIO.write(bi, "bmp", new File("D:\\MyImage.bmp"));

ImageIO.getWriterFormatNames() 给了我 "jpg", "bmp", "jpeg" 还有其他一些格式。

提前感谢。

Jakob


1
“不工作” 到底是什么意思?你有收到任何错误信息吗?由于需要转义反斜杠,所以你的“代码”实际上很可能不会起作用。 - chrylis -cautiouslyoptimistic-
@chrylis 反斜杠已经被转义了,只是在问题中没有显示出来(当您不将其格式化为代码时会发生这种情况)。 - Bernhard Barker
"does not work" 意味着当我使用 "bmp" 格式时未创建文件。 - Jakob Mathiasen
1
write 返回一个 boolean 值,你应该进行检查。 - Bernhard Barker
5
简短回答是:**TYPE_INT_ARGB** 不起作用,但 TYPE_INT_RGB 起作用。 - Evgeni Sergeev
显示剩余5条评论
5个回答

26
我刚刚完成了调试一个类似的问题,虽然Jakob已经选择使用PNG格式。首先,一定要检查ImageIO.write(...)的返回值。如果找不到合适的写入器,它将返回false,而当Jakob尝试将其作为位图写入时,这就应该发生。这种情况发生在文件的实际图像格式与“格式名称”参数中给出的不匹配时。在这种情况下不会抛出异常。请参阅https://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage,%20java.lang.String,%20java.io.File)中的文档了解更多信息。
首先,使用BufferedImage对象的BufferedImage#getType()方法检查图像类型。在https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType()中查看可能的返回值。例如,如果从您的BufferedImage对象(表示带有alpha组件的PNG)获得类型为TYPE_INT_ARGB,则使用ImageIO.write(bi, "BMP", new File("D:\\test.bmp"))将无法成功,并且该方法将返回false,即使您可以在使用ImageIO.getWriterFormatNames()获取到的条目列表中看到BMP/bmp。您可能需要处理编码并将图像转换为所需格式。
其次,当面对这种有时会令人头疼的问题时,始终使用图像编辑器(如GIMP)详细了解图像属性会很有帮助。

@绿箭,一个小提示...你可以使用"bmp"或"BMP"作为图像格式的值。其他格式也适用相同的规则。这没有关系。


2
好的答案:此外(并为我提供完整性),这是一个链接到非常有用的mkyong网站,展示了如何将图像转换为JPEG格式的方法http://www.mkyong.com/java/convert-png-to-jpeg-image-file-in-java/。这个方法也适用于BMP格式的图像。 - reallynice

8
如@bincob所说,如果write返回false,您可以这样重新绘制源图像。
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), 
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);

And then you can write again.


你的代码有一个错误(最后一次出现的“newBufferedImage”应该改为“bufferedImage”)。否则,答案不错!我已经将其添加到我的语言库中:http://tinybrain.de/1004274 - Stefan Reich
1
这应该是被选中的答案。 - David Thielen
我遇到了一個JPEG文件的同樣問題,我認為原因是我試圖通過讓圖像的白色部分透明來節省內存,所以只有PNG格式可用。 - noobianov

1

使用BufferedImage.TYPE_INT_RGB编码可用于“gif”、“png”、“tif”以及“jpg”和“bmp”文件格式:

static void saveBufferedImageToFileTest(){

    String[] types = new String[] {"gif","png","tif","jpg","bmp"};

    //JPEG and BMP needs BufferedImage.TYPE_INT_RGB. See https://mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
    //BufferedImage.TYPE_INT_RGB for all `types`
    int biType = BufferedImage.TYPE_INT_RGB;   // BufferedImage.TYPE_INT_ARGB does not work for "bmp" and "jpeg"
    BufferedImage bi = new BufferedImage(200 ,200, biType);
    Graphics g = bi.getGraphics();
    g.fillRect(50, 50, 100,  100);
    g.dispose();

    try {
        for(String type : types){
            boolean success = ImageIO.write(bi,type,new File("test_image."+type));
            System.out.println(type + (success ?  " file created" : " file NOT created") );
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

0

我没有尝试过,但我认为格式应该是"BMP"而不是"bmp"。 请尝试使用

ImageIO.write(bi, "BMP", new File("D:\\MyImage.bmp"));

看看会发生什么。

我们无法看到您的BI是如何构建的。

BufferedImage bufferedImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);

编码类型设置正确了吗?

我认为你的二进制文件已经损坏了,这个对我来说完美地工作。

BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB);
Graphics gd = bi.getGraphics();
gd.drawRect(0, 0, 10, 10);      
try {
    ImageIO.write(bi, "BMP", new File("C:\\test.bmp"));
    ImageIO.write(bi, "PNG", new File("C:\\test.png"));
} catch (IOException e) {
    System.out.println("error "+e.getMessage());
}

使用type_int_ARGB和“BMP”代替“bmp”怎么样? - Heaven42
当使用BMP和BufferedImage.TYPE_INT_RGB时,会创建一个.bmp文件,但它是全黑的。PNG文件仍然可以正常创建。 - Jakob Mathiasen
我现在不能尝试。今晚会尝试并告诉你我发现了什么。我认为这是一个编码问题。你可以尝试使用全白色图像和不同的编码类型来查看发生了什么。 - Heaven42
你最终用我的编辑修复了它吗?不要忘记bmp没有透明度,也许你正在黑色背景上画黑色。 - Heaven42
绿箭头:抱歉回复晚了。我们没有继续使用位图,而是采用了.png文件的解决方案。感谢您的努力。 - Jakob Mathiasen
显示剩余2条评论

0

虽然有点老旧,但BMP仍然偶尔有用,而且上面的答案都绕过了最佳解决方案:自己动手。这样可以适用于任何类型的位图。

static void writeBMP(BufferedImage image, File f) throws IOException {
    OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
    int width = image.getWidth();
    int height = image.getHeight();
    int row = (width * 3 + 3) / 4 * 4;
    out.write('B');
    out.write('M');
    writeInt(out, 14 + 40 + row * height);  // file size
    writeInt(out, 0); 
    writeInt(out, 14 + 40);        // bitmap offset
    writeInt(out, 40);             // size
    writeInt(out, width);          // width
    writeInt(out, height);         // weight
    writeInt(out, (24<<16) | 1);   // planes, bpp
    writeInt(out, 0);              // compression
    writeInt(out, row * height);   // bitmap size
    writeInt(out, 0);              // resx
    writeInt(out, 0);              // resy
    writeInt(out, 0);              // used colors
    writeInt(out, 0);              // important colors
    for (int y=height-1;y>=0;y--) {
        for (int x=0;x<width;x++) {
            int rgba = image.getRGB(x, y); 
            out.write(rgba & 0xFF); // b
            out.write(rgba >> 8);   // g
            out.write(rgba >> 16);  // r
        }   
        for (int x=width*3;x%4!=0;x++) { // pad to 4 bytes
            out.write(0);
        }   
    }   
    out.close();
}   
private static void writeInt(OutputStream out, int v) throws IOException {
    out.write(v);
    out.write(v >> 8);
    out.write(v >> 16);
    out.write(v >> 24);
}   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接