Python库:
Pillow(PIL)
Python下最好用的图片压缩库oss2
阿里云oss的SDK
脚本作用是将阿里云图片下载在本地,使用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