move MagickWand to wand/magick.rs and filters to filters.rs

This commit is contained in:
Mattis Marjak
2016-05-11 17:03:53 +03:00
parent 85a4b97b70
commit 4c7cebe628
4 changed files with 231 additions and 229 deletions

36
src/filters.rs Normal file
View File

@ -0,0 +1,36 @@
use ::bindings;
pub enum FilterType {
UndefinedFilter = bindings::UndefinedFilter as isize,
PointFilter = bindings::PointFilter as isize,
BoxFilter = bindings::BoxFilter as isize,
TriangleFilter = bindings::TriangleFilter as isize,
HermiteFilter = bindings::HermiteFilter as isize,
HanningFilter = bindings::HanningFilter as isize,
HammingFilter = bindings::HammingFilter as isize,
BlackmanFilter = bindings::BlackmanFilter as isize,
GaussianFilter = bindings::GaussianFilter as isize,
QuadraticFilter = bindings::QuadraticFilter as isize,
CubicFilter = bindings::CubicFilter as isize,
CatromFilter = bindings::CatromFilter as isize,
MitchellFilter = bindings::MitchellFilter as isize,
JincFilter = bindings::JincFilter as isize,
SincFilter = bindings::SincFilter as isize,
SincFastFilter = bindings::SincFastFilter as isize,
KaiserFilter = bindings::KaiserFilter as isize,
WelshFilter = bindings::WelshFilter as isize,
ParzenFilter = bindings::ParzenFilter as isize,
BohmanFilter = bindings::BohmanFilter as isize,
BartlettFilter = bindings::BartlettFilter as isize,
LagrangeFilter = bindings::LagrangeFilter as isize,
LanczosFilter = bindings::LanczosFilter as isize,
LanczosSharpFilter = bindings::LanczosSharpFilter as isize,
Lanczos2Filter = bindings::Lanczos2Filter as isize,
Lanczos2SharpFilter = bindings::Lanczos2SharpFilter as isize,
RobidouxFilter = bindings::RobidouxFilter as isize,
RobidouxSharpFilter = bindings::RobidouxSharpFilter as isize,
CosineFilter = bindings::CosineFilter as isize,
SplineFilter = bindings::SplineFilter as isize,
LanczosRadiusFilter = bindings::LanczosRadiusFilter as isize,
SentinelFilter = bindings::SentinelFilter as isize
}

View File

