是否有一个 LaTeX 技巧可以防止 PDF 查看器复制行号?

是否有一个 LaTeX 技巧可以防止 PDF 查看器复制行号?

通过编译以下代码可获得 PDF 输出。

\documentclass{article}
\usepackage{xcolor}
\usepackage{listings}

\lstset
{
    language={[LaTeX]TeX},
        numbers=left,
        numbersep=1em,
        numberstyle=\tiny,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
    xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
    breaklines=true,
    basicstyle=\small\tt,
    keywordstyle=\color{blue},
    commentstyle=\color[rgb]{0.13,0.54,0.13},
    backgroundcolor=\color{yellow!10},
    tabsize=2,
    columns=flexible,
    morekeywords={maketitle},
}

\begin{document}

\begin{lstlisting}
\documentclass{article}
\usepackage{listings}
\title{Sample Document}
\author{John Smith}
\date{\today}
\begin{document}
\maketitle
Hello World!
% This is a comment.
\end{document}
\end{lstlisting}

\end{document}

我尝试只在 Acrobat Reader 中复制代码。不幸的是,行号也被复制了,如下面的屏幕截图所示。

在此处输入图片描述

行号很有用,但读者不想复制它们。

是否有一个 LaTeX 技巧可以防止 PDF 查看器复制行号?

答案1

此解决方案非常类似于如何使 PDF 预览器中的文本复制忽略 lineno 行号? \protectaccsupp是唯一的要求,也许是由于listings款待一切

在此处输入图片描述

\documentclass{article}
\usepackage{xcolor}% http://ctan.org/pkg/xcolor
\usepackage{listings}% http://ctan.org/pkg/listings
\usepackage{accsupp}% http://ctan.org/pkg/accsupp
\renewcommand{\thelstnumber}{% Line number printing mechanism
  \protect\BeginAccSupp{ActualText={}}\arabic{lstnumber}\protect\EndAccSupp{}%
}
\lstset
{
    language={[LaTeX]TeX},
        numbers=left,
        numbersep=1em,
        numberstyle=\tiny,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
    xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
    breaklines=true,
    basicstyle=\small\tt,
    keywordstyle=\color{blue},
    commentstyle=\color[rgb]{0.13,0.54,0.13},
    backgroundcolor=\color{yellow!10},
    tabsize=2,
    columns=flexible,
    morekeywords={maketitle},
}

\begin{document}

\begin{lstlisting}
\documentclass{article}
\usepackage{listings}
\title{Sample Document}
\author{John Smith}
\date{\today}
\begin{document}
\maketitle
Hello World!
% This is a comment.
\end{document}
\end{lstlisting}

\end{document}

答案2

由于在加载包时第一个答案中也出现了问题hyperref,因此提出了一个相关问题(如何防止 accsupp 和 hyperref 之间发生冲突?)以下解决方案基于Ulrike Fischer 的回答回答该问题,并说明了即使不涉及包,该解决方案的另一个优点(正如 Heiko Oberdiek 指出的)hyperref:可以复制参考文献中的行号。

\documentclass{article}
\usepackage{xcolor}% http://ctan.org/pkg/xcolor

\usepackage{accsupp}% http://ctan.org/pkg/accsupp
\newcommand{\emptyaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}

\usepackage{listings}% http://ctan.org/pkg/listings
\lstset
{
    language={[LaTeX]TeX},
    numbers=left,
    numbersep=1em,
    numberstyle=\tiny\emptyaccsupp,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
    xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
    breaklines=true,
    basicstyle=\small\tt,
    keywordstyle=\color{blue},
    commentstyle=\color[rgb]{0.13,0.54,0.13},
    backgroundcolor=\color{yellow!10},
    tabsize=2,
    columns=flexible,
    morekeywords={maketitle},
    escapeinside={\%LISTING:}{\^^M},
}

\usepackage{hyperref}

\begin{document}

\begin{lstlisting}
\documentclass{article}
\usepackage{listings}
\title{Sample Document}
\author{John Smith}
\date{\today}
\begin{document}
\maketitle %LISTING:\label{title}
Hello World!
% This is a comment.
\end{document}
\end{lstlisting}

