// Copyright (C) 2011 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_SAVE_PnG_CPPh_ #define DLIB_SAVE_PnG_CPPh_ // only do anything with this file if DLIB_PNG_SUPPORT is defined #ifdef DLIB_PNG_SUPPORT #include "save_png.h" #include <cstdio> #include <png.h> #include "../byte_orderer.h" namespace dlib { // Don't do anything when libpng calls us to tell us about an error. Just return to // our own code and throw an exception (at the long jump target). void png_reader_user_error_fn_silent(png_structp png_struct, png_const_charp ) { longjmp(png_jmpbuf(png_struct),1); } void png_reader_user_warning_fn_silent(png_structp , png_const_charp ) { } void png_writer_data_callback(png_structp png, png_bytep data, png_size_t length) { using clb_t = std::function<void(const char*, std::size_t)>; clb_t* clb = (clb_t*)png_get_io_ptr(png); (*clb)((const char*)data, length); } void png_writer_flush_callback(png_structp png) { /*no-op*/ } namespace impl { void impl_save_png ( std::function<void(const char*, std::size_t)> clb, std::vector<unsigned char*>& row_pointers, const long width, const png_type type, const int bit_depth, const bool swap_rgb ) { png_structp png_ptr; png_infop info_ptr; /* Create and initialize the png_struct with the desired error handler * functions. If you want to use the default stderr and longjump method, * you can supply NULL for the last three parameters. We also check that * the library version is compatible with the one used at compile time, * in case we are using dynamically linked libraries. REQUIRED. */ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent); if (png_ptr == NULL) throw image_save_error("Error while writing PNG file : png_create_write_struct()"); /* Allocate/initialize the image information data. REQUIRED */ info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); throw image_save_error("Error while writing PNG file : png_create_info_struct()"); } /* Set error handling. REQUIRED if you aren't supplying your own * error handling functions in the png_create_write_struct() call. */ if (setjmp(png_jmpbuf(png_ptr))) { /* If we get here, we had a problem writing the file */ png_destroy_write_struct(&png_ptr, &info_ptr); throw image_save_error("Error while writing PNG file"); } int color_type = 0; switch(type) { case png_type_rgb: color_type = PNG_COLOR_TYPE_RGB; break; case png_type_rgb_alpha: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break; default: { png_destroy_write_struct(&png_ptr, &info_ptr); throw image_save_error("Invalid color type"); } } png_set_write_fn( png_ptr, &clb, png_writer_data_callback, png_writer_flush_callback ); int png_transforms = PNG_TRANSFORM_IDENTITY; byte_orderer bo; if (bo.host_is_little_endian()) png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN; if (swap_rgb) png_transforms |= PNG_TRANSFORM_BGR; const long height = row_pointers.size(); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_set_rows(png_ptr, info_ptr, &row_pointers[0]); png_write_png(png_ptr, info_ptr, png_transforms, NULL); /* Clean up after the write, and free any memory allocated */ png_destroy_write_struct(&png_ptr, &info_ptr); } } } #endif // DLIB_PNG_SUPPORT #endif // DLIB_SAVE_PnG_CPPh_