图片格式相互转换 -> 前端

1,871 阅读1分钟

前端很多场景下都有可能存在针对图片格式进行转换的情况,比如 canvas 绘制图片:

  • 提供一个网络图片:url -> base64;
  • 接口希望是一个 Blob 或者 File 文件流:Base64 -> Blob -> File;
  • ... more...

一、url-> base64

export function getDataUri(url) {
    return new Promise((resolve, reject) => {
        let image = new Image();

        // CORS 策略,会存在跨域问题 https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
        image.setAttribute('crossOrigin', 'anonymous'); // 允许跨域获取该图片
        image.crossOrigin = 'Anonymous';
        
        image.src = url;

        image.onload = function () {
            let canvas = document.createElement('canvas'),
                width = image.width, // canvas的尺寸和图片一样
                height = image.height;

            canvas.width = width;
            canvas.height = height;

            canvas.getContext('2d').drawImage(this, 0, 0, width, height);
            // Data URI
            resolve(canvas.toDataURL('image/png'));
        };

        // console.log(image.src);
        image.onerror = () => {
            reject(new Error('图片流异常'));
        };
    });
}

二、Base64 -> Blob -> File

/**
 * @return Promise base64 转化成 blob
 * @param {String} b64data base64
 * @param {String} name 图片名称
 * @param {String} type 图片类型 默认:image/jpeg、image/png...
 */
export function base64ToBlob(dataURL, name, type = 'image/jpeg', sliceSize = 512) {
    const base64 = dataURL.split(',')[1];
    return new Promise((resolve, reject) => {
        // 使用 atob() 方法将数据解码
        let byteCharacters = window.atob(base64);
        let byteArrays = [];

        for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
            let slice = byteCharacters.slice(offset, offset + sliceSize);
            let byteNumbers = [];

            for (let i = 0; i < slice.length; i++) {
                byteNumbers.push(slice.charCodeAt(i));
            }
            // 8 位无符号整数值的类型化数组。内容将初始化为 0。
            // 如果无法分配请求数目的字节,则将引发异常。
            byteArrays.push(new Uint8Array(byteNumbers));
        }

        let result = new Blob(byteArrays, {
            type: type,
            name,
        });

        result = Object.assign(result, {
            lastModified: new Date().getTime(),
            lastModifiedDate: new Date(),
            name: name,
            webkitRelativePath: '',
            // 利用 URL.createObjectURL() 为 blob 对象创建临时的 URL
            preview: URL.createObjectURL(result), 
        });

        // Blob -> File
        const newFile = new File([result], result.name, {type: result.type})

        resolve(newFile);
    });
}

三、Blob -> Base64

export function blobToBase64(blob) {
    return new Promise((resolve, reject) => {
        const fileReader = new FileReader();

        fileReader.onload = (e) => {
            resolve(e.target.result);
        };
        // readAsDataURL
        fileReader.readAsDataURL(blob);
        fileReader.onerror = () => {
            reject(new Error('文件流异常'));
        };
    });
}