Serializing and De-Serializing android.graphics.Bitmap

John WordsworthAndroid Dev3 Comments

I recently took it upon myself to write a small application, a bit like Photoshop Express, for Android as a mechanism for learning how to develop on the Android platform. One problem that I stumbled across along was with saving (and subsequently loading) my custom images, which could consist of a number of different layers.

At the heart of my application were a number of layers which consisted of android.graphics.Bitmap layers. I wanted to be able to save (serialize) this data without simply saving the masses of raw binary data from the Bitmap object (which would have been obscenely large).

The following code shows the solution that I came up with. The following code gives an example of how to save a single layer from the application, but as this makes the object serializable, it’s easy then to save a number of these layers into a single file.

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; 

/** This container class makes it easy to serialize / de-serialize the raw PNG bytes. */
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);
}

This solution essentially forces the Bitmap object to compress itself to a ByteArrayOutputStream which we use to store the byte data of the resulting PNG compressed version of the file. There may be a better way to do this, but next up I wrapped this data in a custom object (BitmapDataObject) which can then hook into the standard serializable properties that Java presents to us.

Quite niche I know, but I hope that this saves someone out an hour or two.

John WordsworthSerializing and De-Serializing android.graphics.Bitmap

3 Comments on “Serializing and De-Serializing android.graphics.Bitmap”

Leave a Reply

Your email address will not be published. Required fields are marked *