Skip to content

Instantly share code, notes, and snippets.

@edma2
Created June 29, 2012 04:16
Show Gist options
  • Save edma2/3015704 to your computer and use it in GitHub Desktop.
Save edma2/3015704 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <png.h>
/* The boundaries of the plot */
#define RE_MAX 1.0
#define RE_MIN -2.0
#define IM_MAX 1.0
#define IM_MIN -1.0
/* 8 bits per channel */
#define BIT_DEPTH 8
/* R, G, B */
#define PIXEL_SIZE 3
typedef uint32_t uint;
typedef struct {
uint width;
uint height;
uint *data;
} Plot;
/* Computes the "escape time" of (re) + (im)i.
*
* From i = 0 to i = max, compute z(i) where
* z(0) = 0
* z(n+1) = z(n)^2 + c
*
* Break loop if z(i) >= LIMIT and return i, the "escape time"
* Returns max If z(i) never escapes. */
uint escape_time(double c_re, double c_im, double limit, uint max) {
uint i;
double z_re = 0, z_im = 0;
for (i = 0; z_re < limit && z_im < limit && i < max; i++) {
double z_re_old = z_re;
z_re = z_re * z_re - z_im * z_im + c_re;
z_im = z_re_old * z_im + z_im * z_re_old + c_im;
}
return i;
}
/* Maps the x coordinate of a pixel to an approximate location of the
* mandelbrot set. width is the width of the image in pixels. */
double x_to_re(uint width, uint x) {
return (RE_MAX - RE_MIN) * ((double)x / width) + RE_MIN;
}
/* Same as above but for the y coordinate. */
double y_to_im(uint height, uint y) {
return (IM_MAX - IM_MIN) * ((double)y / height) + IM_MIN;
}
Plot *Plot_new(uint width, uint height) {
Plot *p = malloc(sizeof(Plot));
if (!p) return NULL;
p->width = width;
p->height = height;
p->data = malloc(width * height * sizeof(uint));
if (!p->data) {
free(p);
return NULL;
}
return p;
}
void Plot_free(Plot *p) {
free(p->data);
free(p);
}
/* Set plot data as mandelbrot set. */
void Plot_draw(Plot *p) {
int x, y;
for (x = 0; x < p->width; x++) {
for (y = 0; y < p->height; y++) {
double re = x_to_re(p->width, x);
double im = y_to_im(p->height, y);
uint time = escape_time(re, im, 2.0, 100);
p->data[x + y * p->width] = time;
}
}
}
/* Save plot as PNG in the working directory with filename name. Returns
* nonzero integer on error. */
int Plot_save_png(Plot *p, char *name) {
png_structp png_ptr;
png_infop info_ptr;
FILE *fp;
int status = -1;
/* Create destination PNG file */
fp = fopen(name, "w+");
if (!fp)
goto fopen_failed;
/* Initialize structs and error handling */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
goto png_create_write_struct_failed;
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
goto png_create_info_struct_failed;
if (setjmp(png_jmpbuf(png_ptr)))
goto png_failed;
/* Set header specifying image properties like width and height */
png_set_IHDR(png_ptr, info_ptr, p->width, p->height, BIT_DEPTH,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
/* Fill with pixel data */
png_byte **row_pointers;
row_pointers = png_malloc(png_ptr, p->height * sizeof(png_byte *));
int x, y;
for (y = 0; y < p->height; ++y) {
png_byte *row = png_malloc(png_ptr,
sizeof(uint8_t) * p->width * PIXEL_SIZE);
row_pointers[y] = row;
for (x = 0; x < p->width; ++x) {
uint rgb = p->data[x + y*p->width];
*row++ = rgb * 2;
*row++ = rgb * 2;
*row++ = rgb * 2;
}
}
/* Write image data */
png_init_io(png_ptr, fp);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
/* Set return value to indicate success */
status = 0;
/* Free allocated memory */
for (y = 0; y < p->height; y++)
png_free(png_ptr, row_pointers[y]);
png_free(png_ptr, row_pointers);
png_failed:
png_create_info_struct_failed:
png_destroy_write_struct(&png_ptr, &info_ptr);
png_create_write_struct_failed:
fclose(fp);
fopen_failed:
return status;
}
int main(void) {
Plot *p;
p = Plot_new(800, 500);
if (!p) return -1;
Plot_draw(p);
if (Plot_save_png(p, "test.png") < 0)
printf("failed to save as PNG\n");
Plot_free(p);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment