ImageStat PSDDecoder::DecodeImg(Dib& bmp, CSize& img_size, bool resize, COLORREF rgb_back/*= RGB(255,255,255)*/) { FileStream ifs; if (!ifs.Open(file_path_.c_str())) return IS_OPEN_ERR; if (!psd_.OpenHeader(ifs)) return IS_FMT_NOT_SUPPORTED; if (!psd_.IsSupported()) return IS_FMT_NOT_SUPPORTED; if (!psd_.PrepareReading(ifs, CalcReductionFactor(img_size, false))) return IS_FMT_NOT_SUPPORTED; // image may be reduced in size CSize size= psd_.GetResized(); bmp.Create(size.cx, size.cy, 24); SetTotalLines(psd_.GetHeight()); if (!LinesDecoded(0, false)) return IS_DECODING_CANCELLED; while (psd_.GetScanLine() < psd_.GetHeight()) { psd_.ReadNextLine(ifs, bmp, 0); if (IsICCEnabled()) ApplyICC(bmp.LineBuffer(psd_.GetScanLine() - 1), bmp.GetWidth(), bmp.GetColorComponents()); int scan_line= psd_.GetScanLine(); // report progress if (!LinesDecoded(scan_line, scan_line == psd_.GetHeight())) return IS_DECODING_CANCELLED; } if (resize) bmp.ResizeToFit(img_size, Dib::RESIZE_CUBIC); return IS_OK; }
ImageStat BMPDecoder::DecodeImg(Dib& dib, CSize& img_size, bool resize, COLORREF rgb_back/*= RGB(255,255,255)*/) { BMPReader bmp; ImageStat stat= bmp.Open(filePath_.c_str()); if (stat != IS_OK) return stat; img_size_ = bmp.GetSize(); if (!bmp.IsSupported()) return IS_FMT_NOT_SUPPORTED; //CSize size2= img_size; //if (ImageStat stat= png_.PrepareReading(CalcReductionFactor(size2, false))) // return stat; // image may be reduced in size //CSize size= png_.GetResized(); //dib.Create(size.cx, size.cy, 24); SetTotalLines(img_size_.cy); if (!LinesDecoded(0, false)) { // png_.Close(); return IS_DECODING_CANCELLED; } stat = bmp.ReadImage(dib); if (stat != IS_OK) return stat; /* while (png_.GetPass() < png_.GetNoOfPasses()) { while (png_.GetScanLine() < png_.GetHeight()) { png_.ReadNextLine(bmp); if (png_.GetPass() == png_.GetNoOfPasses() - 1) { int scan_line= png_.GetScanLine(); // report progress if (!LinesDecoded(scan_line, scan_line == png_.GetHeight())) { png_.Close(); return IS_DECODING_CANCELLED; } } } png_.NextPass(); } */ if (!LinesDecoded(img_size_.cy, true)) return IS_DECODING_CANCELLED; if (resize && img_size != img_size_) dib.ResizeToFit(img_size, Dib::RESIZE_CUBIC); return IS_OK; }
void CatalogImages::Impl::ProcessFiles(int img_size, int jpeg_compression_level) { const size_t count= files_.size(); counter_ = 0; for (size_t i= 0; i < count; ++i) { if (parentWnd_) ::PostMessage(parentWnd_, MESSAGE, i, IMG_PROCESSING); if (break_) return; const Path& path= files_[i].first; PhotoFactory::CreateFn fn= 0; int id= 0; if (!GetPhotoFactory().MatchPhotoType(path.GetExtension(), fn, id)) { ASSERT(false); continue; } SmartPhotoPtr photo(fn()); try { CatalogImgRecord img; // ExifBlock exif; // exif.clear(); bool has_exif= photo->Scan(path.c_str(), img.exif_, false, nullptr); // scan image to find EXIF data if (!has_exif && readOnlyPhotosWithEXIF_) continue; if (!has_exif || photo->GetDateTime().is_not_a_date_time()) ReadFileTimeStamp(*photo, path); uint64 fileLength= 0; // write to db img.type_ = id; // get file length and last write time { WIN32_FIND_DATA findFileData; HANDLE find= ::FindFirstFile(path.c_str(), &findFileData); if (find != INVALID_HANDLE_VALUE) { VERIFY(::FindClose(find)); fileLength = uint64(findFileData.nFileSizeLow) + (uint64(findFileData.nFileSizeHigh) << 32); img.time_stamp_ = findFileData.ftLastWriteTime; img.access_time_ = findFileData.ftLastAccessTime; img.creation_time_ = findFileData.ftCreationTime; img.file_attribs_ = findFileData.dwFileAttributes; } } // uint64 fileLength= path.GetFileLength(); //photo->dir_visited_ = static_cast<uint32>(dir_visited); photo->SetFileSize(fileLength); photo->SetPhotoName(path.GetFileName()); photo->SetPhysicalPath(path); photo->exif_data_present_ = has_exif; // SetAutoRotationFlag(photo.get()); img.path_ = String2WStr(path); img.make_ = String2WStr(photo->GetMake()); img.model_ = String2WStr(photo->GetModel()); img.orientation_ = photo->OrientationField(); img.file_size_ = fileLength; // find.GetLastWriteTime(&img.time_stamp_); //photo->index_.Serialize(img.buf_index_); // verify this: =========== // img.jpeg_offset_ = photo->jpeg_offset_; // HACK: this is orientation extracted from CRW file; when reading info from // cache CRW is not scanned, so orientation cannot be set img.exif_orientation_ = has_exif ? 0u : photo->OrientationField(); // ========================= // EXIF block img.has_exif_ = has_exif; // img.exif_ifd_offset_ = static_cast<int32>(exif.ifd0Start); // if (exif.is_raw) // img.exif_type_ = exif.bigEndianByteOrder ? // CatalogImgRecord::RAW_MM_EXIF_BLOCK : CatalogImgRecord::RAW_II_EXIF_BLOCK; // else // img.exif_type_ = CatalogImgRecord::JPEG_EXIF_BLOCK; // img.exif_.swap(exif.exif_buffer); // prepare preview Dib bmp; CSize thumbnail_size(img_size, img_size); CImageDecoderPtr decoder= photo->GetDecoder(); bool ycbcr_image= true; ImageStat stat= decoder->DecodeImgToYCbCr(bmp, thumbnail_size, true); if (stat != IS_OK) { ycbcr_image = false; if (stat == IS_OPERATION_NOT_SUPPORTED) stat = decoder->DecodeImg(bmp, thumbnail_size, true); } if (stat != IS_OK || !bmp.IsValid()) { failed_.push_back(path); continue; } // if EXIF indicates rotation and photo is already physically rotated AND exif reset EXIF orientation // flag back to normal to avoid problems later on... PhotoInfo::ImgOrientation orient= photo->GetOrientation(); if ((orient == PhotoInfo::ORIENT_90CCW || orient == PhotoInfo::ORIENT_90CW) && photo->GetWidth() > photo->GetHeight() && bmp.GetWidth() < bmp.GetHeight()) { //photo->orientation_ = 0; std::swap(img.img_width_, img.img_height_); uint32 w= photo->GetWidth(); uint32 h= photo->GetHeight(); photo->SetSize(h, w); } else if ((orient == PhotoInfo::ORIENT_NORMAL || orient == PhotoInfo::ORIENT_NO_INFO || orient == PhotoInfo::ORIENT_UNKNOWN) && photo->GetWidth() > photo->GetHeight() && bmp.GetWidth() < bmp.GetHeight()) { // orientation is 'normal', but reported size and size of decoded image do not agree uint32 w= photo->GetWidth(); uint32 h= photo->GetHeight(); photo->SetSize(h, w); } img.photo_width_ = photo->GetWidth(); img.photo_height_ = photo->GetHeight(); //TODO: convert non-ycbcr from rgb if needed // calculate 'index' using YCbCr image photo->index_.CalcHistogram(bmp); photo->index_.Serialize(img.index_); // now to RGB if (ycbcr_image) bmp.ConvertYCbCr2RGB(); Dib thm; // little thumbnail if (img_size > 160) bmp.ResizeToFit(CSize(160, 160), Dib::RESIZE_HALFTONE, thm); CSize size= bmp.GetSize(); int big= img_size; if (size.cx > big || size.cy > big) bmp.ResizeToFit(CSize(big, big), Dib::RESIZE_HALFTONE); img.img_width_ = bmp.GetWidth(); img.img_height_ = bmp.GetHeight(); // compress preview into JPEG JPEGEncoder enc(jpeg_compression_level, false, false); if (thm.IsValid()) { // we have both little thumbnail image and preview image { CMemoryDataDestination memdest; enc.Encode(memdest, &thm); memdest.SwapJPEG(img.thumbnail_); } { CMemoryDataDestination memdest; enc.Encode(memdest, &bmp); memdest.SwapJPEG(img.preview_); } } else { // only small preview available; // store it in the thumbnail leaving preview field empty CMemoryDataDestination memdest; enc.Encode(memdest, &bmp); memdest.SwapJPEG(img.thumbnail_); img.preview_.clear(); } // IPTC present? //if (photo->IPTC_.get()) // img.iptc_.reset(photo->IPTC_.release()); if (photo->HasMetadata()) { img.iptc_.reset(new IPTCRecord()); photo->GetIPTCInfo(*img.iptc_); } img.description_ = photo->GetExifDescription(); img.marker_index_ = photo->GetFileTypeIndex(); //TODO: store XMP too!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //TODO: // grab tags; // and description; // EliminateNonPrintableChars(photo->photo_desc_); // PostProcessTime(photo.get()); CatalogHeader::DirPtr dir= files_[i].second; img.dir_visited_ = dir->id_; // add/modify record std::vector<uint8> buf; img.Serialize(buf, 1); uint64 record_offset= dbImages_.Append(buf); // examine tags if (!photo->GetTags().empty()) // has tags? { PhotoTags::const_iterator end= photo->GetTags().end(); for (PhotoTags::const_iterator it = photo->GetTags().begin(); it != end; ++it) tags_[*it].push_back(record_offset); } if (dir->records_.empty()) dir->records_.reserve(dir->reserved_capacity_); if (dir->records_.size() < dir->reserved_capacity_) dir->records_.push_back(record_offset); else { ASSERT(false); continue; } ++counter_; } catch (MemPointer::MemPtrException&) { CString msg= _T("Error parsing file: "); msg += path.c_str(); ::ShowMessageBox(msg); } catch (CMemoryException*) { CString msg= _T("Out of memory reading file: "); msg += path.c_str(); ::ShowMessageBox(msg); } catch (JPEGException& ex) { CString msg= _T("Error processing file: "); msg += path.c_str(); msg += _T("\n\n"); msg += ex.GetMessage(); ::ShowMessageBox(msg); } #ifndef _DEBUG catch (...) { // ASSERT(false); } #endif } }