+ DBG("libpng_write()");
+
+ /* Create libpng structures */
+ png_structp png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
+ io->context, libpng_write_error, libpng_warning,
+ io->internal_pool, libpng_malloc, libpng_free);
+ if (unlikely(!png_ptr))
+ {
+ IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng write structure.");
+ return 0;
+ }
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (unlikely(!info_ptr))
+ {
+ IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Cannot create libpng info structure.");
+ png_destroy_write_struct(&png_ptr, NULL);
+ return 0;
+ }
+
+ /* Setup libpng longjump */
+ if (unlikely(setjmp(png_jmpbuf(png_ptr))))
+ {
+ DBG("Libpng failed to write the image, longjump saved us.");
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 0;
+ }
+
+ /* Setup libpng IO */
+ png_set_write_fn(png_ptr, io->fastbuf, libpng_write_fn, libpng_flush_fn);
+
+ /* Setup PNG parameters */
+ struct image *img = io->image;
+ switch (img->flags & IMAGE_PIXEL_FORMAT)
+ {
+ case COLOR_SPACE_GRAYSCALE | IMAGE_PIXELS_ALIGNED:
+ png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ break;
+ case COLOR_SPACE_GRAYSCALE | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
+ png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_GRAY_ALPHA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ break;
+ case COLOR_SPACE_RGB:
+ png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ break;
+ case COLOR_SPACE_RGB | IMAGE_ALPHA | IMAGE_PIXELS_ALIGNED:
+ png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ break;
+ case COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED:
+ png_set_IHDR(png_ptr, info_ptr, img->cols, img->rows, 8, PNG_COLOR_TYPE_RGB,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
+ break;
+ default:
+ IMAGE_ERROR(io->context, IMAGE_ERROR_WRITE_FAILED, "Libpng does not support this pixel format (0x%x)", img->flags & IMAGE_PIXEL_FORMAT);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 0;
+ }
+ png_write_info(png_ptr, info_ptr);
+
+ /* Write pixels */
+ byte *pixels = img->pixels;
+ png_bytep rows[img->rows];
+ for (uns r = 0; r < img->rows; r++, pixels += img->row_size)
+ rows[r] = (png_bytep)pixels;
+ png_write_image(png_ptr, rows);
+ png_write_end(png_ptr, info_ptr);
+
+ /* Free libpng structure */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 1;