aboutsummaryrefslogtreecommitdiffstats
path: root/components/net_traits/image/base.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/net_traits/image/base.rs')
-rw-r--r--components/net_traits/image/base.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/components/net_traits/image/base.rs b/components/net_traits/image/base.rs
new file mode 100644
index 00000000000..ba86b94d2ff
--- /dev/null
+++ b/components/net_traits/image/base.rs
@@ -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
+ }
+}
+
+