#include #ifndef _plan9_ #include #ifdef USE_PNG #include #endif #include #include #ifndef NO_MALLOC_H #include #endif #include #else #include #include #include #endif #include #include #include #include #ifndef USE_PNG CONST char *writepng(xio_constpath filename, CONST struct image *img) { return "XaoS can not save images because it was incorrectly compiled. Please compile it with zlib and libpng"; } #else CONST char *writepng(xio_constpath filename, CONST struct image *image) { png_structp png_ptr; png_infop info_ptr; png_color palette[256]; volatile unsigned short a = 255; volatile unsigned char *b = (volatile unsigned char *) &a; #ifdef _undefined_ static char text[] = "XaoS" XaoS_VERSION " - a realtime interactive fractal zoomer"; static png_text comments[] = { { -1, "Software", text, sizeof(text)} }; #endif FILE *file = fopen(filename, "wb"); errno = -1; if (file == NULL) { return strerror(errno); } png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (void *) NULL, (png_error_ptr) NULL, (png_error_ptr) NULL); if (!png_ptr) return "Unable to initialize pnglib"; info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp) NULL); return "No memory to create png info structure"; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); return strerror(errno); } png_init_io(png_ptr, file); png_set_filter(png_ptr, 0, PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_PAETH | PNG_FILTER_UP | PNG_FILTER_AVG); /* set the zlib compression level */ /*png_set_compression_level(png_ptr, Z_BEST_COMPRESSION); */ png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); /* set other zlib parameters */ png_set_compression_mem_level(png_ptr, 8); png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY); png_set_compression_window_bits(png_ptr, 15); png_set_compression_method(png_ptr, 8); info_ptr->width = image->width; info_ptr->height = image->height; /*info_ptr->gamma=1.0; */ info_ptr->gamma = 0.5; info_ptr->valid |= PNG_INFO_gAMA | PNG_INFO_pHYs; info_ptr->x_pixels_per_unit = (png_uint_32) (100 / image->pixelwidth); info_ptr->y_pixels_per_unit = (png_uint_32) (100 / image->pixelheight); switch (image->palette->type) { case C256: { int i; info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; info_ptr->bit_depth = image->bytesperpixel * 8; info_ptr->palette = palette; info_ptr->valid |= PNG_INFO_PLTE; for (i = 0; i < image->palette->end; i++) info_ptr->palette[i].red = image->palette->rgb[i][0], info_ptr->palette[i].green = image->palette->rgb[i][1], info_ptr->palette[i].blue = image->palette->rgb[i][2], info_ptr->num_palette = image->palette->end; } break; case SMALLITER: case LARGEITER: case GRAYSCALE: info_ptr->color_type = PNG_COLOR_TYPE_GRAY; info_ptr->bit_depth = image->bytesperpixel * 8; break; case TRUECOLOR: case TRUECOLOR24: case TRUECOLOR16: info_ptr->color_type = PNG_COLOR_TYPE_RGB; info_ptr->bit_depth = 8; info_ptr->sig_bit.red = 8 - image->palette->info.truec.rprec; info_ptr->sig_bit.green = 8 - image->palette->info.truec.gprec; info_ptr->sig_bit.blue = 8 - image->palette->info.truec.bprec; break; } info_ptr->interlace_type = 0; #ifdef _undefined_ png_set_text(png_ptr, info_ptr, comments, sizeof(comments) / sizeof(png_text)); #endif png_write_info(png_ptr, info_ptr); /*png_set_filler(png_ptr,0,PNG_FILLER_AFTER); */ png_set_packing(png_ptr); if (image->palette->type & (TRUECOLOR | TRUECOLOR24 | TRUECOLOR16)) png_set_shift(png_ptr, &(info_ptr->sig_bit)); if (*b == 255) png_set_swap(png_ptr); png_set_bgr(png_ptr); switch (image->palette->type) { case C256: case GRAYSCALE: case SMALLITER: case LARGEITER: #ifdef STRUECOLOR24 case TRUECOLOR24: png_write_image(png_ptr, (png_bytepp) image->currlines); break; #endif case TRUECOLOR: { int i, y; unsigned char *r = (unsigned char *) malloc(image->width * 3); for (i = 0; i < image->height; i++) { for (y = 0; y < image->width; y++) r[y * 3 + 2] = (((pixel32_t **) (image-> currlines))[i][y] & image->palette->info.truec.rmask) >> image-> palette->info.truec.rshift, r[y * 3 + 1] = (((pixel32_t **) (image-> currlines))[i][y] & image->palette->info.truec.gmask) >> image-> palette->info.truec.gshift, r[y * 3] = (((pixel32_t **) (image-> currlines))[i][y] & image->palette->info.truec.bmask) >> image-> palette->info.truec.bshift; png_write_rows(png_ptr, (png_bytepp) & r, 1); } } break; #ifdef SUPPORT16 case TRUECOLOR16: { int i, y; unsigned char *r = (unsigned char *) malloc(image->width * 3); for (i = 0; i < image->height; i++) { for (y = 0; y < image->width; y++) r[y * 3 + 2] = (((pixel16_t **) (image-> currlines))[i][y] & image->palette->info.truec.rmask) >> image-> palette->info.truec.rshift, r[y * 3 + 1] = (((pixel16_t **) (image-> currlines))[i][y] & image->palette->info.truec.gmask) >> image-> palette->info.truec.gshift, r[y * 3] = (((pixel16_t **) (image-> currlines))[i][y] & image->palette->info.truec.bmask) >> image-> palette->info.truec.bshift; png_write_rows(png_ptr, (png_bytepp) & r, 1); } } break; #endif } png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(file); return NULL; } #endif