Сравнение PDF с использованием pdftk и Ghostscript

Я создал сценарий, который объединяет два PDF-файла в один рядом, просматривая некоторые ответы Курта Пфайфле.

Но моя проблема в том, что код не гибкий. Под этим я подразумеваю, что если один PDF-файл больше или имеет другое разрешение, чем другой PDF-файл, выходной PDF-файл (параллельный PDF-файл) будет плохим.

Иллюстрировано это выглядит так:

Input file: a.pdf
+--------+ 
|        |
|  a     |
|        |
+--------+

Input file: b.pdf
+--------+ 
|        |
|  b     |
|        |
+--------+

Desired output file: compare.pdf
+--------+--------+ 
|        |        |
|   a    |  b     |
|        |        |
+--------+--------+

Поэтому мне нужно убедиться, что оба PDF-файла имеют одинаковый обычный PDF-файл формата A4 и разрешение, прежде чем объединять их? Я пробовал так много кодов и скриптов, но не могу понять этот. Как я могу это сделать? Сценарий должен быть пуленепробиваемым, чтобы можно было использовать и сравнивать любые PDF-файлы. Даже если они не одного размера.

Мой скрипт теперь выглядит так и работает с некоторыми PDF-файлами с одинаковым размером и разрешением:

gswin64c.exe                        ^
          -o c.pdf                  ^
          -sDEVICE=pdfwrite         ^
          -g11690x8270              ^
          -dFIXEDMEDIA              ^
          -dPDFSETTINGS=/prepress   ^
          -r300                     ^
          -c "<</PageOffset [0 0]>>setpagedevice" ^
          -f a.pdf

Это создает файл c.pdf, который выглядит следующим образом:

c.pdf
+--------+--------+ 
|        |        |
|   a    | (empty)|
|        |        |
+--------+--------+

Следующая команда:

gswin64c.exe                       ^
          -o left-side-outputs.pdf ^
          -sDEVICE=pdfwrite        ^
          -g11690x8270             ^
          -dPDFSETTINGS=/prepress  ^
          -c "<</PageOffset [0 0]>>setpagedevice" ^
          -f b.pdf

При этом создается файл left-side-outputs.pdf, который выглядит следующим образом:

left-side-outputs.pdf
+--------+--------+ 
|        |        |
|   b    | (empty)|
|        |        |
+--------+--------+

Следующая команда:

gswin64c.exe                        ^
          -o right-side-outputs.pdf ^
          -sDEVICE=pdfwrite         ^
          -g11690x8270              ^
          -dPDFSETTINGS=/prepress   ^
          -c "<</PageOffset [596 0]>>setpagedevice" ^
          -f c.pdf

При этом создается файл right-side-outputs.pdf, который выглядит следующим образом:

right-side-outputs.pdf
+--------+--------+ 
|        |        |
|(empty) |  b     |
|        |        |
+--------+--------+

Последняя команда:

pdftk left-side-outputs.pdf multistamp right-side-outputs.pdf output compare.pdf

Это создает окончательный результат, compare.pdf:

Desired output file: compare.pdf
+--------+--------+ 
|        |        |
|   a    |  b     |
|        |        |
+--------+--------+

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


person Mark Chabert Bergh    schedule 15.11.2013    source источник
comment
Почему-то ваш рисунок и ваши команды выглядят неправильно. Думаю, я знаю, чего вы пытаетесь достичь. Я отредактирую ваш вопрос. Если я неправильно понял, пожалуйста, верните мои правки...   -  person Kurt Pfeifle    schedule 15.11.2013
comment
Вы смотрели на pdfnup? Это часть pdfjam, внешнего интерфейса для пакета LaTex pdfpages. Он автоматически масштабирует PDF-файлы и работает достаточно надежно.   -  person Jakob    schedule 16.11.2013
comment
@Jakob: pdfnup обычно может быть лучше для выполнения 2-up ... Но в этом случае ваша подсказка мало чем помогает. Во-первых, вопрос явно касался Ghostscript и pdftk. Во-вторых, задача состоит в том, чтобы сравнить 2 разных файла, где одна результирующая двойная страница состоит из страниц из каждого из 2 исходных файлов. Я не знаю прямого способа сделать это с pdfnup...   -  person Kurt Pfeifle    schedule 17.11.2013
comment
@Kurt Pfeifle Вы совершенно правы в вопросе и ограничениях, поэтому я разместил комментарий, а не ответ! Тем не менее, pdfnup — хороший инструмент для создания нескольких PDF-файлов без возни с gs.   -  person Jakob    schedule 17.11.2013


