# code by Griffith for LLumen.Neocities.org # currently produces errors that say the server disconnected unexpectedly # I have no idea what the issue is, and it still works from PIL import Image from multiprocessing import Pool import datetime from colorsys import hls_to_rgb # the resolution of each sub-image RES = 300 # the number of sub-images (one axis; the final will be DIM by DIM) DIM = 5 imgout = Image.new("RGB", (RES * DIM, RES * DIM)) # mandelbrot value calculator class MandelGen: # configuration of the view # resolution (pixels) width=400 height=400 zoom=0.4 # location to center on x=-0.8 y=0.0 # formula settings max_steps=100 escape_radius=2.1 # number of parallel processes # works best at threads = cpu cores threads=8 # the output list data = [] # calculates the value of a single pixel def calcPoint(self, n): # locate the pixel x1 = n % self.width y1 = round(n / self.width) # convert to coordinates near the set a = (x1 / self.width - 0.5) / self.zoom # x and y mapped b = (y1 / self.height - 0.5) / self.zoom # to center a /= self.height / self.width # fix aspect ratio a += self.x # center on the set location b += self.y c = complex(a, b) # covert to complex for computation z = c out = 1 out1 = 1 for i in range(self.max_steps): z = z * z + c az = abs(z) # inside, use the minimum distance from the origin out = min(az * 2, out) # lightness out1 = min((az % 0.1) * 10, out) # hue if (az > self.escape_radius): # outside, use iterations out = pow(i % 10 / 10, 0.5) # lightness out1 = int(i / 10) / 10 # hue break # print a percentage finished every 10%(ish) if (y1 % int(self.height / 10) == 0 and x1 == self.width - 1): print(str(round(y1 / self.height * 100)) + "% finished") return (out, out1) # manages and created a parallel pool for calculating pixels def start(self): p = Pool(processes=self.threads) self.data = p.map(self.calcPoint, range(self.width * self.height)) p.close() # code start if __name__ == "__main__": startTime = datetime.datetime.now() dataList = [] for x in range(DIM * DIM): # prepare the generator print("Starting image " + str(x)) gener = MandelGen() gener.width = RES gener.height = RES # a very interesting spot to zoom into (from Wikipedia) gener.x = 0.001643721971153 gener.y = -0.822467633298876 gener.zoom = (pow(10, (x) / 2 - 1) + 0.2) gener.max_steps = 20 + x * 20 + max(x - 22, 0) * 200 gener.start() dataList.append(gener.data) colors = [] # prepare the image data for m in range(RES * DIM * RES * DIM): colors.append((0,0,0)) # fill the image data with the sub-images for u in range(DIM): for v in range(DIM): print("Packing image " + str(v + u * DIM + 1) + " of " + str(DIM * DIM)) data = dataList[u + v * DIM] for x in range(RES): for y in range(RES): cx = x + u * RES cy = y + v * RES pix = data[x + y * RES] colors[cx + cy * RES * DIM] = tuple(int(rgb * 255) for rgb in hls_to_rgb(pix[1], pix[0], 1.0)) imgout.putdata(colors) imgout.save("mandelbrot_{0}x{0}_zoom.png".format(DIM)) # imgout.save("mandelbrot_{0}x{0}_zoom.jpeg".format(DIM), progressive=True, quality=90) deltaTime = datetime.datetime.now() - startTime print("Time required: " + str(deltaTime))