Sample Code

Windows Driver Samples/ XPSDrv Driver and Filter Sample/ C++/ src/ filters/ color/ colconv.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:

   colconv.cpp

Abstract:

   Color conversion manager implementation. The CColorConverter class is responsible
   for coordinating the handling of the color conversion process.

   Note regarding transform caching: The color filter provides caching for the last
   transform. This aids performance as quite some time can be consumed creating a
   transform. The filter may however suffer if source content color profiles are rapidly
   switched (e.g. alternating sRGB and scRGB mark-up). This could be mitigated by increasing
   the number cached transforms beyond one.

--*/

#include "precomp.h"
#include "debug.h"
#include "globals.h"
#include "xdstring.h"
#include "xdexcept.h"
#include "colconv.h"
#include "cmimg.h"
#include "dictionary.h"

using XDPrintSchema::PageSourceColorProfile::EProfileOption;
using XDPrintSchema::PageSourceColorProfile::RGB;
using XDPrintSchema::PageSourceColorProfile::CMYK;

using XDPrintSchema::PageICMRenderingIntent::AbsoluteColorimetric;
using XDPrintSchema::PageICMRenderingIntent::RelativeColorimetric;
using XDPrintSchema::PageICMRenderingIntent::Photographs;
using XDPrintSchema::PageICMRenderingIntent::BusinessGraphics;

COLORTYPE g_nChannelMap[] = {
    COLOR_3_CHANNEL,
    COLOR_CMYK,
    COLOR_5_CHANNEL,
    COLOR_6_CHANNEL,
    COLOR_7_CHANNEL,
    COLOR_8_CHANNEL
};

/*++

Routine Name:

    CColorConverter::CColorConverter

Routine Description:

    Constructor for the base CColorConverter class. Provides common functionality
    between the bitmap and color ref converter classes

Arguments:

    pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources
    pFixedPage   - Pointer to the FixedPage interface. Resource cache uses this when writing
    pResCache    - Pointer to the resource cache.
    pProfManager - Pointer to a profile manager for supplying a suitable color profile

Return Value:

    None
    Throws CXDException(HRESULT) on an error

--*/
CColorConverter::CColorConverter(
    _In_ IXpsDocumentConsumer* pXpsConsumer,
    _In_ IFixedPage*           pFixedPage,
    _In_ CFileResourceCache*   pResCache,
    _In_ CProfileManager*      pProfManager,
    _In_ ResDeleteMap*         pResDel
    ) :
    m_pXpsConsumer(pXpsConsumer),
    m_pFixedPage(pFixedPage),
    m_pProfManager(pProfManager),
    m_pResCache(pResCache),
    m_pResDel(pResDel)
{
    HRESULT hr = S_OK;

    if (FAILED(hr = CHECK_POINTER(m_pXpsConsumer, E_POINTER)) ||
        FAILED(hr = CHECK_POINTER(m_pFixedPage, E_POINTER)) ||
        FAILED(hr = CHECK_POINTER(m_pProfManager, E_POINTER)) ||
        FAILED(hr = CHECK_POINTER(m_pResCache, E_POINTER)) ||
        FAILED(hr = CHECK_POINTER(m_pResDel, E_POINTER)))
    {
        throw CXDException(hr);
    }
}

/*++

Routine Name:

    CColorConverter::~CColorConverter

Routine Description:

    Default destructor for the CColorConverter class

Arguments:

    None

Return Value:

    None

--*/
CColorConverter::~CColorConverter()
{
}

/*++

Routine Name:

    CBitmapColorConverter::CBitmapColorConverter

Routine Description:

    Constructor for the CBitmapColorConverter class

Arguments:

    pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources
    pFixedPage   - Pointer to the FixedPage interface. Resource cache uses this when writing
    pResCache    - Pointer to the resource cache.
    pProfManager - Pointer to a profile manager for supplying a suitable color profile

Return Value:

    None
    Throws CXDException(HRESULT) on an error

--*/
CBitmapColorConverter::CBitmapColorConverter(
    _In_ IXpsDocumentConsumer* pXpsConsumer,
    _In_ IFixedPage*           pFixedPage,
    _In_ CFileResourceCache*   pResCache,
    _In_ CProfileManager*      pProfManager,
    _In_ ResDeleteMap*         pResDel
    ) :
    CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel)
{
}

