-- v2: gdiplus: fix destination area in GdipDrawImagePointsRect function gdiplus: implement PixelOffsetMode Half and HighQuality for GdipDrawImagePointsRect
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphics.c | 15 +++++++++++++-- dlls/gdiplus/tests/image.c | 26 +++++++++++++++++--------- 2 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 65b33cdc960..bbbf598f0e1 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -3217,6 +3217,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image GpMatrix dst_to_src; REAL m11, m12, m21, m22, mdx, mdy; REAL x_dx, x_dy, y_dx, y_dy; + REAL dst_pixel_offset; ARGB *dst_color; GpPointF src_pointf_row, src_pointf;
@@ -3247,12 +3248,22 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image } dst_color = (ARGB*)(dst_data);
+ if ((offset_mode == PixelOffsetModeHalf) || + (offset_mode == PixelOffsetModeHighQuality)) + { + // We are checking color in the middle of destination pixel, + // that's why we are adding 0.5 to destination area. + dst_pixel_offset = 0.5; + } + else + dst_pixel_offset = 0.0; + /* Calculate top left point of transformed image. It would be used as reference point for adding */ src_pointf_row.X = dst_to_src.matrix[4] + - dst_area.left * x_dx + dst_area.top * y_dx; + (dst_area.left + dst_pixel_offset) * x_dx + (dst_area.top + dst_pixel_offset) * y_dx; src_pointf_row.Y = dst_to_src.matrix[5] + - dst_area.left * x_dy + dst_area.top * y_dy; + (dst_area.left + dst_pixel_offset) * x_dy + (dst_area.top + dst_pixel_offset) * y_dy;
for (y = dst_area.top; y < dst_area.bottom; y++, src_pointf_row.X += y_dx, src_pointf_row.Y += y_dy) diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 18fe8fcba37..b9b3466ea4f 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -4618,8 +4618,10 @@ static void test_DrawImage(void) match = memcmp(white_2x2, black_2x2, sizeof(black_2x2)) == 0; ok(match, "data should match\n"); if (!match) - trace("%s\n", dbgstr_hexdata(white_2x2, sizeof(white_2x2))); - + { + trace("Expected: %s\n", dbgstr_hexdata(black_2x2, sizeof(black_2x2))); + trace("Got: %s\n", dbgstr_hexdata(white_2x2, sizeof(white_2x2))); + } status = GdipDeleteGraphics(graphics); expect(Ok, status); status = GdipDisposeImage(u1.image); @@ -4708,7 +4710,10 @@ static void test_GdipDrawImagePointRect(void) match = memcmp(white_2x2, black_2x2, sizeof(black_2x2)) == 0; ok(match, "data should match\n"); if (!match) - trace("%s\n", dbgstr_hexdata(white_2x2, sizeof(white_2x2))); + { + trace("Expected: %s\n", dbgstr_hexdata(black_2x2, sizeof(black_2x2))); + trace("Got: %s\n", dbgstr_hexdata(white_2x2, sizeof(white_2x2))); + }
status = GdipDeleteGraphics(graphics); expect(Ok, status); @@ -4825,6 +4830,8 @@ static void test_DrawImage_scale(void) 0xcc,0xcc,0xcc, 0xcc,0xcc,0xcc, 0x40,0x40,0x40, 0x40,0x40,0x40 }; static const BYTE image_250_half[24] = { 0x40,0x40,0x40, 0x40,0x40,0x40, 0x80,0x80,0x80, 0x80,0x80,0x80, 0x80,0x80,0x80, 0xcc,0xcc,0xcc, 0xcc,0xcc,0xcc, 0x40,0x40,0x40 }; + static const BYTE image_251_half[24] = { 0x40,0x40,0x40, 0x40,0x40,0x40, 0x40,0x40,0x40, 0x80,0x80,0x80, + 0x80,0x80,0x80, 0xcc,0xcc,0xcc, 0xcc,0xcc,0xcc, 0xcc,0xcc,0xcc }; static const struct test_data { REAL scale_x; @@ -4851,19 +4858,20 @@ static void test_DrawImage_scale(void)
{ 0.8, PixelOffsetModeHalf, image_080 }, /* 14 */ { 1.0, PixelOffsetModeHalf, image_100 }, - { 1.2, PixelOffsetModeHalf, image_120_half, TRUE }, + { 1.2, PixelOffsetModeHalf, image_120_half }, { 1.5, PixelOffsetModeHalf, image_150_half, TRUE }, - { 1.8, PixelOffsetModeHalf, image_180_half, TRUE }, - { 2.0, PixelOffsetModeHalf, image_200_half, TRUE }, + { 1.8, PixelOffsetModeHalf, image_180_half }, + { 2.0, PixelOffsetModeHalf, image_200_half }, { 2.5, PixelOffsetModeHalf, image_250_half, TRUE },
{ 0.8, PixelOffsetModeHighQuality, image_080 }, /* 21 */ { 1.0, PixelOffsetModeHighQuality, image_100 }, - { 1.2, PixelOffsetModeHighQuality, image_120_half, TRUE }, + { 1.2, PixelOffsetModeHighQuality, image_120_half }, { 1.5, PixelOffsetModeHighQuality, image_150_half, TRUE }, - { 1.8, PixelOffsetModeHighQuality, image_180_half, TRUE }, - { 2.0, PixelOffsetModeHighQuality, image_200_half, TRUE }, + { 1.8, PixelOffsetModeHighQuality, image_180_half }, + { 2.0, PixelOffsetModeHighQuality, image_200_half }, { 2.5, PixelOffsetModeHighQuality, image_250_half, TRUE }, + { 2.51, PixelOffsetModeHighQuality, image_251_half }, }; BYTE src_2x1[6] = { 0x80,0x80,0x80, 0xcc,0xcc,0xcc }; BYTE dst_8x1[24];
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphics.c | 28 +++++++++++++++++++++++----- dlls/gdiplus/tests/image.c | 12 +++++------- 2 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index bbbf598f0e1..94fc4d640d2 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -324,6 +324,23 @@ static void restore_dc(GpGraphics *graphics, INT state) RestoreDC(graphics->hdc, state); }
+static void round_half_down_points(POINT *pti, GpPointF *ptf, INT count) +{ + int i; + + for(i = 0; i < count; i++){ + if(isnan(ptf[i].X)) + pti[i].x = 0; + else + pti[i].x = ceilf(ptf[i].X - 0.5); + + if(isnan(ptf[i].Y)) + pti[i].y = 0; + else + pti[i].y = ceilf(ptf[i].Y - 0.5); + } +} + static void round_points(POINT *pti, GpPointF *ptf, INT count) { int i; @@ -3042,7 +3059,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image DrawImageAbort callback, VOID * callbackData) { GpPointF ptf[4]; - POINT pti[4]; GpStatus stat;
TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points, @@ -3095,10 +3111,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image if (!srcwidth || !srcheight || (ptf[3].X == ptf[0].X && ptf[3].Y == ptf[0].Y)) return Ok; gdip_transform_points(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceWorld, ptf, 4); - round_points(pti, ptf, 4); - - TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]), - wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
srcx = units_to_pixels(srcx, srcUnit, image->xres, graphics->printer_display); srcy = units_to_pixels(srcy, srcUnit, image->yres, graphics->printer_display); @@ -3111,6 +3123,12 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image GpBitmap* bitmap = (GpBitmap*)image; BOOL do_resampling = FALSE; BOOL use_software = FALSE; + POINT pti[4]; + + round_half_down_points(pti, ptf, 4); + + TRACE("%s %s %s %s\n", wine_dbgstr_point(&pti[0]), wine_dbgstr_point(&pti[1]), + wine_dbgstr_point(&pti[2]), wine_dbgstr_point(&pti[3]));
TRACE("graphics: %.2fx%.2f dpi, fmt %#x, scale %f, image: %.2fx%.2f dpi, fmt %#x, color %08lx\n", graphics->xres, graphics->yres, diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index b9b3466ea4f..84beee49cd2 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -4837,7 +4837,6 @@ static void test_DrawImage_scale(void) REAL scale_x; PixelOffsetMode pixel_offset_mode; const BYTE *image; - BOOL todo; } td[] = { { 0.8, PixelOffsetModeNone, image_080 }, /* 0 */ @@ -4859,18 +4858,18 @@ static void test_DrawImage_scale(void) { 0.8, PixelOffsetModeHalf, image_080 }, /* 14 */ { 1.0, PixelOffsetModeHalf, image_100 }, { 1.2, PixelOffsetModeHalf, image_120_half }, - { 1.5, PixelOffsetModeHalf, image_150_half, TRUE }, + { 1.5, PixelOffsetModeHalf, image_150_half }, { 1.8, PixelOffsetModeHalf, image_180_half }, { 2.0, PixelOffsetModeHalf, image_200_half }, - { 2.5, PixelOffsetModeHalf, image_250_half, TRUE }, + { 2.5, PixelOffsetModeHalf, image_250_half },
{ 0.8, PixelOffsetModeHighQuality, image_080 }, /* 21 */ { 1.0, PixelOffsetModeHighQuality, image_100 }, { 1.2, PixelOffsetModeHighQuality, image_120_half }, - { 1.5, PixelOffsetModeHighQuality, image_150_half, TRUE }, + { 1.5, PixelOffsetModeHighQuality, image_150_half }, { 1.8, PixelOffsetModeHighQuality, image_180_half }, { 2.0, PixelOffsetModeHighQuality, image_200_half }, - { 2.5, PixelOffsetModeHighQuality, image_250_half, TRUE }, + { 2.5, PixelOffsetModeHighQuality, image_250_half }, { 2.51, PixelOffsetModeHighQuality, image_251_half }, }; BYTE src_2x1[6] = { 0x80,0x80,0x80, 0xcc,0xcc,0xcc }; @@ -4915,8 +4914,7 @@ static void test_DrawImage_scale(void) expect(Ok, status);
match = memcmp(dst_8x1, td[i].image, sizeof(dst_8x1)) == 0; - todo_wine_if (!match && td[i].todo) - ok(match, "%d: data should match\n", i); + ok(match, "%d: data should match\n", i); if (!match) { trace("Expected: %s\n", dbgstr_hexdata(td[i].image, sizeof(dst_8x1)));
Bartosz Kosiorek (@gang65) commented about dlls/gdiplus/graphics.c:
GpBitmap* bitmap = (GpBitmap*)image; BOOL do_resampling = FALSE; BOOL use_software = FALSE;
POINT pti[4];
round_half_down_points(pti, ptf, 4);
The destination area is calculated using Round Half Down.