Question:
I want to create a FreeText annotation, where the text and border are opaque (solid), but the background color is semi-transparent. There only seems to be a single Opacity setting for annotations, which gets applied to the entire annotation. How can I accomplish this?
Answer:
Yes, the PDF standard just supports a single opacity for annotations. To make your own adjustments to opacity, you would do the following.
- Set the opacity on the annotation normally.
- Call RefreshAppearance to generate the default appearance.
- Run the following code, which will make the adjustments for you.
// Generation default appearance, and apply custom opacity
static void SetAppearance(pdftron.PDF.Annots.Markup annot, PDFDoc doc)
{
annot.RefreshAppearance(); // create default
Obj app_stm = annot.GetAppearance(); // generate default appearance that will then get modified
ElementBuilder builder = new ElementBuilder();
ElementWriter writer = new ElementWriter();
ElementReader reader = new ElementReader();
reader.Begin(app_stm);
writer.Begin(doc);
//... read from reader, writing everything to the writer, and add your new content
System.Collections.Generic.List<int> visited = new System.Collections.Generic.List<int>();
ProcessElements(reader, writer, visited, annot);
Obj appearance_stream = writer.End();
appearance_stream.Put("BBox", app_stm.FindObj("BBox"));
annot.SetAppearance(appearance_stream);
}
static void ProcessElements(ElementReader reader, ElementWriter writer, System.Collections.Generic.List<int> visited, pdftron.PDF.Annots.Markup markup)
{
Element element;
while ((element = reader.Next()) != null) // Read page contents
{
switch (element.GetType())
{
case Element.Type.e_path: // Solid stroke, and transparent fill
{
GState gs = element.GetGState();
gs.SetStrokeOpacity(1.0);
gs.SetFillOpacity(markup.GetOpacity());
writer.WriteElement(element);
break;
}
case Element.Type.e_text: // solid stroke and fill (text is normally filled)
{
GState gs = element.GetGState();
gs.SetStrokeOpacity(1.0);
gs.SetFillOpacity(1.0);
writer.WriteElement(element);
break;
}
case Element.Type.e_form:
{
writer.WriteElement(element); // write Form XObject reference to current stream
Obj form_obj = element.GetXObject();
if (!visited.Contains(form_obj.GetObjNum())) // if this XObject has not been processed
{
// recursively process the Form XObject
visited.Add(form_obj.GetObjNum());
ElementWriter new_writer = new ElementWriter();
reader.FormBegin();
new_writer.Begin(form_obj, true);
ProcessElements(reader, new_writer, visited, markup);
new_writer.End();
reader.End();
}
break;
}
default:
writer.WriteElement(element);
break;
}
}
}