blog icon indicating copy to clipboard operation
blog copied to clipboard

JS检测是否是heic(heif)格式

Open xianzou opened this issue 2 years ago • 0 comments

HEIC是一种容器格式,可以存储使用HEVC格式编码的声音和图像 ,相比jpg, 具有较小的文件大小和较高的图像质量 ;

Heic(HEIF),虽然有更小的体积, 但是H5显示HEIC格式的图片目前Chrome等浏览器还不支持自动解析,并且http协议中Content-Type默认还没有image/heic这个属性 (微信和钉钉打开该文件会自动转码,或者发送的时候系统底层会自动转码);

有些图片后缀是.jpg格式,但其实是heic格式(可以用记事本打开该图片看第一行是否有heic文字),这时候图片上传根据后缀名来判断会失效,但是其实在手机中确可以预览,但是H5上传会出现问题;;

目前的解决方案有三:

1、前端判断格式,拒绝上传;

2、前端使用 heic2any 转码;

3、后端转码(推荐);

这里介绍判断heic格式代码:

const BASE64_MARKER = ';base64,';

function convertDataURIToBinary(dataURI) {
    const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
    const base64 = dataURI.substring(base64Index);
    const raw = window.atob(base64);
    const rawLength = raw.length;
    const array = new Uint8Array(new ArrayBuffer(rawLength));
  
    for(let i = 0; i < rawLength; i++) {
      array[i] = raw.charCodeAt(i);
    }
    return array;
}
const reader = new FileReader();
// file ===> 文件对象
reader.readAsDataURL(file);
reader.onload = function read(e) {
    const uint8Array = convertDataURIToBinary(img.src);
    isHeic= hasHeic(uint8Array);
    if(isHeic){
       alert('不支持Heic格式文件上传');
    }
    ...
};

以上代码可以使用Promise进行包装;

如果有涉及到图片压缩,推荐在img.onerror中提示:

const reader = new FileReader();
// file ===> 文件对象
reader.readAsDataURL(file);
reader.onload = function read(e) {
    img.src = e.target.result;
};

return new Promise((resolve) => {
 img.onload = function load() {
     const context = canvas.getContext('2d');

     ...图片压缩
     resolve(newPhoto);
 };
    img.onerror = (e) =>{
        //如果是heic格式的图片
        const uint8Array = convertDataURIToBinary(img.src);
        isHeic= hasHeic(uint8Array);
        //如果是heic格式的图片
        resolve({
            type:'error',
            message:isHeic?'不支持Heic格式文件上传':'图片读取失败'
        });
    }
})

xianzou avatar Jan 03 '23 11:01 xianzou