masalibの日記

システム開発、運用と猫の写真ブログです

React Firebase入門 アバター変更:画像切り抜き

アバターの画像は基本的には正方形です。画像をアップする時に画像を切り抜きする機能を追加しました

React Firebase入門シリーズ
1-1・ React Firebase入門 初期設定とsignup - masalibの日記
1-2・ 「react-hook-form」を入れてみた - masalibの日記
1-3・ React Firebase入門 signupの通信エラー対応 - masalibの日記
2・ React Firebase入門 ログイン処理 - masalibの日記
3・ React Firebase入門 ログイン認証とログアウト処理 - masalibの日記
4・ React Firebase入門 パスワード初期化処理 - masalibの日記
5・ React Firebase入門 メールアドレスの有効化 - masalibの日記
6・ React Firebase入門 メールアドレスとパスワード変更 - masalibの日記
7・ React Firebase入門 表示名変更 - masalibの日記
8-1・ React Firebase入門 アバター変更:基礎 - masalibの日記
8-2・React Firebase入門 アバター変更:画像切り抜き 今ここ

画像切り抜きとは

特定の画像から必要な部分たけを取り込む事です。

ブロガーさんなら誰しもがおこなった事がある作業だと思います

画像切り抜き機能の変更について

ソース

ソースの全文をみたいひとはこちら
https://github.com/masalib/Learn-Firebase/blob/updateProfire_image_modal/src/components/UpdateProfile.js

ソース解説

画像処理がメインです

画像選択の処理の変更

今までは画像を選択するとすぐにFirebaseに反映していましたが そちらを一度、画面上に展開します。 画像の展開が終わるとモーダルが表示されて、画像の切り抜き画面が表示しています。

    const handleImage = e => {
        //const image = e.target.files[0];
        e.preventDefault();
        let files;
        if (e.dataTransfer) {
             files = e.dataTransfer.files;
        } else if (e.target) {
         files = e.target.files;
        }
        const reader = new FileReader();
        reader.onload = () => {
            setImage(reader.result);
        };
        reader.readAsDataURL(files[0]);
        setOpen(true)
    };

モーダル表示

モーダルは@material-uiのmodalの機能を使っておこないました

modalを開いたり閉じたりする時の関数です。

    const handleClose = () => {setOpen(false);};
    const handleOpen = () => {setOpen(true);};
<Modal
    aria-labelledby="transition-modal-title"
    aria-describedby="transition-modal-description"
    className={classes.modal}
    open={open}
    onClose={handleClose}
    closeAfterTransition
    BackdropComponent={Backdrop}
    BackdropProps={{
    timeout: 500,
    }}
>
・・・
</Modal>

これでもモーダル表示ができます。なおModalの中は必ずjsx形式にしないといけないので間違えても

test

しか入れていない内容だとエラーになります

material ui の modal で Cannot read property 'hasOwnProperty' of undefined

qiita.com

画像切り抜き画面

react-cropperというツールで切り抜きをおこなっています

react-cropperのサンプル通りつくりました

<Cropper
    style={{ height: 400, width: "100%" }}
    initialAspectRatio={1}
    preview=".img-preview"
    src={image}
    viewMode={1}
    guides={true}
    minCropBoxHeight={10}
    minCropBoxWidth={10}
    background={false}
    responsive={true}
    autoCropArea={1}
    checkOrientation={false} 
    onInitialized={(instance) => {
        setCropper(instance);
    }}
/>

画像切り抜いた画像をFirebaseにアップする

切り抜いた画像はData URL string形式になっています。

Data URL string形式の例

data:text/plain;base64,5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB

普通のputではアップできないのでputStringとう関数でアップしました

    const getCropData  = async(e) => {
        e.preventDefault();
        if (typeof cropper !== "undefined") {
        //console.log(cropper.getCroppedCanvas().toDataURL())
            let imagedata = await cropper.getCroppedCanvas().toDataURL()
            console.log(imagedata)
            // アップロード処理
            console.log("アップロード処理");
            const storages = app.storage();//storageを参照
            const storageRef = storages.ref("images/users/" + currentUser.uid + "/");//どのフォルダの配下に入れるか
            const imagesRef = storageRef.child("profilePicture.png");//ファイル名

            console.log("ファイルをアップする行為");
            //const upLoadTask = imagesRef.put(imagedata);
            const upLoadTask = imagesRef.putString(imagedata, 'data_url');


            console.log("タスク実行前");

            upLoadTask.on(
                "state_changed",
                (snapshot) => {
                    console.log("snapshot", snapshot);
                },
                (error) => {
                    console.log("err", error);
                },
                () => {
                    upLoadTask.snapshot.ref.getDownloadURL().then((downloadURL) => {
                    //console.log("File available at", downloadURL);
                    const url = new URL(downloadURL)
                    console.log(url.href + url.pathname + "?alt=media")
                    dispatch({
                        type: "setPhotoURL",
                        payload: url.href + url.pathname + "?alt=media"
                        });
                    });
                    setOpen(false);
                }
            );
        }
    };

結果

f:id:masalib:20201201012101g:plain

感想

画像切り抜きができた事でアスペクト比が必ず一致するのでアバターとして使いやすいです。
アスペクト比は本当に大切です。

4:3でお願いします。」

とユーザーにお願いしていても

33:3 という画像でアップするという意味のわからない事がする人もいます。

どうしてそうなったと思うレベルなのですが、実際にあった怖い話です。そんなユーザーも回避できる神機能です。本当によかった。