13

Is there any general way to detect if a file is a image (jpg, bmp, png, etc...)

Or is making a list of the file extensions and doing a one-by-one comparison the only way?

Otto Allmendinger
  • 25,140
  • 7
  • 64
  • 79
  • 1
    According to the standard python file types http://docs.python.org/c-api/concrete.html image file isn't standard, so I suppose some external module will be required. –  Jul 10 '11 at 10:43
  • 2
    Use the `imghdr` module. See [How to check if a file is a valid image file?](http://stackoverflow.com/questions/889333/how-to-check-if-a-file-is-a-valid-image-file) – Aaron Digulla Oct 06 '13 at 12:27
  • My solution: `try: Image.open(img_path).format in ["JPEG", "PNG", "GIF", "BMP"]; except: print(img_path)` – 10donovanr Jan 31 '21 at 20:46

2 Answers2

26

Assuming:

>>> files = {"a_movie.mkv", "an_image.png", "a_movie_without_extension", "an_image_without_extension"}

And they are proper movie and image files in script folder.

You can use builtin mimetypes module, but it won't work without extensions.

>>> import mimetypes
>>> {file: mimetypes.guess_type(file) for file in files}
{'a_movie_without_extension': (None, None), 'an_image.png': ('image/png', None), 'an_image_without_extension': (None, None), 'a_movie.mkv': (None, None)}

Or call the unix command file. This works without extensions, but not in Windows:

>>> import subprocess
>>> def find_mime_with_file(path):
...     command = "/usr/bin/file -i {0}".format(path)
...     return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).communicate()[0].split()[1]
... 
>>> {file: find_mime_with_file(file) for file in files}
{'a_movie_without_extension': 'application/octet-stream;', 'an_image.png': 'image/png;', 'an_image_without_extension': 'image/png;', 'a_movie.mkv': 'application/octet-stream;'}

Or you try to open it with PIL, and check for errors, but needs PIL installed:

>>> from PIL import Image
>>> def check_image_with_pil(path):
...     try:
...         Image.open(path)
...     except IOError:
...         return False
...     return True
... 
>>> {file: check_image_with_pil(file) for file in files}
{'a_movie_without_extension': False, 'an_image.png': True, 'an_image_without_extension': True, 'a_movie.mkv': False}

Or, for simplicity, as you say, just check extensions, it's the best way I think.

>>> extensions = {".jpg", ".png", ".gif"} #etc
>>> {file: any(file.endswith(ext) for ext in extensions) for file in files}
{'a_movie_without_extension': False, 'an_image.png': True, 'an_image_without_extension': False, 'a_movie.mkv': False}
utdemir
  • 24,044
  • 9
  • 56
  • 78
  • +1 noting for others that the use of `file` or option two worked best for my use case where I was crawling retrieving images that were returned w/o an extension and need to save them as either .jpg/.png – matchew Jan 15 '13 at 01:48
  • There is also an easy way to this...."if 'file' in request.files:" try this out if there is file then it will return true.. – SR_Mehta Feb 16 '18 at 10:00
  • I was searching for the last solution you gave. Thanks a lot. – Devendra Bhat Aug 27 '18 at 07:26
2

You should use a library for this. Note that extension != file type, because you can change the extension to a .jpg file, open it with paint and paint will interpret it like a jpeg (for example). You should check How to find the mime type of a file in python?.

Community
  • 1
  • 1
Pedro Montoto García
  • 1,630
  • 2
  • 18
  • 35