From 16a9dbaeb82c9392c75912cfc1e9ca08400d8b27 Mon Sep 17 00:00:00 2001 From: James Graham Date: Fri, 24 Apr 2015 19:18:09 +0100 Subject: [PATCH 1/2] Add to_vec function for writing PNG data to a Vec. This mostly copies the implementation of store_png, and could probably be refactored to share more code in the future. --- src/lib.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 01c45fd..871f98d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -244,6 +244,69 @@ pub fn store_png>(img: &mut Image, path: P) -> Result<(),String> Ok(()) } +pub extern fn write_data_to_buf(png_ptr: *mut ffi::png_struct, data: *mut u8, length: size_t) { + unsafe { + let io_ptr = ffi::RUST_png_get_io_ptr(png_ptr); + let dest: &mut Vec = mem::transmute(io_ptr); + dest.reserve_exact(length as usize); + let buf = slice::from_raw_parts(data as *const _, length as usize); + for x in buf { + dest.push(*x); + } + } +} + +pub extern fn flush_data_to_buf(_png_ptr: *mut ffi::png_struct) {} + +//TODO: This should share most of the implementation with store_png +pub fn to_vec(img: &mut Image) -> Result,String> { + let target: Vec = Vec::new(); + + unsafe { + let mut png_ptr = ffi::RUST_png_create_write_struct(&*ffi::RUST_png_get_header_ver(ptr::null_mut()), + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut()); + if png_ptr.is_null() { + return Err("could not create write struct".to_string()); + } + let mut info_ptr = ffi::RUST_png_create_info_struct(png_ptr); + if info_ptr.is_null() { + ffi::RUST_png_destroy_write_struct(&mut png_ptr, ptr::null_mut()); + return Err("could not create info struct".to_string()); + } + let res = ffi::setjmp(ffi::pngshim_jmpbuf(png_ptr)); + if res != 0 { + ffi::RUST_png_destroy_write_struct(&mut png_ptr, &mut info_ptr); + return Err("error writing png".to_string()); + } + + ffi::RUST_png_set_write_fn(png_ptr, mem::transmute(&target), + write_data_to_buf, flush_data_to_buf); + + let (bit_depth, color_type, pixel_width, image_buf) = match img.pixels { + PixelsByColorType::RGB8(ref mut pixels) => (8, ffi::COLOR_TYPE_RGB, 3, pixels.as_mut_ptr()), + PixelsByColorType::RGBA8(ref mut pixels) => (8, ffi::COLOR_TYPE_RGBA, 4, pixels.as_mut_ptr()), + PixelsByColorType::K8(ref mut pixels) => (8, ffi::COLOR_TYPE_GRAY, 1, pixels.as_mut_ptr()), + PixelsByColorType::KA8(ref mut pixels) => (8, ffi::COLOR_TYPE_GA, 2, pixels.as_mut_ptr()), + }; + + ffi::RUST_png_set_IHDR(png_ptr, info_ptr, img.width, img.height, bit_depth, color_type, + ffi::INTERLACE_NONE, ffi::COMPRESSION_TYPE_DEFAULT, ffi::FILTER_NONE); + + let mut row_pointers: Vec<*mut u8> = (0..img.height as usize).map(|idx| { + image_buf.offset((((img.width * pixel_width) as usize) * idx) as isize) + }).collect(); + ffi::RUST_png_set_rows(png_ptr, info_ptr, row_pointers.as_mut_ptr()); + + ffi::RUST_png_write_png(png_ptr, info_ptr, ffi::TRANSFORM_IDENTITY, ptr::null_mut()); + + ffi::RUST_png_destroy_write_struct(&mut png_ptr, &mut info_ptr); + } + + Ok(target) +} + #[cfg(test)] mod test { use std::error::Error; From e3235f8d3be36f4730103111adf1972a7ec25014 Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 28 Apr 2015 16:42:02 +0100 Subject: [PATCH 2/2] Add tests for to_vec. --- src/lib.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 871f98d..0eba0fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,7 +315,7 @@ mod test { use std::iter::repeat; use std::path::PathBuf; - use super::{ffi, load_png, store_png, Image}; + use super::{ffi, load_png, store_png, to_vec, Image}; use super::PixelsByColorType::{RGB8, RGBA8}; #[test] @@ -418,4 +418,26 @@ mod test { let res = store_png(&mut img, &PathBuf::from("test/store.png")); assert!(res.is_ok()); } + + #[test] + fn test_to_vec() { + let mut img = Image { + width: 10, + height: 10, + pixels: RGB8(repeat(100).take(10 * 10 * 3).collect()), + }; + let res = to_vec(&mut img); + assert!(res.is_ok()); + let data = res.unwrap(); + + // Check the PNG header + assert!(data[..8] == *b"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"); + + let path = PathBuf::from("test/to_vec.png"); + let res = store_png(&mut img, &path); + assert!(res.is_ok()); + let mut expected: Vec = Vec::with_capacity(data.len()); + File::open(&path).unwrap().read_to_end(&mut expected).unwrap(); + assert_eq!(data, expected); + } }