Xử lý hình ảnh phía Client hiệu năng cao
Xử lý hình ảnh trong trình duyệt hiện là một yêu cầu tiêu chuẩn. Bạn có thể đang xây dựng các trình chỉnh sửa ảnh, bộ công cụ tài nguyên (asset toolkits), hoặc các bộ lọc hỗ trợ tiếp cận (accessibility filters). Để giữ cho giao diện người dùng (UI) luôn phản hồi nhanh, bạn cần độ trễ thấp.
Một tác vụ đơn giản là đảo ngược màu sắc. Điều này có nghĩa là chuyển đổi các giá trị RGB sang giá trị âm của chúng. Nếu bạn sử dụng cách tiếp cận tiêu chuẩn cho hình ảnh 4K, bạn sẽ gặp phải các nút thắt cổ chai về phần cứng.
Vấn đề: Lặp theo cách thông thường
Hầu hết các nhà phát triển sử dụng phương thức getImageData(). Phương thức này trả về một Uint8ClampedArray. Mảng này lưu trữ các pixel dưới dạng các kênh Đỏ, Xanh lá, Xanh dương và Alpha (RGBA).
Một vòng lặp tiêu chuẩn trông như thế này:
- Lặp qua từng byte một.
- Trừ mỗi giá trị màu cho 255.
- Bỏ qua kênh Alpha.
Cách này hoạt động với các hình ảnh nhỏ. Nhưng nó thất bại với các tài nguyên 4K. Một hình ảnh 4K có hơn 8 triệu pixel. Một vòng lặp tiêu chuẩn thực hiện hơn 33 triệu lần ghi riêng biệt. Điều này làm chặn luồng chính (main thread), gây ra tình trạng giật lag trình duyệt và tụt khung hình.
Giải pháp: Thao tác trên Buffer 32-bit
Bạn có thể ngừng coi mỗi pixel là bốn kênh riêng biệt. Thay vào đó, hãy đè một Uint32Array lên trên buffer dữ liệu.
Bằng cách sử dụng chế độ xem (view) 32-bit, bạn nhóm R, G, B và A thành một số nguyên duy nhất. Vòng lặp của bạn giờ đây chỉ thực hiện 8,2 triệu lần lặp thay vì 33 triệu lần. Bạn xử lý một thao tác cho mỗi pixel thay vì bốn thao tác.
Đảo ngược màu nhanh chóng thông qua bitwise XOR
Để đảo ngược màu mà không chạm vào kênh Alpha, hãy sử dụng toán tử bitwise XOR (^). Sử dụng mặt nạ (mask) 0x00FFFFFF.
Cách thức hoạt động:
- Mặt nạ chỉ nhắm vào các bit màu.
- Các bit Alpha được giữ nguyên.
- CPU xử lý việc này chỉ trong một chu kỳ.
Kết quả:
- Tài nguyên 1080p: nhanh hơn 3,8 lần.
- Template 2K: nhanh hơn 4,1 lần.
- Hình nền 4K: nhanh hơn 4,4 lần.
Mẹo chuyên nghiệp: Sử dụng Web Workers Nếu bạn xử lý nhiều tệp độ phân giải cao, ngay cả các thao tác 32-bit cũng có thể làm chậm UI. Hãy chuyển logic sang một Web Worker. Sử dụng Transferable Objects để truyền buffer. Điều này giúp tránh việc sao chép dữ liệu và giữ cho luồng chính của bạn luôn rảnh rỗi.
Hãy ngừng sử dụng các vòng lặp nặng nề. Hãy sử dụng các từ (words) 32-bit và các cờ bitwise để xây dựng các đường ống (pipelines) xử lý hình ảnh tinh gọn và nhanh chóng.