heic图片转换
問題:
heic圖片在微信小程序端不能回顯也不能上傳成功。
1.了解heic圖
Heic格式是蘋果專門為iOS11開發(fā)的照片格式。Heic是蘋果iOS和macOS的一種文件格式,用于處理圖像和視頻。Heic是H.264和JEP格式,取代了IOS 11系統(tǒng)中的原始視頻和照片。Heic格式不僅可以節(jié)省內存,還可以保留原始圖像質量。Heic格式是蘋果iOS和iOS的特殊格式。
heic的特點:與JPG相比,heic格式占用空間更少,圖像質量更無損。HEIC格式照片支持iOS11和macOS High Sierra(10.13)及更高版本。但是這種格式不能用圖片查看軟件直接在Windows中打開(Windows10 RS4開始支持這種格式)。
2.微信小程序下的回顯
heic的圖片在微信小程序下,經過壓縮,可以轉換為jpeg,展示
wx.compressImage({src: path, // 圖片路徑quality: 50, // 壓縮質量success: (res) => {console.log(res, 'ressss')},fail: (err) => {console.log(err)}})注意:壓縮圖片在微信小程序可以回顯頁面,但是繼續(xù)上傳后端,依舊會失敗
3.解決微信小程序上傳失敗
終極解決方案是后端進行轉換。暫時沒有找到前端能直接轉換的方案,如果有,歡迎討論
(下面是為了上傳heic圖片成功,所以用本地node端測試了一下轉換圖片,在回傳給前端,在重新上傳給真正的后端轉換的圖片上傳成功的案例)
(1)微信小程序端
//選擇圖片wx.chooseMedia({count: 1,mediaType: 'image',success: (r) => {//上傳給node服務器進行轉換wx.uploadFile({url: 'http://localhost:7001/uploadImg/api/heictoany', filePath:r.tempFiles[0].tempFilePath,name: 'file',success: (res) => {let src = 'http://localhost:7001/MKIntouch/' ++JSON.parse(res.data).src//拿到地址重新下載圖片wx.downloadFile({url: src, success (tempR) {if (tempR.statusCode === 200) {//重新生成本地臨時路徑(用這個路徑在去上傳給后端可上傳heic成功,也可以回顯)console.log(tempR.tempFilePath)}}})}})}(2)node端轉換heic
主要使用插件
GitHub - catdad-experiments/heic-convert: 🤳 convert heic/heif images to jpeg and png
node端用了egg.js框架
1.進行配置
文件上傳 | Egg
egg.js內置了
配置插件 - config.default.js
const whitelist = [// images'.jpg', '.jpeg', // image/jpeg'.png', // image/png, image/x-png'.gif', // image/gif'.bmp', // image/bmp'.wbmp', // image/vnd.wap.wbmp'.webp','.tif','.psd',// text'.svg','.js', '.jsx','.json','.css', '.less','.html', '.htm','.heic','.HEIC','.xml',// tar'.zip','.gz', '.tgz', '.gzip',// video'.mp3','.mp4','.avi',];exports.multipart = {whitelist,fileSize: '50mb',};如果不配置config,接收文件流會報錯
2.在router頁面進行創(chuàng)建
創(chuàng)建文件夾 - uploadImg->app,js
'use strict'; module.exports = app => {const { router, controller } = app;const subRouter = router.namespace('/uploadImg');subRouter.post('/api/heictoany', controller.uploadImg.api.heictoany);};3.controller層進行業(yè)務書寫
要使用的插件需要利用npm下載哦
controller新建文件夾uploadImg->app.js
'use strict'; const egg = require('egg'); const convert = require('heic-convert'); const fs = require('fs'); const { promisify } = require('util');const path = require('path'); const awaitWriteStream = require('await-stream-ready').write; const senToWormhole = require('stream-wormhole'); // 時間格式化 const dayjs = require('dayjs'); const await = require('await-stream-ready/lib/await');module.exports = class Pages extends egg.Controller {async heictoany() {const { ctx } = this;// 獲取文件流const stream = await ctx.getFileStream();// 創(chuàng)建基礎的目錄const uploadBasePath = 'public/img';// 創(chuàng)建生成的基礎名const filename = `${Date.now()}${Number.parseInt(Math.random() * 1000)}${path.extname(stream.filename).toLocaleLowerCase()}`;// const resultname = filename.replace(/heic/g, 'png')const resultname = filename.replace(/heic/g, 'jpg')// 生成文件夾const dirname = dayjs(Date.now()).format('YYYY/MM/DD');// 創(chuàng)建目錄function mkdirsSync(dirname) {if (fs.existsSync(dirname)) { // fs.existsSync檢測目錄是否存在,存在返回true,反之亦然return true;}if (mkdirsSync(path.dirname(dirname))) { // 返回 path 的目錄名,尾部的文件名會被忽略path.dirname('/目錄1/目錄2/目錄3');返回'/目錄1/目錄2'fs.mkdirSync(dirname);// fs.mkdirSync同步地創(chuàng)建目錄return true;}}mkdirsSync(path.join(uploadBasePath, dirname));// path.join,以特定的分隔符將路徑連接起來// 生成寫入路徑const target = path.join(uploadBasePath, dirname, filename);console.log(path.join(uploadBasePath, dirname), '文件文件');// 寫入流const writeStream = fs.createWriteStream(target);try {// 異步把文件流 寫入await awaitWriteStream(stream.pipe(writeStream));} catch (err) {// 如果出現(xiàn)錯誤,關閉管道await sendToWormhole(stream);return Promise.reject('上傳錯誤');}const inputBuffer = await promisify(fs.readFile)(target);console.log(inputBuffer, 'inputBuffer');const outputBuffer = await convert({buffer: inputBuffer, // the HEIC file bufferformat: 'JPEG', // output format// format: 'PNG', // output format});console.log(outputBuffer, 'outbuffer')console.log(path.join(uploadBasePath, dirname, resultname), 'xxxx')const resultUrl = path.join(uploadBasePath, dirname, resultname);console.log(resultUrl, 'resultURLLLLL')await promisify(fs.writeFile)(resultUrl, outputBuffer);ctx.status = 200;ctx.body = {src: resultUrl};} };經過測試發(fā)現(xiàn),只有轉成jpg才可以進行重新上傳到服務器。轉成png,依舊無法上傳到服務器
如果是想轉換給前端base64,可以繼續(xù)進行轉化
let res = fs.readFileSync(resultUrl,'binary')const buffer = new Buffer(res, 'binary');const src = 'data: image/png;base64,' + buffer.toString('base64');暫時沒有什么其他方法了,微信官方都推薦后端進行轉換
轉換插件,會發(fā)現(xiàn),如果heic圖片轉換時間有點慢(1.8M的heic轉換啟動本地的node會大概11s左右)
歡迎交流該問題
總結
- 上一篇: 为什么D类音频功放可以免输出滤波器
- 下一篇: 核酸检测软件开发方案(软件工程作业)