Sample Code
Windows Driver Samples/ XPSDrv Driver and Filter Sample/ C++/ src/ filters/ color/ colchan.cpp/
/*++ Copyright (c) 2005 Microsoft Corporation All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. File Name: colchan.cpp Abstract: Color channel class implementation. The color channel class is responsible for maintaining simple single color multiple channel data intialised from color references in the XPS markup. It provides methods for intialization, access and conversion of the data. Note regarding color formats: The CColorChannelData class is only used in the filter for processing color references in mark-up. As such we only ever see 8 bit per channel sRGB and floating point scRGB and n-channel colors and we only ever need convert to 16 bpc for down-level scRGB conversion. If the CColorChannelData is ever used when fixed point input or other output types are required then these formats need support added (see E_NOTIMPL return values). --*/ #include "precomp.h" #include "debug.h" #include "globals.h" #include "xdexcept.h" #include "colchan.h" #define MAX_CHANNEL_COUNT 9 // 1 alpha channel and 8 color channels #define MAX_CHANNEL_SIZE sizeof(FLOAT) DWORD g_cbChannelType[] = { sizeof(BYTE), // COLOR_BYTE sizeof(WORD), // COLOR_WORD sizeof(FLOAT), // COLOR_FLOAT sizeof(WORD) // COLOR_S2DOT13FIXED }; /*++ Routine Name: CColorChannelData::CColorChannelData Routine Description: CColorChannelData default constructor Arguments: None Return Value: None Throws an exception on failure. --*/ CColorChannelData::CColorChannelData() : m_cChannels(0), m_channelType(COLOR_BYTE), m_pChannelData(NULL), m_cbChannelData(0), m_dataType(sRGB) { if (FAILED(AllocateChannelBuffers(&m_cbChannelData, &m_pChannelData))) { throw CXDException(E_OUTOFMEMORY); } } /*++ Routine Name: CColorChannelData::~CColorChannelData Routine Description: CColorChannelData destructor Arguments: None Return Value: None --*/ CColorChannelData::~CColorChannelData() { FreeChannelBuffers(); } /*++ Routine Name: CColorChannelData::AddChannelData Routine Description: Template method for adding channel data. This allows any of the available color channel data types to be added to the channel data buffer Arguments: channelValue - Value for the channel to be added Return Value: HRESULT S_OK - On success E_* - On error --*/ template <class _T> HRESULT CColorChannelData::AddChannelData( _In_ CONST _T& channelValue ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = ValidateDataSize<_T>())) { if (m_cChannels < MAX_CHANNEL_COUNT) { _T* pChannelData = reinterpret_cast<_T*>(m_pChannelData); pChannelData[m_cChannels] = channelValue; m_cChannels++; } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetChannelCount Routine Description: Retrieves the current number of channels defining the color. Arguments: pcChannels - Pointer to a variable that recieves the count of channels Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelCount( _Out_ DWORD* pcChannels ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pcChannels, E_POINTER))) { *pcChannels = m_cChannels; } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetChannelCountNoAlpha Routine Description: Retrieves the number of channels less the alpha channel if present Arguments: pcChannels - Pointer to a variable that recieves the count of non-alpha channels Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelCountNoAlpha( _Out_ DWORD* pcChannels ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = GetChannelCount(pcChannels))) { if (HasAlpha()) { (*pcChannels)--; } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetChannelType Routine Description: Retrieves the COLORDATATYPE for the channel data Arguments: pChannelType - Pointer to a COLORDATATYPE variable that recieves the type Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelType( _Out_ COLORDATATYPE* pChannelType ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pChannelType, E_POINTER))) { *pChannelType = m_channelType; } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ResetChannelType Routine Description: Resets the underlying channel data type to the requested type Arguments: channelType - The channel data type to reset to Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::ResetChannelType( _In_ CONST COLORDATATYPE& channelType ) { m_channelType = channelType; m_cChannels = 0; return S_OK; } /*++ Routine Name: CColorChannelData::GetChannelData Routine Description: Retrieves the buffer and count of bytes of the channel data Arguments: pcbDataSize - Pointer to variable that recieves the count of bytes in the buffer ppData - Pointer to a BYTE pointer that recieves the buffer Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelData( _Out_ DWORD* pcbDataSize, _Out_ _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) PVOID* ppData ) { HRESULT hr = S_OK; DWORD cbDataTypeSize = 0; if (SUCCEEDED(hr = CHECK_POINTER(pcbDataSize, E_POINTER)) && SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbDataTypeSize))) { *ppData = NULL; *pcbDataSize = 0; if (m_cbChannelData >= m_cChannels * cbDataTypeSize) { if (m_cChannels > 0) { *pcbDataSize = m_cChannels * cbDataTypeSize; *ppData = m_pChannelData; } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetChannelDataNoAlpha Routine Description: Retrieves the buffer and count of bytes of the channel data excluding the alpha channel if present Arguments: pcbDataSize - Pointer to variable that recieves the count of bytes in the buffer ppData - Pointer to a BYTE pointer that recieves the buffer Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelDataNoAlpha( _Out_ DWORD* pcbDataSize, _Out_ _When_(*pcbDataSize > 0, _At_(*ppData, _Post_ _Readable_bytes_(*pcbDataSize))) _When_(*pcbDataSize == 0, _At_(*ppData, _Post_ _Maybenull_)) PVOID* ppData ) { HRESULT hr = S_OK; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pcbDataSize, E_POINTER)) && SUCCEEDED(hr = CHECK_POINTER(ppData, E_POINTER)) && SUCCEEDED(hr = GetChannelData(&cbData, reinterpret_cast<PVOID*>(&pData)))) { *pcbDataSize = cbData; *ppData = pData; if (HasAlpha()) { DWORD cbChannelSize = 0; if (SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbChannelSize))) { if (cbData >= cbChannelSize) { *pcbDataSize = cbData - cbChannelSize; *ppData = pData + cbChannelSize; } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ClampChannelValues Routine Description: Template method that recieves the minimum and maximum value for a channel and applies this to all channels defining the color Arguments: min - Minimum channel value max - Maximum channel value Return Value: HRESULT S_OK - On success E_* - On error --*/ template <class _T> HRESULT CColorChannelData::ClampChannelValues( _In_ CONST _T& min, _In_ CONST _T& max ) { HRESULT hr = S_OK; // // Validate the data size against the current type // if (SUCCEEDED(hr = ValidateDataSize<_T>())) { _T* pData = reinterpret_cast<_T*>(m_pChannelData); for (DWORD cChannel = 0; cChannel < m_cChannels; cChannel++, pData++) { if (*pData < min) { *pData = min; } else if (*pData > max) { *pData = max; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::InitializeChannelData Routine Description: Initializes the channel data according to the type, count of channels and a default value Arguments: channelType - The required channel data format dataType - The required data type cChannels - The count of channels defining the color channelValue - The intial value for all channels Return Value: HRESULT S_OK - On success E_* - On error --*/ template <class _T> HRESULT CColorChannelData::InitializeChannelData( _In_ CONST COLORDATATYPE& channelType, _In_ CONST EColorDataType& dataType, _In_ CONST DWORD& cChannels, _In_ CONST _T& channelValue ) { HRESULT hr = S_OK; // // Validate the data size against the current type // if (SUCCEEDED(hr = ResetChannelType(channelType)) && SUCCEEDED(hr = ValidateDataSize<_T>())) { if (cChannels <= MAX_CHANNEL_COUNT) { m_dataType = dataType; m_cChannels = cChannels; _T* pChannelData = reinterpret_cast<_T*>(m_pChannelData); for (DWORD cChannel = 0; cChannel < m_cChannels; cChannel++, pChannelData++) { *pChannelData = channelValue; } } else { hr = E_INVALIDARG; } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::SetColorDataType Routine Description: Sets the color data type Arguments: dataType - The color data type Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::SetColorDataType( _In_ CONST EColorDataType& dataType ) { m_dataType = dataType; return S_OK; } /*++ Routine Name: CColorChannelData::GetColorDataType Routine Description: Retrieves the current color data type Arguments: pDataType - Pointer to a variable to recieve the color data type Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetColorDataType( _Out_ EColorDataType* pDataType ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pDataType, E_POINTER))) { *pDataType = m_dataType; } return S_OK; } /*++ Routine Name: CColorChannelData::HasAlpha Routine Description: Indicates if the color channel data includes an alpha channel Arguments: None Return Value: TRUE - An alpha channel is present FALSE - There is no alpha channel --*/ BOOL CColorChannelData::HasAlpha( VOID ) { // // If the source or destination is n-channel, or if either sRGB or scRGB have 4 channels, // we have an alpha channel // return m_dataType == nChannel || m_cChannels == 4; } /*++ Routine Name: CColorChannelData::GetAlphaChannelSize Routine Description: Retrieves the count of bytes of the alpha channel Arguments: pcbAlphaChannel - pointer to a variable that recieves the count of bytes of the alpha channel Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetAlphaChannelSize( _Out_ DWORD* pcbAlphaChan ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pcbAlphaChan, E_POINTER))) { *pcbAlphaChan = 0; if (HasAlpha()) { hr = GetChannelSizeFromType(m_channelType, pcbAlphaChan); } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::InitializeAlphaChannel Routine Description: Initialize the alpha channel based off a source color channel data object Arguments: pSrcChannelData - Pointer to a source color data channel object Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::InitializeAlphaChannel( _In_ CColorChannelData* pSrcChannelData ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pSrcChannelData, E_POINTER))) { if (HasAlpha()) { FLOAT alpha = 1.0f; if (SUCCEEDED(hr) && pSrcChannelData->HasAlpha() && SUCCEEDED(hr = pSrcChannelData->GetAlphaAsFloat(&alpha))) { // // Ensure alpha lies between 0.0 and 1.0 // if (alpha < 0.0) { alpha = 0.0; } else if (alpha > 1.0) { alpha = 1.0; } } switch (m_channelType) { case COLOR_BYTE: { *m_pChannelData = static_cast<BYTE>(alpha * kMaxByteAsFloat); } break; case COLOR_WORD: { *reinterpret_cast<WORD*>(m_pChannelData) = static_cast<WORD>(alpha * kMaxWordAsFloat); } break; case COLOR_FLOAT: { *reinterpret_cast<FLOAT*>(m_pChannelData) = alpha; } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised channel data format.\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetColor Routine Description: Retrieves a COLOR object based of the channel data Arguments: pColor - Pointer to a color structure to be filled in pType - Pointer to storage to accept the color type Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetColor( _Out_ PCOLOR pColor, _Out_ COLORTYPE* pType ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pColor, E_POINTER)) && SUCCEEDED(hr = CHECK_POINTER(pType, E_POINTER))) { if (m_cChannels == 0) { hr = E_PENDING; } } DWORD cChannels = 0; if (SUCCEEDED(hr) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels))) { if (cChannels <= 4) { hr = ColorToWord(reinterpret_cast<PWORD>(pColor), static_cast<UINT>(sizeof(COLOR))); } else if (cChannels <= 8) { hr = ColorToByte(reinterpret_cast<PBYTE>(pColor), static_cast<UINT>(sizeof(COLOR))); } else { hr = E_FAIL; } if (SUCCEEDED(hr)) { if (m_dataType == sRGB || m_dataType == scRGB) { *pType = COLOR_RGB; } else if (m_dataType == nChannel) { *pType = static_cast<COLORTYPE>(cChannels + 3); } else { RIP("Unrecognised data type.\n"); hr = E_FAIL; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::SetColor Routine Description: Sets the channel data based on a COLOR structure Arguments: pColor - Pointer to a color structure to set the channel data from type - The color type described by the color structure Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::SetColor( _In_ COLOR* pColor, _In_ CONST COLORTYPE& type ) { HRESULT hr = S_OK; DWORD cChannels = 0; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pColor, E_POINTER)) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast<PVOID*>(&pData)))) { DWORD cSrcChannels = 0; switch (type) { case COLOR_RGB: { if (m_dataType == sRGB || m_dataType == scRGB) { cSrcChannels = 3; } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } break; case COLOR_3_CHANNEL: case COLOR_CMYK: case COLOR_5_CHANNEL: case COLOR_6_CHANNEL: case COLOR_7_CHANNEL: case COLOR_8_CHANNEL: { if (m_dataType == nChannel) { cSrcChannels = static_cast<DWORD>(type - 3); } else { hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } } break; case COLOR_GRAY: case COLOR_XYZ: case COLOR_Yxy: case COLOR_Lab: case COLOR_NAMED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised color type\n"); hr = E_FAIL; } break; } if (SUCCEEDED(hr)) { if (cChannels == cSrcChannels) { if (cSrcChannels <= 4) { hr = ColorFromWord(reinterpret_cast<PWORD>(pColor), sizeof(COLOR)); } else if (cSrcChannels <= 8) { hr = ColorFromByte(reinterpret_cast<PBYTE>(pColor), sizeof(COLOR)); } else { RIP("Invalid channel count\n"); hr = E_FAIL; } } else { RIP("Miss-match between source channel count and current channel count\n"); hr = E_FAIL; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ColorToByte Routine Description: Converts the channel data to a 8 bpc COLOR type Arguments: pDstData - Pointer to the data to be set cbDstData - Size of the destination buffer Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::ColorToByte( _Out_writes_bytes_(cbDstData) PBYTE pDstData, _In_ CONST UINT cbDstData ) { HRESULT hr = S_OK; DWORD cChannels = 0; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast<PVOID*>(&pData)))) { ZeroMemory(pDstData, cbDstData); if (cbDstData < cChannels) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } if (SUCCEEDED(hr) && cbData == 0 && cChannels != 0) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { if (cbDstData > 0) { switch (m_channelType) { case COLOR_BYTE: { if (cbDstData >= cbData) { // // Just copy all channels after alpha into the buffer // CopyMemory(pDstData, pData, cbData); } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_WORD: { if (cbDstData >= cChannels * sizeof(BYTE) && cbData >= cChannels * sizeof(WORD)) { PWORD pSrcData = reinterpret_cast<PWORD>(pData); for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbDstData); pDstData[cCurrChan] = static_cast<BYTE>(MulDiv(pSrcData[cCurrChan], 0xFF, 0xFFFF)); } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_FLOAT: { // // Make sure the float data runs between 0.0 and 1.0 for nChannel and sRGB and is // truncated and scaled as follows for scRGB: // // 1. Truncate the input color to between -2.0 and +2.0 // 2. Offset the value by +2.0 to put it into the 0.0 to 4.0 range // 3. Scale the value down by 4.0 to put it into the range 0.0 to 1.0 // 4. Set the 16 bit value according to the channel value from 0x00 // for 0.0 to 0xFF for 1.0 // if (cbDstData >= cChannels * sizeof(BYTE) && cbData >= cChannels * sizeof(FLOAT)) { PFLOAT pSrcData = reinterpret_cast<PFLOAT>(pData); if (m_dataType == scRGB) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbDstData); FLOAT channelValue = pSrcData[cCurrChan]; channelValue = channelValue < -2.0f ? -2.0f : channelValue; channelValue = channelValue > 2.0f ? 2.0f : channelValue; channelValue += 2.0f; channelValue /= 4.0f; pDstData[cCurrChan] = static_cast<BYTE>(channelValue * kMaxByteAsFloat); } } else { if (SUCCEEDED(hr = ClampChannelValues(0.0f, 1.0f))) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbDstData); pDstData[cCurrChan] = static_cast<BYTE>(pSrcData[cCurrChan] * kMaxByteAsFloat); } } } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised color type\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ColorToWord Routine Description: Converts the channel data to a 16 bpc COLOR type Arguments: pDstData - Pointer to the data to be set cbDstData - Size of the destination buffer Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::ColorToWord( _Out_writes_bytes_(cbDstData) PWORD pDstData, _In_ CONST UINT cbDstData ) { HRESULT hr = S_OK; DWORD cChannels = 0; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast<PVOID*>(&pData)))) { ZeroMemory(pDstData, cbDstData); if (cbDstData / sizeof(WORD) < cChannels) { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } if (SUCCEEDED(hr) && cbData == 0 && cChannels != 0) { hr = E_UNEXPECTED; } if (SUCCEEDED(hr)) { if (cbDstData > 0) { switch (m_channelType) { case COLOR_BYTE: { if (cbDstData >= cChannels * sizeof(WORD) && cbData >= cChannels * sizeof(BYTE)) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); pDstData[cCurrChan] = static_cast<WORD>(MulDiv(pData[cCurrChan], 0xFFFF, 0xFF)); } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_WORD: { if (cbDstData - cbData > 0) { // // Just copy all channels after alpha into the COLOR structure // CopyMemory(pDstData, pData, cbData); } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_FLOAT: { // // Make sure the float data runs between 0.0 and 1.0 for nChannel and sRGB and is // truncated and scaled as follows for scRGB: // // 1. Truncate the input color to between -2.0 and +2.0 // 2. Offset the value by +2.0 to put it into the 0.0 to 4.0 range // 3. Scale the value by 4.0 to put it into the range 0.0 to 1.0 // 4. Set the 16 bit value according to the channel value from 0x0000 // for 0.0 to 0xFFFF for 1.0 // if (cbDstData >= cChannels * sizeof(WORD) && cbData >= cChannels * sizeof(FLOAT)) { PFLOAT pSrcData = reinterpret_cast<PFLOAT>(pData); if (m_dataType == scRGB) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); FLOAT channelValue = pSrcData[cCurrChan]; channelValue = channelValue < -2.0f ? -2.0f : channelValue; channelValue = channelValue > 2.0f ? 2.0f : channelValue; channelValue += 2.0f; channelValue /= 4.0f; pDstData[cCurrChan] = static_cast<WORD>(channelValue * kMaxWordAsFloat); } } else { if (SUCCEEDED(hr = ClampChannelValues(0.0f, 1.0f))) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) <= cbDstData); pDstData[cCurrChan] = static_cast<WORD>(pSrcData[cCurrChan] * kMaxWordAsFloat); } } } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised color type\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ColorFromByte Routine Description: Uses an 8 bpc COLOR structure to set the channel data Arguments: pSrcData - Pointer to the source COLOR data cbSrcData - Size of the source buffer in bytes Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::ColorFromByte( _In_reads_bytes_(cbSrcData) PBYTE pSrcData, _In_ CONST UINT& cbSrcData ) { HRESULT hr = S_OK; DWORD cChannels = 0; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast<PVOID*>(&pData)))) { if (cbData == 0 && cChannels != 0) { hr = E_UNEXPECTED; } } if (SUCCEEDED(hr)) { ZeroMemory(pData, cbData); if (cbSrcData > 0) { switch (m_channelType) { case COLOR_BYTE: { if (cbData >= cChannels * sizeof(BYTE) && cbSrcData >= cChannels * sizeof(BYTE)) { // // Just copy src to dst // CopyMemory(pData, pSrcData, cChannels * sizeof(BYTE)); } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_WORD: { if (cbData >= cChannels * sizeof(WORD) && cbSrcData >= cChannels * sizeof(BYTE)) { PWORD pDstData = reinterpret_cast<PWORD>(pData); for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbSrcData); pDstData[cCurrChan] = static_cast<WORD>(MulDiv(pSrcData[cCurrChan], 0xFFFF, 0xFF)); } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_FLOAT: { // // Make sure the float data is scaled to 0.0 and 1.0 for nChannel and sRGB and is // scaled as follows for scRGB: // // 1. Convert the WORD value from 0x00 - 0xFF to 0.0f - 1.0f // 1. Scale the value up by 4.0 to put it into the range 0.0 to 2.0 // 2. Offset the value by -2.0 to put it into the -2.0 to 2.0 range // if (cbData >= cChannels * sizeof(FLOAT) && cbSrcData >= cChannels * sizeof(BYTE)) { PFLOAT pDstData = reinterpret_cast<PFLOAT>(pData); if (m_dataType == scRGB) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbSrcData); pDstData[cCurrChan] = ((static_cast<FLOAT>(pSrcData[cCurrChan])*4.0f)/kMaxByteAsFloat) - 2.0f; } } else { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_(cCurrChan < cbSrcData); pDstData[cCurrChan] = static_cast<FLOAT>(pSrcData[cCurrChan])/kMaxByteAsFloat; } } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised color type\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ColorFromWord Routine Description: Uses an 16 bpc COLOR structure to set the channel data Arguments: pSrcData - Pointer to the source COLOR data cbSrcData - Size of the source buffer in bytes Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::ColorFromWord( _In_reads_bytes_(cbSrcData) PWORD pSrcData, _In_ CONST UINT& cbSrcData ) { HRESULT hr = S_OK; DWORD cChannels = 0; DWORD cbData = 0; PBYTE pData = NULL; if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) && SUCCEEDED(hr = GetChannelCountNoAlpha(&cChannels)) && SUCCEEDED(hr = GetChannelDataNoAlpha(&cbData, reinterpret_cast<PVOID*>(&pData)))) { if (cbData == 0 && cChannels != 0) { hr = E_UNEXPECTED; } } if (SUCCEEDED(hr)) { ZeroMemory(pData, cbData); if (cbSrcData > 0) { switch (m_channelType) { case COLOR_BYTE: { if (cbData >= cChannels * sizeof(BYTE) && cbSrcData >= cChannels * sizeof(WORD)) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); pData[cCurrChan] = static_cast<BYTE>(MulDiv(pSrcData[cCurrChan], 0xFF, 0xFFFF)); } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_WORD: { if (cbData >= cChannels * sizeof(WORD) && cbSrcData >= cChannels * sizeof(WORD)) { // // Just copy src to dst // CopyMemory(pData, pSrcData, cChannels * sizeof(WORD)); } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_FLOAT: { // // Make sure the float data is scaled to 0.0 and 1.0 for nChannel and sRGB and is // scaled as follows for scRGB: // // 1. Convert the WORD value from 0x0000 - 0xFFFF to 0.0f - 1.0f // 1. Scale the value up by 4.0 to put it into the range 0.0 to 2.0 // 2. Offset the value by -2.0 to put it into the -2.0 to 2.0 range // if (cbData >= cChannels * sizeof(FLOAT) && cbSrcData >= cChannels * sizeof(WORD)) { PFLOAT pDstData = reinterpret_cast<PFLOAT>(pData); if (m_dataType == scRGB) { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); pDstData[cCurrChan] = ((static_cast<FLOAT>(pSrcData[cCurrChan])*4.0f)/kMaxWordAsFloat) - 2.0f; } } else { for (UINT cCurrChan = 0; cCurrChan < cChannels; cCurrChan++) { _Analysis_assume_((cCurrChan + 1) * sizeof(WORD) < cbSrcData); pDstData[cCurrChan] = static_cast<FLOAT>(pSrcData[cCurrChan])/kMaxWordAsFloat; } } } else { hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); } } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised color type\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::GetChannelSizeFromType Routine Description: Retrieves the channel data size from the channel data type Arguments: channelType - The color channel data type pcbChannelSize - Pointer to storage to recieve the channel data size Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetChannelSizeFromType( _In_ CONST COLORDATATYPE& channelType, _Out_ DWORD* pcbChannelSize ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pcbChannelSize, E_POINTER))) { if (channelType < COLOR_BYTE || channelType > COLOR_S2DOT13FIXED) { hr = E_INVALIDARG; } } if (SUCCEEDED(hr)) { *pcbChannelSize = g_cbChannelType[channelType - 1]; } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::ValidateDataSize Routine Description: Template method that validates the data size given the current channel data type Arguments: None Return Value: HRESULT S_OK - On success E_* - On error --*/ template <class _T> HRESULT CColorChannelData::ValidateDataSize( VOID ) { HRESULT hr = S_OK; DWORD cbDataSize = 0; if (SUCCEEDED(hr = GetChannelSizeFromType(m_channelType, &cbDataSize))) { // // Make sure the data being added matches the data type in size // if (sizeof(_T) != cbDataSize) { hr = E_INVALIDARG; } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::AllocateChannelBuffers Routine Description: Allocates the channel data buffer Arguments: pcbBuffer - Pointer to variable that recieves the allocated buffer size ppBuffer - Pointer to a pointer that recieves the buffer address Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::AllocateChannelBuffers( _Out_ UINT* pcbBuffer, _Outptr_result_bytebuffer_(*pcbBuffer) _At_buffer_(*ppBuffer, _Iter_, *pcbBuffer, _Post_invalid_) PBYTE* ppBuffer ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pcbBuffer, E_POINTER)) && SUCCEEDED(hr = CHECK_POINTER(ppBuffer, E_POINTER))) { // // Allocate a buffer for the channel data MAX_CHANNEL_COUNT x MAX_CHANNEL_SIZE // This guarantees we have enough storage for the maximum n-channel support // in WCS // *pcbBuffer = MAX_CHANNEL_COUNT*MAX_CHANNEL_SIZE; *ppBuffer = new(std::nothrow) BYTE[*pcbBuffer]; if (*ppBuffer == NULL) { *pcbBuffer = 0; hr = E_OUTOFMEMORY; } } ERR_ON_HR(hr); return hr; } /*++ Routine Name: CColorChannelData::FreeChannelBuffers Routine Description: Releases channel buffer Arguments: None Return Value: None --*/ VOID CColorChannelData::FreeChannelBuffers( VOID ) { if (m_pChannelData != NULL) { delete[] m_pChannelData; m_pChannelData = NULL; } m_cbChannelData = 0; } /*++ Routine Name: CColorChannelData::GetAlphaAsFloat Routine Description: Retrieves the alpha value of the channel data as a float Arguments: pAlpha - Pointer to a float that recieves the alpha value Return Value: HRESULT S_OK - On success E_* - On error --*/ HRESULT CColorChannelData::GetAlphaAsFloat( _Out_ PFLOAT pAlpha ) { HRESULT hr = S_OK; if (SUCCEEDED(hr = CHECK_POINTER(pAlpha, E_POINTER))) { *pAlpha = 0.0f; if (HasAlpha()) { switch (m_channelType) { case COLOR_BYTE: { *pAlpha = static_cast<FLOAT>(*m_pChannelData)/kMaxByteAsFloat; } break; case COLOR_WORD: { *pAlpha = static_cast<FLOAT>(*reinterpret_cast<WORD*>(m_pChannelData))/kMaxWordAsFloat; } break; case COLOR_FLOAT: { *pAlpha = *reinterpret_cast<PFLOAT>(m_pChannelData); } break; case COLOR_S2DOT13FIXED: { hr = E_NOTIMPL; } break; default: { RIP("Unrecognised channel data format.\n"); hr = E_FAIL; } break; } } } ERR_ON_HR(hr); return hr; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials