douglau / gift Goto Github PK
View Code? Open in Web Editor NEWA library for reading and writing GIF images
License: Apache License 2.0
A library for reading and writing GIF images
License: Apache License 2.0
Allow later frames to only update sub-region of image
Add enum of color table building methods:
Maybe Lab of Lch with octree clusering and dithering.
Check out exoquant.
Thanks for your work on this crate.
I'm creating this issue with a brief overview of some issues I've run into during use. (Which would be better to be created as individual issues but currently the most likely alternative is not to write them up at all, so hopefully this format is better than nothing. :) )
todo!
e.g. full color to indexed & the binary sub commands.crates.io
but not tagged in repo.master
handle min_code_bits
incorrectly for the values 4
& 8
when encoding. (see below)master
does not encode images of dimensions such as 2x2 or 3x3 successfully. (8x8 appears to work.) I haven't investigated why but my guess is it's related to the new lzw
implementation.min_code_bits
For the value 4
min_code_size
is set to 2
instead of 3
this results in the colour index being encoded as 0
and the incorrect colour appearing.
This occurs here:
Lines 212 to 213 in 102f3b5
[TODO: Provide more details, examples & code.]
See also:
This patch/workaround "fixed" the issue for me but strictly speaking probably isn't entirely specification compliant[1]:
diff --git a/src/encode.rs b/src/encode.rs
index be410e7..8de1a9a 100644
--- a/src/encode.rs
+++ b/src/encode.rs
@@ -210,7 +210,7 @@ impl ImageData {
/// Format an image data block
fn format<W: Write>(&self, w: &mut W) -> io::Result<()> {
let min_code_bits =
- next_high_bit(self.data().iter().copied().max().unwrap_or(0));
+ next_high_bit(self.data().iter().copied().max().unwrap_or(0)+1);
// minimum code bits must be between 2 and 12
let min_code_bits = 2.max(min_code_bits).min(12);
w.write_all(&[min_code_bits])?;
[1] Because AFAICT the value is intended to be related to the bit-depth.
Example animated GIF exported with workaround in place:
4
was being encoded as 0
.)Edited: Added additional content.
Because the encoding will contain one 0
for the empty string (but it already ends the block), followed by another 0
to end the block. Perhaps there should be a non-empty assertion similar to the max length, or maybe empty comments should be skipped.
Test file:
Test case:
for frame in Decoder::new_unbuffered(Cursor::new(data)) {
if frame.is_err() {
return;
}
}
RUST_BACKTRACE=1 cargo +nightly fuzz run decode artifacts/decode/crash-0936c048a8348fa57649ab0066c53bacac228cc6
Fresh cc v1.0.50
Fresh cfg-if v0.1.10
Fresh lzw v0.10.0
Fresh pix v0.7.0
Fresh arbitrary v0.4.0
Fresh log v0.4.8
Fresh gift v0.4.0 (/home/niklas/Projekte/gift)
Fresh libfuzzer-sys v0.3.0
Fresh gift-fuzz v0.0.0 (/home/niklas/Projekte/gift/fuzz)
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Fresh cc v1.0.50
Fresh cfg-if v0.1.10
Fresh arbitrary v0.4.0
Fresh pix v0.7.0
Fresh lzw v0.10.0
Fresh log v0.4.8
Fresh gift v0.4.0 (/home/niklas/Projekte/gift)
Fresh libfuzzer-sys v0.3.0
Fresh gift-fuzz v0.0.0 (/home/niklas/Projekte/gift/fuzz)
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target/x86_64-unknown-linux-gnu/debug/decode -artifact_prefix=/home/niklas/Projekte/gift/fuzz/artifacts/decode/ artifacts/decode/crash-0936c048a8348fa57649ab0066c53bacac228cc6`
INFO: Seed: 1877210147
INFO: Loaded 1 modules (26284 inline 8-bit counters): 26284 [0x560749144642, 0x56074914acee),
INFO: Loaded 1 PC tables (26284 PCs): 26284 [0x56074914acf0,0x5607491b17b0),
target/x86_64-unknown-linux-gnu/debug/decode: Running 1 inputs 1 time(s) each.
Running: artifacts/decode/crash-0936c048a8348fa57649ab0066c53bacac228cc6
thread '<unnamed>' panicked at 'index out of bounds: the len is 114 but the index is 1686', /home/niklas/Projekte/gift/src/decode.rs:754:27
stack backtrace:
0: backtrace::backtrace::libunwind::trace
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/libunwind.rs:86
1: backtrace::backtrace::trace_unsynchronized
at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.44/src/backtrace/mod.rs:66
2: std::sys_common::backtrace::_print_fmt
at src/libstd/sys_common/backtrace.rs:78
3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
at src/libstd/sys_common/backtrace.rs:59
4: core::fmt::write
at src/libcore/fmt/mod.rs:1052
5: std::io::Write::write_fmt
at src/libstd/io/mod.rs:1428
6: std::sys_common::backtrace::_print
at src/libstd/sys_common/backtrace.rs:62
7: std::sys_common::backtrace::print
at src/libstd/sys_common/backtrace.rs:49
8: std::panicking::default_hook::{{closure}}
at src/libstd/panicking.rs:204
9: std::panicking::default_hook
at src/libstd/panicking.rs:224
10: <alloc::boxed::Box<F> as core::ops::function::Fn<A>>::call
at /rustc/8aa9d2014f4e5258f83b907e8431c59a33acdae7/src/liballoc/boxed.rs:1031
11: libfuzzer_sys::initialize::{{closure}}
at /home/niklas/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.0/src/lib.rs:50
12: std::panicking::rust_panic_with_hook
at src/libstd/panicking.rs:474
13: rust_begin_unwind
at src/libstd/panicking.rs:378
14: core::panicking::panic_fmt
at src/libcore/panicking.rs:85
15: core::panicking::panic_bounds_check
at src/libcore/panicking.rs:63
16: gift::decode::update_raster
at /home/niklas/Projekte/gift/src/decode.rs:754
17: gift::decode::Rasters<R>::apply_frame
at /home/niklas/Projekte/gift/src/decode.rs:716
18: gift::decode::Rasters<R>::next_raster
at /home/niklas/Projekte/gift/src/decode.rs:702
19: <gift::decode::Rasters<R> as core::iter::traits::iterator::Iterator>::next
at /home/niklas/Projekte/gift/src/decode.rs:670
20: rust_fuzzer_test_input
at fuzz_targets/decode.rs:11
21: libfuzzer_sys::test_input_wrap::{{closure}}
at /home/niklas/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.0/src/lib.rs:27
22: std::panicking::try::do_call
at /rustc/8aa9d2014f4e5258f83b907e8431c59a33acdae7/src/libstd/panicking.rs:303
23: __rust_maybe_catch_panic
at src/libpanic_unwind/lib.rs:86
24: std::panicking::try
at /rustc/8aa9d2014f4e5258f83b907e8431c59a33acdae7/src/libstd/panicking.rs:281
25: std::panic::catch_unwind
at /rustc/8aa9d2014f4e5258f83b907e8431c59a33acdae7/src/libstd/panic.rs:394
26: LLVMFuzzerTestOneInput
at /home/niklas/.cargo/registry/src/github.com-1ecc6299db9ec823/libfuzzer-sys-0.3.0/src/lib.rs:25
27: _ZN6fuzzer6Fuzzer15ExecuteCallbackEPKhm
at libfuzzer/FuzzerLoop.cpp:553
28: _ZN6fuzzer10RunOneTestEPNS_6FuzzerEPKcm
29: _ZN6fuzzer12FuzzerDriverEPiPPPcPFiPKhmE
30: main
at libfuzzer/FuzzerMain.cpp:19
31: __libc_start_main
32: _start
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
==140456== ERROR: libFuzzer: deadly signal
#0 0x560748c202f1 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x14f2f1)
#1 0x560748dfe371 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x32d371)
#2 0x560748dedb1e (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x31cb1e)
#3 0x560748ded9bf (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x31c9bf)
#4 0x560748dead95 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x319d95)
#5 0x7f48b227b7ff (/usr/lib/libpthread.so.0+0x147ff)
#6 0x7f48b20c2ce4 (/usr/lib/libc.so.6+0x3bce4)
#7 0x7f48b20ac856 (/usr/lib/libc.so.6+0x25856)
#8 0x560748ffba26 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x52aa26)
#9 0x560748fe3ce5 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x512ce5)
#10 0x560748dd3c68 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x302c68)
#11 0x560748feb184 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x51a184)
#12 0x560748feac9a (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x519c9a)
#13 0x56074901ae70 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x549e70)
#14 0x56074901ae34 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x549e34)
#15 0x560748ccf826 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x1fe826)
#16 0x560748c7adbd (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x1a9dbd)
#17 0x560748c7dad3 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x1acad3)
#18 0x560748c80663 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x1af663)
#19 0x560748c9ef45 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x1cdf45)
#20 0x560748dd3662 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x302662)
#21 0x560748e19634 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x348634)
#22 0x560748ffca36 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x52ba36)
#23 0x560748e19025 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x348025)
#24 0x560748dd4e7c (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x303e7c)
#25 0x560748dd2fa9 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x301fa9)
#26 0x560748def68e (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x31e68e)
#27 0x560748dbdfe1 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x2ecfe1)
#28 0x560748dc2484 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x2f1484)
#29 0x560748dbb8b7 (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0x2ea8b7)
#30 0x7f48b20ae022 (/usr/lib/libc.so.6+0x27022)
#31 0x560748b9fb2d (/home/niklas/Projekte/gift/fuzz/target/x86_64-unknown-linux-gnu/debug/decode+0xceb2d)
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
────────────────────────────────────────────────────────────────────────────────
Error: Fuzz target exited with exit code: 77
The iterator would be safer to use if it would end after an error (i.e. if next returns None
at least once after an error).
Example that loops forever:
fn main() {
for frame in gift::Decoder::new(std::io::Cursor::new(b"")).into_frames() {
println!("{:?}", frame);
}
}
Err(UnexpectedEndOfFile)
Err(UnexpectedEndOfFile)
Err(UnexpectedEndOfFile)
[...]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.