Signed-off-by: Jeff Smith whydoubt@gmail.com --- dlls/gdiplus/image.c | 32 +++++++++++++++-- dlls/gdiplus/tests/image.c | 70 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index f33e2328bf..ace27cd342 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -53,11 +53,11 @@ static const struct WICBitmapPaletteType palette_type; } pixel_formats[] = { - { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, + { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, { &GUID_WICPixelFormat4bppIndexed, PixelFormat4bppIndexed, WICBitmapPaletteTypeFixedHalftone8 }, - { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 }, { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 }, + { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 }, { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 }, { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 }, { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 }, @@ -126,6 +126,31 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT return palette; }
+static HRESULT set_palette(IWICBitmapFrameEncode *frame, ColorPalette *palette) +{ + HRESULT hr; + IWICImagingFactory *factory; + IWICPalette *wic_palette; + + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); + if (FAILED(hr)) + return hr; + + hr = IWICImagingFactory_CreatePalette(factory, &wic_palette); + IWICImagingFactory_Release(factory); + if (SUCCEEDED(hr)) + { + hr = IWICPalette_InitializeCustom(wic_palette, palette->Entries, palette->Count); + + if (SUCCEEDED(hr)) + hr = IWICBitmapFrameEncode_SetPalette(frame, wic_palette); + + IWICPalette_Release(wic_palette); + } + + return hr; +} + GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect, RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize) { @@ -4566,6 +4591,9 @@ static GpStatus encode_frame_wic(IWICBitmapEncoder *encoder, GpImage *image) } }
+ if (SUCCEEDED(hr) && IsIndexedPixelFormat(gdipformat)) + hr = set_palette(frameencode, image->palette); + if (SUCCEEDED(hr)) { stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat, diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 145eadbfd3..56727ce63c 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -5622,6 +5622,75 @@ static void test_png_color_formats(void) #undef PNG_COLOR_TYPE_GRAY_ALPHA #undef PNG_COLOR_TYPE_RGB_ALPHA
+static void test_png_save_palette(void) +{ + GpStatus status; + GpBitmap *bitmap; + HGLOBAL hglob; + BOOL result; + IStream *stream; + GUID enc_format, clsid; + LARGE_INTEGER seek; + ULARGE_INTEGER pos; + UINT i, ptr; + BYTE *data; + + PixelFormat formats[] = { + PixelFormat1bppIndexed, + PixelFormat4bppIndexed, + PixelFormat8bppIndexed, + PixelFormat16bppGrayScale, + PixelFormat16bppRGB555, + PixelFormat16bppRGB565, + PixelFormat16bppARGB1555, + PixelFormat24bppRGB, + PixelFormat32bppRGB, + PixelFormat32bppARGB, + PixelFormat32bppPARGB, + }; + + result = get_encoder_clsid(L"image/png", &enc_format, &clsid); + ok(result, "getting PNG encoding clsid failed"); + + hglob = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, 1024); + + for (i = 0; i < ARRAY_SIZE(formats); i++) + { + status = GdipCreateBitmapFromScan0(8, 8, 0, formats[i], NULL, &bitmap); + ok(status == Ok, "Unexpected return value %d creating bitmap for PixelFormat %#x\n", status, formats[i]); + + CreateStreamOnHGlobal(hglob, FALSE, &stream); + status = GdipSaveImageToStream((GpImage *)bitmap, stream, &clsid, NULL); + GdipDisposeImage((GpImage*)bitmap); + + todo_wine_if(formats[i] == PixelFormat16bppGrayScale) + ok(formats[i] == PixelFormat16bppGrayScale ? + (status == GenericError || status == Win32Error) : status == Ok, + "Unexpected return value %d saving image for PixelFormat %#x\n", status, formats[i]); + + if (status == Ok) + { + data = GlobalLock(hglob); + seek.QuadPart = 0; + IStream_Seek(stream, seek, STREAM_SEEK_CUR, &pos); + for (ptr = 0; ptr < pos.QuadPart - 4; ptr++) + if (!memcmp(data + ptr, "PLTE", 4)) + break; + memset(data, 0, 1024); + GlobalUnlock(hglob); + + if (IsIndexedPixelFormat(formats[i])) + ok(ptr < pos.QuadPart - 4, "Expected palette not found for PixelFormat %#x\n", formats[i]); + else + ok(ptr >= pos.QuadPart - 4, "Unexpected palette found for PixelFormat %#x\n", formats[i]); + } + + IStream_Release(stream); + } + + GlobalFree(hglob); +} + static void test_GdipLoadImageFromStream(void) { IStream *stream; @@ -5865,6 +5934,7 @@ START_TEST(image)
test_GdipInitializePalette(); test_png_color_formats(); + test_png_save_palette(); test_supported_encoders(); test_CloneBitmapArea(); test_ARGB_conversion();
This crashes the gdiplus:image test here. It attempts to access palette->Entries on an image that doesn't have a palette set.
Signed-off-by: Jeff Smith whydoubt@gmail.com --- v2: Don't try setting palette if image->palette is NULL.
dlls/gdiplus/image.c | 32 +++++++++++++++-- dlls/gdiplus/tests/image.c | 70 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index f33e2328bf..4fd7d95a9c 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -53,11 +53,11 @@ static const struct WICBitmapPaletteType palette_type; } pixel_formats[] = { - { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, + { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW }, { &GUID_WICPixelFormat4bppIndexed, PixelFormat4bppIndexed, WICBitmapPaletteTypeFixedHalftone8 }, - { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 }, { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 }, + { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 }, { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 }, { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 }, { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 }, @@ -126,6 +126,31 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT return palette; }
+static HRESULT set_palette(IWICBitmapFrameEncode *frame, ColorPalette *palette) +{ + HRESULT hr; + IWICImagingFactory *factory; + IWICPalette *wic_palette; + + hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); + if (FAILED(hr)) + return hr; + + hr = IWICImagingFactory_CreatePalette(factory, &wic_palette); + IWICImagingFactory_Release(factory); + if (SUCCEEDED(hr)) + { + hr = IWICPalette_InitializeCustom(wic_palette, palette->Entries, palette->Count); + + if (SUCCEEDED(hr)) + hr = IWICBitmapFrameEncode_SetPalette(frame, wic_palette); + + IWICPalette_Release(wic_palette); + } + + return hr; +} + GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect, RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize) { @@ -4566,6 +4591,9 @@ static GpStatus encode_frame_wic(IWICBitmapEncoder *encoder, GpImage *image) } }
+ if (SUCCEEDED(hr) && IsIndexedPixelFormat(gdipformat) && image->palette) + hr = set_palette(frameencode, image->palette); + if (SUCCEEDED(hr)) { stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat, diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 5703db09b2..f63346e1db 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -5615,6 +5615,75 @@ static void test_png_color_formats(void) #undef PNG_COLOR_TYPE_GRAY_ALPHA #undef PNG_COLOR_TYPE_RGB_ALPHA
+static void test_png_save_palette(void) +{ + GpStatus status; + GpBitmap *bitmap; + HGLOBAL hglob; + BOOL result; + IStream *stream; + GUID enc_format, clsid; + LARGE_INTEGER seek; + ULARGE_INTEGER pos; + UINT i, ptr; + BYTE *data; + + PixelFormat formats[] = { + PixelFormat1bppIndexed, + PixelFormat4bppIndexed, + PixelFormat8bppIndexed, + PixelFormat16bppGrayScale, + PixelFormat16bppRGB555, + PixelFormat16bppRGB565, + PixelFormat16bppARGB1555, + PixelFormat24bppRGB, + PixelFormat32bppRGB, + PixelFormat32bppARGB, + PixelFormat32bppPARGB, + }; + + result = get_encoder_clsid(L"image/png", &enc_format, &clsid); + ok(result, "getting PNG encoding clsid failed"); + + hglob = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, 1024); + + for (i = 0; i < ARRAY_SIZE(formats); i++) + { + status = GdipCreateBitmapFromScan0(8, 8, 0, formats[i], NULL, &bitmap); + ok(status == Ok, "Unexpected return value %d creating bitmap for PixelFormat %#x\n", status, formats[i]); + + CreateStreamOnHGlobal(hglob, FALSE, &stream); + status = GdipSaveImageToStream((GpImage *)bitmap, stream, &clsid, NULL); + GdipDisposeImage((GpImage*)bitmap); + + todo_wine_if(formats[i] == PixelFormat16bppGrayScale) + ok(formats[i] == PixelFormat16bppGrayScale ? + (status == GenericError || status == Win32Error) : status == Ok, + "Unexpected return value %d saving image for PixelFormat %#x\n", status, formats[i]); + + if (status == Ok) + { + data = GlobalLock(hglob); + seek.QuadPart = 0; + IStream_Seek(stream, seek, STREAM_SEEK_CUR, &pos); + for (ptr = 0; ptr < pos.QuadPart - 4; ptr++) + if (!memcmp(data + ptr, "PLTE", 4)) + break; + memset(data, 0, 1024); + GlobalUnlock(hglob); + + if (IsIndexedPixelFormat(formats[i])) + ok(ptr < pos.QuadPart - 4, "Expected palette not found for PixelFormat %#x\n", formats[i]); + else + ok(ptr >= pos.QuadPart - 4, "Unexpected palette found for PixelFormat %#x\n", formats[i]); + } + + IStream_Release(stream); + } + + GlobalFree(hglob); +} + static void test_GdipLoadImageFromStream(void) { IStream *stream; @@ -5858,6 +5927,7 @@ START_TEST(image)
test_GdipInitializePalette(); test_png_color_formats(); + test_png_save_palette(); test_supported_encoders(); test_CloneBitmapArea(); test_ARGB_conversion();
Signed-off-by: Vincent Povirk vincent@codeweavers.com
I can't believe msvcrt doesn't have memmem.
On Wed, Apr 29, 2020 at 10:19 AM Esme Povirk (they/them) vincent@codeweavers.com wrote:
I can't believe msvcrt doesn't have memmem.
That would have been nice. Well, what would have been _really_ nice would have been a method in the stream interface to search the stream.