mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-19 05:39:17 +02:00
136 lines
3.6 KiB
C
136 lines
3.6 KiB
C
// Based on example program from
|
|
// http://stackoverflow.com/q/1821806/101258
|
|
#include "write-png.h"
|
|
|
|
/* Attempts to save PNG to file; returns 0 on success, non-zero on error. */
|
|
int bitmap_save_to_png(RGBBitmap *bitmap, const char *path)
|
|
{
|
|
FILE *fp = fopen(path, "wb");
|
|
png_structp png_ptr = NULL;
|
|
png_infop info_ptr = NULL;
|
|
size_t x, y;
|
|
png_uint_32 bytes_per_row;
|
|
png_byte **row_pointers = NULL;
|
|
|
|
if (fp == NULL) return -1;
|
|
|
|
/* Initialize the write struct. */
|
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
if (png_ptr == NULL) {
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize the info struct. */
|
|
info_ptr = png_create_info_struct(png_ptr);
|
|
if (info_ptr == NULL) {
|
|
png_destroy_write_struct(&png_ptr, NULL);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/* Set up error handling. */
|
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
|
|
/* Set image attributes. */
|
|
png_set_IHDR(png_ptr,
|
|
info_ptr,
|
|
bitmap->width,
|
|
bitmap->height,
|
|
8,
|
|
PNG_COLOR_TYPE_RGB,
|
|
PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_DEFAULT,
|
|
PNG_FILTER_TYPE_DEFAULT);
|
|
|
|
/* Initialize rows of PNG. */
|
|
bytes_per_row = bitmap->width * bitmap->bytes_per_pixel;
|
|
row_pointers = png_malloc(png_ptr, bitmap->height * sizeof(png_byte *));
|
|
for (y = 0; y < bitmap->height; ++y) {
|
|
uint8_t *row = png_malloc(png_ptr, sizeof(uint8_t) * bytes_per_row);
|
|
row_pointers[y] = (png_byte *)row;
|
|
for (x = 0; x < bitmap->width; ++x) {
|
|
RGBPixel color = RGBPixelAtPoint(bitmap, x, y);
|
|
*row++ = color.red;
|
|
*row++ = color.green;
|
|
*row++ = color.blue;
|
|
}
|
|
}
|
|
|
|
/* Actually write the 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);
|
|
|
|
/* Cleanup. */
|
|
for (y = 0; y < bitmap->height; y++) {
|
|
png_free(png_ptr, row_pointers[y]);
|
|
}
|
|
png_free(png_ptr, row_pointers);
|
|
|
|
/* Finish writing. */
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
|
|
int bitmap_init(RGBBitmap *img, int width, int height)
|
|
{
|
|
img->width = width;
|
|
img->height = height;
|
|
img->bytes_per_pixel = 3;
|
|
img->pixels = calloc(1, sizeof(RGBPixel) * img->width * img->height);
|
|
return 0;
|
|
}
|
|
|
|
int bitmap_set(RGBBitmap *img, int x, int y, int r, int g, int b)
|
|
{
|
|
RGBPixel *pixel = RGBBufferAtPoint(img, x, y);
|
|
pixel->red = r;
|
|
pixel->green = g;
|
|
pixel->blue = b;
|
|
return 0;
|
|
}
|
|
|
|
void bitmap_fill(RGBBitmap *img, int r, int g, int b)
|
|
{
|
|
int x, y;
|
|
// TODO: could use pointers directly or even memcpy
|
|
// to make this faster
|
|
for (y = 0; y < img->height; y++) {
|
|
for (x = 0; x < img->height; x++) {
|
|
bitmap_set(img, x, y, r, g, b);
|
|
}
|
|
}
|
|
}
|
|
|
|
//int main()
|
|
//{
|
|
// const char path[] = "test.png";
|
|
// int status = 0, x, y;
|
|
// RGBBitmap img;
|
|
//
|
|
// bitmap_init(&img, 100, 100);
|
|
// for (y = 0; y < img.height; y++) {
|
|
// for (x = 0; x < img.height; x++) {
|
|
// bitmap_set(&img, x, y, 255, 255, 255);
|
|
// }
|
|
// }
|
|
// bitmap_set(&img, 50, 50, 0, 0, 255);
|
|
// bitmap_set(&img, 0, 0, 0, 0, 255);
|
|
// bitmap_set(&img, 99, 0, 0, 0, 255);
|
|
// bitmap_set(&img, 0, 99, 0, 0, 255);
|
|
// bitmap_set(&img, 99, 99, 0, 0, 255);
|
|
//
|
|
// status = bitmap_save_to_png(&img, path);
|
|
// if (!status){
|
|
// printf("Successfully saved %s\n", path);
|
|
// } else {
|
|
// printf("Unable to save %s\n", path);
|
|
// }
|
|
// return status;
|
|
//}
|