Sleepy Weim

Python: Picture Tiles that Change

If you jumped straight here, I get it. This code is for randomly selecting a photo from a directory, and saving it to a predefined location and filename. Very sexy, of course, so you couldn’t wait to get here and start running with it!

Feel free to play with the code, break things, and then go back and read the main page where I explain why I do certain things. 😉

There are four main strings to define:

  • path_src: This is the root folder where your pictures are stored
  • path_dst: This is where the selected pictures will be saved; for me this is in my web folder structure
  • thePath: the subfolder you need to pass into the function; in theory, this can be an empty string, I think; I haven’t tried that
  • theFile: the filename (without extension) that will be used to save the picture

I’m showing my code as I use it since it shows how to just call multiple iterations from one script, how to find different classifications of photos (based solely on your folder/organization structure), and how to specify the folder names.

import os
import random
from random import shuffle
from shutil import copyfile
from PIL import Image
from PIL import ExifTags

#
# path: The complete path; function will navigate up one folder
#
def stepUp(path):
    pathLength = len(path)
    loc = path.rfind('/')
    
    if pathLength == (loc + 1):
        #print 'Found the trailing slash.  Remove and repeat.'
        
        tempPath = path[:(-1 * (pathLength - loc))]
        loc = tempPath.rfind('/')
        pathLength = len(tempPath)

    tempPath = path[:(-1 * (pathLength - loc))]
    #print 'New Path: ', tempPath
    
    return tempPath

#
# img: the image object we want to inspect and manipulate
#
def correctRotation(img):
    #
    # Check orientation, and rotate if needed
    # This looks for EXIF data in the file and determines if the camera was rotated when the picture was taken
    # This can throw off the check we do for portrait vs landscape
    # 
    for orientation in ExifTags.TAGS.keys() : 
        if ExifTags.TAGS[orientation]=='Orientation' : break 

    try:
        exif=dict(img._getexif().items())

        if   exif[orientation] == 3 : 
            img=img.rotate(180, expand=True)
            #print ' -- 180'
        elif exif[orientation] == 6 : 
            img=img.rotate(270, expand=True)
            #print ' -- 270'
        elif exif[orientation] == 8 : 
            img=img.rotate(90, expand=True)
            #print ' -- 90'
    except:
        print " -- File contains no EXIF data."
    
    return img

#
# thePath: the subfolder we want to search in; the full path will be 'path_src + thePath'
# theFile: the filename we will use to save the file out to, into the the 'path_dst' location
#
def selectImageFrom(thePath, theFile):
    #
    # Get the combined path and the list of files
    #
    print 'New Loop: ', thePath
    random.seed(os.urandom(4))
    
    path_temp = path_src + thePath
    files = os.listdir(path_temp)
    
    #
    # Loop in case we keep getting invalid files
    #
    for x in range (0, 200):
        #print ' -- count: ', x, file

        file = random.choice(files)
        files.remove(file)
        
        if not files: print "-- WARNING: File list is now empty."
        
        #
        # Check if we have a file or a directory
        #
        if os.path.isdir(path_temp + file):
            print " -- found directory: PATH: ", path_temp, " FILE: ",file
            
            #
            # If dir, then descend into subdir
            # -- Adding and ignoring system folders that are bad
            #
            if file != '@eaDir':
                path_temp = path_temp + file + '/'
                files = os.listdir(path_temp)
            
        else:
            #
            # If file, then check the extension and process, or restart the loop
            #
            filename, file_extension = os.path.splitext(file)

            if file_extension.lower() == '.jpg' or file_extension.lower() == '.jpeg' or file_extension.lower() == '.png':
                #
                # The types of files we are looking for
                #
                img = Image.open(path_temp + file)
                
                img = correctRotation(img)

                #
                # For our display, we only want landscape pictures for better display
                #
                width, height = img.size
                
                if width >= height:
                    print " -- Good File: Landscape ", path_temp + file, ' Width: ', width, 'Height: ', height
                    break
                else:
                    print " --  Bad File: Portrait  ", path_temp + file, ' Width: ', width, 'Height: ', height
            else:
                #
                # The types of files we are NOT looking for
                #
                print " --  Bad File: Not JPG   ", path_temp + file
                    
        if not files: 
            #print ' -- !!!! You should move up a directory at this point. !!!!'
            path_temp = stepUp(path_temp)
            files = os.listdir(path_temp)

    newFile = theFile + file_extension.lower()
    newPath = path_dst + newFile
    
    try:
        #copyfile(os.path.join(path_temp, file), newPath)
        img.save(newPath)
    except:
        print " -- No file was selected."

    return

#
# Path Source: The main location where all the files live; all my photo folders are under this location
# Path Destination: the location in the web folder structure I will use for my URLs
#
path_src = '/volume1/files/GoogleDrive/Pictures/'
path_dst = '/volume1/web/actiontiles/'

#
# Each directory I am using; in my case I have them organized by events
# You can skip this step, but for my 'friends' folder I call it twice, so you can define a folder once but reference it many times later
#
src_running = '# Running/'
src_disney = 'Disney/'
src_friends = '# Parties, Events, Trips/'

#
# We could just put the directories straight into the function calls, but I prefer to define them above
# Since each filename will need to be different, I add them as strings right into the function call
#
selectImageFrom(src_running, 'running')
selectImageFrom(src_disney, 'disney')
selectImageFrom(src_friends, 'friends')
selectImageFrom(src_friends, 'friends2')

Leave a Reply