Line \ref{title} shows the title.

\end{document}

显示选择的列表输出

我故意将这个答案设置为社区维基,以防止我获得声誉点数。

答案3

这个答案只涉及 latex/dvips/ps2pdf。

软件包accsupp与 配合良好dvips。生成的 PostScript 文件包含正确的 pdfmark 运算符。但是ghostscript(版本 9.05)尚未实现这些标签,从源文件gdevpdfm.c

/* [ tag propdict /BDC pdfmark */
static int
pdfmark_BDC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
            const gs_matrix *pctm, const gs_param_string *objname)
{
    return 0;                   /****** NOT IMPLEMENTED YET ******/
}

/* [ /EMC pdfmark */
static int
pdfmark_EMC(gx_device_pdf *pdev, gs_param_string *pairs, uint count,
            const gs_matrix *pctm, const gs_param_string *objname)
{
    return 0;                   /****** NOT IMPLEMENTED YET ******/
}

解决方案草图:

如果行号不是文本,则无法复制。因此,解决方案是使用位图图像。对于每个数字和变体(颜色、大小等),需要生成一个位图。由于BMP可以使用图像格式,因此 受支持dvips。然后\thelstnumber重新定义为将这些图像用于其数字。

答案4

这是一种替代方案。数字仍按常规方式排版,但不是在排版每一行之前排版数字,而是在整个代码块排版之后排版所有行号。

如果 PDF 查看器尊重 PDF 中的“文本顺序”,它应该可以正常工作。

需要 2 次编译。

\documentclass{article}
\usepackage{xcolor}
\usepackage{tikz}
\usepackage{etoolbox}
\usepackage{listings}
\usepackage{hyperref}

\begin{document}

\NewDocumentCommand\fakeTypesetLineNumber{m}{%
    \tikz[remember picture] \coordinate (line\the\value{lstnumber});% remember this location
    % --
    \tiny\phantom{#1}% leave space equal to the line number itself
    % \tiny must be outside any group so that it applies to the following \kern
    % --
    \xappto\typesetPendingLineNumbers{\actualTypesetLineNumber{\the\value{lstnumber}}}% remember to typeset it later
}

% this command must be robust because it's used inside \xappto
\NewDocumentCommand\actualTypesetLineNumber{m}{%
    \node [anchor=south west, inner sep=0pt] at (line#1){\normalfont\tiny#1};% actually typeset it now, need to copy the \tiny here
}

\AddToHook{env/lstlisting/begin}{%
    \gdef\typesetPendingLineNumbers{}%
}

\AddToHook{env/lstlisting/end}{%
    \begin{tikzpicture}[remember picture, overlay]%
    \typesetPendingLineNumbers
    \end{tikzpicture}%
}


\lstset
{
    language={[LaTeX]TeX},
    numbers=left,
    numbersep=1em,
    numberstyle=\fakeTypesetLineNumber,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule\relax,
    xrightmargin=\dimexpr\fboxsep+\fboxrule\relax,
    breaklines=true,
    basicstyle=\small\tt,
    keywordstyle=\color{blue},
    commentstyle=\color[rgb]{0.13,0.54,0.13},
    backgroundcolor=\color{yellow!10},
    tabsize=2,
    columns=flexible,
    morekeywords={maketitle},
    escapeinside={\%LISTING:}{\^^M},
}


\begin{lstlisting}
    \documentclass{article}
    \usepackage{listings}
    \title{Sample Document}
    \author{John Smith}
    \date{\today}
    \begin{document}
    \maketitle %LISTING:\label{title}
    Hello World!
    % This is a comment.
    \end{document}
\end{lstlisting}
Line \ref{title} shows the title.

\lstset{ numberstyle=\tiny }

\begin{lstlisting}
    \documentclass{article}
    \usepackage{listings}
    \title{Sample Document}
    \author{John Smith}
    \date{\today}
    \begin{document}
    \maketitle %LISTING:\label{title2}
    Hello World!
    % This is a comment.
    \end{document}
\end{lstlisting}


\end{document}

当然,对于跨越多个页面的代码块,这将会失败。

相关内容