mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
windowscodecs: Implement the ICNS frame encoder.
This commit is contained in:
parent
51d741f8c8
commit
bbf039fe45
1 changed files with 300 additions and 16 deletions
|
@ -89,6 +89,13 @@ typedef struct IcnsFrameEncode {
|
|||
const IWICBitmapFrameEncodeVtbl *lpVtbl;
|
||||
IcnsEncoder *encoder;
|
||||
LONG ref;
|
||||
BOOL initialized;
|
||||
UINT width;
|
||||
UINT height;
|
||||
icns_type_t icns_type;
|
||||
icns_image_t icns_image;
|
||||
int lines_written;
|
||||
BOOL committed;
|
||||
} IcnsFrameEncode;
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
|
||||
|
@ -133,9 +140,14 @@ static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface)
|
|||
|
||||
if (ref == 0)
|
||||
{
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
This->encoder->outstanding_commits--;
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
if (!This->committed)
|
||||
{
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
This->encoder->outstanding_commits--;
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
}
|
||||
if (This->icns_image.imageData != NULL)
|
||||
picns_free_image(&This->icns_image);
|
||||
|
||||
IUnknown_Release((IUnknown*)This->encoder);
|
||||
HeapFree(GetProcessHeap(), 0, This);
|
||||
|
@ -147,29 +159,91 @@ static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface)
|
|||
static HRESULT WINAPI IcnsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
|
||||
IPropertyBag2 *pIEncoderOptions)
|
||||
{
|
||||
FIXME("(%p,%p): stub\n", iface, pIEncoderOptions);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p,%p)\n", iface, pIEncoderOptions);
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (This->initialized)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
This->initialized = TRUE;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
|
||||
UINT uiWidth, UINT uiHeight)
|
||||
{
|
||||
FIXME("(%p,%u,%u): stub\n", iface, uiWidth, uiHeight);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (!This->initialized || This->icns_image.imageData)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
This->width = uiWidth;
|
||||
This->height = uiHeight;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
|
||||
double dpiX, double dpiY)
|
||||
{
|
||||
FIXME("(%p,%0.2f,%0.2f): stub\n", iface, dpiX, dpiY);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (!This->initialized || This->icns_image.imageData)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
|
||||
WICPixelFormatGUID *pPixelFormat)
|
||||
{
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
|
||||
return E_NOTIMPL;
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (!This->initialized || This->icns_image.imageData)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
|
||||
|
@ -196,21 +270,225 @@ static HRESULT WINAPI IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
|
|||
static HRESULT WINAPI IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
|
||||
UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
|
||||
{
|
||||
FIXME("(%p,%u,%u,%u,%p): stub\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr = S_OK;
|
||||
UINT i;
|
||||
int ret;
|
||||
|
||||
TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (!This->initialized || !This->width || !This->height)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
if (lineCount == 0 || lineCount + This->lines_written > This->height)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!This->icns_image.imageData)
|
||||
{
|
||||
icns_icon_info_t icns_info;
|
||||
icns_info.isImage = 1;
|
||||
icns_info.iconWidth = This->width;
|
||||
icns_info.iconHeight = This->height;
|
||||
icns_info.iconBitDepth = 32;
|
||||
icns_info.iconChannels = 4;
|
||||
icns_info.iconPixelDepth = icns_info.iconBitDepth / icns_info.iconChannels;
|
||||
This->icns_type = picns_get_type_from_image_info(icns_info);
|
||||
if (This->icns_type == ICNS_NULL_TYPE)
|
||||
{
|
||||
WARN("cannot generate ICNS icon from %dx%d image\n", This->width, This->height);
|
||||
hr = E_INVALIDARG;
|
||||
goto end;
|
||||
}
|
||||
ret = picns_init_image_for_type(This->icns_type, &This->icns_image);
|
||||
if (ret != ICNS_STATUS_OK)
|
||||
{
|
||||
WARN("error %d in icns_init_image_for_type\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < lineCount; i++)
|
||||
{
|
||||
BYTE *src_row, *dst_row;
|
||||
UINT j;
|
||||
src_row = pbPixels + cbStride * i;
|
||||
dst_row = This->icns_image.imageData + (This->lines_written + i)*(This->width*4);
|
||||
/* swap bgr -> rgb */
|
||||
for (j = 0; j < This->width*4; j += 4)
|
||||
{
|
||||
dst_row[j] = src_row[j+2];
|
||||
dst_row[j+1] = src_row[j+1];
|
||||
dst_row[j+2] = src_row[j];
|
||||
dst_row[j+3] = src_row[j+3];
|
||||
}
|
||||
}
|
||||
This->lines_written += lineCount;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
|
||||
IWICBitmapSource *pIBitmapSource, WICRect *prc)
|
||||
{
|
||||
FIXME("(%p,%p,%p): stub\n", iface, pIBitmapSource, prc);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
HRESULT hr;
|
||||
WICRect rc;
|
||||
WICPixelFormatGUID guid;
|
||||
UINT stride;
|
||||
BYTE *pixeldata = NULL;
|
||||
|
||||
TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
|
||||
|
||||
if (!This->initialized || !This->width || !This->height)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
|
||||
if (FAILED(hr))
|
||||
goto end;
|
||||
if (!IsEqualGUID(&guid, &GUID_WICPixelFormat32bppBGRA))
|
||||
{
|
||||
FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid));
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!prc)
|
||||
{
|
||||
UINT width, height;
|
||||
hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
|
||||
if (FAILED(hr))
|
||||
goto end;
|
||||
rc.X = 0;
|
||||
rc.Y = 0;
|
||||
rc.Width = width;
|
||||
rc.Height = height;
|
||||
prc = &rc;
|
||||
}
|
||||
|
||||
if (prc->Width != This->width)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
stride = (32 * This->width + 7)/8;
|
||||
pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
|
||||
if (!pixeldata)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
|
||||
stride*prc->Height, pixeldata);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
|
||||
stride*prc->Height, pixeldata);
|
||||
}
|
||||
|
||||
end:
|
||||
HeapFree(GetProcessHeap(), 0, pixeldata);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
|
||||
{
|
||||
FIXME("(%p): stub\n", iface);
|
||||
return E_NOTIMPL;
|
||||
IcnsFrameEncode *This = (IcnsFrameEncode*)iface;
|
||||
icns_element_t *icns_element = NULL;
|
||||
icns_image_t mask;
|
||||
icns_element_t *mask_element = NULL;
|
||||
int ret;
|
||||
int i;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
TRACE("(%p): stub\n", iface);
|
||||
|
||||
memset(&mask, 0, sizeof(mask));
|
||||
|
||||
EnterCriticalSection(&This->encoder->lock);
|
||||
|
||||
if (!This->icns_image.imageData || This->lines_written != This->height || This->committed)
|
||||
{
|
||||
hr = WINCODEC_ERR_WRONGSTATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = picns_new_element_from_image(&This->icns_image, This->icns_type, &icns_element);
|
||||
if (ret != ICNS_STATUS_OK && icns_element != NULL)
|
||||
{
|
||||
WARN("icns_new_element_from_image failed with error %d\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (This->icns_type != ICNS_512x512_32BIT_ARGB_DATA && This->icns_type != ICNS_256x256_32BIT_ARGB_DATA)
|
||||
{
|
||||
/* we need to write the mask too */
|
||||
ret = picns_init_image_for_type(picns_get_mask_type_for_icon_type(This->icns_type), &mask);
|
||||
if (ret != ICNS_STATUS_OK)
|
||||
{
|
||||
WARN("icns_init_image_from_type failed to make mask, error %d\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
for (i = 0; i < mask.imageHeight; i++)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < mask.imageWidth; j++)
|
||||
mask.imageData[i*mask.imageWidth + j] = This->icns_image.imageData[i*mask.imageWidth*4 + j*4 + 3];
|
||||
}
|
||||
ret = picns_new_element_from_image(&mask, picns_get_mask_type_for_icon_type(This->icns_type), &mask_element);
|
||||
if (ret != ICNS_STATUS_OK)
|
||||
{
|
||||
WARN("icns_new_element_from image failed to make element from mask, error %d\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = picns_set_element_in_family(&This->encoder->icns_family, icns_element);
|
||||
if (ret != ICNS_STATUS_OK)
|
||||
{
|
||||
WARN("icns_set_element_in_family failed for image with error %d\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (mask_element)
|
||||
{
|
||||
ret = picns_set_element_in_family(&This->encoder->icns_family, mask_element);
|
||||
if (ret != ICNS_STATUS_OK)
|
||||
{
|
||||
WARN("icns_set_element_in_family failed for mask with error %d\n", ret);
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
This->committed = TRUE;
|
||||
This->encoder->any_frame_committed = TRUE;
|
||||
This->encoder->outstanding_commits--;
|
||||
|
||||
end:
|
||||
LeaveCriticalSection(&This->encoder->lock);
|
||||
picns_free_image(&mask);
|
||||
free(icns_element);
|
||||
free(mask_element);
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
|
||||
|
@ -392,6 +670,12 @@ static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
|
|||
frameEncode->lpVtbl = &IcnsEncoder_FrameVtbl;
|
||||
frameEncode->encoder = This;
|
||||
frameEncode->ref = 1;
|
||||
frameEncode->initialized = FALSE;
|
||||
frameEncode->width = 0;
|
||||
frameEncode->height = 0;
|
||||
memset(&frameEncode->icns_image, 0, sizeof(icns_image_t));
|
||||
frameEncode->lines_written = 0;
|
||||
frameEncode->committed = FALSE;
|
||||
*ppIFrameEncode = (IWICBitmapFrameEncode*)frameEncode;
|
||||
This->outstanding_commits++;
|
||||
IUnknown_AddRef((IUnknown*)This);
|
||||
|
|
Loading…
Reference in a new issue