2 * Copyright 2010 Vincent Povirk for CodeWeavers
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
19 #include "wincodecs_private.h"
21 typedef struct BitmapScaler
{
22 IWICBitmapScaler IWICBitmapScaler_iface
;
24 IMILBitmapScaler IMILBitmapScaler_iface
;
25 IWICBitmapSource
*source
;
27 UINT src_width
, src_height
;
28 WICBitmapInterpolationMode mode
;
30 void (*fn_get_required_source_rect
)(struct BitmapScaler
*,UINT
,UINT
,WICRect
*);
31 void (*fn_copy_scanline
)(struct BitmapScaler
*,UINT
,UINT
,UINT
,BYTE
**,UINT
,UINT
,BYTE
*);
32 CRITICAL_SECTION lock
; /* must be held when initialized */
35 static inline BitmapScaler
*impl_from_IWICBitmapScaler(IWICBitmapScaler
*iface
)
37 return CONTAINING_RECORD(iface
, BitmapScaler
, IWICBitmapScaler_iface
);
40 static inline BitmapScaler
*impl_from_IMILBitmapScaler(IMILBitmapScaler
*iface
)
42 return CONTAINING_RECORD(iface
, BitmapScaler
, IMILBitmapScaler_iface
);
45 static HRESULT WINAPI
BitmapScaler_QueryInterface(IWICBitmapScaler
*iface
, REFIID iid
,
48 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
49 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
51 if (!ppv
) return E_INVALIDARG
;
53 if (IsEqualIID(&IID_IUnknown
, iid
) ||
54 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
55 IsEqualIID(&IID_IWICBitmapScaler
, iid
))
57 *ppv
= &This
->IWICBitmapScaler_iface
;
59 else if (IsEqualIID(&IID_IMILBitmapScaler
, iid
))
61 *ppv
= &This
->IMILBitmapScaler_iface
;
65 FIXME("unknown interface %s\n", debugstr_guid(iid
));
70 IUnknown_AddRef((IUnknown
*)*ppv
);
74 static ULONG WINAPI
BitmapScaler_AddRef(IWICBitmapScaler
*iface
)
76 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
77 ULONG ref
= InterlockedIncrement(&This
->ref
);
79 TRACE("(%p) refcount=%u\n", iface
, ref
);
84 static ULONG WINAPI
BitmapScaler_Release(IWICBitmapScaler
*iface
)
86 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
87 ULONG ref
= InterlockedDecrement(&This
->ref
);
89 TRACE("(%p) refcount=%u\n", iface
, ref
);
93 This
->lock
.DebugInfo
->Spare
[0] = 0;
94 DeleteCriticalSection(&This
->lock
);
95 if (This
->source
) IWICBitmapSource_Release(This
->source
);
96 HeapFree(GetProcessHeap(), 0, This
);
102 static HRESULT WINAPI
BitmapScaler_GetSize(IWICBitmapScaler
*iface
,
103 UINT
*puiWidth
, UINT
*puiHeight
)
105 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
106 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
108 if (!puiWidth
|| !puiHeight
)
112 return WINCODEC_ERR_WRONGSTATE
;
114 *puiWidth
= This
->width
;
115 *puiHeight
= This
->height
;
120 static HRESULT WINAPI
BitmapScaler_GetPixelFormat(IWICBitmapScaler
*iface
,
121 WICPixelFormatGUID
*pPixelFormat
)
123 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
124 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
130 return WINCODEC_ERR_WRONGSTATE
;
132 return IWICBitmapSource_GetPixelFormat(This
->source
, pPixelFormat
);
135 static HRESULT WINAPI
BitmapScaler_GetResolution(IWICBitmapScaler
*iface
,
136 double *pDpiX
, double *pDpiY
)
138 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
139 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
141 if (!pDpiX
|| !pDpiY
)
145 return WINCODEC_ERR_WRONGSTATE
;
147 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
150 static HRESULT WINAPI
BitmapScaler_CopyPalette(IWICBitmapScaler
*iface
,
151 IWICPalette
*pIPalette
)
153 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
154 TRACE("(%p,%p)\n", iface
, pIPalette
);
160 return WINCODEC_ERR_WRONGSTATE
;
162 return IWICBitmapSource_CopyPalette(This
->source
, pIPalette
);
165 static void NearestNeighbor_GetRequiredSourceRect(BitmapScaler
*This
,
166 UINT x
, UINT y
, WICRect
*src_rect
)
168 src_rect
->X
= x
* This
->src_width
/ This
->width
;
169 src_rect
->Y
= y
* This
->src_height
/ This
->height
;
170 src_rect
->Width
= src_rect
->Height
= 1;
173 static void NearestNeighbor_CopyScanline(BitmapScaler
*This
,
174 UINT dst_x
, UINT dst_y
, UINT dst_width
,
175 BYTE
**src_data
, UINT src_data_x
, UINT src_data_y
, BYTE
*pbBuffer
)
178 UINT bytesperpixel
= This
->bpp
/8;
181 src_y
= dst_y
* This
->src_height
/ This
->height
- src_data_y
;
183 for (i
=0; i
<dst_width
; i
++)
185 src_x
= (dst_x
+ i
) * This
->src_width
/ This
->width
- src_data_x
;
186 memcpy(pbBuffer
+ bytesperpixel
* i
, src_data
[src_y
] + bytesperpixel
* src_x
, bytesperpixel
);
190 static HRESULT WINAPI
BitmapScaler_CopyPixels(IWICBitmapScaler
*iface
,
191 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
193 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
196 WICRect src_rect_ul
, src_rect_br
, src_rect
;
200 ULONG src_bytesperrow
;
204 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
206 EnterCriticalSection(&This
->lock
);
210 hr
= WINCODEC_ERR_WRONGSTATE
;
218 dest_rect
.X
= dest_rect
.Y
= 0;
219 dest_rect
.Width
= This
->width
;
220 dest_rect
.Height
= This
->height
;
223 if (dest_rect
.X
< 0 || dest_rect
.Y
< 0 ||
224 dest_rect
.X
+dest_rect
.Width
> This
->width
|| dest_rect
.Y
+dest_rect
.Height
> This
->height
)
230 bytesperrow
= ((This
->bpp
* dest_rect
.Width
)+7)/8;
232 if (cbStride
< bytesperrow
)
238 if ((cbStride
* dest_rect
.Height
) > cbBufferSize
)
244 /* MSDN recommends calling CopyPixels once for each scanline from top to
245 * bottom, and claims codecs optimize for this. Ideally, when called in this
246 * way, we should avoid requesting a scanline from the source more than
247 * once, by saving the data that will be useful for the next scanline after
248 * the call returns. The GetRequiredSourceRect/CopyScanline functions are
249 * designed to make it possible to do this in a generic way, but for now we
250 * just grab all the data we need in each call. */
252 This
->fn_get_required_source_rect(This
, dest_rect
.X
, dest_rect
.Y
, &src_rect_ul
);
253 This
->fn_get_required_source_rect(This
, dest_rect
.X
+dest_rect
.Width
-1,
254 dest_rect
.Y
+dest_rect
.Height
-1, &src_rect_br
);
256 src_rect
.X
= src_rect_ul
.X
;
257 src_rect
.Y
= src_rect_ul
.Y
;
258 src_rect
.Width
= src_rect_br
.Width
+ src_rect_br
.X
- src_rect_ul
.X
;
259 src_rect
.Height
= src_rect_br
.Height
+ src_rect_br
.Y
- src_rect_ul
.Y
;
261 src_bytesperrow
= (src_rect
.Width
* This
->bpp
+ 7)/8;
262 buffer_size
= src_bytesperrow
* src_rect
.Height
;
264 src_rows
= HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE
*) * src_rect
.Height
);
265 src_bits
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
267 if (!src_rows
|| !src_bits
)
269 HeapFree(GetProcessHeap(), 0, src_rows
);
270 HeapFree(GetProcessHeap(), 0, src_bits
);
275 for (y
=0; y
<src_rect
.Height
; y
++)
276 src_rows
[y
] = src_bits
+ y
* src_bytesperrow
;
278 hr
= IWICBitmapSource_CopyPixels(This
->source
, &src_rect
, src_bytesperrow
,
279 buffer_size
, src_bits
);
283 for (y
=0; y
< dest_rect
.Height
; y
++)
285 This
->fn_copy_scanline(This
, dest_rect
.X
, dest_rect
.Y
+y
, dest_rect
.Width
,
286 src_rows
, src_rect
.X
, src_rect
.Y
, pbBuffer
+ cbStride
* y
);
290 HeapFree(GetProcessHeap(), 0, src_rows
);
291 HeapFree(GetProcessHeap(), 0, src_bits
);
294 LeaveCriticalSection(&This
->lock
);
299 static HRESULT WINAPI
BitmapScaler_Initialize(IWICBitmapScaler
*iface
,
300 IWICBitmapSource
*pISource
, UINT uiWidth
, UINT uiHeight
,
301 WICBitmapInterpolationMode mode
)
303 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
305 GUID src_pixelformat
;
307 TRACE("(%p,%p,%u,%u,%u)\n", iface
, pISource
, uiWidth
, uiHeight
, mode
);
309 EnterCriticalSection(&This
->lock
);
313 hr
= WINCODEC_ERR_WRONGSTATE
;
317 This
->width
= uiWidth
;
318 This
->height
= uiHeight
;
321 hr
= IWICBitmapSource_GetSize(pISource
, &This
->src_width
, &This
->src_height
);
324 hr
= IWICBitmapSource_GetPixelFormat(pISource
, &src_pixelformat
);
328 hr
= get_pixelformat_bpp(&src_pixelformat
, &This
->bpp
);
336 FIXME("unsupported mode %i\n", mode
);
338 case WICBitmapInterpolationModeNearestNeighbor
:
339 if ((This
->bpp
% 8) == 0)
341 IWICBitmapSource_AddRef(pISource
);
342 This
->source
= pISource
;
346 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
,
347 pISource
, &This
->source
);
350 This
->fn_get_required_source_rect
= NearestNeighbor_GetRequiredSourceRect
;
351 This
->fn_copy_scanline
= NearestNeighbor_CopyScanline
;
357 LeaveCriticalSection(&This
->lock
);
362 static const IWICBitmapScalerVtbl BitmapScaler_Vtbl
= {
363 BitmapScaler_QueryInterface
,
365 BitmapScaler_Release
,
366 BitmapScaler_GetSize
,
367 BitmapScaler_GetPixelFormat
,
368 BitmapScaler_GetResolution
,
369 BitmapScaler_CopyPalette
,
370 BitmapScaler_CopyPixels
,
371 BitmapScaler_Initialize
374 static HRESULT WINAPI
IMILBitmapScaler_QueryInterface(IMILBitmapScaler
*iface
, REFIID iid
,
377 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
379 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
381 if (!ppv
) return E_INVALIDARG
;
383 if (IsEqualIID(&IID_IUnknown
, iid
) ||
384 IsEqualIID(&IID_IMILBitmapScaler
, iid
) ||
385 IsEqualIID(&IID_IMILBitmapSource
, iid
))
387 IUnknown_AddRef(&This
->IMILBitmapScaler_iface
);
388 *ppv
= &This
->IMILBitmapScaler_iface
;
391 else if (IsEqualIID(&IID_IWICBitmapScaler
, iid
) ||
392 IsEqualIID(&IID_IWICBitmapSource
, iid
))
394 IUnknown_AddRef(&This
->IWICBitmapScaler_iface
);
395 *ppv
= &This
->IWICBitmapScaler_iface
;
399 FIXME("unknown interface %s\n", debugstr_guid(iid
));
401 return E_NOINTERFACE
;
404 static ULONG WINAPI
IMILBitmapScaler_AddRef(IMILBitmapScaler
*iface
)
406 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
407 return IWICBitmapScaler_AddRef(&This
->IWICBitmapScaler_iface
);
410 static ULONG WINAPI
IMILBitmapScaler_Release(IMILBitmapScaler
*iface
)
412 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
413 return IWICBitmapScaler_Release(&This
->IWICBitmapScaler_iface
);
416 static HRESULT WINAPI
IMILBitmapScaler_GetSize(IMILBitmapScaler
*iface
,
417 UINT
*width
, UINT
*height
)
419 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
421 TRACE("(%p,%p,%p)\n", iface
, width
, height
);
424 return WINCODEC_ERR_NOTINITIALIZED
;
426 return IWICBitmapScaler_GetSize(&This
->IWICBitmapScaler_iface
, width
, height
);
429 static HRESULT WINAPI
IMILBitmapScaler_GetPixelFormat(IMILBitmapScaler
*iface
,
432 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
433 IMILBitmapSource
*source
;
436 TRACE("(%p,%p)\n", iface
, format
);
438 if (!format
) return E_INVALIDARG
;
441 return WINCODEC_ERR_NOTINITIALIZED
;
443 hr
= IWICBitmapSource_QueryInterface(This
->source
, &IID_IMILBitmapSource
, (void **)&source
);
446 hr
= source
->lpVtbl
->GetPixelFormat(source
, format
);
447 source
->lpVtbl
->Release(source
);
452 static HRESULT WINAPI
IMILBitmapScaler_GetResolution(IMILBitmapScaler
*iface
,
453 double *dpix
, double *dpiy
)
455 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
457 TRACE("(%p,%p,%p)\n", iface
, dpix
, dpiy
);
460 return WINCODEC_ERR_NOTINITIALIZED
;
462 return IWICBitmapScaler_GetResolution(&This
->IWICBitmapScaler_iface
, dpix
, dpiy
);
465 static HRESULT WINAPI
IMILBitmapScaler_CopyPalette(IMILBitmapScaler
*iface
,
466 IWICPalette
*palette
)
468 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
470 TRACE("(%p,%p)\n", iface
, palette
);
473 return WINCODEC_ERR_NOTINITIALIZED
;
475 return IWICBitmapScaler_CopyPalette(&This
->IWICBitmapScaler_iface
, palette
);
478 static HRESULT WINAPI
IMILBitmapScaler_CopyPixels(IMILBitmapScaler
*iface
,
479 const WICRect
*rc
, UINT stride
, UINT size
, BYTE
*buffer
)
481 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
483 TRACE("(%p,%p,%u,%u,%p)\n", iface
, rc
, stride
, size
, buffer
);
486 return WINCODEC_ERR_NOTINITIALIZED
;
488 return IWICBitmapScaler_CopyPixels(&This
->IWICBitmapScaler_iface
, rc
, stride
, size
, buffer
);
491 static HRESULT WINAPI
IMILBitmapScaler_unknown1(IMILBitmapScaler
*iface
, void **ppv
)
493 TRACE("(%p,%p)\n", iface
, ppv
);
494 return E_NOINTERFACE
;
497 static HRESULT WINAPI
IMILBitmapScaler_Initialize(IMILBitmapScaler
*iface
,
498 IMILBitmapSource
*mil_source
, UINT width
, UINT height
,
499 WICBitmapInterpolationMode mode
)
501 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
502 IWICBitmapSource
*wic_source
;
505 TRACE("(%p,%p,%u,%u,%u)\n", iface
, mil_source
, width
, height
, mode
);
507 if (!mil_source
) return E_INVALIDARG
;
509 hr
= mil_source
->lpVtbl
->QueryInterface(mil_source
, &IID_IWICBitmapSource
, (void **)&wic_source
);
512 hr
= IWICBitmapScaler_Initialize(&This
->IWICBitmapScaler_iface
, wic_source
, width
, height
, mode
);
513 IWICBitmapSource_Release(wic_source
);
518 static const IMILBitmapScalerVtbl IMILBitmapScaler_Vtbl
= {
519 IMILBitmapScaler_QueryInterface
,
520 IMILBitmapScaler_AddRef
,
521 IMILBitmapScaler_Release
,
522 IMILBitmapScaler_GetSize
,
523 IMILBitmapScaler_GetPixelFormat
,
524 IMILBitmapScaler_GetResolution
,
525 IMILBitmapScaler_CopyPalette
,
526 IMILBitmapScaler_CopyPixels
,
527 IMILBitmapScaler_unknown1
,
528 IMILBitmapScaler_Initialize
531 HRESULT
BitmapScaler_Create(IWICBitmapScaler
**scaler
)
535 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapScaler
));
536 if (!This
) return E_OUTOFMEMORY
;
538 This
->IWICBitmapScaler_iface
.lpVtbl
= &BitmapScaler_Vtbl
;
539 This
->IMILBitmapScaler_iface
.lpVtbl
= &IMILBitmapScaler_Vtbl
;
545 This
->src_height
= 0;
548 InitializeCriticalSection(&This
->lock
);
549 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapScaler.lock");
551 *scaler
= &This
->IWICBitmapScaler_iface
;