Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> HTML

Thay đổi màu hình ảnh vẽ trên HTML5 Canvas (Pixel Manipulation)

Để thay đổi màu của hình ảnh đã vẽ trên canvas, bạn phải thao tác trực tiếp trên pixel data qua getImageData(), sửa đổi mảng pixel, sau đó putImageData().

Quy trình

  1. Vẽ hình ảnh nguồn lên canvas tạm (hoặc canvas chính).
  2. Lấy ImageData bằng getImageData(0, 0, width, height).
  3. Duyệt mảng data (RGBA: 4 giá trị/pixel) và sửa đổi.
  4. Đặt lại dữ liệu bằng putImageData().

Ví dụ: Thay đổi màu theo kênh (Colorize/Tint)

function colorizeImage(img, r, g, b) {
  // Tạo canvas tạm
  var canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  var ctx = canvas.getContext('2d');
  
  // Vẽ ảnh gốc
  ctx.drawImage(img, 0, 0);
  
  // Lấy pixel data
  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imageData.data;
  
  // Duyệt từng pixel (4 giá trị: R, G, B, A)
  for (var i = 0; i < data.length; i += 4) {
    // Kết hợp màu gốc với màu mới (OR bitwise - effect "tint")
    // Hoặc thay thế hoàn toàn: data[i] = r; data[i+1] = g; data[i+2] = b;
    
    // Ví dụ: Tint - giữ độ sáng (luminance) nhưng đổi hue
    var gray = (data[i] * 0.299 + data[i+1] * 0.587 + data[i+2] * 0.114);
    data[i]   = Math.min(255, gray * r / 255);     // R
    data[i+1] = Math.min(255, gray * g / 255);     // G
    data[i+2] = Math.min(255, gray * b / 255);     // B
    // data[i+3] = alpha (giữ nguyên)
  }
  
  // Vẽ lại
  ctx.putImageData(imageData, 0, 0);
  
  return canvas; // Trả về canvas đã xử lý
}

// Sử dụng
var img = new Image();
img.crossOrigin = 'anonymous'; // Cần nếu cross-origin
img.onload = function() {
  var newCanvas = colorizeImage(img, 255, 0, 0); // Tint đỏ
  document.body.appendChild(newCanvas);
};
img.src = 'image.png';

Các hiệu ứng pixel phổ biến

Hiệu ứngCông thức (trong loop i+=4)
Grayscalevar gray = 0.299*R + 0.587*G + 0.114*B; R=G=B=gray;
Invert (Negative)R=255-R; G=255-G; B=255-B;
SepiaR=min(255,0.393R+0.769G+0.189B); G=min(255,0.349R+0.686G+0.168B); B=min(255,0.272R+0.534G+0.131B);
BrightnessR=R*factor; G=G*factor; B=B*factor; (factor > 1 sáng hơn)
Threshold (Đen trắng)var avg=(R+G+B)/3; R=G=B=avg>128?255:0;
Tint (Colorize)R=R*tintR/255; G=G*tintG/255; B=B*tintB/255;

Hiệu năng & Tối ưu

  • Duyệt pixel JS chậm trên ảnh lớn (>1MP). Dùng Web Workers hoặc WebGL shaders.
  • Uint32Array view trên imageData.data.buffer để xử lý 4 byte cùng lúc (fast).
  • OffscreenCanvas + Worker cho xử lý nền.
// Fast pixel manipulation with Uint32Array (little-endian: BGRA hoặc RGBA tùy platform)
var buf = new Uint32Array(imageData.data.buffer);
for (var i = 0; i < buf.length; i++) {
  var pixel = buf[i];
  // Extract components (platform dependent order!)
  // Thường là BGRA trên little-endian
  var b = pixel & 0xFF;
  var g = (pixel >> 8) & 0xFF;
  var r = (pixel >> 16) & 0xFF;
  var a = (pixel >> 24) & 0xFF;
  // Modify...
  buf[i] = (a << 24) | (r << 16) | (g << 8) | b;
}

Lưu ý CORS (Quan trọng)

Nếu ảnh từ domain khác, phải có header CORS và set img.crossOrigin = 'anonymous' trước khi gán src, nếu không getImageData() sẽ ném SecurityError (tainted canvas).