2 * Copyright (C) 2007 Google (Evan Stade)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
36 #include "gdiplus_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
41 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
43 static INT ipicture_pixel_height(IPicture *pic)
48 IPicture_get_Height(pic, &y);
52 y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
58 static INT ipicture_pixel_width(IPicture *pic)
63 IPicture_get_Width(pic, &x);
67 x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
74 GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
75 RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
77 FIXME("(%p %p %p %d %p %p): stub\n", bitmap, effect, roi, useAuxData, auxData, auxDataSize);
79 * Note: According to Jose Roca's GDI+ docs, this function is not
80 * implemented in Windows's GDI+.
82 return NotImplemented;
85 GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
86 INT numInputs, CGpEffect* effect, RECT* roi, RECT* outputRect,
87 GpBitmap** outputBitmap, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
89 FIXME("(%p %d %p %p %p %p %d %p %p): stub\n", inputBitmaps, numInputs, effect, roi, outputRect, outputBitmap, useAuxData, auxData, auxDataSize);
91 * Note: According to Jose Roca's GDI+ docs, this function is not
92 * implemented in Windows's GDI+.
94 return NotImplemented;
97 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
101 TRACE("%p %d %d %p\n", bitmap, x, y, color);
103 if(!bitmap || !color)
104 return InvalidParameter;
107 FIXME("not implemented\n");
111 return NotImplemented;
114 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
118 TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
121 return InvalidParameter;
124 FIXME("not implemented\n");
126 return NotImplemented;
129 /* This function returns a pointer to an array of pixels that represents the
130 * bitmap. The *entire* bitmap is locked according to the lock mode specified by
131 * flags. It is correct behavior that a user who calls this function with write
132 * privileges can write to the whole bitmap (not just the area in rect).
134 * FIXME: only used portion of format is bits per pixel. */
135 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
136 UINT flags, PixelFormat format, BitmapData* lockeddata)
139 INT stride, bitspp = PIXELFORMATBPP(format);
141 HBITMAP hbm, old = NULL;
145 GpRect act_rect; /* actual rect to be used */
147 TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
149 if(!lockeddata || !bitmap)
150 return InvalidParameter;
153 if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
154 (rect->Y + rect->Height > bitmap->height) || !flags)
155 return InvalidParameter;
160 act_rect.X = act_rect.Y = 0;
161 act_rect.Width = bitmap->width;
162 act_rect.Height = bitmap->height;
165 if(flags & ImageLockModeUserInputBuf)
166 return NotImplemented;
171 if (bitmap->bits && bitmap->format == format)
173 /* no conversion is necessary; just use the bits directly */
174 lockeddata->Width = act_rect.Width;
175 lockeddata->Height = act_rect.Height;
176 lockeddata->PixelFormat = format;
177 lockeddata->Reserved = flags;
178 lockeddata->Stride = bitmap->stride;
179 lockeddata->Scan0 = bitmap->bits + (bitspp / 8) * act_rect.X +
180 bitmap->stride * act_rect.Y;
182 bitmap->lockmode = flags;
188 hbm = bitmap->hbitmap;
190 bm_is_selected = (hdc != 0);
192 pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
195 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
196 pbmi->bmiHeader.biBitCount = 0;
199 hdc = CreateCompatibleDC(0);
200 old = SelectObject(hdc, hbm);
204 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
206 abs_height = abs(pbmi->bmiHeader.biHeight);
207 stride = pbmi->bmiHeader.biWidth * bitspp / 8;
208 stride = (stride + 3) & ~3;
210 buff = GdipAlloc(stride * abs_height);
212 pbmi->bmiHeader.biBitCount = bitspp;
215 GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
218 SelectObject(hdc, old);
227 lockeddata->Width = act_rect.Width;
228 lockeddata->Height = act_rect.Height;
229 lockeddata->PixelFormat = format;
230 lockeddata->Reserved = flags;
232 if(pbmi->bmiHeader.biHeight > 0){
233 lockeddata->Stride = -stride;
234 lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X +
235 stride * (abs_height - 1 - act_rect.Y);
238 lockeddata->Stride = stride;
239 lockeddata->Scan0 = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
242 bitmap->lockmode = flags;
245 bitmap->bitmapbits = buff;
251 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
253 FIXME("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
255 return NotImplemented;
258 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
259 BitmapData* lockeddata)
262 HBITMAP hbm, old = NULL;
266 if(!bitmap || !lockeddata)
267 return InvalidParameter;
269 if(!bitmap->lockmode)
272 if(lockeddata->Reserved & ImageLockModeUserInputBuf)
273 return NotImplemented;
275 if(lockeddata->Reserved & ImageLockModeRead){
276 if(!(--bitmap->numlocks))
277 bitmap->lockmode = 0;
279 GdipFree(bitmap->bitmapbits);
280 bitmap->bitmapbits = NULL;
284 if (!bitmap->bitmapbits)
286 /* we passed a direct reference; no need to do anything */
287 bitmap->lockmode = 0;
291 hbm = bitmap->hbitmap;
293 bm_is_selected = (hdc != 0);
295 pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
296 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
297 pbmi->bmiHeader.biBitCount = 0;
300 hdc = CreateCompatibleDC(0);
301 old = SelectObject(hdc, hbm);
304 GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
305 pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
306 SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight),
307 bitmap->bitmapbits, pbmi, DIB_RGB_COLORS);
310 SelectObject(hdc, old);
315 GdipFree(bitmap->bitmapbits);
316 bitmap->bitmapbits = NULL;
317 bitmap->lockmode = 0;
322 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
323 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
325 FIXME("(%f,%f,%f,%f,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
327 return NotImplemented;
330 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
331 PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
333 FIXME("(%i,%i,%i,%i,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
335 return NotImplemented;
338 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
340 GpStatus stat = GenericError;
342 TRACE("%p, %p\n", image, cloneImage);
344 if (!image || !cloneImage)
345 return InvalidParameter;
354 hr = CreateStreamOnHGlobal(0, TRUE, &stream);
358 hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
361 WARN("Failed to save image on stream\n");
365 /* Set seek pointer back to the beginning of the picture */
367 hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
371 stat = GdipLoadImageFromStream(stream, cloneImage);
372 if (stat != Ok) WARN("Failed to load image from stream\n");
375 IStream_Release(stream);
378 else if (image->type == ImageTypeBitmap)
380 GpBitmap *bitmap = (GpBitmap*)image;
381 BitmapData lockeddata_src, lockeddata_dst;
385 stat = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, bitmap->format,
387 if (stat != Ok) return stat;
389 stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
390 0, lockeddata_src.PixelFormat, NULL, (GpBitmap**)cloneImage);
393 stat = GdipBitmapLockBits((GpBitmap*)*cloneImage, NULL, ImageLockModeWrite,
394 lockeddata_src.PixelFormat, &lockeddata_dst);
398 /* copy the image data */
399 row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
400 for (i=0; i<lockeddata_src.Height; i++)
401 memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
402 (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
405 GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
408 GdipBitmapUnlockBits(bitmap, &lockeddata_src);
413 GdipDisposeImage(*cloneImage);
417 memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
423 ERR("GpImage with no IPicture or bitmap?!\n");
424 return NotImplemented;
428 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
434 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
436 if(!filename || !bitmap)
437 return InvalidParameter;
439 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
444 stat = GdipCreateBitmapFromStream(stream, bitmap);
446 IStream_Release(stream);
451 GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
452 VOID *bits, GpBitmap **bitmap)
454 DWORD height, stride;
457 FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
459 height = abs(info->bmiHeader.biHeight);
460 stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
462 if(info->bmiHeader.biHeight > 0) /* bottom-up */
464 bits = (BYTE*)bits + (height - 1) * stride;
468 switch(info->bmiHeader.biBitCount) {
470 format = PixelFormat1bppIndexed;
473 format = PixelFormat4bppIndexed;
476 format = PixelFormat8bppIndexed;
479 format = PixelFormat24bppRGB;
482 FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
484 return InvalidParameter;
487 return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
493 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
496 TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
498 return GdipCreateBitmapFromFile(filename, bitmap);
501 GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
502 GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
505 GpStatus stat = InvalidParameter;
507 TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
509 if(!lpBitmapName || !bitmap)
510 return InvalidParameter;
513 hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
514 LR_CREATEDIBSECTION);
517 stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
524 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
525 HBITMAP* hbmReturn, ARGB background)
528 HBITMAP result, oldbitmap;
531 GpGraphics *graphics;
532 BITMAPINFOHEADER bih;
534 TRACE("(%p,%p,%x)\n", bitmap, hbmReturn, background);
536 if (!bitmap || !hbmReturn) return InvalidParameter;
538 GdipGetImageWidth((GpImage*)bitmap, &width);
539 GdipGetImageHeight((GpImage*)bitmap, &height);
541 bih.biSize = sizeof(bih);
543 bih.biHeight = height;
546 bih.biCompression = BI_RGB;
548 bih.biXPelsPerMeter = 0;
549 bih.biYPelsPerMeter = 0;
551 bih.biClrImportant = 0;
553 hdc = CreateCompatibleDC(NULL);
554 if (!hdc) return GenericError;
556 result = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS, &bits,
561 oldbitmap = SelectObject(hdc, result);
563 stat = GdipCreateFromHDC(hdc, &graphics);
566 stat = GdipGraphicsClear(graphics, background);
569 stat = GdipDrawImage(graphics, (GpImage*)bitmap, 0, 0);
571 GdipDeleteGraphics(graphics);
574 SelectObject(hdc, oldbitmap);
581 if (stat != Ok && result)
583 DeleteObject(result);
592 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
593 GpMetafile* metafile, BOOL* succ, EmfType emfType,
594 const WCHAR* description, GpMetafile** out_metafile)
598 if(!ref || !metafile || !out_metafile)
599 return InvalidParameter;
602 *out_metafile = NULL;
605 FIXME("not implemented\n");
607 return NotImplemented;
610 /* FIXME: this should create a bitmap in the given size with the attributes
611 * (resolution etc.) of the graphics object */
612 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
613 GpGraphics* target, GpBitmap** bitmap)
618 if(!target || !bitmap)
619 return InvalidParameter;
622 FIXME("hacked stub\n");
624 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
630 GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
638 BitmapData lockeddata;
643 BITMAPINFOHEADER bih;
648 TRACE("%p, %p\n", hicon, bitmap);
650 if(!bitmap || !GetIconInfo(hicon, &iinfo))
652 DeleteObject(iinfo.hbmColor);
653 DeleteObject(iinfo.hbmMask);
654 return InvalidParameter;
657 /* get the size of the icon */
658 ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
660 DeleteObject(iinfo.hbmColor);
661 DeleteObject(iinfo.hbmMask);
668 height = abs(bm.bmHeight);
669 else /* combined bitmap + mask */
670 height = abs(bm.bmHeight) / 2;
672 bits = HeapAlloc(GetProcessHeap(), 0, 4*width*height);
674 DeleteObject(iinfo.hbmColor);
675 DeleteObject(iinfo.hbmMask);
679 stat = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat32bppARGB, NULL, bitmap);
681 DeleteObject(iinfo.hbmColor);
682 DeleteObject(iinfo.hbmMask);
683 HeapFree(GetProcessHeap(), 0, bits);
690 rect.Height = height;
692 stat = GdipBitmapLockBits(*bitmap, &rect, ImageLockModeWrite, PixelFormat32bppARGB, &lockeddata);
694 DeleteObject(iinfo.hbmColor);
695 DeleteObject(iinfo.hbmMask);
696 HeapFree(GetProcessHeap(), 0, bits);
697 GdipDisposeImage((GpImage*)*bitmap);
701 bih.biSize = sizeof(bih);
703 bih.biHeight = -height;
706 bih.biCompression = BI_RGB;
708 bih.biXPelsPerMeter = 0;
709 bih.biYPelsPerMeter = 0;
711 bih.biClrImportant = 0;
716 GetDIBits(screendc, iinfo.hbmColor, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
718 if (bm.bmBitsPixel == 32)
722 /* If any pixel has a non-zero alpha, ignore hbmMask */
724 for (x=0; x<width && !has_alpha; x++)
725 for (y=0; y<height && !has_alpha; y++)
726 if ((*src++ & 0xff000000) != 0)
729 else has_alpha = FALSE;
733 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
737 /* copy the image data to the Bitmap */
739 dst_row = lockeddata.Scan0;
740 for (y=0; y<height; y++)
742 memcpy(dst_row, src, width*4);
744 dst_row += lockeddata.Stride;
751 /* read alpha data from the mask */
753 GetDIBits(screendc, iinfo.hbmMask, 0, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
755 GetDIBits(screendc, iinfo.hbmMask, height, height, bits, (BITMAPINFO*)&bih, DIB_RGB_COLORS);
758 dst_row = lockeddata.Scan0;
759 for (y=0; y<height; y++)
761 dst = (DWORD*)dst_row;
762 for (x=0; x<height; x++)
764 DWORD src_value = *src++;
768 *dst++ |= 0xff000000;
770 dst_row += lockeddata.Stride;
775 /* set constant alpha of 255 */
777 for (y=0; y<height; y++)
779 dst = (DWORD*)dst_row;
780 for (x=0; x<height; x++)
781 *dst++ |= 0xff000000;
782 dst_row += lockeddata.Stride;
787 ReleaseDC(0, screendc);
789 DeleteObject(iinfo.hbmColor);
790 DeleteObject(iinfo.hbmMask);
792 GdipBitmapUnlockBits(*bitmap, &lockeddata);
794 HeapFree(GetProcessHeap(), 0, bits);
799 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
800 PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
802 BITMAPINFOHEADER bmih;
804 INT row_size, dib_stride;
809 TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
811 if (!bitmap) return InvalidParameter;
813 if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
815 return InvalidParameter;
819 return InvalidParameter;
821 row_size = (width * PIXELFORMATBPP(format)+7) / 8;
822 dib_stride = (row_size + 3) & ~3;
827 bmih.biSize = sizeof(BITMAPINFOHEADER);
828 bmih.biWidth = width;
829 bmih.biHeight = -height;
831 /* FIXME: use the rest of the data from format */
832 bmih.biBitCount = PIXELFORMATBPP(format);
833 bmih.biCompression = BI_RGB;
834 bmih.biSizeImage = 0;
835 bmih.biXPelsPerMeter = 0;
836 bmih.biYPelsPerMeter = 0;
838 bmih.biClrImportant = 0;
840 hdc = CreateCompatibleDC(NULL);
841 if (!hdc) return GenericError;
843 hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits,
848 if (!hbitmap) return GenericError;
850 /* copy bits to the dib if necessary */
851 /* FIXME: should reference the bits instead of copying them */
853 for (i=0; i<height; i++)
854 memcpy(bits+i*dib_stride, scan0+i*stride, row_size);
856 *bitmap = GdipAlloc(sizeof(GpBitmap));
859 DeleteObject(hbitmap);
863 (*bitmap)->image.type = ImageTypeBitmap;
864 memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
865 (*bitmap)->image.flags = ImageFlagsNone;
866 (*bitmap)->width = width;
867 (*bitmap)->height = height;
868 (*bitmap)->format = format;
869 (*bitmap)->image.picture = NULL;
870 (*bitmap)->hbitmap = hbitmap;
871 (*bitmap)->hdc = NULL;
872 (*bitmap)->bits = bits;
873 (*bitmap)->stride = dib_stride;
878 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
883 TRACE("%p %p\n", stream, bitmap);
885 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
890 if((*bitmap)->image.type != ImageTypeBitmap){
891 GdipDisposeImage(&(*bitmap)->image);
893 return GenericError; /* FIXME: what error to return? */
900 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
903 TRACE("%p %p\n", stream, bitmap);
905 return GdipCreateBitmapFromStream(stream, bitmap);
908 GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
909 GpCachedBitmap **cachedbmp)
913 TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
915 if(!bitmap || !graphics || !cachedbmp)
916 return InvalidParameter;
918 *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
922 stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
924 GdipFree(*cachedbmp);
931 GpStatus WINGDIPAPI GdipCreateHICONFromBitmap(GpBitmap *bitmap, HICON *hicon)
933 FIXME("(%p, %p)\n", bitmap, hicon);
935 return NotImplemented;
938 GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
940 TRACE("%p\n", cachedbmp);
943 return InvalidParameter;
945 GdipDisposeImage(cachedbmp->image);
951 GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
952 GpCachedBitmap *cachedbmp, INT x, INT y)
954 TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
956 if(!graphics || !cachedbmp)
957 return InvalidParameter;
959 return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
962 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
963 LPBYTE pData16, INT iMapMode, INT eFlags)
965 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
966 return NotImplemented;
969 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
971 TRACE("%p\n", image);
974 return InvalidParameter;
977 IPicture_Release(image->picture);
978 if (image->type == ImageTypeBitmap)
980 GdipFree(((GpBitmap*)image)->bitmapbits);
981 DeleteDC(((GpBitmap*)image)->hdc);
988 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
991 return InvalidParameter;
993 return NotImplemented;
996 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
999 TRACE("%p %p %p\n", image, srcRect, srcUnit);
1001 if(!image || !srcRect || !srcUnit)
1002 return InvalidParameter;
1003 if(image->type == ImageTypeMetafile){
1004 *srcRect = ((GpMetafile*)image)->bounds;
1005 *srcUnit = ((GpMetafile*)image)->unit;
1007 else if(image->type == ImageTypeBitmap){
1008 srcRect->X = srcRect->Y = 0.0;
1009 srcRect->Width = (REAL) ((GpBitmap*)image)->width;
1010 srcRect->Height = (REAL) ((GpBitmap*)image)->height;
1011 *srcUnit = UnitPixel;
1014 srcRect->X = srcRect->Y = 0.0;
1015 srcRect->Width = ipicture_pixel_width(image->picture);
1016 srcRect->Height = ipicture_pixel_height(image->picture);
1017 *srcUnit = UnitPixel;
1020 TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
1021 srcRect->Width, srcRect->Height, *srcUnit);
1026 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
1029 TRACE("%p %p %p\n", image, width, height);
1031 if(!image || !height || !width)
1032 return InvalidParameter;
1034 if(image->type == ImageTypeMetafile){
1037 *height = convert_unit(hdc, ((GpMetafile*)image)->unit) *
1038 ((GpMetafile*)image)->bounds.Height;
1040 *width = convert_unit(hdc, ((GpMetafile*)image)->unit) *
1041 ((GpMetafile*)image)->bounds.Width;
1046 else if(image->type == ImageTypeBitmap){
1047 *height = ((GpBitmap*)image)->height;
1048 *width = ((GpBitmap*)image)->width;
1051 *height = ipicture_pixel_height(image->picture);
1052 *width = ipicture_pixel_width(image->picture);
1055 TRACE("returning (%f, %f)\n", *height, *width);
1059 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
1060 GpGraphics **graphics)
1064 TRACE("%p %p\n", image, graphics);
1066 if(!image || !graphics)
1067 return InvalidParameter;
1069 if(image->type != ImageTypeBitmap){
1070 FIXME("not implemented for image type %d\n", image->type);
1071 return NotImplemented;
1074 hdc = ((GpBitmap*)image)->hdc;
1077 hdc = CreateCompatibleDC(0);
1078 SelectObject(hdc, ((GpBitmap*)image)->hbitmap);
1079 ((GpBitmap*)image)->hdc = hdc;
1082 return GdipCreateFromHDC(hdc, graphics);
1085 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
1087 TRACE("%p %p\n", image, height);
1089 if(!image || !height)
1090 return InvalidParameter;
1092 if(image->type == ImageTypeMetafile){
1095 *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
1096 ((GpMetafile*)image)->bounds.Height);
1100 else if(image->type == ImageTypeBitmap)
1101 *height = ((GpBitmap*)image)->height;
1103 *height = ipicture_pixel_height(image->picture);
1105 TRACE("returning %d\n", *height);
1110 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
1115 return InvalidParameter;
1118 FIXME("not implemented\n");
1120 return NotImplemented;
1123 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
1125 FIXME("%p %p\n", image, size);
1128 return InvalidParameter;
1130 return NotImplemented;
1133 /* FIXME: test this function for non-bitmap types */
1134 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
1136 TRACE("%p %p\n", image, format);
1138 if(!image || !format)
1139 return InvalidParameter;
1141 if(image->type != ImageTypeBitmap)
1142 *format = PixelFormat24bppRGB;
1144 *format = ((GpBitmap*) image)->format;
1149 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
1151 if(!image || !format)
1152 return InvalidParameter;
1154 memcpy(format, &image->format, sizeof(GUID));
1159 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
1161 TRACE("%p %p\n", image, type);
1164 return InvalidParameter;
1166 *type = image->type;
1171 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
1176 return InvalidParameter;
1179 FIXME("not implemented\n");
1181 return NotImplemented;
1184 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
1186 TRACE("%p %p\n", image, width);
1188 if(!image || !width)
1189 return InvalidParameter;
1191 if(image->type == ImageTypeMetafile){
1194 *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
1195 ((GpMetafile*)image)->bounds.Width);
1199 else if(image->type == ImageTypeBitmap)
1200 *width = ((GpBitmap*)image)->width;
1202 *width = ipicture_pixel_width(image->picture);
1204 TRACE("returning %d\n", *width);
1209 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
1210 MetafileHeader * header)
1214 if(!metafile || !header)
1215 return InvalidParameter;
1218 FIXME("not implemented\n");
1223 GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
1224 UINT num, PropertyItem* items)
1229 FIXME("not implemented\n");
1231 return InvalidParameter;
1234 GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
1239 FIXME("not implemented\n");
1241 return InvalidParameter;
1244 GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
1249 FIXME("not implemented\n");
1251 return InvalidParameter;
1254 GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
1255 PropertyItem* buffer)
1260 FIXME("not implemented\n");
1262 return InvalidParameter;
1265 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
1270 TRACE("%p %x %p\n", image, pid, size);
1273 return InvalidParameter;
1276 FIXME("not implemented\n");
1278 return NotImplemented;
1281 GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
1286 FIXME("not implemented\n");
1288 return InvalidParameter;
1291 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
1292 GDIPCONST GUID* dimensionID, UINT* count)
1296 if(!image || !dimensionID || !count)
1297 return InvalidParameter;
1300 FIXME("not implemented\n");
1302 return NotImplemented;
1305 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
1308 if(!image || !count)
1309 return InvalidParameter;
1318 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
1319 GUID* dimensionIDs, UINT count)
1323 if(!image || !dimensionIDs)
1324 return InvalidParameter;
1327 FIXME("not implemented\n");
1332 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
1333 GDIPCONST GUID* dimensionID, UINT frameidx)
1337 if(!image || !dimensionID)
1338 return InvalidParameter;
1341 FIXME("not implemented\n");
1346 GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
1352 TRACE("(%s) %p\n", debugstr_w(filename), image);
1354 if (!filename || !image)
1355 return InvalidParameter;
1357 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
1362 stat = GdipLoadImageFromStream(stream, image);
1364 IStream_Release(stream);
1369 /* FIXME: no icm handling */
1370 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
1372 TRACE("(%s) %p\n", debugstr_w(filename), image);
1374 return GdipLoadImageFromFile(filename, image);
1377 static const WICPixelFormatGUID *wic_pixel_formats[] = {
1378 &GUID_WICPixelFormat16bppBGR555,
1379 &GUID_WICPixelFormat24bppBGR,
1380 &GUID_WICPixelFormat32bppBGR,
1381 &GUID_WICPixelFormat32bppBGRA,
1382 &GUID_WICPixelFormat32bppPBGRA,
1386 static const PixelFormat wic_gdip_formats[] = {
1387 PixelFormat16bppRGB555,
1388 PixelFormat24bppRGB,
1389 PixelFormat32bppRGB,
1390 PixelFormat32bppARGB,
1391 PixelFormat32bppPARGB,
1394 static GpStatus decode_image_wic(IStream* stream, REFCLSID clsid, GpImage **image)
1399 IWICBitmapDecoder *decoder;
1400 IWICBitmapFrameDecode *frame;
1401 IWICBitmapSource *source=NULL;
1402 WICPixelFormatGUID wic_format;
1403 PixelFormat gdip_format=0;
1406 BitmapData lockeddata;
1410 initresult = CoInitialize(NULL);
1412 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
1413 &IID_IWICBitmapDecoder, (void**)&decoder);
1414 if (FAILED(hr)) goto end;
1416 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1418 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1420 if (SUCCEEDED(hr)) /* got frame */
1422 hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &wic_format);
1426 for (i=0; wic_pixel_formats[i]; i++)
1428 if (IsEqualGUID(&wic_format, wic_pixel_formats[i]))
1430 source = (IWICBitmapSource*)frame;
1431 IWICBitmapSource_AddRef(source);
1432 gdip_format = wic_gdip_formats[i];
1438 /* unknown format; fall back on 32bppARGB */
1439 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)frame, &source);
1440 gdip_format = PixelFormat32bppARGB;
1444 if (SUCCEEDED(hr)) /* got source */
1446 hr = IWICBitmapSource_GetSize(source, &width, &height);
1449 status = GdipCreateBitmapFromScan0(width, height, 0, gdip_format,
1452 if (SUCCEEDED(hr) && status == Ok) /* created bitmap */
1454 status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeWrite,
1455 gdip_format, &lockeddata);
1456 if (status == Ok) /* locked bitmap */
1461 for (i=0; i<height; i++)
1464 hr = IWICBitmapSource_CopyPixels(source, &wrc, abs(lockeddata.Stride),
1465 abs(lockeddata.Stride), (BYTE*)lockeddata.Scan0+lockeddata.Stride*i);
1466 if (FAILED(hr)) break;
1469 GdipBitmapUnlockBits(bitmap, &lockeddata);
1472 if (SUCCEEDED(hr) && status == Ok)
1473 *image = (GpImage*)bitmap;
1477 GdipDisposeImage((GpImage*)bitmap);
1481 IWICBitmapSource_Release(source);
1484 IWICBitmapFrameDecode_Release(frame);
1487 IWICBitmapDecoder_Release(decoder);
1490 if (SUCCEEDED(initresult)) CoUninitialize();
1492 if (FAILED(hr) && status == Ok) status = hresult_to_status(hr);
1497 static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **image)
1499 return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
1502 static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
1507 status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
1509 bitmap = (GpBitmap*)*image;
1511 if (status == Ok && bitmap->format == PixelFormat32bppARGB)
1513 /* WIC supports bmp files with alpha, but gdiplus does not */
1514 bitmap->format = PixelFormat32bppRGB;
1520 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
1522 return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
1525 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
1527 return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
1530 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
1532 return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
1535 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
1539 TRACE("%p %p\n", stream, image);
1541 if(!stream || !image)
1542 return InvalidParameter;
1544 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
1545 (LPVOID*) &pic) != S_OK){
1546 TRACE("Could not load picture\n");
1547 return GenericError;
1550 /* FIXME: missing initialization code */
1551 *image = GdipAlloc(sizeof(GpMetafile));
1552 if(!*image) return OutOfMemory;
1553 (*image)->type = ImageTypeMetafile;
1554 (*image)->picture = pic;
1555 (*image)->flags = ImageFlagsNone;
1560 typedef GpStatus (*encode_image_func)(GpImage *image, IStream* stream,
1561 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params);
1563 typedef GpStatus (*decode_image_func)(IStream *stream, REFCLSID clsid, GpImage** image);
1565 typedef struct image_codec {
1566 ImageCodecInfo info;
1567 encode_image_func encode_func;
1568 decode_image_func decode_func;
1582 static const struct image_codec codecs[NUM_CODECS];
1584 static GpStatus get_decoder_info(IStream* stream, const struct image_codec **result)
1592 /* seek to the start of the stream */
1594 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
1595 if (FAILED(hr)) return hresult_to_status(hr);
1597 /* read the first 8 bytes */
1598 /* FIXME: This assumes all codecs have one signature <= 8 bytes in length */
1599 hr = IStream_Read(stream, signature, 8, &bytesread);
1600 if (FAILED(hr)) return hresult_to_status(hr);
1601 if (hr == S_FALSE || bytesread == 0) return GenericError;
1603 for (i = 0; i < NUM_CODECS; i++) {
1604 if ((codecs[i].info.Flags & ImageCodecFlagsDecoder) &&
1605 bytesread >= codecs[i].info.SigSize)
1607 for (j=0; j<codecs[i].info.SigSize; j++)
1608 if ((signature[j] & codecs[i].info.SigMask[j]) != codecs[i].info.SigPattern[j])
1610 if (j == codecs[i].info.SigSize)
1612 *result = &codecs[i];
1618 TRACE("no match for %i byte signature %x %x %x %x %x %x %x %x\n", bytesread,
1619 signature[0],signature[1],signature[2],signature[3],
1620 signature[4],signature[5],signature[6],signature[7]);
1622 return GenericError;
1625 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
1630 const struct image_codec *codec=NULL;
1632 /* choose an appropriate image decoder */
1633 stat = get_decoder_info(stream, &codec);
1634 if (stat != Ok) return stat;
1636 /* seek to the start of the stream */
1638 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
1639 if (FAILED(hr)) return hresult_to_status(hr);
1641 /* call on the image decoder to do the real work */
1642 stat = codec->decode_func(stream, &codec->info.Clsid, image);
1644 /* take note of the original data format */
1647 memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
1654 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
1656 TRACE("%p %p\n", stream, image);
1658 return GdipLoadImageFromStream(stream, image);
1661 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
1666 return InvalidParameter;
1669 FIXME("not implemented\n");
1671 return NotImplemented;
1674 GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
1679 FIXME("not implemented\n");
1681 return NotImplemented;
1684 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
1685 GDIPCONST CLSID *clsidEncoder,
1686 GDIPCONST EncoderParameters *encoderParams)
1691 TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
1693 if (!image || !filename|| !clsidEncoder)
1694 return InvalidParameter;
1696 stat = GdipCreateStreamOnFile(filename, GENERIC_WRITE, &stream);
1698 return GenericError;
1700 stat = GdipSaveImageToStream(image, stream, clsidEncoder, encoderParams);
1702 IStream_Release(stream);
1706 /*************************************************************************
1707 * Encoding functions -
1708 * These functions encode an image in different image file formats.
1710 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1711 #define BITMAP_FORMAT_JPEG 0xd8ff
1712 #define BITMAP_FORMAT_GIF 0x4947
1713 #define BITMAP_FORMAT_PNG 0x5089
1714 #define BITMAP_FORMAT_APM 0xcdd7
1716 static GpStatus encode_image_WIC(GpImage *image, IStream* stream,
1717 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1721 IWICBitmapEncoder *encoder;
1722 IWICBitmapFrameEncode *frameencode;
1723 IPropertyBag2 *encoderoptions;
1726 PixelFormat gdipformat=0;
1727 WICPixelFormatGUID wicformat;
1729 BitmapData lockeddata;
1733 if (image->type != ImageTypeBitmap)
1734 return GenericError;
1736 bitmap = (GpBitmap*)image;
1738 GdipGetImageWidth(image, &width);
1739 GdipGetImageHeight(image, &height);
1746 initresult = CoInitialize(NULL);
1748 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
1749 &IID_IWICBitmapEncoder, (void**)&encoder);
1752 if (SUCCEEDED(initresult)) CoUninitialize();
1753 return hresult_to_status(hr);
1756 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
1760 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &encoderoptions);
1763 if (SUCCEEDED(hr)) /* created frame */
1765 hr = IWICBitmapFrameEncode_Initialize(frameencode, encoderoptions);
1768 hr = IWICBitmapFrameEncode_SetSize(frameencode, width, height);
1771 /* FIXME: use the resolution from the image */
1772 hr = IWICBitmapFrameEncode_SetResolution(frameencode, 96.0, 96.0);
1776 for (i=0; wic_pixel_formats[i]; i++)
1778 if (wic_gdip_formats[i] == bitmap->format)
1781 if (wic_pixel_formats[i])
1782 memcpy(&wicformat, wic_pixel_formats[i], sizeof(GUID));
1784 memcpy(&wicformat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
1786 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &wicformat);
1788 for (i=0; wic_pixel_formats[i]; i++)
1790 if (IsEqualGUID(&wicformat, wic_pixel_formats[i]))
1793 if (wic_pixel_formats[i])
1794 gdipformat = wic_gdip_formats[i];
1797 ERR("cannot provide pixel format %s\n", debugstr_guid(&wicformat));
1804 stat = GdipBitmapLockBits(bitmap, &rc, ImageLockModeRead, gdipformat,
1809 UINT row_size = (lockeddata.Width * PIXELFORMATBPP(gdipformat) + 7)/8;
1812 /* write one row at a time in case stride is negative */
1813 row = lockeddata.Scan0;
1814 for (i=0; i<lockeddata.Height; i++)
1816 hr = IWICBitmapFrameEncode_WritePixels(frameencode, 1, row_size, row_size, row);
1817 if (FAILED(hr)) break;
1818 row += lockeddata.Stride;
1821 GdipBitmapUnlockBits(bitmap, &lockeddata);
1828 hr = IWICBitmapFrameEncode_Commit(frameencode);
1830 IWICBitmapFrameEncode_Release(frameencode);
1831 IPropertyBag2_Release(encoderoptions);
1835 hr = IWICBitmapEncoder_Commit(encoder);
1837 IWICBitmapEncoder_Release(encoder);
1839 if (SUCCEEDED(initresult)) CoUninitialize();
1841 return hresult_to_status(hr);
1844 static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
1845 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1847 return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
1850 /*****************************************************************************
1851 * GdipSaveImageToStream [GDIPLUS.@]
1853 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
1854 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
1857 encode_image_func encode_image;
1860 TRACE("%p %p %p %p\n", image, stream, clsid, params);
1862 if(!image || !stream)
1863 return InvalidParameter;
1865 /* select correct encoder */
1866 encode_image = NULL;
1867 for (i = 0; i < NUM_CODECS; i++) {
1868 if ((codecs[i].info.Flags & ImageCodecFlagsEncoder) &&
1869 IsEqualCLSID(clsid, &codecs[i].info.Clsid))
1870 encode_image = codecs[i].encode_func;
1872 if (encode_image == NULL)
1873 return UnknownImageFormat;
1875 stat = encode_image(image, stream, clsid, params);
1880 /*****************************************************************************
1881 * GdipGetImagePalette [GDIPLUS.@]
1883 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
1885 static int calls = 0;
1888 return InvalidParameter;
1891 FIXME("not implemented\n");
1893 return NotImplemented;
1896 /*****************************************************************************
1897 * GdipSetImagePalette [GDIPLUS.@]
1899 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
1900 GDIPCONST ColorPalette *palette)
1904 if(!image || !palette)
1905 return InvalidParameter;
1908 FIXME("not implemented\n");
1910 return NotImplemented;
1913 /*************************************************************************
1915 * Structures that represent which formats we support for encoding.
1918 /* ImageCodecInfo creation routines taken from libgdiplus */
1919 static const WCHAR bmp_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'B', 'M', 'P', 0}; /* Built-in BMP */
1920 static const WCHAR bmp_extension[] = {'*','.','B', 'M', 'P',';', '*','.', 'D','I', 'B',';', '*','.', 'R', 'L', 'E',0}; /* *.BMP;*.DIB;*.RLE */
1921 static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0}; /* image/bmp */
1922 static const WCHAR bmp_format[] = {'B', 'M', 'P', 0}; /* BMP */
1923 static const BYTE bmp_sig_pattern[] = { 0x42, 0x4D };
1924 static const BYTE bmp_sig_mask[] = { 0xFF, 0xFF };
1926 static const WCHAR jpeg_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'J','P','E','G', 0};
1927 static const WCHAR jpeg_extension[] = {'*','.','J','P','G',';', '*','.','J','P','E','G',';', '*','.','J','P','E',';', '*','.','J','F','I','F',0};
1928 static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
1929 static const WCHAR jpeg_format[] = {'J','P','E','G',0};
1930 static const BYTE jpeg_sig_pattern[] = { 0xFF, 0xD8 };
1931 static const BYTE jpeg_sig_mask[] = { 0xFF, 0xFF };
1933 static const WCHAR gif_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'G','I','F', 0};
1934 static const WCHAR gif_extension[] = {'*','.','G','I','F',0};
1935 static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
1936 static const WCHAR gif_format[] = {'G','I','F',0};
1937 static const BYTE gif_sig_pattern[4] = "GIF8";
1938 static const BYTE gif_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1940 static const WCHAR emf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'E','M','F', 0};
1941 static const WCHAR emf_extension[] = {'*','.','E','M','F',0};
1942 static const WCHAR emf_mimetype[] = {'i','m','a','g','e','/','x','-','e','m','f', 0};
1943 static const WCHAR emf_format[] = {'E','M','F',0};
1944 static const BYTE emf_sig_pattern[] = { 0x01, 0x00, 0x00, 0x00 };
1945 static const BYTE emf_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1947 static const WCHAR wmf_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'W','M','F', 0};
1948 static const WCHAR wmf_extension[] = {'*','.','W','M','F',0};
1949 static const WCHAR wmf_mimetype[] = {'i','m','a','g','e','/','x','-','w','m','f', 0};
1950 static const WCHAR wmf_format[] = {'W','M','F',0};
1951 static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
1952 static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
1954 static const WCHAR png_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'P','N','G', 0};
1955 static const WCHAR png_extension[] = {'*','.','P','N','G',0};
1956 static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
1957 static const WCHAR png_format[] = {'P','N','G',0};
1958 static const BYTE png_sig_pattern[] = { 137, 80, 78, 71, 13, 10, 26, 10, };
1959 static const BYTE png_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
1961 static const WCHAR ico_codecname[] = {'B', 'u', 'i','l', 't', '-','i', 'n', ' ', 'I','C','O', 0};
1962 static const WCHAR ico_extension[] = {'*','.','I','C','O',0};
1963 static const WCHAR ico_mimetype[] = {'i','m','a','g','e','/','x','-','i','c','o','n', 0};
1964 static const WCHAR ico_format[] = {'I','C','O',0};
1965 static const BYTE ico_sig_pattern[] = { 0x00, 0x00, 0x01, 0x00 };
1966 static const BYTE ico_sig_mask[] = { 0xFF, 0xFF, 0xFF, 0xFF };
1968 static const struct image_codec codecs[NUM_CODECS] = {
1971 /* Clsid */ { 0x557cf400, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
1972 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
1973 /* CodecName */ bmp_codecname,
1975 /* FormatDescription */ bmp_format,
1976 /* FilenameExtension */ bmp_extension,
1977 /* MimeType */ bmp_mimetype,
1978 /* Flags */ ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
1982 /* SigPattern */ bmp_sig_pattern,
1983 /* SigMask */ bmp_sig_mask,
1990 /* Clsid */ { 0x557cf401, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
1991 /* FormatID */ { 0xb96b3caeU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
1992 /* CodecName */ jpeg_codecname,
1994 /* FormatDescription */ jpeg_format,
1995 /* FilenameExtension */ jpeg_extension,
1996 /* MimeType */ jpeg_mimetype,
1997 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2001 /* SigPattern */ jpeg_sig_pattern,
2002 /* SigMask */ jpeg_sig_mask,
2009 /* Clsid */ { 0x557cf402, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2010 /* FormatID */ { 0xb96b3cb0U, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2011 /* CodecName */ gif_codecname,
2013 /* FormatDescription */ gif_format,
2014 /* FilenameExtension */ gif_extension,
2015 /* MimeType */ gif_mimetype,
2016 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2020 /* SigPattern */ gif_sig_pattern,
2021 /* SigMask */ gif_sig_mask,
2028 /* Clsid */ { 0x557cf403, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2029 /* FormatID */ { 0xb96b3cacU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2030 /* CodecName */ emf_codecname,
2032 /* FormatDescription */ emf_format,
2033 /* FilenameExtension */ emf_extension,
2034 /* MimeType */ emf_mimetype,
2035 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
2039 /* SigPattern */ emf_sig_pattern,
2040 /* SigMask */ emf_sig_mask,
2043 decode_image_olepicture_metafile
2047 /* Clsid */ { 0x557cf404, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2048 /* FormatID */ { 0xb96b3cadU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2049 /* CodecName */ wmf_codecname,
2051 /* FormatDescription */ wmf_format,
2052 /* FilenameExtension */ wmf_extension,
2053 /* MimeType */ wmf_mimetype,
2054 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
2058 /* SigPattern */ wmf_sig_pattern,
2059 /* SigMask */ wmf_sig_mask,
2062 decode_image_olepicture_metafile
2066 /* Clsid */ { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2067 /* FormatID */ { 0xb96b3cafU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2068 /* CodecName */ png_codecname,
2070 /* FormatDescription */ png_format,
2071 /* FilenameExtension */ png_extension,
2072 /* MimeType */ png_mimetype,
2073 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2077 /* SigPattern */ png_sig_pattern,
2078 /* SigMask */ png_sig_mask,
2085 /* Clsid */ { 0x557cf407, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x0, 0x0, 0xf8, 0x1e, 0xf3, 0x2e } },
2086 /* FormatID */ { 0xb96b3cabU, 0x0728U, 0x11d3U, {0x9d, 0x7b, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e} },
2087 /* CodecName */ ico_codecname,
2089 /* FormatDescription */ ico_format,
2090 /* FilenameExtension */ ico_extension,
2091 /* MimeType */ ico_mimetype,
2092 /* Flags */ ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
2096 /* SigPattern */ ico_sig_pattern,
2097 /* SigMask */ ico_sig_mask,
2104 /*****************************************************************************
2105 * GdipGetImageDecodersSize [GDIPLUS.@]
2107 GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
2109 int decoder_count=0;
2111 TRACE("%p %p\n", numDecoders, size);
2113 if (!numDecoders || !size)
2114 return InvalidParameter;
2116 for (i=0; i<NUM_CODECS; i++)
2118 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
2122 *numDecoders = decoder_count;
2123 *size = decoder_count * sizeof(ImageCodecInfo);
2128 /*****************************************************************************
2129 * GdipGetImageDecoders [GDIPLUS.@]
2131 GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
2133 int i, decoder_count=0;
2134 TRACE("%u %u %p\n", numDecoders, size, decoders);
2137 size != numDecoders * sizeof(ImageCodecInfo))
2138 return GenericError;
2140 for (i=0; i<NUM_CODECS; i++)
2142 if (codecs[i].info.Flags & ImageCodecFlagsDecoder)
2144 if (decoder_count == numDecoders) return GenericError;
2145 memcpy(&decoders[decoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
2150 if (decoder_count < numDecoders) return GenericError;
2155 /*****************************************************************************
2156 * GdipGetImageEncodersSize [GDIPLUS.@]
2158 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
2160 int encoder_count=0;
2162 TRACE("%p %p\n", numEncoders, size);
2164 if (!numEncoders || !size)
2165 return InvalidParameter;
2167 for (i=0; i<NUM_CODECS; i++)
2169 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
2173 *numEncoders = encoder_count;
2174 *size = encoder_count * sizeof(ImageCodecInfo);
2179 /*****************************************************************************
2180 * GdipGetImageEncoders [GDIPLUS.@]
2182 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
2184 int i, encoder_count=0;
2185 TRACE("%u %u %p\n", numEncoders, size, encoders);
2188 size != numEncoders * sizeof(ImageCodecInfo))
2189 return GenericError;
2191 for (i=0; i<NUM_CODECS; i++)
2193 if (codecs[i].info.Flags & ImageCodecFlagsEncoder)
2195 if (encoder_count == numEncoders) return GenericError;
2196 memcpy(&encoders[encoder_count], &codecs[i].info, sizeof(ImageCodecInfo));
2201 if (encoder_count < numEncoders) return GenericError;
2206 /*****************************************************************************
2207 * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
2209 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
2216 TRACE("%p %p %p\n", hbm, hpal, bitmap);
2219 return InvalidParameter;
2221 /* TODO: Support for device-dependent bitmaps */
2223 FIXME("no support for device-dependent bitmaps\n");
2224 return NotImplemented;
2227 if (GetObjectA(hbm, sizeof(bm), &bm) != sizeof(bm))
2228 return InvalidParameter;
2230 /* TODO: Figure out the correct format for 16, 32, 64 bpp */
2231 switch(bm.bmBitsPixel) {
2233 format = PixelFormat1bppIndexed;
2236 format = PixelFormat4bppIndexed;
2239 format = PixelFormat8bppIndexed;
2242 format = PixelFormat24bppRGB;
2245 format = PixelFormat32bppRGB;
2248 format = PixelFormat48bppRGB;
2251 FIXME("don't know how to handle %d bpp\n", bm.bmBitsPixel);
2252 return InvalidParameter;
2256 bits = (BYTE*)bm.bmBits + (bm.bmHeight - 1) * bm.bmWidthBytes;
2259 FIXME("can only get image data from DIB sections\n");
2263 retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, -bm.bmWidthBytes,
2264 format, bits, bitmap);
2269 GpStatus WINGDIPAPI GdipDeleteEffect(CGpEffect *effect)
2271 FIXME("(%p): stub\n", effect);
2272 /* note: According to Jose Roca's GDI+ Docs, this is not implemented
2273 * in Windows's gdiplus */
2274 return NotImplemented;
2277 /*****************************************************************************
2278 * GdipSetEffectParameters [GDIPLUS.@]
2280 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
2281 const VOID *params, const UINT size)
2286 FIXME("not implemented\n");
2288 return NotImplemented;
2291 /*****************************************************************************
2292 * GdipGetImageFlags [GDIPLUS.@]
2294 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
2296 TRACE("%p %p\n", image, flags);
2298 if(!image || !flags)
2299 return InvalidParameter;
2301 *flags = image->flags;
2306 GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
2308 TRACE("(%d, %p)\n", control, param);
2311 case TestControlForceBilinear:
2313 FIXME("TestControlForceBilinear not handled\n");
2315 case TestControlNoICM:
2317 FIXME("TestControlNoICM not handled\n");
2319 case TestControlGetBuildNumber:
2320 *((DWORD*)param) = 3102;
2327 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
2328 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
2329 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
2330 GpMetafile **metafile)
2332 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2333 frameUnit, debugstr_w(desc), metafile);
2335 return NotImplemented;
2338 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
2339 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
2340 GDIPCONST WCHAR *desc, GpMetafile **metafile)
2342 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2343 frameUnit, debugstr_w(desc), metafile);
2345 return NotImplemented;
2348 GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
2350 FIXME("%p\n", image);
2355 /*****************************************************************************
2356 * GdipGetImageThumbnail [GDIPLUS.@]
2358 GpStatus WINGDIPAPI GdipGetImageThumbnail(GpImage *image, UINT width, UINT height,
2359 GpImage **ret_image, GetThumbnailImageAbort cb,
2362 FIXME("(%p %u %u %p %p %p) stub\n",
2363 image, width, height, ret_image, cb, cb_data);
2364 return NotImplemented;
2367 /*****************************************************************************
2368 * GdipImageRotateFlip [GDIPLUS.@]
2370 GpStatus WINGDIPAPI GdipImageRotateFlip(GpImage *image, RotateFlipType type)
2372 FIXME("(%p %u) stub\n", image, type);
2373 return NotImplemented;