[v3 PATCH 2/2] gdiplus: Implement GdipBitmapGetHistogram()

Nikolay Sivov nsivov at codeweavers.com
Wed Nov 2 13:24:21 CDT 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

Resending without 1/2, hopefully it's okay.

v3: corrected blue channel coefficient when converting to gray

 dlls/gdiplus/gdiplus.spec  |   2 +-
 dlls/gdiplus/image.c       | 123 +++++++++++++++++++++++++++++++++++++++++++++
 dlls/gdiplus/tests/image.c |  94 ++++++++++++++++++++++++++++++++--
 include/gdiplusflat.h      |   1 +
 4 files changed, 216 insertions(+), 4 deletions(-)

diff --git a/dlls/gdiplus/gdiplus.spec b/dlls/gdiplus/gdiplus.spec
index 92251a7..40c19e6 100644
--- a/dlls/gdiplus/gdiplus.spec
+++ b/dlls/gdiplus/gdiplus.spec
@@ -618,7 +618,7 @@
 618 stub GdipInitializePalette
 619 stdcall GdipBitmapCreateApplyEffect(ptr long ptr ptr ptr ptr long ptr ptr)
 620 stdcall GdipBitmapApplyEffect(ptr ptr ptr long ptr ptr)
-621 stub GdipBitmapGetHistogram
+621 stdcall GdipBitmapGetHistogram(ptr long long ptr ptr ptr ptr)
 622 stdcall GdipBitmapGetHistogramSize(long ptr)
 623 stdcall GdipBitmapConvertFormat(ptr long long long ptr float)
 624 stdcall GdipImageSetAbort(ptr ptr)
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 672b2e5..e4eba2b 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -5387,6 +5387,129 @@ GpStatus WINGDIPAPI GdipBitmapConvertFormat(GpBitmap *bitmap, PixelFormat format
     return NotImplemented;
 }
 
+static void set_histogram_point_argb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[ color >> 24        ]++;
+    ch1[(color >> 16) & 0xff]++;
+    ch2[(color >>  8) & 0xff]++;
+    ch3[ color        & 0xff]++;
+}
+
+static void set_histogram_point_pargb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    BYTE alpha = color >> 24;
+
+    ch0[alpha]++;
+    ch1[(((color >> 16) & 0xff) * alpha) / 0xff]++;
+    ch2[(((color >>  8) & 0xff) * alpha) / 0xff]++;
+    ch3[(( color        & 0xff) * alpha) / 0xff]++;
+}
+
+static void set_histogram_point_rgb(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[(color >> 16) & 0xff]++;
+    ch1[(color >>  8) & 0xff]++;
+    ch2[ color        & 0xff]++;
+}
+
+static void set_histogram_point_gray(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[(76 * ((color >> 16) & 0xff) + 150 * ((color >> 8) & 0xff) + 29 * (color & 0xff)) / 0xff]++;
+}
+
+static void set_histogram_point_b(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[color & 0xff]++;
+}
+
+static void set_histogram_point_g(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[(color >> 8) & 0xff]++;
+}
+
+static void set_histogram_point_r(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[(color >> 16) & 0xff]++;
+}
+
+static void set_histogram_point_a(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    ch0[(color >> 24) & 0xff]++;
+}
+
+/*****************************************************************************
+ * GdipBitmapGetHistogram [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipBitmapGetHistogram(GpBitmap *bitmap, HistogramFormat format, UINT num_of_entries,
+    UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3)
+{
+    static void (* const set_histogram_point[])(ARGB color, UINT *ch0, UINT *ch1, UINT *ch2, UINT *ch3) =
+    {
+        set_histogram_point_argb,
+        set_histogram_point_pargb,
+        set_histogram_point_rgb,
+        set_histogram_point_gray,
+        set_histogram_point_b,
+        set_histogram_point_g,
+        set_histogram_point_r,
+        set_histogram_point_a,
+    };
+    UINT width, height, x, y;
+
+    TRACE("(%p, %d, %u, %p, %p, %p, %p)\n", bitmap, format, num_of_entries,
+        ch0, ch1, ch2, ch3);
+
+    if (!bitmap || num_of_entries != 256)
+        return InvalidParameter;
+
+    /* Make sure passed channel pointers match requested format */
+    switch (format)
+    {
+    case HistogramFormatARGB:
+    case HistogramFormatPARGB:
+        if (!ch0 || !ch1 || !ch2 || !ch3)
+            return InvalidParameter;
+        memset(ch0, 0, num_of_entries * sizeof(UINT));
+        memset(ch1, 0, num_of_entries * sizeof(UINT));
+        memset(ch2, 0, num_of_entries * sizeof(UINT));
+        memset(ch3, 0, num_of_entries * sizeof(UINT));
+        break;
+    case HistogramFormatRGB:
+        if (!ch0 || !ch1 || !ch2 || ch3)
+            return InvalidParameter;
+        memset(ch0, 0, num_of_entries * sizeof(UINT));
+        memset(ch1, 0, num_of_entries * sizeof(UINT));
+        memset(ch2, 0, num_of_entries * sizeof(UINT));
+        break;
+    case HistogramFormatGray:
+    case HistogramFormatB:
+    case HistogramFormatG:
+    case HistogramFormatR:
+    case HistogramFormatA:
+        if (!ch0 || ch1 || ch2 || ch3)
+            return InvalidParameter;
+        memset(ch0, 0, num_of_entries * sizeof(UINT));
+        break;
+    default:
+        WARN("Invalid histogram format requested, %d\n", format);
+        return InvalidParameter;
+    }
+
+    GdipGetImageWidth(&bitmap->image, &width);
+    GdipGetImageHeight(&bitmap->image, &height);
+
+    for (y = 0; y < height; y++)
+        for (x = 0; x < width; x++)
+        {
+            ARGB color;
+
+            GdipBitmapGetPixel(bitmap, x, y, &color);
+            set_histogram_point[format](color, ch0, ch1, ch2, ch3);
+        }
+
+    return Ok;
+}
+
 /*****************************************************************************
  * GdipBitmapGetHistogramSize [GDIPLUS.@]
  */
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index baf5c3b..ad0cc6f 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -31,6 +31,7 @@
 #include "wine/test.h"
 
 static GpStatus (WINAPI *pGdipBitmapGetHistogramSize)(HistogramFormat,UINT*);
