/*
* Copyright (C) 2007 Google (Evan Stade)
+ * Copyright (C) 2012 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*/
#include <stdarg.h>
+#include <assert.h>
#define NONAMELESSUNION
#define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
+static const struct
+{
+ const WICPixelFormatGUID *wic_format;
+ PixelFormat gdip_format;
+ /* predefined palette type to use for pixel format conversions */
+ WICBitmapPaletteType palette_type;
+} pixel_formats[] =
+{
+ { &GUID_WICPixelFormatBlackWhite, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
+ { &GUID_WICPixelFormat1bppIndexed, PixelFormat1bppIndexed, WICBitmapPaletteTypeFixedBW },
+ { &GUID_WICPixelFormat8bppGray, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedGray256 },
+ { &GUID_WICPixelFormat8bppIndexed, PixelFormat8bppIndexed, WICBitmapPaletteTypeFixedHalftone256 },
+ { &GUID_WICPixelFormat16bppBGR555, PixelFormat16bppRGB555, WICBitmapPaletteTypeFixedHalftone256 },
+ { &GUID_WICPixelFormat24bppBGR, PixelFormat24bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
+ { &GUID_WICPixelFormat32bppBGR, PixelFormat32bppRGB, WICBitmapPaletteTypeFixedHalftone256 },
+ { &GUID_WICPixelFormat32bppBGRA, PixelFormat32bppARGB, WICBitmapPaletteTypeFixedHalftone256 },
+ { &GUID_WICPixelFormat32bppPBGRA, PixelFormat32bppPARGB, WICBitmapPaletteTypeFixedHalftone256 },
+ { NULL }
+};
+
+static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteType palette_type)
+{
+ HRESULT hr;
+ IWICImagingFactory *factory;
+ IWICPalette *wic_palette;
+ ColorPalette *palette = NULL;
+
+ hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IWICImagingFactory, (void **)&factory);
+ if (hr != S_OK) return NULL;
+
+ hr = IWICImagingFactory_CreatePalette(factory, &wic_palette);
+ if (hr == S_OK)
+ {
+ hr = WINCODEC_ERR_PALETTEUNAVAILABLE;
+ if (frame)
+ hr = IWICBitmapFrameDecode_CopyPalette(frame, wic_palette);
+ if (hr != S_OK)
+ {
+ TRACE("using predefined palette %#x\n", palette_type);
+ hr = IWICPalette_InitializePredefined(wic_palette, palette_type, FALSE);
+ }
+ if (hr == S_OK)
+ {
+ UINT count;
+ BOOL mono, gray;
+
+ IWICPalette_IsBlackWhite(wic_palette, &mono);
+ IWICPalette_IsGrayscale(wic_palette, &gray);
+
+ IWICPalette_GetColorCount(wic_palette, &count);
+ palette = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(UINT) + count * sizeof(ARGB));
+ IWICPalette_GetColors(wic_palette, count, palette->Entries, &palette->Count);
+
+ if (mono)
+ palette->Flags = 0;
+ else if (gray)
+ palette->Flags = PaletteFlagsGrayScale;
+ else
+ palette->Flags = PaletteFlagsHalftone;
+ }
+ IWICPalette_Release(wic_palette);
+ }
+ IWICImagingFactory_Release(factory);
+ return palette;
+}
+
static INT ipicture_pixel_height(IPicture *pic)
{
HDC hdcref;
}
if (bitmap->format & PixelFormatIndexed)
- *color = bitmap->image.palette_entries[index];
+ *color = bitmap->image.palette->Entries[index];
else
*color = a<<24|r<<16|g<<8|b;
return Ok;
}
-static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, GpBitmap* bitmap) {
+static inline UINT get_palette_index(BYTE r, BYTE g, BYTE b, BYTE a, ColorPalette *palette)
+{
BYTE index = 0;
int best_distance = 0x7fff;
int distance;
int i;
+
+ if (!palette) return 0;
/* This algorithm scans entire palette,
computes difference from desired color (all color components have equal weight)
and returns the index of color with least difference.
tables and thus may actually be slower if this method is called only few times per
every image.
*/
- for(i=0;i<bitmap->image.palette_size;i++) {
- ARGB color=bitmap->image.palette_entries[i];
+ for(i=0;i<palette->Count;i++) {
+ ARGB color=palette->Entries[i];
distance=abs(b-(color & 0xff)) + abs(g-(color>>8 & 0xff)) + abs(r-(color>>16 & 0xff)) + abs(a-(color>>24 & 0xff));
if (distance<best_distance) {
best_distance=distance;
}
static inline void setpixel_8bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
- BYTE *row, UINT x, GpBitmap* bitmap)
+ BYTE *row, UINT x, ColorPalette *palette)
{
- BYTE index = get_palette_index(r,g,b,a,bitmap);
+ BYTE index = get_palette_index(r,g,b,a,palette);
row[x]=index;
}
static inline void setpixel_1bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
- BYTE *row, UINT x, GpBitmap* bitmap)
+ BYTE *row, UINT x, ColorPalette *palette)
{
- row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,bitmap)<<(7-x%8));
+ row[x/8] = (row[x/8] & ~(1<<(7-x%8))) | (get_palette_index(r,g,b,a,palette)<<(7-x%8));
}
static inline void setpixel_4bppIndexed(BYTE r, BYTE g, BYTE b, BYTE a,
- BYTE *row, UINT x, GpBitmap* bitmap)
+ BYTE *row, UINT x, ColorPalette *palette)
{
if (x & 1)
- row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,bitmap);
+ row[x/2] = (row[x/2] & 0xf0) | get_palette_index(r,g,b,a,palette);
else
- row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,bitmap)<<4;
+ row[x/2] = (row[x/2] & 0x0f) | get_palette_index(r,g,b,a,palette)<<4;
}
static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
setpixel_64bppPARGB(r,g,b,a,row,x);
break;
case PixelFormat8bppIndexed:
- setpixel_8bppIndexed(r,g,b,a,row,x,bitmap);
+ setpixel_8bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
break;
case PixelFormat4bppIndexed:
- setpixel_4bppIndexed(r,g,b,a,row,x,bitmap);
+ setpixel_4bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
break;
case PixelFormat1bppIndexed:
- setpixel_1bppIndexed(r,g,b,a,row,x,bitmap);
+ setpixel_1bppIndexed(r,g,b,a,row,x,bitmap->image.palette);
break;
default:
FIXME("not implemented for format 0x%x\n", bitmap->format);
GpStatus convert_pixels(INT width, INT height,
INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
- INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette)
+ INT src_stride, const BYTE *src_bits, PixelFormat src_format,
+ ColorPalette *palette)
{
INT x, y;
for (x=0; x<width; x++) \
for (y=0; y<height; y++) { \
BYTE index; \
- BYTE *color; \
+ ARGB argb; \
+ BYTE *color = (BYTE *)&argb; \
getpixel_function(&index, src_bits+src_stride*y, x); \
- color = (BYTE*)(&src_palette[index]); \
+ argb = (palette && index < palette->Count) ? palette->Entries[index] : 0; \
setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
} \
return Ok; \
return Ok; \
} while (0);
+#define convert_rgb_to_indexed(getpixel_function, setpixel_function) do { \
+ for (x=0; x<width; x++) \
+ for (y=0; y<height; y++) { \
+ BYTE r, g, b, a; \
+ getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
+ setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x, palette); \
+ } \
+ return Ok; \
+} while (0);
+
switch (src_format)
{
case PixelFormat1bppIndexed:
case PixelFormat16bppGrayScale:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppGrayScale, setpixel_8bppIndexed);
case PixelFormat16bppRGB555:
convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
case PixelFormat16bppRGB565:
case PixelFormat16bppRGB555:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppRGB555, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
case PixelFormat16bppRGB565:
case PixelFormat16bppRGB565:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppRGB565, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat16bppARGB1555:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_16bppARGB1555, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat24bppRGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_24bppRGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat32bppRGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppRGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat32bppARGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppARGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat32bppPARGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_32bppPARGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat48bppRGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_48bppRGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat64bppARGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_64bppARGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
case PixelFormat64bppPARGB:
switch (dst_format)
{
+ case PixelFormat1bppIndexed:
+ convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_1bppIndexed);
+ case PixelFormat8bppIndexed:
+ convert_rgb_to_indexed(getpixel_64bppPARGB, setpixel_8bppIndexed);
case PixelFormat16bppGrayScale:
convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
case PixelFormat16bppRGB555:
lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
bitmap->stride * act_rect.Y;
- bitmap->lockmode = flags;
+ bitmap->lockmode = flags | ImageLockModeRead;
bitmap->numlocks++;
return Ok;
lockeddata->Stride, lockeddata->Scan0, format,
bitmap->stride,
bitmap->bits + bitmap->stride * act_rect.Y + PIXELFORMATBPP(bitmap->format) * act_rect.X / 8,
- bitmap->format, bitmap->image.palette_entries);
+ bitmap->format, bitmap->image.palette);
if (stat != Ok)
{
}
}
- bitmap->lockmode = flags;
+ bitmap->lockmode = flags | ImageLockModeRead;
bitmap->numlocks++;
bitmap->lockx = act_rect.X;
bitmap->locky = act_rect.Y;
if (format == PixelFormatDontCare)
format = srcBitmap->format;
- area.X = roundr(x);
- area.Y = roundr(y);
- area.Width = roundr(width);
- area.Height = roundr(height);
+ area.X = gdip_round(x);
+ area.Y = gdip_round(y);
+ area.Width = gdip_round(width);
+ area.Height = gdip_round(height);
stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
&lockeddata_src);
return stat;
}
+ else if (image->type == ImageTypeMetafile && ((GpMetafile*)image)->hemf)
+ {
+ GpMetafile *result, *metafile;
+
+ metafile = (GpMetafile*)image;
+
+ result = GdipAlloc(sizeof(*result));
+ if (!result)
+ return OutOfMemory;
+
+ result->image.type = ImageTypeMetafile;
+ result->image.format = image->format;
+ result->image.flags = image->flags;
+ result->image.frame_count = 1;
+ result->image.xres = image->xres;
+ result->image.yres = image->yres;
+ result->bounds = metafile->bounds;
+ result->unit = metafile->unit;
+ result->metafile_type = metafile->metafile_type;
+ result->hemf = CopyEnhMetaFileW(metafile->hemf, NULL);
+
+ if (!result->hemf)
+ {
+ GdipFree(result);
+ return OutOfMemory;
+ }
+
+ *cloneImage = &result->image;
+ return Ok;
+ }
else
{
- ERR("GpImage with no IPicture or bitmap?!\n");
- return NotImplemented;
+ WARN("GpImage with no image data (metafile in wrong state?)\n");
+ return InvalidParameter;
}
}
(*bitmap)->image.type = ImageTypeBitmap;
memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
(*bitmap)->image.flags = ImageFlagsNone;
- (*bitmap)->image.palette_flags = 0;
- (*bitmap)->image.palette_count = 0;
- (*bitmap)->image.palette_size = 0;
- (*bitmap)->image.palette_entries = NULL;
+ (*bitmap)->image.frame_count = 1;
+ (*bitmap)->image.current_frame = 0;
+ (*bitmap)->image.palette = NULL;
(*bitmap)->image.xres = xres;
(*bitmap)->image.yres = yres;
(*bitmap)->width = width;
(*bitmap)->height = height;
(*bitmap)->format = format;
(*bitmap)->image.picture = NULL;
+ (*bitmap)->image.stream = NULL;
(*bitmap)->hbitmap = hbitmap;
(*bitmap)->hdc = NULL;
(*bitmap)->bits = bits;
(*bitmap)->stride = stride;
(*bitmap)->own_bits = own_bits;
+ (*bitmap)->metadata_reader = NULL;
+ (*bitmap)->prop_count = 0;
+ (*bitmap)->prop_item = NULL;
/* set format-related flags */
if (format & (PixelFormatAlpha|PixelFormatPAlpha|PixelFormatIndexed))
format == PixelFormat4bppIndexed ||
format == PixelFormat8bppIndexed)
{
- (*bitmap)->image.palette_size = (*bitmap)->image.palette_count = 1 << PIXELFORMATBPP(format);
- (*bitmap)->image.palette_entries = GdipAlloc(sizeof(ARGB) * ((*bitmap)->image.palette_size));
+ (*bitmap)->image.palette = GdipAlloc(sizeof(UINT) * 2 + sizeof(ARGB) * (1 << PIXELFORMATBPP(format)));
- if (!(*bitmap)->image.palette_entries)
+ if (!(*bitmap)->image.palette)
{
GdipDisposeImage(&(*bitmap)->image);
*bitmap = NULL;
return OutOfMemory;
}
+ (*bitmap)->image.palette->Count = 1 << PIXELFORMATBPP(format);
+
if (format == PixelFormat1bppIndexed)
{
- (*bitmap)->image.palette_flags = PaletteFlagsGrayScale;
- (*bitmap)->image.palette_entries[0] = 0xff000000;
- (*bitmap)->image.palette_entries[1] = 0xffffffff;
+ (*bitmap)->image.palette->Flags = PaletteFlagsGrayScale;
+ (*bitmap)->image.palette->Entries[0] = 0xff000000;
+ (*bitmap)->image.palette->Entries[1] = 0xffffffff;
}
else
{
if (format == PixelFormat8bppIndexed)
- (*bitmap)->image.palette_flags = PaletteFlagsHalftone;
+ (*bitmap)->image.palette->Flags = PaletteFlagsHalftone;
- generate_halftone_palette((*bitmap)->image.palette_entries,
- (*bitmap)->image.palette_count);
+ generate_halftone_palette((*bitmap)->image.palette->Entries,
+ (*bitmap)->image.palette->Count);
}
}
* and free src. */
static void move_bitmap(GpBitmap *dst, GpBitmap *src, BOOL clobber_palette)
{
+ assert(src->image.type == ImageTypeBitmap);
+ assert(dst->image.type == ImageTypeBitmap);
+
GdipFree(dst->bitmapbits);
+ GdipFree(dst->own_bits);
DeleteDC(dst->hdc);
DeleteObject(dst->hbitmap);
if (clobber_palette)
{
- GdipFree(dst->image.palette_entries);
- dst->image.palette_flags = src->image.palette_flags;
- dst->image.palette_count = src->image.palette_count;
- dst->image.palette_entries = src->image.palette_entries;
+ GdipFree(dst->image.palette);
+ dst->image.palette = src->image.palette;
}
else
- GdipFree(src->image.palette_entries);
+ GdipFree(src->image.palette);
dst->image.xres = src->image.xres;
dst->image.yres = src->image.yres;
dst->bits = src->bits;
dst->stride = src->stride;
dst->own_bits = src->own_bits;
-
+ if (dst->metadata_reader)
+ IWICMetadataReader_Release(dst->metadata_reader);
+ dst->metadata_reader = src->metadata_reader;
+ GdipFree(dst->prop_item);
+ dst->prop_item = src->prop_item;
+ dst->prop_count = src->prop_count;
+ if (dst->image.stream)
+ IStream_Release(dst->image.stream);
+ dst->image.stream = src->image.stream;
+ dst->image.frame_count = src->image.frame_count;
+ dst->image.current_frame = src->image.current_frame;
+ dst->image.format = src->image.format;
+
+ src->image.type = ~0;
GdipFree(src);
}
-GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
+static GpStatus free_image_data(GpImage *image)
{
- TRACE("%p\n", image);
-
if(!image)
return InvalidParameter;
GdipFree(((GpBitmap*)image)->own_bits);
DeleteDC(((GpBitmap*)image)->hdc);
DeleteObject(((GpBitmap*)image)->hbitmap);
+ if (((GpBitmap*)image)->metadata_reader)
+ IWICMetadataReader_Release(((GpBitmap*)image)->metadata_reader);
+ GdipFree(((GpBitmap*)image)->prop_item);
}
else if (image->type == ImageTypeMetafile)
{
GpMetafile *metafile = (GpMetafile*)image;
GdipFree(metafile->comment_data);
DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
- DeleteEnhMetaFile(metafile->hemf);
+ if (!metafile->preserve_hemf)
+ DeleteEnhMetaFile(metafile->hemf);
if (metafile->record_graphics)
{
WARN("metafile closed while recording\n");
}
if (image->picture)
IPicture_Release(image->picture);
- GdipFree(image->palette_entries);
+ if (image->stream)
+ IStream_Release(image->stream);
+ GdipFree(image->palette);
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
+{
+ GpStatus status;
+
+ TRACE("%p\n", image);
+
+ status = free_image_data(image);
+ if (status != Ok) return status;
image->type = ~0;
GdipFree(image);
return InvalidParameter;
if(image->type == ImageTypeMetafile){
- HDC hdc = GetDC(0);
- REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
-
- ReleaseDC(0, hdc);
-
- *height = convert_unit(res, ((GpMetafile*)image)->unit) *
- ((GpMetafile*)image)->bounds.Height;
-
- *width = convert_unit(res, ((GpMetafile*)image)->unit) *
- ((GpMetafile*)image)->bounds.Width;
+ *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
+ *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
}
-
else if(image->type == ImageTypeBitmap){
*height = ((GpBitmap*)image)->height;
*width = ((GpBitmap*)image)->width;
stat = GdipCreateFromHDC(hdc, graphics);
if (stat == Ok)
+ {
(*graphics)->image = image;
+ (*graphics)->xres = image->xres;
+ (*graphics)->yres = image->yres;
+ }
}
else if (image->type == ImageTypeMetafile)
stat = METAFILE_GetGraphicsContext((GpMetafile*)image, graphics);
if(!image || !height)
return InvalidParameter;
- if(image->type == ImageTypeMetafile){
- HDC hdc = GetDC(0);
- REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
-
- ReleaseDC(0, hdc);
-
- *height = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
- ((GpMetafile*)image)->bounds.Height);
- }
+ if(image->type == ImageTypeMetafile)
+ *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit, image->yres);
else if(image->type == ImageTypeBitmap)
*height = ((GpBitmap*)image)->height;
else
if(!image || !size)
return InvalidParameter;
- if (image->palette_count == 0)
+ if (!image->palette || image->palette->Count == 0)
*size = sizeof(ColorPalette);
else
- *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette_count;
+ *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette->Count;
TRACE("<-- %u\n", *size);
if(!image || !width)
return InvalidParameter;
- if(image->type == ImageTypeMetafile){
- HDC hdc = GetDC(0);
- REAL res = (REAL)GetDeviceCaps(hdc, LOGPIXELSX);
-
- ReleaseDC(0, hdc);
-
- *width = roundr(convert_unit(res, ((GpMetafile*)image)->unit) *
- ((GpMetafile*)image)->bounds.Width);
- }
+ if(image->type == ImageTypeMetafile)
+ *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit, image->xres);
else if(image->type == ImageTypeBitmap)
*width = ((GpBitmap*)image)->width;
else
return Ok;
}
-GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
- UINT num, PropertyItem* items)
+GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT *num)
{
- static int calls;
-
- TRACE("(%p, %u, %u, %p)\n", image, size, num, items);
-
- if(!(calls++))
- FIXME("not implemented\n");
+ TRACE("(%p, %p)\n", image, num);
- return InvalidParameter;
-}
+ if (!image || !num) return InvalidParameter;
-GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
-{
- static int calls;
+ *num = 0;
- TRACE("(%p, %p)\n", image, num);
+ if (image->type == ImageTypeBitmap)
+ {
+ if (((GpBitmap *)image)->prop_item)
+ {
+ *num = ((GpBitmap *)image)->prop_count;
+ return Ok;
+ }
- if(!(calls++))
- FIXME("not implemented\n");
+ if (((GpBitmap *)image)->metadata_reader)
+ IWICMetadataReader_GetCount(((GpBitmap *)image)->metadata_reader, num);
+ }
- *num = 0;
return Ok;
}
-GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
+GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID *list)
{
- static int calls;
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ IWICEnumMetadataItem *enumerator;
+ UINT prop_count, i, items_returned;
TRACE("(%p, %u, %p)\n", image, num, list);
- if(!(calls++))
- FIXME("not implemented\n");
+ if (!image || !list) return InvalidParameter;
- return InvalidParameter;
-}
+ if (image->type != ImageTypeBitmap)
+ {
+ FIXME("Not implemented for type %d\n", image->type);
+ return NotImplemented;
+ }
-GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
- PropertyItem* buffer)
-{
- static int calls;
+ if (((GpBitmap *)image)->prop_item)
+ {
+ if (num != ((GpBitmap *)image)->prop_count) return InvalidParameter;
- TRACE("(%p, %u, %u, %p)\n", image, id, size, buffer);
+ for (i = 0; i < num; i++)
+ {
+ list[i] = ((GpBitmap *)image)->prop_item[i].id;
+ }
- if(!(calls++))
- FIXME("not implemented\n");
+ return Ok;
+ }
- return InvalidParameter;
-}
+ reader = ((GpBitmap *)image)->metadata_reader;
+ if (!reader)
+ {
+ if (num != 0) return InvalidParameter;
+ return Ok;
+ }
-GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
- UINT* size)
-{
- static int calls;
+ hr = IWICMetadataReader_GetCount(reader, &prop_count);
+ if (FAILED(hr)) return hresult_to_status(hr);
- TRACE("%p %x %p\n", image, pid, size);
+ if (num != prop_count) return InvalidParameter;
- if(!size || !image)
- return InvalidParameter;
+ hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
+ if (FAILED(hr)) return hresult_to_status(hr);
- if(!(calls++))
- FIXME("not implemented\n");
+ IWICEnumMetadataItem_Reset(enumerator);
- return NotImplemented;
-}
+ for (i = 0; i < num; i++)
+ {
+ PROPVARIANT id;
-GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
-{
- static int calls;
+ hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, NULL, &items_returned);
+ if (hr != S_OK) break;
- TRACE("(%p,%p,%p)\n", image, size, num);
+ if (id.vt != VT_UI2)
+ {
+ FIXME("not supported propvariant type for id: %u\n", id.vt);
+ list[i] = 0;
+ continue;
+ }
+ list[i] = id.u.uiVal;
+ }
- if(!(calls++))
- FIXME("not implemented\n");
+ IWICEnumMetadataItem_Release(enumerator);
- return InvalidParameter;
+ return hr == S_OK ? Ok : hresult_to_status(hr);
}
-struct image_format_dimension
+static UINT propvariant_size(PROPVARIANT *value)
{
- const GUID *format;
- const GUID *dimension;
-};
+ switch (value->vt & ~VT_VECTOR)
+ {
+ case VT_EMPTY:
+ return 0;
+ case VT_I1:
+ case VT_UI1:
+ if (!(value->vt & VT_VECTOR)) return 1;
+ return value->u.caub.cElems;
+ case VT_I2:
+ case VT_UI2:
+ if (!(value->vt & VT_VECTOR)) return 2;
+ return value->u.caui.cElems * 2;
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ if (!(value->vt & VT_VECTOR)) return 4;
+ return value->u.caul.cElems * 4;
+ case VT_I8:
+ case VT_UI8:
+ case VT_R8:
+ if (!(value->vt & VT_VECTOR)) return 8;
+ return value->u.cauh.cElems * 8;
+ case VT_LPSTR:
+ return value->u.pszVal ? strlen(value->u.pszVal) + 1 : 0;
+ case VT_BLOB:
+ return value->u.blob.cbSize;
+ default:
+ FIXME("not supported variant type %d\n", value->vt);
+ return 0;
+ }
+}
-static struct image_format_dimension image_format_dimensions[] =
+GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID propid, UINT *size)
{
- {&ImageFormatGIF, &FrameDimensionTime},
- {&ImageFormatIcon, &FrameDimensionResolution},
- {NULL}
-};
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ PROPVARIANT id, value;
-/* FIXME: Need to handle multi-framed images */
-GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
- GDIPCONST GUID* dimensionID, UINT* count)
-{
- static int calls;
+ TRACE("(%p,%#x,%p)\n", image, propid, size);
- TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
+ if (!size || !image) return InvalidParameter;
- if(!image || !count)
- return InvalidParameter;
+ if (image->type != ImageTypeBitmap)
+ {
+ FIXME("Not implemented for type %d\n", image->type);
+ return NotImplemented;
+ }
- if(!(calls++))
- FIXME("returning frame count of 1\n");
+ if (((GpBitmap *)image)->prop_item)
+ {
+ UINT i;
- *count = 1;
+ for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
+ {
+ if (propid == ((GpBitmap *)image)->prop_item[i].id)
+ {
+ *size = sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
+ return Ok;
+ }
+ }
+
+ return PropertyNotFound;
+ }
+
+ reader = ((GpBitmap *)image)->metadata_reader;
+ if (!reader) return PropertyNotFound;
+
+ id.vt = VT_UI2;
+ id.u.uiVal = propid;
+ hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
+ if (FAILED(hr)) return PropertyNotFound;
+
+ *size = propvariant_size(&value);
+ if (*size) *size += sizeof(PropertyItem);
+ PropVariantClear(&value);
return Ok;
}
-GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
- UINT* count)
+#ifndef PropertyTagTypeSByte
+#define PropertyTagTypeSByte 6
+#define PropertyTagTypeSShort 8
+#define PropertyTagTypeFloat 11
+#define PropertyTagTypeDouble 12
+#endif
+
+static UINT vt_to_itemtype(UINT vt)
{
- TRACE("(%p, %p)\n", image, count);
+ static const struct
+ {
+ UINT vt, type;
+ } vt2type[] =
+ {
+ { VT_I1, PropertyTagTypeSByte },
+ { VT_UI1, PropertyTagTypeByte },
+ { VT_I2, PropertyTagTypeSShort },
+ { VT_UI2, PropertyTagTypeShort },
+ { VT_I4, PropertyTagTypeSLONG },
+ { VT_UI4, PropertyTagTypeLong },
+ { VT_I8, PropertyTagTypeSRational },
+ { VT_UI8, PropertyTagTypeRational },
+ { VT_R4, PropertyTagTypeFloat },
+ { VT_R8, PropertyTagTypeDouble },
+ { VT_LPSTR, PropertyTagTypeASCII },
+ { VT_BLOB, PropertyTagTypeUndefined }
+ };
+ UINT i;
+ for (i = 0; i < sizeof(vt2type)/sizeof(vt2type[0]); i++)
+ {
+ if (vt2type[i].vt == vt) return vt2type[i].type;
+ }
+ FIXME("not supported variant type %u\n", vt);
+ return 0;
+}
- /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
+static GpStatus propvariant_to_item(PROPVARIANT *value, PropertyItem *item,
+ UINT size, PROPID id)
+{
+ UINT item_size, item_type;
- if(!image || !count)
+ item_size = propvariant_size(value);
+ if (size != item_size + sizeof(PropertyItem)) return InvalidParameter;
+
+ item_type = vt_to_itemtype(value->vt & ~VT_VECTOR);
+ if (!item_type) return InvalidParameter;
+
+ item->value = item + 1;
+
+ switch (value->vt & ~VT_VECTOR)
+ {
+ case VT_I1:
+ case VT_UI1:
+ if (!(value->vt & VT_VECTOR))
+ *(BYTE *)item->value = value->u.bVal;
+ else
+ memcpy(item->value, value->u.caub.pElems, item_size);
+ break;
+ case VT_I2:
+ case VT_UI2:
+ if (!(value->vt & VT_VECTOR))
+ *(USHORT *)item->value = value->u.uiVal;
+ else
+ memcpy(item->value, value->u.caui.pElems, item_size);
+ break;
+ case VT_I4:
+ case VT_UI4:
+ case VT_R4:
+ if (!(value->vt & VT_VECTOR))
+ *(ULONG *)item->value = value->u.ulVal;
+ else
+ memcpy(item->value, value->u.caul.pElems, item_size);
+ break;
+ case VT_I8:
+ case VT_UI8:
+ case VT_R8:
+ if (!(value->vt & VT_VECTOR))
+ *(ULONGLONG *)item->value = value->u.uhVal.QuadPart;
+ else
+ memcpy(item->value, value->u.cauh.pElems, item_size);
+ break;
+ case VT_LPSTR:
+ memcpy(item->value, value->u.pszVal, item_size);
+ break;
+ case VT_BLOB:
+ memcpy(item->value, value->u.blob.pBlobData, item_size);
+ break;
+ default:
+ FIXME("not supported variant type %d\n", value->vt);
return InvalidParameter;
+ }
- *count = 1;
+ item->length = item_size;
+ item->type = item_type;
+ item->id = id;
return Ok;
}
-GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
- GUID* dimensionIDs, UINT count)
+GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID propid, UINT size,
+ PropertyItem *buffer)
{
- int i;
- const GUID *result=NULL;
+ GpStatus stat;
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ PROPVARIANT id, value;
- TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
+ TRACE("(%p,%#x,%u,%p)\n", image, propid, size, buffer);
- if(!image || !dimensionIDs || count != 1)
- return InvalidParameter;
+ if (!image || !buffer) return InvalidParameter;
- for (i=0; image_format_dimensions[i].format; i++)
+ if (image->type != ImageTypeBitmap)
{
- if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
+ FIXME("Not implemented for type %d\n", image->type);
+ return NotImplemented;
+ }
+
+ if (((GpBitmap *)image)->prop_item)
+ {
+ UINT i;
+
+ for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
{
- result = image_format_dimensions[i].dimension;
- break;
+ if (propid == ((GpBitmap *)image)->prop_item[i].id)
+ {
+ if (size != sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length)
+ return InvalidParameter;
+
+ *buffer = ((GpBitmap *)image)->prop_item[i];
+ buffer->value = buffer + 1;
+ memcpy(buffer->value, ((GpBitmap *)image)->prop_item[i].value, buffer->length);
+ return Ok;
+ }
}
+
+ return PropertyNotFound;
}
- if (!result)
- result = &FrameDimensionPage;
+ reader = ((GpBitmap *)image)->metadata_reader;
+ if (!reader) return PropertyNotFound;
- memcpy(dimensionIDs, result, sizeof(GUID));
+ id.vt = VT_UI2;
+ id.u.uiVal = propid;
+ hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
+ if (FAILED(hr)) return PropertyNotFound;
- return Ok;
+ stat = propvariant_to_item(&value, buffer, size, propid);
+ PropVariantClear(&value);
+
+ return stat;
}
-GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
- GDIPCONST GUID* dimensionID, UINT frameidx)
+GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT *size, UINT *count)
{
- static int calls;
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ IWICEnumMetadataItem *enumerator;
+ UINT prop_count, prop_size, i;
+ PROPVARIANT id, value;
- TRACE("(%p, %s, %u)\n", image, debugstr_guid(dimensionID), frameidx);
+ TRACE("(%p,%p,%p)\n", image, size, count);
- if(!image || !dimensionID)
- return InvalidParameter;
+ if (!image || !size || !count) return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ if (image->type != ImageTypeBitmap)
+ {
+ FIXME("Not implemented for type %d\n", image->type);
+ return NotImplemented;
+ }
+
+ if (((GpBitmap *)image)->prop_item)
+ {
+ *count = ((GpBitmap *)image)->prop_count;
+ *size = 0;
+
+ for (i = 0; i < ((GpBitmap *)image)->prop_count; i++)
+ {
+ *size += sizeof(PropertyItem) + ((GpBitmap *)image)->prop_item[i].length;
+ }
+
+ return Ok;
+ }
+
+ reader = ((GpBitmap *)image)->metadata_reader;
+ if (!reader) return PropertyNotFound;
+
+ hr = IWICMetadataReader_GetCount(reader, &prop_count);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ IWICEnumMetadataItem_Reset(enumerator);
+
+ prop_size = 0;
+
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
+ for (i = 0; i < prop_count; i++)
+ {
+ UINT items_returned, item_size;
+
+ hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
+ if (hr != S_OK) break;
+
+ item_size = propvariant_size(&value);
+ if (item_size) prop_size += sizeof(PropertyItem) + item_size;
+
+ PropVariantClear(&id);
+ PropVariantClear(&value);
+ }
+
+ IWICEnumMetadataItem_Release(enumerator);
+
+ if (hr != S_OK) return PropertyNotFound;
+
+ *count = prop_count;
+ *size = prop_size;
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
+ UINT count, PropertyItem *buf)
+{
+ GpStatus status;
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ IWICEnumMetadataItem *enumerator;
+ UINT prop_count, prop_size, i;
+ PROPVARIANT id, value;
+ char *item_value;
+
+ TRACE("(%p,%u,%u,%p)\n", image, size, count, buf);
+
+ if (!image || !buf) return InvalidParameter;
+
+ if (image->type != ImageTypeBitmap)
+ {
+ FIXME("Not implemented for type %d\n", image->type);
+ return NotImplemented;
+ }
+
+ status = GdipGetPropertySize(image, &prop_size, &prop_count);
+ if (status != Ok) return status;
+
+ if (prop_count != count || prop_size != size) return InvalidParameter;
+
+ if (((GpBitmap *)image)->prop_item)
+ {
+ memcpy(buf, ((GpBitmap *)image)->prop_item, prop_size);
+
+ item_value = (char *)(buf + prop_count);
+
+ for (i = 0; i < prop_count; i++)
+ {
+ buf[i].value = item_value;
+ item_value += buf[i].length;
+ }
+
+ return Ok;
+ }
+
+ reader = ((GpBitmap *)image)->metadata_reader;
+ if (!reader) return PropertyNotFound;
+
+ hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ IWICEnumMetadataItem_Reset(enumerator);
+
+ item_value = (char *)(buf + prop_count);
+
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
+ for (i = 0; i < prop_count; i++)
+ {
+ PropertyItem *item;
+ UINT items_returned, item_size;
+
+ hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &items_returned);
+ if (hr != S_OK) break;
+
+ if (id.vt != VT_UI2)
+ {
+ FIXME("not supported propvariant type for id: %u\n", id.vt);
+ continue;
+ }
+
+ item_size = propvariant_size(&value);
+ if (item_size)
+ {
+ item = HeapAlloc(GetProcessHeap(), 0, item_size + sizeof(*item));
+
+ propvariant_to_item(&value, item, item_size + sizeof(*item), id.u.uiVal);
+ buf[i].id = item->id;
+ buf[i].type = item->type;
+ buf[i].length = item_size;
+ buf[i].value = item_value;
+ memcpy(item_value, item->value, item_size);
+ item_value += item_size;
+
+ HeapFree(GetProcessHeap(), 0, item);
+ }
+
+ PropVariantClear(&id);
+ PropVariantClear(&value);
+ }
+
+ IWICEnumMetadataItem_Release(enumerator);
+
+ if (hr != S_OK) return PropertyNotFound;
+
+ return Ok;
+}
+
+struct image_format_dimension
+{
+ const GUID *format;
+ const GUID *dimension;
+};
+
+static const struct image_format_dimension image_format_dimensions[] =
+{
+ {&ImageFormatGIF, &FrameDimensionTime},
+ {&ImageFormatIcon, &FrameDimensionResolution},
+ {NULL}
+};
+
+GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
+ GDIPCONST GUID* dimensionID, UINT* count)
+{
+ TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
+
+ if(!image || !count)
+ return InvalidParameter;
+
+ if (!dimensionID ||
+ IsEqualGUID(dimensionID, &image->format) ||
+ IsEqualGUID(dimensionID, &FrameDimensionPage) ||
+ IsEqualGUID(dimensionID, &FrameDimensionTime))
+ {
+ *count = image->frame_count;
+ return Ok;
+ }
+
+ return InvalidParameter;
+}
+
+GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
+ UINT* count)
+{
+ TRACE("(%p, %p)\n", image, count);
+
+ /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
+
+ if(!image || !count)
+ return InvalidParameter;
+
+ *count = 1;
+
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
+ GUID* dimensionIDs, UINT count)
+{
+ int i;
+ const GUID *result=NULL;
+
+ TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
+
+ if(!image || !dimensionIDs || count != 1)
+ return InvalidParameter;
+
+ for (i=0; image_format_dimensions[i].format; i++)
+ {
+ if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
+ {
+ result = image_format_dimensions[i].dimension;
+ break;
+ }
+ }
+
+ if (!result)
+ result = &FrameDimensionPage;
+
+ memcpy(dimensionIDs, result, sizeof(GUID));
return Ok;
}
return GdipLoadImageFromFile(filename, image);
}
-static const WICPixelFormatGUID *wic_pixel_formats[] = {
- &GUID_WICPixelFormat16bppBGR555,
- &GUID_WICPixelFormat24bppBGR,
- &GUID_WICPixelFormat32bppBGR,
- &GUID_WICPixelFormat32bppBGRA,
- &GUID_WICPixelFormat32bppPBGRA,
- NULL
-};
+static void add_property(GpBitmap *bitmap, PropertyItem *item)
+{
+ UINT prop_size, prop_count;
+ PropertyItem *prop_item;
-static const PixelFormat wic_gdip_formats[] = {
- PixelFormat16bppRGB555,
- PixelFormat24bppRGB,
- PixelFormat32bppRGB,
- PixelFormat32bppARGB,
- PixelFormat32bppPARGB,
-};
+ if (bitmap->prop_item == NULL)
+ {
+ prop_size = prop_count = 0;
+ prop_item = GdipAlloc(item->length + sizeof(PropertyItem));
+ if (!prop_item) return;
+ }
+ else
+ {
+ UINT i;
+ char *item_value;
+
+ GdipGetPropertySize((GpImage *)bitmap, &prop_size, &prop_count);
+
+ prop_item = GdipAlloc(prop_size + item->length + sizeof(PropertyItem));
+ if (!prop_item) return;
+ memcpy(prop_item, bitmap->prop_item, sizeof(PropertyItem) * bitmap->prop_count);
+ prop_size -= sizeof(PropertyItem) * bitmap->prop_count;
+ memcpy(prop_item + prop_count + 1, bitmap->prop_item + prop_count, prop_size);
+
+ item_value = (char *)(prop_item + prop_count + 1);
+
+ for (i = 0; i < prop_count; i++)
+ {
+ prop_item[i].value = item_value;
+ item_value += prop_item[i].length;
+ }
+ }
+
+ prop_item[prop_count].id = item->id;
+ prop_item[prop_count].type = item->type;
+ prop_item[prop_count].length = item->length;
+ prop_item[prop_count].value = (char *)(prop_item + prop_count + 1) + prop_size;
+ memcpy(prop_item[prop_count].value, item->value, item->length);
-static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
+ GdipFree(bitmap->prop_item);
+ bitmap->prop_item = prop_item;
+ bitmap->prop_count++;
+}
+
+static BOOL get_bool_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
+{
+ HRESULT hr;
+ GUID format;
+ PROPVARIANT id, value;
+ BOOL ret = FALSE;
+
+ IWICMetadataReader_GetMetadataFormat(reader, &format);
+ if (!IsEqualGUID(&format, guid)) return FALSE;
+
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
+ id.vt = VT_LPWSTR;
+ id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
+ if (!id.u.pwszVal) return FALSE;
+ lstrcpyW(id.u.pwszVal, prop_name);
+ hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
+ if (hr == S_OK && value.vt == VT_BOOL)
+ ret = value.u.boolVal;
+
+ PropVariantClear(&id);
+ PropVariantClear(&value);
+
+ return ret;
+}
+
+static PropertyItem *get_property(IWICMetadataReader *reader, const GUID *guid, const WCHAR *prop_name)
+{
+ HRESULT hr;
+ GUID format;
+ PROPVARIANT id, value;
+ PropertyItem *item = NULL;
+
+ IWICMetadataReader_GetMetadataFormat(reader, &format);
+ if (!IsEqualGUID(&format, guid)) return NULL;
+
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
+ id.vt = VT_LPWSTR;
+ id.u.pwszVal = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(prop_name) + 1) * sizeof(WCHAR));
+ if (!id.u.pwszVal) return NULL;
+ lstrcpyW(id.u.pwszVal, prop_name);
+ hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
+ if (hr == S_OK)
+ {
+ UINT item_size = propvariant_size(&value);
+ if (item_size)
+ {
+ item_size += sizeof(*item);
+ item = GdipAlloc(item_size);
+ if (propvariant_to_item(&value, item, item_size, 0) != Ok)
+ {
+ GdipFree(item);
+ item = NULL;
+ }
+ }
+ }
+
+ PropVariantClear(&id);
+ PropVariantClear(&value);
+
+ return item;
+}
+
+static PropertyItem *get_gif_comment(IWICMetadataReader *reader)
+{
+ static const WCHAR textentryW[] = { 'T','e','x','t','E','n','t','r','y',0 };
+ PropertyItem *comment;
+
+ comment = get_property(reader, &GUID_MetadataFormatGifComment, textentryW);
+ if (comment)
+ comment->id = PropertyTagExifUserComment;
+
+ return comment;
+}
+
+static PropertyItem *get_gif_loopcount(IWICMetadataReader *reader)
+{
+ static const WCHAR applicationW[] = { 'A','p','p','l','i','c','a','t','i','o','n',0 };
+ static const WCHAR dataW[] = { 'D','a','t','a',0 };
+ PropertyItem *appext = NULL, *appdata = NULL, *loop = NULL;
+
+ appext = get_property(reader, &GUID_MetadataFormatAPE, applicationW);
+ if (appext)
+ {
+ if (appext->type == PropertyTagTypeByte && appext->length == 11 &&
+ (!memcmp(appext->value, "NETSCAPE2.0", 11) || !memcmp(appext->value, "ANIMEXTS1.0", 11)))
+ {
+ appdata = get_property(reader, &GUID_MetadataFormatAPE, dataW);
+ if (appdata)
+ {
+ if (appdata->type == PropertyTagTypeByte && appdata->length == 4)
+ {
+ BYTE *data = appdata->value;
+ if (data[0] == 3 && data[1] == 1)
+ {
+ loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
+ if (loop)
+ {
+ loop->type = PropertyTagTypeShort;
+ loop->id = PropertyTagLoopCount;
+ loop->length = sizeof(SHORT);
+ loop->value = loop + 1;
+ *(SHORT *)loop->value = data[2] | (data[3] << 8);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ GdipFree(appext);
+ GdipFree(appdata);
+
+ return loop;
+}
+
+static PropertyItem *get_gif_background(IWICMetadataReader *reader)
+{
+ static const WCHAR backgroundW[] = { 'B','a','c','k','g','r','o','u','n','d','C','o','l','o','r','I','n','d','e','x',0 };
+ PropertyItem *background;
+
+ background = get_property(reader, &GUID_MetadataFormatLSD, backgroundW);
+ if (background)
+ background->id = PropertyTagIndexBackground;
+
+ return background;
+}
+
+static PropertyItem *get_gif_palette(IWICBitmapDecoder *decoder, IWICMetadataReader *reader)
+{
+ static const WCHAR global_flagW[] = { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 };
+ HRESULT hr;
+ IWICImagingFactory *factory;
+ IWICPalette *palette;
+ UINT count = 0;
+ WICColor colors[256];
+
+ if (!get_bool_property(reader, &GUID_MetadataFormatLSD, global_flagW))
+ return NULL;
+
+ hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IWICImagingFactory, (void **)&factory);
+ if (hr != S_OK) return NULL;
+
+ hr = IWICImagingFactory_CreatePalette(factory, &palette);
+ if (hr == S_OK)
+ {
+ hr = IWICBitmapDecoder_CopyPalette(decoder, palette);
+ if (hr == S_OK)
+ IWICPalette_GetColors(palette, 256, colors, &count);
+
+ IWICPalette_Release(palette);
+ }
+
+ IWICImagingFactory_Release(factory);
+
+ if (count)
+ {
+ PropertyItem *pal;
+ UINT i;
+ BYTE *rgb;
+
+ pal = GdipAlloc(sizeof(*pal) + count * 3);
+ if (!pal) return NULL;
+ pal->type = PropertyTagTypeByte;
+ pal->id = PropertyTagGlobalPalette;
+ pal->value = pal + 1;
+ pal->length = count * 3;
+
+ rgb = pal->value;
+
+ for (i = 0; i < count; i++)
+ {
+ rgb[i*3] = (colors[i] >> 16) & 0xff;
+ rgb[i*3 + 1] = (colors[i] >> 8) & 0xff;
+ rgb[i*3 + 2] = colors[i] & 0xff;
+ }
+
+ return pal;
+ }
+
+ return NULL;
+}
+
+static PropertyItem *get_gif_transparent_idx(IWICMetadataReader *reader)
+{
+ static const WCHAR transparency_flagW[] = { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 };
+ static const WCHAR colorW[] = { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 };
+ PropertyItem *index = NULL;
+
+ if (get_bool_property(reader, &GUID_MetadataFormatGCE, transparency_flagW))
+ {
+ index = get_property(reader, &GUID_MetadataFormatGCE, colorW);
+ if (index)
+ index->id = PropertyTagIndexTransparent;
+ }
+ return index;
+}
+
+static LONG get_gif_frame_delay(IWICBitmapFrameDecode *frame)
+{
+ static const WCHAR delayW[] = { 'D','e','l','a','y',0 };
+ HRESULT hr;
+ IWICMetadataBlockReader *block_reader;
+ IWICMetadataReader *reader;
+ UINT block_count, i;
+ PropertyItem *delay;
+ LONG value = 0;
+
+ hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
+ if (hr == S_OK)
+ {
+ hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
+ if (hr == S_OK)
+ {
+ for (i = 0; i < block_count; i++)
+ {
+ hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
+ if (hr == S_OK)
+ {
+ delay = get_property(reader, &GUID_MetadataFormatGCE, delayW);
+ if (delay)
+ {
+ if (delay->type == PropertyTagTypeShort && delay->length == 2)
+ value = *(SHORT *)delay->value;
+
+ GdipFree(delay);
+ }
+ IWICMetadataReader_Release(reader);
+ }
+ }
+ }
+ IWICMetadataBlockReader_Release(block_reader);
+ }
+
+ return value;
+}
+
+static void gif_metadata_reader(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT active_frame)
+{
+ HRESULT hr;
+ IWICBitmapFrameDecode *frame;
+ IWICMetadataBlockReader *block_reader;
+ IWICMetadataReader *reader;
+ UINT frame_count, block_count, i;
+ PropertyItem *delay = NULL, *comment = NULL, *background = NULL;
+ PropertyItem *transparent_idx = NULL, *loop = NULL, *palette = NULL;
+
+ IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
+ if (frame_count > 1)
+ {
+ delay = GdipAlloc(sizeof(*delay) + frame_count * sizeof(LONG));
+ if (delay)
+ {
+ LONG *value;
+
+ delay->type = PropertyTagTypeLong;
+ delay->id = PropertyTagFrameDelay;
+ delay->length = frame_count * sizeof(LONG);
+ delay->value = delay + 1;
+
+ value = delay->value;
+
+ for (i = 0; i < frame_count; i++)
+ {
+ hr = IWICBitmapDecoder_GetFrame(decoder, i, &frame);
+ if (hr == S_OK)
+ {
+ value[i] = get_gif_frame_delay(frame);
+ IWICBitmapFrameDecode_Release(frame);
+ }
+ else value[i] = 0;
+ }
+ }
+ }
+
+ hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&block_reader);
+ if (hr == S_OK)
+ {
+ hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
+ if (hr == S_OK)
+ {
+ for (i = 0; i < block_count; i++)
+ {
+ hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
+ if (hr == S_OK)
+ {
+ if (!comment)
+ comment = get_gif_comment(reader);
+
+ if (frame_count > 1 && !loop)
+ loop = get_gif_loopcount(reader);
+
+ if (!background)
+ background = get_gif_background(reader);
+
+ if (!palette)
+ palette = get_gif_palette(decoder, reader);
+
+ IWICMetadataReader_Release(reader);
+ }
+ }
+ }
+ IWICMetadataBlockReader_Release(block_reader);
+ }
+
+ if (frame_count > 1 && !loop)
+ {
+ loop = GdipAlloc(sizeof(*loop) + sizeof(SHORT));
+ if (loop)
+ {
+ loop->type = PropertyTagTypeShort;
+ loop->id = PropertyTagLoopCount;
+ loop->length = sizeof(SHORT);
+ loop->value = loop + 1;
+ *(SHORT *)loop->value = 1;
+ }
+ }
+
+ if (delay) add_property(bitmap, delay);
+ if (comment) add_property(bitmap, comment);
+ if (loop) add_property(bitmap, loop);
+ if (palette) add_property(bitmap, palette);
+ if (background) add_property(bitmap, background);
+
+ GdipFree(delay);
+ GdipFree(comment);
+ GdipFree(loop);
+ GdipFree(palette);
+ GdipFree(background);
+
+ /* Win7 gdiplus always returns transparent color index from frame 0 */
+ hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+ if (hr != S_OK) return;
+
+ hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader);
+ if (hr == S_OK)
+ {
+ hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count);
+ if (hr == S_OK)
+ {
+ for (i = 0; i < block_count; i++)
+ {
+ hr = IWICMetadataBlockReader_GetReaderByIndex(block_reader, i, &reader);
+ if (hr == S_OK)
+ {
+ if (!transparent_idx)
+ transparent_idx = get_gif_transparent_idx(reader);
+
+ IWICMetadataReader_Release(reader);
+ }
+ }
+ }
+ IWICMetadataBlockReader_Release(block_reader);
+ }
+
+ if (transparent_idx) add_property(bitmap, transparent_idx);
+ GdipFree(transparent_idx);
+
+ IWICBitmapFrameDecode_Release(frame);
+}
+
+typedef void (*metadata_reader_func)(GpBitmap *bitmap, IWICBitmapDecoder *decoder, UINT frame);
+
+static GpStatus decode_image_wic(IStream *stream, GDIPCONST CLSID *clsid,
+ UINT active_frame, metadata_reader_func metadata_reader, GpImage **image)
{
GpStatus status=Ok;
GpBitmap *bitmap;
IWICBitmapDecoder *decoder;
IWICBitmapFrameDecode *frame;
IWICBitmapSource *source=NULL;
+ IWICMetadataBlockReader *block_reader;
WICPixelFormatGUID wic_format;
PixelFormat gdip_format=0;
+ ColorPalette *palette = NULL;
+ WICBitmapPaletteType palette_type = WICBitmapPaletteTypeFixedHalftone256;
int i;
- UINT width, height;
+ UINT width, height, frame_count;
BitmapData lockeddata;
WICRect wrc;
HRESULT initresult;
+ TRACE("%p,%s,%u,%p\n", stream, wine_dbgstr_guid(clsid), active_frame, image);
+
initresult = CoInitialize(NULL);
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICBitmapDecoder, (void**)&decoder);
if (FAILED(hr)) goto end;
- hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
+ hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
if (SUCCEEDED(hr))
- hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+ {
+ IWICBitmapDecoder_GetFrameCount(decoder, &frame_count);
+ hr = IWICBitmapDecoder_GetFrame(decoder, active_frame, &frame);
+ }
if (SUCCEEDED(hr)) /* got frame */
{
if (SUCCEEDED(hr))
{
- for (i=0; wic_pixel_formats[i]; i++)
+ IWICBitmapSource *bmp_source;
+ IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICBitmapSource, (void **)&bmp_source);
+
+ for (i=0; pixel_formats[i].wic_format; i++)
{
- if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
+ if (IsEqualGUID(&wic_format, pixel_formats[i].wic_format))
{
- source = (IWICBitmapSource*)frame;
- IWICBitmapSource_AddRef(source);
- gdip_format = wic_gdip_formats[i];
+ source = bmp_source;
+ gdip_format = pixel_formats[i].gdip_format;
+ palette_type = pixel_formats[i].palette_type;
break;
}
}
if (!source)
{
/* unknown format; fall back on 32bppARGB */
- hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
+ hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, bmp_source, &source);
gdip_format = PixelFormat32bppARGB;
+ IWICBitmapSource_Release(bmp_source);
}
+ TRACE("%s => %#x\n", wine_dbgstr_guid(&wic_format), gdip_format);
}
if (SUCCEEDED(hr)) /* got source */
IWICBitmapSource_Release(source);
}
- IWICBitmapFrameDecode_Release(frame);
+ if (SUCCEEDED(hr)) {
+ bitmap->metadata_reader = NULL;
+
+ if (metadata_reader)
+ metadata_reader(bitmap, decoder, active_frame);
+ else if (IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&block_reader) == S_OK)
+ {
+ UINT block_count = 0;
+ if (IWICMetadataBlockReader_GetCount(block_reader, &block_count) == S_OK && block_count)
+ IWICMetadataBlockReader_GetReaderByIndex(block_reader, 0, &bitmap->metadata_reader);
+ IWICMetadataBlockReader_Release(block_reader);
+ }
+
+ palette = get_palette(frame, palette_type);
+ IWICBitmapFrameDecode_Release(frame);
+ }
}
IWICBitmapDecoder_Release(decoder);
{
/* Native GDI+ used to be smarter, but since Win7 it just sets these flags. */
bitmap->image.flags |= ImageFlagsReadOnly|ImageFlagsHasRealPixelSize|ImageFlagsHasRealDPI|ImageFlagsColorSpaceRGB;
+ bitmap->image.frame_count = frame_count;
+ bitmap->image.current_frame = active_frame;
+ bitmap->image.stream = stream;
+ if (palette)
+ {
+ GdipFree(bitmap->image.palette);
+ bitmap->image.palette = palette;
+ }
+ else
+ {
+ if (IsEqualGUID(&wic_format, &GUID_WICPixelFormatBlackWhite))
+ bitmap->image.palette->Flags = 0;
+ }
+ /* Pin the source stream */
+ IStream_AddRef(stream);
+ TRACE("=> %p\n", *image);
}
return status;
}
-static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
- return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
+ return decode_image_wic(stream, &CLSID_WICIcoDecoder, active_frame, NULL, image);
}
-static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
GpStatus status;
GpBitmap* bitmap;
- status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
+ status = decode_image_wic(stream, &CLSID_WICBmpDecoder, active_frame, NULL, image);
bitmap = (GpBitmap*)*image;
return status;
}
-static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
- return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
+ return decode_image_wic(stream, &CLSID_WICJpegDecoder, active_frame, NULL, image);
}
-static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
- return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
+ return decode_image_wic(stream, &CLSID_WICPngDecoder, active_frame, NULL, image);
}
-static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
- return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
+ return decode_image_wic(stream, &CLSID_WICGifDecoder, active_frame, gif_metadata_reader, image);
}
-static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_tiff(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
- return decode_image_wic(stream, &CLSID_WICTiffDecoder, image);
+ return decode_image_wic(stream, &CLSID_WICTiffDecoder, active_frame, NULL, image);
}
-static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, UINT active_frame, GpImage **image)
{
IPicture *pic;
*image = GdipAlloc(sizeof(GpMetafile));
if(!*image) return OutOfMemory;
(*image)->type = ImageTypeMetafile;
+ (*image)->stream = NULL;
(*image)->picture = pic;
(*image)->flags = ImageFlagsNone;
- (*image)->palette_flags = 0;
- (*image)->palette_count = 0;
- (*image)->palette_size = 0;
- (*image)->palette_entries = NULL;
+ (*image)->frame_count = 1;
+ (*image)->current_frame = 0;
+ (*image)->palette = NULL;
TRACE("<-- %p\n", *image);
typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
-typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
+typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, UINT active_frame, GpImage **image);
typedef struct image_codec {
ImageCodecInfo info;
return GenericError;
}
-GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
+GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image, GDIPCONST GUID *dimensionID,
+ UINT frame)
+{
+ GpStatus stat;
+ LARGE_INTEGER seek;
+ HRESULT hr;
+ const struct image_codec *codec = NULL;
+ GpImage *new_image;
+
+ TRACE("(%p,%s,%u)\n", image, debugstr_guid(dimensionID), frame);
+
+ if (!image || !dimensionID)
+ return InvalidParameter;
+
+ if (frame >= image->frame_count)
+ {
+ WARN("requested frame %u, but image has only %u\n", frame, image->frame_count);
+ return InvalidParameter;
+ }
+
+ if (image->type != ImageTypeBitmap && image->type != ImageTypeMetafile)
+ {
+ WARN("invalid image type %d\n", image->type);
+ return InvalidParameter;
+ }
+
+ if (image->current_frame == frame)
+ return Ok;
+
+ if (!image->stream)
+ {
+ TRACE("image doesn't have an associated stream\n");
+ return Ok;
+ }
+
+ /* choose an appropriate image decoder */
+ stat = get_decoder_info(image->stream, &codec);
+ if (stat != Ok)
+ {
+ WARN("can't find decoder info\n");
+ return stat;
+ }
+
+ /* seek to the start of the stream */
+ seek.QuadPart = 0;
+ hr = IStream_Seek(image->stream, seek, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr))
+ return hresult_to_status(hr);
+
+ /* call on the image decoder to do the real work */
+ stat = codec->decode_func(image->stream, &codec->info.Clsid, frame, &new_image);
+
+ if (stat == Ok)
+ {
+ memcpy(&new_image->format, &codec->info.FormatID, sizeof(GUID));
+ free_image_data(image);
+ if (image->type == ImageTypeBitmap)
+ *(GpBitmap *)image = *(GpBitmap *)new_image;
+ else if (image->type == ImageTypeMetafile)
+ *(GpMetafile *)image = *(GpMetafile *)new_image;
+ new_image->type = ~0;
+ GdipFree(new_image);
+ return Ok;
+ }
+
+ return stat;
+}
+
+GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
{
GpStatus stat;
LARGE_INTEGER seek;
if (FAILED(hr)) return hresult_to_status(hr);
/* call on the image decoder to do the real work */
- stat = codec->decode_func(stream, &codec->info.Clsid, image);
+ stat = codec->decode_func(stream, &codec->info.Clsid, 0, image);
/* take note of the original data format */
if (stat == Ok)
{
memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
+ return Ok;
}
return stat;
{
static int calls;
- TRACE("(%p,%p)\n", image, item);
+ if (!image || !item) return InvalidParameter;
+
+ TRACE("(%p,%p:%#x,%u,%u,%p)\n", image, item, item->id, item->type, item->length, item->value);
if(!(calls++))
FIXME("not implemented\n");
- return NotImplemented;
+ return Ok;
}
GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
if (SUCCEEDED(hr))
- /* FIXME: use the resolution from the image */
- hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
+ hr = IWICBitmapFrameEncode_SetResolution(frameencode, image->xres, image->yres);
if (SUCCEEDED(hr))
{
- for (i=0; wic_pixel_formats[i]; i++)
+ for (i=0; pixel_formats[i].wic_format; i++)
{
- if (wic_gdip_formats[i] == bitmap->format)
+ if (pixel_formats[i].gdip_format == bitmap->format)
+ {
+ memcpy(&wicformat, pixel_formats[i].wic_format, sizeof(GUID));
+ gdipformat = bitmap->format;
break;
+ }
}
- if (wic_pixel_formats[i])
- memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
- else
+ if (!gdipformat)
+ {
memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+ gdipformat = PixelFormat32bppARGB;
+ }
hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
-
- for (i=0; wic_pixel_formats[i]; i++)
- {
- if (IsEqualGUID(&wicformat, wic_pixel_formats[i]))
- break;
- }
- if (wic_pixel_formats[i])
- gdipformat = wic_gdip_formats[i];
- else
- {
- ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat));
- hr = E_FAIL;
- }
}
if (SUCCEEDED(hr))
return stat;
}
+/*****************************************************************************
+ * GdipSaveAdd [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipSaveAdd(GpImage *image, GDIPCONST EncoderParameters *params)
+{
+ FIXME("(%p,%p): stub\n", image, params);
+ return Ok;
+}
+
/*****************************************************************************
* GdipGetImagePalette [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
{
+ INT count;
+
TRACE("(%p,%p,%i)\n", image, palette, size);
if (!image || !palette)
return InvalidParameter;
- if (size < (sizeof(UINT)*2+sizeof(ARGB)*image->palette_count))
+ count = image->palette ? image->palette->Count : 0;
+
+ if (size < (sizeof(UINT)*2+sizeof(ARGB)*count))
{
TRACE("<-- InsufficientBuffer\n");
return InsufficientBuffer;
}
- palette->Flags = image->palette_flags;
- palette->Count = image->palette_count;
- memcpy(palette->Entries, image->palette_entries, sizeof(ARGB)*image->palette_count);
-
+ if (image->palette)
+ {
+ palette->Flags = image->palette->Flags;
+ palette->Count = image->palette->Count;
+ memcpy(palette->Entries, image->palette->Entries, sizeof(ARGB)*image->palette->Count);
+ }
+ else
+ {
+ palette->Flags = 0;
+ palette->Count = 0;
+ }
return Ok;
}
GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
GDIPCONST ColorPalette *palette)
{
+ ColorPalette *new_palette;
+
TRACE("(%p,%p)\n", image, palette);
if(!image || !palette || palette->Count > 256)
return InvalidParameter;
- if (palette->Count > image->palette_size)
- {
- ARGB *new_palette;
-
- new_palette = GdipAlloc(sizeof(ARGB) * palette->Count);
- if (!new_palette) return OutOfMemory;
-
- GdipFree(image->palette_entries);
- image->palette_entries = new_palette;
- image->palette_size = palette->Count;
- }
+ new_palette = GdipAlloc(2 * sizeof(UINT) + palette->Count * sizeof(ARGB));
+ if (!new_palette) return OutOfMemory;
- image->palette_flags = palette->Flags;
- image->palette_count = palette->Count;
- memcpy(image->palette_entries, palette->Entries, sizeof(ARGB)*palette->Count);
+ GdipFree(image->palette);
+ image->palette = new_palette;
+ image->palette->Flags = palette->Flags;
+ image->palette->Count = palette->Count;
+ memcpy(image->palette->Entries, palette->Entries, sizeof(ARGB)*palette->Count);
return Ok;
}
static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
static const WCHAR gif_format[] = {'G','I','F',0};
-static const BYTE gif_sig_pattern[4] = "GIF8";
-static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+static const BYTE gif_sig_pattern[12] = "GIF87aGIF89a";
+static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const WCHAR tiff_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'T','I','F','F', 0};
static const WCHAR tiff_extension[] = {'*','.','T','I','F','F',';','*','.','T','I','F',0};
/* MimeType */ gif_mimetype,
/* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
/* Version */ 1,
- /* SigCount */ 1,
- /* SigSize */ 4,
+ /* SigCount */ 2,
+ /* SigSize */ 6,
/* SigPattern */ gif_sig_pattern,
/* SigMask */ gif_sig_mask,
},
GpStatus retval;
PixelFormat format;
BitmapData lockeddata;
- INT y;
TRACE("%p %p %p\n", hbm, hpal, bitmap);
format, &lockeddata);
if (retval == Ok)
{
- if (bm.bmBits)
- {
- for (y=0; y<bm.bmHeight; y++)
- {
- memcpy((BYTE*)lockeddata.Scan0+lockeddata.Stride*y,
- (BYTE*)bm.bmBits+bm.bmWidthBytes*(bm.bmHeight-1-y),
- bm.bmWidthBytes);
- }
- }
- else
- {
- HDC hdc;
- HBITMAP oldhbm;
- BITMAPINFO *pbmi;
- INT src_height, dst_stride;
- BYTE *dst_bits;
+ HDC hdc;
+ BITMAPINFO *pbmi;
+ INT src_height;
- hdc = CreateCompatibleDC(NULL);
- oldhbm = SelectObject(hdc, hbm);
+ hdc = CreateCompatibleDC(NULL);
+ pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-
- if (pbmi)
- {
- pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pbmi->bmiHeader.biBitCount = 0;
-
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
-
- src_height = abs(pbmi->bmiHeader.biHeight);
+ if (pbmi)
+ {
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biBitCount = 0;
- if (pbmi->bmiHeader.biHeight > 0)
- {
- dst_bits = (BYTE*)lockeddata.Scan0+lockeddata.Stride*(src_height-1);
- dst_stride = -lockeddata.Stride;
- }
- else
- {
- dst_bits = lockeddata.Scan0;
- dst_stride = lockeddata.Stride;
- }
+ GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
- for (y=0; y<src_height; y++)
- {
- GetDIBits(hdc, hbm, y, 1, dst_bits+dst_stride*y,
- pbmi, DIB_RGB_COLORS);
- }
+ src_height = abs(pbmi->bmiHeader.biHeight);
+ pbmi->bmiHeader.biHeight = -src_height;
- GdipFree(pbmi);
- }
- else
- retval = OutOfMemory;
+ GetDIBits(hdc, hbm, 0, src_height, lockeddata.Scan0, pbmi, DIB_RGB_COLORS);
- SelectObject(hdc, oldhbm);
- DeleteDC(hdc);
+ GdipFree(pbmi);
}
+ else
+ retval = OutOfMemory;
+
+ DeleteDC(hdc);
GdipBitmapUnlockBits(*bitmap, &lockeddata);
}
GdipGetImageWidth(image, &srcwidth);
GdipGetImageHeight(image, &srcheight);
- stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB,
+ stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppPARGB,
NULL, (GpBitmap**)ret_image);
if (stat == Ok)
TRACE("(%p, %u)\n", image, type);
+ if (!image)
+ return InvalidParameter;
+
rotate_90 = type&1;
flip_x = (type&6) == 2 || (type&6) == 4;
flip_y = (type&3) == 1 || (type&3) == 2;