convert image to byte literal in python

后端 未结 3 420
迷失自我
迷失自我 2021-01-22 21:13

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          


        
相关标签:
3条回答
  • 2021-01-22 21:48

    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

    0 讨论(0)
  • 2021-01-22 21:52

    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')
    
    0 讨论(0)
  • 2021-01-22 21:54

    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
    
    0 讨论(0)
提交回复
热议问题