Skip to content

pbtechlab/pbImageViewer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pbImageViewer icon

pbImageViewer

Read this in other languages: 日本語

A fast, lightweight desktop image viewer built with C++17 and Qt 6. It decodes images asynchronously on a background thread pool, caches them in memory with an LRU policy, prefetches neighboring images for instant navigation, honors EXIF orientation, and supports a wide range of formats — including modern codecs such as HEIC/HEIF and AVIF when the optional libraries are present.


Table of Contents


Features

  • Wide format support. Everything Qt's image plugins can read, plus HEIC/HEIF (via libheif) and AVIF — static and animated — (via libavif) when those optional libraries are found at build time.
  • Animated images. Animated GIF and WebP play back through Qt; animated AVIF plays back through libavif. Per-frame delays are respected.
  • Asynchronous decoding. Images decode on a QThreadPool background worker so the UI never blocks, even on large files.
  • LRU memory cache. Decoded images are stored in a thread-safe least-recently-used cache (default budget 512 MB). Already-seen images redisplay instantly with no re-decode.
  • Neighbor prefetch. When you view an image, the next, previous, and next-next images are decoded in the background so paging through a folder is near-instant.
  • EXIF auto-orientation. Photos are rotated automatically according to their EXIF orientation tag (QImageReader::setAutoTransform).
  • Folder navigation with natural sort. Open a single file or a whole folder. The folder is scanned for all supported images and sorted with natural (numeric-aware) ordering, so img2 comes before img10. Navigation wraps around at the ends.
  • Zoom, pan, rotate, fit. Smooth zooming (2%–6400%), scroll-hand panning, 90° rotation in either direction, fit-to-window, and 100% (1:1) reset.
  • Slideshow. Auto-advance through the folder on a timer.
  • Fullscreen. Hides the menu and status bar; restores the prior maximized/normal state on exit.
  • Drag & drop. Drop a file or folder onto the window to open it.
  • Save As. Export the currently displayed image to PNG, JPEG, BMP, WebP, or TIFF.
  • Command-line / "Open with". A path passed as the first argument opens on launch.
  • Status bar. Shows the file name, position in the folder ([n/total]), whether the image is animated, slideshow state, and the current zoom percentage.

Supported Formats

The exact list of "always available" formats depends on which Qt image format plugins are installed in your Qt build. The table below reflects the formats Qt 6 ships by default plus the optional native decoders.

Format Extensions Decoder Animation
JPEG .jpg, .jpeg Qt
PNG .png Qt
BMP .bmp Qt
GIF .gif Qt Yes (animated)
WebP .webp Qt Yes (animated)
TIFF .tif, .tiff Qt
TGA .tga Qt
ICO .ico Qt
SVG .svg Qt
HEIC / HEIF .heic, .heif libheif (optional) — (primary image)
AVIF .avif, .avifs libavif (optional) Yes (animated)

Notes:

  • The supported-extension list is built at runtime from QImageReader::supportedImageFormats(), so any extra Qt image plugins present on your system are picked up automatically.
  • HEIC/HEIF support is compiled in only when libheif is found at configure time (HAVE_LIBHEIF). The primary (cover) image of the file is decoded.
  • AVIF support is compiled in only when libavif is found at configure time (HAVE_LIBAVIF). Both static and animated AVIF are supported.
  • Without these optional libraries the app still builds and runs; HEIC/AVIF files simply fall back to Qt (and will fail to open if Qt has no plugin).

Keyboard Shortcuts

Action Shortcut
Open File… Ctrl+O
Open Folder… Ctrl+Shift+O
Save As… Ctrl+Shift+S
Quit Ctrl+Q
Previous image Left
Next image Right
First image Home
Last image End
Zoom In +
Zoom Out -
100% (1:1) Ctrl+0
Fit to window Ctrl+F
Fullscreen (toggle) F11
Slideshow (toggle) F5
Rotate clockwise Ctrl+R
Rotate counter-clockwise Ctrl+L

The Open (Ctrl+O), Save As (Ctrl+Shift+S), and Quit (Ctrl+Q) shortcuts are Qt's standard sequences and may map to platform conventions.


Menus & Actions

The menu bar is organized into four menus:

  • File — Open File…, Open Folder…, Save As…, Quit.
  • View — Zoom In, Zoom Out, 100%, Fit, Fullscreen, Slideshow (checkable).
  • Navigate — Previous, Next, First, Last.
  • Edit — Rotate CW, Rotate CCW.

