使用PIL进行图片格式与尺寸转换

现实世界中,图片是经常需要处理的二进制文件类型。从计算机发展的历史来看,图片的格式丰富多彩,但大体来说分成两类:

•位图格式

•矢量格式

矢量格式如svg等,能够随意放大缩小而不变形,原因在于矢量格式描述了如何产生图形的方法。而位图格式(例如BMP/JPEG/PNG等)则指定像素空间大小,并且用不同方法描述了每个点的属性,从而能够保存与恢复图片信息。由于矢量格式与位图格式的内容很丰富,而本系列只是借用工具进行实用化操作,因此不对原理进行深入的讲解。以下代码展示了如何进行多种位图格式的转换。

 

from PIL import Image

def convert(inputfilename, outputfilename):
    im = Image.open(inputfilename)
    print(im.format, im.size, im.mode)
    im.save(outputfilename)

sourceimage = r'd:\test\girl.png'
targetimages = [r'd:\test\demo.jpg',r'd:\test\demo.bmp',r'd:\test\demo.gif',r'd:\test\demo.webp']

for target in targetimages:
    convert(sourceimage,target)

从转换结果来看,bmp格式图片体积最大,jpg格式图片体积最小。原因也很简单,jpg格式是JPEG联合图像专家组定义的一种用于连续色调静态图像压缩的标准。JPEG是一种很灵活的格式,具有调节图像质量的功能,它允许用不同的压缩比例对文件进行压缩,支持多种压缩级别。

在上述代码中,除了常见的图片格式外,还有一种新的图片格式专为web应用而生,这就是webp格式。它能够大大提高网站访问速度,同样的分辨率,大小比 jpg、png小25%以上。在Chrome、Firefox、Edge、Opera等主流浏览器上均获得支持。由于此格式较新,还有许多传统的图片处理工具无法识别,可以使用上述代码将webp与png格式进行相互转换。

在上述代码中,使用了著名的PIL图像处理库。PIL(Python Imaging Library)是一个免费的Python编程语言库。Pillow是一个积极开发的PIL分支,它更易于安装,可在所有主流操作系统上运行,并支持Python 3。该库包含基本图像处理功能。其中格式转换是它的重要功能之一。对于python程序来说,pillow在后,各种所谓的万能格式转化器就直接可以扔了。

 

svg转png格式

虽然pillow非常强悍,但还是有一些格式是连pillow都处理不了的,例如svg格式。svg是一种开放标准的矢量图形语言,是可缩放的矢量图形格式。svg格式的图像可任意放大图形显示,而且边缘异常清晰,生成的文件很小,方便传输,文字在svg图像中保留可编辑和可搜寻的状态,没有字体的限制,所以十分适合用于设计高分辨率的Web图形页面。以下代码展示了svg这种矢量格式转为位图格式的过程。

 

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM,renderPS

def svg2png(svgfile,outputfile):
    """
    对图片格式进行转换

    Args:
        svgfile (string): 源图片
        outputfile (string): 目标图片
    """
    # 打开图片并赋值一份新的图片
    img = svg2rlg(svgfile)
    renderPM.drawToFile(img, outputfile, fmt="PNG")

svg2png(r'D:\test\logo.svg',r'D:\test\logo.png')

visio图转png

Microsoft Visio是Windows操作系统下运行的流程图和矢量绘图软件,它是Microsoft Office软件的一个部分。2000年微软公司收购同名公司后,Visio成为微软公司的产品。它的竞争者是Adobe Illustrator、Macromedia FreeHand和CorelDraw。Visio虽然是Microsoft Office软件的一个部分。但通常以单独形式出售,并不捆绑于Microsoft Office套装中。它的功能极为强悍,能够无缝与word/excel/ppt融合。在跨平台应用时,有将visio图转换成为PNG格式的需求,以下代码演示了如何做到这些。

 

import win32com.client as win32

def convert(visiofile):
    """
    对图片格式进行转换

    Args:
        visiofile (string): 源图片
        outputfile (string): 目标图片
    """
    doc_app = win32.gencache.EnsureDispatch("Visio.Application")

    doc = doc_app.Documents.Open(visiofile)    
    for page in doc.Pages:
        page.Export (r"d:\test\%s.png"%(page.Name))
        
    doc.Close()
    doc_app.Quit()
        
convert(r'D:\test\神经元结构.vsd')

 

上述第三库的安装过程如下所示。

 

python.exe -m pip install --upgrade pip
# 安装pillow
pip install --upgrade Pillow
# 安装svg相关处理库
pip install svglib
pip install reportlab
# 安装pywin32com
pip install pywin32

缩小图片到指定大小

 

由于网站的存储与处理能力有限,经常会要求我们上传图片时不能够超过指定大小(例如2M等),非常麻烦。以前笔者也是临时找某些工具软件加工一下,但当手头没有工具软件时就抓狂了。其实,使用python能够非常轻松的完成。

from PIL import Image
import math

def resize2(inputfilename, outputfilename, targetsize=2048):
    filestatus = os.stat(inputfilename)
    filesize = filestatus.st_size
    rate = round(math.sqrt((filesize/1024)/targetsize))
    im = Image.open(inputfilename)
    width, height = im.size

    bigger = True
    count = 0
    while bigger:
        # 不断的输出,并且判断大小是否合适
        out = im.resize((math.floor(width/rate), math.floor(height/rate)))
        out.save(outputfilename)

        # 判断输出文件尺寸是否达标
        fs = os.stat(outputfilename)
        if fs.st_size/1024 < targetsize:
            bigger = False
        else:
            rate += 0.01
            count += 1
            print(f'{count} times')

sourceimage = r'd:\test\gallery.png'
targetimage = r'd:\test\gallery-small.png'

resize2(sourceimage, targetimage,targetsize= 2048)

上述代码中缺省大小是2M,可以自行调整。今后上传身份证,各类扫描件等就不犯愁了。