webp动图转gif

目录

前言

解决过程

遇到问题

获取duration


前言

上一次我们实现了webp转jpg格式:

https://blog.csdn.net/weixin_54143563/article/details/139758200

那么对于含动图的webp文件我们如何将其转为gif文件呢?

之所以会出现这个问题,是因为我很喜欢芙芙,逛b站的时候发现了一个芙芙的表情包:

https://i0.hdslb.com/bfs/new_dyn/e541e5ee95aaee7ce655f0074d50e5b8180207493.gif@1052w_!web-dynamic.avif

打开链接下载后发现是webp格式的,尽管在“另存为”的时候,将保存类型选为“所有文件”,然后文件名加.gif后缀可以下载为gif格式

但是打开这个文件却并不是动图。

由此我想要思考怎么才能将webp文件转为gif呢?(虽然在线格式转换的工具有很多,但是为什么不尝试自己动手解决呢?)

解决过程

选择imageio库来完成格式转化。

逻辑流程为:使用imageio.get_reader读取webp文件,然后读取每一帧图像,最后将这些图像写入gif文件中,代码如下:
 

import imageio

# 指定输入的webp文件路径
input_path = '芙宁娜.webp'
# 指定输出的gif文件路径
output_path = 'output.gif'

# 使用imageio读取webp文件
webp_reader = imageio.get_reader(input_path)

# 初始化一个空的gif列表,用于存储每一帧
gif_frames = []

# 读取每一帧图像
for i, frame in enumerate(webp_reader):
    gif_frames.append(frame)


# 关闭reader
webp_reader.close()

# 使用imageio写入gif文件,loop=0表示无限循环播放
imageio.mimsave(output_path, gif_frames, format='GIF',loop=0)

print(f"Converted {input_path} to {output_path}")

​

​

遇到问题

可以实现目标但是有一个问题:

播放的速度不一样。

在imageio.mimsave(output_path, gif_frames, format='GIF',loop=0)还有一个参数duration用来设置每帧持续时间,也就是播放速度。

获取duration

如果我们想要与原webp播放速度一致,那么就需要获取原图的duration信息。但是目前我还没有找到什么库能够解析出webp的duration。上网查了查给出的建议是用软件工具获取动图的各种信息。既然如此还不如直接下载格式转化的工具呢,毕竟我们没有必要为了这碟醋包饺子呀。

最后没有办法,只能手动解析了。

WebP 容器规范  |  Google for Developers

进入这个网站查看webp的文件结构。

webp的文件标题如下:

那么我们可以先读取这些信息:

        with open(file_path, 'rb') as f:
            # 读取文件头部 RIFF 标志
            riff = f.read(4)
            if riff != b'RIFF':
                raise ValueError("File is not a valid WebP file.")

            # 读取文件大小
            file_size = struct.unpack('<I', f.read(4))[0]


            # 读取文件类型 WEBP 标志
            webp = f.read(4)
            if webp != b'WEBP':
                raise ValueError("File is not a valid WebP file.")

            frame_durations = []

由于f.read()和f.seek()函数都能够更改文件指针的位置,所以经过上述操作指针f会指向webp文件标题的末尾。

接下来是一些块(chunk),与动画有关的块分别为“ANIM”和“ANMF”,其中我们需要的duration信息则存储在“ANMF”中。

“ANMF”区块的结果为:

在chunkheader中前四位存储的信息为名称ANMF,后四位存储的是ANMF的大小。

上面我们已经获取了整个webp文件的大小file_size,用f.tell()表示当前文件指针位置,在file_size范围内读取文件内容。

            while f.tell() < file_size:
                # 读取四字节的 chunk 标志
                chunk_id = f.read(4)
                if chunk_id == b'ANMF':
                    # 读取 ANMF chunk 大小
                    anmf_size = struct.unpack('<I', f.read(4))[0]

                    # 读取 ANMF chunk 数据
                    chunk_data = f.read(anmf_size)

                    # 解析 Frame Duration,偏移量为 12,读取3个字节
                    duration_bytes = chunk_data[12:15]
                    duration = (duration_bytes[2] << 16) + (duration_bytes[1] << 8) + duration_bytes[0]
                    frame_durations.append(duration)

                    

                else:
                    # 跳过未知的 chunk
                    chunk_size = struct.unpack('<I', f.read(4))[0]

                    f.seek(chunk_size, 1)

            return frame_durations

首先读取4个字节的标志,用条件语句判断是否为'ANMF'区块,进入'ANMF'区块后,由于已经读取了4个字节的标志,用anmf_size = struct.unpack('<I', f.read(4))[0]表示'ANMF'块的大小,这里是按照小字节存储的。

简单来说例如123,1位于百位,那么我们用数组arr这样存储arr[0]=3,arr[1]=2,arr[2]=1.因此在后面按位读取是这样的:

duration = (duration_bytes[2] << 16) + (duration_bytes[1] << 8) + duration_bytes[0]

我们继续刚才的过程,获取anmf_size的过程也有f.read(4),所以之后就进入了:

剩下的:

所以帧时长的偏移量从3+3+3+3=12开始,读取3个字节。

duration_bytes = chunk_data[12:15]

然后读取duration = (duration_bytes[2] << 16) + (duration_bytes[1] << 8) + duration_bytes[0]

其实,我们只用读取第一帧的duration就可以了。

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要保存webp,可以使用Python的Pillow库。以下是保存webp的示例代码: ```python from PIL import Image # 打开webp im = Image.open("example.webp") # 保存为gif格式 im.save("example.gif", save_all=True) ``` 在这个例子中,我们使用Pillow库中的Image模块打开了一个webp,然后使用save()方法将其保存为gif格式。需要注意的是,我们需要将save_all参数设置为True来保存所有帧。如果不设置该参数,则只会保存第一帧。 希望这个例子可以帮助到你。 ### 回答2: Python可以使用第三方库Pillow来保存webp。 Pillow是Python像处理库,支持多种像格式的读取和处理,包括webp格式。要保存webp,需要首先安装Pillow库。 首先,使用pip命令来安装Pillow库: pip install pillow 安装完成后,在Python脚本中引入Pillow库: from PIL import Image 然后,可以使用Pillow库的Image.open()方法打开webp文件: image = Image.open('.webp') 接下来,可以使用Pillow库的Image.save()方法将webp保存为其他格式,比如png或者gif: image.save('.png') 保存为其他格式时,需要根据实际需求指定保存的文件名和文件格式。 此外,Pillow库还提供了其他丰富的像处理功能,如裁剪、调整大小、旋等。可以根据具体需求进行处理。 总结起来,要使用Python保存webp,需要先安装Pillow库,然后使用Image.open()方法打开webp文件,最后使用Image.save()方法将webp保存为其他格式。 ### 回答3: 要使用Python保存webp,可以使用Pillow库。Pillow是一个强大的像处理库,支持多种像格式,包括webp。 首先,确保已经安装了Pillow库。可以使用以下命令在命令行中安装Pillow: ``` pip install pillow ``` 然后,使用下面的代码保存webp: ```python from PIL import Image # 打开webp image = Image.open('animated.webp') # 保存为gif image.save('animated.gif', 'gif') print("保存成功") ``` 在这个例子中,我们首先使用`Image.open()`函数打开webp。然后,我们使用`image.save()`函数将保存为gif格式。你可以根据需要选择其他支持的像格式,例如png、jpeg等。 最后,运行代码,你会看到保存成功的提示信息,同时在当前目录下会生成一个名为`animated.gif`的文件。 使用这种方法,你可以方便地将webp保存为其他格式的,以便在需要的地方使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值