Использование Ghostscript для пакетного добавления номеров страниц

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

У меня есть пакетный файл, который принимает 2 входа: входной PDF и выходной PDF.

@echo off
setlocal

REM Check if the correct number of arguments is provided
if "%~1"= = "" (
    echo Usage: %0 input.pdf output.pdf
    exit /b 1
)

if "%~2"= = "" (
    echo Usage: %0 input.pdf output.pdf
    exit /b 1
)

REM Input and output files
set INPUT_PDF=%~1
set OUTPUT_PDF=%~2

REM Temp file for the page numbering PostScript
set PSF_SCRIPT = "C:\Temp\GhostScript\AddPageNum.ps"
    
REM Run Ghostscript to add page numbers
"C:\Program Files\gs\gs9.53.3\bin\gswin64c.exe" -o %OUTPUT_PDF% -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -dQUIET -dPDFFitPage -c "/Times-Roman findfont 12 scalefont setfont" -c "/showpage {showpage /PageCount 1 add def} def" -f %INPUT_PDF% -f %PSF_SCRIPT%

endlocal
echo Page numbers added to %OUTPUT_PDF%

Мой постскриптум, AddpageNum.ps

/Times-Roman findfont 12 scalefont setfont
/pageNum 1 def
<<
/EndPage {
 2 eq {
   gsave
   0.95 setgray
   /Times-Roman findfont 12 scalefont setfont
   0.5 setgray
   72 36 moveto
   pageNum 40 string cvs show
   grestore
   /pageNum pageNum 1 add def
   true
 } if
} bind
>> setpagedevice

При запуске пакетного файла в командной строке

C:\Users\psun0>C:\Temp\GhostScript\AddPageNum.bat input.pdf output.pdf

Когда я запускаю пакетную команду, появляется новое приглашение и файл не создается.

Я не знаю, как устранить эту неполадку, поскольку у меня нет опыта работы с PostScript или Ghostscript.

можете ли вы отключить эхо для отладки?

Stefan Hegny 28.07.2024 17:55

просто уточню: показанный скрипт работает для одного файла, вам просто нужен способ обработки многих файлов?

Stephan 28.07.2024 18:05

В данный момент это вообще не работает..И. Планируем сначала попытаться заставить это работать, а затем выяснить основную работу

Peter Sun 28.07.2024 18:49

что касается «массовой работы»: вы можете вызвать свой «однофайловый» скрипт для каждого файла с помощью cd /d "L:\ocation to\pdf-files" и for %%A in (*.pdf) do call "C:\Temp\GhostScript\GetNumPages.bat" "%%A" "processed\%%~nxA". Я не могу помочь вам с проблемой Post-/Ghostscript, так как у меня нет с этим опыта.

Stephan 28.07.2024 19:37

Просто комментарии к отправленному вами коду. Пожалуйста, сообщите своим конечным пользователям, чтобы они использовали рекомендуемые и надежные аргументы. Для этого измените оба экземпляра echo Usage: %0 input.pdf output.pdf на Echo Usage: %0 "input.pdf" "output.pdf". Удалите эти три строки REM Input and output files, set INPUT_PDF=%~1, set OUTPUT_PDF=%~2. Используйте Set "PSF_SCRIPT=C:\Temp\GhostScript\AddPageNum.ps" вместо set PSF_SCRIPT = "C:\Temp\GhostScript\AddPageNum.ps".

Compo 28.07.2024 20:11

Тогда используйте "%ProgramFiles%\gs\gs9.53.3\bin\gswin64c.exe" -o "%~2" -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -dQUIET -dPDFFitPage -c "/Times-Roman findfont 12 scalefont setfont" -c "/showpage {showpage /PageCount 1 add def} def" -f "%~1" -f "%PSF_SCRIPT%" вместо "C:\Program Files\gs\gs9.53.3\bin\gswin64c.exe" -o %OUTPUT_PDF% -sDEVICE=pdfwrite -dBATCH -dNOPAUSE -dQUIET -dPDFFitPage -c "/Times-Roman findfont 12 scalefont setfont" -c "/showpage {showpage /PageCount 1 add def} def" -f %INPUT_PDF% -f %PSF_SCRIPT%.

