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 png_read_row(png_ptr, row, NULL);
00391 row+=rowbytes;
00392 }
00393 png_read_end(png_ptr, NULL);
00394
00395
00396 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00397 return true;
00398 }
00399
00400
00401
00402 bool decodePNG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels) {
00403 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00404 if (!png_ptr)
00405 return false;
00406 png_infop info_ptr = png_create_info_struct(png_ptr);
00407 if (!info_ptr) {
00408 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00409 return false;
00410 }
00411 if (setjmp(png_jmpbuf(png_ptr))) {
00412 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00413 return false;
00414 }
00415
00416 png_read_mem_status read_status;
00417 read_status.buf=(png_bytep)inbuf;
00418 read_status.bufsize=inbufSize;
00419 read_status.offset=0;
00420 png_set_read_fn(png_ptr, &read_status, user_read_png_data);
00421
00422
00423 png_read_info(png_ptr, info_ptr);
00424 width=png_get_image_width(png_ptr, info_ptr);
00425 height=png_get_image_height(png_ptr, info_ptr);
00426 channels=3;
00427 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00428 return true;
00429 }
00430
00431 bool decodePNG(std::istream& inStream, size_t& width, size_t& height, size_t& channels) {
00432 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00433 if (!png_ptr)
00434 return false;
00435 png_infop info_ptr = png_create_info_struct(png_ptr);
00436 if (!info_ptr) {
00437 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00438 return false;
00439 }
00440 if (setjmp(png_jmpbuf(png_ptr))) {
00441 png_istream_revert(png_ptr);
00442 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00443 return false;
00444 }
00445
00446 png_read_stream_status status;
00447 status.is = &inStream;
00448 status.n = 0;
00449 png_set_read_fn(png_ptr, &status, user_read_png_istream);
00450
00451
00452 png_read_info(png_ptr, info_ptr);
00453 width=png_get_image_width(png_ptr, info_ptr);
00454 height=png_get_image_height(png_ptr, info_ptr);
00455 channels=3;
00456 bool reverted = png_istream_revert(png_ptr);
00457 png_destroy_read_struct(&png_ptr, &info_ptr,(png_infopp)NULL);
00458 return reverted;
00459 }
00460
00461 bool decodePNG(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00462 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00463 if (!png_ptr)
00464 return false;
00465 png_infop info_ptr = png_create_info_struct(png_ptr);
00466 if (!info_ptr) {
00467 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00468 return false;
00469 }
00470 if (setjmp(png_jmpbuf(png_ptr))) {
00471 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00472 return false;
00473 }
00474
00475 png_read_mem_status read_status;
00476 read_status.buf=(png_bytep)inbuf;
00477 read_status.bufsize=inbufSize;
00478 read_status.offset=0;
00479 png_set_read_fn(png_ptr, &read_status, user_read_png_data);
00480 return decodePNG(png_ptr, info_ptr, width, height, channels, outbuf, outbufSize);
00481 }
00482
00483 bool decodePNG(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00484 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL);
00485 if (!png_ptr)
00486 return false;
00487 png_infop info_ptr = png_create_info_struct(png_ptr);
00488 if (!info_ptr) {
00489 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
00490 return false;
00491 }
00492 if (setjmp(png_jmpbuf(png_ptr))) {
00493 png_istream_revert(png_ptr);
00494 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
00495 return false;
00496 }
00497
00498 png_read_stream_status status;
00499 status.is = &inStream;
00500 status.n = 0;
00501 png_set_read_fn(png_ptr, &status, user_read_png_istream);
00502 return decodePNG(png_ptr, info_ptr, width, height, channels, outbuf, outbufSize, png_istream_revert);
00503 }
00504
00505
00506
00507 const unsigned int TEST_HEADER_LEN=8;
00508 bool decodeImage(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels) {
00509 if(!png_sig_cmp((png_byte*)inbuf, 0, TEST_HEADER_LEN)) {
00510 return decodePNG(inbuf,inbufSize,width,height,channels);
00511 } else {
00512 return decodeJPEG(inbuf,inbufSize,width,height,channels);
00513 }
00514 }
00515 bool decodeImage(char* inbuf, size_t inbufSize, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00516 if(!png_sig_cmp((png_byte*)inbuf, 0, TEST_HEADER_LEN)) {
00517 return decodePNG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00518 } else {
00519 return decodeJPEG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00520 }
00521 }
00522 bool decodeImage(std::istream& inStream, size_t& width, size_t& height, size_t& channels) {
00523 char header[TEST_HEADER_LEN];
00524 inStream.read(header,TEST_HEADER_LEN);
00525 size_t cnt = (size_t)inStream.gcount();
00526 if(cnt==0)
00527 return false;
00528 if(!inStream.seekg(-cnt,ios_base::cur))
00529 return false;
00530 bool png = !png_sig_cmp((png_byte*)header, 0, cnt);
00531 if(png)
00532 return false;
00533 else
00534 return decodeJPEG(inStream, width, height, channels);
00535 }
00536 bool decodeImage(std::istream& inStream, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00537 char header[TEST_HEADER_LEN];
00538 inStream.read(header,TEST_HEADER_LEN);
00539 size_t cnt = (size_t)inStream.gcount();
00540 if(cnt==0)
00541 return false;
00542 if(!inStream.seekg(-cnt,ios_base::cur))
00543 return false;
00544 bool png = !png_sig_cmp((png_byte*)header, 0, cnt);
00545 if(png)
00546 return decodePNG(inStream, width, height, channels, outbuf, outbufSize);
00547 else
00548 return decodeJPEG(inStream, width, height, channels, outbuf, outbufSize);
00549 }
00550
00551
00552
00553 bool loadJPEG(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00554 char* inbuf;
00555 size_t inbufSize;
00556 if(!loadFile(file, inbuf, inbufSize))
00557 return false;
00558 bool res=decodeJPEG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00559 releaseFile(inbuf,inbufSize);
00560 return res;
00561 }
00562 bool loadPNG(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00563 char* inbuf;
00564 size_t inbufSize;
00565 if(!loadFile(file, inbuf, inbufSize))
00566 return false;
00567 bool res=decodePNG(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00568 releaseFile(inbuf,inbufSize);
00569 return res;
00570 }
00571 bool loadImage(const std::string& file, size_t& width, size_t& height, size_t& channels, char*& outbuf, size_t& outbufSize) {
00572 char* inbuf;
00573 size_t inbufSize;
00574 if(!loadFile(file, inbuf, inbufSize))
00575 return false;
00576 bool res=decodeImage(inbuf,inbufSize,width,height,channels,outbuf,outbufSize);
00577 releaseFile(inbuf,inbufSize);
00578 return res;
00579 }
00580
00581
00582
00583 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) {
00584 jpeg_compress_struct cinfo;
00585 jpeg_error_mgr jerr;
00586
00587
00588 cinfo.err = jpeg_std_error(&jerr);
00589 jpeg_create_compress(&cinfo);
00590 size_t ans=encodeJPEG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,quality,cinfo);
00591 jpeg_destroy_compress(&cinfo);
00592 return ans;
00593 }
00594 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) {
00595 return encodeJPEG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,quality,1,1,cinfo);
00596 }
00597 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) {
00598 try {
00599 if(quality>100)
00600 quality=100;
00601 if(quality<0)
00602 quality=0;
00603
00604 if(outbuf==NULL) {
00605 outbufSize=width*height*outbufChannels*(quality+50)/200+768;
00606 outbuf=new char[outbufSize];
00607 }
00608
00609
00610 tk_jpeg_mem_dest(&cinfo, reinterpret_cast<JOCTET*>(outbuf), outbufSize);
00611
00612
00613 cinfo.image_width = width;
00614 cinfo.image_height = height;
00615 cinfo.input_components = inbufChannels;
00616 if(inbufChannels==1) {
00617 cinfo.in_color_space = JCS_GRAYSCALE;
00618 } else if(inbufChannels==3) {
00619 cinfo.in_color_space = JCS_YCbCr;
00620 } else if(inbufChannels==-3U) {
00621
00622 cinfo.input_components = inbufChannels = 3;
00623 cinfo.in_color_space = JCS_RGB;
00624 } else {
00625 cerr << "image_util JPEG compression failed - don't know how to compress into " << outbufChannels << " channels" << endl;
00626 return 0;
00627 }
00628
00629
00630 jpeg_set_defaults(&cinfo);
00631 jpeg_set_quality(&cinfo, quality, false);
00632 #ifndef NO_TEKKOTSU_CONFIG
00633 cinfo.dct_method=config->vision.jpeg_dct_method;
00634 #endif
00635 if(cinfo.in_color_space==JCS_GRAYSCALE && inbufChannels!=1) {
00636
00637 jpeg_start_compress(&cinfo, true);
00638 unsigned int row_stride = width*inbufChannels;
00639 JSAMPROW row_pointer[1] = { new JSAMPLE[width] };
00640 while (cinfo.next_scanline < cinfo.image_height) {
00641 if(inbufSize<row_stride) {
00642 cerr << "image_util ran out of input buffer during JPEG grayscale compression" << endl;
00643 break;
00644 }
00645 for(unsigned int x=0; x<width; x++)
00646 row_pointer[0][x] = inbuf[x*inbufChannels];
00647 jpeg_write_scanlines(&cinfo, row_pointer, 1);
00648 inbuf+=row_stride;
00649 inbufSize-=row_stride;
00650 }
00651 jpeg_finish_compress(&cinfo);
00652 delete [] row_pointer[0];
00653
00654 } else {
00655 if(cinfo.in_color_space==JCS_YCbCr) {
00656 unsigned int ysamp=1;
00657 unsigned int uvsamp=1;
00658 const unsigned int maxsamp=2;
00659 if(yskip>uvskip) {
00660 uvsamp=yskip-uvskip+1;
00661 if(uvsamp>maxsamp)
00662 uvsamp=maxsamp;
00663 } else {
00664 ysamp=uvskip-yskip+1;
00665 if(ysamp>maxsamp)
00666 ysamp=maxsamp;
00667 }
00668 cinfo.comp_info[0].h_samp_factor=ysamp;
00669 cinfo.comp_info[0].v_samp_factor=ysamp;
00670 cinfo.comp_info[1].h_samp_factor=uvsamp;
00671 cinfo.comp_info[1].v_samp_factor=uvsamp;
00672 cinfo.comp_info[2].h_samp_factor=uvsamp;
00673 cinfo.comp_info[2].v_samp_factor=uvsamp;
00674 }
00675
00676
00677 jpeg_start_compress(&cinfo, true);
00678 unsigned int row_stride = width*inbufChannels;
00679 JSAMPROW row_pointer[1] = { const_cast<JSAMPROW>(reinterpret_cast<const JSAMPLE*>(inbuf)) };
00680 while (cinfo.next_scanline < cinfo.image_height) {
00681 if(inbufSize<row_stride) {
00682 cerr << "image_util ran out of input buffer during JPEG compression" << endl;
00683 break;
00684 }
00685 jpeg_write_scanlines(&cinfo, row_pointer, 1);
00686 row_pointer[0]+=row_stride;
00687 inbufSize-=row_stride;
00688 }
00689 jpeg_finish_compress(&cinfo);
00690 }
00691
00692
00693 return tk_jpeg_mem_size(&cinfo);
00694 } catch(const std::exception& ex) {
00695 std::cerr << "image_util Exception while compressing JPEG: " << ex.what() << std::endl;
00696 jpeg_finish_compress(&cinfo);
00697 }
00698 return 0;
00699 }
00700
00701 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) {
00702 return encodePNG(inbuf,inbufSize,width,height,inbufChannels,outbuf,outbufSize,outbufChannels,Z_DEFAULT_COMPRESSION);
00703 }
00704
00705 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) {
00706 if(compressionLevel!=Z_DEFAULT_COMPRESSION) {
00707 if(compressionLevel<Z_NO_COMPRESSION)
00708 compressionLevel=Z_NO_COMPRESSION;
00709 if(compressionLevel>Z_BEST_COMPRESSION)
00710 compressionLevel=Z_BEST_COMPRESSION;
00711 }
00712
00713
00714 if(outbuf==NULL) {
00715 outbufSize=width*height*outbufChannels + 256;
00716 if(compressionLevel==Z_NO_COMPRESSION)
00717 outbufSize=static_cast<size_t>(outbufSize*1.005+50);
00718 else
00719 outbufSize=static_cast<size_t>(outbufSize*2.0/3.0+1);
00720 outbuf=new char[outbufSize];
00721 }
00722
00723
00724 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
00725 if (!png_ptr) {
00726 cerr << "image_util::encodePNG(): png_create_write_struct failed" << endl;
00727 return 0;
00728 }
00729 png_infop info_ptr = png_create_info_struct(png_ptr);
00730 if (!info_ptr) {
00731 png_destroy_write_struct(&png_ptr, NULL);
00732 cerr << "image_util::encodePNG(): png_create_info_struct failed" << endl;
00733 return 0;
00734 }
00735
00736 png_write_mem_status write_status;
00737 write_status.buf=reinterpret_cast<png_byte*>(outbuf);
00738 write_status.bufsize=outbufSize;
00739 write_status.offset=0;
00740 png_set_write_fn(png_ptr, &write_status, user_write_png_data, user_flush_png_data);
00741
00742 if(setjmp(png_jmpbuf(png_ptr))) {
00743 cerr << "An error occurred during PNG compression" << endl;
00744 png_destroy_write_struct(&png_ptr, &info_ptr);
00745 return 0;
00746 }
00747
00748
00749 int bit_depth=8;
00750 int color_type;
00751 if(outbufChannels==3)
00752 color_type=PNG_COLOR_TYPE_RGB;
00753 else if(outbufChannels==1)
00754 color_type=PNG_COLOR_TYPE_GRAY;
00755 else {
00756 cerr << "image_util PNG compression failed - don't know how to compress into " << outbufChannels << " channels" << endl;
00757 return 0;
00758 }
00759 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
00760 png_set_compression_level(png_ptr,compressionLevel);
00761 png_write_info(png_ptr, info_ptr);
00762 png_byte* row=const_cast<png_byte*>(reinterpret_cast<const png_byte*>(inbuf));
00763 const unsigned int inc=inbufChannels;
00764 #ifdef DEBUG
00765 if( (color_type==PNG_COLOR_TYPE_RGB && inc!=3) || (color_type==PNG_COLOR_TYPE_GRAY && inc!=1) ) {
00766 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;
00767 png_write_end(png_ptr, NULL);
00768 return 0;
00769 }
00770 #endif
00771
00772
00773 unsigned int row_stride = width*inc;
00774 const png_byte* endp=reinterpret_cast<const png_byte*>(row+inbufSize);
00775 for(unsigned int h=0; h<height; ++h) {
00776 if(row+row_stride>endp) {
00777 cerr << "image_util ran out of src image -- bad height?" << endl;
00778 break;
00779 }
00780 png_write_row(png_ptr, row);
00781 row+=row_stride;
00782 }
00783 png_write_end(png_ptr, NULL);
00784 png_destroy_write_struct(&png_ptr, &info_ptr);
00785
00786
00787 return write_status.offset;
00788 }
00789
00790 }
00791
00792
00793
00794
00795