mono / libgdiplus Goto Github PK
View Code? Open in Web Editor NEWC-based implementation of the GDI+ API
Home Page: http://www.mono-project.com/
License: MIT License
C-based implementation of the GDI+ API
Home Page: http://www.mono-project.com/
License: MIT License
The current build instructions for builds with X11 support cause an outdated cairo to be used. There's Cairo 1.14.6 distributed with XQuartz and the suggested build command (in README.md) picks it up instead of the cairo build from Homebrew.
To pick-up the Homebrew Cairo it needs to be changed from
PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig ./autogen.sh --prefix=YOUR_PREFIX
to
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig ./autogen.sh --prefix=YOUR_PREFIX
Unfortunately the default cairo Homebrew build is built without X11 support, so furthermore the following is needed:
brew uninstall cairo
brew install --with-x11 cairo
In test_valid
in testwmfcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE leftGreaterThanRight[] = {
/* Placeable Header */ 0xD7, 0xCD, 0xC6, 0x9A, 0x00, 0x00, 0x00, 0x01, 0xCE, 0xF2, 0x00, 0x00, 0x32, 0x0d, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x05, 0xAA,
/* Metafile Header */ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
/* META_EOF */ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
// FIXME: GDI+ uses abs(width).
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (leftGreaterThanRight, 0, -3378, 256, 6756, 650.239929f, 17160.2383f);
#endif
In test_valid2bpp
in testpngcodec.
#if defined(USE_WINDOWS_GDIPLUS)
BYTE grayscale2bpp1x1Interlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x07, 0xC9, 0xB3, 0x62,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x00, 0x00, 0x42, 0x00, 0x41, 0xF9, 0xFB, 0x3C, 0x49,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale2bpp6x4NotInterlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xDF, 0x09, 0x3E,
/* IDAT */ 0x00, 0x00, 0x00, 0x14, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x08, 0x0D, 0x60, 0xC8, 0x9A, 0xC0, 0x50, 0x70, 0x81, 0x81, 0x81, 0x01, 0x00, 0x13, 0x83, 0x02, 0xE0, 0x20, 0x93, 0x79, 0xCF,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale2bpp1x1WithPalette[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x07, 0xC9, 0xB3, 0x62,
/* PLTE */ 0x00, 0x00, 0x00, 0x09, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0xE6, 0xFA, 0x0D, 0xB2, 0xEB, 0x46,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x00, 0x00, 0x42, 0x00, 0x41, 0xF9, 0xFB, 0x3C, 0x49,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
// FIXME: this causes an AV in libgdiplus when trying to convert this image to 32bpp as we assume
// the image has a palette.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (grayscale2bpp1x1Interlaced, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale2bpp6x4NotInterlaced, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale2bpp1x1WithPalette, PixelFormat32bppARGB, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
#endif
This is the only missing library on Windows libgdiplus
I can't see a nuget package anywhere, maybe I'll create one :D
#ifdef _WIN32
# include <Windows.h>
# include <gdiplus.h>
using namespace Gdiplus;
using namespace Gdiplus::DllExports;
# pragma comment(lib, "gdiplus.lib")
#endif
#include <GdiPlusFlat.h>
#include <string>
#ifdef _WIN32
# define WIDEN( x ) L##x
using ucs2_string = std::wstring;
#else
# define WIDEN( x ) u##x
using ucs2_string = std::u16string;
#endif
bool get_encoder_clsid( const ucs2_string& format, CLSID* clsid );
int main()
{
ULONG_PTR token = 0;
GdiplusStartupInput input = { 0 };
input.GdiplusVersion = 1;
GdiplusStartup( &token, &input, nullptr );
GpBitmap* bitmap = nullptr;
GdipCreateBitmapFromScan0( 400, 400, 0, PixelFormat32bppARGB, nullptr, &bitmap );
GpGraphics* graphics = nullptr;
GdipGetImageGraphicsContext( bitmap, &graphics );
GdipGraphicsClear( graphics, 0xFF808080 );
GpPath* rectPath = nullptr;
GdipCreatePath( FillModeAlternate, &rectPath );
GdipAddPathRectangleI( rectPath, 50, 50, 300, 300 );
GpPath* polyPath = nullptr;
GdipCreatePath( FillModeAlternate, &polyPath );
GpPoint polyPoints[] = { { 100, 100 },
{ 200, 75 },
{ 300, 100 },
{ 325, 200 },
{ 300, 300 },
{ 200, 325 },
{ 100, 300 },
{ 75, 200 } };
GdipAddPathPolygonI( polyPath, polyPoints, sizeof( polyPoints ) / sizeof( polyPoints[0] ) );
GpRegion* region = nullptr;
GdipCreateRegion( ®ion );
GdipSetEmpty( region );
GdipCombineRegionPath( region, rectPath, CombineModeUnion );
GdipCombineRegionPath( region, polyPath, CombineModeExclude );
GpSolidFill* brush = nullptr;
GdipCreateSolidFill( 0xFF00FF00, &brush );
GdipFillRegion( graphics, brush, region );
GdipDeleteGraphics( graphics );
GdipDeletePath( rectPath );
GdipDeletePath( polyPath );
GdipDeleteRegion( region );
GdipDeleteBrush( brush );
CLSID clsid = { 0 };
get_encoder_clsid( WIDEN( "image/png" ), &clsid );
GdipSaveImageToFile( bitmap, (const WCHAR*)WIDEN( "test-image.png" ), &clsid, nullptr );
GdipDisposeImage( bitmap );
return 0;
}
bool get_encoder_clsid( const ucs2_string& format, CLSID* clsid )
{
UINT numEncoders = 0;
UINT size = 0;
GdipGetImageEncodersSize( &numEncoders, &size );
ImageCodecInfo* encoders = (ImageCodecInfo*)malloc( size );
GdipGetImageEncoders( numEncoders, size, encoders );
for( UINT j = 0; j < numEncoders; ++j )
{
if( format == (const ucs2_string::value_type*)encoders[j].MimeType )
{
*clsid = encoders[j].Clsid;
free( encoders );
return true;
}
}
free( encoders );
return false;
}
Fills the excluded area with some brighter color.
Should not fill the excluded area at all.
Version Used:
libgdiplus 5.6 (7e5300b)
null
, which causes playing to failnull
, which causes playing to failMM_TEXT
but it should be like MM_TWIPS
Bunch of FIXMEs in test_validImage8bppRle8Compression in testbmpcodec.c
// FIXME: GDI+ converts BI_RLE8 bitmaps to 32bpp.
In test_createFontFromLogFontA/test_createFontFromLogFontW
in testfont.c
:
logfont.lfHeight = 10;
logfont.lfWidth = 11;
logfont.lfEscapement = 0;
logfont.lfOrientation = 1;
logfont.lfWeight = 700;
logfont.lfItalic = TRUE;
logfont.lfUnderline = TRUE;
logfont.lfStrikeOut = TRUE;
logfont.lfCharSet = 0;
logfont.lfOutPrecision = 1;
logfont.lfClipPrecision = 2;
logfont.lfQuality = 4;
logfont.lfPitchAndFamily = 0x50;
strcpy (logfont.lfFaceName, "Times New Roman");
status = GdipCreateFontFromLogfontA (hdc, &logfont, &font);
assertEqualInt (status, Ok);
GdipGetFontStyle (font, &style);
assertEqualInt (style, 15);
GdipGetFontUnit(font, &unit);
assertEqualInt (unit, UnitWorld);
status = GdipGetFamily (font, &family);
// FIXME: this fails with libgdiplus.
#if defined(USE_WINDOWS_LIBGDIPLUS)
assertEqualInt (status, Ok);
assert (family);
#endif
Need to investigate what happens if the font family doesn't exist
These functions are used with non-zero offset in the TIFF code, eg.
gdip_property_get_short(0, bitmap_data->property[index].value, &s);
gdip_property_get_short(2, bitmap_data->property[index].value, &s2);
or
float chromacities[6];
for (j = 0; j < 6; j++) {
gdip_property_get_long(j * 8, bitmap_data->property[index].value, &i);
chromacities[j] = (float)i / 1000000;
}
We have a test for this, but it's wrong... If the test tested what it meant to, it would have revealed a bug
It looks like we’re linking with a 32bit dll (pixman-1.dll)
This causes a crash like in https://stackoverflow.com/questions/28299246/0xc000007b-error
In test_validImage16bppBitmapInfoHeader
in testbmpcodec.c
// FIXME: this returns OutOfMemory libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (rle4Compression16bpp, PixelFormat32bppRGB);
createFileSuccess (rle8Compression16bpp, PixelFormat32bppRGB);
#endif
Does GDI+ try to decompress these images, or does it just ignore the compression?
Currently we don't support any text inputs in WMF records
In test_getEncoderParameterListSize
in testgpimage.c
status = GdipGetEncoderParameterListSize (image, &tifEncoderClsid, &size);
// FIXME: this returns NotImplemented with libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
assertEqualInt (status, Ok);
assertEqualInt (size, is_32bit() ? 164 : 184);
#endif
status = GdipGetEncoderParameterListSize (image, &gifEncoderClsid, &size);
// FIXME: this returns FileNotFound with libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
assertEqualInt (status, Ok);
assertEqualInt (size, is_32bit() ? 64 : 80);
#endif
status = GdipGetEncoderParameterListSize (image, &pngEncoderClsid, &size);
// FIXME: this returns FileNotFound with libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
assertEqualInt (status, Ok);
assertEqualInt (size, is_32bit() ? 32 : 40);
#endif
status = GdipGetEncoderParameterListSize (image, &jpegEncoderClsid, &size);
assertEqualInt (status, Ok);
// FIXME: this returns 44 with libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
assertEqualInt (size, is_32bit() ? 172 : 200);
#endif
If the second allocation in GdipCreatePath fails it leaks memory from the previous allocations.
In test_validImage32bppBitfields
in testbmpcodec.c
// FIXME: libgdiplus can't decode these images.
In test_valid
in testwmfcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE zeroInches[] = {
/* Placeable Header */ 0xD7, 0xCD, 0xC6, 0x9A, 0x00, 0x00, 0x58, 0xF0, 0xCE, 0xF2, 0xA8, 0x0F, 0x32, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x57,
/* Metafile Header */ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
/* META_EOF */ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
// FIXME: GDI+ uses a default inches value if it is zero.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (zeroInches, -4008, -3378, 8016, 6756, 14139.333008f, 11916.833008f);
#endif
In test_getFontHeight
in testfont.c
status = GdipGetFontHeight (font, NULL, &height);
assertEqualInt (status, Ok);
// FIXME: this returns a different value with libgdiplus.
#if defined(USE_WINDOWS_LIBGDIPLUS)
assertEqualFloat (height, 11.3183594f);
#endif
Maybe this is due to GdipGetGenericFontFamilySansSerif
returning different fonts in Linux/Windows - so this could be a test bug
In test_createFont
in testfont.c
// FIXME: there are several places that indirectly call GdipCreateFont in
// libgdiplus but allow negative em sizes on GDI+ because the GDI+
// implementation does not call GdipCreateFont. An example is GdipAddPathString.
// A fix for this will need to carefully account for places where this
// API is called.
#if defined(USE_WINDOWS_LIBGDIPLUS)
status = GdipCreateFont (family, -1, 10, UnitPixel, &font);
assertEqualInt (status, InvalidParameter);
status = GdipCreateFont (family, 0, 10, UnitPixel, &font);
assertEqualInt (status, InvalidParameter);
#endif
In test_invaldImageData
in testwmfcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE noSuchFunction[] = {
/* Placeable Header */ 0xD7, 0xCD, 0xC6, 0x9A, 0x00, 0x00, 0x58, 0xF0, 0xCE, 0xF2, 0xA8, 0x0F, 0x32, 0x0d, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x54,
/* Metafile Header */ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
/* Random */ 0x03, 0x00, 0x00, 0x00, 0x00, 0x01
};
#endif
// FIXME: seems like GDI+ validates records more than libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
createFile (noSuchFunction, OutOfMemory);
#endif
It looks like biColorsUsed is ignored? Might need more tests
In test_valid
in testemfcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE shortMillimetres[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x6C, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE noRecords[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x70, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00
};
BYTE noCbPixelFormat[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00
};
BYTE shortCbPixelFormat[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00
};
BYTE noOffPixelFormat[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
};
BYTE shortOffPixelFormat[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* offPixelFormat */ 0x00, 0x00, 0x00
};
BYTE noOpenGL[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* offPixelFormat */ 0x00, 0x00, 0x00, 0x00,
};
BYTE shortOpenGL[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x78, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* offPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* bOpenGL */ 0x00, 0x00, 0x00
};
BYTE noMicrometers[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x80, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* offPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* bOpenGL */ 0x00, 0x00, 0x00, 0x00
};
BYTE shortMicrometers[] = {
/* EMR_HEADER */ 0x01, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* Bounds */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5D, 0x00, 0x00, 0x00,
/* Frame */ 0xD2, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00,
/* Signature */ 0x20, 0x45, 0x4D, 0x46,
/* Version */ 0x00, 0x00, 0x01, 0x00,
/* Bytes */ 0x80, 0x00, 0x00, 0x00,
/* Records */ 0x02, 0x00, 0x00, 0x00,
/* Handles */ 0x01, 0x00,
/* Reserved */ 0x00, 0x00,
/* nDescription */ 0x00, 0x00, 0x00, 0x00,
/* offDescription*/ 0x00, 0x00, 0x00, 0x00,
/* palEntries */ 0x00, 0x00, 0x00, 0x00,
/* Device */ 0xA0, 0x05, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00,
/* Millimetres */ 0xD8, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00,
/* cbPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* offPixelFormat */ 0x00, 0x00, 0x00, 0x00,
/* bOpenGL */ 0x00, 0x00, 0x00, 0x00,
/* Micrometers */ 0xC0, 0x4B, 0x03, 0x00, 0xD8, 0x41, 0x04
};
#endif
// FIXME: GDI+ allows 4 bytes off the size of Millimetres.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (shortMillimetres, 14, 20, 50, 18, 750, 216);
#endif
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (noRecords, 14, 20, 50, 18, 750, 216);
createFileSuccess (noCbPixelFormat, 14, 20, 50, 18, 750, 216);
createFileSuccess (shortCbPixelFormat, 14, 20, 50, 18, 750, 216);
createFileSuccess (noOffPixelFormat, 14, 20, 50, 18, 750, 216);
createFileSuccess (shortOffPixelFormat, 14, 20, 50, 18, 750, 216);
createFileSuccess (noOpenGL, 14, 20, 50, 18, 750, 216);
createFileSuccess (shortOpenGL, 14, 20, 50, 18, 750, 216);
createFileSuccess (noMicrometers, 14, 20, 50, 18, 750, 216);
createFileSuccess (shortMicrometers, 14, 20, 50, 18, 750, 216);
#endif
In test_getMetafileHeaderFromWmf
in testmetafile.c
// Get from WMF file.
status = GdipGetMetafileHeaderFromWmf (wmfMetafile, &wmfPlaceableFileHeader, &header);
assertEqualInt (status, Ok);
assertEqualInt (header.Type , 2);
assertEqualInt (header.Size, 68142);
assertEqualInt (header.Version, 768);
assertEqualInt (header.EmfPlusFlags, 0);
// FIXME: these values constantly fluctuate with libgdiplus - potential UB?
#if defined(USE_WINDOWS_GDIPLUS)
assertEqualInt (header.DpiX, 0);
assertEqualInt (header.DpiY, 0);
assertEqualInt (header.X, 0);
assertEqualInt (header.Y, 0);
assertEqualInt (header.Width, 0);
assertEqualInt (header.Height, 0);
#endif
// Get from EMF file.
status = GdipGetMetafileHeaderFromWmf (emfMetafile, &wmfPlaceableFileHeader, &header);
assertEqualInt (status, Ok);
assertEqualInt (header.Type , 2);
assertEqualInt (header.Size, 0);
assertEqualInt (header.Version, 108);
assertEqualInt (header.EmfPlusFlags, 0);
// FIXME: these values constantly fluctuate with libgdiplus - potential UB?
#if defined(USE_WINDOWS_GDIPLUS)
assert (header.DpiX > 0);
assert (header.DpiY > 0);
assertEqualInt (header.X, 0);
assertEqualInt (header.Y, 0);
assertEqualInt (header.Width, 0);
assertEqualInt (header.Height, 0);
#endif
With all the work @hughbe is doing it sure looks like libgdiplus is living its renaissance 😄 .
We rely on libgdiplus in our product and we try to make sure our users can install libgdiplus using the normal package management solutions on their platform (Linux distros + Homebrew).
Right now we build the packages ourselves but it would make sense to update the 'official' repositories.
Some thoughts:
In test_valid4bpp
in testpngcodec.c
BYTE grayscaleWithAlpha1x1Interlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x88, 0x89, 0x46, 0xC2,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscaleWithAlpha6x4NotInterlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x9F, 0xFC, 0x9E,
/* IDAT */ 0x00, 0x00, 0x00, 0x18, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x14, 0x14, 0x64, 0x10, 0x71, 0x71, 0x64, 0x90, 0x2F, 0xFF, 0xC8, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x10, 0xFF, 0x02, 0x54, 0xB8, 0xE8, 0x8D, 0xCD,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscaleWithAlpha1x1WithPalette[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x01, 0x88, 0x89, 0x46, 0xC2,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x00, 0x00, 0x12, 0x00, 0x11, 0x75, 0x9A, 0x0F, 0xE8,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
// FIXME: GDI+ converts grayscale alpha 4bpp images to 32bpp.
#if defined(USE_WINDOWS_GDIPLUS)
PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
#else
PixelFormat expectedGrayscalePixelFormat = PixelFormat4bppIndexed;
#endif
createFileSuccess (grayscaleWithAlpha1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscaleWithAlpha6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscaleWithAlpha1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (indexed4bpp1x1PaletteFirst, PixelFormat4bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
In test_invalidImage
in testicocodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE invalidData[] = {0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 22, 0, 0, 0, 40, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 128, 0, 0, 0, 0, 0, 0, 0};
#endif
// FIXME: this returns Ok with libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
createFile (invalidData, OutOfMemory);
#endif
Exception thrown at 0x00007FF8AF470B1D (ntdll.dll) in libgdiplus.tests.exe: 0xC0000005: Access violation writing location 0xFFFFFFFFF6D1C290.
fontconfig.dll!readdir(DIR * dir) Line 100 C Symbols loaded.
fontconfig.dll!FcDirScanConfig(_FcFontSet * set, _FcStrSet * dirs, _FcBlanks * blanks, const unsigned char * dir, int force, _FcConfig * config) Line 186 C Symbols loaded.
fontconfig.dll!FcDirCacheScan(const unsigned char * dir, _FcConfig * config) Line 270 C Symbols loaded.
fontconfig.dll!FcDirCacheRead(const unsigned char * dir, int force, _FcConfig * config) Line 319 C Symbols loaded.
fontconfig.dll!FcConfigAddDirList(_FcConfig * config, _FcSetName set, _FcStrSet * dirSet) Line 355 C Symbols loaded.
fontconfig.dll!FcConfigBuildFonts(_FcConfig * config) Line 388 C Symbols loaded.
[Inline Frame] fontconfig.dll!FcInitLoadConfigAndFonts() Line 106 C Symbols loaded.
fontconfig.dll!FcInit() Line 124 C Symbols loaded.
libgdiplus.dll!GdiplusStartup(unsigned __int64 * token, const GdiplusStartupInput * input, GdiplusStartupOutput * output) Line 51 C Symbols loaded.
Problematic code:
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
result = &dir->result;
result->d_name = dir->info.name;
}
In test_createFontFamilyFromName
in testfont.c
// FIXME: Libgdiplus does not validate that the font family exists
// if the collection is NULL.
#if defined(USE_WINDOWS_GDIPLUS)
status = GdipCreateFontFamilyFromName (NoSuchFont, NULL, &family);
assertEqualInt (status, FontFamilyNotFound);
#endif
GDI+ does validate this
In test_validData
in testgifcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE graphicsControlBlockMissingTerminator[] = {'G', 'I', 'F', '8', '9', 'a', 3, 0, 5, 0, 0, 0, 0, '!', 0xF9, 0x04, 0, 0, 0, 0, ',', 0, 0, 0, 0, 3, 0, 5, 0, B8(10000000), 0, 0, 0, 255, 255, 255, 0x02, 0x06, 0x84, 0x03, 0x81, 0x9a, 0x06, 0x05, 0x00, ';'};
#endif
// FIXME: it appears that GDI+ allows a graphics control extension block without a
// terminating 0 byte.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (graphicsControlBlockMissingTerminator, 3, 5);
#endif
This may not be possible to fix, as we rely on giflib
Seems like GDI+ rejects these, currently we don't. Need to add tests
In test_invalidFileSize
in testwmfcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE tooLargeFileSize[] = {
/* Placeable Header */ 0xD7, 0xCD, 0xC6, 0x9A, 0x00, 0x00, 0x58, 0xF0, 0xCE, 0xF2, 0xA8, 0x0F, 0x32, 0x0d, 0xE8, 0x03, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x54,
/* Metafile Header */ 0x01, 0x00, 0x09, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
/* META_EOF */ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
// FIXME: GDI+ seems to allow overly large file sizes.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (tooLargeFileSize, -4008, -3378, 8016, 6756, 20360.638672f, 17160.2383f);
#endif
NDK compiler?
In test_valid16bpp
in testpngcodec.c
BYTE grayscale1x1Interlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1D, 0xE9, 0x77, 0x80,
/* IDAT */ 0x00, 0x00, 0x00, 0x0B, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xA8, 0xFF, 0x0F, 0x00, 0x02, 0x00, 0x01, 0x7F, 0x2F, 0x5A, 0xAA, 0x27,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale6x4NotInterlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xFF, 0xCD, 0xDC,
/* IDAT */ 0x00, 0x00, 0x00, 0x21, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xFF, 0x9F, 0x01, 0x0E, 0x80, 0x9C, 0x06, 0x28, 0xB3, 0x81, 0x81, 0x85, 0x81, 0xE1, 0x5A, 0x18, 0x94, 0xB7, 0x0A, 0x4A, 0x83, 0x00, 0x03, 0x03, 0x00, 0xF4, 0x31, 0x06, 0xD9, 0x82, 0x8E, 0x6A, 0xA9,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale1x1WithPalette[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x01, 0x1D, 0xE9, 0x77, 0x80,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IDAT */ 0x00, 0x00, 0x00, 0x0B, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xA8, 0xFF, 0x0F, 0x00, 0x02, 0x00, 0x01, 0x7F, 0x2F, 0x5A, 0xAA, 0x27,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE trueColor1x1Interlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x01, 0xB7, 0xE0, 0xBF, 0x0B,
/* IDAT */ 0x00, 0x00, 0x00, 0x0F, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x81, 0x81, 0x81, 0x01, 0x00, 0x0A, 0xFC, 0x01, 0xFF, 0xC0, 0x18, 0x7E, 0x3E,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE trueColor6x4NotInterlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x10, 0x02, 0x00, 0x00, 0x00, 0x72, 0xF6, 0x05, 0x57,
/* IDAT */ 0x00, 0x00, 0x00, 0x36, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xFC, 0xFF, 0x9F, 0x81, 0x20, 0x80, 0x2A, 0x7A, 0xFE, 0xFC, 0xD9, 0xB3, 0x5F, 0xBF, 0xC0, 0x22, 0x28, 0x40, 0x52, 0x52, 0x4A, 0x8A, 0x8D, 0x8D, 0x01, 0xD9, 0xA4, 0x77, 0xEF, 0x9A, 0x9A, 0xDE, 0x01, 0x01, 0x88, 0x84, 0x88, 0x40, 0x64, 0x19, 0x11, 0x4C, 0x5C, 0x80, 0x81, 0x01, 0x00, 0x87, 0xD4, 0x19, 0x72, 0xFD, 0x0D, 0x0C, 0x10,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE trueColor1x1WithPalette[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x00, 0x00, 0x01, 0xB7, 0xE0, 0xBF, 0x0B,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IDAT */ 0x00, 0x00, 0x00, 0x0F, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0xF8, 0xFF, 0x9F, 0x81, 0x81, 0x81, 0x01, 0x00, 0x0A, 0xFC, 0x01, 0xFF, 0xC0, 0x18, 0x7E, 0x3E,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
// FIXME: GDI+ converts grayscale 16bpp images to 32bpp.
#if defined(USE_WINDOWS_GDIPLUS)
PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
PixelFormat expectedTrueColorPixelFormat = PixelFormat32bppARGB;
#else
PixelFormat expectedGrayscalePixelFormat = PixelFormat8bppIndexed ;
PixelFormat expectedTrueColorPixelFormat = PixelFormat24bppRGB ;
#endif
createFileSuccess (grayscale1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (trueColor1x1Interlaced, expectedTrueColorPixelFormat, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (trueColor6x4NotInterlaced, expectedTrueColorPixelFormat, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (trueColor1x1WithPalette, expectedTrueColorPixelFormat, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
In testpngcodec.c
#define createFileSuccess(buffer, format, width, height, flags, propertyCount) \
{ \
createFile (buffer, Ok); \
/* FIXME: grayscale image flags are incorrect. */ \
verifyImage (image, ImageTypeBitmap, pngRawFormat, format, 0, 0, width, height, (REAL) width, (REAL) height, flags, propertyCount, FALSE); \
GdipDisposeImage (image); \
}
In test_valid8bpp
in testpngcodec.c
BYTE grayscale1x1Interlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x4D, 0x79, 0xAB, 0xC3,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x04, 0x00, 0x00, 0x03, 0x00, 0x02, 0xA0, 0x80, 0x44, 0x0F,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale6x4NotInterlaced[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R',0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x88, 0x6F, 0x11, 0x9F,
/* IDAT */ 0x00, 0x00, 0x00, 0x1D, 'I', 'D', 'A', 'T',0x18, 0x57, 0x63, 0x64, 0x64, 0x00, 0x01, 0x46, 0x46, 0x26, 0x20, 0xF9, 0x8F, 0x89, 0xE1, 0x0F, 0x0B, 0xCB, 0x1F, 0xB0, 0x08, 0x03, 0x03, 0x03, 0x00, 0x24, 0xA0, 0x03, 0x07, 0xA7, 0x85, 0xE0, 0xA2,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D',0xAE, 0x42, 0x60, 0x82
};
BYTE grayscale1x1WithPalette[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x01, 0x4D, 0x79, 0xAB, 0xC3,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x04, 0x00, 0x00, 0x03, 0x00, 0x02, 0xA0, 0x80, 0x44, 0x0F,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
// FIXME: GDI+ converts grayscale 8bpp images to 32bpp.
#if defined(USE_WINDOWS_GDIPLUS)
PixelFormat expectedGrayscalePixelFormat = PixelFormat32bppARGB;
#else
PixelFormat expectedGrayscalePixelFormat = PixelFormat8bppIndexed;
#endif
createFileSuccess (grayscale1x1Interlaced, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale6x4NotInterlaced, expectedGrayscalePixelFormat, 6, 4, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
createFileSuccess (grayscale1x1WithPalette, expectedGrayscalePixelFormat, 1, 1, ImageFlagsColorSpaceGRAY | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
In test_validImage16bppBitmapV3Header
in testbmpcodec.c
static void test_validImage16bppBitmapV3Header ()
{
BYTE image1x1RGB565[] = {
// -- BITMAPCOREHEADER -- //
/* Signature */ 0x42, 0x4D,
/* File Size */ 0x4A, 0x00, 0x00, 0x00,
/* Reserved */ 0x00, 0x00, 0x00, 0x00,
/* Offset */ 0x46, 0x00, 0x00, 0x00,
// -- BITMAPINFOHEADER
/* Header Size */ 0x38, 0x00, 0x00, 0x00,
/* Width */ 0x01, 0x00, 0x00, 0x00,
/* Height */ 0x01, 0x00, 0x00, 0x00,
/* Planes */ 0x01, 0x00,
/* Bit Count */ 0x10, 0x00,
/* Compression */ 0x00, 0x00, 0x00, 0x00,
/* Image Size */ 0x00, 0x00, 0x00, 0x00,
/* Horizontal */ 0x00, 0x00, 0x00, 0x00,
/* Vertical */ 0x00, 0x00, 0x00, 0x00,
/* Colors Used */ 0x00, 0x00, 0x00, 0x00,
/* Important Colors */ 0x00, 0x00, 0x00, 0x00,
// -- BITMAPV3INFOHEADER -- //
/* Red Mask */ 0x00, 0xF8, 0x00, 0x00,
/* Green Mask */ 0xE0, 0x07, 0x00, 0x00,
/* Blue Mask */ 0x1F, 0x00, 0x00, 0x00,
/* Alpha Mask */ 0x00, 0x00, 0x00, 0x00,
// -- Image Data --/
0xD7, 0xFE, 0x00, 0x00
};
BYTE image1x1RGB555[] = {
// -- BITMAPCOREHEADER -- //
/* Signature */ 0x42, 0x4D,
/* File Size */ 0x4A, 0x00, 0x00, 0x00,
/* Reserved */ 0x00, 0x00, 0x00, 0x00,
/* Offset */ 0x46, 0x00, 0x00, 0x00,
// -- BITMAPINFOHEADER
/* Header Size */ 0x38, 0x00, 0x00, 0x00,
/* Width */ 0x01, 0x00, 0x00, 0x00,
/* Height */ 0x01, 0x00, 0x00, 0x00,
/* Planes */ 0x01, 0x00,
/* Bit Count */ 0x10, 0x00,
/* Compression */ 0x00, 0x00, 0x00, 0x00,
/* Image Size */ 0x00, 0x00, 0x00, 0x00,
/* Horizontal */ 0x00, 0x00, 0x00, 0x00,
/* Vertical */ 0x00, 0x00, 0x00, 0x00,
/* Colors Used */ 0x00, 0x00, 0x00, 0x00,
/* Important Colors */ 0x00, 0x00, 0x00, 0x00,
// -- BITMAPV3INFOHEADER -- //
/* Red Mask */ 0x7C, 0x00, 0x00, 0x00,
/* Green Mask */ 0xE0, 0x03, 0x00, 0x00,
/* Blue Mask */ 0x1F, 0x00, 0x00, 0x00,
/* Alpha Mask */ 0x00, 0x00, 0x00, 0x00,
// -- Image Data --/
0xD7, 0xFE, 0x00, 0x00
};
createFileSuccessDispose (image1x1RGB565, PixelFormat32bppRGB, 1, 1, bmpFlags, FALSE);
// FIXME: match GDI+ behaviour.
#if defined(USE_WINDOWS_GDIPLUS)
verifyPixels (image, {(ARGB) -19011});
#endif
GdipDisposeImage (image);
createFileSuccessDispose (image1x1RGB555, PixelFormat32bppRGB, 1, 1, bmpFlags, FALSE);
// FIXME: match GDI+ behaviour.
#if defined(USE_WINDOWS_GDIPLUS)
verifyPixels (image, {(ARGB) -19011});
#endif
GdipDisposeImage (image);
}
It seems that the implementation of GdipGetPathData is pretty wrong in relation to how it manages memory. The caller is supposed to allocate the buffers and specify the point count. The current implementation leaks memory on each call by allocating buffers and overriding the passed buffers.
META_RECTANGLE records are currently ignored so not displayed
In test_invalidImageData
in testbmpcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE noImageData[] = {'B', 'M', 62, 0, 0, 0, 0, 0, 0, 0, 0x3E, 0, 0, 0, 40, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0};
#endif
// FIXME: this should fail with OutOfMemory in libgdiplus.
#if defined(USE_WINDOWS_GDIPLUS)
createFile (noImageData, OutOfMemory);
#endif
The fault is in
if (size_read < size) {
/* special case for missing data in the last line */
if (line == result->active_bitmap->height - 1) {
/* MS produce such files for storing ImageList bitmaps, see bug #80797 */
int missing_size = size - size_read;
memset (data_read + size_read, 0, missing_size);
} else {
status = OutOfMemory;
goto error;
}
}
@akoeplinger is there a compat concern? This would disallow images that we previously allowed, but also increase compatability with GDI+...
It seems that the bug https://bugzilla.xamarin.com/show_bug.cgi?id=80797 doesn't exist as well? Maybe this is an old relic
In test_valid1bpp
in testpngcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE indexed1bpp1x1PaletteLast[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xDB, 0x56, 0xCA,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x68, 0x00, 0x00, 0x00, 0x82, 0x00, 0x81, 0xA7, 0x01, 0xBA, 0x10,
/* PLTE */ 0x00, 0x00, 0x00, 0x06, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xA5, 0xD9, 0x9F, 0xDD,
/* IEND*/ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (indexed1bpp1x1PaletteLast, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
In test_valid2bpp
in testpngcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE indexed2bpp6x4PaletteLast[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x00, 0x00, 0x01, 0xA7, 0x6D, 0x96, 0x46,
/* IDAT */ 0x00, 0x00, 0x00, 0x16, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x70, 0x00, 0x43, 0x1F, 0x86, 0x10, 0x86, 0x23, 0x0C, 0x59, 0x13, 0x18, 0x18, 0x18, 0x00, 0x1B, 0x38, 0x03, 0x1F, 0xE2, 0xF7, 0x9D, 0x3B,
/* PLTE */ 0x00, 0x00, 0x00, 0x09, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xE6, 0xE6, 0xFA, 0x0D, 0xB2, 0xEB, 0x46,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (indexed2bpp6x4PaletteLast, PixelFormat32bppARGB, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsHasAlpha | ImageFlagsReadOnly, 3);
#endif
In testvalid4bpp
in testpngcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE indexed4bpp6x4PaletteLast[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
/* IDAT */ 0x00, 0x00, 0x00, 0x1B, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x10, 0x00, 0x43, 0xF1, 0x0F, 0x0C, 0x82, 0x02, 0x0C, 0xDF, 0x05, 0x18, 0x44, 0x5C, 0x1C, 0x19, 0x18, 0x18, 0x18, 0x00, 0x22, 0x93, 0x02, 0xF9, 0x27, 0x14, 0x52, 0x58,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (indexed4bpp6x4PaletteLast, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
In test_valid8bpp
in testpngcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE indexed6x4PaletteLast[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x08, 0x03, 0x00, 0x00, 0x01, 0xED, 0xDD, 0x8E, 0xE7,
/* IDAT */ 0x00, 0x00, 0x00, 0x1E, 'I', 'D', 'A', 'T', 0x18, 0x57, 0x63, 0x60, 0x84, 0x40, 0xF6, 0xFF, 0x0C, 0x8C, 0x8C, 0x8C, 0x0C, 0xFF, 0xD9, 0x81, 0x6C, 0x66, 0x20, 0x60, 0x64, 0x00, 0x01, 0x06, 0x06, 0x00, 0x2A, 0x5E, 0x02, 0x23, 0xF7, 0x26, 0x7C, 0xAC,
/* PLTE */ 0x00, 0x00, 0x00, 0x18, 'P', 'L', 'T', 'E', 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE6, 0xE6, 0xFA, 0xF5, 0xF5, 0xDC, 0xFF, 0xFF, 0xFF, 0x9A, 0xCD, 0x32, 0xEE, 0x82, 0xEE, 0xBD, 0xEB, 0xF4, 0x2B,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
// FIXME: GDI+ allows indexed images with palettes last.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (indexed6x4PaletteLast, PixelFormat8bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
Might not be possible, as we rely on libpng
In test_getImageGraphicsContext
in testbmpcodec.
// FIXME: libgdiplus doesn't support PixelFormat8bppIndexed.
#if defined(USE_WINDOWS_GDIPLUS)
// ImageTypeBitmap - PixelFormat8bppIndexed.
status = GdipGetImageGraphicsContext (gifImage, &graphics);
assertEqualInt (status, Ok);
assert (graphics);
GdipDeleteGraphics (graphics);
#endif
In test_validImage16bppBitmapV4Header
in testbmpcodec.c
// FIXME: this causes a stack buffer overflow (crash) in libgdiplus.
16bpp BITMAPV4HEADER cause libgdiplus to crash
We currently just assume that if the header is not OS/2, then it must be BITMAPINFOHEADER which is wrong. Need to add tests for these headers also verifying the pixel values of the image, as previously we'd read data from the palette or header as image data
This missing error check could cause buffer overrun.
In test_loadImageFromFileJpg
in testgpimage.c
static void test_loadImageFromFileJpg ()
{
GpImage *image = getImage ("test.jpg");
// FIXME: jpg image flags are wrong in libgdiplus.
verifyBitmap (image, jpegRawFormat, PixelFormat24bppRGB, 100, 68, 73744, 2, FALSE);
GdipDisposeImage (image);
}
In test_cloneImage
in testgpimage.c
// ImageTypeBitmap - jpg.
status = GdipCloneImage (jpgImage, &clonedImage);
assertEqualInt (status, Ok);
assert (clonedImage && clonedImage != jpgImage);
// FIXME: jpg image flags are wrong in libgdiplus.
verifyBitmap (clonedImage, jpegRawFormat, PixelFormat24bppRGB, 100, 68, 73744, 2, FALSE);
GdipDisposeImage (clonedImage);
Bunch of FIXMEs in test_validImage4bppRle4Compression
in testbmpcodec.c
// FIXME: GDI+ converts BI_RLE4 bitmaps to 32bpp.
In test_valid
in testpngcodec.c
#if defined(USE_WINDOWS_GDIPLUS)
BYTE longIhdrLength[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0E, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE multipleIhdrs[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
/* PLTE */ 0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
/* IDAT */ 0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE multipleIdats[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
/* PLTE */ 0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
/* IDAT */ 0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE oneEmptyIdat[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IDAT */ 0x00, 0x00, 0x00, 0x00, 'I', 'D', 'A', 'T', 0x00, 0x00, 0x00, 0x00,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE multiplePalettes[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
/* PLTE */ 0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
/* PLTE */ 0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
/* IDAT */ 0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE invalidCrc[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE invalidCompression[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0x00, 0x00, 0x00, 0x00
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE unknownChunk[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x04, 0x03, 0x00, 0x00, 0x01, 0x28, 0x2D, 0x63, 0xE6,
/* UNKNOWN */ 0x00, 0x00, 0x00, 0x02, 'U', 'N', 'K', 'N', 0xFE, 0xEF, 0xAE, 0xCE, 0x1C, 0xE9,
/* PLTE */ 0x00, 0x00, 0x00, 0x0C, 'P', 'L', 'T', 'E', 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0xC1, 0x7F, 0x62, 0xD1,
/* IDAT */ 0x00, 0x00, 0x00, 0x0C, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0xC0, 0x06, 0x18, 0x18, 0x00, 0x00, 0x17, 0x00, 0x01, 0x47, 0xB7, 0x91, 0x37,
/* IEND */ 0x00, 0x00, 0x00, 0x00, 'I', 'E', 'N', 'D', 0xAE, 0x42, 0x60, 0x82
};
#endif
#if defined(USE_WINDOWS_GDIPLUS)
BYTE iendWithLength[] = {
/* Signature */ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
/* IHDR */ 0x00, 0x00, 0x00, 0x0D, 'I', 'H', 'D', 'R', 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x40, 0x69, 0xC9, 0xB2,
/* IDAT */ 0x00, 0x00, 0x00, 0x0A, 'I', 'D', 'A', 'T', 0x18, 0xD3, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x98, 0x63, 0x6C, 0xD7,
/* IEND */ 0x00, 0x00, 0x00, 0x01, 'I', 'E', 'N', 'D', 0x00, 0xAE, 0x42, 0x60, 0x82,
/* sRGB */ 0x00, 0x00, 0x00, 0x01, 's', 'R', 'G', 'B', 0xFF, 0xAE, 0xCE, 0x1C, 0xE9
};
#endif
// FIXME: GDI+ allows long IHDR lengths.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (longIhdrLength, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ allows multiple IHDRs.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (multipleIhdrs, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
//FIXME: GDI+ allows multiple IDATs.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (multipleIdats, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ allows empty IDATs.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (oneEmptyIdat, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ allows multiple palettes
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (multiplePalettes, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
createFileSuccess (noIend, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (invalidCrc, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ does not validate the compression.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (invalidCompression, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (unknownChunk, PixelFormat4bppIndexed, 6, 4, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
// FIXME: GDI+ does not validate the CRC.
#if defined(USE_WINDOWS_GDIPLUS)
createFileSuccess (iendWithLength, PixelFormat1bppIndexed, 1, 1, ImageFlagsColorSpaceRGB | ImageFlagsHasRealPixelSize | ImageFlagsReadOnly, 3);
#endif
This may not be possible as we rely on libpng
In test_setImageAttributesToIdentity
in testimageattributes.c
// FIXME: GdipSetImageAttributesToIdentity is NotImplemented.
#if defined(USE_WINDOWS_GDIPLUS)
status = GdipSetImageAttributesToIdentity (attributes, ColorAdjustTypeDefault);
assertEqualInt (status, Ok);
status = GdipSetImageAttributesToIdentity (attributes, ColorAdjustTypeBitmap);
assertEqualInt (status, Ok);
status = GdipSetImageAttributesToIdentity (attributes, ColorAdjustTypeBrush);
assertEqualInt (status, Ok);
status = GdipSetImageAttributesToIdentity (attributes, ColorAdjustTypePen);
assertEqualInt (status, Ok);
status = GdipSetImageAttributesToIdentity (attributes, ColorAdjustTypeText);
assertEqualInt (status, Ok);
#endif
In test_loadImageFromFileBmp
in testgpimage.c
static void test_loadImageFromFileBmp ()
{
GpImage *image = getImage ("test.bmp");
// FIXME: bmp image flags are wrong in libgdiplus.
verifyBitmap (image, bmpRawFormat, PixelFormat24bppRGB, 100, 68, 77840, 0, FALSE);
GdipDisposeImage (image);
}
In test_cloneImage
in testgpimage.c
// ImageTypeBitmap - bmp.
status = GdipCloneImage (bitmapImage, &clonedImage);
assertEqualInt (status, Ok);
assert (clonedImage && clonedImage != bitmapImage);
// FIXME: bmp image flags are wrong in libgdiplus.
verifyBitmap (clonedImage, bmpRawFormat, PixelFormat24bppRGB, 100, 68, 77840, 0, FALSE);
GdipDisposeImage (clonedImage);
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.