一張圖能打開,只是圖片檢視器的起點。連續看漫畫時,還有檔名順序、翻頁等待、文字放大後的可讀性;處理 HDR 截圖時,則會遇到亮度轉換與分享格式的問題。
我想在同一個 Windows 程式裡處理這幾件事:平常能順手翻圖,需要時再開啟 RTX 增強,也能把 HDR JXR 轉成容易分享的 SDR PNG。EinzigViewer 的實作因此分成兩個重點:一般檢視必須先能用,較重的解碼與 GPU 工作則在背景完成。
這篇依目前公開的 v0.6.0 整理。專案先前曾使用 MiraView、Eidolyx 名稱,現在統一為 EinzigViewer。
先做好連續閱讀,再增加影像處理
開啟一張圖後,EinzigViewer 會索引同一資料夾,以 Windows 自然排序排列檔名,讓 1、2、3、10 保持正常頁序。適合視窗、適合寬度、原始大小、游標定位縮放與全螢幕,都是一般閱讀會直接用到的功能。
目前核心能力包括:
| 使用需求 | 已實作的處理 |
|---|---|
| 連續翻閱資料夾 | 自然排序、背景解碼、鄰頁預讀與記憶體快取 |
| 放大小圖與漫畫文字 | 可切換 RTX VSR,按住 C 與原圖比較 |
| 在 HDR 螢幕觀看增強結果 | 主視窗內的 VSR → TrueHDR 管線與 HDR10 輸出 |
| 分享 HDR JXR 截圖 | 保留浮點資料後做 HDR → SDR 色調映射,再轉存 PNG |
| 縮小圖片 | 指定長邊,保持比例縮小並轉存 sRGB PNG |
它目前仍是以資料夾為基礎的檢視器。CBZ、雙頁模式、縮圖瀏覽器與完整檔案管理還是後續規劃,不能因為用途包含漫畫,就把它當成已完成的漫畫資料庫。
為什麼使用 C++/Win32?
目前採用 C++20、Win32、WIC 與 Direct2D。這個組合讓視窗輸入、Windows 解碼器與繪圖資源都能在原生程式內處理,也方便後面接到 D3D11;執行時不需要 .NET Runtime。
WIC 負責一般格式的解碼與 EXIF 方向,Direct2D 負責一般檢視的縮放、平移與呈現。格式支援有明確邊界:WebP、HEIC、AVIF 等依賴系統安裝的 WIC codec;GIF 等動態圖片目前只顯示第一幀。
這樣可以先利用系統已有的能力,但也代表「這台電腦能開」不保證每台乾淨安裝的 Windows 都能開同一種格式。內建更多 codec,是另一個需要處理部署與授權的工作。
翻頁效能的關鍵是先做哪件事
如果每次按下一頁,才開始從磁碟讀取、解碼、上傳圖片,即使單張處理不慢,連續閱讀也會感覺在等。現在的資料流是:
FolderModel索引資料夾,記住目前位置。ImageCache依頁面距離與翻頁方向排定優先順序。- 最多四條背景解碼執行緒處理圖片,預讀前後各八張。
- UI 執行緒將眼前頁面的 BGRA 資料上傳到 Direct2D,再呈現。
快取採 768 MB LRU 預算,並固定保留目前與鄰近頁面。這是快取管理設定,不是整個程序的記憶體硬上限;超大圖片、固定保留的頁面與 GPU 資源,仍需要另外考慮。
快速連按翻頁時,已經不重要的排隊工作會被清掉,最新要看的頁面回到最高優先。預讀的價值不在於把所有圖片都做完,而是讓眼前與接下來最可能需要的圖片先準備好。
把 RTX Video 用在靜態圖片上
EinzigViewer 直接呼叫 NVIDIA RTX Video SDK 1.1,透過 D3D11 將圖片送入 VSR。它不需要借用瀏覽器的「視訊增強」開關,但仍需要相容的 RTX GPU、驅動與 SDK runtime。
純 VSR 模式只在圖片需要放大時執行,固定使用 Ultra 品質。輸出尺寸依實際顯示需要計算,因此從小視窗切到 4K 全螢幕時,需要重新取得適合的增強結果。
這裡的難點不只有呼叫 SDK:
- GPU 計算不阻塞翻頁。 先顯示一般解碼圖,增強完成後再替換。
- 舊頁結果不能蓋過新頁。 翻頁後要核對請求的 generation,已過期的結果直接丟棄。
- 比較要容易。 按住 C 顯示原圖,放開回到 VSR 結果,方便觀察細字、邊緣與網點的變化。
- 失敗時仍能看圖。 沒有 SDK 的建置使用
NullImageEnhancer;runtime 出錯時則回到一般檢視。
VSR 是超解析度增強,不能拿它當原始內容的證據或保證還原。放大後更銳利的線條,也可能與原圖有差異。保留原圖比較,比只顯示「RTX 已啟用」更有意義。
公開整合紀錄包含在 RTX 4070 Ti SUPER 上完成 960×540 → 3840×2160 的測試。這是功能驗證,不是所有顯卡與所有圖片都能達到同樣速度的效能承諾。
HDR 有兩條方向相反的處理路徑
這個專案裡的「HDR」其實包含兩件不同的事,實作時必須分開。
顯示增強:SDR → VSR → TrueHDR
按 H 啟用的模式,是讓一般圖片先經 VSR,再進入 TrueHDR,在同一個 D3D11 裝置裡以 GPU texture 串接。最後由主視窗內容區的 HDR10 swap chain 呈現 10-bit、PQ/Rec.2020 輸出。
這條路徑啟動前會檢查 Windows HDR 狀態,並依螢幕資訊處理峰值亮度。HDR 的專用顯示區留在原本主視窗內,資料夾索引、翻頁與資訊列可以沿用。
從 HDR 切回純 VSR,還要讓舊的 TrueHDR 工作安全退出,避免舊工作仍持有呈現資源,或上一張 HDR 幀留在畫面上。較重的 TrueHDR 工作也採最新請求佇列,快速翻頁不需要逐張等候。
VSR → TrueHDR 之間不經 CPU 讀回;純 SDR VSR 結果目前仍會讀回 CPU,再交給 Direct2D。這兩條顯示路徑的現況不同,不能一概稱為全程零拷貝。
檔案轉存:HDR JXR → SDR PNG
另一條路徑是分享截圖。HDR JXR 的 extended RGB 可能含有超出一般 SDR 範圍的亮度;若解碼時立刻壓成 8-bit,後面的轉換就已經失去資訊。
目前對這類 JXR 先使用 128bpp float 保留線性 scRGB,再做亮度保持的 tone mapping:以 scRGB 80 nits 參考亮度與 SDR paper white 203 nits 處理,經 ACES shoulder 壓縮高光,最後編碼成 sRGB。
輸出的 PNG 是帶 sRGB 標記的 8-bit 一般圖片,適合瀏覽器與分享用途,並不是 HDR 封存格式。轉存讀取完整解碼後的圖像資料,也不會把當下 RTX 增強過的顯示畫面誤當原圖存出去。
縮小轉存使用 WIC Fant interpolation,按指定長邊保持比例,且只接受縮小。這讓「調整尺寸」與「AI 放大顯示」保持明確的用途區分。
用模組邊界處理不同生命週期
| 模組 | 責任 |
|---|---|
FolderModel | 索引、自然排序與目前位置 |
WicDecoder | 每個背景工作執行緒的 COM/WIC 解碼與色彩轉換 |
ImageCache | 優先佇列、鄰頁保留與 LRU 管理 |
ImageExporter | 原尺寸或縮小的 sRGB PNG 輸出 |
ImageEnhancer | 純 VSR 後端介面與可用性回退 |
RtxHdrProcessor | 同一 D3D11 裝置上的 VSR/TrueHDR 處理 |
RtxHdrPresenter | HDR10 呈現、最新請求佇列與 SDR 恢復 |
App | Win32 訊息、顯示模式、輸入與設定 |
這些模組完成工作的時間不同。UI 已經換頁時,解碼或 GPU 可能還在處理上一頁;關閉增強功能時,背景工作也不一定已結束。除了處理成功路徑,還需要明確處理失效、退出與回退,才能把影像處理接到持續互動的檢視器裡。
現在的限制與下一步
v0.6.0 已有整合式 RTX/HDR、HDR JXR 轉存與縮小功能,但還有幾個值得繼續做的地方:
- SDR VSR 呈現:改善 CPU 讀回成本,研究直接使用 D3D11 texture 呈現。
- 快取:目前 VSR 結果保留在記憶體,尚無磁碟快取;加入前要先定義來源、尺寸、品質與版本的失效規則。
- 色彩處理:JXR tone mapping 目前固定,還沒有曝光、paper white 與曲線控制,也尚未有完整 ICC 色彩管理。
- 閱讀功能:CBZ、雙頁與閱讀方向等都還沒完成。
- 效能驗證:架構文件中的翻頁延遲與預讀命中率是驗收目標,還不能寫成已在各種磁碟和資料集達成的成績。
如果要試用,可以下載 v0.6.0 Windows x64 發行包,完整解壓縮後執行。一般檢視與 RTX 功能的環境要求不同,詳細條件與快捷鍵放在 README。
想看程式如何接在一起,可接著讀 架構文件 與 RTX 整合紀錄。NVIDIA SDK 與 runtime 的授權範圍另見 第三方告知。
