00001 #include "ImageUtil.h"
00002
00003 #include <sys/types.h>
00004 #include <sys/stat.h>
00005 #include <errno.h>
00006 #include <iostream>
00007 #include "Shared/jpeg-6b/jpeg_mem_dest.h"
00008 #include "Shared/jpeg-6b/jpeg_mem_src.h"
00009 #include "Shared/jpeg-6b/jpeg_istream_src.h"
00010 #ifndef NO_TEKKOTSU_CONFIG
00011 # include "Shared/Config.h"
00012 #endif
00013 #ifndef LOADFILE_NO_MMAP
00014 # include <fcntl.h>
00015 # include <errno.h>
00016 # include <sys/types.h>
00017 # include <sys/mman.h>
00018 # include <sys/stat.h>
00019 #endif
00020
00021 #include <png.h>
00022 #include <zlib.h>
00023 extern "C" {
00024 #include <jpeglib.h>
00025 }
00026 using namespace std;
00027
00028 namespace image_util {
00029
00030 bool loadFile(const std::string& file, char*& buf, size_t& size) {
00031 struct stat statbuf;
00032 if(stat(file.c_str(),&statbuf)!=0) {
00033 perror("image_util::loadFile");
00034 return false;
00035 }
00036 #ifdef LOADFILE_NO_MMAP
00037 FILE * infile= fopen(file.c_str(), "rb");
00038 if (infile==NULL) {
00039 int err=errno;
00040 cerr << "image_util::loadFile(): Could not open '" << file << "' (fopen:" << strerror(err) << ")" << endl;
00041 return false;
00042 }
00043 char* inbuf=new char[statbuf.st_size];
00044 if(!fread(inbuf,statbuf.st_size,1,infile)) {
00045 int err=errno;
00046 cerr << "image_util::loadFile(): Could not load '" << file << "' (fread:" << strerror(err) << ")" << endl;
00047 if(fclose(infile))
00048 perror("Warning: image_util::loadFile(), on fclose");
00049 delete [] inbuf;
00050 return false;
00051 }
00052 if(fclose(infile))
00053 perror("Warning: image_util::loadFile(), on fclose");
00054 #else
00055 int infd=open(file.c_str(),O_RDONLY,0666);
00056 if(infd<0) {
00057 int err=errno;
00058 cerr << "image_util::loadFile(): Could not open '" << file << "' (open:" << strerror(err) << ")" << endl;
00059 return false;
00060 }
00061 void* inbuf=mmap(NULL,(size_t)statbuf.st_size,PROT_READ,MAP_FILE|MAP_PRIVATE,infd,0);
00062 if (inbuf == MAP_FAILED) {
00063 int err=errno;
00064 cerr << "image_util::loadFile(): Could not load '" << file << "' (mmap:" << strerror(err) << ")" << endl;
00065 if(close(infd)<0)
00066 perror("Warning: image_util::loadFile(), on closing temporary file descriptor from open");
00067 return false;
00068 }
00069 if(close(infd)<0)
00070 perror("Warning: image_util::loadFile(), on closing temporary file descriptor from open");
00071 #endif
00072 buf=static_cast<char*>(inbuf);
00073 size=(size_t)statbuf.st_size;
00074 return true;
00075 }
00076
00077 #ifdef LOADFILE_NO_MMAP
00078 void releaseFile(char* buf, size_t ) {
00079 delete [] buf;
00080 }
00081 #else
00082 void releaseFile(char* buf, size_t size) {
00083 if(munmap(buf,size))
00084 perror("Warning: image_util::releaseFile(), on munmap");
00085 }
00086 #endif
00087
00088
00089
00090
00091 struct my_error_mgr {
00092
00093 struct jpeg_error_mgr pub;
00094 char buffer[JMSG_LENGTH_MAX];
00095 jmp_buf setjmp_buffer;
00096 };
00097
00098 static void my_error_exit (j_common_ptr cinfo)
00099 {
00100
00101 my_error_mgr * myerr = (my_error_mgr *) cinfo->err;
00102 (*cinfo->err->format_message) (cinfo, myerr->buffer);
00103
00104 longjmp(myerr->setjmp_buffer, 1);
00105 }
00106
00107 typedef int (*cinfo_cleanup_f)(jpeg_decompress_struct* cinfo);
00108
00109
00110 bool decodeJPEG(jpeg_decompress_struct& cinfo, my_error_mgr& jerr, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize, const std::string& filename, cinfo_cleanup_f cinfo_cleanup=NULL) {
00111 jpeg_read_header(&cinfo, true);
00112 cinfo.out_color_space=JCS_YCbCr;
00113 jpeg_calc_output_dimensions(&cinfo);
00114 width=cinfo.output_width;
00115 height=cinfo.output_height;
00116 channels=cinfo.output_components;
00117 if(cinfo.output_width==0 || cinfo.output_height==0 || cinfo.output_components==0) {
00118 jpeg_destroy_decompress(&cinfo);
00119 return true;
00120 }
00121 if(outbuf==NULL) {
00122 outbufSize=width*height*channels;
00123 outbuf=new char[outbufSize];
00124 } else if(width*height*channels>outbufSize) {
00125
00126 if(cinfo_cleanup!=NULL)
00127 (*cinfo_cleanup)(&cinfo);
00128 jpeg_destroy_decompress(&cinfo);
00129 return false;
00130 }
00131
00132
00133 unsigned int remain=cinfo.output_height;
00134 unsigned int row_stride = cinfo.output_width * cinfo.output_components;
00135 JSAMPROW rows[remain];
00136 rows[0]=(JSAMPLE*)outbuf;
00137 for(unsigned int i=1; i<remain; i++)
00138 rows[i]=rows[i-1]+row_stride;
00139 JSAMPROW* curpos=rows;
00140
00141
00142
00143 jpeg_start_decompress(&cinfo);
00144 while (remain>0) {
00145 unsigned int used=jpeg_read_scanlines(&cinfo, curpos, remain);
00146 curpos+=used;
00147 remain-=used;
00148 }
00149 jpeg_finish_decompress(&cinfo);
00150 if(jerr.pub.num_warnings>0) {
00151 if(filename.size()>0)
00152 cerr << "Warning: image_util JPEG decompression of '" << filename << "' had warnings" << endl;
00153 else
00154 cerr << "Warning: image_util JPEG decompression had warnings" << endl;
00155 jerr.pub.num_warnings=0;
00156 }
00157
00158
00159 jpeg_destroy_decompress(&cinfo);
00160 return true;
00161 }
00162
00163
00164
00165 bool decodeJPEG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels) {
00166 jpeg_decompress_struct cinfo;
00167 my_error_mgr jerr;
00168 cinfo.err = jpeg_std_error(&jerr.pub);
00169 jerr.pub.error_exit = my_error_exit;
00170
00171 if (setjmp(jerr.setjmp_buffer)) {
00172
00173
00174
00175 jpeg_destroy_decompress(&cinfo);
00176 cerr << "JPEG header check failed: " << jerr.buffer << endl;
00177 return false;
00178 }
00179
00180 jpeg_create_decompress(&cinfo);
00181
00182
00183 tk_jpeg_mem_src(&cinfo, (JOCTET*)inbuf, inbufSize);
00184 jpeg_read_header(&cinfo, true);
00185 cinfo.out_color_space=JCS_YCbCr;
00186 jpeg_calc_output_dimensions(&cinfo);
00187 width=cinfo.output_width;
00188 height=cinfo.output_height;
00189 channels=cinfo.output_components;
00190 jpeg_destroy_decompress(&cinfo);
00191 return true;
00192 }
00193
00194 bool decodeJPEG(std::istream& inStream, size_t& width, size_t& height, size_t& channels) {
00195 jpeg_decompress_struct cinfo;
00196 my_error_mgr jerr;
00197 cinfo.err = jpeg_std_error(&jerr.pub);
00198 jerr.pub.error_exit = my_error_exit;
00199
00200 if (setjmp(jerr.setjmp_buffer)) {
00201
00202
00203
00204 jpeg_istream_revert(&cinfo);
00205 jpeg_destroy_decompress(&cinfo);
00206 cerr << "JPEG stream header check failed: " << jerr.buffer << endl;
00207 return false;
00208 }
00209
00210 jpeg_create_decompress(&cinfo);
00211
00212
00213 jpeg_istream_src(&cinfo, inStream);
00214 jpeg_read_header(&cinfo, true);
00215 cinfo.out_color_space=JCS_YCbCr;
00216 jpeg_calc_output_dimensions(&cinfo);
00217 width=cinfo.output_width;
00218 height=cinfo.output_height;
00219 channels=cinfo.output_components;
00220 bool reverted = jpeg_istream_revert(&cinfo);
00221 jpeg_destroy_decompress(&cinfo);
00222 return reverted;
00223 }
00224
00225 bool decodeJPEG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize, const std::string& filename) {
00226 jpeg_decompress_struct cinfo;
00227 my_error_mgr jerr;
00228 cinfo.err = jpeg_std_error(&jerr.pub);
00229 jerr.pub.error_exit = my_error_exit;
00230
00231 if (setjmp(jerr.setjmp_buffer)) {
00232
00233
00234
00235 jpeg_destroy_decompress(&cinfo);
00236 cerr << "JPEG decompression failed: " << jerr.buffer << endl;
00237 return false;
00238 }
00239
00240 jpeg_create_decompress(&cinfo);
00241
00242
00243 tk_jpeg_mem_src(&cinfo, (JOCTET*)inbuf, inbufSize);
00244 return decodeJPEG(cinfo,jerr,width,height,channels,outbuf,outbufSize,filename);
00245 }
00246
00247 bool decodeJPEG(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize, const std::string& filename) {
00248 jpeg_decompress_struct cinfo;
00249 my_error_mgr jerr;
00250 cinfo.err = jpeg_std_error(&jerr.pub);
00251 jerr.pub.error_exit = my_error_exit;
00252
00253 if (setjmp(jerr.setjmp_buffer)) {
00254
00255
00256
00257 jpeg_istream_revert(&cinfo);
00258 jpeg_destroy_decompress(&cinfo);
00259 cerr << "JPEG stream decompression failed: " << jerr.buffer << endl;
00260 return false;
00261 }
00262
00263 jpeg_create_decompress(&cinfo);
00264
00265
00266 jpeg_istream_src(&cinfo, inStream);
00267 return decodeJPEG(cinfo,jerr,width,height,channels,outbuf,outbufSize,filename,&jpeg_istream_revert);
00268 }
00269
00270
00271
00272
00273
00274 struct png_read_mem_status {
00275 png_bytep buf;
00276 size_t bufsize;
00277 size_t offset;
00278 };
00279
00280 static void user_read_png_data(png_structp png_ptr, png_bytep data, png_size_t length) {
00281 png_read_mem_status* status=(png_read_mem_status*)(png_get_io_ptr(png_ptr));
00282 size_t endoff=status->offset+length;
00283 if(endoff<=status->bufsize) {
00284 memcpy(data,status->buf+status->offset,length);
00285 status->offset=endoff;
00286 } else {
00287 png_error(png_ptr, "Read Error - ran out of file");
00288 }
00289 }
00290
00291 struct png_read_stream_status {
00292 std::istream* is;
00293 std::streamoff n;
00294 };
00295
00296
00297 static void user_read_png_istream(png_structp png_ptr, png_bytep data, png_size_t length) {
00298 png_read_stream_status* status=(png_read_stream_status*)(png_get_io_ptr(png_ptr));
00299 if(!status->is->read((char*)data,length))
00300 png_error(png_ptr, "Read Error - stream closed early");
00301 status->n+=length;
00302 }
00303
00304
00305 struct png_write_mem_status {
00306 png_bytep buf;
00307 size_t bufsize;
00308 size_t offset;
00309 };
00310
00311 void user_write_png_data(png_structp png_ptr, png_bytep data, png_size_t length) {
00312 png_write_mem_status* status=(png_write_mem_status*)(png_get_io_ptr(png_ptr));
00313 size_t endoff=status->offset+length;
00314 if(endoff<=status->bufsize) {
00315 memcpy(status->buf+status->offset,data,length);
00316 status->offset=endoff;
00317 } else {
00318 png_error(png_ptr, "Write Error - ran out of file");
00319 }
00320 }
00321
00322 void user_flush_png_data(png_structp ) {}
00323
00324 typedef int (*png_cleanup_f)(png_structp png_ptr);
00325 int png_istream_revert(png_structp png_ptr) {
00326 png_read_stream_status* status=(png_read_stream_status*)(png_get_io_ptr(png_ptr));
00327 status->is->seekg(-status->n,ios_base::cur);
00328 status->n=0;
00329 return status->is->good();
00330 }
00331
00332
00333 bool decodePNG(png_structp png_ptr, png_infop info_ptr, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize, png_cleanup_f png_cleanup=NULL) {
00334
00335 png_read_info(png_ptr, info_ptr);
00336 width=png_get_image_width(png_ptr, info_ptr);
00337 height=png_get_image_height(png_ptr, info_ptr);
00338 channels=3;
00339 if(width==0 || height==0)
00340 return true;
00341 if(outbuf==NULL) {
00342 outbufSize=width*height*channels;
00343 outbuf=new char[outbufSize];
00344 } else if(width*height*channels>outbufSize) {
00345 if(png_cleanup)
00346 (*png_cleanup)(png_ptr);
00347 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00348 return false;
00349 }
00350
00351
00352 size_t bit_depth=png_get_bit_depth(png_ptr, info_ptr);
00353 if(bit_depth == 16)
00354 png_set_strip_16(png_ptr);
00355 if (bit_depth < 8)
00356 png_set_packing(png_ptr);
00357
00358 size_t color_type=png_get_color_type(png_ptr, info_ptr);
00359 if (color_type & PNG_COLOR_MASK_ALPHA)
00360 png_set_strip_alpha(png_ptr);
00361 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00362 png_set_gray_to_rgb(png_ptr);
00363
00364 png_color_16 my_background;
00365 my_background.index=0;
00366 my_background.red=1<<15;
00367 my_background.green=1<<15;
00368 my_background.blue=1<<15;
00369 my_background.gray=1<<15;
00370 png_color_16p image_background=NULL;
00371 if (png_get_bKGD(png_ptr, info_ptr, &image_background))
00372 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
00373 else
00374 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
00375 png_read_update_info(png_ptr, info_ptr);
00376
00377
00378 size_t rowbytes=png_get_rowbytes(png_ptr, info_ptr);
00379
00380
00381
00382
00383
00384 png_bytep row=reinterpret_cast<png_bytep>(outbuf);
00385 for(unsigned int h=0; h<height; ++h) {
00386 if(row+rowbytes>reinterpret_cast<png_bytep>(outbuf+outbufSize)) {
00387 cerr << "image_util::decodePNG ran out of PNG buffer space" << endl;
00388 break;
00389 }
00390
00391 png_read_row(png_ptr, row, NULL);
00392 row+=rowbytes;
00393 }
00394 png_read_end(png_ptr, NULL);
00395
00396
00397 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00398 return true;
00399 }
00400
00401
00402
00403 bool decodePNG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels) {
00404 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00405 if (!png_ptr)
00406 return false;
00407 png_infop info_ptr = png_create_info_struct(png_ptr);
00408 if (!info_ptr) {
00409 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00410 return false;
00411 }
00412 if (setjmp(png_jmpbuf(png_ptr))) {
00413 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00414 return false;
00415 }
00416
00417 png_read_mem_status read_status;
00418 read_status.buf=(png_bytep)inbuf;
00419 read_status.bufsize=inbufSize;
00420 read_status.offset=0;
00421 png_set_read_fn(png_ptr, &read_status, user_read_png_data);
00422
00423
00424 png_read_info(png_ptr, info_ptr);
00425 width=png_get_image_width(png_ptr, info_ptr);
00426 height=png_get_image_height(png_ptr, info_ptr);
00427 channels=3;
00428 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00429 return true;
00430 }
00431
00432 bool decodePNG(std::istream& inStream, size_t& width, size_t& height, size_t& channels) {
00433 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00434 if (!png_ptr)
00435 return false;
00436 png_infop info_ptr = png_create_info_struct(png_ptr);
00437 if (!info_ptr) {
00438 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00439 return false;
00440 }
00441 if (setjmp(png_jmpbuf(png_ptr))) {
00442 png_istream_revert(png_ptr);
00443 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00444 return false;
00445 }
00446
00447 png_read_stream_status status;
00448 status.is = &inStream;
00449 status.n = 0;
00450 png_set_read_fn(png_ptr, &status, user_read_png_istream);
00451
00452
00453 png_read_info(png_ptr, info_ptr);
00454 width=png_get_image_width(png_ptr, info_ptr);
00455 height=png_get_image_height(png_ptr, info_ptr);
00456 channels=3;
00457 bool reverted = png_istream_revert(png_ptr);
00458 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00459 return reverted;
00460 }
00461
00462 bool decodePNG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00463 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00464 if (!png_ptr)
00465 return false;
00466 png_infop info_ptr = png_create_info_struct(png_ptr);
00467 if (!info_ptr) {
00468 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00469 return false;
00470 }
00471 if (setjmp(png_jmpbuf(png_ptr))) {
00472 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00473 return false;
00474 }
00475
00476 png_read_mem_status read_status;
00477 read_status.buf=(png_bytep)inbuf;
00478 read_status.bufsize=inbufSize;
00479 read_status.offset=0;
00480 png_set_read_fn(png_ptr, &read_status, user_read_png_data);
00481 return decodePNG(png_ptr, info_ptr, width, height, channels, outbuf, outbufSize);
00482 }
00483
00484 bool decodePNGToDepth(png_structp png_ptr, png_infop info_ptr, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize, png_cleanup_f png_cleanup=NULL) {
00485
00486 png_read_info(png_ptr, info_ptr);
00487 width=png_get_image_width(png_ptr, info_ptr);
00488 height=png_get_image_height(png_ptr, info_ptr);
00489 channels=2;
00490 if(width==0 || height==0)
00491 return true;
00492 if(outbuf==NULL) {
00493 outbufSize=width*height*channels;
00494 outbuf=new char[outbufSize];
00495 } else if(width*height*channels>outbufSize) {
00496 if(png_cleanup)
00497 (*png_cleanup)(png_ptr);
00498 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00499 return false;
00500 }
00501
00502
00503 size_t bit_depth=png_get_bit_depth(png_ptr, info_ptr);
00504 if(bit_depth == 16)
00505 png_set_strip_16(png_ptr);
00506 if (bit_depth < 8)
00507 png_set_packing(png_ptr);
00508
00509 size_t color_type=png_get_color_type(png_ptr, info_ptr);
00510 if (color_type & PNG_COLOR_MASK_ALPHA)
00511 png_set_strip_alpha(png_ptr);
00512 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
00513 png_set_gray_to_rgb(png_ptr);
00514
00515 png_color_16 my_background;
00516 my_background.index=0;
00517 my_background.red=1<<15;
00518 my_background.green=1<<15;
00519 my_background.blue=1<<15;
00520 my_background.gray=1<<15;
00521 png_color_16p image_background=NULL;
00522 if (png_get_bKGD(png_ptr, info_ptr, &image_background))
00523 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
00524 else
00525 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
00526 png_read_update_info(png_ptr, info_ptr);
00527
00528
00529 size_t rowbytes=png_get_rowbytes(png_ptr, info_ptr);
00530
00531 png_bytep row = (png_bytep) (new char*[rowbytes]);
00532
00533 for (unsigned int i = 0; i < rowbytes; ++i) {
00534 row[i] = 0;
00535 }
00536
00537
00538
00539 unsigned short* outputBuf = (unsigned short*) outbuf;
00540
00541 for(unsigned int h=0; h<height; ++h) {
00542
00543 png_read_row(png_ptr, row, NULL);
00544
00545 for (unsigned int w = 0; w < width; ++w) {
00546
00547 int y = row[0 + 3 * w];
00548
00549
00550
00551
00552 double d = (y - 16) / 220.0 * 10000;
00553 unsigned short depth = d;
00554 if (depth > 10000) {
00555 depth = 10000;
00556 }
00557 if (depth < 800) {
00558 depth = 0;
00559 }
00560 *outputBuf++ = depth;
00561 }
00562 }
00563
00564
00565 png_read_end(png_ptr, NULL);
00566
00567
00568 delete(row);
00569 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00570 return true;
00571 }
00572
00573 bool decodePNGToDepth(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00574 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00575 if (!png_ptr)
00576 return false;
00577 png_infop info_ptr = png_create_info_struct(png_ptr);
00578 if (!info_ptr) {
00579 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00580 return false;
00581 }
00582 if (setjmp(png_jmpbuf(png_ptr))) {
00583 png_istream_revert(png_ptr);
00584 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00585 return false;
00586 }
00587
00588 png_read_stream_status status;
00589 status.is = &inStream;
00590 status.n = 0;
00591 png_set_read_fn(png_ptr, &status, user_read_png_istream);
00592 return decodePNGToDepth(png_ptr, info_ptr, width, height, channels, outbuf, outbufSize, png_istream_revert);
00593 }
00594
00595 bool decodePNG(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00596 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00597 if (!png_ptr)
00598 return false;
00599 png_infop info_ptr = png_create_info_struct(png_ptr);
00600 if (!info_ptr) {
00601 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00602 return false;
00603 }
00604 if (setjmp(png_jmpbuf(png_ptr))) {
00605 png_istream_revert(png_ptr);
00606 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00607 return false;
00608 }
00609
00610 png_read_stream_status status;
00611 status.is = &inStream;
00612 status.n = 0;
00613 png_set_read_fn(png_ptr, &status, user_read_png_istream);
00614 return decodePNG(png_ptr, info_ptr, width, height, channels, outbuf, outbufSize, png_istream_revert);
00615 }
00616
00617
00618
00619 const unsigned int TEST_HEADER_LEN=8;
00620 bool decodeImage(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels) {
00621 if(!png_sig_cmp((png_byte*)inbuf, 0, TEST_HEADER_LEN)) {
00622 return decodePNG(inbuf,inbufSize,width,height,channels);
00623 } else {
00624 return decodeJPEG(inbuf,inbufSize,width,height,channels);
00625 }
00626 }
00627 bool decodeImage(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00628 if(!png_sig_cmp((png_byte*)inbuf, 0, TEST_HEADER_LEN)) {
00629 return decodePNG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00630 } else {
00631 return decodeJPEG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00632 }
00633 }
00634 bool decodeImage(std::istream& inStream, size_t& width, size_t& height, size_t& channels) {
00635 char header[TEST_HEADER_LEN];
00636 inStream.read(header,TEST_HEADER_LEN);
00637 size_t cnt = (size_t)inStream.gcount();
00638 if(cnt==0)
00639 return false;
00640 if(!inStream.seekg(-cnt,ios_base::cur))
00641 return false;
00642 bool png = !png_sig_cmp((png_byte*)header, 0, cnt);
00643 if(png)
00644 return false;
00645 else
00646 return decodeJPEG(inStream, width, height, channels);
00647 }
00648 bool decodeImage(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00649 char header[TEST_HEADER_LEN];
00650 inStream.read(header,TEST_HEADER_LEN);
00651 size_t cnt = (size_t)inStream.gcount();
00652 if(cnt==0)
00653 return false;
00654 if(!inStream.seekg(-cnt,ios_base::cur))
00655 return false;
00656 bool png = !png_sig_cmp((png_byte*)header, 0, cnt);
00657 if(png)
00658 return decodePNG(inStream, width, height, channels, outbuf, outbufSize);
00659 else
00660 return decodeJPEG(inStream, width, height, channels, outbuf, outbufSize);
00661 }
00662
00663
00664
00665 bool loadJPEG(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00666 char* inbuf;
00667 size_t inbufSize;
00668 if(!loadFile(file, inbuf, inbufSize))
00669 return false;
00670 bool res=decodeJPEG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00671 releaseFile(inbuf,inbufSize);
00672 return res;
00673 }
00674 bool loadPNG(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00675 char* inbuf;
00676 size_t inbufSize;
00677 if(!loadFile(file, inbuf, inbufSize))
00678 return false;
00679 bool res=decodePNG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00680 releaseFile(inbuf,inbufSize);
00681 return res;
00682 }
00683 bool loadImage(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00684 char* inbuf;
00685 size_t inbufSize;
00686 if(!loadFile(file, inbuf, inbufSize))
00687 return false;
00688 bool res=decodeImage(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00689 releaseFile(inbuf,inbufSize);
00690 return res;
00691 }
00692
00693
00694
00695 size_t encodeJPEG(const char* inbuf, size_t inbufSize, size_t width, size_t height, size_t inbufChannels, char*& outbuf, size_t& outbufSize, size_t outbufChannels, int quality) {
00696 jpeg_compress_struct cinfo;
00697 jpeg_error_mgr jerr;
00698
00699
00700 cinfo.err = jpeg_std_error(&jerr);
00701 jpeg_create_compress(&cinfo);
00702 size_t ans=encodeJPEG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,quality,cinfo);
00703 jpeg_destroy_compress(&cinfo);
00704 return ans;
00705 }
00706 size_t encodeJPEG(const char* inbuf, size_t inbufSize, size_t width, size_t height, size_t inbufChannels, char*& outbuf, size_t& outbufSize, size_t outbufChannels, int quality, jpeg_compress_struct& cinfo) {
00707 return encodeJPEG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,quality,1,1,cinfo);
00708 }
00709 size_t encodeJPEG(const char* inbuf, size_t inbufSize, size_t width, size_t height, size_t inbufChannels, char*& outbuf, size_t& outbufSize, size_t outbufChannels, int quality, unsigned int yskip, unsigned int uvskip, jpeg_compress_struct& cinfo) {
00710 try {
00711 if(quality>100)
00712 quality=100;
00713 if(quality<0)
00714 quality=0;
00715
00716 if(outbuf==NULL) {
00717 outbufSize=width*height*outbufChannels*(quality+50)/200+768;
00718 outbuf=new char[outbufSize];
00719 }
00720
00721
00722 tk_jpeg_mem_dest(&cinfo, reinterpret_cast<JOCTET*>(outbuf), outbufSize);
00723
00724
00725 cinfo.image_width = width;
00726 cinfo.image_height = height;
00727 cinfo.input_components = inbufChannels;
00728 if(inbufChannels==1) {
00729 cinfo.in_color_space = JCS_GRAYSCALE;
00730 } else if(inbufChannels==3) {
00731 cinfo.in_color_space = JCS_YCbCr;
00732 } else if(inbufChannels==-3U) {
00733
00734 cinfo.input_components = inbufChannels = 3;
00735 cinfo.in_color_space = JCS_RGB;
00736 } else {
00737 cerr << "image_util JPEG compression failed - don't know how to compress into " << outbufChannels << " channels" << endl;
00738 return 0;
00739 }
00740
00741
00742 jpeg_set_defaults(&cinfo);
00743 jpeg_set_quality(&cinfo, quality, false);
00744 #ifndef NO_TEKKOTSU_CONFIG
00745 cinfo.dct_method=config->vision.jpeg_dct_method;
00746 #endif
00747 if(cinfo.in_color_space==JCS_GRAYSCALE && inbufChannels!=1) {
00748
00749 jpeg_start_compress(&cinfo, true);
00750 unsigned int row_stride = width*inbufChannels;
00751 JSAMPROW row_pointer[1] = { new JSAMPLE[width] };
00752 while (cinfo.next_scanline < cinfo.image_height) {
00753 if(inbufSize<row_stride) {
00754 cerr << "image_util ran out of input buffer during JPEG grayscale compression" << endl;
00755 break;
00756 }
00757 for(unsigned int x=0; x<width; x++)
00758 row_pointer[0][x] = inbuf[x*inbufChannels];
00759 jpeg_write_scanlines(&cinfo, row_pointer, 1);
00760 inbuf+=row_stride;
00761 inbufSize-=row_stride;
00762 }
00763 jpeg_finish_compress(&cinfo);
00764 delete [] row_pointer[0];
00765
00766 } else {
00767 if(cinfo.in_color_space==JCS_YCbCr) {
00768 unsigned int ysamp=1;
00769 unsigned int uvsamp=1;
00770 const unsigned int maxsamp=2;
00771 if(yskip>uvskip) {
00772 uvsamp=yskip-uvskip+1;
00773 if(uvsamp>maxsamp)
00774 uvsamp=maxsamp;
00775 } else {
00776 ysamp=uvskip-yskip+1;
00777 if(ysamp>maxsamp)
00778 ysamp=maxsamp;
00779 }
00780 cinfo.comp_info[0].h_samp_factor=ysamp;
00781 cinfo.comp_info[0].v_samp_factor=ysamp;
00782 cinfo.comp_info[1].h_samp_factor=uvsamp;
00783 cinfo.comp_info[1].v_samp_factor=uvsamp;
00784 cinfo.comp_info[2].h_samp_factor=uvsamp;
00785 cinfo.comp_info[2].v_samp_factor=uvsamp;
00786 }
00787
00788
00789 jpeg_start_compress(&cinfo, true);
00790 unsigned int row_stride = width*inbufChannels;
00791 JSAMPROW row_pointer[1] = { const_cast<JSAMPROW>(reinterpret_cast<const JSAMPLE*>(inbuf)) };
00792 while (cinfo.next_scanline < cinfo.image_height) {
00793 if(inbufSize<row_stride) {
00794 cerr << "image_util ran out of input buffer during JPEG compression" << endl;
00795 break;
00796 }
00797 jpeg_write_scanlines(&cinfo, row_pointer, 1);
00798 row_pointer[0]+=row_stride;
00799 inbufSize-=row_stride;
00800 }
00801 jpeg_finish_compress(&cinfo);
00802 }
00803
00804
00805 return tk_jpeg_mem_size(&cinfo);
00806 } catch(const std::exception& ex) {
00807 std::cerr << "image_util Exception while compressing JPEG: " << ex.what() << std::endl;
00808 jpeg_finish_compress(&cinfo);
00809 }
00810 return 0;
00811 }
00812
00813 size_t encodePNG(const char* inbuf, size_t inbufSize, size_t width, size_t height, size_t inbufChannels, char*& outbuf, size_t& outbufSize, size_t outbufChannels) {
00814 return encodePNG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,Z_DEFAULT_COMPRESSION);
00815 }
00816
00817 size_t encodePNG(const char* inbuf, size_t inbufSize, size_t width, size_t height, size_t inbufChannels, char*& outbuf, size_t& outbufSize, size_t outbufChannels, int compressionLevel) {
00818 if(compressionLevel!=Z_DEFAULT_COMPRESSION) {
00819 if(compressionLevel<Z_NO_COMPRESSION)
00820 compressionLevel=Z_NO_COMPRESSION;
00821 if(compressionLevel>Z_BEST_COMPRESSION)
00822 compressionLevel=Z_BEST_COMPRESSION;
00823 }
00824
00825
00826 if(outbuf==NULL) {
00827 outbufSize=width*height*outbufChannels + 256;
00828 if(compressionLevel==Z_NO_COMPRESSION)
00829 outbufSize=static_cast<size_t>(outbufSize*1.005+50);
00830 else
00831 outbufSize=static_cast<size_t>(outbufSize*2.0/3.0+1);
00832 outbuf=new char[outbufSize];
00833 }
00834
00835
00836 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00837 if (!png_ptr) {
00838 cerr << "image_util::encodePNG(): png_create_write_struct failed" << endl;
00839 return 0;
00840 }
00841 png_infop info_ptr = png_create_info_struct(png_ptr);
00842 if (!info_ptr) {
00843 png_destroy_write_struct(&png_ptr, NULL);
00844 cerr << "image_util::encodePNG(): png_create_info_struct failed" << endl;
00845 return 0;
00846 }
00847
00848 png_write_mem_status write_status;
00849 write_status.buf=reinterpret_cast<png_byte*>(outbuf);
00850 write_status.bufsize=outbufSize;
00851 write_status.offset=0;
00852 png_set_write_fn(png_ptr, &write_status, user_write_png_data, user_flush_png_data);
00853
00854 if(setjmp(png_jmpbuf(png_ptr))) {
00855 cerr << "An error occurred during PNG compression" << endl;
00856 png_destroy_write_struct(&png_ptr, &info_ptr);
00857 return 0;
00858 }
00859
00860
00861 int bit_depth=8;
00862 int color_type;
00863 if(outbufChannels==3)
00864 color_type=PNG_COLOR_TYPE_RGB;
00865 else if(outbufChannels==1)
00866 color_type=PNG_COLOR_TYPE_GRAY;
00867 else {
00868 cerr << "image_util PNG compression failed - don't know how to compress into " << outbufChannels << " channels" << endl;
00869 return 0;
00870 }
00871 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00872 png_set_compression_level(png_ptr,compressionLevel);
00873 png_write_info(png_ptr, info_ptr);
00874 png_byte* row=const_cast<png_byte*>(reinterpret_cast<const png_byte*>(inbuf));
00875 const unsigned int inc=inbufChannels;
00876 #ifdef DEBUG
00877 if( (color_type==PNG_COLOR_TYPE_RGB && inc!=3) || (color_type==PNG_COLOR_TYPE_GRAY && inc!=1) ) {
00878 cerr << "image_util::encodePNG() only supports color mode from sources with interleaving of 3 samples (increment==3), or grayscale from \"pure\" sources (increment==1)" << endl;
00879 png_write_end(png_ptr, NULL);
00880 return 0;
00881 }
00882 #endif
00883
00884
00885 unsigned int row_stride = width*inc;
00886 const png_byte* endp=reinterpret_cast<const png_byte*>(row+inbufSize);
00887 for(unsigned int h=0; h<height; ++h) {
00888 if(row+row_stride>endp) {
00889 cerr << "image_util ran out of src image -- bad height?" << endl;
00890 break;
00891 }
00892 png_write_row(png_ptr, row);
00893 row+=row_stride;
00894 }
00895 png_write_end(png_ptr, NULL);
00896 png_destroy_write_struct(&png_ptr, &info_ptr);
00897
00898
00899 return write_status.offset;
00900 }
00901
00902 }
00903
00904
00905
00906
00907