Serializar y desializar android.graphics.Bitmap en Java

Empecé a trabajar en una de mis primeras aplicaciones de Android y tengo la base de una aplicación que maneja una imagen con varias capas. Puedo exportar una versión plana del archivo de proyecto como PNG, pero me gustaría poder guardar la imagen en capas para su posterior edición (incluidas las opciones aplicadas a ciertas capas, como las capas basadas en texto).

De todos modos, me he asegurado de que las clases que deben escribirse en un archivo sean ‘Serializables’, pero se han topado con un bloque de ruta causado por el hecho de que android.graphics.Bitmap no es serializable. El siguiente código esencialmente genera el Bitmap como PNG en un ByteArray y debería volver a leerlo como parte de ‘readObject’. Sin embargo, cuando se ejecuta el código, puedo verificar que la variable ‘imageByteArrayLength’ que se lee es la misma que la salida, pero la ‘Imagen de bitmap’ siempre es nula.

Cualquier ayuda sería muy apreciada. Gracias por leer.

private String title; private int width; private int height; private Bitmap sourceImage; private Canvas sourceCanvas; private Bitmap currentImage; private Canvas currentCanvas; private Paint currentPaint; private void writeObject(ObjectOutputStream out) throws IOException{ out.writeObject(title); out.writeInt(width); out.writeInt(height); ByteArrayOutputStream stream = new ByteArrayOutputStream(); currentImage.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] imageByteArray = stream.toByteArray(); int length = imageByteArray.length; out.writeInt(length); out.write(imageByteArray); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{ this.title = (String)in.readObject(); this.width = in.readInt(); this.height = in.readInt(); int imageByteArrayLength = in.readInt(); byte[] imageByteArray = new byte[imageByteArrayLength]; in.read(imageByteArray, 0, imageByteArrayLength); BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.ARGB_8888; Bitmap image = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArrayLength, opt); sourceImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); currentImage = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); sourceCanvas = new Canvas(sourceImage); currentCanvas = new Canvas(currentImage); currentPaint = new Paint(Paint.ANTI_ALIAS_FLAG); if ( image != null ) { sourceCanvas.drawBitmap(image, 0, 0, currentPaint); } } 

Me tomó un tiempo, pero encontré una solución limpia a este problema. Produje un objeto personalizado (BitmapDataObject) que implementa Serializable y tiene un byte [] para almacenar los datos PNG del bitmap original. Al usar esto, los datos se almacenan correctamente en ObjectOutputStream / ObjectInputStream, lo que permite a Serialize y Deserialize un objeto Bitmap almacenandolo como PNG en un byte [] en un objeto personalizado. El siguiente código resuelve mi consulta.

 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); } 

Aquí hay un ejemplo de un objeto serializable que puede envolver mapas de bits.

 public class BitmapDataObject implements Serializable { private Bitmap currentImage; public BitmapDataObject(Bitmap bitmap) { currentImage = bitmap; } private void writeObject(java.io.ObjectOutputStream out) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream(); currentImage.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] byteArray = stream.toByteArray(); out.writeInt(byteArray.length); out.write(byteArray); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { int bufferLength = in.readInt(); byte[] byteArray = new byte[bufferLength]; int pos = 0; do { int read = in.read(byteArray, pos, bufferLength - pos); if (read != -1) { pos += read; } else { break; } } while (pos < bufferLength); currentImage = BitmapFactory.decodeByteArray(byteArray, 0, bufferLength); } }