Esa T. H. Esa T. H. - 7 months ago 49
Python Question

How can I pack images? -Pygame -PyInstaller

So I got

main.py
which I turn into
main.exe
through PyInstaller
--onefile
, but
main.exe
still needs image file
img.png
in
\data
folder which is located in same folder as
main.py/main.exe
...

img_l = pygame.image.load(os.path.join('data', 'img.png'))
screen.blit(img_l, (0, 0))


How can I pack these images correctly? I've been messing around for a while now with
pygame.image.tostring
and then trying to save that into
.txt
file so I can use that
.txt
file in
data
folder instead of
img.png
, from which then I could use
pygame.image.fromstring
(maybe) but I have not figured out how to make it work.

I am not even sure if it is the right/ok way to go about it.

Any ideas/suggestions sincerely appreciated.

jDo jDo
Answer

I don't know much about the fromstring and tostring methods but you could always include the images as base64 data. Pygame seems to need an actual image file and not just a blob of binary data so in the example below, I've included 3 small icons as base64 strings that get written to files in a sub-folder named "data". The filenames are then passed to pygame.image.load().

I tested the demo below with pyinstaller --onefile filename.py and it worked fine without any manual changes to settings/specs/paths etc.

import os
import hashlib
import pygame
import time
import base64

def create_assets(asset_dict, asset_dir):

    """ 
    hand this function a dictionary of assets (images, mp3s, whatever)
    and an absolute path to the data/asset folder. 
    The function creates the folder and files from the base64 strings
    if they don't exist. If the files exist, an md5 check is run
    instead to ensure integrity 
    """

    first_run = False
    if not os.path.isdir(asset_dir):
        os.mkdir(asset_dir)
        first_run = True
    for label in asset_dict:
        asset = asset_dict[label]
        filename = os.path.join(asset_dir, asset["filename"])
        rewrite = False
        # no need to check file if we just created the data folder
        if not first_run:
            if not os.path.isfile(filename):
                # the file doesn't exist
                rewrite = True
            else:
                # file exists - make sure it's intact via md5
                with open(filename, "rb") as f:
                    if not hashlib.md5(f.read()).hexdigest() == asset["md5"]:
                        # the filename exists but the contents is wrong
                        rewrite = True
        if first_run or rewrite:
            # one of our checks failed or first run - write file
            print ("Writing file: ",filename)
            with open(filename, "wb") as f:
                f.write(base64.b64decode(asset["data"]))
        else:
            print ("File exists: ",filename)


""" 
This the data dictionary. It's very easy to save 
the whole thing as json should you feel like it.
The images are just small, random icons at the moment 

"""

