Skip to content

Commit

Permalink
Auto merge of #8503 - craftytrickster:8406/limit-suppported-format, r…
Browse files Browse the repository at this point in the history
…=mbrubeck

Adding method to detect if image formats should be supported by servo

#8406

Please let me know if I need to make any changes.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8503)
<!-- Reviewable:end -->
  • Loading branch information
bors-servo committed Nov 17, 2015
2 parents 20d2685 + 5a75db1 commit f17f890
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 46 deletions.
123 changes: 77 additions & 46 deletions components/net_traits/image/base.rs
Expand Up @@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc::IpcSharedMemory;
use piston_image::{self, DynamicImage, GenericImage};
use piston_image::{self, DynamicImage, GenericImage, ImageFormat};
use stb_image::image as stb_image2;
use util::vec::byte_swap;

Expand Down Expand Up @@ -31,61 +31,80 @@ pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
return None;
}

if is_jpeg(buffer) {
// For JPEG images, we use stb_image because piston_image does not yet support progressive
// JPEG.
let image_fmt_result = detect_image_format(buffer);
match image_fmt_result {
Err(msg) => {
debug!("{}", msg);
None
}
Ok(ImageFormat::JPEG) => {
// For JPEG images, we use stb_image because piston_image does not yet support progressive
// JPEG.

// Can't remember why we do this. Maybe it's what cairo wants
static FORCE_DEPTH: usize = 4;
// Can't remember why we do this. Maybe it's what cairo wants
static FORCE_DEPTH: usize = 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(&mut image.data);
} else {
byte_swap(&mut image.data);
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(&mut image.data);
} else {
byte_swap(&mut image.data);
}
Some(Image {
width: image.width as u32,
height: image.height as u32,
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&image.data[..]),
})
}
stb_image2::LoadResult::ImageF32(_image) => {
debug!("HDR images not implemented");
None
}
stb_image2::LoadResult::Error(e) => {
debug!("stb_image failed: {}", e);
None
}
Some(Image {
width: image.width as u32,
height: image.height as u32,
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&image.data[..]),
})
}
stb_image2::LoadResult::ImageF32(_image) => {
debug!("HDR images not implemented");
None
}
stb_image2::LoadResult::Error(e) => {
debug!("stb_image failed: {}", e);
None
}
}
} else {
match piston_image::load_from_memory(buffer) {
Ok(image) => {
let mut rgba = match image {
DynamicImage::ImageRgba8(rgba) => rgba,
image => image.to_rgba()
};
byte_swap_and_premultiply(&mut *rgba);
Some(Image {
width: rgba.width(),
height: rgba.height(),
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&*rgba),
})
}
Err(e) => {
debug!("Image decoding error: {:?}", e);
None
_ => {
match piston_image::load_from_memory(buffer) {
Ok(image) => {
let mut rgba = match image {
DynamicImage::ImageRgba8(rgba) => rgba,
image => image.to_rgba()
};
byte_swap_and_premultiply(&mut *rgba);
Some(Image {
width: rgba.width(),
height: rgba.height(),
format: PixelFormat::RGBA8,
bytes: IpcSharedMemory::from_bytes(&*rgba),
})
}
Err(e) => {
debug!("Image decoding error: {:?}", e);
None
}
}
}
}
}


// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
pub fn detect_image_format(buffer: &[u8]) -> Result<ImageFormat, &str> {
if is_gif(buffer) { Ok(ImageFormat::GIF) }
else if is_jpeg(buffer) { Ok(ImageFormat::JPEG) }
else if is_png(buffer) { Ok(ImageFormat::PNG) }
else if is_bmp(buffer) { Ok(ImageFormat::BMP) }
else if is_ico(buffer) { Ok(ImageFormat::ICO) }
else { Err("Image Format Not Supported") }
}

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,
Expand All @@ -96,3 +115,15 @@ fn is_gif(buffer: &[u8]) -> bool {
fn is_jpeg(buffer: &[u8]) -> bool {
buffer.starts_with(&[0xff, 0xd8, 0xff])
}

fn is_png(buffer: &[u8]) -> bool {
buffer.starts_with(&[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
}

fn is_bmp(buffer: &[u8]) -> bool {
buffer.starts_with(&[0x42, 0x4D])
}

fn is_ico(buffer: &[u8]) -> bool {
buffer.starts_with(&[0x00, 0x00, 0x01, 0x00])
}
8 changes: 8 additions & 0 deletions components/servo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions components/servo/Cargo.toml
Expand Up @@ -26,6 +26,9 @@ path = "../../tests/unit/gfx"
[dev-dependencies.net_tests]
path = "../../tests/unit/net"

[dev-dependencies.net_traits_tests]
path = "../../tests/unit/net_traits"

[dev-dependencies.script_tests]
path = "../../tests/unit/script"

Expand Down
12 changes: 12 additions & 0 deletions tests/unit/net_traits/Cargo.toml
@@ -0,0 +1,12 @@
[package]
name = "net_traits_tests"
version = "0.0.1"
authors = ["The Servo Project Developers"]

[lib]
name = "net_traits_tests"
path = "lib.rs"
doctest = false

[dependencies.net_traits]
path = "../../../components/net_traits"
24 changes: 24 additions & 0 deletions tests/unit/net_traits/image.rs
@@ -0,0 +1,24 @@
/* 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 net_traits::image::base::detect_image_format;

#[test]
fn test_supported_images() {
let gif1 = [b'G', b'I', b'F', b'8', b'7', b'a'];
let gif2 = [b'G', b'I', b'F', b'8', b'9', b'a'];
let jpeg = [0xff, 0xd8, 0xff];
let png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
let bmp = [0x42, 0x4D];
let ico = [0x00, 0x00, 0x01, 0x00];
let junk_format = [0x01, 0x02, 0x03, 0x04, 0x05];

assert!(detect_image_format(&gif1).is_ok());
assert!(detect_image_format(&gif2).is_ok());
assert!(detect_image_format(&jpeg).is_ok());
assert!(detect_image_format(&png).is_ok());
assert!(detect_image_format(&bmp).is_ok());
assert!(detect_image_format(&ico).is_ok());
assert!(detect_image_format(&junk_format).is_err());
}
7 changes: 7 additions & 0 deletions tests/unit/net_traits/lib.rs
@@ -0,0 +1,7 @@
/* 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/. */

extern crate net_traits;

#[cfg(test)] mod image;

0 comments on commit f17f890

Please sign in to comment.