如何截取屏幕并生成GIF动画

来源:互联网 发布:新疆大学教育网络系统 编辑:程序博客网 时间:2024/06/06 02:51

    前面在写关于VPython的文章的时候,我考虑了一下如何把VPython的动作记录下来,存为GIF动画再放到博客上来.
    首先,在维基百科找到关于GIF文件格式的描述, 由于该部分占用篇幅太多,我就不贴出来了,大家可以查看这里:

    http://en.wikipedia.org/wiki/Graphics_Interchange_Format

    有了上面的信息,就可以编写Python程序了,PIL里面有个类ImageGrab可以轻易地截取屏幕.另外,python的写文件时,可以直接写入字符串和十六进制数,非常方便.

    以下是整个程序源代码:

# -*- coding: cp936 -*-import ImageGrab # from PILimport timeimport stringfrom PIL import Image, ImageChopsfrom PIL.GifImagePlugin import getheader, getdataimport osimport numpy as npdef intToBin(i):    """ 把整型数转换为双字节 """    # 先分成两部分,高8位和低8位    i1 = i % 256    i2 = int( i/256)    # 合成小端对齐的字符串    return chr(i1) + chr(i2)def getheaderAnim(im):    """ 生成动画文件头 """    bb = "GIF89a"    bb += intToBin(im.size[0])    bb += intToBin(im.size[1])    bb += "\x87\x00\x00"  #使用全局颜色表    return bbdef getAppExt(loops=0):    """ 应用扩展,默认为0,为0是表示动画是永不停止    """    bb = "\x21\xFF\x0B"  # application extension    bb += "NETSCAPE2.0"    bb += "\x03\x01"    if loops == 0:        loops = 2**16-1    bb += intToBin(loops)    bb += '\x00'  # end    return bbdef getGraphicsControlExt(duration=0.1):    """ 设置动画时间间隔 """    bb = '\x21\xF9\x04'    bb += '\x08'  # no transparancy    bb += intToBin( int(duration*100) ) # in 100th of seconds    bb += '\x00'  # no transparant color    bb += '\x00'  # end    return bbdef _writeGifToFile(fp, images, durations, loops):    """ 把一系列图像转换为字节并存入文件流中    """    # 初始化    frames = 0    previous = None    for im in images:        if not previous:            # 第一个图像            # 获取相关数据            palette = getheader(im)[1]  #取第一个图像的调色板            data = getdata(im)            imdes, data = data[0], data[1:]                        header = getheaderAnim(im)            appext = getAppExt(loops)            graphext = getGraphicsControlExt(durations[0])                        # 写入全局头            fp.write(header)            fp.write(palette)            fp.write(appext)                        # 写入图像            fp.write(graphext)            fp.write(imdes)            for d in data:                fp.write(d)                    else:            # 获取相关数据                      data = getdata(im)             imdes, data = data[0], data[1:]                   graphext = getGraphicsControlExt(durations[frames])                        # 写入图像            fp.write(graphext)            fp.write(imdes)            for d in data:                fp.write(d)           # 准备下一个回合        previous = im.copy()                frames = frames + 1    fp.write(";")  # 写入完成    return framesdef writeGif(filename, images, duration=0.1, loops=0, dither=1):    """ writeGif(filename, images, duration=0.1, loops=0, dither=1)    从输入的图像序列中创建GIF动画    images 是一个PIL Image [] 或者 Numpy Array    """    images2 = []    # 先把图像转换为PIL格式    for im in images:                if isinstance(im,Image.Image): #如果是PIL Image            images2.append( im.convert('P',dither=dither) )                    elif np and isinstance(im, np.ndarray): #如果是Numpy格式            if im.dtype == np.uint8:                pass            elif im.dtype in [np.float32, np.float64]:                im = (im*255).astype(np.uint8)            else:                im = im.astype(np.uint8)            # 转换            if len(im.shape)==3 and im.shape[2]==3:                im = Image.fromarray(im,'RGB').convert('P',dither=dither)            elif len(im.shape)==2:                im = Image.fromarray(im,'L').convert('P',dither=dither)            else:                raise ValueError("图像格式不正确")            images2.append(im)                    else:            raise ValueError("未知图像格式")        # 检查动画播放时间    durations = [duration for im in images2]    # 打开文件    fp = open(filename, 'wb')    # 写入GIF    try:        n = _writeGifToFile(fp, images2, durations, loops)        print n, '帧图像已经写入'    finally:        fp.close()seq = []steps = float(raw_input("输入录制间隔(单位:秒):"))x = raw_input("按下任意键开始录制...")os.system("mkdir images")  #创建一个文件夹,用于存放临时文件for i in range(10):    time.sleep(steps)    im = ImageGrab.grab((0,0,320,245)) #捕捉屏幕的左上角(0,0,320,245)部分    #这里由于ImageGrab.grab返回的图像格式未知,只能使用笨办法,每次存盘再打开,格式就正确了    im.save("images\\test" +str(i) + ".gif") #图像存入    seq.append(Image.open("images\\test" +str(i) + ".gif")) #重新打开    print "采集了第" + str(i) + "帧图像"print "屏幕捕捉完成"writeGif('output.gif',seq, duration=0.5, dither=0)x = raw_input("按下任意键退出")
    使用方法: 
    1,运行程序,弹出"输入录制间隔(单位:秒):", 输入你希望的间隔,比如0.5秒.
    2,按下任意键开始录制
    3,捕捉完成后,按下任意键结束.
    4,最终的GIF文件将保存为当前目录下的output.gif

    程序输出:

    

输入录制间隔(单位:秒):0.1
按下任意键开始录制...
采集了第0帧图像
采集了第1帧图像
采集了第2帧图像
采集了第3帧图像
采集了第4帧图像
采集了第5帧图像
采集了第6帧图像
采集了第7帧图像
采集了第8帧图像
采集了第9帧图像
屏幕捕捉完成
10 帧图像已经写入
按下任意键退出

    最终效果:


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 注册游戏账号需要身份证怎么办 英雄联盟被裁决了怎么办 百度网盘密码重置不了怎么办 sap密码输入被锁怎么办 dnf二级密码错10怎么办 大网卡网速慢了怎么办 小米路由器无线速度慢怎么办 小米手机无线速度慢怎么办 电脑网卡驱动没了怎么办 电脑显示网卡驱动不正常怎么办 微信别人拒收消息怎么办 电脑无线网卡速度慢怎么办 网吧吃鸡更新慢怎么办 手机号注册不了微信怎么办 小米账号密码忘了怎么办 小米手机账号密码忘了怎么办 华为手机账号密码忘记了怎么办 老年机开不了机怎么办 天谕没有顺网登陆怎么办 苹果密保问题忘了怎么办 密保手机没用了怎么办 qq密保手机没用了怎么办 手机开机按钮坏了怎么办 改了账号游戏角色消失怎么办 华为开机键坏了怎么办 抖音账号已重置怎么办 抖音账号被重置怎么办 吃鸡账号密码忘了怎么办 微信只记得账号忘了手机号怎么办 红米3开机键失灵怎么办 晚自习教室有许多虫子怎么办 泰迪吃草又呕吐怎么办 手机不断收到验证码信息怎么办 樱桃吃多了上火怎么办 过年不想回婆婆家过怎么办 旅行箱提手坏了怎么办 影棚人物后面有影子怎么办 微信运动图标不见了怎么办 逆光拍摄人黑了怎么办 单反镜头刮花了怎么办 股东各50股份不同意退股怎么办