> 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/core/get-started/samples/sdftest.md).

# SDF API for PDF Editing

Sample code to edit an existing PDF document at the object level by using the Apryse SDK Cos/SDF low-level API.  Sample code provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.

Sample code for editing an existing PDF document at the object level by using the Apryse SDK Cos/SDF low-level API. Sample code provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby and VB.

Learn more about our [Server SDK](/core/get-started/get-started.md) and [PDF Editing & Manipulation Library](/core/page-manipulation/manipulation.md).

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

```csharp
//
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
//

using System;
using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;

namespace SDFTestCS
{
	/// <summary>
	/// This sample illustrates how to use basic SDF API (also known as Cos) to edit an 
	/// existing document.
	/// </summary>
	class Class1
	{
		private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
		static Class1() {}
		
		static void Main(string[] args)
		{
			PDFNet.Initialize(PDFTronLicense.Key);

			// Relative path to the folder containing test files.
			string input_path =  "../../../../TestFiles/";
			string output_path = "../../../../TestFiles/Output/";


			//------------------------------------------------------------------
			Console.WriteLine("Opening the test file...");

			try
			{
				// 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.
				using (SDFDoc doc = new SDFDoc(input_path + "fish.pdf"))
				{
					doc.InitSecurityHandler();				
					
					Console.WriteLine("Modifying info dictionary, adding custom properties, embedding a stream...");

					Obj trailer = doc.GetTrailer();	// Get the trailer

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

					// Get the Info dictionary. 
					DictIterator itr = trailer.Find("Info");	
					Obj info;
					if (itr.HasNext()) 
					{
						info = itr.Value();
						// Modify 'Producer' entry.
						info.PutString("Producer", "PDFTron PDFNet");

						// Read title entry (if it is present)
						itr = info.Find("Author"); 
						if (itr.HasNext()) 
						{
							info.PutString("Author", itr.Value().GetAsPDFText() + "- Modified");
						}
						else 
						{
							info.PutString("Author", "Joe Doe");
						}
					}
					else 
					{
						// Info dict is missing. 
						info = trailer.PutDict("Info");
						info.PutString("Producer", "PDFTron PDFNet");
						info.PutString("Title", "My document");
					}

					// Create a custom inline dictionary within Info dictionary
					Obj custom_dict = info.PutDict("My Direct Dict");

					// Add some key/value pairs
					custom_dict.PutNumber("My Number", 100);

					Obj my_array = custom_dict.PutArray("My Array");

					// Create a custom indirect array within Info dictionary
					Obj custom_array = doc.CreateIndirectArray();	
					info.Put("My Indirect Array", custom_array);
					
					// Create indirect link to root
					custom_array.PushBack(trailer.Get("Root").Value());

					// Embed a custom stream (file my_stream.txt).
					MappedFile embed_file = new MappedFile(input_path + "my_stream.txt");
					FilterReader mystm = new FilterReader(embed_file);
					custom_array.PushBack(doc.CreateIndirectStream(mystm));

					// Save the changes.
					Console.WriteLine("Saving modified test file...");
					doc.Save(output_path + "sdftest_out.pdf", 0, "%PDF-1.4");
				}

				Console.WriteLine("Test completed.");
			}
			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}
			PDFNet.Terminate();
		}
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

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

#include <PDF/PDFNet.h>
#include <SDF/SDFDoc.h>
#include <Filters/MappedFile.h>
#include <Filters/FilterReader.h>
#include <iostream>
#include "../../LicenseKey/CPP/LicenseKey.h"

using namespace std;

using namespace pdftron;
using namespace SDF;
using namespace Filters;

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

int main(int argc, char *argv[])
{
	int ret = 0;
	PDFNet::Initialize(LicenseKey);

	// Relative path to the folder containing test files.
	string input_path =  "../../TestFiles/";
	string output_path = "../../TestFiles/Output/";

	try
	{
		cout << "Opening the test file..." << endl;

		// 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.
		SDFDoc doc((input_path + "fish.pdf").c_str());
		doc.InitSecurityHandler();

		cout << "Modifying info dictionary, adding custom properties, embedding a stream..." << endl;
		Obj trailer = doc.GetTrailer();			// Get the trailer

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

		// Get the Info dictionary. 
		DictIterator itr = trailer.Find("Info");	
		Obj info;
		if (itr.HasNext()) 
		{
			info = itr.Value();
			// Modify 'Producer' entry.
			info.PutString("Producer", "PDFTron PDFNet");

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

		// Create a custom inline dictionary within Info dictionary
		Obj custom_dict = info.PutDict("My Direct Dict");
		custom_dict.PutNumber("My Number", 100);	 // Add some key/value pairs
		custom_dict.PutArray("My Array");

		// Create a custom indirect array within Info dictionary
		Obj custom_array = doc.CreateIndirectArray();	
		info.Put("My Indirect Array", custom_array);	// Add some entries
		
		// Create indirect link to root
		custom_array.PushBack(trailer.Get("Root").Value());

		// Embed a custom stream (file mystream.txt).
		MappedFile embed_file((input_path + "my_stream.txt"));
		FilterReader mystm(embed_file);
		custom_array.PushBack( doc.CreateIndirectStream(mystm) );

		// Save the changes.
		cout << "Saving modified test file..." << endl;
		doc.Save((output_path + "sdftest_out.pdf").c_str(), 0, 0, "%PDF-1.4");

		cout << "Test completed." << endl;
	}
	catch(Common::Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	PDFNet::Terminate();
	return ret;    
}
```

