From 56877aaad35f3c443c9ac78b6b175e43378512bb Mon Sep 17 00:00:00 2001 From: Nathan Fiedler Date: Tue, 9 Jun 2015 22:18:57 -0700 Subject: [PATCH] Write image to a vector of bytes (in memory write) cargo test passes --- README.md | 13 +++++++++++-- src/lib.rs | 35 +++++++++++++++++++++++++++++++++-- tests/lib.rs | 17 +++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 11b7d52..2718093 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # magick-rust -A "safe" Rust interface to the [ImageMagick](http://www.imagemagick.org/) system, in particular, the MagickWand library. The *safe* is in scarequotes because honestly nearly everything is little more than calls into a C library with `unsafe` wrapped around it. +A "safe" Rust interface to the [ImageMagick](http://www.imagemagick.org/) system, in particular, the MagickWand library. The word *safe* is in scarequotes because, honestly, nearly everything is little more than a call into a C function with `unsafe` wrapped around it. ## TODO @@ -9,9 +9,18 @@ A "safe" Rust interface to the [ImageMagick](http://www.imagemagick.org/) system 1. Develop Rustic wrappers to the MagickWand library. * Old Rust bindings: https://github.com/influenza/wand-of-rust * Wand API: http://www.imagemagick.org/script/magick-wand.php -1. Write unit tests +1. ~~Write unit tests~~ 1. Test it on lots of images in batches to stress test it; should not crash +## Build and Test + +Pretty simple for now. + +``` +$ cargo build +$ cargo test +``` + ## Generating Bindings To generate the ImageMagick bindings, we use [rust-bindgen](https://github.com/crabtw/rust-bindgen), which reads the C header files and produces a suitable wrapper in Rust. diff --git a/src/lib.rs b/src/lib.rs index c447d8c..6d52b02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,11 @@ //! //! "Safe" wrapper around the low-level bindings to ImageMagick. //! +//! Prior to using the ImageMagick system, the application should invoke +//! `magick_wand_genesis()`, which maps directly to `MagickWandGenesis`. +//! Likewise, when an application is done using ImageMagick, invoke the +//! `magick_wand_terminus()` function, which maps to `MagickWandTerminus`. +//! // Make the Rust bindings compile cleanly, despite being very un-Rust-like // wrappers around C code. @@ -27,12 +32,18 @@ extern crate libc; use std::ffi::CString; +use std::ptr; use libc::{c_uint, size_t, c_double, c_void}; use filters::FilterType; mod bindings; /// MagickWand is a Rustic wrapper to the Rust bindings to ImageMagick. +/// +/// Instantiating a `MagickWand` will construct an ImageMagick "wand" +/// on which operations can be performed via the `MagickWand` functions. +/// When the `MagickWand` is dropped, the ImageMagick wand will be +/// destroyed as well. pub struct MagickWand { wand: *mut bindings::MagickWand } @@ -102,8 +113,6 @@ impl MagickWand { } } - // TODO: get the image from the wand somehow (maybe GetImageFromMagickWand()) - /// Write the current image to the provided path. pub fn write_image(&self, path: &str) -> Result<(), &'static str> { let c_name = CString::new(path).unwrap(); @@ -115,6 +124,28 @@ impl MagickWand { _ => Err("failed to write image") } } + + /// Write the image in the desired format to a new blob. + /// + /// The `format` argument may be any ImageMagick supported image + /// format (e.g. GIF, JPEG, PNG, etc). + pub fn write_image_blob(&self, format: &str) -> Result, &'static str> { + let c_format = CString::new(format).unwrap(); + let mut length: size_t = 0; + let blob = unsafe { + bindings::MagickSetImageFormat(self.wand, c_format.as_ptr()); + bindings::MagickResetIterator(self.wand); + bindings::MagickGetImageBlob(self.wand, &mut length) + }; + // would have used Vec::from_raw_buf() but it is unstable + let mut bytes = Vec::with_capacity(length as usize); + unsafe { + bytes.set_len(length as usize); + ptr::copy_nonoverlapping(blob, bytes.as_mut_ptr(), length as usize); + bindings::MagickRelinquishMemory(blob as *mut c_void); + }; + Ok(bytes) + } } // Automate safe cleanup for MagickWand instances. diff --git a/tests/lib.rs b/tests/lib.rs index abf6bdc..94245b4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -80,3 +80,20 @@ fn test_read_from_blob() { assert_eq!(512, wand.get_image_width()); assert_eq!(384, wand.get_image_height()); } + +#[test] +fn test_write_to_blob() { + START.call_once(|| { + magick_wand_genesis(); + }); + let wand = MagickWand::new(); + assert!(wand.read_image("tests/data/IMG_5745.JPG").is_ok()); + assert_eq!(512, wand.get_image_width()); + assert_eq!(384, wand.get_image_height()); + let blob = wand.write_image_blob("jpeg").unwrap(); + assert_eq!(104061, blob.len()); + // should be able to read it back again + assert!(wand.read_image_blob(blob).is_ok()); + assert_eq!(512, wand.get_image_width()); + assert_eq!(384, wand.get_image_height()); +}