0

I am implementing functionality to allow user to draw figures in pdf. I want to draw all the figures in a single layer, which can be made visible or invisible by the user.I am able to create a new layer in a pdf. I am also able to retrieve that layer.But, I am not able to make modification to layer (PDOptionalContentGroup). I tried converting the PDOptionalContentGroup to PDPage and then making desired changes to PDPPage. I also saved the PDDocument.It only created another layer with the same name as previous one, but the changes were not there.Here is the code that I used:

PDFont font = PDType1Font.HELVETICA;
PDDocument doc = PDDocument.load(src);
PDOptionalContentProperties ocprops = doc.getDocumentCatalog().getOCProperties();
foreach (string groupName in ocprops.getGroupNames())
{
    PDOptionalContentGroup group = ocprops.getGroup(groupName);
    COSBase cosbase = group.getCOSObject();
    PDPage groupPage = new PDPage((COSDictionary)cosbase);
    PDPageContentStream cs = new PDPageContentStream(doc, groupPage, true, false);
    cs.beginText();
    cs.setFont(font, 12);
    cs.moveTextPositionByAmount(150, 200);
    cs.drawString("Testing added to group:" + groupName);
    cs.endText();
    cs.close();
    doc.save(src);
}
V K
  • 1,645
  • 3
  • 26
  • 57
  • I'll try and get back to this later. But as a first hint: it does not make sense to treat an optional content group dictionary as a page, a page references all its content, no matter which ocg it may belong to. – mkl Apr 11 '17 at 10:22
  • @mkl Tilman suggested me to use PDcontentstream.beginMarkedContent(). But, I am using 1.8 ver of pdfbox. So, I have to use PDcontentstream.beginMarkedContentSequence(COSName.OC, resourceName);, where resource name is the resource name of optional content group.But, I am not able to fetch resource name corresponding an OCG. – V K Apr 11 '17 at 11:06

1 Answers1

1

(In a comment the OP indicated that he can only use a 1.8.x version of PDFBox. Thus, the code here is 1.8'ish, tested against PDFBox 1.8.12 for Java.)

In a comment to your question "How to get resource names for optional content group in a pdf?" Tilman Hausherr suggested to use the PDFBox class LayerUtility as template for own solutions.

Thus, as an example how add to an existing OCG this helper method (based on LayerUtility.appendFormAsLayer) shows how to add text to an existing or new OCG. It should be simple to adapt it to adding the content you want to add...

void addTextToLayer(PDDocument document, int pageNumber, String layerName, float x, float y, String text) throws IOException
{
    PDDocumentCatalog catalog = document.getDocumentCatalog();
    PDOptionalContentProperties ocprops = catalog.getOCProperties();
    if (ocprops == null)
    {
        ocprops = new PDOptionalContentProperties();
        catalog.setOCProperties(ocprops);
    }
    PDOptionalContentGroup layer = null;
    if (ocprops.hasGroup(layerName))
    {
        layer = ocprops.getGroup(layerName);
    }
    else
    {
        layer = new PDOptionalContentGroup(layerName);
        ocprops.addGroup(layer);
    }

    PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(pageNumber);

    PDResources resources = page.findResources();
    if (resources == null)
    {
        resources = new PDResources();
        page.setResources(resources);
    }
    PDPropertyList props = resources.getProperties();
    if (props == null)
    {
        props = new PDPropertyList();
        resources.setProperties(props);
    }

    //Find first free resource name with the pattern "MC<index>"
    int index = 0;
    PDOptionalContentGroup ocg;
    COSName resourceName;
    do
    {
        resourceName = COSName.getPDFName("MC" + index);
        ocg = props.getOptionalContentGroup(resourceName);
        index++;
    } while (ocg != null);
    //Put mapping for our new layer/OCG
    props.putMapping(resourceName, layer);

    PDFont font = PDType1Font.HELVETICA;

    PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true, true);
    contentStream.beginMarkedContentSequence(COSName.OC, resourceName);
    contentStream.beginText();
    contentStream.setFont(font, 12);
    contentStream.moveTextPositionByAmount(x, y);
    contentStream.drawString(text);
    contentStream.endText();
    contentStream.endMarkedContentSequence();

    contentStream.close();
}

(AddContentToOCG helper method addTextToLayer)

You can use it like this

PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);

addTextToLayer(document, 0, "MyLayer", 30, 600, "Text in new layer 'MyLayer'");
addTextToLayer(document, 0, "MyOtherLayer", 230, 550, "Text in new layer 'MyOtherLayer'");
addTextToLayer(document, 0, "MyLayer", 30, 500, "Text in existing layer 'MyLayer'");
addTextToLayer(document, 0, "MyOtherLayer", 230, 450, "Text in existing layer 'MyOtherLayer'");

document.save(new File(RESULT_FOLDER, "TextInOCGs.pdf"));
document.close();

(AddContentToOCG test method testAddContentToNewOrExistingOCG)

to add text to existing or not yet existing OCGs.

Community
  • 1
  • 1
mkl
  • 90,588
  • 15
  • 125
  • 265
  • 1
    Thanks it works.Only thing one extra thing that I used is checking if a resource name already exists for the OCG, then I use that for modifying OCG. – V K Apr 12 '17 at 06:25