我们常常上传图片,网站对照片有一定要求,比如说图片大小不能超过多少个kB,图片宽度高度在一个限定值。
平时的你可能会用小画家绘图软件或者PS来处理。既然我们是个程序员,也有了Python这把瑞士军刀。那么本篇文章教你怎么写个代码来处理图片来满足日常需求。有了这个代码以后这种小case也不用求人了。
处理图片分为两个部分:
- 重制图片成指定宽度和指定高度值,并且能保持长宽比
- 不改变图片宽度和高度值,压缩JPEG质量比,来使图片保持在一定的存储大小之内。
这里用到的图片处理库就是Python自带的PIL下面的Image Module
一、图片的resize
图片的resize,一般来说我们会维持图片的原始长宽比,来使图片看起来没有失真。
这里的原始长宽比确定,我们会去找长度和高度哪个大。我们先把那个大的值限定在指定长度内,然后再根据长宽比去计算另一个长度值。分情况讨论:
- 如果原始长高比>目标长高比,那么目标长度定为用户设定值,目标高度根据原始长高比去计算。
- 反之,目标高度设为用户设定值,目标宽度根据原始长高比去计算。
就是这段代码
代码语言:python代码运行次数:1复制max_width=100
min_width=100
max_height=100
min_width=100
new_width=max_width
new_height=max_height
if rgb_im.width/rgb_im.height>new_width/new_height:
new_height=int(new_height*rgb_im.height/rgb_im.width)
else:
new_width=(new_width*rgb_im.width/rgb_im.height)
二、图片的压缩
目标图片是JPEG的话,JPEG有个图片压缩因子。我们的目标是调整这个因子来使得存储尽量接近目标值。换句话说就是不超过存储空间的前提下,调整因子保持最大的图片质量。这里的压缩因子在(25,96)之间。然后采用二分法得出目标压缩因子。也就是代码里的defJPEGSaveWithTargetSize(im, filename, target):函数。
三、完整的程序
程序如下,或者我已经上传到github这里地址下载https://github.com/lumanyu/ai_app/blob/main/image_compress/main.py。
使用的时候需要你需要提供个性化输入:
- 图片是来自本地磁盘还是网络
- 目标图片存储空间不超过多少B
- 目标图片的长度和高度
#!/usr/local/bin/python3
import io
import math
import sys
from PIL import Image
def JPEGSaveWithTargetSize(im, filename, target):
"""Save the image as JPEG with the given name at best quality that makes less than "target" bytes"""
# Min and Max quality
Qmin, Qmax = 25, 96
# Highest acceptable quality found
Qacc = -1
while Qmin <= Qmax:
m = math.floor((Qmin Qmax) / 2)
# Encode into memory and get size
buffer = io.BytesIO()
im.save(buffer, format="JPEG", quality=m)
s = buffer.getbuffer().nbytes
if s <= target:
Qacc = m
Qmin = m 1
elif s > target:
Qmax = m - 1
# Write to disk at the defined quality
if Qacc > -1:
im.save(filename, format="JPEG", quality=Qacc)
im.show()
else:
print("ERROR: No acceptble quality factor found", file=sys.stderr)
################################################################################
# main
################################################################################
# Load sample image
from PIL import Image
import requests
from io import BytesIO
url="https://raw.githubusercontent.com/lumanyu/ai_app/main/data/recipe/braised_pork.png"
response = requests.get(url)
im = Image.open(BytesIO(response.content)) #原始图片来自网络
rgb_im = im.convert('RGB')
#im = Image.open('/Users/mark/sample/images/lena.png') #原始图片来自本地磁盘
# Input Image Limitation
storage=100000 #目标图片存储空间
max_width=100 #目标图片宽度
min_width=100
max_height=100 #目标图片高度
min_width=100
new_width=max_width
new_height=max_height
if rgb_im.width/rgb_im.height>new_width/new_height:
new_height=int(new_height*rgb_im.height/rgb_im.width)
else:
new_width=(new_width*rgb_im.width/rgb_im.height)
resized_im = rgb_im.resize((new_width, new_height), Image.Resampling.LANCZOS)
# Save at best quality under 100,000 bytes
JPEGSaveWithTargetSize(resized_im, "result.jpg", storage)
运行效果如下:
原始图片对比压缩后的图片: