How do I draw a rectangle around each word in a PDF, when those words are rotated?

Question:
I want to draw a rectangle around the results of Text Extractor, but it is not working when text is rotated. Also, it on some documents the rectangles are displaced from the correct position (there is no rotation anywhere).

Answer:
Below is the simplest way to operate on words in a PDF, and in this case, draw a rectangle around each word. The code below work on any page which might happen to have rotation and/or a displaced media/crop box (which essentially moves the origin).

using (PDFDoc doc = new PDFDoc(@"your.pdf"))
using (TextExtractor txt = new TextExtractor())
using (ElementBuilder builder = new ElementBuilder())
using (ElementWriter writer = new ElementWriter())
{
doc.InitSecurityHandler();
//////////////////////////////////////////////////////////////////////////////////
// Since TextExtractor returns coordinates in User Space (also known as Page
// coordinates), we want to turn off ElementWriters default behaviour, which is
// to apply Page.GetDefaultMatrix().Inverse().
// In other words, we can ignore any page rotation or media/crop box displacement.
const bool page_coord_sys = false;
//////////////////////////////////////////////////////////////////////////////////
TextExtractor.Line line;
TextExtractor.Word word;
PageIterator itr;
for (itr = doc.GetPageIterator(); itr.HasNext(); itr.Next())
{
Page page = itr.Current();
writer.Begin(page, ElementWriter.WriteMode.e_overlay, page_coord_sys);
txt.Begin(page);
for (line = txt.GetFirstLine(); line.IsValid(); line = line.GetNextLine())
{
for (word = line.GetFirstWord(); word.IsValid(); word = word.GetNextWord())
{
double[] quad = word.GetQuad();
if (quad.Length == 8)
{
builder.PathBegin();
builder.MoveTo(quad[0], quad[1]);
builder.LineTo(quad[2], quad[3]);
builder.LineTo(quad[4], quad[5]);
builder.LineTo(quad[6], quad[7]);
builder.ClosePath();
Element element = builder.PathEnd();
element.SetPathStroke(true);
GState gs = element.GetGState();
gs.SetStrokeColorSpace(ColorSpace.CreateDeviceRGB());
gs.SetStrokeColor(new ColorPt(1, 0, 1));
writer.WriteElement(element);
}
}
}
writer.End();
}
}