Pillow图片处理

人到中年,稍不留神就被无力感窒息了:老人日渐衰老无力扭转;职业天花板也看得见了;孩子能不能成材跟你的努力和投入有一定相关性,有么?必须得相信有呀,但有多少敢深想么?账单倒是每个月如期而至(╯﹏╰)

有点丧哈,那是因为这是吐槽呀(˶‾᷄ ⁻̫ ‾᷅˵)。其实每晚孩子们滚去睡觉后不被干扰滴刷手机的我都有很真切的幸福感:不看不知道,世界真奇妙!好玩的好看的好听的太多太多,两个眼睛根本不够使,累到不行还舍不得休息。

睡前这段光阴这么宝贵,要是能按个暂停键让时光暂停,然后我们还可以继续玩乐、八卦、看戏……等玩够了按下播放键,时间才继续往前走就好了,我们保证有足够的精气神继续努力生活。

时光暂停黑科技肯定是等不到了,挖掘点属于自己的小确幸小欣喜来给自己充电还是可行哒。不惑之年的普通人,多多少少会有点信“天命难违”,信”时势造英雄“啊啥的,“平平淡淡才是真”也念叨着,然后再找点通过努力能见到成效的事儿做做,比如健身减肥……霸特这个我不行(管不住嘴迈不开腿,口号喊得再响也百搭),我给自己找的是写程序调程序:

扯淡完毕分割线 ♪───O(≧∇≦)O────♪ 

在写图片操控这一章时想加一个彩色转成黑白(其实是灰度)的一小段代码,很简单,一个函数而已:

im = Image.open('青衣.jpg')

im.convert('L')

im.save('青衣黑白.jpg')

打开“青衣黑白.jpg”一看,大跌眼镜,竟然还是彩色的!不敢相信,仔细看了看再运行,还是彩色;去查技术文档,没啥附加条件!完全按照要求调用的呀;又去网上搜“为什么convert(‘L’)转不了黑白“,什么也没搜到,让人抓狂!怎么可能就我一人碰上这糟心事了呢?

http://pythonabc.org/images/pABCArticles/3.26.1.jpg

事实证明这种情况基本上是自己的问题,反正再接下去十八般武器乱比划的一个瞬间突然醒悟哪里出了问题:

im = Image.open('青衣.jpg')

imL = im.convert('L')

imL.save('青衣黑白.jpg')

原来我没有把黑白图片对象保存到变量里,保存成文件的还是原来的对象(im.convert('L')不改变im),难怪看到的还是彩色的。

http://pythonabc.org/images/pABCArticles/3.26.1.jpghttp://pythonabc.org/images/pABCArticles/3.26.1.jpg

查资料排错时发现了im.thumbnail(size)可以生成图片的缩略图,遂用来缩小logo图片的尺寸。

循环处理指定文件夹下的所有图形文件时,把原来的:

for fname in [x for x in imagePath.iterdir() if x.is_file]:

    if not fname.suffix in {'.png', '.jpg', '.jpeg'}:

        continue # skip non-image files and the logo file itself

简化成:

for fname in [x for x in imageFolder.iterdir() if x.suffix in {'.png', '.jpg', '.jpeg', '.gif'}]:

http://pythonabc.org/images/pABCArticles/3.26.1.jpg

以前写的帖子里有提过让我困惑的调用:

“其实这段代码有个让我很头疼的地方:shrinkImage.mkdir(0o777, exist_ok=True),参数exist_ok=True的作用是如果要建立的文件夹存在也不要紧。可是这样写一运行就出错:TypeError: mkdir() got an unexpected keyword argument 'exist_ok',提示不认这个参数。如果把python版本3.6降到3.5就没问题,可我不想降版本,所以现在只好用:shrinkImage.mkdir(0o777),然后运行一次后再运行就会出现错误:FileExistsError: [Errno 17] File exists......就是文件夹已经存在的错误。害得我调试时运行一次,下次再运行前只好手工删除程序帮忙建好的那个文件夹。虽然也可以加个程序段自动删除文件夹,可我不是不忿么,明明有参数专门干这件事啊!!!”

http://pythonabc.org/images/pABCArticles/3.26.1.jpg

现在平静地加了一条判断文件夹如果已存在就删除的语句:

import shuitil

……

imageWithLogoFolder = imageFolder.joinpath('withLogo') # 存放加了logo的文件夹位置和名称

if imageWithLogoFolder.exists():            # 如果文件夹已经存在,删掉(文件夹和里面的文件)

  shutil.rmtree(str(imageWithLogoFolder))

