选择正确的格式保存图像对于保持图像质量和减少伪影至关重要。不同的格式采用不同的压缩方法并且有各自的优点和缺点。
例如,JPG 适合于色彩渐变丰富的真实照片。另一方面,无损 PNG 在示意图方面则更胜一筹:
当处理大量文件时,选择正确的格式可能是一件苦差事。这就是为什么我想找到一种自动化的方法。
关于我的具体用例的一些背景信息:
我正在为我所在大学的一系列讲座制作大量讲义。这些讲义中有很多图片,我必须从 PDF 格式的幻灯片中提取这些图片。提取这些图片可以得到无损 PNG 文件,但有时这些文件会变得过大。
将这些特定文件转换为 JPEG 可以将其大小减少到原始文件大小的 20% 以下,同时保持相同的质量。这一点很重要,因为在文字处理器中处理数百张大图像很容易崩溃。
将所有提取的 PNG 批量转换为 JPEG不是我愿意遵循的选项,因为许多(如果不是大多数)图像更适合格式化为 PNG。转换这些图像会导致尺寸明显减小,有时甚至会导致文件大小增加 - 至少我的测试运行表明了这一点。
由此我们可以得出的结论是,压缩后的文件大小可以作为指示哪种格式最适合特定图像的指标。它不是一个特别准确的预测器,但效果还不错。那么为什么不以脚本的形式使用它呢:
包括我通知等待因为我希望当我将提取的图像拖到文件夹中时脚本能够自动执行。
这是我过去几周一直使用的脚本的简化版本:
#!/bin/bash
inotifywait -m --format "%w%f" --exclude '.jpg' -r -e create -e moved_to --fromfile '/home/MHC/.scripts/Workflow/Conversion/include_inotifywait' | while read file; do mogrify -format jpg -quality 92 "$file"
done
脚本的高级版本必须
- 能够处理文件名和目录名中的空格
- 保留原始文件名
- 如果设置了 alpha 值,则扁平化 PNG 图像
- 比较临时转换后的图像和原始图像的文件大小
- 确定差异是否大于给定的百分比
- 按指示行动
实际的转换可以使用 imagemagick 工具完成:
convert -quality 92 -flatten -background white file.png file.jpg
不幸的是,我的 bash 技能还不够先进,无法将上述方案转换为实际的脚本,但我相信你们中的许多人可以。
我在这里的声誉点数很低,但我很乐意以我所能设定的最高赏金来奖励最有帮助的答案。
参考:http://www.formortals.com/introducing-cnb-imageguide/, http://www.turnkeylinux.org/blog/png-vs-jpg
编辑:另请参阅下面的评论,了解有关我为什么认为该脚本是我所面临的问题的最佳解决方案的更多信息。
答案1
PDF 支持无损编码和 JPEG 编码。(JPEG 2000 也是如此。)您可能需要一个工具,它可直接从 PDF 中提取图像数据,并保持原样。Pdfimages,来自XPDF 包,将会这样做。
ImageMagick 实际上会渲染整个页面并提取它。这会丢弃已存储在 PDF 中的编码选择,并且不是完成此任务的最佳方法。
答案2
编辑:修复了原脚本的一些问题。根据 Marcks Thomas 的提议添加了替代方案。
编辑2:根据一系列更新的截止值测试运行。我仍然不确定如何估计灰度图像的文件大小。如果您正在处理大量 RGB 颜色方案之外的图像,您可能需要将第一个脚本作为第二个脚本的后备模式来实现。
编辑3:添加了optipng
集成。这可优化 PNG 文件大小,且不会造成任何质量损失。请参阅这里了解更多信息。一些较小的改进。
版本 0.1
重要的提示:此脚本已弃用。较新的版本效率更高。
好吧,我的问题可能稍微过于本地化了,所以我花了一些时间并自己编写了脚本:
#!/bin/bash
# AUTHOR: (c) MHC (http://askubuntu.com/users/81372/mhc)
# NAME: Intelliconvert 0.1
# DESCRIPTION: A script to automate and optimize the choice between different image formats.
# LICENSE: GNU GPL v3 (http://www.gnu.org/licenses/gpl.html)
# REQUIREMENTS: Imagemagick
ORIGINAL="$1"
###Filetype check###
MIME=$(file -ib "$ORIGINAL")
if [ "$MIME" = "image/png; charset=binary" ]
then
echo "PNG Mode"
###Variables###
##Original Image##
FILENAME=$(basename "$ORIGINAL")
PARENTDIR=$(dirname "$ORIGINAL")
SUBFOLDER=$(echo "$PARENTDIR" | cut -d"/" -f10-)
ORIGARCHIVE="~/ORIG"
##Converted Image##
TEMPDIR="/tmp/imgcomp"
CONVERTED="$TEMPDIR/$FILENAME.jpg"
##Image comparison##
DIFFLO="50"
DIFFHI="75"
CUTOFF="1000000"
##DEBUG
echo "#### SETTINGS ####"
echo "Filepath to original = $ORIGINAL"
echo "Filename= $FILENAME"
echo "Parent directory = $PARENTDIR"
echo "Archive directory = $ORIGARCHIVE"
echo "Temporary directory = $TEMPDIR"
echo "Filepath to converted image = $CONVERTED"
echo "Low cut-off = $DIFFLO"
echo "High cut-off = $DIFFHI"
###Conversion###
convert -quality 92 -flatten -background white "$ORIGINAL" "$CONVERTED"
###Comparison###
F1=$(stat -c%s "$ORIGINAL" )
F2=$(stat -c%s "$CONVERTED" )
FQ=$(echo "($F2*100/$F1)" | bc)
#Depending on filesize we use a different Cut-off#
if [ "$F1" -ge "$CUTOFF" ]
then
DIFF="$DIFFHI"
else
DIFF="$DIFFLO"
fi
##DEBUG
echo "### COMPARISON ###"
echo "Filesize original = $F1 Bytes"
echo "Filesize converted = $F2 Bytes"
echo "Chosen cut-off = $DIFF %"
echo "Actual Ratio = $FQ %"
if [ "$FQ" -le "$DIFF" ]
then
echo "JPEG is more efficient, converting..."
mv -v "$CONVERTED" "$PARENTDIR"
mkdir -p "$ORIGARCHIVE/$SUBFOLDER"
mv -v "$ORIGINAL" "$ORIGARCHIVE/$SUBFOLDER"
else
echo "PNG is fine, exiting."
rm -v "$CONVERTED"
fi
else
echo "File does not exist or unknown MIME type, exiting."
fi
该脚本与以下结合使用效果很好:观察者。
这是我的第一个正式脚本,因此可能存在一些我没注意到的未解决的错误和问题。请随意使用它并改进它。如果您这样做,我将非常感激您能在这里留下评论,以便我可以从中学习。
版本 0.2.1
找到正确格式的更有效方法是将原始文件大小与其未压缩图像的估计大小:
#!/bin/bash
# AUTHOR: (c) MHC (http://askubuntu.com/users/81372/mhc)
# NAME: Intelliconvert 0.2.1
# DESCRIPTION: A script to automate and optimize the choice between different image formats.
# LICENSE: GNU GPL v3 (http://www.gnu.org/licenses/gpl.html)
# REQUIREMENTS: Imagemagick, Optipng
################ Filetype Check#################
MIME=$(file -ib "$1")
if [ "$MIME" = "image/png; charset=binary" ]
then
echo "###PNG Mode###"
####################Settings####################
##Folders##
ORIGARCHIVE="~/ORIG"
##Comparison##
DIFFLO="25"
DIFFHI="20"
CUTOFF="1000000"
################################################
###Variables###
ORIGINAL="$1"
FILENAME=$(basename "$ORIGINAL")
PARENTDIR=$(dirname "$ORIGINAL")
SUBFOLDER=$(echo "$PARENTDIR" | cut -d"/" -f10-)
CONVERTED="$PARENTDIR/$FILENAME.jpg"
#DEBUG#
echo "###SETTINGS###"
echo "Filepath to original = $ORIGINAL"
echo "Filename= $FILENAME"
echo "Parent directory = $PARENTDIR"
echo "Archive directory = $ORIGARCHIVE"
echo "Filepath to converted image = $CONVERTED"
echo "Low cut-off = $DIFFLO"
echo "High cut-off = $DIFFHI"
###Image data###
WIDTH=$(identify -format "%w" "$ORIGINAL")
HEIGHT=$(identify -format "%h" "$ORIGINAL")
ZBIT=$(identify -format "%z" "$ORIGINAL")
COL=$(identify -format "%[colorspace]" "$ORIGINAL")
F1=$(stat -c%s "$ORIGINAL")
if [ "$COL" = "RGB" ]
then
CHANN="3"
else
CHANN="1"
fi
###Cutoff setting###
if [ "$F1" -ge "$CUTOFF" ]
then
DIFF="$DIFFHI"
else
DIFF="$DIFFLO"
fi
###Calculations on uncompressed image###
BMPSIZE=$(echo "($WIDTH*$HEIGHT*$ZBIT*$CHANN/8)" | bc)
FR=$(echo "($F1*100/$BMPSIZE)" | bc)
#DEBUG#
echo "###IMAGE DATA###"
echo "Image Dimensions = $WIDTH x $HEIGHT"
echo "Colour Depth = $ZBIT"
echo "Colour Profile = $COL"
echo "Channels = $CHANN"
echo "Estimated uncompressed size = $BMPSIZE"
echo "Actual file size = $F1"
echo "Estimated size ratio = $FR %"
echo "Cutoff at $DIFF %"
###Backup###
echo "###BACKUP###"
mkdir -p "$ORIGARCHIVE/$SUBFOLDER" #keep the original folder structure
cp -v "$ORIGINAL" "$ORIGARCHIVE/$SUBFOLDER"
echo ""
###Comparison###
if [ "$FR" -ge "$DIFF" ]
then
echo "JPEG is more efficient, converting..."
convert -quality 92 -flatten -background white "$ORIGINAL" "$CONVERTED"
echo "Done."
echo "Cleaning up..."
rm -v "$ORIGINAL"
else
echo "PNG is fine, passing over to optipng."
echo "Optimizing..."
optipng "$ORIGINAL"
echo "Done."
fi
################ Filetype Check#################
else
echo "File does not exist or unknown MIME type, exiting."
fi
感谢@Marcks Thomas 提出的绝妙想法。