首先说明一下PIL库,PIL(Python Imaging Library)是Python一个强大方便的图像处理库,之前的博客也有用到过PIL模块的demo
http://blog.csdn.net/sm9sun/article/details/53538579
不过可惜的是PIL库只支持到Python 2.7。python3以后,我们可以用pillow模块来代替PIL,pillow是PIL的一个派生分支,大概是PIL low的意思
现如今已经发展成为比PIL本身更具活力的图像处理库,支持PIP安装:pip install Pillow及easy_install安装:easy_install Pillow,本文用的是anaconda4.3.0(很全面的python版本,500多M,反正我听说过的库基本都包含了....)https://baike.baidu.com/item/anaconda/20407441#viewPageContent
anaconda4.3.0内置的pillow版本是4.0.0
首先简单说几个常用的方法
和PIL一样,主要是Image类
from PIL import Image
打开图片:
Image = Image.open("fliename")
保存图片:
Image.save(outfile, "JPEG")
获取图片属性
Image.format, Image.size, Image.mode……
裁剪、粘贴、合并
box = Image.copy()
box = (100, 100, 400, 400)
region = Image.crop(box)
Image.paste(region, box)
几何变换
Image.resize((200,200))、Image.rotate(90)、Image.transpose(Image.ROTATE_90)以及参数一大堆的Image.transform()
更多高级姿势参考官方文档http://pillow.readthedocs.io/en/latest/index.html
然后再说一下plist,plist是一种文件格式,其实就是XML标签类型的配置文件。在Mac OS中较为常用,也经常用于前端开发将小图合并成组图的相关配置文件。
以IOS infoplist视图打开
以xml文本视图打开
python中plistlib模块提供一系列对.plist文件操作的函数,在这里我们也可以写一个简单的tree_to_dict方法以key-dict的形式提取数据
def tree_to_dict(tree): d = {}for index, item in enumerate(tree):if item.tag == 'key':if tree[index+1].tag == 'string':d[item.text] = tree[index + 1].textelif tree[index + 1].tag == 'true':d[item.text] = True elif tree[index + 1].tag == 'false':d[item.text] = False elif tree[index+1].tag == 'dict':d[item.text] = tree_to_dict(tree[index+1])return d
以麻将资源图为例:
我们通过对应的plist文件来提取单个麻将,其pilst文件配置如下:
<plist version="1.0"><dict><key>frames</key><dict><key>M_autumn.png</key><dict><key>frame</key><string>{{79,886},{75,113}}</string><key>offset</key><string>{0,0}</string><key>rotated</key><false/><key>sourceColorRect</key><string>{{0,0},{75,113}}</string><key>sourceSize</key><string>{75,113}</string></dict><key>M_bamboo.png</key><dict><key>frame</key><string>{{79,771},{75,113}}</string><key>offset</key><string>{0,0}</string><key>rotated</key><false/><key>sourceColorRect</key><string>{{0,0},{75,113}}</string><key>sourceSize</key><string>{75,113}</string></dict><key>M_bamboo_1.png</key><dict><key>frame</key><string>{{424,656},{75,113}}</string><key>offset</key><string>{0,0}</string><key>rotated</key><false/><key>sourceColorRect</key><string>{{0,0},{75,113}}</string><key>sourceSize</key><string>{75,113}</string></dict><key>M_bamboo_2.png</key><dict><key>frame</key><string>{{309,618},{75,113}}</string><key>offset</key><string>{0,0}</string><key>rotated</key><true/><key>sourceColorRect</key><string>{{0,0},{75,113}}</string><key>sourceSize</key><string>{75,113}</string></dict> ……省略
读取freames再循环读取每个frame参数,再利用PIL里的几个函数:
crop裁剪
rotate/transpose方法进行角度旋转(plist配置参数rotated)
paste粘贴
save保存
完整python代码:
#!python import os,sys,plistlibfrom xml.etree import ElementTreefrom PIL import Imagedef tree_to_dict(tree): d = {}for index, item in enumerate(tree):if item.tag == 'key':if tree[index+1].tag == 'string':d[item.text] = tree[index + 1].textelif tree[index + 1].tag == 'true':d[item.text] = True elif tree[index + 1].tag == 'false':d[item.text] = False elif tree[index+1].tag == 'dict':d[item.text] = tree_to_dict(tree[index+1])return ddef gen_png_from_plist(plist_filename, png_filename): file_path = plist_filename.replace('.plist', '')big_image = Image.open(png_filename)root = ElementTree.fromstring(open(plist_filename, 'r',encoding='UTF-8').read())plist_dict = tree_to_dict(root[0])to_list = lambda x: x.replace('{','').replace('}','').split(',')for k,v in plist_dict['frames'].items():print('v:',v)rectlist = to_list(v['frame'])width = int( rectlist[3] if v['rotated'] else rectlist[2] )height = int( rectlist[2] if v['rotated'] else rectlist[3] )box=(int(rectlist[0]),int(rectlist[1]),int(rectlist[0]) + width,int(rectlist[1]) + height,)sizelist = [ int(x) for x in to_list(v['sourceSize'])]rect_on_big = big_image.crop(box)if v['rotated']:#rect_on_big = rect_on_big.rotate(90) rect_on_big=rect_on_big.transpose(Image.ROTATE_90)result_image = Image.new('RGBA', sizelist, (0,0,0,0))if v['rotated']:result_box=(( sizelist[0] - height )//2,( sizelist[1] - width )//2,( sizelist[0] + height )//2,( sizelist[1] + width )//2 )else:result_box=(( sizelist[0] - width )//2,( sizelist[1] - height )//2,( sizelist[0] + width )//2,( sizelist[1] + height )//2 )print('rect_on_big:',rect_on_big,'result_box:',result_box)result_image.paste(rect_on_big, result_box, mask=0)if not os.path.isdir(file_path):os.mkdir(file_path)outfile = (file_path+'/' + k).replace('gift_', '')print(outfile,"generated")result_image.save(outfile)if __name__ == '__main__':#filename = sys.argv[1] filename = 'mahjongs'plist_filename = filename + '.plist' png_filename = filename + '.png' if (os.path.exists(plist_filename) and os.path.exists(png_filename)):gen_png_from_plist( plist_filename, png_filename )else:print("make sure you have boith plist and png files in the same directory")
以上代码引用http://blog.csdn.net/linuxchen/article/details/16865645修改而成
1.读取文件时提示"UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 205: illegal multibyte sequence"
编码格式问题,在open参数后面加上encoding='UTF-8'
root = ElementTree.fromstring(open(plist_filename, 'r',encoding='UTF-8').read())
2.paste 执行报错,integer argument expected, got float
因为在Python 3中,要得到一个整数的结果,你需要使用//而不是/
所以计算box时将/改为//
if v['rotated']:result_box=(( sizelist[0] - height )//2,( sizelist[1] - width )//2,( sizelist[0] + height )//2,( sizelist[1] + width )//2 )else:result_box=(( sizelist[0] - width )//2,( sizelist[1] - height )//2,( sizelist[0] + width )//2,( sizelist[1] + height )//2 )
3.paste执行报错,images do not match
由于之前旋转错误导致尺寸异常,将rect_on_big = rect_on_big.rotate(90)换成rect_on_big=rect_on_big.transpose(Image.ROTATE_90)就可以了
可能是这个版本的rotate方法有问题。
if v['rotated']:#rect_on_big = rect_on_big.rotate(90) rect_on_big=rect_on_big.transpose(Image.ROTATE_90)
运行截图:
输出文件:
完整demo工程下载http://download.csdn.net/download/sm9sun/9956972
环境:python3.6&Anaconda4.3.0&VS2017
共同学习,写下你的评论
评论加载中...
作者其他优质文章