import itertools import Image GOLDEN_RATIO = 1.618033989 OFFSET_RULES = [(0, 1), (1, 1/GOLDEN_RATIO/GOLDEN_RATIO), (1/GOLDEN_RATIO/GOLDEN_RATIO, -1/GOLDEN_RATIO), (-1/GOLDEN_RATIO, 0)] def scalars(size): while size >= 0.5: yield int(round(size)) size0 = size size /= GOLDEN_RATIO size = size def offsets(width): yield (0, 0) sizes = scalars(width) left = top = 0 for size, rule in itertools.izip(sizes, itertools.cycle(OFFSET_RULES)): left += rule[0] * size top += rule[1] * size yield (int(round(left)), int(round(top))) def tilestream(im): width, height = im.size assert width == height tiles = itertools.cycle([im.copy(), im.transpose(Image.ROTATE_90), im.transpose(Image.ROTATE_180), im.transpose(Image.ROTATE_270)]) sizes = scalars(width) for tile, size in itertools.izip(tiles, sizes): yield tile.resize((size, size), Image.ANTIALIAS) if __name__ == '__main__': import sys infile, outfile = sys.argv[1:] iheart = Image.open(infile) tiles = tilestream(iheart) width = iheart.size[0] height = int(round(iheart.size[1] * GOLDEN_RATIO)) positions = offsets(width) iheartfractals = Image.new(mode=iheart.mode, size=(width, height), color=(255, 255, 255)) for tile, pos in itertools.izip(tiles, positions): iheartfractals.paste(tile, pos) iheartfractals.save(outfile)