Skip to main content
Skip table of contents

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

  1. Create a custom transform that overrides the transformGroup() method

  2. In the custom transform find optional content groups with group->getOptionalContentDetails()->getGroupReferences()

  3. 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.

CODE
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);
}
C#
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);
}
JAVA
@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);
}
PY
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.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.