@ -31,197 +31,12 @@
extern crate libc;
use std::ffi::{CStr, CString};
use std::ptr;
use libc::{c_uint, c_double, c_void};
use filters::FilterType;
mod wand;
mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); }
pub mod filters;
mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
pub use wand::*;
/// MagickWand is a Rustic wrapper to the Rust bindings to ImageMagick.
///
/// Instantiating a `MagickWand` will construct an ImageMagick "wand"
/// on which operations can be performed via the `MagickWand` functions.
/// When the `MagickWand` is dropped, the ImageMagick wand will be
/// destroyed as well.
pub struct MagickWand {
wand: *mut bindings::MagickWand
}
impl MagickWand {
/// Create a new MagickWand instance. This instance will be properly
/// cleaned up once it falls out of scope.
pub fn new() -> MagickWand {
MagickWand {
wand: unsafe { bindings::NewMagickWand() }
}
}
/// Read the image data from the named file.
pub fn read_image(&self, path: &str) -> Result<(), &'static str> {
let c_name = CString::new(path).unwrap();
let result = unsafe {
bindings::MagickReadImage(self.wand, c_name.as_ptr())
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to read image")
}
}
/// Read the image data from the vector of bytes.
pub fn read_image_blob(&self, data: Vec<u8>) -> Result<(), &'static str> {
let int_slice = &data[..];
let size = data.len();
let result = unsafe {
bindings::MagickReadImageBlob(
self.wand, int_slice.as_ptr() as *const c_void, size as u64)
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to read image")
}
}
/// Retrieve the width of the image.
pub fn get_image_width(&self) -> usize {
unsafe {
bindings::MagickGetImageWidth(self.wand) as usize
}
}
/// Retrieve the height of the image.
pub fn get_image_height(&self) -> usize {
unsafe {
bindings::MagickGetImageHeight(self.wand) as usize
}
}
/// Retrieve the named image property value.
pub fn get_image_property(&self, name: &str) -> Result<String, &'static str> {
let c_name = CString::new(name).unwrap();
let result = unsafe {
bindings::MagickGetImageProperty(self.wand, c_name.as_ptr())
};
let value = if result.is_null() {
Err("missing property")
} else {
// convert (and copy) the C string to a Rust string
let cstr = unsafe { CStr::from_ptr(result) };
Ok(cstr.to_string_lossy().into_owned())
};
unsafe {
bindings::MagickRelinquishMemory(result as *mut c_void);
}
value
}
/// Resize the image to the specified width and height, using the
/// specified filter type with the specified blur / sharpness factor.
///
/// blur_factor values greater than 1 create blurriness, while values
/// less than 1 create sharpness.
pub fn resize_image(&self, width: usize, height: usize,
filter: FilterType, blur_factor: f64) {
unsafe {
bindings::MagickResizeImage(
self.wand, width as u64, height as u64,
filter as c_uint, blur_factor as c_double
);
}
}
/// Resize the image to find within the given dimensions, maintaining
/// the current aspect ratio.
pub fn fit(&self, width: usize, height: usize) {
let mut width_ratio = width as f64;
width_ratio /= self.get_image_width() as f64;
let mut height_ratio = height as f64;
height_ratio /= self.get_image_height() as f64;
let new_width: usize;
let new_height: usize;
if width_ratio < height_ratio {
new_width = width;
new_height = (self.get_image_height() as f64 * width_ratio) as usize;
} else {
new_width = (self.get_image_width() as f64 * height_ratio) as usize;
new_height = height;
}
unsafe {
bindings::MagickResetIterator(self.wand);
while bindings::MagickNextImage(self.wand) != bindings::MagickFalse {
bindings::MagickResizeImage(self.wand, new_width as u64, new_height as u64,
FilterType::LanczosFilter as c_uint, 1.0);
}
}
}
/// Detect if the loaded image is not in top-left orientation, and
/// hence should be "auto" oriented so it is suitable for viewing.
pub fn requires_orientation(&self) -> bool {
unsafe {
bindings::MagickGetImageOrientation(self.wand) != bindings::TopLeftOrientation
}
}
/// Automatically adjusts the loaded image so that its orientation is
/// suitable for viewing (i.e. top-left orientation).
///
/// Returns `true` if successful or `false` if an error occurred.
pub fn auto_orient(&self) -> bool {
unsafe {
bindings::MagickAutoOrientImage(self.wand) == bindings::MagickTrue
}
}
/// Write the current image to the provided path.
pub fn write_image(&self, path: &str) -> Result<(), &'static str> {
let c_name = CString::new(path).unwrap();
let result = unsafe {
bindings::MagickWriteImage(self.wand, c_name.as_ptr())
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to write image")
}
}
/// Write the image in the desired format to a new blob.
///
/// The `format` argument may be any ImageMagick supported image
/// format (e.g. GIF, JPEG, PNG, etc).
pub fn write_image_blob(&self, format: &str) -> Result<Vec<u8>, &'static str> {
let c_format = CString::new(format).unwrap();
let mut length: u64 = 0;
let blob = unsafe {
bindings::MagickSetImageFormat(self.wand, c_format.as_ptr());
bindings::MagickResetIterator(self.wand);
bindings::MagickGetImageBlob(self.wand, &mut length)
};
let mut bytes = Vec::with_capacity(length as usize);
unsafe {
bytes.set_len(length as usize);
ptr::copy_nonoverlapping(blob, bytes.as_mut_ptr(), length as usize);
bindings::MagickRelinquishMemory(blob as *mut c_void);
};
Ok(bytes)
}
}
// Automate safe cleanup for MagickWand instances.
impl Drop for MagickWand {
/// Clear any exceptions and destroy the magic wand.
fn drop(&mut self) {
unsafe {
bindings::MagickClearException(self.wand);
bindings::DestroyMagickWand(self.wand);
}
}
}
/// This function must be called before any other ImageMagick operations
/// are attempted. This function is safe to be called repeatedly.
@ -244,43 +59,3 @@ pub fn magick_wand_terminus() {
}
}
}
pub mod filters {
use bindings;
pub enum FilterType {
UndefinedFilter = bindings::UndefinedFilter as isize,
PointFilter = bindings::PointFilter as isize,
BoxFilter = bindings::BoxFilter as isize,
TriangleFilter = bindings::TriangleFilter as isize,
HermiteFilter = bindings::HermiteFilter as isize,
HanningFilter = bindings::HanningFilter as isize,
HammingFilter = bindings::HammingFilter as isize,
BlackmanFilter = bindings::BlackmanFilter as isize,
GaussianFilter = bindings::GaussianFilter as isize,
QuadraticFilter = bindings::QuadraticFilter as isize,
CubicFilter = bindings::CubicFilter as isize,
CatromFilter = bindings::CatromFilter as isize,
MitchellFilter = bindings::MitchellFilter as isize,
JincFilter = bindings::JincFilter as isize,
SincFilter = bindings::SincFilter as isize,
SincFastFilter = bindings::SincFastFilter as isize,
KaiserFilter = bindings::KaiserFilter as isize,
WelshFilter = bindings::WelshFilter as isize,
ParzenFilter = bindings::ParzenFilter as isize,
BohmanFilter = bindings::BohmanFilter as isize,
BartlettFilter = bindings::BartlettFilter as isize,
LagrangeFilter = bindings::LagrangeFilter as isize,
LanczosFilter = bindings::LanczosFilter as isize,
LanczosSharpFilter = bindings::LanczosSharpFilter as isize,
Lanczos2Filter = bindings::Lanczos2Filter as isize,
Lanczos2SharpFilter = bindings::Lanczos2SharpFilter as isize,
RobidouxFilter = bindings::RobidouxFilter as isize,
RobidouxSharpFilter = bindings::RobidouxSharpFilter as isize,
CosineFilter = bindings::CosineFilter as isize,
SplineFilter = bindings::SplineFilter as isize,
LanczosRadiusFilter = bindings::LanczosRadiusFilter as isize,
SentinelFilter = bindings::SentinelFilter as isize
}
}

