Finding Optional Content Groups by page
📌 Overview
This knowledge base article is an extension to Optional Content (Layers) which outlines how optional content is managed in Mako. This article explains specifically how to find all the optional content groups on a page.
📗 Instructions
In Mako, optional content is marked up either by IDOMGroup objects or annotations. In this example, all groups are checked for optional content membership. This is complicated by the fact that optional content can be almost anywhere, including in patterns, soft masks, or glyphs in Type 3 fonts. To save extra work, a custom transform is used that will walk into every nook and cranny in the content for us, avoiding repeatedly revisiting shared resources.
🪜 Steps
Create a custom transform that overrides the
transformGroup()methodIn the custom transform find optional content groups with
group->getOptionalContentDetails()->getGroupReferences()Call the custom transform on each page and return the result
⌨️ Sample Code
Sample code for the transform is available below. For the full implementation see Visual Studio Projects/OptionalContentSearch, Java Projects/OptionalContentSearch, Python Projects/OptionalContentSearch.
IDOMNodePtr transformGroup(IImplementation* genericImplementation, const IDOMGroupPtr& group, bool& changed, bool transformChildren, const CTransformState& state)
{
// Does this group have optional content information?
const IOptionalContentDetailsPtr details = group->getOptionalContentDetails();
if (details)
{
// What groups does this reference?
COptionalContentGroupReferenceVect referencedGroups = details->getGroupReferences();
// Unfortunately for now we need to laboriously check to see if we've seen this before
for (const IOptionalContentGroupReferencePtr& referencedGroup : referencedGroups)
{
bool found = false;
for (const IOptionalContentGroupReferencePtr& foundGroup : m_foundGroups)
{
if (foundGroup->equals(referencedGroup))
{
found = true;
break;
}
}
if (!found)
{
m_foundGroups.append(referencedGroup);
}
}
}
// Descend further
return genericImplementation->transformGroup(nullptr, group, changed, transformChildren, state);
}
public override IDOMNode transformGroup(ICustomTransform.IImplementation genericImplementation, IDOMGroup group,
ref bool changed, bool transformChildren, CTransformState state)
{
// Does this group have optional content information?
IOptionalContentDetails details = group.getOptionalContentDetails();
if (details != null)
{
// What groups does this reference?
var referencedGroups = details.getGroupReferences().toVector();
// Unfortunately for now we need to laboriously check to see if we've seen this before
foreach (IOptionalContentGroupReference referencedGroup in referencedGroups)
{
bool found = false;
foreach (IOptionalContentGroupReference foundGroup in m_foundGroups)
{
if (foundGroup.Equals(referencedGroup))
{
found = true;
break;
}
}
if (!found)
{
m_foundGroups.Add(referencedGroup);
}
}
}
// Descend further
return genericImplementation.transformGroup(null, group, ref changed, transformChildren, state);
}
@Override
public IDOMNode transformGroup(ICustomTransform.IImplementation genericImpl, IDOMGroup group, boolean[] changed, boolean transformChildren, CTransformState state)
{
// Does this group have optional content information?
IOptionalContentDetails details = group.getOptionalContentDetails();
if (details != null)
{
// What groups does this reference?
CEDLVectIOptionalContentGroupReference refs = details.getGroupReferences();
IOptionalContentGroupReference[] referencedGroups = refs.toArray();
// Unfortunately for now we need to laboriously check to see if we've seen this before
for (IOptionalContentGroupReference ref : referencedGroups)
{
boolean alreadyFound = false;
for (IOptionalContentGroupReference existing : foundGroups)
{
if (existing.equals(ref))
{
alreadyFound = true;
break;
}
}
if (!alreadyFound)
{
foundGroups.add(ref);
}
}
}
// Descend further
return genericImpl.transformGroup(null, group, changed, transformChildren, state);
}
def transformGroup(self, genericImplementation, group, changed_ref, transformChildren, state):
# Does this group have optional content information?
details = group.getOptionalContentDetails()
if details is not None:
# What groups does this reference?
referencedGroups = details.getGroupReferences().toVector()
# Unfortunately for now we need to laboriously check to see if we've seen this before
for referencedGroup in referencedGroups:
if not any(found.equals(referencedGroup) for found in self.m_foundGroups):
self.m_foundGroups.append(referencedGroup)
# Continue traversal
return genericImplementation.transformGroup(None, group, changed_ref, transformChildren, state)
☑️ Conclusion
Identifying optional content groups within a page in Mako is a crucial task for managing complex documents with layered content. By utilizing custom transforms to navigate through all potential locations of optional content, users can efficiently gather necessary information without redundant processing. This approach ensures a comprehensive understanding of content layers, enhancing document manipulation and rendering 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.