J'utilise Python 2.5. Et en utilisant les classes standard de Python, je veux déterminer la taille de l'image d'un fichier.
J'ai entendu PIL (Python Image Library), mais cela nécessite une installation pour fonctionner.
Comment puis-je obtenir la taille d'une image sans utiliser aucune bibliothèque externe, en utilisant simplement les modules de Python 2.5?
Remarque Je souhaite prendre en charge les formats d'image courants, notamment JPG et PNG.
Voici un script python 3) qui retourne un tuple contenant une hauteur et une largeur d'image pour .png, .gif et .jpeg sans utiliser aucune bibliothèque externe (c'est-à-dire ce que Kurt McKee a mentionné plus haut). Devrait être relativement facile à transférer à Python 2.
import struct
import imghdr
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(24)
if len(head) != 24:
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
else:
return
return width, height
La réponse des Kurts devait être légèrement modifiée pour fonctionner pour moi.
D'abord sur Ubuntu: Sudo apt-get install python-imaging
Ensuite:
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) Tuple
Consultez le manuel pour plus d'informations.
Bien qu'il soit possible d'appeler open(filename, 'rb')
et de vérifier les dimensions des en-têtes d'image binaire, il semble beaucoup plus utile d'installer PIL et de passer votre temps à écrire de nouveaux logiciels super! Vous bénéficiez d'une meilleure prise en charge des formats de fichiers et de la fiabilité résultant d'une utilisation généralisée. d'après la documentation PIL , il apparaît que le code nécessaire pour mener à bien votre tâche serait le suivant:
from PIL import Image
im = Image.open('filename.png')
print 'width: %d - height: %d' % im.size # returns (width, height) Tuple
En ce qui concerne l'écriture de code vous-même, je ne connais pas de module dans la bibliothèque standard Python qui fera ce que vous voulez. Vous devrez open()
_ l'image dans en mode binaire et commencez à le décoder vous-même. Vous pouvez en savoir plus sur les formats à:
Voici un moyen d'obtenir les dimensions d'un fichier png sans avoir besoin d'un module tiers. De http://coreygoldberg.blogspot.com/2013/01/python-verify-png-file-and-get-image.html
import struct
def get_image_info(data):
if is_png(data):
w, h = struct.unpack('>LL', data[16:24])
width = int(w)
height = int(h)
else:
raise Exception('not a png image')
return width, height
def is_png(data):
return (data[:8] == '\211PNG\r\n\032\n'and (data[12:16] == 'IHDR'))
if __== '__main__':
with open('foo.png', 'rb') as f:
data = f.read()
print is_png(data)
print get_image_info(data)
Lorsque vous exécutez ceci, il retournera:
True
(x, y)
Et un autre exemple incluant la gestion des fichiers JPEG: http://markasread.net/post/17551554979/get-image-size-info-using-pure-python-code
Concernant la réponse de Fred the Fantastic :
Tous les marqueurs JPEG compris entre C0
-CF
ne sont pas SOF
marqueurs; J'ai exclu DHT (C4
), DNL (C8
) Et DAC (CC
). Notez que je n'ai pas cherché à savoir s'il était même possible d'analyser des images autres que C0
Et C2
De cette manière. Cependant, les autres semblent être assez rares (je n'ai personnellement rencontré personne d'autre que C0
Et C2
).
Quoi qu'il en soit, cela résout le problème mentionné dans les commentaires de Malandy avec Bangles.jpg
(DHT analysé à tort comme un fichier SOF).
L'autre problème mentionné avec 1431588037-WgsI3vK.jpg
Est dû au fait que imghdr
ne peut détecter que les en-têtes APP0 (EXIF) et APP1 (JFIF).
Cela peut être corrigé en ajoutant un test plus laxiste à imghdr (par exemple, simplement FFD8
Ou peut-être FFD8FF
?) Ou quelque chose de beaucoup plus complexe (éventuellement même la validation des données). Avec une approche plus complexe, je n'ai trouvé que des problèmes avec: APP14 (FFEE
) (Adobe); le premier marqueur est DQT (FFDB
); et APP2 et problèmes liés aux fichiers ICC_PROFILE intégrés .
Le code révisé ci-dessous a également modifié légèrement l'appel à imghdr.what()
:
import struct
import imghdr
def test_jpeg(h, f):
# SOI APP2 + ICC_PROFILE
if h[0:4] == '\xff\xd8\xff\xe2' and h[6:17] == b'ICC_PROFILE':
print "A"
return 'jpeg'
# SOI APP14 + Adobe
if h[0:4] == '\xff\xd8\xff\xee' and h[6:11] == b'Adobe':
return 'jpeg'
# SOI DQT
if h[0:4] == '\xff\xd8\xff\xdb':
return 'jpeg'
imghdr.tests.append(test_jpeg)
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(24)
if len(head) != 24:
return
what = imghdr.what(None, head)
if what == 'png':
check = struct.unpack('>i', head[4:8])[0]
if check != 0x0d0a1a0a:
return
width, height = struct.unpack('>ii', head[16:24])
Elif what == 'gif':
width, height = struct.unpack('<HH', head[6:10])
Elif what == 'jpeg':
try:
fhandle.seek(0) # Read 0xff next
size = 2
ftype = 0
while not 0xc0 <= ftype <= 0xcf or ftype in (0xc4, 0xc8, 0xcc):
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
else:
return
return width, height
Remarque: Création d'une réponse complète au lieu d'un commentaire, car je ne suis pas encore autorisé à le faire.
Si vous avez ImageMagick installé, vous pouvez utiliser ' identifier '. Par exemple, vous pouvez l'appeler comme ceci:
path = "//folder/image.jpg"
dim = subprocess.Popen(["identify","-format","\"%w,%h\"",path], stdout=subprocess.PIPE).communicate()[0]
(width, height) = [ int(x) for x in re.sub('[\t\r\n"]', '', dim).split(',') ]
Ce code accomplit 2 choses:
Obtenir le dimension de l'image
Trouver le vrai EOF d'un fichier jpg
Eh bien, quand googler j'étais plus intéressé par le dernier. La tâche consistait à découper un fichier jpg dans un flux de données. Depuis que je n'ai trouvé aucun moyen d'utiliser "l'image" de Pythons pour obtenir le EOF de so jpg-File, j'ai inventé ceci.
Choses/changements/notes intéressants dans cet exemple:
extension de la classe de fichiers Python) normale avec la méthode uInt16 rendant le code source plus lisible et facile à gérer.
Remplacé les zones/morceaux non lus avec la lecture
Si vous souhaitez simplement obtenir les dimensions, vous pouvez supprimer la ligne:
hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00]
-> dans la mesure où cela n’a d’importance que lors de la lecture du bloc de données d’image et du commentaire dans
#break
pour arrêter de lire dès que la dimension a été trouvée. ... mais souriez ce que je dis - vous êtes le codeur;)
import struct
import io,os
class myFile(file):
def byte( self ):
return file.read( self, 1);
def uInt16( self ):
tmp = file.read( self, 2)
return struct.unpack( ">H", tmp )[0];
jpeg = myFile('grafx_ui.s00_\\08521678_Unknown.jpg', 'rb')
try:
height = -1
width = -1
EOI = -1
type_check = jpeg.read(2)
if type_check != b'\xff\xd8':
print("Not a JPG")
else:
byte = jpeg.byte()
while byte != b"":
while byte != b'\xff': byte = jpeg.byte()
while byte == b'\xff': byte = jpeg.byte()
# FF D8 SOI Start of Image
# FF D0..7 RST DRI Define Restart Interval inside CompressedData
# FF 00 Masked FF inside CompressedData
# FF D9 EOI End of Image
# http://en.wikipedia.org/wiki/JPEG#Syntax_and_structure
hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00]
if hasChunk:
ChunkSize = jpeg.uInt16() - 2
ChunkOffset = jpeg.tell()
Next_ChunkOffset = ChunkOffset + ChunkSize
# Find bytes \xFF \xC0..C3 That marks the Start of Frame
if (byte >= b'\xC0' and byte <= b'\xC3'):
# Found SOF1..3 data chunk - Read it and quit
jpeg.seek(1, os.SEEK_CUR)
h = jpeg.uInt16()
w = jpeg.uInt16()
#break
Elif (byte == b'\xD9'):
# Found End of Image
EOI = jpeg.tell()
break
else:
# Seek to next data chunk
print "Pos: %.4x %x" % (jpeg.tell(), ChunkSize)
if hasChunk:
jpeg.seek(Next_ChunkOffset)
byte = jpeg.byte()
width = int(w)
height = int(h)
print("Width: %s, Height: %s JpgFileDataSize: %x" % (width, height, EOI))
finally:
jpeg.close()
J'ai trouvé une solution intéressante dans un autre article de Stackoverflow (en n'utilisant que des bibliothèques standard + traitant également de jpg): réponse de JohnTESlade
Et une autre solution (le moyen rapide) pour ceux qui peuvent se permettre d’exécuter la commande ' du fichier ' au sein de python, exécutez:
import os
info = os.popen("file foo.jpg").read()
print info
Sortie :
foo.jpg: JPEG image data...density 28x28, segment length 16, baseline, precision 8, 352x198, frames 3
Tout ce que vous devez faire maintenant, c'est formater la sortie pour capturer les dimensions. 352x198 dans mon cas.
Cela dépend de la sortie du fichier dont je ne suis pas sûr est normalisé sur tous les systèmes. Certains 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]))