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 \x00s and \xffs 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 imports. 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