2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ReactNativeで写真ライブラリから写真を取得する時に、加工して表示させる方法

Last updated at Posted at 2021-09-17

写真ライブラリから写真を取得し、自分の好きなサイズに加工して表示させる

ReactNativeで写真ライブラリから写真を取得する方法はいくつかありますが、その中で加工や編集も行えるライブラリを紹介します。
ライブラリのGitHub https://github.com/ivpusic/react-native-image-crop-picker

もともとreact-native-image-pickerというライブラリがあり、それを使えば「カメラを起動させるか」「写真ライブラリを開くか」の選択欄も出て、どちらも実装できる便利なものがありましたが、最近のアップデートで選択欄が出なくなったり何かと使いにくなりました。
image-pickerのGitHub https://github.com/react-native-image-picker/react-native-image-picker

またこのライブラリで写真を取得してもそのまま表示されるため、実際にアプリに入れてみないと調整が難しいです。
例えば、アイコンを設定する際に写真全体を表示するのではなく、右下の一部分だけを表示したいとなった時に、従来のimage-pickerだと、まず写真ライブラリ使う写真の加工をして、それを保存してから使わないといけません。
そこがimage-crop-pickerを使うことでアプリ側で加工するためのviewを挟んでくれるため、その場で写真の加工を行えます

実際に実装し、両方を比べてみる

実際にimage-pickerとimage-crop-pickerの両方を実装し、比べてみます。

1、ライブラリをインストール

react-native-image-crop-picker:```yarn add react-native-image-crop-picker

react-native-image-picker:```yarn add react-native-image-picker

このライブラリでは写真ライブラリにアクセスしたり、カメラを起動させるためinfo.plistに設定が必要です。

ios

iOSディレクトリ内のinfo.plistに追記してください

<key>NSPhotoLibraryUsageDescription</key>
<string>${プロジェクト名など} would like to upload photos from your photo gallery</string>
<key>NSCameraUsageDescription</key>
<string>${プロジェクト名など} requires to access camera for uploading photos to your profile or posts</string>
<key>NSPhotoLibraryAddUsageDescription</key>
 <string>${プロジェクト名など} would like to save photos to your photo gallery</string>
<key>NSMicrophoneUsageDescription</key>
<string>${プロジェクト名など}requires to access Audio recording to record and uplod videos</string>

コマンドラインで (cd ios && pod install)を打ち込む

ちなみに()で囲うことで現在のディレクトリから移動せずにpod installしてくれます。

あるあるなのがiosディレクトリにしたままyarn iosをしててエラーになるパターンです。
割と気づかず何でエラーなのか分からなくなってしまいます。

Android

AndroidManifest.xmlに以下を追記してください。

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2、コーディング

プロジェクトを作成し、今回用のファイルを用意します。

ライブラリをインポート

import ImagePicker from 'react-native-image-crop-picker';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';

image-pickerでは写真ライブラリを開きたいときはlaunchImageLibrary、カメラを起動するときはlaunchCameraを使用します。
launchCameraもインポートしている状態ですが、今回は使わないので必要ないです。

余談ですが、アプリなどのアイコンを設定する際に大体カメラを起動するか写真ライブラリから取得するか選択できると思いますが、その場でカメラを起動して撮った写真をアイコンに設定する人なんているんですかね。
僕は一度もカメラを使ったことないし、友人のアイコンを見る限り全員既存の写真を取得して使ってると思います(加工したものをアイコンに使うから)。

image-crop-pickerを実装

このonCropImageをonPressしたタイミングで呼び出せば写真ライブラリから取得できます。
openPickerの中身には現在は画像サイズなど初期の設定しかしてませんが、たくさん種類があるため自分の好みに合わせて色々付け加えてみてください。
https://github.com/ivpusic/react-native-image-crop-picker
取得時にsetImagePath内に格納してますがこれはuseStateで管理している値なので、今はエラーのままで大丈夫です。

const onCropImage = () => {
      ImagePicker.openPicker({
            width: 300,
            height: 300,
            cropping: true,
        }).then(image => {
        setImagePath(image.path)
      });
    }

image-pickerを実装

こちらもoptionsで色々設定できますが今回は説明を割愛します。
https://github.com/react-native-image-picker/react-native-image-picker

表示するためのuriはresponseのassetsの配列内にあるのでそこにある値をuseStateで管理します

const options = {
        mediaType: 'photo',
        maxWidth: 1000,
        maxHeight: 1000,
        quality: 0.8,
        saveToPhotos: true,
      };

      const choosePhoto = () => {
         launchImageLibrary(options, (response) => {
          if (response.didCancel) {
            console.log('User cancelled image picker');
          } else if (response.error) {
            console.log('ImagePicker Error: ', response.error);
          } else {
            console.log(response.assets[0].uri)
            setImagePath(response.assets[0].uri)
          }
        });
      }

