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,

Reply via email to