> 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/ios/get-started/samples/u3dtest.md).

# U3D

Sample Obj-C code for using Apryse SDK to embed U3D content (3 dimensional models) in PDF files.

Sample Obj-C code for using Apryse SDK to embed U3D content (3 dimensional models) in PDF files. Learn more about our [iOS SDK](/ios/guides.md).

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

#import <OBJC/PDFNetOBJC.h>
#import <Foundation/Foundation.h>

void Create3DAnnotation(PTPDFDoc* doc, PTObj* annots)
{
    // ---------------------------------------------------------------------------------
    // Create a 3D annotation based on U3D content. PDF 1.6 introduces the capability 
    // for collections of three-dimensional objects, such as those used by CAD software, 
    // to be embedded in PDF files.
    PTObj * link_3D = [doc CreateIndirectDict];
    [link_3D PutName: @"Subtype" name: @"3D"];

    // Annotation location on the page
    PTPDFRect * link_3D_rect = [[PTPDFRect alloc] init];
    [link_3D_rect Set: 25 y1: 180 x2: 585 y2: 643];
    [link_3D PutRect: @"Rect" x1: [link_3D_rect GetX1] y1: [link_3D_rect GetY1] x2: [link_3D_rect GetX2] y2: [link_3D_rect GetY2]];
    [annots PushBack: link_3D];

    // The 3DA entry is an activation dictionary (see Table 9.34 in the PDF Reference Manual) 
    // that determines how the state of the annotation and its associated artwork can change.
    PTObj * activation_dict_3D = [link_3D PutDict: @"3DA"];

    // Set the annotation so that it is activated as soon as the page containing the 
    // annotation is opened. Other options are: PV (page view) and XA (explicit) activation.
    [activation_dict_3D PutName: @"A" name: @"PO"];  

    // Embed U3D Streams (3D Model/Artwork).
    {
        PTMappedFile *u3d_file = [[PTMappedFile alloc] initWithFilename: @"../../TestFiles/dice.u3d"];
        PTFilterReader *u3d_reader = [[PTFilterReader alloc] initWithFilter: u3d_file];

        // To embed 3D stream without compression, you can omit the second parameter in CreateIndirectStream.
        PTFilter *f = [[PTFilter alloc] init];
        PTObj * u3d_data_dict = [doc CreateIndirectStream: u3d_reader filter_chain: [[PTFlateEncode alloc] initWithInput_filter: [[PTFilter alloc] init] compression_level: -1 buf_sz: 256]];
        [u3d_data_dict PutName: @"Subtype" name: @"U3D"];
        [link_3D Put: @"3DD" obj: u3d_data_dict];
    }

    // Set the initial view of the 3D artwork that should be used when the annotation is activated.
    PTObj * view3D_dict = [link_3D PutDict: @"3DV"];
    {
        [view3D_dict PutString: @"IN" value: @"Unnamed"];
        [view3D_dict PutString: @"XN" value: @"Default"];
        [view3D_dict PutName: @"MS" name: @"M"];
        [view3D_dict PutNumber: @"CO" value: 27.5];

        // A 12-element 3D transformation matrix that specifies a position and orientation 
        // of the camera in world coordinates.
        PTObj * tr3d = [view3D_dict PutArray: @"C2W"]; 
        [tr3d PushBackNumber: 1]; [tr3d PushBackNumber: 0]; [tr3d PushBackNumber: 0]; 
        [tr3d PushBackNumber: 0]; [tr3d PushBackNumber: 0]; [tr3d PushBackNumber: -1];
        [tr3d PushBackNumber: 0]; [tr3d PushBackNumber: 1]; [tr3d PushBackNumber: 0]; 
        [tr3d PushBackNumber: 0]; [tr3d PushBackNumber: -27.5]; [tr3d PushBackNumber: 0];

    }

    // Create annotation appearance stream, a thumbnail which is used during printing or
    // in PDF processors that do not understand 3D data.
    PTObj * ap_dict = [link_3D PutDict: @"AP"];
    {
        PTElementBuilder *builder = [[PTElementBuilder alloc] init];
        PTElementWriter *writer = [[PTElementWriter alloc] init];
        [writer WriterBeginWithSDFDoc: [doc GetSDFDoc] compress: true];

        NSString *thumb_pathname = @"../../TestFiles/dice.jpg";
        PTImage *image = [PTImage CreateWithFile: [doc GetSDFDoc] filename: thumb_pathname encoder_hints: [[PTObj alloc] init]];
        [writer WritePlacedElement: [builder CreateImageWithCornerAndScale: image x: 0.0 y: 0.0 hscale: [link_3D_rect Width] vscale: [link_3D_rect Height]]];

        PTObj * normal_ap_stream = [writer End];
        [normal_ap_stream PutName: @"Subtype" name: @"Form"];
        [normal_ap_stream PutRect: @"BBox" x1: 0 y1: 0 x2: [link_3D_rect Width] y2: [link_3D_rect Height]];
        [ap_dict Put: @"N" obj: normal_ap_stream];
    }
}

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int ret = 0;
        [PTPDFNet Initialize: 0];

        @try  
        {     
            PTPDFDoc *doc = [[PTPDFDoc alloc] init];
            PTPDFRect * rect = [[PTPDFRect alloc] init]; 
            [rect Set: 0 y1: 0 x2: 612 y2: 792];
            PTPage *page = [doc PageCreate: rect];
            [doc PagePushBack: page];
            PTObj * annots = [doc CreateIndirectArray];
            [[page GetSDFObj] Put: @"Annots" obj: annots];
        
            Create3DAnnotation(doc, annots);
            [doc SaveToFile: @"../../TestFiles/Output/dice_u3d.pdf" flags: e_ptlinearized];
            NSLog(@"Done");
        }
        @catch(NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }
        [PTPDFNet Terminate: 0];
        return ret;
    }
}
```

{% endcode %}
{% endtab %}

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

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

import PDFNet
import Foundation

func Create3DAnnotation(doc: PTPDFDoc, annots: PTObj) {
    // ---------------------------------------------------------------------------------
    // Create a 3D annotation based on U3D content. PDF 1.6 introduces the capability
    // for collections of three-dimensional objects, such as those used by CAD software,
    // to be embedded in PDF files.
    let link_3D: PTObj = doc.createIndirectDict()
    link_3D.putName("Subtype", name: "3D")
    
    // Annotation location on the page
    let link_3D_rect: PTPDFRect = PTPDFRect(x1: 25, y1: 180, x2: 585, y2: 643)
    link_3D.putRect("Rect", x1: link_3D_rect.getX1(), y1: link_3D_rect.getY1(), x2: link_3D_rect.getX2(), y2: link_3D_rect.getY2())
    annots.pushBack(link_3D)
    
    // The 3DA entry is an activation dictionary (see Table 9.34 in the PDF Reference Manual)
    // that determines how the state of the annotation and its associated artwork can change.
    let activation_dict_3D: PTObj = link_3D.putDict("3DA")
    
    // Set the annotation so that it is activated as soon as the page containing the
    // annotation is opened. Other options are: PV (page view) and XA (explicit) activation.
    activation_dict_3D.putName("A", name: "PO")
    
    // Embed U3D Streams (3D Model/Artwork).
    do {
        let u3d_file = PTMappedFile(filename: Bundle.main.path(forResource: "dice", ofType: "u3d"))
        let u3d_reader = PTFilterReader(filter: u3d_file)
        // To embed 3D stream without compression, you can omit the second parameter in CreateIndirectStream.
        let u3d_data_dict: PTObj = doc.createIndirectStream(u3d_reader, filter_chain: PTFlateEncode(input_filter: PTFilter(), compression_level: -1, buf_sz: 256))
        u3d_data_dict.putName("Subtype", name: "U3D")
        link_3D.put("3DD", obj: u3d_data_dict)
    }
    
    // Set the initial view of the 3D artwork that should be used when the annotation is activated.
    let view3D_dict: PTObj = link_3D.putDict("3DV")
    do {
        view3D_dict.put("IN", value: "Unnamed")
        view3D_dict.put("XN", value: "Default")
        view3D_dict.putName("MS", name: "M")
        view3D_dict.putNumber("CO", value: 27.5)
    
        // A 12-element 3D transformation matrix that specifies a position and orientation
        // of the camera in world coordinates.
        let tr3d: PTObj = view3D_dict.putArray("C2W")
        tr3d.pushBackNumber(1)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(-1)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(1)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(0)
        tr3d.pushBackNumber(-27.5)
        tr3d.pushBackNumber(0)
    }
    
    // Create annotation appearance stream, a thumbnail which is used during printing or
    // in PDF processors that do not understand 3D data.
    let ap_dict: PTObj = link_3D.putDict("AP")
    do {
        let builder: PTElementBuilder = PTElementBuilder()
        let writer: PTElementWriter = PTElementWriter()
        writer.writerBegin(with: doc.getSDFDoc(), compress: true)
    
        let thumb_pathname: String! = Bundle.main.path(forResource: "dice", ofType: "jpg")
        let image = PTImage.create(withFile: doc.getSDFDoc(), filename: thumb_pathname, encoder_hints: PTObj())
        writer.writePlacedElement(builder.createImage(withCornerAndScale: image, x: 0.0, y: 0.0, hscale: link_3D_rect.width(), vscale: link_3D_rect.height()))
        
        let normal_ap_stream: PTObj = writer.end()
        normal_ap_stream.putName("Subtype", name: "Form")
        normal_ap_stream.putRect("BBox", x1: 0, y1: 0, x2: link_3D_rect.width(), y2: link_3D_rect.height())
        ap_dict.put("N", obj: normal_ap_stream)
    }
}

func runU3DTest() -> Int {
    return autoreleasepool {
        var ret: Int = 0
        

        do {
            try PTPDFNet.catchException {
                let doc: PTPDFDoc = PTPDFDoc()
                let rect: PTPDFRect = PTPDFRect()
                rect.set(0, y1: 0, x2: 612, y2: 792)
                let page: PTPage = doc.pageCreate(rect)
                doc.pagePushBack(page)
                let annots: PTObj = doc.createIndirectArray()
                page.getSDFObj().put("Annots", obj: annots)
                
                Create3DAnnotation(doc: doc, annots: annots)
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("dice_u3d.pdf").path, flags: e_ptlinearized.rawValue)
                print("Done")
            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        return ret
    }
}
```

{% 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/ios/get-started/samples/u3dtest.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.
