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

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

ただいまの
回答率

90.47%

  • Android

    6634questions

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

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

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 41

2150087

score 0

 前提・実現したいこと

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

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

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

 該当のソースコード

SurfaceViewを継承したPaintViewクラス

package com.example.a2150023.kouki_eteam;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayDeque;
import java.util.Deque;


public class PaintView extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder mHolder;



    public Bitmap mLastDrawBitmap;
    private Canvas mLastDrawCanvas;
    public  Paint paint;
    public  Path path;
    //現在のカラー
    private String color = "black";

    //  次へ進む、前に戻るときのデータ(Path)を格納するスタック
    private Deque<Path> mUndoStack = new ArrayDeque<Path>();
    private Deque<Path> mRedoStack = new ArrayDeque<Path>();






    public PaintView(Context context, AttributeSet attrs){
        super(context, attrs);
        init();
    }



    public PaintView(Context context) {
        super(context);
        init();

    }


    private void init(){



        mHolder = getHolder();
        //背景を透過
        setZOrderOnTop(true);

        mHolder.setFormat(PixelFormat.TRANSPARENT);
        mHolder.addCallback(this);

        path = new Path();
        paint = new Paint();
        //ブラシの色
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setAntiAlias(true);
        //ブラシの幅
        paint.setStrokeWidth(10);
    }
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mLastDrawBitmap.recycle();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        clearLastDrawBitmap();
    }

    private void clearLastDrawBitmap(){
        //一つ前のBitmapがないとき
        if(mLastDrawBitmap == null){
            mLastDrawBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        }
        //一つ前のCanvasがないとき
        if(mLastDrawCanvas == null){
            mLastDrawCanvas = new Canvas(mLastDrawBitmap);
        }

        mLastDrawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
    }


    //タッチイベント
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        Log.d("onTouchEvent", "outouchevent発動");

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                onTouchDown(x, y);
                break;
            case MotionEvent.ACTION_MOVE:
                onTouchMove(x, y);
                break;
            case MotionEvent.ACTION_UP:
                onTouchUp(x, y);
                break;
        }
        return true;
    }

    private void onTouchDown(float x, float y){
        path = new Path();
        path.moveTo(x, y);
    }

    private void onTouchMove(float x, float y){
        path.lineTo(x, y);
        drawLine(path);

    }
    //指を離したとき
    private void onTouchUp(float x, float y){
        path.lineTo(x, y);
        drawLine(path);
        //一つ前のキャンバスのデータを保存
        mLastDrawCanvas.drawPath(path, paint);
        //戻るのスタックに現在のPathを格納
        mUndoStack.addLast(path);
        //次へのPathをクリア
        mRedoStack.clear();
    }
    //SurfaceViewのキャンバスに線を描画
    private void drawLine(Path path){
        Canvas canvas = mHolder.lockCanvas();

        canvas.drawColor(0, PorterDuff.Mode.CLEAR);



        //現在のキャンバスをビットマップにして表示
        canvas.drawBitmap(mLastDrawBitmap, 0, 0,null);
        //パス
        canvas.drawPath(path, paint);

        mHolder.unlockCanvasAndPost(canvas);
    }


    //ビットマップをキャンバスに表示
    public void canvasBitmapDraw(Bitmap bitmap){

        Canvas canvas = mHolder.lockCanvas();

        canvas.drawBitmap(bitmap,0,0,null);

        mHolder.unlockCanvasAndPost(canvas);
    }

    public void undo() {
        if (mUndoStack.isEmpty()) {
            return;
        }


        // undoスタックからパスを取り出し、redoスタックに格納します。
        Path lastUndoPath = mUndoStack.removeLast();
        mRedoStack.addLast(lastUndoPath);

        // ロックしてキャンバスを取得します。
        Canvas canvas = mHolder.lockCanvas();

        // キャンバスをクリアします。
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);

        // 描画状態を保持するBitmapをクリアします。
        clearLastDrawBitmap();



        // パスを描画します。
        for (Path path : mUndoStack) {
            canvas.drawPath(path, paint);
            mLastDrawCanvas.drawPath(path, paint);
        }

        // ロックを外します。
        mHolder.unlockCanvasAndPost(canvas);
    }

    public void redo() {
        if (mRedoStack.isEmpty()) {
            return;
        }

        // redoスタックからパスを取り出し、undoスタックに格納します。
        Path lastRedoPath = mRedoStack.removeLast();
        mUndoStack.addLast(lastRedoPath);

        // パスを描画します。
        drawLine(lastRedoPath);

        mLastDrawCanvas.drawPath(lastRedoPath, paint);
    }

    public void reset() {
        Log.d("RESET","RESET発動");
        mUndoStack.clear();
        mRedoStack.clear();

        clearLastDrawBitmap();

        Canvas canvas = mHolder.lockCanvas();
        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        mHolder.unlockCanvasAndPost(canvas);
    }





}


MainActivityクラスの一部

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent resultData) {

        if (requestCode == REQUEST_SAVE_IMAGE && resultCode == Activity.RESULT_OK) {
            if(resultData.getData() != null){

                Uri uri = resultData.getData();

                // Uriを表示
                Toast toast = Toast.makeText(getApplicationContext(), String.format(Locale.US, "Uri: %s",uri.toString()),Toast.LENGTH_SHORT);
                toast.show();

                try(OutputStream outputStream =
                            getContentResolver().openOutputStream(uri);) {

          //mPaintViewはPaintViewクラスをインスタンス化したもの
                    //ここでビューの画面をキャプチャーする
          //おそらくここで問題が発生
                    mPaintView.setDrawingCacheEnabled(true);
                    Bitmap cache = mPaintView.getDrawingCache();
                    final Bitmap screenShot = Bitmap.createBitmap(cache);
                    mPaintView.setDrawingCacheEnabled(false);

                    //png形式にして保存する
                    //サンプルの画像は保存できたので、ここは問題ない
                    screenShot.compress(Bitmap.CompressFormat.PNG , 100, outputStream);

                } catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

 試したこと

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

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

開発環境はAndroidStudio 3.2.1

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

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

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

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Android

    6634questions

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