How to serialize an object that includes BufferedImages
make your ArrayList<BufferedImage>
transient, and implement a custom writeObject()
method. In this, write the regular data for your ImageCanvas, then manually write out the byte data for the images, using PNG format.
class ImageCanvas implements Serializable {
transient List<BufferedImage> images;
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(images.size()); // how many images are serialized?
for (BufferedImage eachImage : images) {
ImageIO.write(eachImage, "png", out); // png is lossless
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
final int imageCount = in.readInt();
images = new ArrayList<BufferedImage>(imageCount);
for (int i=0; i<imageCount; i++) {
images.add(ImageIO.read(in));
}
}
}
Serializing an object that includes BufferedImages
The problem is likely that ImageIO.read(...)
incorrectly positions the stream after the first image read.
I see two options to fix this:
Rewrite the serialization of the
BufferedImage
s to write the backing array(s) of the image, height, width, color model/color space identifer, and other data required to recreate theBufferedImage
. This requires a bit of code to correctly handle all kinds of images, so I'll skip the details for now. Might be faster and more accurate (but might send more data).Continue to serialize using
ImageIO
, but buffer each write using aByteArrayOutputStream
, and prepend each image with its byte count. When reading back, start by reading the byte count, and make sure you fully read each image. This is trivial to implement, but some images might get converted or lose details (ie. JPEG compression), due to file format constraints. Something like:private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(imageSelection.size()); // how many images are serialized?
for (BufferedImage eachImage : imageSelection) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ImageIO.write(eachImage, "jpg", buffer);
out.writeInt(buffer.size()); // Prepend image with byte count
buffer.writeTo(out); // Write image
}
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
int imageCount = in.readInt();
imageSelection = new ArrayList<BufferedImage>(imageCount);
for (int i = 0; i < imageCount; i++) {
int size = in.readInt(); // Read byte count
byte[] buffer = new byte[size];
in.readFully(buffer); // Make sure you read all bytes of the image
imageSelection.add(ImageIO.read(new ByteArrayInputStream(buffer)));
}
}
Is It possible to Serialize an ArrayList of objects that contains a BufferedImage as one of the object's private instance variables in java?
yes u can, and why not?! but we will follow un-straight method and it worked fine with me
- it's known that primitive types and array of primitive types are all Serializable
- it's also known that we can convert a buffered image instance to a byte array and the inverse is also applicable
- so instead of serializing a buffered image we will serialize a byte array that represents this buffered image
I have created a demo that simulate your question
import java.awt.image.*;
import java.io.*;
import javax.imageio.ImageIO;
public class Member implements Serializable
{
private String name;
private byte[] imagebytes;
public Member(String name, BufferedImage image) throws IOException
{
this.name = name;
this.setImage(image);
}
public Member(String name, File imageFile) throws IOException
{
this.name = name;
this.setImage(imageFile);
}
public final void setImage(BufferedImage image) throws IOException
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", outputStream);
this.imagebytes = outputStream.toByteArray();
}
public final void setImage(File imageFile) throws IOException
{
BufferedImage bufferedImage = ImageIO.read(imageFile);
this.setImage(bufferedImage);
}
public BufferedImage getImage()
{
try
{
return ImageIO.read(new ByteArrayInputStream(imagebytes));
} catch (Exception io)
{
return null;
}
}
public String getName()
{
return name;
}
}
you can add methods as u like and customize this class as u need
i hope this answer is useful
Correct way to send BufferedImage in object with serialization. writeObject readObject
Your writeObject never writes to out. It writes to the ByteArrayOutputStream which is not used later
UPDATE
See e.g. the post how list of images is serialized. You can skip the count writing/reading
Serialize Obj with 2 BufferedImage transient fields, second image won't be read
The documentation for ImageIO.read states that the InputStream argument is wrapped in an ImageInputStream.
ImageInputStream is not the same as an InputStream. I don’t think you can safely assume that it only reads as far as it needs to; it may read ahead farther, for caching purposes, or perhaps in order to know what to return from its length() method.
In other words, after reading the first image, your InputStream may not be pointing to the exact byte where the second image starts.
One solution to this is to write byte arrays, rather than writing image data directly. The disadvantage is that it’s not scalable; if you have very large images, keeping them in memory will be a performance issue.
public class Person implements Serializable {
// ...
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject();
if (firstImage != null) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ImageIO.write(firstImage, "png", b);
out.writeInt(b.size());
b.writeTo(out);
System.out.println("First image saved.");
} else {
out.writeInt(0);
}
if (secondImage != null) {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ImageIO.write(secondImage, "png", b);
out.writeInt(b.size());
b.writeTo(out);
System.out.println("Second image saved.");
} else {
out.writeInt(0);
}
}
private void readObject(ObjectInputStream in)
throws IOException,
ClassNotFoundException {
in.defaultReadObject();
int length = in.readInt();
if (length > 0) {
byte[] bytes = new byte[length];
in.readFully(bytes);
firstImage = ImageIO.read(new ByteArrayInputStream(bytes));
}
length = in.readInt();
if (length > 0) {
byte[] bytes = new byte[length];
in.readFully(bytes);
secondImage = ImageIO.read(new ByteArrayInputStream(bytes));
}
}
}
As a side note, IOException and ClassNotFoundException should not be caught inside the serialization methods. They belong in the throws
clause of the method declaration. You don’t want your class pretending that serialization was successful when it didn’t actually succeed, after all. The details of the serialization methods’ signatures are described in the documentation for Serializable.
Serializing/Deserializing buffered images
Edit:Problem solved
Ended up converting the buffered images to a byte array then stuck them in a hash map and used some hash codes as keys.
Then serialized the hash map.
All good.
bufferedImage error while serializing and deserializing objects in Java
SOLVED: the problem was with class "test" in which I had used BufferedImage. the reason I got that error even tough I'd commented that part, was that before commenting that part, I had once run the program and as I was trying to deserialize that already made file, I encountered the error.
Serializing an ArrayList of Objects with BufferedImages
This was answered in the comments so I'll repost it here to close the question.
Mark the attributes you do not want to serialize as transient. V.g., private transient BufferedImage alienImage;. – SJuan76
Write to disk an object that contains a BufferedImage
Solved. It involved some other data that I didn't include in the code that I showed above. Your guys' comments helped me realize what the problem was, though.
It turns out that the BufferedImage there visible wasn't the problem at all. I had a pointer to another object which ALSO contained a BufferedImage, and it was that other BufferedImage (nested in another object) that was causing the OutputStream to throw its exception.
Moral of the story: ObjectOutputStream will serialize even deeply nested objects.
Related Topics
String Valueof VS Concatenation with Empty String
Find Maximum, Minimum, Sum and Average of a List in Java 8
How to Round Time to the Nearest Quarter Hour in Java
Why Is Files.Lines (And Similar Streams) Not Automatically Closed
Differences Between Runtime/Checked/Unchecked/Error/Exception
Why in Java Enum Is Declared as Enum<E Extends Enum<E>>
Concurrent Threads Adding to Arraylist at Same Time - What Happens
What Is the Purpose of Accesstype.Field, Accesstype.Property and @Access
How Are Servlet Url Mappings in Web.Xml Used
Is There Something Like Instanceof(Class<> C) in Java
Adding New Paths for Native Libraries at Runtime in Java
How to Mix --Class-Path and --Module-Path in Javac (Jdk 9)