Как мне обрезать страницы 3 и 4 в многостраничном PDF с использованием ghostscript

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

gswin64.exe -o cropped.pdf -sDEVICE=pdfwrite  -dFirstPage=3 -dLastPage=4 -c "[/CropBox [24 72 1559 1794]" -c " /PAGES pdfmark" -f input.pdf

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

gswin64.exe -o cropped.pdf -sDEVICE=pdfwrite -c "<</EndPage {0 eq {2 mod 0 eq {[/CropBox [0 0 1612 1792] /PAGE pdfmark true}{[/CropBox [500 500 612 792] /PAGE pdfmark true} ifelse}{false}ifelse}>> setpagedevice" -f input.pdf

Это обрезает все страницы в соответствии с настройками второго CropBox. Если кто-то задается вопросом о больших полях... Я применяю это сделать большие рисунки. Я также пытался заменить некоторые операторы, чтобы применить обрезку только к определенному номеру страницы: "sub 4" вместо "2 mod" была одной попыткой достичь условия " 0 eq" только тогда, когда текущий номер страницы достигнет 4.

1 ответ

Решение

ОК, во-первых, Ghostscript и устройство pdfwrite не "модифицируют" входной PDF-файл. Для постоянных читателей; стандартная лекция здесь, если вы прочитали ее раньше, можете пропустить следующий абзац.

Это работает так, что входной файл полностью интерпретируется в виде последовательности графических примитивов, которые отправляются на устройство. Устройства рендеринга затем вызывают графическую библиотеку для рендеринга примитивов в растровое изображение, которое затем выводится. Высокоуровневые (векторные) устройства, такие как pdfwrite, переводят примитивы в эквивалентные операции на некотором языке описания страниц высокого уровня и генерируют его.

Таким образом, когда вы выбираете -dFirstPage и -dLastPage, это только страницы входного файла, который вы выбираете для обработки. Таким образом, pdfwrite не "удаляет" ваши страницы, вы никогда не отправляли их на устройство.

Теперь Ghostscript является интерпретатором PostScript, и поэтому на его действие могут влиять написание программ на PostScript. В вашем случае вы, вероятно, захотите обработать все страницы (так что опустите -dFirstPage и -dLastPage), но пишите pdfmark только на выбранных страницах.

Это можно сделать с помощью процедуры BeginPage или EndPage. Если вы ищете здесь или в теге PostScript, вы найдете несколько примеров. По сути, обе процедуры до сих пор вызываются с кодом причины и количеством страниц.

Из памяти вы захотите проверить, что код причины равен 2. Если это так, то вы хотите проверить количество страниц, и если оно соответствует вашим критериям (в данном случае, количество равно 3 или 4), выполните /PAGE pdfmark. В любом случае вы хотите вернуть 'true', чтобы страница была выброшена.

[РЕДАКТИРОВАТЬ добавлено здесь]

Хм, хорошо, я вижу проблему. Происходит то, что интерпретатор PDF вызывает 'setpagedevice', чтобы установить размер страницы для каждой страницы, в случае, если размер страницы изменился. Проблема в том, что это сбрасывает счетчик страниц до 0 каждый раз.

Теперь я бы обычно не предлагал следующее, потому что оно опирается на некоторые недокументированные аспекты интерпретатора PDF Ghostscript. Однако я случайно узнал, что интерпретатор PDF отслеживает номер страницы внутри, используя именованный объект с именем /Page#.

Итак, если я возьму код, который вы написали, и слегка его изменим:

<<
  /EndPage {
    0 eq {
      pop /Page# where {
        /Page# get
        3 eq {
          (page 3) == flush
          [/CropBox [0 0 1612 1792] /PAGE pdfmark 
          true
        }
        {
          (not page 3) == flush
          [/CropBox [500 500 612 792] /PAGE pdfmark
          true
        } ifelse
      }{
        true
      } ifelse
    }
    {
      false
    }
    ifelse
  }
>> setpagedevice

Несколько вещей, чтобы отметить; там есть некоторая отладка, строки с == flush распечатывают некоторые вещи на обратном канале, чтобы вы знали, как обрабатывается каждая страница. Если / Page # не определен, то код просто оставляет все в покое, это всего лишь некоторые базовые вещи для обеспечения безопасности.

Вместо того, чтобы вводить все это в командной строке (которая также теряет отступы и плохо читается), я вставил ее в файл с именем test.ps, а затем вызвал GS как:

gswin32c -sDEVICE=pdfwrite -sOutputFile=out.pdf test.ps input.pdf

Это не самое лучшее решение в мире, но оно работает для меня.

Другие вопросы по тегам