Как добавить номера страниц в Postscript/PDF

Если у вас есть большой документ (более 500 страниц) в Postscript и вы хотите добавить номера страниц, кто-нибудь знает, как это сделать?


person Brian M. Hunt    schedule 21.10.2009    source источник
comment
Переопределите оператор showpage, как показано в этом ответе, по существу повторяющийся вопрос   -  person RedGrittyBrick    schedule 27.09.2013
comment
См. отличное решение Алана Манна для TeX SE.   -  person Faheem Mitha    schedule 04.03.2016


Ответы (14)


Это может быть решением:

  1. преобразовать постскриптум в pdf с помощью ps2pdf
  2. создайте файл LaTeX и вставьте страницы с помощью пакета pdfpages (\includepdf)
  3. используйте pagecommand={\thispagestyle{plain}} или что-то из пакета fancyhdr в аргументах \includepdf
  4. если требуется вывод постскриптума, преобразуйте вывод pdflatex обратно в постскриптум через pdf2ps
person rcs    schedule 21.10.2009
comment
Я думаю, что это отличная идея, но у меня она не работает. Номера страниц не вставляются поверх страниц \includepdf. - person Brian M. Hunt; 22.10.2009
comment
Вы использовали что-то вроде \includepdf[pages=-,pagecommand={\thispagestyle{plain}}]{document.pdf}? - person rcs; 22.10.2009
comment
По сути, это то, что делает Алан Манн в своем решении, за исключением PS. - person Faheem Mitha; 04.03.2016

Основываясь на предложенном решении rcs, я сделал следующее:

Преобразовал документ в example.pdf и запустил pdflatex addpages, где addpages.tex означает:

\documentclass[8pt]{article}
\usepackage[final]{pdfpages}
\usepackage{fancyhdr}

\topmargin 70pt
\oddsidemargin 70pt

\pagestyle{fancy}
\rfoot{\Large\thepage}
\cfoot{}
\renewcommand {\headrulewidth}{0pt}
\renewcommand {\footrulewidth}{0pt}

\begin{document}
\includepdfset{pagecommand=\thispagestyle{fancy}}
\includepdf[fitpaper=true,scale=0.98,pages=-]{example.pdf}
% fitpaper & scale aren't always necessary - depends on the paper being submitted.
\end{document}

или, альтернативно, для двусторонних страниц (т.е. с постоянным номером страницы снаружи):

\documentclass[8pt]{book}
\usepackage[final]{pdfpages}
\usepackage{fancyhdr}

\topmargin 70pt
\oddsidemargin 150pt
\evensidemargin -40pt

\pagestyle{fancy}
\fancyhead{} 
\fancyfoot{} 
\fancyfoot[LE,RO]{\Large\thepage}

\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}

\begin{document}
\includepdfset{pages=-,pagecommand=\thispagestyle{fancy}}
\includepdf{target.pdf}
\end{document}

Простой способ изменить поля заголовка:

% set margins for headers, won't shrink included pdfs
% you can remove the topmargin/oddsidemargin/evensidemargin lines
\usepackage[margin=1in,includehead,includefoot]{geometry}
person Brian M. Hunt    schedule 22.10.2009
comment
Это выглядит хорошо. Однако кажется, что он удаляет внутренние закладки из example.pdf. - person Eric Duminil; 24.06.2021

вы можете просто использовать

pspdftool

этим способом:

pspdftool 'number(x=-1pt,y=-1pt,start=1,size=10)' input.pdf output.pdf

см. эти два примера (ненумерованный и нумерованный pdf с pspdftool)

ненумерованный pdf

http://ge.tt/7ctUFfj2

пронумерованный pdf

http://ge.tt/7ctUFfj2

с этим в качестве первого аргумента командной строки:

number(start=1, size=40, x=297.5 pt, y=10 pt)
person Dingo    schedule 27.01.2012
comment
Говоря о неработающих ссылках, эти гиперссылки в формате .pdf не работают. - person foobarbecue; 11.01.2017
comment
извините, постараюсь заменить как можно скорее - person Dingo; 11.01.2017
comment
По состоянию на апрель 2017 г. ссылки ifile.it не работают. - person Fractalizer; 12.04.2017
comment
извините за мертвые ссылки, я постараюсь заменить как можно скорее - person Dingo; 12.04.2017
comment
ссылки обновлены и теперь работают; спасибо, что предупредили ;-) - person Dingo; 12.04.2017
comment
Доступно ли pspdftool в macOS? - person HappyFace; 11.06.2021

Раньше я добавлял номера страниц в свой pdf-файл, используя латекс, как в принятом ответе.

