xref: /reactos/dll/win32/windowscodecs/bitmap.c (revision 1734f297)
1 /*
2  * Copyright 2012 Vincent Povirk for CodeWeavers
3  * Copyright 2016 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #ifndef __REACTOS__
21 #include "config.h"
22 #endif
23 
24 #include <stdarg.h>
25 
26 #define COBJMACROS
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 
32 #include "wincodecs_private.h"
33 
34 #include "wine/asm.h"
35 #include "wine/debug.h"
36 
37 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 
39 /* WARNING: .NET Media Integration Layer (MIL) directly dereferences
40  * BitmapImpl members and depends on its exact layout.
41  */
42 typedef struct BitmapImpl {
43     IMILUnknown1 IMILUnknown1_iface;
44     LONG ref;
45     IMILBitmap IMILBitmap_iface;
46     IWICBitmap IWICBitmap_iface;
47     IMILUnknown2 IMILUnknown2_iface;
48     IWICPalette *palette;
49     int palette_set;
50     LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
51     BYTE *data;
52     void *view; /* used if data is a section created by an application */
53     UINT offset; /* offset into view */
54     UINT width, height;
55     UINT stride;
56     UINT bpp;
57     WICPixelFormatGUID pixelformat;
58     double dpix, dpiy;
59     CRITICAL_SECTION cs;
60 } BitmapImpl;
61 
62 typedef struct BitmapLockImpl {
63     IWICBitmapLock IWICBitmapLock_iface;
64     LONG ref;
65     BitmapImpl *parent;
66     UINT width, height;
67     BYTE *data;
68 } BitmapLockImpl;
69 
70 static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface)
71 {
72     return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_iface);
73 }
74 
75 static inline BitmapImpl *impl_from_IMILBitmap(IMILBitmap *iface)
76 {
77     return CONTAINING_RECORD(iface, BitmapImpl, IMILBitmap_iface);
78 }
79 
80 static inline BitmapImpl *impl_from_IMILUnknown1(IMILUnknown1 *iface)
81 {
82     return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown1_iface);
83 }
84 
85 static inline BitmapImpl *impl_from_IMILUnknown2(IMILUnknown2 *iface)
86 {
87     return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown2_iface);
88 }
89 
90 static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface)
91 {
92     return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface);
93 }
94 
95 static BOOL BitmapImpl_AcquireLock(BitmapImpl *This, int write)
96 {
97     if (write)
98     {
99         return 0 == InterlockedCompareExchange(&This->lock, -1, 0);
100     }
101     else
102     {
103         while (1)
104         {
105             LONG prev_val = This->lock;
106             if (prev_val == -1)
107                 return FALSE;
108             if (prev_val == InterlockedCompareExchange(&This->lock, prev_val+1, prev_val))
109                 return TRUE;
110         }
111     }
112 }
113 
114 static void BitmapImpl_ReleaseLock(BitmapImpl *This)
115 {
116     while (1)
117     {
118         LONG prev_val = This->lock, new_val;
119         if (prev_val == -1)
120             new_val = 0;
121         else
122             new_val = prev_val - 1;
123         if (prev_val == InterlockedCompareExchange(&This->lock, new_val, prev_val))
124             break;
125     }
126 }
127 
128 
129 static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFIID iid,
130     void **ppv)
131 {
132     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
133     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
134 
135     if (!ppv) return E_INVALIDARG;
136 
137     if (IsEqualIID(&IID_IUnknown, iid) ||
138         IsEqualIID(&IID_IWICBitmapLock, iid))
139     {
140         *ppv = &This->IWICBitmapLock_iface;
141     }
142     else
143     {
144         FIXME("unknown interface %s\n", debugstr_guid(iid));
145         *ppv = NULL;
146         return E_NOINTERFACE;
147     }
148 
149     IUnknown_AddRef((IUnknown*)*ppv);
150     return S_OK;
151 }
152 
153 static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface)
154 {
155     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
156     ULONG ref = InterlockedIncrement(&This->ref);
157 
158     TRACE("(%p) refcount=%u\n", iface, ref);
159 
160     return ref;
161 }
162 
163 static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface)
164 {
165     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
166     ULONG ref = InterlockedDecrement(&This->ref);
167 
168     TRACE("(%p) refcount=%u\n", iface, ref);
169 
170     if (ref == 0)
171     {
172         BitmapImpl_ReleaseLock(This->parent);
173         IWICBitmap_Release(&This->parent->IWICBitmap_iface);
174         HeapFree(GetProcessHeap(), 0, This);
175     }
176 
177     return ref;
178 }
179 
180 static HRESULT WINAPI BitmapLockImpl_GetSize(IWICBitmapLock *iface,
181     UINT *puiWidth, UINT *puiHeight)
182 {
183     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
184     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
185 
186     if (!puiWidth || !puiHeight)
187         return E_INVALIDARG;
188 
189     *puiWidth = This->width;
190     *puiHeight = This->height;
191 
192     return S_OK;
193 }
194 
195 static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface,
196     UINT *pcbStride)
197 {
198     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
199     TRACE("(%p,%p)\n", iface, pcbStride);
200 
201     if (!pcbStride)
202         return E_INVALIDARG;
203 
204     *pcbStride = This->parent->stride;
205 
206     return S_OK;
207 }
208 
209 static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface,
210     UINT *pcbBufferSize, BYTE **ppbData)
211 {
212     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
213     TRACE("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData);
214 
215     if (!pcbBufferSize || !ppbData)
216         return E_INVALIDARG;
217 
218     *pcbBufferSize = This->parent->stride * (This->height - 1) +
219         ((This->parent->bpp * This->width) + 7)/8;
220     *ppbData = This->data;
221 
222     return S_OK;
223 }
224 
225 static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface,
226     WICPixelFormatGUID *pPixelFormat)
227 {
228     BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
229     TRACE("(%p,%p)\n", iface, pPixelFormat);
230 
231     return IWICBitmap_GetPixelFormat(&This->parent->IWICBitmap_iface, pPixelFormat);
232 }
233 
234 static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl = {
235     BitmapLockImpl_QueryInterface,
236     BitmapLockImpl_AddRef,
237     BitmapLockImpl_Release,
238     BitmapLockImpl_GetSize,
239     BitmapLockImpl_GetStride,
240     BitmapLockImpl_GetDataPointer,
241     BitmapLockImpl_GetPixelFormat
242 };
243 
244 static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid,
245     void **ppv)
246 {
247     BitmapImpl *This = impl_from_IWICBitmap(iface);
248     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
249 
250     if (!ppv) return E_INVALIDARG;
251 
252     if (IsEqualIID(&IID_IUnknown, iid) ||
253         IsEqualIID(&IID_IWICBitmapSource, iid) ||
254         IsEqualIID(&IID_IWICBitmap, iid))
255     {
256         *ppv = &This->IWICBitmap_iface;
257     }
258     else if (IsEqualIID(&IID_IMILBitmap, iid) ||
259              IsEqualIID(&IID_IMILBitmapSource, iid))
260     {
261         *ppv = &This->IMILBitmap_iface;
262     }
263     else
264     {
265         FIXME("unknown interface %s\n", debugstr_guid(iid));
266         *ppv = NULL;
267         return E_NOINTERFACE;
268     }
269 
270     IUnknown_AddRef((IUnknown*)*ppv);
271     return S_OK;
272 }
273 
274 static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface)
275 {
276     BitmapImpl *This = impl_from_IWICBitmap(iface);
277     ULONG ref = InterlockedIncrement(&This->ref);
278 
279     TRACE("(%p) refcount=%u\n", iface, ref);
280 
281     return ref;
282 }
283 
284 static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface)
285 {
286     BitmapImpl *This = impl_from_IWICBitmap(iface);
287     ULONG ref = InterlockedDecrement(&This->ref);
288 
289     TRACE("(%p) refcount=%u\n", iface, ref);
290 
291     if (ref == 0)
292     {
293         if (This->palette) IWICPalette_Release(This->palette);
294         This->cs.DebugInfo->Spare[0] = 0;
295         DeleteCriticalSection(&This->cs);
296         if (This->view)
297             UnmapViewOfFile(This->view);
298         else
299             HeapFree(GetProcessHeap(), 0, This->data);
300         HeapFree(GetProcessHeap(), 0, This);
301     }
302 
303     return ref;
304 }
305 
306 static HRESULT WINAPI BitmapImpl_GetSize(IWICBitmap *iface,
307     UINT *puiWidth, UINT *puiHeight)
308 {
309     BitmapImpl *This = impl_from_IWICBitmap(iface);
310     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
311 
312     if (!puiWidth || !puiHeight)
313         return E_INVALIDARG;
314 
315     *puiWidth = This->width;
316     *puiHeight = This->height;
317 
318     return S_OK;
319 }
320 
321 static HRESULT WINAPI BitmapImpl_GetPixelFormat(IWICBitmap *iface,
322     WICPixelFormatGUID *pPixelFormat)
323 {
324     BitmapImpl *This = impl_from_IWICBitmap(iface);
325     TRACE("(%p,%p)\n", iface, pPixelFormat);
326 
327     if (!pPixelFormat)
328         return E_INVALIDARG;
329 
330     memcpy(pPixelFormat, &This->pixelformat, sizeof(GUID));
331 
332     return S_OK;
333 }
334 
335 static HRESULT WINAPI BitmapImpl_GetResolution(IWICBitmap *iface,
336     double *pDpiX, double *pDpiY)
337 {
338     BitmapImpl *This = impl_from_IWICBitmap(iface);
339     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
340 
341     if (!pDpiX || !pDpiY)
342         return E_INVALIDARG;
343 
344     EnterCriticalSection(&This->cs);
345     *pDpiX = This->dpix;
346     *pDpiY = This->dpiy;
347     LeaveCriticalSection(&This->cs);
348 
349     return S_OK;
350 }
351 
352 static HRESULT WINAPI BitmapImpl_CopyPalette(IWICBitmap *iface,
353     IWICPalette *pIPalette)
354 {
355     BitmapImpl *This = impl_from_IWICBitmap(iface);
356     TRACE("(%p,%p)\n", iface, pIPalette);
357 
358     if (!This->palette_set)
359         return WINCODEC_ERR_PALETTEUNAVAILABLE;
360 
361     return IWICPalette_InitializeFromPalette(pIPalette, This->palette);
362 }
363 
364 static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface,
365     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
366 {
367     BitmapImpl *This = impl_from_IWICBitmap(iface);
368     TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
369 
370     return copy_pixels(This->bpp, This->data, This->width, This->height,
371         This->stride, prc, cbStride, cbBufferSize, pbBuffer);
372 }
373 
374 static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock,
375     DWORD flags, IWICBitmapLock **ppILock)
376 {
377     BitmapImpl *This = impl_from_IWICBitmap(iface);
378     BitmapLockImpl *result;
379     WICRect rc;
380 
381     TRACE("(%p,%s,%x,%p)\n", iface, debug_wic_rect(prcLock), flags, ppILock);
382 
383     if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock)
384         return E_INVALIDARG;
385 
386     if (!prcLock)
387     {
388         rc.X = rc.Y = 0;
389         rc.Width = This->width;
390         rc.Height = This->height;
391         prcLock = &rc;
392     }
393     else if (prcLock->X >= This->width || prcLock->Y >= This->height ||
394              prcLock->X + prcLock->Width > This->width ||
395              prcLock->Y + prcLock->Height > This->height ||
396              prcLock->Width <= 0 || prcLock->Height <= 0)
397         return E_INVALIDARG;
398     else if (((prcLock->X * This->bpp) % 8) != 0)
399     {
400         FIXME("Cannot lock at an X coordinate not at a full byte\n");
401         return E_FAIL;
402     }
403 
404     result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl));
405     if (!result)
406         return E_OUTOFMEMORY;
407 
408     if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite))
409     {
410         HeapFree(GetProcessHeap(), 0, result);
411         return WINCODEC_ERR_ALREADYLOCKED;
412     }
413 
414     result->IWICBitmapLock_iface.lpVtbl = &BitmapLockImpl_Vtbl;
415     result->ref = 1;
416     result->parent = This;
417     result->width = prcLock->Width;
418     result->height = prcLock->Height;
419     result->data = This->data + This->stride * prcLock->Y +
420         (This->bpp * prcLock->X)/8;
421 
422     IWICBitmap_AddRef(&This->IWICBitmap_iface);
423     *ppILock = &result->IWICBitmapLock_iface;
424 
425     return S_OK;
426 }
427 
428 static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette)
429 {
430     BitmapImpl *This = impl_from_IWICBitmap(iface);
431     HRESULT hr;
432 
433     TRACE("(%p,%p)\n", iface, pIPalette);
434 
435     if (!This->palette)
436     {
437         IWICPalette *new_palette;
438         hr = PaletteImpl_Create(&new_palette);
439 
440         if (FAILED(hr)) return hr;
441 
442         if (InterlockedCompareExchangePointer((void**)&This->palette, new_palette, NULL))
443         {
444             /* someone beat us to it */
445             IWICPalette_Release(new_palette);
446         }
447     }
448 
449     hr = IWICPalette_InitializeFromPalette(This->palette, pIPalette);
450 
451     if (SUCCEEDED(hr))
452         This->palette_set = 1;
453 
454     return S_OK;
455 }
456 
457 static HRESULT WINAPI BitmapImpl_SetResolution(IWICBitmap *iface,
458     double dpiX, double dpiY)
459 {
460     BitmapImpl *This = impl_from_IWICBitmap(iface);
461     TRACE("(%p,%f,%f)\n", iface, dpiX, dpiY);
462 
463     EnterCriticalSection(&This->cs);
464     This->dpix = dpiX;
465     This->dpiy = dpiY;
466     LeaveCriticalSection(&This->cs);
467 
468     return S_OK;
469 }
470 
471 static const IWICBitmapVtbl BitmapImpl_Vtbl = {
472     BitmapImpl_QueryInterface,
473     BitmapImpl_AddRef,
474     BitmapImpl_Release,
475     BitmapImpl_GetSize,
476     BitmapImpl_GetPixelFormat,
477     BitmapImpl_GetResolution,
478     BitmapImpl_CopyPalette,
479     BitmapImpl_CopyPixels,
480     BitmapImpl_Lock,
481     BitmapImpl_SetPalette,
482     BitmapImpl_SetResolution
483 };
484 
485 static HRESULT WINAPI IMILBitmapImpl_QueryInterface(IMILBitmap *iface, REFIID iid,
486     void **ppv)
487 {
488     BitmapImpl *This = impl_from_IMILBitmap(iface);
489     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
490     return IWICBitmap_QueryInterface(&This->IWICBitmap_iface, iid, ppv);
491 }
492 
493 static ULONG WINAPI IMILBitmapImpl_AddRef(IMILBitmap *iface)
494 {
495     BitmapImpl *This = impl_from_IMILBitmap(iface);
496     return IWICBitmap_AddRef(&This->IWICBitmap_iface);
497 }
498 
499 static ULONG WINAPI IMILBitmapImpl_Release(IMILBitmap *iface)
500 {
501     BitmapImpl *This = impl_from_IMILBitmap(iface);
502     return IWICBitmap_Release(&This->IWICBitmap_iface);
503 }
504 
505 static HRESULT WINAPI IMILBitmapImpl_GetSize(IMILBitmap *iface,
506     UINT *width, UINT *height)
507 {
508     BitmapImpl *This = impl_from_IMILBitmap(iface);
509     TRACE("(%p,%p,%p)\n", iface, width, height);
510     return IWICBitmap_GetSize(&This->IWICBitmap_iface, width, height);
511 }
512 
513 static const struct
514 {
515     const GUID *WIC_format;
516     int enum_format;
517 } pixel_fmt_map[] =
518 {
519     { &GUID_WICPixelFormatDontCare, 0 },
520     { &GUID_WICPixelFormat1bppIndexed, 1 },
521     { &GUID_WICPixelFormat2bppIndexed, 2 },
522     { &GUID_WICPixelFormat4bppIndexed, 3 },
523     { &GUID_WICPixelFormat8bppIndexed, 4 },
524     { &GUID_WICPixelFormatBlackWhite, 5 },
525     { &GUID_WICPixelFormat2bppGray, 6 },
526     { &GUID_WICPixelFormat4bppGray, 7 },
527     { &GUID_WICPixelFormat8bppGray, 8 },
528     { &GUID_WICPixelFormat16bppBGR555, 9 },
529     { &GUID_WICPixelFormat16bppBGR565, 0x0a },
530     { &GUID_WICPixelFormat16bppGray, 0x0b },
531     { &GUID_WICPixelFormat24bppBGR, 0x0c },
532     { &GUID_WICPixelFormat24bppRGB, 0x0d },
533     { &GUID_WICPixelFormat32bppBGR, 0x0e },
534     { &GUID_WICPixelFormat32bppBGRA, 0x0f },
535     { &GUID_WICPixelFormat32bppPBGRA, 0x10 },
536     { &GUID_WICPixelFormat48bppRGB, 0x15 },
537     { &GUID_WICPixelFormat64bppRGBA, 0x16 },
538     { &GUID_WICPixelFormat64bppPRGBA, 0x17 },
539     { &GUID_WICPixelFormat32bppCMYK, 0x1c }
540 };
541 
542 static HRESULT WINAPI IMILBitmapImpl_GetPixelFormat(IMILBitmap *iface,
543     int *format)
544 {
545     BitmapImpl *This = impl_from_IMILBitmap(iface);
546     int i;
547 
548     TRACE("(%p,%p)\n", iface, format);
549 
550     if (!format) return E_INVALIDARG;
551 
552     *format = 0;
553 
554     for (i = 0; i < ARRAY_SIZE(pixel_fmt_map); i++)
555     {
556         if (IsEqualGUID(pixel_fmt_map[i].WIC_format, &This->pixelformat))
557         {
558             *format = pixel_fmt_map[i].enum_format;
559             break;
560         }
561     }
562 
563     TRACE("=> %u\n", *format);
564     return S_OK;
565 }
566 
567 static HRESULT WINAPI IMILBitmapImpl_GetResolution(IMILBitmap *iface,
568     double *dpix, double *dpiy)
569 {
570     BitmapImpl *This = impl_from_IMILBitmap(iface);
571     TRACE("(%p,%p,%p)\n", iface, dpix, dpiy);
572     return IWICBitmap_GetResolution(&This->IWICBitmap_iface, dpix, dpiy);
573 }
574 
575 static HRESULT WINAPI IMILBitmapImpl_CopyPalette(IMILBitmap *iface,
576     IWICPalette *palette)
577 {
578     BitmapImpl *This = impl_from_IMILBitmap(iface);
579     TRACE("(%p,%p)\n", iface, palette);
580     return IWICBitmap_CopyPalette(&This->IWICBitmap_iface, palette);
581 }
582 
583 static HRESULT WINAPI IMILBitmapImpl_CopyPixels(IMILBitmap *iface,
584     const WICRect *rc, UINT stride, UINT size, BYTE *buffer)
585 {
586     BitmapImpl *This = impl_from_IMILBitmap(iface);
587     TRACE("(%p,%p,%u,%u,%p)\n", iface, rc, stride, size, buffer);
588     return IWICBitmap_CopyPixels(&This->IWICBitmap_iface, rc, stride, size, buffer);
589 }
590 
591 static HRESULT WINAPI IMILBitmapImpl_unknown1(IMILBitmap *iface, void **ppv)
592 {
593     BitmapImpl *This = impl_from_IMILBitmap(iface);
594 
595     TRACE("(%p,%p)\n", iface, ppv);
596 
597     if (!ppv) return E_INVALIDARG;
598 
599     /* reference count is not incremented here */
600     *ppv = &This->IMILUnknown1_iface;
601 
602     return S_OK;
603 }
604 
605 static HRESULT WINAPI IMILBitmapImpl_Lock(IMILBitmap *iface, const WICRect *rc, DWORD flags, IWICBitmapLock **lock)
606 {
607     BitmapImpl *This = impl_from_IMILBitmap(iface);
608     TRACE("(%p,%p,%08x,%p)\n", iface, rc, flags, lock);
609     return IWICBitmap_Lock(&This->IWICBitmap_iface, rc, flags, lock);
610 }
611 
612 static HRESULT WINAPI IMILBitmapImpl_Unlock(IMILBitmap *iface, IWICBitmapLock *lock)
613 {
614     TRACE("(%p,%p)\n", iface, lock);
615     IWICBitmapLock_Release(lock);
616     return S_OK;
617 }
618 
619 static HRESULT WINAPI IMILBitmapImpl_SetPalette(IMILBitmap *iface, IWICPalette *palette)
620 {
621     BitmapImpl *This = impl_from_IMILBitmap(iface);
622     TRACE("(%p,%p)\n", iface, palette);
623     return IWICBitmap_SetPalette(&This->IWICBitmap_iface, palette);
624 }
625 
626 static HRESULT WINAPI IMILBitmapImpl_SetResolution(IMILBitmap *iface, double dpix, double dpiy)
627 {
628     BitmapImpl *This = impl_from_IMILBitmap(iface);
629     TRACE("(%p,%f,%f)\n", iface, dpix, dpiy);
630     return IWICBitmap_SetResolution(&This->IWICBitmap_iface, dpix, dpiy);
631 }
632 
633 static HRESULT WINAPI IMILBitmapImpl_AddDirtyRect(IMILBitmap *iface, const WICRect *rc)
634 {
635     FIXME("(%p,%p): stub\n", iface, rc);
636     return E_NOTIMPL;
637 }
638 
639 static const IMILBitmapVtbl IMILBitmapImpl_Vtbl =
640 {
641     IMILBitmapImpl_QueryInterface,
642     IMILBitmapImpl_AddRef,
643     IMILBitmapImpl_Release,
644     IMILBitmapImpl_GetSize,
645     IMILBitmapImpl_GetPixelFormat,
646     IMILBitmapImpl_GetResolution,
647     IMILBitmapImpl_CopyPalette,
648     IMILBitmapImpl_CopyPixels,
649     IMILBitmapImpl_unknown1,
650     IMILBitmapImpl_Lock,
651     IMILBitmapImpl_Unlock,
652     IMILBitmapImpl_SetPalette,
653     IMILBitmapImpl_SetResolution,
654     IMILBitmapImpl_AddDirtyRect
655 };
656 
657 static HRESULT WINAPI IMILUnknown1Impl_QueryInterface(IMILUnknown1 *iface, REFIID iid,
658     void **ppv)
659 {
660     /* It's not clear what interface should be returned here */
661     FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv);
662     *ppv = NULL;
663     return E_NOINTERFACE;
664 }
665 
666 static ULONG WINAPI IMILUnknown1Impl_AddRef(IMILUnknown1 *iface)
667 {
668     BitmapImpl *This = impl_from_IMILUnknown1(iface);
669     return IWICBitmap_AddRef(&This->IWICBitmap_iface);
670 }
671 
672 static ULONG WINAPI IMILUnknown1Impl_Release(IMILUnknown1 *iface)
673 {
674     BitmapImpl *This = impl_from_IMILUnknown1(iface);
675     return IWICBitmap_Release(&This->IWICBitmap_iface);
676 }
677 
678 DECLSPEC_HIDDEN void WINAPI IMILUnknown1Impl_unknown1(IMILUnknown1 *iface, void *arg)
679 {
680     FIXME("(%p,%p): stub\n", iface, arg);
681 }
682 
683 static HRESULT WINAPI IMILUnknown1Impl_unknown2(IMILUnknown1 *iface, void *arg1, void *arg2)
684 {
685     FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
686     return E_NOTIMPL;
687 }
688 
689 DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown3(IMILUnknown1 *iface, void *arg)
690 {
691     FIXME("(%p,%p): stub\n", iface, arg);
692     return E_NOTIMPL;
693 }
694 
695 static HRESULT WINAPI IMILUnknown1Impl_unknown4(IMILUnknown1 *iface, void *arg)
696 {
697     FIXME("(%p,%p): stub\n", iface, arg);
698     return E_NOTIMPL;
699 }
700 
701 static HRESULT WINAPI IMILUnknown1Impl_unknown5(IMILUnknown1 *iface, void *arg)
702 {
703     FIXME("(%p,%p): stub\n", iface, arg);
704     return E_NOTIMPL;
705 }
706 
707 static HRESULT WINAPI IMILUnknown1Impl_unknown6(IMILUnknown1 *iface, DWORD64 arg)
708 {
709     FIXME("(%p,%s): stub\n", iface, wine_dbgstr_longlong(arg));
710     return E_NOTIMPL;
711 }
712 
713 static HRESULT WINAPI IMILUnknown1Impl_unknown7(IMILUnknown1 *iface, void *arg)
714 {
715     FIXME("(%p,%p): stub\n", iface, arg);
716     return E_NOTIMPL;
717 }
718 
719 DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown8(IMILUnknown1 *iface)
720 {
721     FIXME("(%p): stub\n", iface);
722     return E_NOTIMPL;
723 }
724 
725 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown1, 8)
726 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown3, 8)
727 DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown8, 4)
728 
729 static const IMILUnknown1Vtbl IMILUnknown1Impl_Vtbl =
730 {
731     IMILUnknown1Impl_QueryInterface,
732     IMILUnknown1Impl_AddRef,
733     IMILUnknown1Impl_Release,
734     THISCALL(IMILUnknown1Impl_unknown1),
735     IMILUnknown1Impl_unknown2,
736     THISCALL(IMILUnknown1Impl_unknown3),
737     IMILUnknown1Impl_unknown4,
738     IMILUnknown1Impl_unknown5,
739     IMILUnknown1Impl_unknown6,
740     IMILUnknown1Impl_unknown7,
741     THISCALL(IMILUnknown1Impl_unknown8)
742 };
743 
744 static HRESULT WINAPI IMILUnknown2Impl_QueryInterface(IMILUnknown2 *iface, REFIID iid,
745     void **ppv)
746 {
747     FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv);
748     *ppv = NULL;
749     return E_NOINTERFACE;
750 }
751 
752 static ULONG WINAPI IMILUnknown2Impl_AddRef(IMILUnknown2 *iface)
753 {
754     FIXME("(%p): stub\n", iface);
755     return 0;
756 }
757 
758 static ULONG WINAPI IMILUnknown2Impl_Release(IMILUnknown2 *iface)
759 {
760     FIXME("(%p): stub\n", iface);
761     return 0;
762 }
763 
764 static HRESULT WINAPI IMILUnknown2Impl_unknown1(IMILUnknown2 *iface, void *arg1, void **arg2)
765 {
766     FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
767     if (arg2) *arg2 = NULL;
768     return E_NOTIMPL;
769 }
770 
771 static HRESULT WINAPI IMILUnknown2Impl_unknown2(IMILUnknown2 *iface, void *arg1, void *arg2)
772 {
773     FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2);
774     return E_NOTIMPL;
775 }
776 
777 static HRESULT WINAPI IMILUnknown2Impl_unknown3(IMILUnknown2 *iface, void *arg1)
778 {
779     FIXME("(%p,%p): stub\n", iface, arg1);
780     return E_NOTIMPL;
781 }
782 
783 static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl =
784 {
785     IMILUnknown2Impl_QueryInterface,
786     IMILUnknown2Impl_AddRef,
787     IMILUnknown2Impl_Release,
788     IMILUnknown2Impl_unknown1,
789     IMILUnknown2Impl_unknown2,
790     IMILUnknown2Impl_unknown3
791 };
792 
793 HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasize, void *view,
794     UINT offset, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
795     IWICBitmap **ppIBitmap)
796 {
797     HRESULT hr;
798     BitmapImpl *This;
799     BYTE *data;
800     UINT bpp;
801 
802     hr = get_pixelformat_bpp(pixelFormat, &bpp);
803     if (FAILED(hr)) return hr;
804 
805     if (!stride) stride = (((bpp*uiWidth)+31)/32)*4;
806     if (!datasize) datasize = stride * uiHeight;
807 
808     if (datasize < stride * uiHeight) return WINCODEC_ERR_INSUFFICIENTBUFFER;
809     if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG;
810 
811     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl));
812     if (!This) return E_OUTOFMEMORY;
813 
814     if (view) data = (BYTE *)view + offset;
815     else if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize)))
816     {
817         HeapFree(GetProcessHeap(), 0, This);
818         return E_OUTOFMEMORY;
819     }
820 
821     This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl;
822     This->IMILBitmap_iface.lpVtbl = &IMILBitmapImpl_Vtbl;
823     This->IMILUnknown1_iface.lpVtbl = &IMILUnknown1Impl_Vtbl;
824     This->IMILUnknown2_iface.lpVtbl = &IMILUnknown2Impl_Vtbl;
825     This->ref = 1;
826     This->palette = NULL;
827     This->palette_set = 0;
828     This->lock = 0;
829     This->data = data;
830     This->view = view;
831     This->offset = offset;
832     This->width = uiWidth;
833     This->height = uiHeight;
834     This->stride = stride;
835     This->bpp = bpp;
836     memcpy(&This->pixelformat, pixelFormat, sizeof(GUID));
837     This->dpix = This->dpiy = 0.0;
838     InitializeCriticalSection(&This->cs);
839     This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock");
840 
841     *ppIBitmap = &This->IWICBitmap_iface;
842 
843     return S_OK;
844 }
845