gdiplus: Implement GdipBitmapGetHistogram().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Vincent Povirk <vincent@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2016-11-02 21:24:21 +03:00 committed by Alexandre Julliard
parent 8de0275e48
commit 509ba80bcb
4 changed files with 216 additions and 4 deletions

View file

@ -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)

View file

@ -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.@]
*/

View file

@ -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);
}

View file

@ -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,