Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
rust: ["1.62.0", stable, beta, nightly]
rust: ["1.81.0", stable, beta, nightly]
features: ["", "std", "color_quant"]
steps:
- uses: actions/checkout@v2
Expand All @@ -23,7 +23,6 @@ jobs:
- name: test
run: >
cargo test --tests --benches --no-default-features --features "$FEATURES"
if: ${{ matrix.rust != '1.62.0' }}
env:
FEATURES: ${{ matrix.features }}
rustfmt:
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ repository = "https://github.com/image-rs/image-gif"
documentation = "https://docs.rs/gif"
edition = "2021"
include = ["src/**", "LICENSE-*", "README.md", "benches/*.rs"]
rust-version = "1.62"
rust-version = "1.81"

[lib]
bench = false

[dependencies]
weezl = "0.1.8"
weezl = { version = "0.1.8", default-features = false, features = ["alloc"] }
color_quant = { version = "1.1", optional = true }

[dev-dependencies]
Expand All @@ -32,7 +32,7 @@ default = ["raii_no_panic", "std", "color_quant"]
raii_no_panic = []
color_quant = ["dep:color_quant"]
# Reservation for a feature turning off std
std = []
std = ["weezl/std"]

[[bench]]
name = "decode"
Expand Down
71 changes: 42 additions & 29 deletions benches/decode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use criterion::{black_box, BenchmarkId, BenchmarkGroup, Criterion, Throughput, measurement::Measurement};
use criterion::{
black_box, measurement::Measurement, BenchmarkGroup, BenchmarkId, Criterion, Throughput,
};
use gif::Decoder;

fn read_image(image: &[u8]) -> Option<Vec<u8>> {
Expand Down Expand Up @@ -42,38 +44,49 @@ fn main() {
let mut c = Criterion::default().configure_from_args();
let mut group = c.benchmark_group("gif");

run_bench_def(&mut group, BenchDef {
data: include_bytes!("note.gif"),
id: "note.gif",
sample_size: 100,
});
run_bench_def(
&mut group,
BenchDef {
data: include_bytes!("note.gif"),
id: "note.gif",
sample_size: 100,
},
);

run_bench_def(&mut group, BenchDef {
data: include_bytes!("photo.gif"),
id: "photo.gif",
sample_size: 20,
});
run_bench_def(
&mut group,
BenchDef {
data: include_bytes!("photo.gif"),
id: "photo.gif",
sample_size: 20,
},
);

run_bench_def(&mut group, BenchDef {
data: include_bytes!("../tests/samples/sample_1.gif"),
id: "sample_1.gif",
sample_size: 100,
});
run_bench_def(
&mut group,
BenchDef {
data: include_bytes!("../tests/samples/sample_1.gif"),
id: "sample_1.gif",
sample_size: 100,
},
);

run_bench_def(&mut group, BenchDef {
data: include_bytes!("../tests/samples/sample_big.gif"),
id: "sample_big.gif",
sample_size: 20,
});
run_bench_def(
&mut group,
BenchDef {
data: include_bytes!("../tests/samples/sample_big.gif"),
id: "sample_big.gif",
sample_size: 20,
},
);

group
.bench_with_input(
"extract-metadata-note",
include_bytes!("note.gif"),
|b, input| {
b.iter(|| read_metadata(input));
}
);
group.bench_with_input(
"extract-metadata-note",
include_bytes!("note.gif"),
|b, input| {
b.iter(|| read_metadata(input));
},
);

group.finish();

Expand Down
22 changes: 11 additions & 11 deletions benches/rgb_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ fn main() {
group
.sample_size(50)
.throughput(Throughput::Bytes(size as u64))
.bench_function(path.file_name().unwrap().to_str().unwrap(),
|b| {
match info.color_type {
png::ColorType::Rgb => b.iter(|| {
Frame::from_rgb_speed(w, h, &mut buf[..size], 30)
}),
png::ColorType::Rgba => b.iter(|| {
Frame::from_rgba_speed(w, h, &mut buf[..size], 30)
}),
.bench_function(
path.file_name().unwrap().to_str().unwrap(),
|b| match info.color_type {
png::ColorType::Rgb => {
b.iter(|| Frame::from_rgb_speed(w, h, &mut buf[..size], 30))
}
png::ColorType::Rgba => {
b.iter(|| Frame::from_rgba_speed(w, h, &mut buf[..size], 30))
}
c => {
println!("Image has wrong color type: {c:?}");
}
}
});
},
);

// actually write the image as a singe frame gif... while MSE can be used
// for quality check, it might not be as good as visual inspection
Expand Down
11 changes: 6 additions & 5 deletions examples/check.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use std::{env, fs, process};

fn main() {
let file = env::args().nth(1)
.unwrap_or_else(|| explain_usage());
let file = fs::File::open(file)
.expect("failed to open input file");
let file = env::args().nth(1).unwrap_or_else(|| explain_usage());
let file = fs::File::open(file).expect("failed to open input file");
let mut reader = {
let mut options = gif::DecodeOptions::new();
options.allow_unknown_blocks(true);
Expand All @@ -28,7 +26,10 @@ fn main() {
dispose: {:?}\n \
needs_input: {:?}",
frame.delay,
frame.width, frame.height, frame.left, frame.top,
frame.width,
frame.height,
frame.left,
frame.top,
frame.dispose,
frame.needs_user_input
);
Expand Down
40 changes: 27 additions & 13 deletions examples/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,21 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {

let (send, recv) = std::sync::mpsc::channel();

decoder.into_iter().enumerate().par_bridge().try_for_each(move |(frame_number, frame)| {
let mut frame = frame?;
FrameDecoder::new(DecodeOptions::new())
.decode_lzw_encoded_frame(&mut frame)
.unwrap();
// frame is now pixels
frame.make_lzw_pre_encoded();
// frame is now LZW again, re-encoded
send.send((frame_number, frame)).unwrap();
Ok::<_, gif::DecodingError>(())
})?;
decoder
.into_iter()
.enumerate()
.par_bridge()
.try_for_each(move |(frame_number, frame)| {
let mut frame = frame?;
FrameDecoder::new(DecodeOptions::new())
.decode_lzw_encoded_frame(&mut frame)
.unwrap();
// frame is now pixels
frame.make_lzw_pre_encoded();
// frame is now LZW again, re-encoded
send.send((frame_number, frame)).unwrap();
Ok::<_, gif::DecodingError>(())
})?;

// Decoding and encoding can happen in parallel, but writing to the GIF file is sequential
let mut next_frame_number = 0;
Expand All @@ -59,7 +63,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// frames can arrive in any order, since they're processed in parallel,
// so they have to be stored in a queue
frames_to_process.push((frame_number, frame));
while let Some(index) = frames_to_process.iter().position(|&(num, _)| num == next_frame_number) {
while let Some(index) = frames_to_process
.iter()
.position(|&(num, _)| num == next_frame_number)
{
let frame = frames_to_process.remove(index).1;
encoder.write_lzw_pre_encoded_frame(&frame)?;
next_frame_number += 1;
Expand All @@ -70,6 +77,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let seconds = start.elapsed().as_millis() as f64 / 1000.;
let rate = (input_size / 1024 / 1024) as f64 / seconds;

eprintln!("Finished in {seconds:0.2}s, {rate:0.0}MiB/s {}", if cfg!(debug_assertions) { ". Run with --release for more speed." } else { "" });
eprintln!(
"Finished in {seconds:0.2}s, {rate:0.0}MiB/s {}",
if cfg!(debug_assertions) {
". Run with --release for more speed."
} else {
""
}
);
Ok(())
}
Loading
Loading