ComicViewer.Core 1.0.0-preview.1

This is a prerelease version of ComicViewer.Core.
dotnet add package ComicViewer.Core --version 1.0.0-preview.1
                    
NuGet\Install-Package ComicViewer.Core -Version 1.0.0-preview.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ComicViewer.Core" Version="1.0.0-preview.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ComicViewer.Core" Version="1.0.0-preview.1" />
                    
Directory.Packages.props
<PackageReference Include="ComicViewer.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ComicViewer.Core --version 1.0.0-preview.1
                    
#r "nuget: ComicViewer.Core, 1.0.0-preview.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ComicViewer.Core@1.0.0-preview.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ComicViewer.Core&version=1.0.0-preview.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ComicViewer.Core&version=1.0.0-preview.1&prerelease
                    
Install as a Cake Tool

ComicViewer

A comic reader control for WinUI 3, built on ComiX.

License: MIT .NET NuGet build

ComicViewer is a WinUI 3 control for reading comic archives. It provides single-page and two-page layouts, left-to-right and right-to-left reading, zooming and panning, and interactive page-turn animations.

The default page-turn effect simulates the curvature of a sheet of paper. During a drag, the page follows the pointer and settles with spring-based motion when released. A simpler horizontal slide transition is also available.

Rendering is handled by a Direct3D 11 renderer hosted in the control's composition tree. Pages are decoded at the size at which they are displayed, kept within a configurable cache budget, and prefetched around the current reading position.

<viewer:ComicView x:Name="Viewer" ReadingMode="DoublePage" />
await Viewer.OpenAsync("example.cbz");
Viewer.NextPage();

Packages

Package Target framework Contents
ComicViewer.Core net10.0 ComicDocument built on ComiX, shared viewer types, and the UI-independent reading engine. The engine includes spread layout, navigation, viewport and zoom geometry, transition physics, page caching, and prefetch scheduling.
ComicViewer.WinUI net10.0-windows10.0.26100.0 The ComicView WinUI 3 control, including Direct3D 11 rendering through Vortice.Windows, WIC image decoding, pointer, wheel and keyboard input, and automation support. Requires Windows App SDK 2.4 and Windows 10 1809 or later.

ComicViewer.Core has no UI dependency.

Supported formats

Supported comic containers are the formats provided by ComiX:

  • CBZ
  • CBR
  • CB7
  • CBT

Supported image formats depend on the Windows Imaging Component codecs available on the system. JPEG, PNG, GIF, BMP, and TIFF are always supported. WebP and AVIF are supported when the corresponding Windows image extensions are installed.

Installation

dotnet add package ComicViewer.WinUI --prerelease

ComicViewer.WinUI brings ComicViewer.Core and ComiX with it. Applications that only need document access can reference ComicViewer.Core directly.

Pre-release packages are not selected by NuGet unless --prerelease is specified or an explicit package version is declared in the project file. The API may change between preview releases; see CHANGELOG.md for version-specific changes.

The ComicView control

Opening documents

ComicView.OpenAsync(path) opens a comic archive through ComiX and displays its first page.

A readable, seekable stream can be opened with OpenAsync(stream).

Both overloads accept ComiX's ComicOpenOptions, including password protection, entry limits, metadata reading, and extraction-cache settings.

When no options are supplied, the control uses ComicDocument.DefaultOpenOptions. These defaults enable an in-memory cache for extracted page content. To extend the defaults without replacing them:

await Viewer.OpenAsync(
    path,
    ComicDocument.DefaultOpenOptions with { Password = password });

Creating ComicOpenOptions from scratch replaces the defaults entirely, including the cache settings.

The control owns documents opened through OpenAsync and disposes them when another document is opened or CloseAsync is called.

A ComicDocument created with ComicDocument.OpenAsync can also be assigned directly to ComicView.Document. Documents assigned this way remain owned by the caller and are not disposed by the control.

Opening a document reads its archive index and metadata. Page content is read and decoded on demand.

Properties

