问题
今天处理图片的时候发现有一张后缀为.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’开头 |
gif | GIF(Graphics Interchange Format)的87版本和89版本 | 前6个字节为b’GIF87a’或者b’GIF89a’ |
tiff | TIFF(Tag Image File Format)的两种字节顺序 | 前两个字节为b’MM’或者b’II’ |
rgb | SGI ImgLib | 以字节串b’\x01\xda’开头 |
pbm | Portable Bitmap | 第1个字节为b’P’,第2个字节为b’1’或b’4’,第3个字节为b’\t’或b’\n’或b’\r’ |
pgm | Portable Graymap Files | 第1个字节为b’P’,第2个字节为b’2’或b’5’,第3个字节为b’\t’或b’\n’或b’\r’ |
ppm | Portable Pixmap Files | 第1个字节为b’P’,第2个字节为b’3’或b’6’,第3个字节为b’\t’或b’\n’或b’\r’ |
rast | Sun Raster | 以字节串b’\x59\xA6\x6A\x95’开头 |
xbm | X Bitmap Files | 以字节串b’#define ‘开头 |
bmp | Bitmap,Windows标准图像文件格式 | 以字节串b’BM’开头 |
webp | 谷歌的WebP格式,Python3.5加入 | 以字节串b’RIFF’开头并且第9到第12个字节为b’WEBP’ |
exr | OpenEXR,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