5

Я использую convert (компонент Imagemagick, делегирование Ghostscript в фоновом режиме) для преобразования первой страницы файлов PDF в изображения.

Как правило, convert -density 200 file.pdf[0] first_page.png выполнит эту работу и сэмплит PDF-файл со скоростью 200 пикселей на дюйм бумаги.

Однако редко случается, что некоторые PDF-файлы имеют необычайно большой размер (иногда это бумага формата A0, а в последнее время это PDF-файл со страницей, превышающей 23 м² (183 дюйма в длину, 185 в ширину).

Для таких файлов convert будет зависать, жрать процессорное время. Изображения размером более 35000 пикселей по ширине и высоте просто невозможно использовать.

Поэтому вопрос: есть ли в Imagemagick переключатель, который бы адаптировал плотность к размеру страницы, или, по крайней мере, указал, что мы не хотим делать выборку больше, чем часть максимальной площади файла PDF (верхний левый угол, 30x30 дюймов) например)?

Благодарю.

РЕДАКТИРОВАТЬ: В своем официальном репозитории git MuPDF добавил ключи -w и -h которые вместе с -r будут делать то, что нужно здесь.

2 ответа2

1

Я изменил pdfdraw mupdf для поддержки рисования в режиме наилучшего соответствия, поэтому я могу утверждать, что вывод должен быть максимально 128x128, и он будет соответствовать выводу в окне, сохраняя соотношение сторон. До того, как я это сделал, единственным способом было использовать pdfinfo, чтобы получить размер страницы, а затем выполнить вычисления, чтобы уместить ее в поле, а затем попросить pdfdraw нарисовать ее с этим масштабным коэффициентом (точек на дюйм).

Что ж, после этого длинного рассказа процесс сделать это довольно прост:

  1. получить размер страницы для отображения (в терминах pdf - медиа-блок), это можно сделать через pdfinfo и grep и отобразить в точках (точки, 1/72 дюйма) или через pdf-библиотеку, такую как pyPDF, например:

    import pyPdf
    p = pyPdf.PdfFileReader(file("/home/dan/Desktop/Sieve-JFP.pdf", "rb"))
    x,y,w,h = p.pages[0]['/MediaBox']
    
  2. для коробки подходят dpi = min( A/(w/72.), B/(h/72.) )
    где A - максимальная ширина, а B - максимальная высота; w и h - ширина и высота страницы.

  3. передайте 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");
0

Вы используете неправильную команду. Вместо этого используйте -resample . Желательно также указать конкретную ширину и высоту, если это возможно.

-density это просто флаг. -resample самом деле изменяет размеры в пикселях: единственное значение, которое имеет значение.

редактировать: документ для -resample http://www.imagemagick.org/script/command-line-options.php#resample

Опция -density устанавливает атрибут и не изменяет базовое растровое изображение. Он может использоваться для настройки размера рендеринга для публикации в настольном компьютере путем настройки масштаба, примененного к пикселям. Чтобы изменить размер изображения так, чтобы оно было одинакового размера с другим разрешением, используйте параметр -resample.

На упрощенном уровне в компьютерной графике дюймов не существует. Для растровых изображений сохраняются только пиксели. DPI это просто предложение.

Скажем, у вас есть 3 квадрата на столе и 300 копеек. Если у меня плотность 300 копеек на квадрат, то есть только один квадрат с 300 копейками.

Если я изменю density на 100 pps, у меня теперь будет 3 квадрата, но все равно 300 копеек (100 копеек в каждом квадрате). Вы не изменили количество копеек, только способ, которым вы распределяете копейки по произвольной единице измерения.

Если я resample оригинал в 100pps У меня есть 1 квадрат, и в общей сложности 100 пенсов. Я изменил количество копеек.

Я подозреваю, что в случаях, когда размер страницы увеличивается, вы имеете дело с чем-то с высоким разрешением, например штриховой графикой с разрешением 1200 точек на дюйм, и изменяя density до 300, вы увеличиваете измерение в четыре раза, когда открываете результат с чем-то, что соблюдает флаг ,

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .