Skip to content

Commit

Permalink
Merge pull request #273 from woelper/webp_animation
Browse files Browse the repository at this point in the history
feat: Allow opening of webp animations
  • Loading branch information
woelper authored Feb 12, 2024
2 parents e58b068 + 575d2ad commit 7758151
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 32 deletions.
29 changes: 18 additions & 11 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ image = "0.24"
kamadak-exif = "0.5"
lexical-sort = "0.3"
libavif-image = {version = "0.11", optional = true}
libwebp-sys = "0.9.2"
log = "0.4"
nalgebra = "0.32"
notan = {version = "0.11", default-features = false, features = ["backend", "draw", "glsl-to-spirv","drop_files", "egui"]}
Expand Down Expand Up @@ -75,6 +74,7 @@ bitflags = "2.4.1"
flate2 = "1.0.28"
ruzstd = "0.5.0"
basis-universal = "0.3.1"
webp-animation = { version = "0.9.0", features = ["static"] }

[features]
heif = ["libheif-rs"]
Expand Down
71 changes: 52 additions & 19 deletions src/image_loader.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::ktx2_loader::CompressedImageFormats;
use crate::utils::{fit, Frame, FrameSource};
use crate::{ktx2_loader, FONT};
use libwebp_sys::{WebPDecodeRGBA, WebPGetInfo};
use log::{debug, error, info};
use psd::Psd;

Expand All @@ -20,6 +19,7 @@ use std::path::Path;
use std::sync::mpsc::{channel, Receiver, Sender};
use tiff::decoder::Limits;
use usvg::{TreeParsing, TreeTextToPath};
use webp_animation::prelude::*;
use zune_png::zune_core::options::DecoderOptions;
use zune_png::zune_core::result::DecodingResult;
use zune_png::PngDecoder;
Expand Down Expand Up @@ -429,9 +429,57 @@ pub fn open_image(img_location: &Path) -> Result<Receiver<Frame>> {
return Ok(receiver);
}
"webp" => {
let contents = std::fs::read(img_location)?;
let buf = decode_webp(&contents).context("Can't decode webp")?;
_ = sender.send(Frame::new_still(buf));
// let contents = std::fs::read(img_location)?;
// let buf = decode_webp(&contents).context("Can't decode webp")?;
// _ = sender.send(Frame::new_still(buf));
// return Ok(receiver);

let buffer = std::fs::read(img_location)?;
let mut decoder = Decoder::new(&buffer)?.into_iter();

let mut last_timestamp = 0;

let mut frames = vec![];
let mut i = 0;

loop {
if let Some(frame) = decoder.next() {
if frames.len() > 1 {
if let Some(last) = frames.pop() {
_ = sender.send(last);
}
}
let buf = image::ImageBuffer::from_raw(
frame.dimensions().0,
frame.dimensions().1,
frame.data().to_vec(),
)
.context("Can't create imagebuffer from webp")?;
let t = frame.timestamp();
let delay = t - last_timestamp;
debug!("time {t} {delay}");
last_timestamp = t;
frames.push(Frame::new(buf, delay as u16, FrameSource::Animation));
i += 1;
} else {
break;
}
}

if i == 1 {
debug!("This is a still");
if let Some(mut last) = frames.pop() {
last.source = FrameSource::Still;
_ = sender.send(last);
}
} else {
for f in frames {
_ = sender.send(f);
}
}

// TODO: Use thread for animation and return receiver immediately

return Ok(receiver);
}
"png" => {
Expand Down Expand Up @@ -631,21 +679,6 @@ fn tonemap_rgb(px: [f32; 3]) -> [u8; 4] {
tm
}

// Unsafe webp decoding using webp-sys
fn decode_webp(buf: &[u8]) -> Option<RgbaImage> {
let mut width = 0;
let mut height = 0;
let len = buf.len();
let webp_buffer: Vec<u8>;
unsafe {
WebPGetInfo(buf.as_ptr(), len, &mut width, &mut height);
let out_buf = WebPDecodeRGBA(buf.as_ptr(), len, &mut width, &mut height);
let len = width * height * 4;
webp_buffer = Vec::from_raw_parts(out_buf, len as usize, len as usize);
}
image::ImageBuffer::from_raw(width as u32, height as u32, webp_buffer)
}

fn u16_to_u8(p: u16) -> u8 {
((p as f32 / u16::MAX as f32) * u8::MAX as f32) as u8
}
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ pub const FONT: &[u8; 309828] = include_bytes!("../res/fonts/Inter-Regular.ttf")
#[notan_main]
fn main() -> Result<(), String> {
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "warning");
std::env::set_var("RUST_LOG", "info");
let _ = env_logger::try_init();

}
// on debug builds, override log level
#[cfg(debug_assertions)]
Expand Down
3 changes: 3 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@ pub fn send_image_threaded(
}
// a "normal image (no animation)"
if f.source == FrameSource::Still {

info!("Received image in {:?}", timer.elapsed());

let largest_side = f.buffer.dimensions().0.max(f.buffer.dimensions().1);

// Check if texture is too large to fit on the texture
Expand Down

0 comments on commit 7758151

Please sign in to comment.