Easiest way to create a highlight that starts and ends on selected words, not on the entire Rect ?

Hi,

My team is working on a cross-platform app that allows sharing of highlights and annotations made on PDF docs, across multiple platforms. This is how I’ve been doing it so far:

private ToolManager _pdfToolManager;

private PDFViewWPF _pdfViewer;

private Tool _highlightTool;

private Annot _newAnnot;

private Boolean _newAnnotationAdded;

.
.
.

public void LoadToolManager()
{
_pdfToolManager = new ToolManager(_pdfViewer);
_pdfToolManager.IsEnabled = true;
_pdfToolManager.AnnotationAdded += PdfToolManager_AnnotationAdded;

//Turn on highlighting…it’s always available.
ListenForHighlights();
PdfViewer.OnSetDoc += PdfViewer_OnSetDoc;

}

private void ListenForHighlights()
{

_highlightTool = _pdfToolManager.CreateTool(pdftron.PDF.Tools.ToolManager.ToolType.e_text_highlight, null, true);

_pdfViewer.MouseLeftButtonUp += PdfViewer_MouseLeftButtonUp;
_pdfViewer.MouseLeftButtonDown += PdfViewer_MouseLeftButtonDown;
_pdfViewer.MouseDoubleClick += PdfViewer_MouseDoubleClick;
_pdfViewer.CurrentPageNumberChanged += PdfViewer_CurrentPageNumberChanged;

}

private void PdfToolManager_AnnotationAdded(Annot newAnnot)
{
_newAnnot = newAnnot; //there is a single annot for the highlight (x1, y1, x2, y2)
_newAnnotationAdded = true;
}

This all works fine, and I was creating a capturing highlights based on the entire Rect area of the mouse down/up area (which is recorded as x1, y1, x2, y2). A member of the Android team is now telling this won’t do because if the user starts with a sentence that begins in the middle of one line, and ends in the middle of a line, 3 lines down, then a singular Rect is created for the total 4 lines, and includes text not specifically selected by the user (and outside of the sentence selected), it just creates one large rect for the entire x/y area.

So I have to now rethink my approach…

He suggested I look at the “SelectText” method of the ToolManager, which will deliver separate Rects for each line, which equates to an array of Rects for a single highlight…thus allowing the first and last Rects to only capture the text the user intended (the start and ends of the sentence) and ignore everything else on those respective lines.

Any samples on the easiest way to implement this ? I’m hoping to not have to re-write the entire thing…but just change which tool I’m using, and have a way to capture the created Rects after the mouse button comes up. All highlights created are saved to a database, and shared across devices…and our app loads them back up again when the doc is loaded into the PDFviewer.

I’m using .Net, C#, PDFViewWPF

This is an example similar to what I’m describing. The approach above will capture everything in the outlined dotted box…when what I really want is just what was actually highlighted in yellow !

Thanks,

Barry

Hi Barry,

Provided I understand you correctly, you want regular text selection (like the TextSelectStructural tool provides, but you want to ensure that it is selecting whole words? So, if the selection starts or ends half way through a word, you want the whole one. If this is not the case, please let us know. I attached 2 markers on your image, and so imagine this is where I clicked and dragged to.

To achieve this, you can first do selection in 2 steps. First, you do a rectangular selection (which will select every word covered by your rectangle) and then you take the first and last quad and use those coordinates for a structural text selection. I’ve modified the Select function in the TextSelectStructural.cs file so that it now always includes the whole word of what was selected. The code is below, so if you replace the original function with this, you will get the prescribed behaviour.

The general idea is to first select text as normal. Then find the whole first and whole last word. You then redo your selection using the left side of the first word and the right edge of the last word as boundaries.

protected void Select(UIPoint p1, UIPoint p2)
{
bool success = false;
try
{
double sx = mPDFView.GetHScrollPos();
double sy = mPDFView.GetVScrollPos();

// first, do a regular selection.
mPDFView.SetTextSelectionMode(PDFViewWPF.TextSelectionMode.e_structural);
mPDFView.Select(p1.X - sx, p1.Y - sy, p2.X - sx, p2.Y - sy);

int bp = mPDFView.GetSelectionBeginPage();
int ep = mPDFView.GetSelectionEndPage();
if (bp != ep)
{
sx = 25;
}

if (ep == -1)
{
return;
}

PDFViewWPF.Selection sel1 = mPDFView.GetSelection(bp);
PDFViewWPF.Selection sel2 = mPDFView.GetSelection(ep);

// first point of first quad
double[] quads = sel1.GetQuads();
if (quads.Length == 0)
{
return;
}
double x1 = quads[0];
double y1 = quads[1];
mPDFView.ConvPagePtToScreenPt(ref x1, ref y1, bp);

// third point of last quad
quads = sel2.GetQuads();
if (quads.Length == 0)
{
return;
}
double x2 = quads[quads.Length - 4];
double y2 = quads[quads.Length - 3];
mPDFView.ConvPagePtToScreenPt(ref x2, ref y2, ep);

// Now, do a rectangular selection around the first point (this will get the entire word)
mPDFView.SetTextSelectionMode(PDFViewWPF.TextSelectionMode.e_rectangular);
mPDFView.Select(x1, y1, x1 + 0.05, y1 - 0.05);
if (!mPDFView.HasSelectionOnPage(bp))
{
return;
}
sel1 = mPDFView.GetSelection(bp);
quads = sel1.GetQuads();
if (quads.Length == 0)
{
return;
}
x1 = quads[0];
y1 = quads[1];
mPDFView.ConvPagePtToScreenPt(ref x1, ref y1, bp);

// Now, do a rectangular selection around the first point
mPDFView.SetTextSelectionMode(PDFViewWPF.TextSelectionMode.e_rectangular);
mPDFView.Select(x2, y2, x2 - 0.05, y2 + 0.05);
if (!mPDFView.HasSelectionOnPage(ep))
{
return;
}
sel2 = mPDFView.GetSelection(ep);
quads = sel2.GetQuads();
if (quads.Length == 0)
{
return;
}
x2 = quads[quads.Length - 4];
y2 = quads[quads.Length - 3];
mPDFView.ConvPagePtToScreenPt(ref x2, ref y2, ep);

mPDFView.SetTextSelectionMode(PDFViewWPF.TextSelectionMode.e_structural);
mPDFView.Select(x1, y1, x2, y2);

success = true;
}
finally
{
if (!success)
{
mPDFView.ClearSelection();
}
}
}

Again, if this is not what you were looking for, please let us know.

Best Regards,
Tomas Hofmann