Created
June 29, 2012 04:16
-
-
Save edma2/3015704 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#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