openslide 0.2.0

Rust bindings to the OpenSlide C library
Documentation
//! Developement tests
//!

extern crate openslide;
extern crate failure;
extern crate image;
#[macro_use] extern crate clap;

use std::path::Path;
use std::path;
use std::fs;

use image::{RgbaImage};
use failure::{Error, err_msg};
use clap::{Arg, App, ArgMatches};
use openslide::OpenSlide;


fn get_cli<'a>() -> ArgMatches<'a> {
    let matches = App::new("Analyse wsi")
                          .version("0.2.0")
                          .author("Ole-Johan Skrede")
                          .about("Toy program used for development of openslide.")
                          .arg(Arg::with_name("input_file")
                               .short("i")
                               .long("input_file")
                               .value_name("FILE")
                               .help("Filename of input wsi image")
                               .required(true)
                               )
                          .arg(Arg::with_name("out_root_dir")
                               .short("o")
                               .long("out_root_dir")
                               .value_name("FOLDER")
                               .default_value("/tmp/analyse_wsi")
                               .help("Root directory of output images")
                               )
                          .arg(Arg::with_name("source_row")
                               .short("r")
                               .long("source_row")
                               .value_name("UINT32")
                               .default_value("0")
                               .help("Crop start row in target pixels")
                               )
                          .arg(Arg::with_name("source_column")
                               .short("c")
                               .long("source_column")
                               .value_name("UINT32")
                               .default_value("0")
                               .help("Crop end row in target pixels")
                               )
                          .arg(Arg::with_name("target_height")
                               .short("h")
                               .long("target_height")
                               .allow_hyphen_values(true)
                               .value_name("INT32")
                               .default_value("512")
                               .help("Size of crop in target pixels. -1 indicates full height")
                               )
                          .arg(Arg::with_name("target_width")
                               .short("w")
                               .long("target_width")
                               .allow_hyphen_values(true)
                               .value_name("INT32")
                               .default_value("512")
                               .help("Size of crop in target pixels. -1 indicates full width")
                               )
                          .arg(Arg::with_name("zoom_factor")
                               .short("z")
                               .long("zoom_factor")
                               .value_name("FLOAT32")
                               .default_value("1.0")
                               .help("Zoom factor")
                               )
                          .arg(Arg::with_name("print_properties")
                               .short("p")
                               .long("print_properties")
                               .takes_value(false)
                               .help("Whether or not to print the slide properties")
                               )
                          .get_matches();

    matches
}


fn write_region(
    os: &OpenSlide,
    out_dir: &path::Path,
    source_row: u32,
    source_col: u32,
    target_height: i32,
    target_width: i32,
    zoom_factor: f32,
) -> Result<(), Error> {

    let zoom_lvl = os.get_best_level_for_downsample(zoom_factor as f64)?;
    println!("Best zoom level for zoom factor {} is: {}", zoom_factor, zoom_lvl);

    let target_height = if target_height == -1 {
        let (_, full_height) = os.get_level_dimensions(zoom_lvl)?;
        full_height as u32
    } else {
        target_height as u32
    };

    let target_width = if target_width == -1 {
        let (full_width, _) = os.get_level_dimensions(zoom_lvl)?;
        full_width as u32
    } else {
        target_width as u32
    };

    println!("Read region with height: {}", target_height);
    println!("Read region with width: {}", target_width);
    let im = os.read_region(source_row, source_col, zoom_lvl, target_height, target_width)?;
    im.save(out_dir.join(format!("wsi_region_x{}_y{}_h{}_w{}_z{}.png",
                                 source_row,
                                 source_col,
                                 target_height,
                                 target_width,
                                 zoom_lvl)))?;

    Ok(())
}

fn main() -> Result<(), Error> {

    let matches = get_cli();

    let input_file = match matches.value_of("input_file") {
        Some(val) => {
            let filepath = path::Path::new(val);
            if filepath.exists() {
                filepath
            } else {
                return Err(err_msg("Input file does not exist"))
            }
        }
        None => unreachable!()
    };

    let out_dir = match matches.value_of("out_root_dir") {
        Some(val) => {
            let dirpath = path::Path::new(val);
            if !dirpath.exists() {
                fs::create_dir_all(&dirpath)?;
            }
            dirpath
        }
        None => unreachable!()
    };

    let source_row = value_t!(matches.value_of("source_row"), u32)?;
    let source_column = value_t!(matches.value_of("source_column"), u32)?;
    let target_height = value_t!(matches.value_of("target_height"), i32)?;
    let target_width = value_t!(matches.value_of("target_width"), i32)?;
    let zoom_factor = {
        let val = value_t!(matches.value_of("zoom_factor"), f32)?;
        if val < 1.0 {
            println!("Too small zoom factor: {}", val);
            println!("Zoom factor below 1.0 does not make sense in this application.");
            println!("Zoom factor is set to 1.0");
            1.0
        } else {
            val
        }
    };

    let os = OpenSlide::new(input_file)?;

    if matches.is_present("print_properties") {
        for (key, val) in os.get_properties()? {
            println!("{0:<40} {1}", key, val);
        }
    }

    write_region(
        &os,
        &out_dir,
        source_row,
        source_column,
        target_height,
        target_width,
        zoom_factor,
        )?;



    Ok(())
}