> 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/sdftest.md).

# SDF

Sample Obj-C code to edit an existing PDF document at the object level by using the Apryse SDK Cos/SDF low-level API.

Sample Obj-C code for editing an existing PDF document at the object level by using the Apryse SDK Cos/SDF low-level API. Learn more about our [iOS SDK](/ios/guides.md) and [PDF Editing & Manipulation Library](/core/page-manipulation/manipulation.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>

// This sample illustrates how to use basic SDF API (also known as Cos) to edit an 
// existing document.

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

        @try
        {
            NSLog(@"Opening the test file...");

            // Here we create a SDF/Cos document directly from PDF file. In case you have 
            // PDFDoc you can always access SDF/Cos document using PDFDoc.GetSDFDoc() method.
            PTSDFDoc *doc = [[PTSDFDoc alloc] initWithFilepath: @"../../TestFiles/fish.pdf"];
            [doc InitSecurityHandler];

            NSLog(@"Modifying info dictionary, adding custom properties, embedding a stream...");
            PTObj * trailer = [doc GetTrailer]; // Get the trailer

            // Now we will change PDF document information properties using SDF API

            // Get the Info dictionary. 
            PTDictIterator *itr = [trailer Find: @"Info"];
            PTObj * info = [[PTObj alloc] init];
            if ([itr HasNext]) 
            {
                info = [itr Value];
                // Modify 'Producer' entry.
                [info PutString: @"Producer" value: @"PDFTron PDFNet"];

                // Read title entry (if it is present)
                itr = [info Find: @"Author"]; 
                if ([itr HasNext]) 
                {
                    NSString *oldstr = [[itr Value] GetAsPDFText];
                    [info PutText: @"Author" value: [oldstr stringByAppendingString: @"- Modified"]];
                }
                else 
                {
                    [info PutString: @"Author" value: @"Me, myself, and I"];
                }
            }
            else 
            {
                // Info dict is missing. 
                info = [trailer PutDict: @"Info"];
                [info PutString: @"Producer" value: @"PDFTron PDFNet"];
                [info PutString: @"Title" value: @"My document"];
            }

            // Create a custom inline dictionary within Info dictionary
            PTObj * custom_dict = [info PutDict: @"My Direct Dict"];
            [custom_dict PutNumber: @"My Number" value: 100]; // Add some key/value pairs
            [custom_dict PutArray: @"My Array"];

            // Create a custom indirect array within Info dictionary
            PTObj * custom_array = [doc CreateIndirectArray];
            [info Put: @"My Indirect Array" obj: custom_array]; // Add some entries
            
            // Create indirect link to root
            [custom_array PushBack: [[trailer Get: @"Root"] Value]];

            // Embed a custom stream (file mystream.txt).
            PTMappedFile *embed_file = [[PTMappedFile alloc] initWithFilename: @"../../TestFiles/my_stream.txt"];
            PTFilterReader *mystm = [[PTFilterReader alloc] initWithFilter: embed_file];
            [custom_array PushBack: [doc CreateIndirectStream: mystm]];

            // Save the changes.
            NSLog(@"Saving modified test file...");
            [doc SaveSDFDocToFile: @"../../TestFiles/Output/sdftest_out.pdf" flags:0 header: @"%PDF-1.4"];

            NSLog(@"Test completed.");
        }
        @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

// This sample illustrates how to use basic SDF API (also known as Cos) to edit an
// existing document.

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

        do {
            try PTPDFNet.catchException {
                print("Opening the test file...")
                
                // Here we create a SDF/Cos document directly from PDF file. In case you have
                // PDFDoc you can always access SDF/Cos document using PDFDoc.GetSDFDoc() method.
                let doc: PTSDFDoc = PTSDFDoc(filepath: Bundle.main.path(forResource: "fish", ofType: "pdf"))
                doc.initSecurityHandler()
                
                print("Modifying info dictionary, adding custom properties, embedding a stream...")
                let trailer: PTObj = doc.getTrailer()  // Get the trailer

                // Now we will change PDF document information properties using SDF API
                
                // Get the Info dictionary.
                var itr: PTDictIterator = trailer.find("Info")
                var info: PTObj = PTObj()
                if itr.hasNext() {
                    info = itr.value()
                    // Modify 'Producer' entry.
                    info.put("Producer", value: "PDFTron PDFNet")
                
                    // Read title entry (if it is present)
                    itr = info.find("Author")
                    if itr.hasNext() {
                        let oldstr: String = itr.value().getAsPDFText()
                        info.putText("Author", value: oldstr + "- Modified")
                    }
                    else {
                        info.put("Author", value: "Me, myself, and I")
                    }
                }
                else {
                    // Info dict is missing.
                    info = (trailer.putDict("Info"))!
                    info.put("Producer", value: "PDFTron PDFNet")
                    info.put("Title", value: "My document")
                }

                // Create a custom inline dictionary within Info dictionary
                let custom_dict: PTObj = info.putDict("My Direct Dict")
                custom_dict.putNumber("My Number", value: 100)  // Add some key/value pairs
                custom_dict.putArray("My Array")
                
                // Create a custom indirect array within Info dictionary
                let custom_array: PTObj = doc.createIndirectArray()
                info.put("My Indirect Array", obj: custom_array)    // Add some entries
                
                // Create indirect link to root
                custom_array.pushBack(trailer.get("Root").value())
                
                // Embed a custom stream (file mystream.txt).
                let embed_file = PTMappedFile(filename: Bundle.main.path(forResource: "my_stream", ofType: "txt"))
                let mystm = PTFilterReader(filter: embed_file)
                custom_array.pushBack(doc.createIndirectStream(mystm))
                
                // Save the changes.
                print("Saving modified test file...")
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("sdftest_out.pdf").path, flags: 0, header: "%PDF-1.4")
                
                print("Test completed.")
            }
        } 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/sdftest.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.
