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
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
@ -161,148 +27,136 @@ namespace dlib
|
||||
{
|
||||
longjmp(png_jmpbuf(png_struct),1);
|
||||
}
|
||||
|
||||
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 ) );
|
||||
if ( length > ( state->buffer_size_ - state->current_pos_ ) )
|
||||
{
|
||||
png_error(png_ptr, "png_loader: read error in png_buffer_reader");
|
||||
}
|
||||
memcpy( data, state->buffer_ + state->current_pos_, length );
|
||||
state->current_pos_ += length;
|
||||
using callback_t = std::function<std::size_t(char*,std::size_t)>;
|
||||
callback_t* clb = static_cast<callback_t*>(png_get_io_ptr(png));
|
||||
const auto ret = (*clb)((char*)data, length);
|
||||
if (ret != length)
|
||||
png_error(png, "png_loader: read error in png_reader_callback");
|
||||
}
|
||||
|
||||
void png_loader::read_image( std::unique_ptr<FileInfo> file_info )
|
||||
{
|
||||
DLIB_CASSERT(file_info);
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
ld_.reset(new LibpngData);
|
||||
void png_loader::load(std::function<std::size_t(char*,std::size_t)> clb)
|
||||
{
|
||||
// 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");
|
||||
|
||||
constexpr png_size_t png_header_size = 8;
|
||||
std::string load_error_info;
|
||||
// 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()");
|
||||
|
||||
if ( file_info->fp_ != NULL )
|
||||
png_infop info_ptr = png_create_info_struct( png_ptr );
|
||||
if ( info_ptr == NULL )
|
||||
{
|
||||
png_byte sig[png_header_size];
|
||||
if (fread( sig, 1, png_header_size, file_info->fp_ ) != png_header_size)
|
||||
{
|
||||
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"));
|
||||
png_destroy_read_struct(&png_ptr, ( png_infopp )NULL, ( png_infopp )NULL );
|
||||
throw image_load_error("Error while reading PNG file : png_create_info_struct()");
|
||||
}
|
||||
|
||||
buffer_reader_state_.reset(new PngBufferReaderState);
|
||||
png_infop end_info = png_create_info_struct( png_ptr );
|
||||
if ( end_info == NULL )
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, ( png_infopp )NULL );
|
||||
throw image_load_error("Error while reading PNG file : png_create_info_struct()");
|
||||
}
|
||||
|
||||
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 )
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
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 you get here, then there was an error while parsing.
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
throw image_load_error("png_loader: parse error");
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(ld_->png_ptr_)))
|
||||
{
|
||||
// If we get here, we had a problem writing the file
|
||||
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);
|
||||
}
|
||||
|
||||
png_set_palette_to_rgb(ld_->png_ptr_);
|
||||
|
||||
if ( file_info->fp_ != NULL )
|
||||
{
|
||||
png_init_io( ld_->png_ptr_, file_info->fp_ );
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
byte_orderer bo;
|
||||
int png_transforms = PNG_TRANSFORM_PACKING;
|
||||
if (bo.host_is_little_endian())
|
||||
png_transforms |= PNG_TRANSFORM_SWAP_ENDIAN;
|
||||
png_read_png( ld_->png_ptr_, ld_->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_ );
|
||||
png_read_png(png_ptr, info_ptr, png_transforms, NULL);
|
||||
|
||||
// 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_COLOR_TYPE_RGB &&
|
||||
color_type_ != PNG_COLOR_TYPE_RGB_ALPHA &&
|
||||
color_type_ != PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
{
|
||||
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);
|
||||
}
|
||||
color_type = png_get_color_type( png_ptr, info_ptr );
|
||||
height = png_get_image_height( png_ptr, info_ptr );
|
||||
width = png_get_image_width( png_ptr, info_ptr );
|
||||
bit_depth_ = png_get_bit_depth( png_ptr, info_ptr );
|
||||
rows = (unsigned char**)png_get_rows( png_ptr, info_ptr );
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
throw image_load_error("png_loader: unsupported bit depth of " + std::to_string(bit_depth_));
|
||||
|
||||
if (rows == NULL)
|
||||
throw image_load_error("png_loader: parse error");
|
||||
}
|
||||
|
||||
ld_->row_pointers_ = png_get_rows( ld_->png_ptr_, ld_->info_ptr_ );
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
if ( ld_->row_pointers_ == NULL )
|
||||
void png_loader::load(std::istream& in)
|
||||
{
|
||||
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);
|
||||
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_;}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -310,4 +164,3 @@ namespace dlib
|
||||
#endif // DLIB_PNG_SUPPORT
|
||||
|
||||
#endif // DLIB_PNG_LOADER_CPp_
|
||||
|
||||
|
@ -4,38 +4,41 @@
|
||||
#define DLIB_PNG_IMPORT
|
||||
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
|
||||
#include "png_loader_abstract.h"
|
||||
#include "image_loader.h"
|
||||
#include "../pixel.h"
|
||||
#include "../dir_nav.h"
|
||||
#include "../type_traits.h"
|
||||
#include "../test_for_odr_violations.h"
|
||||
#include "../dir_nav.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
struct LibpngData;
|
||||
struct PngBufferReaderState;
|
||||
struct FileInfo;
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
class png_loader : noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
png_loader( std::istream& in );
|
||||
png_loader( const char* filename );
|
||||
png_loader( const std::string& filename );
|
||||
png_loader( const dlib::file& f );
|
||||
png_loader( const unsigned char* image_buffer, size_t buffer_size );
|
||||
~png_loader();
|
||||
png_loader( const unsigned char* image_buffer, std::size_t buffer_size );
|
||||
|
||||
bool is_gray() const;
|
||||
bool is_graya() const;
|
||||
bool is_rgb() const;
|
||||
bool is_rgba() const;
|
||||
unsigned int bit_depth () const;
|
||||
|
||||
unsigned int bit_depth () const { return bit_depth_; }
|
||||
|
||||
template<typename T>
|
||||
void get_image( T& t_) const
|
||||
template<class image_type>
|
||||
void get_image( image_type& img) const
|
||||
{
|
||||
#ifndef DLIB_PNG_SUPPORT
|
||||
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
@ -45,202 +48,143 @@ namespace dlib
|
||||
to link against the libpng library.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
|
||||
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
|
||||
|
||||
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:
|
||||
const unsigned char* get_row( unsigned i ) const;
|
||||
std::unique_ptr<FileInfo> check_file( const char* filename );
|
||||
void read_image( std::unique_ptr<FileInfo> file_info );
|
||||
unsigned height_, width_;
|
||||
unsigned bit_depth_;
|
||||
int color_type_;
|
||||
std::unique_ptr<LibpngData> ld_;
|
||||
std::unique_ptr<PngBufferReaderState> buffer_reader_state_;
|
||||
void load(std::function<std::size_t(char*,std::size_t)> clb);
|
||||
void load(std::istream& in);
|
||||
|
||||
int height{0};
|
||||
int width{0};
|
||||
int bit_depth_{0};
|
||||
int color_type{0};
|
||||
unsigned char** rows{nullptr};
|
||||
std::shared_ptr<void> finalizer;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
>
|
||||
template <class image_type>
|
||||
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
|
||||
)
|
||||
{
|
||||
png_loader(file_name).get_image(image);
|
||||
png_loader(file_name).get_image(img);
|
||||
}
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
class image_type,
|
||||
class Byte,
|
||||
std::enable_if_t<is_byte<Byte>::value, bool> = true
|
||||
>
|
||||
void load_png (
|
||||
image_type& image,
|
||||
const unsigned char* image_buffer,
|
||||
size_t buffer_size
|
||||
image_type& img,
|
||||
const Byte* image_buffer,
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -250,4 +194,3 @@ namespace dlib
|
||||
#endif
|
||||
|
||||
#endif // DLIB_PNG_IMPORT
|
||||
|
||||
|
@ -78,6 +78,18 @@ namespace dlib
|
||||
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(
|
||||
);
|
||||
/*!
|
||||
@ -166,36 +178,42 @@ namespace dlib
|
||||
- performs: png_loader(file_name).get_image(image);
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
typename image_type,
|
||||
typename Byte
|
||||
>
|
||||
void load_png (
|
||||
image_type& image,
|
||||
const unsigned char* image_buffer,
|
||||
const Byte* image_buffer,
|
||||
size_t buffer_size
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
- Byte is either char, int8_t, uint8_t or std::byte
|
||||
ensures
|
||||
- performs: png_loader(image_buffer, buffer_size).get_image(image);
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename image_type
|
||||
class image_type
|
||||
>
|
||||
void load_png (
|
||||
image_type& image,
|
||||
const char* image_buffer,
|
||||
size_t buffer_size
|
||||
image_type& img,
|
||||
std::istream& in
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- image_type == an image object that implements the interface defined in
|
||||
dlib/image_processing/generic_image.h
|
||||
- in is an input stream containing a complete PNG encoded image
|
||||
ensures
|
||||
- performs: png_loader((unsigned char*)image_buffer, buffer_size).get_image(image);
|
||||
- Reads and ecodes the PNG file located in stream
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -203,5 +221,3 @@ namespace dlib
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
void impl_save_png (
|
||||
const std::string& file_name,
|
||||
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 int bit_depth,
|
||||
const bool swap_rgb
|
||||
)
|
||||
{
|
||||
|
||||
FILE *fp;
|
||||
png_structp png_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
|
||||
* 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
|
||||
@ -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);
|
||||
|
||||
if (png_ptr == NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
throw image_save_error("Error while writing PNG file " + file_name);
|
||||
}
|
||||
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)
|
||||
{
|
||||
fclose(fp);
|
||||
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
|
||||
@ -72,9 +74,8 @@ namespace dlib
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
/* If we get here, we had a problem writing the file */
|
||||
fclose(fp);
|
||||
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;
|
||||
@ -85,34 +86,32 @@ namespace dlib
|
||||
case png_type_gray: color_type = PNG_COLOR_TYPE_GRAY; break;
|
||||
default:
|
||||
{
|
||||
fclose(fp);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
throw image_save_error("Invalid color type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set up the output control if you are using standard C streams */
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
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);
|
||||
|
||||
/* Close the file */
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@
|
||||
#ifndef DLIB_SAVE_PnG_Hh_
|
||||
#define DLIB_SAVE_PnG_Hh_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include "save_png_abstract.h"
|
||||
#include "image_saver.h"
|
||||
#include "../array2d.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../pixel.h"
|
||||
#include "../matrix/matrix_exp.h"
|
||||
#include "../image_transforms/assign_image.h"
|
||||
@ -27,22 +29,22 @@ namespace dlib
|
||||
};
|
||||
|
||||
void impl_save_png (
|
||||
const std::string& file_name,
|
||||
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 int bit_depth,
|
||||
const bool swap_rgb = false
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
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 std::string& file_name
|
||||
std::function<void(const char*, std::size_t)> clb
|
||||
)
|
||||
{
|
||||
const_image_view<image_type> img(img_);
|
||||
@ -64,21 +66,28 @@ namespace dlib
|
||||
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;
|
||||
using pixel_type = pixel_type_t<image_type>;
|
||||
|
||||
if (is_same_type<rgb_pixel,pixel_type>::value)
|
||||
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(file_name, row_pointers, img.nc(), impl::png_type_rgb, 8);
|
||||
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);
|
||||
}
|
||||
else if (is_same_type<rgb_alpha_pixel,pixel_type>::value)
|
||||
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(file_name, row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
||||
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)
|
||||
{
|
||||
@ -88,7 +97,7 @@ namespace dlib
|
||||
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);
|
||||
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb, 8);
|
||||
}
|
||||
else if (pixel_traits<pixel_type>::rgb_alpha)
|
||||
{
|
||||
@ -98,7 +107,7 @@ namespace dlib
|
||||
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);
|
||||
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_rgb_alpha, 8);
|
||||
}
|
||||
else // this is supposed to be grayscale
|
||||
{
|
||||
@ -109,14 +118,14 @@ namespace dlib
|
||||
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);
|
||||
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(file_name, row_pointers, img.nc(), impl::png_type_gray, 16);
|
||||
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -126,28 +135,94 @@ namespace dlib
|
||||
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);
|
||||
impl::impl_save_png(std::move(clb), row_pointers, img.nc(), impl::png_type_gray, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename EXP
|
||||
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 <
|
||||
class image_type
|
||||
>
|
||||
void save_png (
|
||||
const image_type& img,
|
||||
const std::string& file_name
|
||||
)
|
||||
{
|
||||
std::ofstream out(file_name, std::ios::binary);
|
||||
save_png(img, out);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
class image_type,
|
||||
class Byte,
|
||||
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 std::string& file_name
|
||||
Output&& out
|
||||
)
|
||||
{
|
||||
array2d<typename EXP::type> temp;
|
||||
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
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
!*/
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
||||
{
|
||||
array2d<rgb_pixel> img;
|
||||
img.set_size(14,15);
|
||||
|
Loading…
Reference in New Issue
Block a user