🖼️
React(Next.js) で画像のプレビュー・圧縮を試す
こんにちは!この記事は GameWith アドベントカレンダー6日目の記事です!
React(Next.js) で画像のプレビューや、圧縮し Firebase Storage へのアップロードなどを試したので書いていこうと思います
画像のプレビュー
よくある画像のプレビューは、createObjectURL
を利用します
ファイルを丸ごと引数で渡して返ってきた URL をそのまま、img
の src
に渡せば画像が表示されます
export default function Create() {
const [preview, setPreview] = useState('');
const handleChangeFile = (e) => {
const { files } = e.target;
setPreview(window.URL.createObjectURL(files[0]));
};
return (
<img src={preview} />
<input
type="file"
name="photo"
onChange={handleChangeFile}
/>
)
}
ちなみに Next Image を利用すると、createObjectURL
は blob:http://localhost:3000/b2e0e749-3cda-4917-bee9-53a9f91ca59e
のような形式を返し、Next Image 側がドメインをうまくパースできずエラーになり利用することはできませんでした
よく見る画像のプレビュー
<input type="file">
を非表示にしつつ、No Image を出していい感じ見せる場合はこんな感じになります
.preview {
width: 300px;
height: 300px;
}
.previewImg {
object-fit: contain;
width: 100%;
height: 100%;
}
.inputPhoto {
display: none;
}
import styles from './create.module.css';
export default function Create() {
const [preview, setPreview] = useState('/img/no_image.png');
const handleChangeFile = (e) => {
const { files } = e.target;
setPreview(window.URL.createObjectURL(files[0]));
};
return (
<label htmlFor="photo">
<div className={styles.preview}>
<img src={preview} alt="preview" className={styles.previewImg} />
</div>
<input
id="photo"
type="file"
name="photo"
onChange={handleChangeFile}
className={styles.inputPhoto}
/>
</label>
)
}
画像圧縮&Firebase Storage へのアップロード
画像の圧縮はいろいろライブラリなどを調べたのですが、blueimp-load-image
を採用しました
Firebase Storage は Blob
のアップロードができるので、圧縮した画像を Canvas
で受け取り、toBlob
で Blob
に変換してアップロードします
import loadImage from 'blueimp-load-image';
import firebase from 'firebase/app';
export default function Create() {
const handleChangeFile = async (e) => {
const { files } = e.target;
const canvas = await loadImage(files[0], {
maxWidth: 1200,
canvas: true,
});
canvas.image.toBlob((blob) => {
firebase.storage().ref().child(`/${files[0].name}`).put(blob);
}, files[0].type);
};
return (
<input
type="file"
onChange={handleChangeFile}
/>
)
}
圧縮は 1.6MB の画像が、520KB くらいになったので結構満足しています!
最後に
圧縮はいろいろ調べていたのですが、最終的にかなりスッキリとしたコードになりました!
ありがとうライブラリ🙏
Discussion