0
点赞
收藏
分享

微信扫一扫

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


首先说明一下PIL库,PIL(Python Imaging Library)是Python一个强大方便的图像处理库,之前的博客也有用到过PIL模块的demo

不过可惜的是PIL库只支持到Python 2.7。python3以后,我们可以用pillow模块来代替PIL,pillow是PIL的一个派生分支,大概是PIL low的意思


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

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

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

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


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

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

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

以xml文本视图打开

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


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].text
elif 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



以麻将资源图为例:

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


我们通过对应的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,plistlib
from xml.etree import ElementTree
from PIL import Image

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].text
elif 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

def 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")



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——适用于py3的pillow图像处理模块&plist组图分割_图像处理_07

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


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

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



运行截图:

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


输出文件:

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



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

举报

相关推荐

0 条评论