tx2-iff 0.1.0

PPF-IFF (Involuted Fractal Format) - Image codec using Physics-Prime Factorization, 360-prime quantization, and symplectic warping
Documentation
//! CLI tool to decode PPF-IFF format to PNG
//!
//! Usage: cargo run --example decode --features decoder -- input.iff output.png

use std::env;
use std::fs::File;
use std::io::Read;
use tx2_iff::{Decoder, DecoderConfig, IffImage};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::init();

    let args: Vec<String> = env::args().collect();

    if args.len() < 3 {
        eprintln!("Usage: {} <input.iff> <output.png> [options]", args[0]);
        eprintln!();
        eprintln!("Options:");
        eprintln!("  --info    Show IFF file information only (don't decode)");
        std::process::exit(1);
    }

    let input_path = &args[1];
    let output_path = &args[2];
    let info_only = args.contains(&"--info".to_string());

    println!("Reading IFF file: {}", input_path);
    let mut file = File::open(input_path)?;
    let mut iff_bytes = Vec::new();
    file.read_to_end(&mut iff_bytes)?;

    println!("Parsing IFF structure...");
    let iff_image = IffImage::from_bytes(&iff_bytes)?;

    // Print file information
    println!();
    println!("IFF File Information:");
    println!("  Version:       {}.{}", iff_image.header.version.major, iff_image.header.version.minor);
    println!("  Dimensions:    {}x{}", iff_image.header.width, iff_image.header.height);
    println!("  Wavelet levels: {}", iff_image.header.wavelet_levels);
    println!("  Flags:");
    println!("    Alpha:         {}", iff_image.header.flags.has_alpha);
    println!("    Lossless:      {}", iff_image.header.flags.lossless);
    println!("    GPU optimized: {}", iff_image.header.flags.gpu_optimized);
    println!();
    println!("Layer sizes:");
    println!("  Layer 1 (wavelet):  {} bytes", iff_image.header.layer1_size);
    println!("  Layer 2 (texture):  {} bytes", iff_image.header.layer2_size);
    println!("  Layer 3 (warp):     {} bytes", iff_image.header.layer3_size);
    println!("  Residual:           {} bytes", iff_image.header.residual_size);
    println!();
    println!("Layer statistics:");
    let layer1_size = iff_image.layer1.y.data.len() + iff_image.layer1.co.data.len() + iff_image.layer1.cg.data.len();
    println!("  Wavelet data:         {} bytes (compressed)", layer1_size);
    println!("  Texture regions:      {}", iff_image.layer2.regions.len());
    println!("  Warp vortices:        {}", iff_image.layer3.vortices.len());
    println!("  Residual data:        {} bytes (compressed)", iff_image.residual.data.len());

    if info_only {
        println!();
        println!("Info-only mode. Exiting without decoding.");
        return Ok(());
    }

    println!();
    println!("Decoding...");
    let config = DecoderConfig::default();
    let decoder = Decoder::new(config);
    let decoded_image = decoder.decode_to_image(&iff_image)?;

    println!("Saving to: {}", output_path);
    decoded_image.save(output_path)?;

    // Calculate file sizes
    let iff_size = iff_bytes.len();
    let png_metadata = std::fs::metadata(output_path)?;
    let png_size = png_metadata.len() as usize;
    let raw_size = (iff_image.header.width * iff_image.header.height * 3) as usize;

    println!();
    println!("Decoding complete!");
    println!("  IFF size:        {} bytes ({:.2} KB)", iff_size, iff_size as f64 / 1024.0);
    println!("  PNG size:        {} bytes ({:.2} KB)", png_size, png_size as f64 / 1024.0);
    println!("  Raw RGB size:    {} bytes ({:.2} KB)", raw_size, raw_size as f64 / 1024.0);
    println!("  IFF vs Raw:      {:.2}x compression", raw_size as f64 / iff_size as f64);

    Ok(())
}