gdiplus: Use custom cap base inset differently.
[wine] / dlls / gdiplus / image.c
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "wingdi.h"
25
26 #define COBJMACROS
27 #include "objbase.h"
28 #include "olectl.h"
29 #include "ole2.h"
30
31 #include "gdiplus.h"
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
36
37 typedef void ImageItemData;
38
39 static INT ipicture_pixel_height(IPicture *pic)
40 {
41     HDC hdcref;
42     OLE_YSIZE_HIMETRIC y;
43
44     IPicture_get_Height(pic, &y);
45
46     hdcref = GetDC(0);
47
48     y = (UINT)(((REAL)y) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSY)) /
49               ((REAL)INCH_HIMETRIC));
50     ReleaseDC(0, hdcref);
51
52     return y;
53 }
54
55 static INT ipicture_pixel_width(IPicture *pic)
56 {
57     HDC hdcref;
58     OLE_XSIZE_HIMETRIC x;
59
60     IPicture_get_Width(pic, &x);
61
62     hdcref = GetDC(0);
63
64     x = (UINT)(((REAL)x) * ((REAL)GetDeviceCaps(hdcref, LOGPIXELSX)) /
65               ((REAL)INCH_HIMETRIC));
66
67     ReleaseDC(0, hdcref);
68
69     return x;
70 }
71
72 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
73     ARGB *color)
74 {
75     static int calls;
76     TRACE("%p %d %d %p\n", bitmap, x, y, color);
77
78     if(!bitmap || !color)
79         return InvalidParameter;
80
81     if(!(calls++))
82         FIXME("not implemented\n");
83
84     *color = 0xdeadbeef;
85
86     return NotImplemented;
87 }
88
89 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
90     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
91 {
92     BITMAPFILEHEADER *bmfh;
93     BITMAPINFOHEADER *bmih;
94     BYTE *buff;
95     INT datalen = stride * height, size;
96     IStream *stream;
97
98     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
99
100     if(!scan0 || !bitmap)
101         return InvalidParameter;
102
103     *bitmap = GdipAlloc(sizeof(GpBitmap));
104     if(!*bitmap)    return OutOfMemory;
105
106     size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + datalen;
107     buff = GdipAlloc(size);
108     if(!buff){
109         GdipFree(*bitmap);
110         return OutOfMemory;
111     }
112
113     bmfh = (BITMAPFILEHEADER*) buff;
114     bmih = (BITMAPINFOHEADER*) (bmfh + 1);
115
116     bmfh->bfType    = (((WORD)'M') << 8) + (WORD)'B';
117     bmfh->bfSize    = size;
118     bmfh->bfOffBits = size - datalen;
119
120     bmih->biSize            = sizeof(BITMAPINFOHEADER);
121     bmih->biWidth           = width;
122     bmih->biHeight          = height;
123     /* FIXME: use the rest of the data from format */
124     bmih->biBitCount        = format >> 8;
125     bmih->biCompression     = BI_RGB;
126
127     memcpy(bmih + 1, scan0, datalen);
128
129     if(CreateStreamOnHGlobal(buff, TRUE, &stream) != S_OK){
130         ERR("could not make stream\n");
131         GdipFree(*bitmap);
132         GdipFree(buff);
133         return GenericError;
134     }
135
136     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
137         (LPVOID*) &((*bitmap)->image.picture)) != S_OK){
138         TRACE("Could not load picture\n");
139         IStream_Release(stream);
140         GdipFree(*bitmap);
141         GdipFree(buff);
142         return GenericError;
143     }
144
145     (*bitmap)->image.type = ImageTypeBitmap;
146     (*bitmap)->width = width;
147     (*bitmap)->height = height;
148
149     return Ok;
150 }
151
152 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
153     GpBitmap **bitmap)
154 {
155     GpStatus stat;
156
157     stat = GdipLoadImageFromStreamICM(stream, (GpImage**) bitmap);
158
159     if(stat != Ok)
160         return stat;
161
162     (*bitmap)->image.type = ImageTypeBitmap;
163     (*bitmap)->width = ipicture_pixel_width((*bitmap)->image.picture);
164     (*bitmap)->height = ipicture_pixel_height((*bitmap)->image.picture);
165
166     return Ok;
167 }
168
169 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
170 {
171     if(!image)
172         return InvalidParameter;
173
174     IPicture_Release(image->picture);
175     GdipFree(image);
176
177     return Ok;
178 }
179
180 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
181 {
182     if(!image || !item)
183         return InvalidParameter;
184
185     return NotImplemented;
186 }
187
188 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
189     GpUnit *srcUnit)
190 {
191     if(!image || !srcRect || !srcUnit)
192         return InvalidParameter;
193     if(image->type == ImageTypeMetafile){
194         memcpy(srcRect, &((GpMetafile*)image)->bounds, sizeof(GpRectF));
195         *srcUnit = ((GpMetafile*)image)->unit;
196     }
197     else if(image->type == ImageTypeBitmap){
198         srcRect->X = srcRect->Y = 0.0;
199         srcRect->Width = (REAL) ((GpBitmap*)image)->width;
200         srcRect->Height = (REAL) ((GpBitmap*)image)->height;
201         *srcUnit = UnitPixel;
202     }
203     else{
204         srcRect->X = srcRect->Y = 0.0;
205         srcRect->Width = ipicture_pixel_width(image->picture);
206         srcRect->Height = ipicture_pixel_height(image->picture);
207         *srcUnit = UnitPixel;
208     }
209
210     TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
211           srcRect->Width, srcRect->Height, *srcUnit);
212
213     return Ok;
214 }
215
216 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
217 {
218     if(!image || !height)
219         return InvalidParameter;
220
221     if(image->type == ImageTypeMetafile){
222         FIXME("not implemented for metafiles\n");
223         return NotImplemented;
224     }
225     else if(image->type == ImageTypeBitmap)
226         *height = ((GpBitmap*)image)->height;
227     else
228         *height = ipicture_pixel_height(image->picture);
229
230     TRACE("returning %d\n", *height);
231
232     return Ok;
233 }
234
235 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
236 {
237     static int calls;
238
239     if(!image || !res)
240         return InvalidParameter;
241
242     if(!(calls++))
243         FIXME("not implemented\n");
244
245     return NotImplemented;
246 }
247
248 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
249 {
250     static int calls;
251
252     if(!image || !format)
253         return InvalidParameter;
254
255     if(!(calls++))
256         FIXME("not implemented\n");
257
258     return NotImplemented;
259 }
260
261 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
262 {
263     if(!image || !type)
264         return InvalidParameter;
265
266     *type = image->type;
267
268     return Ok;
269 }
270
271 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
272 {
273     static int calls;
274
275     if(!image || !res)
276         return InvalidParameter;
277
278     if(!(calls++))
279         FIXME("not implemented\n");
280
281     return NotImplemented;
282 }
283
284 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
285 {
286     if(!image || !width)
287         return InvalidParameter;
288
289     if(image->type == ImageTypeMetafile){
290         FIXME("not implemented for metafiles\n");
291         return NotImplemented;
292     }
293     else if(image->type == ImageTypeBitmap)
294         *width = ((GpBitmap*)image)->width;
295     else
296         *width = ipicture_pixel_width(image->picture);
297
298     TRACE("returning %d\n", *width);
299
300     return Ok;
301 }
302
303 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
304     MetafileHeader * header)
305 {
306     static int calls;
307
308     if(!metafile || !header)
309         return InvalidParameter;
310
311     if(!(calls++))
312         FIXME("not implemented\n");
313
314     return NotImplemented;
315 }
316
317 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
318     UINT* size)
319 {
320     static int calls;
321
322     TRACE("%p %x %p\n", image, pid, size);
323
324     if(!size || !image)
325         return InvalidParameter;
326
327     if(!(calls++))
328         FIXME("not implemented\n");
329
330     return NotImplemented;
331 }
332
333 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
334     GDIPCONST GUID* dimensionID, UINT* count)
335 {
336     static int calls;
337
338     if(!image || !dimensionID || !count)
339         return InvalidParameter;
340
341     if(!(calls++))
342         FIXME("not implemented\n");
343
344     return NotImplemented;
345 }
346
347 /* FIXME: no ICM */
348 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
349 {
350     if(!stream || !image)
351         return InvalidParameter;
352
353     *image = GdipAlloc(sizeof(GpImage));
354     if(!*image) return OutOfMemory;
355
356     if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
357         (LPVOID*) &((*image)->picture)) != S_OK){
358         TRACE("Could not load picture\n");
359         GdipFree(*image);
360         return GenericError;
361     }
362
363     /* FIXME: use IPicture_get_Type to get image type */
364     (*image)->type = ImageTypeUnknown;
365
366     return Ok;
367 }
368
369 GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
370 {
371     static int calls;
372
373     if(!image)
374         return InvalidParameter;
375
376     if(!(calls++))
377         FIXME("not implemented\n");
378
379     return NotImplemented;
380 }
381
382 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
383     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
384 {
385     if(!image || !stream)
386         return InvalidParameter;
387
388     /* FIXME: CLSID, EncoderParameters not used */
389
390     IPicture_SaveAsFile(image->picture, stream, FALSE, NULL);
391
392     return Ok;
393 }