【问题标题】:Text Highlighting with PDFClown without using PDF Annotations使用 PDFClown 突出显示文本而不使用 PDF 注释
【发布时间】:2016-05-18 23:32:17
【问题描述】:

几周前我开始使用 PDFClown。我的目的是多字突出显示,主要是在报纸上。从org.pdfclown.samples.cli.TextHighlightSample的例子开始,我成功提取了多词位置并高亮显示。在大多数情况下,我什至解决了一些文本排序和匹配问题。

不幸的是,我的框架包含FPDI,它不考虑PDFAnnotations。因此,页面内容流之外的所有内容,如文本注释和其他所谓的标记注释,都会丢失。

那么对于使用 PdfClown 而不使用 PDF 注释创建“文本突出显示”有什么建议吗?

【问题讨论】:

  • 我找到了使用“org.pdfclown.documents.contents.composition.PrimitiveComposer”和“drawRectangle”的部分解决方案。在某些未显示矩形的情况下,它仍然存在一些问题,我认为有必要进行更深入的分析并可能编辑 pdf 结构。
  • 切换到 PDFBox,在这里查看我的答案stackoverflow.com/a/37421890/562566

标签: java pdf pdfclown


【解决方案1】:

要在注释中而不是在实际页面内容流中突出显示,必须将图形突击队放入页面内容流中.

这可以这样实现:

org.pdfclown.files.File file = new org.pdfclown.files.File(resource);
Pattern pattern = Pattern.compile("S", Pattern.CASE_INSENSITIVE);
TextExtractor textExtractor = new TextExtractor(true, true);

for (final Page page : file.getDocument().getPages())
{
    final List<Quad> highlightQuads = new ArrayList<Quad>();

    Map<Rectangle2D, List<ITextString>> textStrings = textExtractor.extract(page);
    final Matcher matcher = pattern.matcher(TextExtractor.toString(textStrings));

    textExtractor.filter(textStrings, new TextExtractor.IIntervalFilter()
    {
        @Override
        public boolean hasNext()
        {
            return matcher.find();
        }

        @Override
        public Interval<Integer> next()
        {
            return new Interval<Integer>(matcher.start(), matcher.end());
        }

        @Override
        public void process(Interval<Integer> interval, ITextString match)
        {
            {
                Rectangle2D textBox = null;
                for (TextChar textChar : match.getTextChars())
                {
                    Rectangle2D textCharBox = textChar.getBox();
                    if (textBox == null)
                    {
                        textBox = (Rectangle2D) textCharBox.clone();
                    }
                    else
                    {
                        if (textCharBox.getY() > textBox.getMaxY())
                        {
                            highlightQuads.add(Quad.get(textBox));
                            textBox = (Rectangle2D) textCharBox.clone();
                        }
                        else
                        {
                            textBox.add(textCharBox);
                        }
                    }
                }
                highlightQuads.add(Quad.get(textBox));
            }
        }

        @Override
        public void remove()
        {
            throw new UnsupportedOperationException();
        }
    });

    // Highlight the text pattern match!
    ExtGState defaultExtGState = new ExtGState(file.getDocument());
    defaultExtGState.setAlphaShape(false);
    defaultExtGState.setBlendMode(Arrays.asList(BlendModeEnum.Multiply));

    PrimitiveComposer composer = new PrimitiveComposer(page);
    composer.getScanner().moveEnd();
    // TODO: reset graphics state here.
    composer.applyState(defaultExtGState);
    composer.setFillColor(new DeviceRGBColor(1, 1, 0));
    {
        for (Quad markupBox : highlightQuads)
        {
            Point2D[] points = markupBox.getPoints();
            double markupBoxHeight = points[3].getY() - points[0].getY();
            double markupBoxMargin = markupBoxHeight * .25;
            composer.drawCurve(new Point2D.Double(points[3].getX(), points[3].getY()),
                    new Point2D.Double(points[0].getX(), points[0].getY()),
                    new Point2D.Double(points[3].getX() - markupBoxMargin, points[3].getY() - markupBoxMargin),
                    new Point2D.Double(points[0].getX() - markupBoxMargin, points[0].getY() + markupBoxMargin));
            composer.drawLine(new Point2D.Double(points[1].getX(), points[1].getY()));
            composer.drawCurve(new Point2D.Double(points[2].getX(), points[2].getY()),
                    new Point2D.Double(points[1].getX() + markupBoxMargin, points[1].getY() + markupBoxMargin),
                    new Point2D.Double(points[2].getX() + markupBoxMargin, points[2].getY() - markupBoxMargin));
            composer.fill();
        }
    }
    composer.flush();
}

file.save(new File(RESULT_FOLDER, "multiPage-highlight-content.pdf"), SerializationModeEnum.Incremental);

(HighlightInContent.java 方法 testHighlightInContent)

您将从原始示例中识别出文本提取框架。只是现在整个页面的四边形在处理之前被收集起来,处理代码(大部分是从TextMarkup.refreshAppearance()借来的)将代表四边形的表格绘制到页面内容中。

注意,要使这项工作正常进行,必须在插入新指令之前重置图形状态(该位置标有TODO 注释)。这可以通过应用保存/恢复状态或通过实际抵消不需要的更改状态条目来完成。不幸的是,我没有看到如何在 PDF Clown 中做前者,也没有时间做后者。

【讨论】:

    猜你喜欢
    • 2014-06-14
    • 2016-05-01
    • 1970-01-01
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-25
    相关资源
    最近更新 更多