PDF = raster, é possível adaptar a resolução de amostragem ao tamanho da página de entrada?

5

Estou usando convert (componente Imagemagick, delegando ao Ghostscript em segundo plano) para transformar a primeira página de arquivos PDF em imagens.

Normalmente, convert -density 200 file.pdf[0] first_page.png fará o trabalho e irá amostrar o arquivo PDF a 200 pixels por polegada de papel.

No entanto, raramente acontece que alguns PDFs sejam anormalmente grandes (por vezes, papel A0 e, recentemente, um PDF com uma página superior a 23 m² (183 polegadas de comprimento, 185 de largura).

Para esses arquivos, convert será interrompido, consumirá o tempo de CPU. Imagens com mais de 35.000 pixels de largura e altura não são utilizáveis.

Portanto, a pergunta: existe uma mudança no Imagemagick que adapte a densidade ao tamanho da página ou, pelo menos, especifique que não queremos amostrar mais do que uma porção da área máxima do arquivo PDF (canto superior esquerdo) , 30x30 polegadas, por exemplo)?

Obrigado.

EDITAR : No seu repositório oficial, o MuPDF adicionou as opções -w e -h que, juntamente com -r , fará o que é desejado aqui.

    
por Benoit 13.02.2012 / 09:21

2 respostas

1

Eu modifiquei o pdfdraw do mupdf para suportar desenho no modo de melhor ajuste, então eu poderia afirmar que a saída precisava ser no máximo 128x128 e caberia na saída na caixa enquanto mantinha a relação de aspecto. Antes de fazer isso, a única maneira era usar o pdfinfo para obter o tamanho da página e depois fazer os cálculos para ajustá-lo em uma caixa e, em seguida, pedir ao pdfdraw para desenhá-lo com esse fator de escala (pontos por polegada).

Bem, depois dessa longa história, o processo para fazer isso é bastante simples:

  1. obtenha o tamanho de página da página para renderizar (em termos de pdf a caixa de mídia) isso pode ser feito via pdfinfo e grep e aparecerá em pts (pontos, 1/72 de polegada) ou via uma biblioteca de pdf como pyPDF como:

    import pyPdf
    p = pyPdf.PdfFileReader(file("/home/dan/Desktop/Sieve-JFP.pdf", "rb"))
    x,y,w,h = p.pages[0]['/MediaBox']
    
  2. para um ajuste de caixa do dpi = min( A/(w/72.), B/(h/72.) )
    onde A é a largura máxima e B é a altura máxima; w e h são a largura e a altura da página.

  3. passar dpi para convert -density $dpi

e conforme solicitado, um diff de confirmação do git ligeiramente falsificado:

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");
    
por 13.02.2012 / 13:01
0

Você está usando o comando errado. Use -resample em vez disso. Também é aconselhável fornecer uma largura e altura específicas, se possível.

-density é meramente um sinalizador. -resample na verdade altera as dimensões do pixel: a única medida que importa.

edite: doc para -resample link

The -density option sets an attribute and does not alter the underlying raster image. It may be used to adjust the rendered size for desktop publishing purposes by adjusting the scale applied to the pixels. To resize the image so that it is the same size at a different resolution, use the -resample option.

Em um nível simplista no CG, polegadas não existem. Para imagens raster, apenas os pixels são armazenados. O dpi é meramente uma sugestão.

Digamos que você tenha 3 quadrados em uma mesa e 300 centavos. Se eu tiver uma densidade de 300 centavos por quadrado, há apenas um quadrado com 300 centavos.

Se eu alterar density para 100 pps, agora tenho 3 quadrados, mas ainda assim 300 centavos no total (100 centavos em cada quadrado). Você não alterou o número de centavos, apenas a maneira pela qual você distribui os centavos através de uma unidade arbitrária de medida.

Se eu resample do original for 100pps, eu tenho 1 quadrado e 100 centavos no total. Eu mudei o número de moedas.

Eu suspeito que nos casos em que o tamanho da página sobe, você está lidando com algo que tinha uma alta resolução, como linha de arte 1200dpi, e alterando a density para 300 quadruplica a medida da polegada quando você abre o resultado com algo que honra a bandeira.

    
por 23.02.2012 / 16:06