现在我正在学习Image。我想复制图像。我尝试:

private BufferedImage mImage, mNewImage;
private int mWidth, mHeight;
private int[] mPixelData;

public void generate() {
    try {
        mImage = ImageIO.read(new File("D:\\Documents\\Pictures\\image.png"));
        mWidth = mImage.getWidth();
        mHeight = mImage.getHeight();
        mPixelData = new int[mWidth * mHeight];
        // get pixel data from image
        for (int i = 0; i < mHeight; i++) {
            for (int j = 0; j < mWidth; j++) {
                int rgb = mImage.getRGB(j, i);
                int a = rgb >>> 24;
                int r = (rgb >> 16) & 0xff;
                int g = (rgb >> 8) & 0xff;
                int b = rgb & 0xff;
                int newRgb = (a << 24 | r << 16 | g << 8 | b);
                mPixelData[i * mWidth + j] = newRgb;
            }

            mNewImage = new BufferedImage(mWidth, mHeight, mImage.getType());
            WritableRaster raster = (WritableRaster) mNewImage.getData();
            raster.setPixels(0, 0, mWidth, mHeight, mPixelData);
            File file = new File("D:\\Documents\\Pictures\\image2.png");
            ImageIO.write(mNewImage, "png", file);
        }
        } catch (IOException e) {
        e.printStackTrace();
        }
 }


但我有一个例外:


线程“主”中的异常java.lang.ArrayIndexOutOfBoundsException:在sun.awt.image.ByteInterleavedRaster.setPixels(ByteInterleavedRaster.java:1108)上的222748

最佳答案

您代码中的逻辑是理智的,但是上面的代码有多个小问题,因此,我将一一指出::-)


您的mPixelData采用压缩的ARGB布局,与BufferedImage.TYPE_INT_ARGB所使用的相同。因此,您要使用此类型,而不是原始图像的类型。如果从堆栈跟踪中看到,则栅格类型为ByteInterleavedRaster,并且与int[]像素不兼容(使用原始类型可能会引起的另一个问题是,它可能是TYPE_CUSTOM,无法使用此构造函数创建)。因此,首先更改:

mNewImage = new BufferedImage(mWidth, mHeight, BufferedImage.TYPE_INT_ARGB);


(注意:此更改后,您仍然会得到IndexOutOfBoundsException,我稍后会再讲)。
BufferedImage.getData()将为您提供像素数据的副本,而不是当前数据的引用。因此,在此副本上设置像素不会影响以后写入磁盘的数据。而是使用getRaster()方法,该方法正是您想要的:

WritableRaster raster = mNewImage.getRaster();

Raster.setPixels(x, y, w, h, pixels)方法期望一个数组每个数组元素包含一个样本(A,R,G和B作为单独的样本)。这意味着您的数组长度仅为该方法预期值的四分之一,这最终是您看到异常的原因。相反,由于数组采用的是int打包的ARGB布局(这是您现在使用的类型的本机布局),因此应使用setDataElements方法:

raster.setDataElements(0, 0, mWidth, mHeight, mPixelData);

最后,我想指出的是,循环中的所有位移都会简单地将所有像素解压缩为单个分量(A,R,G和B),然后再次将它们重新打包在一起...因此,这个案例。但是您可能打算稍后再在此处添加颜色处理,在这种情况下,这很有意义。 :-)




PS:如果您要做的只是创建原始图像的精确副本,则最快的方法可能是:

ColorModel cm = mImage.getColorModel();
WritableRaster raster = (WritableRaster) mImage.getData(); // Here we want a copy of the original image
mNewImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);

关于java - sun.awt.image.ByteInterleavedRaster.setPixels,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39318665/

10-10 03:17