Building a project with Cargo – imgtool

We now have a fairly good understanding of how to manage projects using Cargo. To drive the concepts in, we will build a command-line application that uses a third-party crate. The whole point of this exercise is to become familiar with the usual workflow of building projects by using third-party crates, so we're going to skip over a lot of details about the code we write here. You are encouraged to check out the documentation of the APIs that are used in the code, though.

We'll use a crate called image from crates.io. This crate provides various image manipulation APIs. Our command-line application will be simple; it will take a path to an image file as its argument, rotate it by 90 degrees, and write back to the same file, every time when run.

We'll cd into the imgtool directory, which we created previously. First, we need to tell Cargo that we want to use the image crate. We can use the cargo add [email protected] command to add the image crate with version 0.19.0 from the command line. Here's our updated Cargo.toml file:

[package]
name = "imgtool"
version = "0.1.0"
authors = ["creativcoder"]
edition = "2018"

[dependencies]
image = "0.19.0"

Then, we'll invoke cargo build. This pulls the image crate from crates.io and pulls its dependencies, before finally compiling our project. Once that is done, we are ready to use it in our main.rs file. For our app, we'll provide an image path as an argument. In our main.rs file, we want to read this image's path:

// imgtool/src/main.rs

use std::env;
use std::path::Path;

fn main() {
let image_path = env::args().skip(1).next().unwrap();
let path = Path::new(&image_path);
}

First, we read the argument that was passed to imgtool by invoking the args() function from the env module. This returns a string as a path to the image file. We then take the image path and create a Path instance out of it. Next comes the rotate functionality that comes from the image crate. Note that if you're running Rust 2015 edition, you will need an additional extern crate image; declaration on top of main.rs for you to be able to access the image crate's APIs. With Rust 2018 edition, this is not needed:

// imgtool/src/main.rs

use std::env;
use std::path::Path;

fn main() {
let image_path = env::args().skip(1).next().unwrap();
let path = Path::new(&image_path);
let img = image::open(path).unwrap();
let rotated = img.rotate90();
rotated.save(path).unwrap();
}

From the image crate, we use the open function to open our image and store it in img. We then call rotate90 on img. This returns an image buffer as rotated, which we just save back to the original image path by calling save and passing the path. Most of the function calls in the preceding code return a wrapper value called Result, and so we call unwrap() on Result values to tell the compiler that we don't care whether the function call failed, assuming that it has succeeded, and we just want to get the wrapped value from the Result type. We will learn about the Result type and proper error handling methods in Chapter 6, Error Handling. For the demo, under the project's asset folder, you will find an image of Ferris the crab (assets/ferris.png). Before running the code, we will see the following image:

Time to run our application with this image as an argument. Now, there are two ways you can run the imgtool binary and pass the image as an argument:

  • By doing a cargo build and then invoking the binary manually as ./target/debug/imgtool assets/ferris.png.
  • By directly running cargo run -- assets/ferris.png. The double dashes mark the end of the parameters for Cargo's own arguments. Anything after it is passed to our executable (here, this is imgtool).

After running cargo run -- assets/ferris.png, we can see that Ferris has taken a tumble:

Great! Our application works. We can now install our tool by running cargo install inside our imgtool directory and then use it from anywhere in our terminal. Also, if you are on Ubuntu, we can use the cargo deb subcommand to create a deb package so that you can distribute it to other consumers. Running the cargo deb command produces the .deb file, as shown in the following screenshot:

Now, it's time for you to explore more in relation to the preceding code:

  • Use the Rust standard library docs at https://doc.rust-lang.org/std/ to learn about the unwrap() function in Rust and on what types it is available.
  • Look for the Path type in the standard library docs to see if you can modify the program to not overwrite the files, and instead create a new file with  _rotated as the new file suffix.
  • Use the search bar in the documentation page of the image crate (https://docs.rs/image) and try finding other rotate methods with different angles, and modify the code to make use of them.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset