use std::ptr;
use std::convert::TryInto as _;
use crate::buf::{OwnedBuf, OutputBuf};
use crate::common::{Error, Result};
use crate::handle::Handle;
#[derive(Debug)]
#[doc(alias = "tjhandle")]
pub struct Transformer {
handle: Handle,
}
#[derive(Debug, Default, Clone)]
#[doc(alias = "tjtransform")]
#[non_exhaustive]
pub struct Transform {
pub op: TransformOp,
#[doc(alias = "TJXOPT_CROP")]
pub crop: Option<TransformCrop>,
#[doc(alias = "TJXOPT_PERFECT")]
pub perfect: bool,
#[doc(alias = "TJXOPT_TRIM")]
pub trim: bool,
#[doc(alias = "TJXOPT_GRAY")]
pub gray: bool,
#[doc(alias = "TJXOPT_PROGRESSIVE")]
pub progressive: bool,
#[doc(alias = "TJXOPT_ARITHMETIC")]
pub arithmetic: bool,
#[doc(alias = "TJXOPT_OPTIMIZE")]
pub optimize: bool,
#[doc(alias = "TJXOPT_COPYNONE")]
pub copy_none: bool,
}
impl Transform {
pub fn op(op: TransformOp) -> Transform {
Transform { op, ..Transform::default() }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[doc(alias = "TJXOP")]
#[repr(u32)]
#[non_exhaustive]
pub enum TransformOp {
#[doc(alias = "TJXOP_NONE")]
None = raw::TJXOP_TJXOP_NONE,
#[doc(alias = "TJXOP_HFLIP")]
Hflip = raw::TJXOP_TJXOP_HFLIP,
#[doc(alias = "TJXOP_VFLIP")]
Vflip = raw::TJXOP_TJXOP_VFLIP,
#[doc(alias = "TJXOP_TRANSPOSE")]
Transpose = raw::TJXOP_TJXOP_TRANSPOSE,
#[doc(alias = "TJXOP_TRANSVERSE")]
Transverse = raw::TJXOP_TJXOP_TRANSVERSE,
#[doc(alias = "TJXOP_ROT90")]
Rot90 = raw::TJXOP_TJXOP_ROT90,
#[doc(alias = "TJXOP_ROT180")]
Rot180 = raw::TJXOP_TJXOP_ROT180,
Rot270 = raw::TJXOP_TJXOP_ROT270,
}
impl Default for TransformOp {
fn default() -> Self {
TransformOp::None
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[doc(alias = "tjregion")]
pub struct TransformCrop {
pub x: usize,
pub y: usize,
pub width: Option<usize>,
pub height: Option<usize>,
}
impl Transformer {
#[doc(alias = "tj3Init")]
pub fn new() -> Result<Transformer> {
let handle = Handle::new(raw::TJINIT_TJINIT_TRANSFORM)?;
Ok(Self { handle })
}
#[doc(alias = "tj3Transform")]
pub fn transform(
&mut self,
transform: &Transform,
jpeg_data: &[u8],
output: &mut OutputBuf,
) -> Result<()> {
let mut options = 0;
if transform.perfect { options |= raw::TJXOPT_PERFECT }
if transform.trim { options |= raw::TJXOPT_TRIM }
if transform.gray { options |= raw::TJXOPT_GRAY }
if transform.progressive { options |= raw::TJXOPT_PROGRESSIVE }
if transform.arithmetic { options |= raw::TJXOPT_ARITHMETIC }
if transform.optimize { options |= raw::TJXOPT_OPTIMIZE }
if transform.copy_none { options |= raw::TJXOPT_COPYNONE }
let mut region = raw::tjregion {
x: 0, y: 0,
w: 0, h: 0,
};
if let Some(crop) = transform.crop {
region.x = crop.x.try_into().map_err(|_| Error::IntegerOverflow("crop.x"))?;
region.y = crop.y.try_into().map_err(|_| Error::IntegerOverflow("crop.y"))?;
if let Some(crop_w) = crop.width {
region.w = crop_w.try_into().map_err(|_| Error::IntegerOverflow("crop.width"))?;
}
if let Some(crop_h) = crop.height {
region.h = crop_h.try_into().map_err(|_| Error::IntegerOverflow("crop.height"))?;
}
options |= raw::TJXOPT_CROP;
}
let mut transform = raw::tjtransform {
r: region,
op: transform.op as libc::c_int,
options: options as libc::c_int,
data: ptr::null_mut(),
customFilter: None,
};
self.handle.set(
raw::TJPARAM_TJPARAM_NOREALLOC,
if output.is_owned { 0 } else { 1 } as libc::c_int,
)?;
let mut output_len = output.len as raw::size_t;
let res = unsafe {
raw::tj3Transform(
self.handle.as_ptr(),
jpeg_data.as_ptr(), jpeg_data.len() as raw::size_t,
1, &mut output.ptr, &mut output_len,
&mut transform,
)
};
output.len = output_len as usize;
if res != 0 {
return Err(self.handle.get_error())
} else if output.ptr.is_null() {
output.len = 0;
return Err(Error::Null)
}
Ok(())
}
pub fn transform_to_owned(&mut self, transform: &Transform, jpeg_data: &[u8]) -> Result<OwnedBuf> {
let mut buf = OutputBuf::new_owned();
self.transform(transform, jpeg_data, &mut buf)?;
Ok(buf.into_owned())
}
pub fn transform_to_vec(&mut self, transform: &Transform, jpeg_data: &[u8]) -> Result<Vec<u8>> {
let mut buf = OutputBuf::new_owned();
self.transform(transform, jpeg_data, &mut buf)?;
Ok(buf.to_vec())
}
pub fn transform_to_slice(
&mut self,
transform: &Transform,
jpeg_data: &[u8],
output: &mut [u8],
) -> Result<usize> {
let mut buf = OutputBuf::borrowed(output);
self.transform(transform, jpeg_data, &mut buf)?;
Ok(buf.len())
}
}
pub fn transform(transform: &Transform, jpeg_data: &[u8]) -> Result<OwnedBuf> {
let mut transformer = Transformer::new()?;
transformer.transform_to_owned(transform, jpeg_data)
}