Теперь я нашел более простой способ: используйте enscript для создания пустых страниц с заголовком, содержащим номер страницы, а затем используйте pdftk с опцией multistamp, чтобы поместить заголовок в файл.

Этот скрипт bash ожидает, что файл pdf будет единственным параметром:

#!/bin/bash
input="$1"
output="${1%.pdf}-header.pdf"
pagenum=$(pdftk "$input" dump_data | grep "NumberOfPages" | cut -d":" -f2)
enscript -L1 --header='||Page $% of $=' --output - < <(for i in $(seq "$pagenum"); do echo; done) | ps2pdf - | pdftk "$input" multistamp - output $output
person Dario Seidl    schedule 27.01.2012
comment
предупреждение для других пользователей: только поскольку сборка 1.43 pdftk имеет функцию multistamp - что касается кода, я могу предложить output=${1%03d.pdf}-header.pdf иметь нулевое выравнивание - person Dingo; 01.02.2012
comment
Мультиштамп отличный. Enscript, однако, не очень гибок для этого варианта использования - я пытался получить номера строк по центру нижнего колонтитула, с нужным мне шрифтом и т. д. В итоге я создал 1000 страниц с помощью моего текстового процессора с автоматическими номерами строк. в нижнем колонтитуле. Затем я просто мультиштампую его в своих файлах. - person Chris Lercher; 07.10.2012
comment
Это не работает для меня. Bucle не выполняет итерацию, я пробовал жестко закодировать значение $pagenum, но ничего. - person xsubira; 11.11.2014
comment
Для меня dump_data дает строку для каждой страницы, а seq выдает ошибку. С дополнительным хвостом -n1 у меня сработало: pagenum=$(pdftk $input dump_data | grep NumberOfPages | cut -d: -f2 | tail -n1) - person Weidenrinde; 23.12.2016
comment
Не могли бы вы немного объяснить это для начинающих, таких как я. - person rahim.nagori; 19.08.2020
comment
brew install pdftk-java для macOS. - person HappyFace; 11.06.2021
comment
Как мы перемещаем положение заголовков? - person HappyFace; 11.06.2021

Я искал решение только для постскриптума, используя ghostscript. Мне нужно было это, чтобы объединить несколько PDF-файлов и поставить счетчик на каждой странице. Единственным решением, которое я нашел, было старое сообщение gs-devel, который я сильно упростил:

%!PS
% add page numbers document bottom right (20 units spacing , harcoded below)
% Note: Page dimensions are expressed in units of the default user space (72nds of an inch).
% inspired by https://www.ghostscript.com/pipermail/gs-devel/2005-May/006956.html

globaldict /MyPageCount 1 put % initialize page counter

% executed at the end of each page. Before calling the procedure, the interpreter
% pushes two integers on the operand stack:
% 1. a count of previous showpage executions for this device
% 2. a reason code indicating the circumstances under which this call is being made:
%    0: During showpage or (LanguageLevel 3) copypage
%    1: During copypage (LanguageLevel 2 only)
%    2: At device deactivation
% The procedure must return a boolean value specifying whether to transmit the page image to the
% physical output device.
<< /EndPage {
  exch pop % remove showpage counter (unused)
  0 eq dup { % only run and return true for showpage
    /Helvetica 12 selectfont % select font and size for following operations
    MyPageCount =string cvs % get page counter as string
    dup % need it twice (width determination and actual show)
    stringwidth pop % get width of page counter string ...
    currentpagedevice /PageSize get 0 get % get width from PageSize on stack
    exch sub 20 sub % pagewidth - stringwidth - some extra space
    20 moveto % move to calculated x and y=20 (0/0 is the bottom left corner)
    show % finally show the page counter
    globaldict /MyPageCount MyPageCount 1 add put % increment page counter
  } if
} bind >> setpagedevice

Если вы сохраните это в файл с именем pagecount.ps, вы можете использовать его в командной строке следующим образом:

gs \
  -dBATCH -dNOPAUSE \
  -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress \
  -sOutputFile=/path/to/merged.pdf \
  -f pagecount.ps -f input1.pdf -f input2.pdf

Обратите внимание, что pagecount.ps должен быть указан первым (технически, прямо перед входным файлом, с которого должен начинаться подсчет страниц).

Если вы не хотите использовать дополнительный файл .ps, вы также можете использовать свернутую форму, например:

gs \
  -dBATCH -dNOPAUSE \
  -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress \
  -sOutputFile=/path/to/merged.pdf \
  -c 'globaldict /MyPageCount 1 put << /EndPage {exch pop 0 eq dup {/Helvetica 12 selectfont MyPageCount =string cvs dup stringwidth pop currentpagedevice /PageSize get 0 get exch sub 20 sub 20 moveto show globaldict /MyPageCount MyPageCount 1 add put } if } bind >> setpagedevice' \
  -f input1.pdf -f input2.pdf

В зависимости от вашего ввода вам, возможно, придется использовать gsave/grestore в начале/конце блока if.

person Jakob    schedule 23.07.2019
comment
Это отлично, спасибо. Я немного взломал его, думая, что можно было бы избавиться от /MyPageCount и просто использовать номер страницы, который интерпретатор помещает в стек, но это не работает, по крайней мере, для некоторых PDF-файлов; с ними деактивация устройства, кажется, вызывается после каждой страницы, а затем вызывается showpage с никогда не увеличивающимся количеством страниц. - person jcomeau_ictx; 12.05.2020
comment
@jcomeau_ictx да, я также задавался вопросом, почему количество предыдущих выполнений выставочной страницы для этого устройства всегда оставалось на уровне 1 (IIRC), но так и не удалось выяснить причину, и это не имело достаточного значения для дальнейшего расследования. Есть ответы SO, которые, похоже, успешно его используют. - person Jakob; 13.05.2020
comment
Если вы дополнительно хотите отобразить общее количество страниц: gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -o "$output" -c "globaldict /MyPageCount 1 put /concatstrings { exch dup length 2 index length add string dup dup 4 2 roll copy length 4 -1 roll putinterval } bind def << /EndPage {exch pop 0 eq dup {/Helvetica 12 selectfont MyPageCount =string cvs ( / $npages) concatstrings dup stringwidth pop currentpagedevice /PageSize get 0 get exch sub 20 sub 20 moveto show globaldict /MyPageCount MyPageCount 1 add put } if } bind >> setpagedevice" -f input1.pdf - person caram; 15.02.2021
comment
... где npages определяется как: npages="$(qpdf --show-npages input1.pdf)" - person caram; 15.02.2021
comment
Хороший. Он отлично работает, и в полученном PDF-файле все еще есть внутренние ссылки. Я думаю, что последняя команда требует `` перед последней строкой. - person Eric Duminil; 24.06.2021
comment
@EricDuminil Я думаю, вы имеете в виду, что обратная косая черта \ отсутствует, верно? Спасибо, исправил. - person Jakob; 08.07.2021
comment
@Jakob: Точно. Я забыл экранировать escape-символ. :D Спасибо. - person Eric Duminil; 08.07.2021

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

Требуется enscript, pdftk 1.43 или выше и pdfjam (для утилиты pdfjoin)

#!/bin/bash
input="$1"
count=$2
blank=$((count - 1))
output="${1%.pdf}-header.pdf"
pagenum=$(pdftk "$input" dump_data | grep "NumberOfPages" | cut -d":" -f2)
(for i in $(seq "$blank"); do echo; done) | enscript -L1 -B --output - | ps2pdf - > /tmp/pa$$.pdf
(for i in $(seq "$pagenum"); do echo; done) | enscript -a ${count}- -L1 -F Helvetica@10 --header='||Page $% of $=' --output - | ps2pdf - > /tmp/pb$$.pdf
pdfjoin --paper letter --outfile /tmp/join$$.pdf /tmp/pa$$.pdf /tmp/pb$$.pdf &>/dev/null
cat /tmp/join$$.pdf | pdftk "$input" multistamp - output "$output"
rm /tmp/pa$$.pdf
rm /tmp/pb$$.pdf
rm /tmp/join$$.pdf

Например... поместите это в /usr/local/bin/pagestamp.sh и выполните так:

pagestamp.sh doc.pdf 3

Номер страницы будет начинаться со страницы 3. Это полезно, когда у вас есть титульные листы, титульные листы, оглавление и т. д.

К сожалению, параметр --footer в enscript не работает, поэтому вы не можете получить нумерацию страниц внизу, используя этот метод.

person Bob    schedule 25.04.2012

Мне понравилась идея использования pspdftool (справочная страница), но мне нужно было страница x из y и стиль шрифта, соответствующий остальной части страницы.

Чтобы узнать об именах шрифтов, используемых в документе:

$ strings input.pdf | grep Font

Чтобы получить количество страниц:

$ pdfinfo input.pdf | grep "Pages:" | tr -s ' ' | cut -d" " -f2

Склейте его вместе с помощью нескольких pspdftool команд:

$ in=input.pdf; \
out=output.pdf; \
indent=30; \
pageNumberIndent=49; \
pageCountIndent=56; \
font=LiberationSerif-Italic; \
fontSize=9; \
bottomMargin=40; \
pageCount=`pdfinfo $in | grep "Pages:" | tr -s ' ' | cut -d" " -f2`; \
pspdftool "number(x=$pageNumberIndent pt, y=$bottomMargin pt, start=1, size=$fontSize, font=\"$font\")" $in tmp.pdf; \
pspdftool "text(x=$indent pt, y=$bottomMargin pt, size=$fontSize, font=\"$font\", text=\"page \")" tmp.pdf tmp.pdf; \
pspdftool "text(x=$pageCountIndent pt, y=$bottomMargin pt, size=$fontSize, font=\"$font\", text=\"out of $pageCount\")" tmp.pdf $out; \
rm tmp.pdf;

Вот результат:

введите здесь описание изображения

person Johnny Baloney    schedule 26.01.2016
comment
pspdftools позволяет передать строку для форматирования номера страницы, так что вы можете сделать это за один раз: pspdftool "number(x=$pageNumberIndent pt, y=$bottomMargin pt, start=1, size=$fontSize, font=\"$font\", text=\"page %d out of $pageCount\")" $in $out - person Diab Jerius; 08.12.2020

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

Вы можете использовать следующую командную строку (в GNU/Linux вам нужно экранировать знак $ в оболочке, в Windows это не обязательно):

pdftools.py --input-file ./input/wikipedia_algorithm.pdf --output ./output/addtext.pdf --text "\$page/\$pages" br 1 1 --overwrite

Относительно варианта --text:

  • Первый параметр — это добавляемый текст. Доступны некоторые заполнители. $page обозначает номер текущей страницы, а $pages обозначает общее количество страниц в файле PDF. Таким образом, сформулированный таким образом вариант будет добавлять что-то вроде 1/10 для первой страницы 10-страничного PDF-документа и так далее для следующих страниц.
  • Второй параметр — это точка привязки текстового поля. br поместит нижний правый угол текстового поля
  • Третий параметр — это горизонтальное положение точки привязки текстового поля в процентах от ширины страницы. Должно быть число от 0 до 1 с точкой ., разделяющей десятичные дроби.
  • Четвертый вариант параметра — это вертикальное положение точки привязки в текстовом поле в процентах от высоты страницы. Должно быть число от 0 до 1 с точкой ., разделяющей десятичные дроби.

Отказ от ответственности: я автор pdftools

person robertspierre    schedule 20.05.2020
comment
Спасибо! Я пробовал это, но он показывает только/без указания номеров страниц... это похоже на то, что переменные $page $pages не заполняются... - person AAA; 18.07.2020
comment
@AAA Если вы работаете в GNU/Linux, вам нужно избежать знака $ из оболочки, поэтому вам нужно написать \$, а не только $: назовите это pdftools.py [...] --text \$page/\$pages [...] - person robertspierre; 25.01.2021
comment
с одинарными кавычками оболочка не интерполирует. '$page / $pages' - person usretc; 16.05.2021
comment
Но как переместить br так, чтобы он не находился прямо в углу? Я пробовал br 5 5, br -10 -10 -- страница исчезает или не отображается - person usretc; 16.05.2021
comment
@usretc, каков конечный результат, которого вы пытаетесь достичь? Вы также можете открыть вопрос на странице GitHub pdftools. br 0.9 0.9 поместит нижний правый угол текстового поля, которое вы добавляете, на 90% от левого поля страницы и на 90% от верхнего поля страницы. - person robertspierre; 17.05.2021
comment
Два числа после br находятся в диапазоне от 0 до 1. - person robertspierre; 17.05.2021
comment
это было именно так, как-то я застрял на мысли об абсолютных единицах - person usretc; 17.05.2021

О, давно я не пользовался постскриптумом, но быстрое погружение в синюю книгу скажет вам :) www-cdf.fnal.gov/offline/PostScript/BLUEBOOK.PDF

С другой стороны, Adobe Acrobat и немного javascript тоже могли бы творить чудеса;)

В качестве альтернативы я нашел это: http://www.ghostscript.com/pipermail/gs-devel/2005-May/006956.html, который, кажется, отвечает всем требованиям (я не пробовал)

person brinxmat    schedule 21.10.2009

