DirectXTex: WIC metadata usage

- Check/writes the sRGB information for DXGI_FORMAT_*_SRGB formats
- Updated WICTextureLoader & ScreenGrab
This commit is contained in:
walbourn_cp 2013-06-10 15:34:13 -07:00
parent 8a267b10b2
commit 3474bcbab9
3 changed files with 215 additions and 23 deletions

View File

@ -223,7 +223,46 @@ static HRESULT _DecodeMetadata( _In_ DWORD flags,
if ( metadata.format == DXGI_FORMAT_UNKNOWN )
return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
return S_OK;
GUID containerFormat;
hr = decoder->GetContainerFormat( &containerFormat );
if ( FAILED(hr) )
return hr;
ScopedObject<IWICMetadataQueryReader> metareader;
hr = frame->GetMetadataQueryReader( &metareader );
if ( SUCCEEDED(hr) )
{
// Check for sRGB colorspace metadata
bool sRGB = false;
PROPVARIANT value;
PropVariantInit( &value );
if ( memcmp( &containerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 )
{
// Check for sRGB chunk
if ( SUCCEEDED( metareader->GetMetadataByName( L"/sRGB/RenderingIntent", &value ) ) && value.vt == VT_UI1 )
{
sRGB = true;
}
}
else if ( SUCCEEDED( metareader->GetMetadataByName( L"System.Image.ColorSpace", &value ) ) && value.vt == VT_UI2 && value.uiVal == 1 )
{
sRGB = true;
}
PropVariantClear( &value );
if ( sRGB )
metadata.format = MakeSRGB( metadata.format );
}
else if ( hr == WINCODEC_ERR_UNSUPPORTEDOPERATION )
{
// Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure
hr = S_OK;
}
return hr;
}
@ -384,10 +423,68 @@ static HRESULT _DecodeMultiframe( _In_ DWORD flags, _In_ const TexMetadata& meta
}
//-------------------------------------------------------------------------------------
// Encodes image metadata
//-------------------------------------------------------------------------------------
static HRESULT _EncodeMetadata( _In_ IWICBitmapFrameEncode* frame, _In_ const GUID& containerFormat, _In_ DXGI_FORMAT format )
{
if ( !frame )
return E_POINTER;
ScopedObject<IWICMetadataQueryWriter> metawriter;
HRESULT hr = frame->GetMetadataQueryWriter( &metawriter );
if ( SUCCEEDED( hr ) )
{
PROPVARIANT value;
PropVariantInit( &value );
bool sRGB = IsSRGB( format );
value.vt = VT_LPSTR;
value.pszVal = "DirectXTex";
if ( memcmp( &containerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 )
{
// Set Software name
(void)metawriter->SetMetadataByName( L"/tEXt/{str=Software}", &value );
// Set sRGB chunk
if ( sRGB )
{
value.vt = VT_UI1;
value.bVal = 0;
(void)metawriter->SetMetadataByName( L"/sRGB/RenderingIntent", &value );
}
}
else
{
// Set Software name
(void)metawriter->SetMetadataByName( L"System.ApplicationName", &value );
if ( sRGB )
{
// Set JPEG EXIF Colorspace of sRGB
value.vt = VT_UI2;
value.uiVal = 1;
(void)metawriter->SetMetadataByName( L"System.Image.ColorSpace", &value );
}
}
}
else if ( hr == WINCODEC_ERR_UNSUPPORTEDOPERATION )
{
// Some formats just don't support metadata (BMP, ICO, etc.), so ignore this failure
hr = S_OK;
}
return hr;
}
//-------------------------------------------------------------------------------------
// Encodes a single frame
//-------------------------------------------------------------------------------------
static HRESULT _EncodeImage( _In_ const Image& image, _In_ DWORD flags, _In_ IWICBitmapFrameEncode* frame, _In_opt_ IPropertyBag2* props, _In_opt_ const GUID* targetFormat )
static HRESULT _EncodeImage( _In_ const Image& image, _In_ DWORD flags, _In_ REFGUID containerFormat,
_In_ IWICBitmapFrameEncode* frame, _In_opt_ IPropertyBag2* props, _In_opt_ const GUID* targetFormat )
{
if ( !frame )
return E_INVALIDARG;
@ -427,6 +524,10 @@ static HRESULT _EncodeImage( _In_ const Image& image, _In_ DWORD flags, _In_ IWI
return E_FAIL;
}
hr = _EncodeMetadata( frame, containerFormat, image.format );
if ( FAILED(hr) )
return hr;
if ( memcmp( &targetGuid, &pfGuid, sizeof(WICPixelFormatGUID) ) != 0 )
{
// Conversion required to write
@ -472,7 +573,7 @@ static HRESULT _EncodeImage( _In_ const Image& image, _In_ DWORD flags, _In_ IWI
}
static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags,
_In_ REFGUID guidContainerFormat, _Inout_ IStream* stream, _In_opt_ const GUID* targetFormat )
_In_ REFGUID containerFormat, _Inout_ IStream* stream, _In_opt_ const GUID* targetFormat )
{
if ( !stream )
return E_INVALIDARG;
@ -483,7 +584,7 @@ static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags,
return E_NOINTERFACE;
ScopedObject<IWICBitmapEncoder> encoder;
HRESULT hr = pWIC->CreateEncoder( guidContainerFormat, 0, &encoder );
HRESULT hr = pWIC->CreateEncoder( containerFormat, 0, &encoder );
if ( FAILED(hr) )
return hr;
@ -497,7 +598,7 @@ static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags,
if ( FAILED(hr) )
return hr;
if ( memcmp( &guidContainerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID) ) == 0 )
if ( memcmp( &containerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID) ) == 0 )
{
// Opt-in to the Windows 8 support for writing 32-bit Windows BMP files with an alpha channel if supported
PROPBAG2 option = { 0 };
@ -514,7 +615,7 @@ static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags,
}
}
hr = _EncodeImage( image, flags, frame.Get(), props.Get(), targetFormat );
hr = _EncodeImage( image, flags, containerFormat, frame.Get(), props.Get(), targetFormat );
if ( FAILED(hr) )
return hr;
@ -530,7 +631,7 @@ static HRESULT _EncodeSingleFrame( _In_ const Image& image, _In_ DWORD flags,
// Encodes an image array
//-------------------------------------------------------------------------------------
static HRESULT _EncodeMultiframe( _In_reads_(nimages) const Image* images, _In_ size_t nimages, _In_ DWORD flags,
_In_ REFGUID guidContainerFormat, _Inout_ IStream* stream, _In_opt_ const GUID* targetFormat )
_In_ REFGUID containerFormat, _Inout_ IStream* stream, _In_opt_ const GUID* targetFormat )
{
if ( !stream || nimages < 2 )
return E_INVALIDARG;
@ -544,7 +645,7 @@ static HRESULT _EncodeMultiframe( _In_reads_(nimages) const Image* images, _In_
return E_NOINTERFACE;
ScopedObject<IWICBitmapEncoder> encoder;
HRESULT hr = pWIC->CreateEncoder( guidContainerFormat, 0, &encoder );
HRESULT hr = pWIC->CreateEncoder( containerFormat, 0, &encoder );
if ( FAILED(hr) )
return hr;
@ -572,7 +673,7 @@ static HRESULT _EncodeMultiframe( _In_reads_(nimages) const Image* images, _In_
if ( FAILED(hr) )
return hr;
hr = _EncodeImage( images[index], flags, frame.Get(), nullptr, targetFormat );
hr = _EncodeImage( images[index], flags, containerFormat, frame.Get(), nullptr, targetFormat );
if ( FAILED(hr) )
return hr;
}
@ -800,7 +901,7 @@ HRESULT LoadFromWICFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, Scr
// Save a WIC-supported file to memory
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT SaveToWICMemory( const Image& image, DWORD flags, REFGUID guidContainerFormat, Blob& blob, const GUID* targetFormat )
HRESULT SaveToWICMemory( const Image& image, DWORD flags, REFGUID containerFormat, Blob& blob, const GUID* targetFormat )
{
if ( !image.pixels )
return E_POINTER;
@ -812,7 +913,7 @@ HRESULT SaveToWICMemory( const Image& image, DWORD flags, REFGUID guidContainerF
if ( FAILED(hr) )
return hr;
hr = _EncodeSingleFrame( image, flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeSingleFrame( image, flags, containerFormat, stream.Get(), targetFormat );
if ( FAILED(hr) )
return hr;
@ -846,7 +947,7 @@ HRESULT SaveToWICMemory( const Image& image, DWORD flags, REFGUID guidContainerF
}
_Use_decl_annotations_
HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGUID guidContainerFormat, Blob& blob, const GUID* targetFormat )
HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGUID containerFormat, Blob& blob, const GUID* targetFormat )
{
if ( !images || nimages == 0 )
return E_INVALIDARG;
@ -859,9 +960,9 @@ HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGU
return hr;
if ( nimages > 1 )
hr = _EncodeMultiframe( images, nimages, flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeMultiframe( images, nimages, flags, containerFormat, stream.Get(), targetFormat );
else
hr = _EncodeSingleFrame( images[0], flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeSingleFrame( images[0], flags, containerFormat, stream.Get(), targetFormat );
if ( FAILED(hr) )
return hr;
@ -900,7 +1001,7 @@ HRESULT SaveToWICMemory( const Image* images, size_t nimages, DWORD flags, REFGU
// Save a WIC-supported file to disk
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID guidContainerFormat, LPCWSTR szFile, const GUID* targetFormat )
HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID containerFormat, LPCWSTR szFile, const GUID* targetFormat )
{
if ( !szFile )
return E_INVALIDARG;
@ -921,7 +1022,7 @@ HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID guidContainerFor
if ( FAILED(hr) )
return hr;
hr = _EncodeSingleFrame( image, flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeSingleFrame( image, flags, containerFormat, stream.Get(), targetFormat );
if ( FAILED(hr) )
return hr;
@ -929,7 +1030,7 @@ HRESULT SaveToWICFile( const Image& image, DWORD flags, REFGUID guidContainerFor
}
_Use_decl_annotations_
HRESULT SaveToWICFile( const Image* images, size_t nimages, DWORD flags, REFGUID guidContainerFormat, LPCWSTR szFile, const GUID* targetFormat )
HRESULT SaveToWICFile( const Image* images, size_t nimages, DWORD flags, REFGUID containerFormat, LPCWSTR szFile, const GUID* targetFormat )
{
if ( !szFile || !images || nimages == 0 )
return E_INVALIDARG;
@ -948,9 +1049,9 @@ HRESULT SaveToWICFile( const Image* images, size_t nimages, DWORD flags, REFGUID
return hr;
if ( nimages > 1 )
hr = _EncodeMultiframe( images, nimages, flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeMultiframe( images, nimages, flags, containerFormat, stream.Get(), targetFormat );
else
hr = _EncodeSingleFrame( images[0], flags, guidContainerFormat, stream.Get(), targetFormat );
hr = _EncodeSingleFrame( images[0], flags, containerFormat, stream.Get(), targetFormat );
if ( FAILED(hr) )
return hr;

View File

@ -893,6 +893,7 @@ HRESULT DirectX::SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext,
// Determine source format's WIC equivalent
WICPixelFormatGUID pfGuid;
bool sRGB = false;
switch ( desc.Format )
{
case DXGI_FORMAT_R32G32B32A32_FLOAT: pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break;
@ -909,20 +910,32 @@ HRESULT DirectX::SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext,
case DXGI_FORMAT_A8_UNORM: pfGuid = GUID_WICPixelFormat8bppAlpha; break;
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
pfGuid = GUID_WICPixelFormat32bppRGBA;
break;
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
pfGuid = GUID_WICPixelFormat32bppRGBA;
sRGB = true;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM: // DXGI 1.1
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
pfGuid = GUID_WICPixelFormat32bppBGRA;
break;
case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: // DXGI 1.1
pfGuid = GUID_WICPixelFormat32bppBGRA;
sRGB = true;
break;
case DXGI_FORMAT_B8G8R8X8_UNORM: // DXGI 1.1
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
pfGuid = GUID_WICPixelFormat32bppBGR;
break;
case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: // DXGI 1.1
pfGuid = GUID_WICPixelFormat32bppBGR;
sRGB = true;
break;
default:
return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
}
@ -1037,6 +1050,44 @@ HRESULT DirectX::SaveWICTextureToFile( _In_ ID3D11DeviceContext* pContext,
return E_FAIL;
}
// Encode WIC metadata
ScopedObject<IWICMetadataQueryWriter> metawriter;
if ( SUCCEEDED( frame->GetMetadataQueryWriter( &metawriter ) ) )
{
PROPVARIANT value;
PropVariantInit( &value );
value.vt = VT_LPSTR;
value.pszVal = "DirectXTK";
if ( memcmp( &guidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 )
{
// Set Software name
(void)metawriter->SetMetadataByName( L"/tEXt/{str=Software}", &value );
// Set sRGB chunk
if ( sRGB )
{
value.vt = VT_UI1;
value.bVal = 0;
(void)metawriter->SetMetadataByName( L"/sRGB/RenderingIntent", &value );
}
}
else
{
// Set Software name
(void)metawriter->SetMetadataByName( L"System.ApplicationName", &value );
if ( sRGB )
{
// Set JPEG EXIF Colorspace of sRGB
value.vt = VT_UI2;
value.uiVal = 1;
(void)metawriter->SetMetadataByName( L"System.Image.ColorSpace", &value );
}
}
}
D3D11_MAPPED_SUBRESOURCE mapped;
hr = pContext->Map( pStaging.Get(), 0, D3D11_MAP_READ, 0, &mapped );
if ( FAILED(hr) )

View File

@ -532,6 +532,46 @@ static HRESULT CreateTextureFromWIC( _In_ ID3D11Device* d3dDevice,
if ( !bpp )
return E_FAIL;
// Handle sRGB formats
if ( forceSRGB )
{
format = MakeSRGB( format );
}
else
{
ScopedObject<IWICMetadataQueryReader> metareader;
if ( SUCCEEDED( frame->GetMetadataQueryReader( &metareader ) ) )
{
GUID containerFormat;
if ( SUCCEEDED( metareader->GetContainerFormat( &containerFormat ) ) )
{
// Check for sRGB colorspace metadata
bool sRGB = false;
PROPVARIANT value;
PropVariantInit( &value );
if ( memcmp( &containerFormat, &GUID_ContainerFormatPng, sizeof(GUID) ) == 0 )
{
// Check for sRGB chunk
if ( SUCCEEDED( metareader->GetMetadataByName( L"/sRGB/RenderingIntent", &value ) ) && value.vt == VT_UI1 )
{
sRGB = true;
}
}
else if ( SUCCEEDED( metareader->GetMetadataByName( L"System.Image.ColorSpace", &value ) ) && value.vt == VT_UI2 && value.uiVal == 1 )
{
sRGB = true;
}
PropVariantClear( &value );
if ( sRGB )
format = MakeSRGB( format );
}
}
}
// Verify our target format is supported by the current device
// (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support)
UINT support = 0;
@ -645,7 +685,7 @@ static HRESULT CreateTextureFromWIC( _In_ ID3D11Device* d3dDevice,
desc.Height = theight;
desc.MipLevels = (autogen) ? 0 : 1;
desc.ArraySize = 1;
desc.Format = (forceSRGB) ? MakeSRGB( format ) : format;
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = usage;