+static GpStatus (WINAPI *pGdipBitmapGetHistogram)(GpBitmap*,HistogramFormat,UINT,UINT*,UINT*,UINT*,UINT*);
 
 #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (UINT)(expected), (UINT)(got))
 #define expectf(expected, got) ok(fabs((expected) - (got)) < 0.0001, "Expected %f, got %f\n", (expected), (got))
@@ -4787,8 +4788,9 @@ static void test_getadjustedpalette(void)
     GdipDisposeImageAttributes(imageattributes);
 }
 
-static void test_histogramsize(void)
+static void test_histogram(void)
 {
+    UINT ch0[256], ch1[256], ch2[256], ch3[256];
     HistogramFormat test_formats[] =
     {
         HistogramFormatARGB,
@@ -4800,8 +4802,10 @@ static void test_histogramsize(void)
         HistogramFormatR,
         HistogramFormatA,
     };
+    const UINT WIDTH = 8, HEIGHT = 16;
+    UINT num, i, x;
     GpStatus stat;
-    UINT num, i;
+    GpBitmap *bm;
 
     if (!pGdipBitmapGetHistogramSize)
     {
@@ -4827,6 +4831,89 @@ static void test_histogramsize(void)
         expect(Ok, stat);
         expect(256, num);
     }
+
+    bm = NULL;
+    stat = GdipCreateBitmapFromScan0(WIDTH, HEIGHT, 0, PixelFormat24bppRGB, NULL, &bm);
+    expect(Ok, stat);
+
+    /* Three solid rgb rows, next three rows are rgb shades. */
+    for (x = 0; x < WIDTH; x++)
+    {
+        GdipBitmapSetPixel(bm, x, 0, 0xffff0000);
+        GdipBitmapSetPixel(bm, x, 1, 0xff00ff00);
+        GdipBitmapSetPixel(bm, x, 2, 0xff0000ff);
+
+        GdipBitmapSetPixel(bm, x, 3, 0xff010000);
+        GdipBitmapSetPixel(bm, x, 4, 0xff003f00);
+        GdipBitmapSetPixel(bm, x, 5, 0xff000020);
+    }
+
+    stat = pGdipBitmapGetHistogram(NULL, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, ch3);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, ch2, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, ch1, NULL, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, 123, 256, ch0, NULL, NULL, NULL);
+    expect(InvalidParameter, stat);
+
+    /* Requested format matches bitmap format */
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, ch3);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 100, ch0, ch1, ch2, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 257, ch0, ch1, ch2, NULL);
+    expect(InvalidParameter, stat);
+
+    /* Channel 3 is not used, must be NULL */
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatRGB, 256, ch0, ch1, ch2, NULL);
+    expect(Ok, stat);
+
+    ok(ch0[0xff] == WIDTH, "Got red (0xff) %u\n", ch0[0xff]);
+    ok(ch1[0xff] == WIDTH, "Got green (0xff) %u\n", ch1[0xff]);
+    ok(ch2[0xff] == WIDTH, "Got blue (0xff) %u\n", ch1[0xff]);
+    ok(ch0[0x01] == WIDTH, "Got red (0x01) %u\n", ch0[0x01]);
+    ok(ch1[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch1[0x3f]);
+    ok(ch2[0x20] == WIDTH, "Got blue (0x20) %u\n", ch1[0x20]);
+
+    /* ARGB histogram from RGB data. */
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatARGB, 256, ch0, ch1, ch2, ch3);
+    expect(Ok, stat);
+
+    ok(ch1[0xff] == WIDTH, "Got red (0xff) %u\n", ch1[0xff]);
+    ok(ch2[0xff] == WIDTH, "Got green (0xff) %u\n", ch2[0xff]);
+    ok(ch3[0xff] == WIDTH, "Got blue (0xff) %u\n", ch3[0xff]);
+    ok(ch1[0x01] == WIDTH, "Got red (0x01) %u\n", ch1[0x01]);
+    ok(ch2[0x3f] == WIDTH, "Got green (0x3f) %u\n", ch2[0x3f]);
+    ok(ch3[0x20] == WIDTH, "Got blue (0x20) %u\n", ch3[0x20]);
+
+    ok(ch0[0xff] == WIDTH * HEIGHT, "Got alpha (0xff) %u\n", ch0[0xff]);
+
+    /* Request grayscale histogram from RGB bitmap. */
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, ch3);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, ch2, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, ch1, NULL, NULL);
+    expect(InvalidParameter, stat);
+
+    stat = pGdipBitmapGetHistogram(bm, HistogramFormatGray, 256, ch0, NULL, NULL, NULL);
+    expect(Ok, stat);
+
+    GdipDisposeImage((GpImage*)bm);
 }
 
 START_TEST(image)
