From 7114c56bc3c959ba75df7eeb803ef241f5f1031e Mon Sep 17 00:00:00 2001 From: David Neon Date: Sat, 27 Apr 2024 21:14:14 +0800 Subject: [PATCH] Cherry Picks Part 2 * Various cherry picks from upstream. E.g.: more EXIF, more modern RAW image support --- src/JPEGView.Setup/Product.wxs | 11 ++++ src/JPEGView/Config/JPEGView.ini | 9 ++- src/JPEGView/EXIFDisplayCtl.cpp | 13 ++++ src/JPEGView/ImageLoadThread.cpp | 27 +++++++- src/JPEGView/JPEGView.vcxproj | 36 ++++++----- src/JPEGView/JPEGView.vcxproj.filters | 6 ++ src/JPEGView/MainDlg.cpp | 23 +++++-- src/JPEGView/RAWWrapper.cpp | 92 +++++++++++++++++++++++++++ src/JPEGView/RAWWrapper.h | 9 +++ src/JPEGView/RawMetadata.h | 34 +++++++++- src/JPEGView/SettingsProvider.cpp | 1 + src/JPEGView/SettingsProvider.h | 2 + 12 files changed, 238 insertions(+), 25 deletions(-) create mode 100644 src/JPEGView/RAWWrapper.cpp create mode 100644 src/JPEGView/RAWWrapper.h diff --git a/src/JPEGView.Setup/Product.wxs b/src/JPEGView.Setup/Product.wxs index 361a1c70..e3739e95 100644 --- a/src/JPEGView.Setup/Product.wxs +++ b/src/JPEGView.Setup/Product.wxs @@ -215,6 +215,10 @@ + + + + @@ -408,6 +412,7 @@ + @@ -420,6 +425,7 @@ + @@ -509,6 +515,11 @@ + + + + + diff --git a/src/JPEGView/Config/JPEGView.ini b/src/JPEGView/Config/JPEGView.ini index d046c558..61b26e23 100644 --- a/src/JPEGView/Config/JPEGView.ini +++ b/src/JPEGView/Config/JPEGView.ini @@ -50,7 +50,14 @@ FilesProcessedByWIC=*.wdp;*.hdp;*.jxr;*.ico ; File endings of camera RAW files to be searched for embedded JPEG thumb images to display ; Reading just these embedded JPEGs is much faster than decoding the RAW using WIC -FileEndingsRAW=*.pef;*.dng;*.crw;*.nef;*.cr2;*.mrw;*.rw2;*.orf;*.x3f;*.arw;*.kdc;*.nrw;*.dcr;*.sr2;*.raf +FileEndingsRAW=*.pef;*.dng;*.crw;*.nef;*.cr2;*.mrw;*.rw2;*.orf;*.x3f;*.arw;*.kdc;*.nrw;*.dcr;*.sr2;*.raf;*.kc2;*.erf;*.3fr;*.raw;*.mef;*.mos;*.mdc;*.cr3 + +; Set behavior for opening RAW files listed in FileEndingsRAW +; 0: open embedded thumbnail +; 1: open full size +; 2: open thumbnail, fallback to full size +; 3: open full size, fallback to thumbnail +DisplayFullSizeRAW=0 ; If true, reloads the currently displayed image automatically when it is changed by an external program on disk. ; Also reloads the image list when a file in the current directory is added or deleted. diff --git a/src/JPEGView/EXIFDisplayCtl.cpp b/src/JPEGView/EXIFDisplayCtl.cpp index 1f1e4d59..65cb4ae4 100644 --- a/src/JPEGView/EXIFDisplayCtl.cpp +++ b/src/JPEGView/EXIFDisplayCtl.cpp @@ -126,6 +126,8 @@ void CEXIFDisplayCtl::FillEXIFDataDisplay() { } if (pEXIFReader->GetAcquisitionTimePresent()) { m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Acquisition date:")), pEXIFReader->GetAcquisitionTime()); + } else if (pEXIFReader->GetDateTimePresent()) { + m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Exif Date Time:")), pEXIFReader->GetDateTime()); } else { const FILETIME* pFileTime = pFileList->CurrentModificationTime(); if (pFileTime != NULL) { @@ -161,6 +163,9 @@ void CEXIFDisplayCtl::FillEXIFDataDisplay() { if (pEXIFReader->GetISOSpeedPresent()) { m_pEXIFDisplay->AddLine(CNLS::GetString(_T("ISO Speed:")), (int)pEXIFReader->GetISOSpeed()); } + if (pEXIFReader->GetSoftwarePresent()) { + m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Software:")), pEXIFReader->GetSoftware()); + } } else if (pRawMetaData != NULL) { if (pRawMetaData->GetAcquisitionTime().wYear > 1985) { @@ -172,6 +177,14 @@ void CEXIFDisplayCtl::FillEXIFDataDisplay() { m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Modification date:")), *pFileTime); } } + if (pRawMetaData->IsGPSInformationPresent()) { + CString sGPSLocation = CreateGPSString(pRawMetaData->GetGPSLatitude(), pRawMetaData->GetGPSLongitude()); + m_pEXIFDisplay->SetGPSLocation(sGPSLocation, CreateGPSURL(pRawMetaData->GetGPSLatitude(), pRawMetaData->GetGPSLongitude())); + m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Location:")), sGPSLocation, true); + if (pRawMetaData->IsGPSAltitudePresent()) { + m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Altitude (m):")), pRawMetaData->GetGPSAltitude(), 0); + } + } if (pRawMetaData->GetManufacturer()[0] != 0) { m_pEXIFDisplay->AddLine(CNLS::GetString(_T("Camera model:")), CString(pRawMetaData->GetManufacturer()) + _T(" ") + pRawMetaData->GetModel()); } diff --git a/src/JPEGView/ImageLoadThread.cpp b/src/JPEGView/ImageLoadThread.cpp index 0979d3f0..6ab27e85 100644 --- a/src/JPEGView/ImageLoadThread.cpp +++ b/src/JPEGView/ImageLoadThread.cpp @@ -15,6 +15,7 @@ #include "PNGWrapper.h" #include "JXLWrapper.h" #include "HEIFWrapper.h" +#include "RAWWrapper.h" #include "QOIWrapper.h" #include "PSDWrapper.h" #include "MaxImageDef.h" @@ -1218,9 +1219,29 @@ void CImageLoadThread::ProcessReadQOIRequest(CRequest* request) { void CImageLoadThread::ProcessReadRAWRequest(CRequest * request) { bool bOutOfMemory = false; try { - request->Image = CReaderRAW::ReadRawImage(request->FileName, bOutOfMemory); - } - catch (...) { + int fullsize = CSettingsProvider::This().DisplayFullSizeRAW(); + +#ifndef WINXP + // Try with libraw + UINT nPrevErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + try { + if (fullsize == 2 || fullsize == 3) { + request->Image = RawReader::ReadImage(request->FileName, bOutOfMemory, fullsize == 2); + } + if (request->Image == NULL) { + request->Image = RawReader::ReadImage(request->FileName, bOutOfMemory, fullsize == 0 || fullsize == 3); + } + } catch (...) { + // libraw.dll not found or VC++ Runtime not installed + } + SetErrorMode(nPrevErrorMode); +#endif + + // Try with dcraw_mod + if (request->Image == NULL && fullsize != 1) { + request->Image = CReaderRAW::ReadRawImage(request->FileName, bOutOfMemory); + } + } catch (...) { delete request->Image; request->Image = NULL; } diff --git a/src/JPEGView/JPEGView.vcxproj b/src/JPEGView/JPEGView.vcxproj index e1e27714..fd9fe989 100644 --- a/src/JPEGView/JPEGView.vcxproj +++ b/src/JPEGView/JPEGView.vcxproj @@ -69,14 +69,14 @@ obj\x86\$(Configuration)\ false false - $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(IncludePath) - $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(IncludePath) - $(ProjectDir)libjpeg-turbo\lib;$(ProjectDir)libpng-apng\lib;$(ProjectDir)libjxl\lib;$(ProjectDir)libheif\lib;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\lib;$(LibraryPath) - $(ProjectDir)libjpeg-turbo\lib64;$(ProjectDir)libpng-apng\lib64;$(ProjectDir)libjxl\lib64;$(ProjectDir)libheif\lib64;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib64;$(LibraryPath) - $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(IncludePath) - $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(IncludePath) - $(ProjectDir)libjpeg-turbo\lib;$(ProjectDir)libpng-apng\lib;$(ProjectDir)libjxl\lib;$(ProjectDir)libheif\lib;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib;$(LibraryPath) - $(ProjectDir)libjpeg-turbo\lib64;$(ProjectDir)libpng-apng\lib64;$(ProjectDir)libjxl\lib64;$(ProjectDir)libheif\lib64;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib64;$(LibraryPath) + $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(ProjectDir)\libraw\include;$(IncludePath) + $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(ProjectDir)\libraw\include;$(IncludePath) + $(ProjectDir)libjpeg-turbo\lib;$(ProjectDir)libpng-apng\lib;$(ProjectDir)libjxl\lib;$(ProjectDir)libheif\lib;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib;$(ProjectDir)libraw\lib;$(LibraryPath) + $(ProjectDir)libjpeg-turbo\lib64;$(ProjectDir)libpng-apng\lib64;$(ProjectDir)libjxl\lib64;$(ProjectDir)libheif\lib64;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib64;$(ProjectDir)libraw\lib64;$(LibraryPath) + $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(ProjectDir)\libraw\include;$(IncludePath) + $(ProjectDir)..\..\deps\WTL-sf\Include;$(ProjectDir)libpng-apng\include;$(ProjectDir)libjxl\include;$(ProjectDir)\libheif\include;$(ProjectDir)\libavif\include;$(ProjectDir)\lcms2\include;$(ProjectDir)\libraw\include;$(IncludePath) + $(ProjectDir)libjpeg-turbo\lib;$(ProjectDir)libpng-apng\lib;$(ProjectDir)libjxl\lib;$(ProjectDir)libheif\lib;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib;$(ProjectDir)libraw\lib;$(LibraryPath) + $(ProjectDir)libjpeg-turbo\lib64;$(ProjectDir)libpng-apng\lib64;$(ProjectDir)libjxl\lib64;$(ProjectDir)libheif\lib64;$(ProjectDir)\libavif\include;$(ProjectDir)lcms2\lib64;$(ProjectDir)libraw\lib64;$(LibraryPath) bin\x64\$(Configuration)\ @@ -119,7 +119,7 @@ $(IntDir);%(AdditionalIncludeDirectories) - Dbghelp.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;%(AdditionalDependencies) + Dbghelp.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;libraw.lib;%(AdditionalDependencies) bin\x86\$(Configuration);%(AdditionalLibraryDirectories) @@ -136,6 +136,7 @@ xcopy "$(ProjectDir)Config\*" "$(ProjectDir)\$(OutDir)" /Y /C /D xcopy "$(ProjectDir)libjxl\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D +xcopy "$(ProjectDir)libraw\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D @@ -170,13 +171,13 @@ xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D $(IntDir);%(AdditionalIncludeDirectories) - legacy_stdio_definitions.lib;legacy_stdio_wide_specifiers.lib;Dbghelp.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;avif.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;%(AdditionalDependencies) + legacy_stdio_definitions.lib;legacy_stdio_wide_specifiers.lib;Dbghelp.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;avif.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;libraw.lib;%(AdditionalDependencies) bin\x64\$(Configuration);libavif\lib64;%(AdditionalLibraryDirectories) true Windows - WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll + WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll;libraw.dll LIBCMT /IGNORE:4099 %(AdditionalOptions) @@ -187,6 +188,7 @@ xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)Config\*" "$(ProjectDir)\$(OutDir)" /Y /C /D xcopy "$(ProjectDir)libjxl\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)libheif\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D +xcopy "$(ProjectDir)libraw\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D @@ -227,13 +229,13 @@ xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D $(IntDir);%(AdditionalIncludeDirectories) - gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;%(AdditionalDependencies) + gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;libraw.lib;%(AdditionalDependencies) bin\x86\$(Configuration);%(AdditionalLibraryDirectories) false Windows MachineX86 false - WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll + WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll;libraw.dll true @@ -241,6 +243,7 @@ xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)Config\*" "$(ProjectDir)\$(OutDir)" /Y /C /D xcopy "$(ProjectDir)libjxl\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D +xcopy "$(ProjectDir)libraw\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D @@ -281,12 +284,12 @@ xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D $(IntDir);%(AdditionalIncludeDirectories) - legacy_stdio_definitions.lib;legacy_stdio_wide_specifiers.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;avif.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;%(AdditionalDependencies) + legacy_stdio_definitions.lib;legacy_stdio_wide_specifiers.lib;gdiplus.lib;WICLoader.lib;turbojpeg-static.lib;webp.lib;libpng16.lib;zlib.lib;avif.lib;jxl_dec.lib;jxl_threads.lib;heif.lib;lcms2.lib;libraw.lib;%(AdditionalDependencies) bin\x64\$(Configuration);libavif\lib64;%(AdditionalLibraryDirectories) false Windows false - WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll + WICLoader.dll;webp.dll;jxl_dec.dll;jxl_threads.dll;heif.dll;lcms2.dll;libraw.dll true @@ -295,6 +298,7 @@ xcopy "$(ProjectDir)libheif\bin\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)Config\*" "$(ProjectDir)\$(OutDir)" /Y /C /D xcopy "$(ProjectDir)libjxl\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)libheif\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D +xcopy "$(ProjectDir)libraw\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D @@ -340,6 +344,7 @@ xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D + @@ -433,6 +438,7 @@ xcopy "$(ProjectDir)lcms2\bin64\*.dll" "$(ProjectDir)$(OutDir)" /Y /D + diff --git a/src/JPEGView/JPEGView.vcxproj.filters b/src/JPEGView/JPEGView.vcxproj.filters index 7d6d1e3f..36622ba5 100644 --- a/src/JPEGView/JPEGView.vcxproj.filters +++ b/src/JPEGView/JPEGView.vcxproj.filters @@ -276,6 +276,9 @@ Source Files + + Source Files\Image Types + @@ -539,6 +542,9 @@ Header Files\Image Types + + Header Files\Image Types + diff --git a/src/JPEGView/MainDlg.cpp b/src/JPEGView/MainDlg.cpp index c9d48b98..7d80e887 100644 --- a/src/JPEGView/MainDlg.cpp +++ b/src/JPEGView/MainDlg.cpp @@ -34,6 +34,7 @@ #include "ResizeFilter.h" #include "EXIFReader.h" #include "EXIFHelpers.h" +#include "RawMetadata.h" #include "ProcessingThreadPool.h" #include "PaintMemDCMgr.h" #include "PanelMgr.h" @@ -2316,7 +2317,13 @@ void CMainDlg::ExecuteCommand(int nCommand) { SetIcon(hIconSmall, FALSE); CRect defaultWindowRect = CMultiMonitorSupport::GetDefaultWindowRect(); double dZoom = -1; - windowRect = sp.ExplicitWindowRect() ? defaultWindowRect : Helpers::GetWindowRectMatchingImageSize(m_hWnd, CSize(MIN_WND_WIDTH, MIN_WND_HEIGHT), defaultWindowRect.Size(), dZoom, m_pCurrentImage, false, true, m_bWindowBorderless); + windowRect = sp.ExplicitWindowRect() ? + defaultWindowRect : + Helpers::GetWindowRectMatchingImageSize( + m_hWnd, + CSize(MIN_WND_WIDTH, MIN_WND_HEIGHT), + defaultWindowRect.Size(), + dZoom, m_pCurrentImage, false, true, m_bWindowBorderless); this->SetWindowPos(HWND_TOP, windowRect.left, windowRect.top, windowRect.Width(), windowRect.Height(), SWP_NOZORDER | SWP_NOCOPYBITS); this->MouseOn(); m_bSpanVirtualDesktop = false; @@ -2351,7 +2358,8 @@ void CMainDlg::ExecuteCommand(int nCommand) { // get the size of the border to shift the window pos downwards int windowCaptionHeight = Helpers::GetWindowCaptionSize(); double dZoom = -1; - CRect windowRect = Helpers::GetWindowRectMatchingImageSize(m_hWnd, CSize(MIN_WND_WIDTH, MIN_WND_HEIGHT), HUGE_SIZE, dZoom, m_pCurrentImage, false, true, m_bWindowBorderless); + CRect windowRect = Helpers::GetWindowRectMatchingImageSize( + m_hWnd, CSize(MIN_WND_WIDTH, MIN_WND_HEIGHT), HUGE_SIZE, dZoom, m_pCurrentImage, false, true, m_bWindowBorderless); // don't try to adjust for an image that isn't loaded! if (m_pCurrentImage != NULL) @@ -2365,9 +2373,13 @@ void CMainDlg::ExecuteCommand(int nCommand) { // it causes the window to shift up one pixel at a time when going between borderless and not borderless repeatedly // in other cases, it shifts downwards depending on rounding errors resizing the window and image... hard to hunt down but it's as good as it can get right now if (windowCaptionHeight % 2 == 0) { - newTop = m_bWindowBorderless ? windowRect.top + (windowCaptionHeight / 2) : windowRect.top - (windowCaptionHeight / 2); + newTop = m_bWindowBorderless ? + windowRect.top + (windowCaptionHeight / 2) : + windowRect.top - (windowCaptionHeight / 2); } else { - newTop = m_bWindowBorderless ? windowRect.top + (windowCaptionHeight / 2) : windowRect.top - (windowCaptionHeight / 2) + 1; + newTop = m_bWindowBorderless ? + windowRect.top + (windowCaptionHeight / 2) : + windowRect.top - (windowCaptionHeight / 2) + 1; } // tell the window the Frame has changed, not sure if it makes a difference @@ -4049,8 +4061,11 @@ void CMainDlg::UpdateWindowTitle() { sWindowText += Helpers::GetMultiframeIndex(m_pCurrentImage); if (CSettingsProvider::This().ShowEXIFDateInTitle()) { CEXIFReader* pEXIF = m_pCurrentImage->GetEXIFReader(); + CRawMetadata* pRawMetadata = m_pCurrentImage->GetRawMetadata(); if (pEXIF != NULL && pEXIF->GetAcquisitionTime().wYear > 1600) { sWindowText += " - " + Helpers::SystemTimeToString(pEXIF->GetAcquisitionTime()); + } else if (pRawMetadata != NULL && pRawMetadata->GetAcquisitionTime().wYear > 1985) { + sWindowText += " - " + Helpers::SystemTimeToString(pRawMetadata->GetAcquisitionTime()); } } sWindowText += " - " + CString(JPEGVIEW_TITLE); diff --git a/src/JPEGView/RAWWrapper.cpp b/src/JPEGView/RAWWrapper.cpp new file mode 100644 index 00000000..c0908027 --- /dev/null +++ b/src/JPEGView/RAWWrapper.cpp @@ -0,0 +1,92 @@ +#include "stdafx.h" + +#include "RAWWrapper.h" +#include "libraw/libraw.h" +#include "Helpers.h" +#include "ICCProfileTransform.h" +#include "TJPEGWrapper.h" +#include "RawMetadata.h" +#include "MaxImageDef.h" + +CJPEGImage* RawReader::ReadImage(LPCTSTR strFileName, bool& bOutOfMemory, bool bGetThumb) +{ + unsigned char* pPixelData = NULL; + + LibRaw RawProcessor; + if (RawProcessor.open_file(strFileName) != LIBRAW_SUCCESS) { + return NULL; + } + int width, height, colors, bps; + + CJPEGImage* Image = NULL; + if (!bGetThumb) { + RawProcessor.get_mem_image_format(&width, &height, &colors, &bps); + RawProcessor.imgdata.params.output_bps = 8; + + if (width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) { + return NULL; + } + + if ((double)width * height > MAX_IMAGE_PIXELS) { + bOutOfMemory = true; + return NULL; + } + + if (RawProcessor.unpack() != LIBRAW_SUCCESS || RawProcessor.dcraw_process() != LIBRAW_SUCCESS) { + return NULL; + } + + int stride = Helpers::DoPadding(width * colors, 4); + + pPixelData = new(std::nothrow) unsigned char[stride * height]; + if (pPixelData == NULL) { + bOutOfMemory = true; + return NULL; + } + if (RawProcessor.copy_mem_image(pPixelData, stride, 1) != LIBRAW_SUCCESS) { + delete[] pPixelData; + return NULL; + } + + void* transform = ICCProfileTransform::CreateTransform(RawProcessor.imgdata.color.profile, RawProcessor.imgdata.color.profile_length, ICCProfileTransform::FORMAT_BGR); + ICCProfileTransform::DoTransform(transform, pPixelData, pPixelData, width, height, stride); + ICCProfileTransform::DeleteTransform(transform); + + CRawMetadata* metadata = new CRawMetadata(RawProcessor.imgdata.idata.make, RawProcessor.imgdata.idata.model, RawProcessor.imgdata.other.timestamp, + RawProcessor.imgdata.color.flash_used != 0.0f, RawProcessor.imgdata.other.iso_speed, RawProcessor.imgdata.other.shutter, + RawProcessor.imgdata.other.focal_len, RawProcessor.imgdata.other.aperture, RawProcessor.imgdata.sizes.flip, width, height, + RawProcessor.imgdata.other.parsed_gps.latitude, RawProcessor.imgdata.other.parsed_gps.latref, RawProcessor.imgdata.other.parsed_gps.longitude, + RawProcessor.imgdata.other.parsed_gps.longref, RawProcessor.imgdata.other.parsed_gps.altitude, RawProcessor.imgdata.other.parsed_gps.altref); + + if (pPixelData) + Image = new CJPEGImage(width, height, pPixelData, NULL, colors, 0, IF_CameraRAW, false, 0, 1, 0, NULL, false, metadata); + } else if (RawProcessor.is_jpeg_thumb()) { + TJSAMP eChromoSubSampling; + if (RawProcessor.unpack_thumb() != LIBRAW_SUCCESS) { + return NULL; + } + libraw_processed_image_t* thumb = RawProcessor.dcraw_make_mem_thumb(); + if (thumb == NULL) { + return NULL; + } + pPixelData = (unsigned char*)TurboJpeg::ReadImage(width, height, colors, eChromoSubSampling, bOutOfMemory, thumb->data, thumb->data_size); + if (pPixelData != NULL && (colors == 3 || colors == 1)) + { + CRawMetadata* metadata = new CRawMetadata(RawProcessor.imgdata.idata.make, RawProcessor.imgdata.idata.model, RawProcessor.imgdata.other.timestamp, + RawProcessor.imgdata.color.flash_used != 0.0f, RawProcessor.imgdata.other.iso_speed, RawProcessor.imgdata.other.shutter, + RawProcessor.imgdata.other.focal_len, RawProcessor.imgdata.other.aperture, RawProcessor.imgdata.sizes.flip, width, height, + RawProcessor.imgdata.other.parsed_gps.latitude, RawProcessor.imgdata.other.parsed_gps.latref, RawProcessor.imgdata.other.parsed_gps.longitude, + RawProcessor.imgdata.other.parsed_gps.longref, RawProcessor.imgdata.other.parsed_gps.altitude, RawProcessor.imgdata.other.parsed_gps.altref); + + Image = new CJPEGImage(width, height, pPixelData, NULL /* Helpers::FindEXIFBlock(thumb->data, thumb->data_size) */, colors, + Helpers::CalculateJPEGFileHash(thumb->data, thumb->data_size), IF_JPEG_Embedded, false, 0, 1, 0, NULL, false, metadata); + + Image->SetJPEGComment(Helpers::GetJPEGComment(thumb->data, thumb->data_size)); + Image->SetJPEGChromoSampling(eChromoSubSampling); + } + RawProcessor.dcraw_clear_mem(thumb); + } + // RawProcessor.recycle(); + + return Image; +} diff --git a/src/JPEGView/RAWWrapper.h b/src/JPEGView/RAWWrapper.h new file mode 100644 index 00000000..ba4fd6c8 --- /dev/null +++ b/src/JPEGView/RAWWrapper.h @@ -0,0 +1,9 @@ +#pragma once + +#include "JPEGImage.h" + +class RawReader +{ +public: + static CJPEGImage* ReadImage(LPCTSTR strFileName, bool& bOutOfMemory, bool bGetThumb); +}; diff --git a/src/JPEGView/RawMetadata.h b/src/JPEGView/RawMetadata.h index 7d163280..73c9d62f 100644 --- a/src/JPEGView/RawMetadata.h +++ b/src/JPEGView/RawMetadata.h @@ -1,5 +1,7 @@ #pragma once +#include "EXIFReader.h" + // Metadata read from camera RAW images class CRawMetadata { @@ -16,10 +18,17 @@ class CRawMetadata int GetOrientation() { return m_orientatation; } int GetWidth() { return m_width; } int GetHeight() { return m_height; } + GPSCoordinate* GetGPSLatitude() { return m_pLatitude; } + GPSCoordinate* GetGPSLongitude() { return m_pLongitude; } + double GetGPSAltitude() { return m_altitude; } + bool IsGPSInformationPresent() { return m_pLatitude != NULL && m_pLongitude != NULL; } + bool IsGPSAltitudePresent() { return m_altitude != CEXIFReader::UNKNOWN_DOUBLE_VALUE; } + // Note: Orientation is in cdraw format ('flip' global variable in cdraw_mod.cpp) CRawMetadata(char* manufacturer, char* model, time_t acquisitionTime, bool flashFired, double isoSpeed, double exposureTime, double focalLength, - double aperture, int orientation, int width, int height) + double aperture, int orientation, int width, int height, float* latitude = NULL, char latref = 0, float* longitude = NULL, char longref = 0, + double altitude = CEXIFReader::UNKNOWN_DOUBLE_VALUE, char altref = 0) { m_manufacturer = CString(manufacturer); m_model = CString(model); @@ -31,6 +40,17 @@ class CRawMetadata m_orientatation = orientation; m_width = width; m_height = height; + char zeros[3 * sizeof(float)] = { 0 }; + if (latitude != NULL && longitude != NULL && !(memcmp(latitude, zeros, 3 * sizeof(float)) == 0 && memcmp(longitude, zeros, 3 * sizeof(float)) == 0)) { + wchar_t c[2] = { 0 }; + c[0] = btowc(latref); + m_pLatitude = new GPSCoordinate(c, latitude[0], latitude[1], latitude[2]); + c[0] = btowc(longref); + m_pLongitude = new GPSCoordinate(c, longitude[0], longitude[1], longitude[2]); + } else { + m_pLatitude = m_pLongitude = NULL; + } + m_altitude = altref == 1 ? -altitude : altitude; LONGLONG time = (LONGLONG)acquisitionTime * 10000000 + 116444736000000000; FILETIME fileTime; @@ -39,6 +59,12 @@ class CRawMetadata ::FileTimeToSystemTime(&fileTime, &m_acquisitionTime); } + ~CRawMetadata(void) { + delete m_pLatitude; + delete m_pLongitude; + } + + private: CString m_manufacturer; CString m_model; @@ -50,4 +76,8 @@ class CRawMetadata int m_orientatation; int m_width, m_height; SYSTEMTIME m_acquisitionTime; -}; \ No newline at end of file + GPSCoordinate* m_pLatitude; + GPSCoordinate* m_pLongitude; + double m_altitude; +}; + diff --git a/src/JPEGView/SettingsProvider.cpp b/src/JPEGView/SettingsProvider.cpp index 3415021e..afba2c22 100644 --- a/src/JPEGView/SettingsProvider.cpp +++ b/src/JPEGView/SettingsProvider.cpp @@ -231,6 +231,7 @@ CSettingsProvider::CSettingsProvider(void) { m_sDefaultSaveFormat = GetString(_T("DefaultSaveFormat"), _T("jpg")); m_sFilesProcessedByWIC = GetString(_T("FilesProcessedByWIC"), _T("*.wdp;*.mdp;*.hdp;*.ico")); m_sFileEndingsRAW = GetString(_T("FileEndingsRAW"), _T("*.pef;*.dng;*.crw;*.nef;*.cr2;*.mrw;*.rw2;*.orf;*.x3f;*.arw;*.kdc;*.nrw;*.dcr;*.sr2;*.raf")); + m_nDisplayFullSizeRAW = GetInt(_T("DisplayFullSizeRAW"), 0, 0, 3); m_bCreateParamDBEntryOnSave = GetBool(_T("CreateParamDBEntryOnSave"), true); m_bWrapAroundFolder = GetBool(_T("WrapAroundFolder"), true); m_bWindowAlwaysOnTopOnStartup = GetBool(_T("WindowAlwaysOnTopOnStartup"), false); diff --git a/src/JPEGView/SettingsProvider.h b/src/JPEGView/SettingsProvider.h index a442af17..ff5cb605 100644 --- a/src/JPEGView/SettingsProvider.h +++ b/src/JPEGView/SettingsProvider.h @@ -83,6 +83,7 @@ class CSettingsProvider LPCTSTR FilesProcessedByWIC() { return m_sFilesProcessedByWIC; } LPCTSTR FileEndingsRAW() { return m_sFileEndingsRAW; } void AddTemporaryRAWFileEnding(LPCTSTR sEnding) { m_sFileEndingsRAW += CString(_T(";*.")) + sEnding; } + int DisplayFullSizeRAW() { return m_nDisplayFullSizeRAW; } bool CreateParamDBEntryOnSave() { return m_bCreateParamDBEntryOnSave; } bool SaveWithoutPrompt() { return m_bSaveWithoutPrompt; } bool TrimWithoutPromptLosslessJPEG() { return m_bTrimWithoutPromptLosslessJPEG; } @@ -250,6 +251,7 @@ class CSettingsProvider CString m_sDefaultSaveFormat; CString m_sFilesProcessedByWIC; CString m_sFileEndingsRAW; + int m_nDisplayFullSizeRAW; bool m_bCreateParamDBEntryOnSave; bool m_bWrapAroundFolder; bool m_bSaveWithoutPrompt;