> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/android/get-started/samples/pdflayerstest.md).

# PDFLayers

Sample Java code to use Apryse SDK for creating and manipulating PDF layers (also known as Optional Content Groups - OCGs). These samples demonstrate how to create and extract layers, as well as to se

Sample Java code to use Apryse SDK for creating and manipulating PDF layers (also known as Optional Content Groups - OCGs). These samples demonstrate how to create and extract layers, as well as to selectively render them (show, hide) in conforming PDF readers or printers. Learn more about our [Android SDK](/core/get-started/languages/java.md).

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

package com.pdftron.android.pdfnetsdksamples.samples;

import com.pdftron.android.pdfnetsdksamples.OutputListener;
import com.pdftron.android.pdfnetsdksamples.PDFNetSample;
import com.pdftron.android.pdfnetsdksamples.R;
import com.pdftron.android.pdfnetsdksamples.util.Utils;
import com.pdftron.common.Matrix2D;
import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.ColorPt;
import com.pdftron.pdf.ColorSpace;
import com.pdftron.pdf.Element;
import com.pdftron.pdf.ElementBuilder;
import com.pdftron.pdf.ElementWriter;
import com.pdftron.pdf.Font;
import com.pdftron.pdf.GState;
import com.pdftron.pdf.Image;
import com.pdftron.pdf.PDFDoc;
import com.pdftron.pdf.PDFDocViewPrefs;
import com.pdftron.pdf.PDFDraw;
import com.pdftron.pdf.Page;
import com.pdftron.pdf.ocg.Config;
import com.pdftron.pdf.ocg.Context;
import com.pdftron.pdf.ocg.Group;
import com.pdftron.pdf.ocg.OCMD;
import com.pdftron.sdf.Obj;
import com.pdftron.sdf.SDFDoc;

import java.util.ArrayList;

/**
 * This sample demonstrates how to create layers in PDF.
 * The sample also shows how to extract and render PDF layers in documents
 * that contain optional content groups (OCGs)
 * <p>
 * With the introduction of PDF version 1.5 came the concept of Layers.
 * Layers, or as they are more formally known Optional Content Groups (OCGs),
 * refer to sections of content in a PDF document that can be selectively
 * viewed or hidden by document authors or consumers. This capability is useful
 * in CAD drawings, layered artwork, maps, multi-language documents etc.
 * <p>
 * Couple of notes regarding this sample:
 * ---------------------------------------
 * - This sample is using CreateLayer() utility method to create new OCGs.
 * CreateLayer() is relatively basic, however it can be extended to set
 * other optional entries in the 'OCG' and 'OCProperties' dictionary. For
 * a complete listing of possible entries in OC dictionary please refer to
 * section 4.10 'Optional Content' in the PDF Reference Manual.
 * - The sample is grouping all layer content into separate Form XObjects.
 * Although using PDFNet is is also possible to specify Optional Content in
 * Content Streams (Section 4.10.2 in PDF Reference), Optional Content in
 * XObjects results in PDFs that are cleaner, less-error prone, and faster
 * to process.
 */
public class PDFLayersTest extends PDFNetSample {

	private static OutputListener mOutputListener;

	private static ArrayList<String> mFileList = new ArrayList<>();

    public PDFLayersTest() {
        setTitle(R.string.sample_pdflayers_title);
        setDescription(R.string.sample_pdflayers_description);
    }

