这里采用基于 base64 解码的方式实现,有别与传统的借用 Image、Canvas 两个对象来处理,而是解码为二进制数据方式来进行处理,这个方式更为底层,有助于大家理解图形原理
核心:
window.atob// 解码
atob () 对经过 base-64 编码的字符串进行解码。你可以使用 window.btoa () 方法来编码一个可能在传输过程中出现问题的数据,并且在接受数据之后,使用 atob () 方法再将数据解码。例如:你可以编码、传输和解码操作各种字符,比如 0-31 的 ASCII 码值。
window.btoa// 二进制编码为字符串
btoa () 方法可以将一个二进制字符串(例如,将字符串中的每一个字节都视为一个二进制数据字节)编码为 Base64 编码的 ASCII 字符串。
ImageData
ImageData 接口描述 元素的一个隐含像素数据的区域。使用 ImageData () 构造函数创建或者使用和 canvas 在一起的 CanvasRenderingContext2D 对象的创建方法: createImageData () 和 getImageData ()。也可以使用 putImageData () 设置 canvas 的一部分。
代码
const adjustImage = (base64Image, brightnessDelta, contrastGamma)=> {
new Promise((resolve, reject) => {
// 将 base64 编码的字符串解码为二进制数据
const binary = atob(base64Image.split(',')[1]);
// 计算图片大小
const imageSize = binary.length;
// 计算图片宽度和高度
const sizeData = binary.substr(0, 16).match(/(\d+)x(\d+)/);
const imageWidth = parseInt(sizeData[1]);
const imageHeight = parseInt(sizeData[2]);
// 创建一个新的 Uint8ClampedArray 对象,将像素数据写入其中
const pixels = new Uint8ClampedArray(imageSize - 16);
for (let i = 16, j = 0; i < imageSize; i++, j++) {
pixels[j] = binary.charCodeAt(i);
}
// 创建一个新的 ImageData 对象,使用解码后的像素数据
const imageData = new ImageData(pixels, imageWidth, imageHeight);
const data = imageData.data;
// 遍历所有像素,修改亮度和对比度
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// 降低亮度
const [newR, newG, newB] = decreaseBrightness(r, g, b, brightnessDelta);
// 降低对比度
const [finalR, finalG, finalB] = decreaseContrast(newR, newG, newB, contrastGamma);
// 将修改后的像素写回 imageData
data[i] = finalR;
data[i + 1] = finalG;
data[i + 2] = finalB;
}
// 将修改后的 imageData 转换为 base64 编码的图像
const binaryImageData = String.fromCharCode.apply(null, imageData.data);
resolve( 'data:image/png;base64,' + btoa(binaryImageData));
}
}
// 降低亮度
const decreaseBrightness = (r, g, b, delta) =>{
r = Math.max(0, r - delta);
g = Math.max(0, g - delta);
b = Math.max(0, b - delta);
return [r, g, b];
}
// 降低对比度
const decreaseContrast = (r, g, b, gamma) =>{
let luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
let factor = (259 * (gamma + 255)) / (255 * (259 - gamma));
let newR = Math.max(0, Math.min(factor * (r - luminance) + luminance, 255));
let newG = Math.max(0, Math.min(factor * (g - luminance) + luminance, 255));
let newB = Math.max(0, Math.min(factor * (b - luminance) + luminance, 255));
return [newR,newG, newB];
}