Property Description
Document The document currently displayed.
CurrentPage, PageCount, VisiblePages The current reading position. CurrentPage identifies the first page in the current spread. Setting it changes the reading position without animation.
ReadingDirection Automatic uses the document metadata; LeftToRight and RightToLeft force a direction. EffectiveReadingDirection reports the resolved direction.
ReadingMode SinglePage displays one page at a time. DoublePage displays facing pages on either side of the spine when the viewport is wider than it is tall. Landscape pages and pages declared as spreads are split at the spine. With DisplayCoverAlone, the first page is displayed by itself on the side from which reading starts, like the cover of a closed book.
ZoomMode, ZoomFactor, MinimumZoom, MaximumZoom Zoom behavior and limits. Modes are FitPage, FitWidth, FitHeight, and Manual. ZoomFactor is relative to the scale at which the current spread fits the viewport, so FitPage corresponds to a factor of 1.
Rotation Rotates the spread around its center, clockwise, in degrees. Values are normalized to [0, 360). Fit modes recalculate the layout after rotation, and 90-degree increments are rendered pixel-aligned. RotateClockwise and RotateCounterclockwise rotate by 90 degrees.
TransitionStyle Curl, the default, turns the page over the spine with a paper-like curl. Slide moves spreads horizontally instead.
VersoColor The color used for the blank side of a page during Curl when that side has no page behind it, as in single-page mode.
IsAnimationEnabled Enables or disables animated transitions. Animations are also disabled automatically when the system's animation setting is off.
TransitionSettings Controls drag thresholds and velocity, end-of-document resistance, spring damping and period, curl radius, whether the page remains anchored where the pointer first pressed, and related transition behavior. A curl preserves release velocity and settles within Duration; a slide uses the configured spring.
IsEdgeNavigationEnabled Allows dragging a zoomed spread against its edge to navigate to the adjacent spread.
Sounds, SoundVolume Page-turn sound effects through PageSounds (see Sounds), and their volume from 0 to 1.
Widgets The WidgetLayer containing visual and interactive elements positioned over the pages (see Widgets).
Magnifier The MagnifierWidget displayed over the current spread (see Magnifier).
PrefetchDistance, MaximumCacheSizeInBytes, MaximumDecodedDimension Prefetch distance, decoded-page cache budget (256 MiB by default), and the maximum decode dimension on either axis (8192 pixels by default).
CacheSizeInBytes, CachedImageCount The decoded pages currently cached, reported as texture memory usage and image count. These properties are read-only. The current spread remains cached even when the configured budget would otherwise require eviction.
State Current control state: Idle, Loading, Displaying, Navigating, Dragging, Zooming, Animating, Error, or Disposed.

Methods and events

The control exposes navigation, zoom, document, and lifecycle APIs including:

NextPage, PreviousPage, GoToPage, ZoomIn, ZoomOut, ZoomTo, FitToPage, FitToWidth, FitToHeight, ResetZoom, OpenAsync, and CloseAsync.

The main events are:

PageChanged, ZoomChanged, StateChanged, DocumentOpened, DocumentFailed, and PageFailed.

If a page cannot be decoded, PageFailed reports the error and the remaining pages remain available.

Input

Input Effect
Drag (mouse, touch, pen) Navigates between spreads when the spread fits the viewport, or pans when zoomed. When IsEdgeNavigationEnabled is enabled, dragging against the edge of a zoomed spread can navigate to the adjacent spread. Page turns follow the pointer along the spread's own horizontal axis; after a 90-degree rotation, that axis is vertical on screen. The turn commits or returns on release according to drag distance and velocity.
Pinch Zooms around the center of the contact points.
Double tap or double click Toggles between fit and 2× zoom around the interaction point.
Mouse wheel Pans when the spread extends beyond the viewport in the wheel's direction. Otherwise, each detent advances by one spread after the previous navigation has settled. Holding Ctrl zooms around the pointer. Horizontal wheel input and Shift+wheel navigate horizontally.
Two-finger touchpad gesture Pans when the spread is zoomed. Otherwise, it drives the page turn like a drag: the page follows the fingers and commits or returns when the gesture ends, using the gesture's velocity. Touchpad inertia after release remains part of the same gesture and does not turn additional pages.
Touchpad pinch Zooms around the pointer.
Left / Right Moves to the previous or next spread according to the effective reading direction.
Up / Down Pans vertically when the spread overflows the viewport; otherwise moves between spreads.
Page Up / Page Down / Space / Backspace Moves between spreads.
Home / End Moves to the first or last spread.
+ / − / Ctrl+0 Zooms in, zooms out, or fits the page.

