HTML5: Vẽ ảnh và thao tác với pixel

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

HTML5 xác định <canvas> như một bitmap phụ thuộc vào độ phân giải, được sử dung để vẽ đồ thị, đồ họa game hoặc hình ảnh trực quan khác. Canvas là hình chữ nhật trên trang và có thể sử dụng JavaScript để vữ bất cứ điều gì bạn muốn. HTML5 định nghĩa một tập các chức năng (canvas API) để vẽ hình dạng, xác định đường dẫn, tạo gradient.

HTML5 Canvas là một JavaScript API để mã hóa các bản vẽ. Canvas API cho phép định nghĩa một đối tượng canvas như là thử <canvas> trên trang HTML ,chúng ta có thể vẽ bên trong nó. <canvas> là một khối không gian vô hình, mặc định là 300x250 pixels (trên tất cả trình duyệt).

Chúng ta có thể vẽ cả hình 2D và 3D (WebGL). 2D có sẵn trong tất cả các trình duyệt Web hiện đại, IE9, và thông qua thư viện excanvas.js trong các phiên bản IE hiện tại.

Canvas 2D cung cấp một API đơn giản nhưng mạnh mẽ để có thể vẽ một cách nhanh chóng trên bề mặt bitmap 2D. Không có định dạng tập tin, và bạn chỉ có thể vẽ bằng cách sử dụng script. Bạn không có bất kỳ các nút DOM cho các hình khối bạn vẽ - bạn đang vẽ pixels, không phải vectơ và chỉ là các điểm ảnh được ghi nhớ.

Một số tính năng của Canvas:

  • Vẽ hình ảnh
  • Tô màu
  • Tạo hình học và các kiểu mẫu
  • Văn bản
  • Sao chép hình ảnh, video, những canvas khác
  • Thao tác điểm ảnh
  • Xuất nội dung của một thẻ <canvas> sang tập tin ảnh tĩnh.

Vẽ ảnh và thao tác với pixel

Muốn tạo ra những hiệu ứng đồ họa đặc biệt khi sử dụng canvas, bạn không thể chỉ sử dụng các thuộc tính và phương thức có sẵn của đối tượng context. Chính vì vậy, bài viết này sẽ giới thiệu cho bạn cách vẽ ảnh và thao tác với các pixel từ đối tượng ImageData.

1. Nạp và vẽ ảnh

Để vẽ một ảnh ra canvas, ta tạo một đối tượng image và thực hiện phương thức context.drawImage() trong sự kiện load của image. Như vậy để đảm bảo rằng hình ảnh chỉ được vẽ sau khi đã được nạp hoàn tất. Ngoài ra, bạn nên đặt sự kiện load trước khi gán đường dẫn cho ảnh. Nếu không image có thể được load xong trước khi bạn gắn sự kiện load cho nó.

Phương thức drawImage() có ba overload sau:

- Vẽ image tại một vị trí destX, destY:

context.drawImage(image,destX,destY);

- Vẽ image tại vị trí destX, destY và kích thước destWidth, destHeight:

context.drawImage(image,destX,destY,destWidth,destHeight);

- Cắt image tại vị trí [sourceX, sourceY, sourceWidth, sourceHeight] và vẽ tại [destX, destY, destWidth, destHeight]:

context.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);

Ví dụ:

window.onload = function(){

var canvas = document.getElementById("mycanvas");

var context = canvas.getContext("2d");

var img = new Image();

img.onload = function(){

context.drawImage(img, 10, 10,50,50);

};

img.src = "foo.png";

};

2. Thao tác với pixel

Một ảnh bao gồm một mảng các pixel với các giá trị red, green, blue và alpha (RGBA). Trong đó alpha là giá trị xác định độ mờ đục (opacity) của ảnh. Giá trị alpha càng lớn thì độ màu sắc càng rõ nét và màu sắc sẽ trở nên trong suốt nếu alpha là 0.

Trong Canvas 2D API, dữ liệu ảnh được lưu trong một đối tượng ImageData với 3 thuộc tính là width, height và data. Trong đó data là một mảng một chiều chứa các pixel. Mỗi pixel chứa 4 phần tử tương ứng là R,G,B,A.

