Nếu bạn từng có tuổi thơ chơi những game bốn nút của nintendo đời cũ, hay những game di động trên máy điện thoại đời cũ chắc hẳn các bạn đã từng thấy những hình ảnh nhân vật, vật phẩm, khung cảnh … được thể hiện dưới dạng những chấm ảnh của màn hình. Một ví dụ rất gần gũi với chúng ta từng làm mưa làm gió trên thị trường game một thời của anh Nguyễn Hà Đông chính là nhân vật flappy bird cho bạn dễ hình dung.
Bitmap là một khái niệm quan trọng trong lập trình Android, đặc biệt là khi làm việc với đồ họa và xử lý hình ảnh. Trong bài viết này, chúng ta sẽ tìm hiểu cơ bản về Bitmap, từ khái niệm đến cách sử dụng trong lập trình Android.
1. Vậy bitmap là gì?
Bitmap (Raster Image) là một dạng ảnh số dạng ma trận 2 chiều gồm một loạt các pixel (điểm ảnh). Mỗi một pixel sẽ là một ô vuông tương ứng từng điểm ảnh trên thiết bị màn hình. Chúng được gán màu và vị trí phù hợp để tạo ra hình ảnh theo mắt người nhìn. Một số định dạng có thể bạn đã gặp rồi trên các nền tảng khác nhau như PNG, JPG, BMP, JPEG hay kể cả GIF ….
Đây là một định dạng khá phổ biến trong đời sống hiện nay. Nó có thể chỉnh sửa dễ dàng các điểm ảnh đơn lẻ với, thể hiện rõ ràng màu sắc và có nhiều ứng dụng hỗ trợ mặc dù kích thước của nó lại khá là lớn.
Tuy đó nó vẫn có một điểm trừ khá lớn đó là nếu bitmap không đạt được kích thức phù hợp với độ phân giải của thiết bị media đầu ra ta sẽ gặp tình trạng khó chịu như vỡ hình, mờ ảnh khi phóng to. Điều này khá quan trọng, bạn cần chú ý tới đơn vị đo lường DPI (Dots per inch) hay PPI (Pixels per inch), khi trong thiết bị điện thoại thì ảnh bitmap của bạn có thể đưa ra hình ảnh tuyệt vời, nhưng khi lên một thiết bị lớn hơn như tablet thì chắc là bạn sẽ không muốn nó như vậy đâu. Khi đó thì mình khuyến thích bạn sử dụng ảnh dạng vector hay tạo ra một ảnh khác có tỉ lệ điểm ảnh cao hơn.
2. Cơ bản bitmap trong android
Trong lập trình android, hầu hết mọi thứ được vẽ bởi hệ điều hành Android là bitmap. Bitmap được hỗ trợ thông qua class Bitmap (android.graphics.Bitmap). Với lớp này chúng ta có thể đọc, ghi từng pixel, lấy kích thước chiều dài rộng …
Tương tự như bitmap thông thường, hệ điều hành android hỗ trợ màu với 4 kênh màu tương ứng (A-R-G-B). Mỗi kênh được thể hiện bằng 1 bytes hay một pixel có thể có 232 ~ 16.7 triệu màu khác nhau.
A – Alpha: Độ trong suốt của màu.
R – Red: Độ đậm màu đỏ.
G – Green: Độ đậm màu xanh lá.
B – Blue: Độ đậm màu xanh dương.
Thay vì thể hiện bằng các dãy bit 0-1 dài 32 thì Android cũng dùng hệ Hex để thể hiện
một màu của nó. Chúng được viết liền thể hiện lần lượt cho A -> R -> G -> B
Ví dụ màu StringEE ở đây sẽ có A = E6 = 90%, R = CF = 207, G = OC = 12,
B = OC = 12 (trên dải màu từ 0 tới 255 tức 256 giá trị)
Ví dụ cách tính hệ số Hex sang hệ 10 nếu bạn đang thắc mắc:
Hệ số Hex được tính từ 1 tới 9 rồi tiếp là A tới F tức 16 giá trị khác nhau.
R: CF có C sẽ là 12 còn F là 15, khi đó ta có công thức
Red = 12 * 16 + 15 = 207
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="StringEE">#00000C</color>
</resources>
Vậy làm thế nào để thao tác với từng điểm ảnh trong Android?, chúng ta cùng quay lại với lớp Bitmap đã được đề cập phía trên. Lớp bitmap cung cấp cho chúng ta 2 methods để xử lý từng điểm ảnh:
Đầu tiên sẽ là đọc toàn bộ điểm ảnh để xử lý theo mảng từ một Bitmap có sẵn thông qua method **Bitmap.getPixels()**:<br>
Bitmap.getPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)
- Tiếp theo đó là ghi toàn bộ giá trị điểm ảnh vào Bitmap sau khi đã thay đổi thông qua method Bitmap.setPixels():
Bitmap.setPixels(int[] pixels, int offset, int stride, int x, int y, int width, int height)
Cùng với đó là phương thức quan trọng khác để tạo ra một Bitmap ban đầu, từ đó ta có được một bitmap theo ý của mình, chỉnh sửa hay xuất lên màn hình tùy ý Bitmap.createBitmap(…); Để dễ hình dung những method trên, mình sẽ ví dụ một function quen thuộc với những người làm xử lý ảnh nhằm chuyển ảnh từ ảnh màu về ảnh đa xám bằng phương thức argb2grayScale()
public class StringEE {
public Bitmap argb2grayScale(Bitmap bitmapInput) {
Bitmap bitmapOutput = Bitmap.createBitmap(bitmapInput.getWidth(), bitmapInput.getHeight(), bitmapInput.getConfig());
int A, R, G, B;
int w = bitmapInput.getWidth();
int h = bitmapInput.getHeight();
int[] colors = new int[w * h];
bitmapInput.getPixels(colors, 0, w, 0, 0, w, h);
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
// Lấy vị trí của bitmap tại vị trí [i, j]
int pos = i * w + j;
// Xác định từng mã màu
A = (colors[pos] >> 24) & 0xFF;
R = (colors[pos] >> 16) & 0xFF;
G = (colors[pos] >> 8) & 0xFF;
B = colors[pos] & 0xFF;
// công thức tính chuyển ảnh màu về ảnh đen trắng
R = G = B = (int) (0.299 * R + 0.587 * G + 0.114 * B);
colors[pos] = Color.argb(A, R, G, B);
}
}
bitmapOutput.setPixels(colors, 0, w, 0, 0, w, h);
return bitmapOutput;
}
}
3. Quản lý bộ nhớ khi làm việc với Bitmap
Khi làm việc với Bitmap trong Android, quản lý bộ nhớ là một vấn đề quan trọng. Bitmap có thể chiếm nhiều bộ nhớ, đặc biệt là khi xử lý các hình ảnh lớn. Để tránh tình trạng lãng phí bộ nhớ và tránh các lỗi như OutOfMemoryError, chúng ta nên luôn giải phóng bộ nhớ khi không cần thiết bằng cách gọi phương thức bitmap.recycle()
.
4. Một số điều cần chú ý
Để làm việc với lớp bitmap hiệu quả hơn, Android cũng cung cấp thêm cho chúng ta lớp BitmapFactory. Với lớp này bạn có thể decode một file trong thiết bị android, xác định option mong muốn. Cùng với đó là lớp Canvas, lớp Paint, … để vẽ các điểm ảnh mong muốn lên trên phần mềm android của bạn. trong khuôn khổ bài viết này, mình xin chỉ giới thiệu để bạn có cơ hội tìm hiểu nhiều hơn.
Những bức ảnh từ máy ảnh hiện tại ngày càng lớn. Như bạn có thể thấy một bức ảnh chất lượng cao được chụp từ máy ảnh s23 ultra lên tới 200 megapixel. Một bức ảnh bình thường cũng khoảng 12 megapixel. Ram của bạn sẽ hết vèo nếu bạn đọc một cách truyền thống. Vì vậy hãy xử lý một cách khôn khéo với nó như chia bức ảnh hay scale để có thể thực hiện bức ảnh một cách mượt mà.
Không chỉ Ram mà chi phí dành cho CPU để xử lý bitmap cũng đáng lo ngại. Nó sẽ tốn rất nhiều thời gian để xử lý. Vì vậy đừng dại mà thực hiện nó trên UI Thread (main). Thay vào đó hãy sử dụng các phương thức bất động bộ hoặc background thread để xử lý chúng nhé.
Tổng kết
Hi vọng qua bài viết này thì bạn đã có thể hiểu hơn về bitmap trong android. Những kiến thức cơ bản này sẽ là nền tảng để bạn có thể tìm hiểu sâu hơn sau này. Để tiếp tục với nhiều phương thức khác được cung cấp bởi google bạn có thể đọc tại trang chính thống của Android:Bitmap | Android Developers. Cảm ơn vì bạn đã đọc và chúc bạn có thêm được nhiều điều bổ ích nhé.
Stringee API cung cấp các tính năng như gọi thoại, gọi video, tin nhắn chat, SMS hay tổng đài chăm sóc khách hàng (CSKH) có thể được nhúng trực tiếp vào các ứng dụng/website của doanh nghiệp nhanh chóng. Điều này giúp tiết kiệm đến 80% thời gian và chi phí cho doanh nghiệp, trong khi nếu tự phát triển các tính năng này có thể mất từ 1 - 3 năm.