PDF => 光栅,是否可以根据输入页面大小调整采样分辨率?

Ben*_*oit 5 pdf ghostscript imagemagick

我正在使用convert(Imagemagick 组件,在后台委托给 Ghostscript)将 PDF 文件的第一页转换为图像。

通常,convert -density 200 file.pdf[0] first_page.png它将完成这项工作,它会以每英寸纸张 200 像素的速度对 PDF 文件进行采样。

但是,很少发生某些 PDF 异常巨大的情况(有时是 A0 纸,最近是页面超过 23 平方米(长 183 英寸,宽 185 英寸)的 PDF。

对于这样的文件,convert会挂掉,吃CPU时间。宽度和高度超过 35000 像素的图像根本无法使用。

因此问题是:Imagemagick 中是否有一个开关可以使密度适应页面大小,或者至少指定我们不想采样超过 PDF 文件最大区域的一部分(左上角,30x30 英寸)例如)?

谢谢。

编辑:在其官方 git 存储库中,MuPDF添加了-w-h开关,与-r将在这里执行所需的操作。

Dan*_* D. 1

我修改了 mupdf 的 pdfdraw 以支持在最佳拟合模式下绘图,因此我可以声明输出最多需要为 128x128,并且它将适合框中的输出,同时保持纵横比。在我这样做之前,唯一的方法是使用 pdfinfo 获取页面大小,然后进行计算以将其放入框中,然后要求 pdfdraw 以该比例因子(每英寸点数)绘制它。

好吧,在讲完这个长篇故事之后,执行此操作的过程相当简单:

  1. 获取要渲染的页面的页面大小(在 pdf 术语中为媒体框),这可以通过 pdfinfo 和 grep 完成,并将以 pts(点,1/72 英寸)或通过像 pyPDF 这样的 pdf 库显示:

    import pyPdf
    p = pyPdf.PdfFileReader(file("/home/dan/Desktop/Sieve-JFP.pdf", "rb"))
    x,y,w,h = p.pages[0]['/MediaBox']
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于盒子拟合,dpi = min( A/(w/72.), B/(h/72.) )
    其中A是最大宽度,B是最大高度;wh是页面的宽度和高度。

  3. 传递dpiconvert -density $dpi

并按照要求做了一个稍微捏造的 git commit diff:

commit 0000000000000000000000000000000000000000
Author: Dan D.
Date:   Thu Jul 28 16:33:33 2011 -0400

    add options to pdfdraw to limit the output's width and height

    note that scaling must occur before rotation

diff --git a/apps/pdfdraw.c b/apps/pdfdraw.c
index 0000000..1234567 100644
--- a/apps/pdfdraw.c
+++ b/apps/pdfdraw.c
@@ -12,8 +12,10 @@
 #endif

 char *output = NULL;
-float resolution = 72;
+float resolution = -1;
 float rotation = 0;
+float width = -1;
+float height = -1;

 int showxml = 0;
 int showtext = 0;
@@ -47,6 +49,8 @@ static void usage(void)
        "\t\tsupported formats: pgm, ppm, pam, png, pbm\n"
        "\t-p -\tpassword\n"
        "\t-r -\tresolution in dpi (default: 72)\n"
+       "\t-w -\tmaximum width (default: no limit)\n"
+       "\t-h -\tmaximum height (default: no limit)\n"
        "\t-A\tdisable accelerated functions\n"
        "\t-a\tsave alpha channel (only pam and png)\n"
        "\t-b -\tnumber of bits of antialiasing (0 to 8)\n"
@@ -150,13 +154,39 @@ static void drawpage(pdf_xref *xref, int pagenum)

    if (output || showmd5 || showtime)
    {
-       float zoom;
+       float zoom = 1.0;
        fz_matrix ctm;
        fz_bbox bbox;
        fz_pixmap *pix;
+       float W, H;

-       zoom = resolution / 72;
-       ctm = fz_translate(0, -page->mediabox.y1);
+       ctm = fz_identity;
+       ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.y1));
+       ctm = fz_concat(ctm, fz_rotate(page->rotate));
+       ctm = fz_concat(ctm, fz_rotate(rotation));
+       bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox));
+
+       W = bbox.x1 - bbox.x0; 
+       H = bbox.y1 - bbox.y0;
+       if (resolution != -1)
+           zoom = resolution / 72;
+       if (width != -1) 
+       {
+           if (resolution != -1)
+               zoom = MIN(zoom, width/W);
+           else
+               zoom = width/W;
+       }
+       if (height != -1)
+       {
+           if (resolution != -1 || width != -1)
+               zoom = MIN(zoom, height/H);
+           else
+               zoom = height/H;
+       }
+
+       ctm = fz_identity;
+       ctm = fz_concat(ctm, fz_translate(0, -page->mediabox.y1));
        ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
        ctm = fz_concat(ctm, fz_rotate(page->rotate));
        ctm = fz_concat(ctm, fz_rotate(rotation));
@@ -295,7 +325,7 @@ int main(int argc, char **argv)
    fz_error error;
    int c;

-   while ((c = fz_getopt(argc, argv, "o:p:r:R:Aab:dgmtx5")) != -1)
+   while ((c = fz_getopt(argc, argv, "o:p:r:R:w:h:Aab:dgmtx5")) != -1)
    {
        switch (c)
        {
@@ -303,6 +333,8 @@ int main(int argc, char **argv)
        case 'p': password = fz_optarg; break;
        case 'r': resolution = atof(fz_optarg); break;
        case 'R': rotation = atof(fz_optarg); break;
+       case 'w': width = atof(fz_optarg); break;
+       case 'h': height = atof(fz_optarg); break;
        case 'A': accelerate = 0; break;
        case 'a': savealpha = 1; break;
        case 'b': alphabits = atoi(fz_optarg); break;
@@ -321,6 +353,10 @@ int main(int argc, char **argv)
    if (fz_optind == argc)
        usage();

+   if (width+height == -2)
+       if (resolution == -1)
+           resolution = 72;
+
    if (!showtext && !showxml && !showtime && !showmd5 && !output)
    {
        printf("nothing to do\n");
Run Code Online (Sandbox Code Playgroud)