Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transparent png #12

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

add support for transparent png

  • Loading branch information
ryanhc committed Nov 19, 2013
commit 298ef5d620bdb09dea353de9d5babcf433b93892
13 ffi.rs
@@ -19,11 +19,15 @@ pub static COMPRESSION_TYPE_DEFAULT: c_int = 0;

pub static COLOR_TYPE_GRAY: c_int = 0;
pub static COLOR_TYPE_RGB: c_int = 2;
pub static COLOR_TYPE_PALETTE: c_int = 3;
pub static COLOR_TYPE_GRAY_ALPHA: c_int = 4;
pub static COLOR_TYPE_GA: c_int = 4;
pub static COLOR_TYPE_RGB_ALPHA: c_int = 6;
pub static COLOR_TYPE_RGBA: c_int = 6;

pub static FILLER_AFTER: c_int = 1;
pub static INFO_tRNS: c_int = 0x0010;

pub type png_struct = c_void;
pub type png_info = c_void;

@@ -46,8 +50,8 @@ extern {
pub fn png_destroy_read_struct(png_ptr_ptr: **png_struct, info_ptr_ptr: **png_info, end_info_ptr_ptr: **png_info);
pub fn png_set_read_fn(png_ptr: *mut png_struct, io_ptr: *mut c_void, read_data_fn: extern "C" fn(*png_struct, *mut u8, size_t));
pub fn png_read_info(png_ptr: *mut png_struct, info_ptr: *mut png_info);
pub fn png_read_update_info(png_ptr: *mut png_struct, info_ptr: *mut png_info);
pub fn png_read_image(png_ptr: *mut png_struct, row_pointers: **mut u8);
pub fn png_read_png(png_ptr: *mut png_struct, info_ptr: *mut png_info, transforms: c_int, params: *c_void);

pub fn png_create_write_struct(user_png_ver: *c_char, error_ptr: *c_void, error_fn: *u8, warn_fn: *u8) -> *mut png_struct;
pub fn png_destroy_write_struct(png_ptr_ptr: **png_struct, info_ptr_ptr: **png_info);
@@ -65,4 +69,11 @@ extern {
pub fn png_set_IHDR(png_ptr: *png_struct, info_ptr: *mut png_info, width: u32, height: u32, bit_depth: c_int, color_type: c_int, interlace_method: c_int, compression_method: c_int, filter_method: c_int);
pub fn png_set_pHYs(png_ptr: *png_struct, info_ptr: *mut png_info, res_x: u32, res_y: u32, unit_type: c_int);
pub fn png_set_rows(png_ptr: *png_struct, info_ptr: *mut png_info, row_pointers: **u8);

pub fn png_set_packing(png_ptr: *mut png_struct);
pub fn png_set_palette_to_rgb(png_ptr: *mut png_struct);
pub fn png_set_expand_gray_1_2_4_to_8(png_ptr: *mut png_struct);
pub fn png_set_tRNS_to_alpha(png_ptr: *mut png_struct);
pub fn png_set_filler(png_ptr: *mut png_struct, val: u32, flag: c_int);
pub fn png_set_interlace_handling(png_ptr: *mut png_struct);
}
81 lib.rs
@@ -15,7 +15,7 @@
extern mod std;
use std::cast;
use std::rt::io;
use std::rt::io::file;
use std::rt::io::{file, Reader};
use std::ptr;
use std::vec;
use std::libc::{c_int, size_t};
@@ -41,27 +41,49 @@ pub struct Image {
pixels: ~[u8],
}

// This intermediate data structure is used to read
// an image data from 'offset' position, and store it
// to the data vector.
struct ImageData<'self> {
data: &'self [u8],
offset: uint,
}

#[fixed_stack_segment]
pub fn is_png(image: &[u8]) -> bool {
do image.as_imm_buf |bytes, _len| {
unsafe {
ffi::png_sig_cmp(bytes, 0, 8) == 0
}
}
}

