/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include extern jmp_buf jpeg_jmp_buf; extern GLOBAL(struct jpeg_error_mgr *) my_jpeg_std_error (struct jpeg_error_mgr * err); extern GLOBAL(void) my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile); } #include #include using namespace rtengine::procparams; using namespace rtengine; Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheFileStruct* cf, int fpos) : cachemgr(cm), cfs(cf), tImgData(NULL), tw(-1), th(-1), pparamsValid(false), filePos(fpos), fname(fname), lastImg(NULL), ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { mutex = new Glib::Mutex (); loadProcParams (); if (options.liveThumbnails!=cfs->thumbProcessed) { cfs->thumbProcessed = options.liveThumbnails; generateThumbnailImage (false); } if (!tImgData || !tpp) loadThumbnail (options.thumbCacheMemPolicy==MP_Memory); } Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5, CacheFileStruct* cf, int fpos) : cachemgr(cm), cfs(cf), pparamsValid(false), filePos(fpos), lastImg(NULL), tImgData(NULL), fname(fname), ref(1), enqueueNumber(0), tpp(NULL), needsReProcessing(true) { mutex = new Glib::Mutex (); memcpy (cfs->MD5, md5.c_str(), 32); cfs->ppformat = 0; cfs->preinterp = 0; cfs->accessed = -1; cfs->rank = 0; cfs->stage = 0; cfs->thumbnail = FT_Invalid; cfs->recentlySaved = false; cfs->thumbProcessed = options.liveThumbnails; generateThumbnailImage (false); } void Thumbnail::generateThumbnailImage (bool useLock) { mutex->lock (); if (cfs->thumbProcessed) generateProcessedThumbnailImage (useLock); else generatePreviewThumbnailImage (useLock); mutex->unlock (); } void Thumbnail::generatePreviewThumbnailImage (bool useLock) { // delete everything loaded into memory delete tpp; tpp = NULL; delete [] lastImg; lastImg = NULL; tw = -1; th = options.maxThumbnailHeight; delete [] tImgData; tImgData = NULL; // generate thumbnail image int lastdot = fname.find_last_of ('.'); if (lastdot==Glib::ustring::npos) return; cfs->thumbnail = (int) options.thumbnailFormat; Glib::ustring ext = fname.substr (lastdot); cfs->supported = false; cfs->exifValid = 0; cfs->timeValid = 0; if (ext.lowercase()==".jpg") { // try to load it as jpeg int thumbW, thumbH; int res = loadJPEGThumbnail (0, tImgData, tw, th); if (!res) { cfs->format = (int) FT_Jpeg; infoFromImage (fname); cfs->supported = true; } else { // try to let it load by dcraw rtengine::RawMetaDataLocation ri; res = getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType); if (!res) { cfs->format = (int) FT_Raw; infoFromImage (fname, &ri); cfs->supported = true; if (cfs->thumbImgType == 1) loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); else if (cfs->thumbImgType == 2) loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); else { cfs->thumbnail = (int) FT_None; tw = th * thumbW / thumbH; } } } } else if (ext.lowercase()==".tif" || ext.lowercase()==".tiff") { // try to detect it as raw file first int thumbW, thumbH; rtengine::RawMetaDataLocation ri; if (!getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType)) { cfs->format = (int) FT_Raw; infoFromImage (fname, &ri); cfs->supported = true; if (cfs->thumbImgType == 1) loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); else if (cfs->thumbImgType == 2) loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); else { cfs->thumbnail = (int) FT_None; tw = th * thumbW / thumbH; } } else if (!loadTIFFThumbnail (tImgData, tw, th)) { cfs->format = (int) FT_Tiff; infoFromImage (fname); cfs->supported = true; } } else if (ext.lowercase()==".png") { int res = loadPNGThumbnail (tImgData, tw, th); if (!res) { cfs->format = (int) FT_Png; cfs->supported = true; } } else { int thumbW, thumbH; rtengine::RawMetaDataLocation ri; if (!getRawFileBasicInfo (fname, ri, cfs->rotate, thumbW, thumbH, cfs->thumbOffset, cfs->thumbImgType)) { cfs->format = (int) FT_Raw; infoFromImage (fname, &ri); cfs->supported = true; if (cfs->thumbImgType == 1) loadJPEGThumbnail (cfs->thumbOffset, tImgData, tw, th, cfs->rotate); else if (cfs->thumbImgType == 2) loadPPMThumbnail (cfs->thumbOffset, thumbW, thumbH, tImgData, tw, th, cfs->rotate); else { cfs->thumbnail = (int) FT_None; tw = th * thumbW / thumbH; } } } cfs->thumbProcessed = 0; // save thumbnail image to cache if (cfs->supported) { saveThumbnail (); if (options.thumbCacheMemPolicy==MP_Memory) { delete [] tImgData; tImgData = NULL; } } updateCache (true, true, useLock); } void Thumbnail::generateProcessedThumbnailImage (bool useLock) { // delete everything loaded into memory delete tpp; tpp = NULL; delete [] lastImg; lastImg = NULL; tw = -1; th = options.maxThumbnailHeight; delete [] tImgData; tImgData = NULL; // generate thumbnail image int lastdot = fname.find_last_of ('.'); if (lastdot==Glib::ustring::npos) return; cfs->thumbnail = (int) options.thumbnailFormat; Glib::ustring ext = fname.substr (lastdot); cfs->supported = false; cfs->exifValid = 0; cfs->timeValid = 0; delete tpp; tpp = NULL; if (ext.lowercase()==".jpg" || ext.lowercase()==".tif" || ext.lowercase()==".tiff" || ext.lowercase()==".png") tpp = ThumbnailProcessingParameters::loadFromImage (fname, tw, th, 1); if (tpp) { if (ext.lowercase()==".jpg") { cfs->format = (int) FT_Jpeg; infoFromImage (fname); } else if (ext.lowercase()==".tif" || ext.lowercase()==".tiff") { cfs->format = (int) FT_Tiff; infoFromImage (fname); } else if (ext.lowercase()==".png") cfs->format = (int) FT_Png; } else { rtengine::RawMetaDataLocation ri; tpp = ThumbnailProcessingParameters::loadFromRaw (fname, ri, tw, th, 1); if (tpp) { cfs->format = (int) FT_Raw; infoFromImage (fname, &ri); } } if (tpp) { cfs->supported = true; cfs->camwbRed = tpp->camwbRed; cfs->camwbGreen = tpp->camwbGreen; cfs->camwbBlue = tpp->camwbBlue; cfs->autowbTemp = tpp->autowbTemp; cfs->autowbGreen = tpp->autowbGreen; cfs->aeHistCompression = tpp->aeHistCompression; cfs->embProfileLength = tpp->embProfileLength; cfs->redMultiplier = tpp->redMultiplier; cfs->greenMultiplier = tpp->greenMultiplier; cfs->blueMultiplier = tpp->blueMultiplier; cfs->scale = tpp->scale; cfs->defGain = tpp->defGain; cfs->scaleForSave = tpp->scaleForSave; cfs->gammaCorrected = tpp->gammaCorrected; memcpy (cfs->colorMatrix, tpp->colorMatrix, sizeof (cfs->colorMatrix)); /* IImage8* res = tpp->processImage (getProcParams ()); tw = res->getWidth (); th = res->getHeight (); tImgData = new unsigned char [tw*th*3]; memcpy (tImgData, res->getData (), tw*th*3); res->free ();*/ } cfs->thumbProcessed = 1; // save thumbnail image to cache if (cfs->supported) { saveThumbnail (); if (options.thumbCacheMemPolicy==MP_Memory) { delete tpp; tpp = NULL; // delete [] tImgData; // tImgData = NULL; } } updateCache (true, true, useLock); needsReProcessing = true; } bool Thumbnail::isSupported () { return cfs->supported; } const ProcParams& Thumbnail::getProcParams () { if (pparamsValid) return pparams; else { rtengine::procparams::ProcParams* pp = profileStore.getDefaultProcParams (getType()==FT_Raw); if (pp) return *pp; } return pparams; // there is no valid pp to return, but we have to return something } void Thumbnail::loadProcParams () { pparamsValid = false; if (options.paramsLoadLocation==PLL_Input) { // try to load it from pp2 file next to the image file int ppres = pparams.load (removeExtension(fname) + ".pp2"); pparamsValid = !ppres && pparams.version>=220; // if no success, load it from the cache if (!pparamsValid) pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); } else { // try to load it from cache pparamsValid = !pparams.load (getCacheFileName ("profiles")+".pp2"); // if no success, load it from pp2 file next to the image file if (!pparamsValid) { int ppres = pparams.load (removeExtension(fname) + ".pp2"); pparamsValid = !ppres && pparams.version>=220; } } } void Thumbnail::clearProcParams () { cfs->recentlySaved = false; cfs->ppformat = 0; pparamsValid = false; needsReProcessing = true; // remove pp2 file from cache Glib::ustring fname_ = getCacheFileName ("profiles")+".pp2"; if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) ::g_remove (fname_.c_str()); // remove pp2 file located next to the file fname_ = removeExtension(fname) + ".pp2"; if (Glib::file_test (fname_, Glib::FILE_TEST_EXISTS)) ::g_remove (fname_.c_str()); } bool Thumbnail::hasProcParams () { return pparamsValid; } void Thumbnail::setProcParams (const ProcParams& pp, bool updateCacheNow) { if (pparams!=pp) cfs->recentlySaved = false; pparams = pp; pparamsValid = true; needsReProcessing = true; if (updateCacheNow) pparams.save (getCacheFileName ("profiles")+".pp2"); } bool Thumbnail::isRecentlySaved () { return cfs->recentlySaved; } void Thumbnail::imageDeveloped () { cfs->recentlySaved = true; updateCache (false, false); } void Thumbnail::imageEnqueued () { enqueueNumber++; } void Thumbnail::imageRemovedFromQueue () { enqueueNumber--; } bool Thumbnail::isEnqueued () { return enqueueNumber > 0; } void Thumbnail::increaseRef () { ref++; } void Thumbnail::decreaseRef () { ref--; if (!ref) cachemgr->closeThumbnail (this); } void Thumbnail::getThumbnailSize (int &w, int &h, int fixwh) { // fixwh = 0: fix w and calculate h, =1: fix h and calculate w mutex->lock (); if (fixwh==1) w = tw * h / th; else if (fixwh==0) h = th * w / tw; mutex->unlock (); } unsigned char* Thumbnail::getThumbnailImage (int &w, int &h, int fixwh) { // fixwh = 0: fix w and calculate h, =1: fix h and calculate w getThumbnailSize (w, h, fixwh); mutex->lock (); // if the result of last query fits the needs, we just have to return it if (lastImg && lastW==w && lastH==h && !(cfs->thumbProcessed && needsReProcessing)) { mutex->unlock (); return lastImg; } else delete [] lastImg; if (!cfs->thumbProcessed) { // if thumbnail not loaed yet, load it if (!tImgData) { loadThumbnail (); if (!tImgData) { if (fixwh==1) w = tw * h / th; else if (fixwh==0) h = th * w / tw; mutex->unlock (); return NULL; } } lastW = w; lastH = h; lastImg = new unsigned char [lastW*lastH*3]; thumbInterp (tImgData, tw, th, lastImg, w, h); } else { if (!tpp) loadThumbnail (); IImage8* res = tpp->processImage (getProcParams (), h, TI_Bilinear); lastW = w = res->getWidth (); lastH = h = res->getHeight (); lastImg = new unsigned char [lastW*lastH*3]; memcpy (lastImg, res->getData(), lastW*lastH*3); res->free (); needsReProcessing = false; } // if we have to spare with memory, delete full res thumb image from memory if (options.thumbCacheMemPolicy==MP_Memory) { delete [] tImgData; delete tpp; tpp = NULL; tImgData = NULL; } mutex->unlock (); return lastImg; } Glib::ustring Thumbnail::getExifString () { if (!cfs->exifValid) return ""; std::ostringstream s; s << "f/" << ImageData::apertureToString(cfs->fnumber) << " "; s << ImageData::shutterToString(cfs->shutter) << "s "; s << "ISO" << cfs->iso; return s.str(); } Glib::ustring Thumbnail::getDateTimeString () { if (!cfs->timeValid) return ""; std::string dateFormat = options.dateFormat; std::ostringstream ostr; bool spec = false; for (int i=0; iyear; spec = false; } else if (spec && dateFormat[i]=='m') { ostr << (int)cfs->month; spec = false; } else if (spec && dateFormat[i]=='d') { ostr << (int)cfs->day; spec = false; } else if (dateFormat[i]=='%') spec = true; else { ostr << (char)dateFormat[i]; spec = false; } ostr << " " << (int)cfs->hour << ":" << (int)cfs->min << ":" << (int)cfs->sec; return ostr.str (); } ThFileType Thumbnail::getType () { return (ThFileType) cfs->format; } void Thumbnail::infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml) { ImageMetaData* idata = ImageMetaData::fromFile (fname, rml); if (!idata) return; cfs->timeValid = false; cfs->exifValid = false; if (idata->hasExif()) { cfs->shutter = idata->getShutterSpeed (); cfs->fnumber = idata->getFNumber (); cfs->focalLen = idata->getFocalLen (); cfs->iso = idata->getISOSpeed (); cfs->year = 1900 + idata->getDateTime().tm_year; cfs->month = idata->getDateTime().tm_mon + 1; cfs->day = idata->getDateTime().tm_mday; cfs->hour = idata->getDateTime().tm_hour; cfs->min = idata->getDateTime().tm_min; cfs->sec = idata->getDateTime().tm_sec; cfs->timeValid = true; cfs->exifValid = true; cfs->lens = idata->getLens(); cfs->camera = idata->getMake() + " " + idata->getModel(); } delete idata; } void Thumbnail::loadThumbnail (bool sizeOnly) { mutex->lock (); delete tImgData; delete tpp; tImgData = NULL; tpp = NULL; needsReProcessing = true; if (cfs->thumbnail == FT_None) return; unsigned char* data = NULL; Glib::ustring fname = getCacheFileName ("images"); int imgType = 0; if (Glib::file_test (fname+".cust", Glib::FILE_TEST_EXISTS)) imgType = 1; else if (Glib::file_test (fname+".jpg", Glib::FILE_TEST_EXISTS)) imgType = 2; FILE* f = g_fopen (fname.c_str(), "rb"); if (!f || !imgType) { if (f) fclose(f); mutex->unlock (); generateThumbnailImage (); if (cfs->supported) loadThumbnail (sizeOnly); else return; } else if (imgType==1) { fread (&tw, 1, sizeof (int), f); fread (&th, 1, sizeof (int), f); if (!sizeOnly) { data = new unsigned char [tw*th*3]; fread (data, tw*th, 3, f); } fclose (f); } else if (imgType==2) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; if (!setjmp(jpeg_jmp_buf)) { cinfo.err = my_jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); my_jpeg_stdio_src (&cinfo,f); jpeg_read_header (&cinfo, TRUE); tw = cinfo.image_width; th = cinfo.image_height; if (!sizeOnly) { cinfo.dct_method = JDCT_FASTEST; cinfo.do_fancy_upsampling = 1; jpeg_start_decompress(&cinfo); data = new unsigned char [tw*th*3]; while (cinfo.output_scanline < cinfo.output_height) { unsigned char* row = data + cinfo.output_scanline*tw*3; jpeg_read_scanlines (&cinfo, &row, 1); } jpeg_finish_decompress (&cinfo); } jpeg_destroy_decompress (&cinfo); fclose (f); } else { fclose (f); mutex->unlock (); return; } } if (!cfs->thumbProcessed) { tImgData = data; } else if (!sizeOnly) { tpp = new ThumbnailProcessingParameters (); tpp->data = data; tpp->width = tw; tpp->height = th; tpp->camwbRed = cfs->camwbRed; tpp->camwbGreen = cfs->camwbGreen; tpp->camwbBlue = cfs->camwbBlue; tpp->autowbTemp = cfs->autowbTemp; tpp->autowbGreen = cfs->autowbGreen; tpp->aeHistCompression = cfs->aeHistCompression; FILE* f = fopen (getCacheFileName ("aehistograms").c_str(), "rb"); if (!f) tpp->aeHistogram = NULL; else { tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; fread (tpp->aeHistogram, 1, (65536>>tpp->aeHistCompression)*sizeof(int), f); fclose (f); } tpp->embProfileLength = cfs->embProfileLength; Glib::ustring pfName = getCacheFileName ("embprofiles")+".icc"; f = fopen (pfName.c_str(), "rb"); if (!f) { tpp->embProfileData = NULL; tpp->embProfile = NULL; } else { tpp->embProfileData = new unsigned char[tpp->embProfileLength]; fread (tpp->embProfileData, 1, tpp->embProfileLength, f); fclose (f); tpp->embProfile = cmsOpenProfileFromMem (tpp->embProfileData, tpp->embProfileLength); } tpp->redMultiplier = cfs->redMultiplier; tpp->greenMultiplier = cfs->greenMultiplier; tpp->blueMultiplier = cfs->blueMultiplier; tpp->scale = cfs->scale; tpp->defGain = cfs->defGain; tpp->scaleForSave = cfs->scaleForSave; tpp->gammaCorrected = cfs->gammaCorrected; tpp->isRaw = (cfs->format == (int) FT_Raw); memcpy (tpp->colorMatrix, cfs->colorMatrix, sizeof (tpp->colorMatrix)); tpp->init (); } mutex->unlock (); } void Thumbnail::saveThumbnail () { if (!tImgData && !tpp) return; unsigned char* data = tImgData; int w = tw, h = th; if (cfs->thumbProcessed && tpp) { data = tpp->data; w = tpp->width; h = tpp->height; } if (data) { if (cfs->thumbnail == FT_Custom) { Glib::ustring fname = getCacheFileName ("images")+".cust"; FILE* f = g_fopen (fname.c_str(), "wb"); if (!f) return; fwrite (&w, 1, sizeof (int), f); fwrite (&h, 1, sizeof (int), f); fwrite (data, w*h, 3, f); fclose (f); } else if (cfs->thumbnail == FT_Jpeg) { Glib::ustring fname = getCacheFileName ("images")+".jpg"; FILE* f = g_fopen (fname.c_str(), "wb"); if (!f) return; jpeg_compress_struct cinfo; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error (&jerr); jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, f); cinfo.image_width = w; cinfo.image_height = h; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults (&cinfo); cinfo.write_JFIF_header = FALSE; jpeg_set_quality (&cinfo, 85, true); jpeg_start_compress(&cinfo, TRUE); int rowlen = w*3; while (cinfo.next_scanline < cinfo.image_height) { unsigned char* row = data + cinfo.next_scanline*w*3; if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) { jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); fclose (f); return; } } jpeg_finish_compress (&cinfo); jpeg_destroy_compress (&cinfo); fclose (f); } } if (tpp) { // save aehistogram if (tpp->aeHistogram) { FILE* f = fopen (getCacheFileName ("aehistograms").c_str(), "wb"); if (f) { fwrite (tpp->aeHistogram, 1, (65536>>tpp->aeHistCompression)*sizeof(int), f); fclose (f); } } // save embedded profile if (tpp->embProfileLength) { Glib::ustring pfName = getCacheFileName ("embprofiles")+".icc"; FILE* f = fopen (pfName.c_str(), "wb"); if (f) { fwrite (tpp->embProfileData, 1, tpp->embProfileLength, f); fclose (f); } } } } void Thumbnail::updateCache (bool savePparams, bool saveThumbImg, bool useLock) { if (filePos>=0) { if (pparamsValid) cfs->ppformat = 1; else cfs->ppformat = 0; if (pparamsValid && savePparams) { if (options.saveParamsCache) pparams.save (getCacheFileName ("profiles")); if (options.saveParamsFile) pparams.save (removeExtension(fname) + ".pp2"); } cachemgr->saveThumbnail (this, useLock); } } Thumbnail::~Thumbnail () { delete [] lastImg; delete [] tImgData; } Glib::ustring Thumbnail::getCacheFileName (Glib::ustring subdir) { Glib::ustring cfn = cachemgr->getBaseDir() + "/" + subdir + "/"; for (int i=0; i<32; i++) cfn += cfs->MD5[i]; return cfn; } int Thumbnail::loadJPEGThumbnail (int offset, unsigned char* &data, int &width, int &height, int degree, int fixwh) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; data = NULL; FILE* f = g_fopen (fname.c_str(), "rb"); if (!f) return 2; fseek (f, offset, SEEK_SET); if (!setjmp(jpeg_jmp_buf)) { cinfo.err = my_jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); my_jpeg_stdio_src (&cinfo,f); jpeg_read_header (&cinfo, TRUE); cinfo.dct_method = JDCT_FASTEST; cinfo.scale_num = 1; if (fixwh==1) { if (degree==0 || degree==180) width = height * cinfo.image_width / cinfo.image_height; else width = height * cinfo.image_height / cinfo.image_width; } else { if (degree==0 || degree==180) height = width * cinfo.image_height / cinfo.image_width; else height = width * cinfo.image_width / cinfo.image_height; } if (cinfo.image_width > 8*width && cinfo.image_height > 8*height ) cinfo.scale_denom = 8; else if (cinfo.image_width > 4*width && cinfo.image_height > 4*height ) cinfo.scale_denom = 4; else if (cinfo.image_width > 2*width && cinfo.image_height > 2*height ) cinfo.scale_denom = 2; else cinfo.scale_denom = 1; cinfo.do_fancy_upsampling = 1; jpeg_start_decompress(&cinfo); unsigned char* fullData = new unsigned char [3*cinfo.output_height*cinfo.output_width]; unsigned char* row = fullData; for (int i=0; iio_ptr); if (check != length) png_error(png_ptr, "Read Error"); } int Thumbnail::loadPNGThumbnail (unsigned char* &data, int &width, int &height, int fixwh) { data = NULL; FILE *file=g_fopen(fname.c_str(),"rb"); if (!file) return 2; //reading PNG header unsigned char header[8]; fread(header,1,8,file); if (!png_check_sig(header,8)) { fclose(file); return 3; } //initializing main structures png_structp png= png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0); if (!png) { fclose(file); return 4; } png_infop info= png_create_info_struct(png); png_infop end_info = png_create_info_struct(png); if (!end_info || !info) { png_destroy_read_struct(&png,&info,&end_info); fclose(file); return 5; } if (setjmp(png_jmpbuf(png))) { png_destroy_read_struct(&png,&info,&end_info); fclose(file); return 3; } //set up png read png_set_read_fn(png, file, png_read_data); png_set_sig_bytes(png,8); png_read_info(png,info); //retrieving image information unsigned long fwidth, fheight; int bit_depth,color_type,interlace_type,compression_type,filter_method; png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, &compression_type, &filter_method); //converting to 32bpp format if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png); if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png); if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png); if (interlace_type!=PNG_INTERLACE_NONE) { fclose (file); return 6; } if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png); if (bit_depth==16) png_set_strip_16(png); //setting gamma double gamma; if (png_get_gAMA(png,info,&gamma)) png_set_gamma(png, 2.0, gamma); else png_set_gamma(png, 1.0, 1.0); //updating png info struct png_read_update_info(png,info); png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, &compression_type, &filter_method); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png); if (bit_depth==16) png_set_strip_16(png); png_read_update_info(png,info); png_get_IHDR(png,info,&fwidth,&fheight,&bit_depth,&color_type,&interlace_type, &compression_type, &filter_method); png_timep time; cfs->timeValid = png_get_tIME (png, info, &time); cfs->exifValid = 0; cfs->year = time->year; cfs->month = time->month; cfs->day = time->day; cfs->hour = time->hour; cfs->min = time->minute; cfs->sec = time->second; if (fixwh==1) width = height * fwidth / fheight; else height = width * fheight / fwidth; unsigned char* fullData = new unsigned char [3*fheight*fwidth]; unsigned char* row = fullData; for (int i=0; i> 8; } TIFFClose(in); delete [] linebuffer; } else if (bitspersample == 8) { for (int i=0; i