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

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

ただいまの
回答率

88.91%

Android(Kotlin)でCameraXで撮影した写真を指定した画像サイズで保存できません

受付中

回答 0

投稿

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

前提・実現したいこと

Androidのdevelopersドキュメントの
「CameraXを使ってみる」https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0
「CameraX設定」https://developer.android.com/training/camerax/configuration?hl=ja
を参考にして、画像キャプチャで撮影して、指定した画像サイズで保存する処理をKotlinで書いていますが、指定した画像サイズで保存されずに、スマホカメラの最大値のサイズで保存されてしまいます。
指定した画像サイズで保存する方法をご教示ください。

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

エラーメッセージは表示されません。
Logcatでも特にエラーの表示はありませんでした。

設定した画像サイズは、640 × 4801280 x 720 ですが、どれを指定しても
ストレージに保存された写真のサイズは、3264 x 2448 でした。 

該当のソースコード

class PhotoShootActivity : AppCompatActivity() {
 … 省略

    //プレビューと画像キャプチャのユースケースを実装
    // 以前の★4.View を作成するとき…と、★5.カメラを選択し…が以下に統合
    private fun startCamera() {
        //★3.CameraProviderをリクエストするで追加
        //  ProcessCameraProviderは、カメラのライフサイクルをライフサイクル所有者にバインドするために使用
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)

        //  //★4.View を作成するとき、CameraProviderが利用可能かどうかを確認
        //  リスナーをcameraProviderFutureに追加します。Runnableを1つの引数として追加します。
        cameraProviderFuture.addListener(Runnable {
            // Used to bind the lifecycle of cameras to the lifecycle owner
            // Runnableでは、ProcessCameraProviderを追加、
            // これは、アプリケーションプロセス内LifecycleOwnerにカメラのライフサイクルを結合するために使用
            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()

            //★5.カメラを選択してライフサイクルとユースケースをバインドします。
            // 5-1 Preview を作成します。 Preview オブジェクトを初期化
            preview = Preview.Builder().build()

            // Paste image capture code here!
            //アプリの写真撮影カメラを設定
            imageCapture = ImageCapture.Builder()
                .setTargetRotation(previewView.display.rotation)
                .build()

            // CameraSelectorオブジェクトを作成 Select back camera
            // 5-2 希望のカメラの LensFacing オプションを指定します。
            //  CameraSelector.Builder.requireLensFacingメソッドを使用して、 好みのレンズを渡します。
            val cameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()

            //撮影時の解像度を指定する
            val imageAnalysis = ImageAnalysis.Builder()
                .setTargetResolution(Size(1280, 720))
                .build()

            // tryブロックを作成します。
            // そのブロック内で、cameraProviderに何もバインドされていないことを確認してから、
            // プレビューオブジェクトをバインドします。
            try {
                // Unbind use cases before rebinding
                cameraProvider.unbindAll()

                // 5-3 選択したカメラとユースケースをライフサイクルにバインドします。
                camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, imageAnalysis, preview)
                // 5-4 Preview を プレビュー画面XMLタグ(previewView)PreviewView に接続します。
                preview?.setSurfaceProvider(previewView.createSurfaceProvider(camera?.cameraInfo))
            }

            //アプリがフォーカスされていない場合など、このコードが失敗する原因はいくつかあります。
            //catchブロックで囲み、障害が発生した場合にログに記録
            catch(exc: Exception) {
                Log.e(TAG, "Use case binding failed", exc)
            }

        }, ContextCompat.getMainExecutor(this))
    }

    //画像キャプチャで撮影して保存
    private fun takePhoto() {
        // Get a stable reference of the modifiable image capture use case
        // 画像キャプチャが設定される前に写真ボタンをタップすると、imageCaptureはnullになります。
        // このreturn文がないと、アプリはクラッシュするので、NULLチェック。
        val imageCapture = imageCapture ?: return

        // 画像を保持するファイル名をtimestampで作成
        val photoFile = File(
            outputDirectory,
            SimpleDateFormat(FILENAME_FORMAT, Locale.US
            ).format(System.currentTimeMillis()) + ".jpg")

        // Create output options object which contains file + metadata
        // 出力をどのようにするかについて指定できるOutputFileOptionsオブジェクトを作成します。
        // 上記のphotoFileに出力するので、photoFileを指定
        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        // Setup image capture listener which is triggered after photo has been taken
        // imageCaptureオブジェクトのtakePicture()の呼び出し。
        // 画像を保存するためのoutputOptions、executor、およびコールバックを渡します。
        imageCapture.takePicture(
            outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
                // イメージキャプチャが失敗、イメージキャプチャの保存が失敗した場合のエラーケースを追加
                // 失敗したことをログに記録
                override fun onError(exc: ImageCaptureException) {
                    Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                }
                // 正常なら前に作成したファイルに写真を保存し、成功したことをユーザーに知らせるトーストを提示
                // ログステートメントを記録
                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = Uri.fromFile(photoFile)

                    // 成功したことをユーザーに知らせるトーストを提示
                    val msg = "写真撮影成功!: $savedUri"
                    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
                    // ログステートメントを記録
                    val msg2 = "Photo capture succeeded: $savedUri"
                    Log.d(TAG, msg2)
                }
            })
    }

}

試したこと

・デバッグモードでアプリを起動して、実行状況を確認しましたが、
選択したカメラとユースケースをライフサイクルにバインドする処理
camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, imageAnalysis, preview)
で、撮影時の解像度imageAnalysisを指定しているにもかかわらず、指定したとおりに保存されません。
そもそも、保存時の出力画像には反映されないのでしょうか?
別途、保存時に画像のリサイズの処理が必要でしょうか?

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

Language : Kotlin
Minimum API level :API 22: Android 5.1 (Lollipop) 

Android Studio 4.0
Build #AI-193.6911.18.40.6514223, built on May 21, 2020
Runtime version: 1.8.0_242-release-1644-b01 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Windows 10 10.0

スマホ実機 機種
Plus One Japan Limited FTJ152A
Androidバージョン 5.1

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

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

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

関連した質問

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