#!/usr/bin/env python """ collage.py 2009 Simon Davies. Do what you want with code. """ from PIL import Image # Imaging module: http://www.pythonware.com/products/pil/ from PIL.ExifTags import TAGS from math import sqrt import glob, os import sys import getopt """ If we have 9 images - then the collage picture needs to be a 3x3 image square If we have 15 images - then need to find the next largest square value - 16, so collage picture needs to be 4x4 (one blank square) """ def findNextSquare(n): squares = [ x*x for x in range(1,100) ] saveVal = 0 #print squares for x in squares: #print x, n if saveVal > 0 and saveVal < x: return sqrt(saveVal) elif n == x: return sqrt(n) elif n < x: saveVal = x def get_exif_orientation(i): ret = {} orientVal =0 info = i._getexif() for tag, value in info.items(): decoded = TAGS.get(tag, tag) ret[decoded] = value # only after the orientation tag value if decoded == "Orientation": try: orientVal = ret["Orientation"] except: # do nothing much orientVal = 0 break return orientVal def walkDir(startDir, fileList): directories = [startDir] while len(directories)>0: directory = directories.pop() for name in os.listdir(directory): fullpath = os.path.join(directory,name) if os.path.isfile(fullpath): if fullpath.endswith(".JPG") or fullpath.endswith(".jpg"): fileList.append(fullpath) # It's an image elif os.path.isdir(fullpath): directories.append(fullpath) # It's a directory, store it. def processFiles(inDir, thumbSize=50): #thumbnail sizes thumbX = thumbSize thumbY = thumbSize #find out how many images are in the directory totalFiles = 0 fileList = [] walkDir(inDir, fileList) totalFiles = len(fileList) #for a perfect square - need to find out how many images are needed per row/column spacing = findNextSquare(totalFiles) print "Creating an image %i by %i" % (spacing, spacing) size = spacing * thumbX, spacing * thumbY #coordinates for image paste x = 0 y = 0 count = 1 # master image out = Image.new("RGB", (thumbX * spacing, thumbY * spacing), "white") for infile in fileList: print "Adding %s, [%i of %i]" % (infile, count, totalFiles) im = Image.open(infile) #NOT WORKING YET - need to rotate image, if EXIF orientation tag is set e.g: "Image Orientation Rotated 90 CW" orientVal = get_exif_orientation(im) if orientVal == 6: # 90 CCW im = im.rotate(-90) elif orientVal == 8: # 90 CW im = im.rotate(90) # Crop image to a square, that will then form a square thumbnail, instead of a rectangular one. cropx = im.getbbox() xc = cropx[2] xy = cropx[3] # rectangle? if xc <> xy: if xc > xy: xc = xy else: xy = xc #crop to largest square possible im = im.crop( (0, 0, xc, xy) ) im.thumbnail((thumbX,thumbY), Image.ANTIALIAS) out.paste(im, (x ,y)) # alter position for next image, going to next row if necessary. x = x + thumbX if x >= thumbX * spacing: x = 0 y = y + thumbY count = count+1 out.save("out.png") def main(argv=None): if argv is None: argv = sys.argv if len(argv) == 2: inDir = argv[1] processFiles(inDir) else: print "Please provide the full path to directory containing images (*.jpg)" if __name__ == "__main__": sys.exit(main())