使用 pdfclown 时,chinese/japanese 文档中的少数搜索关键字未突出显示

Using pdfclown few search keywords are not highlighting in chinese/japanese documents

我遇到一些搜索关键字在中文文档中没有突出显示的问题。出于机密考虑,我没有提供实际的 pdf。搜索关键字是 1)亿元或2) 收入亿来源突出显示我提到的搜索关键字。

    import java.awt.Color;
    import java.awt.Desktop;
    import java.awt.geom.Rectangle2D;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.URL;
    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import java.io.BufferedInputStream;
    import java.io.File;
    import org.pdfclown.documents.Page;
    import org.pdfclown.documents.contents.ITextString;
    import org.pdfclown.documents.contents.TextChar;
    import org.pdfclown.documents.contents.colorSpaces.DeviceRGBColor;
    import org.pdfclown.documents.interaction.annotations.TextMarkup;
    import org.pdfclown.documents.interaction.annotations.TextMarkup.MarkupTypeEnum;

    import org.pdfclown.files.SerializationModeEnum;
    import org.pdfclown.util.math.Interval;
    import org.pdfclown.util.math.geom.Quad;
    import org.pdfclown.tools.TextExtractor;

    public class pdfclown2 {
        private static int count;

        public static void main(String[] args) throws IOException {

            highlight("ebook.pdf","C:\Users\Downloads\6.pdf");
            System.out.println("OK");
        }
        private static void highlight(String inputPath, String outputPath) throws IOException {

            URL url = new URL(inputPath);
            InputStream in = new BufferedInputStream(url.openStream());
            org.pdfclown.files.File file = null;

            try {
                file = new org.pdfclown.files.File("C:\Users\Desktop\pdf\test123.pdf");

            Map<String, String> m = new HashMap<String, String>();
                m.put("亿元或","hi");
                m.put("收入亿来","hi");



            System.out.println("map size"+m.size());
             long startTime = System.currentTimeMillis();




                // 2. Iterating through the document pages...
                TextExtractor textExtractor = new TextExtractor(true, true);
                for (final Page page : file.getDocument().getPages()) {
                    Map<Rectangle2D, List<ITextString>> textStrings = textExtractor.extract(page);
                    for (Map.Entry<String, String> entry : m.entrySet()) {

                        Pattern pattern;
                        String serachKey =  entry.getKey();
                        final String translationKeyword = entry.getValue();
                    /*
                            if ((serachKey.contains(")") && serachKey.contains("("))
                                    || (serachKey.contains("(") && !serachKey.contains(")"))
                                    || (serachKey.contains(")") && !serachKey.contains("(")) || serachKey.contains("?")
                                    || serachKey.contains("*") || serachKey.contains("+")) {s
                                pattern = Pattern.compile(Pattern.quote(serachKey), Pattern.CASE_INSENSITIVE);
                            }
                            else*/
                                 pattern = Pattern.compile(serachKey, Pattern.CASE_INSENSITIVE);
                    // 2.1. Extract the page text!

                //System.out.println(textStrings.toString().indexOf(entry.getKey()));

                    // 2.2. Find the text pattern matches!
                    final Matcher matcher = pattern.matcher(TextExtractor.toString(textStrings));
                    // 2.3. Highlight the text pattern matches!
                    textExtractor.filter(textStrings, new TextExtractor.IIntervalFilter() {
                        public boolean hasNext() {
                            // System.out.println(matcher.find());
                            // if(key.getMatchCriteria() == 1){
                            if (matcher.find()) {
                                return true;
                            }
                            /*
                             * } else if(key.getMatchCriteria() == 2) { if
                             * (matcher.hitEnd()) { count++; return true; } }
                             */
                            return false;

                        }

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

                        public void process(Interval<Integer> interval, ITextString match) {
                            // Defining the highlight box of the text pattern
                            // match...
                            System.out.println(match);
                        /*  List<Quad> highlightQuads = new ArrayList<Quad>();
                            {
                                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);
                                        }
                                    }
                                }
                                textBox.setRect(textBox.getX(), textBox.getY(), textBox.getWidth(), textBox.getHeight());
                                highlightQuads.add(Quad.get(textBox));
                            }*/
                            List<Quad> highlightQuads = new ArrayList<Quad>();
                            List<TextChar> textChars = match.getTextChars();
                            Rectangle2D firstRect = textChars.get(0).getBox();
                            Rectangle2D lastRect = textChars.get(textChars.size()-1).getBox();
                            Rectangle2D rect = firstRect.createUnion(lastRect);
                            highlightQuads.add(Quad.get(rect).get(rect));
                            // subtype can be Highlight, Underline, StrikeOut, Squiggly


                            new TextMarkup(page, highlightQuads, translationKeyword, MarkupTypeEnum.Highlight);

                        }

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

                    });
                }

            }

            SerializationModeEnum serializationMode = SerializationModeEnum.Standard;

                file.save(new java.io.File(outputPath), serializationMode);

                System.out.println("file created");
                long endTime = System.currentTimeMillis();

                 System.out.println("seconds take for execution is:"+(endTime-startTime)/1000);

            } catch (Exception e) {
                   e.printStackTrace();
            }
            finally{
                in.close();
            }


        }
    }

的确,在搜索“亿元”时,结果突出显示有些错误:

原因是 PDF Clown 错误。当它解析复合字体(又名 Type 0 字体)时,它期望 Type 0 字体基础字典中的 DW(默认宽度)条目,而它被指定在 CIDFont 子字典中!

在手边的文档中,大多数字符的宽度,尤其是汉字,没有明确给出,因此默认为 DW 值。由于上述错误无法正确确定该值,因此使用了明确给定宽度的平均值,而该平均值恰好仅为正确值的 ¾。因此,突出显示的区域太短了。

您可以在 CompositeFont class(包 org.pdfclown.documents.contents.fonts)方法 onLoad 末尾修复此错误。只需替换

PdfInteger defaultWidthObject = (PdfInteger)getBaseDataObject().get(PdfName.DW);

来自

PdfInteger defaultWidthObject = (PdfInteger)getCIDFontDictionary().get(PdfName.DW);

现在突出显示的结果是