图中的几个对象包括 canvas、image、DataURL、ObjectURL、Blob、ArrayBuffer
- 图片获取DataURL
- dataURL是一种特殊格式的URL。它的前缀是
// 格式
data:[<mediatype>][,base64],<data>
// eg
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhAAAAIwCAYAAADXrFK...
从本地选择图片获取DataURL
const reader = new FileReader();
reader.onload = function () {
const output = document.querySelector("img");
output.src = reader.result;
};
// 这里传入的参数是一个文件File 而上面图片中是blob。 因为File继承Blob
reader.readAsDataURL(event.target.files[0]);
// 补充 reader.readAsText() 可以获取文本的内容
- 图片加载ObjectURL
通过 URL.createObjectURL(blob)创建
// 格式
blob:null/ab24c171-1c5f-4de1-a44e-568bc1f77d7b
// eg
fetch("https://avatars3.githubusercontent.com/u/4220799")
.then((response) => response.blob())
.then((blob) => {
const objectURL = URL.createObjectURL(blob);
image.src = objectURL;
});
// 仅作示例 实际不这么使用
//补充 下载为文件
// const blob = new Blob([res.data], { type: "application/vnd.ms-excel" });
const link = document.createElement('a');
link.download ='test.excel';
link.style.display = 'none';
link.href = URL.createObjectURL(blob);
document.body.appendChild(link);
link.click();
// 这里需要释放掉,否则会一直占用内存
URL.revokeObjectURL(link.href); // 释放URL 对象
document.body.removeChild(link);
- Canvas中的图片处理
- drawImage(image) 根据已有的图片对象 绘制图片
- getImageData(x,y, w,h) 获取画布某一个区域内的图像数据(像素数据)
- putImageData() 将图像数据绘制在画布上
3.1 图片压缩
1. 绘制图片
context.drawImage(img, dx, dy, dWidth, dHeight)
2. 压缩
const dataUrl = canvas.toDataURL(mimeType, qualityArgument);
const blob = canvas.toBlob(callback, mimeType, qualityArgument)
3.2 图片灰度化
1 获取图像的像素数据
const imageData = ctx.getImageData(x, y, W, H);
const data = imageData.data;
2. 处理图像的像素数据
for (let i = 0; i < data.length; i += 4) {
const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
3. 处理后的数据重新绘制
ctx.putImageData(imageData, x, y);
3.3 图片打码
1. 获取图像的像素
const imageData = ctx.getImageData(x, y, w, h).data;
// option defaults
2. 设置马赛克块的像素大小
const res = 4
const size = res
const alpha = 1
const cols = w / res + 1
const rows = h / res + 1
const halfSize = size / 2
3. 双循环行和列
for (let row = 0; row < rows; row++) {
let y = (row - 0.5) * res
// normalize y so shapes around edges get color
let pixelY = Math.max(Math.min(y, h - 1), 0)
for (let col = 0; col < cols; col++) {
let x = (col - 0.5) * res
// normalize y so shapes around edges get color
let pixelX = Math.max(Math.min(x, w - 1), 0)
let pixelIndex = (pixelX + pixelY * w) * 4
const red = imageData[pixelIndex + 0]
const green = imageData[pixelIndex + 1]
const blue = imageData[pixelIndex + 2]
const pixelAlpha = alpha * (imageData[pixelIndex + 3] / 255)
4 绘制马赛克方块 square
ctx.fillStyle = `rgba(${red},${green},${blue},${pixelAlpha})`
ctx.fillRect(x - halfSize, y - halfSize, size, size)
} // col
} // row
3.4 取色器
1. 获取位置
const {x, y} = event;
2. 获取位置后的一个像素
const imageData = ctx.getImageData(x, y, 1, 1).data;
const colorValue = imageData.join(',');
const colorValueEl = document.querySelector('#colorValue');
colorValueEl.innerText = colorValue;
const bgColorEl = document.querySelector('#bgColor');
bgColorEl.style.backgroundColor = `rgba(${colorValue})`
3.4 边缘检测
1. 像素黑白化
const grayData = blackWhitePixel(imageData);
2. 检测边缘
const edgeData = contourDIB(grayData, w, h);
_imageData.data = imageData;
ctx.putImageData(_imageData, 0, 0);
function contourDIB(data, lWidth, lHeight) {
// 保存原始数据
const dataInit = [];
for (let i = 0, len = data.length; i < len; i++) {
dataInit[i] = data[i];
}
for (let j = 1; j < lHeight - 1; j++) {
for (let i = 1; i < lWidth - 1; i++) {
const lpSrc = j * lWidth + i;
const pixel = dataInit[lpSrc * 4];
if (pixel === 0) {
const surroundArr = [lpSrc + lWidth - 1, lpSrc + lWidth,
lpSrc + lWidth + 1, lpSrc - 1, lpSrc + 1,
lpSrc - lWidth - 1, lpSrc - lWidth, lpSrc - lWidth + 1];
let value = 0;
for (let m = 0, len = surroundArr.length; m < len; m++) {
value += dataInit[surroundArr[m] * 4];
}
// 如果相邻对八个点都是黑点 说明不是边缘
if (value === 0) {
for (let k = 0; k < 3; k++) {
data[lpSrc * 4 + k] = 255;
}
}
}
}
}
return data
}
网友评论