sun.awt.image.ByteInterleavedRaster.setPixels
sun.awt.image.ByteInterleavedRaster.setPixels
现在我正在学习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();
}
}
但是我遇到了一个例外:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 222748 at sun.awt.image.ByteInterleavedRaster.setPixels(ByteInterleavedRaster.java:1108)
你的代码逻辑是健全的,但是上面的代码有很多小问题,所以我会试着一一指出::-)
您的 mPixelData
是打包的 ARGB 布局,这与 BufferedImage.TYPE_INT_ARGB
的使用相同。所以你要使用这个类型,而不是原始图像的类型。如果您从堆栈跟踪中看到,您的栅格类型是 ByteInterleavedRaster
,并且这与您的 int[]
像素不兼容(使用原始类型可能引起的另一个问题是,它可能是TYPE_CUSTOM
,无法使用此构造函数创建)。所以,首先改变:
mNewImage = new BufferedImage(mWidth, mHeight, BufferedImage.TYPE_INT_ARGB);
(注意:此更改后您仍会得到 IndexOutOfBoundsException
,稍后我会 return)。
BufferedImage.getData()
将为您提供 像素数据的副本 ,而不是对当前数据的引用。因此,在此副本上设置像素不会影响以后写入磁盘的数据。相反,使用 getRaster()
方法,它完全符合您的要求:
WritableRaster raster = mNewImage.getRaster();
Raster.setPixels(x, y, w, h, pixels)
方法需要一个数组每个数组元素包含一个样本(A、R、G 和 B 作为单独的样本)。这意味着您的数组长度仅为方法预期长度的四分之一,这最终是您看到的异常的原因。相反,因为你的数组是 int
-packed ARGB 布局(这是你现在使用的类型的原生布局),你应该使用 setDataElements
方法:
raster.setDataElements(0, 0, mWidth, mHeight, mPixelData);
最后,我想指出的是,循环中的所有位移都会简单地将所有像素解压缩为单个组件(A、R、G 和 B),然后将它们重新组合在一起再次......所以,在这种情况下,newRGB == rgb
。但是您可能打算稍后在此处添加颜色操作,在这种情况下它是有意义的。 :-)
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);
现在我正在学习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();
}
}
但是我遇到了一个例外:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 222748 at sun.awt.image.ByteInterleavedRaster.setPixels(ByteInterleavedRaster.java:1108)
你的代码逻辑是健全的,但是上面的代码有很多小问题,所以我会试着一一指出::-)
您的
mPixelData
是打包的 ARGB 布局,这与BufferedImage.TYPE_INT_ARGB
的使用相同。所以你要使用这个类型,而不是原始图像的类型。如果您从堆栈跟踪中看到,您的栅格类型是ByteInterleavedRaster
,并且这与您的int[]
像素不兼容(使用原始类型可能引起的另一个问题是,它可能是TYPE_CUSTOM
,无法使用此构造函数创建)。所以,首先改变:mNewImage = new BufferedImage(mWidth, mHeight, BufferedImage.TYPE_INT_ARGB);
(注意:此更改后您仍会得到
IndexOutOfBoundsException
,稍后我会 return)。BufferedImage.getData()
将为您提供 像素数据的副本 ,而不是对当前数据的引用。因此,在此副本上设置像素不会影响以后写入磁盘的数据。相反,使用getRaster()
方法,它完全符合您的要求:WritableRaster raster = mNewImage.getRaster();
Raster.setPixels(x, y, w, h, pixels)
方法需要一个数组每个数组元素包含一个样本(A、R、G 和 B 作为单独的样本)。这意味着您的数组长度仅为方法预期长度的四分之一,这最终是您看到的异常的原因。相反,因为你的数组是int
-packed ARGB 布局(这是你现在使用的类型的原生布局),你应该使用setDataElements
方法:raster.setDataElements(0, 0, mWidth, mHeight, mPixelData);
最后,我想指出的是,循环中的所有位移都会简单地将所有像素解压缩为单个组件(A、R、G 和 B),然后将它们重新组合在一起再次......所以,在这种情况下,
newRGB == rgb
。但是您可能打算稍后在此处添加颜色操作,在这种情况下它是有意义的。 :-)
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);