Ответы (2)


На ваш вопрос...

Поэтому мне нужно убедиться, что оба PDF-файла имеют одинаковый обычный PDF-файл формата A4 и разрешение, прежде чем объединять их?

...ответ: 'Да, относительно размера страницы -- Нет, относительно разрешения (не имеет значения).'

Масштабирование страниц PDF с помощью Ghostscript (1)

Команда для масштабирования всех страниц PDF-файла смешанного размера до формата A4 выглядит следующим образом:

 gswin64c.exe           ^
     -o all-a4.pdf      ^
     -sDEVICE=pdfwrite  ^
     -g5950x8420        ^
     -dPDFFitPage       ^
     -f input.pdf

Это также масштабирует размер носителя и содержимое (проверено с GS v9.10).

Параметр -dPDFFitPage всегда будет сохранять соотношение сторон. Он автоматически повернет содержимое, чтобы сделать его наиболее подходящим. Он не допускает растягивание страницы только в одном направлении. Это, однако, может быть достигнуто с помощью следующего метода.


[Обновлять

Я думаю, что один момент об этом методе я донес недостаточно ясно.

Дело в следующем: если соотношение сторон мультимедиа из вашего входного файла уже не совпадает с вашим целевым мультимедиа, то -dPDFFitPage не будет полностью охватывать ваш целевой мультимедиа.

Предполагая, что ваш носитель ввода использует квадратный размер страницы, 500x500 пункта. Если вы обрабатываете это с целевым размером A4 (-g5950x8420), то -dPDFFitPage сохранит квадратное соотношение сторон и создаст выходной размер только -g5950x5950.

Но вы также не можете пропустить -dPDFFitPage -- иначе вы не масштабируете исходный 400x400 контент, а только размещаете его на большей 595x842 странице, помещая ее в левый нижний угол.

Конец обновления.]


Масштабирование страниц PDF с помощью Ghostscript (2)

Команда для масштабирования содержимого всей страницы PDF до 50% от обоих соответствующих размеров:

 gswin64c.exe                                      ^
     -o 50pc.pdf                                   ^
     -sDEVICE=pdfwrite                             ^
     -c "<</Install {.5 .5 scale}>> setpagedevice" ^
     -f input.pdf

Однако это НЕ одновременно масштабирует боксы мультимедиа!

Если вы знаете, что все страницы в вашем PDF-файле имеют одинаковый размер, вы можете использовать это, чтобы масштабировать PDF-файл A3 до A4:

 gswin64c.exe                                      ^
     -o A4-50pc.pdf                                ^
     -g5950x8420                                   ^
     -sDEVICE=pdfwrite                             ^
     -c "<</Install {.5 .5 scale} /AutoRotatePages /None>> setpagedevice" ^
     -f A3.pdf

Однако первая команда в моем ответе, конечно, тоже сработает, и ее проще использовать!

Для A5 -> A4 или A4 -> A3 используйте:

                    {1.415 1.415 scale}

Для A3 -> A4 или A4 -> A5:

                    { .707  .707 scale}

Но теперь все становится еще интереснее, потому что вы также можете 'растягивать' содержимое! Чтобы масштабировать по горизонтали до 75% и по вертикали до 66%, используйте

     -c "<</Install {.75 .666 scale}>> setpagedevice"

Для своего рода 'жидкого' масштабирования между Letter и A4 вы можете использовать следующее:

  • A4 -> Буква: {1.028571 .940617 scale}
  • Буква -> A4: { .972222 1.063131 scale}

