ImageMagick的基本使用
Table of Contents
简介与安装
ImageMagick简介
ImageMagick是一个开源的强大的图片处理库,可用来创建、编辑、合成或转换位图图像,比如:调整大小,翻转,镜像,旋转,扭曲,剪切和变换图像,调整图像颜色,应用各种特殊效果,或绘制文本,线,多边形,椭圆和贝塞尔曲线等等。
本文只列出我使用过的命令,并不是完整的教程,随着我平时使用的增加,文章会不断更新,命令会不断增加,当然如果我平时用的少,那可能就只会有这些了。
安装ImageMagick
由于我是macOS,所以使用macOS最常用的包管理器brew
来安装
brew install imagemagick
命令使用格式
安装后,它主程序就一个magick
,但它会有很多符号链接链接到magick,如下图所示
既然都是符号链接,从理论上来说,我用identify
和用magick
应该是一模一样的才对,但实际上却是这样的(如图所示)
我猜是因为它把命令本身也当成一个参数,当它识别到是identify时,它就会做输出图片简略信息的操作。事实上,identify是magick的子命令,所以我们还可以这样写
所以,所有的符号链接其实都是magick的子命令,通用的使用方法是
magick 子命令 参数
但magick却巧妙的给magick创建多个符号链接,并把符号链接名称命名为它的子命令名,这样在使用上就好像是多了一个可执行文件,其实内部还是通过识别符号链接的名称来自动识别到它是子命令,以达到简化命令的目的,让我们可以直接以下边这种方式调用
子命令 参数
常用命令
获取图片信息
#显示简略图片信息
identify /path/to/image.png
#显示详细图片信息
identify -verbose /path/to/image.png
缩放图片
使用resize缩放
#缩放到指定大小
convert /path/to/source.png -resize 200x200 /path/to/target.png
#按百分比缩放
convert /path/to/source.png -resize 50% /path/to/target.png
#多次缩放(本例是缩小再放大,效果就是变模糊了,可用于做马赛克)
convert /path/to/source.png -resize 50% -resize 200% /path/to/target.png
#只缩放宽,高按比例(省略高不写即可,但“x”号还是要写的)
convert /path/to/source.png -resize 200x /path/to/target.png
#只缩放高,宽按比例(省略宽不写即可,但“x”号还是要写的)
convert /path/to/source.png -resize x200 /path/to/target.png
#批量把iPhone拍的照片缩小成指定尺寸
declare -i j=0;for i in *.JPG; do convert $i -resize 1008x ${i:0:$[${#i}-4]}_resized.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
使用sample采样缩放(只采样不插值,一般用于做缩略图)
#原图的50%
convert image.png -sample 50% sample.png
#先缩小再放大,就是马赛克效果
convert image.png -sample 10% -sample 1000% sample.png
设置jpg图片质量
90表示转换为原质量的90%
convert input.jpg -quality 90 output.jpg
旋转图片
旋转90度(顺时针)
convert input.jpg -rotate 90 output.jpg
镜像图片
镜像图片其实就是水平翻转,使用-flop
选项即可(-flip
是垂直翻转)
# 水平翻转,就是我们平时说的镜像
convert input.jpg -flop output.jpg
# 垂直翻转,这个一般比较少用
convert input.jpg -flip output.jpg
裁剪图片
#从(50,50)坐标开始,裁剪一个100⨉100大小的图片(乘号用小写英文字母xyz的x就可以)
convert image.png -crop 100x100+50+50 crop.png
#不指定位置,则会把大图片分割成100⨉100的小图片,生成crop-0.png, crop-1.png, ……
convert image.png -crop 100x100 crop.png
把当前文件夹下的所有.jpg
格式的图片都从(597,4)坐标开始(矩形左上角顶点),截取大小为1400×1076的图片,并且把图片名称的后27个字符(包括.jpg
4个字符)去掉(后面再自己拼上)
declare -i j=0;for i in *.jpg; do convert $i -crop 1400x1076+597+4 ${i:0:$[${#i}-27]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
${i:m:n}表示从字符串i的第m位截取到第n位,在我这里i就是图片文件名(包括.jpg
后缀),m是0,n是$[${#i}-27]
,${#i}
是文件名i的总长度。
declare -i j=0;for i in *.jpg; do convert $i -crop 1080x2160+0+240 ${i:0:$[${#i}-29]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
declare -i j=0;for i in *.jpg; do convert $i -crop 2002x1485+544+224 ${i:0:$[${#i}-4]}_crop.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
把当前文件夹下的所有.jpg
格式的图片都从(0,453)坐标开始(矩形左上角顶点),截取大小为540×744的图片
declare -i j=0;for i in *.jpg; do convert $i -crop 540x744+0+453 ${i:0:$[${#i}-27]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
把当前文件夹下的所有.PNG
格式的图片都从(414,4)坐标开始(矩形左上角顶点),截取大小为1530×1242的图片,同时把格式格式转为jpg
declare -i j=0;for i in *.PNG; do convert $i -crop 1530x1242+414+4 ${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
$[${#i}-4]
表示文件名总长度减4(其实就是去掉.PNG
这个后缀,然后再自己拼上.jpg
)。
declare -i j=0;for i in *.PNG; do convert $i -crop 1242x2000+0+208 ${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
裁剪到图像边缘
这个功能也可以叫去除图片的空白,就好像对文本去除空格一样,图片也可以去除空白的像素,以得到能容纳图像的最小图片。
比如这是原始图片
我想裁剪成这样,就是除有效图片外的所有空白都裁掉
很简单,使用-trim
选项即可
convert /path/to/input.jpg -trim /path/to/output.jpg
除了图片,也可以处理pdf格式(图片也可以使用这些参数)
convert -density 300 -trim -fuzz 1% +repage input.pdf output.pdf
-fuzz 1%
主要是设置羽化,1%
这个值可以自己看着来修改,-density 300
表示设置图片dpi(分辨率)为300,300这个数字可以适当降低(数值越大文件越大),或者如果不用这个选项觉得图片质量可以,那也可以不用。
根据实验,-trim
需要和-fuzz 1%
与+repage
一起使用才可以达到截取到图片比较边缘的地方(即几乎不留空白)
convert -trim -fuzz 1% +repage /path/to/input.jpg /path/to/output.jpg
把当前目录下的所有.jpg
(可自己修改)格式图片去除空白(即裁剪到图像的边缘)
declare -i j=0;for i in *.jpg; do convert -trim -fuzz 1% +repage $i ${i:0:$[${#i}-4]}_trimmed.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
抠图
"#FFFDF1"
为要抠掉的背景色(也可写成rgb(255,253,241)
这种格式),-fuzz 90%
为允许误差(因为背景可能不是纯色),90%可以换成其它数字,反正我测试数字越大抠的越干净,而且只能用百分数,90%虽然是0.9,但不能写成0.9
convert /path/to/input.jpg -fuzz 90% -transparent "#FFFDF1" /path/to/output.png
批量抠图:把当前文件夹下的所有.jpg
图片全部抠图
declare -i j=0;for i in *.jpg; do convert $i -fuzz 90% -transparent "#FFFDF1" ${i:0:$[${#i}-4]}.png;j=j+2;echo $j"."$i" convert succeed"!; done
修改背景颜色
-fill
是填充的意思,-opaque
是不透明的意思,意思是用-fill
指定的颜色去填充(即替换)-opaque
指定的颜色(原背景色)
convert /path/to/input.jpg -fuzz 25% -fill "#2DC844" -opaque "#FFFDF1" -flatten /path/to/output.jpg
-fuzz 25%
是允许色差(因为你的背景色可能不是完全的纯色),这个数值自己按实际效果慢慢修改,反正25%我觉得不错,但我测试的是纯色背景,如果你的背景色不是纯色,那问题就比较多了。
-flatten
意思是使用指定的背景色(有可能用-fill
或-background
指定)创建一个虚拟画布,然后将原图合成到这个画面上。
无背景色png图片添加背景色,-background "#2DC844"
用于指定背景色
convert /path/to/input.png -background "#2DC844" -flatten /path/to/output.jpg
批量操作:把当前目录下的所有.png
格式的图片全部添加#FFFDF0
背景色并裁剪掉一个像素(因为那是边)
# 裁剪出1620x3600的图片
declare -i j=0;for i in *.png; do convert $i -background "#FFFDF0" -flatten -crop 1620x3600+1+1 -quality 80 ~/Downloads/生成文件夹/${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
# 裁剪出3456x2234的图片
declare -i j=0;for i in *.png; do convert $i -background "#FFFDF0" -flatten -crop 3456x2234+1+1 -quality 80 ~/Downloads/生成文件夹2/${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
处理后的图片会被放到~/Downloads/生成文件夹/
文件夹中,如果想放在当前文件夹中,可以把~/Downloads/生成文件夹/
删除。
增加亮度
增加亮度(或降低亮度)有两个值,一个是亮度,一个是对比度,这个用过PS的应该都知道。
有两个参数可以使用,一个是-brightness-contrast
,一个是-sigmoidal-contrast
(-
可变成+
),参数格式如下
-brightness-contrast brightness{xcontrast}{%}
-sigmoidal-contrast contrastxmid-point%
-sigmoidal-contrast brightnessx0% 增加亮度
+sigmoidal-contrast brightnessx0% 降低亮度
- 花括号部分表示可以不写;
- 对于
-brightness-contrast
,brightness和contrast的值都是-100到100之间,%
可写可不写,但我习惯写,因为写了才知道是增加百分之几; -sigmoidal-contrast contrastxmid-point%
,一般把mid-point
写成0,只调节contrast就相当于调节亮度(此时contrast就相当于是brightness);mid-point
表示曲线的中点,一般用0,也可以用其它数字,这个得看具体情况;-sigmoidal-contrast
前面的-
变成+
表示降低亮度(刚好与符号相反);- 但这两个参数具体有什么区别我还不知道;
实例:
convert input.jpg -brightness-contrast 5% output.jpg
convert input.jpg -sigmoidal-contrast 5x0% output.jpg
修改位深
convert source.jpg -depth 8 target.png
同时缩放和修改位深(用于压缩png图片)
convert /path/to/source.png -resize 1080x1920 -depth 8 /path/to/target.png
格式转换
直接在输出文件中用不同的后缀就行,它会自动识别后缀来转换
convert /path/to/source.png /path/to/target.jpg
convert /path/to/source.png /path/to/target.webp
把当前文件夹下的所有PNG图片转成JPG
#只转成jpg
declare -i j=0;for i in *.PNG; do convert $i ${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
#转成jpg同时宽高压缩成原来的一半
declare -i j=0;for i in *.PNG; do convert $i -resize 50% ${i:0:$[${#i}-4]}.jpg;j=j+1;echo $j"."$i" convert succeed"!; done
注:${#i}
表示获取i的长度,${i:m:n}
表示从字符串i的第m个字符开始截取,共截取n个字符,感叹号不能放在双引号里面。
使用效果如下:
事实上它是可以直接处理多张图片的,不需要for循环,但仅限简单命令,如果是复杂命令,我试过不生效
convert *.png /path/to/target_%03d.jpg
%03d
:与%d
类似,都表示格式化为整数,只不过3表示至少显示3位,0表示如果不够3位,那就用0填充,整数上0可以换成其它符号,毕竟只是填充符号,但实际上在ImageMagick中只能用%03d
、%04d
这样的格式,不能用%-3d
、%-4d
等格式(否则它会把%当成普通字符打印出来)。
图片方向
下表从上到下,分别是从一个矩形的左上角开始顺时针旋转一圈,最终转到左下角,注意,英文说方向一般都是先说上下,再说左右,但是从5开始,它是先说左右,再说上下,因为它已经转了一圈回来了
imagemagick Orientation | exif:Orientation |
---|---|
TopLeft | 1 |
TopRight | 2 |
BottomRight | 3 |
BottomLeft | 4 |
LeftTop | 5 |
RightTop | 6 |
RightBottom | 7 |
LeftBottom | 8 |
关于图片方向的知识,可以看:这个回答。
关于iPhone拍照的方向,可以查看这里,请的非常详细。
imagemagick查看图片方向
# 方式一:格式化
identify -format '%[EXIF:Orientation]' /path/to/image.jpg
# 方式二:从所有图片信息里查找“Orientation”关键字
identify -verbose /path/to/image.jpg | grep Orientation
imagemagick设置图片方向,其中<方向>
就是上表中的8个英文,注意设置方向是直接修改原图方向,不是生成新图片(当然还有一个特殊值,就是Undefined
,也就是未定义,不带方向信息)
mogrify -orient <方向> IMG_4006.JPG
把当前文件夹下的所有图片方向都修改为TopLeft(即1
)
declare -i j=0;for i in *.jpg; do mogrify -orient TopLeft $i;j=j+1;echo $j"."$i" convert succeed"!; done
多个操作一起使用
直接多个选项合并在一起就行了,比如我要裁剪一个透明png图片,又要给它填充一个背景色,那就是
convert /path/to/input.png -background "#FFFDF0" -flatten -crop 1620x3600+1+1 /path/to/output.jpg
其中-background "#FFFDF0" -flatten
是填充背景色,-crop 1620x3600+1+1
就是剪裁,但是要注意的是,如果你把裁剪放在填充背景色之前,它会无法裁剪(即生成的图片尺寸还是跟原图一样),我也不知道为什么,同理,可能还有其它的选项合在一起有顺序关系,这个自己试试就知道了。
添加文字水印
文字水印1:半透明、有旋转角度、有自定义字体、能指定位置、宽高为主图的百分比
magick nature.jpg -set option:watermarkWidth "%[fx:int(w*0.2)]" -alpha set -background none \( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 10 -undercolor "#00FF0070" -font 爱的目光无所不在.ttf -size "%[watermarkWidth]x" label:"这是水印" -gravity center -geometry +10+10 -rotate -25 \) -composite -quality 60 result.jpg
-set option:watermarkWidth "%[fx:int(w*0.2)]"
-set option
表示设置一个变量,watermarkWidth
是变量名,"%[fx:int(w*0.2)]"
是变量值;"%[fx:int(w*0.2)]"
fx表示函数,int(w*0.2)
表示函数体,其中的w
表示第一个输入图片的宽度(其实就是要添加水印的图片的宽度),整体意思是把主图宽度的0.2倍存到变量中,以后后面把水印宽度设置为这个宽度(高度按比较缩放,不用设置);-alpha
开启alpha通道(透明通道);set -background none
把背景设置为none,再加上又开始alpha通道,所以画布是透明的(这样就可以在上边画水印了);-fill "#FFFFFF80"
填充颜色,前面6位是颜色,后面两位是透明度;-stroke "#FF000080"
描边颜色,前面6位是颜色,后面两位是透明度;-strokeWidth 10
指定描边宽度;-undercolor "#00FF0070"
指定文字底色,前面6位是颜色,后面两位是透明度;-font 爱的目光无所不在.ttf
指定字体路径,只支持ttf(如果不指定,中文会无法显示,英文一般都能显示,当然英文也可以指定字体);-size "%[watermarkWidth]x"
设置水印的宽高,%[watermarkWidth]
就是前面设置的变量,x
是乘号(用英文字母xyz中的x即可),高没有写,表示自动按比例缩放;label:"这是水印"
设置水印文字;-gravity center -geometry +10+10
表示设置水印位置;-gravity
指定9个位置中的一个,正好是在图片上画一个“米”字,“米”字的中心是一个位置,用英文center指定,另外8个位置分别为“东、南、西、北”以及它们斜角“东南、东北、西南、西北”,这些方向遵循地图上的位置定义(即:上北下南左西右东),当然是用英文的,全部小写,即:east, south, west, north, southeast, northeast, southwest, northwest;-geometry +10+10
前面-gravity
指定的位置都是刚好在边上的,用-geometry
可以让跟边有一点距离,+10+10
第一个+10
表示横坐标距离,第二个+10
表示纵坐标距离,注意这个距离是指距离它最靠近的那个边的距离,比如northeast的时候,就表示距离右边和上边的距离,而southwest的时候,就表示距离左边和下边的距离;-rotate -25
旋转角度,可以是正也可以是负;-composite
表示合成图片,其实前面是在把文字变成图片,最后用-composite
表示两张图片叠在一起;-quality 60
指定压缩等级,对于jpg,值为1-100质量逐渐升高,100的质量最好(但是也是会压缩的),因为jpeg格式本来就是有损压缩;而对于png格式,有0-9共10个等级,1-8,数字越大压缩越大,压缩越厉害(质量就越差),但具体解释非常复杂,总之从文件大小上看,1到8,文件是逐渐变小的,但9是例外,0和9质量都是最好,区别是压缩算法不同(0是zlib Z_RLE压缩,而9是Z_HUFFMAN_ONLY压缩),到底哪个更好,我也不知道,自己肉眼看吧。不过写0-9的时候,要写成10-90(为了跟jpeg保持一致),它会自动除以10,所以19表示级别1,21表示级别2;- 不想要设置的选项可以不指定,比如不想要底色,不想要描边,就不用写相对的选项;
- 在Windows中括号不用转义,如果在行末用了
\
作为换行符,在Windows中要换成^
。
文字水印2:使用-pointsize
设置字体大小
magick nature.jpg -alpha set -background none \( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 10 -font 爱的目光无所不在.ttf -pointsize 36 label:"这是水印" -gravity center -geometry +10+10 -rotate -25 \) -composite -quality 60 result.jpg
- 使用了
-pointsize
可以设置字体大小,即字号,但一定要去掉-size
,否则-pointsize
会被-size
覆盖,等于没设置。 - 如果批量设置,我还是建议用
-size
而不是-pointsize
,因为-size
可以根据主图的比例来设置大小,当图片大小不一时,比例也能一致,但如果设置-pointsize
那就没法按主图大小来设置了。
文字水印3:平铺水印
magick nature.jpg -set option:watermarkWidth "%[fx:int(w*0.2)]" -alpha set -background none -fill "#ffffff80" -font 爱的目光无所不在.ttf \( -size "%[watermarkWidth]x" label:"这是水印" -rotate 45 -write mpr:abc +delete \) \( +clone -tile mpr:abc -draw "color 0,0 reset" \) -composite result.jpg
- 什么是mpr?,Memory Program Register,
-write mpr:abc
表示把它前面的配置写入到内存中,并命名为abc
,后面使用的时候,就可以用mpr:abc
来调用它。 +delete
删除序列中最后一个图片;+clone
克隆序列中最后一个图片;-draw "color 0,0 reset"
画图,(0,0)是坐标,表示从(0,0)开始画,reset是直接替换的颜色;
文字水印4:批量设置水印
declare -i j=0;for i in *.jpg; \
do magick $i -set option:watermarkWidth "%[fx:int(w*0.2)]" -alpha set -background none \( -fill "#FFFFFF80" -stroke "#FF000080" -strokeWidth 10 -undercolor "#00FF0070" -font 爱的目光无所不在.ttf -size "%[watermarkWidth]x" label:"这是水印" -gravity center -geometry +10+10 -rotate -25 \) -composite -quality 60 ${i:0:$[${#i}-4]}_wm.jpg; \
j=j+1;echo $j"."$i" convert succeed"!; done
添加图片水印
图片水印:按主图大小比例设置水印大小、设置水印透明度
magick nature.jpg -set option:logowidth "%[fx:int(w*0.25)]" \( logo.png -resize "%[logowidth]x" -background none -rotate -30 -channel A -fx "u*0.3" \) -gravity center -geometry +10+10 -composite result.jpg
-channel A -fx "u*0.3"
设置水印透明度(A通道就是alpha通道);
循环给当前目录下所有jpg图片添加水印
declare -i j=0;for i in *.jpg; \
do magick $i -set option:logowidth "%[fx:int(w*0.25)]" \
\( logo.png -resize "%[logowidth]x" -background none -rotate -30 -channel A -fx "u*0.3" \) -gravity center -geometry +10+10 -composite ${i:0:$[${#i}-4]}_wm.jpg; \
j=j+1;echo $j"."$i" convert succeed"!; done
参考:
后台使用imagemagick的convert命令来处理图片真是太方便了。。
Anatomy of the Command-line
Why do some ImageMagick flags have plus sign (+) and others minus (-)?
Explanation for sprintf(“%03d”, 7) functionality?
ImageMagick命令
Watermarks
使用 ImageMagick 批量去水印
test