PDF 处理的种种方法-R语言
今天,来谈一下 PDF 处理的一些办法:
PDF 裁剪、合并、抽取
需要用到 qpdf 包
> library(qpdf)
> ls('package:qpdf')
[1] "pdf_combine" "pdf_compress" "pdf_length"
[4] "pdf_split" "pdf_subset"
1/ pdf_combine: 用于合并 “正规格式”的 pdf( 注:Acrobat 不能识别合并的 PDF, 该函数也无法进行操作)
2/ pdf_compress: 用于压缩、线性化 PDF, 即减小 PDF 的大小
3/ pdf_length: 返回 PDF 的页数
4/ pdf_split: 把 PDF 拆分为单页的 PDF
5/ pdf_subset: 从原始 PDF 中抽提相应的页数,组成新的 PDF
一些注意事项:
pdf_split('1.pdf','D:\\D\\less\\')
sprintf('%03.0f',1:242) %>% paste0('D:\\D\\lm\\',.,'.pdf') -> q
fi <- list.files("D:\\D\\less\\")
setwd('D:\\D\\less\\')
file.rename(fi,q)
pdf_split() 的路径参数不要含有中文信息。拆分为单页 PDF 后,文件名过长。这时,利用 file.rename() 函数进行文件的批量重命名。
如此:
> dir() %>% head; dir() %>% tail
[1] "001.pdf" "002.pdf" "003.pdf" "004.pdf"
[5] "005.pdf" "006.pdf"
[1] "237.pdf" "238.pdf" "239.pdf" "240.pdf"
[5] "241.pdf" "242.pdf"
重新获得:001.pdf 至 242.pdf
> pdf_length('001.pdf')
[1] 1
> pdf_subset('1.pdf',pages = 1:5)
[1] "D:\\D\\1_output.pdf"
> pdf_subset('1.pdf',pages = 1:5,'a.pdf')
[1] "D:\\D\\a.pdf"
或者,抽取一些不相邻的页面:
> pdf_subset('1.pdf',pages = c(1,10,3,6,7,20),'a1.pdf')
[1] "D:\\D\\a1.pdf"
> pdf_length('a1.pdf')
[1] 6
pdf 合并:
> sprintf('%03.0f',c(1,20,100,120,176,174,200,210)) %>%
+ paste0('D:\\D\\less\\',.,'.pdf') %>%
+ pdf_combine('az.pdf')
[1] "D:\\D\\less\\az.pdf"
> pdf_length('az.pdf')
[1] 8
pdftools
> library(pdftools)
> ls('package:pdftools')
[1] "pdf_attachments" "pdf_combine"
[3] "pdf_compress" "pdf_convert"
[5] "pdf_data" "pdf_fonts"
[7] "pdf_info" "pdf_length"
[9] "pdf_ocr_data" "pdf_ocr_text"
[11] "pdf_pagesize" "pdf_render_page"
[13] "pdf_split" "pdf_subset"
[15] "pdf_text" "pdf_toc"
[17] "poppler_config"
值得注意的是:pdf_combine, pdf_compress, pdf_convert, pdf_length,pdf_split, pdf_subset 源自 qpdf
> unload('qpdf')
Error in unload("qpdf") :
namespace ‘qpdf’ is imported by ‘pdftools’ so cannot be unloaded
以上报错信息提示:
pdftools 在使用时,会自动导入 qpdf, 因此无法在 pdftools 之前卸载 qpdf
> pdf_info('a1.pdf')
$version
[1] "1.3"
$pages
[1] 6
$encrypted
[1] FALSE
$linearized
[1] FALSE
$keys
list()
$metadata
[1] ""
$locked
[1] FALSE
$attachments
[1] FALSE
$layout
[1] "no_layout"
显示 pdf 相关信息。
1/ pdf_fonts: 获取字体信息
2/ pdf_ocr_data, pdf_ocr_text: 进行 OCR 识别
3/ pdf_toc: 识别 PDF 的目录书签
4/ pdf_convert: 用于 PDF 向其他文件格式的转换
> pdf_convert(
pdf,
format = "png",
pages = NULL,
filenames = NULL,
dpi = 72,
antialias = TRUE,
opw = "",
upw = "",
verbose = TRUE
)
注意事项:
format 格式必须为下列内容之一:
> poppler_config()$supported_image_formats
[1] "png" "jpeg" "jpg" "tiff" "pnm"
即意味着:pdf_convert 不能生成单页的 pdf
由于默认的参数:dpi = 72, 所以在导出往往建议 dpi 改至 220 以上,以达到较高的清晰度。
filenames 参数值必须与 pages 值相对应。
示例:
setwd('D:\\D\\lm')
sprintf('%03.0f',1:242) %>% paste0('D:\\D\\lm\\',.,'.png') -> q
pdf_convert('1.pdf', pages = 1:242,filenames = q,dpi = 220)
关于 一页 PDF 内含有多页,如何
裁剪、重新合成成新的 PDF
f <- list.files()
for (i in seq_along(f)) {
a <- image_read(f[i])
p1 <- p[i]
a %>% image_crop('1466x1101+494+466') %>% image_write(paste0(p1,'_1.png'))
Sys.sleep(0.1)
a %>% image_crop('1466x1101+494+466') %>% image_write(paste0(p1,'_2.png'))
Sys.sleep(0.1)
}
敲重点,需要使用 magick 包,以及必须完成 ImageMagick 的环境配置
> library(magick)
Linking to ImageMagick 6.9.9.14
Enabled features: cairo, freetype, fftw, ghostscript, lcms, pango, rsvg, webp
Disabled features: fontconfig, x11
解读:
> setwd('D:\\D\\lm\\m')
> f <- list.files()
> f
[1] "001.png" "002.png" "003.png" "004.png"
[5] "005.png" "006.png" "007.png" "008.png"
[9] "009.png" "010.png"
这里以 10 张 png 为例,里面是 2x1 的ppt页面内容,需要把这些实现批量裁剪输出,最后合并成 PDF
> a <- image_read(f[1])
> a
# A tibble: 1 x 7
format width height colorspace matte filesize
<chr> <int> <int> <chr> <lgl> <int>
1 PNG 1819 2573 sRGB FALSE 717226
# ... with 1 more variable: density <chr>
返回的 tibble 格式信息中, width 和 height 是后续裁剪所需的依据。
f <- list.files(pattern = '*.png')
library(magick)
nchar(as.character(length(f))) %>%
paste0('%0',.,'.0f') %>%
sprintf(1:length(f)) -> p
for (i in seq_along(f)) {
a <- image_read(f[i])
pp <- p[i] %>% paste0(c('_01.png','_02.png'))
a %>% image_crop('1090x818+362+342') %>% image_write(pp[1])
Sys.sleep(0.1)
a %>% image_crop('1090x818+362+1413') %>% image_write(pp[2])
Sys.sleep(0.1)
}
查看文件:
> g <- list.files(pattern = '_')
> g
[1] "01_01.png" "01_02.png" "02_01.png"
[4] "02_02.png" "03_01.png" "03_02.png"
[7] "04_01.png" "04_02.png" "05_01.png"
[10] "05_02.png" "06_01.png" "06_02.png"
[13] "07_01.png" "07_02.png" "08_01.png"
[16] "08_02.png" "09_01.png" "09_02.png"
[19] "10_01.png" "10_02.png"
由于在 for 循环中,image_write() 无法接收字符串向量形式的路径,所以只能使新生成的文件与原文件处于同一路径下
> g <- list.files(pattern = '_')
> g
[1] "01_01.png" "01_02.png" "02_01.png"
[4] "02_02.png" "03_01.png" "03_02.png"
[7] "04_01.png" "04_02.png" "05_01.png"
[10] "05_02.png" "06_01.png" "06_02.png"
[13] "07_01.png" "07_02.png" "08_01.png"
[16] "08_02.png" "09_01.png" "09_02.png"
[19] "10_01.png" "10_02.png"
利用 pattern 参数,进行过滤,获得文件名,当然也可以利用 paste0() 进行生成字符串向量。
接下来使用,file.copy() 函数
> file.copy
function (from, to, overwrite = recursive, recursive = FALSE,
copy.mode = TRUE, copy.date = FALSE)
> g <- list.files(pattern = '_')
> dir.create('D:\\D\\lm\\m\\try')
> file.copy(g, 'D:\\D\\lm\\m\\try')
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[9] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[17] TRUE TRUE TRUE TRUE
如此,即复制至新的路径下,
之后:合并 png 成为 PDF
setwd('D:\\D\\lm\\m\\try')
system('magick *.png a.pdf')
注:此处调用 ImageMagick 命令行,执行。不可添加中文字符!
琐碎的技巧点
Ⅰ/ 像素位置的获取:
① 利用 Windows 系统上的 「画图」工具,即可获得像素点位置,属于免费工具!
② 利用 Photoshop 的标尺功能,并显示单位为像素,来查找待裁剪区域的像素点位置
Ⅱ/ 环境问题:
magick 包必须依赖本地安装的 ImageMagick
ImageMagick 安装时,必须勾选:添加到环境变量
Ⅲ/ qpdf
qpdf 里面的部分函数,在生成文件的路径设置上,不要添加中文字符!
这一点,类似于 ImageMagick 的命令行操作。
---end---