Для всего вышеперечисленного вы можете указать значение -gNNNNxMMMM (определяющее фиксированный размер страницы для выходного PDF-файла — размеры в пикселях при внутреннем разрешении устройства pdfwrite по умолчанию, которое составляет 720 пикселей на дюйм, что дает 1 точку PostScript 10 пикселей.. .)-

Если вы не укажете значение -gNNNNxMMMM, будут использоваться исходные размеры страниц (даже если они имеют смешанные значения), но их содержимое будет отображаться на этих страницах с указанным вами коэффициентом масштабирования.

Чего я пока не знаю: метод "жидкого масштабирования" для каждой отдельной страницы PDF-файла разного размера, включая размеры носителя за один раз...

Сравнение файлов формата All-Letter с PDF-файлами формата A5 на основе формата A4:

Предполагая, что теперь вы хотите сравнить PDF-файл размером всего Letter с PDF-файлом формата A5, и вы хотите сначала масштабировать оба до A4, вот что вы должны сделать:

«Жидкое» масштабное письмо на А4:

 gswin64c.exe                                      ^
     -o a4-1.pdf                                   ^
     -sDEVICE=pdfwrite                             ^
     -g5950x8420                                   ^
     -c "<</Install{.972222 1.063131 scale}>>setpagedevice" ^
     -f letter.pdf

«Фиксированный» масштаб от A5 до A4:

 gswin64c.exe                                      ^
     -o a4-2.pdf                                   ^
     -sDEVICE=pdfwrite                             ^
     -g5950x8420                                   ^
     -c "<</Install{1.415 1.415 scale}>>setpagedevice" ^
     -f a5.pdf

или, альтернативно:

 gswin64c.exe          ^
     -o a4-2.pdf       ^
     -sDEVICE=pdfwrite ^
     -g5950x8420       ^
     -dPDFFitPage      ^
     -f a5.pdf

А теперь сравните оба ваших PDF-файла формата А4....

Оптимизация рабочего процесса сравнения

Вы также можете сохранить один шаг рабочего процесса, как указано в вашем вопросе. Вот лучший подход.

Первый шаг: подготовьте левые стороны (как раньше)

Предполагая, что у вас есть вход A4, а конечный результат должен быть A3:

 gswin64c.exe                   ^
      -o left-sides.pdf         ^
      -sDEVICE=pdfwrite         ^
      -g11900x8420              ^
      -c "<</PageOffset [0 0]>>setpagedevice" ^
      -f a.pdf

Это создает:

left-sides.pdf
+--------+--------+   ^
|        |        |   |
|        |        |   |
|  a     |(empty) |  595 pt == 5950 pixels
|        |        |   |
|        |        |   |
+--------+--------+   v

<-----1190 pt----->
   == 11900 pixels

Второй шаг: подготовить правые стороны (все за один раз)

 gswin64c.exe                   ^
      -o right-sides.pdf        ^
      -sDEVICE=pdfwrite         ^
      -g11900x8420              ^
      -c "<</PageOffset [595 0]>>setpagedevice" ^
      -f b.pdf

Это создает:

right-side.pdf
+--------+--------+   ^
|        |        |   |
|        |        |   |
|(empty) |  b     |  595 pt == 5950 pixels
|        |        |   |
|        |        |   |
+--------+--------+   v

<-----1190 pt----->
   == 11900 pixels

Третий шаг: наложите два файла с pdftk

pdftk right-sides.pdf multistamp left-sides.pdf output compare.pdf

or

pdftk left-sides.pdf multistamp right-sides.pdf output compare2.pdf

Это создает:

compare.pdf
+--------+--------+   ^
|        |        |   |
|        |        |   |
|  a     |  b     |  595 pt == 5950 pixels
|        |        |   |
|        |        |   |
+--------+--------+   v

<-----1190 pt----->
   == 11900 pixels

Обновление, касающееся Crop-/Trim-/Art-/Bleed-Box

Еще кое-что.

