阿里云oss图片压缩

Python库:

脚本作用是将阿里云图片下载在本地,使用Pillow库的Image类压缩后回传覆盖
图片几乎是无损压缩,压缩前后肉眼难辨,针对大图片压缩比还是很明显的

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from __future__ import print_function

import os
import shutil
from itertools import islice
from time import sleep
from datetime import datetime

import oss2
from PIL import Image, ImageFile

def echo(msg):
    time_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    print('[%s]: %s' % (time_str, msg))

def loadMarker(file_path='.marker'):
    """
    读取进度
    """
    marker = ''
    if not os.path.exists(file_path):
        with open(file_path, 'w') as fh:
            fh.write(marker)
    else:
        with open(file_path, 'r') as fh:
            marker = fh.read()
    return marker

def saveMarker(marker, file_path='.marker'):
    """
    保存进度
    """
    with open(file_path, 'w') as fh:
        fh.write(marker)

def compressImage(file_path):
    """
    压缩图片
    """
    ok = False
    backup_file_path = '%s.bak' % file_path
    try:
        os.rename(file_path, backup_file_path)
        with open(backup_file_path, 'rb') as fp:
            img = Image.open(fp)
            file_format = str(img.format)
            if file_format == 'PNG' or file_format == 'JPEG':
                ImageFile.MAXBLOCK = img.size[0] * img.size[1]
                img.save(file_path, quality=90, optimize=True)
                osize = os.path.getsize(backup_file_path)
                nsize = os.path.getsize(file_path)
                if nsize >= osize:
                    result = 'Cannot further compress: %s' % file_path
                    os.remove(file_path)
                else:
                    result = nsize
                    ok = True
            else:
                result = 'Ignoring file: %s format: %s' % (file_path, file_format)
    except Exception as e:
        # shutil.move(backup_file_path, file_path)
        result = 'Compress %s failed, error: %s' % (file_path, e)
    if os.path.exists(backup_file_path):
        os.remove(backup_file_path)
    return ok, result

def do_compressOssImg(bucket, opath):
    """
    下载bucket图片压缩并上传
    """
    ok = False
    nsize = 0
    file_dir, file_name = os.path.split(opath)
    tmp_file_path = '%s%s' % (TMP_DIR, file_name)
    s = bucket.get_object_to_file(opath, tmp_file_path)
    if s.status == 200:
        ok, nsize = compressImage(tmp_file_path)
        if ok:
            s = bucket.put_object_from_file(opath, tmp_file_path)
            if s.status == 200:
                ok = True
                os.remove(tmp_file_path)
    return ok, nsize

def main():
    """
    main
    """
    size = 100
    marker = loadMarker()
    auth = oss2.Auth(OSS_ACCESS_ID, OSS_ACCESS_KEY)
    bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUCKET)
    i = 0
    iterable = oss2.ObjectIterator(bucket, marker=marker)
    while True:
        iterable = oss2.ObjectIterator(bucket, marker=marker)
        iterator = islice(iterable, size)
        opath = ''
        for obj in iterator:
            i += 1
            opath = obj.key
            osize = obj.size
            otype = opath.split('.')[-1]
            if otype.lower() in IMG_TYPE:
                if osize > 1024 * 800:  # 只压缩大于800KB的图片
                    ok, nsize = do_compressOssImg(bucket, opath)
                    if ok:
                        echo('OK:\t%s\t%s\t%s' % (opath, osize, nsize))
                    else:
                        echo("Failed:\t%s\t%s" % (opath, nsize))
                else:
                    echo("Ignore:\t%s\t%s" % (opath, osize))
            else:
                echo("Ignore:\t%s" % opath)
            sleep(0.05)
        if iterable.is_truncated:
            marker = opath
        else:
            marker = ''
            saveMarker(marker)
            echo('End. Total: %s' % i)
            break
        saveMarker(marker)
        sleep(0.2)

if __name__ == '__main__':
    OSS_ENDPOINT = 'oss-cn-beijing.aliyuncs.com'
    OSS_ACCESS_ID = 'xxxxxxxxxxxxxxx'
    OSS_ACCESS_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    OSS_BUCKET = 'test'
    TMP_DIR = '/dev/shm/'
    IMG_TYPE = [
        'jpg',
        'jpeg',
        'png'
    ]
    main()

已在线上实测,只压缩了大于800KB的图片,再加上部分型号相机拍摄的图片格式是不支持的
压缩完后,OSS使用容量从890G降到607G,节省了283G

阿里云oss

订阅
提醒
2 评论
在线反馈
查看全部评论