创建带有图像的 PDF

创建带有图像的 PDF

我的文件夹中有一些图像文件。我想将它们保存为单个 pdf,每页一张图片。

我目前正在使用穆托尔尤其是mutool create。如果您有任何推荐使用的工具(命令行、GUI 或编程库),我愿意切换。更喜欢可以通过脚本或代码自动化的东西。总的来说,我正在寻找一种广泛而自由地操作 pdf 文件的方法。

我无法获得内容流语法的简单来源(从我读到的内容来看,它基本上是内部 pdf 格式语法的一部分,似乎不太用户友好......),这真的是我应该使用 mutool 的方式吗?

使用此内容流文件,如何不调整图像大小?使用1 0 0 1 <x> <y> cm定位应该可以工作(第 206 页)但它也会将图像缩放到 1x1。如何让页面的大小与其中的图像大小相同?如何“切换”到下一页?

那么如何使用 mutool 或其他软件/代码创建带有图像的 pdf?

答案1

你可以这样做HexaPDF用一些脚本:

require 'hexapdf'

doc = HexaPDF::Document.new
ARGV.each do |image_file|
  image = doc.images.add(image_file)
  iw = image.info.width.to_f
  ih = image.info.height.to_f
  page = doc.pages.add(:A4, orientation: (ih > iw ? :portrait : :landscape))
  pw = page.box(:media).width.to_f
  ph = page.box(:media).height.to_f
  rw, rh = pw / iw, ph / ih
  ratio = [rw, rh].min
  iw, ih = iw * ratio, ih * ratio
  x, y = (pw - iw) / 2, (ph - ih) / 2
  page.canvas.image(image, at: [x, y], width: iw, height: ih)
end
doc.write("output.pdf")

此脚本将图像文件作为参数,并将每个文件放在单独的 A4 页面上,缩放图像以适合页面,并在必要时旋转页面。如果您不想缩放图像,只需设置ratio = 1

答案2

因此实际上 mutool 运行脚本提供了API(参见一切(位于“JavaScript Shell”)用于处理 pdf 并且不需要了解 pdf 格式(与示例脚本暗示的相反),供参考这里有一个实现 pdf->每页一张图片->pdf 的脚本。

由于缺乏清晰的文档(尤其是关于参数类型),我决定研究一下 mutool源代码。我收到的大多数错误消息与问题本身无关。

/*
Flatten a pdf by converting each page to an image and putting them in a new pdf.

Usage: mutool run flatten.js in.pdf out.pdf

Documentation:
https://mupdf.com/docs/manual-mutool-run.html
http://git.ghostscript.com/?p=mupdf.git;a=blob;f=source/tools/murun.c;h=16582b5d83234c880c4c3b67b279a4428d3f2303;hb=refs/heads/master
*/

function array_max(a)
{
    var max = a[0];
    for(var i=1;i<a.length;i++)
    {
        if(a[i] > max)
            max = a[i];
    }
    return max;
}

// scale up render if needed to have non-blurry images up to filling up screen when zooming on a page
var minRenderWidth = 1920;
var minRenderHeight = 1080;

var input = new PDFDocument(scriptArgs[0]);
var pages = input.countPages();

var dw = new DocumentWriter(scriptArgs[1], 'pdf');
for(var i=0;i<pages;i++)
{
    var page = input.loadPage(i);
    var pageBounds = page.bound();
    var scale = array_max([1, minRenderWidth/pageBounds[2], minRenderHeight/pageBounds[3]]);
    var pixmapRender = page.toPixmap(Scale(scale, scale), DeviceRGB);
    var imageRender = new Image(pixmapRender);
    var device = dw.beginPage(pageBounds);
    // translate then scale
    // no idea about how the translate bit works: not sure where the origin for coordinates is (but it works)
    device.fillImage(imageRender, Concat(Scale(pageBounds[2] - pageBounds[0], pageBounds[3] - pageBounds[1]), Translate(2*pageBounds[0], 0)), 1);
    device.close();
    dw.endPage(device);
    print('#' + (i+1) + ' done');
}
dw.close();

答案3

我最近了解到img2pdf,一个 Python 包。它的功能与名称所示一致:将图像包装到 PDF 文档中。它不执行 OCR,不对图像重新采样,一切都保持原样。它非常快。使用也非常简单:

img2pdf img1.png img2.jpg -o out.pdf

img2pdf至少在 Debian 上也可以作为软件包使用。

正如在img2pdf地点,立方体如果您有 JPEG 或 PNG,也可能是一个不错的选择。它还具有 OCR 的额外优势,使您可以复制文本并搜索它。这将花费更长的时间,因为 OCR 需要时间。请按如下方式使用它:

ls *.jpg | tesseract - output-file-basename pdf

(请注意,“output-file-basename”和“pdf”是单独的参数。)

如果需要/需要,你可以使用定量PDF之后对文档进行操作。


例如,使用非双面 ADF 扫描仪时,请先扫描所有正面,翻转整个堆栈,然后反向扫描所有背面,然后将两者合并:

qpdf --collate --empty --pages front-sides.pdf 1-z back-sides.pdf z-1 -- out.pdf

答案4

使用 Python 和 PyMuPDF 的操作方法如下:

我必须安装“pymupdf” 包提供菲茨模块 (不是“fitz”包,这是一个不同的包!)

python -m venv .
./bin/pip install pymupdf

(复制粘贴的代码来自https://pymupdf.readthedocs.io/en/latest/recipes-images.html#how-to-make-one-pdf-of-all-your-pictures-or-files

我修改了代码以省略使用 PySimpleGUI,因为它也需要安装 TK。我还在文件列表中添加了基于正则表达式的过滤,允许仅包含与正则表达式匹配的文件。

#!./bin/python
import os, fitz, re # "fitz" comes from the "pymupdf" package
#import PySimpleGUI as psg  # for showing a progress bar
doc = fitz.open()  # PDF with the pictures
imgdir = "."  # folder where the pics are
allfiles = os.listdir(imgdir)  # list of them
imglistUNSORTED = list (filter (lambda fn: re.match (r'c-\d+.jpg', fn), allfiles))
imglist = sorted (imglistUNSORTED)
imgcount = len(imglist)  # pic count

for i, f in enumerate(imglist):
    img = fitz.open(os.path.join(imgdir, f))  # open pic as document
    rect = img[0].rect  # pic dimension
    pdfbytes = img.convert_to_pdf()  # make a PDF stream
    img.close()  # no longer needed
    imgPDF = fitz.open("pdf", pdfbytes)  # open stream as PDF
    page = doc.new_page(width = rect.width,  # new page with ...
                       height = rect.height)  # pic dimension
    page.show_pdf_page(rect, imgPDF, 0)  # image fills the page
    #psg.EasyProgressMeter("Import Images",  # show our progress
    #    i+1, imgcount)
    print ('Import Images: ' +str(i+1)+ '/' +str(imgcount))

doc.save("all-my-pics.pdf")

相关内容