Иногда приведенные выше команды могут «не казаться» работающими. Причина в том, что PDF-файлы внутренне используют не только наивно предполагаемый «размер страницы», но и более сложную настройку MediaBox (то, что мы обычно называем «размером страницы»), а также TrimBox, BleedBox, ArtBox и CropBox. См. здесь точное описание этих полей. ..

Чтобы проверить ваши файлы PDF (входные данные, а также результаты или промежуточные результаты) для всех значений этих полей, используйте команду pdfinfo:

pdfinfo -f 1 -l 5 -box a.pdf
pdfinfo -f 1 -l 5 -box b.pdf
pdfinfo -f 1 -l 5 -box right-sides.pdf
pdfinfo -f 1 -l 5 -box left-sides.pdf
pdfinfo -f 1 -l 5 -box compare.pdf

CropBox заставляет средства просмотра PDF (и принтеры) отображать (или печатать) только ту часть содержимого, которая находится на MediaBox, если она определена иначе, чем MediaBox, может помешать задаче масштабирования. Он не будет затронут Ghostscript, если он его увидит.

Может случиться так, что файл был успешно обработан, но в просмотрщике он по-прежнему показывает вам ту же область просмотра на странице.

Чтобы «обезвредить» эффект этих полей, вы можете использовать очень грубый трюк: переименовать эти строки в PDF-файле в имена, состоящие только из строчных букв. Вот как это сделать с помощью командной строки sed (может быть недоступно в Windows):

cat input.pdf                    \
   | sed 's#CropBox#cropbox#g'   \
   | sed 's#TrimBox#trimbox#g'   \
   | sed 's#BleedBox#bleedbox#g' \
   | sed 's#ArtBox#artbox#g'     \
> disarmed.pdf

или как-то короче, но не так просто для разбора:

sed 's#CropB#cropb#g;s#TrimB#trimb#g;s#BleedB#bleedb#g;s#ArtB#artb#g' \
  in.pdf > out.pdf

Поскольку Ghostscript представляет собой двоичный формат файла, с некоторыми версиями sed вы можете столкнуться с сообщением об ошибке:

sed: ошибка RE: недопустимая последовательность байтов

В этом случае попробуйте другой вариант, например GNU sed, gsed...

person Kurt Pfeifle    schedule 15.11.2013
comment
вау, большое спасибо, Курт - ты приложил много усилий к своему ответу - очень ценю это. Теперь нужно провести небольшое тестирование :-) У меня есть еще одна проблема, с которой, надеюсь, вы мне поможете. Если вы попытаетесь сделать этот PDF-файл шириной 11900 пикселей, это просто не удастся сделать, вы можете понять, почему? gassalg.dk/~/media/gassalg.dk/dokumenter/ регнскаб/ - person Mark Chabert Bergh; 16.11.2013
comment
Код довольно стандартный, но он не может изменить размер PDF: gswin64c.exe -o left-side-outputs.pdf -sDEVICE=pdfwrite -g11900x8420 -dFIXEDMEDIA b.pdf - person Mark Chabert Bergh; 16.11.2013
comment
@MarkChabertBergh: Ссылка, которую вы дали, возвращает мне пустую страницу... -- -dFIXEDMEDIA не из моей команды. Как я указал в комментарии к KenS, -dFIXEDMEDIA в любом случае автоматически подразумевается при использовании -gNNNxMMM. Что gswin64c.exe -version возвращает для вас? -- Что вы подразумеваете под 'это просто невозможно'?? Какие-нибудь сообщения об ошибках вы получаете? - person Kurt Pfeifle; 16.11.2013
comment
gswin64c.exe -version возвращает Ghostscript 9.10 (30 августа 2013 г.). Я удалил dFIXEDMEDIA сейчас. Я не получаю никаких сообщений об ошибках, но Ghostscript просто не может увеличить ширину PDF до 11900 пикселей, как того требует сценарий. Выходной файл остается той же ширины.? Не могу понять, почему и как это тогда должно быть сделано? Это только один файл, который не работает, но я нашел довольно много, где код просто не может изменить ширину. wikisend.com/download/524852/ - person Mark Chabert Bergh; 16.11.2013
comment
@MarkChabertBergh: Вы действительно читали мое последнее обновление (сделанное за девять часов до вашего комментария)?! Тот, что касается коробок {Trim, Bleed, Crop, Art}? Это то, что вызывает проблему... Там также есть "исправление"... - person Kurt Pfeifle; 17.11.2013
comment
Извините, не видел вашего обновления, но вы были правы. Я использую машину с Windows, но удалил коробки с помощью дополнительных инструментов PDF, и теперь это работает как шарм.! Большое спасибо, Курт, без тебя я бы никогда не нашел решение! - person Mark Chabert Bergh; 17.11.2013

