pdflatex(或任何 tex 包)可以自动重新缩放已缩小尺寸的包含图像吗?

pdflatex(或任何 tex 包)可以自动重新缩放已缩小尺寸的包含图像吗?

我正在用 LaTeX 写论文,用 pdflatex 生成。我有大量图表,其中很多都是 PNG/JPEG 格式的位图(而不是 SVG)。我通常将它们创建为相当高的分辨率(比如 1600x1200 左右),以确保无论它们最终在文档中的大小如何,打印时它们至少为 300dpi。

当我编写/布局文档时,我会添加图形(使用包\includegraphics中的图形graphicx)并根据需要设置宽度/高度(例如,子图非常小)。我不需要图像的分辨率超过 300 dpi,因此,当我将 1600x1200 图像缩小到 5 厘米时,图像的分辨率现在是 800 dpi。因此,尽管包含了一些非常小(在页面上)的图像,但 PDF 仍然变得非常大。

有没有办法告诉 pdflatex 或 graphicx (或其他相关的东西?) 将所有图像转换为最大限度300 dpi,基于我设置的尺寸\includegraphics[width=2in]{filename}?也就是说,它将图像缩放到最大 600x600 像素因为它包含在 PDF 中(保持原始文件不变)。

我知道我可以使用各种命令行应用程序调整原始图像的大小,并包括调整大小前的版本,但考虑到图像大小差异很大,要确保它们都是 300dpi 才能保持恒定的打印尺寸,这并不像那么简单。能够轻松创建不同版本的 PDF(网络版与最终版)而无需手动调整图像大小也很好,这样“网络版”PDF 的图像上限为 72-100 dpi,而最终版的上限为 600(如果有的话)。

更新:我发现一个糟糕的解决方案一些案例(很长,所以我自己将其添加为答案,见下文)。通过在创建后重新处理 PDF,您可以转换全部将图像转换为特定分辨率(以 dpi 为单位)的 JPEG。这对于仅包含 JPEG 的文档来说很好,但如果您有 PNG(或类似的无损压缩)图表(这些图表出于某种原因而采用 PNG 格式,例如带有硬边的简单图表),那么这种方法就很糟糕。

因此,我仍然在寻找一种解决方案,可以做到这一点,而无需在所有图像上强制使用相同的压缩算法(无论是 LaTeX 宏/包,还是解析 LaTeX 并生成适当大小的文件的脚本,还是不采用一刀切压缩算法方法的后处理器)。

答案1

我尝试了 LaTeX 中的一些黑魔法,并找到了不使用外部脚本的方法 ─ 尽管它仍然有些不方便且不太容易使用。基本上,您需要从 LaTeX 内部调用 ImageMagick。

为此,您需要使用--shell-escape参数调用它。这允许使用名为的命令\write18,该命令执行传递给它的参数。然后您可以将以下代码添加到序言中:

\newcommand{\doConvert}[2]{\immediate\write18{convert #1 -resample %
  300x300 -resize #2 #1.rs}}
\newcommand{\imgRs}[4]{\doConvert{#1.#2}{#3x#4}%
  \includegraphics[width=#3, height=#4, type=#2, ext=.#2.rs, read=.#2.rs]{#1}%
}

这使您可以调用\imgRs{file}{extension}{width_in_pts}{height_in_pts}以将图像转换为 300 dpi 并将其包含在文档中。

当然,您始终可以以英寸或其他任何单位指定尺寸:您只需将对\doConvertin 的调用更改imgRs为考虑从使用的单位到点的缩放——并且您必须一致地使用尺寸。实际上可以找出使用的单位是什么,或者使某些参数成为可选的,但这与此解决方案无关。

答案2

您可以对 PDF 进行后处理,并且仍使用无损压缩。在撰写论文时,我还必须学习很多有关使用 LaTeX 处理 PDF 文件的知识。基本上,您可以使用 GhostScript 并告诉它您想要使用哪种压缩方法,例如,彩色图像(Win32 示例,但您明白了):

gswin32c.exe -sDEVICE=pdfwrite -dMaxSubsetPct=100 -dPDFSETTINGS=/prepress -dAutoFilterColorImages=false -dColorImageFilter=/FlateEncode -sOutputFile="outfile.pdf" -dNOPAUSE -dBATCH "infile.pdf"

您需要同时指定 -dAutoFilterColorImages=false(不自动选择压缩方法)和 -dColorImageFilter=/FlateEncode(使用 Flate 编码器)。

如果您想控制灰度图像,您还需要指定相应的参数。

Ghostscript 根据 dPDFSETTINGS 重新采样为给定的 dpi:

印前 = 300 dpi

打印机 = 300 dpi

电子书 = 150 dpi

屏幕 = 72 dpi

我在我的网站上写了一个关于处理和压缩 PDF 文件,更详细地解释这一点。

答案3

很抱歉又占用了另一个答案的空间 - 只是想有漂亮的格式:)

好吧,感谢@finrod 和 @Ken Bloom;此外如何从 LaTeX 执行 shell 脚本?如何将 shell 输出保存到 LaTeX 中的变量?缩放(调整大小)超出页边距的大型图像(图形);我设法编写了一个“脚本”(好吧,更确切地说是一个宏),例如:

  • 如果pdflatex用 调用-shell-escape;则\includegraphics重新定义为通过 shell 调用重采样过程,并包含下采样后的图像;
  • 否则,\includegraphics保持原样(即它将包含大图像)

以下是代码(请注意,即使在其中\write18,百分号“ %”仍然起到注释的作用):

% for downsampling large images

\ifnum\pdfshellescape=1
% Yes, enabled
% #2 is the filename - assumed relative
% IFP - image file path
% IFN - image filename only
% here resizing at 800 px wide
\let\Oldincludegraphics\includegraphics
\newread\myinput
% must add default argument [] so typeout works
\renewcommand\includegraphics[2][\@empty]{%
% debug - print arguments to stdout:
\immediate\message{== #1 ==}
\immediate\typeout{== #2 ==}
% run downsampling bash script
\immediate\write18{mkdir -p downsampled; IFP=#2 ; %
echo "Processing $IFP" ; %
IFN=$(basename $IFP) ; %
echo "downsampled/$IFN" > tmpname ; %
if [ ! -f downsampled/$IFN ]; then %
echo "File downsampled/$IFN not found! Converting..." ; %
% convert $IFP -resize 50\% downsampled/$IFN ; %
convert $IFP -resize 800x downsampled/$IFN ; %
else %
echo "Found downsampled/$IFN - reusing." ; %
fi ; %
} % end write18
% here we should have downsampled file
% retrieve downsample filename first
\immediate\openin\myinput=tmpname
% The group localizes the change to \endlinechar
\bgroup
  \endlinechar=-1
  \immediate\read\myinput to \localline
  % Since everything in the group is local, we have to explicitly make the
  % assignment global
  \global\let\myTmpFileName\localline
\egroup
\immediate\closein\myinput
\immediate\typeout{== \myTmpFileName .. #1 ==}
% Clean up after ourselves
% \immediate\write18{rm -f -- tmpname}
% finally, include downsampled image
\Oldincludegraphics[#1]{\myTmpFileName}
} % end renewcommand
\else
% No, disabled
\fi

编辑:这里有一个例子,其中不是重新定义,而是\includegraphicsRS定义了一个新的(因此它可以与通常的 \includegraphics 混合),其行为与上面相同:

% for downsampling large images: \includegraphicsRS
% (\includegraphics "resize")

\newcommand{\includegraphicsRS}{}

\ifnum\pdfshellescape=1
% Yes, enabled
% #2 is the filename - assumed relative
% IFP - image file path
% IFN - image filename only
% here resizing at 800 px wide
\newread\myinput
% must add default argument [] so typeout works
\renewcommand\includegraphicsRS[2][\@empty]{%
% run downsampling bash script
\immediate\write18{mkdir -p downsampled; IFP=#2 ; %
  echo "Processing $IFP" ; %
  IFN=$(basename $IFP) ; %
  echo "downsampled/$IFN" > tmpname ; %
  if [ ! -f downsampled/$IFN ]; then %
  echo "File downsampled/$IFN not found! Converting..." ; %
  % convert $IFP -resize 50\% downsampled/$IFN ; %
  convert $IFP -resize 800x downsampled/$IFN ; %
  else %
  echo "Found downsampled/$IFN - reusing." ; %
  fi ; %
} % end write18
% here we should have downsampled file
% retrieve downsample filename first
\immediate\openin\myinput=tmpname
% The group localizes the change to \endlinechar
\bgroup
  \endlinechar=-1
  \immediate\read\myinput to \localline
  % Since everything in the group is local, we have to explicitly make the
  % assignment global
  \global\let\myTmpFileName\localline
\egroup
\immediate\closein\myinput
% Clean up after ourselves
% \immediate\write18{rm -f -- tmpname}
% finally, include downsampled image
\includegraphics[#1]{\myTmpFileName}
} % end renewcommand
\else
% No, disabled
% in this case, \includegraphicsRS is just the usual \includegraphics
\renewcommand\includegraphicsRS[2][\@empty]{%
\includegraphics[#1]{#2}
}
\fi

答案4

您可以使用 ImageMagick 的 自动更改分辨率convert -resample。这是一个 awk 脚本,它解析 tex 文件,查找\includegraphics语句,然后将嵌入其中的图像转换为所需的分辨率:

(/\\includegraphics/&&(/{.*\.png}/||/{.*\.jpg}/)){
 if(match($0,"width=[0123456789\.]*in")==0){
    print "%Cannot convert, no width in inch!\n" $0;
 }else{
    wid=substr($0,RSTART+6,RLENGTH-8);  
    pixSize=wid*reso;  
    match($0,"{.*}");file=substr($0,RSTART+1,RLENGTH-2);  
    print "%convert " file " -resample " reso "x" reso " -resize " pixSize " RESAMPLED_" file;   
    system("convert " file " -resample " reso "x" reso " -resize " pixSize " RESAMPLED_" file);  
    gsub("{.*}","{RESAMPLED_" file "}",$0); print $0;
 }
}

!(/\\includegraphics/&&(/{.*\.png}/||/{.*\.jpg}/)){print $0}

您可以像这样使用它(假设它在文件中resample.awk):

$ awk -f resample.awk -v reso=300 latexfile.tex > resampledlatexfile.tex
$ pdflatex resampledlatexfile.tex ...

请注意,要正常工作,它需要\includegraphics指定width参数,并以英寸为单位指定;如果不满足,它将跳过此类图片。
它将创建一系列重新采样的图像(带RESAMPLED_前缀),嵌入在 中resampledlatexfile.tex

相关内容