追求长久的幸福,会获得长久的快乐。追求短暂的刺激,会获得短暂的快感与无尽的悔恨
前言
在工作中经常遇到转换图片格式的需求,现在总结下
一、Base64
- 介绍:Base64是一种将二进制数据编码成 ASCII 字符串的方法,前端中通常使用 Base64 来解决图片、音频等二进制文件无法直接传输的问题。
- 优点
- 方便传输:Base64可以通过 HTTP 协议直接传输,无需额外的请求;
- 简化操作:使用 Base64 可以避免一些繁琐操作,比如图片的上传;
- 减轻服务器压力
- 缺点
- 增加体积:Base64编码会让二进制数据的体积增加大约三分之一左右,因此会占用更多的网络带宽和浏览器内存;
- 降低加载速度:相比于直接加载本地或远程图片,Base64编码的图片需要客户端先转换为二进制数据,并解码成图片,所以会降低页面的加载速度;
- 不利于缓存:因为Base64图片是内嵌在HTML或CSS中,无法像普通图片被浏览器缓存
- url转base64
- 首先通过 Image 对象,加载到 url 图片
- 然后将图片绘制到canvas
- 通过 toDataURL() 方法返回一个包含图片展示的 data URL(也就是Base64编码的字符串),toDataURL的第一个参数可以指定转换类型,默认 image/png,如果原图是jpg转为png后size会变大。最好可以根据原图类型来转换格式,或者直接定义为 image/jpeg;
- 注意:如果原图中有透明区域,部分情况下转换后会显示黑色,这时候可以给 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
- 通过 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
- 通过 FileReader.readAsDataURL 方法读取File对象,在读取完成时,通过 result 属性获取到 Data URL格式的 Base64 字符串
- 通过 Image 对象成功加载 Base64
- 检测 Image 宽高是否超出最小尺寸,若超出根据宽高比进行调整
- 将 Image 绘制到 canvas 上
- 最后通过 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
- fetch 的 response 接口呈现了一次请求的响应数据
- 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
- atob() 对 base64进行解码,若不是有效的base64字符串,则抛出 DOMException
- Uint8Array 数组类型表示一个 8 位无符号整型数组,创建时内容被初始化为 0。创建完后,可以以对象的方式或使用数组下标索引的方式引用数组中的元素
- charCodeAt() 方法返回 0 到 65535 之间的整数,表示给定索引处的 UTF-16 代码单元
- 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对象
- 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
- URL.createObjectURL() 方法会创建一个 DOMString,格式大概是 ‘blob:http://127.0.0.1:5500/b08c0131-c178-49be-a8a3-1f13ddf52c7f’,blob:开头,后面跟着当前网站域名加一个guid。这个url的生命周期和创建它的窗口中的document绑定,即刷新页面、关闭页面就会被自动释放了,就失效了。可以当做页面图片回显或者download link用
- 内存管理,在每次调用 createObjectURL 方法时,都会创建一个新的URL对象,即使已经用相同的对象作为参数创建过,当不再需要这些URL对象时,为了获得最佳性能和内存使用状况,每个对象必须通过调用 URL.revokeObjectURL() 方法释放掉。
// blob转url
function fnBlobToUrl(blob) {
return URL.createObjectURL(blob);
}
- Base64转Url
- 先转成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 实现文件下载
- download 属性可以直接调用浏览器的下载功能,而且还可以给download属性设置值来规定下载文件的名称,如果在设置值时没有指定文件的扩展名,浏览器将自动检测正确的文件名并添加到文件(.jpg, .pdf, .txt, .html, 等等)。
- 问题:download 表现最为直观的一个问题就是跨域的问题。如果是加载了非同源的内容,该属性将会失效,会出现下载变浏览的情况。
- 解决:使用 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);
}
😊 谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~