Файлы PDF не содержат разрешения, так что это не может быть проблемой. Обычно я бы не использовал -r с Ghostscript, все, что нужно сделать, это указать разрешение, при котором любой контент, который не может быть передан «как есть» в файл PDF, обрабатывается, чтобы превратить его в изображение. Это не влияет на размер или размещение этого контента.

Вам не нужно /PageOffset, я не думаю, что это вообще повлияет (если входной файл PDF).

Я бы НЕ использовал /PDFSETTINGS. Используя это, вы импортируете все виды готовых настроек, если вы не уверены, что все это именно то, что вам нужно, вам гораздо лучше использовать значения по умолчанию и переключать любые переключатели, которые вы хотите изменить по отдельности.

Вы можете очень хорошо поставить /AutoRotatePages=/None, потому что в противном случае pdfwrite попытается заставить большую часть текста работать слева, чтобы писать горизонтально.

Вы дважды конвертируете один из файлов, этого следует избегать, чем больше конвертаций, тем больше вероятность проблем.

Вы указали размеры носителей для всех трех входных данных Ghostscript, но не указали FIXEDMEDIA для двух из них. Для одного это, вероятно, нормально, потому что это повторная обработка первого (где вы указываете FIXEDMEDIA), но как насчет второго экземпляра?

Вы на самом деле не говорите, в чем проблема, с которой вы столкнулись. Вы также не говорите о проблемах, проявляющихся в отдельных файлах или только тогда, когда вы используете pdftk для их объединения. Без этой информации и некоторых примеров файлов, демонстрирующих проблему, невозможно дать вам больше рекомендаций.

Да, и, кстати, вы могли бы на самом деле сделать n-up верстку, как это, напрямую с Ghostscript, хотя вам придется проделать больше работы, чем с помощью pdftk. Приложив немного усилий, я, вероятно, мог бы сделать все это за один вызов Ghostscript.

person KenS    schedule 15.11.2013
comment
Большое спасибо, что нашли время! Как это можно сделать при n-up вёрстке с ghostscript? Мне нужно, чтобы страницы были рядом друг с другом на одной странице (тогда она в два раза шире обычного формата A4) - person Mark Chabert Bergh; 15.11.2013
comment
@KenS: указание размера носителя с помощью -gNNNxMMM подразумевает -dFIXEDMEDIA, нет? Так что нет необходимости даже указывать его на две команды, которые его пропустили... - person Kurt Pfeifle; 15.11.2013
comment
@KenS: О, мне также было бы интересно увидеть результат вашего 'небольшого усилия сделать все это одним вызовом Ghostscript'. Было бы очень здорово узнать об этом, и мы были бы очень признательны! ;-) - person Kurt Pfeifle; 15.11.2013
comment
Боюсь, я не предлагал это сделать, просто отметил, что это можно сделать. Обратите внимание, что если вы хотите изменить/масштабировать страницы в PDF-файле смешанного размера, вы можете переопределить setpagedevice. Каждый раз, когда изменяется размер страницы PDF, Ghostscript будет выполнять setpagedevice с аргументом словаря, содержащим /PageSize. Таким образом, ваша переопределенная функция может проверить словарь на наличие этого ключа. Если он присутствует, вы заменяете массив соответствующим размером, а также вставляете/заменяете матрицу /Install для масштабирования CTM. Я не пробовал это, но это должно сработать, я использовал подобный трюк раньше. - person KenS; 16.11.2013