Skip to main content

figif_core/
lib.rs

1//! # figif-core
2//!
3//! A Rust library for GIF frame analysis and manipulation with a plugin architecture.
4//!
5//! figif-core provides tools for:
6//! - **Duplicate Detection**: Identify similar/duplicate frames using perceptual hashing
7//! - **Segment Analysis**: Group consecutive similar frames into logical segments
8//! - **Timing Control**: Modify frame delays to speed up, slow down, or collapse segments
9//! - **Export**: Re-encode GIFs with applied modifications
10//!
11//! ## Quick Start
12//!
13//! ```ignore
14//! use figif_core::prelude::*;
15//!
16//! // Create analyzer with default settings (uses dHash)
17//! let figif = Figif::new();
18//!
19//! // Analyze a GIF file
20//! let analysis = figif.analyze_file("demo.gif")?;
21//!
22//! // Inspect detected segments
23//! for segment in &analysis.segments {
24//!     println!(
25//!         "Segment {}: {} frames, {}ms, static={}",
26//!         segment.id,
27//!         segment.frame_count(),
28//!         segment.duration_ms(),
29//!         segment.is_static
30//!     );
31//! }
32//!
33//! // Cap all pause segments to max 300ms
34//! let ops = analysis.pauses().cap(300);
35//!
36//! // Export with a lossless encoder
37//! let encoder = StandardEncoder::new();
38//! analysis.export_to_file(&encoder, &ops, "output.gif", &EncodeConfig::default())?;
39//! # Ok::<(), Box<dyn std::error::Error>>(())
40//! ```
41//!
42//! ## Fluent Selector API
43//!
44//! The selector API provides chainable, ergonomic control over segment operations:
45//!
46//! ```ignore
47//! use figif_core::prelude::*;
48//!
49//! let analysis = Figif::new().analyze_file("demo.gif")?;
50//!
51//! // Cap all pauses to 300ms
52//! let ops = analysis.pauses().cap(300);
53//!
54//! // Collapse only long pauses (> 500ms) to 200ms
55//! let ops = analysis.pauses().longer_than(500).collapse(200);
56//!
57//! // Remove pauses longer than 1 second
58//! let ops = analysis.pauses().longer_than(1000).remove();
59//!
60//! // Speed up motion segments by 1.5x
61//! let ops = analysis.motion().speed_up(1.5);
62//!
63//! // Combine operations: cap long pauses AND speed up motion
64//! let ops = analysis.pauses().longer_than(500).cap(300)
65//!     .merge(&analysis.motion().speed_up(1.2));
66//!
67//! // Get statistics
68//! println!("Pause count: {}", analysis.pauses().count());
69//! println!("Pause duration: {}ms", analysis.pauses().total_duration_ms());
70//! # Ok::<(), Box<dyn std::error::Error>>(())
71//! ```
72//!
73//! ## Using Different Hashers
74//!
75//! ```ignore
76//! use figif_core::{Figif, hashers::{PHasher, BlockHasher}};
77//!
78//! // Use pHash for more robust matching
79//! let figif = Figif::new()
80//!     .with_hasher(PHasher::new())
81//!     .similarity_threshold(8);
82//!
83//! // Or use BlockHash
84//! let figif = Figif::new()
85//!     .with_hasher(BlockHasher::with_size(16, 16));
86//! ```
87//!
88//! ## Lossy Encoding (requires `lossy` feature)
89//!
90//! ```ignore
91//! #[cfg(feature = "lossy")]
92//! {
93//!     use figif_core::encoders::GifskiEncoder;
94//!     use figif_core::EncodeConfig;
95//!
96//!     let encoder = GifskiEncoder::with_quality(85);
97//!     let config = EncodeConfig::new()
98//!         .with_width(480)
99//!         .with_lossy_quality(80);
100//!
101//!     let bytes = analysis.export(&encoder, &ops, &config)?;
102//! }
103//! ```
104//!
105//! ## Feature Flags
106//!
107//! - `parallel` (default): Enable parallel frame hashing using rayon
108//! - `lossy`: Enable GifskiEncoder for high-quality lossy compression
109//!
110//! ## Plugin Architecture
111//!
112//! figif-core is designed to be extensible. You can implement custom:
113//!
114//! - **Hashers**: Implement [`traits::FrameHasher`] for custom duplicate detection
115//! - **Decoders**: Implement [`traits::GifDecoder`] for custom loading
116//! - **Encoders**: Implement [`traits::GifEncoder`] for custom output formats
117//! - **Similarity Metrics**: Implement [`traits::SimilarityMetric`] for custom comparison
118
119#![warn(missing_docs)]
120#![warn(rustdoc::missing_crate_level_docs)]
121
122pub mod analysis;
123pub mod decoders;
124pub mod encoders;
125pub mod error;
126pub mod hashers;
127pub mod pipeline;
128pub mod segment;
129pub mod selector;
130pub mod traits;
131pub mod types;
132
133// Re-export main types at crate root for convenience
134pub use error::{FigifError, Result};
135pub use pipeline::{Analysis, Figif, ProgressCallback};
136pub use selector::{SegmentOpsExt, SegmentSelector};
137pub use types::{
138    AnalyzedFrame, DecodedFrame, DisposalMethod, EncodableFrame, EncodeConfig, FrameOp, FrameOps,
139    GifMetadata, LoopCount, Segment, SegmentOp, SegmentOps,
140};
141
142/// Prelude module for convenient imports.
143///
144/// ```ignore
145/// use figif_core::prelude::*;
146/// ```
147pub mod prelude {
148    pub use crate::decoders::{BufferedDecoder, StreamingDecoder};
149    pub use crate::encoders::StandardEncoder;
150    pub use crate::error::{FigifError, Result};
151    pub use crate::hashers::{BlockHasher, DHasher, PHasher};
152    pub use crate::pipeline::{Analysis, Figif};
153    pub use crate::selector::{SegmentOpsExt, SegmentSelector};
154    pub use crate::traits::{FrameHasher, GifDecoder, GifEncoder};
155    pub use crate::types::{
156        EncodeConfig, FrameOp, FrameOps, LoopCount, Segment, SegmentOp, SegmentOps,
157    };
158
159    #[cfg(feature = "lossy")]
160    pub use crate::encoders::GifskiEncoder;
161
162    #[cfg(feature = "parallel")]
163    pub use crate::traits::ParallelFrameHasher;
164}