使用 WritableRaster 和 DataBufferByte 将图像转换为 Java 中的 byte[] 时出错。
Error while converting image to byte[] in Java using WritableRaster and DataBufferByte.
我正在尝试使用代码
将图像转换为 byte[]
public static byte[] extractBytes(String ImageName) throws IOException {
// open image
File imgPath = new File(ImageName);
BufferedImage bufferedImage = ImageIO.read(imgPath);
// get DataBufferBytes from Raster
WritableRaster raster = bufferedImage.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return (data.getData());
}
当我使用代码测试它时
public static void main(String[] args) throws IOException {
String filepath = "image_old.jpg";
byte[] data = extractBytes(filepath);
System.out.println(data.length);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
File outputfile = new File("image_new.jpg");
ImageIO.write(img, "jpeg", outputfile);
}
我得到 data.length = 4665600 并收到错误
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1591)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
at com.medianet.hello.HbaseUtil.main(HbaseUtil.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
但是当我将 extractBytes 代码更改为
public static byte[] extractBytes (String ImageName) throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedImage img=ImageIO.read(new File(ImageName));
ImageIO.write(img, "jpg", baos);
baos.flush();
return baos.toByteArray();
}
我得到 data.length = 120905 并获得成功(image.jpg 在所需位置创建)
问题是,extractBytes
的第一个版本读取一个图像,只是 returns 图像的像素作为一个字节数组(假设它使用 DataBufferByte
)。这些字节不是文件格式,如果没有额外的信息,如宽度、高度、颜色space等,这些字节是无用的。ImageIO
无法读回这些字节,因此,[=返回 14=](并分配给 img
,随后导致 ImageIO.write(...)
的 IllegalArgumentException
)。
第二个版本对图像进行解码,然后再次以 JPEG 格式对其进行编码。这是一种 ImageIO
能够读取的格式,并且您会如您所愿得到一张图像(分配给 img
)。
但是,您的代码似乎只是一种非常非常昂贵的 CPU 复制图像的方式(您解码图像,然后编码,然后再次解码,最后编码)...对于 JPEG 文件这个 decode/encode 循环也会降低图像质量。除非您计划将图像数据用于任何用途,并且只想将图像从一个地方复制到另一个地方,否则不要使用 ImageIO
和 BufferedImage
。这些类型用于图像处理。
这是您的主要方法的修改版本:
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[1024];
File inFile = new File("image_old.jpg");
File outFile = new File("image_new.jpg");
InputStream in = new FileInputStream(inFile);
try {
OutputStream out = new FileOutputStream(outFile);
try {
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
finally {
out.close();
}
}
finally {
in.close();
}
}
(可以使用 Java 7 中的 try-with-resources 或 Java 8 中的 NIO2 Files.copy
优雅地编写此 better/more,但我保留了给你。:-) )
我正在尝试使用代码
将图像转换为 byte[]public static byte[] extractBytes(String ImageName) throws IOException {
// open image
File imgPath = new File(ImageName);
BufferedImage bufferedImage = ImageIO.read(imgPath);
// get DataBufferBytes from Raster
WritableRaster raster = bufferedImage.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return (data.getData());
}
当我使用代码测试它时
public static void main(String[] args) throws IOException {
String filepath = "image_old.jpg";
byte[] data = extractBytes(filepath);
System.out.println(data.length);
BufferedImage img = ImageIO.read(new ByteArrayInputStream(data));
File outputfile = new File("image_new.jpg");
ImageIO.write(img, "jpeg", outputfile);
}
我得到 data.length = 4665600 并收到错误
Exception in thread "main" java.lang.IllegalArgumentException: image == null!
at javax.imageio.ImageTypeSpecifier.createFromRenderedImage(ImageTypeSpecifier.java:925)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1591)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
at com.medianet.hello.HbaseUtil.main(HbaseUtil.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
但是当我将 extractBytes 代码更改为
public static byte[] extractBytes (String ImageName) throws IOException {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedImage img=ImageIO.read(new File(ImageName));
ImageIO.write(img, "jpg", baos);
baos.flush();
return baos.toByteArray();
}
我得到 data.length = 120905 并获得成功(image.jpg 在所需位置创建)
问题是,extractBytes
的第一个版本读取一个图像,只是 returns 图像的像素作为一个字节数组(假设它使用 DataBufferByte
)。这些字节不是文件格式,如果没有额外的信息,如宽度、高度、颜色space等,这些字节是无用的。ImageIO
无法读回这些字节,因此,[=返回 14=](并分配给 img
,随后导致 ImageIO.write(...)
的 IllegalArgumentException
)。
第二个版本对图像进行解码,然后再次以 JPEG 格式对其进行编码。这是一种 ImageIO
能够读取的格式,并且您会如您所愿得到一张图像(分配给 img
)。
但是,您的代码似乎只是一种非常非常昂贵的 CPU 复制图像的方式(您解码图像,然后编码,然后再次解码,最后编码)...对于 JPEG 文件这个 decode/encode 循环也会降低图像质量。除非您计划将图像数据用于任何用途,并且只想将图像从一个地方复制到另一个地方,否则不要使用 ImageIO
和 BufferedImage
。这些类型用于图像处理。
这是您的主要方法的修改版本:
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[1024];
File inFile = new File("image_old.jpg");
File outFile = new File("image_new.jpg");
InputStream in = new FileInputStream(inFile);
try {
OutputStream out = new FileOutputStream(outFile);
try {
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
finally {
out.close();
}
}
finally {
in.close();
}
}
(可以使用 Java 7 中的 try-with-resources 或 Java 8 中的 NIO2 Files.copy
优雅地编写此 better/more,但我保留了给你。:-) )