mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
[PNG] save_png() now works with std::vector and std::ostream (#2873)
* save_png() works with buffers and streams * optimization for bgr_pixel * explicit overloads for matrix<> and matrix_exp<>. Added docs for new savers * refactored loading implementations details. In my view, easier to read, mirrors saving implementations details, and supports iostreams. We could make the callback API public, and we could support a ton of APIs... * test for iostreams * oops * - reduced code size by templating byte type - docs * spelling * i hope i haven't made a pig's breakfast out of this --------- Co-authored-by: pf <pf@me>
This commit is contained in:
parent
3624bf9f05
commit
106c5a265d
@ -19,140 +19,6 @@
|
|||||||
namespace dlib
|
namespace dlib
|
||||||
{
|
{
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
struct LibpngData
|
|
||||||
{
|
|
||||||
png_bytep* row_pointers_;
|
|
||||||
png_structp png_ptr_;
|
|
||||||
png_infop info_ptr_;
|
|
||||||
png_infop end_info_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PngBufferReaderState
|
|
||||||
{
|
|
||||||
const unsigned char* buffer_;
|
|
||||||
size_t buffer_size_;
|
|
||||||
size_t current_pos_;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileInfo
|
|
||||||
{
|
|
||||||
FileInfo( FILE *fp, const char* filename ) : fp_( fp ), filename_( filename )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInfo( const unsigned char* buffer, size_t buffer_size ) : buffer_( buffer ), buffer_size_( buffer_size )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// no copying this object.
|
|
||||||
FileInfo(const FileInfo&) = delete;
|
|
||||||
FileInfo& operator=(const FileInfo&) = delete;
|
|
||||||
|
|
||||||
~FileInfo()
|
|
||||||
{
|
|
||||||
if ( fp_ != nullptr ) fclose( fp_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE* fp_{nullptr};
|
|
||||||
const char* filename_{nullptr};
|
|
||||||
const unsigned char* buffer_{nullptr};
|
|
||||||
size_t buffer_size_{0};
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
png_loader::
|
|
||||||
png_loader( const char* filename ) : height_( 0 ), width_( 0 )
|
|
||||||
{
|
|
||||||
read_image( check_file( filename ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
png_loader::
|
|
||||||
png_loader( const std::string& filename ) : height_( 0 ), width_( 0 )
|
|
||||||
{
|
|
||||||
read_image( check_file( filename.c_str() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
png_loader::
|
|
||||||
png_loader( const dlib::file& f ) : height_( 0 ), width_( 0 )
|
|
||||||
{
|
|
||||||
read_image( check_file( f.full_name().c_str() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
png_loader::
|
|
||||||
png_loader( const unsigned char* image_buffer, size_t buffer_size ) : height_( 0 ), width_( 0 )
|
|
||||||
{
|
|
||||||
read_image( std::unique_ptr<FileInfo>( new FileInfo( image_buffer, buffer_size ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
const unsigned char* png_loader::get_row( unsigned i ) const
|
|
||||||
{
|
|
||||||
return ld_->row_pointers_[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
png_loader::~png_loader()
|
|
||||||
{
|
|
||||||
if ( ld_ && ld_->row_pointers_ != NULL )
|
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool png_loader::is_gray() const
|
|
||||||
{
|
|
||||||
return ( color_type_ == PNG_COLOR_TYPE_GRAY );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool png_loader::is_graya() const
|
|
||||||
{
|
|
||||||
return ( color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool png_loader::is_rgb() const
|
|
||||||
{
|
|
||||||
return ( color_type_ == PNG_COLOR_TYPE_RGB );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool png_loader::is_rgba() const
|
|
||||||
{
|
|
||||||
return ( color_type_ == PNG_COLOR_TYPE_RGB_ALPHA );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
std::unique_ptr<FileInfo> png_loader::check_file( const char* filename )
|
|
||||||
{
|
|
||||||
if ( filename == NULL )
|
|
||||||
{
|
|
||||||
throw image_load_error("png_loader: invalid filename, it is NULL");
|
|
||||||
}
|
|
||||||
FILE *fp = fopen( filename, "rb" );
|
|
||||||
if ( !fp )
|
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: unable to open file ") + filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::unique_ptr<FileInfo>( new FileInfo( fp, filename ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Don't do anything when libpng calls us to tell us about an error. Just return to
|
// Don't do anything when libpng calls us to tell us about an error. Just return to
|
||||||
@ -161,153 +27,140 @@ namespace dlib
|
|||||||
{
|
{
|
||||||
longjmp(png_jmpbuf(png_struct),1);
|
longjmp(png_jmpbuf(png_struct),1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void png_loader_user_warning_fn_silent(png_structp , png_const_charp )
|
void png_loader_user_warning_fn_silent(png_structp , png_const_charp )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void png_buffer_reader(png_structp png_ptr, png_bytep data, size_t length)
|
void png_reader_callback(png_structp png, png_bytep data, png_size_t length)
|
||||||
{
|
{
|
||||||
PngBufferReaderState* state = static_cast<PngBufferReaderState*>( png_get_io_ptr( png_ptr ) );
|
using callback_t = std::function<std::size_t(char*,std::size_t)>;
|
||||||
if ( length > ( state->buffer_size_ - state->current_pos_ ) )
|
callback_t* clb = static_cast<callback_t*>(png_get_io_ptr(png));
|
||||||
{
|
const auto ret = (*clb)((char*)data, length);
|
||||||
png_error(png_ptr, "png_loader: read error in png_buffer_reader");
|
if (ret != length)
|
||||||
}
|
png_error(png, "png_loader: read error in png_reader_callback");
|
||||||
memcpy( data, state->buffer_ + state->current_pos_, length );
|
|
||||||
state->current_pos_ += length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void png_loader::read_image( std::unique_ptr<FileInfo> file_info )
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void png_loader::load(std::function<std::size_t(char*,std::size_t)> clb)
|
||||||
{
|
{
|
||||||
DLIB_CASSERT(file_info);
|
// Read header
|
||||||
|
png_byte sig[8];
|
||||||
|
if (clb((char*)sig, 8) != 8)
|
||||||
|
throw image_load_error("png_loader: error reading file stream");
|
||||||
|
if (png_sig_cmp(sig, 0, 8 ) != 0)
|
||||||
|
throw image_load_error("png_loader: format error");
|
||||||
|
|
||||||
ld_.reset(new LibpngData);
|
// Create structs
|
||||||
|
png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent );
|
||||||
|
if (png_ptr == NULL)
|
||||||
|
throw image_load_error("Error while reading PNG file : png_create_read_struct()");
|
||||||
|
|
||||||
constexpr png_size_t png_header_size = 8;
|
png_infop info_ptr = png_create_info_struct( png_ptr );
|
||||||
std::string load_error_info;
|
if ( info_ptr == NULL )
|
||||||
|
|
||||||
if ( file_info->fp_ != NULL )
|
|
||||||
{
|
{
|
||||||
png_byte sig[png_header_size];
|
png_destroy_read_struct(&png_ptr, ( png_infopp )NULL, ( png_infopp )NULL );
|
||||||
if (fread( sig, 1, png_header_size, file_info->fp_ ) != png_header_size)
|
throw image_load_error("Error while reading PNG file : png_create_info_struct()");
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: error reading file ") + file_info->filename_);
|
|
||||||
}
|
|
||||||
load_error_info = std::string(" in file ") + file_info->filename_;
|
|
||||||
if ( png_sig_cmp( sig, 0, png_header_size ) != 0 )
|
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: format error") + load_error_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( file_info->buffer_ == NULL )
|
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: invalid image buffer, it is NULL"));
|
|
||||||
}
|
|
||||||
if ( file_info->buffer_size_ == 0 )
|
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: invalid image buffer size, it is 0"));
|
|
||||||
}
|
|
||||||
if ( file_info->buffer_size_ < png_header_size ||
|
|
||||||
png_sig_cmp( (png_bytep)file_info->buffer_, 0, png_header_size ) != 0 )
|
|
||||||
{
|
|
||||||
throw image_load_error(std::string("png_loader: format error in image buffer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer_reader_state_.reset(new PngBufferReaderState);
|
|
||||||
}
|
|
||||||
|
|
||||||
ld_->png_ptr_ = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, &png_loader_user_error_fn_silent, &png_loader_user_warning_fn_silent );
|
|
||||||
if ( ld_->png_ptr_ == NULL )
|
|
||||||
{
|
|
||||||
std::ostringstream sout;
|
|
||||||
sout << "Error, unable to allocate png structure" << std::endl;
|
|
||||||
const char* runtime_version = png_get_header_ver(NULL);
|
|
||||||
if (runtime_version && std::strcmp(PNG_LIBPNG_VER_STRING, runtime_version) != 0)
|
|
||||||
{
|
|
||||||
sout << "This is happening because you compiled against one version of libpng, but then linked to another." << std::endl;
|
|
||||||
sout << "Compiled against libpng version: " << PNG_LIBPNG_VER_STRING << std::endl;
|
|
||||||
sout << "Linking to this version of libpng: " << runtime_version << std::endl;
|
|
||||||
}
|
|
||||||
throw image_load_error(sout.str());
|
|
||||||
}
|
|
||||||
ld_->info_ptr_ = png_create_info_struct( ld_->png_ptr_ );
|
|
||||||
if ( ld_->info_ptr_ == NULL )
|
|
||||||
{
|
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), ( png_infopp )NULL, ( png_infopp )NULL );
|
|
||||||
throw image_load_error(std::string("png_loader: unable to allocate png info structure") + load_error_info);
|
|
||||||
}
|
|
||||||
ld_->end_info_ = png_create_info_struct( ld_->png_ptr_ );
|
|
||||||
if ( ld_->end_info_ == NULL )
|
|
||||||
{
|
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), ( png_infopp )NULL );
|
|
||||||
throw image_load_error(std::string("png_loader: unable to allocate png info structure") + load_error_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setjmp(png_jmpbuf(ld_->png_ptr_)))
|
png_infop end_info = png_create_info_struct( png_ptr );
|
||||||
|
if ( end_info == NULL )
|
||||||
{
|
{
|
||||||
// If we get here, we had a problem writing the file
|
png_destroy_read_struct(&png_ptr, &info_ptr, ( png_infopp )NULL );
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
|
throw image_load_error("Error while reading PNG file : png_create_info_struct()");
|
||||||
throw image_load_error(std::string("png_loader: parse error") + load_error_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
png_set_palette_to_rgb(ld_->png_ptr_);
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
|
|
||||||
if ( file_info->fp_ != NULL )
|
|
||||||
{
|
{
|
||||||
png_init_io( ld_->png_ptr_, file_info->fp_ );
|
// If you get here, then there was an error while parsing.
|
||||||
}
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
else
|
throw image_load_error("png_loader: parse error");
|
||||||
{
|
|
||||||
buffer_reader_state_->buffer_ = file_info->buffer_;
|
|
||||||
buffer_reader_state_->buffer_size_ = file_info->buffer_size_;
|
|
||||||
// skipping header
|
|
||||||
buffer_reader_state_->current_pos_ = png_header_size;
|
|
||||||
png_set_read_fn( ld_->png_ptr_, buffer_reader_state_.get(), png_buffer_reader );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
png_set_sig_bytes( ld_->png_ptr_, png_header_size );
|
png_set_palette_to_rgb(png_ptr);
|
||||||
|
png_set_read_fn(png_ptr, &clb, png_reader_callback);
|
||||||
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
// flags force one byte per channel output
|
// flags force one byte per channel output
|
||||||
byte_orderer bo;
|
byte_orderer bo;
|
||||||
int png_transforms = PNG_TRANSFORM_PACKING;
|
int png_transforms = PNG_TRANSFORM_PACKING;
|
||||||
if (bo.host_is_little_endian())
|
if (bo.host_is_little_endian())
|
||||||
png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
|
png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
|
||||||
png_read_png( ld_->png_ptr_, ld_->info_ptr_, png_transforms, NULL );
|
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
|
||||||
height_ = png_get_image_height( ld_->png_ptr_, ld_->info_ptr_ );
|
|
||||||
width_ = png_get_image_width( ld_->png_ptr_, ld_->info_ptr_ );
|
|
||||||
bit_depth_ = png_get_bit_depth( ld_->png_ptr_, ld_->info_ptr_ );
|
|
||||||
color_type_ = png_get_color_type( ld_->png_ptr_, ld_-> info_ptr_ );
|
|
||||||
|
|
||||||
|
// If you get here, you are no longer affected by C's crazy longjmp
|
||||||
|
finalizer = std::shared_ptr<char>(new char, [=](char* ptr) mutable {
|
||||||
|
delete ptr;
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||||
|
});
|
||||||
|
|
||||||
if (color_type_ != PNG_COLOR_TYPE_GRAY &&
|
color_type = png_get_color_type( png_ptr, info_ptr );
|
||||||
color_type_ != PNG_COLOR_TYPE_RGB &&
|
height = png_get_image_height( png_ptr, info_ptr );
|
||||||
color_type_ != PNG_COLOR_TYPE_RGB_ALPHA &&
|
width = png_get_image_width( png_ptr, info_ptr );
|
||||||
color_type_ != PNG_COLOR_TYPE_GRAY_ALPHA)
|
bit_depth_ = png_get_bit_depth( png_ptr, info_ptr );
|
||||||
{
|
rows = (unsigned char**)png_get_rows( png_ptr, info_ptr );
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
|
|
||||||
throw image_load_error(std::string("png_loader: unsupported color type") + load_error_info);
|
if (!is_gray() && !is_graya() && !is_rgb() && !is_rgba())
|
||||||
}
|
throw image_load_error("png_loader: unsupported color type");
|
||||||
|
|
||||||
if (bit_depth_ != 8 && bit_depth_ != 16)
|
if (bit_depth_ != 8 && bit_depth_ != 16)
|
||||||
{
|
throw image_load_error("png_loader: unsupported bit depth of " + std::to_string(bit_depth_));
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
|
|
||||||
throw image_load_error("png_loader: unsupported bit depth of " + cast_to_string(bit_depth_) + load_error_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
ld_->row_pointers_ = png_get_rows( ld_->png_ptr_, ld_->info_ptr_ );
|
if (rows == NULL)
|
||||||
|
throw image_load_error("png_loader: parse error");
|
||||||
if ( ld_->row_pointers_ == NULL )
|
|
||||||
{
|
|
||||||
png_destroy_read_struct( &( ld_->png_ptr_ ), &( ld_->info_ptr_ ), &( ld_->end_info_ ) );
|
|
||||||
throw image_load_error(std::string("png_loader: parse error") + load_error_info);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void png_loader::load(std::istream& in)
|
||||||
|
{
|
||||||
|
load([&](char* data, std::size_t ndata) {
|
||||||
|
in.read(data, ndata);
|
||||||
|
return in.gcount();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
png_loader::png_loader(const unsigned char* image_buffer, std::size_t buffer_size)
|
||||||
|
{
|
||||||
|
std::size_t counter{0};
|
||||||
|
load([&](char* data, std::size_t ndata) {
|
||||||
|
ndata = std::min(ndata, buffer_size - counter);
|
||||||
|
std::memcpy(data, image_buffer + counter, ndata);
|
||||||
|
counter += ndata;
|
||||||
|
return ndata;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
png_loader::png_loader(std::istream& in)
|
||||||
|
{
|
||||||
|
load(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_loader::png_loader( const char* filename )
|
||||||
|
{
|
||||||
|
std::ifstream in(filename, std::ios::binary);
|
||||||
|
load(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_loader::png_loader( const std::string& filename ) : png_loader(filename.c_str()) {}
|
||||||
|
png_loader::png_loader( const dlib::file& f ) : png_loader(f.full_name()) {}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool png_loader::is_gray() const { return color_type == PNG_COLOR_TYPE_GRAY; }
|
||||||
|
bool png_loader::is_graya() const { return color_type == PNG_COLOR_TYPE_GRAY_ALPHA; }
|
||||||
|
bool png_loader::is_rgb() const { return color_type == PNG_COLOR_TYPE_RGB; }
|
||||||
|
bool png_loader::is_rgba() const { return color_type == PNG_COLOR_TYPE_RGB_ALPHA; }
|
||||||
|
unsigned int png_loader::bit_depth () const {return bit_depth_;}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DLIB_PNG_SUPPORT
|
#endif // DLIB_PNG_SUPPORT
|
||||||
|
|
||||||
#endif // DLIB_PNG_LOADER_CPp_
|
#endif // DLIB_PNG_LOADER_CPp_
|
||||||
|
|
@ -4,38 +4,41 @@
|
|||||||
#define DLIB_PNG_IMPORT
|
#define DLIB_PNG_IMPORT
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <istream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include "png_loader_abstract.h"
|
#include "png_loader_abstract.h"
|
||||||
#include "image_loader.h"
|
#include "image_loader.h"
|
||||||
#include "../pixel.h"
|
#include "../pixel.h"
|
||||||
#include "../dir_nav.h"
|
#include "../type_traits.h"
|
||||||
#include "../test_for_odr_violations.h"
|
#include "../test_for_odr_violations.h"
|
||||||
|
#include "../dir_nav.h"
|
||||||
|
|
||||||
namespace dlib
|
namespace dlib
|
||||||
{
|
{
|
||||||
|
|
||||||
struct LibpngData;
|
// ----------------------------------------------------------------------------------------
|
||||||
struct PngBufferReaderState;
|
|
||||||
struct FileInfo;
|
|
||||||
class png_loader : noncopyable
|
class png_loader : noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
png_loader( std::istream& in );
|
||||||
png_loader( const char* filename );
|
png_loader( const char* filename );
|
||||||
png_loader( const std::string& filename );
|
png_loader( const std::string& filename );
|
||||||
png_loader( const dlib::file& f );
|
png_loader( const dlib::file& f );
|
||||||
png_loader( const unsigned char* image_buffer, size_t buffer_size );
|
png_loader( const unsigned char* image_buffer, std::size_t buffer_size );
|
||||||
~png_loader();
|
|
||||||
|
|
||||||
bool is_gray() const;
|
bool is_gray() const;
|
||||||
bool is_graya() const;
|
bool is_graya() const;
|
||||||
bool is_rgb() const;
|
bool is_rgb() const;
|
||||||
bool is_rgba() const;
|
bool is_rgba() const;
|
||||||
|
unsigned int bit_depth () const;
|
||||||
|
|
||||||
unsigned int bit_depth () const { return bit_depth_; }
|
template<class image_type>
|
||||||
|
void get_image( image_type& img) const
|
||||||
template<typename T>
|
|
||||||
void get_image( T& t_) const
|
|
||||||
{
|
{
|
||||||
#ifndef DLIB_PNG_SUPPORT
|
#ifndef DLIB_PNG_SUPPORT
|
||||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
@ -45,202 +48,143 @@ namespace dlib
|
|||||||
to link against the libpng library.
|
to link against the libpng library.
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
||||||
COMPILE_TIME_ASSERT(sizeof(T) == 0);
|
COMPILE_TIME_ASSERT(sizeof(T) == 0);
|
||||||
|
#else
|
||||||
|
using pixel_type = pixel_type_t<image_type>;
|
||||||
|
auto t = make_image_view(img);
|
||||||
|
|
||||||
|
t.set_size( height, width );
|
||||||
|
|
||||||
|
const auto assign_gray = [&](const auto** lines)
|
||||||
|
{
|
||||||
|
for ( int n = 0; n < height; ++n )
|
||||||
|
for ( int m = 0; m < width; ++m )
|
||||||
|
assign_pixel( t[n][m], lines[n][m]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto assign_gray_alpha = [&](const auto** lines)
|
||||||
|
{
|
||||||
|
for ( int n = 0; n < height; ++n )
|
||||||
|
{
|
||||||
|
for ( int m = 0; m < width; ++m )
|
||||||
|
{
|
||||||
|
if (!pixel_traits<pixel_type>::has_alpha)
|
||||||
|
{
|
||||||
|
assign_pixel(t[n][m], lines[n][m*2]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rgb_alpha_pixel pix;
|
||||||
|
assign_pixel(pix, lines[n][m*2]);
|
||||||
|
assign_pixel(pix.alpha, lines[n][m*2+1]);
|
||||||
|
assign_pixel(t[n][m], pix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto assign_rgb = [&](const auto** lines)
|
||||||
|
{
|
||||||
|
for ( int n = 0; n < height;++n )
|
||||||
|
{
|
||||||
|
for ( int m = 0; m < width;++m )
|
||||||
|
{
|
||||||
|
rgb_pixel p;
|
||||||
|
p.red = static_cast<uint8>(lines[n][m*3]);
|
||||||
|
p.green = static_cast<uint8>(lines[n][m*3+1]);
|
||||||
|
p.blue = static_cast<uint8>(lines[n][m*3+2]);
|
||||||
|
assign_pixel( t[n][m], p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto assign_rgba = [&](const auto** lines)
|
||||||
|
{
|
||||||
|
if (!pixel_traits<pixel_type>::has_alpha)
|
||||||
|
assign_all_pixels(t,0);
|
||||||
|
|
||||||
|
for ( int n = 0; n < height; ++n )
|
||||||
|
{
|
||||||
|
for ( int m = 0; m < width; ++m )
|
||||||
|
{
|
||||||
|
rgb_alpha_pixel p;
|
||||||
|
p.red = static_cast<uint8>(lines[n][m*4]);
|
||||||
|
p.green = static_cast<uint8>(lines[n][m*4+1]);
|
||||||
|
p.blue = static_cast<uint8>(lines[n][m*4+2]);
|
||||||
|
p.alpha = static_cast<uint8>(lines[n][m*4+3]);
|
||||||
|
assign_pixel( t[n][m], p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto assign = [&](const auto** lines)
|
||||||
|
{
|
||||||
|
if (is_gray())
|
||||||
|
assign_gray(lines);
|
||||||
|
|
||||||
|
else if (is_graya())
|
||||||
|
assign_gray_alpha(lines);
|
||||||
|
|
||||||
|
else if (is_rgb())
|
||||||
|
assign_rgb(lines);
|
||||||
|
|
||||||
|
else if (is_rgba())
|
||||||
|
assign_rgba(lines);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (bit_depth_ == 8)
|
||||||
|
assign((const uint8_t**)(rows));
|
||||||
|
|
||||||
|
else if (bit_depth_ == 16)
|
||||||
|
assign((const uint16_t**)(rows));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef typename image_traits<T>::pixel_type pixel_type;
|
|
||||||
image_view<T> t(t_);
|
|
||||||
t.set_size( height_, width_ );
|
|
||||||
|
|
||||||
|
|
||||||
if (is_gray() && bit_depth_ == 8)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const unsigned char* v = get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
unsigned char p = v[m];
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_gray() && bit_depth_ == 16)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const uint16* v = (uint16*)get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
dlib::uint16 p = v[m];
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_graya() && bit_depth_ == 8)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const unsigned char* v = get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_; m++ )
|
|
||||||
{
|
|
||||||
unsigned char p = v[m*2];
|
|
||||||
if (!pixel_traits<pixel_type>::has_alpha)
|
|
||||||
{
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned char pa = v[m*2+1];
|
|
||||||
rgb_alpha_pixel pix;
|
|
||||||
assign_pixel(pix, p);
|
|
||||||
assign_pixel(pix.alpha, pa);
|
|
||||||
assign_pixel(t[n][m], pix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_graya() && bit_depth_ == 16)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const uint16* v = (uint16*)get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_; m++ )
|
|
||||||
{
|
|
||||||
dlib::uint16 p = v[m*2];
|
|
||||||
if (!pixel_traits<pixel_type>::has_alpha)
|
|
||||||
{
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dlib::uint16 pa = v[m*2+1];
|
|
||||||
rgb_alpha_pixel pix;
|
|
||||||
assign_pixel(pix, p);
|
|
||||||
assign_pixel(pix.alpha, pa);
|
|
||||||
assign_pixel(t[n][m], pix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_rgb() && bit_depth_ == 8)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const unsigned char* v = get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
rgb_pixel p;
|
|
||||||
p.red = v[m*3];
|
|
||||||
p.green = v[m*3+1];
|
|
||||||
p.blue = v[m*3+2];
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_rgb() && bit_depth_ == 16)
|
|
||||||
{
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const uint16* v = (uint16*)get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
rgb_pixel p;
|
|
||||||
p.red = static_cast<uint8>(v[m*3]);
|
|
||||||
p.green = static_cast<uint8>(v[m*3+1]);
|
|
||||||
p.blue = static_cast<uint8>(v[m*3+2]);
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_rgba() && bit_depth_ == 8)
|
|
||||||
{
|
|
||||||
if (!pixel_traits<pixel_type>::has_alpha)
|
|
||||||
assign_all_pixels(t,0);
|
|
||||||
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const unsigned char* v = get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
rgb_alpha_pixel p;
|
|
||||||
p.red = v[m*4];
|
|
||||||
p.green = v[m*4+1];
|
|
||||||
p.blue = v[m*4+2];
|
|
||||||
p.alpha = v[m*4+3];
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (is_rgba() && bit_depth_ == 16)
|
|
||||||
{
|
|
||||||
if (!pixel_traits<pixel_type>::has_alpha)
|
|
||||||
assign_all_pixels(t,0);
|
|
||||||
|
|
||||||
for ( unsigned n = 0; n < height_;n++ )
|
|
||||||
{
|
|
||||||
const uint16* v = (uint16*)get_row( n );
|
|
||||||
for ( unsigned m = 0; m < width_;m++ )
|
|
||||||
{
|
|
||||||
rgb_alpha_pixel p;
|
|
||||||
p.red = static_cast<uint8>(v[m*4]);
|
|
||||||
p.green = static_cast<uint8>(v[m*4+1]);
|
|
||||||
p.blue = static_cast<uint8>(v[m*4+2]);
|
|
||||||
p.alpha = static_cast<uint8>(v[m*4+3]);
|
|
||||||
assign_pixel( t[n][m], p );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const unsigned char* get_row( unsigned i ) const;
|
void load(std::function<std::size_t(char*,std::size_t)> clb);
|
||||||
std::unique_ptr<FileInfo> check_file( const char* filename );
|
void load(std::istream& in);
|
||||||
void read_image( std::unique_ptr<FileInfo> file_info );
|
|
||||||
unsigned height_, width_;
|
int height{0};
|
||||||
unsigned bit_depth_;
|
int width{0};
|
||||||
int color_type_;
|
int bit_depth_{0};
|
||||||
std::unique_ptr<LibpngData> ld_;
|
int color_type{0};
|
||||||
std::unique_ptr<PngBufferReaderState> buffer_reader_state_;
|
unsigned char** rows{nullptr};
|
||||||
|
std::shared_ptr<void> finalizer;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template <class image_type>
|
||||||
typename image_type
|
|
||||||
>
|
|
||||||
void load_png (
|
void load_png (
|
||||||
image_type& image,
|
image_type& img,
|
||||||
|
std::istream& in
|
||||||
|
)
|
||||||
|
{
|
||||||
|
png_loader(in).get_image(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class image_type>
|
||||||
|
void load_png (
|
||||||
|
image_type& img,
|
||||||
const std::string& file_name
|
const std::string& file_name
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
png_loader(file_name).get_image(image);
|
png_loader(file_name).get_image(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename image_type
|
class image_type,
|
||||||
>
|
class Byte,
|
||||||
|
std::enable_if_t<is_byte<Byte>::value, bool> = true
|
||||||
|
>
|
||||||
void load_png (
|
void load_png (
|
||||||
image_type& image,
|
image_type& img,
|
||||||
const unsigned char* image_buffer,
|
const Byte* image_buffer,
|
||||||
size_t buffer_size
|
std::size_t buffer_size
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
png_loader(image_buffer, buffer_size).get_image(image);
|
png_loader((const unsigned char*)image_buffer, buffer_size).get_image(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
|
||||||
typename image_type
|
|
||||||
>
|
|
||||||
void load_png (
|
|
||||||
image_type& image,
|
|
||||||
const char* image_buffer,
|
|
||||||
size_t buffer_size
|
|
||||||
)
|
|
||||||
{
|
|
||||||
png_loader(reinterpret_cast<const unsigned char*>(image_buffer), buffer_size).get_image(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -249,5 +193,4 @@ namespace dlib
|
|||||||
#include "png_loader.cpp"
|
#include "png_loader.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // DLIB_PNG_IMPORT
|
#endif // DLIB_PNG_IMPORT
|
||||||
|
|
@ -78,6 +78,18 @@ namespace dlib
|
|||||||
us from loading the given PNG buffer.
|
us from loading the given PNG buffer.
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
|
png_loader(
|
||||||
|
std::istream& in
|
||||||
|
);
|
||||||
|
/*!
|
||||||
|
ensures
|
||||||
|
- loads the PNG file from the c++ IO stream into this object
|
||||||
|
throws
|
||||||
|
- image_load_error
|
||||||
|
This exception is thrown if there is some error that prevents
|
||||||
|
us from loading the given PNG buffer.
|
||||||
|
!*/
|
||||||
|
|
||||||
~png_loader(
|
~png_loader(
|
||||||
);
|
);
|
||||||
/*!
|
/*!
|
||||||
@ -166,42 +178,46 @@ namespace dlib
|
|||||||
- performs: png_loader(file_name).get_image(image);
|
- performs: png_loader(file_name).get_image(image);
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename image_type
|
typename image_type,
|
||||||
|
typename Byte
|
||||||
>
|
>
|
||||||
void load_png (
|
void load_png (
|
||||||
image_type& image,
|
image_type& image,
|
||||||
const unsigned char* image_buffer,
|
const Byte* image_buffer,
|
||||||
size_t buffer_size
|
size_t buffer_size
|
||||||
);
|
);
|
||||||
/*!
|
/*!
|
||||||
requires
|
requires
|
||||||
- image_type == an image object that implements the interface defined in
|
- image_type == an image object that implements the interface defined in
|
||||||
dlib/image_processing/generic_image.h
|
dlib/image_processing/generic_image.h
|
||||||
|
- Byte is either char, int8_t, uint8_t or std::byte
|
||||||
ensures
|
ensures
|
||||||
- performs: png_loader(image_buffer, buffer_size).get_image(image);
|
- performs: png_loader(image_buffer, buffer_size).get_image(image);
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename image_type
|
class image_type
|
||||||
>
|
>
|
||||||
void load_png (
|
void load_png (
|
||||||
image_type& image,
|
image_type& img,
|
||||||
const char* image_buffer,
|
std::istream& in
|
||||||
size_t buffer_size
|
|
||||||
);
|
);
|
||||||
/*!
|
/*!
|
||||||
requires
|
requires
|
||||||
- image_type == an image object that implements the interface defined in
|
- image_type == an image object that implements the interface defined in
|
||||||
dlib/image_processing/generic_image.h
|
dlib/image_processing/generic_image.h
|
||||||
|
- in is an input stream containing a complete PNG encoded image
|
||||||
ensures
|
ensures
|
||||||
- performs: png_loader((unsigned char*)image_buffer, buffer_size).get_image(image);
|
- Reads and ecodes the PNG file located in stream
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DLIB_PNG_IMPORT_ABSTRACT
|
#endif // DLIB_PNG_IMPORT_ABSTRACT
|
||||||
|
|
||||||
|
|
@ -23,26 +23,32 @@ namespace dlib
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
namespace impl
|
||||||
{
|
{
|
||||||
void impl_save_png (
|
void impl_save_png (
|
||||||
const std::string& file_name,
|
std::function<void(const char*, std::size_t)> clb,
|
||||||
std::vector<unsigned char*>& row_pointers,
|
std::vector<unsigned char*>& row_pointers,
|
||||||
const long width,
|
const long width,
|
||||||
const png_type type,
|
const png_type type,
|
||||||
const int bit_depth
|
const int bit_depth,
|
||||||
|
const bool swap_rgb
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
png_structp png_ptr;
|
png_structp png_ptr;
|
||||||
png_infop info_ptr;
|
png_infop info_ptr;
|
||||||
|
|
||||||
/* Open the file */
|
|
||||||
fp = fopen(file_name.c_str(), "wb");
|
|
||||||
if (fp == NULL)
|
|
||||||
throw image_save_error("Unable to open " + file_name + " for writing.");
|
|
||||||
|
|
||||||
/* Create and initialize the png_struct with the desired error handler
|
/* Create and initialize the png_struct with the desired error handler
|
||||||
* functions. If you want to use the default stderr and longjump method,
|
* 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
|
* you can supply NULL for the last three parameters. We also check that
|
||||||
@ -52,18 +58,14 @@ namespace dlib
|
|||||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_reader_user_error_fn_silent, &png_reader_user_warning_fn_silent);
|
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)
|
if (png_ptr == NULL)
|
||||||
{
|
throw image_save_error("Error while writing PNG file : png_create_write_struct()");
|
||||||
fclose(fp);
|
|
||||||
throw image_save_error("Error while writing PNG file " + file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate/initialize the image information data. REQUIRED */
|
/* Allocate/initialize the image information data. REQUIRED */
|
||||||
info_ptr = png_create_info_struct(png_ptr);
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
if (info_ptr == NULL)
|
if (info_ptr == NULL)
|
||||||
{
|
{
|
||||||
fclose(fp);
|
|
||||||
png_destroy_write_struct(&png_ptr, NULL);
|
png_destroy_write_struct(&png_ptr, NULL);
|
||||||
throw image_save_error("Error while writing PNG file " + file_name);
|
throw image_save_error("Error while writing PNG file : png_create_info_struct()");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set error handling. REQUIRED if you aren't supplying your own
|
/* Set error handling. REQUIRED if you aren't supplying your own
|
||||||
@ -72,9 +74,8 @@ namespace dlib
|
|||||||
if (setjmp(png_jmpbuf(png_ptr)))
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||||||
{
|
{
|
||||||
/* If we get here, we had a problem writing the file */
|
/* If we get here, we had a problem writing the file */
|
||||||
fclose(fp);
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
throw image_save_error("Error while writing PNG file " + file_name);
|
throw image_save_error("Error while writing PNG file");
|
||||||
}
|
}
|
||||||
|
|
||||||
int color_type = 0;
|
int color_type = 0;
|
||||||
@ -85,34 +86,32 @@ namespace dlib
|
|||||||
case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break;
|
case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
fclose(fp);
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
throw image_save_error("Invalid color type");
|
throw image_save_error("Invalid color type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
png_set_write_fn(
|
||||||
/* Set up the output control if you are using standard C streams */
|
png_ptr, &clb,
|
||||||
png_init_io(png_ptr, fp);
|
png_writer_data_callback,
|
||||||
|
png_writer_flush_callback
|
||||||
|
);
|
||||||
|
|
||||||
int png_transforms = PNG_TRANSFORM_IDENTITY;
|
int png_transforms = PNG_TRANSFORM_IDENTITY;
|
||||||
byte_orderer bo;
|
byte_orderer bo;
|
||||||
if (bo.host_is_little_endian())
|
if (bo.host_is_little_endian())
|
||||||
png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
|
png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
|
||||||
|
if (swap_rgb)
|
||||||
|
png_transforms |= PNG_TRANSFORM_BGR;
|
||||||
|
|
||||||
const long height = row_pointers.size();
|
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_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_set_rows(png_ptr, info_ptr, &row_pointers[0]);
|
||||||
png_write_png(png_ptr, info_ptr, png_transforms, NULL);
|
png_write_png(png_ptr, info_ptr, png_transforms, NULL);
|
||||||
|
|
||||||
/* Clean up after the write, and free any memory allocated */
|
/* Clean up after the write, and free any memory allocated */
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
/* Close the file */
|
|
||||||
fclose(fp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
#ifndef DLIB_SAVE_PnG_Hh_
|
#ifndef DLIB_SAVE_PnG_Hh_
|
||||||
#define DLIB_SAVE_PnG_Hh_
|
#define DLIB_SAVE_PnG_Hh_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <functional>
|
||||||
#include "save_png_abstract.h"
|
#include "save_png_abstract.h"
|
||||||
#include "image_saver.h"
|
#include "image_saver.h"
|
||||||
#include "../array2d.h"
|
#include "../array2d.h"
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "../pixel.h"
|
#include "../pixel.h"
|
||||||
#include "../matrix/matrix_exp.h"
|
#include "../matrix/matrix_exp.h"
|
||||||
#include "../image_transforms/assign_image.h"
|
#include "../image_transforms/assign_image.h"
|
||||||
@ -27,127 +29,200 @@ namespace dlib
|
|||||||
};
|
};
|
||||||
|
|
||||||
void impl_save_png (
|
void impl_save_png (
|
||||||
const std::string& file_name,
|
std::function<void(const char*, std::size_t)> clb,
|
||||||
std::vector<unsigned char*>& row_pointers,
|
std::vector<unsigned char*>& row_pointers,
|
||||||
const long width,
|
const long width,
|
||||||
const png_type type,
|
const png_type type,
|
||||||
const int bit_depth
|
const int bit_depth,
|
||||||
|
const bool swap_rgb = false
|
||||||
|
);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class image_type
|
||||||
|
>
|
||||||
|
void save_png(
|
||||||
|
const image_type& img_,
|
||||||
|
std::function<void(const char*, std::size_t)> clb
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const_image_view<image_type> img(img_);
|
||||||
|
|
||||||
|
// make sure requires clause is not broken
|
||||||
|
DLIB_CASSERT(img.size() != 0,
|
||||||
|
"\t save_png()"
|
||||||
|
<< "\n\t You can't save an empty image as a PNG"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef DLIB_PNG_SUPPORT
|
||||||
|
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
You are getting this error because you are trying to use save_png()
|
||||||
|
but you haven't defined DLIB_PNG_SUPPORT. You must do so to use
|
||||||
|
this function. You must also make sure you set your build environment
|
||||||
|
to link against the libpng library.
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
||||||
|
COMPILE_TIME_ASSERT(sizeof(image_type) == 0);
|
||||||
|
#else
|
||||||
|
std::vector<unsigned char*> row_pointers(img.nr());
|
||||||
|
using pixel_type = pixel_type_t<image_type>;
|
||||||
|
|
||||||
|
if (std::is_same<rgb_pixel,pixel_type>::value)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);
|
||||||
|
}
|
||||||
|
else if (std::is_same<bgr_pixel,pixel_type>::value)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8, true);
|
||||||
|
}
|
||||||
|
else if (std::is_same<rgb_alpha_pixel,pixel_type>::value)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
||||||
|
}
|
||||||
|
else if (pixel_traits<pixel_type>::lab || pixel_traits<pixel_type>::hsi || pixel_traits<pixel_type>::rgb)
|
||||||
|
{
|
||||||
|
// convert from Lab or HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B)
|
||||||
|
array2d<rgb_pixel> temp_img;
|
||||||
|
assign_image(temp_img, img_);
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);
|
||||||
|
}
|
||||||
|
else if (pixel_traits<pixel_type>::rgb_alpha)
|
||||||
|
{
|
||||||
|
// convert from RGBA pixels that aren't laid out as R G B A
|
||||||
|
array2d<rgb_alpha_pixel> temp_img;
|
||||||
|
assign_image(temp_img, img_);
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
||||||
|
}
|
||||||
|
else // this is supposed to be grayscale
|
||||||
|
{
|
||||||
|
DLIB_CASSERT(pixel_traits<pixel_type>::grayscale, "impossible condition detected");
|
||||||
|
|
||||||
|
if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 1)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 8);
|
||||||
|
}
|
||||||
|
else if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 2)
|
||||||
|
{
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// convert from whatever this is to 16bit grayscale
|
||||||
|
array2d<dlib::uint16> temp_img;
|
||||||
|
assign_image(temp_img, img_);
|
||||||
|
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
||||||
|
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
||||||
|
|
||||||
|
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class image_type
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
|
const image_type& img,
|
||||||
|
std::ostream& out
|
||||||
|
)
|
||||||
|
{
|
||||||
|
impl::save_png (
|
||||||
|
img,
|
||||||
|
[&out](const char* data, std::size_t ndata) {
|
||||||
|
out.write(data, ndata);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename image_type
|
class image_type
|
||||||
>
|
>
|
||||||
typename disable_if<is_matrix<image_type> >::type save_png(
|
void save_png (
|
||||||
const image_type& img_,
|
const image_type& img,
|
||||||
const std::string& file_name
|
const std::string& file_name
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const_image_view<image_type> img(img_);
|
std::ofstream out(file_name, std::ios::binary);
|
||||||
|
save_png(img, out);
|
||||||
// make sure requires clause is not broken
|
|
||||||
DLIB_CASSERT(img.size() != 0,
|
|
||||||
"\t save_png()"
|
|
||||||
<< "\n\t You can't save an empty image as a PNG"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef DLIB_PNG_SUPPORT
|
|
||||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
You are getting this error because you are trying to use save_png()
|
|
||||||
but you haven't defined DLIB_PNG_SUPPORT. You must do so to use
|
|
||||||
this function. You must also make sure you set your build environment
|
|
||||||
to link against the libpng library.
|
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
|
||||||
COMPILE_TIME_ASSERT(sizeof(image_type) == 0);
|
|
||||||
#else
|
|
||||||
std::vector<unsigned char*> row_pointers(img.nr());
|
|
||||||
typedef typename image_traits<image_type>::pixel_type pixel_type;
|
|
||||||
|
|
||||||
if (is_same_type<rgb_pixel,pixel_type>::value)
|
|
||||||
{
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
|
|
||||||
}
|
|
||||||
else if (is_same_type<rgb_alpha_pixel,pixel_type>::value)
|
|
||||||
{
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
|
||||||
}
|
|
||||||
else if (pixel_traits<pixel_type>::lab || pixel_traits<pixel_type>::hsi || pixel_traits<pixel_type>::rgb)
|
|
||||||
{
|
|
||||||
// convert from Lab or HSI to RGB (Or potentially RGB pixels that aren't laid out as R G B)
|
|
||||||
array2d<rgb_pixel> temp_img;
|
|
||||||
assign_image(temp_img, img_);
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
|
|
||||||
}
|
|
||||||
else if (pixel_traits<pixel_type>::rgb_alpha)
|
|
||||||
{
|
|
||||||
// convert from RGBA pixels that aren't laid out as R G B A
|
|
||||||
array2d<rgb_alpha_pixel> temp_img;
|
|
||||||
assign_image(temp_img, img_);
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
|
||||||
}
|
|
||||||
else // this is supposed to be grayscale
|
|
||||||
{
|
|
||||||
DLIB_CASSERT(pixel_traits<pixel_type>::grayscale, "impossible condition detected");
|
|
||||||
|
|
||||||
if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 1)
|
|
||||||
{
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 8);
|
|
||||||
}
|
|
||||||
else if (pixel_traits<pixel_type>::is_unsigned && sizeof(pixel_type) == 2)
|
|
||||||
{
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// convert from whatever this is to 16bit grayscale
|
|
||||||
array2d<dlib::uint16> temp_img;
|
|
||||||
assign_image(temp_img, img_);
|
|
||||||
for (unsigned long i = 0; i < row_pointers.size(); ++i)
|
|
||||||
row_pointers[i] = (unsigned char*)(&temp_img[i][0]);
|
|
||||||
|
|
||||||
impl::impl_save_png(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename EXP
|
class image_type,
|
||||||
>
|
class Byte,
|
||||||
void save_png(
|
class Alloc
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
|
const image_type& img,
|
||||||
|
std::vector<Byte, Alloc>& buf
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static_assert(is_byte<Byte>::value, "Byte must be char, int8_t or uint8_t");
|
||||||
|
impl::save_png (
|
||||||
|
img,
|
||||||
|
[&buf](const char* data, std::size_t ndata) {
|
||||||
|
buf.insert(end(buf), data, data + ndata);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class T, long NR, long NC, class MM, class L,
|
||||||
|
class Output
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
|
const matrix<T,NR,NC,MM,L>& img,
|
||||||
|
Output&& out
|
||||||
|
)
|
||||||
|
{
|
||||||
|
save_png(make_image_view(img), std::forward<Output>(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class EXP,
|
||||||
|
class Output
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
const matrix_exp<EXP>& img,
|
const matrix_exp<EXP>& img,
|
||||||
const std::string& file_name
|
Output&& out
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
array2d<typename EXP::type> temp;
|
array2d<typename EXP::type> temp;
|
||||||
assign_image(temp, img);
|
assign_image(temp, img);
|
||||||
save_png(temp, file_name);
|
save_png(temp, std::forward<Output>(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
@ -40,6 +40,70 @@ namespace dlib
|
|||||||
- std::bad_alloc
|
- std::bad_alloc
|
||||||
!*/
|
!*/
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class image_type
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
|
const image_type& img,
|
||||||
|
std::ostream& out
|
||||||
|
);
|
||||||
|
/*!
|
||||||
|
requires
|
||||||
|
- image_type == an image object that implements the interface defined in
|
||||||
|
dlib/image_processing/generic_image.h or a matrix expression
|
||||||
|
- image.size() != 0
|
||||||
|
ensures
|
||||||
|
- writes the image to the output stream in the PNG (Portable Network Graphics)
|
||||||
|
format.
|
||||||
|
- image[0][0] will be in the upper left corner of the image.
|
||||||
|
- image[image.nr()-1][image.nc()-1] will be in the lower right
|
||||||
|
corner of the image.
|
||||||
|
- This routine can save images containing any type of pixel. However, save_png() can
|
||||||
|
only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8,
|
||||||
|
and uint16. All other pixel types will be converted into one of these types as
|
||||||
|
appropriate before being saved to disk.
|
||||||
|
throws
|
||||||
|
- image_save_error
|
||||||
|
This exception is thrown if there is an error that prevents us from saving
|
||||||
|
the image.
|
||||||
|
- std::bad_alloc
|
||||||
|
!*/
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <
|
||||||
|
class image_type,
|
||||||
|
class Byte,
|
||||||
|
class Alloc
|
||||||
|
>
|
||||||
|
void save_png (
|
||||||
|
const image_type& img,
|
||||||
|
std::vector<Byte, Alloc>& buf
|
||||||
|
);
|
||||||
|
/*!
|
||||||
|
requires
|
||||||
|
- image_type == an image object that implements the interface defined in
|
||||||
|
dlib/image_processing/generic_image.h or a matrix expression
|
||||||
|
- image.size() != 0
|
||||||
|
ensures
|
||||||
|
- writes the image to the vector buffer in the PNG (Portable Network Graphics)
|
||||||
|
format.
|
||||||
|
- image[0][0] will be in the upper left corner of the image.
|
||||||
|
- image[image.nr()-1][image.nc()-1] will be in the lower right
|
||||||
|
corner of the image.
|
||||||
|
- This routine can save images containing any type of pixel. However, save_png() can
|
||||||
|
only natively store the following pixel types: rgb_pixel, rgb_alpha_pixel, uint8,
|
||||||
|
and uint16. All other pixel types will be converted into one of these types as
|
||||||
|
appropriate before being saved to disk.
|
||||||
|
throws
|
||||||
|
- image_save_error
|
||||||
|
This exception is thrown if there is an error that prevents us from saving
|
||||||
|
the image.
|
||||||
|
- std::bad_alloc
|
||||||
|
!*/
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ namespace
|
|||||||
img[r][c].alpha = static_cast<unsigned char>(r*14 + c + 4);
|
img[r][c].alpha = static_cast<unsigned char>(r*14 + c + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save_png(img, "test.png");
|
save_png(img, "test.png");
|
||||||
|
|
||||||
img.clear();
|
img.clear();
|
||||||
@ -275,10 +275,124 @@ namespace
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
matrix<rgb_alpha_pixel> img;
|
||||||
|
matrix<rgb_pixel> img2, img3;
|
||||||
|
img.set_size(14,15);
|
||||||
|
img2.set_size(img.nr(),img.nc());
|
||||||
|
img3.set_size(img.nr(),img.nc());
|
||||||
|
for (long r = 0; r < 14; ++r)
|
||||||
|
{
|
||||||
|
for (long c = 0; c < 15; ++c)
|
||||||
|
{
|
||||||
|
img(r,c).red = static_cast<unsigned char>(r*14 + c + 1);
|
||||||
|
img(r,c).green = static_cast<unsigned char>(r*14 + c + 2);
|
||||||
|
img(r,c).blue = static_cast<unsigned char>(r*14 + c + 3);
|
||||||
|
img(r,c).alpha = static_cast<unsigned char>(r*14 + c + 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save_png(img, "test.png");
|
||||||
|
|
||||||
|
img.set_size(0,0);
|
||||||
|
DLIB_TEST(img.nr() == 0);
|
||||||
|
DLIB_TEST(img.nc() == 0);
|
||||||
|
|
||||||
|
load_png(img, "test.png");
|
||||||
|
|
||||||
|
DLIB_TEST(img.nr() == 14);
|
||||||
|
DLIB_TEST(img.nc() == 15);
|
||||||
|
|
||||||
|
assign_all_pixels(img2, 255);
|
||||||
|
assign_all_pixels(img3, 0);
|
||||||
|
load_png(img2, "test.png");
|
||||||
|
assign_image(img3, img);
|
||||||
|
|
||||||
|
for (long r = 0; r < 14; ++r)
|
||||||
|
{
|
||||||
|
for (long c = 0; c < 15; ++c)
|
||||||
|
{
|
||||||
|
DLIB_TEST(img(r,c).red == r*14 + c + 1);
|
||||||
|
DLIB_TEST(img(r,c).green == r*14 + c + 2);
|
||||||
|
DLIB_TEST(img(r,c).blue == r*14 + c + 3);
|
||||||
|
DLIB_TEST(img(r,c).alpha == r*14 + c + 4);
|
||||||
|
|
||||||
|
DLIB_TEST(img2(r,c).red == img3(r,c).red);
|
||||||
|
DLIB_TEST(img2(r,c).green == img3(r,c).green);
|
||||||
|
DLIB_TEST(img2(r,c).blue == img3(r,c).blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto test_savers = [](const auto& img1)
|
||||||
|
{
|
||||||
|
const auto test_pixels = [](const auto& img1, const auto& img2)
|
||||||
|
{
|
||||||
|
DLIB_TEST(img1.nr() == img2.nr());
|
||||||
|
DLIB_TEST(img1.nc() == img2.nc());
|
||||||
|
|
||||||
|
for (long r = 0; r < img1.nr(); ++r)
|
||||||
|
{
|
||||||
|
for (long c = 0; c < img1.nc(); ++c)
|
||||||
|
{
|
||||||
|
DLIB_TEST(img1[r][c].red == r*14 + c + 1);
|
||||||
|
DLIB_TEST(img1[r][c].green == r*14 + c + 2);
|
||||||
|
DLIB_TEST(img1[r][c].blue == r*14 + c + 3);
|
||||||
|
|
||||||
|
DLIB_TEST(img1[r][c].red == img2[r][c].red);
|
||||||
|
DLIB_TEST(img1[r][c].green == img2[r][c].green);
|
||||||
|
DLIB_TEST(img1[r][c].blue == img2[r][c].blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using image_type = std::decay_t<decltype(img1)>;
|
||||||
|
|
||||||
|
const std::string file_name = "test.png";
|
||||||
|
std::ostringstream out;
|
||||||
|
std::vector<char> buf1;
|
||||||
|
std::vector<int8_t> buf2;
|
||||||
|
std::vector<uint8_t> buf3;
|
||||||
|
|
||||||
|
save_png(img1, file_name);
|
||||||
|
save_png(img1, out);
|
||||||
|
save_png(img1, buf1);
|
||||||
|
save_png(img1, buf2);
|
||||||
|
save_png(img1, buf3);
|
||||||
|
std::istringstream in(out.str());
|
||||||
|
|
||||||
|
image_type img2, img3, img4, img5, img6;
|
||||||
|
load_png(img2, file_name);
|
||||||
|
load_png(img3, in);
|
||||||
|
load_png(img4, (const char*)buf1.data(), buf1.size());
|
||||||
|
load_png(img5, (const char*)buf1.data(), buf1.size());
|
||||||
|
load_png(img6, (const char*)buf1.data(), buf1.size());
|
||||||
|
test_pixels(img1, img2);
|
||||||
|
test_pixels(img1, img3);
|
||||||
|
test_pixels(img1, img4);
|
||||||
|
test_pixels(img1, img5);
|
||||||
|
test_pixels(img1, img6);
|
||||||
|
};
|
||||||
|
|
||||||
|
array2d<rgb_pixel> img1(14,15);
|
||||||
|
array2d<bgr_pixel> img2(14,15);
|
||||||
|
|
||||||
|
for (long r = 0; r < 14; ++r)
|
||||||
|
{
|
||||||
|
for (long c = 0; c < 15; ++c)
|
||||||
|
{
|
||||||
|
img1[r][c].red = static_cast<unsigned char>(r*14 + c + 1);
|
||||||
|
img1[r][c].green = static_cast<unsigned char>(r*14 + c + 2);
|
||||||
|
img1[r][c].blue = static_cast<unsigned char>(r*14 + c + 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assign_image(img2, img1);
|
||||||
|
test_savers(img1);
|
||||||
|
test_savers(img2);
|
||||||
|
}
|
||||||
#endif // DLIB_PNG_SUPPORT
|
#endif // DLIB_PNG_SUPPORT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
array2d<rgb_pixel> img;
|
array2d<rgb_pixel> img;
|
||||||
img.set_size(14,15);
|
img.set_size(14,15);
|
||||||
|
Loading…
Reference in New Issue
Block a user