将int数组转换为BufferedImage

7

我正在使用Robot类进行屏幕截图,并将BufferedImage转换为int数组。然后我想将int数组转换回BufferedImage,但是这会出现错误。这是我的代码:

Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage printscreen = robot.createScreenCapture(new Rectangle(screen));
int[] pixels = ((DataBufferInt) printscreen.getRaster().getDataBuffer()).getData();

BufferedImage image = new BufferedImage(screen.width, screen.height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();
raster.setPixels(0, 0, screen.width, screen.height, pixels);

但我收到了错误提示:ArrayIndexOutOfBoundsException: 2073600,但是为什么会出现这个错误?

我在这一行代码中遇到了异常:

raster.setPixels(0, 0, screen.width, screen.height, pixels);

编辑:如果我将第二个缓冲图像的类型更改为 TYPE_BYTE_GRAY,则它可以正常工作。


2
你能分享一下堆栈跟踪吗?你在哪一行遇到了它? - Swapnil
我建议您将所有尺寸基于“屏幕”大小。为了更快地获得帮助,请发布一个SSCCE。此外,似乎这个问题迫切需要对代码行进行基本跟踪和尺寸显示。 - Andrew Thompson
5个回答

15
int[] bitMasks = new int[]{0xFF0000, 0xFF00, 0xFF, 0xFF000000};
SinglePixelPackedSampleModel sm = new SinglePixelPackedSampleModel(
        DataBuffer.TYPE_INT, width, height, bitMasks);
DataBufferInt db = new DataBufferInt(pixels, pixels.length);
WritableRaster wr = Raster.createWritableRaster(sm, db, new Point());
BufferedImage image = new BufferedImage(ColorModel.getRGBdefault(), wr, false, null);

非常好的解决方案。值得一提的是,这也是页面上唯一对我有效的解决方案。在WritableRaster setPixels()文档中没有说明的部分是,传递给setPixels()的int数组不是作为每像素一个打包的int访问,而是显然是每个通道一个int(即RGB需要一个临时数组3倍于他的打包数组大小,ARGB 4倍 - 显然不是一个优雅的解决方案,但我测试过它可以工作)。 - Gnaural

1

改为:

getRaster().getPixels(0, 0, screen.width, screen.height, pixels)

它有效了!无论如何,感谢您的帮助


0

ArrayIndexOutOfBounds 异常会在您试图访问超出数组大小的索引元素时发生。在这种情况下,您将数组传递给 setPixels 方法,根据其 javadocs,该方法不明确检查数组的边界或大小。因此,在调用该方法之前,您应该明确地进行检查。例如:

    if(x >= 0 && x < arr.length) {
        // some code
    }

这是由WritableRaster使用的SampleModel类的相关代码。

    public int[] getPixels(int x, int y, int w, int h,
                           int iArray[], DataBuffer data) {

        int pixels[];
        int Offset=0;

        if (iArray != null)
            pixels = iArray;
        else
            pixels = new int[numBands * w * h];

        for (int i=y; i<(h+y); i++) {
            for (int j=x; j<(w+x); j++) {
                for(int k=0; k<numBands; k++) {
                    pixels[Offset++] = getSample(j, i, k, data);
                }
            }
        }

    return pixels;
}

谢谢您的回答,但是两个 BufferedImage 的高度和宽度都相同。如果像素数量相同,为什么需要更多的数组元素呢? - Jochem Gruter
我建议将JDK源代码添加到像Eclipse这样的IDE中,并使用调试器来检查变量值。那样会快得多。 - Swapnil
我正在使用Eclipse。 我在你的例子中看到了numBands * w * h,numBands是什么意思?我的像素数组有2073600个元素,即1920*1080。 - Jochem Gruter
您可以在此处浏览源代码 - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/image/SampleModel.java#SampleModel.setPixels%28int%2Cint%2Cint%2Cint%2Cint%5B%5D%2Cjava.awt.image.DataBuffer%29 - Swapnil

0
BufferedImage image = new BufferedImage(screen.width*3, screen.height,BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();

raster.setPixels(0, 0, screen.width*3, screen.height, pixels);

1
请添加一个解释。 - Tim Zimmermann
正如@SamirChen所提到的,你有红色、绿色、蓝色像素宽度。因此实际宽度是图像宽度的3倍。 - ayman

0

raster.setPixels(0, 0, screen.width, screen.height, pixels); 中的 pixels 大小应该为 width*height*3,当你设置 BufferedImage.TYPE_INT_RGB 时。


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