1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
#include "fileio.h"
#ifdef PNGSUPPORT
#include <png.h>
/* write a png file */
bool write_png(const char *filename, Data<u8bit,4> &buff){
FILE *fp;
png_structp png_ptr;
png_infop info_ptr;
Log<FileIO> odinlog("PNGFormat","write");
ODINLOG(odinlog,normalDebug) << "Saving data of shape " << buff.shape() << " to " << filename << STD_endl;
/* open the file */
fp = fopen(filename, "wb");
if (fp == NULL){
ODINLOG(odinlog,errorLog) << "Opening " << filename << " failed: " << strerror(errno) << STD_endl;
errno=0;
return false;
}
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries. REQUIRED.
*/
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL /*user_error_ptr*/, NULL /*user_error_fn*/, NULL /*user_warning_fn*/);
if (png_ptr == NULL){
fclose(fp);
ODINLOG(odinlog,errorLog) << "png_create_write_struct failed: " << (errno ? strerror(errno):"") << STD_endl;
errno=0;
return false;
}
/* Allocate/initialize the image information data. REQUIRED */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL){
fclose(fp);
ODINLOG(odinlog,errorLog) << "png_create_info_struct failed: " << (errno ? strerror(errno):"") << STD_endl;
errno=0;
return false;
}
/* Set error handling. REQUIRED if you aren't supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if (setjmp(png_jmpbuf(png_ptr))){
/* If we get here, we had a problem writing the file */
ODINLOG(odinlog,errorLog) << "Could not write to " << filename << " " << (errno ? strerror(errno):"") << STD_endl;
errno=0;
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
return false;
}
/* set up the output control if you are using standard C streams */
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, buff.shape()(readDim), buff.shape()(phaseDim),8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
/* png needs a pointer to each row */
u8bit *rp=buff.c_array();
png_byte** row_pointers= new png_byte*[buff.shape()(2)];
for (unsigned short r=0; r<buff.shape()(2); r++)
row_pointers[r]=(png_byte*)&rp[r*buff.shape()(3)];
png_set_rows(png_ptr, info_ptr, row_pointers);
/* This is the easy way. Use it if you already have all the
* image info living info in the structure. You could "|" many
* PNG_TRANSFORM flags into the png_transforms integer here.
*/
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
/* clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);
delete[] row_pointers;
/* close the file */
fclose(fp);
/* that's it */
return true;
}
Data<png_byte,2> read_png(const char *filename){
Log<FileIO> odinlog("PNGFormat","read_png");
Data<png_byte,2> ret;
png_byte header[8]; // 8 is the maximum size that can be checked
/* open file and test for it being a png */
FILE *fp = fopen(filename, "rb");
if (!fp){
ODINLOG(odinlog,errorLog) << "File " << filename << " could not be opened." << STD_endl;
return -1;
}
if(fread(header, 1, 8, fp)<=0) {
ODINLOG(odinlog,errorLog) << "Cannot fread file " << filename << STD_endl;
return -1;
}
if (png_sig_cmp(header, 0, 8)){
ODINLOG(odinlog,errorLog) << "File " << filename << " is not recognized as a PNG file." << STD_endl;
return -1;
}
png_structp png_ptr;
png_infop info_ptr;
/* initialize stuff */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
assert(png_ptr);
info_ptr = png_create_info_struct(png_ptr);
assert(info_ptr);
if (setjmp(png_jmpbuf(png_ptr)));
png_init_io(png_ptr, fp);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
unsigned int height=png_get_image_height(png_ptr, info_ptr); // = info_ptr->height;
unsigned int width=png_get_image_width(png_ptr, info_ptr); // = info_ptr->width;
unsigned char colortype=png_get_color_type(png_ptr, info_ptr); // = info_ptr->color_type;
unsigned char bitdepth=png_get_bit_depth(png_ptr, info_ptr); // = info_ptr->bit_depth;
ret.resize(height, width);
png_set_interlace_handling(png_ptr);
ODINLOG(odinlog,normalDebug) << "color_type/bit_depth=" << int(colortype) << "/" << int(bitdepth) << STD_endl;
if(colortype!=PNG_COLOR_TYPE_GRAY) {
ODINLOG(odinlog,errorLog) << "Unsupported color mode, only grayscale images are supported" << STD_endl;
fclose(fp);
return -1;
}
png_read_update_info(png_ptr, info_ptr);
/* png needs a pointer to each row */
png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
png_bytep rp=ret.c_array();
for (unsigned short r=0; r<height; r++)
row_pointers[r]=(png_bytep)&rp[r*width];
png_read_image(png_ptr, row_pointers);
fclose(fp);
return ret;
}
//////////////////////////////////////////////////////////////
struct PNGFormat : public FileFormat {
STD_string description() const {return "Portable Network Graphics";}
svector suffix() const {
svector result; result.resize(1);
result[0]="png";
return result;
}
svector dialects() const {return svector();}
int read(Data<float,4>& data, const STD_string& filename, const FileReadOpts& opts, Protocol& prot){
read_png(filename.c_str()).convert_to(data);
return 1;
}
int write(const Data<float,4>& data, const STD_string& filename, const FileWriteOpts& opts, const Protocol& prot) {
Log<FileIO> odinlog("PNGFormat","write");
Range all=Range::all();
TinyVector<int,4> shape(data.shape());
unsigned short time=shape(timeDim),slices=shape(sliceDim);
ODINLOG(odinlog,normalDebug) << "filename=" << filename << STD_endl;
LDRfileName fname(filename);
bool ok=true;
int s=0,t=0;
Data<u8bit,4> buff;
data.convert_to(buff,!opts.noscale);
for(t=0;ok && t<time;t++)
for (s=0; ok && s<slices; s++) {
STD_string onefilename=fname.get_dirname()+SEPARATOR_STR+fname.get_basename_nosuffix();
if(time>1) onefilename+="_time"+itos(t,time-1);
if(slices>1) onefilename+="_slice"+itos(s,slices-1);
onefilename+="."+fname.get_suffix();
ODINLOG(odinlog,normalDebug) << "Writing " << onefilename << STD_endl;
Data<u8bit,4> slice(buff(Range(t),Range(s),all,all));
ok = write_png(onefilename.c_str(), slice);
}
if(ok){ODINLOG(odinlog,normalDebug) << "Wrote " << t*s << " images" << STD_endl;return t*s;}
else return -1;
}
};
#endif
//////////////////////////////////////////////////////////////
void register_png_format() {
#ifdef PNGSUPPORT
static PNGFormat format;
format.register_format();
#endif
}
|