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
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
37 typedef void ImageItemData;
39 #define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
41 static INT ipicture_pixel_height(IPicture *pic)
46 IPicture_get_Height(pic, &y);
50 y = (UINT)(((REAL)y) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSY)) /
51 ((REAL)INCH_HIMETRIC));
57 static INT ipicture_pixel_width(IPicture *pic)
62 IPicture_get_Width(pic, &x);
66 x = (UINT)(((REAL)x) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSX)) /
67 ((REAL)INCH_HIMETRIC));
74 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
78 TRACE("%p %d %d %p\n", bitmap, x, y, color);
81 return InvalidParameter;
84 FIXME("not implemented\n");
88 return NotImplemented;
91 /* This function returns a pointer to an array of pixels that represents the
92 * bitmap. The *entire* bitmap is locked according to the lock mode specified by
93 * flags. It is correct behavior that a user who calls this function with write
94 * privileges can write to the whole bitmap (not just the area in rect).
96 * FIXME: only used portion of format is bits per pixel. */
97 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
98 UINT flags, PixelFormat format, BitmapData* lockeddata)
101 INT stride, bitspp = PIXELFORMATBPP(format);
109 TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
111 if(!lockeddata || !bitmap || !rect)
112 return InvalidParameter;
114 if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
115 (rect->Y + rect->Height > bitmap->height) || !flags)
116 return InvalidParameter;
118 if(flags & ImageLockModeUserInputBuf)
119 return NotImplemented;
121 if((bitmap->lockmode & ImageLockModeWrite) || (bitmap->lockmode &&
122 (flags & ImageLockModeWrite)))
125 IPicture_get_Handle(bitmap->image.picture, &hbm);
126 IPicture_get_CurDC(bitmap->image.picture, &hdc);
127 bm_is_selected = (hdc != 0);
129 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
130 bmi.bmiHeader.biBitCount = 0;
133 hdc = CreateCompatibleDC(0);
134 old = SelectObject(hdc, (HBITMAP)hbm);
138 GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
140 abs_height = abs(bmi.bmiHeader.biHeight);
141 stride = bmi.bmiHeader.biWidth * bitspp / 8;
142 stride = (stride + 3) & ~3;
144 buff = GdipAlloc(stride * abs_height);
146 bmi.bmiHeader.biBitCount = bitspp;
149 GetDIBits(hdc, (HBITMAP)hbm, 0, abs_height, buff, &bmi, DIB_RGB_COLORS);
152 SelectObject(hdc, old);
159 lockeddata->Width = rect->Width;
160 lockeddata->Height = rect->Height;
161 lockeddata->PixelFormat = format;
162 lockeddata->Reserved = flags;
164 if(bmi.bmiHeader.biHeight > 0){
165 lockeddata->Stride = -stride;
166 lockeddata->Scan0 = buff + (bitspp / 8) * rect->X +
167 stride * (abs_height - 1 - rect->Y);
170 lockeddata->Stride = stride;
171 lockeddata->Scan0 = buff + (bitspp / 8) * rect->X + stride * rect->Y;
174 bitmap->lockmode = flags;
177 if(flags & ImageLockModeWrite)
178 bitmap->bitmapbits = buff;
183 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
184 BitmapData* lockeddata)
192 if(!bitmap || !lockeddata)
193 return InvalidParameter;
195 if(!bitmap->lockmode)
198 if(lockeddata->Reserved & ImageLockModeUserInputBuf)
199 return NotImplemented;
201 if(lockeddata->Reserved & ImageLockModeRead){
202 if(!(--bitmap->numlocks))
203 bitmap->lockmode = 0;
205 GdipFree(lockeddata->Scan0);
209 IPicture_get_Handle(bitmap->image.picture, &hbm);
210 IPicture_get_CurDC(bitmap->image.picture, &hdc);
211 bm_is_selected = (hdc != 0);
213 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
214 bmi.bmiHeader.biBitCount = 0;
217 hdc = CreateCompatibleDC(0);
218 old = SelectObject(hdc, (HBITMAP)hbm);
221 GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
222 bmi.bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
223 SetDIBits(hdc, (HBITMAP)hbm, 0, abs(bmi.bmiHeader.biHeight),
224 bitmap->bitmapbits, &bmi, DIB_RGB_COLORS);
227 SelectObject(hdc, old);
231 GdipFree(bitmap->bitmapbits);
236 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
242 if(!filename || !bitmap)
243 return InvalidParameter;
245 stat = GdipCreateStreamOnFile(filename, GENERIC_READ, &stream);
250 stat = GdipCreateBitmapFromStream(stream, bitmap);
253 IStream_Release(stream);
258 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
259 GpMetafile* metafile, BOOL* succ, EmfType emfType,
260 const WCHAR* description, GpMetafile** out_metafile)
264 if(!ref || !metafile || !out_metafile)
265 return InvalidParameter;
268 *out_metafile = NULL;
271 FIXME("not implemented\n");
273 return NotImplemented;
276 /* FIXME: this should create a bitmap in the given size with the attributes
277 * (resolution etc.) of the graphics object */
278 GpStatus WINGDIPAPI GdipCreateBitmapFromGraphics(INT width, INT height,
279 GpGraphics* target, GpBitmap** bitmap)
284 if(!target || !bitmap)
285 return InvalidParameter;
288 FIXME("hacked stub\n");
290 ret = GdipCreateBitmapFromScan0(width, height, 0, PixelFormat24bppRGB,
296 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
297 PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
299 BITMAPFILEHEADER *bmfh;
300 BITMAPINFOHEADER *bmih;
305 TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
307 if(!bitmap || width <= 0 || height <= 0 || (scan0 && (stride % 4))){
309 return InvalidParameter;
313 return InvalidParameter;
315 /* FIXME: windows allows negative stride (reads backwards from scan0) */
317 FIXME("negative stride\n");
318 return InvalidParameter;
321 *bitmap = GdipAlloc(sizeof(GpBitmap));
322 if(!*bitmap) return OutOfMemory;
325 stride = width * (PIXELFORMATBPP(format) / 8);
326 stride = (stride + 3) & ~3;
329 datalen = abs(stride * height);
330 size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
331 buff = GdipAlloc(size);
337 bmfh = (BITMAPFILEHEADER*) buff;
338 bmih = (BITMAPINFOHEADER*) (bmfh + 1);
340 bmfh->bfType = (((WORD)'M') << 8) + (WORD)'B';
342 bmfh->bfOffBits = size - datalen;
344 bmih->biSize = sizeof(BITMAPINFOHEADER);
345 bmih->biWidth = width;
346 bmih->biHeight = -height;
347 /* FIXME: use the rest of the data from format */
348 bmih->biBitCount = PIXELFORMATBPP(format);
349 bmih->biCompression = BI_RGB;
350 bmih->biSizeImage = datalen;
353 memcpy(bmih + 1, scan0, datalen);
355 memset(bmih + 1, 0, datalen);
357 if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
358 ERR("could not make stream\n");
364 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
365 (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
366 TRACE("Could not load picture\n");
367 IStream_Release(stream);
373 (*bitmap)->image.type = ImageTypeBitmap;
374 (*bitmap)->width = width;
375 (*bitmap)->height = height;
376 (*bitmap)->format = format;
381 GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
386 stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
391 if((*bitmap)->image.type != ImageTypeBitmap){
392 IPicture_Release((*bitmap)->image.picture);
394 return GenericError; /* FIXME: what error to return? */
401 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
404 return GdipCreateBitmapFromStream(stream, bitmap);
407 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
412 return InvalidParameter;
414 IPicture_get_CurDC(image->picture, &hdc);
416 IPicture_Release(image->picture);
422 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
425 return InvalidParameter;
427 return NotImplemented;
430 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
433 if(!image || !srcRect || !srcUnit)
434 return InvalidParameter;
435 if(image->type == ImageTypeMetafile){
436 memcpy(srcRect, &((GpMetafile*)image)->bounds, sizeof(GpRectF));
437 *srcUnit = ((GpMetafile*)image)->unit;
439 else if(image->type == ImageTypeBitmap){
440 srcRect->X = srcRect->Y = 0.0;
441 srcRect->Width = (REAL) ((GpBitmap*)image)->width;
442 srcRect->Height = (REAL) ((GpBitmap*)image)->height;
443 *srcUnit = UnitPixel;
446 srcRect->X = srcRect->Y = 0.0;
447 srcRect->Width = ipicture_pixel_width(image->picture);
448 srcRect->Height = ipicture_pixel_height(image->picture);
449 *srcUnit = UnitPixel;
452 TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
453 srcRect->Width, srcRect->Height, *srcUnit);
458 GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
459 GpGraphics **graphics)
463 if(!image || !graphics)
464 return InvalidParameter;
466 if(image->type != ImageTypeBitmap){
467 FIXME("not implemented for image type %d\n", image->type);
468 return NotImplemented;
471 IPicture_get_CurDC(image->picture, &hdc);
474 hdc = CreateCompatibleDC(0);
475 IPicture_SelectPicture(image->picture, hdc, NULL, NULL);
478 return GdipCreateFromHDC(hdc, graphics);
481 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
483 if(!image || !height)
484 return InvalidParameter;
486 if(image->type == ImageTypeMetafile){
489 *height = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
490 ((GpMetafile*)image)->bounds.Height);
494 else if(image->type == ImageTypeBitmap)
495 *height = ((GpBitmap*)image)->height;
497 *height = ipicture_pixel_height(image->picture);
499 TRACE("returning %d\n", *height);
504 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
509 return InvalidParameter;
512 FIXME("not implemented\n");
514 return NotImplemented;
517 /* FIXME: test this function for non-bitmap types */
518 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
520 if(!image || !format)
521 return InvalidParameter;
523 if(image->type != ImageTypeBitmap)
524 *format = PixelFormat24bppRGB;
526 *format = ((GpBitmap*) image)->format;
531 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
535 if(!image || !format)
536 return InvalidParameter;
539 FIXME("not implemented\n");
541 return NotImplemented;
544 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
547 return InvalidParameter;
554 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
559 return InvalidParameter;
562 FIXME("not implemented\n");
564 return NotImplemented;
567 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
570 return InvalidParameter;
572 if(image->type == ImageTypeMetafile){
575 *width = roundr(convert_unit(hdc, ((GpMetafile*)image)->unit) *
576 ((GpMetafile*)image)->bounds.Width);
580 else if(image->type == ImageTypeBitmap)
581 *width = ((GpBitmap*)image)->width;
583 *width = ipicture_pixel_width(image->picture);
585 TRACE("returning %d\n", *width);
590 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
591 MetafileHeader * header)
595 if(!metafile || !header)
596 return InvalidParameter;
599 FIXME("not implemented\n");
604 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
609 TRACE("%p %x %p\n", image, pid, size);
612 return InvalidParameter;
615 FIXME("not implemented\n");
617 return NotImplemented;
620 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
621 GDIPCONST GUID* dimensionID, UINT* count)
625 if(!image || !dimensionID || !count)
626 return InvalidParameter;
629 FIXME("not implemented\n");
631 return NotImplemented;
634 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
635 GUID* dimensionIDs, UINT count)
639 if(!image || !dimensionIDs)
640 return InvalidParameter;
643 FIXME("not implemented\n");
648 GpStatus WINGDIPAPI GdipImageSelectActiveFrame(GpImage *image,
649 GDIPCONST GUID* dimensionID, UINT frameidx)
653 if(!image || !dimensionID)
654 return InvalidParameter;
657 FIXME("not implemented\n");
662 GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
667 if(!stream || !image)
668 return InvalidParameter;
670 if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
671 (LPVOID*) &pic) != S_OK){
672 TRACE("Could not load picture\n");
676 IStream_AddRef(stream);
678 IPicture_get_Type(pic, &type);
680 if(type == PICTYPE_BITMAP){
682 BITMAPCOREHEADER* bmch;
686 *image = GdipAlloc(sizeof(GpBitmap));
687 if(!*image) return OutOfMemory;
688 (*image)->type = ImageTypeBitmap;
690 (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
691 (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
693 /* get the pixel format */
694 IPicture_get_Handle(pic, &hbm);
695 IPicture_get_CurDC(pic, &hdc);
697 bmch = (BITMAPCOREHEADER*) (&bmi.bmiHeader);
698 bmch->bcSize = sizeof(BITMAPCOREHEADER);
702 hdc = CreateCompatibleDC(0);
703 old = SelectObject(hdc, (HBITMAP)hbm);
704 GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
705 SelectObject(hdc, old);
709 GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
711 (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
713 else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
714 /* FIXME: missing initialization code */
715 *image = GdipAlloc(sizeof(GpMetafile));
716 if(!*image) return OutOfMemory;
717 (*image)->type = ImageTypeMetafile;
720 *image = GdipAlloc(sizeof(GpImage));
721 if(!*image) return OutOfMemory;
722 (*image)->type = ImageTypeUnknown;
725 (*image)->picture = pic;
731 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
733 return GdipLoadImageFromStream(stream, image);
736 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
741 return InvalidParameter;
744 FIXME("not implemented\n");
746 return NotImplemented;
749 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
750 GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
752 if(!image || !stream)
753 return InvalidParameter;
755 /* FIXME: CLSID, EncoderParameters not used */
757 IPicture_SaveAsFile(image->picture, stream, FALSE, NULL);
762 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
763 GDIPCONST ColorPalette *palette)
767 if(!image || !palette)
768 return InvalidParameter;
771 FIXME("not implemented\n");
773 return NotImplemented;