使用Shell脚本批量压缩图片

在开发过程中我们为了减小安装包的体积,我们一般会把工程当中的图片资源文件进行压缩。

在添加图片的时候进行压缩是一个好习惯,但是对于工程当中的大量图片进行压缩替换是一个不小的工作量,而且还有可能不小心弄错,像这种大批量的重复性工作就需要写脚本来帮助我们完成了。

TinyPng&Shell

我们先来介绍我们今天的主角TinyPng,我相信许多开发人员都知道这个网站,TinyPng凭借着优秀的压缩效率和压缩质量备受好评。同时它也提供了相应的API供我们使用,这也是为什么要使用它的原因。

不过TinyPng也有一个限制,单个账号每月最多压缩500张次图片,想要提高相应压缩数量需要付费,这也对脚本的批量压缩造成了一些限制,后面会做相应介绍。

shell脚本就不过多的进行介绍了,网上的教程有很多,本文只会针对比较特殊的地方进行介绍。

实现思路

基本思路是从给定的文件夹下进行遍历查找,如果是图片,进行压缩,将压缩之后的图片下载进行替换,如果是文件夹的话则进入该文件夹下进行更深一层的遍历查找压缩。具体的可以查看脚本,代码如下:

#!/bin/bash

dir=<#directory#>

apikey=<#apikey#>

pngindex=0

#获取上传文件返回的数据当中的url
parse_json()
{
    value=`echo $1 | sed 's/.*"url":"\(.*\)"}}/\1/g'`
    echo $value
}

compress_file()
{
    for file in `ls $1`; do
        #如果是普通文件
        if [ -f "$1/$file" ]; then
            if [ ${file##*.} == "png" ] || [ ${file##*.} == "PNG" ] || [ ${file##*.} == "jpg" ]; then
                echo "压缩文件$1/$file"

                s=$(curl https://api.tinify.com/shrink \
                     --user api:${apikey} \
                     --data-binary "@$1/$file")

                url=$(parse_json $s) 

                #如果url不为空下载
                if [ -n "$url" ]; then
                    length=$(curl $url \
                         --user api:${apikey} \
                         --output "$1/$file")
                else
                    echo "$s1/$file压缩失败"
                fi
            fi
        #如果是文件夹
        else
            compress_file "$1/$file"
        fi
    done
}

check_filenumber()
{
    for file in `ls $1`; do
        #如果是普通文件
        if [ -f "$1/$file" ]; then
            if [ ${file##*.} == "png" ] || [ ${file##*.} == "PNG" ] || [ ${file##*.} == "jpg" ]; then
                pngindex=`expr $pngindex + 1`
            fi
        #如果是文件夹
        else
            check_filenumber "$1/$file"
        fi
    done
}

main()
{
    echo "请输入以下选项:"
    echo "0:查看当前文件夹下的png图片个数"
    echo "1:执行压缩操作"

    read item
    if [ $item == 0 ]; then
        check_filenumber $dir
        echo "图片数:$pngindex";
    elif [ $item == 1 ]; then
        compress_file $dir;
    fi
}

main

<#directory#>替换成需要压缩的路径<#apikey#>替换成TinyPng上申请的key即可

可以看到为了避免文件夹下图片数量超过500,我先写了一个查看该文件夹下图片数量的方法,这样不想付费的用户可以使用多个账号对工程下面的图片数量不超过500进行分次压缩即可。

如果单个文件夹下图片超过500,建议先拆成多个小于500的文件夹进行处理。当然付费提升数量或者改造脚本也是一个不错的选择。

一些说明

1.运行脚本之前最好执行一下chmod +x <#ScriptFile#>命令,赋予脚本文件执行权限

2.shell函数一般把最后一行执行的结果作为函数的结果返回,所以parse_json方法最后一行的echo $value是将value的值返回(控制台并不输出value)。shell当中也可以使用return返回结果,但return只能返回0/1这样的整数,有一定的限制。

3.|在shell当中用来连接两个命令,并将第一个命令执行的结果作为参数传递给后面的命令

4.sed是流编辑器命令,用来处理获取到的文本,此处的作用是将上传返回数据当中的压缩后的图片的地址筛选出来。

5.sed 's/<#value1#>/<#value2#>/g'`是匹配相应正则的value1用value2替换,/g表示全部替换,没有的时候只替换第一个匹配的

6.sed 's/.*"url":"\(.*\)"}}/\1/g'`当中的\1是将()当中标记为1并返回,这样value就可以接收到sed命令的处理结果。

7.curl是一个命令行下文件传输工具,这里不过多介绍。

8.之前因为不熟悉curl命令,将–dump-header <#路径#>添加在curl命令后,造成在compress_file方法当中输出s的值是正常的json数值,而在parse_json方法当中接收到却是网络请求头的第一行HTTP 1.1,遇到这个问题的同学注意下。

9.脚本文件戳这里