Base64、Blob、Url类型的互转,图片压缩、download 文件下载

追求长久的幸福,会获得长久的快乐。追求短暂的刺激,会获得短暂的快感与无尽的悔恨


前言

在工作中经常遇到转换图片格式的需求,现在总结下


一、Base64

  • 介绍:Base64是一种将二进制数据编码成 ASCII 字符串的方法,前端中通常使用 Base64 来解决图片、音频等二进制文件无法直接传输的问题。
  • 优点
    1. 方便传输:Base64可以通过 HTTP 协议直接传输,无需额外的请求;
    2. 简化操作:使用 Base64 可以避免一些繁琐操作,比如图片的上传;
    3. 减轻服务器压力
  • 缺点
    1. 增加体积:Base64编码会让二进制数据的体积增加大约三分之一左右,因此会占用更多的网络带宽和浏览器内存;
    2. 降低加载速度:相比于直接加载本地或远程图片,Base64编码的图片需要客户端先转换为二进制数据,并解码成图片,所以会降低页面的加载速度;
    3. 不利于缓存:因为Base64图片是内嵌在HTML或CSS中,无法像普通图片被浏览器缓存
  • url转base64
    1. 首先通过 Image 对象,加载到 url 图片
    2. 然后将图片绘制到canvas
    3. 通过 toDataURL() 方法返回一个包含图片展示的 data URL(也就是Base64编码的字符串),toDataURL的第一个参数可以指定转换类型,默认 image/png,如果原图是jpg转为png后size会变大。最好可以根据原图类型来转换格式,或者直接定义为 image/jpeg;
    4. 注意:如果原图中有透明区域,部分情况下转换后会显示黑色,这时候可以给 canvas 默认设置底色为白色
/**
 - @desc url转Base64
 - @param url {String} 图片url地址
 - @param type {image/jpeg} 图片转换类型
*/
function fnUrlToBase64 (url, type = 'image/jpeg') {
  return new Promise((resolve, reject) => {
    const img = new Image()
    const canvas = document.createElement('canvas');
    img.crossOrigin = '*';
    img.onload = () => {
      const width = img.width, height = img.height;
      canvas.width = width;
      canvas.height = height;

      const ctx = canvas.getContext('2d');
      // 设置底色为白色
      ctx.fillStyle = 'white';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      // 在画布上绘制图像
      ctx.drawImage(img, 0, 0, width, height);
      const base64 = canvas.toDataURL(type);
      resolve(base64);
    };
    img.onerror = () => {
      reject(new Error('message'));
    };
    img.src = url;
  });
}
  • File、Bolb转Base64
    1. 通过 FileReader.readAsDataURL 方法读取指定的 Blob或 File文件对象,读取完成时,在result属性中将包含一个data:URL格式的Base64字符串,以表示所读取文件的内容
/**
 - @desc File、Blob转base64
 - @param file {Object} 文件
*/
function fnFileToBase64 (file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('load', () => {
      const base64 = reader.result?.toString() || '';
      resolve(base64);
    });
    reader.addEventListener('error', () => {
      reject(new Error('message'));
    });
    reader.readAsDataURL(file);
  });
}
// 调用
<input type="file" id="upload">
document.querySelector('#upload').onchange = (event) => {
  fnFileToBase64(event.target.files[0]).then(res=> {
    console.log(res)
  })
}
  • 将File对象转为base64且尺寸不超过 800 px
    1. 通过 FileReader.readAsDataURL 方法读取File对象,在读取完成时,通过 result 属性获取到 Data URL格式的 Base64 字符串
    2. 通过 Image 对象成功加载 Base64
    3. 检测 Image 宽高是否超出最小尺寸,若超出根据宽高比进行调整
    4. 将 Image 绘制到 canvas 上
    5. 最后通过 toDataURL 获取到 Base64
/*
 * @desc 将File图片对象转为 base64且尺寸不超过 800
 * @param file {Object} file图片对象
 * */
fnImageSizeCompress(file, nSize = 800) {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        const image = new Image();
        let sBase64Src = '';
        image.onload = () => {
            const canvas = document.createElement('canvas');
            const context = canvas.getContext('2d');
            let width = image.width;
            let height = image.height;
            // 获得图片宽高比,大于1说明宽比高大,小于1说明高比宽大
            let rate = width / height;
            if (width > nSize || height > nSize) {
                width = rate > 1 ? nSize : nSize * rate;
                height = rate < 1 ? nSize : nSize / rate;
            }
            canvas.width = width;
            canvas.height = height;
            context.clearRect(0, 0, width, height);
            context.drawImage(image, 0, 0, width, height);
            sBase64Src = canvas.toDataURL(file.type);
            resolve(sBase64Src);
        }
        reader.readAsDataURL(file);
        reader.onload = (e => {
            image.src = e.target.result;
        });
        image.onerror = () => {
            reject();
        }
    })
}

二、Blob

  • 介绍:Blob对象表示一个不可变、原始数据的类文件对象,他的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。Blob 表示的不一定是 JavaScript 原生格式的数据。File 接口基于 Blob,继承了 blob 的功能并将其扩展以支持用户系统上的文件
  • File 确实基于 Blob 构造函数
    在这里插入图片描述
  • Url转Blob
    1. fetch 的 response 接口呈现了一次请求的响应数据
    2. response.blob() 读取 response 对象,并返回一个被解析为 Blob 格式的 Promise 对象
