Question

I have a PDF file with a hierarchy of layers (aka OCG). Using the following code snippet

var ocProps = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES);
var occd = ocProps.GetAsDict(PdfName.D);
var order = occd.GetAsArray(PdfName.ORDER);

I can query the current order from the source file. But I have no idea how to modify this data in order to copy it into a new file with the following snippet.

var reader = new PdfReader(input);
var document = new Document(reader.GetPageSizeWithRotation(1));
var pdfCopyProvider = new PdfCopy(document,
    new System.IO.FileStream(output, System.IO.FileMode.Create));            
document.Open();
// TBD do OCG modification ...
var importedPage = pdfCopyProvider.GetImportedPage(reader, 1);
pdfCopyProvider.AddPage(importedPage);
document.Close();

Nonetheless, the ocg information is copied to the new pdf file by default. I saw a comment from Bruno Lowagie several weeks ago concerning merging of ocgs https://stackoverflow.com/questions/21573892/itextsharp-merge-impose-pdfs-while-maintaining-layers-optional-content-groups but I'm not sure whether this includes simple copying also.

Any hint on this is welcome. Merging of ocgs might be a topic in future so hints on that topic are welcome, too

Regards, Holger

Added: I'm using most recent version 5.5.0.0

Added: In addition to Bruno's answer, I publish the C# version of the manipulatePdf method

public void ManipulatePdf(string source, string destination)
    {
        var reader = new PdfReader(source);
        var ocProps = reader.Catalog.GetAsDict(PdfName.OCPROPERTIES);
        var occd = ocProps.GetAsDict(PdfName.D);
        var order = occd.GetAsArray(PdfName.ORDER);

        var nestedLayers = (PdfObject)order[0];
        var nestedLayerArray = (PdfObject)order[1];
        var groupedLayers = (PdfObject)order[2];
        var radiogroup = (PdfObject)order[3];

        order[0] = radiogroup;
        order[1] = nestedLayers;
        order[2] = nestedLayerArray;
        order[3] = groupedLayers;

        var stamper = new PdfStamper(reader, new System.IO.FileStream(destination, System.IO.FileMode.Create));

        stamper.Close();
        reader.Close();
    }
Was it helpful?

Solution

You're already very close to the solution. See the ChangeOCGOrder to find out how to change ocg.pdf into ocg_reordered.pdf. (The code is in Java, but you shouldn't have any trouble porting it to... VB.NET?)

You already had something like this:

PdfDictionary catalog = reader.getCatalog();
PdfDictionary ocProps = catalog.getAsDict(PdfName.OCPROPERTIES);
PdfDictionary occd = ocProps.getAsDict(PdfName.D);
PdfArray order = occd.getAsArray(PdfName.ORDER);

This is good: you're looking at the right place!

Now you need something like this:

PdfObject nestedLayers = order.getPdfObject(0);
PdfObject nestedLayerArray = order.getPdfObject(1);
PdfObject groupedLayers = order.getPdfObject(2);
PdfObject radiogroup = order.getPdfObject(3);
order.set(0, radiogroup);
order.set(1, nestedLayers);
order.set(2, nestedLayerArray);
order.set(3, groupedLayers);

In my example, the ORDER array contains 4 elements. I get these four elements, and I change the order of the entries in the original array.

Note that I could also have done something like:

order.addFirst(order.remove(3));

That would have the same effect as the 8 lines of code above, but the 8 lines help you understand the mechanism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top