{% endcode %}
{% endtab %}

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

```go
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------

package main
import (
	"fmt"
	. "pdftron"
)

import  "pdftron/Samples/LicenseKey/GO"

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

func main(){
    PDFNetInitialize(PDFTronLicense.Key)
    
    // Relative path to the folder containing the test files.
    inputPath := "../../TestFiles/"
    outputPath := "../../TestFiles/Output/"
    
    fmt.Println("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.
    doc := NewSDFDoc(inputPath + "fish.pdf")
    doc.InitSecurityHandler()
    
    fmt.Println("Modifying info dictionary, adding custom properties, embedding a stream...")
    trailer := doc.GetTrailer()  // Get the trailer
    
    // Now we will change PDF document information properties using SDF API
    
    // Get the Info dictionary
    itr := trailer.Find("Info")
    info := NewObj()
    if itr.HasNext(){
        info = itr.Value()
        // Modify 'Producer' entry
        info.PutString("Producer", "PDFTron PDFNet")
        
        // Read title entry (if it is present)
        itr = info.Find("Author")
        if itr.HasNext(){
		fmt.Println("Author inside")
            oldstr := itr.Value().GetAsPDFText()
            info.PutText("Author", oldstr + "- Modified")
        }else{
            info.PutString("Author", "Me, myself, and I")
		}
    }else{
        // Info dict is missing.
        info = trailer.PutDict("Info")
        info.PutString("Producer", "PDFTron PDFNet")
        info.PutString("Title", "My document")
    }    
    // Create a custom inline dictionary within Info dictionary
    customDict := info.PutDict("My Direct Dict")
    customDict.PutNumber("My Number", 100)     // Add some key/value pairs
    customDict.PutArray("My Array")
    
    // Create a custom indirect array within Info dictionary
    customArray := doc.CreateIndirectArray()
    info.Put("My Indirect Array", customArray)    // Add some entries
    
    // Create indirect link to root
    customArray.PushBack(trailer.Get("Root").Value())
    
    // Embed a custom stream (file mystream.txt).
    embedFile := NewMappedFile(inputPath + "my_stream.txt")
    mystm := NewFilterReader(embedFile)
    customArray.PushBack( doc.CreateIndirectStream(mystm) )
    
    // Save the changes.
    fmt.Println("Saving modified test file...")
    doc.Save(outputPath + "sdftest_out.pdf", uint(0), "%PDF-1.4")
    doc.Close()
    
    PDFNetTerminate()
    fmt.Println("Test Completed")
    
}
```

{% endcode %}
{% endtab %}

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

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

import com.pdftron.pdf.*;
import com.pdftron.sdf.*;
import com.pdftron.filters.*;