A non-movable toolbar exposes the most common actions: Open File, Open Folder, Previous, Next, Zoom In, Zoom Out, 100%, Fit, Rotate CW, and Rotate CCW.


Mouse Controls

Gesture Result
Mouse wheel up / down Zoom in / out, anchored under the cursor
Click & drag Pan (scroll-hand drag)
Double-click Toggle between Fit-to-window and 100%

Architecture

The codebase is small and cleanly separated into single-responsibility classes.

File Responsibility
src/main.cpp Entry point; sets app/org name; opens a CLI path argument.
src/MainWindow.{h,cpp} Window, menus, toolbar, status bar; wires up loading, navigation, slideshow, fullscreen, save-as, drag & drop.
src/ImageView.{h,cpp} QGraphicsView-based canvas for zoom/pan/rotate/fit and animation playback.
src/ImageLoader.{h,cpp} Backend dispatch (Qt / libheif / libavif), supported-extension list, and async decode via QThreadPool.
src/ImageCache.{h,cpp} Thread-safe LRU cache keyed by file path with a byte budget.
src/FolderScanner.{h,cpp} Lists and natural-sorts supported images in a directory.
src/DecodedImage.h Frame and DecodedImage value types shared across threads.

Asynchronous decode. ImageLoader::request() issues a monotonically increasing token and starts a LoadTask (a QRunnable) on its internal QThreadPool (sized to max(2, idealThreadCount())). The task decodes off the UI thread and posts the result back via a queued loaded(token, path, image) signal. MainWindow only displays a result whose token matches the image the user is currently waiting for, so stale results from rapid navigation are ignored (but still cached).

Backend dispatch. ImageLoader::decode() routes by extension: .heic/.heif → libheif, .avif/.avifs → libavif, everything else → Qt's QImageReader (with setAutoTransform(true) for EXIF orientation and multi-frame reading for animations).

LRU cache + prefetch. Decoded images go into ImageCache, an LRU keyed by path with a default 512 MB budget; the least-recently-used entries are evicted when the budget is exceeded. After showing an image, MainWindow prefetches index+1, index-1, and index+2 so paging is instant. Cache hits display synchronously with no decode.

Rendering. ImageView is a QGraphicsView with a smooth-transform pixmap item over a dark background. Zoom and rotation are applied through a combined QTransform; zoom is clamped to 2%–6400% (0.0264.0). Fit-to-window never upscales beyond 100% and re-fits automatically on resize and rotation. Animated images advance frame-by-frame on a single-shot QTimer honoring each frame's delay.


Building

Requirements

  • CMake ≥ 3.21
  • Qt 6.9.1 (MSVC 2022 64-bit build) — expected at C:\Qt\6.9.1\msvc2022_64
  • Visual Studio 2022 (MSVC toolchain)
  • Optional: libheif and libavif (e.g. via vcpkg) for HEIC/HEIF and AVIF support

Qt components used: Widgets and Concurrent.

Configure & build (Qt only)

cmake -S . -B build -G "Ninja" ^
  -DCMAKE_PREFIX_PATH="C:/Qt/6.9.1/msvc2022_64"

cmake --build build --config Release

Or with the Visual Studio generator:

cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ^
  -DCMAKE_PREFIX_PATH="C:/Qt/6.9.1/msvc2022_64"

cmake --build build --config Release

Configure & build with HEIC/AVIF (vcpkg)

Install the optional decoders and point CMake at both Qt and the vcpkg toolchain:

vcpkg install libheif libavif

cmake -S . -B build -G "Ninja" ^
  -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" ^
  -DCMAKE_PREFIX_PATH="C:/Qt/6.9.1/msvc2022_64"

cmake --build build --config Release

During configuration CMake prints which optional decoders were enabled, e.g.:

pbImageViewer: libheif ENABLED (HEIC/HEIF support)
pbImageViewer: libavif ENABLED (AVIF support)

If a library is not found, the corresponding line reads NOT found ... disabled and the app builds without that format.


Running

build\pbImageViewer.exe                 # start empty
build\pbImageViewer.exe path\to\img.jpg # open a file (or folder) on launch

You can also register the executable as the default "Open with" handler — the first command-line argument is opened automatically.

About

Fast Qt6 desktop image viewer (C++17). HEIC/AVIF/WebP/animated formats, async decode + prefetch cache, customizable shortcuts, EN/JP UI.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors