将图像读入像素数组,然后写回文件

时间:2015-06-11 15:01:21

标签: java image

我正在做一个示例程序来读取图像文件并将像素细节存储到整数数组中,然后将数据写回另一个文件。

但是当我打开生成的输出文件时,它只显示一些随机颜色,而不是显示原始图像。

这是我的计划:

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class MainApp {

    public static void main(String[] args) throws IOException {
        String filename = "input.jpeg";

        // Reading the image into byte array
        BufferedImage bimg = ImageIO.read(new File(filename));
        int width = bimg.getWidth();
        int height = bimg.getHeight();

        Raster raster = bimg.getData();

        byte[] byteArray = readImageToArray(bimg);
        // Convert the byte array into integer array           
        int[] array = raster.getPixels(0, 0, width,height,new int[byteArray.length]);

        // Writing the image to another file.
        writeImageFromArray(array, width, height);
    }

    public static byte[] readImageToArray(BufferedImage bimg){
        DataBufferByte data = (DataBufferByte) bimg.getRaster().getDataBuffer();
        byte[] byteArray = data.getData();
        return byteArray;

    }

    public static void writeImageFromArray(int[] pixels, int width, int height) {
        BufferedImage image = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_ARGB);

        File outputfile = new File("image.jpg");
        try {
            ImageIO.write(image, "jpg", outputfile);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

我对图像处理完全不熟悉,请帮助我在这段代码中犯错的地方。

更新

我修改了我的代码,它写了一个像这样的图像文件:

   public static void writeImageFromArray(int[] pixels, int width, int height) {
        File outputfile = new File("output.jpeg");
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        WritableRaster raster = (WritableRaster) image.getData();
        raster.setPixels(0,0,width,height,pixels);

        try {
            ImageIO.write(image, "jpeg", outputfile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

但现在我得到一个例外:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 151194
    at java.awt.image.SinglePixelPackedSampleModel.setPixels(SinglePixelPackedSampleModel.java:685)
    at java.awt.image.WritableRaster.setPixels(WritableRaster.java:565)
    at MainApp.writeImageFromArray(MainApp.java:40)
    at MainApp.main(MainApp.java:27)

1 个答案:

答案 0 :(得分:0)

原因是底层的 SampleModel 不兼容。 BufferedImage 实际上使用 IntegerInterleavedRaster 和 SinglePixelPackedSampleModel 作为示例模型,但我不会依赖它,因为它很可能依赖于实现。

相反,我建议使用与缓冲图像相同的样本模型从像素数据创建数据栅格,然后将其提供给缓冲图像。此外,通过这种方式,您也不需要获取和转换缓冲图像的内部数据栅格(= 类型安全)。

public static void writeImageFromArray(int[] pixels, int width, int height) throws IOException {
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    Raster raster = Raster.createRaster(image.getSampleModel(), new DataBufferInt(pixels, pixels.length), null);
    image.setData(raster);
    File outputFile = new File("output.jpeg");
    ImageIO.write(image, "jpeg", outputFile);
}

我遇到了同样的异常消息,并以上述方式解决了问题。


我刚刚注意到您的图像读取代码也有一些小错误。例如,方法 readImageToArray 实际上没有做任何事情。当然,您必须确保输入图像的图像类型也是 TYPE_INT_ARGB。否则,您必须相应地转换字节。

// open the image
File inputFile = new File("input.jpeg");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
// get the pixel data as integer array, presumingly ARGB
int[] pixels = (int[]) image.getData().getDataElements(0, 0, width, height, null);
// do something with the pixels
...

在您的情况下,使用 getPixels 实际上会返回一个四倍于所有像素大小的数组,因为对于每个像素,将添加四个条目(R、G、B、A)。再次注意,这取决于输入图像的颜色模型。例如,灰度图像通常只有一个颜色通道。请注意,您不必自己创建输出数组。

// get the pixel component data as integer array, presumingly RGBA
int[] pixelComponents = image.getData().getPixels(0, 0, width, height, (int[]) null);

另一种可能是使用 BufferedImage 的 getRGB 和 setRGB 方法。在这种情况下,无论图像的底层颜色模型是什么,像素格式始终为 ARGB。因此,这大概是在二进制级别操作像素数据的最安全方法。

// open the image
File inputFile = new File("input.jpeg");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
// get the pixel data as integer array (always ARGB)
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
// do something with the pixels
...
// optionally create a new image instance
// image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// write back the pixel data (always ARGB)
image.setRGB(0, 0, width, height, pixels, 0, width);
// save the image
File outputFile = new File("output.jpeg");
ImageIO.write(image, "jpeg", outputFile);

最后,我想指出您也可以使用 2D 图形绘制来直接处理图像。

Graphics2D graphics = (Graphics2D) image.getGraphics();