使用Python压缩图片成指定大小

2024-05-10 01:32:33 浏览数 (2)

我们常常上传图片,网站对照片有一定要求,比如说图片大小不能超过多少个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
  • 目标图片的长度和高度
代码语言:python代码运行次数:9复制
#!/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)

运行效果如下:

原始图片对比压缩后的图片:

0 人点赞