Sibainu Relax Room

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

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

今日は柴犬はお休みです。彼は別に病気とかではないですが、ただちょっと前の写真になってしまうのでカモにします。近くの公園に接する用水路で親ガモが2羽でその周りに子ガモたくさんいます。元気に育っているようです。

概要

FtpAccess では私の今の技量ではうまくいきませんでした。FtpAccessB を修正して次の  FtpAccessC にしたところエミュレートではうまくいきましたので記録します。

1冊のみでは理解に苦しいところがあるので更に新しく本を購入しました。

WEBのみでは断片的で覚えにくいので最初に購入した Kotlin の本です。

FtpAccessC

引数にアップロードするファイルの InputStream を加えることにしました。

copy

    public void FtpAccessC(String filename, InputStream ips) {

        Map<String, String> ftpmap = new HashMap<>();
        ftpmap.put("ftpUsername",FTPUSERNAME);
        ftpmap.put("ftpPassword",FTPPASSWORD);
        ftpmap.put("ftpServer",FTPSERVER);
        ftpmap.put("ftpDirectory",FTPDIRECTORY);
        ftpmap.put("filename",filename);

        Log.d(TAG, "FtpAccessC");

        new FtpAsyncTaskC(){
            @Override
            protected void onPostExecute(String response) {
                TextView tv = findViewById(R.id.tvinfo);
                //アップロードしたフォルダーのファイル一覧を表示します。
                tv.setText(response);
            }
        }.execute(new FtpTaskParamsC(ftpmap, ips));
    }

//--------------------------------
    public class FtpTaskParamsC {
        InputStream _ips;
        Map<String, String> _ftpData;
        public FtpTaskParamsC(Map<String, String> ftpData, InputStream ips) {
            this._ips = ips;
            this._ftpData = ftpData;
            Log.d(TAG, "FtpTaskParamsC");
        }
    }


//--------------------------------
    public class FtpAsyncTaskC extends AsyncTask<FtpTaskParamsC, String, String> {
        @Override
        protected String doInBackground(FtpTaskParamsC... params) {
            Map<String, String> ftpData = params[0]._ftpData;
            InputStream _ips = params[0]._ips;
            final String _ftpUsername = ftpData.get("ftpUsername");
            final String _ftpPassword = ftpData.get("ftpPassword");
            final String _ftpServer = ftpData.get("ftpServer");
            final String _ftpDirectory = ftpData.get("ftpDirectory");
            final String _filename = ftpData.get("filename");
            Log.d(TAG, "FtpAsyncTaskC");

            //ファイルの一覧表を返します
            ArrayList<String> infolist = new ArrayList<>();
            FTPClient ftpClient = new FTPClient();

            try {
                Log.d(TAG, _ftpServer);
                //デフォルト ポートでリモート ホストに接続され、システムに割り当てられたポートで現在のホストから発信されるソケットを開きます
                ftpClient.connect(_ftpServer);
                Log.d(TAG, _ftpServer);
                //指定されたユーザーとパスワードを使用して FTP サーバーにログインします
                ftpClient.login(_ftpUsername, _ftpPassword);
                Log.d(TAG, _ftpPassword);
                //データ転送を行うために接続するデータ ポートを開くようにサーバーに指示されます
                ftpClient.enterLocalPassiveMode();

                //多くの FTP サーバーはデフォルトで BINARY になっています
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
                //文字化け対策
                ftpClient.setControlEncoding("CP932");

                Log.d("ServerFileAccess", ftpClient.getStatus());

                //ディレクトリ移動
                ftpClient.changeWorkingDirectory(_ftpDirectory);
                Log.d(TAG, _ftpDirectory);
                //
                String[] filenames;
                filenames = ftpClient.listNames();

                for (String filename : filenames) {
                    Log.d("ServerFileAccess", filename);
                    infolist.add(filename);
                }

                //NASにファイルをアップロード
                try {
                    // staoreFile関数の呼び出しでアップロードする。
                    ftpClient.storeFile(_filename, _ips);
                    // ログ出力
                    Log.d(TAG, "Upload - " + _filename);
                    infolist.add("Upload - " + _filename);
                } catch(Exception e) {
                    e.printStackTrace();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                Log.d("ServerFileAccess", "finally");
                infolist.add("処理を終了します");
                try {
                    ftpClient.logout();
                    ftpClient.disconnect();
                } catch (Exception e) {
                    Log.d(TAG, "FTP開放エラー :", e);
                }
            }
            return join("\n",infolist);
        }
    }

takePhoto/
imagecapture.takePicture

アップロード非同期処理を行う FtpAccessC 関数の引数に InputStream を加えました。

キャプチャー画像の URI が分かっているので resolver.openInputStream で InputStram を取得します。

copy

    private final String FTPUSERNAME = "sora";
    private final String  FTPPASSWORD = "Ryu<0220>Siba";
    private final String FTPSERVER = "192.168.0.5";
    private final String FTPDIRECTORY = "photo/JIJISora/";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        略
    }

    private void startCamera() {
        略
    }

    @UiThread
    private void takePhoto() {
        略
        // 撮影後にトリガーされる画像キャプチャのリスナーを設定する
        imagecapture.takePicture(
                outputOptions,
                ContextCompat.getMainExecutor(this),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onError(ImageCaptureException error) {
                        Log.e(TAG, "Photo capture failed: " + error.toString(), error);
                    }
                    @Override
                    public void onImageSaved(ImageCapture.OutputFileResults outputFileResults) {

                        CharSequence msg = "Photo capture succeeded: " + outputFileResults.getSavedUri();
                        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
                        Log.d(TAG, 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");
                            // アップロード非同期処理
                            FtpAccessC(name + ".jpg", ips);
                        } catch (Exception ex) {
                            Log.d(TAG, "アップロードエラー :", ex);
                        }
                    }
                });
    }

エミュレートの状況

エミュレートの段階ではうまくいっているようです。

左が起動時の画面、右がボタン「Shutter」をクリックした時です。結果が表示されるまでに30秒程要しているのが気になります。

activity_main.xml

テキストビューをスクロールで表示できるようにしました。

ガイドラインを設定して形が崩れないようにしました。

copy

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.camera.view.PreviewView
        android:id="@+id/viewFinder"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/guideline2"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0"
        tools:layout_editor_absoluteX="-2dp" />

    <Button
        android:id="@+id/bt_shutter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/bt_shutter"
        app:layout_constraintBottom_toTopOf="@+id/scrollView2"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintHorizontal_bias="0.25"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/guideline2" />

    <ScrollView
        android:id="@+id/scrollView2"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_marginTop="65dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/viewFinder"
        app:layout_constraintVertical_bias="0.0">

        <TextView
            android:id="@+id/tvinfo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TextView" />
    </ScrollView>

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.3" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.6" />


</androidx.constraintlayout.widget.ConstraintLayout>

NAS

NAS の保存状況です。

次の画像は、保存ファイルのそのままです。

幅 960px  高さ1280px  ファイルサイズ 220 KB (226,301 バイト) となりました。テスト画像がそうなのか、高解像度にするにどうすればいいのか今後調べていきたいと思います。