Q: We produce a series of PDF documents which contain some machine
readable text on them. Neither of these fonts are available on the
workstations of users to whom these PDFs are distributed. The tool
that we’re using to actually generate the PDFs in the first place does
not support embedding fonts. So, my desire is to simply use the
pdftron sdk (http://www.pdftron.com/pdfnet/) to open an existing PDF,
and then embed the fonts. Ideally, we would introspect the file to see
what fonts are in use, and then embed a subset of the fonts on that
list. (Some of the fonts we know will be available on all of the
workstations, and we wouldn’t want to embed those for file size
reasons).
A: You could use PDFNet SDK to embed fonts. As a starting point you
would need to take a look at the type of font you are dealing with as
well as the PDF file generated using a third party tool. There are
several ways this functionality can be implemented using PDFNet. For
example, assuming that the tool generates text that reference a simple
true type font with WinAnsiiEncoding you could embed the font along
the following lines:
// C# Pseudocode
using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;
…
for (PageIterator itr = doc.GetPageIterator(); itr.HasNext(); itr.Next
())
{
Page pg = itr.Current();
Obj res = pg.GetResources();
if (res == null) continue;
Obj fonts = res.FindObj(“Font”);
if (fonts == null) continue;
for (DictIterator i = fonts.GetDictIterator(); i.HasNext(); i.Next
()) {
Font font = new Font(itr.Value());
if (font.GetType() != pdftron.PDF.Font.Type.e_TrueType) continue;
string fname = font.GetName();
if (fname != “MyFont”) continue;
// … we encountered ‘MyFont’, so embed the font…
// 1) Obtain or create a font descriptor
Obj fd = font.GetDescriptor();
if (fd == null) fd = font.GetSDFObj().PutDict("FontDescriptor");
if (fd.FindObj("FontFile2") != null) continue;
// 2) Embed the font.
MappedFile file = new MappedFile("my.ttf");
FilterReader reader = new FilterReader(file);
Obj stm = doc.CreateIndirectStream(reader);
// To embed Flate compressed stream use:
// Obj stm = doc.CreateIndirectStream(reader, new FlateEncode
(null));
stm.PutNumber(“Length1”, file.FileSize());
fd.Put(“FontFile2”, stm);
file.Close();
}
}
There are many other possible variants and optimizations to the above
technique (e.g. in case there are many font instances which are not
sharing the same font descriptor you can make sure that the font is
embedded only once for the entire document etc). Another approach it
to change font property in the graphics state while enumerating PDF
content (similar to ElementEdit sample - http://www.pdftron.com/pdfnet/samplecode.html#ElementEdit).
This technique is more invasive to the document and shouldn’t be used
unless you really need to edit content on a PDF page.