Bitmap から PNG 形式でファイルへ保存する方法

このページでは Bitmap に描画した内容を、ファイルに出力し保存する方法を紹介します。

ここでは PNG 形式のファイルとして書き出すことを考えます。

PNG 形式で保存するには、実はクラスの compress メソッドを呼び出すだけで OK です。

このメソッドがサポートしているファイルフォーマットは3種類です。PNG 形式、JPEG 形式、WebP 形式です。

ちなみに、WebP 形式というのは Google 社が開発を進めている新しいファイルフォーマットで、ロスレス、ロスあり (lossy) の両圧縮形式をサポートしています。 PNG や JPEG などよりもファイルサイズが小さくなると言われているものです。

ここでは従来の PNG を使います。

オフスクリーン・キャンバスの利用によるお絵かきソフトの開発」で作ったサンプルを拡張して、 お絵かきしたイメージを、PNG ファイルで保存します。

オプションメニューに "SAVE" ボタンを追加して、これを押したときにその時点で描画されている内容を新しいファイルとして出力します。

Bitmap から PNG 形式でファイルへ保存する方法

オプションメニューを実装する方法については、「オプションメニュー」を参考にしてください。 今回はメニュー (res/menu/main.xml) を次のように作成しています。

<menu
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  tools:context="com.example.canvastest3.MainActivity" >
  <item
    android:id="@+id/action_save"
    android:orderInCategory="10"
    android:showAsAction="ifRoom"
    android:title="@string/action_save"/>
</menu>

また保存 (Save) という文字列は文字列リソース (res/values/strings.xml) に action_save という名前で記述しています。

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="app_name">CanvasTest3</string>
  <string name="hello_world">Hello world!</string>
  <string name="action_save">Save</string>
    <string-array name="color_array">
      <item>Blue</item>
      <item>Green</item>
      <item>Red</item>
    </string-array>
</resources>

メニューの showAsAction 属性で ifRoom とすることで、場所がある時にメニュー項目がドロップダウンにならずに "SAVE" というボタンを押せるようになります。

さてここから本題です。前述の通り Bitmap から PNG 形式のファイルに保存するのは簡単です。

コードは次の通りです。CanvasTest3View.java に次のメソッドを追加しました。

  public void saveAsPngImage(){
    try {
      File extStrageDir =
        Environment.getExternalStorageDirectory();
      File file = new File(
        extStrageDir.getAbsolutePath()
          + "/" + Environment.DIRECTORY_DCIM,
        getFileName());
      FileOutputStream outStream = new FileOutputStream(file);
      bitmap.compress(CompressFormat.PNG, 100, outStream);
      outStream.close();

      Toast.makeText(
        context,
        "Image saved",
        Toast.LENGTH_SHORT).show();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  protected String getFileName(){
    Calendar c = Calendar.getInstance();
    String s = c.get(Calendar.YEAR)
      + "_" + (c.get(Calendar.MONTH)+1)
      + "_" + c.get(Calendar.DAY_OF_MONTH)
      + "_" + c.get(Calendar.HOUR_OF_DAY)
      + "_" + c.get(Calendar.MINUTE)
      + "_" + c.get(Calendar.SECOND)
      + "_" + c.get(Calendar.MILLISECOND)
      + ".png";
    return s;
  }
}

ポイントは Bitmap の compress メソッドに、画像フォーマットの指定と、ファイル出力用のストリームを渡すところです。

ファイルの保存先として、外部ストレージディレクトリを getExternalStorageDirectory() メソッドで取得し、その直下の DCIM フォルダに保存しています。 AndroidManifest.xml にて、android.permission.WRITE_EXTERNAL_STORAGE のパーミッションを指定してください。

一般的に Java でファイルに書き出す方法については、Java 入門 の「基本的な IO」などを参考にしてください。

一応、これだけで描画した内容はファイルに保存されるのですが、背景部分が透明になってしまいます。これでは画面に表示されている状況と異なってしまっているので、 onSizeChanged でビットマップを作成した時に Canvas の drawColor メソッドを用いて白で埋めておくと良いでしょう。

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  canvas = new Canvas(bitmap);		
  canvas.drawColor(0xFFFFFFFF);
}

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Android 開発入門