使用R从PDF文件中提取字符字体大小

时间:2018-03-16 12:52:03

标签: r pdf text-mining

为了类似的目的,我一直在尝试重现这个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版本更快(也许)。但我不知道如何获得字体大小。我该怎么办?特别是如果我们假设文件的扫描版本,例如在上述论文中。

观察:我可能会在一个单独的问题中提出这个问题,但如果有人能够在评论中找到关于边距大小和行间距的一些想法,我会很珍惜。

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

1 个答案:

答案 0 :(得分:3)

可能无法确定实际的字体大小,至少在不知道确切字体及其规格的情况下。 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,然后合并... < / p>

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