python 将png图片格式转换生成gif动画
先看知乎上面的一个连接
用Python写过哪些【脑洞大开】的小工具?
https://www.zhihu.com/question/33646570/answer/157806339
这个哥们通过爬气象网站的气象雷达图,生成一个gif的动态图。非常有趣且很实用,那咱也实现下。
首先先了解下什么是帧,什么是GIF http://baike.baidu.com/item/GIF/217778
我们先实现一个从GIF提取帧的代码
我们这有个gif
代码如下:
- from PIL import Image
- import sys
- def processImage(infile):
- try:
- im = Image.open(infile)
- except IOError:
- print ("Cant load", infile)
- sys.exit(1)
- i = 0
- mypalette = im.getpalette()
- try:
- while 1:
- im.putpalette(mypalette)
- new_im = Image.new("RGBA", im.size)
- new_im.paste(im)
- new_im.save(\'image\\a\'+str(i)+\'.png\')
- i += 1
- im.seek(im.tell() + 1)
- except EOFError:
- pass # end of sequence
- processImage(\'source.gif\')
生成效果:
从gif提取frame是不是很简单,只需要一个PIL库搞定
但从frame生成gif就麻烦了,因为我们使用的是py3,网上一大堆代码用的是py2.*的 比如 PythonMagick 、 images2gif
还有部分手写gif文件头部GIF89a,调用帧palette、NETSCAPE2.0写入图像等,你们都运行成功了,为什么我没有运行成功呢?
唉!
python就是牛,库如此之多,虽然本人Py一般般,但有前人为你写诗,您只要尾行加句号就可以了。这里我说的是imageio
下载地址: https://pypi.python.org/pypi/imageio (Version:2.2.0 by 2017-05-25)
- import matplotlib.pyplot as plt
- import imageio,os
- images = []
- filenames=sorted((fn for fn in os.listdir(\'.\') if fn.endswith(\'.png\')))
- for filename in filenames:
- images.append(imageio.imread(filename))
- imageio.mimsave(\'gif.gif\', images,duration=1)
OK! gif生成了!
imageio查看参数: http://imageio.readthedocs.io/
- imageio.help(\'gif\')
其实,PIL自身也有一个save方法,里面有一个‘save_all’ 参数,意思就是save多个,当format指定为gif时,生成的便是gif的动画
- from PIL import Image
- im=Image.open("a0.png")
- images=[]
- images.append(Image.open(\'a1.png\'))
- images.append(Image.open(\'a2.png\'))
- im.save(\'gif.gif\', save_all=True, append_images=images,loop=1,duration=1,comment=b"aaabb")
读取第一帧,将第一个帧的像素设置为gif像素
python将png图片格式转换生成gif动画已经可以实现了,但我们这里要实现的是获取气象雷达图生成GIF。
1.获取数据
中国气象网网站: http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB 这里是上海南汇雷达站点图
获取数据,我们使用pquery
- from pyquery import PyQuery as pq
- d = pq(\'http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB\')
- DomTree = d(\'#slideform #slide option\')
2.下载气象雷达png图
想这个用Image.open 直接打开url的文件路径就可以
- images.append(Image.open(\'http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png\'))
那肯定是失败的:
- Traceback (most recent call last):
- File "E:/project/test2/my.py", line 29, in <module>
- images.append(Image.open(\'http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png\'))
- File "C:\Python36\lib\site-packages\PIL\Image.py", line 2410, in open
- fp = builtins.open(filename, "rb")
- OSError: [Errno 22] Invalid argument: \'http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png\'
异想天开呀!!!
imageio支持url文件路径 参考: http://imageio.readthedocs.io/en/latest/examples.html
- import imageio
- import visvis as vv
- im = imageio.imread(\'http://upload.wikimedia.org/wikipedia/commons/d/de/Wikipedia_Logo_1.0.png\')
- vv.imshow(im)
使用requests 库保存图片
- import requests
- r = requests.get(\'http://pi.weather.com.cn/i/product/pic/l/sevp_aoc_rdcp_sldas_ebref_az9210_l88_pi_20170621014800000.png\', timeout=3)
- file = open(\'b1.png\', \'wb\')
- size = file.write(r.content)
- file.close()
3.生成气象雷达GIF图
python 生成gif在上面我们已经说到两种方法,一种是imageio 另一种是PIL自带save_all, 这里我们直接写一个类封装方法
源码如下:
- # -*- coding: UTF8 -*-
- import requests
- from pyquery import PyQuery as pq
- import os, sys
- import imageio
- from PIL import Image
- \'\'\'
- 天气预报.gif 生成class
- \'\'\'
- class weatherForecast():
- def __init__(self, weatherSite, path, endpng, savemodel):
- self.savemodel = savemodel
- if not os.path.exists(path):
- os.makedirs(path)
- def getPic(self):
- \'\'\'
- 获取资源
- \'\'\'
- print(\'获取pic\')
- d = pq(weatherSite)
- DomTree = d(\'#slideform #slide option\') # 获取DOM节点option 标签
- num = 100
- for bigpic in DomTree.items():
- pic = bigpic.attr(\'bigpic\') # 获取bigpic 属性指
- num += 1
- self.download(pic, \'a\' + str(num) + \'.png\') # 下载pic
- print(\'pic下载成功,共下载\' + str(num - 100) + \'个png\')
- self.download(endpng, \'a1200.png\') # 下载end.png
- self.download(endpng, \'a1201.png\')
- self.download(endpng, \'a1202.png\')
- self.download(endpng, \'a1203.png\')
- def download(self, url, fname):
- \'\'\'
- 下载pic
- :return images size
- \'\'\'
- size = 0
- try:
- r = requests.get(url, timeout=3)
- file = open(path + fname, \'wb\')
- size = file.write(r.content)
- file.close()
- except:
- pass
- return size
- def getGIF(self):
- \'\'\'
- 生成gif
- \'\'\'
- images = []
- print(\'执行开始\')
- self.getPic() # 获取图片资源
- filenames = sorted(fn for fn in os.listdir(path) if fn.endswith(\'.png\'))
- if self.savemodel == 1: # imageio方法
- for filename in filenames:
- images.append(imageio.imread(path + filename))
- print(\'执行conversion操作\')
- imageio.mimsave(\'weather.gif\', images, duration=0.5, loop=1) # duration 每帧间隔时间,loop 循环次数
- print(\'完成……\')
- elif self.savemodel == 2: # PIL 方法
- imN = 1
- for filename in filenames:
- if imN == 1: # 执行一次 im的open操作,PIL在保存gif之前,必须先打开一个生成的帧,默认第一个frame的大小、调色
- im = Image.open(path + filename)
- imN = 2
- images.append(Image.open(path + filename))
- print(\'执行conversion操作\')
- im.save(\'weather.gif\', save_all=True, append_images=images, loop=1, duration=500,
- comment=b"this is my weather.gif")
- print(\'完成……\')
- \'\'\'
- 注:loop循环次数在浏览器有效果,用看图软件不起作用
- \'\'\'
- if __name__ == "__main__":
- weatherSite = "http://products.weather.com.cn/product/radar/index/procode/JC_RADAR_AZ9210_JB" # 上海南汇
- path = \'images/\' # png 图片存储位置
- endpng = \'http://images.cnblogs.com/likecs_com/dcb3688/982266/o_end.png\' # 因gif是循环播放,end png 区分新loop
- savemodel = 1 # 1:imageio保存图片, 2:PIL保存图片
- weatherForecast = weatherForecast(weatherSite, path, endpng, savemodel)
- weatherForecast.getGIF()
- sys.exit()
也可以修改gif尺寸大小,先修改png大小
- def download(self, url, fname):
- \'\'\'
- 下载pic
- :return images size
- \'\'\'
- size = 0
- try:
- r = requests.get(url, timeout=3)
- file = open(path + fname, \'wb\')
- size = file.write(r.content)
- file.close()
- # 修改图片大小,原:x=640*y=480 = 320*240
- ima = Image.open(path + fname)
- (x, y) = ima.size # read image size
- x_s = 320
- y_s = int((y * x_s) / x) # #calc height based on standard width
- out = ima.resize((x_s, y_s), Image.ANTIALIAS) # resize image with high-quality
- out.save(path + fname)
- except:
- pass
- return size
images目录
生成气象雷达图gif
4.外部访问气象雷达图
脚步写好了,如何让别人也能访问呢,直接仍到公网IP的website目录就行了,然后写一个crontab定时脚步,每5分钟生成一次
- */5 * * * * python /home/wwwroot/www/web/static/weather/weather_forecast.py #每5分钟执行天气查询脚本
在这里,如果执行crontab定时脚步,代码生成的gif就要指定位置,否则生成的gif会在/root 目录里面
- imageio.mimsave(\'/home/wwwroot/www/web/static/weather/weather.gif\', images, duration=0.5, loop=1) # duration 每帧间隔时间,loop 循环次数