assets = {
    "background": {
        "filename": "bg1.png", 
        "data": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACOUlEQVQ4je2VQUhTcRzHP3szJyHiwbH5aCzpMCJ6NHIjWmzFtCBwKkEX7RYN2g4eAyF2jLRLzE5GoIegOgQNEarJCBwtYeQgPEQ0dC+fDNK5yFD3OuR7zL13WNCx7/ED3x8/vr8/379FVVWVA5WVZZY/TCEXMxxtdxLou082PU61sgpgYKI7hFzM4BD99A/PACBog9KpKPMvruvDwpEnlJUC4YFp2jtcpkzyxQBQ5BxKKQeANdj7LZHPTrK9VQTA7vTiD95lfe09+ewEtrZOTp29xbHjlwysyyFR3iiwvVXkR6XEiZPDtMjFjD5I8sfpdgV4OdtPeGCa/b2f9HgGWUhFqdV2DSwyMofkiyEXM/qWgt3pJRx5zJVrT+l2BQCoVlZ5++omojvIQipKZfOLKQPockiI7hAAy7kkltmkRzU7QLNq9ApmYQMIwhEkXxyr1aabG5mZ1/ow+SzRGPbnT8853XsbyR9HEFpZX1sEMLCLVx8ZDmUNnPma8J4bw9bWSY9nkHfzY/za+U5Z+YggtFJYmqJW2z14p4fZhrxEo9cym/So7R0uLlx+wOKbO3rYzarRKwDUarvs7+3om/yNGr3/j/IPjiK6Q1Qrq+QXJ4mMzDEaW9Hz6R+a0TM1Y6OxFYZuvKbLIXG+7x6iO4RgVkHN1tefGA5Xn0VVVTWdih4qSqWUo6wUyGcnkHxxRHeQ/b0dA9PKWJPd6aUFMFRQNj3eVH1peddXn0X7Auq3VOScIWyzA9QP0vQbENbTigXxO1gAAAAASUVORK5CYII=",
        "md5": "12f7eb2eea8992a2644de649dfaf00b3"
        },
    "player_sprite": {
        "filename": "player_img.png", 
        "data": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACh0lEQVQ4jZWUS2gTURiFv5lkmiZpk5KmNWmbIFratLWlCiq2blwILly4EFSsG3EjCK5EFITiQhFXbgRBXbXgouBe3GkRKTaYvtLWR01sa5M0j8nDpK9xEWZIwqStZ3nuzLmX/7v3CIE7HxR5KobvwUkaB9wApAIx7H1O5h5+Jv5pFYAjT05r3maygHfIR8OxZlTJs+uERoKI3iEf1kN2HKdc2mJoJEjme1ILK/WyP1IcvNFTFpZfy7H0coaUP4qgKIqSC6exeOrJr2YxuSxM3x1nM5Hn7+8MpTK31Wme/WgTnsud2Puc2npyMlIMVI3p++O0XDiM44SLVCDGt2d+8itZdpOt10n77X7MrXUAGEtnkPJH2c5uItlNLI8t7hlW19FA68V2alusmickv0aVSgD7lR4oUQ8AgGAU8Vz1IdaIVT09UIabg9eHo+9DbMkbZYGeK514h3wIkkjKH9X1CpEcciBGfjVL5F0IeXa9CEUPgFgj4rnWRXg0yE5+u6pXKUEOxpXwaJDExNp/za+ahI/n3ip7f7a36rscRShVd9oHFFWmZosGxWjrdSJPxYoLLguFPzkA2i51FHesNfDr1UxVD6AQybHw9AtmtxXD8/HXw/Y+J/LsOu23+tlKb5BfyZKZjyNIIuHRIMpWcSp6nirfveNkFpIY0/MJlscWkRpMxXtklUhMrLGzsVN2CkDXU+en/lv2ltUKUu9dNakAwm8WqKw+7S2rFZSei+8apgKwdTciGEV+vpgqqz7tLatKTka0naEclBbqsmB2W+l5NEhl9RnOLw0MpwIxbN0OJFsNtW4rB8560QOlSgXQdMaDZDcBEHw8gWSrwahXQdVAVQIonb1aff8A8A1zY9iTMCcAAAAASUVORK5CYII=",
        "md5": "79f25f0784a7849415f9c3d0d9d05267"
        },
    "weapon": {
        "filename": "sword1.png", 
        "data": "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACzUlEQVQ4jZWVX0hTYRjGfydHZJb5J03SrIarrQaNEhKERgT25yaiIjEGQUWB0U03BUHWRVS3BUUOHGkUFg2LjW5bQkUjs6bNHcskJZRVplHTzs7bxdphy0Ot5+Ycnu99n3O+5/l4P+Q32u7FxO0JyOWOPvkbWjujouu68e72BOTqrX5j3UIG9mxdQXOTA4BI7AvB0Aca6itxOUoNruPBW5y2Yupc5RzauxoALakbGkrbvZgA1FQXUr++HEVR8PlVfH7VKGrcYeVoo51L3lcEQyNsql3CueMbjPWnL8eJDn0FIG9i7raWmuWF7G5YgaIoALgcpThtRWiacGSfnZ1bqlEUhYJ8Cw+7Rzm8dzXVSxcYglUVBYQjcW50DcLljj7Dk1zwt/rWzqgoIiL8gSs3+4m+myCiTmC3LqJ27WISM8lZXNpD750BDu5ZldqhiMjrgc9ysbVXevrjIiJy5Ey36Louw6NTouu6nLjwzJRL97o9AXnSM5ZKOTOAYGiExh1Wou++MjQyhXVZIeOffhDuiwOYcsHQB+NZ5yrHcmCXDaetiOCjERrqK9m4roxwJM7KqoWMf/pBeWk+LnsJ375rsziAhvpKgqFUL4Cph9duv2FweIpwXxyXvQSXo5TEtDaLO7DLZnje3ORAURTmpEW8dwZIa2tJITGjAZCYSaJpuimXxrH9a4wjh5mx/xtKZqAWM2NzDcUsUIuZsTXVhTmFYhaoEUqmsf8bShZaO6M5japc0N6lSt7kvO0tmqazfu3irA9FYl+44H2Fw1pEVUWBwfn8KgX5FirK5mfVd9wfxHs3Rt7JU6dbdBE0TYxGAJ9fRR2eZOZnks0bl+Lzq5y/3os6PMnD7lES00lqnamfCEfivB+dwmkrTh0bkdTEztx+T39c3J6APA5/NLjnr8fl7JUX8qRnzLCivUvNmthZgm5PIEv0X6OtvUuddQX8Ag5COzDf7kUwAAAAAElFTkSuQmCC",
        "md5": "92485d36b8ac414cc758d9a6c6f28d23"
        },
}

# get absolute path to asset directory
asset_dir = "data"
asset_dir_path = os.path.join(os.getcwd(), asset_dir)

# create files in asset directory using the assets dictionary
create_assets(assets, asset_dir_path)

pygame.init()

WIDTH = 800
HEIGHT = 600

SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))

loaded_images = {}

# initalize/load all the newly created images
for label in assets:
    file_path = os.path.join(asset_dir_path,assets[label]["filename"])
    loaded_images[label] = pygame.image.load(file_path)

pos1 = 0
pos2 = 0
t_start = time.time()

while time.time() - t_start < 5:
    for img in loaded_images:
        SCREEN.blit(loaded_images[img], (pos1, pos2))
        time.sleep(0.2)
        pos1 += 20
        pos2 += 20
        pygame.display.update()

I turned the images into base64 strings like so:

import base64

with open(img_input, "rb") as f:
    with open(img_output_b64, "wb") as f2:
        f2.write(base64.b64encode(f.read()))