How to add custom data to an Element in a page stream?

Question:

I would like to add some custom data to an element in a page content stream. How can I do that?

Answer:

Yes, this is possible taking advantage of the Marked Content feature of the PDF standard, which allows for adding primitive data such as strings or numbers to the page content stream. You would wrap this data around the target element, rather than too.

So the following code adds Marked Content to some a text run.

string myKey = "customKey";
string myStringValue = "customValue";
std::stringstream ss;
ss << "/Artifact << /" << myKey << " (" << myStringValue << ") >> BDC "; // strings are enclosed in paranthesis, so additional care needs to be taken for string beyond ASCII.
writer.WriteString(ss.str().c_str());

element = eb.CreateTextBegin(Font::Create(doc, Font::e_times_roman), 12);
// ... write text
writer.WriteElement(eb.CreateTextEnd());

writer.WriteString("EMC "); // close your marked content

Then later you can retrieve using our ElementReader sample as starting point.

for (Element element=reader.Next(); element; element = reader.Next()) // Read page contents
{
switch (element.GetType())
{
case Element::e_marked_content_begin:
case Element::e_marked_content_point:
{
SDF::Obj obj = element.GetMCPropertyDict();
if (obj.IsValid())
{
SDF::Obj myValue = obj.FindObj("customKey");
if (myValue.IsValid() && myValue.IsString())
{
UString str = myValue.GetAsPDFText();
cout << str.ConvertToUtf8() << "\n";
}
}
}
break;

It is also possible to connect the Marked Content to data to in the PDF cross reference table, either officially using Tagged PDF features, or you can do manually. See here for example code.