преобразовать изображение в байтовый литерал в python

1

Я пытаюсь сохранить изображение как текст, так что я могу сделать что-то вроде этого примера прозрачного значка для Tk gui:

import tempfile

# byte literal code for a transparent icon, I think
ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05\x00\x00'
        b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00'
        b'\x08\x00\x00\x00\x00\x00@\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        b'\x00\x01\x00\x00\x00\x01') + b'\x00'*1282 + b'\xff'*64

# makes a temp file for the transparent icon and saves it
_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:
    icon_file.write(ICON)

Я пробовал кодировку base 64, декодирование с помощью utf8, преобразование в байты и bytearray и некоторые ответы из другого сообщения: (Python Script для преобразования Image в массив байтов)

import tempfile, base64, io

# byte literal code for a transparent icon, I think
ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05\x00\x00'
        b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00'
        b'\x08\x00\x00\x00\x00\x00@\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        b'\x00\x01\x00\x00\x00\x01') + b'\x00'*1282 + b'\xff'*64

# makes a temp file for the transparent icon and saves it
_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:
    icon_file.write(ICON)

a = open(ICON_PATH, 'rb').read()

b = base64.b64encode(a)

print b # output does not match what ICON equals above

#b = bytes(a).decode('utf-8') # doesn't work -- gives error UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 1342: invalid start byte

c = bytearray(a)

print c # prints garbled junk


# gives error AttributeError: __exit__ on Image.open(ICON_PATH) line
with io.BytesIO() as output:
    from PIL import Image
    with Image.open(ICON_PATH) as img:
        img.convert('RGB').save(output, 'BMP')                
    data = output.getvalue()[14:]

print data

Он также не работает для b.decode('utf-8') или b.encode('utf-8')

  • 0
    stackoverflow.com/questions/22351254/… решения, упомянутые здесь, не работают?
  • 0
    Нет, они не работали. Обновленный вопрос, чтобы отразить это
Показать ещё 2 комментария
Теги:

3 ответа

2
Лучший ответ

Я думаю, что вы ищете

print(repr(a))

Для a, как определено в вашем коде, это напечатает b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00\x08 и т.д., как и исходное определение ICON, но довольно большое, потому что все \x00 и \xff в конце написаны из.


В вашем коде вы включили некоторое сжатие ad hoc (а именно + b'\x00'*1282 + b'\xff'*64). Чтобы автоматически получать сжатие, поэтому определение ICON в исходном файле не должно быть таким большим, используйте существующую библиотеку сжатия, например zlib:

import zlib
print(repr(zlib.compress(a)))

На моей машине это печатает 'x\x9cc``\x04B\x01\x01\x06 \xc9\xc1\x90\xc1\xca\xc0 \xc6\xc0\xc0\xa0\x01\xc4@!\x06\x05\x06\x888\x088\xb02 \x00#\x14\x8f\x82Q0\nF\xc1\x08\x05\xff)\x04\x00U\xf1A\x17', что довольно мало. Чтобы распаковать, используйте zlib.decompress:

import zlib

ICON = zlib.decompress(b'x\x9cc``\x04B\x01\x01\x06 \xc9\xc1\x90\xc1\xca\xc0 '
    b'\xc6\xc0\xc0\xa0\x01\xc4@!\x06\x05\x06\x888\x088\xb02 \x00#\x14\x8f\x82'
    b'Q0\nF\xc1\x08\x05\xff)\x04\x00U\xf1A\x17')

ICON теперь имеет то же значение, что и в вашем исходном примере.


Если вам требуется еще более компактное представление в исходном файле, пришло время применить кодировку base 64, которая избавится от многословной двоичной кодировки в python (\x.. -формат).

Для кодирования:

import base64, zlib

print(repr(base64.b64encode(zlib.compress(a))))

Это дает мне 'eJxjYGAEQgEBBiDJwZDBysAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4JRMApGwQgF/ykEAFXxQRc='

Чтобы декодировать:

import base64, zlib

ICON = zlib.decompress(base64.b64decode('eJxjYGAEQgEBBiDJwZDBy'
    'sAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4JRMApGwQgF/ykEAFXxQRc='))

И снова, ICON имеет то же значение, что и изначально указано.


Окончательная стратегия, представленная, хороша для файлов ico. Я вижу, что вы также упоминаете файлы png. У них уже есть сжатие, поэтому вы, вероятно, предпочли бы использовать только кодировку base 64:

import base64

print(base64.b64encode(png_icon))

и

PNG_ICON = base64.b64decode( ** insert literal here ** )

Как оказалось, эти кодировки также доступны через str.encode и str.decode. Это позволяет отключить, не записывая import s. Для полноты здесь они:

Кодировка:

print(repr(a.encode('zlib').encode('base64')))

Декодирование:

ICON = ('eJxjYGAEQgEBBiDJwZDBysAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4J'
    'RMApGwQgF/ykEAFXxQRc=').decode('base64').decode('zlib')
2

Я думаю, что вы просто не печатаете данные правильно -— Кажется, что нет необходимости возиться с base64, делая это.

Здесь доказательство:

from itertools import izip
import tempfile

# byte literal code for a transparent icon, I think
ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05\x00\x00'
        b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00'
        b'\x08\x00\x00\x00\x00\x00@\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        b'\x00\x01\x00\x00\x00\x01') + b'\x00'*1282 + b'\xff'*64

# make a temp file from ICON data for testing
_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:
    icon_file.write(ICON)

# Convert raw data in the file into a valid Python string literal.

# helper function
def grouper(n, seq):
    "s -> (s0,s1,...sn-1), (sn,sn+1,...s2n-1), (s2n,s2n+1,...s3n-1), ..."
    for i in xrange(0, len(seq), n):
        yield seq[i:i+n]

# read data file in binary mode
a = open(ICON_PATH, 'rb').read()

# create Python code to define string literal
code = '\n'.join(['ICON2 = ('] +
                 ['    '+repr(group) for group in grouper(16, a)] +
                 [')'])

print 'len(ICON): {}'.format(len(ICON))
print 'len(a): {}'.format(len(a))
print code
exec(code)
print
print 'len(ICON2): {}'.format(len(ICON2))
print 'ICON2 == ICON: {}'.format(ICON2 == ICON)

Вывод:

len(ICON): 1406
len(a): 1406
ICON2 = (
    '\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05'
    '\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00'
    '\x00\x00\x01\x00\x08\x00\x00\x00\x00\x00@\x05\x00\x00\x00\x00'
    '\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00'
    '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
       ...
    '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
    '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
    '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
    '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
    '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
)

len(ICON2): 1406
ICON2 == ICON: True
0

Ну, я понял, что вы можете сделать это так:

import tempfile, base64, io

# byte literal code for a transparent icon, I think
ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x01\x00\x08\x00h\x05\x00\x00'
        b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00'
        b'\x08\x00\x00\x00\x00\x00@\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        b'\x00\x01\x00\x00\x00\x01') + b'\x00'*1282 + b'\xff'*64

# makes a temp file for the transparent icon and saves it
_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:
    icon_file.write(ICON)

with open(ICON_PATH, 'rb') as imgFile:
    a = imgFile.read()

b = base64.b64encode(a)

print b # output does not match what ICON equals above

with open('test.png','wb') as writeFile:
    writeFile.write(b.decode('base64'))

но я все еще хочу знать, как получить тот же формат, что и "ICON = (..." вверху

Ещё вопросы

Сообщество Overcoder
Наверх
Меню