Determine if a color channel is used
📌 Overview
This article explains the best practice for color reporting - using a custom transform.
Issue Description
A customer asked: “How can we determine if a process color channel is used on a page. We want to know if a document has no pixel of cyan or magenta although these color channels always exist. We could count the separations contents, but this might be unreliable in low resolutions and I wonder if there is a simpler way.“
💡 Solution
To solve this, a custom transform can be used to scan the content to discover which color spaces are in use.
Create a custom transform implementation: Override the
transformColor()method and append each color to a new list property. Seem_colorListin the sample code.Apply the transform to every page: Create an instance of the transform and apply it to a page with
ICustomTransform::transform()Get the list of colors and process accordingly: Retrieve the list of colors using a “get method”. See
CEDLVector<IDOMColorPtr> getColorList() const { return m_colorList; }in the sample code below. From here you can get the color space and color space type usingIDOMColor::getColorSpace()andIDOMColorSpace::GetColorSpaceType()respectively.
⌨️ Sample Code
This C+ example shows how it’s done. See snippets below or find the full example at ColorReporting.cpp.
Custom Transform
class CColorTransformImplementation : public ICustomTransform::IImplementation
{
public:
CColorTransformImplementation()
{
}
virtual IDOMBrushPtr transformShadingPatternBrush(IImplementation* genericImplementation, const IDOMShadingPatternBrushPtr& brush, const CTransformState& state)
{
return genericImplementation->transformShadingPatternBrush(NULL, brush, state);
}
virtual IDOMColorPtr transformColor(IImplementation* genericImplementation, const IDOMColorPtr& color, const CTransformState& state)
{
m_colorList.append(color);
return genericImplementation->transformColor(NULL, color, state);
}
CEDLVector<IDOMColorPtr> getColorList() const
{
return m_colorList;
}
private:
CEDLVector<IDOMColorPtr> m_colorList;
};
Get list of colors
IDocumentPtr document = assembly->getDocument();
uint32 pageCount = document->getNumPages();
// Create a transform to gather color info
CColorTransformImplementation implementation;
ITransformPtr getColors = ICustomTransform::create(jawsMako, &implementation, abort, true, true, true, true, true, true);
std::map<String, IDOMColorPtr> inkMap;
// Apply the transform to every page
for (uint32 pageNum = 0; pageNum < pageCount; pageNum++)
{
IPagePtr page = document->getPage(pageNum);
IDOMFixedPagePtr fixedPage = page->edit();
// Get inks
inkMap.clear();
IRendererTransform::CInkInfoVect inks = IRendererTransform::findInks(jawsMako, fixedPage);
for (auto ink : inks)
{
inkMap.insert({ U8StringToString(ink.inkName), ink.inkColor });
}
// get colors
bool result = false;
getColors->transform(fixedPage, result);
}
CEDLVector<IDOMColorPtr> colors = implementation.getColorList();
std::wcout << L"Color count: " << colors.size() << std::endl;
Process results
// Process colors
int index = 0;
for (IDOMColorPtr color : colors)
{
auto colorSpace = color->getColorSpace();
auto colorSpaceEnum = colorSpace->getColorSpaceType();
String colorSpaceType = colorSpaceMap.at(colorSpaceEnum);
uint8 numComponents = colorSpace->getNumComponents();
wprintf_s(L"%3d ", ++index);
std::wcout << colorSpaceType << L" (";
for (uint32 c = 0; c < numComponents; c++)
{
wprintf_s(L"%4.2f", color->getComponentValue(c));
if (c < numComponents - 1)
std::wcout << ",";
}
std::wcout << L") ";
if (colorSpaceEnum == IDOMColorSpace::eDeviceN)
{
IDOMColorSpaceDeviceNPtr deviceN = edlobj2IDOMColorSpaceDeviceN(colorSpace);
numComponents = deviceN->getNumComponents();
for (uint8 componentIdx = 0; componentIdx < numComponents; componentIdx++)
{
auto altColorSpace = deviceN->getAlternateColorSpace();
auto altColorSpaceEnum = altColorSpace->getColorSpaceType();
IDOMDeviceNColorantPtr colorant = deviceN->getColorant(componentIdx);
String colorantName = U8StringToString(U8String(colorant->getName()));
// Only process if a not a special
if (colorantName != L"All" && colorantName != L"None")
{
IDOMColorPtr colorantColor = inkMap.at(colorantName);
std::wcout << L"('" << colorantName << L"'\t";
String altColorSpaceType = colorSpaceMap.at(altColorSpaceEnum);
// Components of the alternate color space
uint8 altNumComponents = altColorSpace->getNumComponents();
std::wcout << altColorSpaceType << L" (";
for (uint32 altComponentIdx = 0; altComponentIdx < altNumComponents; altComponentIdx++)
{
wprintf_s(L"%4.2f", colorantColor->getComponentValue(altComponentIdx));
if (altComponentIdx < (altNumComponents - 1))
std::wcout << ",";
}
std::wcout << L") ";
}
}
std::wcout << std::endl;
}
std::wcout << std::endl;
}
☑️ Conclusion
By implementing a custom transform, you can effectively determine the usage of color channels within a document. This method provides a reliable way to identify color spaces and their components, ensuring accurate color reporting even in complex documents. Utilizing the provided sample code and resources, you can integrate this solution into your workflow to enhance color management capabilities.
📚 Additional Resources
If you need additional help, see our API documentation for detailed information on class/method usage, or raise a support ticket via our customer portal.