2 * Copyright 2010 Vincent Povirk for CodeWeavers
3 * Copyright 2016 Dmitry Timoshkov
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.
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.
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
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
36 typedef struct BitmapScaler
{
37 IWICBitmapScaler IWICBitmapScaler_iface
;
39 IMILBitmapScaler IMILBitmapScaler_iface
;
40 IWICBitmapSource
*source
;
42 UINT src_width
, src_height
;
43 WICBitmapInterpolationMode mode
;
45 void (*fn_get_required_source_rect
)(struct BitmapScaler
*,UINT
,UINT
,WICRect
*);
46 void (*fn_copy_scanline
)(struct BitmapScaler
*,UINT
,UINT
,UINT
,BYTE
**,UINT
,UINT
,BYTE
*);
47 CRITICAL_SECTION lock
; /* must be held when initialized */
50 static inline BitmapScaler
*impl_from_IWICBitmapScaler(IWICBitmapScaler
*iface
)
52 return CONTAINING_RECORD(iface
, BitmapScaler
, IWICBitmapScaler_iface
);
55 static inline BitmapScaler
*impl_from_IMILBitmapScaler(IMILBitmapScaler
*iface
)
57 return CONTAINING_RECORD(iface
, BitmapScaler
, IMILBitmapScaler_iface
);
60 static HRESULT WINAPI
BitmapScaler_QueryInterface(IWICBitmapScaler
*iface
, REFIID iid
,
63 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
64 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
66 if (!ppv
) return E_INVALIDARG
;
68 if (IsEqualIID(&IID_IUnknown
, iid
) ||
69 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
70 IsEqualIID(&IID_IWICBitmapScaler
, iid
))
72 *ppv
= &This
->IWICBitmapScaler_iface
;
74 else if (IsEqualIID(&IID_IMILBitmapScaler
, iid
))
76 *ppv
= &This
->IMILBitmapScaler_iface
;
80 FIXME("unknown interface %s\n", debugstr_guid(iid
));
85 IUnknown_AddRef((IUnknown
*)*ppv
);
89 static ULONG WINAPI
BitmapScaler_AddRef(IWICBitmapScaler
*iface
)
91 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
92 ULONG ref
= InterlockedIncrement(&This
->ref
);
94 TRACE("(%p) refcount=%u\n", iface
, ref
);
99 static ULONG WINAPI
BitmapScaler_Release(IWICBitmapScaler
*iface
)
101 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
102 ULONG ref
= InterlockedDecrement(&This
->ref
);
104 TRACE("(%p) refcount=%u\n", iface
, ref
);
108 This
->lock
.DebugInfo
->Spare
[0] = 0;
109 DeleteCriticalSection(&This
->lock
);
110 if (This
->source
) IWICBitmapSource_Release(This
->source
);
111 HeapFree(GetProcessHeap(), 0, This
);
117 static HRESULT WINAPI
BitmapScaler_GetSize(IWICBitmapScaler
*iface
,
118 UINT
*puiWidth
, UINT
*puiHeight
)
120 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
121 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
124 return WINCODEC_ERR_NOTINITIALIZED
;
126 if (!puiWidth
|| !puiHeight
)
129 *puiWidth
= This
->width
;
130 *puiHeight
= This
->height
;
135 static HRESULT WINAPI
BitmapScaler_GetPixelFormat(IWICBitmapScaler
*iface
,
136 WICPixelFormatGUID
*pPixelFormat
)
138 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
139 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
146 memcpy(pPixelFormat
, &GUID_WICPixelFormatDontCare
, sizeof(*pPixelFormat
));
150 return IWICBitmapSource_GetPixelFormat(This
->source
, pPixelFormat
);
153 static HRESULT WINAPI
BitmapScaler_GetResolution(IWICBitmapScaler
*iface
,
154 double *pDpiX
, double *pDpiY
)
156 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
157 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
160 return WINCODEC_ERR_NOTINITIALIZED
;
162 if (!pDpiX
|| !pDpiY
)
165 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
168 static HRESULT WINAPI
BitmapScaler_CopyPalette(IWICBitmapScaler
*iface
,
169 IWICPalette
*pIPalette
)
171 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
172 TRACE("(%p,%p)\n", iface
, pIPalette
);
178 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
180 return IWICBitmapSource_CopyPalette(This
->source
, pIPalette
);
183 static void NearestNeighbor_GetRequiredSourceRect(BitmapScaler
*This
,
184 UINT x
, UINT y
, WICRect
*src_rect
)
186 src_rect
->X
= x
* This
->src_width
/ This
->width
;
187 src_rect
->Y
= y
* This
->src_height
/ This
->height
;
188 src_rect
->Width
= src_rect
->Height
= 1;
191 static void NearestNeighbor_CopyScanline(BitmapScaler
*This
,
192 UINT dst_x
, UINT dst_y
, UINT dst_width
,
193 BYTE
**src_data
, UINT src_data_x
, UINT src_data_y
, BYTE
*pbBuffer
)
196 UINT bytesperpixel
= This
->bpp
/8;
199 src_y
= dst_y
* This
->src_height
/ This
->height
- src_data_y
;
201 for (i
=0; i
<dst_width
; i
++)
203 src_x
= (dst_x
+ i
) * This
->src_width
/ This
->width
- src_data_x
;
204 memcpy(pbBuffer
+ bytesperpixel
* i
, src_data
[src_y
] + bytesperpixel
* src_x
, bytesperpixel
);
208 static HRESULT WINAPI
BitmapScaler_CopyPixels(IWICBitmapScaler
*iface
,
209 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
211 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
214 WICRect src_rect_ul
, src_rect_br
, src_rect
;
218 ULONG src_bytesperrow
;
222 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
224 EnterCriticalSection(&This
->lock
);
228 hr
= WINCODEC_ERR_NOTINITIALIZED
;
236 dest_rect
.X
= dest_rect
.Y
= 0;
237 dest_rect
.Width
= This
->width
;
238 dest_rect
.Height
= This
->height
;
241 if (dest_rect
.X
< 0 || dest_rect
.Y
< 0 ||
242 dest_rect
.X
+dest_rect
.Width
> This
->width
|| dest_rect
.Y
+dest_rect
.Height
> This
->height
)
248 bytesperrow
= ((This
->bpp
* dest_rect
.Width
)+7)/8;
250 if (cbStride
< bytesperrow
)
256 if ((cbStride
* dest_rect
.Height
) > cbBufferSize
)
262 /* MSDN recommends calling CopyPixels once for each scanline from top to
263 * bottom, and claims codecs optimize for this. Ideally, when called in this
264 * way, we should avoid requesting a scanline from the source more than
265 * once, by saving the data that will be useful for the next scanline after
266 * the call returns. The GetRequiredSourceRect/CopyScanline functions are
267 * designed to make it possible to do this in a generic way, but for now we
268 * just grab all the data we need in each call. */
270 This
->fn_get_required_source_rect(This
, dest_rect
.X
, dest_rect
.Y
, &src_rect_ul
);
271 This
->fn_get_required_source_rect(This
, dest_rect
.X
+dest_rect
.Width
-1,
272 dest_rect
.Y
+dest_rect
.Height
-1, &src_rect_br
);
274 src_rect
.X
= src_rect_ul
.X
;
275 src_rect
.Y
= src_rect_ul
.Y
;
276 src_rect
.Width
= src_rect_br
.Width
+ src_rect_br
.X
- src_rect_ul
.X
;
277 src_rect
.Height
= src_rect_br
.Height
+ src_rect_br
.Y
- src_rect_ul
.Y
;
279 src_bytesperrow
= (src_rect
.Width
* This
->bpp
+ 7)/8;
280 buffer_size
= src_bytesperrow
* src_rect
.Height
;
282 src_rows
= HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE
*) * src_rect
.Height
);
283 src_bits
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
285 if (!src_rows
|| !src_bits
)
287 HeapFree(GetProcessHeap(), 0, src_rows
);
288 HeapFree(GetProcessHeap(), 0, src_bits
);
293 for (y
=0; y
<src_rect
.Height
; y
++)
294 src_rows
[y
] = src_bits
+ y
* src_bytesperrow
;
296 hr
= IWICBitmapSource_CopyPixels(This
->source
, &src_rect
, src_bytesperrow
,
297 buffer_size
, src_bits
);
301 for (y
=0; y
< dest_rect
.Height
; y
++)
303 This
->fn_copy_scanline(This
, dest_rect
.X
, dest_rect
.Y
+y
, dest_rect
.Width
,
304 src_rows
, src_rect
.X
, src_rect
.Y
, pbBuffer
+ cbStride
* y
);
308 HeapFree(GetProcessHeap(), 0, src_rows
);
309 HeapFree(GetProcessHeap(), 0, src_bits
);
312 LeaveCriticalSection(&This
->lock
);
317 static HRESULT WINAPI
BitmapScaler_Initialize(IWICBitmapScaler
*iface
,
318 IWICBitmapSource
*pISource
, UINT uiWidth
, UINT uiHeight
,
319 WICBitmapInterpolationMode mode
)
321 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
323 GUID src_pixelformat
;
325 TRACE("(%p,%p,%u,%u,%u)\n", iface
, pISource
, uiWidth
, uiHeight
, mode
);
327 if (!pISource
|| !uiWidth
|| !uiHeight
)
330 EnterCriticalSection(&This
->lock
);
334 hr
= WINCODEC_ERR_WRONGSTATE
;
338 This
->width
= uiWidth
;
339 This
->height
= uiHeight
;
342 hr
= IWICBitmapSource_GetSize(pISource
, &This
->src_width
, &This
->src_height
);
345 hr
= IWICBitmapSource_GetPixelFormat(pISource
, &src_pixelformat
);
349 hr
= get_pixelformat_bpp(&src_pixelformat
, &This
->bpp
);
357 FIXME("unsupported mode %i\n", mode
);
359 case WICBitmapInterpolationModeNearestNeighbor
:
360 if ((This
->bpp
% 8) == 0)
362 IWICBitmapSource_AddRef(pISource
);
363 This
->source
= pISource
;
367 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
,
368 pISource
, &This
->source
);
371 This
->fn_get_required_source_rect
= NearestNeighbor_GetRequiredSourceRect
;
372 This
->fn_copy_scanline
= NearestNeighbor_CopyScanline
;
378 LeaveCriticalSection(&This
->lock
);
383 static const IWICBitmapScalerVtbl BitmapScaler_Vtbl
= {
384 BitmapScaler_QueryInterface
,
386 BitmapScaler_Release
,
387 BitmapScaler_GetSize
,
388 BitmapScaler_GetPixelFormat
,
389 BitmapScaler_GetResolution
,
390 BitmapScaler_CopyPalette
,
391 BitmapScaler_CopyPixels
,
392 BitmapScaler_Initialize
395 static HRESULT WINAPI
IMILBitmapScaler_QueryInterface(IMILBitmapScaler
*iface
, REFIID iid
,
398 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
399 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
400 return IWICBitmapScaler_QueryInterface(&This
->IWICBitmapScaler_iface
, iid
, ppv
);
403 static ULONG WINAPI
IMILBitmapScaler_AddRef(IMILBitmapScaler
*iface
)
405 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
406 return IWICBitmapScaler_AddRef(&This
->IWICBitmapScaler_iface
);
409 static ULONG WINAPI
IMILBitmapScaler_Release(IMILBitmapScaler
*iface
)
411 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
412 return IWICBitmapScaler_Release(&This
->IWICBitmapScaler_iface
);
415 static HRESULT WINAPI
IMILBitmapScaler_GetSize(IMILBitmapScaler
*iface
,
416 UINT
*width
, UINT
*height
)
418 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
419 TRACE("(%p,%p,%p)\n", iface
, width
, height
);
420 return IWICBitmapScaler_GetSize(&This
->IWICBitmapScaler_iface
, width
, height
);
423 static HRESULT WINAPI
IMILBitmapScaler_GetPixelFormat(IMILBitmapScaler
*iface
,
426 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
427 IMILBitmapSource
*source
;
430 TRACE("(%p,%p)\n", iface
, format
);
432 if (!format
) return E_INVALIDARG
;
435 return WINCODEC_ERR_NOTINITIALIZED
;
437 hr
= IWICBitmapSource_QueryInterface(This
->source
, &IID_IMILBitmapSource
, (void **)&source
);
440 hr
= source
->lpVtbl
->GetPixelFormat(source
, format
);
441 source
->lpVtbl
->Release(source
);
446 static HRESULT WINAPI
IMILBitmapScaler_GetResolution(IMILBitmapScaler
*iface
,
447 double *dpix
, double *dpiy
)
449 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
450 TRACE("(%p,%p,%p)\n", iface
, dpix
, dpiy
);
451 return IWICBitmapScaler_GetResolution(&This
->IWICBitmapScaler_iface
, dpix
, dpiy
);
454 static HRESULT WINAPI
IMILBitmapScaler_CopyPalette(IMILBitmapScaler
*iface
,
455 IWICPalette
*palette
)
457 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
459 TRACE("(%p,%p)\n", iface
, palette
);
462 return WINCODEC_ERR_NOTINITIALIZED
;
464 return IWICBitmapScaler_CopyPalette(&This
->IWICBitmapScaler_iface
, palette
);
467 static HRESULT WINAPI
IMILBitmapScaler_CopyPixels(IMILBitmapScaler
*iface
,
468 const WICRect
*rc
, UINT stride
, UINT size
, BYTE
*buffer
)
470 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
471 TRACE("(%p,%p,%u,%u,%p)\n", iface
, rc
, stride
, size
, buffer
);
472 return IWICBitmapScaler_CopyPixels(&This
->IWICBitmapScaler_iface
, rc
, stride
, size
, buffer
);
475 static HRESULT WINAPI
IMILBitmapScaler_unknown1(IMILBitmapScaler
*iface
, void **ppv
)
477 TRACE("(%p,%p)\n", iface
, ppv
);
478 return E_NOINTERFACE
;
481 static HRESULT WINAPI
IMILBitmapScaler_Initialize(IMILBitmapScaler
*iface
,
482 IMILBitmapSource
*mil_source
, UINT width
, UINT height
,
483 WICBitmapInterpolationMode mode
)
485 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
486 IWICBitmapSource
*wic_source
;
489 TRACE("(%p,%p,%u,%u,%u)\n", iface
, mil_source
, width
, height
, mode
);
491 if (!mil_source
) return E_INVALIDARG
;
493 hr
= mil_source
->lpVtbl
->QueryInterface(mil_source
, &IID_IWICBitmapSource
, (void **)&wic_source
);
496 hr
= IWICBitmapScaler_Initialize(&This
->IWICBitmapScaler_iface
, wic_source
, width
, height
, mode
);
497 IWICBitmapSource_Release(wic_source
);
502 static const IMILBitmapScalerVtbl IMILBitmapScaler_Vtbl
= {
503 IMILBitmapScaler_QueryInterface
,
504 IMILBitmapScaler_AddRef
,
505 IMILBitmapScaler_Release
,
506 IMILBitmapScaler_GetSize
,
507 IMILBitmapScaler_GetPixelFormat
,
508 IMILBitmapScaler_GetResolution
,
509 IMILBitmapScaler_CopyPalette
,
510 IMILBitmapScaler_CopyPixels
,
511 IMILBitmapScaler_unknown1
,
512 IMILBitmapScaler_Initialize
515 HRESULT
BitmapScaler_Create(IWICBitmapScaler
**scaler
)
519 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapScaler
));
520 if (!This
) return E_OUTOFMEMORY
;
522 This
->IWICBitmapScaler_iface
.lpVtbl
= &BitmapScaler_Vtbl
;
523 This
->IMILBitmapScaler_iface
.lpVtbl
= &IMILBitmapScaler_Vtbl
;
529 This
->src_height
= 0;
532 InitializeCriticalSection(&This
->lock
);
533 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapScaler.lock");
535 *scaler
= &This
->IWICBitmapScaler_iface
;