やりたいこと
Vueでアップした画像を加工したりBlobにしたりしてプレビューも見せたい。
画像処理にはJimpを利用しました。
Blobにするのはフォームから送信するのが前提だったから。
準備
Jimpをインストール
npm install --save jimp
ReferenceError対応
もしReferenceError: regeneratorRuntime is not defined
というエラーが出た場合はこちらご参考ください
実装
UIとかCSSはこちらの記事参考にしてます!
CSS等々勉強中なので命名とか書き方は見逃してください。
uploadImage.vue
<template>
...
<form @submit="checkForm">
...
<div class="form-item">
<label for="uploadedImage" class="form-item__label"
>アップ画像</label
>
<label v-show="!previewUploadedSrc" class="img-title-label"
>画像を選択
<input
ref="imageUploader"
name="uploadedImage"
type="file"
@change="onFileChange"
/>
</label>
<div v-show="previewUploadedSrc" class="preview-item">
<img :src="previewUploadedSrc" />
<div class="preview-close-button" @click="onClickRemoveImage">
<label class="preview-image__title">{{ imageTitle }}</label>
</div>
</div>
</div>
...
</form>
...
</template>
<style scoped>
.img-title-label > input {
display: none;
}
.img-title-label {
padding: 0.1rem 1rem;
border: 1px solid #888;
}
.img-title-label::after {
content: '+';
font-size: 1rem;
color: #888;
padding-left: 1rem;
}
.preview-item > img {
width: 150px;
height: 150px;
background-color: #666;
object-fit: contain;
}
.preview-image__title {
padding: 0.1rem 1rem;
border: 1px solid #888;
}
.preview-image__title::after {
content: 'x';
font-size: 1rem;
color: #888;
padding-left: 0.5rem;
}
</style>
<script>
...
data() {
return {
previewUploadedSrc: '',
imageTitle: '',
uploadedImageBlob = ''
}
},
methods: {
/**
* =================
* 画像アップロード
* =================
*/
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files
let file = files[0]
let reader = new FileReader()
reader.onload = e => {
this.createImage(e.target.result)
this.imageTitle = file.name
}
reader.readAsDataURL(file)
},
createImage(file) {
// コールバック内からthisを呼び出すため一時的に代入
var tmpThis = this
// 画像サイズ調整
Jimp.read(file, function(err, image) {
const width = 200
const height = 200
image
// 画像を指定された幅と高さに全て覆われるよう縦横比を維持して拡大/縮小します
.cover(width, height)
// ポスタライズとか
.posterize(10)
.getBase64(Jimp.MIME_PNG, function(err, src) {
tmpThis.uploadedImageBlob = tmpThis.base64ToBlob(src)
tmpThis.previewUploadedSrc = src
})
})
},
onClickRemoveImage() {
this.$refs.imageUploader.value = ''
this.uploadedImageBlob = ''
this.previewUploadedSrc = ''
this.imageTitle = ''
},
base64ToBlob(base64) {
const bin = atob(base64.replace(/^.*,/, ''))
const buffer = new Uint8Array(bin.length)
for (let i = 0; i < bin.length; i++) {
buffer[i] = bin.charCodeAt(i)
}
return new Blob([buffer.buffer], {
type: 'image/png'
})
},
...
}
</script>
詰まったところ
Jimpで加工したものを別のメソッドに渡したいがコールバック関数内なのでthis
のスコープが違う
ドキュメントチラ見していたときには他人事の顔でスルーしてましたがついにぶち当たりました。
あらかじめtmpThis
という別の変数にthis
を入れて呼び出しました。
// コールバック内からthisを呼び出すため一時的に代入
var tmpThis = this
Jimpに渡すデータの指定方法
他の記事見てると大体画像がパス指定だったので、inputで取得した画像を渡すにはどうしたらいいのかなと少し悩みました。
FileReaderのonload処理の中で呼んであげれば良いだけでした。