将JavaFX Image对象转换为字节数组

6
我们可以通过以下方式创建FX Image对象:
byte [] bytes = ------; //valid image in bytes
javafx.scene.image.Image image = new Image(new ByteArrayInputStream(bytes));

同样的方式也可以应用到 ImageView 上。

我需要相反的操作,不需要先将其转换为 BufferedImage (SwingFXUtils.fromFXImage(image,null))。

这样我就能直接将字节写入文件。

我尝试过以下方法:

PixelReader pixelReader = image.getPixelReader();
    int width = (int)image.getWidth();
    int height = (int)image.getHeight();
    byte[] buffer = new byte[width * height * 4];
    pixelReader.getPixels(
            0,
            0,
            width,
            height,
            PixelFormat.getByteBgraInstance(),
            buffer,
            0,
            width * 4
    );

然而,通过写入byte []缓冲区生成的文件不是有效的图像。

对此有何见解?

编辑:如何从javafx ImageView获取byte []中给出的解决方案不能应用于我的问题。正如我已经清楚地提到的那样,我不想使用SwingFXUtils将其转换为BufferedImage。 此外,我想将其转换为字节数组,以便将其写入图像文件。


3
可能是如何从JavaFX ImageView获取byte[]?的重复问题。 - Destrif
2个回答

7
这是较晚的时间,但如果有人想了解,请尝试以下方法:
// Load the Image into a Java FX Image Object //

Image img = new Image(new FileInputStream("SomeImageFile.png") );

// Cache Width and Height to 'int's (because getWidth/getHeight return Double) and getPixels needs 'int's //

int w = (int)img.getWidth();
int h = (int)img.getHeight();

// Create a new Byte Buffer, but we'll use BGRA (1 byte for each channel) //

byte[] buf = new byte[w * h * 4];

/* Since you can get the output in whatever format with a WritablePixelFormat,
   we'll use an already created one for ease-of-use. */

img.getPixelReader().getPixels(0, 0, w, h, PixelFormat.getByteBgraInstance(), buf, 0, w * 4);

/* Second last parameter is byte offset you want to start in your buffer,
   and the last parameter is stride (in bytes) per line for your buffer. */

1
使用 ByteArrayInputStream 创建 JavaFX Image 只能使用原始的、未修改的图像文件字节,支持的格式有 bmp,jpg,gif,png
在使用 PixelReader 读取 Image 后,字节数组将包含原始的图像字节,只能使用 PixelWriter 将其写回到 WritableImage 中,这就是为什么使用 ByteArrayInputStream 会产生无效图像的原因。
下面是一个可重现的示例,使用了这个 image
// Original image bytes
File file = new File("F:/Downloads/duke.png");
byte[] fileBytes = Files.readAllBytes(file.toPath());
System.out.println(fileBytes.length);  // 17776 bytes
InputStream in = new ByteArrayInputStream(fileBytes);
Image image = new Image(in);
ImageView view = new ImageView(image);
VBox pane = new VBox();
pane.getChildren().add(view);  // Works
in.close();

// PixelReader generated image bytes
int width = (int) image.getWidth();
int height = (int) image.getHeight();
byte[] pixelBytes = new byte[width * height * 4];
System.out.println(pixelBytes.length);  // 367928 bytes
image.getPixelReader().getPixels(0, 0, width, height,
        PixelFormat.getByteBgraInstance(),
        pixelBytes, 0, width * 4);
Image image2 = new Image(new ByteArrayInputStream(pixelBytes));
ImageView view2 = new ImageView(image2);
pane.getChildren().add(view2);  // Won't work

// PixelWriter generated image
WritableImage image3 = new WritableImage(width, height);
image3.getPixelWriter().setPixels(0, 0, width, height,
        PixelFormat.getByteBgraInstance(),
        pixelBytes, 0, width * 4);
ImageView view3 = new ImageView(image3);
pane.getChildren().add(view3);  // Works

Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();

作为原始图像格式,PixelReader 图像比原始图像大得多,因此,如果您将这些图像存储在数据库中并且关心空间,则应尝试存储原始文件字节。否则,SwingFXUtils 类仍然可以用于转换回压缩格式。
另一个问题是,在写回 PixelReader 图像字节时,您必须以某种方式存储宽度和高度,可以将其作为数据库中的单独字段存储,也可以将其作为额外的字节附加到图像字节数组上。

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