pyimg was written as a learning project. I wanted to clone the functionality of taimg in Python. I chose to recreate taimg because it is something I use frequently and it has very clear requirements.
Written for Python > 2.0 and imagemagick > 6.0
#! /usr/bin/env python import sys, os, commands, glob def main(args): """pyimg: python-based gallery control for Obscura Usage: pyimage [index|conv] {arguments} Example: Create image index for current directory $ pyimg index "title" "location" "date" Example: Call imagemagick to create thumbnails etc $ pyimg conv """ # Set conversion options options_sq = "-quality 95 -density 72x72 -resize 300 -crop 125x125+20+20 -bordercolor white -border 1x1" options_vert = "-quality 100 -density 72x72 -resize x500" options_hor = "-quality 100 -density 72x72 -resize 500" # Set default information defaultTechnical = "Canon T70" defaultCopyright = "Copyright © 2005, Steve Block" if args[0] == "index": print "Generating index..." write_cat(defaultTechnical, defaultCopyright, args[1:]) elif args[0] == "print": print_cat() elif args[0] == "conv": print "Converting images..." convert(options_sq, options_vert, options_hor) else: print main.__doc__ class Cat(file): "Manipulate a catfile" # Writes an individual record to the cat file following the formatting # convention used by Obscura def write_record(self, thisfile, args, defaultTechnical="Canon T70", \ defaultCopyright="Copyright © 2005, Steve Block"): self.write("%s|%s|%s|%s|%s\n" % (thisfile, args[0], defaultTechnical, \ defaultCopyright, "|".join(args[1:]))) # Reads a line from the cat file and returns a tuple containing all the # useful information from the file. If the line is blank (last line), # return None def read_record(self): line = self.readline() line = line.strip() if line != '': (filename,title,tech,copy,location,date) = line.split("|") return (filename,title,tech,copy,location,date) else: return None # Prints the contents of the cat file to the screen. Unformatted. def print_cat(self): for line in self.readlines(): line = line.strip() print line.split("|") def write_cat(defaultTechnical, defaultCopyright, args): """Creates a file named index.cat in the current directory The index.cat file contains a list of files and attributes for the image files in a directory. Each line of the file represents a single jpeg image. The format of each line is: file|title|technical|copyright|location|date """ # Check that the right number of arguments has been passed if len(args) != 3: print main.__doc__ return -1 # Create and sort a list of jpeg files in the current directory files = glob.glob('*.jpg') files.sort() # Take that directory list and create the index.cat file this_cat = Cat("index.cat", "w") for this_file in files: this_cat.write_record(this_file[:-4], args, \ defaultTechnical, defaultCopyright) this_cat.close() def print_cat(filename="index.cat"): "Reads a cat file and prints the contents." this_cat = Cat(filename, "r") this_cat.print_cat() this_cat.close() def convert(opt_s,opt_v,opt_h,filename="index.cat"): "Reads a catfile and calls imagemagick to perform conversions" # Check for existence of the scale directory and create it if it doesn't # exist. if not os.path.exists("scale"): os.mkdir("scale",0755) # Open the cat file this_cat = Cat(filename, "r") # Read the first record from the file, and begin a loop that will continue # until the last record in the file is reached. The loop will create # pathnames and call imagemagick's convert script to do the file # conversions. record = this_cat.read_record() while record != None: (filename,title,tech,copy,location,date) = record record = this_cat.read_record() # Generate filenames obs_file = "scale/%s-obs.jpg" % filename sq_file = "scale/%s-sq.jpg" % filename # Call convert to create the square file if it doesn't already exist if not os.path.exists(sq_file): commands.getstatusoutput("convert %s.jpg %s %s" % \ (filename, opt_s, sq_file)) # Determine the image dimensions (w,h) = jpgSize("%s.jpg" % filename) # Perform conversion if not os.path.exists(obs_file): if h > w: print "Making %s, original %i x %i, height mode." % \ (obs_file, w, h) commands.getstatusoutput("convert '%s.jpg' %s '%s'" % \ (filename, opt_v, obs_file)) else: print "Making %s, original %i x %i, width mode." % \ (obs_file, w, h) commands.getstatusoutput("convert '%s.jpg' %s '%s'" % \ (filename, opt_h, obs_file)) def jpgSize(jpeg): markers = '\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf' # Check image format. Make sure it is a jpg image = file(jpeg, mode="rb") if image.read(2) != '\xff\xd8': image.close() return -1 while 1: frame_header = image.read(2) if frame_header == '': image.close() return -1 boundary, marker = frame_header if boundary != '\xff': image.close() return -1 found = 1 for this_marker in markers: if marker == this_marker: found = 0 break if found == 0: break frame_length = image.read(2) if frame_length == '': image.close() return -1 frame_length = s2n(frame_length) image.seek(frame_length - 2,1) image.seek(3,1) height = s2n(image.read(2)) width = s2n(image.read(2)) image.close() return (width,height) def s2n(string): x = 0 for c in string: x = (x << 8) | ord(c) return x if __name__ == "__main__": if len(sys.argv) > 1: main(sys.argv[1:]) else: print main.__doc__