Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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 say, 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?

share|improve this question

8 Answers 8

up vote 64 down vote accepted

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 '/black/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

share|improve this answer
12  
Wow! Very clever! –  Alan Munn May 22 '11 at 1:13
4  
Holy ImageMagick Batman! –  Sharpie May 22 '11 at 17:46
    
Jake, that is pretty impressive! –  Daniel May 23 '11 at 7:57
    
The result is very impressive! Running it from LaTeX is not an issue: the idea would be to run a script on each conference submission so that the referee can use the line numbers. I am no Graphics Magick user and I ran intro problems when trying to run the script myself (Ubuntu 10, GraphicsMagick 1.3.12), first of which being that that the first call to convert just generates "convert: Request did not return an image.". I will explore this week and comment more later. –  Jeremy May 23 '11 at 14:42
1  
That is amazing, Jake. Favoriting this question for this answer alone. +1 –  Jack Henahan Jun 18 '11 at 2:18

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[margins=.5in]{geometry}
\usepackage{pdfpages}
\usepackage{fancyhdr}
\fancyhf{}
\renewcommand{\headrulewidth}{0pt}
\lfoot{\textit{My pdf document}}
\rfoot{\thepage}
\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.

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

share|improve this answer
    
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. –  Jeremy May 23 '11 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 May 23 '11 at 14:35

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

share|improve this answer
    
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! –  Jeremy May 23 '11 at 14:11

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);

}
share|improve this answer
    
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 Sep 17 '12 at 14:25
1  
You can always use ps2pdf14 to change the PDF level of your file. –  yannis Sep 17 '12 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 Sep 17 '12 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 Sep 21 '12 at 13:34

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

share|improve this answer

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

share|improve this answer
2  
This adds the line numbers in the source LaTeX document. @Jeremy need to add line numbers to an existing pdf documemt. –  Alan Munn May 21 '11 at 18:03
1  
No, I think the OP wants to add line numbers to an existing PDF. –  Martin Scharrer May 21 '11 at 18:03
    
@Alan Munn & @Martin Scharrer: Ahh, of course. I am the king of misunderstanding people! –  benregn May 21 '11 at 18:15
    
Agreed with Alan and Martin (althouh I think the feature would be useful for many other people too!) –  Jeremy May 23 '11 at 14:12

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.

share|improve this answer
    
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. –  Jeremy Jun 19 '11 at 4:26

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

share|improve this answer
2  
The line numbers and the lines are not aligned, the shift becomes more and more dominant at the end of the page. –  Christian Hupfer Aug 4 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. –  Jeremy Aug 5 at 13:31

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.