Использование Ghostscript, как разместить номера страниц в комбинированных файлах PDF - PullRequest
0 голосов
/ 21 июня 2019

Используя только Ghostscript на довольно закрытой «голой» машине Linux, мне нужно объединить три существующих PDF-файла в новый PDF-файл, наложить статический заголовок на каждую страницу нового PDF-файла, наложить статический нижний колонтитул на каждую страницу нового PDF-файла.PDF и нумерация каждой из страниц (например, «Страница 1257»).

У меня есть решения первых трех проблем.Ghostscript из коробки может легко объединить несколько PDF-файлов в один новый PDF-файл.Работая с PostScript в опции командной строки -c, я могу добавить статический верхний и нижний колонтитулы в новый PDF.Что я пока не могу сделать, так это заставить номера страниц в новом PDF-файле.

Это сложная командная строка, которая у меня теперь есть:

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=final.pdf -c "<</EndPage {2 ne {200 0 0 setrgbcolor /NimbusSans-Bold 24 selectfont 240 2 moveto (Static Footer) show 240 773 moveto (Static Header) show 0 0 0 setrgbcolor /NimbusSans-Regular 12 selectfont 2 24 moveto (Page ) show true}{pop false} ifelse} >> setpagedevice" -f title.pdf parta.pdf partb.pdf

Удаление статического верхнего и нижнего колонтитуловв несколько более простую командную строку:

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=final.pdf -c "<</EndPage {2 ne {0 0 0 setrgbcolor /NimbusSans-Regular 12 selectfont 2 24 moveto (Page ) show true}{pop false} ifelse} >> setpagedevice" -f title.pdf parta.pdf partb.pdf

Я пробовал много вещей, чтобы показать номер страницы, но они либо приводили к сбою Ghostscript, либо просто отображали один и тот же номер страницы на каждой странице.Единственное другое осложнение заключается в том, что новый PDF будет содержать от 1000 до 2000 страниц.

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

1 Ответ

0 голосов
/ 25 июня 2019

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

Мы начинаем с создания собственного словаря, в котором мы можем хранитьвещи.Мы уверены, что это определено в 'userdict', чтобы мы всегда могли его найти (userdict, как и systemdict, всегда доступен).Выбранное имя должно быть уникальным, чтобы другие программы PostScript или PDF не перезаписывали его!

userdict begin                  %% Make userdict the current dictionary
/My_working_Dict                %% Create a name for our dict (choose something unique)
10 dict                         %% create a 10-element dictionary
def                             %% def takes a key and value and puts them in the current dictionary
My_working_Dict begin           %% make our working dictionary the current one
/PageCount                      %% Make a name for our counter
0                               %% 0, this will be the initial value
def                             %% define PageCount as 0 in the current dictionary
end                             %% close the current dictionary (My_working_Dict)
end                             %% close the current dictionary (userdict)

Есть более эффективные способы сделать это, но это простой способ описать и следовать.С этого момента, пока мы не закроем интерпретатор PostScript (или не вернем его в более раннее состояние), userdict будет содержать словарь My_working_Dict, в котором будет ключ PageCount.Значение, связанное с PageCount, изначально будет равно 0, но мы можем изменить это.

Вы определили процедуру EndPage следующим образом:

<<
  /EndPage {
    2 ne {
      200 0 0 setrgbcolor
      /NimbusSans-Bold 24 selectfont
      240 2 moveto 
      (Static Footer) show
      240 773 moveto
      (Static Header) show
      0 0 0 setrgbcolor
      /NimbusSans-Regular 12 selectfont
      2 24 moveto
      (Page ) show
      true
    }
    {
      pop
      false
    } ifelse
  }
>> setpagedevice

Теперь, когда вызывается процедура EndPage, естьэто два числа в стеке, самое верхнее число - это «код причины», а следующее число - количество предыдущих выполнений showpage.Теперь вы можете подумать (разумно), что вы можете использовать это количество для количества страниц, но, к сожалению, оно сбрасывается до 0 при каждом вызове setpagedevice, и интерпретатор PDF вызывает setpagedevice на каждой странице, потому что это возможно для каждой страницы в PDF.размер файла должен быть разным, а setpagedevice - это то, как мы меняем размер страницы.

Когда мы возвращаемся из процедуры EndPage, мы должны поместить логическое значение в стек, которое либо «true» (отправить страницу наoutput) или 'false' (выбросьте его и ничего не делайте).

Итак, ваша процедура проверяет код причины, чтобы увидеть, почему был вызван EndPage.Если это не «2» (устройство деактивируется), то это либо страница для копирования, либо страница для показа, поэтому вы рисуете нужные дополнения на странице.Если это 2, тогда мы просто выталкиваем количество страниц и возвращаем «ложь», чтобы не пытаться создать дополнительную страницу.

Если это 2, тогда вы устанавливаете цвет на RGB черный (вывместо этого можно сделать 0 setgray) найти шрифт NimbusSans-Bold, масштабировать его до 24 и установить в качестве текущего шрифта.Затем вы перемещаетесь в положение x = 240, y = 2 (0,0 слева внизу, а единицы измерения - точки, 1/72 дюйма) и рисуете текст «Статический нижний колонтитул» (скобки NB являются разделителями строк в PostScript)

Затем вы перемещаетесь в положение x = 240, y = 773 и рисуете текст «Статический заголовок».