On Windows, touchpad input reaches the control through wheel events. Small deltas are interpreted as touchpad movement, while whole detents are treated as mouse-wheel input.

Sounds

WIP

Widgets

ComicView.Widgets is a WidgetLayer containing PageWidget objects. Each widget is anchored to a page by index and renders a WidgetVisual: a rectangle, ellipse, polygon, path, text box, or group of visuals under a transform.

Widget geometry is expressed in the page's own coordinate system, using the page's natural pixel dimensions from GetPageSize. The viewer rasterizes widget content with Direct2D and DirectWrite into an overlay, at the resolution used to display the page, and composites that overlay onto the page surface. As a result, widgets zoom, rotate, and curl with the page.

Transform changes a widget's position without requiring its visual geometry to be recreated. Changing Visual, Transform, IsVisible, Opacity, or ZOrder causes the widget layer to redraw.

The widget layer belongs to the document currently being displayed and is cleared when another document is attached.

TryMapToPage and MapFromPage convert positions between the control and page-pixel coordinates on the current spread.

Widget input

Widgets are passive unless IsHitTestVisible is enabled.

Interactive widgets receive pointer input through WidgetPointerEventArgs, which provides the pointer position in page coordinates, the pressed Button, active Modifiers, and the input Device.

Hover

PointerEntered, PointerMoved (with IsInContact false), and PointerExited are raised as the pointer moves across the widget. The widget's Cursor is used, with a hand cursor by default.

Tap

PointerPressed is raised when contact begins on the widget. If the contact is released at its starting position, Tapped is raised.

When a primary-button press is not handled, it continues through widgets underneath and then to the page. This means a drag can still pan or turn the page, while a tap remains available to the widget.

A secondary or other non-primary button press that no widget handles is ignored.

Contact

A widget can claim a contact by handling PointerPressed.

Once claimed, it receives PointerMoved events with IsInContact set to true, including positions extrapolated beyond the page edges, followed by PointerReleased. IsCanceled indicates that the contact was lost without a normal release.

Claimed contacts are not seen by the page gesture handlers.

A Tapped event is still raised after a claimed release when movement stays within TransitionSettings.MinimumDragDistance.

Widget event routing

Each pointer event passes through three layers:

  1. A protected virtual OnPointer... method on the widget, which derived widgets can override.
  2. The widget's public event.
  3. The corresponding event on ComicView, such as WidgetPointerPressed or WidgetTapped.

This allows a component managing multiple widgets to subscribe at the control level instead of subscribing to every widget individually.

HitTestWidget returns the topmost widget at a position, while HitTest can be overridden by widgets with custom geometry.

Widgets do not receive input while a page is turning. The magnifier takes precedence over widget hit testing.

The control does not prescribe what a widget should do with a tap or drag. Selection, movement, resizing, and presentation are responsibilities of the component that owns the widget. It receives the position, button, and modifiers needed to implement that behavior.

The PanelWidget of the ComicViewer.Sample application, for example, uses Transform for dragging, while its window handles selection on tap and exposes a menu on the secondary button.

Magnifier

ComicView.Magnifier provides a lens over the current spread.

The lens is a disc with a configurable Radius and Position. Magnification ranges from 1.5× to 6×. The effect simulates thick glass: magnification is strongest at the center and falls toward the edge, where the image is also refracted.

Enable it with IsEnabled.

The magnifier starts at the center of the control. Pressing inside the lens drags it; a double press switches it into pointer-following mode until the next interaction. The mouse wheel over the lens changes its magnification.

The lens samples directly from the page images rather than from the rendered frame. It decodes the source page at the resolution required by the lens, so text remains as sharp as the available page data allows.

The magnifier is rendered only while the spread is at rest. It is hidden during page turns and restored to its previous position when the turn settles.

Accessibility

