Я пытаюсь сохранить изображение как текст, так что я могу сделать что-то вроде этого примера прозрачного значка для 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')
Я думаю, что вы ищете
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')
Я думаю, что вы просто не печатаете данные правильно -— Кажется, что нет необходимости возиться с 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
Ну, я понял, что вы можете сделать это так:
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 = (..." вверху