Je comprends que vous pouvez obtenir la taille de l'image à l'aide de PIL de la manière suivante
from PIL import Image
im = Image.open(image_filename)
width, height = im.size
Cependant, je voudrais obtenir la largeur et la hauteur de l'image sans avoir à charger l'image en mémoire. Est-ce possible? Je ne fais que des statistiques sur les tailles d'image et ne me soucie pas du contenu de l'image. Je veux juste accélérer mon traitement.
Comme l'indiquent les commentaires, PIL ne charge pas l'image en mémoire lors de l'appel de .open
. En regardant les docs de PIL 1.1.7
, la docstring pour .open
dit:
def open(fp, mode="r"):
"Open an image file, without loading the raster data"
Il y a quelques opérations de fichier dans le source comme:
...
prefix = fp.read(16)
...
fp.seek(0)
...
mais ceux-ci constituent à peine la lecture du fichier entier. En réalité .open
renvoie simplement un objet fichier et le nom du fichier en cas de succès. De plus, les docs disent:
ouvert (fichier, mode = "r")
Ouvre et identifie le fichier image donné.
C'est une opération paresseuse; cette fonction identifie le fichier, mais les données d'image réelles ne sont pas lues à partir du fichier tant que vous n'avez pas essayé de traiter les données (ni appelé la méthode load ).
En creusant plus profond, on voit que .open
appels _open
qui est une surcharge spécifique au format d’image. Chacune des implémentations à _open
peut être trouvé dans un nouveau fichier, par exemple. Les fichiers .jpeg sont en JpegImagePlugin.py
. Regardons cela en profondeur.
Ici, les choses semblent devenir un peu délicates, il y a une boucle infinie qui se casse lorsque le marqueur jpeg est trouvé:
while True:
s = s + self.fp.read(1)
i = i16(s)
if i in MARKER:
name, description, handler = MARKER[i]
# print hex(i), name, description
if handler is not None:
handler(self, i)
if i == 0xFFDA: # start of scan
rawmode = self.mode
if self.mode == "CMYK":
rawmode = "CMYK;I" # assume Adobe conventions
self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
# self.__offset = self.fp.tell()
break
s = self.fp.read(1)
Elif i == 0 or i == 65535:
# padded marker or junk; move on
s = "\xff"
else:
raise SyntaxError("no marker found")
Ce qui en ressemble pourrait lire tout le fichier s'il était mal formé. Cependant, si le marqueur d’information est OK, il devrait se déclencher tôt. La fonction handler
définit finalement self.size
qui sont les dimensions de l'image.
Si vous ne vous souciez pas du contenu de l'image, le PIL est probablement un peu exagéré.
Je suggère d'analyser la sortie du module magique python:
>>> t = magic.from_file('teste.png')
>>> t
'PNG image data, 782 x 602, 8-bit/color RGBA, non-interlaced'
>>> re.search('(\d+) x (\d+)', t).groups()
('782', '602')
C'est une enveloppe autour de libmagic qui lit le moins d'octets possible afin d'identifier une signature de type de fichier.
Version pertinente du script:
https://raw.githubusercontent.com/scardine/image_size/master/get_image_size.py
[mise à jour]
Hmmm, malheureusement, lorsqu’il est appliqué à des jpegs, le texte ci-dessus donne "" Données d’image JPEG, norme EXIF 2.21 "". Aucune taille d'image! - Alex Flint
On dirait que les jpeg sont résistants à la magie. :-)
Je peux comprendre pourquoi: pour obtenir les dimensions de l’image pour les fichiers JPEG, il se peut que vous deviez lire plus d’octets que libmagic n’aime en lire.
A retroussé mes manches et est venu avec cet extrait très non testé (récupéré auprès de GitHub) qui ne nécessite aucun module tiers.
#-------------------------------------------------------------------------------
# Name: get_image_size
# Purpose: extract image dimensions given a file path using just
# core modules
#
# Author: Paulo Scardine (based on code from Emmanuel VAÏSSE)
#
# Created: 26/09/2013
# Copyright: (c) Paulo Scardine 2013
# Licence: MIT
#-------------------------------------------------------------------------------
#!/usr/bin/env python
import os
import struct
class UnknownImageFormat(Exception):
pass
def get_image_size(file_path):
"""
Return (width, height) for a given img file content - no external
dependencies except the os and struct modules from core
"""
size = os.path.getsize(file_path)
with open(file_path) as input:
height = -1
width = -1
data = input.read(25)
if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
# GIFs
w, h = struct.unpack("<HH", data[6:10])
width = int(w)
height = int(h)
Elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
and (data[12:16] == 'IHDR')):
# PNGs
w, h = struct.unpack(">LL", data[16:24])
width = int(w)
height = int(h)
Elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
# older PNGs?
w, h = struct.unpack(">LL", data[8:16])
width = int(w)
height = int(h)
Elif (size >= 2) and data.startswith('\377\330'):
# JPEG
msg = " raised while trying to decode as JPEG."
input.seek(0)
input.read(2)
b = input.read(1)
try:
while (b and ord(b) != 0xDA):
while (ord(b) != 0xFF): b = input.read(1)
while (ord(b) == 0xFF): b = input.read(1)
if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
input.read(3)
h, w = struct.unpack(">HH", input.read(4))
break
else:
input.read(int(struct.unpack(">H", input.read(2))[0])-2)
b = input.read(1)
width = int(w)
height = int(h)
except struct.error:
raise UnknownImageFormat("StructError" + msg)
except ValueError:
raise UnknownImageFormat("ValueError" + msg)
except Exception as e:
raise UnknownImageFormat(e.__class__.__+ msg)
else:
raise UnknownImageFormat(
"Sorry, don't know how to get information from this file."
)
return width, height
[mise à jour 2019]
Découvrez une Rust: https://github.com/scardine/imsz
Il y a un paquet sur pypi appelé imagesize
qui fonctionne actuellement pour moi, bien qu'il ne semble pas très actif.
Installer:
pip install imagesize
Usage:
import imagesize
width, height = imagesize.get("test.png")
print(width, height)
Page d'accueil: https://github.com/shibukawa/imagesize_py
Je récupère souvent les tailles d’image sur Internet. Bien sûr, vous ne pouvez pas télécharger l’image, puis la charger pour analyser les informations. Cela prend trop de temps. Ma méthode consiste à insérer des fragments dans un conteneur d'image et à vérifier s'il peut analyser l'image à chaque fois. Arrêtez la boucle lorsque je reçois l'information que je veux.
J'ai extrait le noyau de mon code et l'ai modifié pour analyser les fichiers locaux.
from PIL import ImageFile
ImPar=ImageFile.Parser()
with open(r"D:\testpic\test.jpg", "rb") as f:
ImPar=ImageFile.Parser()
chunk = f.read(2048)
count=2048
while chunk != "":
ImPar.feed(chunk)
if ImPar.image:
break
chunk = f.read(2048)
count+=2048
print(ImPar.image.size)
print(count)
Sortie:
(2240, 1488)
38912
La taille réelle du fichier est de 1 543 580 octets et vous ne lisez que 38 912 octets pour obtenir la taille de l'image. J'espère que cela aidera.
Une autre façon de le faire sur les systèmes Unix. Cela dépend de la sortie de file
dont je ne suis pas sûr est standardisé sur tous les systèmes. Cela ne devrait probablement pas être utilisé dans le code de production. De plus, la plupart des fichiers JPEG ne signalent pas la taille de l'image.
import subprocess, re
image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file " + filename))[-1]))
Ce réponse a une autre bonne résolution, mais il manque le format pgm . Ceci réponse a résolu le pgm . Et j'ajoute le bmp .
Codes est ci-dessous
import struct, imghdr, re, magic
def get_image_size(fname):
'''Determine the image type of fhandle and return its size.
from draco'''
with open(fname, 'rb') as fhandle:
head = fhandle.read(32)
if len(head) != 32:
return
if imghdr.what(fname) == 'png':
check = struct.unpack('>i', head[4:8])[0]
if check != 0x0d0a1a0a:
return
width, height = struct.unpack('>ii', head[16:24])
Elif imghdr.what(fname) == 'gif':
width, height = struct.unpack('<HH', head[6:10])
Elif imghdr.what(fname) == 'jpeg':
try:
fhandle.seek(0) # Read 0xff next
size = 2
ftype = 0
while not 0xc0 <= ftype <= 0xcf:
fhandle.seek(size, 1)
byte = fhandle.read(1)
while ord(byte) == 0xff:
byte = fhandle.read(1)
ftype = ord(byte)
size = struct.unpack('>H', fhandle.read(2))[0] - 2
# We are at a SOFn block
fhandle.seek(1, 1) # Skip `precision' byte.
height, width = struct.unpack('>HH', fhandle.read(4))
except Exception: #IGNORE:W0703
return
Elif imghdr.what(fname) == 'pgm':
header, width, height, maxval = re.search(
b"(^P5\s(?:\s*#.*[\r\n])*"
b"(\d+)\s(?:\s*#.*[\r\n])*"
b"(\d+)\s(?:\s*#.*[\r\n])*"
b"(\d+)\s(?:\s*#.*[\r\n]\s)*)", head).groups()
width = int(width)
height = int(height)
Elif imghdr.what(fname) == 'bmp':
_, width, height, depth = re.search(
b"((\d+)\sx\s"
b"(\d+)\sx\s"
b"(\d+))", str).groups()
width = int(width)
height = int(height)
else:
return
return width, height