【问题标题】:Serializing and De-Serializing android.graphics.Bitmap in Java在 Java 中序列化和反序列化 android.graphics.Bitmap
【发布时间】:2011-08-17 19:22:46
【问题描述】:

我已经开始开发我的第一个 android 应用程序,并且拥有处理具有多个层的图像的应用程序的基础。我可以将项目文件的平面版本导出为 PNG,但我希望能够保存分层图像以供以后编辑(包括应用于某些图层的任何选项,例如基于文本的图层)。

无论如何,我已确保需要写入文件的类是“可序列化”的,但由于 android.graphics.Bitmap 不可序列化这一事实而遇到了一些障碍。以下代码实质上将位图作为 PNG 输出到 ByteArray 中,并应将其作为“readObject”的一部分读回。但是,当代码运行时——我可以验证读入的“imageByteArrayLength”变量与输出的变量相同——但“位图图像”始终为空。

任何帮助将不胜感激。感谢阅读。

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

【问题讨论】:

    标签: java android serialization


    【解决方案1】:

    花了一段时间,但我找到了解决这个问题的干净方法。我生成了一个自定义对象 (BitmapDataObject),它实现了 Serializable 并有一个 byte[] 来存储来自原始 Bitmap 的 PNG 数据。使用它,数据被正确地存储在 ObjectOutputStream / ObjectInputStream - 这有效地允许通过将位图对象作为 PNG 存储在自定义对象中的字节 [] 中来序列化和反序列化。下面的代码解决了我的查询。

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

    【讨论】:

    • 我不认为这段代码代表了如何正确使用可序列化。
    【解决方案2】:

    这是一个可以包装位图的可序列化对象的示例。

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

    【讨论】:

      【解决方案3】:

      只需使用此代码创建一个类 BitmapDataObject。使用 getter 和 setter 在 Bitmap 和 BitmapDataObject 类之间切换。

      import android.graphics.Bitmap;
      import android.graphics.BitmapFactory;
      
      import java.io.ByteArrayOutputStream;
      import java.io.IOException;
      import java.io.Serializable;
      
      public class BitmapDataObject implements Serializable {
      
          private Bitmap currentImage;
      
          public Bitmap getCurrentImage() {
              return currentImage;
          }
      
          public void setCurrentImage(Bitmap currentImage) {
              this.currentImage = 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);
          }
      
      }
      

      【讨论】: