本文主要是介绍Python利用PIL进行图片压缩,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Python利用PIL进行图片压缩》有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所以本文为大家介绍了Python中图片压缩的方法,需要的可以参考下...
有时在发送一些文件如PPT、Word时,由于文件中的图片太大,导致文件也太大,无法发送,所有可以对文件中的图片进行压缩,下面代码根据用户自定义的目标大小(如30KB或40KB)进行压缩,并尽可能保证图片清晰度。
高质量缩放:使用LANCZOS重采样算法,保证缩放后的图片清晰度。
锐化增强:在压缩后对图片进行锐化处理,进一步提升清晰度。
智能判断:优先降低质量,避免不必要的缩放,减少清晰度损失。
from PIL import Image, ImageFilter import io def compress_image(input_path, output_path, max_size_kb, quality=85, step=5): """ 压缩图片到指定大小以下,并尽可能保证清晰度。 :param input_path: 输入图片CBeuy路径 :param output_path: 输出图片路径 :param max_size_kb: 目标大小(单位:KB) :param quality: 初始压缩质量(默认85) :param step: 每次降低质量的步长(默认5) """ # 打开图片 img = Image.open(input_path) # 将图片转换为RGB模式(如果是RGBA或其他模式) if img.mode in ('RGBA', 'LA'): img = img.convert('RGB') # 创建一个字节流对象 img_byte_arr = io.BytesIO() # 保存图片到字节流,初始质量为quality img.save(img_byte_arr, format='JPEG', quality=quality) # 获取当前图片android大小 current_size = len(img_byte_arr.getvalue()) / 1024 # 转换为KB # 如果图片大小超过最大限制,逐步降低质量 while current_size > max_size_kb and quality > 10: quality -= step img_byte_编程arr = io.BytesIO() img.save(img_byte_arr, format='JPEG', quality=quality) current_size = len(img_byte_arr.getvalue()) / 1024 # 如果图片大小仍然超过最大限制,调整图片尺寸 while current_size > max_size_kb: width, height = img.size # 计算缩放比例,确保图片大小接近目标大小 scale_factor = (max_size_kb / current_size) ** 0.5 new_width = int(width * scale_factor) new_height = int(height * scale_factor) img = img.resize((new_width, new_height), Image.Resampling.LANCZOS) img_byte_arr = io.BytesIO() img.save(img_byte_arr, format='JPEG', quality=quality) current_size = len(img_byte_arr.getvalue()) / 1024 #php 对图片进行锐化处理 img = img.filter(ImageFilter.SHARPEN) # 保存压缩后的图片 with open(output_path, 'wb') as f: img.save(f, format='JPEG', quality=quality) print(f"压缩后的图片大小: {current_size:.2f} KB") input_image = r"E:\桌面\2.jpg" output_image = r"E:\桌面\2-1.jpg" target_size_kb = 35 # 自定义目标大小,例如30KB compress_image(input_image, output_image, max_size_kb=target_size_kb)
python+PIL将压缩图片刚好 200KB
解决思路
压缩图片至低于目标大小,再把差的部分全部填充 “0”。
核心内容
核心内容是如何补齐,以下提供两种思路:
第一种(save):
① 打开图片文件并转换为 BytesIO
② 计算 (目标大小 - 压缩后大小) 的差值, 并用 “\x00” 补足
③ 保存
第二种(save2):
① cmd 生成一个指定大小的文件
② 将压缩后的二进制流写入生成的文件
文件结构
main.py
| - - new
| - - old
| - - | - - test.jpg
代码
#!/usr/bin/env python # -*- coding: utf-8 -*- # # main.py from PIL import Image from io import BytesIO from os import system from os import listdir from os import remove from os.path import getsize from os.path import exists __author__ = 'one-ccs' """ 功能: 把 ".\old" 目录下的所有图片压缩并填充至 200KB 后存放在 ".\new" 目录下. """ settings = { 'loadPath': r'.\old', # 待压缩图片路径 'savePath': r'.\new', # 保存路径 'size': 200, 'quality': 90 } class ImageFixCompressor(): def __init__(self) -> None: self.imgBytes = None self.imgPath = None self.name = None self.oldSize = 0 self.newSize = 0 self.saveSize = 0 self.format = 'JPEG' self.targetSize = 200 # 目标大小 (KB) self.quality = 90 # 压缩比率 若压缩后图片大于目标大小应减小该值 def split_path(self, path:str='') -> tuple: """ 提取 path 中的路径与文件名. """ if not isinstance(path, str): raise ValueError(f'参数 "path" 的数据类型应该为 "str", 但是传入了 "{type(path)}" 类型.') # 判断是否是以 '/' '\' 作为目录分隔符 flag = path[::-1].find('/') if flag == -1: flag = path[::-1].find('\\') if flag == -1: raise ValueError(f'参数 "path" 的数据类型应该为 "str", 但是传入了 "{type(path)}" 类型.') name = path[-flag:] path = path[:-flag] return (path, name) def full_path(self, path) -> str: return fr'{path}\{self.name}' def open(self, imgPath:stCBeuyr) -> None: """ 打开图像文件 :参数 imgPath: 图片文件路径. """ try: _, self.name = self.split_path(imgPath) self.oldSize = getsize(imgPath) self.image = Image.open(imgPath) print(f'打开: "{imgPath}" 成功; 大小: {self.oldSize / 1024:.2f} KB.') except Exception as e: print(f'错误: 文件 "{imgPath}" 打开失败; 原因: "{e}".') def show(self) -> None: self.image.show() def compress(self, format='JPEG', quality=None) -> None: if format == 'PNG' or format == 'png': self.format = 'PNG' if quality: self.quality = quality self.image.tobytes() self.imageBuffer = BytesIO() self.image.save(self.imageBuffer, format=self.format, quality=self.quality) def save(self, savePath:str, cover:bool=False, name=None) -> None: if cover: mode = 'wb+' else: mode = 'rb+' try: self.newSize = self.imageBuffer.tell() / 1024 # ~ 补齐大小 for i in range(0, self.targetSize * 1024 - self.imageBuffer.tell()): self.imageBuffer.write(b'\x00') with open(self.full_path(savePath), mode) as fb: fb.write(self.imageBuffer.getvalue()) self.saveSize = getsize(self.full_path(savePath)) / 1024 print(fr'保存: "{self.full_path(savePath)}" 成功; 压缩大小: {self.newSize:.2f} KB; 保存大小: {self.saveSize:.2f} KB.') except Exception as e: print(f'错误: "{self.name}" 保存失败; 原因: "{e}".') def save2(self, savePath:str, cover:bool=False, name=None) -> None: if cover: if exists(self.full_path(savePath)): remove(self.full_path(savePath)) else: print(f'异常: 文件 "{savePath}" 已存在, 已放弃保存.') return system('@echo off') system(f'fsutil file createnew {self.full_path(savePath)} {self.targetSize * 1024}') try: with open(self.full_path(savePath), 'rb+') as fb: fb.write(self.imageBuffer.getvalue()) self.newSize = self.imageBuffer.tell() / 1024 self.saveSize = getsize(self.full_path(savePath)) / 1024 print(fr'保存: "{self.full_path(savePath)}" 成功; 压缩大小: {self.newSize:.2f} KB; 保存大小: {self.saveSize:.2f} KB.') except Exception as e: print(f'错误: "{self.name}" 保存失败; 原因: "{e}".') def main(args): compressor = ImageFixCompressor() oldImgPaths = listdir(settings['loadPath']) for oldImgPath in oldImgPaths: fullPath = f"{settings['loadPath']}\{oldImgPath}" compressor.open(fullPath) compressor.compress() compressor.save(settings['savePath'], cover=True) # ~ return return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv))
到此这篇关于Python利用PIL进行图片压缩的文章就介绍到这了,更多相关Python PIL压缩图片内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!
这篇关于Python利用PIL进行图片压缩的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!