How can I create a annotation that duplicates elements from the underlying page?

Question:
I would like to create a type of annotation that would duplicate the page contents within a given rectangle selection.

Answer:
This can be achieved using the RubberStamp annotation tool. First, the elements from the page must be written into a Form XObject after which a selection bounding box can be applied to effectively crop the elements before the object is passed to the RubberStamp annotation. This implementation also colors the contents of the annotation as desired.

`

private pdftron.PDF.Annots.RubberStamp CreateAndFillStamp(PDFDoc doc, Page page, Rect selectBBox, ColorPt color)
{
using (ElementBuilder eb = new ElementBuilder())
using (ElementWriter writer = new ElementWriter())
using (ElementReader reader = new ElementReader())
{
// Set the page rotation to zero to ensure any transform data is easier to deal with and store the
// original rotation.
Page.Rotate rotation = page.GetRotation();
page.SetRotation(0);

// Write the page elements into a new Obj added to the doc and color them as desired
XSet visited = new XSet();
visited.Add(page.GetSDFObj().GetObjNum());
reader.Begin(page);
writer.Begin(doc);
ProcessElements(reader, writer, eb, visited, color);
Obj appearanceStream = writer.End();
reader.End();

// Set the BBox on our Obj to effectively crop the elements
appearanceStream.PutRect(“BBox”, selectBBox.x1, selectBBox.y1, selectBBox.x2, selectBBox.y2);

// Create our stamp annotation and set it to use the XRef Obj we created
pdftron.PDF.Annots.RubberStamp stamp = pdftron.PDF.Annots.RubberStamp.Create(doc, new Rect(selectBBox.x1, selectBBox.y1, selectBBox.x2, selectBBox.y2));
stamp.SetAppearance(appearanceStream);
page.AnnotPushBack(stamp);

// Finally return the page to it’s original orientation
page.SetRotation(rotation);

return stamp;
}
}

private void ProcessElements(ElementReader reader, ElementWriter writer, ElementBuilder builder, XSet visited, ColorPt color)
{
ColorSpace RGBSpace = ColorSpace.CreateDeviceRGB();
Element element;
while ((element = reader.Next()) != null)
{
Element.Type elemType = element.GetType();
switch (elemType)
{
case Element.Type.e_image:
case Element.Type.e_inline_image:
{
writer.WriteElement(element);

// Create a rectangle ontop of the image that will allow us to
// change the blend mode. This will effectively colorize the image.
var elem = builder.CreateRect(0.0, 0.0, 1.0, 1.0);
elem.SetPathFill(true);
elem.SetPathStroke(false);

var gs = elem.GetGState();
gs.SetFillColorSpace(RGBSpace);
gs.SetFillColor(color);
gs.SetBlendMode(GState.BlendMode.e_bl_screen);
writer.WritePlacedElement(elem);
break;
}
case Element.Type.e_text:
{
// Set text elements to our desired color.
Rect bbox = new Rect();
element.GetBBox(bbox);
{
GState gs = element.GetGState();
gs.SetFillColorSpace(RGBSpace);
gs.SetFillColor(color);
writer.WriteElement(element);
}
break;
}
case Element.Type.e_path:
{
// Set path elements to our desired color.
Rect bbox = new Rect();
element.GetBBox(bbox);
{
GState gstate = element.GetGState();
gstate.SetStrokeOpacity(1.0);
gstate.SetStrokeColorSpace(RGBSpace);
gstate.SetStrokeColor(color);
gstate.SetFillColorSpace(RGBSpace);
gstate.SetFillColor(color);

writer.WriteElement(element);
}
break;
}
case Element.Type.e_form:
{
// Write the form element
writer.WriteElement(element);
Obj form_obj = element.GetXObject();

// Recurse to children if not already written
if (!visited.Contains(form_obj.GetObjNum()))
{
visited.Add(form_obj.GetObjNum());
ElementWriter new_writer = new ElementWriter();

reader.FormBegin();
new_writer.Begin(form_obj, true);
ProcessElements(reader, writer, builder, visited, color);
new_writer.End();
reader.End();
}

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

`