0

I have a proof of concept in Python where it just keeps redrawing a window, keeps track of the time, and removes images as the time passes. This seems fine, but feels clunky, not sure I trust this to run if there were 1000 images. Example shared below.

Regardless, is there a better way to do this with another language? If so, anyone got an example?

import pygame
import win32api
import win32con
import win32gui
import time
import random

class testHug():

    def __init__(self):
        
        pygame.init()

        
        self.screen_width = 800
        self.screen_height = 600
        self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
        self.hwnd = pygame.display.get_wm_info()["window"]
        
        win32gui.SetWindowLong(self.hwnd, win32con.GWL_EXSTYLE, win32gui.GetWindowLong(
                            self.hwnd, win32con.GWL_EXSTYLE) | win32con.WS_EX_LAYERED)
        
        win32gui.SetLayeredWindowAttributes(self.hwnd, win32api.RGB(255, 0, 128), 0, win32con.LWA_COLORKEY)


        self.screen.fill((255, 0, 128))
        pygame.display.flip()
        

        self.image_list = [
            pygame.image.load("image.png"),
            pygame.image.load("image2.png"),
            pygame.image.load("image3.png")
        ]

        self.duration = 4000 

        self.killtime = 10000

        self.current_ticker_time = pygame.time.get_ticks()

        self.image_dict = {'user1' : {'image': pygame.image.load("image.png"), 'shown':0, 'starttime': self.current_ticker_time, 'widthmodifier': random.randrange(-350,350), 'heightmodifier': random.randrange(-250,250)} }        

        

        self.current_ticker_time = pygame.time.get_ticks()

        self.image_dict['user2'] = {'image': pygame.image.load("image2.png"), 'shown':0, 'starttime': self.current_ticker_time, 'widthmodifier': random.randrange(-350,350), 'heightmodifier': random.randrange(-250,250)}

        

        self.current_ticker_time = pygame.time.get_ticks()

        self.image_dict['user3'] = {'image': pygame.image.load("image3.png"), 'shown':0, 'starttime': self.current_ticker_time, 'widthmodifier': random.randrange(-350,350), 'heightmodifier': random.randrange(-250,250)}

        

        self.current_ticker_time = pygame.time.get_ticks()

        self.image_dict['user4'] = {'image': pygame.image.load("image4.png"), 'shown':0, 'starttime': self.current_ticker_time, 'widthmodifier': random.randrange(-350,350), 'heightmodifier': random.randrange(-250,250)}

                        

       


        self.running = True

    def processImages(self, user, image):
        self.current_ticker_time = pygame.time.get_ticks()
        self.image_dict[user] = {'image': pygame.image.load(image), 'shown':0, 'starttime': self.current_ticker_time, 'widthmodifier': random.randrange(-350,350), 'heightmodifier': random.randrange(-250,250)}
        
        self.image_index = 0

        while self.running:
            
            elapsed_time = pygame.time.get_ticks() - self.current_ticker_time

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False
            
            if elapsed_time >= self.killtime and self.image_index >= len(self.image_dict):
                break
            
            if elapsed_time >= self.duration and self.image_index < len(self.image_dict):
                self.image_index += 1    
                self.screen.fill((255, 0, 128)) 
                pygame.display.flip()
                
                for x in range(0, self.image_index):
                    
                    if (self.image_index <= len(self.image_dict)):

                        imageToGrab = "user"+ str(x+1)

                        if self.image_dict[imageToGrab]["shown"] == 0:
                            self.image_dict[imageToGrab]["starttime"] = pygame.time.get_ticks()
                            self.image_dict[imageToGrab]["shown"] = 1


                        imageElapsedTime = pygame.time.get_ticks() - int(self.image_dict[imageToGrab]["starttime"])
                        
                        print("starttime, imageElapsedTime, and imageToGrab", self.image_dict[imageToGrab]["starttime"], imageElapsedTime, imageToGrab)
                        
                        if imageElapsedTime < (self.duration * 2.5):
                            image_rect = self.image_dict[imageToGrab]["image"].get_rect()
                            image_rect.center = ((self.screen_width / 2)+self.image_dict[imageToGrab]["widthmodifier"], (self.screen_height / 2)+self.image_dict[imageToGrab]["heightmodifier"])
                            self.screen.blit(self.image_dict[imageToGrab]["image"], image_rect)

                pygame.display.flip() #redraw screen

                self.current_ticker_time = pygame.time.get_ticks()

        pygame.quit()


