mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
parent
74f8c0eeb7
commit
ba36a108c1
56 changed files with 674 additions and 518 deletions
86
components/net_traits/image/base.rs
Normal file
86
components/net_traits/image/base.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use png;
|
||||
use stb_image::image as stb_image2;
|
||||
use std::iter::range_step;
|
||||
use util::vec::byte_swap;
|
||||
|
||||
// FIXME: Images must not be copied every frame. Instead we should atomically
|
||||
// reference count them.
|
||||
pub type Image = png::Image;
|
||||
|
||||
// TODO(pcwalton): Speed up with SIMD, or better yet, find some way to not do this.
|
||||
fn byte_swap_and_premultiply(data: &mut [u8]) {
|
||||
let length = data.len();
|
||||
for i in range_step(0, length, 4) {
|
||||
let r = data[i + 2];
|
||||
let g = data[i + 1];
|
||||
let b = data[i + 0];
|
||||
let a = data[i + 3];
|
||||
data[i + 0] = ((r as u32) * (a as u32) / 255) as u8;
|
||||
data[i + 1] = ((g as u32) * (a as u32) / 255) as u8;
|
||||
data[i + 2] = ((b as u32) * (a as u32) / 255) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
|
||||
if buffer.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
if png::is_png(buffer) {
|
||||
match png::load_png_from_memory(buffer) {
|
||||
Ok(mut png_image) => {
|
||||
match png_image.pixels {
|
||||
png::PixelsByColorType::RGB8(ref mut data) => byte_swap(data.as_mut_slice()),
|
||||
png::PixelsByColorType::RGBA8(ref mut data) => {
|
||||
byte_swap_and_premultiply(data.as_mut_slice())
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Some(png_image)
|
||||
}
|
||||
Err(_err) => None,
|
||||
}
|
||||
} else {
|
||||
// For non-png images, we use stb_image
|
||||
// Can't remember why we do this. Maybe it's what cairo wants
|
||||
static FORCE_DEPTH: uint = 4;
|
||||
|
||||
match stb_image2::load_from_memory_with_depth(buffer, FORCE_DEPTH, true) {
|
||||
stb_image2::LoadResult::ImageU8(mut image) => {
|
||||
assert!(image.depth == 4);
|
||||
// handle gif separately because the alpha-channel has to be premultiplied
|
||||
if is_gif(buffer) {
|
||||
byte_swap_and_premultiply(image.data.as_mut_slice());
|
||||
} else {
|
||||
byte_swap(image.data.as_mut_slice());
|
||||
}
|
||||
Some(png::Image {
|
||||
width: image.width as u32,
|
||||
height: image.height as u32,
|
||||
pixels: png::PixelsByColorType::RGBA8(image.data)
|
||||
})
|
||||
}
|
||||
stb_image2::LoadResult::ImageF32(_image) => {
|
||||
error!("HDR images not implemented");
|
||||
None
|
||||
}
|
||||
stb_image2::LoadResult::Error(e) => {
|
||||
error!("stb_image failed: {}", e);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_gif(buffer: &[u8]) -> bool {
|
||||
match buffer {
|
||||
[b'G',b'I',b'F',b'8', n, b'a', ..] if n == b'7' || n == b'9' => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue