93

Is there any quick script to add page and line numbers to each page of a pdf document?

  1. I often enough get articles in pdf to review, with no page number. I end up writing them by hand to refer to each page when pointing errors.

  2. When referring an error, I end up counting by hand the lines from the beginning or from the end, or copying the context, to precise the location of the error. It would be much more practical to have a standard way to add line numbers to an existing document.

I could manage editing the LaTeX source to obtain this, but not when I receive a pdf. PDF format does not contain lines per se, so identifying them would require to cluster the $y$-coordinates of the letters, and adding those numbers in the margin would require to take the min of the $x$-coordinates and remove a fixed amount from it. Anybody did this script already, or seen another way?

10 Answers 10

124
+100

Alright, here's a go at numbering lines in a PDF (or any other image format) without access to the source.

I wrote a little shell script that, using ImageMagick (at least version 6.6.9-4), converts a given PDF into separate raster images for each page, splits these into half pages, shrinks them to a width of one pixel (so takes the horizontal average, basically), turns this into a monochrome image with a given threshold (black=text, white=no text), shrinks every black sequence down to one pixel (=middle of a line), outputs this as a text, pipes it to sed to clean it up and remove all the non-text lines and finally writes a txt file with the position of each line as 1/1000 of the text height.

findlines.sh:

convert $1.pdf -crop 50x100% png:$1
for f in $1-*; do 
convert $f -flatten -resize 1X1000! -black-threshold 99% -white-threshold 10% -negate -morphology Erode Diamond -morphology Thinning:-1 Skeleton -black-threshold 50% txt:-| sed -e '1d' -e '/#000000/d' -e 's/^[^,]*,//' -e 's/[(]//g' -e 's/:.*//' -e 's/,/ /g' > $f.txt;
done

Running the script takes about 1 second for one page, resulting in a number of files: basename-<number>.txt, where odd <numbers> contain the positions of the left line numbers, and even <numbers> those of the right page numbers. These files can then be read by pgfplotstable (at least v 1.4) and be used to typeset the line numbers on top of the imported pdf file. I defined a command that takes the page number and four line numbers as arguments, where the four line numbers are used to tell the macro at which "raw" line numbers the "real" text lines start and end in the left and right column. By setting \pgfkeys{print raw line numbers=true}, the raw line numbers as found by the algorithm are shown in red.

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplotstable}

\newif\ifprintrawlinenumbers
\pgfkeys{print raw line numbers/.is if=printrawlinenumbers,
  print raw line numbers=true}
\newcommand{\addlinenumbers}[5]{
  \pgfmathtruncatemacro{\leftnumber}{(#1-1)*2}
  \pgfmathtruncatemacro{\rightnumber}{(#1-1)*2+1}
  \pgfplotstableread{\pdfname-\leftnumber.txt}\leftlines
  \pgfplotstableread{\pdfname-\rightnumber.txt}\rightlines
  \begin{tikzpicture}[font=\tiny,anchor=east]
  \node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics[width=14cm,page=#1]{\pdfname.pdf}};
    \begin{scope}[x={(image.south east)},y={(image.north west)}]
      \pgfplotstableforeachcolumnelement{[index] 0}\of\leftlines\as\position{
        \ifprintrawlinenumbers
          \node [font=\tiny,red] at (0.04,1-\position/1000)         {\pgfplotstablerow};
        \fi
        \pgfmathtruncatemacro{\checkexcluded}{
          (\pgfplotstablerow>=#2 && \pgfplotstablerow<=#3) ? 1 : 0)
        }
        \ifnum\checkexcluded=1
          \pgfmathtruncatemacro\linenumber{\pgfplotstablerow-#2+1}
          \node [font=\tiny,align=right,anchor=east] at (0.08,1-\position/1000) {\linenumber};
        \fi
      }
      \pgfplotstablegetrowsof{\leftlines}
      \pgfmathtruncatemacro\rightstart{min((\pgfplotsretval-#2),(#3-#2+1))}
      \pgfplotstableforeachcolumnelement{[index] 0}\of\rightlines\as\position{
        \ifprintrawlinenumbers
          \node [font=\tiny,red,anchor=east] at (1.0,1-\position/1000) {\pgfplotstablerow};
        \fi
        \pgfmathtruncatemacro{\checkexcluded}{
                  (\pgfplotstablerow>=#4 && \pgfplotstablerow<=#5) ? 1 : 0)
        }
        \ifnum\checkexcluded=1
          \pgfmathtruncatemacro\linenumber{\pgfplotstablerow-#4+\rightstart+1}
          \node [font=\tiny] at (0.96,1-\position/1000) {\linenumber};
        \fi
      }
    \end{scope}
  \end{tikzpicture}
}

\begin{document}

\def\pdfname{article}
\addlinenumbers{1}{20}{50}{2}{65}
\pgfkeys{print raw line numbers=false}
\addlinenumbers{2}{0}{69}{0}{64}
\addlinenumbers{3}{19}{47}{21}{48}

\end{document}

As a proof of concept, here's the output for the first two pages of an article from the Environmental Science & Technology Journal. I think it works really well. I haven't been able to call findlines.sh from within LaTeX, though, this step has to be performed manually before compiling the .tex file.

first page of a pdf with line numbers

second page of a pdf with line numbers

22
  • 16
    Holy ImageMagick Batman!
    – Sharpie
    Commented May 22, 2011 at 17:46
  • 3
    Jake, that is pretty impressive!
    – Daniel
    Commented May 23, 2011 at 7:57
  • 1
    @Jeremy: Sorry, somehow part of the script got cut off. I've fixed the code now.
    – Jake
    Commented May 30, 2011 at 11:21
  • 2
    That is amazing, Jake. Favoriting this question for this answer alone. +1 Commented Jun 18, 2011 at 2:18
  • 2
    Nevermind. I did something completely stupid. Now it works. Sorry!
    – Arne
    Commented Jul 3, 2023 at 14:31
25

You can do (1) easily with the pdfpages package.

\documentclass{article}
\usepackage{pdfpages}
\begin{document}
\includepdf[pages=1-,pagecommand={\thispagestyle{plain}}]{<pdffile>}
\end{document}

In the example document, I simply passed the pagestyle plain to the pagecommand, but using the fancyhdr package you can make any kind of extra header/footer you like. To place the page number appropriately you may also need to adjust the margins using the geometry package. For example:

\documentclass{article}
\usepackage[margin=.5in]{geometry}
\usepackage{pdfpages}
\usepackage{fancyhdr}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\lfoot{\textit{My pdf document}}
\rfoot{\thepage}
\begin{document} 
\includepdf[pages=1-,pagecommand={\thispagestyle{fancy}}]{<pdffile>}
\end{document}

This places a footer containing "My pdf document" on the left and the page number on the right. The margin is made very small so that the page number won't likely interfere with the included document.

To make sure the paper size of the output PDF is the same as the included PDF, add the fitpaper option to \includepdf. From the pdfpages manual:

fitpaper Adjusts the paper size to the one of the inserted document.

See Jake's answer for a very ingenious method of adding line numbers to an existing pdf.

7
  • This indeed adds the page numbers in a very easy way. Thanks! It has problem with margins, but I guess checking the options of pdfpages should give ways to place the page numbers in other places than down center.
    – J..y B..y
    Commented May 23, 2011 at 14:19
  • @Jeremy, you can't do this with pdfpages directly, (it can only pass a page commend) but instead you do it within the document using, e.g. the fancyhdr package, and/or geometry (to change the margins.) I'll update my answer to make this clearer.
    – Alan Munn
    Commented May 23, 2011 at 14:35
  • In the case of the second script, can you suggest how one would adjust the position of the page number? There are no obvious adjustable parameters. Commented Mar 5, 2016 at 0:12
  • @FaheemMitha This is just using fancyhdr to place the page number. So I've put it in the \rfoot = right side of the footer, but you could put it in \cfoot to centre it, \lhead to put it on the left at the top etc.
    – Alan Munn
    Commented Mar 5, 2016 at 3:44
  • If the pdf has only one page(even if it is strange to add page number to one-page pdf), it won't work.
    – warem
    Commented Sep 10, 2021 at 9:47
13

If I understand your need to add line numbers to the PDF, you can by using the lineno package. It does, however, only add line numbers according to how LaTeX sets up the text, which can be quite different from the source.

\documentclass[11pt,a4paper]{article}
\usepackage{lineno}
\usepackage{lipsum}
\begin{document}
    \linenumbers
    \lipsum
\end{document}

Line number example

5
  • 4
    This adds the line numbers in the source LaTeX document. @Jeremy need to add line numbers to an existing pdf documemt.
    – Alan Munn
    Commented May 21, 2011 at 18:03
  • 1
    No, I think the OP wants to add line numbers to an existing PDF. Commented May 21, 2011 at 18:03
  • @Alan Munn & @Martin Scharrer: Ahh, of course. I am the king of misunderstanding people!
    – benregn
    Commented May 21, 2011 at 18:15
  • Agreed with Alan and Martin (althouh I think the feature would be useful for many other people too!)
    – J..y B..y
    Commented May 23, 2011 at 14:12
  • @AlanMunn I get linenumbers in pdf when I convert the latex to pdf. I use overleaf, and have linenumbers in the src editor. Commented Jan 20 at 9:27
11

I've encountered the same problems as the OP jeremy, and my version of convert doesn't have morphology as an option. So, I've had to find another solution.

If one does not care whether the line numbers correspond to actual lines in the text (for example numbering a scanned document in pdf format) but only that there are line numbers going down the side of the page, one can combine pdfpages with "Knuth's loop" described here to put a column of numbers down the left side of every page, which is often sufficient for the purpose at hand.

For example, the LaTeX code

\documentclass{article}
\usepackage{pdfpages}
\usepackage[top=0in, bottom=0in, left=0in, right=0in]{geometry}
\usepackage[usenames,dvipsnames]{color}

\makeatletter
 \newsavebox{\@linebox}
 \savebox{\@linebox}[3em][t]{\parbox[t]{3em}{%
   \@tempcnta\@ne\relax
   \loop{\color{Red} \small\the\@tempcnta}\\
     \advance\@tempcnta by \@ne\ifnum\@tempcnta<66\repeat}}
\makeatother

\begin{document}
\makeatletter

%% IF PAGE NUMBERS ALSO ARE NEEDED, USE \thispagestyle{plain} INSTEAD
\includepdf[pages=1-,pagecommand={\thispagestyle{empty} \hspace{0.5in} \usebox{\@linebox}},fitpaper]{loremipsum.pdf}

%% FOR LINE NUMBERS > 66 INCLUE OPTION openright AND DISCARD FIRST TWO PAGES OF OUTPUT
% \setcounter{page}{-1}  %% FOR LINE NUMBERS > 66 AND PAGESTYLE plain
% \includepdf[pages=1-,pagecommand={\thispagestyle{empty} \hspace{0.5in} \usebox{\@linebox}},fitpaper,openright]{loremipsum.pdf}

\makeatother
\end{document}

%% TO MAKE LOREMIPSUM.PDF
% \documentclass[10pt]{article}
% \usepackage{lipsum}
% \begin{document}
% \section*{Lorem Ipsum}
% \lipsum
% \end{document}

produces the output addlinenumbers.pdf

To get numbers going all the way down the page, I had to find a workaround described in the LaTeX code. For numbering greater than 65, the first page's numbers get shifted to a second page (for some unknown reason), so my trick is to insert a blank page with the openright option (resetting the page count as needed) and then remove the first two pages of output later. Someone better versed in LaTeX might find a more elegant solution, but this seems to work for me. You can bet that the authors of unnumbered papers are going to get a short lecture on how important it is to provide the reviewer with line (and equation) numbers throughout.

2
  • This might solve the problem for some, but in my case the coordinates (page,line) used in an anonymous review should be understandable by the authors: it won't be the case if the numbers do not correspond to the lines of the document.
    – J..y B..y
    Commented Jun 19, 2011 at 4:26
  • 1
    Springer journals seems to do something like this. Commented Nov 3, 2014 at 4:37
7

You could also consider using PDF annotations to comment the PDF file. You don't need Adobe Acrobat anymore. Adobe Reader X now has support for PDF text and Highlight markup annotations. There are other alternatives like Foxit Reader or PDF X-Change viewer. If you also have the LaTeX source you can use a package like pdfcomment. It's more flexible and powerful than what Adobe Reader offers.

enter image description here

1
  • I am already using pdf annotator to annotate the pdf document, I could indeed write the numbers by hand, but it is faster to count the lines only when I spot a mistake. An automated solution is what is needed!
    – J..y B..y
    Commented May 23, 2011 at 14:11
6

It can be done very easily for files produces by pdflatex by using the simple Perl script below. Caveats: the PDF file must be of level at most 1.4 (to obtain this, use \pdfminorversion=4 when compiling it in pdflatex).

You will need to install two Perl packages: CAM::PDF and PDF::API2. The numbers are aligned at a distance of $leftmargin bp units from the left margin of the paper (this value has to be set on line 5 of the script). The names of the input and output PDF files are provided as command line arguments.

Notice that there is another variable $threshold: this is the minimal distance between two lines. Indeed, when you typeset, for example, a superscript, then there is small jump in the PDF file which my script considers as a separate line. But by asking for line skips of at least the threshold, these small jumps are not taken into account.

Here is the script:

use CAM::PDF;
use PDF::API2;
$file=$ARGV[0];
$newfile=$ARGV[1];
$leftmargin=70;
$threshold=8;
if (-e $file) {

$pdf = CAM::PDF->new($file);

$nbpages=$pdf->numPages();

foreach $i (1 .. $nbpages) {
$page1 = $pdf->getPageContent($i);
@BTS=();
while ($page1 =~ m/^BT\n((.|\n|\r)+?)\nET/gm) {
push @BTS, $1; 
}
foreach $BT (@BTS) {
$x=0; $y=0;
while ($BT =~ m/([0-9.-]+) ([0-9.-]+) Td/g) {
$x=$x + ($1);
$y=$y + ($2);
if ($2 > $threshold or $2 < -$threshold) { push @{"PAGES".$i}, $y; }
}
}
@{"PAGES".$i} = sort { $b <=> $a; } @{"PAGES".$i}; 

$prey=10000000; @X=();
foreach $y (@{"PAGES".$i}) {
if ($prey - $y < $threshold) {}
else { push @X, $y; }
$prey=$y;
}
@{"PAGES".$i}=@X;

}

$pdf = PDF::API2->open($file);

# Add a built-in font to the PDF
$font = $pdf->corefont('Times-Roman');

# Add an external TTF font to the PDF
#    $font = $pdf->ttfont('/path/to/font.ttf');

# Add some text to the page
foreach $i (1 .. $nbpages) {
$page = $pdf->openpage($i);
$j=0;
foreach $y (@{"PAGES".$i}) {
$text = $page->text();
$text->font($font, 10);
$text->fillcolor('blue');
$text->translate($leftmargin, $y);
$text->text($j);
$j++;
}
}

# Save the PDF
$pdf->saveas($newfile);

}
5
  • 2
    That's a very elegant approach! It's a bit unfortunate that it requires the document to be compiled with pdflatex and a special option, though. The chance that a document has been created that way are pretty slim, and if you had access to the source to recompile the document correctly, you might as well just use the lineno package as benregn suggests.
    – Jake
    Commented Sep 17, 2012 at 14:25
  • 2
    You can always use ps2pdf14 to change the PDF level of your file.
    – yannis
    Commented Sep 17, 2012 at 17:15
  • Ah, that's a useful hint! Do I understand correctly, though, that the files have to be produced by pdflatex? I haven't been able to get the script to work with PDFs of journal articles (for example the one linked to in my answer).
    – Jake
    Commented Sep 17, 2012 at 18:21
  • The limitation is on the level of PDF code parsing. I'm only considering the Td operator (as pdflatex always uses solely that one), but there are others. You should uncompress your file and look at what operators are used for moving to the next line, in the ET/BT areas.
    – yannis
    Commented Sep 21, 2012 at 13:34
  • I've had good luck with this script on many files by also grabbing Tm. This is a simple modification, @yannis, would you be opposed to adding it?
    – Michaël
    Commented Feb 3, 2022 at 22:39
5

If you really want to add them to a PDF file, such as for legal documents, these tricks might work for you.

Add page numbers to a doc

  1. fix xref table if necessary with pdftk test-foo.pdf output test-bar.pdf
  2. pspdftool 'number(start=1, size=20, x=550 pt, y=10 pt)' test-bar.pdf test-baz.pdf

These numbers are a little big, but this works great for scanned evidence sections. I prepare the evidence section as a separate doc and then number it with the correct "start" number to start after the last page of the brief.

pspdftool takes font options, but you have to figure out the font name from the name of the font file, not how it appears in a word processor.

Add evenly-spaced line numbers to a doc

I do this because in a trial court filing, the lines should be numbered with even spaces, even if I use blockquotes with thin spacing.

LibreOffice links the line numbers to specific paragraphs on the page.

I got tired of using awkward text area blocks for blockquotes and linking them across pages.

I just want to write whatever I want in the page with different styles and stamp on the numbers later.

Solution:

  1. Format one page with line numbers turned on in your word processor, and nothing else.
  2. Export the line numbers page to nums.text.pdf.
  3. Vectorize it so the numbers don't show up in text search. This worked:
    gs -o temp.ps -dNOCACHE -sDEVICE=pswrite nums.text.pdf;
    gs -o nums-outlines.pdf -sDEVICE=pdfwrite temp.ps
  4. Stamp the numbers:
    pdftk unnumbered-fulldoc.pdf multibackground nums-outlines.pdf output combinedfile.pdf

Hope this helps. -Mark

2

Here, we give a simple answer to this question by using a few latex packages. For example, the LaTeX code:

%% To make "loremipsum.pdf"
% \documentclass[10pt]{article}
% \usepackage{lipsum}
%\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry}
%  \renewcommand{\baselinestretch}{1.33}
% \begin{document}
% \section*{Lorem Ipsum}
% \lipsum
% \end{document}

\documentclass[12pt]{article} \usepackage[top=2.5cm, bottom=2.5cm, left=0.5cm, right=0.5cm]{geometry} \usepackage{ifthen} \usepackage{pdfpages} \usepackage[left]{lineno} \renewcommand\thelinenumber{\bf\scriptsize\color{red}\arabic{linenumber}} \renewcommand{\baselinestretch}{1.0} % interline spacing

\begin{document} \newcounter{ctr} \newcounter{ct} \setcounter{ct}{1} \whiledo {\value{ct} < 3} % 2 is the number of the Pdf pages { \enlargethispage{3cm} \begin{minipage}[t]{0.1\textwidth} \internallinenumbers \begin{runninglinenumbers*} \setcounter{ctr}{1} \whiledo {\value{ctr} < 48} % each page contain 32 line { $\longleftrightarrow$\ \stepcounter {ctr}% } \end{runninglinenumbers*} \end{minipage} \begin{minipage}[t]{0.8\textwidth} \includepdf[pages=\thect,pagecommand={\thispagestyle{empty}}]{loremipsum.pdf} \end{minipage} \clearpage \stepcounter {ct}% } \end{document}

enter code here

produces the output enter image description here enter image description here

2
  • 3
    The line numbers and the lines are not aligned, the shift becomes more and more dominant at the end of the page.
    – user31729
    Commented Aug 4, 2014 at 12:10
  • As for Johnson's solution above: This might solve the problem for some, but in my case the coordinates (page,line) used in an anonymous review should be understandable by the authors: it won't be the case if the numbers do not correspond to the lines of the document.
    – J..y B..y
    Commented Aug 5, 2014 at 13:31
2

Here is a minor variation on Alan Munn's second answer for adding page numbers to a PDF.

The difference here is that the page numbers are placed in the lower corner of the page. With the twosided option, the numbers are placed on the right lower corner on odd pages, and the left lower corner on even pages. The position of the page numbers are adjustable via the put parameters. Also, the page numbers are circled, which makes them show up better.

Thanks to David Carlisle for providing the code and explanations.

\documentclass[14pt,twoside]{article}
\usepackage[margin=.5in]{geometry}
\usepackage{pdfpages}
\usepackage[T1]{fontenc}
\usepackage{fouriernc}
\usepackage{tikz}
\newcommand*\numcircledtikz[1]{\tikz[baseline=(char.base)]{
    \node[shape=circle,draw,inner sep=1.2pt] (char) {#1};}}
\usepackage{fancyhdr}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\fancyfoot[LE,RO]{\begin{picture}(0,0)\put(-10,30){\numcircledtikz{\thepage}}\end{picture}}
\begin{document}
\includepdf[pages=1-,pagecommand={\thispagestyle{fancy}}]{<pdffile>}
\end{document}
1

Here's how I figured out how to add line numbers to an existing pdf. It doesn't use TeX and it's a little fiddly to get the sizing right, but here goes:

Prepare a file of numbers, from 1 to approximately 32, using Excel or something else. Somehow make a png file. You could do this by saving to pdf in Excel and then using an online conversion tool, or by making a screenshot. Make sure the column of numbers is waay over to the left edge of the page, and size your row heights so that the numbers take up a reasonable amount of space.

Download and install PDFill.

Choose Item 8, "Add Watermark to Image." (It will walk you through opening two files.)

Open the pdf whose pages need line numbers.

Open the png file with the column of numbers.

Now you will choose an amplification factor and an offset value. Here, as an example, is what worked for me:

enter image description here

Hit "Save as" and save the file. The new file will probably open up automatically. (If not, check your settings in PDFill.)

Now count the line numbers on a sample page, and see if you need to adjust the amplification factor. Rinse and repeat. Once you've got the right number of lines, play with the offset value until "1" lines up with the first line of your pdf text. Save a screenshot of the successful values so you can remember next time!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .