Sibainu Relax Room

愛犬の柴犬とともに過ごす部屋

Android Java で CameraX の写真をキャプチャ3

今回もよく頑張ったなと言ってくれいる柴犬です。

前回のアプリを実行

撮影後にトリガーされる画像キャプチャのリスナーを設定する imagecapture.takePicture から全く動きません。

エミュレートでは全く問題なく最後まで実行されましたが、動きません。

左が起動直後の画像で、右がシャッターボタン「Shutter」をタップして実行させたところです。

やってみたこと

ContentValues の設定の見直し

        // ContentValuesオブジェクトを生成。
        ContentValues values = new ContentValues();

        // 画像ファイル名を設定。
        values.put(MediaStore.Images.Media.TITLE, name);

        // 画像ファイルの表示名を設定。
        values.put(MediaStore.Images.Media.DISPLAY_NAME, name);

        // 画像ファイルの種類を設定。
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

        // 共有ストレージに保存するパス
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image");
        }

ImageCapture.OutputFileOptions.Builder() の引数関係の見直し

        // file + metadata 出力オプション・オブジェクトの作成
        ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(resolver,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                values).build();

imagecapture.takePicture の引数関係の見直し

        // 撮影後にトリガーされる画像キャプチャのリスナーを設定する
        imagecapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {省略});

ここまで、いろいろやってみましたが大同小異で状況に変わりはありません。

次に、何かが邪魔をしているのではないかと考えました。

ContentValues values を適当な位置で削除することにしました。

values.clear();

を入れることにしました。

やりました最後まで実行されました。完了表示まで1秒もかかりませんでした。

takePhoto

うまくいったコードです。

いろいろ触りましたのでごちゃごちゃしています。

copy

    private void takePhoto() {

        if (imagecapture == null) {
            return;
        }
        Log.d(TAG, "imagecapture");
        tv.setText("キャプチャ・保存処理中");

        // 一意の名前にしなければならないのでミリ秒までつかいます。
        SimpleDateFormat dateFormat = new SimpleDateFormat(FILENAME_FORMAT, Locale.JAPAN);

        // 現在の日時を取得。
        Date now = new Date(System.currentTimeMillis());

        // 取得した日時データを「yyyyMMddHHmmssSSS」形式に整形した文字列を生成。
        String nowStr = dateFormat.format(now);

        // ストレージに格納する画像のファイル名を生成。ファイル名の一意を確保するためにタイムスタンプの値を利用。
        String name = "Photo_" + nowStr;
        Log.d(TAG,name);
        tv.setText("ファイル名 :" + name);

        //↓↓↓↓↓ ContentValuesオブジェクトを生成開始。
        ContentValues values = new ContentValues();

        // 画像ファイル名を設定。
        values.put(MediaStore.Images.Media.TITLE, name);

        // 画像ファイルの表示名を設定。
        values.put(MediaStore.Images.Media.DISPLAY_NAME, name);

        // 画像ファイルの種類を設定。
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");

        // 共有ストレージに保存するパス
        // P  Constant Value: 28
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            //values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image");
            values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/CameraX-Image");
        }
        //↑↑↑↑↑オブジェクトを生成終り
        Log.d(TAG,"共有ストレージパス");

        // ContentResolverオブジェクトを生成。
        ContentResolver resolver = getContentResolver();
        Log.d(TAG,"resolver");

        // ContentResolverを使って URI を取得(予約)
        imageuri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        Log.d(TAG,"imageuri");
        tv.setText("URI :" + imageuri.toString());


        // file + metadata 出力オプションオブジェクトの作成
        ImageCapture.OutputFileOptions outputOptions = new ImageCapture.OutputFileOptions.Builder(
                //resolver,
                getContentResolver(),
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                //imageuri,  エラー
                values).build();

        // これがないとキャプチャーでエラーになります。
        values.clear();

        Log.d(TAG,"outputOptions");
        tv.setText("アウトプットオプション");

        //シャッター音追
        MediaActionSound sound = new MediaActionSound();
        sound.load(MediaActionSound.SHUTTER_CLICK);

        // 撮影後にトリガーされる画像キャプチャのリスナーを設定する
        imagecapture.takePicture(
                outputOptions,
                //Executors.newSingleThreadExecutor(),
                ContextCompat.getMainExecutor(MainActivity.this),
                //キャプチャー処理がなされた後のコールバックオブジェクト
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onError(ImageCaptureException e) {
                        Log.e(TAG, "Photo capture failed: " + e.toString(), e);
                        tv.setText("キャプチャーエラー");
                    }
                    @Override
                    public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) {
                        CharSequence msg = "Photo capture succeeded: " + outputFileResults.getSavedUri();
                        Log.d(TAG, msg.toString());
                        tv.setText(msg.toString());
                        // Uriの取得
                        Uri uri = Uri.parse(outputFileResults.getSavedUri().toString());
                        try {
                            Log.d(TAG,"begin try");
                            InputStream ips = resolver.openInputStream(uri);
                            Log.d(TAG,"InputStream");
                            //シャッター音の追加
                            sound.play(MediaActionSound.SHUTTER_CLICK);
                            // アップロード非同期処理
                            FtpAccessC(name + ".jpg", ips);
                        } catch (Exception ex) {
                            Log.d(TAG, "アップロードエラー :", ex);

                        }
                    }
                });
    }

NAS

NAS を見てみると確かに保存されています。

今回ここまでとします。