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

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

谁能启发我为什么一个图像可以与我的代码一起使用,而另一个图像却不能呢?

图像文件:

  • test3.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();
            }
        }
    
    }
    

    最佳答案

    (扩大我的评论)

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

    ImageIO.getReaderFileSuffixes();
    

    受Java支持。

    但这不是应该被理解/理解的方式,因为那根本不是它的工作方式。

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

    正确:“ImageIO无法读取使用不是这些格式之一的格式编码的图像”

    但是,这对出现在该列表中的格式有何说明?好吧,这很棘手。

    例如,该列表通常返回“PNG”和“BMP”(以及其他格式)。但是没有“一个” PNG和“一个” BMP。明天我可以使用一种“有效的” PNG(子)格式,该格式会很好,但是没有一个PNG解码器可以解码(必须经过验证并接受:但是一旦被接受,它将“破坏所有现有的PNG解码器)。幸运的是,对于PNG图片而言,问题还算不错。

    BMP格式非常复杂。您是否可以进行压缩(这可以解释您所看到的文件大小的变化)。您可以使用各种标题(长度不同,也可以解释您看到的不同文件大小)。哎呀,BMP实际上是如此复杂,以至于您可以将PNG编码的像素嵌入BMP“ shell ”中。

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

    创建Java解码器后出现的BMP变体
  • BMP变体非常模糊,以至于Java ImageIO实现者认为它不值得支持

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

    因此,您的情况是这样的:
  • ,您正在从MS Paint中读取原始BMP文件,并且MS Paint能够读取该文件,因为它恰好是MS Paint可以理解的BMP格式。
  • ,相同的BMP格式与您正在使用的Java版本无关(希望它会在另一个Java版本中受支持,但我不会指望它)。
  • 当您从MS Paint重新保存该文件时,您所保存的BMP格式肯定是,而不是与原始格式相同(不同的文件大小是很容易判断的)
  • 您的Java版本恰好支持其他格式。

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

    这些库通常也进行更新,以支持更新的变体和格式,比Java快得多。例如,相当多的图像处理库已经支持Google令人惊叹的WebP格式(在无损+半透明图像上比PNG好28%到34%),但是在执行ImageIO时我并不屏息。阅读(someWebPpicture)...

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

    10-06 13:49
    查看更多