将Targa(TGA)加载为HBITMAP后颜色显示异常问题排查
TGA转HBITMAP颜色异常问题解决及替代方案
问题根源
你的TGA文件是24位RGB格式,但TGA的24位像素存储顺序是BGR,而Windows GDI的24位DIB(设备无关位图)同样使用BGR顺序存储像素。你直接将TGA的RGB数据传入SetDIBits,导致红色和蓝色通道反转,这就是显示颜色不一致的核心原因。
解决方案
方案1:修改现有代码,转换像素通道顺序
在调用SetDIBits前,遍历像素数据,交换每个像素的R和B通道:
auto image = ReadImageFile("test.tga"); if (image == nullptr) break; unsigned int displayWidth = 1920; unsigned int displayHeight = 1080; BITMAPINFO bmi = {}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = image->GetWidth(); bmi.bmiHeader.biHeight = -static_cast<int>(image->GetHeight()); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hBitmap = CreateDIBSection(hdcMem, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); if (hBitmap) { // 获取像素数据并转换RGB到BGR unsigned char* pixels = image->GetPixels(); const unsigned int pixelCount = image->GetWidth() * image->GetHeight(); for (unsigned int i = 0; i < pixelCount; ++i) { const unsigned char temp = pixels[i*3]; pixels[i*3] = pixels[i*3 + 2]; pixels[i*3 + 2] = temp; } SetDIBits(hdcMem, hBitmap, 0, image->GetHeight(), pixels, &bmi, DIB_RGB_COLORS); SelectObject(hdcMem, hBitmap); SetStretchBltMode(hdc, HALFTONE); StretchBlt(hdc, 0, 0, displayWidth, displayHeight, hdcMem, 0, 0, image->GetWidth(), image->GetHeight(), SRCCOPY); DeleteObject(hBitmap); } DeleteDC(hdcMem); EndPaint(hWnd, &ps); break;
注意:如果image->GetPixels()返回的是const指针,需要先将像素数据拷贝到可修改的内存区域再进行通道转换。
方案2:使用GDI+直接加载TGA(更简洁高效)
如果不想手动处理像素格式,GDI+支持直接加载TGA文件,无需自行解析格式或转换通道:
#include <gdiplus.h> #pragma comment(lib, "gdiplus.lib") // 程序启动时初始化GDI+(仅需调用一次) Gdiplus::GdiplusStartupInput gdiplusInput; ULONG_PTR gdiplusToken; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusInput, nullptr); // 加载并绘制TGA的代码 auto displayWidth = 1920u; auto displayHeight = 1080u; PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); Gdiplus::Image tgaImage(L"test.tga"); if (tgaImage.GetLastStatus() == Gdiplus::Ok) { Gdiplus::Graphics graphics(hdc); // 设置高质量插值模式,拉伸时更清晰 graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); graphics.DrawImage(&tgaImage, 0, 0, displayWidth, displayHeight); } EndPaint(hWnd, &ps); // 程序退出时关闭GDI+ Gdiplus::GdiplusShutdown(gdiplusToken);
优势:无需手动处理TGA格式细节,GDI+会自动完成格式转换和内存管理,代码更简洁,不易出错。
内容的提问来源于stack exchange,提问作者avgcoder
相关产品推荐
相关产品推荐

