Ani.Reader 1.2.6

There is a newer version of this package available.
See the version list below for details.
dotnet add package Ani.Reader --version 1.2.6
                    
NuGet\Install-Package Ani.Reader -Version 1.2.6
                    
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="Ani.Reader" Version="1.2.6" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ani.Reader" Version="1.2.6" />
                    
Directory.Packages.props
<PackageReference Include="Ani.Reader" />
                    
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 Ani.Reader --version 1.2.6
                    
#r "nuget: Ani.Reader, 1.2.6"
                    
#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 Ani.Reader@1.2.6
                    
#: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=Ani.Reader&version=1.2.6
                    
Install as a Cake Addin
#tool nuget:?package=Ani.Reader&version=1.2.6
                    
Install as a Cake Tool

Ani.Reader icon Ani.Reader

NuGet Version NuGet Downloads

Ani.Reader is a cross-platform library designed for extracting animated cursors from .ani files, as well as from embedded resources within .exe and .dll files.

Installation

dotnet add package Ani.Reader

Requirements: .NET Standard 2.0 or later (compatible with .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+).

Key Features

  • Platform-Independent Design: Extracts animated cursors from ANI, EXE, and DLL files without relying on Windows-specific functions, making it fully cross-platform.
  • Supports ANI Files and PE Resources: Reads animated cursors from standalone .ani files as well as embedded resources within executables and DLLs.
  • Efficient Memory Usage: Implements lazy frame loading — individual frame image data is not decoded until it is needed.
  • Multiple Animation Variants: A single ANI source can contain variants at different sizes and bit depths, each accessible as a separate AnimationInformation.
  • Flexible Data Access: Supports reading from file paths, byte arrays, and streams.
  • WebP Export: Animated cursors can be exported as animated WebP images via the built-in WebPCreator extension.

Getting Started

Reading aniData

var aniReader = new AniReader();

// Reading from a file path (most memory-efficient)
AniData[]? aniFromPath = aniReader.Read("path/to/cursor.ani");
AniData[]? aniFromDll  = aniReader.Read("path/to/user32.dll");
AniData[]? aniFromExe  = aniReader.Read("path/to/app.exe");

// Reading from a byte array
byte[] aniBytes = File.ReadAllBytes("path/to/cursor.ani");
AniData[]? aniFromBytes = aniReader.Read(aniBytes);

// Reading from a stream (copies the stream for independent access)
using var stream = File.OpenRead("path/to/cursor.ani");
AniData[]? aniFromStream = aniReader.Read(stream: stream, copyStream: true);

// Reading from a stream without copying (as efficient as direct file reading)
using (var streamOrigin = File.OpenRead("path/to/cursor.ani"))
{
    AniData[]? aniFromStreamDirect = aniReader.Read(stream: streamOrigin, copyStream: false);
    // ✅ This is as memory-efficient as reading directly from a file.
    // 🔴 WARNING: All frames must be accessed before closing the stream,
    // otherwise an error will occur.
}
  • copyStream: true → The stream is copied, allowing access to frames even after the original stream is closed.
  • copyStream: false → The stream is used directly, making it as memory-efficient as reading from a file, but the stream must remain open while accessing frames.

Note: All Read() overloads return null if the file does not exist, the format is unrecognised, or the data cannot be parsed.

Working with AniData

Read() returns an AniData[] because a single PE file can embed multiple animated cursors. Each AniData represents one animation and exposes its frames and animation variants.

AniData Properties
Property Type Description
Name string Derived from the file name or PE resource ID
Origin AniOriginFileType Executable, Dll, or Ani
TotalAnimationDuration TimeSpan Sum of all frame durations
TotalFrames int Total number of frames in the sequence
FrameRate float Frames per second (60 / DisplayRate)
Frames ReadOnlyCollection<FrameInformation> Ordered sequence of frame steps including timing
Animations ReadOnlyCollection<AnimationInformation> Available size and bit-depth variants
FrameInformation Properties
Property Type Description
Position int Index of this step in the animation sequence
Start TimeSpan Time offset when this frame begins
Duration TimeSpan How long this frame is displayed
FrameReference AniFrameReference Raw byte offset and size within the source stream
AnimationInformation Properties
Property Type Description
Width int Frame width in pixels
Height int Frame height in pixels
BitCount int Bit depth (e.g. 1, 4, 8, 24, 32)
FrameHotspots List<FrameHotspot> Cursor hotspot position per frame step

Retrieving Frame Data

Each AnimationInformation describes one size/depth variant. Use it to retrieve the decoded PNG bytes of a specific frame:

foreach (var aniData in aniDatas)
{
    var animation = aniData.Animations[0];

    // Get the decoded PNG bytes for a single frame
    byte[]? frameBytes = await aniData.GetFrameBytes(animation, aniData.Frames[0]);
}

Selecting the Preferred Animation Variant

AniData.PreferredAnimationIndex() returns the index of the AnimationInformation with the highest quality score, calculated as BitCount × Width × Height.

int preferredIndex = aniData.PreferredAnimationIndex();
var animation = aniData.Animations[preferredIndex];

Saving / Exporting

Saving Frames as PNG
// Save all frames of an animation variant as individual PNG files
await aniData.SaveImages("output/", animation);
Exporting as Animated WebP
// Save as an animated WebP file
await aniData.SaveAsWebP("output/cursor.webp", animation);

// Get the animated WebP as a byte array
byte[]? webpBytes = await aniData.GetWebpBytes(animation);

Configuration

By default, AniReader uses built-in decoders. You can supply a custom AniReaderConfiguration to override any part of the decoding pipeline:

var config = new AniReaderConfiguration
{
    AniDecoder   = new MyCustomAniDecoder(),
    AniPeDecoder = new MyCustomAniPeDecoder(),
    IcoReader    = new IcoReader()
};

var aniReader = new AniReader(config);

AniReaderConfiguration properties:

Property Type Description
AniDecoder IAniDecoder Decoder for parsing ANI RIFF data
AniPeDecoder IAniPeDecoder Decoder for extracting ANI resources from .exe / .dll files
IcoReader IcoReader ICO reader used to decode individual animation frames

Dependency Injection Support

For applications utilizing Dependency Injection, Ani.Reader provides an extension method to seamlessly register its services with the DI container.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAniReader();
}

Dependencies

Ani.Reader is designed with minimal external dependencies to ensure lightweight integration into your projects.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.7 52 5/23/2026
1.2.6 53 5/20/2026