if __name__ == '__main__':
    th = testHug()
    th.processImages('user5', "image5.png")

1 Answer 1

1

If I'm understanding your goals correctly, it may be easier to load your images into self.image_list programmatically, instead of explicitly loading them line by line. You could even store all of your images in one place, like an images file, for example, and read it using os.listdir() to read each image one by one. It might look something like this (consider that this is psuedo-code):

import ... # your imports here
from os import listdir, path # use this to read every file in a directory

class testHug():

    def __init__(self):
    
        ... # your pygame window setup code here

        # create this as an empty list instead
        self.image_list = [] 

        # set this to your images file path, directory, etc.
        images_file_path = "\directory\to\your\images"     

        # gives you a list of filenames in the image folder
        images_in_file = os.listdir(images_file_path) 

        # for each image file found in your folder
        for _image in images_in_file: 
            # use path.join to connect the images folder directory
            # to the individual image file's name
            full_image_path = path.join(images_file_path, _image)
            # load the image file
            _loaded_image = pygame.image.load(full_image_path)
            # add your newly loaded image to the image list
            self.image_list.append(_loaded_image)

From there, with your self.image_list now created, you can do a similar loop to apply your random timed events and put each image into a dict:

# like before, create the image_dict as an empty dict
self.image_dict = {}
# for every image loaded into the self.image_list
# we use an i-iterating loop instead of an access loop
for i in range(len(self.image_list)):
    # set the current ticker time
    self.current_ticker_time = pygame.time.get_ticks()
    # create your dictionary entry's key ("user1", "user2", etc)
    dict_key = "user" + str(i + 1)
    # create your image dict key:value pair like you did originally
    # however, difference is that you will use the already loaded image
    #  instead of loading it again...
    new_pair = {dict_key : 
        {'image': self.image_list[i], 
         'shown': 0, 
         'starttime': self.current_ticker_time, 
         'widthmodifier': random.randrange(-350,350), 
         'heightmodifier': random.randrange(-250,250)
        } 
    }
    # add the new key:value pair to the dictionary
    self.image_dict[dict_key] = new_pair

# self.image_dict now holds a dict key:val pair 
# for every image you load in your images file

Now, your concern about image quantity is valid. Loading all of these images into memory all at once would get pricey on hardware. However, what's your use case for this program? Do you think you'll ever actually use it on 1,000 images? If so, then this would surely crash a good portion of machines running the program... But, this code would likely be capable of running on an upwards of 100-200 images (assuming they are not insanely large image files). Is this satisfactory for how you plan to use your program?

If you do want to use this for a large amount of images, you would probably want to change this to load a single image at once, create the ticker, and unload that image after it has reached the end of its showing time. This way, you could have 100 billion images in a file (crazy, I know) but only ever load one, which pretty much any computer can easily handle.

I hope this is helpful and I understood your goal correctly. Let me know!

Sign up to request clarification or add additional context in comments.

2 Comments

This is helpful, one thing I should probably of mentioned is that the images will be from links, not from a local folder. That's just for the P.O.C., though, I guess I should of just used links in the P.O.C. to make that more clear.
@mud_punk In that case, you could list the links out in a Py list (like image_links = [link1, link2, ... linkn]) and run your loop over the links instead of the folder. The only difference would be loading the links onto each separate POC machine and then creating the code to GET the image -- using the Python requests library here -- from the link instead of pulling it from native storage.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.