Làm thế nào để kiểm tra xem một tệp có phải là tệp hình ảnh hợp lệ hay không?


105

Tôi hiện đang sử dụng PIL.

from PIL import Image
try:
    im=Image.open(filename)
    # do stuff
except IOError:
    # filename not an image file

Tuy nhiên, trong khi điều này đủ bao gồm hầu hết các trường hợp, một số tệp hình ảnh như, xcf, svg và psd không được phát hiện. Tệp psd ném một ngoại lệ OverflowError.

Có cách nào đó mà tôi có thể bao gồm chúng không?


21
Việc đóng các bản sao trên các ngôn ngữ khác nhau không phải là phương pháp đặc biệt phổ biến. Nếu bạn không thể tìm thấy bất kỳ câu hỏi Python nào khác với điều này, hãy để nó mở vì có thể có các giải pháp dành riêng cho Python mà mọi người muốn đăng đã không phù hợp với câu hỏi bạn đã đăng.
Paolo Bergantino

vâng, trước hết tôi thực sự hy vọng về một lib python mà tôi không biết về: P và sau đó như ben đã chỉ ra, chỉ là những con số kỳ diệu không xác thực toàn bộ hình ảnh.
Sujoy

@Sujoy, xác thực toàn bộ hình ảnh là điều gần như không thể, trừ khi bạn đã có bản sao của nó, vì máy tính không thể phân biệt giữa pixel màu chính xác và tập hợp 1 và 0 bị cắt xén, miễn là có tất cả sự kiểm soát (số phép thuật) là đúng.
DevinB

@devinb, đã đồng ý, tôi sẽ chỉ lấy những con số kỳ diệu và hoàn thành nó trừ khi ai đó nghĩ ra điều gì đó tốt hơn để gọi cho một nhà tái cấu trúc :)
Sujoy

xcf và psd không thực sự là hình ảnh, chúng là các tệp dự án chứa (thường là nhiều) hình ảnh ... bạn có thể tạo trường hợp cho svg.
mgalgs

Câu trả lời:


11

Rất nhiều lần cặp ký tự đầu tiên sẽ là một con số kỳ diệu cho các định dạng tệp khác nhau. Bạn có thể kiểm tra điều này ngoài việc kiểm tra ngoại lệ của bạn ở trên.


10
Điều đó sẽ không đủ nếu anh ta thực sự kiểm tra các hình ảnh "hợp lệ"; Ví dụ: sự hiện diện của một số ma thuật không đảm bảo rằng tệp không bị cắt bớt.
Ben Blank

1
lời khuyên tuyệt vời, bây giờ tôi chỉ cần tìm ra những con số đó là gì. cảm ơn :)
Sujoy

@ben, ouch, tôi chưa nghĩ đến điều đó. đó thực sự là một điểm tốt
Sujoy

@Ben, làm thế nào bạn mong đợi một thư viện suy ra một tệp đã bị cắt bớt?
DevinB

6
@Ben Blank: Đúng, nhưng giải quyết một vấn đề 99% theo cách thường tốt hơn sau đó không giải quyết nó chút nào.
Brian R. Bondy

205

Tôi vừa tìm thấy mô-đun imghdr nội trang . Từ tài liệu python:

Mô-đun imghdr xác định loại hình ảnh có trong tệp hoặc luồng byte.

Đây là cách nó hoạt động:

>>> import imghdr
>>> imghdr.what('/tmp/bass')
'gif'

Sử dụng một mô-đun tốt hơn nhiều so với việc thực hiện lại chức năng tương tự


2
vâng imghdr hoạt động với hầu hết các định dạng hình ảnh nhưng không phải tất cả. Theo vấn đề ban đầu của tôi với các tệp svg, xcf và psd, chúng cũng không bị phát hiện trong imghdr
Sujoy

2
Câu trả lời của bạn thực sự tốt hơn, cảm ơn. Giống như ai đó ở trên đã nói ... nhưng giải quyết một vấn đề 99% theo cách thường tốt hơn sau đó không giải quyết nó chút nào ..
RinkyPinku

2
Đáng lưu ý: imghdr.what(path)trả về Nonenếu pathkhông nhận dạng được loại tệp hình ảnh được cung cấp . Danh sách các loại hình ảnh hiện được công nhận: rgb , gif , pbm , pgm , ppm , tiff , rast , xbm , jpeg , bmp , png , webp , exr .
patryk.beza

1
Hãy cẩn thận! Một hdr hợp lệ không có nghĩa là một hình ảnh hợp lệ (ví dụ như các byte hình ảnh có thể được scrambled!)
Filippo Mazza

1
Theo nhận xét của @FilippoMazza, tôi có thể xác nhận rằng một hình ảnh xấu bị cắt trong quá trình truyền tải có thể vượt qua bài kiểm tra này, nhưng sẽ bị hỏng khi PIL cố gắng đọc nó.
kevinmicke

47

Ngoài những gì Brian đang đề xuất, bạn có thể sử dụng phương pháp xác minh của PIL để kiểm tra xem tệp có bị hỏng hay không.

