提取字体粗细

时间:2015-11-24 20:00:15

标签: c# pdf itextsharp

我有一些文件预测了我想要提取的某些文字的位置。在大多数情况下,它的效果非常好,但是我对某些文本略厚的文档有困难。

细文:

enter image description here

厚文:

enter image description here

我知道在这个分辨率上很难区分,但是如果你看一下MO DAY YEAR TIME(2400)部分,你可以看出第二个更厚。

细文本给出了我所期望的内容:

2015年9月28日 0820

但是,厚版本给了我每个字符的三倍,每个重复的字符之间都有空格:

1 1 11 1 1 / / / 1 1 19 9 9 / / / 2 2 20 0 01 1 15 5 5 1 1 17 7 70 0 02 2 2

我正在使用以下代码从文档中提取文本:

public static Document GetDocumentInfo(string fileName)
{
    // Using 11 in x 8.5 in dimensions at 72 dpi.
    var boudingBoxes = new[]
    {
        new RectangleJ(446, 727, 85, 14),
        new RectangleJ(396, 702, 43, 14),
        new RectangleJ(306, 680, 58, 7),
        new RectangleJ(378, 680, 58, 7),
        new RectangleJ(446, 680, 45, 7),
        new RectangleJ(130, 727, 29, 10),
        new RectangleJ(130, 702, 29, 10)
    };

    var data = GetPdfData(fileName, 1, boudingBoxes);

    // I would populated the new document with extracted data
    // here, but it's not important for the example.
    var doc = new Document();
    return doc;
}

public static string[] GetPdfData(string fileName, int pageNum, RectangleJ[] boundingBoxes)
{
    // Omitted safety checks, as they're not important for the example.

    var data = new string[boundingBoxes.Length];

    using (var reader = new PdfReader(fileName))
    {
        if (reader.NumberOfPages < 1)
        {
            return null;
        }

        RenderFilter filter;
        ITextExtractionStrategy strategy;

        for (var i = 0; i < boundingBoxes.Length; ++i)
        {
            filter = new RegionTextRenderFilter(boundingBoxes[i]);
            strategy = new FilteredTextRenderListener(new LocationTextExtractionStrategy(), filter);
            data[i] = PdfTextExtractor.GetTextFromPage(reader, pageNum, strategy);
        }

        return data;
    }
}

显然,如果没有别的方法可行,我可以在阅读后删除重复的字符,因为有一个非常明显的模式,但我宁愿找到一个正确的方式而不是黑客。我试着在过去几个小时里四处寻找,但找不到任何人遇到类似的问题。

修改

我终于遇到了这个问题:

Text Extraction Duplicate Bold Text

...在评论中,它表明一些低质量的PDF制作者会复制文本以模拟大胆,因此这是可能发生的事情之一。但是,有人提到在该位置省略重复文本,我不知道如何从我的代码部分开始实现......

data[i] = PdfTextExtractor.GetTextFromPage(reader, pageNum, strategy);

...完全在任何指定的位置读取重复的文本。

修改

我现在遇到的文件重复内容最多四次以模拟厚度。这是一种非常奇怪的做事方式,但我确信该方法的设计者有他们的理由。

修改

我制作了 A 解决方案(请参阅我的回答)。它在已经提取数据后处理数据并删除任何重复。理想情况下,这可以在提取过程中完成,但它可能变得相当复杂,这似乎是一种非常简洁的方法,可以完成同样的工作。

1 个答案:

答案 0 :(得分:0)

正如@mkl建议的那样,解决此问题的一种方法是覆盖LocationExtractionStrategy;然而,事情变得相当复杂,因为它需要比较在特定边界处找到的每个字符的位置。我尝试做一些研究以实现这一目标,但由于文档很差,它有点失控。

所以,相反,当我创建一个后处理方法时,松散地基于@TheMuffinMan的建议,清理任何重复。我决定不处理像素,而是处理已知静态位置中的字符计数异常。在我的情况下,我知道提取的第二个数据块永远不会超过三个字符,所以这对我来说是一个很好的比较点。如果您知道文档布局,则可以使用您知道的固定长度的任何内容。

用我原始帖子中列出的方法提取数据后,检查第二个数据块的长度是否大于3。如果它返回true,那么我将给定的长度除以3,因为它是它可以拥有的最多的字符,并且因为所有的重复都是偶数长度,我知道我会得到偶数个重复的情况:

var data = GetPdfData(fileName, 1, boudingBoxes);

if (data[1].Length > 3)
{
    var count = data[1].Length / 3;
    for (var i = 0; i < data.Length; ++i)
    {
        data[i] = RemoveRepetitions(data[i], count);
    }
}

如您所见,然后我循环遍历数据并将每个部分传递到RemoveRepetitions()方法:

public static string RemoveRepetitions(string original, int count)
{
    if (original.Length % count != 0)
    {
        return null;
    }
    var temp = new char[original.Length / count];
    for (int i = 0; i < original.Length; i += count)
    {
        temp[i / count] = original[i];
    }

    return new string(temp);
}

此方法获取我们之前计算的字符串和预期重复次数。需要注意的一点是,我不必担心在重复的过程中插入的空格,正如原始帖子中显示的那样,因为计数将代表只有一个字符的总字符数应该是。