gdiplus: Add partial support for GdipDrawImagePointsRect on metafile.
Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Vincent Povirk <vincent@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1a75f763db
commit
e1e4dd2023
|
@ -82,6 +82,7 @@ extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace d
|
|||
GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
|
||||
|
||||
extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
|
||||
extern GpStatus encode_image_png(GpImage *image, IStream* stream, GDIPCONST EncoderParameters* params) DECLSPEC_HIDDEN;
|
||||
|
||||
extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
|
||||
extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
|
||||
|
@ -105,6 +106,10 @@ extern GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) DE
|
|||
extern GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
|
||||
extern GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
|
||||
extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
|
||||
extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *image,
|
||||
GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
|
||||
REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
|
||||
DrawImageAbort callback, VOID *callbackData) DECLSPEC_HIDDEN;
|
||||
|
||||
extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
|
||||
REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -2872,6 +2872,13 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
|
|||
TRACE("%s %s %s\n", debugstr_pointf(&points[0]), debugstr_pointf(&points[1]),
|
||||
debugstr_pointf(&points[2]));
|
||||
|
||||
if (graphics->image && graphics->image->type == ImageTypeMetafile)
|
||||
{
|
||||
return METAFILE_DrawImagePointsRect((GpMetafile*)graphics->image,
|
||||
image, points, count, srcx, srcy, srcwidth, srcheight,
|
||||
srcUnit, imageAttributes, callback, callbackData);
|
||||
}
|
||||
|
||||
memcpy(ptf, points, 3 * sizeof(GpPointF));
|
||||
|
||||
/* Ensure source width/height is positive */
|
||||
|
|
|
@ -4527,7 +4527,7 @@ static GpStatus encode_image_tiff(GpImage *image, IStream* stream,
|
|||
return encode_image_wic(image, stream, &GUID_ContainerFormatTiff, params);
|
||||
}
|
||||
|
||||
static GpStatus encode_image_png(GpImage *image, IStream* stream,
|
||||
GpStatus encode_image_png(GpImage *image, IStream* stream,
|
||||
GDIPCONST EncoderParameters* params)
|
||||
{
|
||||
return encode_image_wic(image, stream, &GUID_ContainerFormatPng, params);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
|
||||
|
@ -156,6 +157,99 @@ typedef struct container
|
|||
GpRegion *clip;
|
||||
} container;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BitmapDataTypePixel,
|
||||
BitmapDataTypeCompressed,
|
||||
} BitmapDataType;
|
||||
|
||||
typedef struct EmfPlusBitmap
|
||||
{
|
||||
DWORD Width;
|
||||
DWORD Height;
|
||||
DWORD Stride;
|
||||
DWORD PixelFormat;
|
||||
DWORD Type;
|
||||
BYTE BitmapData[1];
|
||||
} EmfPlusBitmap;
|
||||
|
||||
typedef struct EmfPlusMetafile
|
||||
{
|
||||
DWORD Type;
|
||||
DWORD MetafileDataSize;
|
||||
BYTE MetafileData[1];
|
||||
} EmfPlusMetafile;
|
||||
|
||||
typedef enum ImageDataType
|
||||
{
|
||||
ImageDataTypeUnknown,
|
||||
ImageDataTypeBitmap,
|
||||
ImageDataTypeMetafile,
|
||||
} ImageDataType;
|
||||
|
||||
typedef struct EmfPlusImage
|
||||
{
|
||||
DWORD Version;
|
||||
ImageDataType Type;
|
||||
union
|
||||
{
|
||||
EmfPlusBitmap bitmap;
|
||||
EmfPlusMetafile metafile;
|
||||
} ImageData;
|
||||
} EmfPlusImage;
|
||||
|
||||
typedef enum ObjectType
|
||||
{
|
||||
ObjectTypeInvalid,
|
||||
ObjectTypeBrush,
|
||||
ObjectTypePen,
|
||||
ObjectTypePath,
|
||||
ObjectTypeRegion,
|
||||
ObjectTypeImage,
|
||||
ObjectTypeFont,
|
||||
ObjectTypeStringFormat,
|
||||
ObjectTypeImageAttributes,
|
||||
ObjectTypeCustomLineCap,
|
||||
} ObjectType;
|
||||
|
||||
typedef struct EmfPlusObject
|
||||
{
|
||||
EmfPlusRecordHeader Header;
|
||||
union
|
||||
{
|
||||
EmfPlusImage image;
|
||||
} ObjectData;
|
||||
} EmfPlusObject;
|
||||
|
||||
typedef struct EmfPlusRectF
|
||||
{
|
||||
float X;
|
||||
float Y;
|
||||
float Width;
|
||||
float Height;
|
||||
} EmfPlusRectF;
|
||||
|
||||
typedef struct EmfPlusPointF
|
||||
{
|
||||
float X;
|
||||
float Y;
|
||||
} EmfPlusPointF;
|
||||
|
||||
typedef struct EmfPlusDrawImagePoints
|
||||
{
|
||||
EmfPlusRecordHeader Header;
|
||||
DWORD ImageAttributesID;
|
||||
DWORD SrcUnit;
|
||||
EmfPlusRectF SrcRect;
|
||||
DWORD count;
|
||||
union
|
||||
{
|
||||
/*EmfPlusPointR pointR;
|
||||
EmfPlusPoint point;*/
|
||||
EmfPlusPointF pointF;
|
||||
} PointData[3];
|
||||
} EmfPlusDrawImagePoints;
|
||||
|
||||
static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
|
||||
{
|
||||
DWORD size_needed;
|
||||
|
@ -202,6 +296,12 @@ static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void *
|
|||
return Ok;
|
||||
}
|
||||
|
||||
static void METAFILE_RemoveLastRecord(GpMetafile *metafile, EmfPlusRecordHeader *record)
|
||||
{
|
||||
assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size);
|
||||
metafile->comment_data_length -= record->Size;
|
||||
}
|
||||
|
||||
static void METAFILE_WriteRecords(GpMetafile *metafile)
|
||||
{
|
||||
if (metafile->comment_data_length > 4)
|
||||
|
@ -2209,3 +2309,147 @@ GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
|
|||
FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
static GpStatus METAFILE_CreateCompressedImageStream(GpImage *image, IStream **stream, DWORD *size)
|
||||
{
|
||||
LARGE_INTEGER zero;
|
||||
STATSTG statstg;
|
||||
GpStatus stat;
|
||||
HRESULT hr;
|
||||
|
||||
*size = 0;
|
||||
|
||||
hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
|
||||
if (FAILED(hr)) return hresult_to_status(hr);
|
||||
|
||||
stat = encode_image_png(image, *stream, NULL);
|
||||
if (stat != Ok)
|
||||
{
|
||||
IStream_Release(*stream);
|
||||
return stat;
|
||||
}
|
||||
|
||||
hr = IStream_Stat(*stream, &statstg, 1);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
IStream_Release(*stream);
|
||||
return hresult_to_status(hr);
|
||||
}
|
||||
*size = statstg.cbSize.u.LowPart;
|
||||
|
||||
zero.QuadPart = 0;
|
||||
hr = IStream_Seek(*stream, zero, STREAM_SEEK_SET, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
IStream_Release(*stream);
|
||||
return hresult_to_status(hr);
|
||||
}
|
||||
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static GpStatus METAFILE_FillEmfPlusBitmap(EmfPlusBitmap *record, IStream *stream, DWORD size)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
record->Width = 0;
|
||||
record->Height = 0;
|
||||
record->Stride = 0;
|
||||
record->PixelFormat = 0;
|
||||
record->Type = BitmapDataTypeCompressed;
|
||||
|
||||
hr = IStream_Read(stream, record->BitmapData, size, NULL);
|
||||
if (FAILED(hr)) return hresult_to_status(hr);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
static GpStatus METAFILE_AddImageObject(GpMetafile *metafile, GpImage *image)
|
||||
{
|
||||
if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
|
||||
return Ok;
|
||||
|
||||
if (image->type == ImageTypeBitmap)
|
||||
{
|
||||
EmfPlusObject *object_record;
|
||||
IStream *stream;
|
||||
DWORD size, aligned_size;
|
||||
GpStatus stat;
|
||||
|
||||
stat = METAFILE_CreateCompressedImageStream(image, &stream, &size);
|
||||
if (stat != Ok) return stat;
|
||||
aligned_size = (size + 3) & ~3;
|
||||
|
||||
stat = METAFILE_AllocateRecord(metafile,
|
||||
FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.bitmap.BitmapData[aligned_size]),
|
||||
(void**)&object_record);
|
||||
if (stat != Ok)
|
||||
{
|
||||
IStream_Release(stream);
|
||||
return stat;
|
||||
}
|
||||
memset(object_record->ObjectData.image.ImageData.bitmap.BitmapData + size, 0, aligned_size - size);
|
||||
|
||||
object_record->Header.Type = EmfPlusRecordTypeObject;
|
||||
object_record->Header.Flags = ObjectTypeImage << 8;
|
||||
object_record->ObjectData.image.Version = 0xDBC01002;
|
||||
object_record->ObjectData.image.Type = ImageDataTypeBitmap;
|
||||
|
||||
stat = METAFILE_FillEmfPlusBitmap(&object_record->ObjectData.image.ImageData.bitmap, stream, size);
|
||||
IStream_Release(stream);
|
||||
if (stat != Ok) METAFILE_RemoveLastRecord(metafile, &object_record->Header);
|
||||
return stat;
|
||||
}
|
||||
else
|
||||
{
|
||||
FIXME("not supported image type (%d)\n", image->type);
|
||||
return NotImplemented;
|
||||
}
|
||||
}
|
||||
|
||||
GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage *image,
|
||||
GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
|
||||
REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
|
||||
DrawImageAbort callback, VOID *callbackData)
|
||||
{
|
||||
EmfPlusDrawImagePoints *draw_image_record;
|
||||
GpStatus stat;
|
||||
|
||||
if (count != 3) return InvalidParameter;
|
||||
|
||||
if (metafile->metafile_type == MetafileTypeEmf)
|
||||
{
|
||||
FIXME("MetafileTypeEmf metafiles not supported\n");
|
||||
return NotImplemented;
|
||||
}
|
||||
else
|
||||
FIXME("semi-stub\n");
|
||||
|
||||
if (imageAttributes)
|
||||
{
|
||||
FIXME("ImageAttributes != NULL not supported\n");
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
stat = METAFILE_AddImageObject(metafile, image);
|
||||
if (stat != Ok) return stat;
|
||||
|
||||
stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawImagePoints), (void**)&draw_image_record);
|
||||
if (stat != Ok) return stat;
|
||||
draw_image_record->Header.Type = EmfPlusRecordTypeDrawImagePoints;
|
||||
draw_image_record->Header.Flags = 0;
|
||||
draw_image_record->ImageAttributesID = -1;
|
||||
draw_image_record->SrcUnit = UnitPixel;
|
||||
draw_image_record->SrcRect.X = units_to_pixels(srcx, srcUnit, metafile->image.xres);
|
||||
draw_image_record->SrcRect.Y = units_to_pixels(srcy, srcUnit, metafile->image.yres);
|
||||
draw_image_record->SrcRect.Width = units_to_pixels(srcwidth, srcUnit, metafile->image.xres);
|
||||
draw_image_record->SrcRect.Height = units_to_pixels(srcheight, srcUnit, metafile->image.yres);
|
||||
draw_image_record->count = 3;
|
||||
draw_image_record->PointData[0].pointF.X = points[0].X;
|
||||
draw_image_record->PointData[0].pointF.Y = points[0].Y;
|
||||
draw_image_record->PointData[1].pointF.X = points[1].X;
|
||||
draw_image_record->PointData[1].pointF.Y = points[1].Y;
|
||||
draw_image_record->PointData[2].pointF.X = points[2].X;
|
||||
draw_image_record->PointData[2].pointF.Y = points[2].Y;
|
||||
METAFILE_WriteRecords(metafile);
|
||||
return Ok;
|
||||
}
|
||||
|
|
|
@ -2325,8 +2325,8 @@ static void test_gditransform(void)
|
|||
static const emfplus_record draw_image_records[] = {
|
||||
{0, EMR_HEADER},
|
||||
{0, EmfPlusRecordTypeHeader},
|
||||
{1, EmfPlusRecordTypeObject},
|
||||
{1, EmfPlusRecordTypeDrawImagePoints},
|
||||
{0, EmfPlusRecordTypeObject},
|
||||
{0, EmfPlusRecordTypeDrawImagePoints},
|
||||
{1, EMR_SAVEDC},
|
||||
{1, EMR_SETICMMODE},
|
||||
{1, EMR_BITBLT},
|
||||
|
@ -2384,6 +2384,7 @@ static void test_drawimage(void)
|
|||
expect(Ok, stat);
|
||||
|
||||
check_emfplus(hemf, draw_image_records, "draw image");
|
||||
DeleteEnhMetaFile(hemf);
|
||||
|
||||
stat = GdipDisposeImage((GpImage*)metafile);
|
||||
expect(Ok, stat);
|
||||
|
|
Loading…
Reference in New Issue