【问题标题】:Turn an array of pixels into an Image object with Java's ImageIO?使用 Java 的 ImageIO 将像素数组转换为 Image 对象?
【发布时间】:2010-09-12 14:00:21
【问题描述】:

我目前正在使用以下代码将像素值数组(最初使用 java.awt.image.PixelGrabber 对象创建)转换为 Image 对象:

public Image getImageFromArray(int[] pixels, int width, int height) {
    MemoryImageSource mis = new MemoryImageSource(width, height, pixels, 0, width);
    Toolkit tk = Toolkit.getDefaultToolkit();
    return tk.createImage(mis);
}

是否可以使用 ImageIO 包中的类来实现相同的结果,这样我就不必使用 AWT 工具包了?

Toolkit.getDefaultToolkit() 似乎不是 100% 可靠,有时会抛出 AWTError,而 ImageIO 类应该始终可用,这就是我对更改方法感兴趣的原因。

【问题讨论】:

    标签: java image awt toolkit javax.imageio


    【解决方案1】:

    您可以在不使用 ImageIO 的情况下创建图像。只需使用与像素数组内容匹配的图像类型创建一个 BufferedImage。

    public static Image getImageFromArray(int[] pixels, int width, int height) {
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                WritableRaster raster = (WritableRaster) image.getData();
                raster.setPixels(0,0,width,height,pixels);
                return image;
            }
    

    使用 PixelGrabber 时,不要忘记在调用 getImageFromArray 之前从像素数组中提取 RGBA 信息。在 PixelGrabber javadoc 的 handlepixelmethod 中有一个这样的例子。完成此操作后,请确保 BufferedImage 构造函数中的图像类型为BufferedImage.TYPE_INT_ARGB

    【讨论】:

    • 感谢 bcash,但是当我尝试该代码时,我得到了 java.lang.ArrayIndexOutOfBoundsException。有什么想法吗?
    • 我认为这已经接近了,我们可能需要 Chris 提供更多详细信息?这看起来应该可以工作......你的整数是什么?它们是 RGB 吗? ARGB?某种打包格式?
    • 像素来自 PixelGrabber,例如:int[] pixel = new int[width * height]; PixelGrabber pg = new PixelGrabber(img, 0, 0, 宽度, 高度, 像素, 0, 宽度); pg.grabPixels();
    • 克里斯,你得到了一个 AOOB 异常,因为 BufferedImage“图像”的大小是宽度 * 高度 * 3,因为它的类型是 int RGB。查看编辑。
    • 正如@haraldK(在下面的帖子中)所通知的,Java 文档提到BufferedImage.getData() 返回一个RasterBufferedImage.getRaster() 返回一个WritableRaster。因此,如果您使用 getData() 似乎它会返回一个副本,并且在 setPixels() 之后您必须使用 BufferedImage.setData() 将其放回,这是一个开销。所以最好使用getRaster() 并使用它。
    【解决方案2】:

    使用光栅我得到一个ArrayIndexOutOfBoundsException,即使我用TYPE_INT_ARGB创建了BufferedImage。但是,使用BufferedImagesetRGB(...) 方法对我有用。

    【讨论】:

    • 我遇到了类似的问题,即使输入和输出的数组大小匹配。我最终也使用了 setRGB。它可能会慢一些,但它可以工作。不会认为 Alpha 与非 alpha 应该改变数组大小,因为它只是单个 int 上的 2 个最重要的字节。
    • 如何在上面的代码中使用 setRGB() ?谢谢...
    【解决方案3】:

    BufferedImage.getData() 上的 JavaDoc 说:“一个 Raster,它是图像数据的副本。”

    这段代码对我有用,但我怀疑它的效率:

            // Получаем картинку из массива.
            int[] pixels = new int[width*height];
                // Рисуем диагональ.
                for (int j = 0; j < height; j++) {
                    for (int i = 0; i < width; i++) {
                        if (i == j) {
                            pixels[j*width + i] = Color.RED.getRGB();
                        }
                        else {
                            pixels[j*width + i] = Color.BLUE.getRGB();
                            //pixels[j*width + i] = 0x00000000;
                        }
                    }
                }
    
    BufferedImage pixelImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);    
        pixelImage.setRGB(0, 0, width, height, pixels, 0, width);
    

    【讨论】:

    • ..或使用getRaster() 而不是getData()
    【解决方案4】:

    我在使用 java.awt.Robot 抓取屏幕截图(或屏幕的一部分)方面取得了巨大成功,但要使用 ImageIO,您需要将其存储在 BufferedImage 中而不是内存图像中资源。然后您可以调用 ImageIO 的一种静态方法并保存文件。尝试类似:

    // Capture whole screen
    Rectangle region = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    BufferedImage capturedImage = new Robot().createScreenCapture(region);
    
    // Save as PNG
    File imageFile = new File("capturedImage.png");
    ImageIO.write(capturedImage, "png", imageFile);
    

    【讨论】:

      【解决方案5】:

      由于这是在 SO 上使用 ImageIO 标记的投票率最高的问题之一,因此我认为仍有更好的解决方案的空间,即使问题已经过时。 :-)

      查看我在 GitHub 上的开源 imageio 项目中的 BufferedImageFactory.java 类。

      有了它,你可以简单地写:

      BufferedImage image = new BufferedImageFactory(image).getBufferedImage();
      

      另一个好处是,在最坏的情况下,这种方法的性能(时间)与该线程中基于 PixelGrabber 的示例大致相同。对于大多数常见情况(通常是 JPEG),它的速度大约是原来的两倍。无论如何,它使用的内存更少。

      作为附带奖励,原始图像的颜色模型和像素布局被保留,而不是使用默认颜色模型转换为 int ARGB。这可能会节省额外的内存。

      (PS:如果有人感兴趣,工厂还支持二次采样、感兴趣区域和进度侦听器。:-)

      【讨论】:

        【解决方案6】:

        我有同样的问题,其他人都试图应用这个问题的正确答案,我的 int 数组实际上得到了一个 OutOfboundException,我修复了它添加了一个索引,因为数组的长度必须是 widht*height*3在此之后我无法获取图像,所以我修复了它,将光栅设置为图像

        public static Image getImageFromArray(int[] pixels, int width, int height) {
                BufferedImage image = new BufferedImage(width, height,     BufferedImage.TYPE_INT_ARGB);
                WritableRaster raster = (WritableRaster) image.getData();
                raster.setPixels(0,0,width,height,pixels);
                image.setData(raster); 
                return image;
            }
        

        如果你在这样的 jframe 上的标签上显示图像,你可以看到图像

            JFrame frame = new JFrame();
            frame.getContentPane().setLayout(new FlowLayout());
            frame.getContentPane().add(new JLabel(new ImageIcon(image)));
            frame.pack();
            frame.setVisible(true);
        

        在 imageIcon() 上设置图像。 最后一个建议,您可以尝试将 Bufferedimage.TYPE_INT_ARGB 更改为与您从该类型获得的数组相匹配的其他内容,这非常重要我有一个 0 和 -1 的数组,所以我使用了这种类型 BufferedImage.TYPE_3BYTE_BGR

        【讨论】:

          猜你喜欢
          • 2018-03-05
          • 1970-01-01
          • 2017-05-10
          • 2016-10-31
          • 2017-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多