imageWithLogoFolder.mkdir(0o777)            # 建立文件夹

http://pythonabc.org/images/pABCArticles/3.26.1.jpg

调整一个文件夹下的所有图片的尺寸,宽和高有超过400的调整成400;把logo的图片调成缩略图,并加到每张的右下角:

from pathlib import Path
from PIL import Image
import shutil

PATH = '/Users/Smonkey/Documents//PythonABC_Book/bookProg/2-16image/toAddLogo/'
# 要做成logo的图片和要加logo的图片们所在的文件夹
imageFolder = Path(PATH)
SQUARE_FIT_SIZE = 300	# 图片长或宽的最大尺寸
LOGO_SIZE = 128			# logo尺寸

# 调整图片尺寸:logo调整成LOGO_SIZE的缩略图,要加logo的图片的宽和高超过SQUARE_FIT_SIZE的也要调整
def resizeIM(size, imageFile): # size接收要调整的尺寸,imageFile接收要调整的图片文件对象

    im = Image.open(imageFile)	# 生成图片对象

    if size == LOGO_SIZE:	# 如果传进来的是logo图片
        size = LOGO_SIZE, LOGO_SIZE	# size是图片尺寸元组(宽, 高)
        im.thumbnail(size)	# 把图片调整成规定size的缩略图
        return im	# 返回调整好的缩略图logo

    width, height = im.size	# 图片的尺寸
    # 检查是否需要调整
    if width > SQUARE_FIT_SIZE and height > SQUARE_FIT_SIZE:
        # 宽和高如果超过SQUARE_FIT_SIZE就要按比例调整,确保图片不变形
        if width > height:
            height = int((SQUARE_FIT_SIZE / width) * height)
            width = SQUARE_FIT_SIZE
        else:
            width = int((SQUARE_FIT_SIZE / height) * width)
            height = SQUARE_FIT_SIZE

    im.resize((width, height))    # 调整尺寸
    return(im)		# 返回调整好的尺寸

logoImage = imageFolder / 'transparentLogo.png'		# 要做成logo的图片
logoIm = resizeIM(LOGO_SIZE, logoImage)				# 调用函数将图片调整成缩略图logo

# set up new folder for image with logo
imageWithLogoFolder = imageFolder.joinpath('withLogo')	# 存放加了logo的文件夹位置和名称
if imageWithLogoFolder.exists():				# 如果文件夹已经存在,删掉(文件夹和里面的文件)
    shutil.rmtree(str(imageWithLogoFolder))
imageWithLogoFolder.mkdir(0o777)				# 建立文件夹

for fname in [x for x in imageFolder.iterdir() if x.suffix in {'.png', '.jpg', '.jpeg', '.gif'}]:
# for x in imageFolder.iterdir()遍历存放要加logo的图片的文件夹的每个文件;if x.suffix in {'.png', '.jpg', '.jpeg', '.gif'}
# 只有扩展名在集合里的文件(图片文件)才符合条件;[x ……]图片文件放进列表;for fname in ……遍历图片文件
    width, height = Image.open(fname).size	# 获得图片的尺寸
    im = resizeIM(SQUARE_FIT_SIZE, fname)	# 调用函数调整图片尺寸

    # Add logo.
    print('Adding logo to {}...'.format(fname.name))	# 提示正在加哪张图片的logo
    im.paste(logoIm, (width - LOGO_SIZE, height - LOGO_SIZE), logoIm)	# 把图片放在右下角的位置

    # 保存成文件
    im.save(str(imageWithLogoFolder)+'/'+fname.name)	# 将加了logo的图片保存到前面新建的文件夹内

批处理大量文件运行中如果出现错误提示:OSError: cannot write mode RGBA as JPEG,是因为JPG格式图片不支持透明(模式RGBA的四个字母表示RedGreenBlueAlphaAlpha管透明)。解决办法一个是抛弃Alpha频道,图片对象有个方法函数convert()可以把RGRA转换成RGB,抛弃Alpha,所以保存图片前添加一条语句im = im.convert('RGB')就可以了:

	print('Converting {}...'.format(filename))
	im = im.convert('RGB')
	# 排除:OSError: cannot write mode RGBA as JPEG

	# 保存成文件
	im.save(str(shrinkImage.joinpath(filename)))

另一个是把图片格式改成支持Alpha的,比如PNG

	# 改变图片格式保存,fname.stem只取文件名,不取文件的扩展名
	im.save(shrinkImage.joinpath(fname.stem + '.png'))