	@Override
	public void run(OutputListener outputListener) {
		super.run(outputListener);
		mOutputListener = outputListener;
		mFileList.clear();
		printHeader(outputListener);

        try (PDFDoc doc = new PDFDoc()) {
            // Create three layers...
            Group image_layer = createLayer(doc, "Image Layer");
            Group text_layer = createLayer(doc, "Text Layer");
            Group vector_layer = createLayer(doc, "Vector Layer");

            // Start a new page ------------------------------------
            Page page = doc.pageCreate();

            ElementBuilder builder = new ElementBuilder(); // ElementBuilder is used to build new Element objects
            ElementWriter writer = new ElementWriter(); // ElementWriter is used to write Elements to the page
            writer.begin(page);        // Begin writing to the page

            // Add new content to the page and associate it with one of the layers.
            Element element = builder.createForm(createGroup1(doc, image_layer.getSDFObj()));
            writer.writeElement(element);

            element = builder.createForm(createGroup2(doc, vector_layer.getSDFObj()));
            writer.writeElement(element);

            // Add the text layer to the page...
            if (false)  // set to true to enable 'ocmd' example.
            {
                // A bit more advanced example of how to create an OCMD text layer that
                // is visible only if text, image and path layers are all 'ON'.
                // An example of how to set 'Visibility Policy' in OCMD.
                Obj ocgs = doc.createIndirectArray();
                ocgs.pushBack(image_layer.getSDFObj());
                ocgs.pushBack(vector_layer.getSDFObj());
                ocgs.pushBack(text_layer.getSDFObj());
                OCMD text_ocmd = OCMD.create(doc, ocgs, OCMD.e_AllOn);
                element = builder.createForm(createGroup3(doc, text_ocmd.getSDFObj()));
            } else {
                element = builder.createForm(createGroup3(doc, text_layer.getSDFObj()));
            }
            writer.writeElement(element);

            // Add some content to the page that does not belong to any layer...
            // In this case this is a rectangle representing the page border.
            element = builder.createRect(0, 0, page.getPageWidth(), page.getPageHeight());
            element.setPathFill(false);
            element.setPathStroke(true);
            element.getGState().setLineWidth(40);
            writer.writeElement(element);

            writer.end();  // save changes to the current page
            doc.pagePushBack(page);

            // Set the default viewing preference to display 'Layer' tab.
            PDFDocViewPrefs prefs = doc.getViewPrefs();
            prefs.setPageMode(PDFDocViewPrefs.e_UseOC);

            doc.save(Utils.createExternalFile("pdf_layers.pdf", mFileList).getAbsolutePath(), SDFDoc.SaveMode.LINEARIZED, null);
            mOutputListener.println("Done.");
        } catch (Exception e) {
            mOutputListener.printError(e.getStackTrace());
        }

        // The following is a code snippet shows how to selectively render
        // and export PDF layers.
        try (PDFDoc doc = new PDFDoc(Utils.createExternalFile("pdf_layers.pdf", mFileList).getAbsolutePath())) {
            doc.initSecurityHandler();

            if (doc.hasOC() == false) {
                mOutputListener.println("The document does not contain 'Optional Content'");
            } else {
                Config init_cfg = doc.getOCGConfig();
                Context ctx = new Context(init_cfg);

                PDFDraw pdfdraw = new PDFDraw();
                pdfdraw.setImageSize(1000, 1000);
                pdfdraw.setOCGContext(ctx); // Render the page using the given OCG context.

                Page page = doc.getPage(1); // Get the first page in the document.
                pdfdraw.export(page, Utils.createExternalFile("pdf_layers_default.png", mFileList).getAbsolutePath());
                // output "pdf_layers_default.png"

                // Disable drawing of content that is not optional (i.e. is not part of any layer).
                ctx.setNonOCDrawing(false);

                // Now render each layer in the input document to a separate image.
                Obj ocgs = doc.getOCGs(); // Get the array of all OCGs in the document.
                if (ocgs != null) {
                    int i, sz = (int) ocgs.size();
                    for (i = 0; i < sz; ++i) {
                        Group ocg = new Group(ocgs.getAt(i));
                        ctx.resetStates(false);
                        ctx.setState(ocg, true);
                        String fname =  "pdf_layers_" + ocg.getName() + ".png";
                        mOutputListener.println(fname);
                        pdfdraw.export(page, Utils.createExternalFile(fname, mFileList).getAbsolutePath());
                        // output "pdf_layers_" + ocg.getName() + ".png"
                    }
                }

                // Now draw content that is not part of any layer...
                ctx.setNonOCDrawing(true);
                ctx.setOCDrawMode(Context.e_NoOC);
                pdfdraw.export(page, Utils.createExternalFile("pdf_layers_non_oc.png", mFileList).getAbsolutePath());
                // output "pdf_layers_non_oc.png"
            }

            mOutputListener.println("Done.");
        } catch (Exception e) {
            mOutputListener.printError(e.getStackTrace());
        }

		for (String file : mFileList) {
			addToFileList(file);
		}
		printFooter(outputListener);
	}

