画像選択時のプレビュー表示とExif対応のhook版
問題
Javascriptで画像ファイルを選択させた後に、クライアントのみで画像プレビューを出すのは簡単だが、縦横が実際の画像とは違って表示される(orientation)問題がある。
exifのorientationを考慮しないサンプル
PreviewImageTest.tsx
// 選択した画像ファイルを表示するだけ
// これだと画像のorientationを見ていないので、回転のかかった画像では縦横が変に表示される
import React from "react"
interface Props {}
const PreviewImageTest: React.FC<Props> = props => {
const [url, setUrl] = React.useState(null)
return (
<>
<input
type="file"
accept="image/*"
onChange={({ target: { validity, files } }) => {
if (validity.valid) {
// 単純にFileオブジェクトから表示可能なURLを作ってるだけ
setUrl(URL.createObjectURL(files[0]))
}
}}
/>
{url ? (
<img
src={url}
style={{ width: "100%" }}
onLoad={() => {
// メモリ解放
URL.revokeObjectURL(url)
}}
/>
) : null}
</>
)
}
export default PreviewImageTest
解決方法
PreviewImageTest.tsx
// 選択した画像ファイルを表示するだけ
// これだと画像のorientationを見ていないので、回転のかかった画像では縦横が変に表示される
import React from "react"
interface Props {}
const PreviewImageTest: React.FC<Props> = props => {
const [url, setUrl] = React.useState(null)
return (
<>
<input
type="file"
accept="image/*"
onChange={({ target: { validity, files } }) => {
if (validity.valid) {
// 単純にFileオブジェクトから表示可能なURLを作ってるだけ
setUrl(URL.createObjectURL(files[0]))
}
}}
/>
{url ? (
<img
src={url}
style={{ width: "100%" }}
onLoad={() => {
// メモリ解放
URL.revokeObjectURL(url)
}}
/>
) : null}
</>
)
}
export default PreviewImageTest
を使う。
useExifOrientation.tsx
import React from "react"
import loadImage from "blueimp-load-image"
// canvas.toBlobが対応で無い場合はこれが必要
// https://developer.mozilla.org/ja/docs/Web/API/HTMLCanvasElement/toBlob
// import "blueimp-canvas-to-blob" SSRでなければここに
interface Props {
image: File | string
}
const useExifOrientation = ({ image }: Props) => {
const [src, setSrc] = React.useState<null | string>(null)
React.useEffect(() => {
if (typeof image === "string") {
// 単なるurl文字ならそのまま返す
setSrc(image)
}
// SSRでは[window undefined]問題があるのでここで動的にロード
// そうでなければファイル上部に通常通り
// import "blueimp-canvas-to-blob"
// で問題ない
import("blueimp-canvas-to-blob").then(() => {
// blueimp-load-imageの関数[loadImage]を使い、
loadImage(
image,
canvas => {
// このcallback内でcanvasが返ってくるので
// toBlobを使ってblobをとり、そのblobからcreateObjectURLでurlを作る
canvas.toBlob(
blob => {
const src = URL.createObjectURL(blob)
setSrc(src)
},
// png画像の場合はblobにするのが遅いので、JPEG表示にする
"image/jpeg",
// JPEGの圧縮を利かせる 80%
0.8
)
},
// orientationを利かせる これだけで縦横がちゃんと表示される
// orientationを設定すると、cropの指定が必要?みたい
{ orientation: true, crop: false }
)
})
}, [image])
return src
}
export default useExifOrientation
PreviewImageTest.tsx
import React from "react"
import useExifOrientation from "./useExifOrientation"
interface OrientedImgProps {
image: File
}
const OrientedImg: React.FC<OrientedImgProps> = ({ image }) => {
const src = useExifOrientation({ image })
return (
<img
src={src}
style={{ width: "100%" }}
onLoad={() => {
URL.revokeObjectURL(src)
}}
/>
)
}
interface Props {}
const PreviewImageTest: React.FC<Props> = props => {
const [file, setFile] = React.useState<File | null>(null)
return (
<>
<input
type="file"
accept="image/*"
onChange={({ target: { validity, files } }) => {
if (validity.valid) {
setFile(files[0])
}
}}
/>
<OrientedImg image={file} />
</>
)
}
export default PreviewImageTest
Author And Source
この問題について(画像選択時のプレビュー表示とExif対応のhook版), 我々は、より多くの情報をここで見つけました https://qiita.com/github0013@github/items/eff3893598b22e7ff278著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .