天天看點

python 使用pngquant和ImageMagick批處理壓縮png/jpg

最近閑着沒事,大佬便配置設定個壓縮圖檔的任務給我。于是,我就上網找尋相對需求而言最優的解決方案。

 初步實踐後,得出結論:pngquant與ImageMagick各方面都符合需求。

python 使用pngquant和ImageMagick批處理壓縮png/jpg

各方法比對​​​​​​

ImageMagick下載下傳位址 :http://www.imagemagick.org/script/download.php/

pngquant下載下傳位址: http://pngquant.org/

我的是windows系統,是以選擇下載下傳windows版的。

python 使用pngquant和ImageMagick批處理壓縮png/jpg

pngquant下載下傳

python 使用pngquant和ImageMagick批處理壓縮png/jpg

ImageMagick下載下傳

pngquant_window.zip解壓後用到的是pngquant.exe。你可以把它添加進系統變量,也可直接放在.py檔案的目錄下調用。

ImageMagick則運作exe安裝。一路next之後,安裝完成。如果你是使用PyCharm編輯,且安裝之前打開的話,需重新開機PyCharm才能調用'magick'指令。

準備工作都做好了,上代碼。

#!/usr/bin/python
# coding=utf-8

import os
import time
import shutil
import math

# PYTHON 2.7

srcPath = r"./tsimg"
savePath = r"./pngquantImg1"

# 運作指令行
def runSystem(ossys):
    result = os.system(ossys)
    if result == 0:
        print(str(ossys) + ' success')
        return True
    else:
        print(str(ossys) + ' fail')
        return False


# 删除空檔案夾
def delete_null_dir(dirr):
    if os.path.isdir(dirr):
        for p in os.listdir(dirr):
            d = os.path.join(dirr, p)
            if (os.path.isdir(d) == True):
                delete_null_dir(d)
    if not os.listdir(dirr):
        os.rmdir(dirr)

# pngqyant 參數:
# --ext new.png 新名字(不傳就預設字尾加'-or8.png' 或 '-fs8.png') 好像不行 用 -o new.png 可以
# --quality min-max 訓示pngquant使用滿足或超過最大品質所需的最少顔色量
# --speed 速度/品質權衡從1(蠻力)到10(最快)。預設值為3。速度10的品質降低5%,但比預設速度快8倍。
# --iebug E6的解決方案,它隻顯示完全不透明的像素。pngquant将使幾乎不透明的像素完全不透明,并避免建立新的透明顔色
# --version 将版本資訊列印到stdout
# - 從stdin讀取圖像并将結果發送到stdout
# -- 停止處理參數。這允許使用以-開頭的檔案名。如果在腳本中使用pngquant,建議将其放在檔案名之前:pngquant $OPTIONS -- "$FILE"
# 網上說的
# --force 參數無效,隻要輸出檔案存在,就會報錯,無視這個本用來指定覆寫的參數
# --skip-if-larger 參數不正常,有時候生成檔案明明比較小,也會被skip掉……

def usePngQuantAndImageMagickAPI(max_size):
    if os.path.exists(savePath):
        shutil.rmtree(savePath, True)
    print(savePath)

    os.mkdir(savePath)

    for n, f, file in os.walk(srcPath):
        if len(file) != 0:
            for i in file:
                filetotledir = os.path.join(n, i)
                temp_savePath = n.replace(srcPath, savePath)
                if not os.path.exists(temp_savePath):
                    os.makedirs(temp_savePath)
                filetotledir1 = os.path.join(temp_savePath, i)

                CompressImage(filetotledir, max_size, filetotledir1)  # 75
        else:
            continue

    delete_null_dir(savePath)

def CompressImage(image_name, max_size, replace_name=''):
    image_stat = os.stat(image_name)
    image_size = image_stat.st_size / 1024.0  # 計算KB
    print 'st_size:{0} image_size:{1}'.format(image_stat.st_size, image_size)

    global g_total
    global g_compress_size
    global png_array
    global jpg_array
    global g_pic_num
    global g_compress_pic_num

    if image_size > max_size and not '.meta' in image_name:
        compress_factor = max_size / image_size * 500  # 100

        base_name = os.path.basename(image_name)
        print("compressing :{0} compress_factor:{1} basename:{2}".format(image_name, compress_factor, base_name))

        for ext_name in png_array:
            if ext_name in image_name:
                compress_factor = math.trunc(round(compress_factor))
                if compress_factor > 90:
                    compress_factor = 85
                # if compress_factor < 75:
                #     compress_factor = 75
                iscompress = runSystem('pngquant.exe --force --verbose --speed=1 --quality={2}-100 {0} -o {1}'
                                       .format(image_name, replace_name, compress_factor))

                if iscompress:
                    g_compress_size = g_compress_size + math.ceil(os.stat(replace_name).st_size / 1024.0)
                    g_compress_pic_num = g_compress_pic_num + 1

                g_total = g_total + math.ceil(image_size)
                g_pic_num = g_pic_num + 1
                break

        for ext_name in jpg_array:
            if ext_name in image_name:
                iscompress = runSystem('magick convert {0} -quality {1} {2}'
                                       .format(image_name, compress_factor, replace_name))
                if iscompress:
                    g_compress_size = g_compress_size + math.ceil(os.stat(replace_name).st_size / 1024.0)
                    g_compress_pic_num = g_compress_pic_num + 1

                g_total = g_total + math.ceil(image_size)
                g_pic_num = g_pic_num + 1
                break
    elif not '.meta' in image_name:  # 不複制原圖,隻記大小
        for ext_name in png_array:
            if ext_name in image_name:
                # shutil.copy(image_name, replace_name)

                g_total = g_total + math.ceil(image_size)
                g_pic_num = g_pic_num + 1

                break

        for ext_name in jpg_array:
            if ext_name in image_name:
                # shutil.copy(image_name, replace_name)

                g_total = g_total + math.ceil(image_size)
                g_pic_num = g_pic_num + 1

                break


if __name__ == "__main__":
    # 給個預設值
    time1 = time.time()
    # 圖檔總大小
    global g_total
    g_total = 0
    # 圖檔壓縮大小
    global g_compress_size
    g_compress_size = 0
    # png
    global png_array
    png_array = ['.png', '.PNG']
    # jpg
    global jpg_array
    jpg_array = ['.JPG', '.jpg', '.jepg', '.JPEG']

    # 圖檔總數
    global g_pic_num
    g_pic_num = 0

    # 壓縮圖檔數量
    global g_compress_pic_num
    g_compress_pic_num = 0

    max_size = 50

    usePngQuantAndImageMagickAPI(max_size)


    print (u'總共圖檔大小:{0}KB 壓縮了:{1}KB 壓縮後大小:{2}KB'
           .format(g_total, g_compress_size, (g_total - g_compress_size)))
    print (u'圖檔總數:{0}張 壓縮圖檔數:{1}張'.format(g_pic_num, g_compress_pic_num))

    time2 = time.time()

    print u'總共耗時:' + str(time2 - time1) + 's'
           

我的項目運作後:

總共圖檔大小:29232.0KB 壓縮了:14152.0KB 壓縮後大小:15080.0KB

圖檔總數:759張 壓縮圖檔數:94張

總共耗時:42.7580001354s

參數還可再調整下,現在還湊合。

總結:網上的輪子很多,仔細找找,總有一款合适你的需求。但要成為大牛,還是自己實作一遍比較diao。

再分享個技巧:找不到合适的方法時,可以下載下傳類似軟體,看下它們的庫檔案。就像ImageMagick,我是下載下傳搜尋排行第一的壓縮寶,才找到的。/手動斜眼笑