[v2 PATCH 2/2] gdiplus: Implement GdipBitmapGetHistogram()
Nikolay Sivov
nsivov at codeweavers.com
Wed Nov 2 04:56:31 CDT 2016
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v2: removed debug leftovers from tests
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..2ede0f3 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) + 28 * (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