這裏採用基於base64解碼的方式實現,有別與傳統的借用Image、Canvas兩個對象來處理,而是解碼爲二進制數據方式來進行處理,這個方式更爲底層,有助於大家理解圖形原理
核心:
window.atob //解碼
atob() 對經過 base-64 編碼的字符串進行解碼。你可以使用 window.btoa() 方法來編碼一個可能在傳輸過程中出現問題的數據,並且在接受數據之後,使用 atob() 方法再將數據解碼。例如:你可以編碼、傳輸和解碼操作各種字符,比如 0-31 的 ASCII 碼值。
window.btoa //二進制編碼爲字符串
btoa() 方法可以將一個二進制字符串(例如,將字符串中的每一個字節都視爲一個二進制數據字節)編碼爲 Base64 編碼的 ASCII 字符串。
ImageData
ImageData 接口描述 <canvas> 元素的一個隱含像素數據的區域。使用 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];
}