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
29 #include "wincodecs_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
35 typedef struct BitmapScaler
{
36 IWICBitmapScaler IWICBitmapScaler_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 HRESULT WINAPI
BitmapScaler_QueryInterface(IWICBitmapScaler
*iface
, REFIID iid
,
56 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
57 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
59 if (!ppv
) return E_INVALIDARG
;
61 if (IsEqualIID(&IID_IUnknown
, iid
) ||
62 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
63 IsEqualIID(&IID_IWICBitmapScaler
, iid
))
65 *ppv
= &This
->IWICBitmapScaler_iface
;
73 IUnknown_AddRef((IUnknown
*)*ppv
);
77 static ULONG WINAPI
BitmapScaler_AddRef(IWICBitmapScaler
*iface
)
79 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
80 ULONG ref
= InterlockedIncrement(&This
->ref
);
82 TRACE("(%p) refcount=%u\n", iface
, ref
);
87 static ULONG WINAPI
BitmapScaler_Release(IWICBitmapScaler
*iface
)
89 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
90 ULONG ref
= InterlockedDecrement(&This
->ref
);
92 TRACE("(%p) refcount=%u\n", iface
, ref
);
96 This
->lock
.DebugInfo
->Spare
[0] = 0;
97 DeleteCriticalSection(&This
->lock
);
98 if (This
->source
) IWICBitmapSource_Release(This
->source
);
99 HeapFree(GetProcessHeap(), 0, This
);
105 static HRESULT WINAPI
BitmapScaler_GetSize(IWICBitmapScaler
*iface
,
106 UINT
*puiWidth
, UINT
*puiHeight
)
108 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
109 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
112 return WINCODEC_ERR_NOTINITIALIZED
;
114 if (!puiWidth
|| !puiHeight
)
117 *puiWidth
= This
->width
;
118 *puiHeight
= This
->height
;
123 static HRESULT WINAPI
BitmapScaler_GetPixelFormat(IWICBitmapScaler
*iface
,
124 WICPixelFormatGUID
*pPixelFormat
)
126 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
127 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
134 memcpy(pPixelFormat
, &GUID_WICPixelFormatDontCare
, sizeof(*pPixelFormat
));
138 return IWICBitmapSource_GetPixelFormat(This
->source
, pPixelFormat
);
141 static HRESULT WINAPI
BitmapScaler_GetResolution(IWICBitmapScaler
*iface
,
142 double *pDpiX
, double *pDpiY
)
144 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
145 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
148 return WINCODEC_ERR_NOTINITIALIZED
;
150 if (!pDpiX
|| !pDpiY
)
153 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
156 static HRESULT WINAPI
BitmapScaler_CopyPalette(IWICBitmapScaler
*iface
,
157 IWICPalette
*pIPalette
)
159 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
160 TRACE("(%p,%p)\n", iface
, pIPalette
);
166 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
168 return IWICBitmapSource_CopyPalette(This
->source
, pIPalette
);
171 static void NearestNeighbor_GetRequiredSourceRect(BitmapScaler
*This
,
172 UINT x
, UINT y
, WICRect
*src_rect
)
174 src_rect
->X
= x
* This
->src_width
/ This
->width
;
175 src_rect
->Y
= y
* This
->src_height
/ This
->height
;
176 src_rect
->Width
= src_rect
->Height
= 1;
179 static void NearestNeighbor_CopyScanline(BitmapScaler
*This
,
180 UINT dst_x
, UINT dst_y
, UINT dst_width
,
181 BYTE
**src_data
, UINT src_data_x
, UINT src_data_y
, BYTE
*pbBuffer
)
184 UINT bytesperpixel
= This
->bpp
/8;
187 src_y
= dst_y
* This
->src_height
/ This
->height
- src_data_y
;
189 for (i
=0; i
<dst_width
; i
++)
191 src_x
= (dst_x
+ i
) * This
->src_width
/ This
->width
- src_data_x
;
192 memcpy(pbBuffer
+ bytesperpixel
* i
, src_data
[src_y
] + bytesperpixel
* src_x
, bytesperpixel
);
196 static HRESULT WINAPI
BitmapScaler_CopyPixels(IWICBitmapScaler
*iface
,
197 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
199 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
202 WICRect src_rect_ul
, src_rect_br
, src_rect
;
206 ULONG src_bytesperrow
;
210 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
212 EnterCriticalSection(&This
->lock
);
216 hr
= WINCODEC_ERR_WRONGSTATE
;
224 dest_rect
.X
= dest_rect
.Y
= 0;
225 dest_rect
.Width
= This
->width
;
226 dest_rect
.Height
= This
->height
;
229 if (dest_rect
.X
< 0 || dest_rect
.Y
< 0 ||
230 dest_rect
.X
+dest_rect
.Width
> This
->width
|| dest_rect
.Y
+dest_rect
.Height
> This
->height
)
236 bytesperrow
= ((This
->bpp
* dest_rect
.Width
)+7)/8;
238 if (cbStride
< bytesperrow
)
244 if ((cbStride
* dest_rect
.Height
) > cbBufferSize
)
250 /* MSDN recommends calling CopyPixels once for each scanline from top to
251 * bottom, and claims codecs optimize for this. Ideally, when called in this
252 * way, we should avoid requesting a scanline from the source more than
253 * once, by saving the data that will be useful for the next scanline after
254 * the call returns. The GetRequiredSourceRect/CopyScanline functions are
255 * designed to make it possible to do this in a generic way, but for now we
256 * just grab all the data we need in each call. */
258 This
->fn_get_required_source_rect(This
, dest_rect
.X
, dest_rect
.Y
, &src_rect_ul
);
259 This
->fn_get_required_source_rect(This
, dest_rect
.X
+dest_rect
.Width
-1,
260 dest_rect
.Y
+dest_rect
.Height
-1, &src_rect_br
);
262 src_rect
.X
= src_rect_ul
.X
;
263 src_rect
.Y
= src_rect_ul
.Y
;
264 src_rect
.Width
= src_rect_br
.Width
+ src_rect_br
.X
- src_rect_ul
.X
;
265 src_rect
.Height
= src_rect_br
.Height
+ src_rect_br
.Y
- src_rect_ul
.Y
;
267 src_bytesperrow
= (src_rect
.Width
* This
->bpp
+ 7)/8;
268 buffer_size
= src_bytesperrow
* src_rect
.Height
;
270 src_rows
= HeapAlloc(GetProcessHeap(), 0, sizeof(BYTE
*) * src_rect
.Height
);
271 src_bits
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
273 if (!src_rows
|| !src_bits
)
275 HeapFree(GetProcessHeap(), 0, src_rows
);
276 HeapFree(GetProcessHeap(), 0, src_bits
);
281 for (y
=0; y
<src_rect
.Height
; y
++)
282 src_rows
[y
] = src_bits
+ y
* src_bytesperrow
;
284 hr
= IWICBitmapSource_CopyPixels(This
->source
, &src_rect
, src_bytesperrow
,
285 buffer_size
, src_bits
);
289 for (y
=0; y
< dest_rect
.Height
; y
++)
291 This
->fn_copy_scanline(This
, dest_rect
.X
, dest_rect
.Y
+y
, dest_rect
.Width
,
292 src_rows
, src_rect
.X
, src_rect
.Y
, pbBuffer
+ cbStride
* y
);
296 HeapFree(GetProcessHeap(), 0, src_rows
);
297 HeapFree(GetProcessHeap(), 0, src_bits
);
300 LeaveCriticalSection(&This
->lock
);
305 static HRESULT WINAPI
BitmapScaler_Initialize(IWICBitmapScaler
*iface
,
306 IWICBitmapSource
*pISource
, UINT uiWidth
, UINT uiHeight
,
307 WICBitmapInterpolationMode mode
)
309 BitmapScaler
*This
= impl_from_IWICBitmapScaler(iface
);
311 GUID src_pixelformat
;
313 TRACE("(%p,%p,%u,%u,%u)\n", iface
, pISource
, uiWidth
, uiHeight
, mode
);
315 if (!pISource
|| !uiWidth
|| !uiHeight
)
318 EnterCriticalSection(&This
->lock
);
322 hr
= WINCODEC_ERR_WRONGSTATE
;
326 This
->width
= uiWidth
;
327 This
->height
= uiHeight
;
330 hr
= IWICBitmapSource_GetSize(pISource
, &This
->src_width
, &This
->src_height
);
333 hr
= IWICBitmapSource_GetPixelFormat(pISource
, &src_pixelformat
);
337 hr
= get_pixelformat_bpp(&src_pixelformat
, &This
->bpp
);
345 FIXME("unsupported mode %i\n", mode
);
347 case WICBitmapInterpolationModeNearestNeighbor
:
348 if ((This
->bpp
% 8) == 0)
350 IWICBitmapSource_AddRef(pISource
);
351 This
->source
= pISource
;
355 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
,
356 pISource
, &This
->source
);
359 This
->fn_get_required_source_rect
= NearestNeighbor_GetRequiredSourceRect
;
360 This
->fn_copy_scanline
= NearestNeighbor_CopyScanline
;
366 LeaveCriticalSection(&This
->lock
);
371 static const IWICBitmapScalerVtbl BitmapScaler_Vtbl
= {
372 BitmapScaler_QueryInterface
,
374 BitmapScaler_Release
,
375 BitmapScaler_GetSize
,
376 BitmapScaler_GetPixelFormat
,
377 BitmapScaler_GetResolution
,
378 BitmapScaler_CopyPalette
,
379 BitmapScaler_CopyPixels
,
380 BitmapScaler_Initialize
383 HRESULT
BitmapScaler_Create(IWICBitmapScaler
**scaler
)
387 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapScaler
));
388 if (!This
) return E_OUTOFMEMORY
;
390 This
->IWICBitmapScaler_iface
.lpVtbl
= &BitmapScaler_Vtbl
;
396 This
->src_height
= 0;
399 InitializeCriticalSection(&This
->lock
);
400 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": BitmapScaler.lock");
402 *scaler
= &This
->IWICBitmapScaler_iface
;