#include "ole2.h"
#include "initguid.h"
+#include "wincodec.h"
#include "gdiplus.h"
#include "gdiplus_private.h"
#include "wine/debug.h"
return x;
}
+GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
+ RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
+{
+ FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
+ /*
+ * Note: According to Jose Roca's GDI+ docs, this function is not
+ * implemented in Windows's GDI+.
+ */
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
+ INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
+ GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
+{
+ FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
+ /*
+ * Note: According to Jose Roca's GDI+ docs, this function is not
+ * implemented in Windows's GDI+.
+ */
+ return NotImplemented;
+}
+
+static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+ *index = (row[x/8]>>(7-x%8)) & 1;
+}
+
+static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+ if (x & 1)
+ *index = row[x/2]&0xf;
+ else
+ *index = row[x/2]>>4;
+}
+
+static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+ *index = row[x];
+}
+
+static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = *g = *b = row[x*2+1];
+ *a = 255;
+}
+
+static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ WORD pixel = *((WORD*)(row)+x);
+ *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
+ *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
+ *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+ *a = 255;
+}
+
+static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ WORD pixel = *((WORD*)(row)+x);
+ *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
+ *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
+ *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+ *a = 255;
+}
+
+static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ WORD pixel = *((WORD*)(row)+x);
+ *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
+ *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
+ *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+ if ((pixel&0x8000) == 0x8000)
+ *a = 255;
+ else
+ *a = 0;
+}
+
+static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = row[x*3+2];
+ *g = row[x*3+1];
+ *b = row[x*3];
+ *a = 255;
+}
+
+static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = row[x*4+2];
+ *g = row[x*4+1];
+ *b = row[x*4];
+ *a = 255;
+}
+
+static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = row[x*4+2];
+ *g = row[x*4+1];
+ *b = row[x*4];
+ *a = row[x*4+3];
+}
+
+static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *a = row[x*4+3];
+ if (*a == 0)
+ *r = *g = *b = 0;
+ else
+ {
+ *r = row[x*4+2] * 255 / *a;
+ *g = row[x*4+1] * 255 / *a;
+ *b = row[x*4] * 255 / *a;
+ }
+}
+
+static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = row[x*6+5];
+ *g = row[x*6+3];
+ *b = row[x*6+1];
+ *a = 255;
+}
+
+static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *r = row[x*8+5];
+ *g = row[x*8+3];
+ *b = row[x*8+1];
+ *a = row[x*8+7];
+}
+
+static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+ const BYTE *row, UINT x)
+{
+ *a = row[x*8+7];
+ if (*a == 0)
+ *r = *g = *b = 0;
+ else
+ {
+ *r = row[x*8+5] * 255 / *a;
+ *g = row[x*8+3] * 255 / *a;
+ *b = row[x*8+1] * 255 / *a;
+ }
+}
+
GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
ARGB *color)
{
- static int calls;
+ BYTE r, g, b, a;
+ BYTE index;
+ BYTE *row;
TRACE("%p %d %d %p\n", bitmap, x, y, color);
- if(!bitmap || !color)
+ if(!bitmap || !color ||
+ x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ row = bitmap->bits+bitmap->stride*y;
- *color = 0xdeadbeef;
+ switch (bitmap->format)
+ {
+ case PixelFormat1bppIndexed:
+ getpixel_1bppIndexed(&index,row,x);
+ break;
+ case PixelFormat4bppIndexed:
+ getpixel_4bppIndexed(&index,row,x);
+ break;
+ case PixelFormat8bppIndexed:
+ getpixel_8bppIndexed(&index,row,x);
+ break;
+ case PixelFormat16bppGrayScale:
+ getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat16bppRGB555:
+ getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat16bppRGB565:
+ getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat16bppARGB1555:
+ getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat24bppRGB:
+ getpixel_24bppRGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat32bppRGB:
+ getpixel_32bppRGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat32bppARGB:
+ getpixel_32bppARGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat32bppPARGB:
+ getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat48bppRGB:
+ getpixel_48bppRGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat64bppARGB:
+ getpixel_64bppARGB(&r,&g,&b,&a,row,x);
+ break;
+ case PixelFormat64bppPARGB:
+ getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
+ break;
+ default:
+ FIXME("not implemented for format 0x%x\n", bitmap->format);
+ return NotImplemented;
+ }
+
+ if (bitmap->format & PixelFormatIndexed)
+ *color = bitmap->image.palette_entries[index];
+ else
+ *color = a<<24|r<<16|g<<8|b;
+
+ return Ok;
+}
+
+static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((WORD*)(row)+x) = (r+g+b)*85;
+}
+
+static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((WORD*)(row)+x) = (r<<7&0x7c00)|
+ (g<<2&0x03e0)|
+ (b>>3&0x001f);
+}
+
+static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((WORD*)(row)+x) = (r<<8&0xf800)|
+ (g<<3&0x07e0)|
+ (b>>3&0x001f);
+}
+
+static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((WORD*)(row)+x) = (a<<8&0x8000)|
+ (r<<7&0x7c00)|
+ (g<<2&0x03e0)|
+ (b>>3&0x001f);
+}
+
+static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ row[x*3+2] = r;
+ row[x*3+1] = g;
+ row[x*3] = b;
+}
+
+static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ r = r * a / 255;
+ g = g * a / 255;
+ b = b * a / 255;
+ *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ row[x*6+5] = row[x*6+4] = r;
+ row[x*6+3] = row[x*6+2] = g;
+ row[x*6+1] = row[x*6] = b;
+}
+
+static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ UINT64 a64=a, r64=r, g64=g, b64=b;
+ *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
+}
+
+static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+ BYTE *row, UINT x)
+{
+ UINT64 a64, r64, g64, b64;
+ a64 = a * 257;
+ r64 = r * a / 255;
+ g64 = g * a / 255;
+ b64 = b * a / 255;
+ *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
+}
+
+GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
+ ARGB color)
+{
+ BYTE a, r, g, b;
+ BYTE *row;
+ TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
+
+ if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
+ return InvalidParameter;
+
+ a = color>>24;
+ r = color>>16;
+ g = color>>8;
+ b = color;
+
+ row = bitmap->bits + bitmap->stride * y;
+
+ switch (bitmap->format)
+ {
+ case PixelFormat16bppGrayScale:
+ setpixel_16bppGrayScale(r,g,b,a,row,x);
+ break;
+ case PixelFormat16bppRGB555:
+ setpixel_16bppRGB555(r,g,b,a,row,x);
+ break;
+ case PixelFormat16bppRGB565:
+ setpixel_16bppRGB565(r,g,b,a,row,x);
+ break;
+ case PixelFormat16bppARGB1555:
+ setpixel_16bppARGB1555(r,g,b,a,row,x);
+ break;
+ case PixelFormat24bppRGB:
+ setpixel_24bppRGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat32bppRGB:
+ setpixel_32bppRGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat32bppARGB:
+ setpixel_32bppARGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat32bppPARGB:
+ setpixel_32bppPARGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat48bppRGB:
+ setpixel_48bppRGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat64bppARGB:
+ setpixel_64bppARGB(r,g,b,a,row,x);
+ break;
+ case PixelFormat64bppPARGB:
+ setpixel_64bppPARGB(r,g,b,a,row,x);
+ break;
+ default:
+ FIXME("not implemented for format 0x%x\n", bitmap->format);
+ return NotImplemented;
+ }
+
+ return Ok;
+}
+
+GpStatus convert_pixels(UINT width, UINT height,
+ INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
+ INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette)
+{
+ UINT x, y;
+
+ if (src_format == dst_format ||
+ (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
+ {
+ UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
+ for (y=0; y<height; y++)
+ memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
+ return Ok;
+ }
+
+#define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
+ for (x=0; x<width; x++) \
+ for (y=0; y<height; y++) { \
+ BYTE index; \
+ BYTE *color; \
+ getpixel_function(&index, src_bits+src_stride*y, x); \
+ color = (BYTE*)(&src_palette[index]); \
+ setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
+ } \
+ return Ok; \
+} while (0);
+
+#define convert_rgb_to_rgb(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); \
+ } \
+ return Ok; \
+} while (0);
+
+ switch (src_format)
+ {
+ case PixelFormat1bppIndexed:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat4bppIndexed:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat8bppIndexed:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat16bppGrayScale:
+ switch (dst_format)
+ {
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat16bppRGB555:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat16bppRGB565:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat16bppARGB1555:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat24bppRGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat32bppRGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat32bppARGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB);
+ case PixelFormat32bppPARGB:
+ convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
+ return Ok;
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat32bppPARGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat48bppRGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat64bppARGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB);
+ default:
+ break;
+ }
+ break;
+ case PixelFormat64bppPARGB:
+ switch (dst_format)
+ {
+ case PixelFormat16bppGrayScale:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
+ case PixelFormat16bppRGB555:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555);
+ case PixelFormat16bppRGB565:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565);
+ case PixelFormat16bppARGB1555:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555);
+ case PixelFormat24bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB);
+ case PixelFormat32bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB);
+ case PixelFormat32bppARGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB);
+ case PixelFormat32bppPARGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB);
+ case PixelFormat48bppRGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB);
+ case PixelFormat64bppARGB:
+ convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB);
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+#undef convert_indexed_to_rgb
+#undef convert_rgb_to_rgb
return NotImplemented;
}
GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
UINT flags, PixelFormat format, BitmapData* lockeddata)
{
- BOOL bm_is_selected;
INT stride, bitspp = PIXELFORMATBPP(format);
- HDC hdc;
- HBITMAP hbm, old = NULL;
- BITMAPINFO *pbmi;
BYTE *buff = NULL;
UINT abs_height;
GpRect act_rect; /* actual rect to be used */
+ GpStatus stat;
- TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
+ TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
if(!lockeddata || !bitmap)
return InvalidParameter;
}
if(flags & ImageLockModeUserInputBuf)
+ {
+ static int fixme=0;
+ if (!fixme++) FIXME("ImageLockModeUserInputBuf not implemented\n");
return NotImplemented;
+ }
if(bitmap->lockmode)
+ {
+ WARN("bitmap is already locked and cannot be locked again\n");
return WrongState;
+ }
- IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
- IPicture_get_CurDC(bitmap->image.picture, &hdc);
- bm_is_selected = (hdc != 0);
+ if (bitmap->bits && bitmap->format == format)
+ {
+ /* no conversion is necessary; just use the bits directly */
+ lockeddata->Width = act_rect.Width;
+ lockeddata->Height = act_rect.Height;
+ lockeddata->PixelFormat = format;
+ lockeddata->Reserved = flags;
+ lockeddata->Stride = bitmap->stride;
+ lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
+ bitmap->stride * act_rect.Y;
+
+ bitmap->lockmode = flags;
+ bitmap->numlocks++;
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
- if (!pbmi)
- return OutOfMemory;
- pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pbmi->bmiHeader.biBitCount = 0;
+ return Ok;
+ }
- if(!bm_is_selected){
- hdc = CreateCompatibleDC(0);
- old = SelectObject(hdc, hbm);
+ /* Make sure we can convert to the requested format. */
+ stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
+ if (stat == NotImplemented)
+ {
+ FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
+ return NotImplemented;
}
- /* fill out bmi */
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+ /* If we're opening for writing, make sure we'll be able to write back in
+ * the original format. */
+ if (flags & ImageLockModeWrite)
+ {
+ stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
+ if (stat == NotImplemented)
+ {
+ FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
+ return NotImplemented;
+ }
+ }
- abs_height = abs(pbmi->bmiHeader.biHeight);
- stride = pbmi->bmiHeader.biWidth * bitspp / 8;
+ abs_height = bitmap->height;
+ stride = (bitmap->width * bitspp + 7) / 8;
stride = (stride + 3) & ~3;
buff = GdipAlloc(stride * abs_height);
- pbmi->bmiHeader.biBitCount = bitspp;
+ if (!buff) return OutOfMemory;
- if(buff)
- GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
-
- if(!bm_is_selected){
- SelectObject(hdc, old);
- DeleteDC(hdc);
- }
+ stat = convert_pixels(bitmap->width, bitmap->height,
+ stride, buff, format,
+ bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries);
- if(!buff){
- GdipFree(pbmi);
- return OutOfMemory;
+ if (stat != Ok)
+ {
+ GdipFree(buff);
+ return stat;
}
lockeddata->Width = act_rect.Width;
lockeddata->Height = act_rect.Height;
lockeddata->PixelFormat = format;
lockeddata->Reserved = flags;
-
- if(pbmi->bmiHeader.biHeight > 0){
- lockeddata->Stride = -stride;
- lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X +
- stride * (abs_height - 1 - act_rect.Y);
- }
- else{
- lockeddata->Stride = stride;
- lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
- }
+ lockeddata->Stride = stride;
+ lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
bitmap->lockmode = flags;
bitmap->numlocks++;
-
bitmap->bitmapbits = buff;
- GdipFree(pbmi);
+ return Ok;
+}
+
+GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
+{
+ TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
+
+ if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
+ return InvalidParameter;
+
+ bitmap->image.xres = xdpi;
+ bitmap->image.yres = ydpi;
+
return Ok;
}
GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
BitmapData* lockeddata)
{
- HDC hdc;
- HBITMAP hbm, old = NULL;
- BOOL bm_is_selected;
- BITMAPINFO *pbmi;
+ GpStatus stat;
+
+ TRACE("(%p,%p)\n", bitmap, lockeddata);
+
+ if(!bitmap || !lockeddata)
+ return InvalidParameter;
+
+ if(!bitmap->lockmode)
+ return WrongState;
+
+ if(lockeddata->Reserved & ImageLockModeUserInputBuf)
+ return NotImplemented;
+
+ if(lockeddata->Reserved & ImageLockModeRead){
+ if(!(--bitmap->numlocks))
+ bitmap->lockmode = 0;
+
+ GdipFree(bitmap->bitmapbits);
+ bitmap->bitmapbits = NULL;
+ return Ok;
+ }
+
+ if (!bitmap->bitmapbits)
+ {
+ /* we passed a direct reference; no need to do anything */
+ bitmap->lockmode = 0;
+ bitmap->numlocks = 0;
+ return Ok;
+ }
+
+ stat = convert_pixels(bitmap->width, bitmap->height,
+ bitmap->stride, bitmap->bits, bitmap->format,
+ lockeddata->Stride, bitmap->bitmapbits, lockeddata->PixelFormat, NULL);
+
+ if (stat != Ok)
+ {
+ ERR("failed to convert pixels; this should never happen\n");
+ }
+
+ GdipFree(bitmap->bitmapbits);
+ bitmap->bitmapbits = NULL;
+ bitmap->lockmode = 0;
+ bitmap->numlocks = 0;
+
+ return stat;
+}
+
+GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
+ PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
+{
+ BitmapData lockeddata_src, lockeddata_dst;
+ int i;
+ UINT row_size;
+ Rect area;
+ GpStatus stat;
- if(!bitmap || !lockeddata)
- return InvalidParameter;
+ TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
- if(!bitmap->lockmode)
- return WrongState;
+ if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
+ x < 0 || y < 0 ||
+ x + width > srcBitmap->width || y + height > srcBitmap->height)
+ {
+ TRACE("<-- InvalidParameter\n");
+ return InvalidParameter;
+ }
- if(lockeddata->Reserved & ImageLockModeUserInputBuf)
- return NotImplemented;
+ if (format == PixelFormatDontCare)
+ format = srcBitmap->format;
- if(lockeddata->Reserved & ImageLockModeRead){
- if(!(--bitmap->numlocks))
- bitmap->lockmode = 0;
+ area.X = roundr(x);
+ area.Y = roundr(y);
+ area.Width = roundr(width);
+ area.Height = roundr(height);
- GdipFree(bitmap->bitmapbits);
- bitmap->bitmapbits = NULL;
- return Ok;
- }
+ stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
+ &lockeddata_src);
+ if (stat != Ok) return stat;
- IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
- IPicture_get_CurDC(bitmap->image.picture, &hdc);
- bm_is_selected = (hdc != 0);
+ stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
+ 0, lockeddata_src.PixelFormat, NULL, dstBitmap);
+ if (stat == Ok)
+ {
+ stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
+ lockeddata_src.PixelFormat, &lockeddata_dst);
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
- pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- pbmi->bmiHeader.biBitCount = 0;
+ if (stat == Ok)
+ {
+ /* copy the image data */
+ row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
+ for (i=0; i<lockeddata_src.Height; i++)
+ memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
+ (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
+ row_size);
+
+ GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
+ }
- if(!bm_is_selected){
- hdc = CreateCompatibleDC(0);
- old = SelectObject(hdc, hbm);
+ if (stat != Ok)
+ GdipDisposeImage((GpImage*)*dstBitmap);
}
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
- pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
- SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight),
- bitmap->bitmapbits, pbmi, DIB_RGB_COLORS);
+ GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
- if(!bm_is_selected){
- SelectObject(hdc, old);
- DeleteDC(hdc);
+ if (stat != Ok)
+ {
+ *dstBitmap = NULL;
}
- GdipFree(pbmi);
- GdipFree(bitmap->bitmapbits);
- bitmap->bitmapbits = NULL;
- bitmap->lockmode = 0;
-
- return Ok;
+ return stat;
}
GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
{
- FIXME("(%i,%i,%i,%i,%i,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
+ TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
- return NotImplemented;
+ return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
}
GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
{
- IStream* stream;
- HRESULT hr;
- INT size;
- LARGE_INTEGER move;
GpStatus stat = GenericError;
TRACE("%p, %p\n", image, cloneImage);
if (!image || !cloneImage)
return InvalidParameter;
- hr = CreateStreamOnHGlobal(0, TRUE, &stream);
- if (FAILED(hr))
- return GenericError;
-
- hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
- if(FAILED(hr))
+ if (image->picture)
{
- WARN("Failed to save image on stream\n");
- goto out;
+ IStream* stream;
+ HRESULT hr;
+ INT size;
+ LARGE_INTEGER move;
+
+ hr = CreateStreamOnHGlobal(0, TRUE, &stream);
+ if (FAILED(hr))
+ return GenericError;
+
+ hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
+ if(FAILED(hr))
+ {
+ WARN("Failed to save image on stream\n");
+ goto out;
+ }
+
+ /* Set seek pointer back to the beginning of the picture */
+ move.QuadPart = 0;
+ hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr))
+ goto out;
+
+ stat = GdipLoadImageFromStream(stream, cloneImage);
+ if (stat != Ok) WARN("Failed to load image from stream\n");
+
+ out:
+ IStream_Release(stream);
+ return stat;
}
+ else if (image->type == ImageTypeBitmap)
+ {
+ GpBitmap *bitmap = (GpBitmap*)image;
+ BitmapData lockeddata_src, lockeddata_dst;
+ int i;
+ UINT row_size;
+
+ stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
+ &lockeddata_src);
+ if (stat != Ok) return stat;
+
+ stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
+ 0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
+ if (stat == Ok)
+ {
+ stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
+ lockeddata_src.PixelFormat, &lockeddata_dst);
+
+ if (stat == Ok)
+ {
+ /* copy the image data */
+ row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
+ for (i=0; i<lockeddata_src.Height; i++)
+ memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
+ (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
+ row_size);
+
+ GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
+ }
+
+ if (stat != Ok)
+ GdipDisposeImage(*cloneImage);
+ }
- /* Set seek pointer back to the beginning of the picture */
- move.QuadPart = 0;
- hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
- if (FAILED(hr))
- goto out;
+ GdipBitmapUnlockBits(bitmap, &lockeddata_src);
- stat = GdipLoadImageFromStream(stream, cloneImage);
- if (stat != Ok) WARN("Failed to load image from stream\n");
+ if (stat != Ok)
+ {
+ *cloneImage = NULL;
+ }
+ else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
-out:
- IStream_Release(stream);
- return stat;
+ return stat;
+ }
+ else
+ {
+ ERR("GpImage with no IPicture or bitmap?!\n");
+ return NotImplemented;
+ }
}
GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
HBITMAP* hbmReturn, ARGB background)
{
- FIXME("stub\n");
+ GpStatus stat;
+ HBITMAP result, oldbitmap;
+ UINT width, height;
+ HDC hdc;
+ GpGraphics *graphics;
+ BITMAPINFOHEADER bih;
+ void *bits;
+ TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
+
+ if (!bitmap || !hbmReturn) return InvalidParameter;
+
+ GdipGetImageWidth((GpImage*)bitmap, &width);
+ GdipGetImageHeight((GpImage*)bitmap, &height);
+
+ bih.biSize = sizeof(bih);
+ bih.biWidth = width;
+ bih.biHeight = height;
+ bih.biPlanes = 1;
+ bih.biBitCount = 32;
+ bih.biCompression = BI_RGB;
+ bih.biSizeImage = 0;
+ bih.biXPelsPerMeter = 0;
+ bih.biYPelsPerMeter = 0;
+ bih.biClrUsed = 0;
+ bih.biClrImportant = 0;
+
+ hdc = CreateCompatibleDC(NULL);
+ if (!hdc) return GenericError;
+
+ result = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &bits,
+ NULL, 0);
+
+ if (result)
+ {
+ oldbitmap = SelectObject(hdc, result);
- hbmReturn = NULL;
+ stat = GdipCreateFromHDC(hdc, &graphics);
+ if (stat == Ok)
+ {
+ stat = GdipGraphicsClear(graphics, background);
- return NotImplemented;
+ if (stat == Ok)
+ stat = GdipDrawImage(graphics, (GpImage*)bitmap, 0, 0);
+
+ GdipDeleteGraphics(graphics);
+ }
+
+ SelectObject(hdc, oldbitmap);
+ }
+ else
+ stat = GenericError;
+
+ DeleteDC(hdc);
+
+ if (stat != Ok && result)
+ {
+ DeleteObject(result);
+ result = NULL;
+ }
+
+ *hbmReturn = result;
+
+ return stat;
}
GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
{
static int calls;
+ TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
+ debugstr_w(description), out_metafile);
+
if(!ref || !metafile || !out_metafile)
return InvalidParameter;
GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
{
- HICON icon_copy;
+ GpStatus stat;
ICONINFO iinfo;
- PICTDESC desc;
+ BITMAP bm;
+ int ret;
+ UINT width, height;
+ GpRect rect;
+ BitmapData lockeddata;
+ HDC screendc;
+ BOOL has_alpha;
+ int x, y;
+ BYTE *bits;
+ BITMAPINFOHEADER bih;
+ DWORD *src;
+ BYTE *dst_row;
+ DWORD *dst;
TRACE("%p, %p\n", hicon, bitmap);
if(!bitmap || !GetIconInfo(hicon, &iinfo))
return InvalidParameter;
- *bitmap = GdipAlloc(sizeof(GpBitmap));
- if(!*bitmap) return OutOfMemory;
+ /* get the size of the icon */
+ ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
+ if (ret == 0) {
+ DeleteObject(iinfo.hbmColor);
+ DeleteObject(iinfo.hbmMask);
+ return GenericError;
+ }
- icon_copy = CreateIconIndirect(&iinfo);
+ width = bm.bmWidth;
- if(!icon_copy){
- GdipFree(*bitmap);
- return InvalidParameter;
+ if (iinfo.hbmColor)
+ height = abs(bm.bmHeight);
+ else /* combined bitmap + mask */
+ height = abs(bm.bmHeight) / 2;
+
+ bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height);
+ if (!bits) {
+ DeleteObject(iinfo.hbmColor);
+ DeleteObject(iinfo.hbmMask);
+ return OutOfMemory;
}
- desc.cbSizeofstruct = sizeof(PICTDESC);
- desc.picType = PICTYPE_ICON;
- desc.u.icon.hicon = icon_copy;
+ stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap);
+ if (stat != Ok) {
+ DeleteObject(iinfo.hbmColor);
+ DeleteObject(iinfo.hbmMask);
+ HeapFree(GetProcessHeap(), 0, bits);
+ return stat;
+ }
- if(OleCreatePictureIndirect(&desc, &IID_IPicture, TRUE,
- (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
- DestroyIcon(icon_copy);
- GdipFree(*bitmap);
- return GenericError;
+ rect.X = 0;
+ rect.Y = 0;
+ rect.Width = width;
+ rect.Height = height;
+
+ stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
+ if (stat != Ok) {
+ DeleteObject(iinfo.hbmColor);
+ DeleteObject(iinfo.hbmMask);
+ HeapFree(GetProcessHeap(), 0, bits);
+ GdipDisposeImage((GpImage*)*bitmap);
+ return stat;
}
- (*bitmap)->format = PixelFormat32bppARGB;
- (*bitmap)->image.type = ImageTypeBitmap;
- (*bitmap)->image.flags = ImageFlagsNone;
- (*bitmap)->width = ipicture_pixel_width((*bitmap)->image.picture);
- (*bitmap)->height = ipicture_pixel_height((*bitmap)->image.picture);
+ bih.biSize = sizeof(bih);
+ bih.biWidth = width;
+ bih.biHeight = -height;
+ bih.biPlanes = 1;
+ bih.biBitCount = 32;
+ bih.biCompression = BI_RGB;
+ bih.biSizeImage = 0;
+ bih.biXPelsPerMeter = 0;
+ bih.biYPelsPerMeter = 0;
+ bih.biClrUsed = 0;
+ bih.biClrImportant = 0;
+
+ screendc = GetDC(0);
+ if (iinfo.hbmColor)
+ {
+ GetDIBits(screendc, iinfo.hbmColor, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+
+ if (bm.bmBitsPixel == 32)
+ {
+ has_alpha = FALSE;
+
+ /* If any pixel has a non-zero alpha, ignore hbmMask */
+ src = (DWORD*)bits;
+ for (x=0; x<width && !has_alpha; x++)
+ for (y=0; y<height && !has_alpha; y++)
+ if ((*src++ & 0xff000000) != 0)
+ has_alpha = TRUE;
+ }
+ else has_alpha = FALSE;
+ }
+ else
+ {
+ GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+ has_alpha = FALSE;
+ }
+
+ /* copy the image data to the Bitmap */
+ src = (DWORD*)bits;
+ dst_row = lockeddata.Scan0;
+ for (y=0; y<height; y++)
+ {
+ memcpy(dst_row, src, width*4);
+ src += width;
+ dst_row += lockeddata.Stride;
+ }
+
+ if (!has_alpha)
+ {
+ if (iinfo.hbmMask)
+ {
+ /* read alpha data from the mask */
+ if (iinfo.hbmColor)
+ GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+ else
+ GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
+
+ src = (DWORD*)bits;
+ dst_row = lockeddata.Scan0;
+ for (y=0; y<height; y++)
+ {
+ dst = (DWORD*)dst_row;
+ for (x=0; x<height; x++)
+ {
+ DWORD src_value = *src++;
+ if (src_value)
+ *dst++ = 0;
+ else
+ *dst++ |= 0xff000000;
+ }
+ dst_row += lockeddata.Stride;
+ }
+ }
+ else
+ {
+ /* set constant alpha of 255 */
+ dst_row = bits;
+ for (y=0; y<height; y++)
+ {
+ dst = (DWORD*)dst_row;
+ for (x=0; x<height; x++)
+ *dst++ |= 0xff000000;
+ dst_row += lockeddata.Stride;
+ }
+ }
+ }
+
+ ReleaseDC(0, screendc);
DeleteObject(iinfo.hbmColor);
DeleteObject(iinfo.hbmMask);
+ GdipBitmapUnlockBits(*bitmap, &lockeddata);
+
+ HeapFree(GetProcessHeap(), 0, bits);
+
+ return Ok;
+}
+
+static void generate_halftone_palette(ARGB *entries, UINT count)
+{
+ static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
+ UINT i;
+
+ for (i=0; i<8 && i<count; i++)
+ {
+ entries[i] = 0xff000000;
+ if (i&1) entries[i] |= 0x800000;
+ if (i&2) entries[i] |= 0x8000;
+ if (i&4) entries[i] |= 0x80;
+ }
+
+ if (8 < count)
+ entries[i] = 0xffc0c0c0;
+
+ for (i=9; i<16 && i<count; i++)
+ {
+ entries[i] = 0xff000000;
+ if (i&1) entries[i] |= 0xff0000;
+ if (i&2) entries[i] |= 0xff00;
+ if (i&4) entries[i] |= 0xff;
+ }
+
+ for (i=16; i<40 && i<count; i++)
+ {
+ entries[i] = 0;
+ }
+
+ for (i=40; i<256 && i<count; i++)
+ {
+ entries[i] = 0xff000000;
+ entries[i] |= halftone_values[(i-40)%6];
+ entries[i] |= halftone_values[((i-40)/6)%6] << 8;
+ entries[i] |= halftone_values[((i-40)/36)%6] << 16;
+ }
+}
+
+static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
+{
+ HDC screendc = GetDC(0);
+
+ if (!screendc) return GenericError;
+
+ *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
+ *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
+
+ ReleaseDC(0, screendc);
+
return Ok;
}
GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
{
- BITMAPFILEHEADER *bmfh;
- BITMAPINFOHEADER *bmih;
- BYTE *buff;
- INT datalen, size;
- IStream *stream;
+ BITMAPINFO* pbmi;
+ HBITMAP hbitmap;
+ INT row_size, dib_stride;
+ HDC hdc;
+ BYTE *bits;
+ int i;
+ REAL xres, yres;
+ GpStatus stat;
- TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
+ TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
if (!bitmap) return InvalidParameter;
if(scan0 && !stride)
return InvalidParameter;
- *bitmap = GdipAlloc(sizeof(GpBitmap));
- if(!*bitmap) return OutOfMemory;
+ stat = get_screen_resolution(&xres, &yres);
+ if (stat != Ok) return stat;
- if(stride == 0){
- stride = width * (PIXELFORMATBPP(format) / 8);
- stride = (stride + 3) & ~3;
- }
+ row_size = (width * PIXELFORMATBPP(format)+7) / 8;
+ dib_stride = (row_size + 3) & ~3;
+
+ if(stride == 0)
+ stride = dib_stride;
- datalen = abs(stride * height);
- size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
- buff = GdipAlloc(size);
- if(!buff){
- GdipFree(*bitmap);
+ pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+ if (!pbmi)
return OutOfMemory;
+
+ pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ pbmi->bmiHeader.biWidth = width;
+ pbmi->bmiHeader.biHeight = -height;
+ pbmi->bmiHeader.biPlanes = 1;
+ /* FIXME: use the rest of the data from format */
+ pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
+ pbmi->bmiHeader.biCompression = BI_RGB;
+ pbmi->bmiHeader.biSizeImage = 0;
+ pbmi->bmiHeader.biXPelsPerMeter = 0;
+ pbmi->bmiHeader.biYPelsPerMeter = 0;
+ pbmi->bmiHeader.biClrUsed = 0;
+ pbmi->bmiHeader.biClrImportant = 0;
+
+ hdc = CreateCompatibleDC(NULL);
+ if (!hdc) {
+ GdipFree(pbmi);
+ return GenericError;
}
- bmfh = (BITMAPFILEHEADER*) buff;
- bmih = (BITMAPINFOHEADER*) (bmfh + 1);
+ hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
- bmfh->bfType = (((WORD)'M') << 8) + (WORD)'B';
- bmfh->bfSize = size;
- bmfh->bfOffBits = size - datalen;
+ DeleteDC(hdc);
+ GdipFree(pbmi);
- bmih->biSize = sizeof(BITMAPINFOHEADER);
- bmih->biWidth = width;
- /* FIXME: use the rest of the data from format */
- bmih->biBitCount = PIXELFORMATBPP(format);
- bmih->biCompression = BI_RGB;
- bmih->biSizeImage = datalen;
+ if (!hbitmap) return GenericError;
+ /* copy bits to the dib if necessary */
+ /* FIXME: should reference the bits instead of copying them */
if (scan0)
- {
- if (stride > 0)
- {
- bmih->biHeight = -height;
- memcpy(bmih + 1, scan0, datalen);
- }
- else
- {
- bmih->biHeight = height;
- memcpy(bmih + 1, scan0 + stride * (height - 1), datalen);
- }
- }
- else
- {
- bmih->biHeight = height;
- memset(bmih + 1, 0, datalen);
- }
-
- if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
- ERR("could not make stream\n");
- GdipFree(*bitmap);
- GdipFree(buff);
- *bitmap = NULL;
- return GenericError;
- }
+ for (i=0; i<height; i++)
+ memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
- if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
- (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
- TRACE("Could not load picture\n");
- IStream_Release(stream);
- GdipFree(*bitmap);
- GdipFree(buff);
- *bitmap = NULL;
- return GenericError;
+ *bitmap = GdipAlloc(sizeof(GpBitmap));
+ if(!*bitmap)
+ {
+ DeleteObject(hbitmap);
+ return OutOfMemory;
}
(*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.xres = xres;
+ (*bitmap)->image.yres = yres;
(*bitmap)->width = width;
(*bitmap)->height = height;
(*bitmap)->format = format;
+ (*bitmap)->image.picture = NULL;
+ (*bitmap)->hbitmap = hbitmap;
+ (*bitmap)->hdc = NULL;
+ (*bitmap)->bits = bits;
+ (*bitmap)->stride = dib_stride;
+
+ if (format == PixelFormat1bppIndexed ||
+ 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));
+
+ if (!(*bitmap)->image.palette_entries)
+ {
+ GdipDisposeImage(&(*bitmap)->image);
+ *bitmap = NULL;
+ return OutOfMemory;
+ }
+
+ if (format == PixelFormat1bppIndexed)
+ {
+ (*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;
+
+ generate_halftone_palette((*bitmap)->image.palette_entries,
+ (*bitmap)->image.palette_count);
+ }
+ }
+
+ TRACE("<-- %p\n", *bitmap);
return Ok;
}
return stat;
if((*bitmap)->image.type != ImageTypeBitmap){
- IPicture_Release((*bitmap)->image.picture);
- GdipFree(bitmap);
+ GdipDisposeImage(&(*bitmap)->image);
+ *bitmap = NULL;
return GenericError; /* FIXME: what error to return? */
}
return Ok;
}
+GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
+{
+ FIXME("(%p, %p)\n", bitmap, hicon);
+
+ return NotImplemented;
+}
+
GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
{
TRACE("%p\n", cachedbmp);
return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
}
-GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
+GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
+ LPBYTE pData16, INT iMapMode, INT eFlags)
{
- HDC hdc;
+ FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
+ return NotImplemented;
+}
+GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
+{
TRACE("%p\n", image);
if(!image)
return InvalidParameter;
- IPicture_get_CurDC(image->picture, &hdc);
- DeleteDC(hdc);
- IPicture_Release(image->picture);
+ if (image->picture)
+ IPicture_Release(image->picture);
if (image->type == ImageTypeBitmap)
+ {
GdipFree(((GpBitmap*)image)->bitmapbits);
+ DeleteDC(((GpBitmap*)image)->hdc);
+ DeleteObject(((GpBitmap*)image)->hbitmap);
+ }
+ GdipFree(image->palette_entries);
GdipFree(image);
return Ok;
GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
{
+ static int calls;
+
+ TRACE("(%p,%p)\n", image, item);
+
if(!image || !item)
return InvalidParameter;
+ if (!(calls++))
+ FIXME("not implemented\n");
+
+ return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
+{
+ static int calls;
+
+ TRACE("(%p,%p)\n", image, item);
+
+ if (!(calls++))
+ FIXME("not implemented\n");
+
return NotImplemented;
}
return NotImplemented;
}
- IPicture_get_CurDC(image->picture, &hdc);
+ hdc = ((GpBitmap*)image)->hdc;
if(!hdc){
hdc = CreateCompatibleDC(0);
- IPicture_SelectPicture(image->picture, hdc, NULL, NULL);
+ SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
+ ((GpBitmap*)image)->hdc = hdc;
}
return GdipCreateFromHDC(hdc, graphics);
GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
{
- static int calls;
-
if(!image || !res)
return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ *res = image->xres;
- return NotImplemented;
+ TRACE("(%p) <-- %0.2f\n", image, *res);
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
{
- FIXME("%p %p\n", image, size);
+ TRACE("%p %p\n", image, size);
if(!image || !size)
return InvalidParameter;
- return NotImplemented;
+ if (image->palette_count == 0)
+ *size = sizeof(ColorPalette);
+ else
+ *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette_count;
+
+ TRACE("<-- %u\n", *size);
+
+ return Ok;
}
/* FIXME: test this function for non-bitmap types */
GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
{
- static int calls;
-
if(!image || !format)
return InvalidParameter;
- if(!(calls++))
- FIXME("stub\n");
+ memcpy(format, &image->format, sizeof(GUID));
- /* FIXME: should be detected from embedded picture or stored separately */
- switch (image->type)
- {
- case ImageTypeBitmap: *format = ImageFormatBMP; break;
- case ImageTypeMetafile: *format = ImageFormatEMF; break;
- default:
- WARN("unknown type %u\n", image->type);
- *format = ImageFormatUndefined;
- }
return Ok;
}
GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
{
- static int calls;
-
if(!image || !res)
return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ *res = image->yres;
- return NotImplemented;
+ TRACE("(%p) <-- %0.2f\n", image, *res);
+
+ return Ok;
}
GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
{
static int calls;
+ TRACE("(%p,%p,%p)\n", image, size, num);
+
if(!(calls++))
FIXME("not implemented\n");
return InvalidParameter;
}
+struct image_format_dimension
+{
+ const GUID *format;
+ const GUID *dimension;
+};
+
+struct image_format_dimension image_format_dimensions[] =
+{
+ {&ImageFormatGIF, &FrameDimensionTime},
+ {&ImageFormatIcon, &FrameDimensionResolution},
+ {NULL}
+};
+
GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
GDIPCONST GUID* dimensionID, UINT* count)
{
static int calls;
+ TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
+
if(!image || !dimensionID || !count)
return InvalidParameter;
GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
UINT* count)
{
+ /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
+
if(!image || !count)
return InvalidParameter;
*count = 1;
- FIXME("stub\n");
-
return Ok;
}
GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
GUID* dimensionIDs, UINT count)
{
- static int calls;
+ int i;
+ const GUID *result=NULL;
- if(!image || !dimensionIDs)
+ TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
+
+ if(!image || !dimensionIDs || count != 1)
return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ 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);
}
-GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
+static const WICPixelFormatGUID *wic_pixel_formats[] = {
+ &GUID_WICPixelFormat16bppBGR555,
+ &GUID_WICPixelFormat24bppBGR,
+ &GUID_WICPixelFormat32bppBGR,
+ &GUID_WICPixelFormat32bppBGRA,
+ &GUID_WICPixelFormat32bppPBGRA,
+ NULL
+};
+
+static const PixelFormat wic_gdip_formats[] = {
+ PixelFormat16bppRGB555,
+ PixelFormat24bppRGB,
+ PixelFormat32bppRGB,
+ PixelFormat32bppARGB,
+ PixelFormat32bppPARGB,
+};
+
+static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ GpStatus status=Ok;
+ GpBitmap *bitmap;
+ HRESULT hr;
+ IWICBitmapDecoder *decoder;
+ IWICBitmapFrameDecode *frame;
+ IWICBitmapSource *source=NULL;
+ WICPixelFormatGUID wic_format;
+ PixelFormat gdip_format=0;
+ int i;
+ UINT width, height;
+ BitmapData lockeddata;
+ WICRect wrc;
+ HRESULT initresult;
+
+ 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);
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+
+ if (SUCCEEDED(hr)) /* got frame */
+ {
+ hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
+
+ if (SUCCEEDED(hr))
+ {
+ for (i=0; wic_pixel_formats[i]; i++)
+ {
+ if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
+ {
+ source = (IWICBitmapSource*)frame;
+ IWICBitmapSource_AddRef(source);
+ gdip_format = wic_gdip_formats[i];
+ break;
+ }
+ }
+ if (!source)
+ {
+ /* unknown format; fall back on 32bppARGB */
+ hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
+ gdip_format = PixelFormat32bppARGB;
+ }
+ }
+
+ if (SUCCEEDED(hr)) /* got source */
+ {
+ hr = IWICBitmapSource_GetSize(source, &width, &height);
+
+ if (SUCCEEDED(hr))
+ status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
+ NULL, &bitmap);
+
+ if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
+ {
+ status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
+ gdip_format, &lockeddata);
+ if (status == Ok) /* locked bitmap */
+ {
+ wrc.X = 0;
+ wrc.Width = width;
+ wrc.Height = 1;
+ for (i=0; i<height; i++)
+ {
+ wrc.Y = i;
+ hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
+ abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
+ if (FAILED(hr)) break;
+ }
+
+ GdipBitmapUnlockBits(bitmap, &lockeddata);
+ }
+
+ if (SUCCEEDED(hr) && status == Ok)
+ *image = (GpImage*)bitmap;
+ else
+ {
+ *image = NULL;
+ GdipDisposeImage((GpImage*)bitmap);
+ }
+ }
+
+ IWICBitmapSource_Release(source);
+ }
+
+ IWICBitmapFrameDecode_Release(frame);
+ }
+
+ IWICBitmapDecoder_Release(decoder);
+
+end:
+ if (SUCCEEDED(initresult)) CoUninitialize();
+
+ if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
+
+ return status;
+}
+
+static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
+}
+
+static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ GpStatus status;
+ GpBitmap* bitmap;
+
+ status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
+
+ bitmap = (GpBitmap*)*image;
+
+ if (status == Ok && bitmap->format == PixelFormat32bppARGB)
+ {
+ /* WIC supports bmp files with alpha, but gdiplus does not */
+ bitmap->format = PixelFormat32bppRGB;
+ }
+
+ return status;
+}
+
+static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
+}
+
+static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
+}
+
+static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+ return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
+}
+
+static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
{
IPicture *pic;
- short type;
TRACE("%p %p\n", stream, image);
return GenericError;
}
- IPicture_get_Type(pic, &type);
+ /* FIXME: missing initialization code */
+ *image = GdipAlloc(sizeof(GpMetafile));
+ if(!*image) return OutOfMemory;
+ (*image)->type = ImageTypeMetafile;
+ (*image)->picture = pic;
+ (*image)->flags = ImageFlagsNone;
+ (*image)->palette_flags = 0;
+ (*image)->palette_count = 0;
+ (*image)->palette_size = 0;
+ (*image)->palette_entries = NULL;
+
+ TRACE("<-- %p\n", *image);
- if(type == PICTYPE_BITMAP){
- BITMAPINFO *pbmi;
- BITMAPCOREHEADER* bmch;
- HBITMAP hbm;
- HDC hdc;
+ return Ok;
+}
- pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
- if (!pbmi)
- return OutOfMemory;
- *image = GdipAlloc(sizeof(GpBitmap));
- if(!*image){
- GdipFree(pbmi);
- return OutOfMemory;
- }
- (*image)->type = ImageTypeBitmap;
+typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
+ GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
- (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
- (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
+typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
- /* get the pixel format */
- IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
- IPicture_get_CurDC(pic, &hdc);
+typedef struct image_codec {
+ ImageCodecInfo info;
+ encode_image_func encode_func;
+ decode_image_func decode_func;
+} image_codec;
- bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
- bmch->bcSize = sizeof(BITMAPCOREHEADER);
+typedef enum {
+ BMP,
+ JPEG,
+ GIF,
+ EMF,
+ WMF,
+ PNG,
+ ICO,
+ NUM_CODECS
+} ImageFormat;
- if(!hdc){
- HBITMAP old;
- hdc = CreateCompatibleDC(0);
- old = SelectObject(hdc, hbm);
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
- SelectObject(hdc, old);
- DeleteDC(hdc);
- }
- else
- GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+static const struct image_codec codecs[NUM_CODECS];
- switch(bmch->bcBitCount)
+static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
+{
+ BYTE signature[8];
+ LARGE_INTEGER seek;
+ HRESULT hr;
+ UINT bytesread;
+ int i, j;
+
+ /* seek to the start of the stream */
+ seek.QuadPart = 0;
+ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ /* read the first 8 bytes */
+ /* FIXME: This assumes all codecs have one signature <= 8 bytes in length */
+ hr = IStream_Read(stream, signature, 8, &bytesread);
+ if (FAILED(hr)) return hresult_to_status(hr);
+ if (hr == S_FALSE || bytesread == 0) return GenericError;
+
+ for (i = 0; i < NUM_CODECS; i++) {
+ if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
+ bytesread >= codecs[i].info.SigSize)
{
- case 1:
- (*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
- break;
- case 4:
- (*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
- break;
- case 8:
- (*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
- break;
- case 16:
- (*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
- break;
- case 24:
- (*((GpBitmap**) image))->format = PixelFormat24bppRGB;
- break;
- case 32:
- (*((GpBitmap**) image))->format = PixelFormat32bppRGB;
- break;
- case 48:
- (*((GpBitmap**) image))->format = PixelFormat48bppRGB;
- break;
- default:
- FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
- (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
- break;
+ for (j=0; j<codecs[i].info.SigSize; j++)
+ if ((signature[j] & codecs[i].info.SigMask[j]) != codecs[i].info.SigPattern[j])
+ break;
+ if (j == codecs[i].info.SigSize)
+ {
+ *result = &codecs[i];
+ return Ok;
+ }
}
-
- GdipFree(pbmi);
- }
- else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
- /* FIXME: missing initialization code */
- *image = GdipAlloc(sizeof(GpMetafile));
- if(!*image) return OutOfMemory;
- (*image)->type = ImageTypeMetafile;
- }
- else{
- *image = GdipAlloc(sizeof(GpImage));
- if(!*image) return OutOfMemory;
- (*image)->type = ImageTypeUnknown;
}
- (*image)->picture = pic;
- (*image)->flags = ImageFlagsNone;
+ TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
+ signature[0],signature[1],signature[2],signature[3],
+ signature[4],signature[5],signature[6],signature[7]);
- return Ok;
+ return GenericError;
+}
+
+GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
+{
+ GpStatus stat;
+ LARGE_INTEGER seek;
+ HRESULT hr;
+ const struct image_codec *codec=NULL;
+
+ /* choose an appropriate image decoder */
+ stat = get_decoder_info(stream, &codec);
+ if (stat != Ok) return stat;
+
+ /* seek to the start of the stream */
+ seek.QuadPart = 0;
+ hr = IStream_Seek(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(stream, &codec->info.Clsid, image);
+
+ /* take note of the original data format */
+ if (stat == Ok)
+ {
+ memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
+ }
+
+ return stat;
}
/* FIXME: no ICM */
{
static int calls;
+ TRACE("(%p,%u)\n", image, propId);
+
if(!image)
return InvalidParameter;
{
static int calls;
+ TRACE("(%p,%p)\n", image, item);
+
if(!(calls++))
FIXME("not implemented\n");
if (!image || !filename|| !clsidEncoder)
return InvalidParameter;
- if (!(image->picture))
- return InvalidParameter;
-
stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
if (stat != Ok)
return GenericError;
#define BITMAP_FORMAT_PNG 0x5089
#define BITMAP_FORMAT_APM 0xcdd7
-static GpStatus encode_image_BMP(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
- void **output, unsigned int *output_size)
+static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
+ GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
{
- int num_palette_entries;
- BITMAPFILEHEADER *bmp_file_hdr;
- BITMAPINFO *bmp_info_hdr;
+ GpStatus stat;
+ GpBitmap *bitmap;
+ IWICBitmapEncoder *encoder;
+ IWICBitmapFrameEncode *frameencode;
+ IPropertyBag2 *encoderoptions;
+ HRESULT hr;
+ UINT width, height;
+ PixelFormat gdipformat=0;
+ WICPixelFormatGUID wicformat;
+ GpRect rc;
+ BitmapData lockeddata;
+ HRESULT initresult;
+ UINT i;
+
+ if (image->type != ImageTypeBitmap)
+ return GenericError;
- if (bitmap_info->bmiHeader.biClrUsed) {
- num_palette_entries = bitmap_info->bmiHeader.biClrUsed;
- if (num_palette_entries > 256) num_palette_entries = 256;
- } else {
- if (bitmap_info->bmiHeader.biBitCount <= 8)
- num_palette_entries = 1 << bitmap_info->bmiHeader.biBitCount;
- else
- num_palette_entries = 0;
+ bitmap = (GpBitmap*)image;
+
+ GdipGetImageWidth(image, &width);
+ GdipGetImageHeight(image, &height);
+
+ rc.X = 0;
+ rc.Y = 0;
+ rc.Width = width;
+ rc.Height = height;
+
+ initresult = CoInitialize(NULL);
+
+ hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IWICBitmapEncoder, (void**)&encoder);
+ if (FAILED(hr))
+ {
+ if (SUCCEEDED(initresult)) CoUninitialize();
+ return hresult_to_status(hr);
}
- *output_size =
- sizeof(BITMAPFILEHEADER) +
- sizeof(BITMAPINFOHEADER) +
- num_palette_entries * sizeof(RGBQUAD) +
- bitmap_info->bmiHeader.biSizeImage;
+ hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
- *output = GdipAlloc(*output_size);
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
+ }
- bmp_file_hdr = *output;
- bmp_file_hdr->bfType = BITMAP_FORMAT_BMP;
- bmp_file_hdr->bfSize = *output_size;
- bmp_file_hdr->bfOffBits =
- sizeof(BITMAPFILEHEADER) +
- sizeof(BITMAPINFOHEADER) +
- num_palette_entries * sizeof (RGBQUAD);
+ if (SUCCEEDED(hr)) /* created frame */
+ {
+ hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
- bmp_info_hdr = (BITMAPINFO*) ((unsigned char*)(*output) + sizeof(BITMAPFILEHEADER));
- memcpy(bmp_info_hdr, bitmap_info, sizeof(BITMAPINFOHEADER) + num_palette_entries * sizeof(RGBQUAD));
- memcpy((unsigned char *)(*output) +
- sizeof(BITMAPFILEHEADER) +
- sizeof(BITMAPINFOHEADER) +
- num_palette_entries * sizeof(RGBQUAD),
- bitmap_bits, bitmap_info->bmiHeader.biSizeImage);
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
- return Ok;
-}
+ if (SUCCEEDED(hr))
+ /* FIXME: use the resolution from the image */
+ hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
-typedef GpStatus encode_image_func(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
- void **output, unsigned int *output_size);
+ if (SUCCEEDED(hr))
+ {
+ for (i=0; wic_pixel_formats[i]; i++)
+ {
+ if (wic_gdip_formats[i] == bitmap->format)
+ break;
+ }
+ if (wic_pixel_formats[i])
+ memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
+ else
+ memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+
+ 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;
+ }
+ }
-typedef enum {
- BMP,
- NUM_ENCODERS_SUPPORTED
-} ImageFormat;
+ if (SUCCEEDED(hr))
+ {
+ stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
+ &lockeddata);
+
+ if (stat == Ok)
+ {
+ UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
+ BYTE *row;
+
+ /* write one row at a time in case stride is negative */
+ row = lockeddata.Scan0;
+ for (i=0; i<lockeddata.Height; i++)
+ {
+ hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
+ if (FAILED(hr)) break;
+ row += lockeddata.Stride;
+ }
+
+ GdipBitmapUnlockBits(bitmap, &lockeddata);
+ }
+ else
+ hr = E_FAIL;
+ }
-static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED];
-static encode_image_func *const encode_image_funcs[NUM_ENCODERS_SUPPORTED] = {
- encode_image_BMP,
-};
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapFrameEncode_Commit(frameencode);
+
+ IWICBitmapFrameEncode_Release(frameencode);
+ IPropertyBag2_Release(encoderoptions);
+ }
+
+ if (SUCCEEDED(hr))
+ hr = IWICBitmapEncoder_Commit(encoder);
+
+ IWICBitmapEncoder_Release(encoder);
+
+ if (SUCCEEDED(initresult)) CoUninitialize();
+
+ return hresult_to_status(hr);
+}
+
+static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
+ GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+ return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
+}
+
+static GpStatus encode_image_png(GpImage *image, IStream* stream,
+ GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+ return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
+}
/*****************************************************************************
* GdipSaveImageToStream [GDIPLUS.@]
GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
{
GpStatus stat;
- HRESULT hr;
- short type;
- HBITMAP hbmp;
- HBITMAP old_hbmp;
- HDC hdc;
- int bm_is_selected;
- BITMAPINFO bmp_info;
- LPVOID bmp_bits;
- encode_image_func* encode_image;
- LPVOID output;
- unsigned int output_size;
- unsigned int dummy;
+ encode_image_func encode_image;
int i;
- old_hbmp = 0;
- output = NULL;
- output_size = 0;
-
TRACE("%p %p %p %p\n", image, stream, clsid, params);
if(!image || !stream)
return InvalidParameter;
- if (!image->picture)
- return GenericError;
-
- hr = IPicture_get_Type(image->picture, &type);
- if (FAILED(hr) || type != PICTYPE_BITMAP)
- return GenericError;
-
/* select correct encoder */
encode_image = NULL;
- for (i = 0; i < NUM_ENCODERS_SUPPORTED; i++) {
- if (IsEqualCLSID(clsid, &codecs[i].Clsid))
- encode_image = encode_image_funcs[i];
+ for (i = 0; i < NUM_CODECS; i++) {
+ if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
+ IsEqualCLSID(clsid, &codecs[i].info.Clsid))
+ encode_image = codecs[i].encode_func;
}
if (encode_image == NULL)
return UnknownImageFormat;
- /* extract underlying hbitmap representation from the IPicture */
- hr = IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbmp);
- if (FAILED(hr) || !hbmp)
- return GenericError;
- hr = IPicture_get_CurDC(image->picture, &hdc);
- if (FAILED(hr))
- return GenericError;
- bm_is_selected = (hdc != 0);
- if (!bm_is_selected) {
- hdc = CreateCompatibleDC(0);
- old_hbmp = SelectObject(hdc, hbmp);
- }
+ stat = encode_image(image, stream, clsid, params);
- /* get bits from HBITMAP */
- bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
- bmp_info.bmiHeader.biBitCount = 0;
- GetDIBits(hdc, hbmp, 0, 0, NULL, &bmp_info, DIB_RGB_COLORS);
+ return stat;
+}
- bmp_bits = GdipAlloc(bmp_info.bmiHeader.biSizeImage);
+/*****************************************************************************
+ * GdipGetImagePalette [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
+{
+ TRACE("(%p,%p,%i)\n", image, palette, size);
- if (bmp_bits)
- GetDIBits(hdc, hbmp, 0, abs(bmp_info.bmiHeader.biHeight), bmp_bits, &bmp_info, DIB_RGB_COLORS);
+ if (!image || !palette)
+ return InvalidParameter;
- if (!bm_is_selected) {
- SelectObject(hdc, old_hbmp);
- DeleteDC(hdc);
+ if (size < (sizeof(UINT)*2+sizeof(ARGB)*image->palette_count))
+ {
+ TRACE("<-- InsufficientBuffer\n");
+ return InsufficientBuffer;
}
- if (!bmp_bits)
- return OutOfMemory;
-
- stat = encode_image(bmp_bits, &bmp_info, &output, &output_size);
- if (stat == Ok)
- IStream_Write(stream, output, output_size, &dummy);
-
- GdipFree(output);
- GdipFree(bmp_bits);
+ palette->Flags = image->palette_flags;
+ palette->Count = image->palette_count;
+ memcpy(palette->Entries, image->palette_entries, sizeof(ARGB)*image->palette_count);
- return stat;
+ return Ok;
}
/*****************************************************************************
GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
GDIPCONST ColorPalette *palette)
{
- static int calls;
+ TRACE("(%p,%p)\n", image, palette);
- if(!image || !palette)
+ if(!image || !palette || palette->Count > 256)
return InvalidParameter;
- if(!(calls++))
- FIXME("not implemented\n");
+ if (palette->Count > image->palette_size)
+ {
+ ARGB *new_palette;
- return NotImplemented;
+ 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;
+ }
+
+ image->palette_flags = palette->Flags;
+ image->palette_count = palette->Count;
+ memcpy(image->palette_entries, palette->Entries, sizeof(ARGB)*palette->Count);
+
+ return Ok;
}
/*************************************************************************
static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
-static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED] =
+static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
+static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
+static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
+static const WCHAR jpeg_format[] = {'J','P','E','G',0};
+static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
+static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
+
+static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
+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 WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
+static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
+static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
+static const WCHAR emf_format[] = {'E','M','F',0};
+static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
+static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
+static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
+static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
+static const WCHAR wmf_format[] = {'W','M','F',0};
+static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
+static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
+
+static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
+static const WCHAR png_extension[] = {'*','.','P','N','G',0};
+static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
+static const WCHAR png_format[] = {'P','N','G',0};
+static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
+static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
+static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
+static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
+static const WCHAR ico_format[] = {'I','C','O',0};
+static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
+static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
+
+static const struct image_codec codecs[NUM_CODECS] = {
{
{ /* BMP */
/* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
/* SigPattern */ bmp_sig_pattern,
/* SigMask */ bmp_sig_mask,
},
- };
+ encode_image_BMP,
+ decode_image_bmp
+ },
+ {
+ { /* JPEG */
+ /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ jpeg_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ jpeg_format,
+ /* FilenameExtension */ jpeg_extension,
+ /* MimeType */ jpeg_mimetype,
+ /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 2,
+ /* SigPattern */ jpeg_sig_pattern,
+ /* SigMask */ jpeg_sig_mask,
+ },
+ NULL,
+ decode_image_jpeg
+ },
+ {
+ { /* GIF */
+ /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ gif_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ gif_format,
+ /* FilenameExtension */ gif_extension,
+ /* MimeType */ gif_mimetype,
+ /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 4,
+ /* SigPattern */ gif_sig_pattern,
+ /* SigMask */ gif_sig_mask,
+ },
+ NULL,
+ decode_image_gif
+ },
+ {
+ { /* EMF */
+ /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ emf_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ emf_format,
+ /* FilenameExtension */ emf_extension,
+ /* MimeType */ emf_mimetype,
+ /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 4,
+ /* SigPattern */ emf_sig_pattern,
+ /* SigMask */ emf_sig_mask,
+ },
+ NULL,
+ decode_image_olepicture_metafile
+ },
+ {
+ { /* WMF */
+ /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ wmf_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ wmf_format,
+ /* FilenameExtension */ wmf_extension,
+ /* MimeType */ wmf_mimetype,
+ /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 2,
+ /* SigPattern */ wmf_sig_pattern,
+ /* SigMask */ wmf_sig_mask,
+ },
+ NULL,
+ decode_image_olepicture_metafile
+ },
+ {
+ { /* PNG */
+ /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ png_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ png_format,
+ /* FilenameExtension */ png_extension,
+ /* MimeType */ png_mimetype,
+ /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 8,
+ /* SigPattern */ png_sig_pattern,
+ /* SigMask */ png_sig_mask,
+ },
+ encode_image_png,
+ decode_image_png
+ },
+ {
+ { /* ICO */
+ /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
+ /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
+ /* CodecName */ ico_codecname,
+ /* DllName */ NULL,
+ /* FormatDescription */ ico_format,
+ /* FilenameExtension */ ico_extension,
+ /* MimeType */ ico_mimetype,
+ /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+ /* Version */ 1,
+ /* SigCount */ 1,
+ /* SigSize */ 4,
+ /* SigPattern */ ico_sig_pattern,
+ /* SigMask */ ico_sig_mask,
+ },
+ NULL,
+ decode_image_icon
+ },
+};
/*****************************************************************************
* GdipGetImageDecodersSize [GDIPLUS.@]
*/
GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
{
- FIXME("%p %p stub!\n", numDecoders, size);
+ int decoder_count=0;
+ int i;
+ TRACE("%p %p\n", numDecoders, size);
if (!numDecoders || !size)
return InvalidParameter;
- *numDecoders = 0;
- *size = 0;
+ for (i=0; i<NUM_CODECS; i++)
+ {
+ if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
+ decoder_count++;
+ }
+
+ *numDecoders = decoder_count;
+ *size = decoder_count * sizeof(ImageCodecInfo);
return Ok;
}
*/
GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
{
- FIXME("%u %u %p stub!\n", numDecoders, size, decoders);
+ int i, decoder_count=0;
+ TRACE("%u %u %p\n", numDecoders, size, decoders);
- if (!decoders)
+ if (!decoders ||
+ size != numDecoders * sizeof(ImageCodecInfo))
return GenericError;
- return NotImplemented;
+ for (i=0; i<NUM_CODECS; i++)
+ {
+ if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
+ {
+ if (decoder_count == numDecoders) return GenericError;
+ memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
+ decoder_count++;
+ }
+ }
+
+ if (decoder_count < numDecoders) return GenericError;
+
+ return Ok;
}
/*****************************************************************************
*/
GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
{
+ int encoder_count=0;
+ int i;
TRACE("%p %p\n", numEncoders, size);
if (!numEncoders || !size)
return InvalidParameter;
- *numEncoders = NUM_ENCODERS_SUPPORTED;
- *size = sizeof (codecs);
+ for (i=0; i<NUM_CODECS; i++)
+ {
+ if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
+ encoder_count++;
+ }
+
+ *numEncoders = encoder_count;
+ *size = encoder_count * sizeof(ImageCodecInfo);
return Ok;
}
*/
GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
{
+ int i, encoder_count=0;
TRACE("%u %u %p\n", numEncoders, size, encoders);
if (!encoders ||
- (numEncoders != NUM_ENCODERS_SUPPORTED) ||
- (size != sizeof (codecs)))
+ size != numEncoders * sizeof(ImageCodecInfo))
return GenericError;
- memcpy(encoders, codecs, sizeof (codecs));
+ for (i=0; i<NUM_CODECS; i++)
+ {
+ if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
+ {
+ if (encoder_count == numEncoders) return GenericError;
+ memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
+ encoder_count++;
+ }
+ }
+
+ if (encoder_count < numEncoders) return GenericError;
return Ok;
}
BITMAP bm;
GpStatus retval;
PixelFormat format;
- BYTE* bits;
+ BitmapData lockeddata;
+ INT y;
TRACE("%p %p %p\n", hbm, hpal, bitmap);
return InvalidParameter;
}
- if (bm.bmBits)
- bits = (BYTE*)bm.bmBits + (bm.bmHeight - 1) * bm.bmWidthBytes;
- else
+ retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
+ format, NULL, bitmap);
+
+ if (retval == Ok)
{
- FIXME("can only get image data from DIB sections\n");
- bits = NULL;
+ retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
+ 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 = CreateCompatibleDC(NULL);
+ oldhbm = SelectObject(hdc, hbm);
+
+ 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->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;
+ }
+
+ for (y=0; y<src_height; y++)
+ {
+ GetDIBits(hdc, hbm, y, 1, dst_bits+dst_stride*y,
+ pbmi, DIB_RGB_COLORS);
+ }
+
+ GdipFree(pbmi);
+ }
+ else
+ retval = OutOfMemory;
+
+ SelectObject(hdc, oldhbm);
+ DeleteDC(hdc);
+ }
+
+ GdipBitmapUnlockBits(*bitmap, &lockeddata);
+ }
}
- retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, -bm.bmWidthBytes,
- format, bits, bitmap);
-
return retval;
}
+GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
+{
+ FIXME("(%p): stub\n", effect);
+ /* note: According to Jose Roca's GDI+ Docs, this is not implemented
+ * in Windows's gdiplus */
+ return NotImplemented;
+}
+
/*****************************************************************************
* GdipSetEffectParameters [GDIPLUS.@]
*/
{
static int calls;
+ TRACE("(%p,%p,%u)\n", effect, params, size);
+
if(!(calls++))
FIXME("not implemented\n");
return Ok;
}
+
+/*****************************************************************************
+ * GdipGetImageThumbnail [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
+ GpImage **ret_image, GetThumbnailImageAbort cb,
+ VOID * cb_data)
+{
+ FIXME("(%p %u %u %p %p %p) stub\n",
+ image, width, height, ret_image, cb, cb_data);
+ return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipImageRotateFlip [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
+{
+ FIXME("(%p %u) stub\n", image, type);
+ return NotImplemented;
+}