Compo 28.07.2024 20:11

@Compo, хотя ваше знание скриптов идеальное, команду GS можно модернизировать, поскольку текущая защищенная версия GS — 10.03.1, поэтому абсолютно нет нормальной необходимости в -dBATCH -dNOPAUSE -dQUIET также неясно, почему используется Times-Roman, поскольку это проблема. Устаревшее имя Adobe и GS, возможно, будут использовать Nimbus в качестве шрифта, поставляемого GS.

K J 28.07.2024 20:28

Первая ошибка при правильном запуске должна быть Error: /undefinedfilename in (findfont)

K J 28.07.2024 20:33

Если мне нужны номера страниц, я бы использовал приложение командной строки для выполнения такой простой задачи, как методология BATES (один exe-файл, одна строка), но для использования GS это будет так же просто, как запуск каждого файла gs.lnk -sDEVICE=pdfwrite -o"%cd%\output.pdf" "%cd%\numpages.ps" "%cd%\input.pdf", потому что все сценарии выполняются с использованием файла PostScript. и нет необходимости в устаревших методах, это 10.3.1 и шрифт будет Nimbus-Sans Regular Page 1 будет NimbusSans-Regular (Type1; Ansi; embedded)

K J 28.07.2024 20:50

@KJ, просто чтобы уточнить: мои комментарии были конкретными, поскольку касались только представленного ими кода. Я не пытался решить проблему, о которой они сообщили, или изменить используемые gswin64c.exe параметры/аргументы.

Compo 28.07.2024 21:48

@Compo Я ЗНАЮ, как указано в вашем exePert в этой части, но это проблема XY, исходная предпосылка неверна. Postscript - это программирование на Turin Stack, и он лучше всего самодостаточен, поэтому для ввода > действия > вывода необходимо изменить только имена ИЛИ на практике -oOUTPUT<actions<inputs

K J 28.07.2024 21:53
Как конвертировать HTML в PDF с помощью jsPDF
Как конвертировать HTML в PDF с помощью jsPDF
В этой статье мы рассмотрим, как конвертировать HTML в PDF с помощью jsPDF. Здесь мы узнаем, как конвертировать HTML в PDF с помощью javascript.
Включение UTF-8 в jsPDF с помощью Angular
Включение UTF-8 в jsPDF с помощью Angular
Привет, разработчики, я предполагаю, что вы уже знаете, как экспортировать pdf через jsPDF. Если ответ отрицательный, то вы можете ознакомиться с моей...
1
11
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Другие дали хороший совет в комментариях, предложив файл с отзывами, например, этот потенциальный сингл run.cmd. Он не должен работать в полном объеме, но выдаст ложный результат и позволит вам увидеть ошибки.

ПРИМЕЧАНИЕ. Для GhostScript требуются полные имена файлов с учетом регистра, поэтому используются %~f1" и %~f2".

@echo off

REM Check if the correct number of arguments is provided
if "%~1"= = "" ( echo Usage: %0 input.pdf output.pdf & exit /b 1 )
if "%~2"= = "" ( echo Usage: %0 input.pdf output.pdf & exit /b 1 )

REM Input and output files
set "INPUT_PDF=%~f1"
set "OUTPUT_PDF=%~f2"

REM Temp file for the page numbering PostScript
set "PSF_SCRIPT=C:\Temp\GhostScript\AddPageNum.ps"
    
REM Run Ghostscript to add page numbers
"C:\Program Files\gs\gs10.03.1\bin\gswin64c.exe" -o"%OUTPUT_PDF%" -sDEVICE=pdfwrite -dPDFFitPage "%PSF_SCRIPT%" -c "/Times-Roman findfont 12 scalefont setfont" -c "/showpage {showpage /PageCount 1 add def} def" -f "%INPUT_PDF%"

if exist %OUTPUT_PDF% echo Page numbers added to %OUTPUT_PDF%

Скорее всего, результат должен быть чем-то вроде