Затем вы снова устанавливаете цвет без необходимости, вам не нужно этого делать,он остается неизменным, пока вы его не измените, и снова не найдете шрифт NimbusSans-Bold, на этот раз масштабируя его до 12 точек и выбирая его в качестве текущего шрифта.Наконец, вы перемещаетесь в положение x = 2, y = 24 и рисуете текст «Страница».

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

Что-то вроде:

userdict begin                  %% Make userdict the current dictionary
/My_working_Dict                %% Create a name for our dict (choose something unique)
10 dict                         %% create a 10-element dictionary
def                             %% def takes a key and value and puts them in the current dictionary
My_working_Dict begin           %% make our working dictionary the current one
/PageCount                      %% Make a name for our counter
0                               %% 0, this will be the initial value
def                             %% define PageCount as 0 in the current dictionary
end                             %% close the current dictionary (My_working_Dict)
end                             %% close the current dictionary (userdict)

<<
  /EndPage {
    2 ne {
      0 0 0 setrgbcolor
      /NimbusSans-Bold 24 selectfont
      240 2 moveto 
      (Static Footer) show
      240 773 moveto
      (Static Header) show
      0 0 0 setrgbcolor
      /NimbusSans-Regular 12 selectfont
      2 24 moveto
      (Page ) show

      userdict /My_working_Dict get   %% get My_working_dict from userdict (leaves My_working_dict on the operand stack
      dup                             %% duplicate the dictionary reference
      /PageCount get                  %% get PageCount from the dictionary on the stack
      1 add                           %% add one to the count
      /PageCount                      %% put the key on the stack
                                      %% stack now holds << >> int /PageCount
                                      %% where << >> is a reference to My_working_Dict, int is our new value for PageCount, and /PageCount is the key name we are using
      exch                            %% swap the topmost two stack items
                                      %% stack is now << >> /PageCount int
      put                             %% puts the top two items on the stack into the dictionary which is third on the stack.

      256 string                      %% Temporary string to hold the count
      userdict /My_working_Dict get   %% get My_working_dict from userdict (leaves My_working_dict on the operand stack
      /PageCount get                  %% get PageCount from the dictionary on the stack
      exch
      cvs                             %% Convert the top object on the stack into a string, storing the result in the second object down, whic must be a string
      show                            %% draw the string on the page using the current colour and font.
      true
    }
    {
      pop
      false
    } ifelse
  }
>> setpagedevice

Затем вы выполните Ghostscript с помощью:

gs -dNOPAUSE -dBATCH -sDEVICE = pdfwrite -sOutputFile = final.pdf modifyPDF.ps title.pdf parta.pdf partb.pdf

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

[Обновление 2]

Эта программа в основном такая же, но хранит переменную в глобальном виртуальном виртуальном хранилище для сохранения / восстановления.

globaldict begin                %% Make globaldict the current dictionary
currentglobal true setglobal    %% We need to make the VM allocation mode for the dictionary global
/My_working_Dict                %% Create a name for our dict (choose something unique)
10 dict                         %% create a 10-element dictionary
def                             %% def takes a key and value and puts them in the current dictionary
setglobal           %% put the VM allocation mode back
globaldict /My_working_Dict     %% Get the dictionary from globaldict
get begin                       %% make our working dictionary the current one
/PageCount                      %% Make a name for our counter
0                               %% 0, this will be the initial value
def                             %% define PageCount as 0 in the current dictionary
end                             %% close the current dictionary (My_working_Dict)
end                             %% close the current dictionary (globaldict)

<<
  /EndPage {
    2 ne {
      0 0 0 setrgbcolor
      /NimbusSans-Bold 24 selectfont
      240 2 moveto 
      (Static Footer) show
      240 773 moveto
      (Static Header) show
      0 0 0 setrgbcolor
      /NimbusSans-Regular 12 selectfont
      2 24 moveto
      (Page ) show

      globaldict /My_working_Dict get %% get My_working_dict from globaldict (leaves My_working_dict on the operand stack
      dup                             %% duplicate the dictionary reference
      /PageCount get                  %% get PageCount from the dictionary on the stack
      1 add                           %% add one to the count
      /PageCount                      %% put the key on the stack
                                      %% stack now holds << >> int /PageCount
                                      %% where << >> is a reference to My_working_Dict, int is our new value for PageCount, and /PageCount is the key name we are using
      exch                            %% swap the topmost two stack items
                                      %% stack is now << >> /PageCount int
      put                             %% puts the top two items on the stack into the dictionary which is third on the stack.
      globaldict /My_working_Dict get %% get My_working_dict from globaldict (leaves My_working_dict on the operand stack
      /PageCount get                  %% get PageCount from the dictionary on the stack
      256 string                      %% Temporary string to hold the count
      globaldict /My_working_Dict get %% get My_working_dict from globaldict (leaves My_working_dict on the operand stack
      /PageCount get                  %% get PageCount from the dictionary on the stack
      exch
      cvs                             %% Convert the top object on the stack into a string, storing the result in the second object down, whic must be a string
      show                            %% draw the string on the page using the current colour and font.
      true
    }
    {
      pop
      false
    } ifelse
  }
>> setpagedevice

У меня естьпопробовал это на прилагаемом примере, и он работает для меня.

...