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
28 #include "wincodecs_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
34 typedef struct BitmapScaler
{
35 IWICBitmapScaler IWICBitmapScaler_iface
;
37 IMILBitmapScaler IMILBitmapScaler_iface
;
38 IWICBitmapSource
*source
;
40 UINT src_width
, src_height
;
41 WICBitmapInterpolationMode mode
;
43 void (*fn_get_required_source_rect
)(struct BitmapScaler
*,UINT
,UINT
,WICRect
*);
44 void (*fn_copy_scanline
)(struct BitmapScaler
*,UINT
,UINT
,UINT
,BYTE
**,UINT
,UINT
,BYTE
*);
45 CRITICAL_SECTION lock
; /* must be held when initialized */
48 static inline BitmapScaler
*impl_from_IWICBitmapScaler(IWICBitmapScaler
*iface
)
50 return CONTAINING_RECORD(iface
, BitmapScaler
, IWICBitmapScaler_iface
);
53 static inline BitmapScaler
*impl_from_IMILBitmapScaler(IMILBitmapScaler
*iface
)
55 return CONTAINING_RECORD(iface
, BitmapScaler
, IMILBitmapScaler_iface
);
58 static HRESULT WINAPI
BitmapScaler_QueryInterface(IWICBitmapScaler
*iface
, REFIID iid
,
61 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
62 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
64 if (!ppv
) return E_INVALIDARG
;
66 if (IsEqualIID(&IID_IUnknown
, iid
) ||
67 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
68 IsEqualIID(&IID_IWICBitmapScaler
, iid
))
70 *ppv
= &This
->IWICBitmapScaler_iface
;
72 else if (IsEqualIID(&IID_IMILBitmapScaler
, iid
))
74 *ppv
= &This
->IMILBitmapScaler_iface
;
78 FIXME("unknown interface %s\n", debugstr_guid(iid
));
83 IUnknown_AddRef((IUnknown
*)*ppv
);
87 static ULONG WINAPI
BitmapScaler_AddRef(IWICBitmapScaler
*iface
)
89 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
90 ULONG ref
= InterlockedIncrement(&This
->ref
);
92 TRACE("(%p) refcount=%lu\n", iface
, ref
);
97 static ULONG WINAPI
BitmapScaler_Release(IWICBitmapScaler
*iface
)
99 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
100 ULONG ref
= InterlockedDecrement(&This
->ref
);
102 TRACE("(%p) refcount=%lu\n", iface
, ref
);
106 This
->lock
.DebugInfo
->Spare
[0] = 0;
107 DeleteCriticalSection(&This
->lock
);
108 if (This
->source
) IWICBitmapSource_Release(This
->source
);
109 HeapFree(GetProcessHeap(), 0, This
);
115 static HRESULT WINAPI
BitmapScaler_GetSize(IWICBitmapScaler
*iface
,
116 UINT
*puiWidth
, UINT
*puiHeight
)
118 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
119 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
122 return WINCODEC_ERR_NOTINITIALIZED
;
124 if (!puiWidth
|| !puiHeight
)
127 *puiWidth
= This
->width
;
128 *puiHeight
= This
->height
;
133 static HRESULT WINAPI
BitmapScaler_GetPixelFormat(IWICBitmapScaler
*iface
,
134 WICPixelFormatGUID
*pPixelFormat
)
136 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
137 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
144 memcpy(pPixelFormat
, &GUID_WICPixelFormatDontCare
, sizeof(*pPixelFormat
));
148 return IWICBitmapSource_GetPixelFormat(This
->source
, pPixelFormat
);
151 static HRESULT WINAPI
BitmapScaler_GetResolution(IWICBitmapScaler
*iface
,
152 double *pDpiX
, double *pDpiY
)
154 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
155 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
158 return WINCODEC_ERR_NOTINITIALIZED
;
160 if (!pDpiX
|| !pDpiY
)
163 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
166 static HRESULT WINAPI
BitmapScaler_CopyPalette(IWICBitmapScaler
*iface
,
167 IWICPalette
*pIPalette
)
169 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
170 TRACE("(%p,%p)\n", iface
, pIPalette
);
176 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
178 return IWICBitmapSource_CopyPalette(This
->source
, pIPalette
);
181 static void NearestNeighbor_GetRequiredSourceRect(BitmapScaler
*This
,
182 UINT x
, UINT y
, WICRect
*src_rect
)
184 src_rect
->X
= x
* This
->src_width
/ This
->width
;
185 src_rect
->Y
= y
* This
->src_height
/ This
->height
;
186 src_rect
->Width
= src_rect
->Height
= 1;
189 static void NearestNeighbor_CopyScanline(BitmapScaler
*This
,
190 UINT dst_x
, UINT dst_y
, UINT dst_width
,
191 BYTE
**src_data
, UINT src_data_x
, UINT src_data_y
, BYTE
*pbBuffer
)
194 UINT bytesperpixel
= This
->bpp
/8;
197 src_y
= dst_y
* This
->src_height
/ This
->height
- src_data_y
;
199 for (i
=0; i
<dst_width
; i
++)
201 src_x
= (dst_x
+ i
) * This
->src_width
/ This
->width
- src_data_x
;
202 memcpy(pbBuffer
+ bytesperpixel
* i
, src_data
[src_y
] + bytesperpixel
* src_x
, bytesperpixel
);
206 static HRESULT WINAPI
BitmapScaler_CopyPixels(IWICBitmapScaler
*iface
,
207 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
209 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
212 WICRect src_rect_ul
, src_rect_br
, src_rect
;
216 ULONG src_bytesperrow
;
220 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
222 EnterCriticalSection(&This
->lock
);
226 hr
= WINCODEC_ERR_NOTINITIALIZED
;
234 dest_rect
.X
= dest_rect
.Y
= 0;
235 dest_rect
.Width
= This
->width
;
236 dest_rect
.Height
= This
->height
;
239 if (dest_rect
.X
< 0 || dest_rect
.Y
< 0 ||
240 dest_rect
.X
+dest_rect
.Width
> This
->width
|| dest_rect
.Y
+dest_rect
.Height
> This
->height
)
246 bytesperrow
= ((This
->bpp
* dest_rect
.Width
)+7)/8;
248 if (cbStride
< bytesperrow
)
254 if (cbStride
* (dest_rect
.Height
- 1) + bytesperrow
> cbBufferSize
)
260 /* MSDN recommends calling CopyPixels once for each scanline from top to
261 * bottom, and claims codecs optimize for this. Ideally, when called in this
262 * way, we should avoid requesting a scanline from the source more than
263 * once, by saving the data that will be useful for the next scanline after
264 * the call returns. The GetRequiredSourceRect/CopyScanline functions are
265 * designed to make it possible to do this in a generic way, but for now we
266 * just grab all the data we need in each call. */
268 This
->fn_get_required_source_rect(This
, dest_rect
.X
, dest_rect
.Y
, &src_rect_ul
);
269 This
->fn_get_required_source_rect(This
, dest_rect
.X
+dest_rect
.Width
-1,
270 dest_rect
.Y
+dest_rect
.Height
-1, &src_rect_br
);
272 src_rect
.X
= src_rect_ul
.X
;
273 src_rect
.Y
= src_rect_ul
.Y
;
274 src_rect
.Width
= src_rect_br
.Width
+ src_rect_br
.X
- src_rect_ul
.X
;
275 src_rect
.Height
= src_rect_br
.Height
+ src_rect_br
.Y
- src_rect_ul
.Y
;
277 src_bytesperrow
= (src_rect
.Width
* This
->bpp
+ 7)/8;
278 buffer_size
= src_bytesperrow
* src_rect
.Height
;
280 src_rows
= HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE
*) * src_rect
.Height
);
281 src_bits
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
283 if (!src_rows
|| !src_bits
)
285 HeapFree(GetProcessHeap(), 0, src_rows
);
286 HeapFree(GetProcessHeap(), 0, src_bits
);
291 for (y
=0; y
<src_rect
.Height
; y
++)
292 src_rows
[y
] = src_bits
+ y
* src_bytesperrow
;
294 hr
= IWICBitmapSource_CopyPixels(This
->source
, &src_rect
, src_bytesperrow
,
295 buffer_size
, src_bits
);
299 for (y
=0; y
< dest_rect
.Height
; y
++)
301 This
->fn_copy_scanline(This
, dest_rect
.X
, dest_rect
.Y
+y
, dest_rect
.Width
,
302 src_rows
, src_rect
.X
, src_rect
.Y
, pbBuffer
+ cbStride
* y
);
306 HeapFree(GetProcessHeap(), 0, src_rows
);
307 HeapFree(GetProcessHeap(), 0, src_bits
);
310 LeaveCriticalSection(&This
->lock
);
315 static HRESULT WINAPI
BitmapScaler_Initialize(IWICBitmapScaler
*iface
,
316 IWICBitmapSource
*pISource
, UINT uiWidth
, UINT uiHeight
,
317 WICBitmapInterpolationMode mode
)
319 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
321 GUID src_pixelformat
;
323 TRACE("(%p,%p,%u,%u,%u)\n", iface
, pISource
, uiWidth
, uiHeight
, mode
);
325 if (!pISource
|| !uiWidth
|| !uiHeight
)
328 EnterCriticalSection(&This
->lock
);
332 hr
= WINCODEC_ERR_WRONGSTATE
;
336 This
->width
= uiWidth
;
337 This
->height
= uiHeight
;
340 hr
= IWICBitmapSource_GetSize(pISource
, &This
->src_width
, &This
->src_height
);
343 hr
= IWICBitmapSource_GetPixelFormat(pISource
, &src_pixelformat
);
347 hr
= get_pixelformat_bpp(&src_pixelformat
, &This
->bpp
);
355 FIXME("unsupported mode %i\n", mode
);
357 case WICBitmapInterpolationModeNearestNeighbor
:
358 if ((This
->bpp
% 8) == 0)
360 IWICBitmapSource_AddRef(pISource
);
361 This
->source
= pISource
;
365 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
,
366 pISource
, &This
->source
);
369 This
->fn_get_required_source_rect
= NearestNeighbor_GetRequiredSourceRect
;
370 This
->fn_copy_scanline
= NearestNeighbor_CopyScanline
;
376 LeaveCriticalSection(&This
->lock
);
381 static const IWICBitmapScalerVtbl BitmapScaler_Vtbl
= {
382 BitmapScaler_QueryInterface
,
384 BitmapScaler_Release
,
385 BitmapScaler_GetSize
,
386 BitmapScaler_GetPixelFormat
,
387 BitmapScaler_GetResolution
,
388 BitmapScaler_CopyPalette
,
389 BitmapScaler_CopyPixels
,
390 BitmapScaler_Initialize
393 static HRESULT WINAPI
IMILBitmapScaler_QueryInterface(IMILBitmapScaler
*iface
, REFIID iid
,
396 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
397 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
398 return IWICBitmapScaler_QueryInterface(&This
->IWICBitmapScaler_iface
, iid
, ppv
);
401 static ULONG WINAPI
IMILBitmapScaler_AddRef(IMILBitmapScaler
*iface
)
403 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
404 return IWICBitmapScaler_AddRef(&This
->IWICBitmapScaler_iface
);
407 static ULONG WINAPI
IMILBitmapScaler_Release(IMILBitmapScaler
*iface
)
409 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
410 return IWICBitmapScaler_Release(&This
->IWICBitmapScaler_iface
);
413 static HRESULT WINAPI
IMILBitmapScaler_GetSize(IMILBitmapScaler
*iface
,
414 UINT
*width
, UINT
*height
)
416 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
417 TRACE("(%p,%p,%p)\n", iface
, width
, height
);
418 return IWICBitmapScaler_GetSize(&This
->IWICBitmapScaler_iface
, width
, height
);
421 static HRESULT WINAPI
IMILBitmapScaler_GetPixelFormat(IMILBitmapScaler
*iface
,
424 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
425 IMILBitmapSource
*source
;
428 TRACE("(%p,%p)\n", iface
, format
);
430 if (!format
) return E_INVALIDARG
;
433 return WINCODEC_ERR_NOTINITIALIZED
;
435 hr
= IWICBitmapSource_QueryInterface(This
->source
, &IID_IMILBitmapSource
, (void **)&source
);
438 hr
= source
->lpVtbl
->GetPixelFormat(source
, format
);
439 source
->lpVtbl
->Release(source
);
444 static HRESULT WINAPI
IMILBitmapScaler_GetResolution(IMILBitmapScaler
*iface
,
445 double *dpix
, double *dpiy
)
447 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
448 TRACE("(%p,%p,%p)\n", iface
, dpix
, dpiy
);
449 return IWICBitmapScaler_GetResolution(&This
->IWICBitmapScaler_iface
, dpix
, dpiy
);
452 static HRESULT WINAPI
IMILBitmapScaler_CopyPalette(IMILBitmapScaler
*iface
,
453 IWICPalette
*palette
)
455 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
457 TRACE("(%p,%p)\n", iface
, palette
);
460 return WINCODEC_ERR_NOTINITIALIZED
;
462 return IWICBitmapScaler_CopyPalette(&This
->IWICBitmapScaler_iface
, palette
);
465 static HRESULT WINAPI
IMILBitmapScaler_CopyPixels(IMILBitmapScaler
*iface
,
466 const WICRect
*rc
, UINT stride
, UINT size
, BYTE
*buffer
)
468 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
469 TRACE("(%p,%p,%u,%u,%p)\n", iface
, rc
, stride
, size
, buffer
);
470 return IWICBitmapScaler_CopyPixels(&This
->IWICBitmapScaler_iface
, rc
, stride
, size
, buffer
);
473 static HRESULT WINAPI
IMILBitmapScaler_unknown1(IMILBitmapScaler
*iface
, void **ppv
)
475 TRACE("(%p,%p)\n", iface
, ppv
);
476 return E_NOINTERFACE
;
479 static HRESULT WINAPI
IMILBitmapScaler_Initialize(IMILBitmapScaler
*iface
,
480 IMILBitmapSource
*mil_source
, UINT width
, UINT height
,
481 WICBitmapInterpolationMode mode
)
483 BitmapScaler
*This
= impl_from_IMILBitmapScaler(iface
);
484 IWICBitmapSource
*wic_source
;
487 TRACE("(%p,%p,%u,%u,%u)\n", iface
, mil_source
, width
, height
, mode
);
489 if (!mil_source
) return E_INVALIDARG
;
491 hr
= mil_source
->lpVtbl
->QueryInterface(mil_source
, &IID_IWICBitmapSource
, (void **)&wic_source
);
494 hr
= IWICBitmapScaler_Initialize(&This
->IWICBitmapScaler_iface
, wic_source
, width
, height
, mode
);
495 IWICBitmapSource_Release(wic_source
);
500 static const IMILBitmapScalerVtbl IMILBitmapScaler_Vtbl
= {
501 IMILBitmapScaler_QueryInterface
,
502 IMILBitmapScaler_AddRef
,
503 IMILBitmapScaler_Release
,
504 IMILBitmapScaler_GetSize
,
505 IMILBitmapScaler_GetPixelFormat
,
506 IMILBitmapScaler_GetResolution
,
507 IMILBitmapScaler_CopyPalette
,
508 IMILBitmapScaler_CopyPixels
,
509 IMILBitmapScaler_unknown1
,
510 IMILBitmapScaler_Initialize
513 HRESULT
BitmapScaler_Create(IWICBitmapScaler
**scaler
)
517 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapScaler
));
518 if (!This
) return E_OUTOFMEMORY
;
520 This
->IWICBitmapScaler_iface
.lpVtbl
= &BitmapScaler_Vtbl
;
521 This
->IMILBitmapScaler_iface
.lpVtbl
= &IMILBitmapScaler_Vtbl
;
527 This
->src_height
= 0;
530 InitializeCriticalSection(&This
->lock
);
531 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapScaler.lock");
533 *scaler
= &This
->IWICBitmapScaler_iface
;