/**
 * @desc url转Blob(fetch)
 * */ 
function fnUrlToBlob(url) {
    return window.fetch(url).then(response => response.blob());
}
/**
 * @desc url转Blob(XMLHttpRequest)
 * */ 
fnUrlToBlob(url) {
    return new Promise(resolve => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'blob';
        xhr.onload = () => {
            if (xhr.status === 200) {
                resolve(xhr.response);
            }
        };
        xhr.send();
    });
}
  • Base64转Blob
    1. atob() 对 base64进行解码,若不是有效的base64字符串,则抛出 DOMException
    2. Uint8Array 数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素
    3. charCodeAt() 方法返回 0 到 65535 之间的整数,表示给定索引处的 UTF-16 代码单元
    4. Blob(array, options) 构造函数返回一个新的 Blob 对象,blob 的内容由参数数组中给出的值的串联组成。
      4.1 array 是一个由ArrayBuffer, ArrayBufferView, Blob, DOMString 等对象构成的 Array ,或者其他类似对象的混合体,它将会被放进 Blob。DOMStrings 会被编码为 UTF-8。
      4.2 options.type 默认值为 “”,它代表了将会被放入到 blob 中的数组内容的 MIME 类型
 /*
 * base64转Blob对象
 * data(string)==》base64
 * return Blob 对象
 *  */
function fnDataURItoBlob(data) {
    let byteString;
    if (data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(data.split(',')[1])
    } else {
        return;
    }
    let mimeString = data.split(',')[0].split(':')[1].split(';')[0];
    let ia = new Uint8Array(byteString.length)
    for (let i = 0; i < byteString.length; i += 1) {
        ia[i] = byteString.charCodeAt(i)
    }
    return new Blob([ia], {type: mimeString})
}
  • File转Blob
new Blob([this.file], { type: "image/png" })
  • Canvas转Blob对象
    1. HTMLCanvasElement.toBlob() 方法创造 Blob 对象
/*
 * @desc 将一个canvas对象转变为一个Blob对象
 * @param canvas {canvas} canvas对象
 * @param type {String} 图片类型
 * @param quality {Number} 图片质量
 * */
function fnCanvasToBlob(canvas, type = 'image/png', quality = 1) {
    return new Promise(resolve => canvas.toBlob(blob => resolve(blob), type, quality))
}

三、Url

  • Blob转Url
    1. URL.createObjectURL() 方法会创建一个 DOMString,格式大概是 ‘blob:http://127.0.0.1:5500/b08c0131-c178-49be-a8a3-1f13ddf52c7f’,blob:开头,后面跟着当前网站域名加一个guid。这个url的生命周期和创建它的窗口中的document绑定,即刷新页面、关闭页面就会被自动释放了,就失效了。可以当做页面图片回显或者download link用
    2. 内存管理,在每次调用 createObjectURL 方法时,都会创建一个新的URL对象,即使已经用相同的对象作为参数创建过,当不再需要这些URL对象时,为了获得最佳性能和内存使用状况,每个对象必须通过调用 URL.revokeObjectURL() 方法释放掉。
// blob转url
function fnBlobToUrl(blob) {
    return URL.createObjectURL(blob);  
}
  • Base64转Url
    1. 先转成Blob,然后再转url
function fnBase64ToUrl(data) {
    var parts = data.split(';base64,'),
        contentType = parts[0].split(':')[1],
        raw = window.atob(parts[1]),
        length = raw.length,
        arr = new Uint8Array(length);
    for (var i = 0; i < length; i++) {
        arr[i] = raw.charCodeAt(i);
    }
    var blob = new Blob([arr], { type: contentType });
    return URL.createObjectURL(blob);
};
  • 使用 a 标签的 download 实现文件下载
    1. download 属性可以直接调用浏览器的下载功能,而且还可以给download属性设置值来规定下载文件的名称,如果在设置值时没有指定文件的扩展名,浏览器将自动检测正确的文件名并添加到文件(.jpg, .pdf, .txt, .html, 等等)。
    2. 问题:download 表现最为直观的一个问题就是跨域的问题。如果是加载了非同源的内容,该属性将会失效,会出现下载变浏览的情况。
    3. 解决:使用 URL.createObjectURL() 方法就可以在跨域的情况下,通过a标签下载资源了
document.querySelector('button').onclick = () => {
  fnDownloadFile('./p2678027668.jpg', '忍冬')
}
/**
 * @desc 下载文件
 * @param url {String} 文件链接
 * @param filename {String} 文件名称
 * */ 
function fnDownloadFile (url, filename) {
  // 下载源数据文件,生成blob对象
  window.fetch(url).then(response => response.blob()).then(blob => {
    fnDownFile(blob, filename)
  })
}
/**
 * @desc 下载文件
 * @param blob {Blob} Blob文件
 * @param filename {String} 文件名称
 * */ 
function fnDownFile (blob, filename) {
  const a = document.createElement('a');
  a.download = filename;
  const blobUrl = URL.createObjectURL(blob);
  a.href = blobUrl;
  a.style.display = 'none';
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(blobUrl);
}


😊 谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忍冬 ⁡⁡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值