photostax-core 0.4.2

Unified photo stack library for Epson FastFoto repositories — scanning, metadata, and search
Documentation

photostax-core

Unified photo stack library for Epson FastFoto repositories — scanning, metadata, and search.

Crates.io Documentation License

Overview

Epson FastFoto scanners produce multiple files per scanned photo:

File Pattern Description
<name>.jpg or <name>.tif Original front scan
<name>_a.jpg or <name>_a.tif Enhanced version (color-corrected)
<name>_b.jpg or <name>_b.tif Back of the photo

This library groups them into a single PhotoStack abstraction, enabling applications to operate on complete photos rather than individual files.

Installation

cargo add photostax-core

Features

  • PhotoStack-centric API — all I/O through stack.original.read(), stack.metadata.write(), etc.
  • Multi-format support — JPEG (.jpg, .jpeg) and TIFF (.tif, .tiff)
  • ImageRef / MetadataRef — lazy, cached accessors for image data and metadata
  • Repository trait — pluggable storage backends (local filesystem included)
  • SessionManager — multi-repo cache with unified query and pagination
  • Search & filter — query stacks by metadata with a fluent builder API
  • ScanSnapshot — point-in-time snapshots with O(1) staleness detection

Quick Start

use photostax_core::backends::local::LocalRepository;
use photostax_core::stack_manager::StackManager;
use photostax_core::photo_stack::ScannerProfile;
use photostax_core::search::SearchQuery;

// Create a manager with a local repository
let repo = LocalRepository::new("/path/to/photos");
let mut mgr = StackManager::single(Box::new(repo), ScannerProfile::Auto).unwrap();
mgr.scan().unwrap();

// Query all stacks → returns a ScanSnapshot
let snap = mgr.query(&SearchQuery::new());

for stack in snap.stacks() {
    println!("Photo: {} ({})", stack.name, stack.id);

    // Read original image via ImageRef
    if stack.original.is_present() {
        let mut reader = stack.original.read().unwrap();
        // ... process image bytes ...
    }

    // Read metadata via MetadataRef (lazy-loaded)
    let meta = stack.metadata.read().unwrap();
    if let Some(make) = meta.exif_tags.get("Make") {
        println!("  Camera: {make}");
    }
}

API Overview

Core Types

Type Description
PhotoStack Grouped photo with original, enhanced, back (ImageRef) and metadata (MetadataRef)
ImageRef Lazy, cached accessor for a single image variant — read(), hash(), dimensions(), rotate()
MetadataRef Lazy accessor for stack metadata — read(), write()
Metadata EXIF, XMP, and custom tags for a photo stack
Repository Trait for storage backend abstraction
LocalRepository Local filesystem implementation
StackManager Multi-repo cache manager (aliased as SessionManager)
SearchQuery Builder for filtering stacks by metadata
ScanSnapshot Point-in-time snapshot for consistent pagination
PaginatedResult<T> A page of results with total count and navigation metadata

Key Operations

// Scanning
let mut mgr = StackManager::single(Box::new(repo), ScannerProfile::Auto)?;
mgr.scan()?;

// Per-stack image I/O via ImageRef
let stack = snap.stacks().first().unwrap();
let mut reader = stack.original.read()?;      // Read image bytes
let hash = stack.enhanced.hash()?;            // SHA-256 (cached)
let (w, h) = stack.back.dimensions()?;        // Image dimensions (cached)
stack.back.rotate(Rotation::Cw90)?;           // Rotate in place

// Per-stack metadata via MetadataRef
let meta = stack.metadata.read()?;            // Lazy load EXIF/XMP/custom
stack.metadata.write(&updated_meta)?;         // Write back

// Search + pagination via ScanSnapshot
let query = SearchQuery::new()
    .with_text("vacation")
    .with_has_back(true);
let snap = mgr.query(&query);
let page = snap.get_page(0, 20);
println!("{} of {} stacks", page.items.len(), page.total_count);

// Next page from the same snapshot
if page.has_more {
    let page2 = snap.get_page(20, 20);
}

Building from Source

git clone https://github.com/JeromySt/photostax
cd photostax
cargo build --release --package photostax-core
cargo test --package photostax-core

License

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


← Back to main README | API Documentation