itextlayerpdf-annotations

3D Annotation and PdfLayer


Suppose that I have two instances layer1 and layer2 of type com.itextpdf.text.pdf.PdfLayer, with layer1 will be used for an instance of typecom.itextpdf.text.pdf.PdfTemplatethat contains a instance of type com.itextpdf.text.Image and layer2 will be used for a 3D annotation of type com.itextpdf.text.pdf.PdfAnnotation.

The problem: after setting the visibility and activating the area reserved for layer2, I can neither make it(layer2) unvisible nor displaying layer1.

Essential Code:

private Document document;
private PdfWriter writer;
PdfContentByte upperLayer;

Rectangle box;

private PdfLayer view2D;
private PdfLayer view3D;

public static void main(String[] args) throws DocumentException, MalformedURLException, URISyntaxException, IOException 
{
    LayersWithDiffDimsDemo generator = new LayersWithDiffDimsDemo();

    generator.setupResources();
    generator.report();
    generator.cleanupResources();

}

public void setupResources() throws DocumentException, IOException
{
    document = new Document(PageSize.A4);

    FileOutputStream outputStream = new FileOutputStream("layers_with_diff_dimensions.pdf");
    writer = PdfWriter.getInstance(document, outputStream);

    document.open();
    upperLayer = writer.getDirectContent();

    box = new Rectangle(26.0f, document.getPageSize().getHeight() - 455.0f, 550, document.getPageSize().getHeight() - 210.0f);
    box.setBorder(Rectangle.BOX);
    box.setBorderWidth(0.5f);
    box.setBorderColor(new BaseColor(0xFF, 0x00, 0x00));
    document.add(box);

    PdfLayer views = PdfLayer.createTitle("Ansichtsmodi", writer);

    view2D = new PdfLayer("2D", writer);
    view2D.setOn(true);

    view3D = new PdfLayer("3D", writer);
    view3D.setOn(false);

    views.addChild(view3D);
    views.addChild(view2D);

    ArrayList<PdfLayer> radio = new ArrayList<>();
    radio.add(view3D);
    radio.add(view2D);
    writer.addOCGRadioGroup(radio);
}

public void report() throws URISyntaxException, MalformedURLException, IOException 
{
    try 
    {
        // Output the dimension drawing
        // teapot.jpg is a screen shot of the 3d model
        Image imageIn2D = Image.getInstance("teapot.jpg");

        imageIn2D.setAbsolutePosition((document.getPageSize().getWidth() - imageIn2D.getWidth()) / 2, 400.0f);
        imageIn2D.setLayer(view2D);
        upperLayer.addImage(imageIn2D, true);

        try {
            // The file name that contains the 3D Model
            FileInputStream inputStream = new FileInputStream("teapot.u3d");
            PdfStream stream3D = new PdfStream(inputStream, writer);
            stream3D.put(PdfName.TYPE, new PdfName("3D"));
            stream3D.put(PdfName.SUBTYPE, new PdfName("U3D"));
            stream3D.flateCompress();
            try {
                PdfIndirectObject streamObject = writer.addToBody(stream3D);
                stream3D.writeLength();
                PdfDictionary dict3D = new PdfDictionary();
                dict3D.put(PdfName.TYPE, new PdfName("3DView"));
                dict3D.put(new PdfName("XN"), new PdfString("Default"));
                dict3D.put(new PdfName("IN"), new PdfString("Unnamed"));
                dict3D.put(new PdfName("MS"), PdfName.M);
                dict3D.put(new PdfName("C2W"), new PdfArray(new float[]{1, 0, 0, 0, 0, -1, 0, 1, 0, 3, -235, 28}));
                dict3D.put(PdfName.CO, new PdfNumber(235));
                PdfIndirectObject dictObject = writer.addToBody(dict3D);
                PdfAnnotation annot = new PdfAnnotation(writer, box);
                annot.setLayer(view3D);
                annot.put(PdfName.CONTENTS, new PdfString("3D Model"));
                annot.put(PdfName.SUBTYPE, new PdfName("3D"));
                annot.put(PdfName.TYPE, PdfName.ANNOT);
                annot.put(new PdfName("3DD"), streamObject.getIndirectReference());
                annot.put(new PdfName("3DV"), dictObject.getIndirectReference());
                PdfAppearance ap = upperLayer.createAppearance(box.getWidth(), box.getHeight());
                annot.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, ap);
                annot.setPage();

                upperLayer.addAnnotation(annot, false);

            } catch (IOException ex) {
                Logger.getLogger(LayersWithDiffDimsDemo.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(LayersWithDiffDimsDemo.class.getName()).log(Level.SEVERE, null, ex);
        }

    } catch (DocumentException ex) 
    {
        Logger.getLogger(LayersWithDiffDimsDemo.class.getName()).log(Level.SEVERE, null, ex);
    }
}

public void cleanupResources()
{
    document.close();
}

Thank you for any suggests!


Solution

  • Assuming your viewer is Acrobat or Reader, as long as the 3D annotation is active it's going to be visible. The fact that the annot is associated with a layer, visible or otherwise, won't change that.

    Defending my assertion...

    Open the file at http://practicalpdf.com/downloads/BrakeAssembly.pdf.

    The file has a single 3D Annotation taking up the whole page and is set to activate when clicked. It's deactivated when the file first opens. The 3D annot is also on a layer called "3DAnnot" and the file initial view is set to open in Reader with the layers panel showing. Associating an annotation with a layer is supported in the PDF Specification but there's no way to author it in Acrobat without a plugin or via a library as you are doing.

    Notice when you first open the file, the 3D annotation is not active and you can toggle the layer visibility. Notice that the annotation poster visibility is following the layer visibility. Now activate the annot by clicking on it. Now notice that the activated 3D Annot is not affected by the visibility of the layer.

    This is because layer visibility only applies to PDF Page content. The poster (appearance) of the 3D annot is the only part of that dictionary that is page content. The 3D viewer runtime is simply projecting into the same rectangle as the annot. While active, the 3D will always display over the page content even if you add a layer on top of the one that holds the 3D annotation.