为了账号安全,请及时绑定邮箱和手机立即绑定

python——适用于py3的pillow图像处理模块&plist组图分割

标签:
Python

首先说明一下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的意思


https://img1.sycdn.imooc.com//5b4dd5ec0001331000710072.jpg

现如今已经发展成为比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

https://img1.sycdn.imooc.com//5b4dd6e90001fc6405560331.jpg


首先简单说几个常用的方法

和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视图打开

https://img1.sycdn.imooc.com//5b4dd6fb0001075405450307.jpg

以xml文本视图打开

https://img1.sycdn.imooc.com//5b4dd70300014e9005730434.jpg


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




以麻将资源图为例:

https://img1.sycdn.imooc.com//5b4dd70e0001ee5b03660409.jpg


https://img1.sycdn.imooc.com//5b4dd73f0001a29203860365.jpg

我们通过对应的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

https://img1.sycdn.imooc.com//5b4dd7480001f4ed04910056.jpg

因为在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

https://img1.sycdn.imooc.com//5b4dd75000011b1a04950069.jpg

由于之前旋转错误导致尺寸异常,将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)




运行截图:

https://img1.sycdn.imooc.com//5b4dd75900019bba04820242.jpg


输出文件:

https://img1.sycdn.imooc.com//5b4dd7610001d6f705510454.jpg



完整demo工程下载http://download.csdn.net/download/sm9sun/9956972

环境:python3.6&Anaconda4.3.0&VS2017


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消