diff --git a/build.rs b/build.rs index 1adc92c..d5a4bb2 100644 --- a/build.rs +++ b/build.rs @@ -23,10 +23,10 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::Command; -const MIN_VERSION: &'static str = "7.0"; -const MAX_VERSION: &'static str = "7.2"; +const MIN_VERSION: &str = "7.0"; +const MAX_VERSION: &str = "7.2"; -static HEADER: &'static str = "#include \n"; +static HEADER: &str = "#include \n"; //on windows path env always contain : like c: pub const PATH_SEPARATOR: &str = match cfg!(target_os = "windows") { @@ -220,7 +220,7 @@ fn determine_mode>(libdirs: &Vec, libs: &[T]) -> &'static // See what files we actually have to link against, and see what our // possibilities even are. let files = libdirs - .into_iter() + .iter() .flat_map(|d| d.read_dir().unwrap()) .map(|e| e.unwrap()) .map(|e| e.file_name()) diff --git a/src/lib.rs b/src/lib.rs index 218028c..4cffebd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,19 +32,22 @@ extern crate libc; -mod conversions; -mod wand; -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +use libc::size_t; +#[cfg(not(target_os = "freebsd"))] +use libc::ssize_t; pub use bindings::{ ColorspaceType, CompositeOperator, DitherMethod, FilterType, GravityType, MetricType, }; pub use conversions::ToMagick; +pub use result::MagickError; +use result::Result; pub use wand::*; -use libc::size_t; -#[cfg(not(target_os = "freebsd"))] -use libc::ssize_t; +mod conversions; +mod result; +mod wand; +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); /// This function must be called before any other ImageMagick operations /// are attempted. This function is safe to be called repeatedly. @@ -67,13 +70,13 @@ pub fn magick_wand_terminus() { } } -pub fn magick_query_fonts(pattern: &str) -> Result, &'static str> { +pub fn magick_query_fonts(pattern: &str) -> Result> { let mut number_fonts: size_t = 0; let c_string = ::std::ffi::CString::new(pattern).map_err(|_| "could not convert to cstring")?; let ptr = unsafe { bindings::MagickQueryFonts(c_string.as_ptr(), &mut number_fonts as *mut size_t) }; if ptr.is_null() { - Err("null ptr returned by magick_query_fonts") + Err(MagickError("null ptr returned by magick_query_fonts")) } else { let mut v = Vec::new(); let c_str_ptr_slice = unsafe { ::std::slice::from_raw_parts(ptr, number_fonts as usize) }; diff --git a/src/result.rs b/src/result.rs new file mode 100644 index 0000000..7a0b4d6 --- /dev/null +++ b/src/result.rs @@ -0,0 +1,20 @@ +use std::fmt::{Debug, Display, Formatter}; + +pub type Result = std::result::Result; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct MagickError(pub &'static str); + +impl From<&'static str> for MagickError { + fn from(s: &'static str) -> Self { + MagickError(s) + } +} + +impl Display for MagickError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Display::fmt(self.0, f) + } +} + +impl std::error::Error for MagickError {} diff --git a/src/wand/drawing.rs b/src/wand/drawing.rs index 6d2f934..85b08a7 100644 --- a/src/wand/drawing.rs +++ b/src/wand/drawing.rs @@ -13,13 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -use bindings; +use std::ffi::{CStr, CString}; +use std::fmt; + #[cfg(target_os = "freebsd")] use libc::size_t; #[cfg(not(target_os = "freebsd"))] use size_t; -use std::ffi::{CStr, CString}; -use std::fmt; + +use bindings; + +use crate::result::MagickError; +use crate::result::Result; wand_common!( DrawingWand, @@ -34,7 +39,7 @@ wand_common!( ); impl DrawingWand { - pub fn draw_annotation(&mut self, x: f64, y: f64, text: &str) -> Result<(), &'static str> { + pub fn draw_annotation(&mut self, x: f64, y: f64, text: &str) -> Result<()> { let c_string = CString::new(text).map_err(|_| "could not convert to cstring")?; unsafe { bindings::DrawAnnotation(self.wand, x, y, c_string.as_ptr() as *const _) }; Ok(()) diff --git a/src/wand/macros.rs b/src/wand/macros.rs index 5b85626..24cf39a 100644 --- a/src/wand/macros.rs +++ b/src/wand/macros.rs @@ -37,10 +37,14 @@ macro_rules! wand_common { unsafe { ::bindings::$clear_wand(self.wand) } } - pub fn clear_exception(&mut self) -> Result<(), &'static str> { + pub fn clear_exception(&mut self) -> Result<()> { match unsafe { ::bindings::$clear_exc(self.wand) } { ::bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(concat!("failed to clear", stringify!($wand), "exception")), + _ => Err(MagickError(concat!( + "failed to clear", + stringify!($wand), + "exception" + ))), } } @@ -48,29 +52,27 @@ macro_rules! wand_common { unsafe { ::bindings::$get_exc_type(self.wand) } } - pub fn get_exception( - &self, - ) -> Result<(String, ::bindings::ExceptionType), &'static str> { + pub fn get_exception(&self) -> Result<(String, ::bindings::ExceptionType)> { let mut severity: ::bindings::ExceptionType = ::bindings::ExceptionType_UndefinedException; // TODO: memory management let ptr = unsafe { ::bindings::$get_exc(self.wand, &mut severity as *mut _) }; if ptr.is_null() { - Err(concat!( + Err(MagickError(concat!( "null ptr returned by", stringify!($wand), "get_exception" - )) + ))) } else { let c_str = unsafe { CStr::from_ptr(ptr) }; Ok((c_str.to_string_lossy().into_owned(), severity)) } } - pub fn is_wand(&self) -> Result<(), &'static str> { + pub fn is_wand(&self) -> Result<()> { match unsafe { ::bindings::$is_wand(self.wand) } { ::bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(concat!(stringify!($wand), " not a wand")), + _ => Err(MagickError(concat!(stringify!($wand), " not a wand"))), } } } @@ -110,10 +112,10 @@ macro_rules! set_get { pub fn $get(&self) -> $typ { unsafe { ::bindings::$c_get(self.wand) } } - pub fn $set(&mut self, v: $typ) -> Result<(), &'static str> { + pub fn $set(&mut self, v: $typ) -> Result<()> { match unsafe { ::bindings::$c_set(self.wand, v) } { ::bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(concat!(stringify!($set), " returned false")) + _ => Err(MagickError(concat!(stringify!($set), " returned false"))) } } )* @@ -143,10 +145,13 @@ macro_rules! set_get_unchecked { macro_rules! string_get { ($get:ident, $c_get:ident) => { - pub fn $get(&self) -> Result { + pub fn $get(&self) -> Result { let ptr = unsafe { ::bindings::$c_get(self.wand) }; if ptr.is_null() { - Err(concat!("null ptr returned by ", stringify!($get))) + Err(MagickError(concat!( + "null ptr returned by ", + stringify!($get) + ))) } else { let c_str = unsafe { ::std::ffi::CStr::from_ptr(ptr) }; let result: String = c_str.to_string_lossy().into_owned(); @@ -161,11 +166,11 @@ macro_rules! string_set_get { ($($get:ident, $set:ident, $c_get:ident, $c_set:ident)*) => { $( string_get!($get, $c_get); - pub fn $set(&mut self, s: &str) -> Result<(), &'static str> { + pub fn $set(&mut self, s: &str) -> Result<()> { let c_string = std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?; match unsafe { ::bindings::$c_set(self.wand, c_string.as_ptr()) } { ::bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(concat!(stringify!($set), " returned false")) + _ => Err(MagickError(concat!(stringify!($set), " returned false"))) } } )* @@ -180,7 +185,7 @@ macro_rules! string_set_get_unchecked { ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => { $( string_get!($get, $c_get); - pub fn $set(&mut self, s: &str) -> Result<(), &'static str> { + pub fn $set(&mut self, s: &str) -> Result<()> { let c_string = ::std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?; unsafe { ::bindings::$c_set(self.wand, c_string.as_ptr()) }; Ok(()) @@ -252,10 +257,10 @@ macro_rules! mutations { ($($(#[$attr:meta])* $c_fun:ident => $fun:ident($($arg:ident: $ty:ty),*))*) => { $( $(#[$attr])* - pub fn $fun(&self $(, $arg: $ty)*) -> Result<(), &'static str> { + pub fn $fun(&self $(, $arg: $ty)*) -> Result<()> { match unsafe { bindings::$c_fun(self.wand $(, $arg)*) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(concat!(stringify!($c_fun), " invocation failed")) + _ => Err(MagickError(concat!(stringify!($c_fun), " invocation failed"))) } } )* diff --git a/src/wand/magick.rs b/src/wand/magick.rs index e50c4c8..0c5d6ee 100644 --- a/src/wand/magick.rs +++ b/src/wand/magick.rs @@ -13,18 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -use libc::c_void; use std::ffi::{CStr, CString}; use std::{fmt, ptr, slice}; -use super::{DrawingWand, PixelWand}; -use bindings; -use conversions::*; +use libc::c_void; #[cfg(target_os = "freebsd")] use libc::{size_t, ssize_t}; + +use bindings; +use conversions::*; +use result::MagickError; #[cfg(not(target_os = "freebsd"))] use {size_t, ssize_t}; +use crate::result::Result; + +use super::{DrawingWand, PixelWand}; + wand_common!( MagickWand, NewMagickWand, @@ -61,19 +66,14 @@ pub enum ResourceType { /// When the `MagickWand` is dropped, the ImageMagick wand will be /// destroyed as well. impl MagickWand { - pub fn new_image( - &self, - columns: size_t, - rows: size_t, - pixel_wand: &PixelWand, - ) -> Result<(), &'static str> { + pub fn new_image(&self, columns: size_t, rows: size_t, pixel_wand: &PixelWand) -> Result<()> { match unsafe { bindings::MagickNewImage(self.wand, columns, rows, pixel_wand.wand) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("Could not create image"), + _ => Err(MagickError("Could not create image")), } } - pub fn set_resource_limit(resource: ResourceType, limit: u64) -> Result<(), &'static str> { + pub fn set_resource_limit(resource: ResourceType, limit: u64) -> Result<()> { let result = unsafe { bindings::SetMagickResourceLimit( resource as bindings::ResourceType, @@ -82,18 +82,18 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to set resource limit"), + _ => Err(MagickError("failed to set resource limit")), } } - pub fn set_option(&mut self, key: &str, value: &str) -> Result<(), &'static str> { + pub fn set_option(&mut self, key: &str, value: &str) -> Result<()> { let c_key = CString::new(key).unwrap(); let c_value = CString::new(value).unwrap(); let result = unsafe { bindings::MagickSetOption(self.wand, c_key.as_ptr(), c_value.as_ptr()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to set option"), + _ => Err(MagickError("failed to set option")), } } @@ -104,7 +104,7 @@ impl MagickWand { y: f64, angle: f64, text: &str, - ) -> Result<(), &'static str> { + ) -> Result<()> { let c_string = CString::new(text).map_err(|_| "could not convert to cstring")?; match unsafe { bindings::MagickAnnotateImage( @@ -117,15 +117,15 @@ impl MagickWand { ) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("unable to annotate image"), + _ => Err(MagickError("unable to annotate image")), } } /// Add all images from another wand to this wand at the current index. - pub fn add_image(&mut self, other_wand: &MagickWand) -> Result<(), &'static str> { + pub fn add_image(&mut self, other_wand: &MagickWand) -> Result<()> { match unsafe { bindings::MagickAddImage(self.wand, other_wand.wand) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("unable to add images from another wand"), + _ => Err(MagickError("unable to add images from another wand")), } } @@ -136,37 +136,37 @@ impl MagickWand { } } - pub fn label_image(&self, label: &str) -> Result<(), &'static str> { + pub fn label_image(&self, label: &str) -> Result<()> { let c_label = CString::new(label).unwrap(); let result = unsafe { bindings::MagickLabelImage(self.wand, c_label.as_ptr()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to add label"), + _ => Err(MagickError("failed to add label")), } } - pub fn write_images(&self, path: &str, adjoin: bool) -> Result<(), &'static str> { + pub fn write_images(&self, path: &str, adjoin: bool) -> Result<()> { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickWriteImages(self.wand, c_name.as_ptr(), adjoin.to_magick()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to write images"), + _ => Err(MagickError("failed to write images")), } } /// Read the image data from the named file. - pub fn read_image(&self, path: &str) -> Result<(), &'static str> { + pub fn read_image(&self, path: &str) -> Result<()> { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickReadImage(self.wand, c_name.as_ptr()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to read image"), + _ => Err(MagickError("failed to read image")), } } /// Read the image data from the vector of bytes. - pub fn read_image_blob>(&self, data: T) -> Result<(), &'static str> { + pub fn read_image_blob>(&self, data: T) -> Result<()> { let int_slice = data.as_ref(); let size = int_slice.len(); let result = unsafe { @@ -178,24 +178,24 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to read image"), + _ => Err(MagickError("failed to read image")), } } /// Same as read_image, but reads only the width, height, size and format of an image, /// without reading data. - pub fn ping_image(&self, path: &str) -> Result<(), &'static str> { + pub fn ping_image(&self, path: &str) -> Result<()> { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickPingImage(self.wand, c_name.as_ptr()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to ping image"), + _ => Err(MagickError("failed to ping image")), } } /// Same as read_image, but reads only the width, height, size and format of an image, /// without reading data. - pub fn ping_image_blob>(&self, data: T) -> Result<(), &'static str> { + pub fn ping_image_blob>(&self, data: T) -> Result<()> { let int_slice = data.as_ref(); let size = int_slice.len(); let result = unsafe { @@ -207,7 +207,7 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to ping image"), + _ => Err(MagickError("failed to ping image")), } } @@ -238,7 +238,7 @@ impl MagickWand { clip_to_self: bool, x: isize, y: isize, - ) -> Result<(), &'static str> { + ) -> Result<()> { let native_clip_to_self = if clip_to_self { bindings::MagickBooleanType_MagickTrue } else { @@ -256,7 +256,7 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to compose images"), + _ => Err(MagickError("failed to compose images")), } } @@ -265,19 +265,23 @@ impl MagickWand { &self, clut_wand: &MagickWand, method: bindings::PixelInterpolateMethod, - ) -> Result<(), &'static str> { + ) -> Result<()> { let result = unsafe { bindings::MagickClutImage(self.wand, clut_wand.wand, method) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to replace colors in the image from color lookup table"), + _ => Err(MagickError( + "failed to replace colors in the image from color lookup table", + )), } } - pub fn hald_clut_image(&self, clut_wand: &MagickWand) -> Result<(), &'static str> { + pub fn hald_clut_image(&self, clut_wand: &MagickWand) -> Result<()> { let result = unsafe { bindings::MagickHaldClutImage(self.wand, clut_wand.wand) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to replace colors in the image from color lookup table"), + _ => Err(MagickError( + "failed to replace colors in the image from color lookup table", + )), } } @@ -287,42 +291,39 @@ impl MagickWand { MagickWand::new_from_wand(wand) } - pub fn set_size(&self, columns: size_t, rows: size_t) -> Result<(), &'static str> { + pub fn set_size(&self, columns: size_t, rows: size_t) -> Result<()> { let result = unsafe { bindings::MagickSetSize(self.wand, columns, rows) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to set size of wand"), + _ => Err(MagickError("failed to set size of wand")), } } // Define two 'quantum_range' functions because the bindings::QuantumRange symbol // is not available if hdri is disabled in the compiled ImageMagick libs - #[cfg(not(feature="disable-hdri"))] - fn quantum_range(&self) -> Result { - return Ok(bindings::QuantumRange); + #[cfg(not(feature = "disable-hdri"))] + fn quantum_range(&self) -> Result { + Ok(bindings::QuantumRange) } // with disable-hdri enabled we define our own quantum_range // values lifted directly from magick-type.h - #[cfg(feature="disable-hdri")] - fn quantum_range(&self) -> Result { + #[cfg(feature = "disable-hdri")] + fn quantum_range(&self) -> Result { match bindings::MAGICKCORE_QUANTUM_DEPTH { 8 => Ok(255.0f64), 16 => Ok(65535.0f64), 32 => Ok(4294967295.0f64), 64 => Ok(18446744073709551615.0f64), - _ => Err("Quantum depth must be one of 8, 16, 32 or 64") + _ => Err(MagickError( + ("Quantum depth must be one of 8, 16, 32 or 64"), + )), } } // Level an image. Black and white points are multiplied with QuantumRange to // decrease dependencies on the end user. - pub fn level_image( - &self, - black_point: f64, - gamma: f64, - white_point: f64, - ) -> Result<(), &'static str> { + pub fn level_image(&self, black_point: f64, gamma: f64, white_point: f64) -> Result<()> { let quantum_range = self.quantum_range()?; let result = unsafe { @@ -335,23 +336,17 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to set size of wand"), + _ => Err(MagickError("failed to set size of wand")), } } /// Extend the image as defined by the geometry, gravity, and wand background color. Set the /// (x,y) offset of the geometry to move the original wand relative to the extended wand. - pub fn extend_image( - &self, - width: usize, - height: usize, - x: isize, - y: isize, - ) -> Result<(), &'static str> { + pub fn extend_image(&self, width: usize, height: usize, x: isize, y: isize) -> Result<()> { let result = unsafe { bindings::MagickExtentImage(self.wand, width, height, x, y) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to extend image"), + _ => Err(MagickError("failed to extend image")), } } @@ -359,7 +354,7 @@ impl MagickWand { &self, name: &str, profile: T, - ) -> Result<(), &'static str> { + ) -> Result<()> { let c_name = CString::new(name).unwrap(); let result = unsafe { let profile = profile.into(); @@ -375,75 +370,75 @@ impl MagickWand { }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to profile image"), + _ => Err(MagickError("failed to profile image")), } } - pub fn flip_image(&self) -> Result<(), &'static str> { + pub fn flip_image(&self) -> Result<()> { let result = unsafe { bindings::MagickFlipImage(self.wand) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to flip image"), + _ => Err(MagickError("failed to flip image")), } } - pub fn negate_image(&self) -> Result<(), &'static str> { + pub fn negate_image(&self) -> Result<()> { let result = unsafe { bindings::MagickNegateImage(self.wand, bindings::MagickBooleanType_MagickTrue) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to flip image"), + _ => Err(MagickError("failed to flip image")), } } - pub fn flop_image(&self) -> Result<(), &'static str> { + pub fn flop_image(&self) -> Result<()> { let result = unsafe { bindings::MagickFlopImage(self.wand) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to flip image"), + _ => Err(MagickError("failed to flip image")), } } - pub fn blur_image(&self, radius: f64, sigma: f64) -> Result<(), &'static str> { + pub fn blur_image(&self, radius: f64, sigma: f64) -> Result<()> { let result = unsafe { bindings::MagickBlurImage(self.wand, radius, sigma) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to blur image"), + _ => Err(MagickError("failed to blur image")), } } - pub fn gaussian_blur_image(&self, radius: f64, sigma: f64) -> Result<(), &'static str> { + pub fn gaussian_blur_image(&self, radius: f64, sigma: f64) -> Result<()> { let result = unsafe { bindings::MagickGaussianBlurImage(self.wand, radius, sigma) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to gaussian blur image"), + _ => Err(MagickError("failed to gaussian blur image")), } } /// Adaptively resize the currently selected image. - pub fn adaptive_resize_image(&self, width: usize, height: usize) -> Result<(), &'static str> { + pub fn adaptive_resize_image(&self, width: usize, height: usize) -> Result<()> { match unsafe { bindings::MagickAdaptiveResizeImage(self.wand, width, height) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to adaptive-resize image"), + _ => Err(MagickError("failed to adaptive-resize image")), } } /// Rotate the currently selected image by the given number of degrees, /// filling any empty space with the background color of a given PixelWand - pub fn rotate_image(&self, background: &PixelWand, degrees: f64) -> Result<(), &'static str> { + pub fn rotate_image(&self, background: &PixelWand, degrees: f64) -> Result<()> { match unsafe { bindings::MagickRotateImage(self.wand, background.wand, degrees) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to rotate image"), + _ => Err(MagickError("failed to rotate image")), } } /// Trim the image removing the backround color from the edges. - pub fn trim_image(&self, fuzz: f64) -> Result<(), &'static str> { + pub fn trim_image(&self, fuzz: f64) -> Result<()> { let result = unsafe { bindings::MagickTrimImage(self.wand, fuzz) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to trim image"), + _ => Err(MagickError("failed to trim image")), } } @@ -467,22 +462,22 @@ impl MagickWand { } /// Reset the Wand page canvas and position. - pub fn reset_image_page(&self, page_geometry: &str) -> Result<(), &'static str> { + pub fn reset_image_page(&self, page_geometry: &str) -> Result<()> { let c_page_geometry = CString::new(page_geometry).unwrap(); let result = unsafe { bindings::MagickResetImagePage(self.wand, c_page_geometry.as_ptr()) }; if result == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("Resetting page geometry failed.") + Err(MagickError("Resetting page geometry failed.")) } } /// Retrieve the named image property value. - pub fn get_image_property(&self, name: &str) -> Result { + pub fn get_image_property(&self, name: &str) -> Result { 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") + Err(MagickError("missing property")) } else { // convert (and copy) the C string to a Rust string let cstr = unsafe { CStr::from_ptr(result) }; @@ -495,7 +490,7 @@ impl MagickWand { } /// Set the named image property. - pub fn set_image_property(&self, name: &str, value: &str) -> Result<(), &'static str> { + pub fn set_image_property(&self, name: &str, value: &str) -> Result<()> { let c_name = CString::new(name).unwrap(); let c_value = CString::new(value).unwrap(); let result = unsafe { @@ -504,7 +499,7 @@ impl MagickWand { if result == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("Setting image property failed.") + Err(MagickError("Setting image property failed.")) } } @@ -526,7 +521,7 @@ impl MagickWand { /// Sets the image sampling factors. /// /// samplingFactors: An array of floats representing the sampling factor for each color component (in RGB order). - pub fn set_sampling_factors(&self, samplingFactors: &[f64]) -> Result<(), &'static str> { + pub fn set_sampling_factors(&self, samplingFactors: &[f64]) -> Result<()> { match unsafe { bindings::MagickSetSamplingFactors( self.wand, @@ -535,7 +530,7 @@ impl MagickWand { ) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("SetSamplingFactors returned false"), + _ => Err(MagickError("SetSamplingFactors returned false")), } } @@ -564,34 +559,34 @@ impl MagickWand { /// /// sigma: the standard deviation of the Gaussian, in pixels. /// - pub fn sharpen_image(&self, radius: f64, sigma: f64) -> Result<(), &'static str> { + pub fn sharpen_image(&self, radius: f64, sigma: f64) -> Result<()> { match unsafe { bindings::MagickSharpenImage(self.wand, radius, sigma) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("SharpenImage returned false"), + _ => Err(MagickError("SharpenImage returned false")), } } /// Set the background color. - pub fn set_background_color(&self, pixel_wand: &PixelWand) -> Result<(), &'static str> { + pub fn set_background_color(&self, pixel_wand: &PixelWand) -> Result<()> { match unsafe { bindings::MagickSetBackgroundColor(self.wand, pixel_wand.wand) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("SetBackgroundColor returned false"), + _ => Err(MagickError("SetBackgroundColor returned false")), } } /// Set the image background color. - pub fn set_image_background_color(&self, pixel_wand: &PixelWand) -> Result<(), &'static str> { + pub fn set_image_background_color(&self, pixel_wand: &PixelWand) -> Result<()> { match unsafe { bindings::MagickSetImageBackgroundColor(self.wand, pixel_wand.wand) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("SetImageBackgroundColor returned false"), + _ => Err(MagickError("SetImageBackgroundColor returned false")), } } /// Returns the image resolution as a pair (horizontal resolution, vertical resolution) - pub fn get_image_resolution(&self) -> Result<(f64, f64), &'static str> { + pub fn get_image_resolution(&self) -> Result<(f64, f64)> { let mut x_resolution = 0f64; let mut y_resolution = 0f64; unsafe { @@ -600,50 +595,46 @@ impl MagickWand { { Ok((x_resolution, y_resolution)) } else { - Err("GetImageResolution returned false") + Err(MagickError("GetImageResolution returned false")) } } } /// Sets the image resolution - pub fn set_image_resolution( - &self, - x_resolution: f64, - y_resolution: f64, - ) -> Result<(), &'static str> { + pub fn set_image_resolution(&self, x_resolution: f64, y_resolution: f64) -> Result<()> { unsafe { if bindings::MagickSetImageResolution(self.wand, x_resolution, y_resolution) == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("SetImageResolution returned false") + Err(MagickError("SetImageResolution returned false")) } } } /// Sets the wand resolution - pub fn set_resolution(&self, x_resolution: f64, y_resolution: f64) -> Result<(), &'static str> { + pub fn set_resolution(&self, x_resolution: f64, y_resolution: f64) -> Result<()> { unsafe { if bindings::MagickSetResolution(self.wand, x_resolution, y_resolution) == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("SetResolution returned false") + Err(MagickError("SetResolution returned false")) } } } /// Returns the image resolution as a pair (horizontal resolution, vertical resolution) - pub fn sepia_tone_image(&self, threshold: f64) -> Result<(), &'static str> { + pub fn sepia_tone_image(&self, threshold: f64) -> Result<()> { unsafe { if bindings::MagickSepiaToneImage(self.wand, threshold * self.quantum_range()?) == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("SepiaToneImage returned false") + Err(MagickError("SepiaToneImage returned false")) } } } @@ -701,17 +692,11 @@ impl MagickWand { /// Extract a region of the image. The width and height is used as the size /// of the region. X and Y is the offset. - pub fn crop_image( - &self, - width: usize, - height: usize, - x: isize, - y: isize, - ) -> Result<(), &'static str> { + pub fn crop_image(&self, width: usize, height: usize, x: isize, y: isize) -> Result<()> { let result = unsafe { bindings::MagickCropImage(self.wand, width, height, x, y) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to crop image"), + _ => Err(MagickError("failed to crop image")), } } @@ -719,11 +704,11 @@ impl MagickWand { /// /// This is incredibly fast, as it does 1-1 pixel mapping for downscales, and box filtering for /// upscales - pub fn sample_image(&self, width: usize, height: usize) -> Result<(), &'static str> { + pub fn sample_image(&self, width: usize, height: usize) -> Result<()> { let result = unsafe { bindings::MagickSampleImage(self.wand, width, height) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to sample image"), + _ => Err(MagickError("failed to sample image")), } } @@ -740,20 +725,27 @@ impl MagickWand { } } - /// Rescale the image using seam carving algorithm - pub fn liquid_rescale_image(&self, width: usize, height: usize, delta_x: f64, rigidity: f64) -> Result<(), &'static str> { - match unsafe { bindings::MagickLiquidRescaleImage(self.wand, width, height, delta_x, rigidity) } { + pub fn liquid_rescale_image( + &self, + width: usize, + height: usize, + delta_x: f64, + rigidity: f64, + ) -> Result<()> { + match unsafe { + bindings::MagickLiquidRescaleImage(self.wand, width, height, delta_x, rigidity) + } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to liquid-rescale image") + _ => Err(MagickError("failed to liquid-rescale image")), } } /// Implodes the image towards the center by the specified percentage - pub fn implode(&self, amount: f64, method: bindings::PixelInterpolateMethod) -> Result<(), &'static str> { + pub fn implode(&self, amount: f64, method: bindings::PixelInterpolateMethod) -> Result<()> { match unsafe { bindings::MagickImplodeImage(self.wand, amount, method) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to implode image") + _ => Err(MagickError("failed to implode image")), } } @@ -808,12 +800,12 @@ impl MagickWand { } /// Write the current image to the provided path. - pub fn write_image(&self, path: &str) -> Result<(), &'static str> { + pub fn write_image(&self, path: &str) -> Result<()> { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickWriteImage(self.wand, c_name.as_ptr()) }; match result { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to write image"), + _ => Err(MagickError("failed to write image")), } } @@ -821,7 +813,7 @@ impl MagickWand { /// /// 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, &'static str> { + pub fn write_image_blob(&self, format: &str) -> Result> { let c_format = CString::new(format).unwrap(); let mut length: size_t = 0; let blob = unsafe { @@ -842,7 +834,7 @@ impl MagickWand { /// /// The `format` argument may be any ImageMagick supported image /// format (e.g. GIF, JPEG, PNG, etc). - pub fn write_images_blob(&self, format: &str) -> Result, &'static str> { + pub fn write_images_blob(&self, format: &str) -> Result> { let c_format = CString::new(format).unwrap(); let mut length: size_t = 0; let blob = unsafe { @@ -863,14 +855,14 @@ impl MagickWand { /// That is, the image is RGB rather than RGBA or CMYK rather than CMYKA pub fn get_image_alpha_channel(&self) -> bool { let res = unsafe { bindings::MagickGetImageAlphaChannel(self.wand) }; - return res == bindings::MagickBooleanType_MagickTrue; + res == bindings::MagickBooleanType_MagickTrue } /// Renders the drawing wand on the current image - pub fn draw_image(&mut self, drawing_wand: &DrawingWand) -> Result<(), &'static str> { + pub fn draw_image(&mut self, drawing_wand: &DrawingWand) -> Result<()> { match unsafe { bindings::MagickDrawImage(self.wand, drawing_wand.wand) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("unable to draw image"), + _ => Err(MagickError("unable to draw image")), } } @@ -886,15 +878,11 @@ impl MagickWand { /// expression to an image. Use these operators to lighten or darken an image, /// to increase or decrease contrast in an image, or to produce the "negative" /// of an image. - pub fn evaluate_image( - &mut self, - op: bindings::MagickEvaluateOperator, - val: f64, - ) -> Result<(), &'static str> { + pub fn evaluate_image(&mut self, op: bindings::MagickEvaluateOperator, val: f64) -> Result<()> { let res = unsafe { bindings::MagickEvaluateImage(self.wand, op, val) }; match res { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to evaluate image"), + _ => Err(MagickError("failed to evaluate image")), } } @@ -906,31 +894,25 @@ impl MagickWand { width: usize, height: usize, compose: bindings::CompositeOperator, - ) -> Result<(), &'static str> { + ) -> Result<()> { match unsafe { bindings::MagickBorderImage(self.wand, pixel_wand.wand, width, height, compose) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("border image returned false"), + _ => Err(MagickError("border image returned false")), } } /// Simulate an image shadow - pub fn shadow_image( - &self, - alpha: f64, - sigma: f64, - x: isize, - y: isize, - ) -> Result<(), &'static str> { + pub fn shadow_image(&self, alpha: f64, sigma: f64, x: isize, y: isize) -> Result<()> { unsafe { if bindings::MagickShadowImage(self.wand, alpha, sigma, x, y) == bindings::MagickBooleanType_MagickTrue { Ok(()) } else { - Err("ShadowImage returned false") + Err(MagickError("ShadowImage returned false")) } } } @@ -944,7 +926,7 @@ impl MagickWand { columns: usize, rows: usize, pixels: &Vec, - ) -> Result<(), &'static str> { + ) -> Result<()> { let pixel_map = CString::new("RGBA").unwrap(); match unsafe { bindings::MagickImportImagePixels( @@ -959,7 +941,7 @@ impl MagickWand { ) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("unable to import pixels"), + _ => Err(MagickError("unable to import pixels")), } } diff --git a/src/wand/pixel.rs b/src/wand/pixel.rs index 8d727d4..b825404 100644 --- a/src/wand/pixel.rs +++ b/src/wand/pixel.rs @@ -13,13 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -use bindings; +use std::ffi::{CStr, CString}; +use std::fmt; + #[cfg(target_os = "freebsd")] use libc::size_t; #[cfg(not(target_os = "freebsd"))] use size_t; -use std::ffi::{CStr, CString}; -use std::fmt; + +use bindings; +use result::MagickError; + +use crate::result::Result; #[derive(Default, Debug)] pub struct HSL { @@ -41,10 +46,10 @@ wand_common!( ); impl PixelWand { - pub fn is_similar(&self, other: &PixelWand, fuzz: f64) -> Result<(), &'static str> { + pub fn is_similar(&self, other: &PixelWand, fuzz: f64) -> Result<()> { match unsafe { bindings::IsPixelWandSimilar(self.wand, other.wand, fuzz) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("not similar"), + _ => Err(MagickError("not similar")), } } @@ -78,11 +83,11 @@ impl PixelWand { writeln!(f, "{}}}", prefix) } - pub fn set_color(&mut self, s: &str) -> Result<(), &'static str> { + pub fn set_color(&mut self, s: &str) -> Result<()> { let c_string = CString::new(s).map_err(|_| "could not convert to cstring")?; match unsafe { bindings::PixelSetColor(self.wand, c_string.as_ptr()) } { bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err("failed to set color"), + _ => Err(MagickError("failed to set color")), } } diff --git a/tests/lib.rs b/tests/lib.rs index b97a938..dc219d8 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -16,15 +16,15 @@ extern crate magick_rust; -use magick_rust::{bindings, magick_wand_genesis, MagickWand, PixelWand, ResourceType}; - -use magick_rust::ToMagick; use std::error::Error; use std::fs::File; use std::io::Read; use std::path::Path; use std::sync::Once; +use magick_rust::{MagickError, ToMagick}; +use magick_rust::{bindings, magick_wand_genesis, MagickWand, PixelWand, ResourceType}; + // Used to make sure MagickWand is initialized exactly once. Note that we // do not bother shutting down, we simply exit when the tests are done. static START: Once = Once::new(); @@ -81,7 +81,6 @@ fn test_thumbnail_image() { assert_eq!(192, wand.get_image_height()); } - #[test] fn test_read_from_blob() { START.call_once(|| { @@ -172,7 +171,7 @@ fn test_get_image_property() { // retrieve a property that does not exist let missing_value = wand.get_image_property("exif:Foobar"); assert!(missing_value.is_err()); - assert_eq!("missing property", missing_value.unwrap_err()); + assert_eq!(MagickError("missing property"), missing_value.unwrap_err()); } #[test]