Serializing and De-Serializing Android.Graphics.Bitmap in Java

Serializing and De-Serializing android.graphics.Bitmap in Java

It took a while, but I have found a clean solution to this problem. I produced a custom object (BitmapDataObject) that implements Serializable and has a byte[] to store the PNG data from the original Bitmap. Using this, the data is stored correctly in the ObjectOutputStream / ObjectInputStream - which effectively allows one to Serialize and Deserialize a Bitmap object by storing it as a PNG in a byte[] in a custom object. The code below resolves my query.

private String title;
private int sourceWidth, currentWidth;
private int sourceHeight, currentHeight;
private Bitmap sourceImage;
private Canvas sourceCanvas;
private Bitmap currentImage;
private Canvas currentCanvas;
private Paint currentPaint;

protected class BitmapDataObject implements Serializable {
private static final long serialVersionUID = 111696345129311948L;
public byte[] imageByteArray;
}

/** Included for serialization - write this layer to the output stream. */
private void writeObject(ObjectOutputStream out) throws IOException{
out.writeObject(title);
out.writeInt(currentWidth);
out.writeInt(currentHeight);

ByteArrayOutputStream stream = new ByteArrayOutputStream();
currentImage.compress(Bitmap.CompressFormat.PNG, 100, stream);
BitmapDataObject bitmapDataObject = new BitmapDataObject();
bitmapDataObject.imageByteArray = stream.toByteArray();

out.writeObject(bitmapDataObject);
}

/** Included for serialization - read this object from the supplied input stream. */
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
title = (String)in.readObject();
sourceWidth = currentWidth = in.readInt();
sourceHeight = currentHeight = in.readInt();

BitmapDataObject bitmapDataObject = (BitmapDataObject)in.readObject();
Bitmap image = BitmapFactory.decodeByteArray(bitmapDataObject.imageByteArray, 0, bitmapDataObject.imageByteArray.length);

sourceImage = Bitmap.createBitmap(sourceWidth, sourceHeight, Bitmap.Config.ARGB_8888);
currentImage = Bitmap.createBitmap(sourceWidth, sourceHeight, Bitmap.Config.ARGB_8888);

sourceCanvas = new Canvas(sourceImage);
currentCanvas = new Canvas(currentImage);

currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thumbnailPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thumbnailPaint.setARGB(255, 200, 200, 200);
thumbnailPaint.setStyle(Paint.Style.FILL);
}

Object not deserializing

As per the comment by user, Every ChessPiece has a Bitmap

The Bitmaps in Java are not serializable either add a transient keyword before those Bitmap objects or if you want to serialize Bitmaps look below links for more help

Serializing and De-Serializing android.graphics.Bitmap in Java

android how to save a bitmap - buggy code

Problem serializing Drawable

java.io.NotSerializableException: android.graphics.drawable.BitmapDrawable

This message seems pretty clear - the specific drawable instance in the photo field is a BitmapDrawable, which wasn't designed to be serialized. Your class cannot be serialized without dealing with the non-serializable field.

If you can ensure your class will always have a BitmapDrawable or a Bitmap, you can see this code for an example of how to handle a Bitmap field:

android how to save a bitmap - buggy code

Android how to save a bitmap - buggy code

Here is the code for a serialization with memory optimisation. Im using a static buffer that is growing to the biggest bitmap size and that I reuse each time.

public class Video implements Serializable{
public long videoId;
public String title;
public String publisher;
public String language;
public Date lastModified;
public Date published;
public String imageUrl;
public String url;
public Bitmap myVideoScreenshotBm;
public Date expireTime;
//public Drawable myVideoScreenshotDrawable;

private static ByteBuffer dst;
private static byte[] bytesar;

public Video (long newVideoId) {
this.videoId=newVideoId;
}
private void writeObject(ObjectOutputStream out) throws IOException{

out.writeLong(videoId);

out.writeObject(title);
out.writeObject(publisher);
out.writeObject(language);
out.writeObject(lastModified);
out.writeObject(published);
out.writeObject(expireTime);

out.writeObject(imageUrl);
out.writeObject(url);

out.writeInt(myVideoScreenshotBm.getRowBytes());
out.writeInt(myVideoScreenshotBm.getHeight());
out.writeInt(myVideoScreenshotBm.getWidth());

int bmSize = myVideoScreenshotBm.getRowBytes() * myVideoScreenshotBm.getHeight();
if(dst==null || bmSize > dst.capacity())
dst= ByteBuffer.allocate(bmSize);

out.writeInt(dst.capacity());

dst.position(0);

myVideoScreenshotBm.copyPixelsToBuffer(dst);
if(bytesar==null || bmSize > bytesar.length)
bytesar=new byte[bmSize];

dst.position(0);
dst.get(bytesar);

out.write(bytesar, 0, bytesar.length);

}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{

videoId=in.readLong();

title=(String) in.readObject();
publisher=(String) in.readObject();
language=(String) in.readObject();
lastModified=(Date) in.readObject();
published=(Date) in.readObject();
expireTime=(Date) in.readObject();

imageUrl = (String) in.readObject();
url = (String) in.readObject();

int nbRowBytes=in.readInt();
int height=in.readInt();
int width=in.readInt();

int bmSize=in.readInt();

if(bytesar==null || bmSize > bytesar.length)
bytesar= new byte[bmSize];

int offset=0;

while(in.available()>0){
offset=offset + in.read(bytesar, offset, in.available());
}

if(dst==null || bmSize > dst.capacity())
dst= ByteBuffer.allocate(bmSize);
dst.position(0);
dst.put(bytesar);
dst.position(0);
myVideoScreenshotBm=Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
myVideoScreenshotBm.copyPixelsFromBuffer(dst);
//in.close();
}

}

How does Bitmap compress work in android?

A bitmap doesn't HAVE to be compressed, but compressing them achieves two goals: It serializes them and it makes them smaller.

Bit maps are just .... maps of bits ... As trivial as it is, consider this:

If you had an image of 1000 x 1000, and each pixel represented a color using a short. (that's just an example, so roll with me). Now imagine that each pixel in this picture is WHITE.

If you serialized this without compressing then the file would store something like:
height:1000,width:1000,content:WHITE,WHITE,WHITE,WHITE,WHITE,WHITE,WHITE,WHITE,.........

Serializing depends on the algorithm used, but let's say you use a variation of the LZW and use one int to indicate how many pixels are in the set and the color. In this case, all you had to save to the compressed file are height:1000,width:1000,content:1000000xWHITE. Which could be easily saved in a few bytes.

Google App Engine with Android Bitmap class

It looks like you're serializing the data using Java's built in serialization support. Deserializing data in this way requires having the class definitions for the serialized object available, which obviously isn't the case on App Engine.

Instead, you should encode the bitmap in a standard format, such as PNG, and decode it as you would any other image on the App Engine end.

How can I start a new Android activity without sending savedInstanceState?

Finally, it was my readObject and writeObject which were not adapted for the serialization of the bitmap. I found an alternative way, but there is some performance issue (4 or 5 second to return to the list) : Serializing and De-Serializing android.graphics.Bitmap in Java



Related Topics



Leave a reply



Submit