// This sample illustrates how to use basic SDF API (also known as Cos) to edit an 
// existing document.
public class SDFTest {
    public static void main(String[] args) {
        PDFNet.initialize(PDFTronLicense.Key());

        // Relative path to the folder containing test files.
        String input_path = "../../TestFiles/";
        String output_path = "../../TestFiles/Output/";

        try {
            System.out.println("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.
            SDFDoc doc = new SDFDoc((input_path + "fish.pdf"));
            doc.initSecurityHandler();

            System.out.println("Modifying info dictionary, adding custom properties, embedding a stream...");
            Obj trailer = doc.getTrailer();            // Get the trailer

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

            // Get the Info dictionary.
            DictIterator itr = trailer.find("Info");
            Obj info;
            if (itr.hasNext()) {
                info = itr.value();
                // Modify 'Producer' entry.
                info.putString("Producer", "PDFTron PDFNet");

                // Read title entry (if it is present)
                itr = info.find("Author");
                if (itr.hasNext()) {
                    String oldstr = itr.value().getAsPDFText();

                    info.putText("Author", oldstr + "- Modified");
                } else {
                    info.putString("Author", "Me, myself, and I");
                }
            } else {
                // Info dict is missing.
                info = trailer.putDict("Info");
                info.putString("Producer", "PDFTron PDFNet");
                info.putString("Title", "My document");
            }

            // Create a custom inline dictionary within Info dictionary
            Obj custom_dict = info.putDict("My Direct Dict");
            custom_dict.putNumber("My Number", 100);     // Add some key/value pairs
            custom_dict.putArray("My Array");

            // Create a custom indirect array within Info dictionary
            Obj custom_array = doc.createIndirectArray();
            info.put("My Indirect Array", custom_array);    // Add some entries

            // Create indirect link to root
            custom_array.pushBack(trailer.get("Root").value());

            // Embed a custom stream (file mystream.txt).
            MappedFile embed_file = new MappedFile(input_path + "my_stream.txt");
            FilterReader mystm = new FilterReader(embed_file);
            custom_array.pushBack(doc.createIndirectStream(mystm));

            // Save the changes.
            System.out.println("Saving modified test file...");
            doc.save(output_path + "sdftest_out.pdf", SDFDoc.SaveMode.NO_FLAGS, null, "%PDF-1.4");
            // output PDF doc
            doc.close();

            System.out.println("Test completed.");
        } catch (Exception e) {
            System.out.println(e);
        }

        PDFNet.terminate();
    }
}
```

{% endcode %}
{% endtab %}

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

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

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

const { PDFNet } = require('@pdftron/pdfnet-node');
const PDFTronLicense = require('../LicenseKey/LicenseKey');

((exports) => {

  exports.runSDFTest = () => {

    const main = async() => {
      // Relative path to the folder containing test files.
      const inputPath = '../TestFiles/';

      try {
        console.log('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.
        const doc = await PDFNet.SDFDoc.createFromFileUString(inputPath + 'fish.pdf');
        doc.initSecurityHandler();
        console.log('Modifying into dictionary, adding custom properties, embedding a stream...');

        const trailer = await doc.getTrailer(); // Get the trailer

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

        // Get the Info dictionary.

        let itr = await trailer.find('Info');
        let info;
        if (await itr.hasNext()) {
          info = await itr.value();
          // Modify 'Producer' entry.
          info.putString('Producer', 'PDFTron PDFNet');

          // read title entry if it is present
          itr = await info.find('Author');
          if (await itr.hasNext()) {
            const itrval = await itr.value();
            const oldstr = await itrval.getAsPDFText();
            info.putText('Author', oldstr + ' - Modified');
          } else {
            info.putString('Author', 'Me, myself, and I');
          }
        } else {
          // Info dict is missing.
          info = await trailer.putDict('Info');
          info.putString('Producer', 'PDFTron PDFNet');
          info.putString('Title', 'My document');
        }

        // Create a custom inline dictionary within Infor dictionary
        const customDict = await info.putDict('My Direct Dict');
        customDict.putNumber('My Number', 100); // Add some key/value pairs
        customDict.putArray('My Array');

        // Create a custom indirect array within Info dictionary
        const customArray = await doc.createIndirectArray();
        info.put('My Indirect Array', customArray); // Add some entries

        // create indirect link to root
        const trailerRoot = await trailer.get('Root');
        customArray.pushBack((await trailerRoot.value()));

        // Embed a custom stream (file mystream.txt).
        const embedFile = await PDFNet.Filter.createMappedFileFromUString(inputPath + 'my_stream.txt');
        const mystm = await PDFNet.FilterReader.create(embedFile);
        const indStream = await doc.createIndirectStreamFromFilter(mystm);
        customArray.pushBack(indStream);

        console.log('Saving modified test file...');
        await doc.save(inputPath + 'Output/sdftest_out.pdf', 0, '%PDF-1.4');
        console.log('Test completed.');
      } catch (err) {
        console.log(err);
      }
    };
    PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function(error){console.log('Error: ' + JSON.stringify(error));}).then(function(){return PDFNet.shutdown();});
  };
  exports.runSDFTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=SDFTest.js
```

{% endcode %}
{% endtab %}

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

```php
<?php
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------
if(file_exists("../../../PDFNetC/Lib/PDFNetPHP.php"))
include("../../../PDFNetC/Lib/PDFNetPHP.php");
include("../../LicenseKey/PHP/LicenseKey.php");

// Relative path to the folder containing the test files.
$input_path = getcwd()."/../../TestFiles/";
$output_path = $input_path."Output/";

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

	PDFNet::Initialize($LicenseKey);
	PDFNet::GetSystemFontList();    // Wait for fonts to be loaded if they haven't already. This is done because PHP can run into errors when shutting down if font loading is still in progress.

	echo nl2br("Opening the test file...\n");

	// 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.
	$doc = new SDFDoc($input_path."fish.pdf");
	$doc->InitSecurityHandler();

	echo nl2br("Modifying info dictionary, adding custom properties, embedding a stream...\n");
	$trailer = $doc->GetTrailer();			// Get the trailer

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

	// Get the Info dictionary. 
	$itr = $trailer->Find("Info");
	if ($itr->HasNext()) 
	{
		$info = $itr->Value();
		// Modify 'Producer' entry.
		$info->PutString("Producer", "PDFTron PDFNet");

		// Read title entry (if it is present)
		$itr = $info->Find("Author"); 
		if ($itr->HasNext()) 
		{
			// Modify 'Producer' entry
			$itr->Value()->PutString("Producer", "PDFTron PDFNet");

			// Read title entry (if it is present)
			$itr = $info->Find("Author");
			if ($itr->HasNext()) {
				$oldstr = $itr->Value()->GetAsPDFTest();
				$info->PutText("Author",$oldstr."- Modified");
			}
			else {
				$info->PutString("Author", "Me, myself, and I");
			}
		}
		else 
		{
			$info->PutString("Author", "Me, myself, and I");
		}
	}
	else 
	{
		// Info dict is missing. 
		$info = $trailer->PutDict("Info");
		$info->PutString("Producer", "PDFTron PDFNet");
		$info->PutString("Title", "My document");
	}

	// Create a custom inline dictionary within Info dictionary
	$custom_dict = $info->PutDict("My Direct Dict");
	$custom_dict->PutNumber("My Number", 100);	 // Add some key/value pairs
	$custom_dict->PutArray("My Array");

	// Create a custom indirect array within Info dictionary
	$custom_array = $doc->CreateIndirectArray();	
	$info->Put("My Indirect Array", $custom_array);	// Add some entries
		
	// Create indirect link to root
	$custom_array->PushBack($trailer->Get("Root")->Value());

	// Embed a custom stream (file mystream.txt).
	$embed_file = new MappedFile($input_path."my_stream.txt");
	$mystm = new FilterReader($embed_file);
	$custom_array->PushBack( $doc->CreateIndirectStream($mystm) );

	// Save the changes.
	echo nl2br("Saving modified test file...\n");
	$doc->Save($output_path."sdftest_out.pdf", 0, "%PDF-1.4");
	$doc->Close();
	PDFNet::Terminate();
	echo nl2br("Test completed.\n");
	
	
?>
```

{% endcode %}
{% endtab %}

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

```ruby
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

require '../../../PDFNetC/Lib/PDFNetRuby'
include PDFNetRuby
require '../../LicenseKey/RUBY/LicenseKey'

$stdout.sync = true

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

	PDFNet.Initialize(PDFTronLicense.Key)
	
	# Relative path to the folder containing the test files.
	input_path = "../../TestFiles/"
	output_path = "../../TestFiles/Output/"
	
	puts "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.
	doc = SDFDoc.new(input_path + "fish.pdf")
	doc.InitSecurityHandler
	
	puts "Modifying info dictionary, adding custom properties, embedding a stream..."
	trailer = doc.GetTrailer  # Get the trailer
	
	# Now we will change PDF document information properties using SDF API
	
	# Get the Info dictionary
	itr = trailer.Find("Info")
	info = Obj.new
	if itr.HasNext
		info = itr.Value
		# Modify 'Producer' entry
		info.PutString("Producer", "PDFTron PDFNet")
		
		# Read title entry (if it is present)
		itr = info.Find("Author")
		if itr.HasNext
			oldstr = itr.Value.GetAsPDFTest
			info.PutText("Author", oldstr + "- Modified")
		else
			info.PutString("Author", "Me, myself, and I")
		end
	else
		# Info dict is missing.
		info = trailer.PutDict("Info")
		info.PutString("Producer", "PDFTron PDFNet")
		info.PutString("Title", "My document")
	end
		
	# Create a custom inline dictionary within Info dictionary
	custom_dict = info.PutDict("My Direct Dict")
	custom_dict.PutNumber("My Number", 100)	 # Add some key/value pairs
	custom_dict.PutArray("My Array")
	
	# Create a custom indirect array within Info dictionary
	custom_array = doc.CreateIndirectArray
	info.Put("My Indirect Array", custom_array)	# Add some entries
	
	# Create indirect link to root
	custom_array.PushBack(trailer.Get("Root").Value)
	
	# Embed a custom stream (file mystream.txt).
	embed_file = MappedFile.new(input_path + "my_stream.txt")
	mystm = FilterReader.new(embed_file)
	custom_array.PushBack( doc.CreateIndirectStream(mystm) )
	
	# Save the changes.
	puts "Saving modified test file..."
	doc.Save(output_path + "sdftest_out.pdf", 0, "%PDF-1.4")
	doc.Close
	PDFNet.Terminate
	puts "Test Completed"
```

{% endcode %}
{% endtab %}

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

```python
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

import site
site.addsitedir("../../../PDFNetC/Lib")
import sys
from PDFNetPython import *

sys.path.append("../../LicenseKey/PYTHON")
from LicenseKey import *


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

def main():
    PDFNet.Initialize(LicenseKey)
    
    # Relative path to the folder containing the test files.
    input_path = "../../TestFiles/"
    output_path = "../../TestFiles/Output/"
    
    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.
    doc = SDFDoc(input_path + "fish.pdf")
    doc.InitSecurityHandler()
    
    print("Modifying info dictionary, adding custom properties, embedding a stream...")
    trailer = doc.GetTrailer()  # Get the trailer
    
    # Now we will change PDF document information properties using SDF API
    
    # Get the Info dictionary
    itr = trailer.Find("Info")
    info = Obj()
    if itr.HasNext():
        info = itr.Value()
        # Modify 'Producer' entry
        info.PutString("Producer", "PDFTron PDFNet")
        
        # Read title entry (if it is present)
        itr = info.Find("Author")
        if itr.HasNext():
            oldstr = itr.Value().GetAsPDFTest()
            info.PutText("Author", oldstr + "- Modified")
        else:
            info.PutString("Author", "Me, myself, and I")
    else:
        # Info dict is missing.
        info = trailer.PutDict("Info")
        info.PutString("Producer", "PDFTron PDFNet")
        info.PutString("Title", "My document")
        
    # Create a custom inline dictionary within Info dictionary
    custom_dict = info.PutDict("My Direct Dict")
    custom_dict.PutNumber("My Number", 100)     # Add some key/value pairs
    custom_dict.PutArray("My Array")
    
    # Create a custom indirect array within Info dictionary
    custom_array = doc.CreateIndirectArray()
    info.Put("My Indirect Array", custom_array)    # Add some entries
    
    # Create indirect link to root
    custom_array.PushBack(trailer.Get("Root").Value())
    
    # Embed a custom stream (file mystream.txt).
    embed_file = MappedFile(input_path + "my_stream.txt")
    mystm = FilterReader(embed_file)
    custom_array.PushBack( doc.CreateIndirectStream(mystm) )
    
    # Save the changes.
    print("Saving modified test file...")
    doc.Save(output_path + "sdftest_out.pdf", 0, "%PDF-1.4")
    doc.Close()
    
    PDFNet.Terminate()
    print("Test Completed")
    
if __name__ == '__main__':
    main()
```

{% endcode %}
{% endtab %}

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

```vb
'
' Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
'

Imports System

Imports pdftron
Imports pdftron.Common
Imports pdftron.Filters
Imports pdftron.SDF
Imports pdftron.PDF

Module SDFTestVB
	Dim pdfNetLoader As PDFNetLoader
	Sub New()
		pdfNetLoader = pdftron.PDFNetLoader.Instance()
	End Sub

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

		PDFNet.Initialize(PDFTronLicense.Key)

		' Relative path to the folder containing test files.
		Dim input_path As String = "../../../../TestFiles/"
		Dim output_path As String = "../../../../TestFiles/Output/"

		Try
			'------------------------------------------------------------------
			Console.WriteLine("-------------------------------------------------")
			Console.WriteLine("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.
			Using doc As SDFDoc = New SDFDoc(input_path + "fish.pdf")
				doc.InitSecurityHandler()

				Console.WriteLine("-------------------------------------------------")
				Console.WriteLine("Modifying info dictionary, adding custom properties, embedding a stream...")

				Dim trailer As Obj = doc.GetTrailer()		   ' Get the trailer

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

				' Get the Info dictionary. 
				Dim itr As DictIterator = trailer.Find("Info")
				Dim info As Obj
				If itr.HasNext() Then
					info = itr.Value()
					' Modify 'Producer' entry.
					info.PutString("Producer", "PDFTron PDFNet")

					' Read title entry (if it is present)
					itr = info.Find("Author")
					If Not itr.HasNext() Then
						info.PutString("Author", "Joe Doe")
					Else
						info.PutString("Author", itr.Value().GetAsPDFText() + "- Modified")
					End If
				Else
					' Info dict is missing. 
					info = trailer.PutDict("Info")
					info.PutString("Producer", "PDFTron PDFNet")
					info.PutString("Title", "My document")
				End If


				' Create a custom inline dictionary within Info dictionary
				Dim custom_dict As Obj = info.PutDict("My Direct Dict")

				' Add some key/value pairs
				custom_dict.PutNumber("My Number", 100)
				Dim my_array As Obj = custom_dict.PutArray("My Array")

				' Create a custom indirect array within Info dictionary
				Dim custom_array As Obj = doc.CreateIndirectArray()
				info.Put("My Indirect Array", custom_array)

				' Create indirect link to root
				custom_array.PushBack(trailer.Get("Root").Value())

				' Embed a custom stream (file my_stream.txt).
				Dim embed_file As MappedFile = New MappedFile(input_path + "my_stream.txt")
				Dim mystm As FilterReader = New FilterReader(embed_file)
				custom_array.PushBack(doc.CreateIndirectStream(mystm))

				' Save the changes.
				Console.WriteLine("Saving modified test file...")
				doc.Save(output_path + "sdftest_out.pdf", 0, "%PDF-1.4")

				Console.WriteLine("Done. Result saved in sdftest_out.pdf")
			End Using
		Catch ex As PDFNetException
			Console.WriteLine(ex.Message)
		Catch ex As Exception
			MsgBox(ex.Message)
		End Try
		PDFNet.Terminate()
	End Sub
End Module
```

{% 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/core/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.
