Java 为什么';t ImageIO读取BMP文件,直到它重新保存在MS Paint中?

Java 为什么';t ImageIO读取BMP文件,直到它重新保存在MS Paint中?,java,image,bmp,Java,Image,Bmp,我有一个位图文件,test3.bmp,我可以用我测试过的每个图像查看器查看和编辑它 也就是说,我无法将其读入Java应用程序。如果我在MS Paint中编辑BMP,保存它,撤消更改,然后保存它(test3\u resaved.BMP),我会得到相同的图像,但文件大小不同。不同的文件大小与我无关。。。我的应用程序可以读取重新保存的文件 有谁能告诉我为什么一个图像可以与我的代码一起工作,而另一个不能 图像文件: 以下是一个最小的测试应用程序: package Test; import ja

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

也就是说,我无法将其读入Java应用程序。如果我在MS Paint中编辑BMP,保存它,撤消更改,然后保存它(
test3\u 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();
        }
    }

}

这里有一些示例代码将枚举JDK支持的图像格式

高级图像工具包支持BMP,但我知道它也有一些基本JDK现在也支持的东西。因此,如果两者都支持,那么JAI的支持可能更全面。但这似乎不太可能,因为这没有多大意义。哦,是太阳

如果您使用的是JDK 6,那么肯定可以使用PNG(更便于携带),您可以转换图像吗?IIRC MS Paint将保存一个png。

(根据我的评论展开)

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

ImageIO.getReaderFileSuffixes();
Java支持的

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

错误:“ImageIO可以读取使用以下格式之一编码的任何文件”

更正:“ImageIO无法读取非这些格式编码的图像”

但是现在,对于列表中出现的格式,这意味着什么呢?好。。。这会变得棘手

例如,该列表通常同时返回“PNG”和“BMP”(以及其他格式)。但是没有“一个”PNG和“一个”BMP。明天我可以带上一个“有效”的PNG(sub)格式,这很好,但是没有一个PNG解码器可以解码(它必须被验证和接受:但一旦被接受,它将“破坏”所有现有的PNG解码器)。幸运的是,对于PNG图片来说,问题并不太严重

BMP格式非常复杂。您可以进行压缩,也可以不进行压缩(这可以解释您所看到的文件大小的变化)。您可以有不同的头文件(长度不同,这也可以解释您所看到的文件大小的不同)。见鬼,BMP实际上是如此复杂,以至于我认为可以将PNG编码的像素嵌入BMP“外壳”中

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

  • 创建Java解码器后出现的BMP变体
“错误”在于认为存在一种PNG或BMP格式。这两种格式(以及其他图像格式)实际上都是“可扩展的”。每当一个新的变体出现时,它就有可能破坏任何解码器

你的情况是这样的:

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

  • 同样的BMP格式对于您正在使用的Java版本来说是陌生的(希望它能在另一个Java版本中得到支持,但我不指望它)

  • 当您从MS Paint重新保存该文件时,您保存的BMP格式肯定与原始格式不同(不同的文件大小非常明显)

  • 您的Java版本恰好支持另一种格式

  • 现在来实际解决您的问题:根据我的经验,像ImageMagick这样的图像库能够读取比默认的Java ImageIO API多得多的图片,所以我想看看ImageMagick周围的其他图像库或包装器

    这些库通常也会更新,以支持比Java快得多的新变体和新格式。例如,谷歌令人惊叹的WebP格式(在无损+半透明图像上比PNG好28%到34%)已经得到了相当多的图像处理库的支持,但当涉及到ImageIO.read(someWebPpicture)时,我并没有屏息以待


    另一个选择是使用PNG:即使理论上PNG可以扩展,但在野外也不太可能找到“不受支持”的PNG。对于BMP来说,这太普遍了。

    我用自己的Java BMP解码器测试了这两幅图像。它还转储图像的一些信息。我发现原来的是一个32位的bmp,而重新保存的是一个24位的。所以我假设imageio bmp阅读器无法正确处理32位bmp

    更新:为了证实我很久以前的猜测,我再次测试了图像,但仍然有问题。问题是没有显示图像,原因是Java ImageIO认为图像是完全透明的。以下是Java ImageIO创建的BuffereImage的转储:

     DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=ff000000
     IntegerInterleavedRaster: width = 494 height = 516 #Bands = 4 xOff = 0 yOff = 0
     dataOffset[0] 0
     java.awt.image.SinglePixelPackedSampleModel@80809ee
    
    我们可以在这里看到,有4个带表示Java ImageIO解释的RGBA。事实上,对于32位Windows BMP图像,第四个频带或第四个字节不适用于alpha通道。它只是垃圾,或者使它双字对齐

    一个Windows 3.x BMP解码器和更多信息,这里有许多不同类型的BMP文件。可能您的MS Paint可以读取原始格式,但在保存文件时正在使用其他BMP标题/编码。我确信Java绝对不能读取所有的BMP文件(很少有BMP阅读器可以)。恰好Java支持MS Paint输出的特定类型的BMP。为什么是BMP?如果你想要无损,PNG会是一个选项吗?这里的问题和“Roman B.”一样。。。BMP文件的链接无法工作。你可以用hexd