Skip to content

Commit

Permalink
python: Expose new functions on the python side
Browse files Browse the repository at this point in the history
Signed-off-by: caleb <[email protected]>
  • Loading branch information
etemesi254 committed Oct 14, 2023
1 parent 89572ae commit 7e008e3
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 4 deletions.
3 changes: 2 additions & 1 deletion zune-python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use py_functions::*;
use py_image::*;
use pyo3::prelude::*;

use crate::py_enums::{PyImageColorSpace, PyImageDepth, PyImageFormats};
use crate::py_enums::{PyImageColorSpace, PyImageDepth, PyImageFormats, PyImageThresholdType};

mod py_enums;
mod py_functions;
Expand All @@ -23,6 +23,7 @@ fn zune_python(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<PyImageColorSpace>()?;
m.add_class::<PyImage>()?;
m.add_class::<PyImageDepth>()?;
m.add_class::<PyImageThresholdType>()?;

m.add_function(wrap_pyfunction!(guess_format, m)?)?;
m.add_function(wrap_pyfunction!(decode_image, m)?)?;
Expand Down
34 changes: 34 additions & 0 deletions zune-python/src/py_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use zune_core::bit_depth::BitDepth;
use zune_core::colorspace::ColorSpace;
use zune_image::codecs::ImageFormat;
use zune_image::errors::ImageErrors;
use zune_image::filters::threshold::ThresholdMethod;

#[pyclass]
pub struct PyImageErrors {
Expand Down Expand Up @@ -135,13 +136,25 @@ impl From<ColorSpace> for PyImageColorSpace {
}

#[pyclass]
#[derive(Copy, Clone, Debug)]
pub enum PyImageDepth {
Eight,
Sixteen,
F32,
Unknown
}

impl PyImageDepth {
pub(crate) fn to_depth(self) -> BitDepth {
match self {
PyImageDepth::Eight => BitDepth::Eight,
PyImageDepth::Sixteen => BitDepth::Sixteen,
PyImageDepth::F32 => BitDepth::Float32,
PyImageDepth::Unknown => BitDepth::Unknown
}
}
}

impl From<BitDepth> for PyImageDepth {
fn from(value: BitDepth) -> Self {
match value {
Expand All @@ -153,3 +166,24 @@ impl From<BitDepth> for PyImageDepth {
}
}
}

/// Different threshold arguments for the threshold parameter
#[pyclass]
#[derive(Copy, Clone, Debug)]
pub enum PyImageThresholdType {
Binary,
BinaryInv,
ThreshTrunc,
ThreshToZero
}

impl PyImageThresholdType {
pub(crate) fn to_threshold(self) -> ThresholdMethod {
match self {
PyImageThresholdType::Binary => ThresholdMethod::Binary,
PyImageThresholdType::BinaryInv => ThresholdMethod::BinaryInv,
PyImageThresholdType::ThreshTrunc => ThresholdMethod::ThreshTrunc,
PyImageThresholdType::ThreshToZero => ThresholdMethod::ThreshToZero
}
}
}
101 changes: 98 additions & 3 deletions zune-python/src/py_image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ use std::fs::read;
use pyo3::exceptions::PyException;
use pyo3::prelude::*;
use zune_image::filters::crop::Crop;
use zune_image::filters::threshold::Threshold;
use zune_image::filters::transpose::Transpose;
use zune_image::image::Image;
use zune_image::traits::OperationsTrait;
use zune_png::zune_core::options::DecoderOptions;

use crate::py_enums::{PyImageColorSpace, PyImageDepth, PyImageErrors, PyImageFormats};
use crate::py_enums::{
PyImageColorSpace, PyImageDepth, PyImageErrors, PyImageFormats, PyImageThresholdType
};

#[pyclass]
#[derive(Clone)]
Expand Down Expand Up @@ -82,8 +86,6 @@ impl PyImage {
}
/// Convert from one colorspace to another
///
/// This operation modifies the image in place
///
/// # Arguments
/// - to: The new colorspace to convert to
/// - in_place: Whether to perform the conversion in place or to create a copy and convert that
Expand Down Expand Up @@ -183,6 +185,99 @@ impl PyImage {
Ok(Some(im_clone))
};
}
/// Transpose the image.
///
/// This rewrites pixels into `dst(i,j)=src(j,i)`
///
/// # Arguments
/// - inplace: Whether to transpose the image in place or generate a clone
/// and transpose the new clone
#[pyo3(signature = (in_place = false))]
pub fn transpose(&mut self, in_place: bool) -> PyResult<Option<PyImage>> {
let exec = |image: &mut PyImage| -> PyResult<()> {
Transpose::new()
.execute(&mut image.image)
.map_err(|x| PyImageErrors::from(x))?;
Ok(())
};
return if in_place {
exec(self)?;
Ok(None)
} else {
let mut im_clone = self.clone();
exec(&mut im_clone)?;
Ok(Some(im_clone))
};
}

/// Convert from one depth to another
///
/// # Arguments
/// - to: The new depth to convert to
/// - in_place: Whether to perform the conversion in place or to create a copy and convert that
///
/// # Returns
/// - If `in_place=True`: Nothing on success, on error returns error that occurred
/// - If `in_place=False`: An image copy on success on error, returns error that occurred
#[pyo3(signature = (to, in_place = false))]
pub fn convert_depth(&mut self, to: PyImageDepth, in_place: bool) -> PyResult<Option<PyImage>> {
let color = to.to_depth();

let exec = |image: &mut PyImage| -> PyResult<()> {
if let Err(e) = image.image.convert_depth(color) {
return Err(PyErr::new::<PyException, _>(format!(
"Error converting: {:?}",
e
)));
}
Ok(())
};

if in_place {
exec(self)?;
Ok(None)
} else {
let mut im_clone = self.clone();
exec(&mut im_clone)?;

Ok(Some(im_clone))
}
}
/// Applies a fixed-level threshold to each array element.
///
/// Thresholding works best for grayscale images, passing a colored image
/// does not implicitly convert it to grayscale, you need to do that explicitly
///
/// # Arguments
/// - value: Non-zero value assigned to the pixels for which the condition is satisfied
/// - method: The thresholding method used, defaults to binary which generates a black
/// and white image from a grayscale image
/// - in_place: Whether to perform the image in-place or to clone and return a copy
///
#[pyo3(signature = (value, method = PyImageThresholdType::Binary, in_place = false))]
pub fn threshold(
&mut self, value: f32, method: PyImageThresholdType, in_place: bool
) -> PyResult<Option<PyImage>> {
let exec = |image: &mut PyImage| -> PyResult<()> {
if let Err(e) = Threshold::new(value, method.to_threshold()).execute(&mut image.image) {
return Err(PyErr::new::<PyException, _>(format!(
"Error converting: {:?}",
e
)));
}
Ok(())
};

if in_place {
exec(self)?;
Ok(None)
} else {
let mut im_clone = self.clone();
exec(&mut im_clone)?;

Ok(Some(im_clone))
}
}
}

#[pyfunction]
Expand Down

0 comments on commit 7e008e3

Please sign in to comment.