/*++

Routine Name:

    CBitmapColorConverter::~CBitmapColorConverter

Routine Description:

    Destructor for the CBitmapColorConverter class

Arguments:

    None

Return Value:

    None

--*/
CBitmapColorConverter::~CBitmapColorConverter()
{
}

/*++

Routine Name:

    CColorConverter::ConvertBitmap

Routine Description:

    Method which performs the color conversion process to a bitmap resource and sets
    the resource URI to contain the URI of the converted bitmap resource

Arguments:

    pbstrBmpURI - Pointer to a string containing the bitmap resource path and name

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CBitmapColorConverter::Convert(
    _Inout_ BSTR* pbstrBmpURI
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pbstrBmpURI, E_POINTER)))
    {
        try
        {
            //
            // Create a color managed image object
            //
            CColorManagedImage bmpColManaged(*pbstrBmpURI, m_pProfManager, m_pFixedPage, m_pResDel);

            //
            // Write out the cached bitmap and get a keyname for the written bitmap
            //
            CComBSTR bstrKey;
            if (SUCCEEDED(hr = m_pResCache->WriteResource<IPartImage>(m_pXpsConsumer, m_pFixedPage, &bmpColManaged)) &&
                SUCCEEDED(hr = bmpColManaged.GetKeyName(&bstrKey)))
            {
                hr = m_pResCache->GetURI(bstrKey, pbstrBmpURI);

                ASSERTMSG(SUCCEEDED(hr), "Failed to process image");
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }
    else
    {
        hr = E_POINTER;
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::CColorRefConverter

Routine Description:

    Constructor for the base CColorRefConverter class which handles parsing and
    conversion of a color string within XPS mark-up

Arguments:

    pXpsConsumer - Pointer to the XPS consumer interface. Used to write out resources
    pFixedPage   - Pointer to the FixedPage interface. Resource cache uses this when writing
    pResCache    - Pointer to the resource cache.
    pProfManager - Pointer to a profile manager for supplying a suitable color profile

Return Value:

    None
    Throws CXDException(HRESULT) on an error

--*/
CColorRefConverter::CColorRefConverter(
    _In_ IXpsDocumentConsumer* pXpsConsumer,
    _In_ IFixedPage*           pFixedPage,
    _In_ CFileResourceCache*   pResCache,
    _In_ CProfileManager*      pProfManager,
    _In_ ResDeleteMap*         pResDel
    ) :
    CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel)
{
}

/*++

Routine Name:

    CColorRefConverter::~CColorRefConverter

Routine Description:

    Destructor for the CColorRefConverter class

Arguments:

    None

Return Value:

    None

--*/
CColorRefConverter::~CColorRefConverter()
{
}

