The low resolution version generated by our app is nice for the CLI, but not enough to grasp the
infinite complexity of the Mandelbrot set. To achieve this, we’ll need the resolution and versatility
of digital images.
Both CLI and image representations have something in common: for every pixel, we know if they are part of the
Mandelbrot set. Let’s use this to create a new structRepresentation that handles the state of every pixel
using a two dimensional array:
This type will help us setting and getting the state of every pixel. Let’s make use of it by generating a
Representation from the structConfig; it’s the same double loop used in the main method,
but instead of printing the output, we save the info in the new struct:
Export the representation
Now that we have separated the representation of the Mandelbrot set from its creation, we can continue
improving our app by creating a type responsible of exporting this representation to the format that we desire.
Even though our final goal is generating images, let’s start with the CLI version:
The export() method returns a string with the representation of the set. Using it in the main method is
As you can see the separation of concerns has improved the readability of our code, but unfortunately
this doesn’t bring us closer to our objective… until now!
Let’s add a new structImageExporter that, using a Representation, prints pixels in a png image.
Keep in mind that after drawing the pixels, the file needs to be saved with a given name in a specific folder.
Both default Exporter and ImageExporter have the same export() method, which means that they share
the same goal. With a little renaming, an interface and a new method CreateExporter,
we can use any Representation of a Mandelbrot set without taking care of where
it writes the result: the CLI or an image.
With a couple of additions in the main method, the app will be able to generate custom images of the Mandelbrot set.
From now on the default output of the app will be an image, that’s why we will also have to tweak default
values like width and height:
Now we can build, execute and enjoy the first image generated by the app! The git checkout command is optional,
in case you want to use the exact same code as me:
The resulting image (mandelbrot/800x601.png) should look like this:
Testing and refactoring
Check the new tests added to the app,
especially the ones related to the exporters (exporter_test.go).
Working with files is tricky, that’s why the TDD approach has helped in edge cases like
incorrect file extensions or directories that need to be created.
The generated images might look correct until you start generating them with custom ratios.
For example, run the next command:
The resulting image displays a stretched version of the Mandelbrot set:
To solve this problem, the app must calculate automatically the value of imagMax using the rest of the boundaries,
instead of defining it manually. Let’s make some changes in the config.go file:
This new method returns a Config with accurate image ratio values. For the sake of correctness,
let’s modify the default parameters so that the resulting image has a 4:3 ratio:
Add them to the flags in the main method:
These default values will return a horizontally centered image.
Also, custom parameters won’t stretch the image. Get the
refactored version of the app and test it by yourself!
Now that the app generates images, the next goal is to make them more appealing by using colors.
See you in the next post!