#!/usr/bin/env python # Image Splitter for GSV - (non-Zoomifyer edition) # imageSplitterGSV.py is BSD-licensed. __version__ = '1.1' usage = """\ usage: %prog [options] example: %prog -f image.tif You can also import this module and pass an options class to splitImage, like this: class SplitOptions: def __init__(self): self.blockSize = 512 self.jpegQuality = 88 self.verbose = True self.dirName = os.path.join(tilesDir, fileBaseName) self.filename = jpeg splitOptions = SplitOptions() return imageSplitter.splitImage(splitOptions) # This returns the max zoom level """ # Last modified: Aug. 27, 2006 from __future__ import division import PIL.Image, os, sys, math, optparse, shutil def debug(msg): if options.verbose == True: sys.stdout.write(msg) sys.stdout.flush() def warning(msg): sys.stdout.write(msg) sys.stdout.flush() from optparse import OptionParser parser = OptionParser(usage=usage, version="%prog " + __version__) parser.add_option("-f", "--file", dest="filename", metavar="FILE", help="Input image for splitting. The recommended formats are TIFF, JPEG, PNG, and BMP. Formats listed at www.pythonware.com/library/pil/handbook/formats.htm may also be supported.", default=None) parser.add_option("-d", "--dir", dest="dirName", metavar="DIR", help="Output directory for image blocks and metadata. The default is the filename without the extension. Do not specify any slashes.", default=None) parser.add_option("-b", "--block", dest="blockSize", default=512, metavar="PX", help="Block size in pixels, default: 512. The value should be in multiples of 32 for JPEG processing. Try 512 or even higher for large, full-screen Flash objects.") parser.add_option("-q", "--quality", dest="jpegQuality", default=85, metavar="QUALITY", help="JPEG Quality of output blocks, from 1-100.") parser.add_option("-s", "--silent", action="store_false", dest="verbose", default=False, help="Don't print processing messages to stdout") def splitImage(options): imageFile = options.filename if imageFile == None or imageFile == "": print "An image file was not specified (option -f), printing --help...\n" parser.print_help() sys.exit() elif not os.path.isfile(imageFile): raise IOError, "File '%s' does not exist." % (imageFile) blockSize = int(options.blockSize) jpegQuality = int(options.jpegQuality) if options.dirName == None: dirName = imageFile[:imageFile.rfind(".")] else: dirName = options.dirName if os.path.isdir(dirName): warning("""\ WARNING: Directory '%s' already exists! Will proceed anyway, but if the tile size has changed you must delete the directory and re-run the program.\n """ % dirName) else: debug("Creating directory '%s'.\n" % dirName) os.mkdir(dirName) debug("Block size: %dx%d pixels\n" % (blockSize, blockSize)) debug("JPEG Quality: %d\n" % jpegQuality) debug("\n") debug("Loading original.\n") # image Handle iH = PIL.Image.open(imageFile) width, height = iH.size largestCoord = max(width, height) # divide to find # of levels levelsNeeded = 0 levelsDict = {} currentSize = largestCoord while True: currentSize /= 2 levelsNeeded += 1 if currentSize <= blockSize: break debug("Levels needed: 0..%d\n" % levelsNeeded) currentLevel = levelsNeeded # split full-size image first if not os.path.isdir(dirName): os.mkdir(dirName) currentWidth = width currentHeight = height numBlocks = 0 while currentLevel >= 0: levelsDict[currentLevel] = {} if currentWidth != width or currentHeight != height: debug("Resizing original to %dx%d.\n" % (currentWidth, currentHeight)) ciH = iH.resize((currentWidth, currentHeight), PIL.Image.ANTIALIAS) else: ciH = iH debug("Generating blocks for %dx%d image.\n" % (currentWidth, currentHeight)) blocksWidth = int(math.ceil(currentWidth / blockSize)) blocksHeight = int(math.ceil(currentHeight / blockSize)) currentTileGroup = 0 for blockVert in range(blocksHeight): levelsDict[currentLevel][blockVert] = {} for blockHoriz in range(blocksWidth): if not 'dimensions' in levelsDict[currentLevel]: levelsDict[currentLevel]['dimensions'] = (blocksWidth, blocksHeight) minCornerX = blockSize * blockHoriz minCornerY = blockSize * blockVert maxCornerX = min(minCornerX + blockSize, currentWidth) maxCornerY = min(minCornerY + blockSize, currentHeight) debug(".") #if (numBlocks % 256) == 0: # currentTileGroup += 1 # os.mkdir("%s/TileGroup%d" % (dirName, currentTileGroup)) levelsDict[currentLevel][blockVert][blockHoriz] = ciH.crop((minCornerX, minCornerY, maxCornerX, maxCornerY)) levelsDict[currentLevel][blockVert][blockHoriz].load() levelsDict[currentLevel][blockVert][blockHoriz].save("%s/%d-%d-%d.jpg" % (dirName, currentLevel, blockHoriz, blockVert), "JPEG", quality=jpegQuality) numBlocks += 1 del levelsDict[currentLevel][blockVert][blockHoriz] debug("\n") debug("\n") # replace with reducer currentLevel -= 1 currentWidth = int(math.floor(currentWidth / 2)) currentHeight = int(math.floor(currentHeight / 2)) debug("Done writing %d blocks.\n" % (numBlocks)) return levelsNeeded if __name__ == '__main__': (options, args) = parser.parse_args() splitImage(options)