Python利用PIL進行圖片壓縮
有時在發(fā)送一些文件如PPT、Word時,由于文件中的圖片太大,導(dǎo)致文件也太大,無法發(fā)送,所有可以對文件中的圖片進行壓縮,下面代碼根據(jù)用戶自定義的目標大?。ㄈ?0KB或40KB)進行壓縮,并盡可能保證圖片清晰度。
高質(zhì)量縮放:使用LANCZOS重采樣算法,保證縮放后的圖片清晰度。
銳化增強:在壓縮后對圖片進行銳化處理,進一步提升清晰度。
智能判斷:優(yōu)先降低質(zhì)量,避免不必要的縮放,減少清晰度損失。
from PIL import Image, ImageFilter import io def compress_image(input_path, output_path, max_size_kb, quality=85, step=5): """ 壓縮圖片到指定大小以下,并盡可能保證清晰度。 :param input_path: 輸入圖片路徑 :param output_path: 輸出圖片路徑 :param max_size_kb: 目標大?。▎挝唬篕B) :param quality: 初始壓縮質(zhì)量(默認85) :param step: 每次降低質(zhì)量的步長(默認5) """ # 打開圖片 img = Image.open(input_path) # 將圖片轉(zhuǎn)換為RGB模式(如果是RGBA或其他模式) if img.mode in ('RGBA', 'LA'): img = img.convert('RGB') # 創(chuàng)建一個字節(jié)流對象 img_byte_arr = io.BytesIO() # 保存圖片到字節(jié)流,初始質(zhì)量為quality img.save(img_byte_arr, format='JPEG', quality=quality) # 獲取當前圖片大小 current_size = len(img_byte_arr.getvalue()) / 1024 # 轉(zhuǎn)換為KB # 如果圖片大小超過最大限制,逐步降低質(zhì)量 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 # 如果圖片大小仍然超過最大限制,調(diào)整圖片尺寸 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 # 對圖片進行銳化處理 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”。
核心內(nèi)容
核心內(nèi)容是如何補齊,以下提供兩種思路:
第一種(save):
① 打開圖片文件并轉(zhuǎn)換為 BytesIO
② 計算 (目標大小 - 壓縮后大小) 的差值, 并用 “\x00” 補足
③ 保存
第二種(save2):
① cmd 生成一個指定大小的文件
② 將壓縮后的二進制流寫入生成的文件
文件結(jié)構(gòu)
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 # 壓縮比率 若壓縮后圖片大于目標大小應(yīng)減小該值 def split_path(self, path:str='') -> tuple: """ 提取 path 中的路徑與文件名. """ if not isinstance(path, str): raise ValueError(f'參數(shù) "path" 的數(shù)據(jù)類型應(yīng)該為 "str", 但是傳入了 "{type(path)}" 類型.') # 判斷是否是以 '/' '\' 作為目錄分隔符 flag = path[::-1].find('/') if flag == -1: flag = path[::-1].find('\\') if flag == -1: raise ValueError(f'參數(shù) "path" 的數(shù)據(jù)類型應(yīng)該為 "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:str) -> None: """ 打開圖像文件 :參數(shù) 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))
到此這篇關(guān)于Python利用PIL進行圖片壓縮的文章就介紹到這了,更多相關(guān)Python PIL壓縮圖片內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python數(shù)據(jù)預(yù)處理時缺失值的不同處理方式總結(jié)
在使用python做數(shù)據(jù)分析的時候,經(jīng)常需要先對數(shù)據(jù)做統(tǒng)一化的處理,缺失值的處理是經(jīng)常會使用到的。今天介紹的是使用差補法/均值/固定值等不同的方式完成數(shù)據(jù)填充從而保證數(shù)據(jù)的完整性,感興趣的可以了解一下2022-12-12如何用python 操作MongoDB數(shù)據(jù)庫
這篇文章主要介紹了如何用python 操作MongoDB數(shù)據(jù)庫,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-04-04pandas.concat實現(xiàn)DataFrame豎著拼接、橫著拼接方式
這篇文章主要介紹了pandas.concat實現(xiàn)DataFrame豎著拼接、橫著拼接方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10Python+tkinter實現(xiàn)音樂下載軟件的制作
平常我們下載的歌曲,都是各種妖魔鬼怪的格式橫行,想下載下來用一下都不行,還只能在它的播放器內(nèi)聽,這誰受得了~本文就來用Python制作個音樂下載軟件,需要的可以參考一下2022-09-09在Python的Django框架的視圖中使用Session的方法
這篇文章主要介紹了在Python的Django框架的視圖中使用Session的方法,包括相關(guān)的設(shè)置測試Cookies的方法,需要的朋友可以參考下2015-07-07