diff --git a/src/lib.rs b/src/lib.rs index 78a2dc1..b7d5877 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,8 +33,6 @@ extern crate libc; use libc::size_t; -#[cfg(not(target_os = "freebsd"))] -use libc::ssize_t; pub use conversions::ToMagick; pub use result::MagickError; diff --git a/src/types/align_type.rs b/src/types/align_type.rs new file mode 100644 index 0000000..c6a8c99 --- /dev/null +++ b/src/types/align_type.rs @@ -0,0 +1,39 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum AlignType { + Undefined = bindings::AlignType_UndefinedAlign, + Left = bindings::AlignType_LeftAlign, + Center = bindings::AlignType_CenterAlign, + Right = bindings::AlignType_RightAlign, +} + +impl Default for AlignType { + fn default() -> Self { + return AlignType::Undefined; + } +} + +impl From for bindings::AlignType { + fn from(value: AlignType) -> Self { + return value as bindings::AlignType; + } +} + +impl From for AlignType { + fn from(value: bindings::AlignType) -> Self { + /* + * SAFETY: + * + * `AlignType` has the same repr as `bindings::AlignType` - u32 + * + * If `value` is less than Right than it is in the vaild range and can be safely + * reinterpreted as `AlignType` + */ + if value <= bindings::AlignType_RightAlign { + return unsafe { std::mem::transmute(value) }; + } + return AlignType::default(); + } +} diff --git a/src/types/alpha_channel_option.rs b/src/types/alpha_channel_option.rs new file mode 100644 index 0000000..51d8551 --- /dev/null +++ b/src/types/alpha_channel_option.rs @@ -0,0 +1,52 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum AlphaChannelOption { + Undefined = bindings::AlphaChannelOption_UndefinedAlphaChannel, + Activate = bindings::AlphaChannelOption_ActivateAlphaChannel, + Associate = bindings::AlphaChannelOption_AssociateAlphaChannel, + Background = bindings::AlphaChannelOption_BackgroundAlphaChannel, + Copy = bindings::AlphaChannelOption_CopyAlphaChannel, + Deactivate = bindings::AlphaChannelOption_DeactivateAlphaChannel, + Discrete = bindings::AlphaChannelOption_DiscreteAlphaChannel, + Disassociate = bindings::AlphaChannelOption_DisassociateAlphaChannel, + Extract = bindings::AlphaChannelOption_ExtractAlphaChannel, + Off = bindings::AlphaChannelOption_OffAlphaChannel, + On = bindings::AlphaChannelOption_OnAlphaChannel, + Opaque = bindings::AlphaChannelOption_OpaqueAlphaChannel, + Remove = bindings::AlphaChannelOption_RemoveAlphaChannel, + Set = bindings::AlphaChannelOption_SetAlphaChannel, + Shape = bindings::AlphaChannelOption_ShapeAlphaChannel, + Transparent = bindings::AlphaChannelOption_TransparentAlphaChannel, + OffIfOpaque = bindings::AlphaChannelOption_OffIfOpaqueAlphaChannel, +} + +impl Default for AlphaChannelOption { + fn default() -> Self { + return AlphaChannelOption::Undefined; + } +} + +impl From for bindings::AlphaChannelOption { + fn from(value: AlphaChannelOption) -> Self { + return value as bindings::AlphaChannelOption; + } +} + +impl From for AlphaChannelOption { + fn from(value: bindings::AlphaChannelOption) -> Self { + /* + * SAFETY: + * + * `AlphaChannelOption` has the same repr as `bindings::AlphaChannelOption` - u32 + * + * If `value` is less than OffIfOpaque than it is in the vaild range and can be safely + * reinterpreted as `AlphaChannelOption` + */ + if value <= bindings::AlphaChannelOption_OffIfOpaqueAlphaChannel { + return unsafe { std::mem::transmute(value) }; + } + return AlphaChannelOption::default(); + } +} diff --git a/src/types/auto_threshold_method.rs b/src/types/auto_threshold_method.rs new file mode 100644 index 0000000..3bb7e7a --- /dev/null +++ b/src/types/auto_threshold_method.rs @@ -0,0 +1,22 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum AutoThresholdMethod { + Undefined = bindings::AutoThresholdMethod_UndefinedThresholdMethod, + Kapur = bindings::AutoThresholdMethod_KapurThresholdMethod, + OTSU = bindings::AutoThresholdMethod_OTSUThresholdMethod, + Triangle = bindings::AutoThresholdMethod_TriangleThresholdMethod, +} + +impl Default for AutoThresholdMethod { + fn default() -> Self { + return AutoThresholdMethod::Undefined; + } +} + +impl From for bindings::AutoThresholdMethod { + fn from(value: AutoThresholdMethod) -> Self { + return value as bindings::AutoThresholdMethod; + } +} diff --git a/src/types/channel_type.rs b/src/types/channel_type.rs new file mode 100644 index 0000000..46e42cf --- /dev/null +++ b/src/types/channel_type.rs @@ -0,0 +1,105 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy)] +pub enum ChannelType { + Undefined, + RedChannel, + GrayChannel, + CyanChannel, + LChannel, + GreenChannel, + MagentaChannel, + aChannel, + BlueChannel, + bChannel, + YellowChannel, + BlackChannel, + AlphaChannel, + OpacityChannel, + IndexChannel, + ReadMaskChannel, + WriteMaskChannel, + MetaChannel, + CompositeMaskChannel, + CompositeChannels, + AllChannels, + TrueAlphaChannel, + RGBChannels, + GrayChannels, + SyncChannels, + DefaultChannels, +} + +impl Default for ChannelType { + fn default() -> Self { + return ChannelType::DefaultChannels; + } +} + +impl From for bindings::ChannelType { + fn from(value: ChannelType) -> Self { + match value { + ChannelType::Undefined => { bindings::ChannelType_UndefinedChannel }, + ChannelType::RedChannel => { bindings::ChannelType_RedChannel }, + ChannelType::GrayChannel => { bindings::ChannelType_GrayChannel }, + ChannelType::CyanChannel => { bindings::ChannelType_CyanChannel }, + ChannelType::LChannel => { bindings::ChannelType_LChannel }, + ChannelType::GreenChannel => { bindings::ChannelType_GreenChannel }, + ChannelType::MagentaChannel => { bindings::ChannelType_MagentaChannel }, + ChannelType::aChannel => { bindings::ChannelType_aChannel }, + ChannelType::BlueChannel => { bindings::ChannelType_BlueChannel }, + ChannelType::bChannel => { bindings::ChannelType_bChannel }, + ChannelType::YellowChannel => { bindings::ChannelType_YellowChannel }, + ChannelType::BlackChannel => { bindings::ChannelType_BlackChannel }, + ChannelType::AlphaChannel => { bindings::ChannelType_AlphaChannel }, + ChannelType::OpacityChannel => { bindings::ChannelType_OpacityChannel }, + ChannelType::IndexChannel => { bindings::ChannelType_IndexChannel }, + ChannelType::ReadMaskChannel => { bindings::ChannelType_ReadMaskChannel }, + ChannelType::WriteMaskChannel => { bindings::ChannelType_WriteMaskChannel }, + ChannelType::MetaChannel => { bindings::ChannelType_MetaChannel }, + ChannelType::CompositeMaskChannel => { bindings::ChannelType_CompositeMaskChannel }, + ChannelType::CompositeChannels => { bindings::ChannelType_CompositeChannels }, + ChannelType::AllChannels => { bindings::ChannelType_AllChannels }, + ChannelType::TrueAlphaChannel => { bindings::ChannelType_TrueAlphaChannel }, + ChannelType::RGBChannels => { bindings::ChannelType_RGBChannels }, + ChannelType::GrayChannels => { bindings::ChannelType_GrayChannels }, + ChannelType::SyncChannels => { bindings::ChannelType_SyncChannels }, + ChannelType::DefaultChannels => { bindings::ChannelType_DefaultChannels }, + } + } +} + +impl From for ChannelType { + fn from(value: bindings::ChannelType) -> Self { + // Unreachable match arms commented out + match value { + bindings::ChannelType_UndefinedChannel => { ChannelType::Undefined }, + bindings::ChannelType_RedChannel => { ChannelType::RedChannel }, + // bindings::ChannelType_GrayChannel => { ChannelType::GrayChannel }, + // bindings::ChannelType_CyanChannel => { ChannelType::CyanChannel }, + // bindings::ChannelType_LChannel => { ChannelType::LChannel }, + bindings::ChannelType_GreenChannel => { ChannelType::GreenChannel }, + // bindings::ChannelType_MagentaChannel => { ChannelType::MagentaChannel }, + // bindings::ChannelType_aChannel => { ChannelType::aChannel }, + bindings::ChannelType_BlueChannel => { ChannelType::BlueChannel }, + // bindings::ChannelType_bChannel => { ChannelType::bChannel }, + // bindings::ChannelType_YellowChannel => { ChannelType::YellowChannel }, + bindings::ChannelType_BlackChannel => { ChannelType::BlackChannel }, + bindings::ChannelType_AlphaChannel => { ChannelType::AlphaChannel }, + // bindings::ChannelType_OpacityChannel => { ChannelType::OpacityChannel }, + bindings::ChannelType_IndexChannel => { ChannelType::IndexChannel }, + bindings::ChannelType_ReadMaskChannel => { ChannelType::ReadMaskChannel }, + bindings::ChannelType_WriteMaskChannel => { ChannelType::WriteMaskChannel }, + bindings::ChannelType_MetaChannel => { ChannelType::MetaChannel }, + bindings::ChannelType_CompositeMaskChannel => { ChannelType::CompositeMaskChannel }, + bindings::ChannelType_CompositeChannels => { ChannelType::CompositeChannels }, + bindings::ChannelType_AllChannels => { ChannelType::AllChannels }, + // bindings::ChannelType_TrueAlphaChannel => { ChannelType::TrueAlphaChannel }, + // bindings::ChannelType_RGBChannels => { ChannelType::RGBChannels }, + bindings::ChannelType_GrayChannels => { ChannelType::GrayChannels }, + bindings::ChannelType_SyncChannels => { ChannelType::SyncChannels }, + // bindings::ChannelType_DefaultChannels => { ChannelType::DefaultChannels }, + _ => { ChannelType::Undefined }, + } + } +} diff --git a/src/types/clip_path_units.rs b/src/types/clip_path_units.rs new file mode 100644 index 0000000..762efe8 --- /dev/null +++ b/src/types/clip_path_units.rs @@ -0,0 +1,39 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum ClipPathUnits { + Undefined = bindings::ClipPathUnits_UndefinedPathUnits, + UserSpace = bindings::ClipPathUnits_UserSpace, + UserSpaceOnUse = bindings::ClipPathUnits_UserSpaceOnUse, + ObjectBoundingBox = bindings::ClipPathUnits_ObjectBoundingBox, +} + +impl Default for ClipPathUnits { + fn default() -> Self { + return ClipPathUnits::Undefined; + } +} + +impl From for bindings::ClipPathUnits { + fn from(value: ClipPathUnits) -> Self { + return value as bindings::ClipPathUnits; + } +} + +impl From for ClipPathUnits { + fn from(value: bindings::ClipPathUnits) -> Self { + /* + * SAFETY: + * + * `ClipPathUnits` has the same repr as `bindings::ClipPathUnits` - u32 + * + * If `value` is less than ObjectBoundingBox than it is in the vaild range and can be safely + * reinterpreted as `ClipPathUnits` + */ + if value <= bindings::ClipPathUnits_ObjectBoundingBox { + return unsafe { std::mem::transmute(value) }; + } + return ClipPathUnits::default(); + } +} diff --git a/src/types/compression_type.rs b/src/types/compression_type.rs new file mode 100644 index 0000000..3a3799d --- /dev/null +++ b/src/types/compression_type.rs @@ -0,0 +1,64 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum CompressionType { + Undefined = bindings::CompressionType_UndefinedCompression, + B44A = bindings::CompressionType_B44ACompression, + B44 = bindings::CompressionType_B44Compression, + BZip = bindings::CompressionType_BZipCompression, + DXT1 = bindings::CompressionType_DXT1Compression, + DXT3 = bindings::CompressionType_DXT3Compression, + DXT5 = bindings::CompressionType_DXT5Compression, + Fax = bindings::CompressionType_FaxCompression, + Group4 = bindings::CompressionType_Group4Compression, + JBIG1 = bindings::CompressionType_JBIG1Compression, + JBIG2 = bindings::CompressionType_JBIG2Compression, + JPEG2000 = bindings::CompressionType_JPEG2000Compression, + JPEG = bindings::CompressionType_JPEGCompression, + LosslessJPEG = bindings::CompressionType_LosslessJPEGCompression, + LZMA = bindings::CompressionType_LZMACompression, + LZW = bindings::CompressionType_LZWCompression, + No = bindings::CompressionType_NoCompression, + Piz = bindings::CompressionType_PizCompression, + Pxr24 = bindings::CompressionType_Pxr24Compression, + RLE = bindings::CompressionType_RLECompression, + Zip = bindings::CompressionType_ZipCompression, + ZipS = bindings::CompressionType_ZipSCompression, + Zstd = bindings::CompressionType_ZstdCompression, + WebP = bindings::CompressionType_WebPCompression, + DWAA = bindings::CompressionType_DWAACompression, + DWAB = bindings::CompressionType_DWABCompression, + BC7 = bindings::CompressionType_BC7Compression, + BC5 = bindings::CompressionType_BC5Compression, + LERC = bindings::CompressionType_LERCCompression, +} + +impl Default for CompressionType { + fn default() -> Self { + return CompressionType::Undefined; + } +} + +impl From for bindings::CompressionType { + fn from(value: CompressionType) -> Self { + return value as bindings::CompressionType; + } +} + +impl From for CompressionType { + fn from(value: bindings::CompressionType) -> Self { + /* + * SAFETY: + * + * `CompressionType` has the same repr as `bindings::CompressionType` - u32 + * + * If `value` is less than LERC than it is in the vaild range and can be safely + * reinterpreted as `CompressionType` + */ + if value <= bindings::CompressionType_LERCCompression { + return unsafe { std::mem::transmute(value) }; + } + return CompressionType::default(); + } +} diff --git a/src/types/decoration_type.rs b/src/types/decoration_type.rs new file mode 100644 index 0000000..a5d8efb --- /dev/null +++ b/src/types/decoration_type.rs @@ -0,0 +1,40 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum DecorationType { + Undefined = bindings::DecorationType_UndefinedDecoration, + No = bindings::DecorationType_NoDecoration, + Underline = bindings::DecorationType_UnderlineDecoration, + Overline = bindings::DecorationType_OverlineDecoration, + LineThrough = bindings::DecorationType_LineThroughDecoration, +} + +impl Default for DecorationType { + fn default() -> Self { + return DecorationType::Undefined; + } +} + +impl From for bindings::DecorationType { + fn from(value: DecorationType) -> Self { + return value as bindings::DecorationType; + } +} + +impl From for DecorationType { + fn from(value: bindings::DecorationType) -> Self { + /* + * SAFETY: + * + * `DecorationType` has the same repr as `bindings::DecorationType` - u32 + * + * If `value` is less than LineThrough than it is in the vaild range and can be safely + * reinterpreted as `DecorationType` + */ + if value <= bindings::DecorationType_LineThroughDecoration { + return unsafe { std::mem::transmute(value) }; + } + return DecorationType::default(); + } +} diff --git a/src/types/direction_type.rs b/src/types/direction_type.rs new file mode 100644 index 0000000..7bcaa2b --- /dev/null +++ b/src/types/direction_type.rs @@ -0,0 +1,39 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum DirectionType { + Undefined = bindings::DirectionType_UndefinedDirection, + RightToLeft = bindings::DirectionType_RightToLeftDirection, + LeftToRight = bindings::DirectionType_LeftToRightDirection, + TopToBottom = bindings::DirectionType_TopToBottomDirection, +} + +impl Default for DirectionType { + fn default() -> Self { + return DirectionType::Undefined; + } +} + +impl From for bindings::DirectionType { + fn from(value: DirectionType) -> Self { + return value as bindings::DirectionType; + } +} + +impl From for DirectionType { + fn from(value: bindings::DirectionType) -> Self { + /* + * SAFETY: + * + * `DirectionType` has the same repr as `bindings::DirectionType` - u32 + * + * If `value` is less than TopToBottom than it is in the vaild range and can be safely + * reinterpreted as `DirectionType` + */ + if value <= bindings::DirectionType_TopToBottomDirection { + return unsafe { std::mem::transmute(value) }; + } + return DirectionType::default(); + } +} diff --git a/src/types/dispose_type.rs b/src/types/dispose_type.rs new file mode 100644 index 0000000..46c632a --- /dev/null +++ b/src/types/dispose_type.rs @@ -0,0 +1,43 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum DisposeType { + /* + * Identical to `Undefined` + */ + // Unrecognized = bindings::DisposeType_UnrecognizedDispose, + Undefined = bindings::DisposeType_UndefinedDispose, + None = bindings::DisposeType_NoneDispose, + Background = bindings::DisposeType_BackgroundDispose, + Previous = bindings::DisposeType_PreviousDispose, +} + +impl Default for DisposeType { + fn default() -> Self { + return DisposeType::Undefined; + } +} + +impl From for bindings::DisposeType { + fn from(value: DisposeType) -> Self { + return value as bindings::DisposeType; + } +} + +impl From for DisposeType { + fn from(value: bindings::DisposeType) -> Self { + /* + * SAFETY: + * + * `DisposeType` has the same repr as `bindings::DisposeType` - u32 + * + * If `value` is less than Previous than it is in the vaild range and can be safely + * reinterpreted as `DisposeType` + */ + if value <= bindings::DisposeType_PreviousDispose { + return unsafe { std::mem::transmute(value) }; + } + return DisposeType::default(); + } +} diff --git a/src/types/endian_type.rs b/src/types/endian_type.rs new file mode 100644 index 0000000..406bb3a --- /dev/null +++ b/src/types/endian_type.rs @@ -0,0 +1,38 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum EndianType { + Undefined = bindings::EndianType_UndefinedEndian, + LSB = bindings::EndianType_LSBEndian, + MSB = bindings::EndianType_MSBEndian, +} + +impl Default for EndianType { + fn default() -> Self { + return EndianType::Undefined; + } +} + +impl From for bindings::EndianType { + fn from(value: EndianType) -> Self { + return value as bindings::EndianType; + } +} + +impl From for EndianType { + fn from(value: bindings::EndianType) -> Self { + /* + * SAFETY: + * + * `EndianType` has the same repr as `bindings::EndianType` - u32 + * + * If `value` is less than MSB than it is in the vaild range and can be safely + * reinterpreted as `EndianType` + */ + if value <= bindings::EndianType_MSBEndian { + return unsafe { std::mem::transmute(value) }; + } + return EndianType::default(); + } +} diff --git a/src/types/fill_rule.rs b/src/types/fill_rule.rs new file mode 100644 index 0000000..d48bf66 --- /dev/null +++ b/src/types/fill_rule.rs @@ -0,0 +1,38 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum FillRule { + Undefined = bindings::FillRule_UndefinedRule, + EvenOdd = bindings::FillRule_EvenOddRule, + NonZero = bindings::FillRule_NonZeroRule, +} + +impl Default for FillRule { + fn default() -> Self { + return FillRule::Undefined; + } +} + +impl From for bindings::FillRule { + fn from(value: FillRule) -> Self { + return value as bindings::FillRule; + } +} + +impl From for FillRule { + fn from(value: bindings::FillRule) -> Self { + /* + * SAFETY: + * + * `FillRule` has the same repr as `bindings::FillRule` - u32 + * + * If `value` is less than NonZero than it is in the vaild range and can be safely + * reinterpreted as `FillRule` + */ + if value <= bindings::FillRule_NonZeroRule { + return unsafe { std::mem::transmute(value) }; + } + return FillRule::default(); + } +} diff --git a/src/types/geometry_info.rs b/src/types/geometry_info.rs new file mode 100644 index 0000000..f9bee99 --- /dev/null +++ b/src/types/geometry_info.rs @@ -0,0 +1,37 @@ +use crate::bindings; + +pub type GeometryInfo = bindings::GeometryInfo; + +impl GeometryInfo { + pub fn new() -> GeometryInfo { + return GeometryInfo { + rho: 0.0, + sigma: 0.0, + xi: 0.0, + psi: 0.0, + chi: 0.0, + }; + } + + pub fn set_rho(&mut self, rho: f64) { + self.rho = rho; + } + pub fn set_sigma(&mut self, sigma: f64) { + self.sigma = sigma; + } + pub fn set_xi(&mut self, xi: f64) { + self.xi = xi; + } + pub fn set_psi(&mut self, psi: f64) { + self.psi = psi; + } + pub fn set_chi(&mut self, chi: f64) { + self.chi = chi; + } +} + +impl Default for GeometryInfo { + fn default() -> Self { + Self::new() + } +} diff --git a/src/types/image.rs b/src/types/image.rs new file mode 100644 index 0000000..17ae07a --- /dev/null +++ b/src/types/image.rs @@ -0,0 +1,21 @@ +use std::marker::PhantomData; + +use crate::bindings; + +pub struct Image<'a> { + image: *mut bindings::Image, + phantom_data: PhantomData<&'a bindings::Image>, +} + +impl Image<'_> { + pub unsafe fn new(img: *mut bindings::Image) -> Self { + Image { + image: img, + phantom_data: PhantomData + } + } + + pub unsafe fn get_ptr(&self) -> *mut bindings::Image { + self.image + } +} diff --git a/src/types/image_type.rs b/src/types/image_type.rs new file mode 100644 index 0000000..2375868 --- /dev/null +++ b/src/types/image_type.rs @@ -0,0 +1,47 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum ImageType { + Undefined = bindings::ImageType_UndefinedType, + Bilevel = bindings::ImageType_BilevelType, + Grayscale = bindings::ImageType_GrayscaleType, + GrayscaleAlpha = bindings::ImageType_GrayscaleAlphaType, + Palette = bindings::ImageType_PaletteType, + PaletteAlpha = bindings::ImageType_PaletteAlphaType, + TrueColor = bindings::ImageType_TrueColorType, + TrueColorAlpha = bindings::ImageType_TrueColorAlphaType, + ColorSeparation = bindings::ImageType_ColorSeparationType, + ColorSeparationAlpha = bindings::ImageType_ColorSeparationAlphaType, + Optimize = bindings::ImageType_OptimizeType, + PaletteBilevelAlpha = bindings::ImageType_PaletteBilevelAlphaType, +} + +impl Default for ImageType { + fn default() -> Self { + return ImageType::Undefined; + } +} + +impl From for bindings::ImageType { + fn from(value: ImageType) -> Self { + return value as bindings::ImageType; + } +} + +impl From for ImageType { + fn from(value: bindings::ImageType) -> Self { + /* + * SAFETY: + * + * `ImageType` has the same repr as `bindings::ImageType` - u32 + * + * If `value` is less than SouthEast than it is in the vaild range and can be safely + * reinterpreted as `ImageType` + */ + if value <= bindings::ImageType_PaletteBilevelAlphaType { + return unsafe { std::mem::transmute(value) }; + } + return ImageType::default(); + } +} diff --git a/src/types/interlace_type.rs b/src/types/interlace_type.rs new file mode 100644 index 0000000..4ad792e --- /dev/null +++ b/src/types/interlace_type.rs @@ -0,0 +1,43 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum InterlaceType { + Undefined = bindings::InterlaceType_UndefinedInterlace, + No = bindings::InterlaceType_NoInterlace, + Line = bindings::InterlaceType_LineInterlace, + Plane = bindings::InterlaceType_PlaneInterlace, + Partition = bindings::InterlaceType_PartitionInterlace, + GIF = bindings::InterlaceType_GIFInterlace, + JPEG = bindings::InterlaceType_JPEGInterlace, + PNG = bindings::InterlaceType_PNGInterlace, +} + +impl Default for InterlaceType { + fn default() -> Self { + return InterlaceType::Undefined; + } +} + +impl From for bindings::InterlaceType { + fn from(value: InterlaceType) -> Self { + return value as bindings::InterlaceType; + } +} + +impl From for InterlaceType { + fn from(value: bindings::InterlaceType) -> Self { + /* + * SAFETY: + * + * `InterlaceType` has the same repr as `bindings::InterlaceType` - u32 + * + * If `value` is less than PNG than it is in the vaild range and can be safely + * reinterpreted as `InterlaceType` + */ + if value <= bindings::InterlaceType_PNGInterlace { + return unsafe { std::mem::transmute(value) }; + } + return InterlaceType::default(); + } +} diff --git a/src/types/kernel.rs b/src/types/kernel.rs new file mode 100644 index 0000000..eea766e --- /dev/null +++ b/src/types/kernel.rs @@ -0,0 +1,390 @@ +use std::ffi::CString; + +use crate::bindings; +use crate::{Result, MagickError}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum KernelInfoType { + Undefined = bindings::KernelInfoType_UndefinedKernel, + Unity = bindings::KernelInfoType_UnityKernel, + Gaussian = bindings::KernelInfoType_GaussianKernel, + DoG = bindings::KernelInfoType_DoGKernel, + LoG = bindings::KernelInfoType_LoGKernel, + Blur = bindings::KernelInfoType_BlurKernel, + Comet = bindings::KernelInfoType_CometKernel, + Binomial = bindings::KernelInfoType_BinomialKernel, + Laplacian = bindings::KernelInfoType_LaplacianKernel, + Sobel = bindings::KernelInfoType_SobelKernel, + FreiChen = bindings::KernelInfoType_FreiChenKernel, + Roberts = bindings::KernelInfoType_RobertsKernel, + Prewitt = bindings::KernelInfoType_PrewittKernel, + Compass = bindings::KernelInfoType_CompassKernel, + Kirsch = bindings::KernelInfoType_KirschKernel, + Diamond = bindings::KernelInfoType_DiamondKernel, + Square = bindings::KernelInfoType_SquareKernel, + Rectangle = bindings::KernelInfoType_RectangleKernel, + Octagon = bindings::KernelInfoType_OctagonKernel, + Disk = bindings::KernelInfoType_DiskKernel, + Plus = bindings::KernelInfoType_PlusKernel, + Cross = bindings::KernelInfoType_CrossKernel, + Ring = bindings::KernelInfoType_RingKernel, + Peaks = bindings::KernelInfoType_PeaksKernel, + Edges = bindings::KernelInfoType_EdgesKernel, + Corners = bindings::KernelInfoType_CornersKernel, + Diagonals = bindings::KernelInfoType_DiagonalsKernel, + LineEnds = bindings::KernelInfoType_LineEndsKernel, + LineJunctions = bindings::KernelInfoType_LineJunctionsKernel, + Ridges = bindings::KernelInfoType_RidgesKernel, + ConvexHull = bindings::KernelInfoType_ConvexHullKernel, + ThinSE = bindings::KernelInfoType_ThinSEKernel, + Skeleton = bindings::KernelInfoType_SkeletonKernel, + Chebyshev = bindings::KernelInfoType_ChebyshevKernel, + Manhattan = bindings::KernelInfoType_ManhattanKernel, + Octagonal = bindings::KernelInfoType_OctagonalKernel, + Euclidean = bindings::KernelInfoType_EuclideanKernel, + UserDefined = bindings::KernelInfoType_UserDefinedKernel, +} + +impl Default for KernelInfoType { + fn default() -> Self { + return KernelInfoType::Undefined; + } +} + +impl From for bindings::KernelInfoType { + fn from(value: KernelInfoType) -> Self { + return value as bindings::KernelInfoType; + } +} + + + + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum MorphologyMethod { + Undefined = bindings::MorphologyMethod_UndefinedMorphology, + Convolve = bindings::MorphologyMethod_ConvolveMorphology, + Correlate = bindings::MorphologyMethod_CorrelateMorphology, + Erode = bindings::MorphologyMethod_ErodeMorphology, + Dilate = bindings::MorphologyMethod_DilateMorphology, + ErodeIntensity = bindings::MorphologyMethod_ErodeIntensityMorphology, + DilateIntensity = bindings::MorphologyMethod_DilateIntensityMorphology, + IterativeDistance = bindings::MorphologyMethod_IterativeDistanceMorphology, + Open = bindings::MorphologyMethod_OpenMorphology, + Close = bindings::MorphologyMethod_CloseMorphology, + OpenIntensity = bindings::MorphologyMethod_OpenIntensityMorphology, + CloseIntensity = bindings::MorphologyMethod_CloseIntensityMorphology, + Smooth = bindings::MorphologyMethod_SmoothMorphology, + EdgeIn = bindings::MorphologyMethod_EdgeInMorphology, + EdgeOut = bindings::MorphologyMethod_EdgeOutMorphology, + Edge = bindings::MorphologyMethod_EdgeMorphology, + TopHat = bindings::MorphologyMethod_TopHatMorphology, + BottomHat = bindings::MorphologyMethod_BottomHatMorphology, + HitAndMiss = bindings::MorphologyMethod_HitAndMissMorphology, + Thinning = bindings::MorphologyMethod_ThinningMorphology, + Thicken = bindings::MorphologyMethod_ThickenMorphology, + Distance = bindings::MorphologyMethod_DistanceMorphology, + Voronoi = bindings::MorphologyMethod_VoronoiMorphology, +} + +impl Default for MorphologyMethod { + fn default() -> Self { + return MorphologyMethod::Undefined; + } +} + +impl From for bindings::KernelInfoType { + fn from(value: MorphologyMethod) -> Self { + return value as bindings::MorphologyMethod; + } +} + + + + +/// Builder, that creates instances of [KernelInfo](self::KernelInfo) +/// +/// # Examples +/// +/// Here is an example of how you can use this struct to create a kernel to convolve an image: +/// +/// ``` +/// use magick_rust::{MagickWand, PixelWand, KernelBuilder}; +/// +/// fn main() -> Result<(), magick_rust::MagickError> { +/// let mut wand1 = MagickWand::new(); +/// wand1.new_image(4, 4, &PixelWand::new())?; // Replace with `read_image` to open your image file +/// let wand2 = wand1.clone(); +/// +/// let kernel_info = KernelBuilder::new() +/// .set_size((3, 3)) +/// .set_center((1, 1)) // Not really needed here - the center is in the middle of kernel +/// // by default +/// .set_values(&[0.111, 0.111, 0.111, +/// 0.111, 0.111, 0.111, +/// 0.111, 0.111, 0.111]) +/// .build()?; +/// +/// wand1.convolve_image(&kernel_info)?; +/// +/// Ok(()) +/// } +/// ``` +/// +/// Here is an example of how you can use this struct to create builtin kernel to gaussian blur an +/// image (not the best way to do it, just an example): +/// +/// ``` +/// use magick_rust::{MagickWand, PixelWand, KernelBuilder, KernelInfoType, GeometryInfo}; +/// +/// fn main() -> Result<(), magick_rust::MagickError> { +/// let mut wand1 = MagickWand::new(); +/// wand1.new_image(4, 4, &PixelWand::new())?; // Replace with `read_image` to open your image file +/// let wand2 = wand1.clone(); +/// +/// let mut geom_info = GeometryInfo::new(); +/// geom_info.set_sigma(15.0); +/// let kernel_info = KernelBuilder::new() +/// .set_info_type(KernelInfoType::Gaussian) +/// .set_geom_info(geom_info) +/// .build_builtin()?; +/// +/// wand1.convolve_image(&kernel_info)?; +/// +/// Ok(()) +/// } +/// ``` +#[derive(Debug, Clone)] +pub struct KernelBuilder { + size: Option<(usize, usize)>, + center: Option<(usize, usize)>, + values: Option>, + + info_type: Option, + geom_info: Option, +} + +impl KernelBuilder { + pub fn new() -> KernelBuilder { + return KernelBuilder { + size: None, + center: None, + values: None, + + info_type: None, + geom_info: None, + }; + } + + /// Used for user defined kernels + pub fn set_size(mut self, size: (usize, usize)) -> KernelBuilder { + self.size = Some(size); + return self; + } + + /// Used for user defined kernels + pub fn set_center(mut self, center: (usize, usize)) -> KernelBuilder { + self.center = Some(center); + return self; + } + + /// Used for user defined kernels + pub fn set_values(mut self, values: &[f64]) -> KernelBuilder { + self.values = Some(values.into()); + return self; + } + + pub fn build(&self) -> Result { + let size = self.size.ok_or(MagickError("no kernel size given"))?; + let values = self.values.as_ref().ok_or(MagickError("no kernel values given"))?; + + if values.len() != size.0 * size.1 { + return Err(MagickError("kernel size doesn't match kernel values size")); + } + + // Create kernel string + let mut kernel_string = if let Some(center) = self.center { + format!( + "{}x{}+{}+{}:", + size.0, + size.1, + center.0, + center.1 + ) + } else { + format!( + "{}x{}:", + size.0, + size.1, + ) + }; + + // Add values + values.iter().for_each(|x| { + kernel_string.push_str(&format!("{x},")); + }); + + // Remove trailing "," + kernel_string.pop(); + + // Create null terminated string + let c_kernel_string = CString::new(kernel_string).expect("CString::new() has failed"); + + // Create kernel info + let kernel_info = unsafe { + bindings::AcquireKernelInfo( + c_kernel_string.as_ptr(), + std::ptr::null_mut() + ) + }; + + if kernel_info.is_null() { + return Err(MagickError("failed to acquire kernel info")); + } + + Ok(KernelInfo::new(kernel_info)) + } + + /// Used for builtin kernels + pub fn set_info_type(mut self, info_type: KernelInfoType) -> KernelBuilder { + self.info_type = Some(info_type); + return self; + } + + /// Used for builtin kernels + pub fn set_geom_info(mut self, geom_info: crate::GeometryInfo) -> KernelBuilder { + self.geom_info = Some(geom_info); + return self; + } + + pub fn build_builtin(&self) -> Result { + let info_type = self.info_type.ok_or(MagickError("no info type given"))?; + let mut geom_info = self.geom_info.ok_or(MagickError("no geometry info given"))?; + + // Create kernel info + let kernel_info = unsafe { + bindings::AcquireKernelBuiltIn( + info_type.into(), + &mut geom_info, + std::ptr::null_mut() + ) + }; + + if kernel_info.is_null() { + return Err(MagickError("failed to acquire builtin kernel info")); + } + + Ok(KernelInfo::new(kernel_info)) + } +} + +pub struct KernelInfo { + kernel_info: *mut bindings::KernelInfo, +} + +impl KernelInfo { + fn new(kernel_info: *mut bindings::KernelInfo) -> KernelInfo { + return KernelInfo { + kernel_info + }; + } + + /// The values within the kernel is scaled directly using given scaling factor without change. + pub fn scale(&mut self, factor: f64) { + unsafe { + bindings::ScaleKernelInfo( + self.kernel_info, + factor, + 0 + ) + } + } + + /// Kernel normalization is designed to ensure that any use of the kernel scaling factor with + /// 'Convolve' or 'Correlate' morphology methods will fall into -1.0 to +1.0 range. Note that + /// for non-HDRI versions of IM this may cause images to have any negative results clipped, + /// unless some 'bias' is used. + /// + /// More specifically. Kernels which only contain positive values (such as a 'Gaussian' kernel) + /// will be scaled so that those values sum to +1.0, ensuring a 0.0 to +1.0 output range for + /// non-HDRI images. + /// + /// For Kernels that contain some negative values, (such as 'Sharpen' kernels) the kernel will + /// be scaled by the absolute of the sum of kernel values, so that it will generally fall + /// within the +/- 1.0 range. + /// + /// For kernels whose values sum to zero, (such as 'Laplacian' kernels) kernel will be scaled + /// by just the sum of the positive values, so that its output range will again fall into the + /// +/- 1.0 range. + pub fn normalize(&mut self) { + unsafe { + bindings::ScaleKernelInfo( + self.kernel_info, + 1.0, + bindings::GeometryFlags_NormalizeValue + ) + } + } + + /// For special kernels designed for locating shapes using 'Correlate', (often only containing + /// +1 and -1 values, representing foreground/background matching) a special normalization + /// method is provided to scale the positive values separately to those of the negative values, + /// so the kernel will be forced to become a zero-sum kernel better suited to such searches. + pub fn correlate_normalize(&mut self) { + unsafe { + bindings::ScaleKernelInfo( + self.kernel_info, + 1.0, + bindings::GeometryFlags_CorrelateNormalizeValue + ) + } + } + + /// Adds a given amount of the 'Unity' Convolution Kernel to the given pre-scaled and + /// normalized Kernel. This in effect adds that amount of the original image into the resulting + /// convolution kernel. This value is usually provided by the user as a percentage value in the + /// 'convolve:scale' setting. + /// + /// The resulting effect is to convert the defined kernels into blended soft-blurs, unsharp + /// kernels or into sharpening kernels. + pub fn unity_add(&mut self, scale: f64) { + unsafe { + bindings::UnityAddKernelInfo( + self.kernel_info, + scale + ) + } + } + + pub unsafe fn get_ptr(&self) -> *mut bindings::KernelInfo { + return self.kernel_info; + } +} + +impl Drop for KernelInfo { + fn drop(&mut self) { + unsafe { bindings::DestroyKernelInfo(self.kernel_info) }; + } +} + +impl Clone for KernelInfo { + fn clone(&self) -> Self { + let kernel_info = unsafe { + bindings::CloneKernelInfo(self.kernel_info) + }; + + if kernel_info.is_null() { + panic!("failed to clone kernel info"); + } + + return KernelInfo::new(kernel_info); + } +} + +impl std::fmt::Debug for KernelInfo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + unsafe { write!(f, "{:?}", *self.kernel_info) } + } +} diff --git a/src/types/layer_method.rs b/src/types/layer_method.rs new file mode 100644 index 0000000..e502af9 --- /dev/null +++ b/src/types/layer_method.rs @@ -0,0 +1,35 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum LayerMethod { + Undefined = bindings::LayerMethod_UndefinedLayer, + Coalesce = bindings::LayerMethod_CoalesceLayer, + CompareAny = bindings::LayerMethod_CompareAnyLayer, + CompareClear = bindings::LayerMethod_CompareClearLayer, + CompareOverlay = bindings::LayerMethod_CompareOverlayLayer, + Dispose = bindings::LayerMethod_DisposeLayer, + Optimize = bindings::LayerMethod_OptimizeLayer, + OptimizeImage = bindings::LayerMethod_OptimizeImageLayer, + OptimizePlus = bindings::LayerMethod_OptimizePlusLayer, + OptimizeTrans = bindings::LayerMethod_OptimizeTransLayer, + RemoveDups = bindings::LayerMethod_RemoveDupsLayer, + RemoveZero = bindings::LayerMethod_RemoveZeroLayer, + Composite = bindings::LayerMethod_CompositeLayer, + Merge = bindings::LayerMethod_MergeLayer, + Flatten = bindings::LayerMethod_FlattenLayer, + Mosaic = bindings::LayerMethod_MosaicLayer, + TrimBounds = bindings::LayerMethod_TrimBoundsLayer, +} + +impl Default for LayerMethod { + fn default() -> Self { + return LayerMethod::Undefined; + } +} + +impl From for bindings::LayerMethod { + fn from(value: LayerMethod) -> Self { + return value as bindings::LayerMethod; + } +} diff --git a/src/types/line_cap.rs b/src/types/line_cap.rs new file mode 100644 index 0000000..a5384ac --- /dev/null +++ b/src/types/line_cap.rs @@ -0,0 +1,39 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum LineCap { + Undefined = bindings::LineCap_UndefinedCap, + Butt = bindings::LineCap_ButtCap, + Round = bindings::LineCap_RoundCap, + Square = bindings::LineCap_SquareCap, +} + +impl Default for LineCap { + fn default() -> Self { + return LineCap::Undefined; + } +} + +impl From for bindings::LineCap { + fn from(value: LineCap) -> Self { + return value as bindings::LineCap; + } +} + +impl From for LineCap { + fn from(value: bindings::LineCap) -> Self { + /* + * SAFETY: + * + * `LineCap` has the same repr as `bindings::LineCap` - u32 + * + * If `value` is less than Square than it is in the vaild range and can be safely + * reinterpreted as `LineCap` + */ + if value <= bindings::LineCap_SquareCap { + return unsafe { std::mem::transmute(value) }; + } + return LineCap::default(); + } +} diff --git a/src/types/line_join.rs b/src/types/line_join.rs new file mode 100644 index 0000000..d356f3e --- /dev/null +++ b/src/types/line_join.rs @@ -0,0 +1,39 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum LineJoin { + Undefined = bindings::LineJoin_UndefinedJoin, + Miter = bindings::LineJoin_MiterJoin, + Round = bindings::LineJoin_RoundJoin, + Bevel = bindings::LineJoin_BevelJoin, +} + +impl Default for LineJoin { + fn default() -> Self { + return LineJoin::Undefined; + } +} + +impl From for bindings::LineJoin { + fn from(value: LineJoin) -> Self { + return value as bindings::LineJoin; + } +} + +impl From for LineJoin { + fn from(value: bindings::LineJoin) -> Self { + /* + * SAFETY: + * + * `LineJoin` has the same repr as `bindings::LineJoin` - u32 + * + * If `value` is less than Bevel than it is in the vaild range and can be safely + * reinterpreted as `LineJoin` + */ + if value <= bindings::LineJoin_BevelJoin { + return unsafe { std::mem::transmute(value) }; + } + return LineJoin::default(); + } +} diff --git a/src/types/magick_evaluate_operator.rs b/src/types/magick_evaluate_operator.rs new file mode 100644 index 0000000..bbfff5e --- /dev/null +++ b/src/types/magick_evaluate_operator.rs @@ -0,0 +1,52 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum MagickEvaluateOperator { + Undefined = bindings::MagickEvaluateOperator_UndefinedEvaluateOperator, + Abs = bindings::MagickEvaluateOperator_AbsEvaluateOperator, + Add = bindings::MagickEvaluateOperator_AddEvaluateOperator, + AddModulus = bindings::MagickEvaluateOperator_AddModulusEvaluateOperator, + And = bindings::MagickEvaluateOperator_AndEvaluateOperator, + Cosine = bindings::MagickEvaluateOperator_CosineEvaluateOperator, + Divide = bindings::MagickEvaluateOperator_DivideEvaluateOperator, + Exponential = bindings::MagickEvaluateOperator_ExponentialEvaluateOperator, + GaussianNoise = bindings::MagickEvaluateOperator_GaussianNoiseEvaluateOperator, + ImpulseNoise = bindings::MagickEvaluateOperator_ImpulseNoiseEvaluateOperator, + LaplacianNoise = bindings::MagickEvaluateOperator_LaplacianNoiseEvaluateOperator, + LeftShift = bindings::MagickEvaluateOperator_LeftShiftEvaluateOperator, + Log = bindings::MagickEvaluateOperator_LogEvaluateOperator, + Max = bindings::MagickEvaluateOperator_MaxEvaluateOperator, + Mean = bindings::MagickEvaluateOperator_MeanEvaluateOperator, + Median = bindings::MagickEvaluateOperator_MedianEvaluateOperator, + Min = bindings::MagickEvaluateOperator_MinEvaluateOperator, + MultiplicativeNoise = bindings::MagickEvaluateOperator_MultiplicativeNoiseEvaluateOperator, + Multiply = bindings::MagickEvaluateOperator_MultiplyEvaluateOperator, + Or = bindings::MagickEvaluateOperator_OrEvaluateOperator, + PoissonNoise = bindings::MagickEvaluateOperator_PoissonNoiseEvaluateOperator, + Pow = bindings::MagickEvaluateOperator_PowEvaluateOperator, + RightShift = bindings::MagickEvaluateOperator_RightShiftEvaluateOperator, + RootMeanSquare = bindings::MagickEvaluateOperator_RootMeanSquareEvaluateOperator, + Set = bindings::MagickEvaluateOperator_SetEvaluateOperator, + Sine = bindings::MagickEvaluateOperator_SineEvaluateOperator, + Subtract = bindings::MagickEvaluateOperator_SubtractEvaluateOperator, + Sum = bindings::MagickEvaluateOperator_SumEvaluateOperator, + ThresholdBlack = bindings::MagickEvaluateOperator_ThresholdBlackEvaluateOperator, + Threshold = bindings::MagickEvaluateOperator_ThresholdEvaluateOperator, + ThresholdWhite = bindings::MagickEvaluateOperator_ThresholdWhiteEvaluateOperator, + UniformNoise = bindings::MagickEvaluateOperator_UniformNoiseEvaluateOperator, + Xor = bindings::MagickEvaluateOperator_XorEvaluateOperator, + InverseLog = bindings::MagickEvaluateOperator_InverseLogEvaluateOperator, +} + +impl Default for MagickEvaluateOperator { + fn default() -> Self { + return MagickEvaluateOperator::Undefined; + } +} + +impl From for bindings::MagickEvaluateOperator { + fn from(value: MagickEvaluateOperator) -> Self { + return value as bindings::MagickEvaluateOperator; + } +} diff --git a/src/types/magick_function.rs b/src/types/magick_function.rs new file mode 100644 index 0000000..ee68042 --- /dev/null +++ b/src/types/magick_function.rs @@ -0,0 +1,23 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum MagickFunction { + Undefined = bindings::MagickFunction_UndefinedFunction, + Arcsin = bindings::MagickFunction_ArcsinFunction, + Arctan = bindings::MagickFunction_ArctanFunction, + Polynomial = bindings::MagickFunction_PolynomialFunction, + Sinusoid = bindings::MagickFunction_SinusoidFunction, +} + +impl Default for MagickFunction { + fn default() -> Self { + return MagickFunction::Undefined; + } +} + +impl From for bindings::MagickFunction { + fn from(value: MagickFunction) -> Self { + return value as bindings::MagickFunction; + } +} diff --git a/src/types/mod.rs b/src/types/mod.rs index d1c3572..8edb988 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,15 +1,73 @@ +mod align_type; +mod alpha_channel_option; +mod auto_threshold_method; +mod channel_type; +mod clip_path_units; mod colorspace_type; mod composite_operator; +mod compression_type; +mod decoration_type; +mod direction_type; +mod dispose_type; mod dither_method; +mod endian_type; +mod fill_rule; mod filter_type; +mod geometry_info; mod gravity_type; +mod image; +mod image_type; +mod interlace_type; +mod kernel; +mod layer_method; +mod line_cap; +mod line_join; +mod magick_evaluate_operator; +mod magick_function; mod metric_type; +mod orientation_type; +mod pixel_interpolate_method; +mod pixel_mask; +mod rendering_intent; +mod resolution_type; mod resource_type; +mod statistic_type; +mod stretch_type; +mod style_type; +pub use self::align_type::AlignType; +pub use self::alpha_channel_option::AlphaChannelOption; +pub use self::auto_threshold_method::AutoThresholdMethod; +pub use self::channel_type::ChannelType; +pub use self::clip_path_units::ClipPathUnits; pub use self::colorspace_type::ColorspaceType; pub use self::composite_operator::CompositeOperator; +pub use self::compression_type::CompressionType; +pub use self::decoration_type::DecorationType; +pub use self::direction_type::DirectionType; +pub use self::dispose_type::DisposeType; pub use self::dither_method::DitherMethod; +pub use self::endian_type::EndianType; +pub use self::fill_rule::FillRule; pub use self::filter_type::FilterType; +pub use self::geometry_info::GeometryInfo; pub use self::gravity_type::GravityType; +pub use self::image::Image; +pub use self::image_type::ImageType; +pub use self::interlace_type::InterlaceType; +pub use self::kernel::*; +pub use self::layer_method::LayerMethod; +pub use self::line_cap::LineCap; +pub use self::line_join::LineJoin; +pub use self::magick_evaluate_operator::MagickEvaluateOperator; +pub use self::magick_function::MagickFunction; pub use self::metric_type::MetricType; +pub use self::orientation_type::OrientationType; +pub use self::pixel_interpolate_method::PixelInterpolateMethod; +pub use self::pixel_mask::PixelMask; +pub use self::rendering_intent::RenderingIntent; +pub use self::resolution_type::ResolutionType; pub use self::resource_type::ResourceType; +pub use self::statistic_type::StatisticType; +pub use self::stretch_type::StretchType; +pub use self::style_type::StyleType; diff --git a/src/types/orientation_type.rs b/src/types/orientation_type.rs new file mode 100644 index 0000000..af2e8e7 --- /dev/null +++ b/src/types/orientation_type.rs @@ -0,0 +1,44 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum OrientationType { + Undefined = bindings::OrientationType_UndefinedOrientation, + TopLeft = bindings::OrientationType_TopLeftOrientation, + TopRight = bindings::OrientationType_TopRightOrientation, + BottomRight = bindings::OrientationType_BottomRightOrientation, + BottomLeft = bindings::OrientationType_BottomLeftOrientation, + LeftTop = bindings::OrientationType_LeftTopOrientation, + RightTop = bindings::OrientationType_RightTopOrientation, + RightBottom = bindings::OrientationType_RightBottomOrientation, + LeftBottom = bindings::OrientationType_LeftBottomOrientation, +} + +impl Default for OrientationType { + fn default() -> Self { + return OrientationType::Undefined; + } +} + +impl From for bindings::OrientationType { + fn from(value: OrientationType) -> Self { + return value as bindings::OrientationType; + } +} + +impl From for OrientationType { + fn from(value: bindings::OrientationType) -> Self { + /* + * SAFETY: + * + * `OrientationType` has the same repr as `bindings::OrientationType` - u32 + * + * If `value` is less than LeftBottom than it is in the vaild range and can be safely + * reinterpreted as `OrientationType` + */ + if value <= bindings::OrientationType_LeftBottomOrientation { + return unsafe { std::mem::transmute(value) }; + } + return OrientationType::default(); + } +} diff --git a/src/types/pixel_interpolate_method.rs b/src/types/pixel_interpolate_method.rs new file mode 100644 index 0000000..d99c6c4 --- /dev/null +++ b/src/types/pixel_interpolate_method.rs @@ -0,0 +1,47 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum PixelInterpolateMethod { + Undefined = bindings::PixelInterpolateMethod_UndefinedInterpolatePixel, + Average = bindings::PixelInterpolateMethod_AverageInterpolatePixel, + Average9 = bindings::PixelInterpolateMethod_Average9InterpolatePixel, + Average16 = bindings::PixelInterpolateMethod_Average16InterpolatePixel, + Background = bindings::PixelInterpolateMethod_BackgroundInterpolatePixel, + Bilinear = bindings::PixelInterpolateMethod_BilinearInterpolatePixel, + Blend = bindings::PixelInterpolateMethod_BlendInterpolatePixel, + Catrom = bindings::PixelInterpolateMethod_CatromInterpolatePixel, + Integer = bindings::PixelInterpolateMethod_IntegerInterpolatePixel, + Mesh = bindings::PixelInterpolateMethod_MeshInterpolatePixel, + Nearest = bindings::PixelInterpolateMethod_NearestInterpolatePixel, + Spline = bindings::PixelInterpolateMethod_SplineInterpolatePixel, +} + +impl Default for PixelInterpolateMethod { + fn default() -> Self { + return PixelInterpolateMethod::Undefined; + } +} + +impl From for bindings::PixelInterpolateMethod { + fn from(value: PixelInterpolateMethod) -> Self { + return value as bindings::PixelInterpolateMethod; + } +} + +impl From for PixelInterpolateMethod { + fn from(value: bindings::PixelInterpolateMethod) -> Self { + /* + * SAFETY: + * + * `PixelInterpolateMethod` has the same repr as `bindings::PixelInterpolateMethod` - u32 + * + * If `value` is less than Spline than it is in the vaild range and can be safely + * reinterpreted as `PixelInterpolateMethod` + */ + if value <= bindings::PixelInterpolateMethod_SplineInterpolatePixel { + return unsafe { std::mem::transmute(value) }; + } + return PixelInterpolateMethod::default(); + } +} diff --git a/src/types/pixel_mask.rs b/src/types/pixel_mask.rs new file mode 100644 index 0000000..52a3b4f --- /dev/null +++ b/src/types/pixel_mask.rs @@ -0,0 +1,22 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum PixelMask { + Undefined = bindings::PixelMask_UndefinedPixelMask, + Read = bindings::PixelMask_ReadPixelMask, + Write = bindings::PixelMask_WritePixelMask, + Composite = bindings::PixelMask_CompositePixelMask, +} + +impl Default for PixelMask { + fn default() -> Self { + return PixelMask::Undefined; + } +} + +impl From for bindings::PixelMask { + fn from(value: PixelMask) -> Self { + return value as bindings::PixelMask; + } +} diff --git a/src/types/rendering_intent.rs b/src/types/rendering_intent.rs new file mode 100644 index 0000000..d63c9cc --- /dev/null +++ b/src/types/rendering_intent.rs @@ -0,0 +1,40 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum RenderingIntent { + Undefined = bindings::RenderingIntent_UndefinedIntent, + Saturation = bindings::RenderingIntent_SaturationIntent, + Perceptual = bindings::RenderingIntent_PerceptualIntent, + Absolute = bindings::RenderingIntent_AbsoluteIntent, + Relative = bindings::RenderingIntent_RelativeIntent, +} + +impl Default for RenderingIntent { + fn default() -> Self { + return RenderingIntent::Undefined; + } +} + +impl From for bindings::RenderingIntent { + fn from(value: RenderingIntent) -> Self { + return value as bindings::RenderingIntent; + } +} + +impl From for RenderingIntent { + fn from(value: bindings::RenderingIntent) -> Self { + /* + * SAFETY: + * + * `RenderingIntent` has the same repr as `bindings::RenderingIntent` - u32 + * + * If `value` is less than Relative than it is in the vaild range and can be safely + * reinterpreted as `RenderingIntent` + */ + if value <= bindings::RenderingIntent_RelativeIntent { + return unsafe { std::mem::transmute(value) }; + } + return RenderingIntent::default(); + } +} diff --git a/src/types/resolution_type.rs b/src/types/resolution_type.rs new file mode 100644 index 0000000..f94f55e --- /dev/null +++ b/src/types/resolution_type.rs @@ -0,0 +1,38 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum ResolutionType { + Undefined = bindings::ResolutionType_UndefinedResolution, + PixelsPerInch = bindings::ResolutionType_PixelsPerInchResolution, + PixelsPerCentimeter = bindings::ResolutionType_PixelsPerCentimeterResolution, +} + +impl Default for ResolutionType { + fn default() -> Self { + return ResolutionType::Undefined; + } +} + +impl From for bindings::ResolutionType { + fn from(value: ResolutionType) -> Self { + return value as bindings::ResolutionType; + } +} + +impl From for ResolutionType { + fn from(value: bindings::ResolutionType) -> Self { + /* + * SAFETY: + * + * `ResolutionType` has the same repr as `bindings::ResolutionType` - u32 + * + * If `value` is less than PixelsPerCentimeter than it is in the vaild range and can be safely + * reinterpreted as `ResolutionType` + */ + if value <= bindings::ResolutionType_PixelsPerCentimeterResolution { + return unsafe { std::mem::transmute(value) }; + } + return ResolutionType::default(); + } +} diff --git a/src/types/statistic_type.rs b/src/types/statistic_type.rs new file mode 100644 index 0000000..2a73945 --- /dev/null +++ b/src/types/statistic_type.rs @@ -0,0 +1,46 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum StatisticType { + Undefined = bindings::StatisticType_UndefinedStatistic, + Gradient = bindings::StatisticType_GradientStatistic, + Maximum = bindings::StatisticType_MaximumStatistic, + Mean = bindings::StatisticType_MeanStatistic, + Median = bindings::StatisticType_MedianStatistic, + Minimum = bindings::StatisticType_MinimumStatistic, + Mode = bindings::StatisticType_ModeStatistic, + Nonpeak = bindings::StatisticType_NonpeakStatistic, + RootMeanSquare = bindings::StatisticType_RootMeanSquareStatistic, + StandardDeviation = bindings::StatisticType_StandardDeviationStatistic, + Contrast = bindings::StatisticType_ContrastStatistic, +} + +impl Default for StatisticType { + fn default() -> Self { + return StatisticType::Undefined; + } +} + +impl From for bindings::StatisticType { + fn from(value: StatisticType) -> Self { + return value as bindings::StatisticType; + } +} + +impl From for StatisticType { + fn from(value: bindings::StatisticType) -> Self { + /* + * SAFETY: + * + * `StatisticType` has the same repr as `bindings::StatisticType` - u32 + * + * If `value` is less than Contrast than it is in the vaild range and can be safely + * reinterpreted as `StatisticType` + */ + if value <= bindings::StatisticType_ContrastStatistic { + return unsafe { std::mem::transmute(value) }; + } + return StatisticType::default(); + } +} diff --git a/src/types/stretch_type.rs b/src/types/stretch_type.rs new file mode 100644 index 0000000..40b76d0 --- /dev/null +++ b/src/types/stretch_type.rs @@ -0,0 +1,46 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum StretchType { + Undefined = bindings::StretchType_UndefinedStretch, + Normal = bindings::StretchType_NormalStretch, + UltraCondensed = bindings::StretchType_UltraCondensedStretch, + ExtraCondensed = bindings::StretchType_ExtraCondensedStretch, + Condensed = bindings::StretchType_CondensedStretch, + SemiCondensed = bindings::StretchType_SemiCondensedStretch, + SemiExpanded = bindings::StretchType_SemiExpandedStretch, + Expanded = bindings::StretchType_ExpandedStretch, + ExtraExpanded = bindings::StretchType_ExtraExpandedStretch, + UltraExpanded = bindings::StretchType_UltraExpandedStretch, + Any = bindings::StretchType_AnyStretch, +} + +impl Default for StretchType { + fn default() -> Self { + return StretchType::Undefined; + } +} + +impl From for bindings::StretchType { + fn from(value: StretchType) -> Self { + return value as bindings::StretchType; + } +} + +impl From for StretchType { + fn from(value: bindings::StretchType) -> Self { + /* + * SAFETY: + * + * `StretchType` has the same repr as `bindings::StretchType` - u32 + * + * If `value` is less than Any than it is in the vaild range and can be safely + * reinterpreted as `StretchType` + */ + if value <= bindings::StretchType_AnyStretch { + return unsafe { std::mem::transmute(value) }; + } + return StretchType::default(); + } +} diff --git a/src/types/style_type.rs b/src/types/style_type.rs new file mode 100644 index 0000000..be22eaf --- /dev/null +++ b/src/types/style_type.rs @@ -0,0 +1,41 @@ +use crate::bindings; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum StyleType { + Undefined = bindings::StyleType_UndefinedStyle, + Normal = bindings::StyleType_NormalStyle, + Italic = bindings::StyleType_ItalicStyle, + Oblique = bindings::StyleType_ObliqueStyle, + Any = bindings::StyleType_AnyStyle, + Bold = bindings::StyleType_BoldStyle, +} + +impl Default for StyleType { + fn default() -> Self { + return StyleType::Undefined; + } +} + +impl From for bindings::StyleType { + fn from(value: StyleType) -> Self { + return value as bindings::StyleType; + } +} + +impl From for StyleType { + fn from(value: bindings::StyleType) -> Self { + /* + * SAFETY: + * + * `StyleType` has the same repr as `bindings::StyleType` - u32 + * + * If `value` is less than Bold than it is in the vaild range and can be safely + * reinterpreted as `StyleType` + */ + if value <= bindings::StyleType_BoldStyle { + return unsafe { std::mem::transmute(value) }; + } + return StyleType::default(); + } +} diff --git a/src/wand/drawing.rs b/src/wand/drawing.rs index 6740123..c918703 100644 --- a/src/wand/drawing.rs +++ b/src/wand/drawing.rs @@ -16,15 +16,22 @@ 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 bindings; use crate::result::MagickError; use crate::result::Result; +use crate::{ + AlignType, + ClipPathUnits, + DecorationType, + DirectionType, + FillRule, + GravityType, + LineCap, + LineJoin, + StretchType, + StyleType, +}; wand_common!( DrawingWand, @@ -91,30 +98,30 @@ impl DrawingWand { ); set_get_unchecked!( - get_gravity, set_gravity, DrawGetGravity, DrawSetGravity, bindings::GravityType + get_gravity, set_gravity, DrawGetGravity, DrawSetGravity, GravityType get_opacity, set_opacity, DrawGetOpacity, DrawSetOpacity, f64 - get_clip_rule, set_clip_rule, DrawGetClipRule, DrawSetClipRule, bindings::FillRule - get_clip_units, set_clip_units, DrawGetClipUnits, DrawSetClipUnits, bindings::ClipPathUnits - get_fill_rule, set_fill_rule, DrawGetFillRule, DrawSetFillRule, bindings::FillRule + get_clip_rule, set_clip_rule, DrawGetClipRule, DrawSetClipRule, FillRule + get_clip_units, set_clip_units, DrawGetClipUnits, DrawSetClipUnits, ClipPathUnits + get_fill_rule, set_fill_rule, DrawGetFillRule, DrawSetFillRule, FillRule 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, bindings::StyleType - get_font_weight, set_font_weight, DrawGetFontWeight, DrawSetFontWeight, size_t - get_font_stretch, set_font_stretch, DrawGetFontStretch, DrawSetFontStretch, bindings::StretchType + get_font_style, set_font_style, DrawGetFontStyle, DrawSetFontStyle, StyleType + get_font_weight, set_font_weight, DrawGetFontWeight, DrawSetFontWeight, usize + get_font_stretch, set_font_stretch, DrawGetFontStretch, DrawSetFontStretch, StretchType get_stroke_dash_offset, set_stroke_dash_offset, DrawGetStrokeDashOffset, DrawSetStrokeDashOffset, f64 - get_stroke_line_cap, set_stroke_line_cap, DrawGetStrokeLineCap, DrawSetStrokeLineCap, bindings::LineCap - get_stroke_line_join, set_stroke_line_join, DrawGetStrokeLineJoin, DrawSetStrokeLineJoin, bindings::LineJoin - get_stroke_miter_limit, set_stroke_miter_limit, DrawGetStrokeMiterLimit, DrawSetStrokeMiterLimit, size_t + get_stroke_line_cap, set_stroke_line_cap, DrawGetStrokeLineCap, DrawSetStrokeLineCap, LineCap + get_stroke_line_join, set_stroke_line_join, DrawGetStrokeLineJoin, DrawSetStrokeLineJoin, LineJoin + get_stroke_miter_limit, set_stroke_miter_limit, DrawGetStrokeMiterLimit, DrawSetStrokeMiterLimit, usize 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, bindings::MagickBooleanType - get_text_alignment, set_text_alignment, DrawGetTextAlignment, DrawSetTextAlignment, bindings::AlignType + get_text_alignment, set_text_alignment, DrawGetTextAlignment, DrawSetTextAlignment, AlignType get_text_antialias, set_text_antialias, DrawGetTextAntialias, DrawSetTextAntialias, bindings::MagickBooleanType - get_text_decoration, set_text_decoration, DrawGetTextDecoration, DrawSetTextDecoration, bindings::DecorationType - get_text_direction, set_text_direction, DrawGetTextDirection, DrawSetTextDirection, bindings::DirectionType + get_text_decoration, set_text_decoration, DrawGetTextDecoration, DrawSetTextDecoration, DecorationType + get_text_direction, set_text_direction, DrawGetTextDirection, DrawSetTextDirection, DirectionType 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 diff --git a/src/wand/macros.rs b/src/wand/macros.rs index 24cf39a..437f6d2 100644 --- a/src/wand/macros.rs +++ b/src/wand/macros.rs @@ -100,7 +100,7 @@ macro_rules! get { ($($get:ident, $c_get:ident, $typ:ty )*) => { $( pub fn $get(&self) -> $typ { - unsafe { ::bindings::$c_get(self.wand) } + unsafe { ::bindings::$c_get(self.wand).into() } } )* } @@ -110,10 +110,10 @@ 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) } + unsafe { ::bindings::$c_get(self.wand).into() } } pub fn $set(&mut self, v: $typ) -> Result<()> { - match unsafe { ::bindings::$c_set(self.wand, v) } { + match unsafe { ::bindings::$c_set(self.wand, v.into()) } { ::bindings::MagickBooleanType_MagickTrue => Ok(()), _ => Err(MagickError(concat!(stringify!($set), " returned false"))) } @@ -130,10 +130,10 @@ 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) } + unsafe { ::bindings::$c_get(self.wand).into() } } pub fn $set(&mut self, v: $typ) { - unsafe { ::bindings::$c_set(self.wand, v) } + unsafe { ::bindings::$c_set(self.wand, v.into()) } } )* pub fn fmt_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result { @@ -258,7 +258,7 @@ macro_rules! mutations { $( $(#[$attr])* pub fn $fun(&self $(, $arg: $ty)*) -> Result<()> { - match unsafe { bindings::$c_fun(self.wand $(, $arg)*) } { + match unsafe { bindings::$c_fun(self.wand $(, $arg.into())*) } { bindings::MagickBooleanType_MagickTrue => Ok(()), _ => Err(MagickError(concat!(stringify!($c_fun), " invocation failed"))) } diff --git a/src/wand/magick.rs b/src/wand/magick.rs index 1e594a9..adca422 100644 --- a/src/wand/magick.rs +++ b/src/wand/magick.rs @@ -18,25 +18,46 @@ use std::{fmt, ptr, slice}; use libc::c_void; #[cfg(target_os = "freebsd")] -use libc::{size_t, ssize_t}; +use libc::size_t; use bindings; use conversions::*; use result::MagickError; #[cfg(not(target_os = "freebsd"))] -use {size_t, ssize_t}; +use size_t; use crate::result::Result; +use super::{MagickTrue, MagickFalse}; use super::{DrawingWand, PixelWand}; use crate::{ + AlphaChannelOption, + AutoThresholdMethod, + ChannelType, ColorspaceType, CompositeOperator, + CompressionType, + DisposeType, DitherMethod, + EndianType, FilterType, GravityType, + Image, + ImageType, + InterlaceType, + KernelInfo, + LayerMethod, + MagickEvaluateOperator, + MagickFunction, MetricType, - ResourceType + MorphologyMethod, + OrientationType, + PixelInterpolateMethod, + PixelMask, + RenderingIntent, + ResolutionType, + ResourceType, + StatisticType, }; wand_common!( @@ -58,9 +79,24 @@ wand_common!( /// 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<()> { - match unsafe { bindings::MagickNewImage(self.wand, columns, rows, pixel_wand.wand) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + /// Creates new wand by cloning the image. + /// + /// * `img`: the image. + pub fn new_from_image(img: &Image<'_>) -> Result { + let result = unsafe { + bindings::NewMagickWandFromImage(img.get_ptr()) + }; + + return if result.is_null() { + Err(MagickError("failed to create wand from image")) + } else { + Ok(MagickWand { wand: result }) + } + } + + pub fn new_image(&self, columns: usize, rows: usize, background: &PixelWand) -> Result<()> { + match unsafe { bindings::MagickNewImage(self.wand, columns.into(), rows.into(), background.wand) } { + MagickTrue => Ok(()), _ => Err(MagickError("Could not create image")), } } @@ -75,7 +111,7 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to set resource limit")), } } @@ -86,7 +122,7 @@ impl MagickWand { let result = unsafe { bindings::MagickSetOption(self.wand, c_key.as_ptr(), c_value.as_ptr()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to set option")), } } @@ -110,7 +146,7 @@ impl MagickWand { c_string.as_ptr() as *const _, ) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("unable to annotate image")), } } @@ -118,7 +154,7 @@ impl MagickWand { /// Add all images from another wand to this wand at the current index. pub fn add_image(&mut self, other_wand: &MagickWand) -> Result<()> { match unsafe { bindings::MagickAddImage(self.wand, other_wand.wand) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("unable to add images from another wand")), } } @@ -134,7 +170,7 @@ impl MagickWand { let c_label = CString::new(label).unwrap(); let result = unsafe { bindings::MagickLabelImage(self.wand, c_label.as_ptr()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to add label")), } } @@ -144,7 +180,7 @@ impl MagickWand { let result = unsafe { bindings::MagickWriteImages(self.wand, c_name.as_ptr(), adjoin.to_magick()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to write images")), } } @@ -154,7 +190,7 @@ impl MagickWand { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickReadImage(self.wand, c_name.as_ptr()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to read image")), } } @@ -167,11 +203,11 @@ impl MagickWand { bindings::MagickReadImageBlob( self.wand, int_slice.as_ptr() as *const c_void, - size as size_t, + size.into(), ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to read image")), } } @@ -182,7 +218,7 @@ impl MagickWand { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickPingImage(self.wand, c_name.as_ptr()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to ping image")), } } @@ -196,15 +232,46 @@ impl MagickWand { bindings::MagickPingImageBlob( self.wand, int_slice.as_ptr() as *const c_void, - size as size_t, + size.into(), ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to ping image")), } } + /// Composes all the image layers from the current given image onward to produce a single image + /// of the merged layers. + /// + /// The inital canvas's size depends on the given LayerMethod, and is initialized using the + /// first images background color. The images are then composited onto that image in sequence + /// using the given composition that has been assigned to each individual image. + /// + /// * `method`: the method of selecting the size of the initial canvas. + /// MergeLayer: Merge all layers onto a canvas just large enough to hold all the actual + /// images. The virtual canvas of the first image is preserved but otherwise ignored. + /// + /// FlattenLayer: Use the virtual canvas size of first image. Images which fall outside + /// this canvas is clipped. This can be used to 'fill out' a given virtual canvas. + /// + /// MosaicLayer: Start with the virtual canvas of the first image, enlarging left and right + /// edges to contain all images. Images with negative offsets will be clipped. + pub fn merge_image_layers(&self, method: LayerMethod) -> Result { + let result = unsafe { + bindings::MagickMergeImageLayers(self.wand, method.into()) + }; + if result.is_null() { + return Err(MagickError("failed to merge image layres")); + } + return Ok(MagickWand { wand: result }); + } + + /// Returns the number of images associated with a magick wand. + pub fn get_number_images(&self) -> usize { + return unsafe { bindings::MagickGetNumberImages(self.wand).into() }; + } + /// Compare two images and return tuple `(distortion, diffImage)` /// `diffImage` is `None` if `distortion == 0` pub fn compare_images( @@ -224,19 +291,6 @@ impl MagickWand { (distortion, wand) } - pub fn get_image_compose(&self) -> CompositeOperator { - unsafe { bindings::MagickGetImageCompose(self.wand).into() } - } - - pub fn set_image_compose(&self, composite_operator: CompositeOperator) -> Result<()> { - match unsafe { bindings::MagickSetImageCompose(self.wand, composite_operator.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(MagickError( - "Failed to set the image composite operator type", - )), - } - } - /// Compose another image onto self at (x, y) using composition_operator pub fn compose_images( &self, @@ -247,9 +301,9 @@ impl MagickWand { y: isize, ) -> Result<()> { let native_clip_to_self = if clip_to_self { - bindings::MagickBooleanType_MagickTrue + MagickTrue } else { - bindings::MagickBooleanType_MagickFalse + MagickFalse }; let result = unsafe { bindings::MagickCompositeImage( @@ -262,7 +316,7 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to compose images")), } } @@ -283,7 +337,7 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to compose images")), } } @@ -304,11 +358,11 @@ impl MagickWand { pub fn clut_image( &self, clut_wand: &MagickWand, - method: bindings::PixelInterpolateMethod, + method: PixelInterpolateMethod, ) -> Result<()> { - let result = unsafe { bindings::MagickClutImage(self.wand, clut_wand.wand, method) }; + let result = unsafe { bindings::MagickClutImage(self.wand, clut_wand.wand, method.into()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError( "failed to replace colors in the image from color lookup table", )), @@ -318,7 +372,7 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError( "failed to replace colors in the image from color lookup table", )), @@ -331,10 +385,10 @@ impl MagickWand { MagickWand::new_from_wand(wand) } - pub fn set_size(&self, columns: size_t, rows: size_t) -> Result<()> { - let result = unsafe { bindings::MagickSetSize(self.wand, columns, rows) }; + pub fn set_size(&self, columns: usize, rows: usize) -> Result<()> { + let result = unsafe { bindings::MagickSetSize(self.wand, columns.into(), rows.into()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to set size of wand")), } } @@ -373,7 +427,27 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), + _ => Err(MagickError("Failed to level the image")), + } + } + + /// Applies the reversed [level_image](Self::level_image). It compresses the full range of color values, so + /// that they lie between the given black and white points. Gamma is applied before the values + /// are mapped. It can be used to de-contrast a greyscale image to the exact levels specified. + pub fn levelize_image(&self, black_point: f64, gamma: f64, white_point: f64) -> Result<()> { + let quantum_range = self.quantum_range()?; + + let result = unsafe { + bindings::MagickLevelizeImage( + self.wand, + black_point * quantum_range, + gamma, + white_point * quantum_range, + ) + }; + match result { + MagickTrue => Ok(()), _ => Err(MagickError("Failed to level the image")), } } @@ -389,7 +463,7 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("Failed to apply contrast stretch to image")), } } @@ -410,17 +484,27 @@ impl MagickWand { ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("Failed to apply ordered dither to image")), } } /// Apply sigmoidal contrast to the image - /// Midpoint is a number in range [0, 1] + /// + /// Adjusts the contrast of an image with a non-linear sigmoidal contrast algorithm. Increase + /// the contrast of the image using a sigmoidal transfer function without saturating highlights + /// or shadows. Contrast indicates how much to increase the contrast (0 is none; 3 is typical; + /// 20 is pushing it); mid-point indicates where midtones fall in the resultant image (0.0 is + /// white; 0.5 is middle-gray; 1.0 is black). Set sharpen to `true` to increase the image + /// contrast otherwise the contrast is reduced. + /// + /// * `sharpen`: increase or decrease image contrast + /// * `strength`: strength of the contrast, the larger the number the more 'threshold-like' it becomes. + /// * `midpoint`: midpoint of the function as a number in range [0, 1] pub fn sigmoidal_contrast_image( &self, sharpen: bool, - contrast: f64, + strength: f64, midpoint: f64, ) -> Result<()> { let quantum_range = self.quantum_range()?; @@ -429,12 +513,12 @@ impl MagickWand { bindings::MagickSigmoidalContrastImage( self.wand, sharpen.to_magick(), - contrast, + strength, midpoint * quantum_range, ) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("Failed to apply sigmoidal contrast to image")), } } @@ -444,7 +528,7 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to extend image")), } } @@ -468,7 +552,7 @@ impl MagickWand { bindings::MagickProfileImage(self.wand, c_name.as_ptr(), profile_ptr, profile_len) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to profile image")), } } @@ -476,7 +560,7 @@ impl MagickWand { pub fn strip_image(&self) -> Result<()> { let result = unsafe { bindings::MagickStripImage(self.wand) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to strip image")), } } @@ -484,17 +568,17 @@ impl MagickWand { pub fn flip_image(&self) -> Result<()> { let result = unsafe { bindings::MagickFlipImage(self.wand) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to flip image")), } } pub fn negate_image(&self) -> Result<()> { let result = unsafe { - bindings::MagickNegateImage(self.wand, bindings::MagickBooleanType_MagickTrue) + bindings::MagickNegateImage(self.wand, MagickTrue) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to flip image")), } } @@ -502,7 +586,7 @@ impl MagickWand { pub fn flop_image(&self) -> Result<()> { let result = unsafe { bindings::MagickFlopImage(self.wand) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to flip image")), } } @@ -510,7 +594,7 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to blur image")), } } @@ -518,15 +602,46 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to gaussian blur image")), } } + /// Replace each pixel with corresponding statistic from the neighborhood of the specified width and height. + /// + /// * `statistic_type`: the statistic type (e.g. `StatisticType::Median`, `StatisticType::Mode`, etc.). + /// * `width`: the width of the pixel neighborhood. + /// * `height`: the height of the pixel neighborhood. + pub fn statistic_image( + &self, + statistic_type: StatisticType, + width: usize, + height: usize, + ) -> Result<()> { + match unsafe { + bindings::MagickStatisticImage( + self.wand, + statistic_type.into(), + width.into(), + height.into() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to calculate statistics for image")), + } + } + + /// Calculate median for each pixel's neighborhood. + /// + /// See [statistic_image](Self::statistic_image) + pub fn median_blur_image(&self, width: usize, height: usize) -> Result<()> { + return self.statistic_image(StatisticType::Median, width, height); + } + /// Adaptively resize the currently selected image. pub fn adaptive_resize_image(&self, width: usize, height: usize) -> Result<()> { match unsafe { bindings::MagickAdaptiveResizeImage(self.wand, width, height) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to adaptive-resize image")), } } @@ -535,7 +650,7 @@ impl MagickWand { /// filling any empty space with the background color of a given PixelWand pub fn rotate_image(&self, background: &PixelWand, degrees: f64) -> Result<()> { match unsafe { bindings::MagickRotateImage(self.wand, background.wand, degrees) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to rotate image")), } } @@ -544,7 +659,7 @@ impl MagickWand { pub fn trim_image(&self, fuzz: f64) -> Result<()> { let result = unsafe { bindings::MagickTrimImage(self.wand, fuzz) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to trim image")), } } @@ -572,13 +687,142 @@ impl MagickWand { 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 { + if result == MagickTrue { Ok(()) } else { Err(MagickError("Resetting page geometry failed.")) } } + /// Returns a value associated with the specified artifact. + /// + /// * `artifact`: the artifact. + pub fn get_image_artifact(&self, artifact: &str) -> Result { + let c_artifact = CString::new(artifact).map_err(|_| MagickError("artifact string contains null byte"))?; + + let result = unsafe { + bindings::MagickGetImageArtifact( + self.wand, + c_artifact.as_ptr() + ) + }; + + let value = if result.is_null() { + Err(MagickError("missing artifact")) + } 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 + } + + pub fn get_image_artifacts(&self, pattern: &str) -> Result> { + let c_pattern = CString::new(pattern).map_err(|_| MagickError("artifact string contains null byte"))?; + let mut num_of_artifacts: size_t = 0; + + let result = unsafe { + bindings::MagickGetImageArtifacts( + self.wand, + c_pattern.as_ptr(), + &mut num_of_artifacts + ) + }; + + let value = if result.is_null() { + Err(MagickError("no artifacts found")) + } else { + let mut artifacts: Vec = Vec::with_capacity(num_of_artifacts); + for i in 0..num_of_artifacts { + // convert (and copy) the C string to a Rust string + let cstr = unsafe { CStr::from_ptr(*result.add(i)) }; + artifacts.push(cstr.to_string_lossy().into_owned()); + } + + Ok(artifacts) + }; + + unsafe { + bindings::MagickRelinquishMemory(result as *mut c_void); + } + + value + } + + /// Sets a key-value pair in the image artifact namespace. Artifacts differ from properties. + /// Properties are public and are generally exported to an external image format if the format + /// supports it. Artifacts are private and are utilized by the internal ImageMagick API to + /// modify the behavior of certain algorithms. + /// + /// * `artifact`: the artifact. + /// * `value`: the value. + /// + /// # Example + /// + /// This example shows how you can blend an image with its blurred copy with 50% opacity by + /// setting "compose:args" to "50". This is equivalent to having `-define compose:args=50` when + /// using imagemagick cli. + /// + /// ``` + /// use magick_rust::{MagickWand, PixelWand, CompositeOperator}; + /// + /// fn main() -> Result<(), magick_rust::MagickError> { + /// let mut wand1 = MagickWand::new(); + /// wand1.new_image(4, 4, &PixelWand::new())?; // Replace with `read_image` to open your image file + /// let wand2 = wand1.clone(); + /// + /// wand1.median_blur_image(10, 10)?; + /// + /// wand1.set_image_artifact("compose:args", "50")?; + /// wand1.compose_images(&wand2, CompositeOperator::Blend, false, 0, 0)?; + /// + /// Ok(()) + /// } + /// ``` + pub fn set_image_artifact( + &mut self, + artifact: &str, + value: &str + ) -> Result<()> { + let c_artifact = CString::new(artifact).map_err(|_| MagickError("artifact string contains null byte"))?; + let c_value = CString::new(value).map_err(|_| MagickError("value string contains null byte"))?; + + let result = unsafe { + bindings::MagickSetImageArtifact( + self.wand, + c_artifact.as_ptr(), + c_value.as_ptr() + ) + }; + + match result { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to set image artifact")), + } + } + + /// Deletes a wand artifact. + /// + /// * `artifact`: the artifact. + pub fn delete_image_artifact(&mut self, artifact: &str) -> Result<()> { + let c_artifact = CString::new(artifact).map_err(|_| MagickError("artifact string contains null byte"))?; + + match unsafe { + bindings::MagickDeleteImageArtifact( + self.wand, + c_artifact.as_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to delete image artifact")), + } + } + /// Retrieve the named image property value. pub fn get_image_property(&self, name: &str) -> Result { let c_name = CString::new(name).unwrap(); @@ -596,6 +840,38 @@ impl MagickWand { value } + pub fn get_image_properties(&self, pattern: &str) -> Result> { + let c_pattern = CString::new(pattern).map_err(|_| MagickError("artifact string contains null byte"))?; + let mut num_of_artifacts: size_t = 0; + + let result = unsafe { + bindings::MagickGetImageProperties( + self.wand, + c_pattern.as_ptr(), + &mut num_of_artifacts + ) + }; + + let value = if result.is_null() { + Err(MagickError("no artifacts found")) + } else { + let mut artifacts: Vec = Vec::with_capacity(num_of_artifacts); + for i in 0..num_of_artifacts { + // convert (and copy) the C string to a Rust string + let cstr = unsafe { CStr::from_ptr(*result.add(i)) }; + artifacts.push(cstr.to_string_lossy().into_owned()); + } + + Ok(artifacts) + }; + + unsafe { + bindings::MagickRelinquishMemory(result as *mut c_void); + } + + value + } + /// Set the named image property. pub fn set_image_property(&self, name: &str, value: &str) -> Result<()> { let c_name = CString::new(name).unwrap(); @@ -603,7 +879,7 @@ impl MagickWand { let result = unsafe { bindings::MagickSetImageProperty(self.wand, c_name.as_ptr(), c_value.as_ptr()) }; - if result == bindings::MagickBooleanType_MagickTrue { + if result == MagickTrue { Ok(()) } else { Err(MagickError("Setting image property failed.")) @@ -616,7 +892,7 @@ impl MagickWand { unsafe { if bindings::MagickGetImagePixelColor(self.wand, x, y, pw.wand) - == bindings::MagickBooleanType_MagickTrue + == MagickTrue { Some(pw) } else { @@ -636,7 +912,7 @@ impl MagickWand { &samplingFactors[0], ) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("SetSamplingFactors returned false")), } } @@ -668,7 +944,7 @@ impl MagickWand { /// pub fn sharpen_image(&self, radius: f64, sigma: f64) -> Result<()> { match unsafe { bindings::MagickSharpenImage(self.wand, radius, sigma) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("SharpenImage returned false")), } @@ -677,7 +953,7 @@ impl MagickWand { /// Set the background color. pub fn set_background_color(&self, pixel_wand: &PixelWand) -> Result<()> { match unsafe { bindings::MagickSetBackgroundColor(self.wand, pixel_wand.wand) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("SetBackgroundColor returned false")), } @@ -686,7 +962,7 @@ impl MagickWand { /// Set the image background color. pub fn set_image_background_color(&self, pixel_wand: &PixelWand) -> Result<()> { match unsafe { bindings::MagickSetImageBackgroundColor(self.wand, pixel_wand.wand) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("SetImageBackgroundColor returned false")), } @@ -698,7 +974,7 @@ impl MagickWand { let mut y_resolution = 0f64; unsafe { if bindings::MagickGetImageResolution(self.wand, &mut x_resolution, &mut y_resolution) - == bindings::MagickBooleanType_MagickTrue + == MagickTrue { Ok((x_resolution, y_resolution)) } else { @@ -711,7 +987,7 @@ impl MagickWand { 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 + == MagickTrue { Ok(()) } else { @@ -724,7 +1000,7 @@ impl MagickWand { 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 + == MagickTrue { Ok(()) } else { @@ -737,7 +1013,7 @@ impl MagickWand { pub fn sepia_tone_image(&self, threshold: f64) -> Result<()> { unsafe { if bindings::MagickSepiaToneImage(self.wand, threshold * self.quantum_range()?) - == bindings::MagickBooleanType_MagickTrue + == MagickTrue { Ok(()) } else { @@ -771,7 +1047,39 @@ impl MagickWand { c_map.as_ptr(), bindings::StorageType_CharPixel, pixels.as_mut_ptr() as *mut c_void, - ) == bindings::MagickBooleanType_MagickTrue + ) == MagickTrue + { + Some(pixels) + } else { + None + } + } + } + + pub fn export_image_pixels_double( + &self, + x: isize, + y: isize, + width: usize, + height: usize, + map: &str, + ) -> Option> { + let c_map = CString::new(map).unwrap(); + let capacity = width * height * map.len(); + let mut pixels = Vec::with_capacity(capacity); + pixels.resize(capacity, 0.0); + + unsafe { + if bindings::MagickExportImagePixels( + self.wand, + x, + y, + width, + height, + c_map.as_ptr(), + bindings::StorageType_DoublePixel, + pixels.as_mut_ptr() as *mut c_void, + ) == MagickTrue { Some(pixels) } else { @@ -782,18 +1090,42 @@ impl MagickWand { /// Resize the image to the specified width and height, using the /// specified filter type. - pub fn resize_image(&self, width: usize, height: usize, filter: FilterType) { - unsafe { - bindings::MagickResizeImage(self.wand, width as size_t, height as size_t, filter.into()); + pub fn resize_image(&self, width: usize, height: usize, filter: FilterType) -> Result<()> { + match unsafe { + bindings::MagickResizeImage(self.wand, width.into(), height.into(), filter.into()) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to resize image")), } } + /// Resize image by specifying the new size in percent of last size. + /// + /// Effectively resizes image to (current width * `width_scale`, current height * + /// `height_scale`) + pub fn scale_image( + &self, + width_scale: f64, + height_scale: f64, + filter: FilterType) -> Result<()> { + let width = self.get_image_width(); + let height = self.get_image_height(); + + let width = ((width as f64) * width_scale) as usize; + let height = ((height as f64) * height_scale) as usize; + + return self.resize_image(width, height, filter); + } + /// Resize the image to the specified width and height, using the /// 'thumbnail' optimizations which remove a lot of image meta-data with the goal /// of producing small low cost images suited for display on the web. - pub fn thumbnail_image(&self, width: usize, height: usize) { - unsafe { - bindings::MagickThumbnailImage(self.wand, width as size_t, height as size_t); + pub fn thumbnail_image(&self, width: usize, height: usize) -> Result<()> { + match unsafe { + bindings::MagickThumbnailImage(self.wand, width.into(), height.into()) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to create thumbnail")), } } @@ -802,7 +1134,7 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to crop image")), } } @@ -814,7 +1146,7 @@ impl MagickWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to sample image")), } } @@ -826,9 +1158,12 @@ impl MagickWand { x_resolution: f64, y_resolution: f64, filter: FilterType, - ) { - unsafe { - bindings::MagickResampleImage(self.wand, x_resolution, y_resolution, filter.into()); + ) -> Result<()> { + match unsafe { + bindings::MagickResampleImage(self.wand, x_resolution, y_resolution, filter.into()) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to resample image")), } } @@ -843,22 +1178,22 @@ impl MagickWand { match unsafe { bindings::MagickLiquidRescaleImage(self.wand, width, height, delta_x, rigidity) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => 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<()> { - match unsafe { bindings::MagickImplodeImage(self.wand, amount, method) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + pub fn implode(&self, amount: f64, method: PixelInterpolateMethod) -> Result<()> { + match unsafe { bindings::MagickImplodeImage(self.wand, amount, method.into()) } { + MagickTrue => Ok(()), _ => Err(MagickError("failed to implode image")), } } /// Resize the image to fit within the given dimensions, maintaining /// the current aspect ratio. - pub fn fit(&self, width: size_t, height: size_t) { + 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; @@ -866,21 +1201,21 @@ impl MagickWand { let (new_width, new_height) = if width_ratio < height_ratio { ( width, - (self.get_image_height() as f64 * width_ratio) as size_t, + (self.get_image_height() as f64 * width_ratio) as usize, ) } else { ( - (self.get_image_width() as f64 * height_ratio) as size_t, + (self.get_image_width() as f64 * height_ratio) as usize, height, ) }; unsafe { bindings::MagickResetIterator(self.wand); - while bindings::MagickNextImage(self.wand) != bindings::MagickBooleanType_MagickFalse { + while bindings::MagickNextImage(self.wand) != MagickFalse { bindings::MagickResizeImage( self.wand, - new_width, - new_height, + new_width.into(), + new_height.into(), bindings::FilterType_LanczosFilter, ); } @@ -890,10 +1225,7 @@ impl MagickWand { /// 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::OrientationType_TopLeftOrientation - } + return self.get_image_orientation() != OrientationType::TopLeft; } /// Automatically adjusts the loaded image so that its orientation is @@ -902,7 +1234,7 @@ impl MagickWand { /// Returns `true` if successful or `false` if an error occurred. pub fn auto_orient(&self) -> bool { unsafe { - bindings::MagickAutoOrientImage(self.wand) == bindings::MagickBooleanType_MagickTrue + bindings::MagickAutoOrientImage(self.wand) == MagickTrue } } @@ -911,7 +1243,7 @@ impl MagickWand { let c_name = CString::new(path).unwrap(); let result = unsafe { bindings::MagickWriteImage(self.wand, c_name.as_ptr()) }; match result { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to write image")), } } @@ -966,13 +1298,13 @@ 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) }; - res == bindings::MagickBooleanType_MagickTrue + res == MagickTrue } /// Renders the drawing wand on the current image pub fn draw_image(&mut self, drawing_wand: &DrawingWand) -> Result<()> { match unsafe { bindings::MagickDrawImage(self.wand, drawing_wand.wand) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("unable to draw image")), } } @@ -983,27 +1315,48 @@ impl MagickWand { /// not placed completely flat when scanned pub fn deskew_image(&mut self, threshold: f64) -> Result<()> { match unsafe { bindings::MagickDeskewImage(self.wand, threshold) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("unable to deskew image")), } } + /// Sets image clip mask. + /// + /// * `pixel_mask`: type of mask, Read or Write. + /// * `clip_mask`: the clip_mask wand. + pub fn set_image_mask( + &mut self, + pixel_mask: PixelMask, + clip_mask: &MagickWand + ) -> Result<()> { + match unsafe { + bindings::MagickSetImageMask( + self.wand, + pixel_mask.into(), + clip_mask.wand + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to set image mask")), + } + } + /// Set image channel mask pub fn set_image_channel_mask( &mut self, - option: bindings::ChannelType, - ) -> bindings::ChannelType { - unsafe { bindings::MagickSetImageChannelMask(self.wand, option) } + option: ChannelType, + ) -> ChannelType { + unsafe { bindings::MagickSetImageChannelMask(self.wand, option.into()).into() } } /// Apply an arithmetic, relational, or logical /// 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<()> { - let res = unsafe { bindings::MagickEvaluateImage(self.wand, op, val) }; + pub fn evaluate_image(&mut self, op: MagickEvaluateOperator, val: f64) -> Result<()> { + let res = unsafe { bindings::MagickEvaluateImage(self.wand, op.into(), val) }; match res { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to evaluate image")), } } @@ -1020,7 +1373,7 @@ impl MagickWand { match unsafe { bindings::MagickBorderImage(self.wand, pixel_wand.wand, width, height, compose.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("border image returned false")), } @@ -1030,7 +1383,7 @@ impl MagickWand { 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 + == MagickTrue { Ok(()) } else { @@ -1063,7 +1416,34 @@ impl MagickWand { pixels.as_ptr() as *const libc::c_void, ) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), + _ => Err(MagickError("unable to import pixels")), + } + } + + pub fn import_image_pixels_double( + &mut self, + x: isize, + y: isize, + columns: usize, + rows: usize, + pixels: &[f64], + map: &str, + ) -> Result<()> { + let pixel_map = CString::new(map).unwrap(); + match unsafe { + bindings::MagickImportImagePixels( + self.wand, + x, + y, + columns, + rows, + pixel_map.as_ptr(), + bindings::StorageType_DoublePixel, + pixels.as_ptr() as *const libc::c_void, + ) + } { + MagickTrue => Ok(()), _ => Err(MagickError("unable to import pixels")), } } @@ -1080,16 +1460,16 @@ impl MagickWand { /// See for more information. pub fn next_image(&self) -> bool { let res = unsafe { bindings::MagickNextImage(self.wand) }; - res == bindings::MagickBooleanType_MagickTrue + res == MagickTrue } /// Automatically performs threshold method to reduce grayscale data /// down to a binary black & white image. Included algorithms are /// Kapur, Otsu, and Triangle methods. /// See for more information. - pub fn auto_threshold(&self, method: bindings::AutoThresholdMethod) -> Result<()> { - match unsafe { bindings::MagickAutoThresholdImage(self.wand, method) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + pub fn auto_threshold(&self, method: AutoThresholdMethod) -> Result<()> { + match unsafe { bindings::MagickAutoThresholdImage(self.wand, method.into()) } { + MagickTrue => Ok(()), _ => Err(MagickError("unable to auto threshold image")), } } @@ -1098,7 +1478,7 @@ impl MagickWand { /// the process. pub fn transform_image_colorspace(&self, colorspace: ColorspaceType) -> Result<()> { match unsafe { bindings::MagickTransformImageColorspace(self.wand, colorspace.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to transform image colorspace")), } } @@ -1106,19 +1486,19 @@ impl MagickWand { /// Reduce the number of colors in the image. pub fn quantize_image( &self, - number_of_colors: size_t, + number_of_colors: usize, colorspace: ColorspaceType, - tree_depth: size_t, + tree_depth: usize, dither_method: DitherMethod, measure_error: bool) -> Result<()> { match unsafe { bindings::MagickQuantizeImage( self.wand, - number_of_colors, + number_of_colors.into(), colorspace.into(), - tree_depth, + tree_depth.into(), dither_method.into(), measure_error.to_magick()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to quantize image")), } } @@ -1126,64 +1506,202 @@ impl MagickWand { /// Reduce the number of colors in the images. pub fn quantize_images( &self, - number_of_colors: size_t, + number_of_colors: usize, colorspace: ColorspaceType, - tree_depth: size_t, + tree_depth: usize, dither_method: DitherMethod, measure_error: bool) -> Result<()> { match unsafe { bindings::MagickQuantizeImages( self.wand, - number_of_colors, + number_of_colors.into(), colorspace.into(), - tree_depth, + tree_depth.into(), dither_method.into(), measure_error.to_magick()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to quantize images")), } } - pub fn get_colorspace(&self) -> ColorspaceType { - return unsafe { bindings::MagickGetColorspace(self.wand).into() }; - } - - pub fn set_colorspace(&mut self, colorspace: ColorspaceType) -> Result<()> { - match unsafe { bindings::MagickSetColorspace(self.wand, colorspace.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(MagickError("failed to set colorspace")), + /// Applies an arithmetic, relational, or logical 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. + /// + /// * `function`: the image function. + /// * `args`: the function arguments. + /// + /// # Example + /// + /// This example show how you can apply smoothstep function (a polynomial `-2x^3 + 3x^2`) to + /// every image pixel. + /// + /// ``` + /// use magick_rust::{MagickWand, PixelWand, MagickFunction}; + /// + /// fn main() -> Result<(), magick_rust::MagickError> { + /// let mut wand1 = MagickWand::new(); + /// wand1.new_image(4, 4, &PixelWand::new())?; // Replace with `read_image` to open your image file + /// + /// // Apply smoothstep polynomial + /// wand1.function_image(MagickFunction::Polynomial, &[-2.0, 3.0, 0.0, 0.0])?; + /// + /// Ok(()) + /// } + /// ``` + pub fn function_image( + &self, + function: MagickFunction, + args: &[f64] + ) -> Result<()> { + let num_of_args: size_t = args.len().into(); + match unsafe { + bindings::MagickFunctionImage( + self.wand, + function.into(), + num_of_args, + args.as_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to apply function to image")), } } - pub fn get_image_colorspace(&self) -> ColorspaceType { - return unsafe { bindings::MagickGetImageColorspace(self.wand).into() }; - } - - pub fn set_image_colorspace(&self, colorspace: ColorspaceType) -> Result<()> { - match unsafe { bindings::MagickSetImageColorspace(self.wand, colorspace.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(MagickError("failed to set image colorspace")), + /// Returns an image where each pixel is the sum of the pixels in the image sequence after + /// applying its corresponding terms (coefficient and degree pairs). + /// + /// * `terms`: the list of polynomial coefficients and degree pairs and a constant. + pub fn polynomial_image(&self, terms: &[f64]) -> Result<()> { + if terms.len() & 1 != 1 { + return Err(MagickError("no constant coefficient given")); + } + let num_of_terms: size_t = (terms.len() >> 1).into(); + match unsafe { + bindings::MagickPolynomialImage( + self.wand, + num_of_terms, + terms.as_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to apply polynomial to image")), } } - pub fn get_gravity(&self) -> GravityType { - return unsafe { bindings::MagickGetGravity(self.wand).into() }; - } - - pub fn set_gravity(&mut self, gravity: GravityType) -> Result<()> { - match unsafe { bindings::MagickSetGravity(self.wand, gravity.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(MagickError("failed to set gravity")), + /// Applies a custom convolution kernel to the image. + /// + /// * `kernel_info`: An array of doubles representing the convolution kernel. + pub fn convolve_image(&self, kernel_info: &KernelInfo) -> Result<()> { + match unsafe { + bindings::MagickConvolveImage( + self.wand, + kernel_info.get_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to convolve image")), } } - pub fn get_image_gravity(&self) -> GravityType { - return unsafe { bindings::MagickGetImageGravity(self.wand).into() }; + /// Applies a user supplied kernel to the image according to the given morphology method. + /// + /// * `morphology_method`: the morphology method to be applied. + /// * `iterations`: apply the operation this many times (or no change). A value of -1 means loop until no change found. How this is applied may depend on the morphology method. Typically this is a value of 1. + /// * `kernel_info`: An array of doubles representing the morphology kernel. + pub fn morphology_image( + &self, + morphology_method: MorphologyMethod, + iterations: isize, + kernel_info: &KernelInfo + ) -> Result<()> { + match unsafe { + bindings::MagickMorphologyImage( + self.wand, + morphology_method.into(), + iterations.into(), + kernel_info.get_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to morphology image")), + } } - pub fn set_image_gravity(&mut self, gravity: GravityType) -> Result<()> { - match unsafe { bindings::MagickSetImageGravity(self.wand, gravity.into()) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), - _ => Err(MagickError("failed to set image gravity")), + /// Apply color transformation to an image. The method permits saturation changes, hue rotation, + /// luminance to alpha, and various other effects. Although variable-sized transformation + /// matrices can be used, typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA + /// (or RGBA with offsets). The matrix is similar to those used by Adobe Flash except offsets + /// are in column 6 rather than 5 (in support of CMYKA images) and offsets are normalized + /// (divide Flash offset by 255). + /// + /// * `color_matrix`: the color matrix. + pub fn color_matrix_image(&self, color_matrix: &KernelInfo) -> Result<()> { + match unsafe { + bindings::MagickColorMatrixImage( + self.wand, + color_matrix.get_ptr() + ) + } { + MagickTrue => Ok(()), + _ => Err(MagickError("failed to color matrix image")), + } + } + + /// Applies a channel expression to the specified image. The expression + /// consists of one or more channels, either mnemonic or numeric (e.g. red, 1), separated by + /// actions as follows: + /// + /// <=> exchange two channels (e.g. red<=>blue) => transfer a channel to another (e.g. + /// red=>green) , separate channel operations (e.g. red, green) | read channels from next input + /// image (e.g. red | green) ; write channels to next output image (e.g. red; green; blue) A + /// channel without a operation symbol implies extract. For example, to create 3 grayscale + /// images from the red, green, and blue channels of an image, use: + /// + /// * `expression`: the expression. + pub fn channel_fx_image(&self, expression: &str) -> Result { + let c_expression = CString::new(expression).map_err(|_| MagickError("artifact string contains null byte"))?; + + let result = unsafe { + bindings::MagickChannelFxImage( + self.wand, + c_expression.as_ptr() + ) + }; + + return if result.is_null() { + Err(MagickError("failed to apply expression to image")) + } else { + Ok(MagickWand{ wand: result }) + }; + } + + /// Combines one or more images into a single image. The grayscale value of the pixels of each + /// image in the sequence is assigned in order to the specified channels of the combined image. + /// The typical ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc. + /// + /// * `colorspace`: the colorspace. + pub fn combine_images(&self, colorspace: ColorspaceType) -> Result { + let result = unsafe { + bindings::MagickCombineImages(self.wand, colorspace.into()) + }; + + return if result.is_null() { + Err(MagickError("failed to combine images")) + } else { + Ok(MagickWand{ wand: result }) + } + } + + /// Returns the current image from the magick wand. + pub fn get_image<'wand>(&'wand self) -> Result> { + let result = unsafe { + bindings::GetImageFromMagickWand(self.wand) + }; + + return if result.is_null() { + Err(MagickError("no image in wand")) + } else { + unsafe { Ok(Image::new(result)) } } } @@ -1198,14 +1716,13 @@ impl MagickWand { MagickBrightnessContrastImage => brightness_contrast_image(brightness: f64, contrast: f64) /// Set the image alpha channel mode. - MagickSetImageAlphaChannel => set_image_alpha_channel( - alpha_channel: bindings::AlphaChannelOption) + MagickSetImageAlphaChannel => set_image_alpha_channel(alpha_channel: AlphaChannelOption) /// Discard all but one of any pixel color. MagickUniqueImageColors => unique_image_colors() /// Applies k-means color reduction to the image. - MagickKmeansImage => kmeans(number_colors: size_t, max_iterations: size_t, tolerance: f64) + MagickKmeansImage => kmeans(number_colors: usize, max_iterations: usize, tolerance: f64) /// Extracts the 'mean' from the image and adjust the image to try make set its gamma appropriately. MagickAutoGammaImage => auto_gamma() @@ -1214,7 +1731,7 @@ impl MagickWand { MagickAutoLevelImage => auto_level() ); - get!(get_image_colors, MagickGetImageColors, size_t); + get!(get_image_colors, MagickGetImageColors, usize); string_set_get!( get_filename, set_filename, MagickGetFilename, MagickSetFilename @@ -1225,30 +1742,35 @@ impl MagickWand { ); set_get!( - get_compression, set_compression, MagickGetCompression, MagickSetCompression, bindings::CompressionType - get_compression_quality, set_compression_quality, MagickGetCompressionQuality, MagickSetCompressionQuality, size_t - get_image_compression, set_image_compression, MagickGetImageCompression, MagickSetImageCompression, bindings::CompressionType - get_image_compression_quality, set_image_compression_quality, MagickGetImageCompressionQuality, MagickSetImageCompressionQuality, size_t - get_image_delay, set_image_delay, MagickGetImageDelay, MagickSetImageDelay, size_t - get_image_depth, set_image_depth, MagickGetImageDepth, MagickSetImageDepth, size_t - get_image_dispose, set_image_dispose, MagickGetImageDispose, MagickSetImageDispose, bindings::DisposeType - get_image_endian, set_image_endian, MagickGetImageEndian, MagickSetImageEndian, bindings::EndianType + get_colorspace, set_colorspace, MagickGetColorspace, MagickSetColorspace, ColorspaceType + get_image_compose, set_image_compose, MagickGetImageCompose, MagickSetImageCompose, CompositeOperator + get_compression, set_compression, MagickGetCompression, MagickSetCompression, CompressionType + get_compression_quality, set_compression_quality, MagickGetCompressionQuality, MagickSetCompressionQuality, usize + get_gravity, set_gravity, MagickGetGravity, MagickSetGravity, GravityType + get_image_colorspace, set_image_colorspace, MagickGetImageColorspace, MagickSetImageColorspace, ColorspaceType + get_image_compression, set_image_compression, MagickGetImageCompression, MagickSetImageCompression, CompressionType + get_image_compression_quality, set_image_compression_quality, MagickGetImageCompressionQuality, MagickSetImageCompressionQuality, usize + get_image_delay, set_image_delay, MagickGetImageDelay, MagickSetImageDelay, usize + get_image_depth, set_image_depth, MagickGetImageDepth, MagickSetImageDepth, usize + get_image_dispose, set_image_dispose, MagickGetImageDispose, MagickSetImageDispose, DisposeType + get_image_endian, set_image_endian, MagickGetImageEndian, MagickSetImageEndian, EndianType get_image_fuzz, set_image_fuzz, MagickGetImageFuzz, MagickSetImageFuzz, f64 get_image_gamma, set_image_gamma, MagickGetImageGamma, MagickSetImageGamma, f64 - get_image_interlace_scheme, set_image_interlace_scheme, MagickGetImageInterlaceScheme, MagickSetImageInterlaceScheme, bindings::InterlaceType - get_image_interpolate_method, set_image_interpolate_method, MagickGetImageInterpolateMethod, MagickSetImageInterpolateMethod, bindings::PixelInterpolateMethod - get_image_iterations, set_image_iterations, MagickGetImageIterations, MagickSetImageIterations, size_t - get_image_orientation, set_image_orientation, MagickGetImageOrientation, MagickSetImageOrientation, bindings::OrientationType - get_image_rendering_intent, set_image_rendering_intent, MagickGetImageRenderingIntent, MagickSetImageRenderingIntent, bindings::RenderingIntent - get_image_scene, set_image_scene, MagickGetImageScene, MagickSetImageScene, size_t - get_image_type, set_image_type, MagickGetImageType, MagickSetImageType, bindings::ImageType - get_image_units, set_image_units, MagickGetImageUnits, MagickSetImageUnits, bindings::ResolutionType - get_interlace_scheme, set_interlace_scheme, MagickGetInterlaceScheme, MagickSetInterlaceScheme, bindings::InterlaceType - get_interpolate_method, set_interpolate_method, MagickGetInterpolateMethod, MagickSetInterpolateMethod, bindings::PixelInterpolateMethod - get_iterator_index, set_iterator_index, MagickGetIteratorIndex, MagickSetIteratorIndex, ssize_t - get_orientation, set_orientation, MagickGetOrientation, MagickSetOrientation, bindings::OrientationType + get_image_gravity, set_image_gravity, MagickGetImageGravity, MagickSetImageGravity, GravityType + get_image_interlace_scheme, set_image_interlace_scheme, MagickGetImageInterlaceScheme, MagickSetImageInterlaceScheme, InterlaceType + get_image_interpolate_method, set_image_interpolate_method, MagickGetImageInterpolateMethod, MagickSetImageInterpolateMethod, PixelInterpolateMethod + get_image_iterations, set_image_iterations, MagickGetImageIterations, MagickSetImageIterations, usize + get_image_orientation, set_image_orientation, MagickGetImageOrientation, MagickSetImageOrientation, OrientationType + get_image_rendering_intent, set_image_rendering_intent, MagickGetImageRenderingIntent, MagickSetImageRenderingIntent, RenderingIntent + get_image_scene, set_image_scene, MagickGetImageScene, MagickSetImageScene, usize + get_image_type, set_image_type, MagickGetImageType, MagickSetImageType, ImageType + get_image_units, set_image_units, MagickGetImageUnits, MagickSetImageUnits, ResolutionType + get_interlace_scheme, set_interlace_scheme, MagickGetInterlaceScheme, MagickSetInterlaceScheme, InterlaceType + get_interpolate_method, set_interpolate_method, MagickGetInterpolateMethod, MagickSetInterpolateMethod, PixelInterpolateMethod + get_iterator_index, set_iterator_index, MagickGetIteratorIndex, MagickSetIteratorIndex, isize + get_orientation, set_orientation, MagickGetOrientation, MagickSetOrientation, OrientationType get_pointsize, set_pointsize, MagickGetPointsize, MagickSetPointsize, f64 - get_type, set_type, MagickGetType, MagickSetType, bindings::ImageType + get_type, set_type, MagickGetType, MagickSetType, ImageType ); } diff --git a/src/wand/mod.rs b/src/wand/mod.rs index 29601df..292a4ce 100644 --- a/src/wand/mod.rs +++ b/src/wand/mod.rs @@ -22,3 +22,6 @@ mod pixel; pub use self::drawing::DrawingWand; pub use self::magick::MagickWand; pub use self::pixel::{PixelWand, HSL}; + +use bindings::MagickBooleanType_MagickTrue as MagickTrue; +use bindings::MagickBooleanType_MagickFalse as MagickFalse; diff --git a/src/wand/pixel.rs b/src/wand/pixel.rs index b825404..c63ff23 100644 --- a/src/wand/pixel.rs +++ b/src/wand/pixel.rs @@ -16,15 +16,11 @@ 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 bindings; use result::MagickError; use crate::result::Result; +use super::MagickTrue; #[derive(Default, Debug)] pub struct HSL { @@ -48,7 +44,7 @@ wand_common!( impl PixelWand { pub fn is_similar(&self, other: &PixelWand, fuzz: f64) -> Result<()> { match unsafe { bindings::IsPixelWandSimilar(self.wand, other.wand, fuzz) } { - bindings::MagickBooleanType_MagickTrue => Ok(()), + MagickTrue => Ok(()), _ => Err(MagickError("not similar")), } } @@ -86,7 +82,7 @@ impl PixelWand { 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(()), + MagickTrue => Ok(()), _ => Err(MagickError("failed to set color")), } } @@ -98,8 +94,8 @@ impl PixelWand { ); set_get_unchecked!( - get_color_count, set_color_count, PixelGetColorCount, PixelSetColorCount, size_t - get_index, set_index, PixelGetIndex, PixelSetIndex, bindings::Quantum + get_color_count, set_color_count, PixelGetColorCount, PixelSetColorCount, usize + get_index, set_index, PixelGetIndex, PixelSetIndex, f32 get_fuzz, set_fuzz, PixelGetFuzz, PixelSetFuzz, f64 ); diff --git a/tests/lib.rs b/tests/lib.rs index f55c864..f929aa4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -22,7 +22,7 @@ use std::io::Read; use std::path::Path; use std::sync::Once; -use magick_rust::{bindings, magick_wand_genesis, MagickWand, PixelWand}; +use magick_rust::{magick_wand_genesis, MagickWand, PixelWand}; use magick_rust::MagickError; // Used to make sure MagickWand is initialized exactly once. Note that we @@ -54,7 +54,7 @@ fn test_resize_image() { 1 => 1, height => height / 2, }; - wand.resize_image(halfwidth, halfheight, magick_rust::FilterType::Lanczos); + assert!(wand.resize_image(halfwidth, halfheight, magick_rust::FilterType::Lanczos).is_ok()); assert_eq!(256, wand.get_image_width()); assert_eq!(192, wand.get_image_height()); } @@ -76,7 +76,7 @@ fn test_thumbnail_image() { 1 => 1, height => height / 2, }; - wand.thumbnail_image(halfwidth, halfheight); + assert!(wand.thumbnail_image(halfwidth, halfheight).is_ok()); assert_eq!(256, wand.get_image_width()); assert_eq!(192, wand.get_image_height()); } @@ -317,7 +317,7 @@ fn test_set_image_background_color() { let mut pw = PixelWand::new(); pw.set_color("#0000FF").unwrap(); wand.set_image_background_color(&pw).unwrap(); - wand.set_image_alpha_channel(bindings::AlphaChannelOption_RemoveAlphaChannel) + wand.set_image_alpha_channel(magick_rust::AlphaChannelOption::Remove) .unwrap(); let blob = wand.write_image_blob("rgb").unwrap(); assert_eq!(0u8, blob[0]); @@ -364,7 +364,7 @@ fn test_clut_image() { assert!(wand .clut_image( &gradient, - bindings::PixelInterpolateMethod_BilinearInterpolatePixel + magick_rust::PixelInterpolateMethod::Bilinear ) .is_ok()); } @@ -422,7 +422,7 @@ fn test_image_compose() { START.call_once(|| { magick_wand_genesis(); }); - let wand = MagickWand::new(); + let mut wand = MagickWand::new(); wand.new_image(4, 4, &PixelWand::new()).unwrap(); let operators = [