im.verify ()

Cố gắng xác định xem tệp có bị hỏng hay không mà không thực sự giải mã dữ liệu hình ảnh. Nếu phương pháp này tìm thấy bất kỳ vấn đề nào, nó sẽ đưa ra các ngoại lệ phù hợp. Phương pháp này chỉ hoạt động trên một hình ảnh mới mở; nếu hình ảnh đã được tải, kết quả là không xác định. Ngoài ra, nếu bạn cần tải hình ảnh sau khi sử dụng phương pháp này, bạn phải mở lại tệp hình ảnh. Thuộc tính


vấn đề chính là không thể mở các tệp svg, xcf và psd bằng Image.open () do đó, không có cơ hội xác minh bằng im.verify ()
Sujoy

16
Chúa ơi, tài liệu về PIL thật tệ. Chính xác thì một "ngoại lệ phù hợp" là gì?
Timmmm

Đây là liên kết đến tài liệu Pillow cho Image.verify () . Thật không may, nó không tốt hơn và có vẻ như họ chỉ nâng đoạn trên lên mà không thêm bất cứ điều gì.
Nhà giả kim hai bit

Tôi đã nhìn thấy xác minh tăng Lỗi Cú pháp cho các tập tin png tham nhũng
Carl

có cách nào để xác minh "VỚI thực sự giải mã dữ liệu hình ảnh"?
Trevor Boyd Smith

7

Ngoài PILkiểm tra hình ảnh, bạn cũng có thể thêm kiểm tra phần mở rộng tên tệp như sau:

filename.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif'))

Lưu ý rằng điều này chỉ kiểm tra xem tên tệp có phần mở rộng hình ảnh hợp lệ hay không, nó không thực sự mở hình ảnh để xem đó có phải là hình ảnh hợp lệ hay không, đó là lý do tại sao bạn cần sử dụng bổ sung PILhoặc một trong các thư viện được đề xuất trong các câu trả lời khác.


Điều gì xảy ra nếu phần mở rộng không chính xác trong tệp? Ví dụ: tệp văn bản được lưu với phần mở rộng .jpg hoặc ngược lại.
hafiz031

1
@ hafiz031 Để có được định dạng thực tế, bạn có thể làm from PIL import Image img = Image.open(filename) print(img.format)và sau đó kiểm tra nó như thế này:img.format.lower() in ['png', 'jpg', 'jpeg', 'tiff', 'bmp', 'gif']
tsveti_iko

Thật không may, điều này đã không làm việc cho tôi. Nó vẫn đang xác định một hình ảnh bị hỏng là một hình ảnh JPEG. Cuối cùng, tôi đã xử lý được trường hợp này theo cách này (tôi đang sử dụng OpenCv): stackoverflow.com/a/63421847/6907424
hafiz031

6

Cập nhật

Tôi cũng đã triển khai giải pháp sau trong tập lệnh Python của mình tại đây trên GitHub .

Tôi cũng xác minh rằng các tệp bị hỏng (jpg) thường không phải là ảnh 'bị hỏng', tức là tệp ảnh bị hỏng đôi khi vẫn là tệp ảnh hợp pháp, ảnh gốc bị mất hoặc bị thay đổi nhưng bạn vẫn có thể tải nó mà không bị lỗi. Tuy nhiên, việc cắt ngắn tệp luôn gây ra lỗi.

Kết thúc cập nhật

Bạn có thể sử dụng mô-đun Python Pillow (PIL), với hầu hết các định dạng hình ảnh, để kiểm tra xem tệp có phải là tệp hình ảnh hợp lệ và nguyên vẹn hay không.

Trong trường hợp bạn nhắm đến việc phát hiện cả hình ảnh bị hỏng, @Nadia Alramli đề xuất chính xác im.verify()phương pháp, nhưng điều này không phát hiện tất cả các lỗi hình ảnh có thể có , ví dụ: im.verifykhông phát hiện hình ảnh bị cắt ngắn (mà hầu hết người xem thường tải với một vùng xám).

Pillow cũng có thể phát hiện các loại khuyết tật này, nhưng bạn phải áp dụng thao tác hình ảnh hoặc giải mã / mã hóa hình ảnh trong hoặc để kích hoạt kiểm tra. Cuối cùng, tôi đề nghị sử dụng mã này:

try:
  im = Image.load(filename)
  im.verify() #I perform also verify, don't know if he sees other types o defects
  im.close() #reload is necessary in my case
  im = Image.load(filename) 
  im.transpose(PIL.Image.FLIP_LEFT_RIGHT)
  im.close()
except: 
  #manage excetions here

Trong trường hợp có lỗi hình ảnh, mã này sẽ đưa ra một ngoại lệ. Hãy coi rằng im.verify nhanh hơn khoảng 100 lần so với việc thực hiện thao tác trên hình ảnh (và tôi nghĩ rằng lật là một trong những phép biến đổi rẻ hơn). Với mã này, bạn sẽ xác minh một tập hợp hình ảnh ở tốc độ khoảng 10 MByte / giây với Pillow tiêu chuẩn hoặc 40 MByte / giây với mô-đun Pillow-SIMD (CPU 2,5Ghz x86_64 hiện đại).

