### Run Image Comparison Example Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Compares two images using the `compare_images` example. Provide the paths to the two image files as arguments. ```bash cargo run --example compare_images -- images/photo1.jpg images/photo2.jpg ``` -------------------------------- ### ImageFingerprinter Usage Example Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Demonstrates the basic usage of the ImageFingerprinter to compute a fingerprint for an image. Ensure the image path is valid and the library is correctly set up. ```rust use imgfprint::ImageFingerprinter; let img_path = "path/to/your/image.jpg"; let fingerprint = ImageFingerprinter::fingerprint(img_path)?; println!("Image fingerprint: {:?}", fingerprint); ``` -------------------------------- ### Serialize Example with Tracing and Serde Features Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CHANGELOG.md This example demonstrates serialization, requiring both 'serialize' and 'tracing' features. It is used for testing feature flag interactions. ```rust fn main() { // ... serialization logic ... } ``` -------------------------------- ### Compute and Compare Image Fingerprints (Default) Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md This example demonstrates how to compute fingerprints for two images using the default multi-algorithm approach (AHash + PHash + DHash) and compare their similarity. It reads image data from files. ```rust use imgfprint::ImageFingerprinter; fn main() -> Result<(), Box> { let img1 = std::fs::read("photo1.jpg")?; let img2 = std::fs::read("photo2.jpg")?; // Compute all hashes (AHash + PHash + DHash) for best accuracy let fp1 = ImageFingerprinter::fingerprint(&img1)?; let fp2 = ImageFingerprinter::fingerprint(&img2)?; let sim = fp1.compare(&fp2); println!("Similarity: {:.2}", sim.score); println!("Exact match: {}", sim.exact_match); if sim.score > 0.8 { println!("Images are perceptually similar"); } Ok(()) } ``` -------------------------------- ### Complete Error Handling Example Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md A comprehensive example demonstrating how to handle various ImgFprintError variants using a match statement. This covers image-related, processing, and embedding errors. ```rust use imgfprint::{ImageFingerprinter, ImgFprintError}; match ImageFingerprinter::fingerprint(&bytes) { Ok(fp) => { // Use fingerprint } // Image-related errors Err(ImgFprintError::InvalidImage(msg)) => { eprintln!("Invalid image: {}", msg); } Err(ImgFprintError::UnsupportedFormat(msg)) => { eprintln!("Unsupported format: {}", msg); } Err(ImgFprintError::DecodeError(msg)) => { eprintln!("Decode failed: {}", msg); } Err(ImgFprintError::ImageTooSmall(msg)) => { eprintln!("Image too small: {} (minimum 32x32)", msg); } // Processing errors Err(ImgFprintError::ProcessingError(msg)) => { eprintln!("Processing error: {}", msg); } // Embedding errors Err(ImgFprintError::EmbeddingDimensionMismatch { expected, actual }) => { eprintln!("Dimension mismatch: expected {}, got {}", expected, actual); } Err(ImgFprintError::ProviderError(msg)) => { eprintln!("Provider error: {}", msg); } Err(ImgFprintError::InvalidEmbedding(msg)) => { eprintln!("Invalid embedding: {}", msg); } } ``` -------------------------------- ### Compute Fingerprint with Specific Algorithm Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md This example shows how to compute an image fingerprint using a specific algorithm, such as DHash, for potentially better speed. It reads image data from a file. ```rust use imgfprint::{ImageFingerprinter, HashAlgorithm}; fn main() -> Result<(), Box> { let img = std::fs::read("photo.jpg")?; // Use specific algorithm for better speed let fp = ImageFingerprinter::fingerprint_with(&img, HashAlgorithm::DHash)?; Ok(()) } ``` -------------------------------- ### Run Semantic Search Example Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Performs content-based image search using a local CLIP model. Requires the `local-embedding` feature to be enabled. Specify the ONNX model path, query image, image directory, and similarity threshold. ```bash cargo run --example semantic_search --features local-embedding -- model.onnx query.jpg ./images 0.85 ``` -------------------------------- ### Configuring Preprocessing Limits Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Adjusts input size and dimension caps for image preprocessing, affecting both file-size checks and decode-time guards. This example sets a tight ingest path with a 1 MiB maximum file size and 2048 pixels maximum edge dimension. ```rust use imgfprint::{ImageFingerprinter, PreprocessConfig}; // Tight ingest path: 1 MiB max, 2048 max edge, default 32 min edge. let cfg = PreprocessConfig { max_input_bytes: 1 * 1024 * 1024, max_dimension: 2048, ..PreprocessConfig::default() }; let fp = ImageFingerprinter::fingerprint_path_with_preprocess("untrusted.jpg", &cfg)?; # Ok::<_, Box>(()) ``` -------------------------------- ### Get Image Fingerprint by Algorithm Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Retrieve the fingerprint for a specific hashing algorithm from a multi-hash fingerprint object. Ensure the `imgfprint` crate is imported. ```rust use imgfprint::HashAlgorithm; let fp = multi.get(HashAlgorithm::PHash); ``` -------------------------------- ### Implement Custom CLIP-Style Embedding Provider Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Implement the `EmbeddingProvider` trait to integrate custom embedding models like CLIP. This example shows a basic structure using `reqwest` to call an external API for embeddings. ```rust use imgfprint::{Embedding, EmbeddingProvider, ImgFprintError}; struct MyClipProvider { client: reqwest::Client, api_key: String, } impl EmbeddingProvider for MyClipProvider { fn embed(&self, image: &[u8]) -> Result { let response = self.client .post("https://api.example.com/embed") .header("Authorization", &self.api_key) .body(image.to_vec()) .send() .map_err(|e| ImgFprintError::ProviderError(e.to_string()))?; let vector: Vec = response.json() .map_err(|e| ImgFprintError::ProviderError(e.to_string()))?; Embedding::new(vector) } } // Usage let provider = MyClipProvider { client: reqwest::Client::new(), api_key: "your-api-key".to_string(), }; let img1 = std::fs::read("cat.jpg")?; let img2 = std::fs::read("dog.jpg")?; let emb1 = provider.embed(&img1)?; let emb2 = provider.embed(&img2)?; let similarity = imgfprint::semantic_similarity(&emb1, &emb2)?; println!("Semantic similarity: {:.4}", similarity); ``` -------------------------------- ### BLAKE3 Exact Hash Algorithm Walkthrough Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Details the steps involved in computing the BLAKE3 exact hash for image bytes. ```text INPUT: encoded image bytes HASH: BLAKE3 Step 1 - Reset reusable hasher: exact_hasher.reset() Step 2 - Feed original bytes: exact_hasher.update(image_bytes) Step 3 - Finalize: exact = *exact_hasher.finalize().as_bytes() Step 4 - Store: exact: [u8; 32] ``` -------------------------------- ### Get Image Fingerprint by Algorithm Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Retrieves the image fingerprint for a specified hashing algorithm. This is a fundamental operation for generating fingerprints. ```APIDOC ## get() ### Description Returns the fingerprint for a specific algorithm. ### Method `get(&self, algorithm: HashAlgorithm) -> &ImageFingerprint` ### Parameters #### Path Parameters - `algorithm` (HashAlgorithm) - Required - The hashing algorithm to use for generating the fingerprint. ### Response #### Success Response - Returns a reference to the `ImageFingerprint`. ### Example ```rust use imgfprint::HashAlgorithm; let fp = multi.get(HashAlgorithm::PHash); ``` ``` -------------------------------- ### AHash Algorithm Steps Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Illustrates the steps involved in computing an AHash from a 32x32 grayscale buffer, including downsampling, mean calculation, and bit generation. ```text INPUT: 32x32 grayscale float buffer in [0.0, 1.0] Step 1 - Downsample: bilinear_resample(32x32 -> 8x8) Step 2 - Mean: mean = sum(small[0..64]) / 64 Step 3 - Bits: hash = 0 bit_pos = 63 for y in 0..8: for x in 0..8: if small[y * 8 + x] >= mean: hash |= 1 << bit_pos bit_pos -= 1 Step 4 - Output: u64 perceptual hash ``` -------------------------------- ### Run Benchmarks Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CONTRIBUTING.md Execute the performance benchmarks defined in the crate. ```bash cargo bench ``` -------------------------------- ### Clone Repository and Navigate Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Clones the imgfprint-rs repository from GitHub and changes the current directory to the project root. ```bash git clone https://github.com/themankindproject/imgfprint-rs cd imgfprint-rs ``` -------------------------------- ### Get Global Perceptual Hash Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Retrieve the global perceptual hash, calculated from the center 32x32 region of the image. The algorithm used (PHash or DHash) is determined at the time the fingerprint is created. ```rust let hash: u64 = fp.global_hash(); println!("Perceptual hash: {:016x}", hash); ``` -------------------------------- ### Generate Documentation Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Generates documentation for the imgfprint-rs project without including dependencies and automatically opens it in a web browser. ```bash cargo doc --no-deps --open ``` -------------------------------- ### Get Exact BLAKE3 Hash of Image Bytes Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Retrieve the BLAKE3 hash of the original image bytes using `exact_hash()`. This is useful for exact deduplication before performing perceptual comparisons, as it is significantly faster. ```rust let exact: &[u8; 32] = fp.exact_hash(); // Convert to hex string let hex = hex::encode(exact); println!("Exact hash: {}", hex); ``` -------------------------------- ### Get 16 Block Hashes for Crop-Resistant Comparison Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Retrieve an array of 16 block-level hashes arranged in a 4x4 grid using `block_hashes()`. This is useful for comparing partial regions of images that may have been cropped. ```rust let blocks: &[u64; 16] = fp.block_hashes(); // Access individual blocks for (i, hash) in blocks.iter().enumerate() { println!("Block {}: {:016x}", i, hash); } ``` -------------------------------- ### Run Tests with All Features Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Runs the test suite for the imgfprint-rs project, enabling all available features. ```bash cargo test --all-features ``` -------------------------------- ### Run Tests Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CONTRIBUTING.md Execute all tests within the crate. Use the `--all-features` flag to include tests for all available features. ```bash cargo test ``` ```bash cargo test --all-features ``` -------------------------------- ### MultiHash Configuration and Usage Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Shows how to configure and use multiple hashing algorithms for fingerprinting. This allows for a more robust comparison by combining different hashing strategies. ```rust use imgfprint::{MultiHashConfig, HashAlgorithm, ImageFingerprinter}; let config = MultiHashConfig { algorithms: vec![HashAlgorithm::Ahash, HashAlgorithm::Phash, HashAlgorithm::Dhash], weights: vec![1.0, 1.0, 1.0], }; let img_path = "path/to/another/image.jpeg"; let fingerprint = ImageFingerprinter::fingerprint_with_config(img_path, &config)?; println!("Multi-hash fingerprint: {:?}", fingerprint); ``` -------------------------------- ### Batch Processing for Parallel Workloads Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Demonstrates how to process multiple images in parallel using the `fingerprint_batch` method, which can provide a significant speedup on multi-core systems. ```rust // Process 100 images in parallel using all CPU cores let results = ImageFingerprinter::fingerprint_batch(&images); ``` -------------------------------- ### Initialize Tracing Subscriber and Fingerprint Image Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Initialize a tracing subscriber using an environment filter (RUST_LOG) and then perform fingerprint operations. Ensure RUST_LOG is set before initializing the subscriber to see trace output. ```rust use imgfprint::ImageFingerprinter; // Initialize a tracing subscriber with env filter // RUST_LOG env var controls the log level: info, debug, trace std::env::set_var("RUST_LOG", "info"); tracing_subscriber::fmt::init(); // Now all fingerprint operations emit trace events let fp = ImageFingerprinter::fingerprint(&data).unwrap(); // Outputs: TRACE fingerprinter: fingerprint completed duration_ms=1.23 ``` -------------------------------- ### Running Benchmarks Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Command to execute the library's benchmarks. This helps in evaluating the performance of different operations. ```bash cargo bench ``` -------------------------------- ### Basic Image Comparison (Multi-Algorithm) Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Compares two images using AHash, PHash, and DHash with default weighted combination. This provides a good balance of accuracy and performance for general use. ```rust use imgfprint::ImageFingerprinter; fn main() -> Result<(), Box> { // Load images let img1 = std::fs::read("photo1.jpg")?; let img2 = std::fs::read("photo2.jpg")?; // Generate fingerprints (computes AHash, PHash, and DHash in parallel) let fp1 = ImageFingerprinter::fingerprint(&img1)?; let fp2 = ImageFingerprinter::fingerprint(&img2)?; // Compare using default weighted combination (10% AHash, 60% PHash, 30% DHash). // For per-deployment tuning use `fp1.compare_with_config(&fp2, &cfg)` — // see the Configurability section below. let sim = fp1.compare(&fp2); println!("Similarity: {:.2}", sim.score); println!("Exact match: {}", sim.exact_match); if sim.score > 0.8 { println!("Images are perceptually similar"); } Ok(()) } ``` -------------------------------- ### Run Tests Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Executes the test suite for the imgfprint-rs project. ```bash cargo test ``` -------------------------------- ### Runtime Sequence for MultiHash Fingerprint Path Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Illustrates the sequence of operations when the MultiHash fingerprinting path is taken, detailing interactions between components. ```mermaid sequenceDiagram participant User participant API as ImageFingerprinter participant Ctx as FingerprinterContext participant Dec as decode_image_with_config participant Prep as Preprocessor participant Hash as Hash algorithms participant FP as MultiHashFingerprint User->>API: fingerprint(image_bytes) API->>Ctx: thread-local context Ctx->>Ctx: BLAKE3(image_bytes) Ctx->>Dec: decode + validate + orient Dec-->>Ctx: DynamicImage Ctx->>Prep: normalize_as_slice(image) Prep-->>Ctx: &[u8] 256x256 grayscale Ctx->>Ctx: extract_global_region_from_raw() Ctx->>Ctx: extract_blocks_from_raw() Ctx->>Hash: compute AHash/PHash/DHash Hash-->>Ctx: global_hash + block_hashes per algorithm Ctx->>FP: MultiHashFingerprint::new() FP-->>User: exact + ahash + phash + dhash ``` -------------------------------- ### BLAKE3 Exact Hash Comparison Logic Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Shows how the exact hash comparison is performed using constant-time equality checks. ```text exact_match = ct_eq(a.exact, b.exact) if exact_match: score = 1.0 perceptual_distance = 0 else: continue with perceptual score ``` -------------------------------- ### Configuring imgfprint-rs with Feature Flags Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Shows how to configure the imgfprint-rs library using Cargo.toml to enable or disable specific features like serialization, parallel processing, or local ONNX inference. ```toml [dependencies] # Minimal build (no parallel processing) imgfprint = { version = "0.4.2", default-features = false } # Default (serialization + parallel processing) imgfprint = "0.4.2" # With local ONNX inference imgfprint = { version = "0.4.2", features = ["local-embedding"] } ``` -------------------------------- ### Decoding Image with Custom Configuration Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Shows how to decode an image using a specific configuration, allowing control over preprocessing parameters. This is useful for optimizing performance or handling specific image constraints. ```rust use imgfprint::{PreprocessConfig, ImageFingerprinter}; let img_path = "path/to/your/image.png"; let config = PreprocessConfig { max_input_bytes: 10 * 1024 * 1024, // 10MB min_dimension: 32, max_dimension: 8192, }; let fingerprint = ImageFingerprinter::decode_image_with_config(img_path, &config)?; println!("Decoded fingerprint: {:?}", fingerprint); ``` -------------------------------- ### Minimal Build (No Parallel Processing) Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md To create a minimal build without parallel processing, disable default features. ```toml [dependencies] imgfprint = { version = "0.4.2", default-features = false } ``` -------------------------------- ### PHash NaN and Ordering Handling Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Explains the two distinct computational paths within `compute_hash_from_coeffs` for handling NaN values and ensuring deterministic median selection. ```text if any coefficient is NaN: sort indexed values deterministically else: use select_nth_unstable_by(total_cmp) for O(n) median selection ``` -------------------------------- ### Create a New Fingerprinter Context Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Initializes a new `FingerprinterContext` which reuses internal buffers for efficient, repeated fingerprinting. This is recommended for processing thousands of images. ```rust pub fn new() -> Self ``` ```rust use imgfprint::FingerprinterContext; let mut ctx = FingerprinterContext::new(); ``` -------------------------------- ### Image Fingerprinting Process Trace Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md This trace outlines the steps involved in generating an image fingerprint, from input to output. It details decoding, normalization, feature extraction, and hashing stages. ```text Input: "photo.jpg" bytes Decode: byte cap OK dimensions OK image::load_from_memory -> DynamicImage EXIF orientation 6 -> rotate90 Normalize: resize oriented image to 256x256 RGB convert to grayscale with BT.601 luma Extract: global_region = center 32x32 blocks = 16 regions of 64x64 Hash: exact = BLAKE3(original bytes) ahash.global = AHash(global_region) phash.global = PHash(global_region) dhash.global = DHash(global_region) ahash.blocks[0..16] = AHash(each block) phash.blocks[0..16] = PHash(each block) dhash.blocks[0..16] = DHash(each block) Output: MultiHashFingerprint { exact, ahash: ImageFingerprint { exact, global_hash, block_hashes }, phash: ImageFingerprint { exact, global_hash, block_hashes }, dhash: ImageFingerprint { exact, global_hash, block_hashes }, } ``` -------------------------------- ### PHash Algorithm Steps Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Details the process of calculating a PHash, including row-wise and column-wise DCT-II, median thresholding of coefficients, and bit generation. ```text INPUT: 32x32 grayscale float buffer in [0.0, 1.0] Step 1 - Row-wise DCT: for row in 0..32: dct2_32(row, col_buffer[row]) Step 2 - Column-wise DCT: for col in 0..8: collect col_buffer[0..32, col] dct2_32(column) keep rows 0..8 Step 3 - Low-frequency matrix: hash_matrix = 8x8 coefficients Step 4 - Median threshold: median = nth_element(hash_matrix, 32) Step 5 - Bits: bit i = 1 if coeff[i] >= median else 0 bit order: bit 63 for coeff[0], down to bit 0 Step 6 - Output: u64 perceptual hash ``` -------------------------------- ### DHash for 64x64 Blocks Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Explains how DHash is applied to 64x64 blocks by directly resampling to 9x8 and performing the horizontal gradient comparison. ```text For 64x64 blocks, DHash directly resamples to 9x8 and runs the same gradient comparison. ``` -------------------------------- ### Compare Multi-Hash Fingerprints with Custom Configuration Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md A tunable variant of the `compare()` method that allows integrators to control all six weights and the block distance threshold. Defaults reproduce `compare()` exactly. ```APIDOC ## compare_with_config() ### Description Tunable variant of `compare()`. All six weights and the block distance threshold are integrator-controlled — defaults reproduce `compare()` exactly. ### Method `compare_with_config(&self, other: &MultiHashFingerprint, config: &MultiHashConfig) -> Similarity` ### Parameters #### Path Parameters - `other` (*MultiHashFingerprint) - Required - The other multi-hash fingerprint to compare against. - `config` (*MultiHashConfig) - Required - A configuration object to tune comparison weights and thresholds. ### Example ```rust use imgfprint::MultiHashConfig; // PHash-only scoring let cfg = MultiHashConfig { ahash_weight: 0.0, phash_weight: 1.0, dhash_weight: 0.0, ..MultiHashConfig::default() }; let sim = multi1.compare_with_config(&multi2, &cfg); ``` ``` -------------------------------- ### DHash Pipeline Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Illustrates the steps involved in generating a DHash fingerprint, from image region resampling to bitwise comparison. ```mermaid flowchart TD A["32x32 or 64x64 grayscale region"] --> B["bilinear_resample to 9x8"] B --> C["compare each pixel to right neighbor"] C --> D["8 rows x 8 comparisons"] D --> E["set bit 63..0"] E --> F["u64 DHash"] ``` -------------------------------- ### Slow vs. Fast Image Fingerprinting Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Compares a slow method of creating new allocations for each image fingerprint with a faster method that reuses buffers via the FingerprinterContext. ```rust // Slow: Allocates buffers for each image for path in paths { let fp = ImageFingerprinter::fingerprint(&std::fs::read(path)?)?; } ``` ```rust // Fast: Reuses buffers let mut ctx = FingerprinterContext::new(); for path in paths { let fp = ctx.fingerprint(&std::fs::read(path)?)?; } ``` -------------------------------- ### Exact Hash Check Before Perceptual Comparison Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Illustrates a performance optimization where an exact byte match (BLAKE3 hash) is checked before performing a slower perceptual comparison. ```rust // Fast path: exact byte match (BLAKE3 comparison) if fp1.exact_hash() == fp2.exact_hash() { return Similarity::perfect(); } // Slow path: perceptual comparison (DCT-based) let sim = ImageFingerprinter::compare(&fp1, &fp2); ``` -------------------------------- ### Run Clippy Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CONTRIBUTING.md Analyze the code for common mistakes and style issues using Clippy. The `--all-targets` flag ensures all code is checked. ```bash cargo clippy --all-targets ``` -------------------------------- ### Zero-Copy Persistence with bytemuck::Pod Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CHANGELOG.md Demonstrates using `bytemuck::cast_slice` for zero-copy persistence of `MultiHashFingerprint` slices. This avoids serde overhead for storing large numbers of fingerprints. ```rust use imgfprint::MultiHashFingerprint; let bytes: &[u8] = bytemuck::cast_slice(&fingerprints); // ...write to disk / mmap / send over the wire... let back: &[MultiHashFingerprint] = bytemuck::cast_slice(bytes); ``` -------------------------------- ### Compare Fingerprints with Custom Configuration Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Compare two multi-hash fingerprints using a custom configuration to tune algorithm weights and block distance thresholds. This allows for fine-grained control over the comparison process. ```rust use imgfprint::MultiHashConfig; // PHash-only scoring let cfg = MultiHashConfig { ahash_weight: 0.0, phash_weight: 1.0, dhash_weight: 0.0, ..MultiHashConfig::default() }; let sim = multi1.compare_with_config(&multi2, &cfg); ``` -------------------------------- ### Add imgfprint to Cargo.toml Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Add the imgfprint crate to your project's dependencies in Cargo.toml. ```toml [dependencies] imgfprint = "0.4.2" ``` -------------------------------- ### Comparing Fingerprints for Similarity Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Demonstrates how to check if two image fingerprints are similar based on a given threshold. This uses the Hamming distance for hash comparison. ```rust use imgfprint::Similarity; // Assume fingerprint1 and fingerprint2 are valid ImageFingerprint instances let threshold = 0.8; let is_similar = fingerprint1.is_similar(&fingerprint2, threshold); if is_similar { println!("Fingerprints are similar."); } else { println!("Fingerprints are not similar."); } ``` -------------------------------- ### PHash for 64x64 Blocks Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Outlines the process for computing PHash on 64x64 blocks, involving a 2x2 average downsampling to 32x32 before applying the standard DCT-II path. ```text downsampled[y, x] = (block[2y, 2x] + block[2y, 2x + 1] + block[2y + 1, 2x] + block[2y + 1, 2x + 1]) / 4 ``` -------------------------------- ### Enable Tracing Feature in Cargo.toml Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Add the 'tracing' feature to the imgfprint dependency in your Cargo.toml file to enable performance instrumentation. ```toml [dependencies] imgfprint = { version = "0.4.2", features = ["tracing"] } ``` -------------------------------- ### compare() Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Compares two image fingerprints and returns a similarity score along with exact match and perceptual distance information. Suitable for direct comparison of pre-computed fingerprints. ```APIDOC ## compare() ### Description Compares two fingerprints and returns a similarity score. ### Method `compare(a: &ImageFingerprint, b: &ImageFingerprint) -> Similarity` ### Parameters - `a` (&ImageFingerprint): The first image fingerprint. - `b` (&ImageFingerprint): The second image fingerprint. ### Returns - `Similarity` struct: - `score` (f64): Similarity score from 0.0 (different) to 1.0 (identical). - `exact_match` (bool): True if BLAKE3 hashes match. - `perceptual_distance` (u64): Hamming distance between 0 and 64. ### Example ```rust let sim = ImageFingerprinter::compare(&fp1, &fp2); println!("Score: {:.2}", sim.score); // 0.0 - 1.0 println!("Exact match: {}", sim.exact_match); // true/false println!("Distance: {}", sim.perceptual_distance); // 0-64 ``` ### Similarity Thresholds | Score Range | Interpretation | |-------------|----------------| | 1.0 | Identical images | | 0.8 - 1.0 | Same image, minor edits | | 0.5 - 0.8 | Visually similar | | < 0.5 | Different images | ``` -------------------------------- ### Sorting Similarity Results Source: https://github.com/themankindproject/imgfprint-rs/blob/main/CHANGELOG.md Shows how to sort a collection of similarity results by their score using `partial_cmp`. ```rust results.sort_by(|a, b| a.partial_cmp(b).unwrap()) ``` -------------------------------- ### FingerprinterContext::new() Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Creates a new `FingerprinterContext` instance. This context is designed for high-performance, repeated fingerprinting operations by reusing internal buffers and cached resources, minimizing allocations. ```APIDOC ## FingerprinterContext::new() ### Description Creates a new, reusable context for fingerprinting operations. This context reuses internal buffers and cached resources to optimize performance when processing many images. ### Method `new() -> Self` ### Returns A new `FingerprinterContext` instance. ### Example ```rust use imgfprint::FingerprinterContext; let mut ctx = FingerprinterContext::new(); ``` ``` -------------------------------- ### Customizing Multi-Algorithm Comparison Weights Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Allows tuning the weights of AHash, PHash, and DHash for custom similarity scoring. Set an algorithm's weight to 0.0 to exclude it from the score. ```rust use imgfprint::{ImageFingerprinter, MultiHashConfig}; let bytes_a = std::fs::read("a.jpg")?; let bytes_b = std::fs::read("b.jpg")?; let fp_a = ImageFingerprinter::fingerprint(&bytes_a)?; let fp_b = ImageFingerprinter::fingerprint(&bytes_b)?; // PHash-only scoring — useful when AHash/DHash aren't trusted on this corpus. // Setting an algorithm weight to 0.0 removes it from the score. let cfg = MultiHashConfig { ahash_weight: 0.0, phash_weight: 1.0, dhash_weight: 0.0, ..MultiHashConfig::default() }; let sim = fp_a.compare_with_config(&fp_b, &cfg); # Ok::<_, Box>(()) ``` -------------------------------- ### FingerprinterContext::fingerprint_with() Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Computes a single algorithm's fingerprint for an image using the `FingerprinterContext`. This method allows for targeted fingerprinting with a specific algorithm, optimizing for speed when only one hash type is needed. ```APIDOC ## FingerprinterContext::fingerprint_with() ### Description Computes a single algorithm's fingerprint for an image using the `FingerprinterContext`, allowing for buffer reuse. This is useful when only a specific hash algorithm is required, optimizing for speed. ### Method `fingerprint_with(&mut self, image_bytes: &[u8], algorithm: HashAlgorithm) -> Result` ### Parameters - `image_bytes`: A slice containing the raw bytes of the image. - `algorithm`: The `HashAlgorithm` to use for fingerprinting (e.g., `HashAlgorithm::DHash`). ### Returns A `Result` containing an `ImageFingerprint` for the specified algorithm on success, or an `ImgFprintError` on failure. ### Example ```rust use imgfprint::{FingerprinterContext, HashAlgorithm}; let mut ctx = FingerprinterContext::new(); // Process only DHash for speed for path in image_paths { let bytes = std::fs::read(path)?; let fp = ctx.fingerprint_with(&bytes, HashAlgorithm::DHash)?; // Process fingerprint... } ``` ``` -------------------------------- ### Fingerprint Image Bytes with Context (All Hashes) Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Computes all available image hashes (AHash, PHash, DHash) for a given image byte slice using an existing `FingerprinterContext`. This method reuses internal buffers for performance. ```rust pub fn fingerprint( &mut self, image_bytes: &[u8] ) -> Result ``` ```rust use imgfprint::FingerprinterContext; let mut ctx = FingerprinterContext::new(); // Process thousands of images efficiently for path in image_paths { let bytes = std::fs::read(path)?; let fp = ctx.fingerprint(&bytes)?; // fp is MultiHashFingerprint } ``` -------------------------------- ### DHash Algorithm Steps Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Details the steps for computing a DHash, including downsampling to 9x8 and comparing adjacent pixels to generate gradient bits. ```text INPUT: 32x32 grayscale float buffer in [0.0, 1.0] Step 1 - Downsample: bilinear_resample(32x32 -> 9x8) Step 2 - Gradient bits: hash = 0 bit_pos = 63 for y in 0..8: for x in 0..8: left = small[y * 9 + x] right = small[y * 9 + x + 1] if left > right: hash |= 1 << bit_pos bit_pos -= 1 Step 3 - Output: u64 perceptual hash ``` -------------------------------- ### Build with Local Embeddings Source: https://github.com/themankindproject/imgfprint-rs/blob/main/README.md Enable the 'local-embedding' feature to use local ONNX models for semantic embeddings. This requires an ONNX model to be available. ```toml [dependencies] imgfprint = { version = "0.4.2", features = ["local-embedding"] } ``` -------------------------------- ### Creating ImgFprint Errors Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Use optimized error constructors for custom providers or library extensions. These constructors help in creating specific error types with descriptive messages. ```rust use imgfprint::ImgFprintError; let err = ImgFprintError::decode_error("invalid format"); let err = ImgFprintError::invalid_image("dimensions too large"); let err = ImgFprintError::processing_error("resize failed"); let size = 1024; let err = ImgFprintError::invalid_image(format!("image too large: {} bytes", size)); ``` -------------------------------- ### PHash DCT-II Formula Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Presents the mathematical formula for computing the DCT-II used in PHash, utilizing a real FFT plan. ```text DCT-II(x) = 2 * Re(exp(-j * pi * k / (2N)) * FFT(y)) ``` -------------------------------- ### Format ImageFingerprint and MultiHashFingerprint as Strings Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Both `ImageFingerprint` and `MultiHashFingerprint` implement the `Display` trait for easy logging and serialization to strings. The format differs slightly between the two types. ```rust let fp = ImageFingerprinter::fingerprint_with(&img, HashAlgorithm::PHash)?; // Format: exact_hex:global_hex:block0,block1,...,block15 println!("{}", fp); let multi = ImageFingerprinter::fingerprint(&img)?; // Format: exact_hex|ahash_global|phash_global|dhash_global println!("{}", multi); ``` -------------------------------- ### fingerprint_batch() Source: https://github.com/themankindproject/imgfprint-rs/blob/main/USAGE.md Processes multiple images in parallel to generate their fingerprints. This method is optimized for performance by utilizing per-thread context caching and can provide a significant speedup when the 'parallel' feature is enabled. ```APIDOC ## fingerprint_batch() ### Description Processes multiple images in parallel using per-thread context caching for efficient fingerprint generation. Requires the `parallel` feature to be enabled. ### Method `fingerprint_batch(images: &[(S, Vec)]) -> Vec<(S, Result)>` ### Type Parameters - `S`: Type of the image identifier, must be `Send + Sync + Clone + 'static`. ### Parameters - `images`: A slice of tuples, where each tuple contains an image identifier (`S`) and its byte data (`Vec`). ### Returns A vector of tuples, where each tuple contains the image identifier (`S`) and a `Result`. The `Result` is either an `Ok(MultiHashFingerprint)` on success or an `Err(ImgFprintError)` on failure. ### Example ```rust let images = vec![ ("img1.jpg".to_string(), std::fs::read("img1.jpg")?), ("img2.jpg".to_string(), std::fs::read("img2.jpg")?), ("img3.jpg".to_string(), std::fs::read("img3.jpg")?), ]; let results = ImageFingerprinter::fingerprint_batch(&images); for (id, result) in results { match result { Ok(fp) => println!("{}: fingerprinted successfully", id), Err(e) => println!("{}: error - {}", id, e), } } ``` ### Performance Note With the `parallel` feature enabled (default), batch processing uses all available CPU cores for 2-3x speedup. ``` -------------------------------- ### imgfprint-rs Module Organization Source: https://github.com/themankindproject/imgfprint-rs/blob/main/image.md Provides a hierarchical view of the source code structure for the imgfprint-rs library. ```text src/ ├── lib.rs # Re-exports, FORMAT_VERSION ├── error.rs # ImgFprintError ├── core/ │ ├── mod.rs │ ├── fingerprint.rs # ImageFingerprint, MultiHashFingerprint, config │ ├── fingerprinter.rs # public API, context, batch, pipeline glue │ └── similarity.rs # hamming, block similarity, score assembly ├── hash/ │ ├── mod.rs │ ├── algorithms.rs # HashAlgorithm enum │ ├── ahash.rs # average hash │ ├── phash.rs # DCT perceptual hash │ └── dhash.rs # horizontal gradient hash ├── imgproc/ │ ├── mod.rs │ ├── decode.rs # image decode, EXIF orientation, guards │ └── preprocess.rs # resize, grayscale, extraction, resampling └── embed/ ├── mod.rs # Embedding, EmbeddingProvider, cosine similarity └── local.rs # optional ONNX local provider docs/ └── WATERMARK_ARCHITECTURE.md # planned forensic watermarking design ```