pub extern fn read_data(png_ptr: *ffi::png_struct, data: *mut u8, length: size_t) {
unsafe {
let io_ptr = ffi::png_get_io_ptr(png_ptr);
let reader: @@mut io::Reader = cast::transmute(io_ptr);
do vec::raw::mut_buf_as_slice(data, length as uint) |buf| {
reader.read(buf);
let image_data: &mut ImageData = cast::transmute(io_ptr);
let len = length as uint;
do vec::raw::mut_buf_as_slice(data, len) |buf| {
let end_pos = std::num::min(image_data.data.len()-image_data.offset, len);
vec::raw::copy_memory(buf,
image_data.data.slice(image_data.offset, image_data.offset+end_pos),
end_pos);
image_data.offset += end_pos;
}
cast::forget(reader);
}
}

#[fixed_stack_segment]
pub fn load_png(path: &Path) -> Result<Image,~str> {
let reader = match file::open(path, io::Open, io::Read) {
Some(r) => @mut r as @mut io::Reader,
None => return Err(~"could not open file")
let mut reader = match file::open(path, io::Open, io::Read) {
Some(r) => r,
None => return Err(~"could not open file"),
};
let buf = reader.read_to_end();
load_png_from_memory(buf)
}

// Box it again because an @Trait is too big to fit in a void*
let reader = @reader;

#[fixed_stack_segment]
pub fn load_png_from_memory(image: &[u8]) -> Result<Image,~str> {
unsafe {
let png_ptr = ffi::png_create_read_struct(ffi::png_get_header_ver(ptr::null()),
ptr::null(),
@@ -84,17 +106,42 @@ pub fn load_png(path: &Path) -> Result<Image,~str> {
return Err(~"error reading png");
}

ffi::png_set_read_fn(png_ptr, cast::transmute(reader), read_data);
let mut image_data = ImageData {
data: image,
offset: 0,
};

ffi::png_set_read_fn(png_ptr, cast::transmute(&mut image_data), read_data);
ffi::png_read_info(png_ptr, info_ptr);

let width = ffi::png_get_image_width(&*png_ptr, &*info_ptr);
let height = ffi::png_get_image_height(&*png_ptr, &*info_ptr);
let bit_depth = ffi::png_get_bit_depth(&*png_ptr, &*info_ptr);
let color_type = ffi::png_get_color_type(&*png_ptr, &*info_ptr);

// we convert palette to rgb
if color_type as c_int == ffi::COLOR_TYPE_PALETTE {
ffi::png_set_palette_to_rgb(png_ptr);
}
// make each channel use 1 byte
if (color_type as c_int == ffi::COLOR_TYPE_GRAY) && (bit_depth < 8) {
ffi::png_set_expand_gray_1_2_4_to_8(png_ptr);
}
// add alpha channels to palette and rgb
if (color_type as c_int == ffi::COLOR_TYPE_PALETTE) ||
(color_type as c_int == ffi::COLOR_TYPE_RGB) {
ffi::png_set_tRNS_to_alpha(png_ptr);
ffi::png_set_filler(png_ptr, 0xff, ffi::FILLER_AFTER);
}

ffi::png_set_packing(png_ptr);
ffi::png_set_interlace_handling(png_ptr);
ffi::png_read_update_info(png_ptr, info_ptr);

let (color_type, pixel_width) = match (color_type as c_int, bit_depth) {
(ffi::COLOR_TYPE_RGB, 8) => (RGB8, 3),
(ffi::COLOR_TYPE_RGBA, 8) => (RGBA8, 4),
(ffi::COLOR_TYPE_RGB, 8) |
(ffi::COLOR_TYPE_RGBA, 8) |
(ffi::COLOR_TYPE_PALETTE, 8) => (RGBA8, 4),
(ffi::COLOR_TYPE_GRAY, 8) => (K8, 1),
(ffi::COLOR_TYPE_GA, 8) => (KA8, 2),
_ => fail!(~"color type not supported"),
@@ -174,15 +221,15 @@ pub fn store_png(img: &Image, path: &Path) -> Result<(),~str> {
}

ffi::png_set_write_fn(png_ptr, cast::transmute(writer), write_data, flush_data);

let (bit_depth, color_type, pixel_width) = match img.color_type {
RGB8 => (8, ffi::COLOR_TYPE_RGB, 3),
RGBA8 => (8, ffi::COLOR_TYPE_RGBA, 4),
K8 => (8, ffi::COLOR_TYPE_GRAY, 1),
KA8 => (8, ffi::COLOR_TYPE_GA, 2),
_ => fail!("bad color type"),
};

ffi::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);

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.