Commit 04b4d0f3 authored by Zhiyi Zhang's avatar Zhiyi Zhang Committed by Alexandre Julliard

gdi32: Partially implement HALFTONE stretch mode.

COLORONCOLOR(STRETCH_DELETESCANS) was used in place of HALFTONE. COLORONCOLOR mode may delete rows of pixels without trying to preserve information so it will cause Wine to render poorly when the destination rectangle is small. According to tests, HALFTONE mode uses box filter when doing integer downscaling and nearest neighbor interpolation when doing upscaling in both horizontally and vertically. In other cases, HALFTONE mode uses a lanczos3 like algorithm to interpolate pixels. There are also other heuristics involved. For example, shrinking a 2x2 image to 1x1 may not use box filter depending on image data. Since this algorithm is undocumented, it's difficult to reverse engineer the original algorithm and produce identical results. Instead, this patch uses a naive implementation of bilinear interpolation to implement HALFTONE mode and it produces good quality images. For 8-bit and lower color depth images, nulldrv_StretchBlt should resize the images first and then converts color depth. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46375Signed-off-by: 's avatarZhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 2191c0f4
......@@ -1216,6 +1216,12 @@ DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit
init_dib_info_from_bitmapinfo( &src_dib, src_info, src_bits );
init_dib_info_from_bitmapinfo( &dst_dib, dst_info, dst_bits );
if (mode == HALFTONE)
{
dst_dib.funcs->halftone( &dst_dib, dst, &src_dib, src );
goto done;
}
/* v */
ret = calc_1d_stretch_params( dst->y, dst->height, dst->visrect.top, dst->visrect.bottom,
src->y, src->height, src->visrect.top, src->visrect.bottom,
......@@ -1300,6 +1306,7 @@ DWORD stretch_bitmapinfo( const BITMAPINFO *src_info, void *src_bits, struct bit
}
}
done:
/* update coordinates, the destination rectangle is always stored at 0,0 */
*src = *dst;
src->x -= src->visrect.left;
......
......@@ -211,6 +211,8 @@ typedef struct primitive_funcs
void (* shrink_row)(const dib_info *dst_dib, const POINT *dst_start,
const dib_info *src_dib, const POINT *src_start,
const struct stretch_params *params, int mode, BOOL keep_dst);
void (* halftone)(const dib_info *dst_dib, const struct bitblt_coords *dst,
const dib_info *src_dib, const struct bitblt_coords *src);
} primitive_funcs;
extern const primitive_funcs funcs_8888 DECLSPEC_HIDDEN;
......
......@@ -2897,10 +2897,10 @@ static COLORREF get_color_from_bits(const unsigned char *bits, const BITMAPINFO
return RGB(color.rgbRed, color.rgbGreen, color.rgbBlue);
}
#define compare_bitmap_bits(a, b, c, d, e, f, g) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g)
#define compare_bitmap_bits(a, b, c, d, e, f, g, h) compare_bitmap_bits_(__LINE__, a, b, c, d, e, f, g, h)
static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BITMAPINFO *bmi,
size_t result_bits_size, const unsigned char *expected_bits, unsigned int test_index,
const unsigned char *expected_broken_bits)
BOOL allow_todo, const unsigned char *expected_broken_bits)
{
unsigned char *result_bits;
unsigned int row, column;
......@@ -2919,6 +2919,7 @@ static void compare_bitmap_bits_(unsigned int line, HDC hdc, HBITMAP bitmap, BIT
result = get_color_from_bits(result_bits, bmi, row, column);
expected = get_color_from_bits(expected_bits, bmi, row, column);
todo_wine_if(allow_todo && result != expected)
ok_(__FILE__, line)(result == expected || broken(expected_broken_bits
&& result == get_color_from_bits(expected_broken_bits, bmi, row, column)),
"Colors do not match, got 0x%06x, expected 0x%06x, test_index %u, row %u, column %u.\n",
......@@ -2999,21 +3000,22 @@ static void test_Image_StretchMode(void)
size_t test_bits_size, result_bits_size;
const RGBQUAD *bmi_colors;
size_t bmi_colors_size;
BOOL allow_todo;
const unsigned char *expected_broken_bits;
}
tests[] =
{
{4, 4, 2, 2, 24, test_bits_24, expected_bits_24,
sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0,
sizeof(test_bits_24), sizeof(expected_bits_24), NULL, 0, TRUE,
/* Broken on Windows before Win10 1607+ */ expected_broken_bits_24},
{4, 4, 2, 2, 1, test_bits_1, expected_bits_1,
sizeof(test_bits_1), sizeof(expected_bits_1), colors_bits_1,
sizeof(colors_bits_1)},
{4, 4, 2, 2, 8, test_bits_8, expected_bits_8,
sizeof(test_bits_8), sizeof(expected_bits_8), colors_bits_8,
sizeof(colors_bits_8)},
sizeof(colors_bits_8), TRUE},
{4, 4, 2, 2, 16, (const unsigned char *)test_bits_16, (const unsigned char *)expected_bits_16,
sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0},
sizeof(test_bits_16), sizeof(expected_bits_16), NULL, 0, TRUE},
};
static const char filename[] = "test.bmp";
BITMAPINFO *bmi, *bmi_output;
......@@ -3059,7 +3061,8 @@ static void test_Image_StretchMode(void)
ok(!!bitmap_copy, "CopyImage() failed, result %u.\n", GetLastError());
compare_bitmap_bits(hdc, bitmap_copy, bmi_output, tests[test_index].result_bits_size,
tests[test_index].expected_bits, test_index, tests[test_index].expected_broken_bits);
tests[test_index].expected_bits, test_index, tests[test_index].allow_todo,
tests[test_index].expected_broken_bits);
DeleteObject(bitmap);
DeleteObject(bitmap_copy);
......@@ -3069,7 +3072,8 @@ static void test_Image_StretchMode(void)
ok(!!bitmap, "LoadImageA() failed, result %u.\n", GetLastError());
DeleteFileA(filename);
compare_bitmap_bits(hdc, bitmap, bmi_output, tests[test_index].result_bits_size,
tests[test_index].expected_bits, test_index, tests[test_index].expected_broken_bits);
tests[test_index].expected_bits, test_index, tests[test_index].allow_todo,
tests[test_index].expected_broken_bits);
DeleteObject(bitmap);
}
ReleaseDC(0, hdc);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment