Why is Form XObject not positioned correctly after editing PDF page content?

Q:

We have encountered an issue when editing page content that invokes a Form XObject. We’ve noticed that if we simply iterate through all page elements (including Form XObjects by using ElementReader.FormBegin()) and write them back to the page as-is (using ElementReader/Writer with WriteMode.e_replacement), the Form XObject content is being “flattened” (i.e. copied into the page content stream). In the case where the current transformation matrix is not the Identity when invoking the Form XObject, that transformation is being lost. This results in the content from the Form XObject no longer being positioned properly. We have a few questions regarding this behaviour:

  1. Is it by design that Form XObjects are being flattened into the page content? We can understand why you might want to do this to protect the user from unknowingly modifying the appearance of many pages that all invoke the same Form XObject, but in our case that is the desired behaviour. Flattening the Form XObject in our case simply results in redundant data on every page that invokes the same Form XObject, increasing the total PDF file size.

a) If it is by design, should we be separately iterating through Form XObjects to edit them rather than doing it through ElementReader.FormBegin(), or have you considered adding a setting that controls whether Form XObjects get flattened vs edited in place?

b) If it is by design, can you confirm that the loss of the transformation matrix is a bug?

Please see the following sample code.

static void Main(string[] args)

{

PDFNet.Initialize();

string input = @“C:\input.pdf”;

string output = @“C:\output.pdf”;

using (PDFDoc pdf = new PDFDoc(input))

using (ElementBuilder elementBuilder = new ElementBuilder())

using (ElementReader elementReader = new ElementReader())

using (ElementWriter elementWriter = new ElementWriter()) {

for (PageIterator itrPage = pdf.GetPageIterator(); itrPage.HasNext(); itrPage.Next()) {

Page page = itrPage.Current();

elementReader.Begin(page);

elementWriter.Begin(page, ElementWriter.WriteMode.e_replacement, false);

ProcessElements(elementReader, elementWriter);

elementWriter.End();

elementReader.End();

}

pdf.Save(output, SDFDoc.SaveOptions.e_remove_unused);

}

}

private static void ProcessElements(ElementReader elementReader, ElementWriter elementWriter)

{

Element element;

while ((element = elementReader.Next()) != null) {

switch (element.GetType()) {

case Element.Type.e_form:

elementReader.FormBegin();

ProcessElements(elementReader, elementWriter);

elementReader.End();

break;

}

elementWriter.WriteElement(element);

}

}

A:

With ElementReader/Writer you can choose whether or not you want to flatten form XObjects.

Actually you can flatten forms while preserving Forms matrix (as described here https://groups.google.com/d/msg/pdfnet-sdk/85uqFiZl_rw/S5WjKJmqBfIJ), but it is usually a better idea to preserve forms (since flattening may increase file size and may also interfere with patterns).

Attached is a version of ElementEdit sample showing how to do this.