/*++

Routine Name:

    CColorRefConverter::ConvertColor

Routine Description:

    Method which performs the color conversion process to an XPS color ref element

Arguments:

    pbstrColorRef - Pointer to a string containing the color data to be converted

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::Convert(
    _Inout_ BSTR* pbstrColorRef
    )
{
    HRESULT hr = S_OK;

    BOOL bIsResourceReference = FALSE;
    if (SUCCEEDED(hr = CHECK_POINTER(pbstrColorRef, E_POINTER)) &&
        SUCCEEDED(hr = ParseColorString(*pbstrColorRef, &m_srcData, &bIsResourceReference)) &&
        !bIsResourceReference)
    {
        //
        // If the source and destination types are the same (e.g. scRGB in and scRGB out)
        // we need go no further - simply return the existing string. This does not apply
        // to nChannel as ContextColors specify their own profile and we cannot prove that
        // this matches our output. The color space for sRGB and scRGB are implicit however.
        //
        EColorDataType srcType = sRGB;
        EColorDataType dstType = sRGB;
        if (SUCCEEDED(hr = InitDstChannels(&m_srcData, &m_dstData)) &&
            SUCCEEDED(hr = m_srcData.GetColorDataType(&srcType)) &&
            SUCCEEDED(hr = m_dstData.GetColorDataType(&dstType)))
        {
            if (dstType == nChannel ||
                dstType != srcType)
            {
                if (SUCCEEDED(hr = TransformColor(&m_srcData, &m_dstData)))
                {
                    hr = CreateColorString(&m_dstData, pbstrColorRef);
                }
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::InitDstChannels

Routine Description:

    Initialise the destination color channel data based on the destination color
    profile

Arguments:

    pChannelDataDst - Pointer to a color channel data object to be intialised

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::InitDstChannels(
    _In_    CColorChannelData* pChannelDataSrc,
    _Inout_ CColorChannelData* pChannelDataDst
    )
{
    HRESULT hr = S_OK;

    EProfileOption profileType = RGB;
    if (SUCCEEDED(hr = CHECK_POINTER(pChannelDataSrc, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pChannelDataDst, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(m_pProfManager, E_FAIL)) &&
        SUCCEEDED(hr = m_pProfManager->GetDstProfileType(&profileType)))
    {
        //
        // Initialize the channel data based on the destination color profile
        // settings:
        //    RGB  = 3 channel with no src alpha
        //           4 channel with src alpha
        //    CMYK = 5 channel (nChannel always has an alpha channel)
        //
        // The color type is based off the OS. XP does not have access to WCS
        // and therefore floating point formats are converted to 16 bits per channel
        //
        // The conversion process for  downlevel handling depends on the source format.
        // If we are color matching for scRGB we convert the floating point value as
        // follows:
        //
        //    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
        //    5. Call TranslateColors passing the 16 bit value
        //    6. Reverse steps 1 - 4 to retrieve the floating point value
        //
        //  If we are color matching for context colors we apply the following conversion
        //
        //    1. Truncate the input color to between 0.0 and +1.0
        //    2. Set the 16 bit value according to the channel value from 0x0000
        //       for 0.0 to 0xFFFF for 1.0
        //    3. Call TranslateColors passing the 16 bit value
        //    4. Reverse steps 1 - 2 to retrieve the floating point value
        //
        //  Note: We do not modify the gamma during the scRGB conversion process as this will
        //        be applied by WCS/ICM as the gamma is encapsulated by the relevant ICC
        //        profile. i.e. The gamma is maintained linear as that is what the transform
        //        is expecting.
        //
        COLORDATATYPE colorDataType = COLOR_FLOAT;
        EColorDataType dataType = sRGB;

        DWORD cChannels = 0;
        if (profileType == RGB)
        {
            dataType = scRGB;
            cChannels = 3;
            if (pChannelDataSrc->HasAlpha())
            {
                cChannels++;
            }
        }
        else if (profileType == CMYK)
        {
            dataType = nChannel;
            cChannels = 5;
        }
        else
        {
            RIP("Unsupported color channel format\n");
            hr = E_FAIL;
        }

        if (SUCCEEDED(hr) &&
            SUCCEEDED(hr = pChannelDataDst->InitializeChannelData<FLOAT>(colorDataType, dataType, cChannels, 0.0f)))
        {
            hr = pChannelDataDst->InitializeAlphaChannel(pChannelDataSrc);
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::GetFloatChannelData

Routine Description:

    Method which converts a comma delimited set of floating point values
    defining color channels into floating point values in a list

Arguments:

    szColorRef   - The srting containing the comma seperated color values
    pChannelData - Pointer to the color channels object

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::GetFloatChannelData(
    _In_    LPCWSTR            szColorRef,
    _Inout_ CColorChannelData* pChannelData
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(szColorRef, E_POINTER)) &&
        SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT)))
    {
        try
        {
            CStringXDW cstrColorRef(szColorRef);
            cstrColorRef.Trim();
            cstrColorRef.MakeLower();

            INT cTokenIndex = 0;
            INT cChars = cstrColorRef.GetLength();
            while (SUCCEEDED(hr) &&
                   cTokenIndex < cChars &&
                   cTokenIndex != -1)
            {
                CStringXDW cstrChannel(cstrColorRef.Tokenize(L",", cTokenIndex));
                hr = pChannelData->AddChannelData(static_cast<FLOAT>(_wtof(cstrChannel)));
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::SetFloatChannelData

Routine Description:

    Method which converts channel data object into a comma delimited set of
    floating point values

Arguments:

    pChannelData      - Pointer to the color channel data
    pcstrChannelData  - Pointer to the color string to be populated

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::SetFloatChannelData(
    _In_    CColorChannelData* pChannelData,
    _Inout_ CStringXDW*        pcstrChannelData
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pcstrChannelData, E_POINTER)))
    {
        try
        {
            //
            // Over all channels, write out comma seperated float values
            //
            DWORD  cbData = 0;
            PFLOAT pData = NULL;
            DWORD cChanCount = 0;
            if (SUCCEEDED(hr = pChannelData->GetChannelData(&cbData, reinterpret_cast<PVOID*>(&pData))) &&
                SUCCEEDED(hr = pChannelData->GetChannelCount(&cChanCount)))
            {
                if (cChanCount == 0)
                {
                    hr = E_FAIL;
                }

                if (SUCCEEDED(hr) &&
                    cbData >= cChanCount * sizeof(FLOAT))
                {
                    CStringXDW cstrChannel;
                    cstrChannel.Format(L"%f", pData[0]);
                    pcstrChannelData->Append(cstrChannel);
                    for (DWORD cChan = 1; cChan < cChanCount; cChan++)
                    {
                        cstrChannel.Format(L",%f", pData[cChan]);
                        pcstrChannelData->Append(cstrChannel);
                    }
                }
                else
                {
                    hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
                }
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::ParseColorString

Routine Description:

    Method which converts a XML formatted color string into useable color data

Arguments:

    bstrColorRef - The color ref string to be parsed
    pChannelData - Pointer to the color channel data object to be populated

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::ParseColorString(
    _In_    BSTR               bstrColorRef,
    _Inout_ CColorChannelData* pChannelData,
    _Out_   BOOL*              pbIsResourceReference
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pChannelData, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pbIsResourceReference, E_POINTER)))
    {
        *pbIsResourceReference = FALSE;

        if (SysStringLen(bstrColorRef) <= 0)
        {
            hr = E_INVALIDARG;
        }
    }

    if (SUCCEEDED(hr))
    {
        try
        {
            CStringXDW cstrColRef(bstrColorRef);
            cstrColRef.Trim();

            if (0 == cstrColRef.Find(L"sc#"))
            {
                //
                // Strip the "sc#" prefix ready to parse the floating point channels
                //
                cstrColRef.Delete(0, 3);

                //
                // Set the src profile to xdwscRGB.icc - this is an ICC profile with
                // the system wcsRGB profile embedded so should work down-level
                // Set the color data type and retrieve the channel data
                //
                if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromColDir(L"xdwscRGB.icc")) &&
                    SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT)) &&
                    SUCCEEDED(hr = pChannelData->SetColorDataType(scRGB)))
                {
                    hr = GetFloatChannelData(cstrColRef, pChannelData);
                }
            }
            else if (0 == cstrColRef.Find(L"ContextColor"))
            {
                //
                // Context colors always have an associated profile - retrieve
                // this and set it in the profile manager
                //
                cstrColRef.Delete(0, countof(L"ContextColor "));
                cstrColRef.Trim();
                CStringXDW cstrProfile(cstrColRef.Left(cstrColRef.Find(L" ")));
                cstrColRef.Delete(0, cstrProfile.GetLength());

                //
                // Set the source profile ready to create the transform, retrieve the channel data
                // and clamp between 0.0 and 1.0.
                //
                if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromContainer(cstrProfile.GetBuffer())) &&
                    SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_FLOAT)) &&
                    SUCCEEDED(hr = pChannelData->SetColorDataType(nChannel)) &&
                    SUCCEEDED(hr = GetFloatChannelData(cstrColRef, pChannelData)) &&
                    SUCCEEDED(hr = pChannelData->ClampChannelValues(0.0f, 1.0f)))
                {
                    //
                    // Mark the color profile for deletion
                    //
                    (*m_pResDel)[cstrProfile] = TRUE;
                }
            }
            else if (0 == cstrColRef.Find(L"#"))
            {
                //
                // Delete the # symbol so we are just left with the RGB values
                //
                cstrColRef.Delete(0, 1);

                //
                // Set the source profile to sRGB rather than assume the default is set to
                // sRGB.
                //
                if (SUCCEEDED(hr = m_pProfManager->SetSrcProfileFromColDir(L"sRGB Color Space Profile.icm")) &&
                    SUCCEEDED(hr = pChannelData->ResetChannelType(COLOR_BYTE)) &&
                    SUCCEEDED(hr = pChannelData->SetColorDataType(sRGB)))
                {
                    while (SUCCEEDED(hr) &&
                           cstrColRef.GetLength() > 0)
                    {
                        //
                        // Add the channel data
                        //
                        hr = pChannelData->AddChannelData(static_cast<BYTE>(wcstol(cstrColRef.Left(2), NULL, 16)));

                        //
                        // Delete the channel from the color ref string
                        //
                        cstrColRef.Delete(0, 2);
                    }
                }
            }
            else if (0 == cstrColRef.Find(L"{StaticResource"))
            {
                *pbIsResourceReference = TRUE;
            }
            else
            {
                //
                // Unrecognised type
                //
                RIP("Unrecognised color syntax.");
                hr = E_FAIL;
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
        catch (exception& DBG_ONLY(e))
        {
            ERR(e.what());
            hr = E_FAIL;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::TransformColor

Routine Description:

    Method which applies a color transform to a set of color data

Arguments:

    pSrcData - Pointer to the source color channel data
    pDstData - Pointer to the destination color channel data

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::TransformColor(
    _In_    CColorChannelData* pSrcData,
    _Inout_ CColorChannelData* pDstData
    )
{
    HRESULT hr = S_OK;

    HTRANSFORM hColorTrans = NULL;

    BOOL bUseWCS = FALSE;

    if (SUCCEEDED(hr = CHECK_POINTER(pSrcData, E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pDstData, E_POINTER)) &&
        SUCCEEDED(hr = m_pProfManager->GetColorTransform(&hColorTrans, &bUseWCS)))
    {
        if (bUseWCS)
        {
            DWORD cSrcChan = 0;
            DWORD cDstChan = 0;

            COLORDATATYPE srcDataType = COLOR_FLOAT;
            COLORDATATYPE dstDataType = COLOR_FLOAT;

            DWORD cbSrcChan = 0;
            DWORD cbDstChan = 0;

            PBYTE pSrcBuff = NULL;
            PBYTE pDstBuff = NULL;

            if (SUCCEEDED(hr = CHECK_POINTER(hColorTrans, E_HANDLE)) &&
                SUCCEEDED(hr = pSrcData->GetChannelCountNoAlpha(&cSrcChan)) &&
                SUCCEEDED(hr = pSrcData->GetChannelType(&srcDataType)) &&
                SUCCEEDED(hr = pSrcData->GetChannelDataNoAlpha(&cbSrcChan, reinterpret_cast<PVOID*>(&pSrcBuff))) &&
                SUCCEEDED(hr = pDstData->GetChannelCountNoAlpha(&cDstChan)) &&
                SUCCEEDED(hr = pDstData->GetChannelType(&dstDataType)) &&
                SUCCEEDED(hr = pDstData->GetChannelDataNoAlpha(&cbDstChan, reinterpret_cast<PVOID*>(&pDstBuff))))
            {
                if (cbDstChan > 0)
                {
                    if (!WcsTranslateColorsXD(hColorTrans,
                                              1,
                                              cSrcChan,
                                              srcDataType,
                                              cbSrcChan,
                                              pSrcBuff,
                                              cDstChan,
                                              dstDataType,
                                              cbDstChan,
                                              pDstBuff))
                    {
                        hr = GetLastErrorAsHResult();
                    }
                }
                else
                {
                    hr = E_FAIL;
                }
            }
        }
        else
        {
            COLOR srcColor;
            COLOR dstColor;

            COLORTYPE srcType;
            COLORTYPE dstType;

            if (SUCCEEDED(hr = pSrcData->GetColor(&srcColor, &srcType)) &&
                SUCCEEDED(hr = pDstData->GetColor(&dstColor, &dstType)))
            {
                if (TranslateColors(hColorTrans,
                                    &srcColor,
                                    1,
                                    srcType,
                                    &dstColor,
                                    dstType))
                {
                    hr = pDstData->SetColor(&dstColor, dstType);
                }
                else
                {
                    hr = GetLastErrorAsHResult();
                }
            }
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CColorRefConverter::CreateColorString

Routine Description:

    Method which creates a XML formatted string descripting a transformed set of colors

Arguments:

    pDstData      - Pointer to destination color channel data
    pbstrColorRef - Pointer to a string to contain the XML formatted color data

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CColorRefConverter::CreateColorString(
    _In_    CColorChannelData* pDstData,
    _Inout_ BSTR*              pbstrColorRef
    )
{
    CComBSTR bstrTmpHolder;

    HRESULT hr = S_OK;

    EColorDataType colDataType = sRGB;
    if (SUCCEEDED(hr = CHECK_POINTER(pDstData,  E_POINTER)) &&
        SUCCEEDED(hr = CHECK_POINTER(pbstrColorRef, E_POINTER)) &&
        SUCCEEDED(hr = pDstData->GetColorDataType(&colDataType)))
    {
        try
        {
            CStringXDW cstrChannelData;

            if (colDataType == scRGB)
            {
                //
                // scRGB
                //
                cstrChannelData += L"sc#";
                hr = SetFloatChannelData(pDstData, &cstrChannelData);
            }
            else if (colDataType == nChannel)
            {
                //
                // CMYK
                //
                cstrChannelData += L"ContextColor ";

                //
                // Add the ICC profile and retrieve the URI
                //
                CComBSTR bstrKey;
                CComBSTR bstrICCURI;
                if (SUCCEEDED(hr = m_pResCache->WriteResource<IPartColorProfile>(m_pXpsConsumer, m_pFixedPage, m_pProfManager)) &&
                    SUCCEEDED(hr = m_pProfManager->GetKeyName(&bstrKey)) &&
                    SUCCEEDED(hr = m_pResCache->GetURI(bstrKey, &bstrICCURI)))
                {
                    //
                    // Append the URI and a space
                    //
                    cstrChannelData += bstrICCURI;
                    cstrChannelData += L" ";

                    hr = SetFloatChannelData(pDstData, &cstrChannelData);
                }
            }
            else if (colDataType == sRGB)
            {
                //
                // sRGB
                //
                cstrChannelData += L"#";

                //
                // Over all channels, write out hex byte values
                //
                DWORD cbData = 0;
                PBYTE pData = NULL;
                DWORD cChanCount = 0;
                if (SUCCEEDED(hr = pDstData->GetChannelData(&cbData, reinterpret_cast<PVOID*>(&pData))) &&
                    SUCCEEDED(hr = pDstData->GetChannelCount(&cChanCount)))
                {
                    if (cbData >= cChanCount * sizeof(BYTE))
                    {
                        for (DWORD cChan = 0; cChan < cChanCount; cChan++)
                        {
                            _Analysis_assume_(cChan < cbData);

                            CStringXDW cstrChannel;
                            cstrChannel.Format(L"%02x", pData[cChan]);
                            cstrChannelData.Append(cstrChannel);
                        }
                    }
                    else
                    {
                        hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
                    }
                }
            }
            else
            {
                RIP("Invalid color type\n");
                hr = E_FAIL;
            }

            if (SUCCEEDED(hr))
            {
                SysFreeString(*pbstrColorRef);
                *pbstrColorRef = cstrChannelData.AllocSysString();
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
    }

    ERR_ON_HR(hr);
    return hr;
}

/*++

Routine Name:

    CResourceDictionaryConverter::CResourceDictionaryConverter

Routine Description:

    CResourceDictionaryConverter constructir

Arguments:

    pXpsConsumer - Pointer to the XPS consumer interface
    pFixedPage   - Pointer to the fixed page interface
    pResCache    - Pointer to the resource cache
    pProfManager - Pointer to the color profile manager
    pResDel      - Pointer to the list of resources to delete from the page
    pBmpConv     - Pointer to the bitmap conversion class
    pRefConv     - Pointer to the color reference conversion class

Return Value:

    None
    Throws an exception on error.

--*/
CResourceDictionaryConverter::CResourceDictionaryConverter(
    _In_ IXpsDocumentConsumer*  pXpsConsumer,
    _In_ IFixedPage*            pFixedPage,
    _In_ CFileResourceCache*    pResCache,
    _In_ CProfileManager*       pProfManager,
    _In_ ResDeleteMap*          pResDel,
    _In_ CBitmapColorConverter* pBmpConv,
    _In_ CColorRefConverter*    pRefConv
    ) :
    CColorConverter(pXpsConsumer, pFixedPage, pResCache, pProfManager, pResDel),
    m_pBmpConv(pBmpConv),
    m_pRefConv(pRefConv)
{
    if (m_pBmpConv == NULL ||
        m_pRefConv == NULL)
    {
        throw CXDException(E_POINTER);
    }
}

