Files
geant4/source/analysis/g4tools/include/tools/png
T
2020-12-04 12:30:43 +01:00

491 lines
12 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_png
#define tools_png
#include <cstdio> //FILE,size_t
#include <string>
#include <tools/sout>
#include <tools/mnmx>
#ifdef TOOLS_USE_NATIVE_PNG
#include <png.h>
#else
#include <ourex_png.h> //enforce ourex png
#endif
namespace tools {
namespace png {
inline bool is(const std::string& a_file){
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) return false; //if file does not exist, then it is not a png !
png_byte header[8]; // 8 is the maximum size that can be checked
size_t nitem = ::fread(header,1,8,file);
::fclose(file);
if(nitem!=8) return false;
return ::png_sig_cmp(header,0,8)?false:true;
}
}}
#include <ostream>
namespace tools {
namespace png {
inline unsigned char* read_FILE(FILE* a_file,unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) {
png_byte header[8]; // 8 is the maximum size that can be checked
if(::fread(header,1,8,a_file)!=8) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
if(::png_sig_cmp(header,0,8)) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
png_structp png_ptr =
::png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
if(!png_ptr) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
png_infop info_ptr = ::png_create_info_struct(png_ptr);
if(!info_ptr) {
::png_destroy_read_struct(&png_ptr,NULL,NULL);
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
if(::setjmp(png_jmpbuf(png_ptr))) {
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
::png_init_io(png_ptr,a_file);
::png_set_sig_bytes(png_ptr,8);
::png_read_info(png_ptr,info_ptr);
int width = info_ptr->width;
int height = info_ptr->height;
int bpp = info_ptr->width?info_ptr->rowbytes/info_ptr->width:0;
if((width<=0)||(height<=0)||(bpp<=0)) {
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
a_bpp = bpp; //avoid the clobbered -W warning.
//png_byte color_type = info_ptr->color_type;
//info_ptr->bit_depth;
//int number_of_passes = ::png_set_interlace_handling(png_ptr);
::png_read_update_info(png_ptr,info_ptr);
if(::setjmp(png_jmpbuf(png_ptr))) {
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
unsigned char* buffer = new unsigned char[info_ptr->rowbytes * height];
if(!buffer) {
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_height = 0;
a_width = 0;
a_bpp = 0;
return 0;
}
{png_bytep* row_pointers = new png_bytep[height];
png_byte* pos = buffer+info_ptr->rowbytes*(height-1);
for(int y=0;y<height;y++) {
row_pointers[y] = pos;
pos -= info_ptr->rowbytes;
}
::png_read_image(png_ptr,row_pointers);
delete [] row_pointers;}
::png_read_end(png_ptr,info_ptr);
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_width = width;
a_height = height;
//a_bpp = bpp; //avoid the clobbered -W warning.
return buffer;
}
inline unsigned char* read(std::ostream& a_out,const std::string& a_file,unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) {
//a_bpp = number of bytes per pixel.
FILE* file = fopen(a_file.c_str(),"rb");
if(!file) {
a_out << "tools::png::read :"
<< " can't open file " << tools::sout(a_file) << "."
<< std::endl;
a_width = 0;
a_height = 0;
a_bpp = 0;
return 0;
}
unsigned char* buffer = read_FILE(file,a_width,a_height,a_bpp);
if(!buffer) {
::fclose(file);
a_width = 0;
a_height = 0;
a_bpp = 0;
a_out << "tools::png::read :"
<< " read_FILE " << tools::sout(a_file) << " failed."
<< std::endl;
return 0;
}
::fclose(file);
return buffer;
}
inline unsigned char* read_part(std::ostream& a_out,
const std::string& a_file,
unsigned int a_sx,unsigned int a_sy,
unsigned int a_sw,unsigned int a_sh,
unsigned int& a_rw,unsigned int& a_rh,
unsigned int& a_rbpp) {
a_out << "tools::png::read_part :"
<< " not yet implemented."
<< std::endl;
a_rw = 0;
a_rh = 0;
a_rbpp = 0;
return 0;
unsigned int w,h,bpp;
unsigned char* buffer = read(a_out,a_file,w,h,bpp);
if(!buffer){
a_rw = 0;
a_rh = 0;
a_rbpp = 0;
return 0;
}
if((a_sx>=w)||(a_sy>=h)){
delete [] buffer;
a_rw = 0;
a_rh = 0;
a_rbpp = 0;
return 0;
}
// 012345
a_rw = tools::mn<unsigned int>(w-a_sx,a_sw);
a_rh = tools::mn<unsigned int>(h-a_sy,a_sh);
a_rbpp = bpp;
if(!a_rw||!a_rh||!a_rbpp){
delete [] buffer;
a_rw = 0;
a_rh = 0;
a_rbpp = 0;
return 0;
}
unsigned char* rb = new unsigned char[a_rw*a_rh*a_rbpp];
if(!rb) {
delete [] buffer;
a_rw = 0;
a_rh = 0;
a_rbpp = 0;
return 0;
}
unsigned int rstride = a_rw * a_rbpp;
unsigned char* rpos = rb;
unsigned int stride = w * bpp;
unsigned char* pos = buffer+a_sy*stride+a_sx*bpp;
for(unsigned int j=0;j<a_rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom.
::memcpy(rpos,pos,rstride);
}
delete [] buffer;
return rb;
}
inline bool write_FILE(FILE* a_file,unsigned char* a_buffer,unsigned int a_width,unsigned int a_height,unsigned int a_bpp) {
//from gl2ps.c.
if((a_bpp!=3)&&(a_bpp!=4)) {
return false;
}
png_structp png_ptr;
if(!(png_ptr = ::png_create_write_struct
(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL))) return false;
png_infop info_ptr;
if(!(info_ptr = ::png_create_info_struct(png_ptr))){
::png_destroy_write_struct(&png_ptr,NULL);
return false;
}
if(::setjmp(png_ptr->jmpbuf)) {
::png_destroy_write_struct(&png_ptr,&info_ptr);
return false;
}
::png_init_io(png_ptr,a_file);
::png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
::png_set_IHDR(png_ptr,info_ptr,a_width,a_height,8,
a_bpp==3?PNG_COLOR_TYPE_RGB:PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
::png_write_info(png_ptr,info_ptr);
for(unsigned int row=0;row<a_height;row++){
unsigned char* pos = a_buffer+(a_height-1-row)*(a_width*a_bpp);
::png_write_row(png_ptr,(png_bytep)pos);
}
::png_write_end(png_ptr,info_ptr);
::png_destroy_write_struct(&png_ptr,&info_ptr);
return true;
}
inline bool write(std::ostream& a_out,
const std::string& a_file,
unsigned char* a_buffer,
unsigned int a_width,
unsigned int a_height,
unsigned int a_bpp) {
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) {
a_out << "tools::png::write :"
<< " can't open file " << tools::sout(a_file) << "."
<< std::endl;
return false;
}
if(!write_FILE(file,a_buffer,a_width,a_height,a_bpp)) {
::fclose(file);
a_out << "tools::png::write :"
<< " can't write file " << tools::sout(a_file) << "."
<< std::endl;
return false;
}
::fclose(file);
return true;
}
inline bool infos_FILE(FILE* a_file,unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) {
//a_bpp = number of bytes per pixel.
png_byte header[8]; // 8 is the maximum size that can be checked
if(::fread(header,1,8,a_file)!=8) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
if(::png_sig_cmp(header,0,8)) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
png_structp png_ptr =
::png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
if(!png_ptr) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
png_infop info_ptr = ::png_create_info_struct(png_ptr);
if(!info_ptr) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
if(::setjmp(png_jmpbuf(png_ptr))) {
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
::png_init_io(png_ptr,a_file);
::png_set_sig_bytes(png_ptr,8);
::png_read_info(png_ptr,info_ptr);
int width = info_ptr->width;
int height = info_ptr->height;
a_bpp = info_ptr->width?info_ptr->rowbytes/info_ptr->width:0;
::png_destroy_read_struct(&png_ptr,&info_ptr,NULL);
a_width = width;
a_height = height;
//a_bpp = bpp; //avoid the clobbered -W warning.
return true;
}
inline bool infos(std::ostream& a_out,const std::string& a_file,unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) {
if(!is(a_file)) {
a_out << "tools::png::infos :"
<< " file " << a_file << " is not png."
<< std::endl;
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {
a_out << "tools::png::infos :"
<< " can't open " << a_file
<< std::endl;
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
unsigned int w,h,bpp;
bool status = infos_FILE(file,w,h,bpp);
::fclose(file);
if(!status) {
a_out << "tools::png::infos :"
<< " problem reading " << a_file
<< std::endl;
a_width = 0;
a_height = 0;
a_bpp = 0;
return false;
}
a_width = w;
a_height = h;
a_bpp = bpp;
return true;
}
}}
#include <tools/xpm>
namespace tools {
namespace png {
inline bool to_xpm(std::ostream& a_out,const std::string& a_file,const std::string& a_name,bool a_verbose = false) {
return tools::xpm::to_xpm(a_out,a_file,a_name,read,a_verbose);
}
}}
#include <tools/image>
#include <vector>
namespace tools {
namespace png {
inline bool concatenate(std::ostream& a_out,
const std::vector<std::string>& a_files,
unsigned int a_cols,unsigned int a_rows,
unsigned int a_bw,unsigned int a_bh,
unsigned char a_bc,
const std::string& a_file) {
unsigned int wa,ha,bppa;
unsigned char* ba =
tools::image::concatenate
(a_out,a_files,a_cols,a_rows,a_bw,a_bh,a_bc,read,wa,ha,bppa);
if(!ba) {
a_out << "tools::png::concatenate :"
<< " failed to concatenate all buffers."
<< std::endl;
delete [] ba;
return false;
}
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) {
a_out << "tools::png::concatenate :"
<< " can't open " << file << " for writing."
<< std::endl;
delete [] ba;
return false;
}
if(!write_FILE(file,ba,wa,ha,bppa)) {
a_out << "tools::png::concatenate :"
<< " can't write " << a_file << "."
<< std::endl;
delete [] ba;
::fclose(file);
return false;
}
delete [] ba;
::fclose(file);
return true;
}
class reader : public virtual tools::image::ireader {
public:
virtual tools::image::ireader* copy() const {return new reader(*this);}
virtual bool is(const std::string& a_file) const {return tools::png::is(a_file);}
virtual bool infos(std::ostream& a_out,const std::string& a_file,
unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) const {
return tools::png::infos(a_out,a_file,a_width,a_height,a_bpp);
}
virtual unsigned char* read(std::ostream& a_out,const std::string& a_file,
unsigned int& a_width,unsigned int& a_height,unsigned int& a_bpp) const {
return tools::png::read(a_out,a_file,a_width,a_height,a_bpp);
}
virtual unsigned char* read_part(std::ostream& a_out,const std::string& a_file,
unsigned int a_sx,unsigned int a_sy,
unsigned int a_sw,unsigned int a_sh,
unsigned int& a_rw,unsigned int& a_rh,unsigned int& a_rbpp) const {
return tools::png::read_part(a_out,a_file,a_sx,a_sy,a_sw,a_sh,a_rw,a_rh,a_rbpp);
}
public:
reader(){}
virtual ~reader(){}
public:
reader(const reader&):ireader(){}
reader& operator=(const reader&){return *this;}
};
}}
#endif