picturium-libvips 0.1.3

Libvips bindings for picturium media server
Documentation
use std::os::raw::c_int;
use std::ptr::null_mut;
use crate::{Vips, VipsFailOn, VipsImage, VipsIntent, VipsInteresting, VipsSize, NULL};
use crate::bindings::{vips_thumbnail, vips_thumbnail_image};
use crate::result::{Error, Result};
use crate::utils::c_string;

pub trait VipsThumbnails {
    fn thumbnail(filename: &str, width: i32, options: Option<ThumbnailOptions>) -> Result<VipsImage>;
    fn thumbnail_image(self, width: i32, options: Option<ThumbnailOptions>) -> Result<VipsImage>;
}

impl VipsThumbnails for VipsImage {
    fn thumbnail(filename: &str, width: i32, options: Option<ThumbnailOptions>) -> Result<VipsImage> {
        let mut output_image: *mut crate::bindings::VipsImage = null_mut();

        let result = match options {
            Some(options) => unsafe {
                vips_thumbnail(
                    c_string(filename)?.as_ptr(), &mut output_image, width,
                    c_string("height")?.as_ptr(), options.height,
                    c_string("size")?.as_ptr(), options.size,
                    c_string("no-rotate")?.as_ptr(), options.no_rotate as c_int,
                    c_string("crop")?.as_ptr(), options.crop,
                    c_string("linear")?.as_ptr(), options.linear as c_int,
                    c_string("import-profile")?.as_ptr(), c_string(&options.import_profile)?.as_ptr(),
                    c_string("export-profile")?.as_ptr(), c_string(&options.export_profile)?.as_ptr(),
                    c_string("intent")?.as_ptr(), options.intent,
                    c_string("fail_on")?.as_ptr(), options.fail_on,
                    NULL
                )
            },
            None => unsafe { vips_thumbnail(c_string(filename)?.as_ptr(), &mut output_image, width, NULL) }
        };

        if result != 0 || output_image.is_null() {
            return Err(Error::ImageOperationError(Vips::get_error()));
        }

        Ok(VipsImage(output_image, None))
    }

    fn thumbnail_image(self, width: i32, options: Option<ThumbnailOptions>) -> Result<VipsImage> {
        let mut output_image: *mut crate::bindings::VipsImage = null_mut();

        let result = match options {
            Some(options) => unsafe {
                vips_thumbnail_image(
                    self.0, &mut output_image, width,
                    c_string("height")?.as_ptr(), options.height,
                    c_string("size")?.as_ptr(), options.size,
                    c_string("no-rotate")?.as_ptr(), options.no_rotate as c_int,
                    c_string("crop")?.as_ptr(), options.crop,
                    c_string("linear")?.as_ptr(), options.linear as c_int,
                    c_string("import-profile")?.as_ptr(), c_string(&options.import_profile)?.as_ptr(),
                    c_string("export-profile")?.as_ptr(), c_string(&options.export_profile)?.as_ptr(),
                    c_string("intent")?.as_ptr(), options.intent,
                    c_string("fail_on")?.as_ptr(), options.fail_on,
                    NULL
                )
            },
            None => unsafe { vips_thumbnail_image(self.0, &mut output_image, width, NULL) }
        };

        if result != 0 || output_image.is_null() {
            return Err(Error::ImageOperationError(Vips::get_error()));
        }

        let mut output_image = VipsImage(output_image, None);
        output_image.keepalive(self);

        Ok(output_image)
    }
}

#[derive(Debug)]
pub struct ThumbnailOptions {
    pub height: i32,
    pub size: VipsSize,
    pub no_rotate: bool,
    pub crop: VipsInteresting,
    pub linear: bool,
    pub import_profile: String,
    pub export_profile: String,
    pub intent: VipsIntent,
    pub fail_on: VipsFailOn
}

impl Default for ThumbnailOptions {
    fn default() -> Self {
        Self {
            height: 0,
            size: VipsSize::default(),
            no_rotate: false,
            crop: VipsInteresting::default(),
            linear: false,
            import_profile: "sRGB".into(),
            export_profile: "sRGB".into(),
            intent: VipsIntent::default(),
            fail_on: VipsFailOn::default(),
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::VipsSaving;
    use super::*;

    #[test]
    fn it_can_generate_thumbnail() {
        let vips = Vips::new("picturium").unwrap();
        vips.check_leaks();

        let image = VipsImage::thumbnail("data/example.jpg", 200, Some(ThumbnailOptions {
            height: 200,
            ..Default::default()
        }));

        if let Err(e) = image {
            panic!("{e}");
        }

        image.unwrap().save_jpeg("data/output/thumbnail.jpg", None).unwrap();
    }

    #[test]
    fn it_can_generate_thumbnail_image() {
        let vips = Vips::new("picturium").unwrap();
        vips.check_leaks();

        let mut image = VipsImage::new_from_file("data/example.jpg", None);
        image = VipsImage::thumbnail_image(image.unwrap(), 200, Some(ThumbnailOptions {
            height: 200,
           ..Default::default()
        }));

        if let Err(e) = image {
            panic!("{e}");
        }

        image.unwrap().save_jpeg("data/output/thumbnail.jpg", None).unwrap();
    }
}