python打开webp图片


问题

今天处理图片的时候发现有一张后缀为.jpg的图片在电脑上无法打开,但是使用Chrome浏览器能打开。尝试用OpenCV读取,但是也无法打开。

仔细查看了OpenCV支持的图片格式

Windows bitmaps - *.bmp, *.dib (always supported)
JPEG files - *.jpeg, *.jpg, *.jpe (see the Notes section)
JPEG 2000 files - *.jp2 (see the Notes section)
Portable Network Graphics - *.png (see the Notes section)
Portable image format - *.pbm, *.pgm, *.ppm (always supported)
Sun rasters - *.sr, *.ras (always supported)
TIFF files - *.tiff, *.tif (see the Notes section)

按照后缀判断是jpg格式,仔细想想有可能是图片后缀和实际格式不符合。通过以字节码的形式读取该图片,发现一个问题:
在这里插入图片描述

思考

字节码头显示RIFF和WEBPVP8这两个关键信息,根据这判断其不是jpg格式,再搜索发现这是谷歌推出的webp图片格式。
以下是常见的图片格式及判断方法:

格式描述判断方式
jpeg用JFIF或者Exif格式保存的JPEG图片第7到第10个字节是b’JFIF’或者b’Exif’
png可移植网络图形格式(Portable Network Graphic Format)以字节串b’\x89PNG\r\n\x1a\n’开头
gifGIF(Graphics Interchange Format)的87版本和89版本前6个字节为b’GIF87a’或者b’GIF89a’
tiffTIFF(Tag Image File Format)的两种字节顺序前两个字节为b’MM’或者b’II’
rgbSGI ImgLib以字节串b’\x01\xda’开头
pbmPortable Bitmap第1个字节为b’P’,第2个字节为b’1’或b’4’,第3个字节为b’\t’或b’\n’或b’\r’
pgmPortable Graymap Files第1个字节为b’P’,第2个字节为b’2’或b’5’,第3个字节为b’\t’或b’\n’或b’\r’
ppmPortable Pixmap Files第1个字节为b’P’,第2个字节为b’3’或b’6’,第3个字节为b’\t’或b’\n’或b’\r’
rastSun Raster以字节串b’\x59\xA6\x6A\x95’开头
xbmX Bitmap Files以字节串b’#define ‘开头
bmpBitmap,Windows标准图像文件格式以字节串b’BM’开头
webp谷歌的WebP格式,Python3.5加入以字节串b’RIFF’开头并且第9到第12个字节为b’WEBP’
exrOpenEXR,Python3.5加入以字节串b’\x76\x2f\x31\x01’开头

解决

既然知道了这个假的“jpg”实际上是“webp”图片。那么如何读取呢?
使用OpenCV读取会报错,使用PIL发现可以读取。
在这里插入图片描述

from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('fake.jpg')
plt.imshow(img)
plt.show()


可以直接通过PIL读取后存储为真正的jpg格式图片。

from PIL import Image
img = Image.open('fake.jpg')
img.save('real.jpg')

扩展

图片格式繁多,在处理时很容易出现格式问题。怎么样才能确保出现报错前就能预知问题呢?
经过搜索,发现了一个比较好用的package——imghdr
在这里插入图片描述
这个包是python自带,使用方式如下:

import imghdr
imghdr.what('fake.jpg')

在这里插入图片描述
处理图片前判断一下格式,就能避免很多格式上的问题。
另外,python下有webp包可以加载和保存webp格式图片。

pip install webp
import webp

# Save an image
webp.save_image(img, 'image.webp', quality=80)

# Load an image
img = webp.load_image('image.webp', 'RGBA')

# Save an animation
webp.save_images(imgs, 'anim.webp', fps=10, lossless=True)

# Load an animation
imgs = webp.load_images('anim.webp', 'RGB', fps=10)


参考资料

[1] RIFF格式图片在ios浏览器中无法显示
[2] OpenCV的imread函数支持的图片格式
[3] imghdr — 推测图像类型
[4] python webp package