質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

0回答

696閲覧

SurfaceViewを継承したクラスのViewをキャプチャしてBitmapに変換して保存する方法について

2150087

総合スコア10

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2018/11/07 05:57

前提・実現したいこと

Androidでペイントソフトを作成しています。現在その中で描いた絵を保存する機能を作成しています。

発生している問題・エラーメッセージ

SurfaceViewを継承したクラスの画面をキャプチャして、それをBitmapに変換して保存する機能を実装したのですが、しかしファイル自体は保存されても、ファイルの中身が無く一面真っ黒な画像が表示されるのみです。どうすれば正常に画像が保存されるでしょうか。

該当のソースコード

SurfaceViewを継承したPaintViewクラス

java

1package com.example.a2150023.kouki_eteam; 2 3import android.content.Context; 4import android.graphics.Bitmap; 5import android.graphics.Canvas; 6import android.graphics.Color; 7import android.graphics.Paint; 8import android.graphics.Path; 9import android.graphics.PixelFormat; 10import android.graphics.PorterDuff; 11import android.util.AttributeSet; 12import android.util.Log; 13import android.view.MotionEvent; 14import android.view.SurfaceHolder; 15import android.view.SurfaceView; 16import java.util.ArrayDeque; 17import java.util.Deque; 18 19 20public class PaintView extends SurfaceView implements SurfaceHolder.Callback { 21 22 private SurfaceHolder mHolder; 23 24 25 26 public Bitmap mLastDrawBitmap; 27 private Canvas mLastDrawCanvas; 28 public Paint paint; 29 public Path path; 30 //現在のカラー 31 private String color = "black"; 32 33 // 次へ進む、前に戻るときのデータ(Path)を格納するスタック 34 private Deque<Path> mUndoStack = new ArrayDeque<Path>(); 35 private Deque<Path> mRedoStack = new ArrayDeque<Path>(); 36 37 38 39 40 41 42 public PaintView(Context context, AttributeSet attrs){ 43 super(context, attrs); 44 init(); 45 } 46 47 48 49 public PaintView(Context context) { 50 super(context); 51 init(); 52 53 } 54 55 56 private void init(){ 57 58 59 60 mHolder = getHolder(); 61 //背景を透過 62 setZOrderOnTop(true); 63 64 mHolder.setFormat(PixelFormat.TRANSPARENT); 65 mHolder.addCallback(this); 66 67 path = new Path(); 68 paint = new Paint(); 69 //ブラシの色 70 paint.setColor(Color.BLACK); 71 paint.setStyle(Paint.Style.STROKE); 72 paint.setStrokeJoin(Paint.Join.ROUND); 73 paint.setStrokeCap(Paint.Cap.ROUND); 74 paint.setAntiAlias(true); 75 //ブラシの幅 76 paint.setStrokeWidth(10); 77 } 78 @Override 79 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 80 81 } 82 83 @Override 84 public void surfaceDestroyed(SurfaceHolder holder) { 85 mLastDrawBitmap.recycle(); 86 } 87 88 @Override 89 public void surfaceCreated(SurfaceHolder holder) { 90 clearLastDrawBitmap(); 91 } 92 93 private void clearLastDrawBitmap(){ 94 //一つ前のBitmapがないとき 95 if(mLastDrawBitmap == null){ 96 mLastDrawBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); 97 } 98 //一つ前のCanvasがないとき 99 if(mLastDrawCanvas == null){ 100 mLastDrawCanvas = new Canvas(mLastDrawBitmap); 101 } 102 103 mLastDrawCanvas.drawColor(0, PorterDuff.Mode.CLEAR); 104 } 105 106 107 //タッチイベント 108 @Override 109 public boolean onTouchEvent(MotionEvent event) { 110 float x = event.getX(); 111 float y = event.getY(); 112 113 Log.d("onTouchEvent", "outouchevent発動"); 114 115 switch (event.getAction()) { 116 case MotionEvent.ACTION_DOWN: 117 onTouchDown(x, y); 118 break; 119 case MotionEvent.ACTION_MOVE: 120 onTouchMove(x, y); 121 break; 122 case MotionEvent.ACTION_UP: 123 onTouchUp(x, y); 124 break; 125 } 126 return true; 127 } 128 129 private void onTouchDown(float x, float y){ 130 path = new Path(); 131 path.moveTo(x, y); 132 } 133 134 private void onTouchMove(float x, float y){ 135 path.lineTo(x, y); 136 drawLine(path); 137 138 } 139 //指を離したとき 140 private void onTouchUp(float x, float y){ 141 path.lineTo(x, y); 142 drawLine(path); 143 //一つ前のキャンバスのデータを保存 144 mLastDrawCanvas.drawPath(path, paint); 145 //戻るのスタックに現在のPathを格納 146 mUndoStack.addLast(path); 147 //次へのPathをクリア 148 mRedoStack.clear(); 149 } 150 //SurfaceViewのキャンバスに線を描画 151 private void drawLine(Path path){ 152 Canvas canvas = mHolder.lockCanvas(); 153 154 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 155 156 157 158 //現在のキャンバスをビットマップにして表示 159 canvas.drawBitmap(mLastDrawBitmap, 0, 0,null); 160 //パス 161 canvas.drawPath(path, paint); 162 163 mHolder.unlockCanvasAndPost(canvas); 164 } 165 166 167 //ビットマップをキャンバスに表示 168 public void canvasBitmapDraw(Bitmap bitmap){ 169 170 Canvas canvas = mHolder.lockCanvas(); 171 172 canvas.drawBitmap(bitmap,0,0,null); 173 174 mHolder.unlockCanvasAndPost(canvas); 175 } 176 177 public void undo() { 178 if (mUndoStack.isEmpty()) { 179 return; 180 } 181 182 183 // undoスタックからパスを取り出し、redoスタックに格納します。 184 Path lastUndoPath = mUndoStack.removeLast(); 185 mRedoStack.addLast(lastUndoPath); 186 187 // ロックしてキャンバスを取得します。 188 Canvas canvas = mHolder.lockCanvas(); 189 190 // キャンバスをクリアします。 191 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 192 193 // 描画状態を保持するBitmapをクリアします。 194 clearLastDrawBitmap(); 195 196 197 198 // パスを描画します。 199 for (Path path : mUndoStack) { 200 canvas.drawPath(path, paint); 201 mLastDrawCanvas.drawPath(path, paint); 202 } 203 204 // ロックを外します。 205 mHolder.unlockCanvasAndPost(canvas); 206 } 207 208 public void redo() { 209 if (mRedoStack.isEmpty()) { 210 return; 211 } 212 213 // redoスタックからパスを取り出し、undoスタックに格納します。 214 Path lastRedoPath = mRedoStack.removeLast(); 215 mUndoStack.addLast(lastRedoPath); 216 217 // パスを描画します。 218 drawLine(lastRedoPath); 219 220 mLastDrawCanvas.drawPath(lastRedoPath, paint); 221 } 222 223 public void reset() { 224 Log.d("RESET","RESET発動"); 225 mUndoStack.clear(); 226 mRedoStack.clear(); 227 228 clearLastDrawBitmap(); 229 230 Canvas canvas = mHolder.lockCanvas(); 231 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 232 mHolder.unlockCanvasAndPost(canvas); 233 } 234 235 236 237 238 239}

MainActivityクラスの一部

Java

1@Override 2 public void onActivityResult(int requestCode, int resultCode, Intent resultData) { 3 4 if (requestCode == REQUEST_SAVE_IMAGE && resultCode == Activity.RESULT_OK) { 5 if(resultData.getData() != null){ 6 7 Uri uri = resultData.getData(); 8 9 // Uriを表示 10 Toast toast = Toast.makeText(getApplicationContext(), String.format(Locale.US, "Uri: %s",uri.toString()),Toast.LENGTH_SHORT); 11 toast.show(); 12 13 try(OutputStream outputStream = 14 getContentResolver().openOutputStream(uri);) { 15 16          //mPaintViewはPaintViewクラスをインスタンス化したもの 17 //ここでビューの画面をキャプチャーする 18          //おそらくここで問題が発生 19 mPaintView.setDrawingCacheEnabled(true); 20 Bitmap cache = mPaintView.getDrawingCache(); 21 final Bitmap screenShot = Bitmap.createBitmap(cache); 22 mPaintView.setDrawingCacheEnabled(false); 23 24 //png形式にして保存する 25 //サンプルの画像は保存できたので、ここは問題ない 26 screenShot.compress(Bitmap.CompressFormat.PNG , 100, outputStream); 27 28 } catch(Exception e){ 29 e.printStackTrace(); 30 } 31 } 32 } 33 }

試したこと

SurfaceViewをキャプチャして、Bitmapに変換した画像ではなく、試しにリソースからBitmap画像を引っ張ってきてcompress(Bitmap.CompressFormat.PNG , 100, outputStream);をしてみたら正常に保存できたので、SurfaceViewをBitmapに変換する過程で失敗しているのかと思われます。

補足情報(FW/ツールのバージョンなど)

開発環境はAndroidStudio 3.2.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問