jfifdump 0.6.0

Read and dump structure of a jpeg file
Documentation
use crate::{App0Jfif, Dac, Dht, Dqt, Frame, Handler, Rst, Scan};

pub struct TextFormat {
    verbose: bool,
}

impl TextFormat {
    pub fn new(verbose: bool) -> TextFormat {
        TextFormat { verbose }
    }
}

fn print_ascii_value(v: u8) {
    if v.is_ascii_graphic() || v == 0x20 {
        print!("{}", v as char);
    } else {
        print!("\\x{:#04X}", v);
    }
}

impl Handler for TextFormat {
    fn handle_app(&mut self, position: usize, length: usize, nr: u8, data: &[u8]) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        print!("App(0x{:X}):", nr);

        for &v in data.iter().take(20) {
            print_ascii_value(v);
        }

        println!();
    }

    fn handle_app0_jfif(&mut self, position: usize, length: usize, jfif: &App0Jfif) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("App(0x0): JFIF");

        println!("  Version: {}.{:02}", jfif.major, jfif.minor);

        let unit = match jfif.unit {
            0 => "pixel".to_owned(),
            1 => "dots per inch".to_owned(),
            2 => "dots per cm".to_owned(),
            _ => format!("Unknown unit: {}", jfif.unit),
        };

        println!("  Density: {}x{} {}", jfif.x_density, jfif.y_density, unit);
        println!("  Thumbnail: {}x{}", jfif.x_thumbnail, jfif.y_thumbnail);
    }

    fn handle_dqt(&mut self, position: usize, length: usize, tables: &[Dqt]) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("DQT:");

        for table in tables {
            print!("  {}: Precision {}", table.dest, table.precision);
            if self.verbose {
                for (i, &v) in table.values.iter().enumerate() {
                    if i % 8 == 0 {
                        print!("\n    ");
                    }
                    if v < 10 {
                        print!(" ");
                    }
                    if v < 100 {
                        print!(" ");
                    }
                    print!("{}, ", v)
                }
            }
            println!();
        }
    }

    fn handle_dht(&mut self, position: usize, length: usize, tables: &[Dht]) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("DHT:");

        for table in tables {
            println!("  Table {}: Class {}", table.dest, table.class);
            if self.verbose {
                print!("    Code lengths: ");
                for (i, &v) in table.code_lengths.iter().enumerate() {
                    if i > 0 {
                        print!(", ");
                    }
                    print!("{}", v)
                }
                println!();
            }
        }
    }

    fn handle_dac(&mut self, position: usize, length: usize, dac: &Dac) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("DAC:");

        for param in &dac.params {
            println!(
                "  Class: {}   Dest: {}    Value: {}",
                param.class, param.dest, param.value
            );
        }
    }

    fn handle_frame(&mut self, position: usize, length: usize, frame: &Frame) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("Frame: {}", frame.get_sof_name());
        println!("  Precision: {}", frame.precision);
        println!("  Dimension: {}x{}", frame.dimension_x, frame.dimension_y);

        for component in &frame.components {
            println!(
                "  Component({}): Sampling {}x{} Quantization: {}",
                component.id,
                component.horizontal_sampling_factor,
                component.vertical_sampling_factor,
                component.quantization_table
            );
        }
    }

    fn handle_scan(&mut self, position: usize, length: usize, scan: &Scan) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("Scan: ");

        for component in &scan.components {
            println!(
                "  Component: {} DC:{} AC:{}",
                component.id, component.dc_table, component.dc_table
            );
        }

        println!(
            "  Selection: {} to {}",
            scan.selection_start, scan.selection_end
        );
        println!(
            "  Approximation: {} to {}",
            scan.approximation_low, scan.approximation_high
        );
        println!("  Data: {} bytes", scan.data.len());
    }

    fn handle_dri(&mut self, position: usize, length: usize, restart: u16) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("DRI: {}", restart);
    }

    fn handle_rst(&mut self, position: usize, length: usize, restart: &Rst) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("RST({}): Data: {} bytes", restart.nr, restart.data.len());
    }

    fn handle_comment(&mut self, position: usize, length: usize, data: &[u8]) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        if let Ok(comment) = std::str::from_utf8(data) {
            println!("Comment: {}", comment);
        } else {
            println!("Comment: BAD STRING WITH LENGTH {}", data.len());
        }
    }

    fn handle_unknown(&mut self, position: usize, length: usize, marker: u8, data: &[u8]) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("Unknown(0x{:X}): Length {}", marker, data.len());
    }

    fn handle_eoi(&mut self, position: usize, length: usize) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("EOI");
    }

    fn handle_soi(&mut self, position: usize, length: usize) {
        if self.verbose {
            print!("0x{:X}/0x{:X}: ", position, length);
        }
        println!("SOI");
    }
}