Photostax 0.2.2

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

Photostax .NET Binding

A .NET wrapper for the photostax library — access Epson FastFoto photo repositories from C#.

NuGet License

Overview

This package provides idiomatic C# access to Epson FastFoto photo repositories. It groups scanner output files (original, enhanced, back scans) into PhotoStack objects and provides metadata reading and writing.

Architecture

PhotostaxRepository is a managed wrapper around the Rust StackManager — the unified cache and query engine that powers photostax. Each PhotostaxRepository instance creates a StackManager internally with a single repository, giving you:

  • O(1) stack lookups by opaque ID
  • Unified Query() API for search + pagination in one call
  • Lazy metadata loading — scan first, load EXIF/XMP on demand
  • Filesystem watching and reactive cache updates (Rust-only for now)

Multi-repo support: The Rust core supports managing multiple repositories through a single StackManager (via add_repo()). This capability is now also available in the .NET binding via the StackManager class.

Multi-repo with StackManager

using var mgr = new StackManager();
mgr.AddRepo("/photos/2024", recursive: true);
mgr.AddRepo("/photos/2023", recursive: true);

mgr.Scan();
Console.WriteLine($"Managing {mgr.RepoCount} repos");

// Query across all repos
var page = mgr.Query(new SearchQuery().WithText("birthday"), offset: 0, limit: 20);
foreach (var stack in page.Items)
    Console.WriteLine($"{stack.Name} ({stack.Id})");

Installation

dotnet add package Photostax

Quick Start

using Photostax;

// Open a repository
using var repo = new PhotostaxRepository("/path/to/photos");

// Query all stacks (no filter, no pagination)
var all = repo.Query();

foreach (var stack in all.Items)
{
    // stack.Id is a 16-char hex hash (e.g. "a1b2c3d4e5f67890")
    // stack.Name is the human-readable display name
    Console.WriteLine($"{stack.Name} ({stack.Id})");
    Console.WriteLine($"  Folder: {stack.Folder ?? "(root)"}");
    Console.WriteLine($"  Original: {stack.OriginalPath}");
    Console.WriteLine($"  Enhanced: {stack.EnhancedPath}");
    Console.WriteLine($"  Back: {stack.BackPath}");
    Console.WriteLine($"  Format: {stack.Format}");
}

// Search with filter and pagination using Query()
var page = repo.Query(
    new SearchQuery().WithText("birthday").WithHasBack(true),
    offset: 0,
    limit: 20
);

Console.WriteLine($"Page has {page.Items.Count} of {page.TotalCount} total");
Console.WriteLine($"Has more: {page.HasMore}");

// Iterate pages
foreach (var stack in page.Items)
    Console.WriteLine($"{stack.Name} ({stack.Id})");

if (page.HasMore)
{
    var nextPage = repo.Query(
        new SearchQuery().WithText("birthday"),
        offset: 20, limit: 20);
}

// Read image bytes
var imageData = repo.ReadImage(all.Items[0].OriginalPath!);

// Write metadata (use stack.Id for lookups)
var metadata = new Metadata().WithCustomTag("album", "Family Photos");
repo.WriteMetadata(all.Items[0].Id, metadata);

Note — Stack IDs changed in v0.2.x: Stack IDs are now opaque 16-character hex strings (truncated SHA-256 hashes) rather than human-readable stems. Use stack.Name when displaying a stack to users and stack.Id for programmatic lookups such as GetStack() or WriteMetadata().

API Overview

PhotostaxRepository

The main entry point for working with photo repositories.

Method Description
Query() (v0.2.x) Search and paginate in one call. Accepts an optional SearchQuery, offset, and limit. Returns a PagedResult<PhotoStack>.
Scan() Discover all photo stacks in the repository
GetStack(id) Get a specific stack by its opaque hash ID
ReadImage(path) Read raw image bytes
WriteMetadata(id, metadata) Write metadata to a stack
Search(query) Find stacks matching a query (convenience wrapper around Query())
ScanPaginated(offset, limit) Scan with pagination (convenience wrapper around Query())
SearchPaginated(query, offset, limit) Search with pagination (convenience wrapper around Query())
Query() — Preferred Search & Pagination API

Query() is the recommended way to search and paginate as of v0.2.x. The older Search(), ScanPaginated(), and SearchPaginated() methods still work but are now convenience wrappers around Query().

// All stacks (no filter, no pagination)
var all = repo.Query();

// With filter and pagination
var page = repo.Query(
    new SearchQuery().WithText("birthday").WithHasBack(true),
    offset: 0,
    limit: 20
);

// Iterate pages
foreach (var stack in page.Items)
    Console.WriteLine($"{stack.Name} ({stack.Id})");

if (page.HasMore)
{
    var nextPage = repo.Query(
        new SearchQuery().WithText("birthday"),
        offset: 20, limit: 20);
}

PhotoStack

Represents a photo stack with its associated images and metadata.

Property Type Description
Id string Opaque 16-char hex hash (SHA-256). Use for lookups.
Name string (v0.2.x) Human-readable display name for the stack.
Folder string? (v0.2.x) Subfolder within the repository, or null if at root.
OriginalPath string? Path to original scan
EnhancedPath string? Path to enhanced scan
BackPath string? Path to back scan
Metadata Metadata EXIF, XMP, and custom tags
Format ImageFormat? JPEG, TIFF, or Unknown

SearchQuery

Builder for constructing search queries.

var query = new SearchQuery()
    .WithText("vacation")           // Free-text search
    .WithExifFilter("Make", "EPSON") // EXIF tag filter
    .WithCustomFilter("album", "2020") // Custom tag filter
    .WithHasBack(true)              // Has back scan
    .WithHasEnhanced(true);         // Has enhanced scan

Building from Source

Prerequisites

Build Steps

# 1. Build native library
cd <repo_root>
cargo build --release -p photostax-ffi

# 2. Build .NET library
cd bindings/dotnet
dotnet build

# 3. Run tests
dotnet test

Native Library Location

The native library must be in your application's runtime directory:

Platform File
Windows photostax_ffi.dll
macOS libphotostax_ffi.dylib
Linux libphotostax_ffi.so

Running Tests

cd bindings/dotnet
dotnet test

# Skip integration tests (no native library required)
dotnet test --filter "Category!=Integration"

License

Licensed under either of Apache License, Version 2.0 or MIT License at your option.


← Back to main README | FFI Documentation

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

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
0.6.1 100 3/23/2026
0.5.0 88 3/22/2026
0.4.3 94 3/21/2026
0.4.2 87 3/21/2026
0.4.1 84 3/21/2026
0.4.0 94 3/20/2026
0.3.0 88 3/20/2026
0.2.2 87 3/20/2026
0.2.1 86 3/19/2026
0.2.0 90 3/19/2026
0.1.13 90 3/17/2026
0.1.12 88 3/17/2026
0.1.11 114 3/17/2026
0.1.10 148 3/16/2026
0.1.9 136 3/16/2026
0.1.8 136 3/16/2026
0.1.7 147 3/14/2026
0.1.6 212 3/14/2026
0.1.5 160 3/8/2026
0.1.4 102 3/8/2026
Loading failed