Created
December 13, 2012 21:52
-
-
Save agrif/4280301 to your computer and use it in GitHub Desktop.
a mandelbrot set renderer using the Overviewer dispatcher
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python2 | |
import sys | |
sys.path += ["../../"] | |
from PIL import Image | |
from math import log, ceil | |
import os | |
from overviewer_core.dispatcher import MultiprocessingDispatcher | |
from overviewer_core.observer import ProgressBarObserver | |
class Renderer(object): | |
def get_size(self): | |
raise NotImplementedError("Renderer.get_size") | |
def render(self, origin, im): | |
raise NotImplementedError("Renderer.render") | |
class MandelbrotSet(Renderer): | |
def __init__(self, size, iterations, palette): | |
self.size = size | |
self.iterations = iterations | |
self.palette = list(Image.open(palette).getdata()) | |
self.palsize = len(self.palette) | |
def get_size(self): | |
return (self.size, self.size) | |
def _get_color(self, n, z, bound): | |
nu = n - log(log(abs(z), bound), 2) | |
nu = nu * self.palsize | |
intpart = int(nu % self.palsize) | |
fracpart = nu % 1 | |
a = self.palette[intpart] | |
b = self.palette[(intpart + 1) % self.palsize] | |
color = [int(x * (1.0 - fracpart) + y * fracpart) for (x, y) in zip(a, b)] | |
return tuple(color) | |
def render(self, origin, im): | |
for x in xrange(im.size[0]): | |
for y in xrange(im.size[1]): | |
point = [2 * float(2 * i - self.size) / self.size for i in (x + origin[0], y + origin[1])] | |
z = 0 | |
c = complex(*point) | |
in_set = True | |
for i in xrange(self.iterations): | |
if abs(z) > 2.0: | |
# we do escape, colorize this | |
in_set = False | |
im.putpixel((x, y), self._get_color(i, z, 2.0)) | |
break | |
z = z ** 2 + c | |
if in_set: | |
# we do not escape, make this black | |
im.putpixel((x, y), (0, 0, 0, 255)) | |
class SimpleCanvas(object): | |
region_size = 256 | |
def __init__(self, renderer, output): | |
self.renderer = renderer | |
self.output = output | |
self.size = renderer.get_size() | |
self.numx = int(ceil(float(self.size[0]) / self.region_size)) | |
self.numy = int(ceil(float(self.size[1]) / self.region_size)) | |
def get_num_phases(self): | |
return 2 | |
def get_phase_length(self, phase): | |
if phase == 0: | |
return self.numx * self.numy | |
return 1 | |
def iterate_work_items(self, phase): | |
if phase == 1: | |
# do the one final thing | |
yield (None, []) | |
else: | |
# do all the regions | |
for x in xrange(self.numx): | |
for y in xrange(self.numy): | |
yield ((x, y), []) | |
def do_work(self, item): | |
if item is None: | |
bigim = Image.new("RGBA", self.size) | |
for x in xrange(self.numx): | |
for y in xrange(self.numy): | |
path = self.output + '.' + str(x) + '.' + str(y) + '.png' | |
im = Image.open(path) | |
bigim.paste(im, (x * self.region_size, y * self.region_size)) | |
os.remove(path) | |
bigim.save(self.output) | |
return | |
x, y = item | |
origin = (x * self.region_size, y * self.region_size) | |
size = tuple([min([self.size[i] - origin[i], self.region_size]) for i in range(2)]) | |
im = Image.new("RGBA", size) | |
self.renderer.render(origin, im) | |
im.save(self.output + '.' + str(x) + '.' + str(y) + '.png') | |
if __name__ == "__main__": | |
r = MandelbrotSet(10000, 100, "palette.png") | |
c = SimpleCanvas(r, "output.png") | |
d = MultiprocessingDispatcher() | |
observer = ProgressBarObserver() | |
observer.UPDATE_INTERVAL = 1 | |
d.render_all([c], observer) | |
d.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment