いつもお世話になっております。
現在Nuxtで画像アップロード機能を実装しているのですが、
画像を選択直後にプレビュー表示させるためにreadAsDataURL()
を用いて
base64(厳密にはData URL)に変換し、HMTLの <img src="〇〇">
で表示をしています。
ここまでは想定通りの動きをしてくれているのですが、
バックエンドに画像をアップする際にはbase64
のままアップすると
当然ですがDB内にbase64
のデータがそのまま入ってしまいます。
これで良いと言えば良いのですが、
できればDBにはファイルまでのパスを保存し、画像データは専用のフォルダに格納をしたいと思っています。
そこで、フロント側で画像データをアップする前にbase64(厳密にはData URL)を画像データに戻してからアップしようとしているのですが、この戻す作業ができません。
(下記pages/upload.vue
のupload()
に該当の記述があります)
以下はフロント側のコードですが、
日本語を含んでいないにもかかわらず文字化けを起こしてしまうのですが、
どこが良くないのでしょうか。もしわかる方がいらっしゃればご教授いただけますと幸いです。
// components/Upload.vue <template> <div> <label v-if="!value"> <input type="file" ref="file" @change="upload" > </label> <div v-if="value"> <label> <input ref="file" type="file" @change="upload" > <img :src="value" class="img-child"> </label> <button type="button" @click="deleteImage"> 削除する </button> </div> <ul v-if="fileErrorMessages.length > 0"> <li v-for="(message, index) in fileErrorMessages" :key="index"> {{ message }} </li> </ul> </div> </template> <script> export default { name: 'Upload', props: { value: { type: String, default: null } }, data(){ return { file: null, fileErrorMessages: [] } }, methods: { /* 親コンポーネントにエンコード済み画像データをバインド */ async upload( e ){ const files = e.target.files || e.dataTransfer.files const file = files[0] if ( this.checkFile( file ) ){ const picture = await this.getBase64( file ) // 親コンポーネントにエンコード済み値を渡す // inputなのは親側でv-model(内部にinputを利用)しているから this.$emit( 'input', picture ) } }, // 削除 deleteImage(){ this.$emit( 'input', null ) this.$refs.file = null }, /* 画像データチェック */ checkFile( file ){ let result = true this.fileErrorMessages = [] const SIZE_LIMIT = 5000000 // キャンセルしたら処理中断 if ( !file ){ result = false } // jpeg か png 関連ファイル以外は受け付けない if ( file.type !== 'image/jpeg' && file.type !== 'image/png' ){ this.fileErrorMessages.push( 'アップロードできるのは jpeg画像ファイル か png画像ファイルのみです。' ) result = false } // 上限サイズより大きければ受け付けない if ( file.size > SIZE_LIMIT ){ this.fileErrorMessages.push( 'アップロードできるファイルサイズは5MBまでです。' ) result = false } return result }, /* base64エンコード(ただしreadAsDataURL()利用) */ getBase64( file ){ return new Promise( ( ( resolve, reject ) => { // FileReader のインスタンスメソッドを利用してエンコード const reader = new FileReader() // FileReader.readAsDataURLで得られるのはData URIであって純粋なbase64文字列じゃないぞ reader.readAsDataURL( file ) reader.onload = () => resolve( reader.result ) reader.onerror = error => reject( error ) } ) ) }, } } </script> <style scoped> .img-child { width : 300px; } </style>
// pages/upload.vue <template> <div> <input type="text" v-model="title"> <upload v-model="picture"/> <img :src="picture" class="img"> <div v-if="picture"> <button @click="upload">アップロード</button> </div> </div> </template> <script> import Upload from "~/components/Upload"; export default { components: { Upload }, data(){ return { title: "", picture: null, uploadedPicture: null, } }, methods: { async upload(){ const dataURI = this.picture const base64EncodedFile = dataURI.replace( /data:.*/.*;base64,/, '' ) // // 予定ではここでデコードされた画像データが出力される console.log( atob( base64EncodedFile ) ) }, } } </script>
# 元画像データ File {name: "logo.png", lastModified: 1611321882584, lastModifiedDate: Fri Jan 22 2021 22:24:42 GMT+0900 (日本標準時), webkitRelativePath: "", size: 11088, …} lastModified: 1611321882584 lastModifiedDate: Fri Jan 22 2021 22:24:42 GMT+0900 (日本標準時) {} name: "logo.png" size: 11088 type: "image/png" webkitRelativePath: "" __proto__: File # base64(Data URL)のコード data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANkAAADOCAYAAACzbadVAAAACXBIWXMAACE3AAAhNwEzWJ96AAAgAElEQVR4nO2dCZQU1dXH7ww7w7BD+xERkIRoWGZQ84kgiraKxoXFz4AQBU1UiEYBxS0qgwGXSHA0UQgaZTQu0SiLCwo0izigCeoMiws6wIgLjbIMzTD7zHf+Na+anu6qrvdqr+76nTMHpqe6urqq/nXvu+++ezMaGhrIJ3UIBrKnEdFoIioiokPsZ10oHCnyL7Mz+CJLQYKB7MVENCnum5UREV7PD4Uju9P9HNmJL7IURUVoMrND4Uheup8ju/BFlsIEA9lLiWiUyjdcD7cyFI4cSvfzZDWZqf310p5pzE1U4mzmPvpYjC+yFIaNvZYm+YajWKDEx0J8kaU+6zS+YV4wkN0x3U+SlfgiS320xlwdiGhyup8kK/FFlvqM4PiGo9P9JFmJL7LUh0dAZ6f7SbISX2QpTDCQjbmw # デコードした画像(?)データ PNG IHDRÙγm§U pHYs!7!73Xz IDATxí ÕÕÇï;ðCûhXfPó ¶Æ ÅÏMTFÅ-*Hp4Qe4.Ñ( 48 ê:À²Í0ûÌwþ5¯îª®÷j¯îú3¦§ºººªþuï»ï¾{3È'u²§Ñh"*"¢Cìg]()ò/³3ø"KAìÅD4)î^Ï #»ÓýÙ/²EEh2³CáH^º#»ðEÂÙKhÊ7\·2J÷ód5©ýõÒiÌMTâlæ>úX/²½&ù£X ÄÇB|¥>ë4¾a^0Ý1ÝOø"K}´Æ\hrº$+ñEúàø£Óý$Y/²ÔG@g§ûI²_d)L0¹°^é~ÆYdc5KôÛÙ½1dó¸>ø"KAÀÕóÍXØ[dç§û¹4_d)sE?a-ç6ÞdûÅñE"07oQc.-Ç·hÆðEæq0̬×.QÂø¬Ü¸ßaÑz§ÝÉ5æ)ñ-Ò¥1ýt0pJCáH4 Vi ð-|yÅ%#å.ÆìWÍÝôE¦_d!ÈÎe"P[#¦:¶öl´I¢õÃaã Ñ,·0Ç#d²h}ðEæ2Û6ý¨-¸tq§N|¹5ÂeÂEkÉ ¾È¥-ɲÂ4d?}àÌ&XàbDÌ~ +ýø"³6®U®#wH¹ò+[ÀIÙ£cDå÷i¾3_N' VE.