modulos - paquetes python
¿Cómo obtener el tamaño de imagen usando la clase estándar de Python(sin usar una biblioteca externa)? (9)
Estoy usando Python 2.5. Y usando las clases estándar de Python, quiero determinar el tamaño de la imagen de un archivo.
He escuchado PIL (Biblioteca de imágenes de Python), pero requiere que la instalación funcione.
¿Cómo puedo obtener el tamaño de una imagen sin usar ninguna biblioteca externa, solo usando los módulos de Python 2.5?
Tenga en cuenta que quiero admitir formatos de imagen comunes, particularmente JPG y PNG.
Aquí hay una manera de obtener las dimensiones de un archivo png sin necesidad de un módulo de terceros. Desde 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 __name__ == ''__main__'':
with open(''foo.png'', ''rb'') as f:
data = f.read()
print is_png(data)
print get_image_info(data)
Cuando ejecutas esto, volverá:
True
(x, y)
Y otro ejemplo que incluye el manejo de archivos JPEG también: http://markasread.net/post/17551554979/get-image-size-info-using-pure-python-code
Aquí hay una secuencia de comandos de python 3 que devuelve una tupla que contiene una altura y un ancho de imagen para .png, .gif y .jpeg sin utilizar ninguna biblioteca externa (es decir, a qué se refirió Kurt McKee anteriormente). Debería ser relativamente fácil transferirlo a 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
En cuanto a la respuesta de Fred el Fantástico :
No todos los marcadores JPEG entre C0
- CF
son marcadores SOF
; Excluí DHT ( C4
), DNL ( C8
) y DAC ( CC
). Tenga en cuenta que no he investigado si es posible analizar los cuadros que no sean C0
y C2
de esta manera. Sin embargo, los otros parecen ser bastante raros (personalmente no he encontrado otro que C0
y C2
).
De cualquier manera, esto resuelve el problema mencionado en los comentarios de Malandy con Bangles.jpg
(DHT erróneamente analizado como SOF).
El otro problema mencionado con 1431588037-WgsI3vK.jpg
se debe a que imghdr
solo puede detectar los encabezados APP0 (EXIF) y APP1 (JFIF).
Esto se puede solucionar agregando una prueba más laxa a imghdr (por ejemplo, simplemente FFD8
o tal vez FFD8FF
?) O algo mucho más complejo (posiblemente incluso la validación de datos). Con un enfoque más complejo, solo he encontrado problemas con: APP14 ( FFEE
) (Adobe); el primer marcador es DQT ( FFDB
); y APP2 y problemas con ICC_PROFILE incrustados .
El código revisado a continuación, también alteró la llamada a imghdr.what()
levemente:
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
Nota: Creado una respuesta completa en lugar de un comentario, ya que todavía no estoy autorizado.
Encontré una buena solución en otra publicación de (usando solo librerías estándar + que tratan con jpg también): Respuesta de JohnTESlade
Y otra solución (la forma más rápida) para aquellos que pueden permitirse ejecutar el comando '' file '' dentro de python, ejecute:
import os
info = os.popen("file foo.jpg").read()
print info
Salida :
foo.jpg: JPEG image data...density 28x28, segment length 16, baseline, precision 8, 352x198, frames 3
Todo lo que tienes que hacer ahora es formatear la salida para capturar las dimensiones. 352x198 en mi caso.
Ese código logra 2 cosas:
Obtener la dimensión de la imagen
Encuentra el EOF real de un archivo jpg
Bueno, cuando busqué en Google, estaba más interesado en el posterior. La tarea era cortar un archivo jpg de un flujo de datos. Dado que II no encontró ninguna forma de usar la imagen de Pythons para obtener el EOF de modo que jpg-File lo inventé.
Cosas / cambios / notas interesantes en esta muestra:
ampliando la clase de archivo Python normal con el método uInt16, haciendo que el código fuente sea más legible y mantenible. Jugar con struct.unpack () rápidamente hace que el código se vea feo
Se reemplazó la lectura de áreas / fragmentos insatisfactorios con búsqueda
En caso de que quiera obtener las dimensiones, puede eliminar la línea:
hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00]
-> ya que eso solo es importante cuando se lee el fragmento de datos de la imagen y se comenta
#break
para dejar de leer tan pronto como se encuentre la dimensión. ... pero sonría lo que estoy diciendo, usted es el codificador;)
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()
La respuesta de Kurts necesitaba ser modificada ligeramente para que funcione para mí.
Primero, en ubuntu: sudo apt-get install python-imaging
Entonces:
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
Consulte el handbook para obtener más información.
Si bien es posible llamar a open(filename, ''rb'')
y verificar a través de los encabezados de las imágenes binarias las dimensiones, ¡parece mucho más útil instalar PIL y dedicar mucho tiempo a la creación de un excelente software nuevo! Obtiene mayor soporte de formato de archivo y la confiabilidad que proviene del uso generalizado. De la documentación de PIL , parece que el código que necesitaría para completar su tarea sería:
from PIL import Image
im = Image.open(''filename.png'')
print ''width: %d - height: %d'' % im.size # returns (width, height) tuple
En cuanto a escribir código usted mismo, no conozco un módulo en la biblioteca estándar de Python que haga lo que quiera. Deberá open()
la imagen en modo binario y comenzar a decodificarla usted mismo. Puede leer sobre los formatos en:
Si tiene instalado ImageMagick , puede usar '' identify ''. Por ejemplo, puede llamarlo así:
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('','') ]
Tropecé con este, pero puedes obtenerlo usando lo siguiente, siempre y cuando importes numpy.
import numpy as np
[y, x] = np.shape(img[:,:,0])
Funciona porque ignoras todos los colores excepto uno, y luego la imagen es solo 2D, por lo que la forma te dice qué tan alta es. Todavía es un poco nuevo para Python, pero parece una forma sencilla de hacerlo.