問題
今天處理圖片的時候發現有一張後綴爲.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