你能看懂下面这个macOS命令吗?(GNU/Linux xargs可能会略有不同)

ls *.JPG | xargs -n1 -I '{}'  convert '{}' -resize "x1600" -profile "/System/Library/ColorSync/Profiles/sRGB Profile.icc" -auto-orient -strip -quality 50 './compact/{}'

解释一下
ls *.JPG为列出当前目录所有JPG图像文件,注意这里区分大小写。
| 为管道操作,表示将左边的结果传递给右边。
xargs为接收管道传递值的命令,由于convert不能直接接收管道,所以需要xargs。

上面这个命令的意思是把每一个JPG文件的文件名依次传递给convert命令,传递到'{}'的位置。一共有多少个JPG文件就执行多少次convert的命令。

比如你的目录里面有2个文件,a.JPG和b.JPG,那么上面的命令就相当于下面的两行命令:

convert a.JPG -resize "x1600" -profile "/System/Library/ColorSync/Profiles/sRGB Profile.icc" -auto-orient -strip -quality 50 './compact/a.JPG'
convert b.JPG -resize "x1600" -profile "/System/Library/ColorSync/Profiles/sRGB Profile.icc" -auto-orient -strip -quality 50 './compact/b.JPG'

好,再来看一下convert命令,
convert是ImageMagick套件的一个命令,这个套件有非常强大的图像处理功能,这里我们只介绍上面列出的参数。

第一个参数 '{}'事实上就是通过管道传进来的JPG文件名,我们以a.JPG为例。

第二个参数表示将a.JPG的高度调节为1600像素,但长宽比例不变。
resize这个参数经常会用到,所以我多说两句。假设图片为4000x2000:
-resize "200%" 长宽同比例缩放到200%,8000x4000
-resize "1000" 宽度调整为1000px,高度同比例调节。调整后尺寸1000x500
-resize "x1000" 高度调整为1000px,宽度同比例调节。调整后尺寸2000x1000
-resize "1000x1000" 长边调整为1000px,短边同比例调节。调整后尺寸1000x500
-resize "1000x1000^" 短边调整为1000px,长边同比例调节。调整后尺寸2000x1000
-resize "1000x1000!" 宽度高度都调整为1000px,忽略宽高比例。调整后尺寸1000x1000
-resize "1000x1000>" 只有原图像大于1000x1000才调整。
-resize "1000x1000<" 只有原图像小于1000x1000才调整。
光说不练假把式,自己试试就知道啦。

第三个参数表示将图像转码为sRGB色彩空间。色彩空间的概念这里先不赘述了,以后有机会写篇文章。
简单来说,单反相机的照片一般你可以选择aRGB或者sRGB,而iphone拍出来的照片一般都是苹果自己的p3空间的。sRGB为web标准色彩空间,一般也是默认的色彩空间。

第四个参数表示根据图像exif中的旋转信息把图像旋转。因为有些相机,无论你横排还是竖拍,图片存档都是横置的,图片的旋转信息是根据设备的重力感知系统记录到exif信息上的。

第五个参数是去掉图片的exif等profile信息。这也是为什么需要前两个参数进行转换,否则你直接用-strip来去掉exif信息会丢掉色彩空间信息和旋转信息。删掉exif一方面是会缩小体积,另一方面也是避免了一些隐私的暴露,比如位置信息等。

第六个参数表示JPG压缩质量为50。数值为1-100之间,数值越大画质越好,体积越大。

第七个参数为转换后文件的位置。保存在当前目录下面compact目录下的同名文件a.jpg。你需要提前建立好compact子目录。

好了,你能根据自己的需要修改这条命令了吗?
ImageMagick是一款非常强大的开源图片处理工具。macOS出厂时并没有安装这款软件,因此你需要自己将它安装到Mac上,推荐使用brew安装。

老张说:

如果文件名有空格的话,上面的命令会出错的,你知道怎么解决吗?

ls *.JPG | tr \\n \\0 | xargs -n1 -0 -I '{}'  convert '{}' -resize "x1600" -profile "/System/Library/ColorSync/Profiles/sRGB Profile.icc" -auto-orient -strip -quality 50 './compact/{}'

再说一下xargs吧。

ls *.JPG | xargs命令默认是-n5000,啥意思呢?也就是说,先把ls的结果以空格或者换行来分割成n条记录,xargs默认一次接受5000条记录。这显然不是我们想要的。所以我加上了-n1的参数,就是说,我们一条记录一条记录来,有几个文件我们就传递几次。

正常来说这没问题,但是如果文件中有空格就出问题了。

比如有个’c d.JPG’的文件。那么这个文件会被中间的空格分割成2条记录,c和d.JPG。也就是说会分两次传递出去。
显然目录里即没有文件c,也没有文件d.JPG。因此会出错。

如果恰巧你的目录里有文件c和d.JPG,

如果c也是一个图像文件的话,那么虽然也不会报错,但是’c d.JPG’文件本身并不会被传递处理,
同时c会被额外处理(因为ls列出的JPG文件本身是不包括c的,因此c本来不会被处理),
而d.JPG会被处理2遍。(d.JPG本身就会被ls列出来传给管道)
如果c不是图像文件,那么convert也会报错。

所以我们先加上了ls *.JPG | tr \\n \\0。啥意思呢,就是说,先把ls输出中的换行替换成null。
你看这里管道就不需要xargs命令,因为tr命令本身能够接受管道传过来的数据。

注意,虽然ls命令显示的文件名可能看上去在同一行,但其实每一个文件名后面都是有换行的。
不信你用ls > a把结果输出到文件a,然后查看一下文件。

光把换行替换了还是不行,xargs还不知道呀。因此xargs后面又加上了-0这个参数,意思是,嘿xargs,不要用空格和换行来分割记录了,统一用null来分割吧。这样,每一个文件就会被分割成一条记录通过管道传递给convert命令了。

支持我们

如果您喜欢这篇文章,您可以分享给您的朋友,分享到您的社交账号比如:

或者 点击这个链接 观看广告支持我【广告内容与我们无关,请不要轻易相信并打开弹出的广告】。
若您经济宽裕,更欢迎通过下面的方式小额赞助以支持我们的创作。