From b1bf9e7974852ca4d01fd8b3fea798e627e9f95a Mon Sep 17 00:00:00 2001 From: Francesca Sunshine Date: Wed, 13 Dec 2017 21:23:22 -0500 Subject: [PATCH] Ran rustfmt on everything + updated Travis config to check formatting and automatically push test images. --- .travis.yml | 22 +++++- deploy-docs.sh | 25 ++++++ rustfmt.toml | 5 ++ src/blend.rs | 132 ++++++++++++++++++++++--------- src/color.rs | 75 +++++++----------- src/compare.rs | 59 ++++++-------- src/editor.rs | 133 ++++++++++++++++++++++--------- src/endec.rs | 86 ++++++++++---------- src/error.rs | 62 +++++++++++---- src/filter.rs | 136 +++++++++++++++++--------------- src/image.rs | 34 ++++---- src/interpolate.rs | 65 +++++++-------- src/lib.rs | 68 +++++++--------- src/position.rs | 30 ++++--- src/transform.rs | 96 +++++++++++------------ tests/color_tests.rs | 14 ++-- tests/filter_tests.rs | 5 +- tests/integration_tests.rs | 2 +- tests/io_tests.rs | 157 ++++++++++++++++--------------------- 19 files changed, 672 insertions(+), 534 deletions(-) create mode 100644 deploy-docs.sh create mode 100644 rustfmt.toml diff --git a/.travis.yml b/.travis.yml index dd7fb722..d3690aba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,25 @@ language: rust +cache: cargo rust: - stable - beta - - nightly matrix: - allow_failures: + include: - rust: nightly - + env: RUSTFMT=0.3.1 + install: + - export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + - if [[ `rustfmt --version` != $RUSTFMT* ]] ; then travis_wait cargo install --force rustfmt-nightly --vers $RUSTFMT; fi + - export PATH="$PATH:$HOME/.cargo/bin" + script: + - rustfmt --write-mode=diff src/lib.rs + - cargo build + - cargo test before_script: - - sudo chmod -R 0777 /home/travis/build/kosinix/raster/tests/ \ No newline at end of file + - sudo chmod -R 0777 /home/travis/build/kosinix/raster/tests/ +script: + - cargo build + - cargo test + - cargo doc +after_success: + - test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy-docs.sh diff --git a/deploy-docs.sh b/deploy-docs.sh new file mode 100644 index 00000000..a8fbfc45 --- /dev/null +++ b/deploy-docs.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -o errexit -o nounset + +: ${TRAVIS:?"This should only be run on Travis CI."} + +rev=$(git rev-parse --short HEAD) + +git init +git config user.name "Francesca Sunshine" +git config user.email "francesca@comfy.love" + +git remote add upstream "https://$GH_TOKEN@github.com/kosinix/raster.git" +git fetch upstream +git reset upstream/gh-pages + +rm -rf in out docs +mv tests/in in +mv tests/out out +rm out/.gitignore +mv target/doc docs + +git add -A in out docs +git commit -m "Updated docs for ${rev}" +git push --force --quiet upstream HEAD:gh-pages diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..091a80c5 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +use_try_shorthand = true + +# This was merged, but doesn't seem to work? https://github.com/rust-lang-nursery/rustfmt/pull/1869 +# error_on_line_overflow_comments = false +error_on_line_overflow = false diff --git a/src/blend.rs b/src/blend.rs index e99fd5f2..22264a77 100644 --- a/src/blend.rs +++ b/src/blend.rs @@ -1,13 +1,10 @@ //! A module for blending 2 images. // See https://en.wikipedia.org/wiki/Alpha_compositing - // from rust - // from external crate - // from local crate use error::RasterResult; use Image; @@ -20,24 +17,33 @@ pub enum BlendMode { Difference, Multiply, Overlay, - Screen + Screen, } -pub fn difference(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, loop_start_x:i32, loop_end_x:i32, offset_x:i32, offset_y:i32, opacity:f32) -> RasterResult { - +pub fn difference( + image1: &Image, + image2: &Image, + loop_start_y: i32, + loop_end_y: i32, + loop_start_x: i32, + loop_end_x: i32, + offset_x: i32, + offset_y: i32, + opacity: f32, +) -> RasterResult { let mut canvas = image1.clone(); for y in loop_start_y..loop_end_y { for x in loop_start_x..loop_end_x { let canvas_x = x + offset_x; let canvas_y = y + offset_y; - let rgba1 = try!(image1.get_pixel(canvas_x, canvas_y)); + let rgba1 = image1.get_pixel(canvas_x, canvas_y)?; let a1 = rgba1.a as f32 / 255.0; // convert to 0.0 - 1.0 let r1 = rgba1.r as f32 * a1; let g1 = rgba1.g as f32 * a1; let b1 = rgba1.b as f32 * a1; - let rgba2 = try!(image2.get_pixel(x, y)); + let rgba2 = image2.get_pixel(x, y)?; let a2 = rgba2.a as f32 / 255.0 * opacity; // convert to 0.0 - 1.0 let r2 = rgba2.r as f32; let g2 = rgba2.g as f32; @@ -48,28 +54,41 @@ pub fn difference(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i let b3 = ch_alpha_f(b1, b2, BlendFunction::Difference, a2); let a3 = 255; - try!(canvas.set_pixel(canvas_x, canvas_y, &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8))); + canvas.set_pixel( + canvas_x, + canvas_y, + &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8), + )?; } } Ok(canvas) } -pub fn multiply(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, loop_start_x:i32, loop_end_x:i32, offset_x:i32, offset_y:i32, opacity:f32) -> RasterResult { - +pub fn multiply( + image1: &Image, + image2: &Image, + loop_start_y: i32, + loop_end_y: i32, + loop_start_x: i32, + loop_end_x: i32, + offset_x: i32, + offset_y: i32, + opacity: f32, +) -> RasterResult { let mut canvas = image1.clone(); for y in loop_start_y..loop_end_y { for x in loop_start_x..loop_end_x { let canvas_x = x + offset_x; let canvas_y = y + offset_y; - let rgba1 = try!(image1.get_pixel(canvas_x, canvas_y)); + let rgba1 = image1.get_pixel(canvas_x, canvas_y)?; let a1 = rgba1.a as f32 / 255.0; // convert to 0.0 - 1.0 let r1 = rgba1.r as f32 * a1; let g1 = rgba1.g as f32 * a1; let b1 = rgba1.b as f32 * a1; - let rgba2 = try!(image2.get_pixel(x, y)); + let rgba2 = image2.get_pixel(x, y)?; let a2 = rgba2.a as f32 / 255.0 * opacity; // convert to 0.0 - 1.0 let r2 = rgba2.r as f32; let g2 = rgba2.g as f32; @@ -80,28 +99,41 @@ pub fn multiply(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32 let b3 = ch_alpha_f(b1, b2, BlendFunction::Multiply, a2); let a3 = 255; - try!(canvas.set_pixel(canvas_x, canvas_y, &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8))); + canvas.set_pixel( + canvas_x, + canvas_y, + &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8), + )?; } } Ok(canvas) } -pub fn normal(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, loop_start_x:i32, loop_end_x:i32, offset_x:i32, offset_y:i32, opacity:f32) -> RasterResult { - +pub fn normal( + image1: &Image, + image2: &Image, + loop_start_y: i32, + loop_end_y: i32, + loop_start_x: i32, + loop_end_x: i32, + offset_x: i32, + offset_y: i32, + opacity: f32, +) -> RasterResult { let mut canvas = image1.clone(); for y in loop_start_y..loop_end_y { for x in loop_start_x..loop_end_x { let canvas_x = x + offset_x; let canvas_y = y + offset_y; - let color1 = try!(image1.get_pixel(canvas_x, canvas_y)); + let color1 = image1.get_pixel(canvas_x, canvas_y)?; let a1 = color1.a as f32 / 255.0; // convert to 0.0 - 1.0 let r1 = color1.r as f32 * a1; let g1 = color1.g as f32 * a1; let b1 = color1.b as f32 * a1; - let color2 = try!(image2.get_pixel(x, y)); + let color2 = image2.get_pixel(x, y)?; let a2 = color2.a as f32 / 255.0 * opacity; // convert to 0.0 - 1.0 let r2 = color2.r as f32; let g2 = color2.g as f32; @@ -112,28 +144,41 @@ pub fn normal(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, let b3 = (a2 * b2) + ((1.0 - a2) * b1); let a3 = 255; - try!(canvas.set_pixel(canvas_x, canvas_y, &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8))); + canvas.set_pixel( + canvas_x, + canvas_y, + &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8), + )?; } } Ok(canvas) } -pub fn overlay(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, loop_start_x:i32, loop_end_x:i32, offset_x:i32, offset_y:i32, opacity:f32) -> RasterResult { - +pub fn overlay( + image1: &Image, + image2: &Image, + loop_start_y: i32, + loop_end_y: i32, + loop_start_x: i32, + loop_end_x: i32, + offset_x: i32, + offset_y: i32, + opacity: f32, +) -> RasterResult { let mut canvas = image1.clone(); for y in loop_start_y..loop_end_y { for x in loop_start_x..loop_end_x { let canvas_x = x + offset_x; let canvas_y = y + offset_y; - let rgba1 = try!(image1.get_pixel(canvas_x, canvas_y)); + let rgba1 = image1.get_pixel(canvas_x, canvas_y)?; let a1 = rgba1.a as f32 / 255.0; // convert to 0.0 - 1.0 let r1 = rgba1.r as f32 * a1; let g1 = rgba1.g as f32 * a1; let b1 = rgba1.b as f32 * a1; - let rgba2 = try!(image2.get_pixel(x, y)); + let rgba2 = image2.get_pixel(x, y)?; let a2 = rgba2.a as f32 / 255.0 * opacity; // convert to 0.0 - 1.0 let r2 = rgba2.r as f32; let g2 = rgba2.g as f32; @@ -144,28 +189,41 @@ pub fn overlay(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, let b3 = ch_alpha_f(b1, b2, BlendFunction::Overlay, a2); let a3 = 255; - try!(canvas.set_pixel(canvas_x, canvas_y, &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8))); + canvas.set_pixel( + canvas_x, + canvas_y, + &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8), + )?; } } Ok(canvas) } -pub fn screen(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, loop_start_x:i32, loop_end_x:i32, offset_x:i32, offset_y:i32, opacity:f32) -> RasterResult { - +pub fn screen( + image1: &Image, + image2: &Image, + loop_start_y: i32, + loop_end_y: i32, + loop_start_x: i32, + loop_end_x: i32, + offset_x: i32, + offset_y: i32, + opacity: f32, +) -> RasterResult { let mut canvas = image1.clone(); for y in loop_start_y..loop_end_y { for x in loop_start_x..loop_end_x { let canvas_x = x + offset_x; let canvas_y = y + offset_y; - let rgba1 = try!(image1.get_pixel(canvas_x, canvas_y)); + let rgba1 = image1.get_pixel(canvas_x, canvas_y)?; let a1 = rgba1.a as f32 / 255.0; // convert to 0.0 - 1.0 let r1 = rgba1.r as f32 * a1; let g1 = rgba1.g as f32 * a1; let b1 = rgba1.b as f32 * a1; - let rgba2 = try!(image2.get_pixel(x, y)); + let rgba2 = image2.get_pixel(x, y)?; let a2 = rgba2.a as f32 / 255.0 * opacity; // convert to 0.0 - 1.0 let r2 = rgba2.r as f32; let g2 = rgba2.g as f32; @@ -176,7 +234,11 @@ pub fn screen(image1: &Image, image2: &Image, loop_start_y:i32, loop_end_y:i32, let b3 = ch_alpha_f(b1, b2, BlendFunction::Screen, a2); let a3 = 255; - try!(canvas.set_pixel(canvas_x, canvas_y, &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8))); + canvas.set_pixel( + canvas_x, + canvas_y, + &Color::rgba(r3 as u8, g3 as u8, b3 as u8, a3 as u8), + )?; } } @@ -197,15 +259,15 @@ enum BlendFunction { Difference, Multiply, Overlay, - Screen + Screen, } fn ch_alpha_f(base: f32, top: f32, f: BlendFunction, opacity: f32) -> f32 { match f { - BlendFunction::Difference => ch_alpha( base, ch_difference( base, top ), opacity ), - BlendFunction::Multiply => ch_alpha( base, ch_multiply( base, top ), opacity ), - BlendFunction::Overlay => ch_alpha( base, ch_overlay( base, top ), opacity ), - BlendFunction::Screen => ch_alpha( base, ch_screen( base, top ), opacity ) + BlendFunction::Difference => ch_alpha(base, ch_difference(base, top), opacity), + BlendFunction::Multiply => ch_alpha(base, ch_multiply(base, top), opacity), + BlendFunction::Overlay => ch_alpha(base, ch_overlay(base, top), opacity), + BlendFunction::Screen => ch_alpha(base, ch_screen(base, top), opacity), } } @@ -229,6 +291,6 @@ fn ch_overlay(base: f32, top: f32) -> f32 { } } -fn ch_screen(base: f32, top:f32) -> f32 { +fn ch_screen(base: f32, top: f32) -> f32 { 255.0 - (((255.0 - base) * (255.0 - top)) / 255.0) } diff --git a/src/color.rs b/src/color.rs index a773b826..7030cc07 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,12 +1,10 @@ //! A module for handling colors. - // from rust use std; // from external crate - // from local crate use error::{RasterError, RasterResult}; @@ -27,7 +25,6 @@ pub struct Color { } impl<'a> Color { - /// Returns a black Color. pub fn black() -> Color { Color { @@ -100,18 +97,20 @@ impl<'a> Color { /// assert_eq!(255, color.g); /// ``` pub fn hex(hex: &str) -> RasterResult { - if hex.len() == 9 && hex.starts_with('#') { // #FFFFFFFF (Red Green Blue Alpha) + if hex.len() == 9 && hex.starts_with('#') { + // #FFFFFFFF (Red Green Blue Alpha) Ok(Color { - r: try!(_hex_dec(&hex[1..3])), - g: try!(_hex_dec(&hex[3..5])), - b: try!(_hex_dec(&hex[5..7])), - a: try!(_hex_dec(&hex[7..9])), + r: _hex_dec(&hex[1..3])?, + g: _hex_dec(&hex[3..5])?, + b: _hex_dec(&hex[5..7])?, + a: _hex_dec(&hex[7..9])?, }) - } else if hex.len() == 7 && hex.starts_with('#') { // #FFFFFF (Red Green Blue) + } else if hex.len() == 7 && hex.starts_with('#') { + // #FFFFFF (Red Green Blue) Ok(Color { - r: try!(_hex_dec(&hex[1..3])), - g: try!(_hex_dec(&hex[3..5])), - b: try!(_hex_dec(&hex[5..7])), + r: _hex_dec(&hex[1..3])?, + g: _hex_dec(&hex[3..5])?, + b: _hex_dec(&hex[5..7])?, a: 255, }) } else { @@ -145,13 +144,8 @@ impl<'a> Color { /// assert_eq!(rgb.b, 0); /// assert_eq!(rgb.a, 255); /// ``` - pub fn rgb(r:u8, g:u8, b:u8) -> Color { - Color { - r: r, - g: g, - b: b, - a: 255, - } + pub fn rgb(r: u8, g: u8, b: u8) -> Color { + Color { r, g, b, a: 255 } } /// Create a RGBA color. @@ -170,13 +164,8 @@ impl<'a> Color { /// assert_eq!(rgba.b, 255); /// assert_eq!(rgba.a, 255); /// ``` - pub fn rgba(r:u8, g:u8, b:u8, a:u8) -> Color { - Color { - r: r, - g: g, - b: b, - a: a, - } + pub fn rgba(r: u8, g: u8, b: u8, a: u8) -> Color { + Color { r, g, b, a } } /// Convert RGB to HSV/HSB (Hue, Saturation, Brightness). @@ -192,7 +181,6 @@ impl<'a> Color { /// ``` // Using f32 for s,v for accuracy when converting from RGB-HSV and vice-versa. pub fn to_hsv(r: u8, g: u8, b: u8) -> (u16, f32, f32) { - let r = r as f32 / 255.0; let g = g as f32 / 255.0; let b = b as f32 / 255.0; @@ -226,13 +214,9 @@ impl<'a> Color { }; let v = max; - let s = if v != 0.0 { - chroma / v - } else { - 0.0 - }; + let s = if v != 0.0 { chroma / v } else { 0.0 }; - ( h.round() as u16, s * 100.0, v * 100.0 ) + (h.round() as u16, s * 100.0, v * 100.0) } /// Convert HSV/HSB (Hue, Saturation, Brightness) to RGB. @@ -250,15 +234,14 @@ impl<'a> Color { /// assert_eq!(rgb1.2, rgb2.2); /// ``` // Using f32 for s,v for accuracy when converting from RGB-HSV and vice-versa. - pub fn to_rgb(h:u16, s: f32, v: f32) -> (u8, u8, u8) { - + pub fn to_rgb(h: u16, s: f32, v: f32) -> (u8, u8, u8) { let h = h as f32 / 60.0; let s = s as f32 / 100.0; // Convert to 0.0 - 1.0 let v = v as f32 / 100.0; let chroma = v * s; - let x = chroma * ( 1.0 - ( (h % 2.0) - 1.0 ).abs() ); + let x = chroma * (1.0 - ((h % 2.0) - 1.0).abs()); let mut r = 0.0; let mut g = 0.0; @@ -296,7 +279,11 @@ impl<'a> Color { r += m; g += m; b += m; - ( (r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8) + ( + (r * 255.0).round() as u8, + (g * 255.0).round() as u8, + (b * 255.0).round() as u8, + ) } /// Returns a white Color. @@ -320,11 +307,7 @@ fn _hex_dec(hex_string: &str) -> RasterResult { } fn rgb_min(r: f32, g: f32, b: f32) -> f32 { - let min = if g < r { - g - } else { - r - }; + let min = if g < r { g } else { r }; if b < min { b @@ -334,15 +317,11 @@ fn rgb_min(r: f32, g: f32, b: f32) -> f32 { } fn rgb_max(r: f32, g: f32, b: f32) -> f32 { - let max = if g > r { - g - } else { - r - }; + let max = if g > r { g } else { r }; if b > max { b } else { max } -} \ No newline at end of file +} diff --git a/src/compare.rs b/src/compare.rs index 008cf8b3..22434529 100644 --- a/src/compare.rs +++ b/src/compare.rs @@ -1,6 +1,5 @@ //! A module for comparing images. - // from rust // from external crate @@ -10,8 +9,9 @@ use error::RasterResult; use Image; use editor::{self, ResizeMode}; -/// Compare two images and returns a hamming distance. A value of 0 indicates a likely similar picture. -/// A value between 1 and 10 is potentially a variation. A value greater than 10 is likely a different image. +/// Compare two images and returns a hamming distance. A value of 0 indicates a likely similar +/// picture. A value between 1 and 10 is potentially a variation. A value greater than 10 is +/// likely a different image. /// /// # Examples /// ``` @@ -24,9 +24,8 @@ use editor::{self, ResizeMode}; /// println!("{}", hamming_distance); /// ``` pub fn similar(image1: &Image, image2: &Image) -> RasterResult { - - let bin1 = try!(diff_hash(image1)); - let bin2 = try!(diff_hash(image2)); + let bin1 = diff_hash(image1)?; + let bin2 = diff_hash(image2)?; let mut distance = 0; for (index, value) in bin1.iter().enumerate() { if value != &bin2[index] { @@ -36,9 +35,10 @@ pub fn similar(image1: &Image, image2: &Image) -> RasterResult { Ok(distance) } -/// Compare if two images are equal. It will compare if the two images are of the same width and height. -/// If the dimensions differ, it will return false. If the dimensions are equal, it will loop through each pixels. -/// If one of the pixel don't match, it will return false. The pixels are compared using their RGB (Red, Green, Blue) values. +/// Compare if two images are equal. It will compare if the two images are of the same width and +/// height. If the dimensions differ, it will return false. If the dimensions are equal, it will +/// loop through each pixels. If one of the pixel don't match, it will return false. The pixels +/// are compared using their RGB (Red, Green, Blue) values. /// /// # Examples /// ``` @@ -50,30 +50,22 @@ pub fn similar(image1: &Image, image2: &Image) -> RasterResult { /// let equal = compare::equal(&image1, &image2).unwrap(); /// assert_eq!(true, equal); /// ``` -pub fn equal(image1: &Image, image2: &Image)-> RasterResult { - +pub fn equal(image1: &Image, image2: &Image) -> RasterResult { // Check if image dimensions are equal if image1.width != image2.width || image1.height != image2.height { - Ok(false) } else { - // Loop using image1 for y in 0..image1.height { for x in 0..image1.width { - // Get image1 pixel - let pixel1 = try!(image1.get_pixel(x, y)); + let pixel1 = image1.get_pixel(x, y)?; // Get image2 pixel - let pixel2 = try!(image2.get_pixel(x, y)); + let pixel2 = image2.get_pixel(x, y)?; // Compare pixel value - if - pixel1.r != pixel2.r || - pixel1.g != pixel2.g || - pixel1.b != pixel2.b - { + if pixel1.r != pixel2.r || pixel1.g != pixel2.g || pixel1.b != pixel2.b { return Ok(false); } } @@ -88,36 +80,37 @@ pub fn equal(image1: &Image, image2: &Image)-> RasterResult { // DifferenceHash // // Algorithm: -// Reduce size. The fastest way to remove high frequencies and detail is to shrink the image. In this case, shrink it to 9x8 so that there are 72 total pixels. -// Reduce color. Convert the image to a grayscale picture. This changes the hash from 72 pixels to a total of 72 colors. -// Compute the difference. The algorithm works on the difference between adjacent pixels. This identifies the relative gradient direction. In this case, the 9 pixels per row yields 8 differences between adjacent pixels. Eight rows of eight differences becomes 64 bits. -// Assign bits. Each bit is simply set based on whether the left pixel is brighter than the right pixel. +// Reduce size. The fastest way to remove high frequencies and detail is to shrink the image. In +// this case, shrink it to 9x8 so that there are 72 total pixels. Reduce color. Convert the image +// to a grayscale picture. This changes the hash from 72 pixels to a total of 72 colors. Compute +// the difference. The algorithm works on the difference between adjacent pixels. This identifies +// the relative gradient direction. In this case, the 9 pixels per row yields 8 differences +// between adjacent pixels. Eight rows of eight differences becomes 64 bits. Assign bits. Each bit +// is simply set based on whether the left pixel is brighter than the right pixel. // // http://www.hackerfactor.com/blog/index.php?/archives/529-Kind-of-Like-That.html // // fn diff_hash(image: &Image) -> RasterResult> { - - let width = 9; + let width = 9; let height = 8; let mut image = image.clone(); // copy it since resize is desctructive - try!(editor::resize(&mut image, width, height, ResizeMode::Exact)); // Resize to exactly 9x8 + editor::resize(&mut image, width, height, ResizeMode::Exact)?; // Resize to exactly 9x8 // Build hash let mut hash = Vec::new(); for y in 0..height { - // Get the pixel value for the leftmost pixel. - let pixel = try!(image.get_pixel(0, y)); + let pixel = image.get_pixel(0, y)?; let mut left = ((pixel.r as f32 + pixel.g as f32 + pixel.b as f32) / 3.0).floor(); // Get the pixel value for each pixel starting from position 1. for x in 1..width { - - let pixel = try!(image.get_pixel(x, y)); + let pixel = image.get_pixel(x, y)?; let right = ((pixel.r as f32 + pixel.g as f32 + pixel.b as f32) / 3.0).floor(); - // Each hash bit is set based on whether the left pixel is brighter than the right pixel. + // Each hash bit is set based on whether the left pixel is brighter than the right + // pixel. if left > right { hash.push(1); } else { diff --git a/src/editor.rs b/src/editor.rs index a3330df1..1d2b797b 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -5,7 +5,6 @@ use std::cmp; // from external crate - // from local crate use error::{RasterError, RasterResult}; use blend::{self, BlendMode}; @@ -22,7 +21,8 @@ use transform; /// /// # Errors /// -/// If image2 falls outside the canvas area, then this fails with `RasterError::BlendingImageFallsOutsideCanvas`. +/// If image2 falls outside the canvas area, then this fails with +/// `RasterError::BlendingImageFallsOutsideCanvas`. /// /// # Examples /// ``` @@ -32,7 +32,8 @@ use transform; /// let image1 = raster::open("tests/in/sample.jpg").unwrap(); /// let image2 = raster::open("tests/in/watermark.png").unwrap(); /// -/// // Blend image2 on top of image1 using normal mode, opacity of 1.0 (100%), with image2 at the center, with 0 x and 0 y offsets. whew +/// // Blend image2 on top of image1 using normal mode, opacity of 1.0 (100%), with image2 at the +/// // center, with 0 x and 0 y offsets. whew /// let normal = editor::blend(&image1, &image2, BlendMode::Normal, 1.0, PositionMode::Center, 0, 0).unwrap(); /// /// // All the other blend modes @@ -83,8 +84,15 @@ use transform; /// /// ![](https://kosinix.github.io/raster/out/test_blend_screen.png) /// -pub fn blend(image1: &Image, image2: &Image, blend_mode: BlendMode, opacity: f32, position: PositionMode, offset_x: i32, offset_y: i32) -> RasterResult { - +pub fn blend( + image1: &Image, + image2: &Image, + blend_mode: BlendMode, + opacity: f32, + position: PositionMode, + offset_x: i32, + offset_y: i32, +) -> RasterResult { let opacity = if opacity > 1.0 { 1.0 } else if opacity < 0.0 { @@ -97,17 +105,14 @@ pub fn blend(image1: &Image, image2: &Image, blend_mode: BlendMode, opacity: f32 let positioner = Position::new(position, offset_x, offset_y); // Position is for image2, image1 is canvas. - let (offset_x, offset_y) = try!(positioner.get_x_y( image1.width, image1.height, image2.width, image2.height)); + let (offset_x, offset_y) = + positioner.get_x_y(image1.width, image1.height, image2.width, image2.height)?; let (w1, h1) = (image1.width, image1.height); let (w2, h2) = (image2.width, image2.height); // Check if it overlaps - if (offset_x >= w1 ) || - (offset_x + w2 <= 0) || - (offset_y >= h1) || - (offset_y + h2 <= 0) { - + if (offset_x >= w1) || (offset_x + w2 <= 0) || (offset_y >= h1) || (offset_y + h2 <= 0) { return Err(RasterError::BlendingImageFallsOutsideCanvas); } @@ -122,7 +127,7 @@ pub fn blend(image1: &Image, image2: &Image, blend_mode: BlendMode, opacity: f32 // Loop end X let mut loop_end_x = w2; let canvas_end_x = offset_x + w2; - if canvas_end_x > w1{ + if canvas_end_x > w1 { let diff = canvas_end_x - w1; loop_end_x -= diff; } @@ -144,22 +149,69 @@ pub fn blend(image1: &Image, image2: &Image, blend_mode: BlendMode, opacity: f32 } match blend_mode { - BlendMode::Normal => - blend::normal(image1, image2, loop_start_y, loop_end_y, loop_start_x, loop_end_x, offset_x, offset_y, opacity), - BlendMode::Difference => - blend::difference(image1, image2, loop_start_y, loop_end_y, loop_start_x, loop_end_x, offset_x, offset_y, opacity), - BlendMode::Multiply => - blend::multiply(image1, image2, loop_start_y, loop_end_y, loop_start_x, loop_end_x, offset_x, offset_y, opacity), - BlendMode::Overlay => - blend::overlay(image1, image2, loop_start_y, loop_end_y, loop_start_x, loop_end_x, offset_x, offset_y, opacity), - BlendMode::Screen => - blend::screen(image1, image2, loop_start_y, loop_end_y, loop_start_x, loop_end_x, offset_x, offset_y, opacity), + BlendMode::Normal => blend::normal( + image1, + image2, + loop_start_y, + loop_end_y, + loop_start_x, + loop_end_x, + offset_x, + offset_y, + opacity, + ), + BlendMode::Difference => blend::difference( + image1, + image2, + loop_start_y, + loop_end_y, + loop_start_x, + loop_end_x, + offset_x, + offset_y, + opacity, + ), + BlendMode::Multiply => blend::multiply( + image1, + image2, + loop_start_y, + loop_end_y, + loop_start_x, + loop_end_x, + offset_x, + offset_y, + opacity, + ), + BlendMode::Overlay => blend::overlay( + image1, + image2, + loop_start_y, + loop_end_y, + loop_start_x, + loop_end_x, + offset_x, + offset_y, + opacity, + ), + BlendMode::Screen => blend::screen( + image1, + image2, + loop_start_y, + loop_end_y, + loop_start_x, + loop_end_x, + offset_x, + offset_y, + opacity, + ), } } /// Crop the image to the given dimension and position. /// -/// The `offset_x` and `offset_y` are added to the final position. Can also be negative offsets. Offsets can be used to nudge the final position. Or you can set the position to `PositionMode::TopLeft` and use the offsets as a normal screen x and y coordinates. +/// The `offset_x` and `offset_y` are added to the final position. Can also be negative offsets. +/// Offsets can be used to nudge the final position. Or you can set the position to +/// `PositionMode::TopLeft` and use the offsets as a normal screen x and y coordinates. /// /// # Examples /// @@ -217,15 +269,21 @@ pub fn blend(image1: &Image, image2: &Image, blend_mode: BlendMode, opacity: f32 /// ### Output /// The cropped images arranged in a grid, showing how you can easily set the crop position. /// -/// ![](https://kosinix.github.io/raster/out/test_crop_top_left.jpg) ![](https://kosinix.github.io/raster/out/test_crop_top_center.jpg) ![](https://kosinix.github.io/raster/out/test_crop_top_right.jpg) -/// ![](https://kosinix.github.io/raster/out/test_crop_center_left.jpg) ![](https://kosinix.github.io/raster/out/test_crop_center.jpg) ![](https://kosinix.github.io/raster/out/test_crop_center_right.jpg) +/// ![](https://kosinix.github.io/raster/out/test_crop_top_left.jpg) ![](https://kosinix.github.io/raster/out/test_crop_top_center.jpg) ![](https://kosinix.github.io/raster/out/test_crop_top_right.jpg) +/// ![](https://kosinix.github.io/raster/out/test_crop_center_left.jpg) ![](https://kosinix.github.io/raster/out/test_crop_center.jpg) ![](https://kosinix.github.io/raster/out/test_crop_center_right.jpg) /// ![](https://kosinix.github.io/raster/out/test_crop_bottom_left.jpg) ![](https://kosinix.github.io/raster/out/test_crop_bottom_center.jpg) ![](https://kosinix.github.io/raster/out/test_crop_bottom_right.jpg) -pub fn crop(mut src: &mut Image, crop_width: i32, crop_height: i32, position: PositionMode, offset_x: i32, offset_y: i32) -> RasterResult<()> { - +pub fn crop( + src: &mut Image, + crop_width: i32, + crop_height: i32, + position: PositionMode, + offset_x: i32, + offset_y: i32, +) -> RasterResult<()> { // Turn into positioner struct let positioner = Position::new(position, offset_x, offset_y); - let (offset_x, offset_y) = try!(positioner.get_x_y( src.width, src.height, crop_width, crop_height)); + let (offset_x, offset_y) = positioner.get_x_y(src.width, src.height, crop_width, crop_height)?; let offset_x = cmp::max(0, offset_x); let offset_y = cmp::max(0, offset_y); @@ -239,12 +297,12 @@ pub fn crop(mut src: &mut Image, crop_width: i32, crop_height: i32, position: Po cmp::min(width2, src.width) }; - let mut dest = Image::blank(width2-offset_x, height2-offset_y); + let mut dest = Image::blank(width2 - offset_x, height2 - offset_y); for y in 0..dest.height { for x in 0..dest.width { - let pixel = try!(src.get_pixel(offset_x + x, offset_y + y)); - try!(dest.set_pixel(x, y, &Color::rgba(pixel.r, pixel.g, pixel.b, pixel.a))); + let pixel = src.get_pixel(offset_x + x, offset_y + y)?; + dest.set_pixel(x, y, &Color::rgba(pixel.r, pixel.g, pixel.b, pixel.a))?; } } src.width = dest.width; @@ -273,11 +331,10 @@ pub fn crop(mut src: &mut Image, crop_width: i32, crop_height: i32, position: Po /// ``` /// /// -pub fn fill(mut src: &mut Image, color: Color) -> RasterResult<()> { - +pub fn fill(src: &mut Image, color: Color) -> RasterResult<()> { for y in 0..src.height { for x in 0..src.width { - try!(src.set_pixel(x, y, &color)); + src.set_pixel(x, y, &color)?; } } @@ -296,7 +353,7 @@ pub enum ResizeMode { /// Resize an image to fit within the given width and height. Fit, /// Resize image to fill all the space in the given dimension. Excess parts are cropped. - Fill + Fill, } /// Resize an image to a given width, height and mode. @@ -368,7 +425,7 @@ pub enum ResizeMode { /// /// The images will have a width of 200. The height is auto-calculated. /// -/// ![](https://kosinix.github.io/raster/out/test_resize_exact_width_1.jpg) +/// ![](https://kosinix.github.io/raster/out/test_resize_exact_width_1.jpg) /// ![](https://kosinix.github.io/raster/out/test_resize_exact_width_2.jpg) /// /// ### Resize to Exact Height @@ -411,12 +468,12 @@ pub enum ResizeMode { /// /// ![](https://kosinix.github.io/raster/out/test_resize_exact_1.jpg) ![](https://kosinix.github.io/raster/out/test_resize_exact_2.jpg) /// -pub fn resize(mut src: &mut Image, w: i32, h: i32, mode: ResizeMode) -> RasterResult<()> { +pub fn resize(src: &mut Image, w: i32, h: i32, mode: ResizeMode) -> RasterResult<()> { match mode { ResizeMode::Exact => transform::resize_exact(src, w, h), ResizeMode::ExactWidth => transform::resize_exact_width(src, w), ResizeMode::ExactHeight => transform::resize_exact_height(src, h), ResizeMode::Fit => transform::resize_fit(src, w, h), - ResizeMode::Fill => transform::resize_fill(src, w, h) + ResizeMode::Fill => transform::resize_fill(src, w, h), } } diff --git a/src/endec.rs b/src/endec.rs index 1a22eb7a..b1014b7d 100644 --- a/src/endec.rs +++ b/src/endec.rs @@ -15,84 +15,84 @@ use Image; use ImageFormat; // Decode GIF -pub fn decode_gif(image_file: &File) -> RasterResult{ - +pub fn decode_gif(image_file: &File) -> RasterResult { let mut decoder = gif::Decoder::new(image_file); // Configure the decoder such that it will expand the image to RGBA. gif::SetParameter::set(&mut decoder, gif::ColorOutput::RGBA); // Read the file header - let mut reader = try!(decoder.read_info()); - - // Read frame 1. + let mut reader = decoder.read_info()?; + + // Read frame 1. // TODO: Work on all frames - if let Some(_) = try!(reader.next_frame_info()) { + if let Some(_) = reader.next_frame_info()? { let mut bytes = vec![0; reader.buffer_size()]; - try!(reader.read_into_buffer(&mut bytes)); - Ok( - Image { - width: reader.width() as i32, - height: reader.height() as i32, - bytes: bytes - } - ) + reader.read_into_buffer(&mut bytes)?; + Ok(Image { + width: reader.width() as i32, + height: reader.height() as i32, + bytes: bytes, + }) } else { - Err(RasterError::Decode(ImageFormat::Gif, "Error getting frame info".to_string())) + Err(RasterError::Decode( + ImageFormat::Gif, + "Error getting frame info".to_string(), + )) } } // Encode GIF pub fn encode_gif(image: &Image, path: &Path) -> RasterResult<()> { - // Open the file with basic error check - let file = try!(File::create(path)); + let file = File::create(path)?; let writer = BufWriter::new(file); - let frame = gif::Frame::from_rgba(image.width as u16, image.height as u16, &mut image.bytes.clone()); // TODO: Perf issue? - let mut encoder = try!( - gif::Encoder::new(writer, frame.width, frame.height, &[]) - ); - try!(encoder.write_frame(&frame).map_err(RasterError::Io)); + let frame = gif::Frame::from_rgba( + image.width as u16, + image.height as u16, + &mut image.bytes.clone(), + ); // TODO: Perf issue? + let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?; + encoder.write_frame(&frame).map_err(RasterError::Io)?; Ok(()) } // Decode PNG -pub fn decode_png(image_file: &File) -> RasterResult{ +pub fn decode_png(image_file: &File) -> RasterResult { let decoder = png::Decoder::new(image_file); - let (info, mut reader) = try!(decoder.read_info()); + let (info, mut reader) = decoder.read_info()?; let mut bytes = vec![0; info.buffer_size()]; - - try!(reader.next_frame(&mut bytes)); - if info.color_type == png::ColorType::RGB { // Applies only to RGB + reader.next_frame(&mut bytes)?; + + if info.color_type == png::ColorType::RGB { + // Applies only to RGB let mut insert_count = 0; let len = (info.width * info.height) as usize; - for i in 0..len { // TODO: This is slow! - let insert_pos = 3 * (i+1) + insert_count; + for i in 0..len { + // TODO: This is slow! + let insert_pos = 3 * (i + 1) + insert_count; bytes.insert(insert_pos, 255); - insert_count+=1; + insert_count += 1; } } // TODO other ::ColorType - Ok( - Image { - width: info.width as i32, - height: info.height as i32, - bytes: bytes - } - ) + Ok(Image { + width: info.width as i32, + height: info.height as i32, + bytes: bytes, + }) } // Encode PNG -pub fn encode_png(image: &Image, path: &Path) -> RasterResult<()>{ - +pub fn encode_png(image: &Image, path: &Path) -> RasterResult<()> { // Open the file with basic error check - let file = try!(File::create(path)); + let file = File::create(path)?; let ref mut w = BufWriter::new(file); let mut encoder = png::Encoder::new(w, image.width as u32, image.height as u32); png::HasParameters::set(&mut encoder, png::ColorType::RGBA); png::HasParameters::set(&mut encoder, png::BitDepth::Eight); - let mut writer = try!(encoder.write_header()); - Ok(try!(writer.write_image_data(&image.bytes))) -} \ No newline at end of file + let mut writer = encoder.write_header()?; + Ok(writer.write_image_data(&image.bytes)?) +} diff --git a/src/error.rs b/src/error.rs index 5c4e7223..362072c2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -51,8 +51,12 @@ impl From for RasterError { impl From for RasterError { fn from(err: gif::DecodingError) -> RasterError { match err { - gif::DecodingError::Format(msg) => RasterError::Decode(ImageFormat::Gif, msg.to_string()), - gif::DecodingError::Internal(msg) => RasterError::Decode(ImageFormat::Gif, msg.to_string()), + gif::DecodingError::Format(msg) => { + RasterError::Decode(ImageFormat::Gif, msg.to_string()) + } + gif::DecodingError::Internal(msg) => { + RasterError::Decode(ImageFormat::Gif, msg.to_string()) + } gif::DecodingError::Io(io_err) => RasterError::Io(io_err), } } @@ -61,17 +65,30 @@ impl From for RasterError { // JPEG /// Convert gif::DecodingError to RasterError::Decode -// NOTE: We assume that we are in decoding jpeg since this error's entry point is only in raster::open +// NOTE: We assume that we are in decoding jpeg since this error's entry point is only in +// raster::open impl From for RasterError { fn from(err: piston_image::ImageError) -> RasterError { match err { - piston_image::ImageError::FormatError(msg) => RasterError::Decode(ImageFormat::Jpeg, msg), - piston_image::ImageError::DimensionError => RasterError::Decode(ImageFormat::Jpeg, "DimensionError".to_string()), - piston_image::ImageError::UnsupportedError(msg) => RasterError::Decode(ImageFormat::Jpeg,msg), - piston_image::ImageError::UnsupportedColor(_) => RasterError::Decode(ImageFormat::Jpeg, "UnsupportedColor".to_string()), - piston_image::ImageError::NotEnoughData => RasterError::Decode(ImageFormat::Jpeg, "NotEnoughData".to_string()), + piston_image::ImageError::FormatError(msg) => { + RasterError::Decode(ImageFormat::Jpeg, msg) + } + piston_image::ImageError::DimensionError => { + RasterError::Decode(ImageFormat::Jpeg, "DimensionError".to_string()) + } + piston_image::ImageError::UnsupportedError(msg) => { + RasterError::Decode(ImageFormat::Jpeg, msg) + } + piston_image::ImageError::UnsupportedColor(_) => { + RasterError::Decode(ImageFormat::Jpeg, "UnsupportedColor".to_string()) + } + piston_image::ImageError::NotEnoughData => { + RasterError::Decode(ImageFormat::Jpeg, "NotEnoughData".to_string()) + } piston_image::ImageError::IoError(io_err) => RasterError::Io(io_err), - piston_image::ImageError::ImageEnd => RasterError::Decode(ImageFormat::Jpeg, "ImageEnd".to_string()), + piston_image::ImageError::ImageEnd => { + RasterError::Decode(ImageFormat::Jpeg, "ImageEnd".to_string()) + } } } } @@ -82,11 +99,21 @@ impl From for RasterError { fn from(err: png::DecodingError) -> RasterError { match err { png::DecodingError::IoError(io_err) => RasterError::Io(io_err), - png::DecodingError::Format(_) => RasterError::Decode(ImageFormat::Png, "Format".to_string()), - png::DecodingError::InvalidSignature => RasterError::Decode(ImageFormat::Png, "InvalidSignature".to_string()), - png::DecodingError::CrcMismatch {..} => RasterError::Decode(ImageFormat::Png, "CrcMismatch".to_string()), - png::DecodingError::Other(_) => RasterError::Decode(ImageFormat::Png, "Other".to_string()), - png::DecodingError::CorruptFlateStream => RasterError::Decode(ImageFormat::Png, "CorruptFlateStream".to_string()), + png::DecodingError::Format(_) => { + RasterError::Decode(ImageFormat::Png, "Format".to_string()) + } + png::DecodingError::InvalidSignature => { + RasterError::Decode(ImageFormat::Png, "InvalidSignature".to_string()) + } + png::DecodingError::CrcMismatch { .. } => { + RasterError::Decode(ImageFormat::Png, "CrcMismatch".to_string()) + } + png::DecodingError::Other(_) => { + RasterError::Decode(ImageFormat::Png, "Other".to_string()) + } + png::DecodingError::CorruptFlateStream => { + RasterError::Decode(ImageFormat::Png, "CorruptFlateStream".to_string()) + } } } } @@ -96,10 +123,13 @@ impl From for RasterError { fn from(err: png::EncodingError) -> RasterError { match err { png::EncodingError::IoError(io_err) => RasterError::Io(io_err), - png::EncodingError::Format(_) => RasterError::Encode(ImageFormat::Png, "Format".to_string()), + png::EncodingError::Format(_) => { + RasterError::Encode(ImageFormat::Png, "Format".to_string()) + } } } } -/// [Type alias](https://doc.rust-lang.org/book/error-handling.html#the-result-type-alias-idiom) for Result. +/// [Type alias](https://doc.rust-lang.org/book/error-handling.html#the-result-type-alias-idiom) +/// for Result. pub type RasterResult = Result; diff --git a/src/filter.rs b/src/filter.rs index b8f8c4f8..5f80da99 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,12 +1,10 @@ //! A module for filtering pixels. - // from rust use std::cmp; // from external crate - // from local crate use error::{RasterError, RasterResult}; use Image; @@ -16,7 +14,7 @@ use Color; #[derive(Debug)] pub enum BlurMode { Box, - Gaussian + Gaussian, } /// An enum to specify orientation of a filter. @@ -27,7 +25,7 @@ pub enum Orientation { DiagonalUp, DiagonalDown, DiagonalBoth, - Both + Both, } /// Apply box or Gaussian blur. @@ -65,10 +63,10 @@ pub enum Orientation { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_gaussian_blur.jpg) /// -pub fn blur(mut src: &mut Image, mode: BlurMode) -> RasterResult<()> { +pub fn blur(src: &mut Image, mode: BlurMode) -> RasterResult<()> { match mode { BlurMode::Box => blur_box(src), - BlurMode::Gaussian => blur_gaussian(src) + BlurMode::Gaussian => blur_gaussian(src), } } @@ -91,7 +89,7 @@ pub fn blur(mut src: &mut Image, mode: BlurMode) -> RasterResult<()> { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_brightness.jpg) /// -pub fn brightness(mut src: &mut Image, factor: f32) -> RasterResult<()> { +pub fn brightness(src: &mut Image, factor: f32) -> RasterResult<()> { let w: i32 = src.width; let h: i32 = src.height; @@ -102,13 +100,14 @@ pub fn brightness(mut src: &mut Image, factor: f32) -> RasterResult<()> { for y in 0..h { for x in 0..w { - let p = try!(src.get_pixel(x, y)); + let p = src.get_pixel(x, y)?; let r = cmp::max(0, cmp::min(255, (p.r as f32 * factor) as i32)); let g = cmp::max(0, cmp::min(255, (p.g as f32 * factor) as i32)); let b = cmp::max(0, cmp::min(255, (p.b as f32 * factor) as i32)); - let a = cmp::max(0, cmp::min(255, (p.a as f32 * factor) as i32)); // TODO: Should alpha be included? + // TODO: Should alpha be included? + let a = cmp::max(0, cmp::min(255, (p.a as f32 * factor) as i32)); - try!(src.set_pixel(x, y, &Color::rgba(r as u8, g as u8, b as u8, a as u8))); + src.set_pixel(x, y, &Color::rgba(r as u8, g as u8, b as u8, a as u8))?; } } @@ -164,7 +163,7 @@ pub fn convolve(src: &mut Image, matrix: [[i32; 3]; 3], divisor: i32) -> RasterR src_x = w - 1; } - let pixel = try!(copy.get_pixel(src_x, src_y)); + let pixel = copy.get_pixel(src_x, src_y)?; accum_red += pixel.r as i32 * matrix[m_index_y][m_index_x]; accum_green += pixel.g as i32 * matrix[m_index_y][m_index_x]; accum_blue += pixel.b as i32 * matrix[m_index_y][m_index_x]; @@ -205,7 +204,16 @@ pub fn convolve(src: &mut Image, matrix: [[i32; 3]; 3], divisor: i32) -> RasterR accum_alpha = 255; } - try!(src.set_pixel(x, y, &Color::rgba(accum_red as u8, accum_green as u8, accum_blue as u8, accum_alpha as u8))); + src.set_pixel( + x, + y, + &Color::rgba( + accum_red as u8, + accum_green as u8, + accum_blue as u8, + accum_alpha as u8, + ), + )?; } } @@ -230,13 +238,8 @@ pub fn convolve(src: &mut Image, matrix: [[i32; 3]; 3], divisor: i32) -> RasterR /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_emboss.jpg) /// -pub fn emboss(mut src: &mut Image) -> RasterResult<()> { - let matrix: [[i32; 3]; 3] = [ - [-2, -1, 0], - [-1, 1, 1], - [0, 1, 2] - ]; - +pub fn emboss(src: &mut Image) -> RasterResult<()> { + let matrix: [[i32; 3]; 3] = [[-2, -1, 0], [-1, 1, 1], [0, 1, 2]]; convolve(src, matrix, 1) } @@ -258,34 +261,54 @@ pub fn emboss(mut src: &mut Image) -> RasterResult<()> { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_sobel_x.jpg) /// -pub fn sobel(mut src: &mut Image, mode: Orientation) -> RasterResult<()> { - try!(grayscale(src)); +pub fn sobel(src: &mut Image, mode: Orientation) -> RasterResult<()> { + grayscale(src)?; let matrix = match mode { Orientation::Horizontal => [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], Orientation::Vertical => [[-1, -2, -1], [0, 0, 0], [1, 2, 1]], Orientation::DiagonalUp => [[0, -1, -2], [1, 0, -1], [2, 1, 0]], Orientation::DiagonalDown => [[-2, -1, 0], [-1, 0, 1], [0, 1, 2]], - Orientation::Both => return sobel_both(src, [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], [[-1, -2, -1], [0, 0, 0], [1, 2, 1]]), - Orientation::DiagonalBoth => return sobel_both(src, [[0, -1, -2], [1, 0, -1], [2, 1, 0]], [[-2, -1, 0], [-1, 0, 1], [0, 1, 2]]), + Orientation::Both => { + return sobel_both( + src, + [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], + [[-1, -2, -1], [0, 0, 0], [1, 2, 1]], + ) + } + Orientation::DiagonalBoth => { + return sobel_both( + src, + [[0, -1, -2], [1, 0, -1], [2, 1, 0]], + [[-2, -1, 0], [-1, 0, 1], [0, 1, 2]], + ) + } }; convolve(src, matrix, 1) } -fn sobel_both(mut src: &mut Image, matrix_one: [[i32; 3]; 3], matrix_two: [[i32; 3]; 3]) -> RasterResult<()> { +fn sobel_both( + src: &mut Image, + matrix_one: [[i32; 3]; 3], + matrix_two: [[i32; 3]; 3], +) -> RasterResult<()> { let mut image_x = src.clone(); let mut image_y = src.clone(); - try!(convolve(&mut image_x, matrix_one, 1)); - try!(convolve(&mut image_y, matrix_two, 1)); + convolve(&mut image_x, matrix_one, 1)?; + convolve(&mut image_y, matrix_two, 1)?; let w: i32 = src.width; let h: i32 = src.height; for y in 0..h { for x in 0..w { - let pixel_x = try!(image_x.get_pixel(x, y)); - let pixel_y = try!(image_y.get_pixel(x, y)); - //Calculate the sum of the derivatives with sqrt((dImage/dx)²+(dImage/dy)²) + let pixel_x = image_x.get_pixel(x, y)?; + let pixel_y = image_y.get_pixel(x, y)?; + // Calculate the sum of the derivatives with sqrt((dImage/dx)²+(dImage/dy)²) let pixel = ((pixel_x.r as f64).powi(2) + (pixel_y.r as f64).powi(2)).sqrt(); - try!(src.set_pixel(x, y, &Color::rgba(pixel as u8, pixel as u8, pixel as u8, pixel_x.a as u8))); + src.set_pixel( + x, + y, + &Color::rgba(pixel as u8, pixel as u8, pixel as u8, pixel_x.a as u8), + )?; } } @@ -313,7 +336,7 @@ fn sobel_both(mut src: &mut Image, matrix_one: [[i32; 3]; 3], matrix_two: [[i32; /// ![](https://kosinix.github.io/raster/out/test_filter_gamma.jpg) /// // http://stackoverflow.com/questions/14088889/changing-a-color-brightness -pub fn gamma(mut src: &mut Image, gamma: f32) -> RasterResult<()> { +pub fn gamma(src: &mut Image, gamma: f32) -> RasterResult<()> { let w: i32 = src.width; let h: i32 = src.height; @@ -323,12 +346,12 @@ pub fn gamma(mut src: &mut Image, gamma: f32) -> RasterResult<()> { for y in 0..h { for x in 0..w { - let p = try!(src.get_pixel(x, y)); + let p = src.get_pixel(x, y)?; let r = (p.r as f32 / 255.0).powf(gamma) * 255.0; let g = (p.g as f32 / 255.0).powf(gamma) * 255.0; let b = (p.b as f32 / 255.0).powf(gamma) * 255.0; - try!(src.set_pixel(x, y, &Color::rgba(r as u8, g as u8, b as u8, p.a as u8))); + src.set_pixel(x, y, &Color::rgba(r as u8, g as u8, b as u8, p.a as u8))?; } } @@ -352,16 +375,20 @@ pub fn gamma(mut src: &mut Image, gamma: f32) -> RasterResult<()> { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_grayscale.jpg) /// -pub fn grayscale(mut src: &mut Image) -> RasterResult<()> { +pub fn grayscale(src: &mut Image) -> RasterResult<()> { let w: i32 = src.width; let h: i32 = src.height; for y in 0..h { for x in 0..w { - let p = try!(src.get_pixel(x, y)); + let p = src.get_pixel(x, y)?; let gray = (p.r as f32 * 0.3) + (p.g as f32 * 0.59) + (p.b as f32 * 0.11); - try!(src.set_pixel(x, y, &Color::rgba(gray as u8, gray as u8, gray as u8, gray as u8))); + src.set_pixel( + x, + y, + &Color::rgba(gray as u8, gray as u8, gray as u8, gray as u8), + )?; } } @@ -370,7 +397,8 @@ pub fn grayscale(mut src: &mut Image) -> RasterResult<()> { /// Change saturation. /// -/// Pass a float value for sat. < 0.0 to decrease and > 0.0 to increase. Eg 0.5 for 50% increase in saturation. +/// Pass a float value for sat. < 0.0 to decrease and > 0.0 to increase. Eg 0.5 for 50% increase +/// in saturation. /// /// Note: Saturation does not look good at the moment. /// @@ -390,13 +418,13 @@ pub fn grayscale(mut src: &mut Image) -> RasterResult<()> { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_saturation.jpg) /// -pub fn saturation(mut src: &mut Image, sat: f32) -> RasterResult<()> { +pub fn saturation(src: &mut Image, sat: f32) -> RasterResult<()> { let w: i32 = src.width; let h: i32 = src.height; for y in 0..h { for x in 0..w { - let p = try!(src.get_pixel(x, y)); + let p = src.get_pixel(x, y)?; let hsv = Color::to_hsv(p.r, p.g, p.b); let s = hsv.1; let factor = (100.0 - s) * sat; // use % remaining @@ -408,7 +436,7 @@ pub fn saturation(mut src: &mut Image, sat: f32) -> RasterResult<()> { } let rgb = Color::to_rgb(hsv.0, new_s, hsv.2); - try!(src.set_pixel(x, y, &Color::rgb(rgb.0, rgb.1, rgb.2))); + src.set_pixel(x, y, &Color::rgb(rgb.0, rgb.1, rgb.2))?; } } @@ -432,37 +460,21 @@ pub fn saturation(mut src: &mut Image, sat: f32) -> RasterResult<()> { /// ### After /// ![](https://kosinix.github.io/raster/out/test_filter_sharpen.jpg) /// -pub fn sharpen(mut src: &mut Image) -> RasterResult<()> { - let matrix: [[i32; 3]; 3] = [ - [0, -1, 0], - [-1, 5, -1], - [0, -1, 0] - ]; - +pub fn sharpen(src: &mut Image) -> RasterResult<()> { + let matrix: [[i32; 3]; 3] = [[0, -1, 0], [-1, 5, -1], [0, -1, 0]]; convolve(src, matrix, 1) } - // Private functions // Box -fn blur_box(mut src: &mut Image) -> RasterResult<()> { - let matrix: [[i32; 3]; 3] = [ - [1, 1, 1], - [1, 1, 1], - [1, 1, 1] - ]; - +fn blur_box(src: &mut Image) -> RasterResult<()> { + let matrix: [[i32; 3]; 3] = [[1, 1, 1], [1, 1, 1], [1, 1, 1]]; convolve(src, matrix, 9) } // Gaussian -fn blur_gaussian(mut src: &mut Image) -> RasterResult<()> { - let matrix: [[i32; 3]; 3] = [ - [1, 2, 1], - [2, 4, 2], - [1, 2, 1] - ]; - +fn blur_gaussian(src: &mut Image) -> RasterResult<()> { + let matrix: [[i32; 3]; 3] = [[1, 2, 1], [2, 4, 2], [1, 2, 1]]; convolve(src, matrix, 16) } diff --git a/src/image.rs b/src/image.rs index 675d1c9c..d886a865 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,12 +1,10 @@ //! A module for generic representation of image. - // from rust use std::collections::HashMap; // from external crate - // from local crate use error::{RasterError, RasterResult}; use color::Color; @@ -25,7 +23,6 @@ pub struct Image { } impl<'a> Image { - /// Create a blank image. Default color is black. /// /// # Examples @@ -40,8 +37,7 @@ impl<'a> Image { /// assert_eq!(image.width, 2); /// assert_eq!(image.height, 2); /// ``` - pub fn blank(w:i32, h:i32) -> Image { - + pub fn blank(w: i32, h: i32) -> Image { let mut bytes = Vec::with_capacity((w * h) as usize * 4); for _ in 0..h { for _ in 0..w { @@ -51,7 +47,7 @@ impl<'a> Image { Image { width: w, height: h, - bytes: bytes + bytes: bytes, } } @@ -67,8 +63,9 @@ impl<'a> Image { /// assert_eq!(image.check_pixel(0, 0), true); /// assert_eq!(image.check_pixel(3, 3), false); /// ``` - pub fn check_pixel(&self, x: i32, y:i32) -> bool { - if y < 0 || y > self.height { // TODO: check on actual vectors and not just width and height? + pub fn check_pixel(&self, x: i32, y: i32) -> bool { + if y < 0 || y > self.height { + // TODO: check on actual vectors and not just width and height? false } else { !(x < 0 || x > self.width) @@ -111,13 +108,10 @@ impl<'a> Image { /// let key = x as u8; /// match r_bin.get(&key) { /// Some(count) => { - /// /// let height = (canvas_h as f32 * (*count as f32 / max_r_bin as f32)).round() as i32; /// /// for y in canvas_h-height..canvas_h { - /// /// image.set_pixel(x, y, &Color::hex("#e22d11").unwrap()).unwrap(); - /// /// } /// }, /// None => {} @@ -145,9 +139,11 @@ impl<'a> Image { let mut a_bin: HashMap = HashMap::new(); for y in 0..h { for x in 0..w { - let pixel = try!(self.get_pixel(x, y)); + let pixel = self.get_pixel(x, y)?; - let r_bin_c = r_bin.entry(pixel.r).or_insert(0); // Insert the key with a value of 0 if key does not exist yet. Then return the count (which is zero). + // Insert the key with a value of 0 if key does not exist yet. Then return the + // count (which is zero). + let r_bin_c = r_bin.entry(pixel.r).or_insert(0); *r_bin_c += 1; // +1 to the count. let g_bin_c = g_bin.entry(pixel.g).or_insert(0); @@ -158,7 +154,6 @@ impl<'a> Image { let a_bin_c = a_bin.entry(pixel.a).or_insert(0); *a_bin_c += 1; - } } @@ -187,7 +182,7 @@ impl<'a> Image { /// assert_eq!(0, pixel.b); /// assert_eq!(255, pixel.a); /// ``` - pub fn get_pixel(&self, x: i32, y:i32) -> RasterResult { + pub fn get_pixel(&self, x: i32, y: i32) -> RasterResult { let rgba = 4; let start = (y * self.width) + x; let start = start * rgba; @@ -234,7 +229,7 @@ impl<'a> Image { /// assert_eq!(0, pixel.b); /// assert_eq!(255, pixel.a); /// ``` - pub fn set_pixel(&mut self, x: i32, y:i32, color: &Color ) -> RasterResult<()> { + pub fn set_pixel(&mut self, x: i32, y: i32, color: &Color) -> RasterResult<()> { let rgba = 4; // length let start = (y * &self.width) + x; let start = start * rgba; @@ -255,7 +250,12 @@ impl<'a> Image { } /// Holds histogram information. -pub type Histogram = (HashMap, HashMap, HashMap, HashMap); +pub type Histogram = ( + HashMap, + HashMap, + HashMap, + HashMap, +); /// Enumeration of supported raster formats. #[derive(Debug)] diff --git a/src/interpolate.rs b/src/interpolate.rs index 1d2ec9a5..504738b4 100644 --- a/src/interpolate.rs +++ b/src/interpolate.rs @@ -5,7 +5,6 @@ use std::cmp; // from external crate - // from local crate use error::RasterResult; use Image; @@ -16,33 +15,36 @@ use Color; pub enum InterpolationMode { Bilinear, Bicubic, - Nearest + Nearest, } /// Resample an image into a new size using a given interpolation method. -pub fn resample(mut src: &mut Image, w: i32, h: i32, interpolation: InterpolationMode) -> RasterResult<()> { +pub fn resample( + src: &mut Image, + w: i32, + h: i32, + interpolation: InterpolationMode, +) -> RasterResult<()> { match interpolation { InterpolationMode::Bilinear => bilinear(src, w, h), InterpolationMode::Bicubic => bilinear(src, w, h), // TODO: bicubic - InterpolationMode::Nearest => nearest(src, w, h) + InterpolationMode::Nearest => nearest(src, w, h), } } /// Interpolate using nearest neighbor. -pub fn nearest(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { - +pub fn nearest(src: &mut Image, w: i32, h: i32) -> RasterResult<()> { let x_ratio: f64 = src.width as f64 / w as f64; let y_ratio: f64 = src.height as f64 / h as f64; let mut dest = Image::blank(w, h); for y in 0..h { for x in 0..w { + let px: i32 = (x as f64 * x_ratio).floor() as i32; + let py: i32 = (y as f64 * y_ratio).floor() as i32; + let pixel = src.get_pixel(px, py)?; - let px: i32 = ( x as f64 * x_ratio ).floor() as i32; - let py: i32 = ( y as f64 * y_ratio ).floor() as i32; - let pixel = try!(src.get_pixel(px, py)); - - try!(dest.set_pixel(x, y, &pixel)); + dest.set_pixel(x, y, &pixel)?; } } src.width = dest.width; @@ -53,16 +55,14 @@ pub fn nearest(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { } /// Interpolate using linear function. -pub fn bilinear(mut src: &mut Image, w2: i32, h2: i32) -> RasterResult<()> { - bilinear_width(src, w2) - .and_then(|_| bilinear_height(src, h2)) +pub fn bilinear(src: &mut Image, w2: i32, h2: i32) -> RasterResult<()> { + bilinear_width(src, w2).and_then(|_| bilinear_height(src, h2)) } // Private functions /// Interpolate the width using linear function. -fn bilinear_width(mut src: &mut Image, w2: i32) -> RasterResult<()> { - +fn bilinear_width(src: &mut Image, w2: i32) -> RasterResult<()> { let w1 = src.width; let h1 = src.height; @@ -77,7 +77,6 @@ fn bilinear_width(mut src: &mut Image, w2: i32) -> RasterResult<()> { for y in 0..h1 { for x in x_start..x_end { - let src_x = { let src_x = x as f64 * x_ratio; if src_x < 0.0 { @@ -89,13 +88,13 @@ fn bilinear_width(mut src: &mut Image, w2: i32) -> RasterResult<()> { let src_x_int = (src_x).floor() as i32; - let src_x_int2 = cmp::min(src_x_int + 1, w1-1); // limit range within $w1-1 + let src_x_int2 = cmp::min(src_x_int + 1, w1 - 1); // limit range within $w1-1 // limit range from 0 - 1 let t_x = src_x - src_x_int as f64; - let src_color1 = try!(src.get_pixel(src_x_int, y)); - let src_color2 = try!(src.get_pixel(src_x_int2, y)); + let src_color1 = src.get_pixel(src_x_int, y)?; + let src_color2 = src.get_pixel(src_x_int2, y)?; // red let red = _lerp(src_color1.r, src_color2.r, t_x); @@ -109,8 +108,7 @@ fn bilinear_width(mut src: &mut Image, w2: i32) -> RasterResult<()> { // alpha let alpha = _lerp(src_color1.a, src_color2.a, t_x); - try!(dest.set_pixel(x+offset_x, y, &Color::rgba(red, green, blue, alpha))); - + dest.set_pixel(x + offset_x, y, &Color::rgba(red, green, blue, alpha))?; } } src.width = dest.width; @@ -121,8 +119,7 @@ fn bilinear_width(mut src: &mut Image, w2: i32) -> RasterResult<()> { } /// Interpolate the height using linear function. -fn bilinear_height(mut src: &mut Image, h2: i32) -> RasterResult<()> { - +fn bilinear_height(src: &mut Image, h2: i32) -> RasterResult<()> { let w1 = src.width; let h1 = src.height; @@ -137,7 +134,6 @@ fn bilinear_height(mut src: &mut Image, h2: i32) -> RasterResult<()> { for x in 0..w1 { for y in y_start..y_end { - let src_y = { let src_y = y as f64 * y_ratio; if src_y < 0.0 { @@ -149,13 +145,13 @@ fn bilinear_height(mut src: &mut Image, h2: i32) -> RasterResult<()> { let src_y_int = (src_y).floor() as i32; - let src_y_int2 = cmp::min(src_y_int + 1, h1-1); // limit range within $h1-1 + let src_y_int2 = cmp::min(src_y_int + 1, h1 - 1); // limit range within $h1-1 // limit range from 0 - 1 let t_y = src_y - src_y_int as f64; - let src_color1 = try!(src.get_pixel(x, src_y_int)); - let src_color2 = try!(src.get_pixel(x, src_y_int2)); + let src_color1 = src.get_pixel(x, src_y_int)?; + let src_color2 = src.get_pixel(x, src_y_int2)?; // red let red = _lerp(src_color1.r, src_color2.r, t_y); @@ -169,8 +165,7 @@ fn bilinear_height(mut src: &mut Image, h2: i32) -> RasterResult<()> { // alpha let alpha = _lerp(src_color1.a, src_color2.a, t_y); - try!(dest.set_pixel(x, y+offset_y, &Color::rgba(red, green, blue, alpha))); - + dest.set_pixel(x, y + offset_y, &Color::rgba(red, green, blue, alpha))?; } } src.width = dest.width; @@ -181,20 +176,16 @@ fn bilinear_height(mut src: &mut Image, h2: i32) -> RasterResult<()> { } // Simple linear function -fn _lerp(a:u8, b:u8, t:f64) -> u8{ - +fn _lerp(a: u8, b: u8, t: f64) -> u8 { let a = a as f64; let b = b as f64; (a + (t * (b - a))) as u8 - } // Linear function using difference fn _bilinear(a: u8, b: u8, c: u8, d: u8, x_diff: f64, y_diff: f64) -> u8 { // Y = A(1-w)(1-h) + B(w)(1-h) + C(h)(1-w) + Dwh - ( - a as f64 * (1.0 - x_diff) * (1.0 - y_diff) + b as f64 * (x_diff) * (1.0 - y_diff) + - c as f64 * (y_diff) * (1.0 - x_diff) + d as f64 * (x_diff * y_diff) - ) as u8 + (a as f64 * (1.0 - x_diff) * (1.0 - y_diff) + b as f64 * (x_diff) * (1.0 - y_diff) + + c as f64 * (y_diff) * (1.0 - x_diff) + d as f64 * (x_diff * y_diff)) as u8 } diff --git a/src/lib.rs b/src/lib.rs index 87c3887b..f56775cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,8 @@ //! //! raster = "x.x.x" //! ``` -//! Where x are version numbers of the [latest version](https://crates.io/crates/raster) of raster. Eg.: 0.1.0 +//! Where x are version numbers of the [latest version](https://crates.io/crates/raster) of +//! raster. Eg.: 0.1.0 //! //! Then add the raster crate in your main.rs: //! @@ -72,7 +73,8 @@ //! //! ## Rotating Images //! -//! Images can be rotated both clockwise and counter-clockwise at any arbitrary angle with a custom background color. +//! Images can be rotated both clockwise and counter-clockwise at any arbitrary angle with a +//! custom background color. //! //! ![](https://kosinix.github.io/raster/out/test_transform_rotate_45.png) //! ![](https://kosinix.github.io/raster/out/test_transform_rotate_45cc.png) @@ -124,12 +126,12 @@ pub use interpolate::InterpolationMode; pub use position::PositionMode; pub use transform::TransformMode; - /// Create an image from an image file. /// /// # Errors /// -/// This function can return `RasterError::Io`, `RasterError::Decode`, or `RasterError::UnsupportedFormat` upon failure. +/// This function can return `RasterError::Io`, `RasterError::Decode`, or +/// `RasterError::UnsupportedFormat` upon failure. /// See error module for more info. /// /// # Examples @@ -140,20 +142,18 @@ pub use transform::TransformMode; /// println!("{:?}", image.bytes); /// ``` pub fn open(image_file: &str) -> RasterResult { - let path = Path::new(image_file); - let ext = path.extension().and_then(|s| s.to_str()) - .map_or("".to_string(), |s| s.to_ascii_lowercase()); + let ext = path.extension() + .and_then(|s| s.to_str()) + .map_or("".to_string(), |s| s.to_ascii_lowercase()); // Open the file with basic error check - let file = try!(File::open(image_file)); + let file = File::open(image_file)?; match &ext[..] { - "gif" => { - Ok(try!(endec::decode_gif(&file))) - }, + "gif" => Ok(endec::decode_gif(&file)?), "jpg" | "jpeg" => { - let src = try!(piston_image::open(image_file)); + let src = piston_image::open(image_file)?; let (w, h) = src.dimensions(); let mut bytes = Vec::with_capacity((w * h) as usize * 4); for y in 0..h { @@ -162,26 +162,24 @@ pub fn open(image_file: &str) -> RasterResult { bytes.extend_from_slice(&p.data[0..4]); } } - Ok(Image{ + Ok(Image { width: w as i32, height: h as i32, - bytes: bytes + bytes: bytes, }) - }, - "png" => { - Ok(try!(endec::decode_png(&file))) - }, - _ => { - Err(RasterError::UnsupportedFormat(ext)) } - } + "png" => Ok(endec::decode_png(&file)?), + _ => Err(RasterError::UnsupportedFormat(ext)), + } } -/// Save an image to an image file. The image type is detected from the file extension of the file name. +/// Save an image to an image file. The image type is detected from the file extension of the file +/// name. /// /// # Errors /// -/// This function can return `RasterError::Io`, `RasterError::Encode`, or `RasterError::UnsupportedFormat` upon failure. +/// This function can return `RasterError::Io`, `RasterError::Encode`, or +/// `RasterError::UnsupportedFormat` upon failure. /// See error module for more info. /// /// # Examples @@ -192,29 +190,23 @@ pub fn open(image_file: &str) -> RasterResult { /// raster::save(&image, "tests/out/test.png").unwrap(); /// ``` pub fn save(image: &Image, out: &str) -> RasterResult<()> { - let path = Path::new(out); - let ext = path.extension().and_then(|s| s.to_str()) - .map_or("".to_string(), |s| s.to_ascii_lowercase()); + let ext = path.extension() + .and_then(|s| s.to_str()) + .map_or("".to_string(), |s| s.to_ascii_lowercase()); match &ext[..] { - "gif" => { - Ok(try!(endec::encode_gif(&image, &path))) - }, + "gif" => Ok(endec::encode_gif(&image, &path)?), "jpg" | "jpeg" => { piston_image::save_buffer( &path, &image.bytes, image.width as u32, image.height as u32, - piston_image::RGBA(8) + piston_image::RGBA(8), ).map_err(|_| RasterError::Encode(ImageFormat::Jpeg, "Format".to_string())) - }, - "png" => { - Ok(try!(endec::encode_png(&image, &path))) - }, - _ => { - Err(RasterError::UnsupportedFormat(ext)) } - } -} \ No newline at end of file + "png" => Ok(endec::encode_png(&image, &path)?), + _ => Err(RasterError::UnsupportedFormat(ext)), + } +} diff --git a/src/position.rs b/src/position.rs index 84a99e06..fd37c4e3 100644 --- a/src/position.rs +++ b/src/position.rs @@ -2,10 +2,8 @@ // from rust - // from external crate - // from local crate use error::RasterResult; @@ -20,14 +18,14 @@ pub enum PositionMode { CenterRight, BottomLeft, BottomCenter, - BottomRight + BottomRight, } /// Struct for computing position on an image. pub struct Position { position: PositionMode, offset_x: i32, - offset_y: i32 + offset_y: i32, } impl Position { @@ -35,13 +33,19 @@ impl Position { Position { position: position, offset_x: offset_x, - offset_y: offset_y + offset_y: offset_y, } } /// Get X and Y position based on parameters. // Will this ever fail? - pub fn get_x_y(&self, canvas_width: i32, canvas_height: i32, image_width:i32, image_height:i32) -> RasterResult<(i32, i32)> { + pub fn get_x_y( + &self, + canvas_width: i32, + canvas_height: i32, + image_width: i32, + image_height: i32, + ) -> RasterResult<(i32, i32)> { let offset_x = self.offset_x; let offset_y = self.offset_y; @@ -50,34 +54,34 @@ impl Position { PositionMode::TopCenter => { let x = ((canvas_width / 2) - (image_width / 2)) + offset_x; (x, offset_y) - }, + } PositionMode::TopRight => { let x = (canvas_width - image_width) + offset_x; (x, offset_y) - }, + } PositionMode::CenterLeft => { let y = ((canvas_height / 2) - (image_height / 2)) + offset_x; (offset_x, y) - }, + } PositionMode::Center => { let x = ((canvas_width / 2) - (image_width / 2)) + offset_x; let y = ((canvas_height / 2) - (image_height / 2)) + offset_y; (x, y) - }, + } PositionMode::CenterRight => { let x = (canvas_width - image_width) + offset_x; let y = ((canvas_height / 2) - (image_height / 2)) + offset_y; (x, y) - }, + } PositionMode::BottomLeft => { let y = (canvas_height - image_height) + offset_y; (offset_x, y) - }, + } PositionMode::BottomCenter => { let x = ((canvas_width / 2) - (image_width / 2)) + offset_x; let y = (canvas_height - image_height) + offset_y; (x, y) - }, + } PositionMode::BottomRight => { let x = (canvas_width - image_width) + offset_y; let y = (canvas_height - image_height) + offset_y; diff --git a/src/transform.rs b/src/transform.rs index 62ca08b3..b68ac5c6 100644 --- a/src/transform.rs +++ b/src/transform.rs @@ -1,12 +1,10 @@ //! A module for 2D transformation. - // from rust use std::cmp; // from external crate - // from local crate use error::RasterResult; use Image; @@ -21,7 +19,7 @@ pub enum TransformMode { /// Transform on x axis. Horizontal, /// Transform on y axis. - Vertical + Vertical, } /// Flip an image on its x or y axis. @@ -56,8 +54,7 @@ pub enum TransformMode { /// /// ![](https://kosinix.github.io/raster/out/test_transform_flip_y.png) /// -pub fn flip(mut src: &mut Image, mode: TransformMode ) -> RasterResult<()> { - +pub fn flip(src: &mut Image, mode: TransformMode) -> RasterResult<()> { let w: i32 = src.width; let h: i32 = src.height; @@ -70,18 +67,16 @@ pub fn flip(mut src: &mut Image, mode: TransformMode ) -> RasterResult<()> { break; } for y in 0..h { + let pixel_left = src.get_pixel(src_x, y)?; + let pixel_right = src.get_pixel(dest_x, y)?; - let pixel_left = try!(src.get_pixel(src_x, y)); - let pixel_right = try!(src.get_pixel(dest_x, y)); - - try!(src.set_pixel(dest_x, y, &pixel_left)); - try!(src.set_pixel(src_x, y, &pixel_right)); - + src.set_pixel(dest_x, y, &pixel_left)?; + src.set_pixel(src_x, y, &pixel_right)?; } } Ok(()) - }, + } TransformMode::Vertical => { for y in 0..h { let src_y = y; @@ -90,25 +85,25 @@ pub fn flip(mut src: &mut Image, mode: TransformMode ) -> RasterResult<()> { break; } for x in 0..w { + let pixel_top = src.get_pixel(x, src_y)?; + let pixel_bottom = src.get_pixel(x, dest_y)?; - let pixel_top = try!(src.get_pixel(x, src_y)); - let pixel_bottom = try!(src.get_pixel(x, dest_y)); - - try!(src.set_pixel(x, dest_y, &pixel_top)); - try!(src.set_pixel(x, src_y, &pixel_bottom)); - + src.set_pixel(x, dest_y, &pixel_top)?; + src.set_pixel(x, src_y, &pixel_bottom)?; } } Ok(()) } } - } -/// Rotate an image clockwise. Negate the degrees to do a counter-clockwise rotation. Background color can be any color. +/// Rotate an image clockwise. Negate the degrees to do a counter-clockwise rotation. Background +/// color can be any color. /// -/// Note: If you look closely, the quality for arbitrary angles is not very good due to the simple sampling algorithm. The 90, 180, and 270 angles looks fine because no pixels are lost. This will be fixed in the future with a better sampling algorithm. +/// Note: If you look closely, the quality for arbitrary angles is not very good due to the simple +/// sampling algorithm. The 90, 180, and 270 angles looks fine because no pixels are lost. This +/// will be fixed in the future with a better sampling algorithm. /// /// # Examples /// @@ -141,8 +136,7 @@ pub fn flip(mut src: &mut Image, mode: TransformMode ) -> RasterResult<()> { /// /// ![](https://kosinix.github.io/raster/out/test_transform_rotate_45cc.png) /// -pub fn rotate(mut src: &mut Image, degree: i32, bg: Color) -> RasterResult<()>{ - +pub fn rotate(src: &mut Image, degree: i32, bg: Color) -> RasterResult<()> { let w1 = src.width; let h1 = src.height; @@ -181,13 +175,13 @@ pub fn rotate(mut src: &mut Image, degree: i32, bg: Color) -> RasterResult<()>{ for (dest_y, y) in (0..).zip(min_y..max_y + 1) { for (dest_x, x) in (0..).zip(min_x..max_x + 1) { - let point: (i32, i32) = _rotate((x,y), -degree); + let point: (i32, i32) = _rotate((x, y), -degree); - if point.0 >= 0 && point.0 < w1 && point.1 >=0 && point.1 < h1 { - let pixel = try!(src.get_pixel(point.0, point.1)); - try!(dest.set_pixel(dest_x, dest_y, &pixel)); + if point.0 >= 0 && point.0 < w1 && point.1 >= 0 && point.1 < h1 { + let pixel = src.get_pixel(point.0, point.1)?; + dest.set_pixel(dest_x, dest_y, &pixel)?; } else { - try!(dest.set_pixel(dest_x, dest_y, &Color::rgba(bg.r, bg.g, bg.b, bg.a))); + dest.set_pixel(dest_x, dest_y, &Color::rgba(bg.r, bg.g, bg.b, bg.a))?; } } } @@ -201,14 +195,13 @@ pub fn rotate(mut src: &mut Image, degree: i32, bg: Color) -> RasterResult<()>{ /// Resize image to exact dimensions ignoring aspect ratio. /// Useful if you want to force exact width and height. -pub fn resize_exact(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { +pub fn resize_exact(src: &mut Image, w: i32, h: i32) -> RasterResult<()> { resample(src, w, h, InterpolationMode::Bicubic) } /// Resize image to exact height. Width is auto calculated. /// Useful for creating row of images with the same height. -pub fn resize_exact_height(mut src: &mut Image, h: i32) -> RasterResult<()> { - +pub fn resize_exact_height(src: &mut Image, h: i32) -> RasterResult<()> { let width = src.width; let height = src.height; let ratio = width as f32 / height as f32; @@ -221,52 +214,57 @@ pub fn resize_exact_height(mut src: &mut Image, h: i32) -> RasterResult<()> { /// Resize image to exact width. Height is auto calculated. /// Useful for creating column of images with the same width. -pub fn resize_exact_width(mut src: &mut Image, w: i32) -> RasterResult<()> { - let width = src.width; +pub fn resize_exact_width(src: &mut Image, w: i32) -> RasterResult<()> { + let width = src.width; let height = src.height; - let ratio = width as f32 / height as f32; + let ratio = width as f32 / height as f32; - let resize_width = w; + let resize_width = w; let resize_height = (w as f32 / ratio).round() as i32; resample(src, resize_width, resize_height, InterpolationMode::Bicubic) } /// Resize image to fill all the space in the given dimension. Excess parts are removed. -pub fn resize_fill(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { - let width = src.width; +pub fn resize_fill(src: &mut Image, w: i32, h: i32) -> RasterResult<()> { + let width = src.width; let height = src.height; - let ratio = width as f32 / height as f32; + let ratio = width as f32 / height as f32; // Base optimum size on new width - let mut optimum_width = w; + let mut optimum_width = w; let mut optimum_height = (w as f32 / ratio).round() as i32; - if (optimum_width < w) || (optimum_height < h) { // Oops, where trying to fill and there are blank areas + if (optimum_width < w) || (optimum_height < h) { + // Oops, where trying to fill and there are blank areas // So base optimum size on height instead - optimum_width = (h as f32 * ratio) as i32; + optimum_width = (h as f32 * ratio) as i32; optimum_height = h; } - resample(src, optimum_width, optimum_height, InterpolationMode::Bicubic) - .and_then(|_| crop(src, w, h, PositionMode::Center, 0, 0)) // Trim excess parts + resample( + src, + optimum_width, + optimum_height, + InterpolationMode::Bicubic, + ).and_then(|_| crop(src, w, h, PositionMode::Center, 0, 0)) // Trim excess parts } /// Resize an image to fit within the given width and height. /// The re-sized image will not exceed the given dimension. /// Preserves the aspect ratio. -pub fn resize_fit(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { - +pub fn resize_fit(src: &mut Image, w: i32, h: i32) -> RasterResult<()> { let ratio: f64 = src.width as f64 / src.height as f64; // Try basing it on width first - let mut resize_width = w; + let mut resize_width = w; let mut resize_height = (w as f64 / ratio).round() as i32; - if (resize_width > w) || (resize_height > h) { // Oops, either width or height does not fit + if (resize_width > w) || (resize_height > h) { + // Oops, either width or height does not fit // So base on height instead resize_height = h; - resize_width = (h as f64 * ratio).round() as i32; + resize_width = (h as f64 * ratio).round() as i32; } resample(src, resize_width, resize_height, InterpolationMode::Bicubic) @@ -276,7 +274,7 @@ pub fn resize_fit(mut src: &mut Image, w: i32, h: i32) -> RasterResult<()> { // Rotate a point clockwise to a given degree. fn _rotate(p: (i32, i32), deg: f32) -> (i32, i32) { - let radians:f32 = deg.to_radians(); + let radians: f32 = deg.to_radians(); let px: f32 = p.0 as f32; let py: f32 = p.1 as f32; let cos = radians.cos(); diff --git a/tests/color_tests.rs b/tests/color_tests.rs index a7231c88..d3a11711 100644 --- a/tests/color_tests.rs +++ b/tests/color_tests.rs @@ -3,18 +3,16 @@ extern crate raster; use raster::Color; #[test] -fn hsb_test(){ +fn hsb_test() { + let hsv = Color::to_hsv(50, 50, 100); - let hsv = Color::to_hsv(50,50,100); - assert_eq!(240, hsv.0); assert_eq!(50, (hsv.1).round() as i32); // round and cast to integer because float - assert_eq!(39, (hsv.2).round() as i32); // round and cast to integer because float + assert_eq!(39, (hsv.2).round() as i32); } #[test] -fn conversion_accuracy_test(){ - +fn conversion_accuracy_test() { let rgb1 = (127, 70, 60); let hsv = Color::to_hsv(rgb1.0, rgb1.1, rgb1.2); let rgb2 = Color::to_rgb(hsv.0, hsv.1, hsv.2); @@ -39,7 +37,7 @@ fn hex_test() { let color = Color::hex("#"); assert!(color.is_err()); - + let color = Color::hex("#FFF"); assert!(color.is_err()); -} \ No newline at end of file +} diff --git a/tests/filter_tests.rs b/tests/filter_tests.rs index df5f65a2..fe8ee58b 100644 --- a/tests/filter_tests.rs +++ b/tests/filter_tests.rs @@ -3,8 +3,7 @@ extern crate raster; use raster::{filter, Orientation}; #[test] -fn brightness_test(){ - +fn brightness_test() { let mut image = raster::open("tests/in/sample.jpg").unwrap(); filter::brightness(&mut image, 1.5).unwrap(); raster::save(&image, "tests/out/test_filter_brightness.jpg").unwrap(); @@ -43,4 +42,4 @@ fn sobel_d2_test() { let mut image = raster::open("tests/in/sample.jpg").unwrap(); filter::sobel(&mut image, Orientation::DiagonalDown).unwrap(); raster::save(&image, "tests/out/test_filter_sobel_d2.jpg").unwrap(); -} \ No newline at end of file +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index d5bcd86a..a6ca4eef 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -5,4 +5,4 @@ fn prepare_test() { let _ = std::fs::create_dir_all("./tests/out"); // Make sure test out dir is present. This might be a symptom that we need better error handling in editor::save } -// TODO: test open and save \ No newline at end of file +// TODO: test open and save diff --git a/tests/io_tests.rs b/tests/io_tests.rs index a6bce6a4..3ef10a49 100644 --- a/tests/io_tests.rs +++ b/tests/io_tests.rs @@ -1,41 +1,34 @@ extern crate raster; #[test] -fn open_fail(){ - - assert!( - { - if let Err(_) = raster::open(""){ - true - } else { - false - } +fn open_fail() { + assert!({ + if let Err(_) = raster::open("") { + true + } else { + false } - ); + }); } #[test] -fn unsupported_format(){ - +fn unsupported_format() { let fail = { - match raster::open("tests/in/unsupported.txt"){ + match raster::open("tests/in/unsupported.txt") { Ok(_) => false, - Err(e) => { - match e { - raster::error::RasterError::UnsupportedFormat(_) => true, - _ => false, - } - } + Err(e) => match e { + raster::error::RasterError::UnsupportedFormat(_) => true, + _ => false, + }, } }; assert!(fail); } #[test] -fn read_gif_format(){ - +fn read_gif_format() { let ok = { - if let Ok(_) = raster::open("tests/in/sample.gif"){ + if let Ok(_) = raster::open("tests/in/sample.gif") { true } else { false @@ -45,10 +38,9 @@ fn read_gif_format(){ } #[test] -fn read_jpg_format(){ - +fn read_jpg_format() { let ok = { - if let Ok(_) = raster::open("tests/in/sample.jpg"){ + if let Ok(_) = raster::open("tests/in/sample.jpg") { true } else { false @@ -58,10 +50,9 @@ fn read_jpg_format(){ } #[test] -fn read_png_format(){ - +fn read_png_format() { let ok = { - if let Ok(_) = raster::open("tests/in/sample.png"){ + if let Ok(_) = raster::open("tests/in/sample.png") { true } else { false @@ -71,76 +62,64 @@ fn read_png_format(){ } #[test] -fn read_gif_format_fail(){ - - assert!( - { - if let Err(e) = raster::open("tests/in/not-a-gif.gif"){ - if let raster::error::RasterError::Decode(format, _) = e { - assert!( - { - if let raster::ImageFormat::Gif = format { // Should be gif - true - } else { - false - } - } - ); - } - true - } else { - false +fn read_gif_format_fail() { + assert!({ + if let Err(e) = raster::open("tests/in/not-a-gif.gif") { + if let raster::error::RasterError::Decode(format, _) = e { + assert!({ + if let raster::ImageFormat::Gif = format { + // Should be gif + true + } else { + false + } + }); } + true + } else { + false } - ); + }); } #[test] -fn read_jpeg_format_fail(){ - - assert!( - { - if let Err(e) = raster::open("tests/in/not-a-jpeg.jpg"){ - if let raster::error::RasterError::Decode(format, _) = e { - assert!( - { - if let raster::ImageFormat::Jpeg = format { // Should be jpg - true - } else { - false - } - } - ); - } - true - } else { - false +fn read_jpeg_format_fail() { + assert!({ + if let Err(e) = raster::open("tests/in/not-a-jpeg.jpg") { + if let raster::error::RasterError::Decode(format, _) = e { + assert!({ + if let raster::ImageFormat::Jpeg = format { + // Should be jpg + true + } else { + false + } + }); } + true + } else { + false } - ); + }); } #[test] -fn read_png_format_fail(){ - - assert!( - { - if let Err(e) = raster::open("tests/in/not-a-png.png"){ - if let raster::error::RasterError::Decode(format, _) = e { - assert!( - { - if let raster::ImageFormat::Png = format { // Should be png - true - } else { - false - } - } - ); - } - true - } else { - false +fn read_png_format_fail() { + assert!({ + if let Err(e) = raster::open("tests/in/not-a-png.png") { + if let raster::error::RasterError::Decode(format, _) = e { + assert!({ + if let raster::ImageFormat::Png = format { + // Should be png + true + } else { + false + } + }); } + true + } else { + false } - ); -} \ No newline at end of file + }); +}