Như vậy với một ảnh có kích thước 10×20 ta sẽ có 200 pixel và có 200*4=400 phần tử trong mảng ImageData.data.

http://v1study.com/public/images/article/game2d-mau-sac.png

Bạn có thể tham khảo thông tin về các API này tại: http://www.whatwg.org/specs/web-

apps/current-work/multipage/the-canvas-element.HTML#pixel-manipulation:

imagedata = context.createImageData(sw, sh)

Trả về một đối tượng ImageData với kích thước sw x sh. Tất cả pixel của đối tượng này có màu đen trong suốt.

imagedata = context.createImageData(imagedata)

Trả về đối tượng ImageData với kích thước bằng với đối tượng trong tham số. Tất cả pixel có màu đen trong suốt.

imagedata = context.getImageData(sx, sy, sw, sh)

Trả về một đối tượng ImageData chứa dữ liệu ảnh vùng chữ nhật (xác định bởi các tham số) của canvas.

Ném NotSupportedError exception nếu như có bất kì tham số nào không phải là số hợp lệ. Ném

IndexSizeError exception nếu width hoặc height là zero.

imagedata.width

imagedata.height

Trả về kích thước thật của đối tượng ImageData, tính theo pixel.

imagedata.data

Trả về mảng một chiều chứa dữ liệu dạng RGBA, mỗi giá trị nằm trong khoảng 0 đến 255.

context . putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])

Vẽ dữ liệu từ đối tượng ImageData lên canvas tại vị trí dx, dy. Nếu như hình chữ nhật (từ các tham số dirtyX, dirtyY, dirtWidth, dirtyHeight) được xác định, thì phần dữ liệu của ImageData trong vùng chữ nhật này mới được vẽ lên canvas.

http://v1study.com/public/images/article/game2d-imagedata-canvas.png

Các thuộc tính xác định hiệu ứng vẽ của context sẽ bị bỏ qua khi phương thức này được gọi. Các pixel từ canvas sẽ được thay thế hoàn toàn bởi ImageData mà không có các sự kết hợp màu sắc, hiệu ứng, ... với các dữ liệu ảnh sẵn có trên canvas.

Một trong những ví dụ thường gặp và đơn giản nhất là đảo ngược màu của ảnh. Điều này được thực hiện bằng cách lấy giá trị màu tối đa (255) trừ đi giá trị của mỗi kênh màu RGB hiện tại của mỗi pixel. Giá trị alpha sẽ để giá trị tối đa để ảnh được rõ nét nhất.

<HTML>

<head>

<script>

window.onload = function(){

var img = new Image();

img.onload = function(){

invertColor(this);

};

img.src="panda.jpg";

};

function invertColor(img){

var canvas = document.getElementById("mycanvas");

var context = canvas.getContext("2d");

// draw image at top-left corner

context.drawImage(img,0,0);

// draw original image right beside the previous image

context.drawImage(img,img.width,0);

// get ImageData object from the left image

var imageData = context.getImageData(0, 0, img.width,

img.height);

var data = imageData.data;

for (var i = 0; i < data.length; i += 4) {

data[i] = 255 - data[i]; // red

data[i + 1] = 255 - data[i+1]; // green

data[i + 2] = 255 - data[i+2]; // blue

data[i + 3] = 255; // alpha

}

context.putImageData(imageData,0,0);

}

</script>

</head>

<body>

<canvas id="mycanvas" width="600" height="250"></canvas>

</body>

</HTML>

Kết quả:

http://v1study.com/public/images/article/game2d-ket-qua-vi-du.png

Bạn có thể thêm các tham số để tạo một “dirty rectangle” trong phương thức putImageData() nếu muốn vẽ ImageData lên một vùng chữ nhật xác định của canvas.

Ví dụ ta chọn cùng một vùng chữ nhật trên ImageData và vẽ lên hai vùng chữ nhật khác nhau trên canvas để được kết quả sau:

context.putImageData(imageData,0,0,0,0,img.width/2,img.height/2);

context.putImageData(imageData,img.width,0,0,0,img.width/2,img.height/2);

http://v1study.com/public/images/article/game2d-ket-qua-vi-du1.png

» Tiếp: Vẽ hình bằng chuột
« Trước: Tạo chuyển động với WindowAnimationTiming API
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!