全体を実装

今回アイコンをタップした際に出てくる選択欄(アクションシート)はライブラリを使って実装してますが、別の記事で実装方法を取り上げてるのでそこを参照ください。
https://qiita.com/flutter_daisuki/items/949869756b3d10944b7f

import React ,{useState}from 'react';
import {StyleSheet, TouchableOpacity, View,Image} from 'react-native';
import {ActionSheet} from 'react-native-cross-actionsheet';
import Icon from 'react-native-vector-icons/FontAwesome';
import ImagePicker from 'react-native-image-crop-picker';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';


export const ImageCropPicker = () => {
    const [imagePath ,setImagePath] = useState('') 

    const onCropImage = () => {
      ImagePicker.openPicker({
            width: 300,
            height: 300,
            cropping: true,
        }).then(image => {
        setImagePath(image.path)
      });
    }

    const options = {
        mediaType: 'photo',
        maxWidth: 1000,
        maxHeight: 1000,
        quality: 0.8,
        saveToPhotos: true,
      };

      const choosePhoto = () => {
         launchImageLibrary(options, (response) => {
          if (response.didCancel) {
            console.log('User cancelled image picker');
          } else if (response.error) {
            console.log('ImagePicker Error: ', response.error);
          } else {
            console.log(response.assets[0].uri)
            setImagePath(response.assets[0].uri)
          }
        });
      }
      
  const onPressAction = () => {
    return ActionSheet.options({
      options: [
        {text: 'image-picker', onPress:choosePhoto},
        {text: 'image-crop-picker', onPress:onCropImage},
      ],
      cancel: {text: 'キャンセル'},
    });
  };

  return (
    <View>
      <TouchableOpacity onPress={onPressAction}>
        <View style={styles.iconButton}>
        {imagePath ? (
            <Image style={styles.Photo} source={{uri: imagePath}} />
          ) : (
            <Icon style={styles.icon} name="user-o" size={70} />
          )}
        </View>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  iconButton: {
    borderWidth: 1,
    width: 100,
    height: 100,
    borderRadius: 100,
    marginLeft: 'auto',
    marginRight: 'auto',
  },
  icon: {
    marginLeft: 'auto',
    marginRight: 'auto',
    marginTop: 'auto',
    marginBottom: 'auto',
  },
  Photo: {
    width: 100,
    height: 100,
    borderRadius: 50,
  },
});

コードを解説するとアイコン全体をtouchableOpacityでタップできるようにし、タップした際にアクションシートを出すようにしています。
またアイコンはuseStateのimagePathがある場合はそのまま写真を表示するようにして、ない場合はIconを表示するようにしています。
三項演算子を使ってますが、めちゃくちゃ使う場面が多いのでぜひ覚えてください。

そして、アクションシート内で上をタップするとimage-pickerの処理が、下をタップするとimage-crop-pickerの処理が動くようになってます。

3、実際にどんな感じか確認してみる

初期画面
スクリーンショット 2021-09-07 18.06.57.png
タップ時
スクリーンショット 2021-09-07 18.07.20.png

image-pickerを選択時
スクリーンショット 2021-09-07 18.07.56.png
ライブラリが開き、右上の滝をタップすると
スクリーンショット 2021-09-07 18.08.06.png
表示されました!

ただ、今回は綺麗に映りましたが、もし写真の一部分だけをアイコンに使いたいのにこうされると思うようにアイコンが設定できないです。

image-crop-pickerを選択時
スクリーンショット 2021-09-07 18.10.30.png
ライブラリが開き、さっきと同じ滝の写真をタップすると。。。
スクリーンショット 2021-09-07 18.10.38.png

写真編集用のviewが出てきました!
滝を拡大させて、アイコンいっぱい滝にしよう
スクリーンショット 2021-09-07 18.10.56.png
スクリーンショット 2021-09-07 18.11.48.png
できました!
ユーザーのことを考えるとこっちの方がいいですね✨
皆さんもぜひ使ってみてください

補足

写真ライブラリから選んだ写真を加工することはできましたが、他にも
アプリ内でカメラを起動し、撮った写真を加工したい場合は

const onCropImage = () => {
      ImagePicker.openCamera({
            width: 300,
            height: 300,
            cropping: true,
        }).then(image => {
        setImagePath(image.path)
      });
    }

openPickerをopenCameraにするだけでオッケーです!!
このimage-crop-pickerというライブラリだけでアプリの画像設定はいけそうです

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?