【问题标题】:Extracting character font size from PDF files with R使用R从PDF文件中提取字符字体大小
【发布时间】:2018-08-25 13:12:02
【问题描述】:

出于类似目的,我一直在尝试重现此paper 中解释的类似数据集(我强调不完全相同)。但是我在想出一个在 R 中编码时获取字体大小的想法时遇到了麻烦。其他解决方案似乎在其他编码语言中可用。

例如,可以非常轻松地提取有关页面中字符数的信息或转换图像中的每个页面并获取有关像素数等数据 - 无论如何这将成为我的元数据的一部分。比如下面的例子:

library(pdftools)
library(png)

download.file("http://arxiv.org/pdf/1403.2805.pdf", "1403.2805.pdf", mode = "wb")

txt <- pdf_text("1403.2805.pdf")

num_char_page = unlist(lapply(txt,nchar))

height = 1:length(txt)
width =1:length(txt)

for (i in 1:length(txt)) {

  bitmap <- pdf_render_page("1403.2805.pdf", page = i)

  png::writePNG(bitmap, paste0("page",i,".png"))

  photo=readPNG(paste0("page",i,".png"))

  height[i]  = dim(photo)[1]

  width[i] = dim(photo)[2]

}

layout_df = data.frame(page=1:length(txt), num_char_page=num_char_page, height=height, width=width)

所以这相当简单,尽管在循环部分(也许)使用一些 lapply 版本可以使代码更快。但我不知道如何获得字体大小。我该怎么做?特别是如果我们假设文件的扫描版本,例如在上述论文中。


观察:我可能会在一个单独的问题中提出这个问题,但如果有人能指出关于边距大小和 cmets 中行间距的一些想法,我会很高兴。

第二次观察:我认为(在这种特殊情况下)我用作示例的 PDF 可能具有可以启用字体大小提取的元数据。但我正在尝试从扫描的(可能是 OCR 的)PDF 中获取字体大小。可以将 PDF 的页面(在示例中)转换为图像,然后将它们再次转换为非 OCR 的 PDF,这可能与扫描的 PDF 情况有些相似。

【问题讨论】:

  • 在 png::writePNG 语句中,是否需要另一个右括号?
  • 是的,已经编辑过了。
  • 我正在尝试对律师事务所发布的 PDF 格式的调查报告进行类似的分析。我们可以就我们各自的研究和工具聊天或发送电子邮件吗?
  • 是的,当然o/
  • 很好,我怎么联系到你或者你联系到我?

标签: r pdf text-mining


【解决方案1】:

可能无法确定实际字体大小,至少在不知道确切字体及其规格的情况下是不可能的。 see here for an explanation of why

如果您只想比较文档之间的字体大小,使用平均行高作为比较可能就足够了,这可能更容易做到。如果您不关心实际值并且只需要知道文档之间的相对大小,则以下可能有效。您必须考虑或避免不同文档大小和/或 DPI 的潜在影响。

library(tesseract)
library(dplyr)
library(tidyr)

df <- ocr_data("http://arxiv.org/pdf/1403.2805.pdf")

df %>% 
  separate(bbox, c('x1', 'y1', 'x2', 'y2'), convert = T) %>% 
  mutate(line_height = y2 - y1) %>% 
  summarise(avg_line_height = mean(line_height))

# # A tibble: 1 x 1
#   avg_line_height
#             <dbl>
# 1            58.7

平均字母高度和宽度的示例......

df %>%
  separate(bbox, c('x1', 'y1', 'x2', 'y2'), convert = T) %>%
  mutate(word_height = y2 - y1) %>%
  mutate(word_width = x2 - x1) %>%
  mutate(num_letters = nchar(word)) %>%
  mutate(avg_letter_width = word_width / num_letters) %>%
  summarise(avg_letter_height = mean(word_height),
            avg_letter_width = mean(avg_letter_width))

# # A tibble: 1 x 2
#   avg_letter_height avg_letter_width
#               <dbl>            <dbl>
# 1              58.7             37.3

如果你想每页都这样做,你可以使用pdftools单独渲染多页PDF的每一页,然后在每一页上运行ocr_data,然后合并...

library(pdftools)
library(tesseract)
library(dplyr)
library(tidyr)

download.file(url = "http://arxiv.org/pdf/1403.2805.pdf",
              destfile = pdf_path <- tempfile(fileext = ".pdf"))

page_pngs <-
  lapply(seq_len(pdf_info(pdf_path)$pages), function(page_num) {
    pdf_convert(pdf_path, pages = page_num, dpi = 300)
  })

df <-
  bind_rows(
    lapply(seq_len(length(page_pngs)), function(page_num) {
      ocr_data(page_pngs[[page_num]]) %>%
        separate(bbox, c('x1', 'y1', 'x2', 'y2'), convert = T) %>%
        mutate(word_height = y2 - y1) %>%
        mutate(word_width = x2 - x1) %>%
        mutate(num_letters = nchar(word)) %>%
        mutate(avg_letter_width = word_width / num_letters) %>%
        mutate(page = page_num) %>%
        select(page, letter_height = word_height, letter_width = avg_letter_width)
    })
  )

df %>%
  group_by(page) %>%
  summarise(avg_letter_height = mean(letter_height),
            avg_letter_width = mean(letter_width)) %>%
  mutate(avg_letter_area = avg_letter_height * avg_letter_width)

# # A tibble: 29 x 4
#     page avg_letter_height avg_letter_width avg_letter_area
#    <int>             <dbl>            <dbl>           <dbl>
#  1     1              29.4             17.9            525.
#  2     2              29.3             18.9            554.
#  3     3              30.0             19.1            574.
#  4     4              30.2             18.7            565.
#  5     5              29.8             19.0            566.
#  6     6              28.2             17.7            498.
#  7     7              28.9             18.3            529.
#  8     8              29.8             18.6            554.
#  9     9              29.1             18.6            541.
# 10    10              28.3             18.3            519.
# # ... with 19 more rows

【讨论】:

  • 是否有替代构建宽度的方法?如果我用面积(宽度 x 高度)和每行字符数(类似于字符数除以面积的平均值)构造一个平均值,我可能会得到足够接近字符字体大小的东西。
  • tesseract 返回每个单词的边界框,因此您可以计算每个单词的 word_with/num_of_chars = avg_letter_width。
  • 见上面的新例子
  • 我认为ocr_data 功能不太好。第 3、4、5、6 和 7 页(以及其他)不会产生小标题。您认为我们可以在这方面有替代方案吗?也许将 png 文件转换为更高分辨率。我会试试的。
  • tesseract 是我所知道的最古老、最好的 OCR 系统之一。完全使用我上面的示例代码,所有页面都成功进行了 OCR 处理,并创建并合并了数据框。也许您的机器上发生了其他错误。
猜你喜欢
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-29
  • 2013-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多