188
src/wand/magick.rs Normal file
View File

@ -0,0 +1,188 @@
use std::ffi::{CStr, CString};
use std::ptr;
use libc::{c_uint, c_double, c_void};
use ::filters::FilterType;
use ::bindings;
/// MagickWand is a Rustic wrapper to the Rust bindings to ImageMagick.
///
/// Instantiating a `MagickWand` will construct an ImageMagick "wand"
/// on which operations can be performed via the `MagickWand` functions.
/// When the `MagickWand` is dropped, the ImageMagick wand will be
/// destroyed as well.
pub struct MagickWand {
wand: *mut bindings::MagickWand
}
impl MagickWand {
/// Create a new MagickWand instance. This instance will be properly
/// cleaned up once it falls out of scope.
pub fn new() -> MagickWand {
MagickWand {
wand: unsafe { bindings::NewMagickWand() }
}
}
/// Read the image data from the named file.
pub fn read_image(&self, path: &str) -> Result<(), &'static str> {
let c_name = CString::new(path).unwrap();
let result = unsafe {
bindings::MagickReadImage(self.wand, c_name.as_ptr())
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to read image")
}
}
/// Read the image data from the vector of bytes.
pub fn read_image_blob(&self, data: Vec<u8>) -> Result<(), &'static str> {
let int_slice = &data[..];
let size = data.len();
let result = unsafe {
bindings::MagickReadImageBlob(
self.wand, int_slice.as_ptr() as *const c_void, size as u64)
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to read image")
}
}
/// Retrieve the width of the image.
pub fn get_image_width(&self) -> usize {
unsafe {
bindings::MagickGetImageWidth(self.wand) as usize
}
}
/// Retrieve the height of the image.
pub fn get_image_height(&self) -> usize {
unsafe {
bindings::MagickGetImageHeight(self.wand) as usize
}
}
/// Retrieve the named image property value.
pub fn get_image_property(&self, name: &str) -> Result<String, &'static str> {
let c_name = CString::new(name).unwrap();
let result = unsafe {
bindings::MagickGetImageProperty(self.wand, c_name.as_ptr())
};
let value = if result.is_null() {
Err("missing property")
} else {
// convert (and copy) the C string to a Rust string
let cstr = unsafe { CStr::from_ptr(result) };
Ok(cstr.to_string_lossy().into_owned())
};
unsafe {
bindings::MagickRelinquishMemory(result as *mut c_void);
}
value
}
/// Resize the image to the specified width and height, using the
/// specified filter type with the specified blur / sharpness factor.
///
/// blur_factor values greater than 1 create blurriness, while values
/// less than 1 create sharpness.
pub fn resize_image(&self, width: usize, height: usize,
filter: FilterType, blur_factor: f64) {
unsafe {
bindings::MagickResizeImage(
self.wand, width as u64, height as u64,
filter as c_uint, blur_factor as c_double
);
}
}
/// Resize the image to find within the given dimensions, maintaining
/// the current aspect ratio.
pub fn fit(&self, width: usize, height: usize) {
let mut width_ratio = width as f64;
width_ratio /= self.get_image_width() as f64;
let mut height_ratio = height as f64;
height_ratio /= self.get_image_height() as f64;
let new_width: usize;
let new_height: usize;
if width_ratio < height_ratio {
new_width = width;
new_height = (self.get_image_height() as f64 * width_ratio) as usize;
} else {
new_width = (self.get_image_width() as f64 * height_ratio) as usize;
new_height = height;
}
unsafe {
bindings::MagickResetIterator(self.wand);
while bindings::MagickNextImage(self.wand) != bindings::MagickFalse {
bindings::MagickResizeImage(self.wand, new_width as u64, new_height as u64,
FilterType::LanczosFilter as c_uint, 1.0);
}
}
}
/// Detect if the loaded image is not in top-left orientation, and
/// hence should be "auto" oriented so it is suitable for viewing.
pub fn requires_orientation(&self) -> bool {
unsafe {
bindings::MagickGetImageOrientation(self.wand) != bindings::TopLeftOrientation
}
}
/// Automatically adjusts the loaded image so that its orientation is
/// suitable for viewing (i.e. top-left orientation).
///
/// Returns `true` if successful or `false` if an error occurred.
pub fn auto_orient(&self) -> bool {
unsafe {
bindings::MagickAutoOrientImage(self.wand) == bindings::MagickTrue
}
}
/// Write the current image to the provided path.
pub fn write_image(&self, path: &str) -> Result<(), &'static str> {
let c_name = CString::new(path).unwrap();
let result = unsafe {
bindings::MagickWriteImage(self.wand, c_name.as_ptr())
};
match result {
bindings::MagickTrue => Ok(()),
_ => Err("failed to write image")
}
}
/// Write the image in the desired format to a new blob.
///
/// The `format` argument may be any ImageMagick supported image
/// format (e.g. GIF, JPEG, PNG, etc).
pub fn write_image_blob(&self, format: &str) -> Result<Vec<u8>, &'static str> {
let c_format = CString::new(format).unwrap();
let mut length: u64 = 0;
let blob = unsafe {
bindings::MagickSetImageFormat(self.wand, c_format.as_ptr());
bindings::MagickResetIterator(self.wand);
bindings::MagickGetImageBlob(self.wand, &mut length)
};
let mut bytes = Vec::with_capacity(length as usize);
unsafe {
bytes.set_len(length as usize);
ptr::copy_nonoverlapping(blob, bytes.as_mut_ptr(), length as usize);
bindings::MagickRelinquishMemory(blob as *mut c_void);
};
Ok(bytes)
}
}
// Automate safe cleanup for MagickWand instances.
impl Drop for MagickWand {
/// Clear any exceptions and destroy the magic wand.
fn drop(&mut self) {
unsafe {
bindings::MagickClearException(self.wand);
bindings::DestroyMagickWand(self.wand);
}
}
}

3
src/wand/mod.rs Normal file
View File

@ -0,0 +1,3 @@
mod magick;
pub use self::magick::MagickWand;