/*++

Routine Name:

    CResourceDictionaryConverter::~CResourceDictionaryConverter

Routine Description:

    CResourceDictionaryConverter destructor

Arguments:

    None

Return Value:

    None

--*/
CResourceDictionaryConverter::~CResourceDictionaryConverter()
{
}

/*++

Routine Name:

    CResourceDictionaryConverter::Convert

Routine Description:

    Applies color conversion on a remote resource dictionary. This is achieved
    by creating a color SAX parser passing a stream based off the resource

Arguments:

    pbstrDictionaryURI - The remote dictionary URI

Return Value:

    HRESULT
    S_OK - On success
    E_*  - On error

--*/
HRESULT
CResourceDictionaryConverter::Convert(
    _Inout_ BSTR* pbstrDictionaryURI
    )
{
    HRESULT hr = S_OK;

    if (SUCCEEDED(hr = CHECK_POINTER(pbstrDictionaryURI, E_POINTER)))
    {
        try
        {
            CStringXDW cstrOriginalURI(*pbstrDictionaryURI);

            //
            // Create a color managed dictionary object and pass to the cache manager
            //
            CRemoteDictionary newDictionary(m_pFixedPage, m_pBmpConv, m_pRefConv, *pbstrDictionaryURI);

            CComBSTR bstrKey;
            if (SUCCEEDED(hr = m_pResCache->WriteResource<IPartResourceDictionary>(m_pXpsConsumer, m_pFixedPage, &newDictionary)) &&
                SUCCEEDED(hr = newDictionary.GetKeyName(&bstrKey)) &&
                SUCCEEDED(hr = m_pResCache->GetURI(bstrKey, pbstrDictionaryURI)))
            {
                (*m_pResDel)[cstrOriginalURI] = TRUE;
            }
        }
        catch (CXDException& e)
        {
            hr = e;
        }
        catch (exception& DBG_ONLY(e))
        {
            ERR(e.what());
            hr = E_FAIL;
        }
    }

    return hr;
}

Our Services

  • What our customers say about us?

© 2011-2024 All Rights Reserved. Joya Systems. 4425 South Mopac Building II Suite 101 Austin, TX 78735 Tel: 800-DEV-KERNEL

Privacy Policy. Terms of use. Valid XHTML & CSS