    // A utility function used to add new Content Groups (Layers) to the document.
    static Group createLayer(PDFDoc doc, String layer_name) throws PDFNetException {
        Group grp = Group.create(doc, layer_name);
        Config cfg = doc.getOCGConfig();
        if (cfg == null) {
            cfg = Config.create(doc, true);
            cfg.setName("Default");
        }

        // Add the new OCG to the list of layers that should appear in PDF viewer GUI.
        Obj layer_order_array = cfg.getOrder();
        if (layer_order_array == null) {
            layer_order_array = doc.createIndirectArray();
            cfg.setOrder(layer_order_array);
        }
        layer_order_array.pushBack(grp.getSDFObj());

        return grp;
    }

    // Creates some content (3 images) and associate them with the image layer
    static Obj createGroup1(PDFDoc doc, Obj layer) throws PDFNetException {
        ElementWriter writer = new ElementWriter();
        writer.begin(doc);

        // Create an Image that can be reused in the document or on the same page.
        Image img = Image.create(doc.getSDFDoc(), (Utils.getAssetTempFile(INPUT_PATH + "peppers.jpg").getAbsolutePath()));

        ElementBuilder builder = new ElementBuilder();
        Element element = builder.createImage(img, new Matrix2D(img.getImageWidth() / 2, -145, 20, img.getImageHeight() / 2, 200, 150));
        writer.writePlacedElement(element);

        GState gstate = element.getGState();    // use the same image (just change its matrix)
        gstate.setTransform(200, 0, 0, 300, 50, 450);
        writer.writePlacedElement(element);

        // use the same image again (just change its matrix).
        writer.writePlacedElement(builder.createImage(img, 300, 600, 200, -150));

        Obj grp_obj = writer.end();

        // Indicate that this form (content group) belongs to the given layer (OCG).
        grp_obj.putName("Subtype", "Form");
        grp_obj.put("OC", layer);
        grp_obj.putRect("BBox", 0, 0, 1000, 1000);  // Set the clip box for the content.

        return grp_obj;
    }

    // Creates some content (a path in the shape of a heart) and associate it with the vector layer
    static Obj createGroup2(PDFDoc doc, Obj layer) throws PDFNetException {
        ElementWriter writer = new ElementWriter();
        writer.begin(doc);

        // Create a path object in the shape of a heart.
        ElementBuilder builder = new ElementBuilder();
        builder.pathBegin();        // start constructing the path
        builder.moveTo(306, 396);
        builder.curveTo(681, 771, 399.75, 864.75, 306, 771);
        builder.curveTo(212.25, 864.75, -69, 771, 306, 396);
        builder.closePath();
        Element element = builder.pathEnd(); // the path geometry is now specified.

        // Set the path FILL color space and color.
        element.setPathFill(true);
        GState gstate = element.getGState();
        gstate.setFillColorSpace(ColorSpace.createDeviceCMYK());
        gstate.setFillColor(new ColorPt(1, 0, 0, 0));  // cyan

        // Set the path STROKE color space and color.
        element.setPathStroke(true);
        gstate.setStrokeColorSpace(ColorSpace.createDeviceRGB());
        gstate.setStrokeColor(new ColorPt(1, 0, 0));  // red
        gstate.setLineWidth(20);

        gstate.setTransform(0.5, 0, 0, 0.5, 280, 300);

        writer.writeElement(element);

        Obj grp_obj = writer.end();

        // Indicate that this form (content group) belongs to the given layer (OCG).
        grp_obj.putName("Subtype", "Form");
        grp_obj.put("OC", layer);
        grp_obj.putRect("BBox", 0, 0, 1000, 1000);    // Set the clip box for the content.

        return grp_obj;
    }

    // Creates some text and associate it with the text layer
    static Obj createGroup3(PDFDoc doc, Obj layer) throws PDFNetException {
        ElementWriter writer = new ElementWriter();
        writer.begin(doc);

        // Create a path object in the shape of a heart.
        ElementBuilder builder = new ElementBuilder();

        // Begin writing a block of text
        Element element = builder.createTextBegin(Font.create(doc, Font.e_times_roman), 120);
        writer.writeElement(element);

        element = builder.createTextRun("A text layer!");

        // Rotate text 45 degrees, than translate 180 pts horizontally and 100 pts vertically.
        Matrix2D transform = Matrix2D.rotationMatrix(-45 * (3.1415 / 180.0));
        transform.concat(1, 0, 0, 1, 180, 100);
        element.setTextMatrix(transform);

        writer.writeElement(element);
        writer.writeElement(builder.createTextEnd());

        Obj grp_obj = writer.end();

        // Indicate that this form (content group) belongs to the given layer (OCG).
        grp_obj.putName("Subtype", "Form");
        grp_obj.put("OC", layer);
        grp_obj.putRect("BBox", 0, 0, 1000, 1000);    // Set the clip box for the content.

        return grp_obj;
    }

}
```

{% endcode %}
{% endtab %}

{% tab title="Kotlin" %}
{% code lineNumbers="true" %}

```kotlin
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
package com.pdftron.android.pdfnetsdksamples.samples

import com.pdftron.android.pdfnetsdksamples.OutputListener
import com.pdftron.android.pdfnetsdksamples.PDFNetSample
import com.pdftron.android.pdfnetsdksamples.R
import com.pdftron.android.pdfnetsdksamples.util.Utils
import com.pdftron.common.Matrix2D
import com.pdftron.common.PDFNetException
import com.pdftron.pdf.*
import com.pdftron.pdf.ocg.Config
import com.pdftron.pdf.ocg.Context
import com.pdftron.pdf.ocg.Group
import com.pdftron.pdf.ocg.OCMD
import com.pdftron.sdf.Obj
import com.pdftron.sdf.SDFDoc
import java.util.*

/**
 * This sample demonstrates how to create layers in PDF.
 * The sample also shows how to extract and render PDF layers in documents
 * that contain optional content groups (OCGs)
 *
 *
 * With the introduction of PDF version 1.5 came the concept of Layers.
 * Layers, or as they are more formally known Optional Content Groups (OCGs),
 * refer to sections of content in a PDF document that can be selectively
 * viewed or hidden by document authors or consumers. This capability is useful
 * in CAD drawings, layered artwork, maps, multi-language documents etc.
 *
 *
 * Couple of notes regarding this sample:
 * ---------------------------------------
 * - This sample is using CreateLayer() utility method to create new OCGs.
 * CreateLayer() is relatively basic, however it can be extended to set
 * other optional entries in the 'OCG' and 'OCProperties' dictionary. For
 * a complete listing of possible entries in OC dictionary please refer to
 * section 4.10 'Optional Content' in the PDF Reference Manual.
 * - The sample is grouping all layer content into separate Form XObjects.
 * Although using PDFNet is is also possible to specify Optional Content in
 * Content Streams (Section 4.10.2 in PDF Reference), Optional Content in
 * XObjects results in PDFs that are cleaner, less-error prone, and faster
 * to process.
 */
