diff --git a/src/conversions.rs b/src/conversions.rs new file mode 100644 index 0000000..b19e9ee --- /dev/null +++ b/src/conversions.rs @@ -0,0 +1,27 @@ +use super::bindings; + +pub trait FromRust { + fn from_rust(t: T) -> Self; +} + +impl FromRust for bindings::MagickBooleanType { + fn from_rust(b: bool) -> Self { + if b { + bindings::MagickTrue + } else { + bindings::MagickFalse + } + } +} + +pub trait ToMagick { + fn to_magick(self) -> T; +} + +impl ToMagick for E + where T: FromRust +{ + fn to_magick(self) -> T { + >::from_rust(self) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8be898a..319443e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,8 +32,9 @@ extern crate libc; mod wand; -mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } +mod conversions; pub mod filters; +mod bindings { include!(concat!(env!("OUT_DIR"), "/bindings.rs")); } pub use wand::*; @@ -59,3 +60,21 @@ pub fn magick_wand_terminus() { } } } + +pub fn magick_query_fonts(pattern: &str) -> Result, &'static str> { + let mut number_fonts: u64 = 0; + let c_string = try!(::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 _) }; + if ptr.is_null() { + Err("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) }; + for c_str_ptr in c_str_ptr_slice { + let c_str = unsafe { ::std::ffi::CStr::from_ptr(*c_str_ptr) }; + v.push(c_str.to_string_lossy().into_owned()) + } + Ok(v) + } + +} diff --git a/src/wand/drawing.rs b/src/wand/drawing.rs new file mode 100644 index 0000000..a43d547 --- /dev/null +++ b/src/wand/drawing.rs @@ -0,0 +1,79 @@ +use std::fmt; +use std::ffi::{CStr, CString}; +use ::bindings; + + +wand_common!( + DrawingWand, + NewDrawingWand, ClearDrawingWand, IsDrawingWand, CloneDrawingWand, DestroyDrawingWand, + DrawClearException, DrawGetExceptionType, DrawGetException +); + +impl DrawingWand { + pub fn draw_annotation(&mut self, x: f64, y: f64, text: &str) -> Result<(), &'static str> { + let c_string = try!(CString::new(text).map_err(|_| "could not convert to cstring")); + unsafe { bindings::DrawAnnotation(self.wand, x, y, c_string.as_ptr() as *const _) }; + Ok(()) + } + + string_set_get!( + get_font, set_font, DrawGetFont, DrawSetFont + get_font_family, set_font_family, DrawGetFontFamily, DrawSetFontFamily + get_vector_graphics, set_vector_graphics, DrawGetVectorGraphics, DrawSetVectorGraphics + get_clip_path, set_clip_path, DrawGetClipPath, DrawSetClipPath + ); + + string_set_get_unchecked!( + get_text_encoding, set_text_encoding, DrawGetTextEncoding, DrawSetTextEncoding + ); + + pixel_set_get!( + get_border_color, set_border_color, DrawGetBorderColor, DrawSetBorderColor + get_fill_color, set_fill_color, DrawGetFillColor, DrawSetFillColor + get_stroke_color, set_stroke_color, DrawGetStrokeColor, DrawSetStrokeColor + get_text_under_color, set_text_under_color, DrawGetTextUnderColor, DrawSetTextUnderColor + ); + + set_get_unchecked!( + get_gravity, set_gravity, DrawGetGravity, DrawSetGravity, u32 + get_opacity, set_opacity, DrawGetOpacity, DrawSetOpacity, f64 + get_clip_rule, set_clip_rule, DrawGetClipRule, DrawSetClipRule, u32 + get_clip_units, set_clip_units, DrawGetClipUnits, DrawSetClipUnits, u32 + get_fill_rule, set_fill_rule, DrawGetFillRule, DrawSetFillRule, u32 + get_fill_opacity, set_fill_opacity, DrawGetFillOpacity, DrawSetFillOpacity, f64 + + get_font_size, set_font_size, DrawGetFontSize, DrawSetFontSize, f64 + get_font_style, set_font_style, DrawGetFontStyle, DrawSetFontStyle, u32 + get_font_weight, set_font_weight, DrawGetFontWeight, DrawSetFontWeight, u64 + get_font_stretch, set_font_stretch, DrawGetFontStretch, DrawSetFontStretch, u32 + + get_stroke_dash_offset, set_stroke_dash_offset, DrawGetStrokeDashOffset, DrawSetStrokeDashOffset, f64 + get_stroke_line_cap, set_stroke_line_cap, DrawGetStrokeLineCap, DrawSetStrokeLineCap, u32 + get_stroke_line_join, set_stroke_line_join, DrawGetStrokeLineJoin, DrawSetStrokeLineJoin, u32 + get_stroke_miter_limit, set_stroke_miter_limit, DrawGetStrokeMiterLimit, DrawSetStrokeMiterLimit, u64 + get_stroke_opacity, set_stroke_opacity, DrawGetStrokeOpacity, DrawSetStrokeOpacity, f64 + get_stroke_width, set_stroke_width, DrawGetStrokeWidth, DrawSetStrokeWidth, f64 + get_stroke_antialias, set_stroke_antialias, DrawGetStrokeAntialias, DrawSetStrokeAntialias, u32 + + get_text_alignment, set_text_alignment, DrawGetTextAlignment, DrawSetTextAlignment, u32 + get_text_antialias, set_text_antialias, DrawGetTextAntialias, DrawSetTextAntialias, u32 + get_text_decoration, set_text_decoration, DrawGetTextDecoration, DrawSetTextDecoration, u32 + get_text_direction, set_text_direction, DrawGetTextDirection, DrawSetTextDirection, u32 + get_text_kerning, set_text_kerning, DrawGetTextKerning, DrawSetTextKerning, f64 + get_text_interline_spacing, set_text_interline_spacing, DrawGetTextInterlineSpacing, DrawSetTextInterlineSpacing, f64 + get_text_interword_spacing, set_text_interword_spacing, DrawGetTextInterwordSpacing, DrawSetTextInterwordSpacing, f64 + ); +} + +impl fmt::Debug for DrawingWand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "DrawingWand {{")); + try!(writeln!(f, " Exception: {:?}", self.get_exception())); + try!(writeln!(f, " IsWand: {:?}", self.is_wand())); + try!(self.fmt_unchecked_settings(f, " ")); + try!(self.fmt_string_settings(f, " ")); + try!(self.fmt_string_unchecked_settings(f, " ")); + try!(self.fmt_pixel_settings(f, " ")); + writeln!(f, "}}") + } +} diff --git a/src/wand/macros.rs b/src/wand/macros.rs new file mode 100644 index 0000000..d1aa154 --- /dev/null +++ b/src/wand/macros.rs @@ -0,0 +1,214 @@ +macro_rules! wand_common { + ( $wand:ident, + $new_wand:ident, $clear_wand:ident, $is_wand:ident, $clone:ident, $destroy:ident, + $clear_exc:ident, $get_exc_type:ident, $get_exc:ident + ) => { + pub struct $wand { + pub wand: *mut ::bindings::$wand + } + + impl $wand { + pub fn new() -> Self { + $wand { + wand: unsafe { ::bindings::$new_wand() } + } + } + + fn clear(&mut self) { + unsafe { ::bindings::$clear_wand(self.wand) } + } + + fn clear_exception(&mut self) -> Result<(), &'static str> { + match unsafe { ::bindings::$clear_exc(self.wand) } { + ::bindings::MagickTrue => Ok(()), + _ => Err(concat!("failed to clear", stringify!($wand), "exception")) + } + } + + fn get_exception_type(&self) -> u32 { + unsafe { ::bindings::$get_exc_type(self.wand) } + } + + fn get_exception(&self) -> Result<(String, u32), &'static str> { + let mut severity: u32 = 0; + // TODO: memory management + let ptr = unsafe { ::bindings::$get_exc(self.wand, &mut severity as *mut _) }; + if ptr.is_null() { + Err(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> { + match unsafe { ::bindings::$is_wand(self.wand) } { + ::bindings::MagickTrue => Ok(()), + _ => Err(concat!(stringify!($wand), " not a wand")) + } + } + } + + impl Clone for $wand { + fn clone(&self) -> Self { + $wand { + wand: unsafe { ::bindings::$clone(self.wand) } + } + } + } + + impl Drop for $wand { + fn drop(&mut self) { + unsafe { + ::bindings::$clear_exc(self.wand); + ::bindings::$destroy(self.wand); + } + } + } + } +} + +macro_rules! set_get { + ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => { + $( + pub fn $get(&self) -> $typ { + unsafe { ::bindings::$c_get(self.wand) } + } + pub fn $set(&mut self, v: $typ) -> Result<(), &'static str> { + match unsafe { ::bindings::$c_set(self.wand, v) } { + ::bindings::MagickTrue => Ok(()), + _ => Err(concat!(stringify!($set), " returned false")) + } + } + )* + pub fn fmt_checked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + $( try!(writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())); )* + Ok(()) + } + } +} + +macro_rules! set_get_unchecked { + ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => { + $( + pub fn $get(&self) -> $typ { + unsafe { ::bindings::$c_get(self.wand) } + } + pub fn $set(&mut self, v: $typ) { + unsafe { ::bindings::$c_set(self.wand, v) } + } + )* + pub fn fmt_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + $( try!(writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())); )* + Ok(()) + } + } +} + +macro_rules! string_get { + ($get:ident, $c_get:ident) => { + pub fn $get(&self) -> Result { + // TODO: memory management + let ptr = unsafe { ::bindings::$c_get(self.wand) }; + if ptr.is_null() { + Err(concat!("null ptr returned by ", stringify!($get))) + } else { + let c_str = unsafe { ::std::ffi::CStr::from_ptr(ptr) }; + Ok(c_str.to_string_lossy().into_owned()) + } + } + } +} + +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> { + let c_string = try!(::std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")); + match unsafe { ::bindings::$c_set(self.wand, c_string.as_ptr()) } { + ::bindings::MagickTrue => Ok(()), + _ => Err(concat!(stringify!($set), " returned false")) + } + } + )* + pub fn fmt_string_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + $( try!(writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())); )* + Ok(()) + } + } +} + + +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> { + let c_string = try!(::std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")); + unsafe { ::bindings::$c_set(self.wand, c_string.as_ptr()) }; + Ok(()) + } + )* + pub fn fmt_string_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + $( try!(writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())); )* + Ok(()) + } + } +} + + +macro_rules! pixel_set_get { + ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => { + $( + pub fn $get(&self) -> ::PixelWand { + let pw = ::PixelWand::new(); + unsafe { ::bindings::$c_get(self.wand, pw.wand) }; + pw + } + pub fn $set(&mut self, pw: &::PixelWand) { + unsafe { ::bindings::$c_set(self.wand, pw.wand) } + } + )* + pub fn fmt_pixel_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + $( + try!(writeln!(f, "{}{:<50}: ", prefix, stringify!($c_get))); + try!(self.$get().fmt_w_prefix(f, &format!("{}{:<53}", prefix, " ") )); + )* + Ok(()) + } + } +} + +macro_rules! color_set_get { + ($( + $get:ident, $get_quantum:ident, $set:ident, $set_quantum:ident, + $c_get:ident, $c_get_quantum:ident, $c_set:ident, $c_set_quantum:ident + )*) => { + $( + pub fn $get(&self) -> f64 { + unsafe { ::bindings::$c_get(self.wand) } + } + pub fn $get_quantum(&self) -> u16 { + unsafe { ::bindings::$c_get_quantum(self.wand) } + } + pub fn $set(&mut self, v: f64) { + unsafe { ::bindings::$c_set(self.wand, v) } + } + pub fn $set_quantum(&mut self, v: u16) { + unsafe { ::bindings::$c_set_quantum(self.wand, v) } + } + )* + pub fn fmt_color_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { + try!(writeln!(f, "{}Color: {:?}, normalized: {:?}\n{}hsl: {:?}", + prefix, + self.get_color_as_string(), + self.get_color_as_normalized_string(), + prefix, + self.get_hsl() + )); + $( try!(writeln!(f, "{}{:<10}: {:>} quantum: {}", prefix, stringify!($c_get).split_at(8).1, self.$get(), self.$get_quantum())); )* + Ok(()) + } + } +} diff --git a/src/wand/magick.rs b/src/wand/magick.rs index a744956..d07fc60 100644 --- a/src/wand/magick.rs +++ b/src/wand/magick.rs @@ -1,8 +1,13 @@ -use std::ffi::{CStr, CString}; +use std::fmt; use std::ptr; +use std::ffi::{CStr, CString}; use libc::{c_uint, c_double, c_void}; + use ::filters::FilterType; use ::bindings; +use ::conversions::*; +use super::{DrawingWand, PixelWand}; + /// MagickWand is a Rustic wrapper to the Rust bindings to ImageMagick. /// @@ -10,17 +15,55 @@ use ::bindings; /// 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 -} +wand_common!( + MagickWand, + NewMagickWand, ClearMagickWand, IsMagickWand, CloneMagickWand, DestroyMagickWand, + MagickClearException, MagickGetExceptionType, MagickGetException +); impl MagickWand { - /// Create a new MagickWand instance. This instance will be properly - /// cleaned up once it falls out of scope. - pub fn new() -> MagickWand { + pub fn new_image(&self, columns: u64, rows: u64, pixel_wand: &PixelWand) -> Result<(), &'static str> { + match unsafe { bindings::MagickNewImage(self.wand, columns, rows, pixel_wand.wand) } { + bindings::MagickTrue => Ok(()), + _ => Err("Could not create image"), + } + } + + pub fn annotate_image(&mut self, drawing_wand: &DrawingWand, x: f64, y: f64, angle: f64, text: &str) -> Result<(), &'static str> { + let c_string = try!(CString::new(text).map_err(|_| "could not convert to cstring")); + match unsafe { bindings::MagickAnnotateImage(self.wand, drawing_wand.wand, x, y, angle, c_string.as_ptr() as *const _) } { + bindings::MagickTrue => Ok(()), + _ => Err("unable to annotate image") + } + } + + pub fn append_all(&mut self, stack: bool) -> MagickWand { + unsafe { bindings::MagickResetIterator(self.wand) }; MagickWand { - wand: unsafe { bindings::NewMagickWand() } + wand: unsafe { bindings::MagickAppendImages(self.wand, stack.to_magick()) } + } + } + + pub fn label_image(&self, label: &str) -> Result<(), &'static str> { + let c_label = CString::new(label).unwrap(); + let result = unsafe { + bindings::MagickLabelImage(self.wand, c_label.as_ptr()) + }; + match result { + bindings::MagickTrue => Ok(()), + _ => Err("failed to add label") + } + } + + pub fn write_images(&self, path: &str, adjoin: bool) -> Result<(), &'static str> { + let c_name = CString::new(path).unwrap(); + let result = unsafe { + bindings::MagickWriteImages(self.wand, c_name.as_ptr(), adjoin.to_magick()) + }; + match result { + bindings::MagickTrue => Ok(()), + _ => Err("failed to write images") } } @@ -173,16 +216,57 @@ impl MagickWand { }; Ok(bytes) } + + string_set_get!( + get_filename, set_filename, MagickGetFilename, MagickSetFilename + get_font, set_font, MagickGetFont, MagickSetFont + get_format, set_format, MagickGetFormat, MagickSetFormat + get_image_filename, set_image_filename, MagickGetImageFilename, MagickSetImageFilename + get_image_format, set_image_format, MagickGetImageFormat, MagickSetImageFormat + ); + + set_get!( + get_colorspace, set_colorspace, MagickGetColorspace, MagickSetColorspace, u32 + get_compression, set_compression, MagickGetCompression, MagickSetCompression, u32 + get_compression_quality, set_compression_quality, MagickGetCompressionQuality, MagickSetCompressionQuality, u64 + get_gravity, set_gravity, MagickGetGravity, MagickSetGravity, u32 + get_image_colorspace, set_image_colorspace, MagickGetImageColorspace, MagickSetImageColorspace, u32 + get_image_compose, set_image_compose, MagickGetImageCompose, MagickSetImageCompose, u32 + get_image_compression, set_image_compression, MagickGetImageCompression, MagickSetImageCompression, u32 + get_image_compression_quality, set_image_compression_quality, MagickGetImageCompressionQuality, MagickSetImageCompressionQuality, u64 + get_image_delay, set_image_delay, MagickGetImageDelay, MagickSetImageDelay, u64 + get_image_depth, set_image_depth, MagickGetImageDepth, MagickSetImageDepth, u64 + get_image_dispose, set_image_dispose, MagickGetImageDispose, MagickSetImageDispose, u32 + get_image_endian, set_image_endian, MagickGetImageEndian, MagickSetImageEndian, u32 + get_image_fuzz, set_image_fuzz, MagickGetImageFuzz, MagickSetImageFuzz, f64 + get_image_gamma, set_image_gamma, MagickGetImageGamma, MagickSetImageGamma, f64 + get_image_gravity, set_image_gravity, MagickGetImageGravity, MagickSetImageGravity, u32 + get_image_index, set_image_index, MagickGetImageIndex, MagickSetImageIndex, i64 + get_image_interlace_scheme, set_image_interlace_scheme, MagickGetImageInterlaceScheme, MagickSetImageInterlaceScheme, u32 + get_image_interpolate_method, set_image_interpolate_method, MagickGetImageInterpolateMethod, MagickSetImageInterpolateMethod, u32 + get_image_iterations, set_image_iterations, MagickGetImageIterations, MagickSetImageIterations, u64 + get_image_orientation, set_image_orientation, MagickGetImageOrientation, MagickSetImageOrientation, u32 + get_image_rendering_intent, set_image_rendering_intent, MagickGetImageRenderingIntent, MagickSetImageRenderingIntent, u32 + get_image_scene, set_image_scene, MagickGetImageScene, MagickSetImageScene, u64 + get_image_type, set_image_type, MagickGetImageType, MagickSetImageType, u32 + get_image_units, set_image_units, MagickGetImageUnits, MagickSetImageUnits, u32 + get_interlace_scheme, set_interlace_scheme, MagickGetInterlaceScheme, MagickSetInterlaceScheme, u32 + get_interpolate_method, set_interpolate_method, MagickGetInterpolateMethod, MagickSetInterpolateMethod, u32 + get_iterator_index, set_iterator_index, MagickGetIteratorIndex, MagickSetIteratorIndex, i64 + get_orientation, set_orientation, MagickGetOrientation, MagickSetOrientation, u32 + get_pointsize, set_pointsize, MagickGetPointsize, MagickSetPointsize, f64 + get_type, set_type, MagickGetType, MagickSetType, u32 + ); + } -// 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); - } +impl fmt::Debug for MagickWand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(writeln!(f, "MagickWand {{")); + try!(writeln!(f, " Exception: {:?}", self.get_exception())); + try!(writeln!(f, " IsWand: {:?}", self.is_wand())); + try!(self.fmt_string_settings(f, " ")); + try!(self.fmt_checked_settings(f, " ")); + writeln!(f, "}}") } } diff --git a/src/wand/mod.rs b/src/wand/mod.rs index 5ac3b6d..bad31d4 100644 --- a/src/wand/mod.rs +++ b/src/wand/mod.rs @@ -1,3 +1,8 @@ +#[macro_use] mod macros; mod magick; +mod drawing; +mod pixel; pub use self::magick::MagickWand; +pub use self::drawing::DrawingWand; +pub use self::pixel::{HSL, PixelWand}; diff --git a/src/wand/pixel.rs b/src/wand/pixel.rs new file mode 100644 index 0000000..9b479f5 --- /dev/null +++ b/src/wand/pixel.rs @@ -0,0 +1,99 @@ +use std::fmt; +use std::ffi::{CStr, CString}; +use ::bindings; + + +#[derive(Default, Debug)] +pub struct HSL { + hue: f64, + saturation: f64, + lightness: f64 +} + +wand_common!( + PixelWand, + NewPixelWand, ClearPixelWand, IsPixelWand, ClonePixelWand, DestroyPixelWand, + PixelClearException, PixelGetExceptionType, PixelGetException +); + +impl PixelWand { + pub fn is_similar(&self, other: &PixelWand, fuzz: f64) -> Result<(), &'static str> { + match unsafe { bindings::IsPixelWandSimilar(self.wand, other.wand, fuzz) } { + bindings::MagickTrue => Ok(()), + _ => Err("not similar") + } + } + + pub fn get_hsl(&self) -> HSL { + let mut hsl = HSL::default(); + unsafe { bindings::PixelGetHSL( + self.wand, + &mut hsl.hue as *mut _, + &mut hsl.saturation as *mut _, + &mut hsl.lightness as *mut _ + );} + hsl + } + + pub fn set_hsl(&self, hsl: &HSL) { + unsafe { bindings::PixelSetHSL( + self.wand, + hsl.hue, + hsl.saturation, + hsl.lightness + );} + } + + pub fn fmt_w_prefix(&self, f: &mut fmt::Formatter, prefix: &str) -> fmt::Result { + let mut prf = prefix.to_string(); + prf.push_str(" "); + try!(writeln!(f, "{}PixelWand {{", prefix)); + try!(writeln!(f, "{}Exception: {:?}", prf, self.get_exception())); + try!(writeln!(f, "{}IsWand: {:?}", prf, self.is_wand())); + try!(self.fmt_unchecked_settings(f, &prf)); + try!(self.fmt_color_settings(f, &prf)); + writeln!(f, "{}}}", prefix) + } + + pub fn set_color(&mut self, s: &str) -> Result<(), &'static str> { + let c_string = try!(CString::new(s).map_err(|_| "could not convert to cstring")); + match unsafe { bindings::PixelSetColor(self.wand, c_string.as_ptr())} { + bindings::MagickTrue => Ok(()), + _ => Err("failed to set color") + } + } + + string_get!(get_color_as_string, PixelGetColorAsString); + string_get!(get_color_as_normalized_string, PixelGetColorAsNormalizedString); + + set_get_unchecked!( + get_color_count, set_color_count, PixelGetColorCount, PixelSetColorCount, u64 + get_index, set_index, PixelGetIndex, PixelSetIndex, u16 + get_fuzz, set_fuzz, PixelGetFuzz, PixelSetFuzz, f64 + ); + + color_set_get!( + get_alpha, get_alpha_quantum, set_alpha, set_alpha_quantum, + PixelGetAlpha, PixelGetAlphaQuantum, PixelSetAlpha, PixelSetAlphaQuantum + get_black, get_black_quantum, set_black, set_black_quantum, + PixelGetBlack, PixelGetBlackQuantum, PixelSetBlack, PixelSetBlackQuantum + get_blue, get_blue_quantum, set_blue, set_blue_quantum, + PixelGetBlue, PixelGetBlueQuantum, PixelSetBlue, PixelSetBlueQuantum + get_cyan, get_cyan_quantum, set_cyan, set_cyan_quantum, + PixelGetCyan, PixelGetCyanQuantum, PixelSetCyan, PixelSetCyanQuantum + get_green, get_green_quantum, set_green, set_green_quantum, + PixelGetGreen, PixelGetGreenQuantum, PixelSetGreen, PixelSetGreenQuantum + get_magenta, get_magenta_quantum, set_magenta, set_magenta_quantum, + PixelGetMagenta, PixelGetMagentaQuantum, PixelSetMagenta, PixelSetMagentaQuantum + get_red, get_red_quantum, set_red, set_red_quantum, + PixelGetRed, PixelGetRedQuantum, PixelSetRed, PixelSetRedQuantum + get_yellow, get_yellow_quantum, set_yellow, set_yellow_quantum, + PixelGetYellow, PixelGetYellowQuantum, PixelSetYellow, PixelSetYellowQuantum + ); +} + +impl fmt::Debug for PixelWand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.fmt_w_prefix(f, "") + } +}