raster/
lib.rs

1//! # Raster
2//!
3//! Raster is an image processing lib for Rust.
4//!
5//! It provides a simplified API for processing raster images (JPEG, PNG and GIF).
6//!
7//! ## Installation
8//! Add this to your Cargo.toml file:
9//!
10//! ```rust,ignore
11//! [dependencies]
12//!
13//! raster = "x.x.x"
14//! ```
15//! Where x are version numbers of the [latest version](https://crates.io/crates/raster) of raster. Eg.: 0.1.0
16//!
17//! Then add the raster crate in your main.rs:
18//!
19//! ```rust,ignore
20//! extern crate raster; // In your main rust file
21//! ```
22//!
23//! ## Creating Images
24//! ### From an image file
25//!
26//! ```rust,ignore
27//! // Create an image from file
28//! let image = raster::open("tests/in/sample.png").unwrap();
29//!
30//! ```
31//! Raster will detect the image format based on the file name.
32//!
33//! ### Create a blank image
34//! ```rust,ignore
35//! use raster::Image; // Include the Image struct
36//!
37//! // Create a blank 150x100 image. Defaults to a black background.
38//! let image = Image::blank(150, 100);
39//!
40//! ```
41//!
42//! ## Saving Images
43//! Save the opened image file:
44//!
45//! ```
46//! // Create an image from file
47//! let image = raster::open("tests/in/sample.png").unwrap();
48//!
49//! // Save opened image
50//! raster::save(&image, "tests/out/test_open_save.png").unwrap();
51//!
52//! ```
53//!
54//!
55//!
56//!
57//! ## Blending 2 Images
58//!
59//! Here are two images blended using the normal mode.
60//!
61//! ![](https://kosinix.github.io/raster/out/test_blend_normal.png)
62//!
63//! More blending modes and options are available, see the blend API.
64//!
65//! ## Resizing Images
66//!
67//! An example of images resized to "fit" in a 200x200 box.
68//!
69//! ![](https://kosinix.github.io/raster/out/test_resize_fit_1.jpg) ![](https://kosinix.github.io/raster/out/test_resize_fit_2.jpg)
70//!
71//! More modes available, see the resize API.
72//!
73//! ## Rotating Images
74//!
75//! Images can be rotated both clockwise and counter-clockwise at any arbitrary angle with a custom background color.
76//!
77//! ![](https://kosinix.github.io/raster/out/test_transform_rotate_45.png)
78//! ![](https://kosinix.github.io/raster/out/test_transform_rotate_45cc.png)
79//!
80//! ## And Many More...
81//!
82//! More options are available, checkout the modules below.
83//!
84
85// modules
86pub mod compare;
87pub mod editor;
88pub mod error;
89pub mod filter;
90pub mod interpolate;
91pub mod transform;
92mod blend;
93mod color;
94mod endec;
95mod image;
96mod position;
97
98// crates
99extern crate gif;
100extern crate image as piston_image;
101extern crate png;
102
103// from rust
104use std::ascii::AsciiExt;
105use std::fs::File;
106use std::path::Path;
107
108// from external crate
109use piston_image::GenericImage;
110
111// from local crate
112use error::{RasterError, RasterResult};
113
114// re-exports
115pub use blend::BlendMode;
116pub use color::Color;
117pub use editor::ResizeMode;
118pub use filter::BlurMode;
119pub use image::Histogram;
120pub use image::Image;
121pub use image::ImageFormat;
122pub use interpolate::InterpolationMode;
123pub use position::PositionMode;
124pub use transform::TransformMode;
125
126
127/// Create an image from an image file.
128///
129/// # Errors
130///
131/// This function can return `RasterError::Io`, `RasterError::Decode`, or `RasterError::UnsupportedFormat` upon failure. 
132/// See error module for more info.
133///
134/// # Examples
135///
136/// ```
137/// // Create an image from file
138/// let image = raster::open("tests/in/sample.png").unwrap();
139/// println!("{:?}", image.bytes);
140/// ```
141pub fn open(image_file: &str) -> RasterResult<Image> {
142
143    let path = Path::new(image_file);
144    let ext = path.extension().and_then(|s| s.to_str())
145                  .map_or("".to_string(), |s| s.to_ascii_lowercase());
146
147    // Open the file with basic error check
148    let file = try!(File::open(image_file));
149
150    match &ext[..] {
151        "gif"  => {
152            Ok(try!(endec::decode_gif(&file)))
153        },
154        "jpg" | "jpeg" => {
155            let src = try!(piston_image::open(image_file));
156            let (w, h) = src.dimensions();
157            let mut bytes = Vec::with_capacity((w * h) as usize * 4);
158            for y in 0..h {
159                for x in 0..w {
160                    let p = src.get_pixel(x, y);
161                    bytes.extend_from_slice(&p.data[0..4]);
162                }
163            }
164            Ok(Image{
165                width: w as i32,
166                height: h as i32,
167                bytes: bytes
168            })
169        },
170        "png"  => {
171            Ok(try!(endec::decode_png(&file)))
172        },
173        _ => {
174            Err(RasterError::UnsupportedFormat(ext))
175        }
176    } 
177}
178
179/// Save an image to an image file. The image type is detected from the file extension of the file name.
180///
181/// # Errors
182///
183/// This function can return `RasterError::Io`, `RasterError::Encode`, or `RasterError::UnsupportedFormat` upon failure. 
184/// See error module for more info.
185///
186/// # Examples
187///
188/// ```
189/// // Create an image from file
190/// let image = raster::open("tests/in/sample.png").unwrap();
191/// raster::save(&image, "tests/out/test.png").unwrap();
192/// ```
193pub fn save(image: &Image, out: &str) -> RasterResult<()> {
194
195    let path = Path::new(out);
196    let ext = path.extension().and_then(|s| s.to_str())
197                  .map_or("".to_string(), |s| s.to_ascii_lowercase());
198
199    match &ext[..] {
200        "gif"  => {
201            Ok(try!(endec::encode_gif(&image, &path)))
202        },
203        "jpg" | "jpeg" => {
204            piston_image::save_buffer(
205                &path,
206                &image.bytes,
207                image.width as u32,
208                image.height as u32,
209                piston_image::RGBA(8)
210            ).map_err(|_| RasterError::Encode(ImageFormat::Jpeg, "Format".to_string()))
211        },
212        "png"  => {
213            Ok(try!(endec::encode_png(&image, &path)))
214        },
215        _ => {
216            Err(RasterError::UnsupportedFormat(ext))
217        }
218    } 
219}