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
|
# 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
|
## 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.
|
1. Develop Rustic wrappers to the MagickWand library.
|
||||||
* Old Rust bindings: https://github.com/influenza/wand-of-rust
|
* Old Rust bindings: https://github.com/influenza/wand-of-rust
|
||||||
* Wand API: http://www.imagemagick.org/script/magick-wand.php
|
* 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
|
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
|
## 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.
|
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.
|
//! "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
|
// Make the Rust bindings compile cleanly, despite being very un-Rust-like
|
||||||
// wrappers around C code.
|
// wrappers around C code.
|
||||||
@ -27,12 +32,18 @@
|
|||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
use libc::{c_uint, size_t, c_double, c_void};
|
use libc::{c_uint, size_t, c_double, c_void};
|
||||||
use filters::FilterType;
|
use filters::FilterType;
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
|
|
||||||
/// MagickWand is a Rustic wrapper to the Rust bindings to ImageMagick.
|
/// 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 {
|
pub struct MagickWand {
|
||||||
wand: *mut bindings::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.
|
/// Write the current image to the provided path.
|
||||||
pub fn write_image(&self, path: &str) -> Result<(), &'static str> {
|
pub fn write_image(&self, path: &str) -> Result<(), &'static str> {
|
||||||
let c_name = CString::new(path).unwrap();
|
let c_name = CString::new(path).unwrap();
|
||||||
@ -115,6 +124,28 @@ impl MagickWand {
|
|||||||
_ => Err("failed to write image")
|
_ => 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.
|
// 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!(512, wand.get_image_width());
|
||||||
assert_eq!(384, wand.get_image_height());
|
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