2

ユーザーがJPedalライブラリを使用してPDFドキュメント内の単語をダブルクリックして強調表示できる機能を実装したいと思います。これは、単語の境界矩形を取得して、MouseEventの場所がその範囲内にあるかどうかを確認できれば簡単です。次のスニペットは、リージョンを強調表示する方法を示しています。

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();
}

ただし、ドキュメントには平文の抽出例しかありません。

4

1 に答える 1

0

マークの例を見た後、私はなんとかそれを機能させることができました。いくつかの癖があるので、他の人に役立つ場合に備えて、すべてがどのように機能するかを説明します。キーメソッドは、です。これは、抽出する領域が指定されたときにフォームのextractTextAsWordlistaを返します。ステップバイステップの手順を以下に示します。List<String>{word1, w1_x1, w1_y1, w1_x2, w1_y2, word2, w2_x1, ...}

まず、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);
}

次に、テキストをスキャンするボックスを作成します。私はこれをページの幅にし、垂直方向に+/- 20ページ単位(これはかなり任意の数です)にし、MouseEvent:を中心に配置することを選択しました。

/**
 * 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;
}

次に、これを一連のRectanglesに解析しました。

/**
 * 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;
}

Rectangle次に、どちらが該当するかを特定しましたMouseEvent

/**
 * 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;
}

何らかの理由で、この長方形を強調表示方法に渡すだけでは機能しませんでした。Rectangle少しいじくり回した後、両側のポイントを1つずつ縮小すると、問題が解決することがわかりました。

/**
 * 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);
}

次に、これをこのメソッドに渡して、ハイライトを追加しました。

/**
 * Highlights text on the document
 */
private void highlightText(Rectangle highlightRectangle) {
    pdfDecoder.getTextLines().addHighlights(new Rectangle[]{highlightRectangle}, false, currentPage);
    pdfDecoder.repaint();
}

最後に、上記のすべての呼び出しは、この便利なメソッドにパックされています。

/**
 * 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();
    }
}
于 2012-09-27T08:06:33.597 に答える