How do I embed a file in a PDF document when I only have a stream?

Question:
Is it possible to embed a file in a PDF document when I only have a stream?

Answer:
Yes it is possible.

All file streams are based on the SDF/COS Object Model and that includes embedded files. If you have access to the stream of a file but not the file on disk you can embed that file within a PDF by creating the proper Obj objects and inserting them into the document.

The following C# pseudo-code mimics the sample shown here under the section How to Embed an XML in a PDF. The difference is that instead of using a file path to create a FileSpec object it mimics the FileSpec object by creating matching low-level Obj objects.

Be sure to replace CreateYourFileStream pseudo-code with your actual code to generate/retrieve your FileStream.

byte[] doc_bytes_invoice_added = null;
using (PDFDoc in_doc = new PDFDoc(input_path + "fish.pdf"))
{
in_doc.InitSecurityHandler();

NameTree files = NameTree.Create(in_doc, "EmbeddedFiles");

// Manually mimic the FileSpec object.
Obj fsDict = doc.CreateIndirectDict();

fsDict.PutName("AFRelationship", "Alternative");
fsDict.PutString("F", input_path + "ZUGFeRD-invoice.xml");
fsDict.PutString("UF", input_path + "ZUGFeRD-invoice.xml");
fsDict.PutText("Desc", "Your file description here");

// Replace 'CreateYourFileStream()' with the actual code to create the stream.
FileStream fs = CreateYourFileStream();

// Create a new MemoryFilter to add your filestream to the document
pdftron.Filters.MemoryFilter memoryFilter = new pdftron.Filters.MemoryFilter((int)fs.Length, false); // false = sink
pdftron.Filters.FilterWriter writer = new pdftron.Filters.FilterWriter(memoryFilter); // helper filter to allow us to write to buffer

int bytes_read = 0;

__byte[] buf = new byte[10 * 1024]; // 10 MiB buffer__
do
{
Console.WriteLine(bytes_read);
bytes_read = fs.Read(buf, 0, buf.Length);
if (bytes_read < buf.Length)
{
for (int i = 0; i < bytes_read; i++)
{
writer.WriteUChar(buf[i]);
}
}
else
{
writer.WriteBuffer(buf);
}
} while (bytes_read > 0);

writer.Flush();

// switch from sink to source
memoryFilter.SetAsInputFilter();

FilterReader fr = new FilterReader(memoryFilter);

// Add a new dict to the main object that will contain the file stream
Obj fsObj = fsDict.PutDict("EF");
Obj fileStreamObj = doc.CreateIndirectStream(fr);

// Add the file stream
fsObj.Put("F", fileStreamObj);

byte[] file1_name = System.Text.Encoding.UTF8.GetBytes("ZUGFeRD-invoice.xml");
Obj collection = in_doc.GetRoot().FindObj("Collection");

if (collection == null) collection = in_doc.GetRoot().PutDict("Collection");

collection.PutName("View", "T");
doc_bytes_invoice_added = in_doc.Save(SDFDoc.SaveOptions.e_incremental);
}