Python3 — анализ информации об измерении jpeg

#python #binary #python-3.x #hex #jpeg

#python #двоичный #python-3.x #шестнадцатеричный #jpeg

Вопрос:

Я пытаюсь написать функцию Python для анализа ширины и высоты из файла jpeg. Код, который у меня есть в настоящее время, выглядит следующим образом

 import struct

image = open('images/image.jpg','rb')
image.seek(199)
#reverse hex to deal with endianness...
hex = image.read(2)[::-1] image.read(2)[::-1]
print(struct.unpack('HH',hex))
image.close()
  

Однако с этим связано несколько проблем: во-первых, мне нужно просмотреть файл, чтобы определить, откуда читать (после ff c0 00 11 08), а во-вторых, мне нужно избегать получения данных из встроенных эскизов. Есть предложения?

Ответ №1:

Я не смог заставить ни одно из решений работать в Python3 из-за изменений в байтах и строках. Основываясь на решении Acorn, я придумал это, которое работает для меня в Python3:

 import struct
import io

height = -1
width = -1

dafile = open('test.jpg', 'rb')
jpeg = io.BytesIO(dafile.read())
try:

    type_check = jpeg.read(2)
    if type_check != b'xffxd8':
      print("Not a JPG")
    else:
      byte = jpeg.read(1)

      while byte != b"":

        while byte != b'xff': byte = jpeg.read(1)
        while byte == b'xff': byte = jpeg.read(1)

        if (byte >= b'xC0' and byte <= b'xC3'):
          jpeg.read(3)
          h, w = struct.unpack('>HH', jpeg.read(4))
          break
        else:
          jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)

        byte = jpeg.read(1)

      width = int(w)
      height = int(h)

      print("Width: %s, Height: %s" % (width, height))
finally:
    jpeg.close()
  

Комментарии:

1. Вы открываете ‘dafile’, но не закрываете его. Кроме того, он отлично работает.

Ответ №2:

Раздел JPEG этой функции может быть полезен: http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py

 jpeg.read(2)
b = jpeg.read(1)
try:
    while (b and ord(b) != 0xDA):
        while (ord(b) != 0xFF): b = jpeg.read(1)
        while (ord(b) == 0xFF): b = jpeg.read(1)
        if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
            jpeg.read(3)
            h, w = struct.unpack(">HH", jpeg.read(4))
            break
        else:
            jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
        b = jpeg.read(1)
    width = int(w)
    height = int(h)
except struct.error:
    pass
except ValueError:
    pass
  

Комментарии:

1. Спасибо, это выглядит действительно полезным, конечно, для начала использовать struct.unpack('>HH',hex)) намного аккуратнее.

Ответ №3:

Мое предложение: используйте PIL (библиотеку изображений Python).

 >>> import Image
>>> img= Image.open("test.jpg")
>>> print img.size
(256, 256)
  

В противном случае используйте Hachoir, который является чистой библиотекой Python; особенно hachoir-metadata, похоже, обладает нужной вам функциональностью).

Комментарии:

1. Насколько я знаю, PIL все еще не запускается на py3k.

2. в этом случае используйте pillow

Ответ №4:

Дальнейшая модернизация и упрощение кода pep8d от Acorn и manafire. Можно было бы внести дополнительные улучшения, например, для большей эффективности использовать большой размер блока, но достаточно хороший для краткого примера:

 import sys
from struct import unpack


with open(sys.argv[1], 'rb') as jpegfile:

    if jpegfile.read(2) == b'xffxd8':

        byte = jpegfile.read(1)
        h = w = -1
        while byte != b'':

            # skip early segments
            while byte != b'xff':
                byte = jpegfile.read(1)
            while byte == b'xff':
                byte = jpegfile.read(1)

            # read dimensions
            if byte >= b'xC0' and byte <= b'xC3':
                jpegfile.read(3)
                h, w = unpack('>HH', jpegfile.read(4))
                break
            else:
                size = int(unpack('>H', jpegfile.read(2))[0])
                jpegfile.read(size - 2)

            byte = jpegfile.read(1)

        print(f'Width: {w}, Height: {h}')
    else:
        print('Not a JPG!')