ComicView is a tab stop and exposes an automation peer of type Pane, named after the current document.

Page changes are announced through automation notifications. Default colors come from theme resources, allowing high-contrast themes to be respected.

Transitions are disabled automatically when the system's animation setting is disabled.

Performance and behavior

  • Archive access and page decoding never block the UI thread. Reads and decodes run on background threads and their results are applied on the UI thread.
  • Decoded pages are kept within MaximumCacheSizeInBytes, except that the pages of the current spread are never evicted. The cache can therefore exceed the configured budget temporarily when the current spread alone is larger than that budget.
  • Pages are decoded at the size at which they are displayed, up to MaximumDecodedDimension on either axis. Zooming beyond that limit magnifies the existing decoded image.
  • Navigation cancels loads that are no longer relevant. A page that fails to decode is not retried while the document remains open.
  • Rendering runs on its own thread and redraws only when something changes. A static page therefore consumes no ongoing CPU or GPU time. On systems without a GPU, rendering falls back to the WARP software rasterizer.
  • A curl transition always starts from the fit-page layout, so beginning a curl returns the viewport to ZoomMode.FitPage.
  • During a curl, the leaf is anchored at the point where the interaction began. A corner start produces a corner lift, while a start near the center of an edge produces a straighter fold. Keyboard, wheel, and button-driven turns use the bottom corner as the anchor.
  • Spreads with different proportions can fit the viewport at different scales. During a curl, the back of the moving leaf is stretched to match the leaf, and the destination spread is shown at its own scale when the turn commits.
  • Rotation applies to the entire document immediately and is not animated. Quarter turns are rendered pixel-aligned; other angles are resampled.
  • Widgets follow the page during a curl but accept input only while the spread is at rest. The magnifier is hidden during the turn and restored when the spread settles.
  • If the graphics device is lost, ComicViewer recreates it and decodes the visible pages again. Repeated failures are reported through RenderingFailed.
  • All ComicView members must be accessed from the control's UI thread.

Limitations

  • Continuous vertical scrolling is not currently supported; ReadingMode provides page-based layouts only.
  • Only the first frame of an animated image is displayed.
  • If a control is discarded without calling CloseAsync, its decoded pages are released by garbage collection rather than immediately.
  • Widget overlays are rasterized at the page image's resolution, with a maximum of 4096 pixels on either axis. Larger pages therefore produce reduced-resolution widget overlays.
  • A widget can track one active contact at a time and does not receive wheel or keyboard input.
  • Hit testing for text, paths, and rounded corners uses their bounding rectangles rather than their exact shapes.
  • When no widget claims a press, Tapped is derived from the gesture recognizer. Because that recognizer reports the first tap of a double tap as a tap, a widget receives the tap before the page performs the double-tap zoom.
  • If a shader fails to compile on the host system, the control remains in the Loading state instead of reporting the failure through the normal error path.

Building from source

Building from source requires the .NET 10 SDK and the Windows App SDK 2.4 runtime.

All packages, are restored from nuget.org.

dotnet build
dotnet run --project tests/ComicViewer.Core.Tests
dotnet run --project tests/ComicViewer.WinUI.Tests

The WinUI test suite starts a WinUI application on its own thread and therefore requires an interactive desktop session; the continuous integration workflow runs the Core suite only, and the WinUI suite is run locally before a version is tagged.

Pointer tests inject mouse input and are skipped when input injection is unavailable.

Set COMICVIEWER_SNAPSHOTS to a directory to make snapshot tests save curl frames for visual inspection.

Set COMICVIEWER_SAMPLE to a comic archive to run the diagnostics test against it. The test reports decode time, render time, input latency, and the results of injected wheel gestures.

License

Released under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • ComiX (>= 1.0.0-preview.2)

NuGet packages (1)

Showing the top 1 NuGet packages that depend on ComicViewer.Core:

Package Downloads
ComicViewer.WinUI

A WinUI 3 comic reading control over ComiX: gesture-driven page transitions, zoom and pan, single and double page layouts, and bounded page caching, rendered through Direct3D 11 on a composition swap chain, with page turns that curl like paper.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-preview.1 79 9/21/2026