class PDFLayersTest : PDFNetSample() {
    override fun run(outputListener: OutputListener?) {
        super.run(outputListener)
        mOutputListener = outputListener
        mFileList.clear()
        printHeader(outputListener!!)
        try {
            PDFDoc().use { doc ->
                // Create three layers...
                val image_layer = createLayer(doc, "Image Layer")
                val text_layer = createLayer(doc, "Text Layer")
                val vector_layer = createLayer(doc, "Vector Layer")

                // Start a new page ------------------------------------
                val page = doc.pageCreate()
                val builder = ElementBuilder() // ElementBuilder is used to build new Element objects
                val writer = ElementWriter() // ElementWriter is used to write Elements to the page
                writer.begin(page) // Begin writing to the page

                // Add new content to the page and associate it with one of the layers.
                var element = builder.createForm(createGroup1(doc, image_layer.sdfObj))
                writer.writeElement(element)
                element = builder.createForm(createGroup2(doc, vector_layer.sdfObj))
                writer.writeElement(element)

                // Add the text layer to the page...
                element = if (false) // set to true to enable 'ocmd' example.
                {
                    // A bit more advanced example of how to create an OCMD text layer that
                    // is visible only if text, image and path layers are all 'ON'.
                    // An example of how to set 'Visibility Policy' in OCMD.
                    val ocgs = doc.createIndirectArray()
                    ocgs.pushBack(image_layer.sdfObj)
                    ocgs.pushBack(vector_layer.sdfObj)
                    ocgs.pushBack(text_layer.sdfObj)
                    val text_ocmd = OCMD.create(doc, ocgs, OCMD.e_AllOn)
                    builder.createForm(createGroup3(doc, text_ocmd.sdfObj))
                } else {
                    builder.createForm(createGroup3(doc, text_layer.sdfObj))
                }
                writer.writeElement(element)

                // Add some content to the page that does not belong to any layer...
                // In this case this is a rectangle representing the page border.
                element = builder.createRect(0.0, 0.0, page.pageWidth, page.pageHeight)
                element.setPathFill(false)
                element.setPathStroke(true)
                element.gState.lineWidth = 40.0
                writer.writeElement(element)
                writer.end() // save changes to the current page
                doc.pagePushBack(page)

                // Set the default viewing preference to display 'Layer' tab.
                val prefs = doc.viewPrefs
                prefs.pageMode = PDFDocViewPrefs.e_UseOC
                doc.save(Utils.createExternalFile("pdf_layers.pdf", mFileList).absolutePath, SDFDoc.SaveMode.LINEARIZED, null)
                mOutputListener!!.println("Done.")
            }
        } catch (e: Exception) {
            mOutputListener!!.printError(e.stackTrace)
        }

        // The following is a code snippet shows how to selectively render
        // and export PDF layers.
        try {
            PDFDoc(Utils.createExternalFile("pdf_layers.pdf", mFileList).absolutePath).use { doc ->
                doc.initSecurityHandler()
                if (doc.hasOC() == false) {
                    mOutputListener!!.println("The document does not contain 'Optional Content'")
                } else {
                    val init_cfg = doc.ocgConfig
                    val ctx = Context(init_cfg)
                    val pdfdraw = PDFDraw()
                    pdfdraw.setImageSize(1000, 1000)
                    pdfdraw.setOCGContext(ctx) // Render the page using the given OCG context.
                    val page = doc.getPage(1) // Get the first page in the document.
                    pdfdraw.export(page, Utils.createExternalFile("pdf_layers_default.png", mFileList).absolutePath)

                    // Disable drawing of content that is not optional (i.e. is not part of any layer).
                    ctx.setNonOCDrawing(false)

                    // Now render each layer in the input document to a separate image.
                    val ocgs = doc.ocGs // Get the array of all OCGs in the document.
                    if (ocgs != null) {
                        var i: Int
                        val sz = ocgs.size().toInt()
                        i = 0
                        while (i < sz) {
                            val ocg = Group(ocgs.getAt(i))
                            ctx.resetStates(false)
                            ctx.setState(ocg, true)
                            val fname = "pdf_layers_" + ocg.name + ".png"
                            mOutputListener!!.println(fname)
                            pdfdraw.export(page, Utils.createExternalFile(fname, mFileList).absolutePath)
                            ++i
                        }
                    }

                    // Now draw content that is not part of any layer...
                    ctx.setNonOCDrawing(true)
                    ctx.setOCDrawMode(Context.e_NoOC)
                    pdfdraw.export(page, Utils.createExternalFile("pdf_layers_non_oc.png", mFileList).absolutePath)
                }
                mOutputListener!!.println("Done.")
            }
        } catch (e: Exception) {
            mOutputListener!!.printError(e.stackTrace)
        }
        for (file in mFileList) {
            addToFileList(file)
        }
        printFooter(outputListener)
    }

    companion object {
        private var mOutputListener: OutputListener? = null
        private val mFileList = ArrayList<String>()

        // A utility function used to add new Content Groups (Layers) to the document.
        @Throws(PDFNetException::class)
        fun createLayer(doc: PDFDoc, layer_name: String?): Group {
            val grp = Group.create(doc, layer_name)
            var cfg = doc.ocgConfig
            if (cfg == null) {
                cfg = Config.create(doc, true)
                cfg.name = "Default"
            }

            // Add the new OCG to the list of layers that should appear in PDF viewer GUI.
            var layer_order_array = cfg!!.order
            if (layer_order_array == null) {
                layer_order_array = doc.createIndirectArray()
                cfg.order = layer_order_array
            }
            layer_order_array!!.pushBack(grp.sdfObj)
            return grp
        }

        // Creates some content (3 images) and associate them with the image layer
        @Throws(PDFNetException::class)
        fun createGroup1(doc: PDFDoc, layer: Obj?): Obj {
            val writer = ElementWriter()
            writer.begin(doc)

            // Create an Image that can be reused in the document or on the same page.
            val img = Image.create(doc.sdfDoc, Utils.getAssetTempFile(INPUT_PATH + "peppers.jpg")!!.absolutePath)
            val builder = ElementBuilder()
            val element = builder.createImage(img, Matrix2D((img.imageWidth / 2).toDouble(), -145.0, 20.0, (img.imageHeight / 2).toDouble(), 200.0, 150.0))
            writer.writePlacedElement(element)
            val gstate = element.gState // use the same image (just change its matrix)
            gstate.setTransform(200.0, 0.0, 0.0, 300.0, 50.0, 450.0)
            writer.writePlacedElement(element)

            // use the same image again (just change its matrix).
            writer.writePlacedElement(builder.createImage(img, 300.0, 600.0, 200.0, -150.0))
            val grp_obj = writer.end()

            // Indicate that this form (content group) belongs to the given layer (OCG).
            grp_obj.putName("Subtype", "Form")
            grp_obj.put("OC", layer)
            grp_obj.putRect("BBox", 0.0, 0.0, 1000.0, 1000.0) // Set the clip box for the content.
            return grp_obj
        }

        // Creates some content (a path in the shape of a heart) and associate it with the vector layer
        @Throws(PDFNetException::class)
        fun createGroup2(doc: PDFDoc?, layer: Obj?): Obj {
            val writer = ElementWriter()
            writer.begin(doc)

            // Create a path object in the shape of a heart.
            val builder = ElementBuilder()
            builder.pathBegin() // start constructing the path
            builder.moveTo(306.0, 396.0)
            builder.curveTo(681.0, 771.0, 399.75, 864.75, 306.0, 771.0)
            builder.curveTo(212.25, 864.75, -69.0, 771.0, 306.0, 396.0)
            builder.closePath()
            val element = builder.pathEnd() // the path geometry is now specified.

            // Set the path FILL color space and color.
            element.setPathFill(true)
            val gstate = element.gState
            gstate.fillColorSpace = ColorSpace.createDeviceCMYK()
            gstate.fillColor = ColorPt(1.0, 0.0, 0.0, 0.0) // cyan

            // Set the path STROKE color space and color.
            element.setPathStroke(true)
            gstate.strokeColorSpace = ColorSpace.createDeviceRGB()
            gstate.strokeColor = ColorPt(1.0, 0.0, 0.0) // red
            gstate.lineWidth = 20.0
            gstate.setTransform(0.5, 0.0, 0.0, 0.5, 280.0, 300.0)
            writer.writeElement(element)
            val grp_obj = writer.end()

            // Indicate that this form (content group) belongs to the given layer (OCG).
            grp_obj.putName("Subtype", "Form")
            grp_obj.put("OC", layer)
            grp_obj.putRect("BBox", 0.0, 0.0, 1000.0, 1000.0) // Set the clip box for the content.
            return grp_obj
        }

        // Creates some text and associate it with the text layer
        @Throws(PDFNetException::class)
        fun createGroup3(doc: PDFDoc?, layer: Obj?): Obj {
            val writer = ElementWriter()
            writer.begin(doc)

            // Create a path object in the shape of a heart.
            val builder = ElementBuilder()

            // Begin writing a block of text
            var element = builder.createTextBegin(Font.create(doc, Font.e_times_roman), 120.0)
            writer.writeElement(element)
            element = builder.createTextRun("A text layer!")

            // Rotate text 45 degrees, than translate 180 pts horizontally and 100 pts vertically.
            val transform = Matrix2D.rotationMatrix(-45 * (3.1415 / 180.0))
            transform.concat(1.0, 0.0, 0.0, 1.0, 180.0, 100.0)
            element.textMatrix = transform
            writer.writeElement(element)
            writer.writeElement(builder.createTextEnd())
            val grp_obj = writer.end()

            // Indicate that this form (content group) belongs to the given layer (OCG).
            grp_obj.putName("Subtype", "Form")
            grp_obj.put("OC", layer)
            grp_obj.putRect("BBox", 0.0, 0.0, 1000.0, 1000.0) // Set the clip box for the content.
            return grp_obj
        }
    }

    init {
        setTitle(R.string.sample_pdflayers_title)
        setDescription(R.string.sample_pdflayers_description)
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/android/get-started/samples/pdflayerstest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
