How do I deal with Form XObjects when editing a PDF page?

181 views
Skip to first unread message

Support

unread,
Oct 28, 2009, 8:35:25 PM10/28/09
to PDFTron PDFNet SDK
Q: We need to change the color of text in a given area on a PDF page.
The code (see attached) works fine in most cases but not when it
encounters a form element that has been scaled. This occurs because I
shrink the page content to fit margins by creating a new page,
creating a scaled form (see code below) and then writing the form to
the new page. At some point later, I execute the attached code to
change the text color. This is done the typical way of reading
elements from the original page and writing them to the new page and
changing the color as I go. The problem is that the resulting page no
longer has the contents scaled. How do I account for scaling when
writing elements (not just text) to the new page?

private void SetTextColor(PDFRectArray rectarray, ElementReader
reader, ElementWriter writer, ElementBuilder builder, ColorPt colorpt,
int iMatch)
{
Element element;
while ((element = reader.Next()) != null)
{
switch (element.GetType())
{
case Element.Type.e_text:
Rect rectText = new Rect();
element.GetBBox(rectText);

// See if this text matches any that we want to change
if (IsRectMatched(rectarray, rectText, iMatch))
{
// Set text color
GState gs = element.GetGState();
gs.SetFillColorSpace(ColorSpace.CreateDeviceRGB());
gs.SetFillColor(colorpt);
}
writer.WriteElement(element);
break;

case Element.Type.e_form:
reader.FormBegin();
SetTextColor(rectarray, reader, writer, builder, colorpt,
iMatch);
reader.End();
break;

default:
writer.WriteElement(element);
break;
}
}
}


// Code used to place the page on another page (used for scaling...)
Element element = builder.CreateForm(m_page, m_doc);
Matrix2D matrix = new Matrix2D(dblScale, 0, 0, dblScale, dblX, dblY);
element.GetGState().SetTransform(matrix);
writer.WritePlacedElement(element);

----------------
A: Based on your code it seems that you would like to flatten Form
XObject (Element.Type.e_form) elements. In this case you need to save
the graphics state before opening form xobject’s display list, account
for the matrix in xobject, process form (as before), and restore the
graphics state to previous value. This is illustrated in the following
snippet (also attached):

case Element.Type.e_form:
// Save GState ...
Element e = builder.CreateGroupBegin();

// account for the matrix in xobject
Matrix2D form_mtx = element.GetGState().GetTransform();
Obj m = element.GetXObject().FindObj("Matrix");
if (m != null) form_mtx.Concat(m.GetAt(0).GetNumber(),
m.GetAt(1).GetNumber(),
m.GetAt(2).GetNumber(),
m.GetAt(3).GetNumber(),
m.GetAt(4).GetNumber(),
m.GetAt(5).GetNumber());
e.GetGState().SetTransform(form_mtx);
writer.WriteElement(e);

// Obj bbox = element.GetXObject().FindObj("BBox");
// if (bbox != null) {
// TODO: you may need to transform the clip using
form_mtx...
// Element clip = builder.CreateRect(new Rect(bbox));
// clip.SetClipPath(true); clip.SetFillPath(false);
clip.SetStrokePath(false);
// writer.WriteElement(cliprect);
//}

reader.FormBegin();
SetTextColor(reader, writer, builder, colorpt);

// Restore the graphics state
writer.WriteElement(builder.CreateGroupEnd());
reader.End();
break;


-----------------

Full sample:

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

namespace ElementEditTestCS
{
/// <summary>
/// The sample code shows how to edit the page display list and how
to modify graphics state
/// attributes on existing Elements. In particular the sample changes
text color to red.
/// </summary>
///
class ElementEditTest
{
static void SetTextColor(ElementReader reader, ElementWriter writer,
ElementBuilder builder, ColorPt colorpt)
{
Element element;
while ((element = reader.Next()) != null)
{
switch (element.GetType())
{
case Element.Type.e_text:
// Rect rectText = new Rect();
// element.GetBBox(rectText);

// See if this text matches any that we want to change
if (true) // IsRectMatched(rectarray, rectText, iMatch))
{
// Set text color
GState gs = element.GetGState();
gs.SetFillColorSpace(ColorSpace.CreateDeviceRGB());
gs.SetFillColor(colorpt);
}
writer.WriteElement(element);
break;

case Element.Type.e_form:
// Save GState ...
Element e = builder.CreateGroupBegin();
Matrix2D form_mtx = element.GetGState().GetTransform();
Obj m = element.GetXObject().FindObj("Matrix");
if (m != null) form_mtx.Concat(m.GetAt(0).GetNumber(), m.GetAt
(1).GetNumber(), m.GetAt(2).GetNumber(), m.GetAt(3).GetNumber(),
m.GetAt(4).GetNumber(), m.GetAt(5).GetNumber());
e.GetGState().SetTransform(form_mtx);
writer.WriteElement(e);

// Obj bbox = element.GetXObject().FindObj("BBox");
// if (bbox != null) {
// TODO: you may need to transform the clip using form_mtx...
// Element clip = builder.CreateRect(new Rect(bbox));
// clip.SetClipPath(true); clip.SetFillPath(false);
clip.SetStrokePath(false);
// writer.WriteElement(cliprect);
//}

reader.FormBegin();
SetTextColor(reader, writer, builder, colorpt);

// Restore the graphics state
writer.WriteElement(builder.CreateGroupEnd());
reader.End();
break;
default:
writer.WriteElement(element);
break;
}
}
}

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
PDFNet.Initialize();

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

try
{
Console.WriteLine
("-------------------------------------------------");

// Open the test file
Console.WriteLine("Opening the input file...");
PDFDoc doc = new PDFDoc(input_path + "in.pdf");
doc.InitSecurityHandler();

int num_pages = doc.GetPageCount();

ElementWriter writer = new ElementWriter();
ElementReader reader = new ElementReader();
ElementBuilder builder = new ElementBuilder();

for (int i = 1; i <= num_pages; ++i)
{
Page page = doc.GetPage(1);
reader.Begin(page);

Page new_page = doc.PageCreate();
doc.PagePushBack(new_page);

writer.Begin(new_page);

SetTextColor(reader, writer, builder, new ColorPt(1, 0, 0));

writer.End();
reader.End();

new_page.SetMediaBox(page.GetCropBox());
doc.PageRemove(doc.GetPageIterator(1)); // Remove the old page
}

writer.Dispose();
reader.Dispose();
builder.Dispose();

doc.Save(output_path + "out.pdf",
SDFDoc.SaveOptions.e_remove_unused);
doc.Close();
}
catch (PDFNetException e)
{
Console.WriteLine(e.Message);
}
}
}
}
Reply all
Reply to author
Forward
0 new messages