#include #include #include #include #include typedef uint32_t pixel_t; typedef struct { pixel_t *pixels; size_t width; size_t height; } bitmap_t; /* The maximum iteration count. */ const int max_it = 170; /* Compute the out-coloring based on the iteration counter. */ pixel_t outcolor(int it) { /* return 0x00010001 * ((it * 0xff) / max_it); */ return 0x00000001 * ((it * 0xff) / max_it); } /* "Compute" the in-coloring. */ pixel_t incolor() { return 0x00000000; /* black */ } void drawmandelbrot(bitmap_t * mbrot) { for (size_t i = 0; i < mbrot->width * mbrot->height; i++) { size_t y = i / mbrot->width; size_t x = i % mbrot->width; float complex c = ((3.0f * x / mbrot->width) - 2.0f) + I * ((2.0f * y / mbrot->height) - 1.0f); bool diverges = false; float complex z = 0; int it; for (it = 1; it <= max_it; it++) { /* z = z² + c */ z = cpowf(z, 2) + c; /* If |z| ever gets greater than 2, it diverges. */ if (cabsf(z) > 2) { diverges = true; break; } } uint32_t color; if (diverges) { color = outcolor(it); } else { color = incolor(); } mbrot->pixels[i] = color; } } /* Write "bitmap" to a PNG file specified by "path"; returns 0 on success, non-zero on error. */ static int save_png_to_file(bitmap_t * bitmap, const char *path) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; size_t x, y; png_byte **row_pointers = NULL; /* "status" contains the return value of this function. At first it is set to * a value which means 'failure'. When the routine has finished its work, it * is set to a value which means 'success'. */ int status = -1; /* FIXME The following number is set by trial and error only. I cannot see * where it it is documented in the libpng manual. */ int pixel_size = 3; int depth = 8; fp = fopen(path, "wb"); if (!fp) { goto fopen_failed; } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { goto png_create_write_struct_failed; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { goto png_create_info_struct_failed; } /*Set up error handling. */ if (setjmp(png_jmpbuf(png_ptr))) { goto png_failure; } /* Set image attributes. */ png_set_IHDR(png_ptr, info_ptr, bitmap->width, bitmap->height, depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* Initialize rows of PNG. */ row_pointers = png_malloc(png_ptr, bitmap->height * sizeof(png_byte *)); for (y = 0; y < bitmap->height; ++y) { png_byte *row = png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size); row_pointers[y] = row; for (x = 0; x < bitmap->width; ++x) { /* FIXME */ pixel_t *pixel = bitmap->pixels + (y*bitmap->width + x); *row++ = (*pixel & 0x00ff0000) >> 16; *row++ = (*pixel & 0x0000ff00) >> 8; *row++ = (*pixel & 0x000000ff); } } /* Write the image data to "fp". */ 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); /* The routine has successfully written the file, so we set "status" to a * value which indicates success. */ status = 0; for (y = 0; y < bitmap->height; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); png_failure: /* FIXME info struct destroy? */ 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(int argc, char *argv[]) { bitmap_t mbrot; mbrot.width = 640; mbrot.height = 480; /* FIXME calculate */ mbrot.pixels = calloc(sizeof(pixel_t), mbrot.width * mbrot.height); /* Do the mandelbrot. */ drawmandelbrot(&mbrot); /* Save PNG */ char *file = "multibrot.png"; if (save_png_to_file(&mbrot, file) != 0) { fprintf(stderr, "Could not save PNG to %s.\n", file); exit(1); } /* Quit. */ return 0; }