/*
* Mandlebrot image using Tiny PNG Output (C)
*
* Copyright (c) 2018 Project Nayuki
* https://www.nayuki.io/page/tiny-png-output
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program (see COPYING.txt and COPYING.LESSER.txt).
* If not, see .
*/
#include
#include
#include
#include
#include
#include "TinyPngOut.h"
/* Image parameters */
static const int width = 512;
static const int height = 512;
static const double xMin = -1.9;
static const double xMax = 0.5;
static const double yMin = -1.2;
static const double yMax = 1.2;
static const int iterations = 1000;
static uint32_t mandelbrot(int x, int y);
static int printError(enum TinyPngOut_Status status);
/* Function implementations */
int main(void) {
// Allocate single line buffer
uint8_t *line = calloc((size_t)width * 3, sizeof(uint8_t));
if (line == NULL) {
perror("Error: calloc");
return EXIT_FAILURE;
}
// Open output file
FILE *fout = fopen("demo-mandelbrot.png", "wb");
if (fout == NULL) {
perror("Error: fopen");
return EXIT_FAILURE;
}
// Initialize Tiny PNG Output
struct TinyPngOut pngout;
enum TinyPngOut_Status status = TinyPngOut_init(&pngout, (uint32_t)width, (uint32_t)height, fout);
if (status != TINYPNGOUT_OK)
return printError(status);
// Compute and write Mandelbrot one line at a time
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint32_t pix = mandelbrot(x, y);
line[x * 3 + 0] = (uint8_t)(pix >> 16);
line[x * 3 + 1] = (uint8_t)(pix >> 8);
line[x * 3 + 2] = (uint8_t)(pix >> 0);
}
status = TinyPngOut_write(&pngout, line, (size_t)width);
if (status != TINYPNGOUT_OK)
return printError(status);
}
free(line);
// Close output file
if (fclose(fout) != 0) {
perror("Error: fclose");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static uint32_t mandelbrot(int x, int y) {
double cr = xMin + (x + 0.5) / width * (xMax - xMin);
double ci = yMax - (y + 0.5) / height * (yMax - yMin);
double zr = 0;
double zi = 0;
int i;
for (i = 0; i < iterations; i++) {
if (zr * zr + zi * zi > 4)
break;
double temp = zr * zr - zi * zi + cr;
zi = 2 * zr * zi + ci;
zr = temp;
}
double j = (double)i / iterations;
return (uint32_t)(pow(j, 0.6) * 255 + 0.5) << 16
| (uint32_t)(pow(j, 0.3) * 255 + 0.5) << 8
| (uint32_t)(pow(j, 0.1) * 255 + 0.5) << 0;
}
static int printError(enum TinyPngOut_Status status) {
const char *msg;
switch (status) {
case TINYPNGOUT_OK : msg = "OK"; break;
case TINYPNGOUT_INVALID_ARGUMENT: msg = "Invalid argument"; break;
case TINYPNGOUT_IMAGE_TOO_LARGE : msg = "Image too large"; break;
case TINYPNGOUT_IO_ERROR : msg = "I/O error"; break;
default : msg = "Unknown error"; break;
}
fprintf(stderr, "Error: %s\n", msg);
return EXIT_FAILURE;
}