为什么ImageIO在将其重新保存到MS Paint中之前不会读取BMP文件?

Tho*_*ing 8 java image bmp

我有一个位图文件,test3.bmp我可以使用我测试过的每个图像查看器查看和编辑它.

也就是说,我无法将其读入我的Java应用程序.如果我在MS Paint中编辑BMP,保存它,撤消更改并保存它(test3_resaved.bmp),我有相同的图像,但文件大小不同.不同的文件大小与我无关......我的应用程序可以读取重新保存的文件是什么.

任何人都可以告诉我为什么一个图像与我的代码一起工作但另一个图像没有?

图像文件:

这是一个最小的测试应用程序:

package Test;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.swing.ImageIcon;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Test extends JFrame {
    private ImageIcon imageIcon;

    public Test(String filename) throws IOException {
        super();
        BufferedImage image = javax.imageio.ImageIO.read(new File(filename));
        imageIcon = new ImageIcon(image);
        setVisible(true);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        repaint();
    }

    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        setSize(imageIcon.getIconWidth(), imageIcon.getIconHeight());
        if (imageIcon != null)
            g2d.drawImage(imageIcon.getImage(), 0, 0, this);
    }


    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            if (args.length > 0)
                new Test(args[0]);
            else
                System.out.println("usage - specify image filename on command line");
        }
        catch (Throwable t) {
            t.printStackTrace();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Tac*_*der 10

(扩大我的意见)

问题归结为:人们通常认为以下命令给出的"格式":

ImageIO.getReaderFileSuffixes();
Run Code Online (Sandbox Code Playgroud)

受Java支持.

但这不是应该如何阅读/理解,因为这根本不是它的工作原理.

错误:"ImageIO可以读取以这些格式之一编码的任何文件"

正确:"ImageIO无法读取以不是这些格式之一的格式编码的图像"

但是现在对于该列表中出现的格式有什么看法呢?嗯......这很棘手.

例如,该列表通常返回"PNG"和"BMP"(以及其他格式).但是,没有"一个"PNG,也没有"一个"BMP.我明天可以用一个"有效"的PNG(子)格式来完美,但是那里没有单个PNG解码器可以解码(它必须经过验证和接受:但一旦它被接受,它就会"破坏" "所有现有的PNG解码器都在那里.幸运的是,对于PNG图片来说问题并不算太糟糕.

BMP格式非常复杂.你可以压缩或不压缩(这可以解释你看到的不同文件大小).您可以拥有各种标题(不同长度,也可以解释您看到的不同文件大小).哎呀,BMP实际上非常复杂,我认为你可以将PNG编码的像素嵌入到BMP"shell"中.

基本上有两种有问题的BMP文件类型:

  • 创建Java解码器后出现的BMP变体
  • BMP变体模糊不清,因此Java ImageIO实现者不认为它值得支持

"错误"在于认为有一种PNG或一种BMP格式.两种格式(以及其他图像格式)实际上都是"可扩展的".每当一个新的变种出现时,它就有可能打破那里的任何解码器.

那么在你的情况下发生的是这样的:

  1. 你正在从MS Paint读取原始的BMP文件,MS Paint能够读取该文件,因为它恰好是MS Paint理解的BMP格式.

  2. 相同的BMP格式与您正在使用的Java版本不同(希望它将在另一个Java版本中得到支持,但我不会指望它).

  3. 当您重新保存从MS油漆文件,你在一个BMP格式,绝对是节省一样的原始格式(变化的文件大小是相当告诉)

  4. 您的Java版本恰好支持其他格式.

现在要真正解决您的问题:根据我的经验,像ImageMagick这样的图像库能够读取比默认Java ImageIO API更多的图片,所以我将看看ImageMagick周围的其他图像库或包装器.

这些库通常也会更新,以便比Java更快地支持更新的变体和更新的格式.例如,来自谷歌的惊人的WebP格式(无损+半透明图像上比PNG高出28%到34%)已经得到了相当多的图像处理库的支持,但是在做一个ImageIO时我并没有屏住呼吸.读(someWebPpicture) ......

另一种选择是使用PNG:即使理论上PNG可以扩展,你也不太可能在野外找到"不支持的"PNG.对于BMP来说,它太常见了.