Я попробовал pspdftool (http://sourceforge.net/projects/pspdftool).

В конце концов я заставил его работать, но сначала я получил эту ошибку:

pspdftool: xreftable read error

Исходный файл был создан с помощью pdfjoin из pdfjam и содержал кучу сканов из моего Epson Workforce, а также сгенерированные страницы тегов. Я не мог найти способ исправить таблицу внешних ссылок, поэтому я преобразовал ее в ps с помощью pdf2ps и обратно в pdf с помощью pdf2ps. Затем я мог бы использовать это, чтобы получить хорошие номера страниц в правом нижнем углу:

pspdftool 'number(start=1, size=20, x=550 pt, y=10 pt)' input.pdf output.pdf

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

Есть ли способ исправить или очистить таблицу внешних ссылок файла PDF, не теряя страницы, доступные для поиска?

person Mark Hedges    schedule 03.06.2013

Я предполагаю, что вы ищете решение на основе PS. В PS нет оператора уровня страницы, который позволил бы вам это сделать. Вам нужно добавить что-то вроде нижнего колонтитула в разделе PageSetup для каждой страницы. Любой язык сценариев должен быть в состоянии помочь вам в этом.

person dirkgently    schedule 21.10.2009
comment
Я видел решение с Perl на osti.gov/bridge / - person Brian M. Hunt; 22.10.2009

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

#!/bin/bash
clear
echo
echo This skript adds pagenumbers to a given .pdf file.
echo 
echo This skript needs the packages pdftk and enscript
echo if not installed the script will fail.
echo use the command sudo apt-get install pdftk enscript
echo to install.
echo 
input="$1"
output="${1%.pdf}-header.pdf"
echo input file is $input
echo output file will be $output
echo 
pagenum=$(pdftk "$input" dump_data | grep "NumberOfPages" | cut -d":" -f2)
enscript -L1 --header='||Page $% of $=' --output - < <(for i in $(seq "$pagenum"); do echo; done) | ps2pdf - | pdftk "$input" multistamp - output "$output"
echo done.
person corpsman    schedule 08.05.2015

Я написал следующий скрипт shell, чтобы решить эту проблему для слайдов в стиле LaTeX beamer, созданных с помощью inkscapepdftk cat объединил слайды в окончательную презентацию PDF, а затем добавил номера слайдов, используя приведенный ниже скрипт):

#!/bin/sh

# create working directory
tmpdir=$(mktemp --directory)

# read un-numbered beamer slides PDF from STDIN & create temporary copy
cat > $tmpdir/input.pdf

# get total number of pages
pagenum=$(pdftk $tmpdir/input.pdf dump_data | awk '/NumberOfPages/{print $NF}')

# generate latex beamer document with the desired number of empty but numbered slides
printf '%s' '
\documentclass{beamer}
\usenavigationsymbolstemplate{}
\setbeamertemplate{footline}[frame number]
\usepackage{forloop}
\begin{document}
 \newcounter{thepage}
  \forloop{thepage}{0}{\value{thepage} < '$pagenum'}{
    \begin{frame}
    \end{frame}
  }
\end{document}
' > $tmpdir/numbers.tex

# compile latex file into PDF (2nd run needed for total number of pages) & redirect output to STDERR
pdflatex -output-directory=$tmpdir numbers.tex >&2 && pdflatex -output-directory=$tmpdir numbers.tex >&2

# add empty numbered PDF slides as background to (transparent background) input slides (page by
# page) & write results to STDOUT
pdftk $tmpdir/input.pdf multibackground $tmpdir/numbers.pdf output -

# remove temporary working directory with all intermediate files
rm -r $tmpdir >&2

Скрипт читает STDIN и записывает STDOUT вывод диагностики pdflatex в STDERR.

Так что просто скопируйте и вставьте приведенный выше код в текстовый файл, скажем, enumerate_slides.sh, сделайте его исполняемым (chmod +x enumerate_slides.sh) и назовите его так:

./enumerate_slides.sh < input.pdf > output.pdf [2>/dev/null]

Это должно быть легко настроить для любого другого типа документа, настроив шаблон LaTeX, чтобы использовать правильные параметры documentclass, размера бумаги и стиля.

изменить: я заменил echo на $(which echo), так как в ubuntu символические ссылки /bin/sh на dash переопределяют команду echo внутренней интерпретацией escape-последовательностей оболочки по умолчанию и не предоставляют параметр -E для переопределения это поведение. Обратите внимание, что в качестве альтернативы вы можете экранировать все \ в шаблоне LaTeX как \\.

Изменить: я заменил $(which echo) на printf '%s', так как в zsh which echo возвращает echo: shell built-in command вместо /bin/echo. Подробнее о том, почему я решил использовать printf, см. этот вопрос.

person mschilli    schedule 06.06.2015

Может быть, для этого можно использовать pstops (часть psutils)?

person Filip Korling    schedule 21.10.2009
comment
Я потратил на это довольно много времени, и кажется, что psutils этого не сделает, если только я что-то не упустил. - person Brian M. Hunt; 22.10.2009