I'd like to create a page in my LaTeX document that just consists of lines. It should look like this:
Additionally, I want the lines numbered. I have no idea where to start. Are there any hints?
line-numbering
I'd like to create a page in my LaTeX document that just consists of lines. It should look like this:
Additionally, I want the lines numbered. I have no idea where to start. Are there any hints?
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.
I dont think you can do without some manual labour, if you don't have a system of numbering. However you can trick listings
to use other values.
For reference it is the counter lstnumber
which holds the current line number.
So the solution is to do conditional checking with the counter and insert the correct format, or reference.
I have created a macro which collects information on the line number and inserts the correct format upon the line number reached.
% Save the original way of printing the number
\let\othelstnumber=\thelstnumber
\def\createlinenumber#1#2{
\edef\thelstnumber{%
\unexpanded{%
\ifnum#1=\value{lstnumber}\relax
#2%
\else}%
\expandafter\unexpanded\expandafter{\thelstnumber\othelstnumber\fi}%
}
\ifx\othelstnumber=\relax\else
\let\othelstnumber\relax
\fi
}
This macro will consecutively store any information that you wish to replace with the lstnumber
counter.
So calling:
\createlinenumber{105}{3.1}
\createlinenumber{107}{3.1.5}
will globally change lines 105 and 107 to 3.1, 3.1.5, respectively.
Thus the following
\documentclass{article}
\usepackage{listings}
\begin{document}
% Save the original way of printing the number
\let\othelstnumber=\thelstnumber
\def\createlinenumber#1#2{
\edef\thelstnumber{%
\unexpanded{%
\ifnum#1=\value{lstnumber}\relax
#2%
\else}%
\expandafter\unexpanded\expandafter{\thelstnumber\othelstnumber\fi}%
}
\ifx\othelstnumber=\relax\else
\let\othelstnumber\relax
\fi
}
\bgroup
\createlinenumber{105}{3.1}
\createlinenumber{107}{3.1.5}
\begin{lstlisting}[numbers=left,firstnumber=100,numberstyle=\ttfamily]
begin { empty lines }
end; { empty lines }
\end{lstlisting}
\egroup
\end{document}
will produce:
Notice the use of \bgroup
and \egroup
to not being globally changed.
If you do not wish to display any other than yours provided you simply need to tell TeX
to discard those. Notice that you cannot use numbers=none
as that will never execute \thelstnumber
.
Thus the code looks like this:
\def\createlinenumber#1#2{
\edef\thelstnumber{%
\unexpanded{%
\ifnum#1=\value{lstnumber}\relax
#2%
\fi}%
\ifx\thelstnumber\relax\else
\expandafter\unexpanded\expandafter{\thelstnumber}%
\fi
}
}
However the above requires an initialisation before first use. You then have to add: \let\thelstnumber\relax
after the first \bgroup
but before the first execution of \createlinenumber
.
As bonus info. This was originally intended for a friends thesis who would love to have 007
printed on page 7
. Hence I of course used it on \thepage
. :)
I just expanded it to do other things as well.
Best Answer
This seems to work very well:
Tools:
\loop ... \if ... \repeat
construct\linespagelength
to the\textwidth
and we remove the height#2
from it at each step#1
and the line number in a\vbox
of the height#2