heic图片转换
問(wèn)題:
heic圖片在微信小程序端不能回顯也不能上傳成功。
1.了解heic圖
Heic格式是蘋果專門為iOS11開發(fā)的照片格式。Heic是蘋果iOS和macOS的一種文件格式,用于處理圖像和視頻。Heic是H.264和JEP格式,取代了IOS 11系統(tǒng)中的原始視頻和照片。Heic格式不僅可以節(jié)省內(nèi)存,還可以保留原始圖像質(zhì)量。Heic格式是蘋果iOS和iOS的特殊格式。
heic的特點(diǎn):與JPG相比,heic格式占用空間更少,圖像質(zhì)量更無(wú)損。HEIC格式照片支持iOS11和macOS High Sierra(10.13)及更高版本。但是這種格式不能用圖片查看軟件直接在Windows中打開(Windows10 RS4開始支持這種格式)。
2.微信小程序下的回顯
heic的圖片在微信小程序下,經(jīng)過(guò)壓縮,可以轉(zhuǎn)換為jpeg,展示
wx.compressImage({src: path, // 圖片路徑quality: 50, // 壓縮質(zhì)量success: (res) => {console.log(res, 'ressss')},fail: (err) => {console.log(err)}})注意:壓縮圖片在微信小程序可以回顯頁(yè)面,但是繼續(xù)上傳后端,依舊會(huì)失敗
3.解決微信小程序上傳失敗
終極解決方案是后端進(jìn)行轉(zhuǎn)換。暫時(shí)沒(méi)有找到前端能直接轉(zhuǎn)換的方案,如果有,歡迎討論
(下面是為了上傳heic圖片成功,所以用本地node端測(cè)試了一下轉(zhuǎn)換圖片,在回傳給前端,在重新上傳給真正的后端轉(zhuǎn)換的圖片上傳成功的案例)
(1)微信小程序端
//選擇圖片wx.chooseMedia({count: 1,mediaType: 'image',success: (r) => {//上傳給node服務(wù)器進(jìn)行轉(zhuǎn)換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) {//重新生成本地臨時(shí)路徑(用這個(gè)路徑在去上傳給后端可上傳heic成功,也可以回顯)console.log(tempR.tempFilePath)}}})}})}(2)node端轉(zhuǎn)換heic
主要使用插件
GitHub - catdad-experiments/heic-convert: 🤳 convert heic/heif images to jpeg and png
node端用了egg.js框架
1.進(jìn)行配置
文件上傳 | Egg
egg.js內(nèi)置了
配置插件 - 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,接收文件流會(huì)報(bào)錯(cuò)
2.在router頁(yè)面進(jìn)行創(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層進(jìn)行業(yè)務(wù)書寫
要使用的插件需要利用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'); // 時(shí)間格式化 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)建基礎(chǔ)的目錄const uploadBasePath = 'public/img';// 創(chuàng)建生成的基礎(chǔ)名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檢測(cè)目錄是否存在,存在返回true,反之亦然return true;}if (mkdirsSync(path.dirname(dirname))) { // 返回 path 的目錄名,尾部的文件名會(huì)被忽略path.dirname('/目錄1/目錄2/目錄3');返回'/目錄1/目錄2'fs.mkdirSync(dirname);// fs.mkdirSync同步地創(chuàng)建目錄return true;}}mkdirsSync(path.join(uploadBasePath, dirname));// path.join,以特定的分隔符將路徑連接起來(lái)// 生成寫入路徑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)錯(cuò)誤,關(guān)閉管道await sendToWormhole(stream);return Promise.reject('上傳錯(cuò)誤');}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};} };經(jīng)過(guò)測(cè)試發(fā)現(xiàn),只有轉(zhuǎn)成jpg才可以進(jìn)行重新上傳到服務(wù)器。轉(zhuǎn)成png,依舊無(wú)法上傳到服務(wù)器
如果是想轉(zhuǎn)換給前端base64,可以繼續(xù)進(jìn)行轉(zhuǎn)化
let res = fs.readFileSync(resultUrl,'binary')const buffer = new Buffer(res, 'binary');const src = 'data: image/png;base64,' + buffer.toString('base64');暫時(shí)沒(méi)有什么其他方法了,微信官方都推薦后端進(jìn)行轉(zhuǎn)換
轉(zhuǎn)換插件,會(huì)發(fā)現(xiàn),如果heic圖片轉(zhuǎn)換時(shí)間有點(diǎn)慢(1.8M的heic轉(zhuǎn)換啟動(dòng)本地的node會(huì)大概11s左右)
歡迎交流該問(wèn)題
總結(jié)
- 上一篇: 为什么D类音频功放可以免输出滤波器
- 下一篇: 核酸检测软件开发方案(软件工程作业)