https://git.reactos.org/?p=reactos.git;a=commitdiff;h=97b64c45c6dcdd2b1e56bcb078d8be72de860ba0
commit 97b64c45c6dcdd2b1e56bcb078d8be72de860ba0 Author: Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> AuthorDate: Sat Sep 9 08:42:55 2023 +0900 Commit: GitHub <nore...@github.com> CommitDate: Sat Sep 9 08:42:55 2023 +0900 [ATL][ATL_APITEST] CImage testcase should cover all formats (#5653) Strengthen CImage testcase and improve CImage class. ROSTESTS-387, CORE-19008 --- modules/rostests/apitests/atl/CImage.cpp | 465 ++++++++++++++++++------------- sdk/lib/atl/atlimage.h | 44 ++- 2 files changed, 303 insertions(+), 206 deletions(-) diff --git a/modules/rostests/apitests/atl/CImage.cpp b/modules/rostests/apitests/atl/CImage.cpp index 3ee98304da8..32116d0a811 100644 --- a/modules/rostests/apitests/atl/CImage.cpp +++ b/modules/rostests/apitests/atl/CImage.cpp @@ -1,11 +1,12 @@ /* * PROJECT: ReactOS api tests * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory - * PURPOSE: Test for CImage + * PURPOSE: Test for CImage and CImageDC * PROGRAMMER: Katayama Hirofumi MZ (katayama.hirofumi...@gmail.com) */ #include <atlimage.h> +#include <strsafe.h> #include "resource.h" #ifdef HAVE_APITEST @@ -14,250 +15,313 @@ #include "atltest.h" #endif -const TCHAR* szFiles[] = { - TEXT("ant.png"), - TEXT("ant.tif"), - TEXT("ant.gif"), - TEXT("ant.jpg"), - TEXT("ant.bmp"), -}; - -static TCHAR szTempPath[MAX_PATH]; -TCHAR* file_name(const TCHAR* file) +struct BITMAPINFOEX : BITMAPINFO { - static TCHAR buffer[MAX_PATH]; - lstrcpy(buffer, szTempPath); - lstrcat(buffer, TEXT("\\")); - lstrcat(buffer, file); - return buffer; -} + RGBQUAD bmiColorsExtra[256 - 1]; +}; -static void write_bitmap(HINSTANCE hInst, int id, TCHAR* file) +static void +Test_PixelAddress(INT iLine, const CImage &image1, const BITMAP &bm, INT x, INT y, BOOL bTopDown) { - HRSRC rsrc; + LPBYTE pb = (LPBYTE)bm.bmBits; - rsrc = FindResource(hInst, MAKEINTRESOURCE(id), RT_BITMAP); - ok(rsrc != NULL, "Expected to find an image resource\n"); - if (rsrc) - { - void *rsrc_data; - HANDLE hfile; - BOOL ret; - HGLOBAL glob = LoadResource(hInst, rsrc); - DWORD rsrc_size = SizeofResource(hInst, rsrc); + if (bTopDown) + pb += bm.bmWidthBytes * y; + else + pb += bm.bmWidthBytes * (bm.bmHeight - y - 1); - rsrc_data = LockResource(glob); + pb += (x * bm.bmBitsPixel) / 8; - hfile = CreateFile(file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - ok(hfile != INVALID_HANDLE_VALUE, "Unable to open temp file: %lu\n", GetLastError()); - if (hfile != INVALID_HANDLE_VALUE) - { - BITMAPFILEHEADER bfh = { 0 }; - DWORD dwWritten; - - bfh.bfType = 'MB'; - bfh.bfSize = rsrc_size + sizeof(BITMAPFILEHEADER); - bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - bfh.bfReserved1 = bfh.bfReserved2 = 0; - ret = WriteFile(hfile, &bfh, sizeof(bfh), &dwWritten, NULL); - ok(ret, "Unable to write temp file: %lu\n", GetLastError()); - ret = WriteFile(hfile, rsrc_data, rsrc_size, &dwWritten, NULL); - ok(ret, "Unable to write temp file: %lu\n", GetLastError()); - CloseHandle(hfile); - } - UnlockResource(rsrc_data); - } + LPCVOID addr = image1.GetPixelAddress(x, y); + ok(pb == addr, "Line %d: (%d, %d): %p vs %p\n", iLine, x, y, pb, addr); } -typedef Gdiplus::GpStatus (WINAPI *STARTUP)(ULONG_PTR *, const Gdiplus::GdiplusStartupInput *, Gdiplus::GdiplusStartupOutput *); -typedef void (WINAPI *SHUTDOWN)(ULONG_PTR); -typedef Gdiplus::GpStatus (WINGDIPAPI *CREATEBITMAPFROMFILE)(GDIPCONST WCHAR*, Gdiplus::GpBitmap **); -typedef Gdiplus::GpStatus (WINGDIPAPI *GETPIXELFORMAT)(Gdiplus::GpImage *image, Gdiplus::PixelFormat *format); -typedef Gdiplus::GpStatus (WINGDIPAPI *DISPOSEIMAGE)(Gdiplus::GpImage *); +static void +Test_BitmapEntry(INT iLine, INT bpp, INT width, INT height, BOOL bTopDown) +{ + HBITMAP hBitmap = ::CreateBitmap(width, height, bpp, 1, NULL); + ok(hBitmap != NULL, "Line %d: hBitmap was NULL\n", iLine); -static HINSTANCE hinstGdiPlus; -static ULONG_PTR gdiplusToken; + CImage image1; -static STARTUP Startup; -static SHUTDOWN Shutdown; -static CREATEBITMAPFROMFILE CreateBitmapFromFile; -static GETPIXELFORMAT GetImagePixelFormat; -static DISPOSEIMAGE DisposeImage; + ok(image1.IsNull(), "Line %d: IsNull() was TRUE\n", iLine); + image1.Attach(hBitmap, (bTopDown ? CImage::DIBOR_TOPDOWN : CImage::DIBOR_BOTTOMUP)); -template <typename TYPE> -TYPE AddrOf(const char *name) -{ - FARPROC proc = ::GetProcAddress(hinstGdiPlus, name); - return reinterpret_cast<TYPE>(proc); + ok(!image1.IsNull(), "Line %d: IsNull() was FALSE\n", iLine); + ok(!image1.IsDIBSection(), "Line %d: IsDIBSection() was TRUE\n", iLine); + + ok(image1.GetWidth() == width, "Line %d: %d vs %d\n", iLine, image1.GetWidth(), width); + ok(image1.GetHeight() == height, "Line %d: %d vs %d\n", iLine, image1.GetHeight(), height); + ok(image1.GetBPP() == bpp, "Line %d: %d vs %d\n", iLine, image1.GetBPP(), 1); } -static void init_gdip() +static void Test_Bitmap(void) { - hinstGdiPlus = ::LoadLibraryA("gdiplus.dll"); - Startup = AddrOf<STARTUP>("GdiplusStartup"); - Shutdown = AddrOf<SHUTDOWN>("GdiplusShutdown"); - CreateBitmapFromFile = AddrOf<CREATEBITMAPFROMFILE>("GdipCreateBitmapFromFile"); - GetImagePixelFormat = AddrOf<GETPIXELFORMAT>("GdipGetImagePixelFormat"); - DisposeImage = AddrOf<DISPOSEIMAGE>("GdipDisposeImage"); + Test_BitmapEntry(__LINE__, 1, 20, 30, FALSE); + Test_BitmapEntry(__LINE__, 1, 30, 20, TRUE); + Test_BitmapEntry(__LINE__, 4, 20, 30, FALSE); + Test_BitmapEntry(__LINE__, 4, 30, 20, TRUE); + Test_BitmapEntry(__LINE__, 8, 20, 30, FALSE); + Test_BitmapEntry(__LINE__, 8, 30, 20, TRUE); + Test_BitmapEntry(__LINE__, 24, 20, 30, FALSE); + Test_BitmapEntry(__LINE__, 24, 30, 20, TRUE); + Test_BitmapEntry(__LINE__, 32, 20, 30, FALSE); + Test_BitmapEntry(__LINE__, 32, 30, 20, TRUE); } -static void determine_file_bpp(TCHAR* tfile, Gdiplus::PixelFormat expect_pf) +static void Test_CompatBitmapEntry(INT iLine, HDC hdc, INT width, INT height) { - using namespace Gdiplus; - GpBitmap *pBitmap = NULL; - -#ifdef UNICODE - WCHAR* file = tfile; -#else - WCHAR file[MAX_PATH]; - ::MultiByteToWideChar(CP_ACP, 0, tfile, -1, file, MAX_PATH); -#endif + HBITMAP hBitmap = ::CreateCompatibleBitmap(hdc, width, height); + ok(hBitmap != NULL, "Line %d: hBitmap was NULL\n", iLine); - if (Startup == NULL) - init_gdip(); + CImage image1; - Gdiplus::GdiplusStartupInput gdiplusStartupInput; - Startup(&gdiplusToken, &gdiplusStartupInput, NULL); + ok(image1.IsNull(), "Line %d: IsNull() was TRUE\n", iLine); + image1.Attach(hBitmap); + ok(!image1.IsNull(), "Line %d: IsNull() was FALSE\n", iLine); + ok(!image1.IsDIBSection(), "Line %d: IsDIBSection() was TRUE\n", iLine); - Gdiplus::GpStatus status = CreateBitmapFromFile(file, &pBitmap); - ok(status == Gdiplus::Ok, "Expected status to be %i, was: %i\n", (int)Gdiplus::Ok, (int)status); - ok(pBitmap != NULL, "Expected a valid bitmap\n"); - if (pBitmap) - { - PixelFormat pf; - GetImagePixelFormat(pBitmap, &pf); - ok(pf == expect_pf, "Expected PixelFormat to be 0x%x, was: 0x%x\n", (int)expect_pf, (int)pf); - - DisposeImage(pBitmap); - } - Shutdown(gdiplusToken); + ok(image1.GetWidth() == width, "Line %d: %d vs %d\n", iLine, image1.GetWidth(), width); + ok(image1.GetHeight() == height, "Line %d: %d vs %d\n", iLine, image1.GetHeight(), height); } -static void Test_LoadSaveImage(void) +static void Test_CompatBitmap(void) { - HRESULT hr; - TCHAR* file; - BOOL bOK; - int width, height, bpp; - size_t n; - CImage image1, image2; - COLORREF color; - HDC hDC; + HDC hdc = ::CreateCompatibleDC(NULL); - HINSTANCE hInst = GetModuleHandle(NULL); - GetTempPath(MAX_PATH, szTempPath); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); - image1.LoadFromResource(hInst, IDB_ANT); - ok(!image1.IsNull(), "Expected image1 is not null\n"); + ::DeleteDC(hdc); - width = image1.GetWidth(); - ok(width == 48, "Expected width to be 48, was: %d\n", width); - height = image1.GetHeight(); - ok(height == 48, "Expected height to be 48, was: %d\n", height); - bpp = image1.GetBPP(); - ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp); + hdc = ::GetDC(NULL); - image2.LoadFromResource(hInst, IDB_CROSS); - ok(!image2.IsNull(), "Expected image2 is not null\n"); - image2.SetTransparentColor(RGB(255, 255, 255)); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); + Test_CompatBitmapEntry(__LINE__, hdc, 20, 30); - width = image2.GetWidth(); - ok(width == 32, "Expected width to be 32, was: %d\n", width); - height = image2.GetHeight(); - ok(height == 32, "Expected height to be 32, was: %d\n", height); - bpp = image2.GetBPP(); - ok(bpp == 8, "Expected bpp to be 8, was: %d\n", bpp); + ::ReleaseDC(NULL, hdc); +} - color = image1.GetPixel(5, 5); - ok(color == RGB(166, 202, 240), "Expected color to be 166, 202, 240; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color)); +static void +Test_DIBSectionEntry(INT iLine, HDC hdc, INT bpp, INT width, INT height, BOOL bTopDown) +{ + // Initialize BITMAPINFOEX + BITMAPINFOEX bmi; + ZeroMemory(&bmi, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = (bTopDown ? -height : height); + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = bpp; + switch (bpp) + { + case 1: + bmi.bmiHeader.biClrUsed = 2; + bmi.bmiColorsExtra[0].rgbBlue = 0xFF; + bmi.bmiColorsExtra[0].rgbGreen = 0xFF; + bmi.bmiColorsExtra[0].rgbRed = 0xFF; + break; + case 4: + case 8: + bmi.bmiHeader.biClrUsed = 3; + bmi.bmiColorsExtra[0].rgbBlue = 0xFF; + bmi.bmiColorsExtra[0].rgbGreen = 0xFF; + bmi.bmiColorsExtra[0].rgbRed = 0xFF; + bmi.bmiColorsExtra[1].rgbBlue = 0; + bmi.bmiColorsExtra[1].rgbGreen = 0; + bmi.bmiColorsExtra[1].rgbRed = 0xFF; + break; + default: + break; + } - hDC = image1.GetDC(); - bOK = image2.Draw(hDC, 0, 0); - image1.ReleaseDC(); - ok(bOK != FALSE, "Expected bDraw to be TRUE, was: %d\n", bOK); - image2.Destroy(); + // Create a DIB bitmap + HBITMAP hBitmap = ::CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); + ok(hBitmap != NULL, "Line %d: hBitmap was NULL\n", iLine); - color = image1.GetPixel(5, 5); - ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i\n", GetRValue(color), GetGValue(color), GetBValue(color)); + BITMAP bm; + ::GetObject(hBitmap, sizeof(bm), &bm); + INT pitch = (bTopDown ? bm.bmWidthBytes : -bm.bmWidthBytes); - file = file_name(TEXT("ant.bmp")); - write_bitmap(hInst, IDB_ANT, file); + CImage image1; - init_gdip(); + ok(image1.IsNull(), "Line %d: IsNull() was FALSE\n", iLine); + + image1.Attach(hBitmap, (bTopDown ? CImage::DIBOR_TOPDOWN : CImage::DIBOR_BOTTOMUP)); + + ok(!image1.IsNull(), "Line %d: IsNull() was FALSE\n", iLine); + ok(image1.IsDIBSection(), "Line %d: IsDIBSection() was FALSE\n", iLine); + if (bpp == 4 || bpp == 8) + { + ok(image1.GetTransparentColor() == 0xFFFFFFFF, "Line %d: 0x%08lX\n", iLine, + image1.GetTransparentColor()); + } + + switch (bpp) + { + case 1: + ok(image1.GetMaxColorTableEntries() == 2, + "Line %d: %d\n", iLine, image1.GetMaxColorTableEntries()); + break; + case 4: + ok(image1.GetMaxColorTableEntries() == 16, + "Line %d: %d\n", iLine, image1.GetMaxColorTableEntries()); + break; + case 8: + ok(image1.GetMaxColorTableEntries() == 256, + "Line %d: %d\n", iLine, image1.GetMaxColorTableEntries()); + break; + case 24: + case 32: + ok(image1.GetMaxColorTableEntries() == 0, + "Line %d: %d\n", iLine, image1.GetMaxColorTableEntries()); + break; + } - determine_file_bpp(file, PixelFormat8bppIndexed); + ok(image1.GetWidth() == width, "Line %d: %d vs %d\n", iLine, image1.GetWidth(), width); + ok(image1.GetHeight() == height, "Line %d: %d vs %d\n", iLine, image1.GetHeight(), height); + ok(image1.GetBPP() == bpp, "Line %d: %d vs %d\n", iLine, image1.GetBPP(), bpp); + ok(image1.GetPitch() == pitch, "Line %d: %d vs %d\n", iLine, image1.GetPitch(), pitch); - hr = image2.Load(file); - ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx\n", hr); - ok(!image2.IsNull(), "Expected image1 is not null\n"); - bOK = DeleteFile(file); - ok(bOK, "Expected bOK to be TRUE, was: %d\n", bOK); + LPBYTE pbBits = (LPBYTE)bm.bmBits; + if (!bTopDown) + pbBits += bm.bmWidthBytes * (height - 1); + ok(image1.GetBits() == pbBits, "Line %d: %p vs %p\n", iLine, image1.GetBits(), pbBits); - width = image2.GetWidth(); - ok_int(width, 48); - height = image2.GetHeight(); - ok_int(height, 48); - bpp = image2.GetBPP(); - ok(bpp == 32 || bpp == 8, "bpp was %d\n", bpp); + // Test Color Table + if (bpp <= 8) + { + DWORD Colors[3]; + C_ASSERT(sizeof(DWORD) == sizeof(RGBQUAD)); + FillMemory(Colors, sizeof(Colors), 0xCC); + image1.GetColorTable(0, _countof(Colors), (RGBQUAD *)Colors); + ok(Colors[0] == 0, "Line %d: 0x%08lX\n", iLine, Colors[0]); + ok(Colors[1] == 0xFFFFFF, "Line %d: 0x%08lX\n", iLine, Colors[1]); + if (bpp >= 4) + ok(Colors[2] == 0xFF0000, "Line %d: 0x%08lX\n", iLine, Colors[2]); + } - for (n = 0; n < _countof(szFiles); ++n) + // Test SetPixel/GetPixel + COLORREF color; + image1.SetPixel(0, 0, RGB(255, 255, 255)); + color = image1.GetPixel(0, 0); + ok(color == RGB(255, 255, 255), "Line %d: color was 0x%08lX\n", iLine, color); + image1.SetPixel(0, 0, RGB(0, 0, 0)); + color = image1.GetPixel(0, 0); + ok(color == RGB(0, 0, 0), "Line %d: color was 0x%08lX\n", iLine, color); + + // Test GetDC/ReleaseDC { - file = file_name(szFiles[n]); - image2.Destroy(); - - if (n == 0) - hr = image1.Save(file, Gdiplus::ImageFormatPNG); - else - hr = image1.Save(file); - ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n); - - bOK = (GetFileAttributes(file) != 0xFFFFFFFF); - ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n); - - hr = image2.Load(file); - ok(hr == S_OK, "Expected hr to be S_OK, was: %08lx (for %i)\n", hr, n); - - width = image2.GetWidth(); - ok(width == 48, "Expected width to be 48, was: %d (for %i)\n", width, n); - height = image2.GetHeight(); - ok(height == 48, "Expected height to be 48, was: %d (for %i)\n", height, n); - bpp = image2.GetBPP(); - if (n == 3) + HDC hdc1 = image1.GetDC(); + ok(hdc1 != NULL, "Line %d: hdc1 was NULL\n", iLine); + ::SetPixelV(hdc1, 2, 2, RGB(255, 255, 255)); { - ok(bpp == 24 || bpp == 32, "Expected bpp to be 24 or 32, was: %d (for %i)\n", bpp, n); - determine_file_bpp(file, PixelFormat24bppRGB); - } - else - { - determine_file_bpp(file, PixelFormat8bppIndexed); + HDC hdc2 = image1.GetDC(); + ok(hdc2 != NULL, "Line %d: hdc2 was NULL\n", iLine); + color = ::GetPixel(hdc2, 2, 2); + ok(color == RGB(255, 255, 255), "Line %d: color was 0x%08lX\n", iLine, color); + image1.ReleaseDC(); } - color = image1.GetPixel(5, 5); - ok(color == RGB(255, 0,0), "Expected color to be 255, 0, 0; was: %i, %i, %i (for %i)\n", GetRValue(color), GetGValue(color), GetBValue(color), n); + image1.ReleaseDC(); + } + // Test CImageDC + { + CImageDC hdc1(image1); + ok(hdc1 != NULL, "Line %d: hdc1 was NULL\n", iLine); + ::SetPixelV(hdc1, 1, 0, RGB(255, 255, 255)); { - CImageDC dc1(image1); - ::SetPixel(dc1, 5, 5, RGB(0, 255, 0)); - { - CImageDC dc2(image1); - ::SetPixel(dc2, 5, 5, RGB(0, 0, 255)); - } + CImageDC hdc2(image1); + ok(hdc2 != NULL, "Line %d: hdc2 was NULL\n", iLine); + color = ::GetPixel(hdc2, 1, 0); + ok(color == RGB(255, 255, 255), "Line %d: color was 0x%08lX\n", iLine, color); } + } - { - HDC hdcImage = image1.GetDC(); - color = ::GetPixel(hdcImage, 5, 5); - ok_long(color, RGB(0, 0, 255)); - - ::SetPixel(hdcImage, 5, 5, RGB(255, 0, 0)); - color = ::GetPixel(hdcImage, 5, 5); - ok_long(color, RGB(255, 0, 0)); - image1.ReleaseDC(); - } + HRESULT hr; + TCHAR szFileName[MAX_PATH]; + LPCTSTR dotexts[] = + { + TEXT(".bmp"), TEXT(".jpg"), TEXT(".png"), TEXT(".gif"), TEXT(".tif") + }; - bOK = DeleteFile(file); - ok(bOK, "Expected bOK to be TRUE, was: %d (for %i)\n", bOK, n); + // Test Save/Load + for (UINT iDotExt = 0; iDotExt < _countof(dotexts); ++iDotExt) + { + ::ExpandEnvironmentStrings(TEXT("%TEMP%\\CImage"), szFileName, _countof(szFileName)); + StringCchCat(szFileName, _countof(szFileName), dotexts[iDotExt]); + hr = image1.Save(szFileName); + ok(hr == S_OK, "Line %d: %d: hr was 0x%08lX\n", iLine, iDotExt, hr); + + CImage image2; + hr = image2.Load(szFileName); + ok(hr == S_OK, "Line %d: %d: hr was 0x%08lX\n", iLine, iDotExt, hr); + ::DeleteFile(szFileName); + + CImageDC hdc2(image2); + ok(hdc2 != NULL, "Line %d: %d: hdc2 was NULL\n", iLine, iDotExt); + color = ::GetPixel(hdc2, 0, 0); + ok(color == RGB(0, 0, 0), "Line %d: %d: color was 0x%08lX\n", iLine, iDotExt, color); + color = ::GetPixel(hdc2, 1, 0); + ok(color == RGB(255, 255, 255), "Line %d: %d: color was 0x%08lX\n", iLine, iDotExt, color); } + + // Test GetPixelAddress + Test_PixelAddress(iLine, image1, bm, 0, 0, bTopDown); + Test_PixelAddress(iLine, image1, bm, 10, 0, bTopDown); + Test_PixelAddress(iLine, image1, bm, 0, 10, bTopDown); + Test_PixelAddress(iLine, image1, bm, 4, 6, bTopDown); + Test_PixelAddress(iLine, image1, bm, 6, 2, bTopDown); +} + +static void Test_DIBSection(void) +{ + HDC hdc = ::CreateCompatibleDC(NULL); + + Test_DIBSectionEntry(__LINE__, hdc, 1, 30, 20, FALSE); + Test_DIBSectionEntry(__LINE__, hdc, 1, 20, 30, TRUE); + Test_DIBSectionEntry(__LINE__, hdc, 4, 30, 20, FALSE); + Test_DIBSectionEntry(__LINE__, hdc, 4, 20, 30, TRUE); + Test_DIBSectionEntry(__LINE__, hdc, 8, 30, 20, FALSE); + Test_DIBSectionEntry(__LINE__, hdc, 8, 20, 30, TRUE); + Test_DIBSectionEntry(__LINE__, hdc, 24, 30, 20, FALSE); + Test_DIBSectionEntry(__LINE__, hdc, 24, 20, 30, TRUE); + Test_DIBSectionEntry(__LINE__, hdc, 32, 30, 20, FALSE); + Test_DIBSectionEntry(__LINE__, hdc, 32, 20, 30, TRUE); + + ::DeleteDC(hdc); +} + +static void Test_ResBitmap(void) +{ + HINSTANCE hInst = GetModuleHandle(NULL); + + CImage image1; + ok_int(image1.IsNull(), TRUE); + image1.LoadFromResource(hInst, IDB_ANT); + ok_int(image1.IsNull(), FALSE); + + ok_int(image1.GetWidth(), 48); + ok_int(image1.GetHeight(), 48); + ok_int(image1.GetBPP(), 8); + ok_int(image1.GetPitch(), -48); + + CImage image2; + ok_int(image2.IsNull(), TRUE); + image2.LoadFromResource(hInst, IDB_CROSS); + ok_int(image2.IsNull(), FALSE); + + ok_int(image2.GetWidth(), 32); + ok_int(image2.GetHeight(), 32); + ok_int(image2.GetBPP(), 8); + ok_int(image2.GetPitch(), -32); } static INT FindGUID(REFGUID rguid, const CSimpleArray<GUID>& guids) @@ -428,7 +492,10 @@ static void Test_Exporter(void) START_TEST(CImage) { - Test_LoadSaveImage(); + Test_Bitmap(); + Test_CompatBitmap(); + Test_DIBSection(); + Test_ResBitmap(); Test_Importer(); Test_Exporter(); } diff --git a/sdk/lib/atl/atlimage.h b/sdk/lib/atl/atlimage.h index a8546b085c0..84bfe64fc76 100644 --- a/sdk/lib/atl/atlimage.h +++ b/sdk/lib/atl/atlimage.h @@ -33,8 +33,8 @@ public: enum DIBOrientation { DIBOR_DEFAULT, // default - DIBOR_BOTTOMUP, // bottom-up DIB - DIBOR_TOPDOWN // top-down DIB + DIBOR_TOPDOWN, // top-down DIB + DIBOR_BOTTOMUP // bottom-up DIB }; CImage() noexcept @@ -283,6 +283,17 @@ public: return pb; } + const void *GetBits() const noexcept + { + ATLASSERT(IsDIBSection()); + const BYTE *pb = (const BYTE *)m_bm.bmBits; + if (m_eOrientation == DIBOR_BOTTOMUP) + { + pb += m_bm.bmWidthBytes * (m_bm.bmHeight - 1); + } + return pb; + } + int GetBPP() const noexcept { ATLASSERT(m_hBitmap); @@ -350,6 +361,15 @@ public: return pb; } + const void* GetPixelAddress(int x, int y) const noexcept + { + ATLASSERT(IsDIBSection()); + const BYTE *pb = (const BYTE *)GetBits(); + pb += GetPitch() * y; + pb += (GetBPP() * x) / 8; + return pb; + } + COLORREF GetTransparentColor() const noexcept { return m_clrTransparentColor; @@ -1020,6 +1040,8 @@ private: } private: + // FIXME: MS ATL CImage has m_nWidth, m_nHeight, m_nPitch, m_nBPP, and m_pBits. + // FIXME: MS ATL CImage hasn't m_eOrientation, m_bm, and m_ds. HBITMAP m_hBitmap; mutable HBITMAP m_hOldBitmap; mutable HDC m_hDC; @@ -1142,14 +1164,22 @@ private: m_bIsDIBSection = (::GetObject(hBitmap, size, &m_ds) == size); bool bOK = (::GetObject(hBitmap, sizeof(BITMAP), &m_bm) != 0); + if (!bOK) + return; + + m_hBitmap = hBitmap; - if (bOK) + if (m_bIsDIBSection && eOrientation == DIBOR_DEFAULT) { - m_hBitmap = hBitmap; - m_eOrientation = eOrientation; - m_bHasAlphaChannel = (m_bm.bmBitsPixel == 32); - m_clrTransparentColor = CLR_INVALID; + if (m_ds.dsBmih.biHeight < 0) + eOrientation = DIBOR_TOPDOWN; + else + eOrientation = DIBOR_BOTTOMUP; } + m_eOrientation = eOrientation; + + m_bHasAlphaChannel = (m_bm.bmBitsPixel == 32); + m_clrTransparentColor = CLR_INVALID; } BOOL CreateInternal(int nWidth, int nHeight, int nBPP,