Đối với các định dạng khác psd , xcf , .. bạn có thể sử dụng Imagemagick wrapper Wand , mã như sau:

im = wand.image.Image(filename=filename)
temp = im.flip;
im.close()

Tuy nhiên, từ các thử nghiệm của tôi, Wand không phát hiện ra hình ảnh bị cắt bớt, tôi nghĩ rằng nó tải các phần thiếu dưới dạng vùng xám mà không cần nhắc.

Tôi đỏ mà ImageMagick có một lệnh bên ngoài xác định rằng có thể làm cho công việc, nhưng tôi đã không tìm thấy một cách để gọi chức năng lập trình và tôi đã không kiểm tra tuyến đường này.

Tôi đề nghị luôn thực hiện kiểm tra sơ bộ, kiểm tra kích thước tệp để không bằng 0 (hoặc rất nhỏ), là một ý tưởng rất rẻ :

statfile = os.stat(filename)
filesize = statfile.st_size
if filesize == 0:
  #manage here the 'faulty image' case

4

Trên Linux, bạn có thể sử dụng python-magic ( http://pypi.python.org/pypi/python-magic/0.1 ) sử dụng libmagic để xác định định dạng tệp.

AFAIK, libmagic nhìn vào tệp và cố gắng cho bạn biết nhiều hơn về nó chứ không chỉ là định dạng, như kích thước bitmap, phiên bản định dạng, v.v. Vì vậy, bạn có thể xem đây là một bài kiểm tra bề ngoài về "tính hợp lệ".

Đối với các định nghĩa khác về "hợp lệ", bạn có thể phải viết các bài kiểm tra của riêng mình.


4

Bạn có thể sử dụng các liên kết Python với libmagic, python-magic và sau đó kiểm tra các loại kịch câm. Điều này sẽ không cho bạn biết nếu các tệp bị hỏng hay còn nguyên vẹn nhưng nó sẽ có thể xác định loại hình ảnh đó là.


3

Vâng, tôi không biết về bên trong của psd, nhưng tôi, chắc chắn, biết rằng, trên thực tế, svg không phải là một tệp hình ảnh, - nó dựa trên xml, vì vậy về cơ bản, nó là một tệp văn bản thuần túy.


aha, bạn nói đúng. nó là xml. tuy nhiên, nó chứa một số dữ liệu hình ảnh được nhúng trong đó.
Sujoy

2

Một lựa chọn là sử dụng filetypegói.

Cài đặt

python -m pip install filetype

Ưu điểm

  1. Nhanh chóng: Nó có hoạt động bằng cách tải vài byte đầu tiên của hình ảnh của bạn ( kiểm tra con số kỳ diệu )
  2. Hỗ trợ các loại kịch câm khác nhau: Hình ảnh, Video, Phông chữ, Âm thanh, Lưu trữ.

Ví dụ giải pháp

import filetype

filename = "/path/to/file.jpg"

if filetype.image(filename):
    print(f"{filename} is a valid image...")
elif filetype.video(filename):
    print(f"{filename} is a valid video...")

Thông tin bổ sung về repo chính thức: https://github.com/h2non/filetype.py


1

Việc kiểm tra phần mở rộng tệp có được chấp nhận không hay bạn đang cố gắng xác nhận rằng bản thân dữ liệu đại diện cho tệp hình ảnh?

Nếu bạn có thể kiểm tra phần mở rộng tệp, một biểu thức chính quy hoặc một phép so sánh đơn giản có thể đáp ứng yêu cầu.


chỉ cần kiểm tra tiện ích mở rộng là không đủ, vì người ta có thể đổi tên tệp txt thành jpg hoặc một cái gì đó. tôi đoán, nếu tôi không thể tìm thấy giải pháp nào, chỉ khi đó tôi sẽ sử dụng kiểm tra tiện ích mở rộng cho xcf và svg
Sujoy

Có thể hiểu được, tôi chỉ hy vọng có một số điều rõ ràng trước khi tôi tiến hành đưa ra một giải pháp có thể phù hợp hơn với nhu cầu của bạn. Cảm ơn!
doomspork

-1
format = [".jpg",".png",".jpeg"]
 for (path,dirs,files) in os.walk(path):
     for file in files:
         if file.endswith(tuple(format)):
             print(path)
             print ("Valid",file)
         else:
             print(path)
             print("InValid",file)

Mã của bạn có một số vấn đề thụt lề và sẽ không chạy đúng cách. Ngoài ra, hãy xem xét thêm một số giải thích về lý do và cách mã của bạn giải quyết vấn đề. Câu trả lời chỉ có mã bởi không quá hữu ích cho những độc giả trong tương lai đến đây.
Tomerikoo

Ở đây chúng tôi đã sử dụng phương pháp Agrparser.
rObinradOO
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.