Write image to a vector of bytes (in memory write)
cargo test passes
This commit is contained in:
13
README.md
13
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.
|
||||
|
||||
35
src/lib.rs
35
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<Vec<u8>, &'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.
|
||||
|
||||
17
tests/lib.rs
17
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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user