我正在使用convert
(Imagemagick 组件,委托给后台的 Ghostscript)将 PDF 文件的第一页转换为图像。
通常,convert -density 200 file.pdf[0] first_page.png
它将完成这项工作,并以每英寸纸张 200 像素的速度对 PDF 文件进行采样。
但是,很少会出现 PDF 异常巨大的情况(有时是 A0 纸,最近有一页的 PDF 超过 23 平方米(长 183 英寸,宽 185 英寸)。
对于这样的文件,convert
会挂起,消耗 CPU 时间。宽度和高度超过 35000 像素的图像根本无法使用。
因此问题是:Imagemagick 中是否有一个开关可以使密度适应页面大小,或者至少指定我们不想对 PDF 文件最大区域的一部分以上进行采样(例如左上角 30x30 英寸)?
谢谢。
编辑:在其官方 git 存储库中,多媒体PDF已添加-w
和-h
开关,它们将共同-r
完成这里所需的操作。
答案1
我修改了 mupdf 的 pdfdraw 以支持以最佳适配模式进行绘制,因此我可以声明输出最多需要 128x128,并且它将适合框中的输出,同时保持纵横比。在我这样做之前,唯一的方法是使用 pdfinfo 获取页面大小,然后进行计算以使其适合框,然后要求 pdfdraw 使用该比例因子(每英寸点数)进行绘制。
好吧,说了这么多,其实过程很简单:
获取要呈现的页面的页面大小(在 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']
对于盒子适合,
dpi = min( A/(w/72.), B/(h/72.) )
其中A
是最大宽度,B
是最大高度;w
和h
是页面的宽度和高度。- 传递
dpi
给convert -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");
答案2
您使用了错误的命令。请使用-resample
。如果可能,建议提供具体的宽度和高度。
-density
仅仅是一个标志。-resample
实际上改变了像素尺寸:唯一重要的测量。
编辑:文档-resample
http://www.imagemagick.org/script/command-line-options.php#resample
-density 选项设置属性,不会改变底层光栅图像。它可用于通过调整应用于像素的比例来调整渲染大小以用于桌面出版目的。要调整图像大小以使其在不同分辨率下保持相同大小,请使用 -resample 选项。
在 CG 中,简单的说英寸是不存在的。对于光栅图像,只存储像素。dpi 只是一个建议。
假设桌子上有 3 个方格,300 枚硬币。如果每方格有 300 枚硬币,则只有一个方格中有 300 枚硬币。
如果我改为density
100 pps,我现在有 3 个方格,但总共仍有 300 个便士(每个方格中有 100 个便士)。你并没有改变便士的数量,只是改变了在任意测量单位中分配便士的方式。
如果我resample
将原版改为 100pps,则有 1 平方,总共 100 便士。我更改了便士的数量。
我怀疑在页面尺寸增加的情况下,您正在处理具有高分辨率的内容(例如 1200 dpi 的线条图),并且density
当您使用符合标志的内容打开结果时,将其更改为 300 会使英寸测量值增加四倍。