Loading NimbusRoman-Regular font from %rom%Resource/Font/NimbusRoman-Regular... 3865264 2515446 1741192 449709 1 done.
Processing pages 1 through 1.
Page 1
   **** Error: Page drawing error occurred.
               Could not draw this page at all, page will be missing in the output.
GPL Ghostscript 10.03.1: Page object was reserved for an Annotation destination, but no such page was drawn, annotation in output will be invalid.

Page numbers added to C:\blah blah\output.pdf

Обратите внимание, что упомянутый шрифт НЕ Times, который является «суррогатным» именем шрифта, предпринятый шрифт будет Nimbus, и если Times действительно отображается как вынужденный, он будет без шрифта (не встроен). Что вам нужно, это

Loading NimbusRoman-Regular font from %rom%Resource/Font/NimbusRoman-Regular... 3865264 2515400 1915392 597811 1 done.
Processing pages 1 through 1.
Page 1
Loading NimbusSans-Bold font from %rom%Resource/Font/NimbusSans-Bold... 4025408 2714730 2136536 804225 2 done.
Page numbers added to C:\blah blah\output.pdf

с отчетом со встроенным шрифтом

Это делается путем удаления всех этих плохих внешних указаний и упрощения до:

"C:\Program Files\gs\gs10.03.1\bin\gswin64c.exe" -o"%OUTPUT_PDF%" -sDEVICE=pdfwrite -dPDFFitPage "%PSF_SCRIPT%" -f "%INPUT_PDF%"

И предоставьте более полный современный AddPageNum.ps, чтобы использовать аналогичный ответ в следующем духе.

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 12 selectfont
      72 36 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

Я получаю сообщение: «Система не может найти указанный путь». Наверное потому, что у меня нет шрифта Nimbus? Это то, что мне нужно скачать и установить? Спасибо за ответ, совершенно не в моей рубке.

Peter Sun 28.07.2024 23:56

если вы правильно установили GS, шрифты ищутся в правильных местах ресурсов (включая шрифты Windows), поэтому вы потенциально можете использовать локальный, но нет СТАРОЙ Helvetica или Ancient Times-Roman и т. д., если вы точно не определите, какая замена является почему по умолчанию GhostScript использует собственную замену Nimbus. Я настоятельно рекомендую переустановить, поскольку версии 10.03.1 (текущая)/10.04 (следующая) безопаснее, однако отчеты КАКАЯ СТРОКА не найдена?

K J 29.07.2024 00:00

я понял это... мой путь к gs был неправильным... есть ли способ передать количество страниц? я хочу, чтобы он указал страницу x из y?

Peter Sun 29.07.2024 14:55

хорошо, часто проблема с таким вызовом возникает из-за простой оплошности, поэтому не используйте отключение эха до тех пор, пока вам не перестанут видеть сообщения об ошибках. Код PS не принадлежит мне, но исходит от сотрудников службы поддержки GS, поэтому он адаптирован для обеспечения нескольких входных данных (объединенный файл или одна страница), и вы также должны иметь возможность добавлять другой текст или начинать с произвольного числа, изменив преамбулу, чтобы PDF учитывался. от 0 до героя, что 0 — это начальный номер (1-я страница), и он выводит плюс 1, пока все страницы не будут исчерпаны. ОДНАКО все PDF-файлы не знают, сколько страниц у них есть, поэтому страница № бесконечности - это все, что они изначально знают.

K J 29.07.2024 15:07

Существует два подхода к странице x из y: один — позволить PS дважды передать весь файл, чтобы получить номер последней страницы, или использовать две командные строки, где одна передает другую, но это проблема, с которой вы начали с нескольких неработающих вызовов. Серьезно, есть гораздо более простые методы, такие как pdfcpu stamp add -mode text -- "Page %p of %P" "scale:1.0 abs, pos:bc, rot:0" in.pdf out.pdf

K J 29.07.2024 15:14

я попробую pdfcpu

Peter Sun 29.07.2024 15:39

синтаксис может быть «причудливым», поэтому bc выше — это нижний центр, но он также использует позиции XY и должен иметь возможность использовать именованные шрифты. еще один аналогичный инструмент — cpdf Coherent Community.

K J 29.07.2024 15:41

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