@@ -4843,6 +4930,7 @@ START_TEST(image)
     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
 
     pGdipBitmapGetHistogramSize = (void*)GetProcAddress(mod, "GdipBitmapGetHistogramSize");
+    pGdipBitmapGetHistogram = (void*)GetProcAddress(mod, "GdipBitmapGetHistogram");
 
     test_supported_encoders();
     test_CloneBitmapArea();
@@ -4890,7 +4978,7 @@ START_TEST(image)
     test_dispose();
     test_createeffect();
     test_getadjustedpalette();
-    test_histogramsize();
+    test_histogram();
 
     GdiplusShutdown(gdiplusToken);
 }
diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h
index 824b460..0c40223 100644
--- a/include/gdiplusflat.h
+++ b/include/gdiplusflat.h
@@ -41,6 +41,7 @@ GpStatus WINGDIPAPI GdipSetAdjustableArrowCapWidth(GpAdjustableArrowCap*,REAL);
 /* Bitmap */
 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap*,CGpEffect*,RECT*,BOOL,VOID**,INT*);
 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap**,INT,CGpEffect*,RECT*,RECT*,GpBitmap**,BOOL,VOID**,INT*);
+GpStatus WINGDIPAPI GdipBitmapGetHistogram(GpBitmap*,HistogramFormat,UINT,UINT*,UINT*,UINT*,UINT*);
 GpStatus WINGDIPAPI GdipBitmapGetHistogramSize(HistogramFormat,UINT*);
 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap*,INT,INT,ARGB*);
 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap*,GDIPCONST GpRect*,UINT,
-- 
2.10.1




More information about the wine-patches mailing list