@@ -44,6 +44,7 @@ using namespace QuickView;
4444#include "TinyExrLoader.h"
4545#include <shobjidl.h> // [Add] for IShellItemImageFactory
4646#include <thread>
47+ #include "MiniTiff.h"
4748
4849extern FileNavigator& g_navigator;
4950
@@ -532,67 +533,6 @@ void CImageLoader::ReleaseJxlRunner() {
532533namespace QuickView {
533534namespace Codec {
534535
535- struct DecodeContext {
536- // Memory Allocator: Returns pointer to allocated memory.
537- // Caller (Codec) calculates 'totalSize' based on aligned stride and height.
538- QuickView::AllocatorCallback allocator;
539- QuickView::FreeCallback freeFunc;
540-
541- // Runtime Control
542- QuickView::SimplePredicate checkCancel;
543- std::stop_token stopToken;
544-
545- // Parameters
546- int targetWidth = 0 ; // 0 = Full
547- int targetHeight = 0 ;
548- PixelFormat format = PixelFormat::BGRA8888 ; // Preferred Output Format
549- bool forcePreview = false ; // Force fast preview (e.g. JXL/Embedded Thumb)
550- float targetHdrHeadroomStops = -1 .0f ; // < 0 = codec default
551-
552- // [v5.3] Telemetry Output - backward compatible
553- std::wstring *pLoaderName = nullptr ;
554- std::wstring *pFormatDetails = nullptr ;
555-
556- // [v5.3] Unified metadata pointer (optional - if set, loaders will populate)
557- CImageLoader::ImageMetadata *pMetadata = nullptr ;
558-
559- // [v10] Fallback control for Titan Base Layer
560- bool forceRenderFull = false ;
561-
562- // [v10.1] Override to prevent 1x1 Fake Base generation (e.g. for specific
563- // LODs)
564- bool allowFakeBase = true ;
565- bool isTitanMode = false ;
566-
567- // [v6.2.5.3] Flag to preserve FP16/FP32 data (bypassing CPU SDR reduction).
568- // True for main viewport rendering.
569- bool preserveFloat = false ;
570-
571- // [Async Gain Map] Callback to post AuxLayer back to main engine
572- QuickView::AuxLayerCallback onAuxLayerReady;
573- };
574-
575- struct DecodeResult {
576- uint8_t *pixels = nullptr ;
577- int width = 0 ;
578- int height = 0 ;
579- int stride = 0 ; // Must be 16/64 byte aligned for SIMD/GPU
580- PixelFormat format = PixelFormat::BGRA8888 ;
581- bool success = false ;
582-
583- // [v5.3] Unified metadata (includes loader name, format details, EXIF, etc.)
584- CImageLoader::ImageMetadata metadata;
585-
586- // [GPU Pipeline] Multi-layer composition asset package
587- GpuBlendOp blendOp = GpuBlendOp::None;
588- std::unique_ptr<AuxLayer> auxLayer;
589- GpuShaderPayload shaderPayload;
590-
591- // [v10.5] Animation Decoder Payload
592- std::shared_ptr<QuickView::IAnimationDecoder> animator;
593- QuickView::AnimationFrameMeta frameMeta; // Transport for first frame meta
594- };
595-
596536// File I/O Helpers
597537// ------------------------------------------------------------------------
598538
@@ -842,7 +782,8 @@ bool IsUnifiedBufferCodec(const std::wstring &fmt) {
842782 return fmt == L"JPEG" || fmt == L"WebP" || fmt == L"PNG" || fmt == L"GIF" ||
843783 fmt == L"BMP" || fmt == L"JXL" || fmt == L"AVIF" || fmt == L"QOI" ||
844784 fmt == L"TGA" || fmt == L"PNM" || fmt == L"WBMP" || fmt == L"PSD" ||
845- fmt == L" HDR" || fmt == L" PIC" || fmt == L" PCX" || fmt == L" EXR" ;
785+ fmt == L"HDR" || fmt == L"PIC" || fmt == L"PCX" || fmt == L"EXR" ||
786+ fmt == L"TIFF";
846787}
847788
848789bool ShouldProbeAnimatedBufferCodec(const std::wstring &fmt) {
@@ -2819,6 +2760,78 @@ HRESULT CImageLoader::LoadRegionToFrame(
28192760 targetHeight);
28202761 }
28212762
2763+ // --- Strategy 1c: MiniTIFF Region Decoding ---
2764+ if (format == L"TIFF") {
2765+ int origWidth = 0, origHeight = 0;
2766+ if (SUCCEEDED(GetImageSize(filePath, (UINT*)&origWidth, (UINT*)&origHeight))) {
2767+ RegionScalePlan plan{};
2768+ if (BuildRegionScalePlan(srcRect, origWidth, origHeight, scale, targetWidth, targetHeight, &plan)) {
2769+ QuickView::MappedFile mapping(filePath);
2770+ if (mapping.IsValid()) {
2771+ outFrame->width = plan.frameW;
2772+ outFrame->height = plan.frameH;
2773+ outFrame->stride = CalculateAlignedStride(plan.frameW, 4);
2774+ outFrame->format = PixelFormat::BGRA8888;
2775+ size_t totalSize = outFrame->GetBufferSize();
2776+ if (tileManager && totalSize <= TILE_SLAB_SIZE) {
2777+ outFrame->pixels = (uint8_t *)tileManager->Allocate();
2778+ if (outFrame->pixels) {
2779+ outFrame->memoryDeleter.ctx = tileManager;
2780+ outFrame->memoryDeleter.pfn = [](uint8_t *p, void *ctx) {
2781+ static_cast<QuickView::TileMemoryManager *>(ctx)->Free(p);
2782+ };
2783+ }
2784+ }
2785+ if (!outFrame->pixels) {
2786+ outFrame->pixels = (uint8_t *)_aligned_malloc(totalSize, 64);
2787+ outFrame->memoryDeleter = QuickView::MemoryDeleter::FromAlignedFree();
2788+ }
2789+ if (!outFrame->pixels) {
2790+ return E_OUTOFMEMORY;
2791+ }
2792+ if (plan.contentH < plan.frameH || plan.contentW < plan.frameW) {
2793+ memset(outFrame->pixels, 0, totalSize);
2794+ }
2795+
2796+ QuickView::Codec::DecodeContext tiffCtx;
2797+ tiffCtx.allocator.ctx = nullptr;
2798+ tiffCtx.allocator.pfn = [](void*, size_t s) -> uint8_t* {
2799+ return static_cast<uint8_t*>(_aligned_malloc(s, 64));
2800+ };
2801+ tiffCtx.checkCancel = checkCancel;
2802+
2803+ QuickView::Codec::DecodeResult roiResult;
2804+ HRESULT hrRegion = QuickView::MiniTiff::LoadRegion(
2805+ mapping.data(), mapping.size(), tiffCtx, roiResult,
2806+ plan.cropX, plan.cropY, plan.cropW, plan.cropH
2807+ );
2808+
2809+ if (SUCCEEDED(hrRegion)) {
2810+ ImageLoaderSimd::ResizeBilinear(
2811+ roiResult.pixels, plan.cropW, plan.cropH, roiResult.stride,
2812+ outFrame->pixels, plan.contentW, plan.contentH, outFrame->stride
2813+ );
2814+ if (roiResult.pixels) {
2815+ _aligned_free(roiResult.pixels);
2816+ }
2817+ if (pLoaderName) {
2818+ *pLoaderName = L"MiniTIFF Region";
2819+ }
2820+ return S_OK;
2821+ } else {
2822+ outFrame->Release();
2823+ if (hrRegion == E_NOTIMPL) {
2824+ return LoadRegionGeneric_StrategyB(filePath, srcRect, scale, outFrame,
2825+ tileManager, arena, checkCancel,
2826+ targetWidth, targetHeight);
2827+ }
2828+ return hrRegion;
2829+ }
2830+ }
2831+ }
2832+ }
2833+ }
2834+
28222835 // --- Strategy 2: Strategy B (Load Full & Crop/Resize) ---
28232836 // For formats without native region decoding support (PNG, etc.)
28242837 if (format == L"PNG") {
@@ -9178,6 +9191,17 @@ HRESULT CImageLoader::LoadImageUnified(LPCWSTR filePath,
91789191 return hrErr;
91799192 return hr; // Returns libavif error if WIC error was generic
91809193 } else {
9194+ if (fmt == L"TIFF") {
9195+ HRESULT hr = QuickView::MiniTiff::Load(mappedData, mappedSize, ctx, result);
9196+ if (SUCCEEDED(hr)) {
9197+ return S_OK;
9198+ }
9199+ if (hr == E_OUTOFMEMORY || hr == E_ABORT) {
9200+ return hr;
9201+ }
9202+ return hr; // Returns E_NOTIMPL to fallback, other to fail
9203+ }
9204+
91819205 HRESULT hr = LoadBufferUnified(mappedData, mappedSize, fmt, ctx, result);
91829206 if (hr == E_OUTOFMEMORY || hr == E_ABORT)
91839207 return hr;
0 commit comments