I\'m trying to store an image as text, so that I can do something like this example of a transparent icon for a Tk gui:
import tempfile
# byte literal code for
Well I did figure out you can do it this way:
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'))
but I still want to know how to get the same format as 'ICON = (...' at the top
I think you're looking for
print(repr(a))
For a
as defined in your code, this will print 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
and so on, similar to your original ICON
definition, but quite large because all the \x00
s and \xff
s at the end are written out.
In your code, you have included some ad hoc compression (namely + b'\x00'*1282 + b'\xff'*64
). To get compression automatically, so the ICON
definition in your source file doesn't have to be so large, leverage an existing compression library, like zlib:
import zlib
print(repr(zlib.compress(a)))
On my machine, this prints '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'
, which is quite small. To decompress, use 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
now has the same value as in your original example.
If you now want a representation that's still more compact in your source file, it is time to apply base 64 encoding, which gets rid of the verbose binary encoding in python (the \x..
-format).
To encode:
import base64, zlib
print(repr(base64.b64encode(zlib.compress(a))))
This gives me 'eJxjYGAEQgEBBiDJwZDBysAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4JRMApGwQgF/ykEAFXxQRc='
To decode:
import base64, zlib
ICON = zlib.decompress(base64.b64decode('eJxjYGAEQgEBBiDJwZDBy'
'sAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4JRMApGwQgF/ykEAFXxQRc='))
And again, ICON
has the same value as originally specified.
The final strategy as presented is good for ico
files. I see that you also mention png
files. These already have compression applied, so you should probably prefer to use only base 64 encoding:
import base64
print(base64.b64encode(png_icon))
and
PNG_ICON = base64.b64decode( ** insert literal here ** )
As it turns out, these encodings are also available through the str.encode and str.decode APIs. This lets you off without writing the import
s. For completeness, here they are:
Encoding:
print(repr(a.encode('zlib').encode('base64')))
Decoding:
ICON = ('eJxjYGAEQgEBBiDJwZDBysAgxsDAoAHEQCEGBQaIOAg4sDIgACMUj4J'
'RMApGwQgF/ykEAFXxQRc=').decode('base64').decode('zlib')
I think you're just not printing out the data properly — there doesn't seem to be any need to mess around with base64
doing this.
Here's proof:
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)
Output:
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