检测所有包含颜色的页面

检测所有包含颜色的页面

在较大的 LaTeX 文档中,通常只有一些页面包含彩色内容(主要是图片),其余页面只有黑白内容。由于彩色页面的打印成本比黑白页面高得多,因此最好能够提取所有彩色页面并单独打印。第一步是能够检测页面是否包含颜色。这可以是适合 PDF 页面提取脚本读取的页码文本列表(例如使用pdftk)。

对于许多人来说,一个简单的解决方案就是检测所有包含 的页面,figure并假设只有这些页面有颜色。但是,一个通用的解决方案会更好。只应考虑打印的彩色元素,而hyperref不应考虑例如链接周围的彩色框架。解决方案可以禁用这些检测。

答案1

Ghostscript 的较新版本(9.05 版及更高版本)包含一个名为 的“设备” inkcov。它计算每个(不针对每一个图像) 中的青色 (C)、洋红色 (M)、黄色 (Y) 和黑色 (K) 值,其中 0.00000 表示 0%,1.00000 表示 100%。

命令行示例:

gs -o - -sDEVICE=inkcov /path/to/your.pdf

示例输出:

Page 1
0.00000  0.00000  0.00000  0.02230 CMYK OK
Page 2
0.02360  0.02360  0.02360  0.02360 CMYK OK
Page 3
0.02525  0.02525  0.02525  0.00000 CMYK OK
Page 4
0.00000  0.00000  0.00000  0.01982 CMYK OK

您可以在此处看到,第 1+4 页未使用任何颜色,而第 2+3 页使用了颜色。这种情况对于想要节省彩色墨水的人来说尤其“糟糕”:因为第 2+3 页的所有 C、M、Y(和 K)值都完全相同,所以它们可能在人眼看来不是彩色页面,而是(“丰富的”)灰度(如果每个像素都与这些颜色值混合)。

Ghostscript 还可以将颜色转换为灰度。示例命令行:

gs                                \
  -o grayscale.pdf                \
  -sDEVICE=pdfwrite               \
  -sColorConversionStrategy=Gray  \
  -sProcessColorModel=/DeviceGray \
   /path/to/your.pdf

再次检查墨水覆盖率分布(请注意,添加-q参数会稍微改变输出格式):

gs -q  -o - -sDEVICE=inkcov grayscale.pdf
 0.00000  0.00000  0.00000  0.02230 CMYK OK
 0.00000  0.00000  0.00000  0.02360 CMYK OK
 0.00000  0.00000  0.00000  0.02525 CMYK OK
 0.00000  0.00000  0.00000  0.01982 CMYK OK

答案2

对于一般情况,使用外部工具来测试所有包含颜色的页面似乎确实更好。这是提到的 SO 问题的主题 如何知道 PDF 页面是彩色的还是黑白的?我现在写了一个回答它,其中包括小脚本为了这。

但是,获取包含图片的所有页面的列表要容易得多。在这里,我使用zref-abspage包来获取绝对页面计数器。可以使用常规命令,当周围的内容真正放置在页面上时,它将扩展其内容。因此,页面计数器将具有正确的值。然后可以简单地修补的\write结束宏以保存此代码。figure

\documentclass{book}
\usepackage{mwe}

\usepackage{zref-abspage}% absolute page counter
\newwrite\figpages
\openout\figpages=\jobname.fpg
\makeatletter
\g@addto@macro\endfigure{%
    % Write absolute page number and page label to file
    % Do not use \immediate!
    \write\figpages{\number\value{abspage}: \thepage}%
}
\makeatother

\newcount\mycount% for example loop
\begin{document}
\frontmatter
\Blindtext

\begin{figure}
    \centering
    \includegraphics[width=.8\textwidth,height=5cm]{example-image}
    \caption{Some caption}
\end{figure}

\mainmatter
\Blindtext

\loop% keep MWE small by using a loop

\begin{figure}
    \centering
    \includegraphics[width=.8\textwidth,height=5cm]{example-image}
    \caption{Some caption}
\end{figure}

{\Blindtext}

\advance\mycount by 1
    \ifnum\mycount<20\relax
\repeat

\backmatter
\appendix
\Blindtext

\begin{figure}
    \centering
    \includegraphics[width=.8\textwidth,height=5cm]{example-image}
    \caption{Some caption}
\end{figure}

\end{document}

这将生成一个.fpg文件(用于图页) 如下所示:

2: ii
4: 2
5: 3
7: 5
8: 6
10: 8
11: 9
13: 11
14: 12
16: 14
18: 16
19: 17
21: 19
22: 20
24: 22
25: 23
27: 25
28: 26
30: 28
31: 29
33: 31
38: 36

如果需要,可以更改格式。

答案3

有一个相当有用的 Python 脚本http://homepages.inf.ed.ac.uk/imurray2/code/hacks/pdfcolorsplit它使用pdftk将其拆分为彩色和黑白文件,尽管它不处理 hyperref 周围的框。如果您可以访问 LaTeX 源代码,为什么不关闭 hyperref 中的颜色呢 - 我这样做是这样的:

\usepackage[colorlinks=true,
            linkcolor=black,
            citecolor=black,
            filecolor=black,
            urlcolor=black]{hyperref}

据我所知,如果你只是设置它们,[colorlinks=false]它们是不可点击的。

答案4

这是一个 MATLAB 脚本,它使用 Kurt Pfeifle 的答案将 PDF 拆分为两个文件,一个彩色文件和一个灰度文件。原始文件被保留。它确实不是处理双面打印。

它不是万无一失的,可能需要一些调试,但希望它能够开箱即用。

你会需要:

  • Ghostscript(9.05 及更高版本)
  • MATLAB 函数 ghostscript() 和 user_input() 来自这里
  • pdftk

以下是脚本(您需要更改第 4、5 行,可能还有第 6 行):

clear all; close all; clc;

%Change these:
pathToFile = '/Users/nikos/Desktop/';
fName = 'thesis.pdf';
%you might need to change the path to pdftk (if in windows for example)
pdftkPath = '/usr/local/bin/pdftk';

disp('Reminder: you might want to set \hypersetup{colorlinks=false} in latex');
disp('Do you want to manually set as grayscale any pages that have (C == M == Y)?');
a = input('Otherwise they will be treated as colour! (y/n) ','s');

if (a~= 'y' && a~='Y')
    manualMode = false;
else
    manualMode = true;
end

[status, ret] = ghostscript(['-o - -sDEVICE=inkcov ',pathToFile,fName]);

inds = strfind(ret,'0.');
pages = length(inds)/4;

if (round(pages) ~= pages)
    disp('Something went wrong');
    disp('Check the variable ret');
    disp('I am looking the the string ''0.'' which should only occur when listing CMYK values');
end

a = input(['Is your pdf ', num2str(pages), ' pages long (y/n) ?'],'s');

if (a ~= 'y' && a ~= 'Y')
    break;
end

disp([num2str(pages), ' pages processed.']);
c = 1:4:length(inds);
m = 2:4:length(inds);
y = 3:4:length(inds);
k = 4:4:length(inds);

colorPages = '';
bwPages = '';
cpCounter = 0;
bwCounter = 0;
for i = 1:pages
    C = str2num(ret(inds(c(i)):inds(c(i))+6));
    M = str2num(ret(inds(m(i)):inds(m(i))+6));
    Y = str2num(ret(inds(y(i)):inds(y(i))+6));
    K = str2num(ret(inds(k(i)):inds(k(i))+6));

    if (C == 0 && M == 0 && Y == 0)
        bwPages = [bwPages, ' ',num2str(i)];
        bwCounter = bwCounter+1;
    elseif (C == M && C == Y && manualMode)
        a = input(['Is page ', num2str(i), ' colour (C == M == Y) (y/n) ?'],'s');
        if (a ~= 'y' && a ~= 'Y')
            bwPages = [bwPages, ' ',num2str(i)];
            bwCounter = bwCounter+1;            
        else
            colorPages = [colorPages, ' ', num2str(i)];
            cpCounter = cpCounter+1;
        end
    else
        colorPages = [colorPages, ' ', num2str(i)];
        cpCounter = cpCounter+1;
    end
end

cName = [pathToFile, 'color_',fName];
bName = [pathToFile, 'bw_',fName];
disp([cName, ' (',num2str(cpCounter), ' pages)']);
disp([bName, ' (',num2str(bwCounter), ' pages)']);

system([pdftkPath, ' ', pathToFile, fName, ' cat ', colorPages,' output ', cName]);
system([pdftkPath, ' ', pathToFile, fName, ' cat ', bwPages,' output ', bName]);

相关内容