1. Tổng quan về GDI+ và hiệu ứng độ trong suốt
1.1 Giới thiệu về GDI+
GDI+ (Graphics Device Interface Plus) là thư viện đồ họa nâng cao do Microsoft cung cấp cho các ứng dụng Windows. So với GDI truyền thống, GDI+ bổ sung nhiều tính năng mạnh mẽ như biến đổi hình học, điều khiển độ trong suốt và xử lý ảnh phong phú.
1.2 Khái niệm độ trong suốt
Độ trong suốt (transparency) mô tả khả năng cho phép ánh sáng đi qua bề mặt của đối tượng. Trong GDI+, độ trong suốt được biểu diễn thông qua kênh Alpha với giá trị từ 0 đến 255: 0 là hoàn toàn trong suốt, 255 là hoàn toàn đặc.
1.3 Ứng dụng của hiệu ứng độ trong suốt
Hiệu ứng thay đổi độ trong suốt được sử dụng rộng rãi trong tạo giao diện người dùng đẹp mắt, hiệu ứng hoạt hình fade in/fade out, cũng như trong trực quan hóa dữ liệu và phát triển game.
2. Sử dụng hàm AlphaBlend
2.1 Cơ bản về AlphaBlend
Hàm AlphaBlend là API chính để thực hiện hiệu ứng chồng lớp có độ trong suốt:
BOOL AlphaBlend(
HDC hdcDest, // Context đích
int xOriginDest, // Tọa độ X điểm gốc đích
int yOriginDest, // Tọa độ Y điểm gốc đích
int widthDest, // Chiều rộng vùng đích
int heightDest, // Chiều cao vùng đích
HDC hdcSrc, // Context nguồn
int xOriginSrc, // Tọa độ X điểm gốc nguồn
int yOriginSrc, // Tọa độ Y điểm gốc nguồn
int widthSrc, // Chiều rộng vùng nguồn
int heightSrc, // Chiều cao vùng nguồn
BLENDFUNCTION blendFunc // Cấu trúc trộn màu
);
2.2 Thực hành với AlphaBlend
Ví dụ tạo hiệu ứng trong suốt giữa hai bitmap:
// Thiết lập cấu trúc blend
BLENDFUNCTION blendParams = {0};
blendParams.BlendOp = AC_SRC_OVER;
blendParams.SourceConstantAlpha = 128; // 50% trong suốt
blendParams.AlphaFormat = AC_SRC_ALPHA;
// Lấy context thiết bị
HDC targetDC = ::GetDC(windowHandle);
HDC sourceDC = ::CreateCompatibleDC(targetDC);
HBITMAP oldBitmap = (HBITMAP)::SelectObject(sourceDC, foregroundBitmap);
// Thực hiện blend
::AlphaBlend(targetDC, 0, 0, destWidth, destHeight,
sourceDC, 0, 0, srcWidth, srcHeight,
blendParams);
// Dọn dẹp tài nguyên
::SelectObject(sourceDC, oldBitmap);
::DeleteDC(sourceDC);
::ReleaseDC(windowHandle, targetDC);
3. Khởi tạo và sử dụng GDI+ trong dự án VC++
3.1 Cấu hình môi trường GDI+
Khởi động môi trường chạy GDI+:
#include <gdiplus.h>
using namespace Gdiplus;
ULONG_PTR gdiplusInstance;
GdiplusStartupInput startupConfig;
// Khởi tạo GDI+
GdiplusStartup(&gdiplusInstance, &startupConfig, NULL);
Kết thúc chương trình cần gọi:
GdiplusShutdown(gdiplusInstance);
3.2 Quản lý đối tượng Graphics
Tạo và sử dụng đối tượng Graphics để vẽ:
// Trong hàm xử lý sự kiện OnPaint
Graphics painter(paintEventArgs->Hdc);
// Vẽ ellipse với brush màu đỏ bán trong suốt
SolidBrush redBrush(Color(128, 255, 0, 0)); // Alpha=128
painter.FillEllipse(&redBrush, 10, 10, 200, 100);
4. Triển khai thay đổi độ trong suốt hình ảnh
4.1 Chuẩn bị tài nguyên hình ảnh
Định dạng PNG hỗ trợ tốt nhất cho độ trong suốt. Tải hình ảnh:
// Khởi tạo GDI+
GdiplusStartup(&token, &input, NULL);
// Tải hình ảnh PNG
Image* loadedImage = Image::FromFile(L"path/to/image.png", TRUE);
// Dọn dẹp khi kết thúc
delete loadedImage;
GdiplusShutdown(token);
4.2 Cài đặt hàm thay đổi độ trong suốt
Sử dụng ColorMatrix và ImageAttributes:
void ModifyImageOpacity(Image* img, BYTE opacityLevel) {
// Kiểm tra giới hạn giá trị
opacityLevel = min(255, max(0, opacityLevel));
// Ma trận màu cho điều chỉnh alpha
ColorMatrix transformMatrix = {
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, opacityLevel / 255.0f, 0,
0, 0, 0, 0, 1
};
ImageAttributes attributes;
attributes.SetColorMatrix(&transformMatrix, ColorMatrixFlagDefault, ColorAdjustTypeBitmap);
Graphics canvas(...);
canvas.DrawImage(img, destRect, 0, 0, img->GetWidth(), img->GetHeight(), UnitPixel, &attributes);
}
5. Vai trò của ColorMatrix và ImageAttributes
5.1 Cấu trúc và chức năng ColorMatrix
ColorMatrix là ma trận 5x5 dùng để biến đổi màu sắc pixel. Mỗi hàng tương ứng R, G, B, A, và mỗi cột xác định hệ số biến đổi cho từng kênh.
5.2 Ứng dụng nâng cao ImageAttributes
Tạo hiệu ứng làm tối nền:
ColorMatrix darkenEffect = {
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0,
0, 0, 0, 0, 0.5f // Giảm độ sáng xuống 50%
};
ImageAttributes imgAttrs;
imgAttrs.SetColorMatrix(&darkenEffect);
graphics.DrawImage(image, rect, 0, 0, width, height, GraphicsUnit.Pixel, &imgAttrs);
6. Kết hợp timer tạo hiệu ứng hoạt hình
6.1 Thiết lập timer trong VC++
UINT_PTR timerId = 1;
UINT intervalMs = 50;
// Tạo timer
SetTimer(timerId, intervalMs, nullptr);
// Xử lý sự kiện timer
void OnTimer(UINT_PTR id) {
if (id == timerId) {
UpdateAnimation();
InvalidateRect(); // Yêu cầu vẽ lại
}
CWnd::OnTimer(id);
}
// Hủy timer
KillTimer(timerId);
6.2 Tối ưu hiệu suất hoạt hình
Cập nhật độ trong suốt theo thời gian:
void AnimateTransparency() {
static float currentAlpha = 0.0f;
static bool directionUp = true;
currentAlpha += directionUp ? 0.02f : -0.02f;
if (currentAlpha >= 1.0f) {
currentAlpha = 1.0f;
directionUp = false;
} else if (currentAlpha <= 0.0f) {
currentAlpha = 0.0f;
directionUp = true;
}
ApplyAlphaToImage(currentAlpha * 255);
}