[英]JPedal - Highlight word at a point in a PDF
I want to implement a feature which allows the user to double-click to highlight a word in a PDF document using the JPedal library. 我想实现一个功能,该功能允许用户双击以使用JPedal库突出显示PDF文档中的单词。 This would be trivial to do if I could get a word's bounding rectangle and see if the MouseEvent location falls within it;
如果我可以得到一个单词的边界矩形并查看MouseEvent位置是否在其中,这将是微不足道的。 the following snippet demonstrates how to highlight a region:
以下代码段演示了如何突出显示区域:
private void highlightText() {
Rectangle highlightRectangle = new Rectangle(firstPoint.x, firstPoint.y,
secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y);
pdfDecoder.getTextLines().addHighlights(new Rectangle[]{highlightRectangle}, false, currentPage);
pdfDecoder.repaint();
}
I can only find plaintext extraction examples in the documentation however. 但是,我只能在文档中找到明文提取示例。
After looking at Mark's examples I managed to get it working. 在查看了Mark的示例后,我设法使其正常运行。 There are a few quirks so I'll explain how it all works in case it helps someone else.
有一些怪癖,所以我会解释一下这一切如何工作,以防它对其他人有帮助。 The key method is
extractTextAsWordlist
, which returns a List<String>
of the form {word1, w1_x1, w1_y1, w1_x2, w1_y2, word2, w2_x1, ...}
when given a region to extract from. 关键方法是
extractTextAsWordlist
,当给定要提取的区域时,它以{word1, w1_x1, w1_y1, w1_x2, w1_y2, word2, w2_x1, ...}
的形式返回List<String>
。 Step-by-step instructions are listed below. 下面列出了分步说明。
Firstly, you need to transform the MouseEvent
's Component/screen coordinates to PDF page coordinates and correct for scaling: 首先,您需要将
MouseEvent
“组件/屏幕”坐标转换为PDF页面坐标并进行缩放:
/**
* Transforms Component coordinates to page coordinates, correcting for
* scaling and panning.
*
* @param x Component x-coordinate
* @param y Component y-coordinate
* @return Point on the PDF page
*/
private Point getPageCoordinates(int x, int y) {
float scaling = pdfDecoder.getScaling();
int x_offset = ((pdfDecoder.getWidth() - pdfDecoder.getPDFWidth()) / 2);
int y_offset = pdfDecoder.getPDFHeight();
int correctedX = (int)((x - x_offset + viewportOffset.x) / scaling);
int correctedY = (int)((y_offset - (y + viewportOffset.y)) / scaling);
return new Point(correctedX, correctedY);
}
Next, create a box to scan for text. 接下来,创建一个框以扫描文本。 I chose to make this the width of the page and +/- 20 page units vertically (this is a fairly arbitrary number), centered at the
MouseEvent
: 我选择将其宽度设置为垂直于
MouseEvent
的页面宽度和+/- 20个页面单位(这是一个相当任意的数字):
/**
* Scans for all the words located with in a box the width of the page and
* 40 points high, centered at the supplied point.
*
* @param p Point to centre the scan box around
* @return A List of words within the scan box
* @throws PdfException
*/
private List<String> scanForWords(Point p) throws PdfException {
List<String> result = Collections.emptyList();
if (pdfDecoder.getlastPageDecoded() > 0) {
PdfGroupingAlgorithms currentGrouping = pdfDecoder.getGroupingObject();
PdfPageData currentPageData = pdfDecoder.getPdfPageData();
int x1 = currentPageData.getMediaBoxX(currentPage);
int x2 = currentPageData.getMediaBoxWidth(currentPage) + x1;
int y1 = p.y + 20;
int y2 = p.y - 20;
result = currentGrouping.extractTextAsWordlist(x1, y1, x2, y2, currentPage, true, "");
}
return result;
}
Then I parsed this into a sequence of Rectangle
s: 然后,我将其解析为一个
Rectangle
序列:
/**
* Parse a String sequence of:
* {word1, w1_x1, w1_y1, w1_x2, w1_y2, word2, w2_x1, ...}
*
* Into a sequence of Rectangles.
*
* @param wordList Word list sequence to parse
* @return A List of Rectangles
*/
private List<Rectangle> parseWordBounds(List<String> wordList) {
List<Rectangle> wordBounds = new LinkedList<Rectangle>();
Iterator<String> wordListIterator = wordList.iterator();
while(wordListIterator.hasNext()) {
// sequences are: {word, x1, y1, x2, y2}
wordListIterator.next(); // skip the word
int x1 = (int) Float.parseFloat(wordListIterator.next());
int y1 = (int) Float.parseFloat(wordListIterator.next());
int x2 = (int) Float.parseFloat(wordListIterator.next());
int y2 = (int) Float.parseFloat(wordListIterator.next());
wordBounds.add(new Rectangle(x1, y2, x2 - x1, y1 - y2)); // in page, not screen coordinates
}
return wordBounds;
}
Then identified which Rectangle
the MouseEvent
fell within: 然后确定
MouseEvent
属于哪个Rectangle
:
/**
* Finds the bounding Rectangle of a word located at a Point.
*
* @param p Point to find word bounds
* @param wordBounds List of word boundaries to search
* @return A Rectangle that bounds a word and contains a point, or null if
* there is no word located at the point
*/
private Rectangle findWordBoundsAtPoint(Point p, List<Rectangle> wordBounds) {
Rectangle result = null;
for (Rectangle wordBound : wordBounds) {
if (wordBound.contains(p)) {
result = wordBound;
break;
}
}
return result;
}
For some reason, just passing this Rectangle to the highlighting method didn't work. 由于某种原因,仅将此Rectangle传递给突出显示方法不起作用。 After some tinkering, I found that shrinking the
Rectangle
by a point on each side resolved the problem: 经过一番修补后,我发现将
Rectangle
的每一边缩小一点可以解决问题:
/**
* Contracts a Rectangle to enable it to be highlighted.
*
* @return A contracted Highlight Rectangle
*/
private Rectangle contractHighlight(Rectangle highlight){
int x = highlight.x + 1;
int y = highlight.y + 1;
int width = highlight.width -2;
int height = highlight.height - 2;
return new Rectangle(x, y, width, height);
}
Then I just passed it to this method to add highlights: 然后,我将其传递给此方法以添加亮点:
/**
* Highlights text on the document
*/
private void highlightText(Rectangle highlightRectangle) {
pdfDecoder.getTextLines().addHighlights(new Rectangle[]{highlightRectangle}, false, currentPage);
pdfDecoder.repaint();
}
Finally, all the above calls are packed into this convenient method: 最后,将上述所有调用打包到此便捷方法中:
/**
* Highlights the word at the given point.
*
* @param p Point where word is located
*/
private void highlightWordAtPoint(Point p) {
try {
Rectangle wordBounds = findWordBoundsAtPoint(p, parseWordBounds(scanForWords(p)));
if (wordBounds != null) {
highlightText(contractHighlight(wordBounds));
}
} catch (PdfException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.