mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-14 22:42:46 +00:00
gif: expose first-frame data byte count
This commit is contained in:
1 parent
3c51d88330
commit
ededdd75c9
2 files changed
+32
No files matched your search
@@ -253,6 +253,29 @@ pub fn first_frame_decoded_pixels(bytes: &[u8]) -> Option<u64> {
|
||||
Some(pixels)
|
||||
}
|
||||
|
||||
/// Counts compressed image-data bytes in the first frame's sub-blocks, excluding its LZW code-size
|
||||
/// byte and all later blocks. A truncated final sub-block contributes only the bytes present.
|
||||
pub fn first_frame_compressed_bytes(bytes: &[u8]) -> Option<usize> {
|
||||
let parsed = scan(bytes, 1)?;
|
||||
let frame = parsed.frames.first()?;
|
||||
let packed = *bytes.get(frame.offset.checked_add(9)?)?;
|
||||
let mut pos = frame.offset.checked_add(10)?.checked_add(table_len(packed))?.checked_add(1)?;
|
||||
let mut total = 0usize;
|
||||
loop {
|
||||
let length = usize::from(*bytes.get(pos)?);
|
||||
pos = pos.checked_add(1)?;
|
||||
if length == 0 {
|
||||
return Some(total);
|
||||
}
|
||||
let end = pos.checked_add(length)?;
|
||||
total = total.checked_add(end.min(bytes.len()).saturating_sub(pos))?;
|
||||
if end > bytes.len() {
|
||||
return Some(total);
|
||||
}
|
||||
pos = end;
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether a file of `file_len` bytes can plausibly hold `declared_bytes` of decoded picture: at
|
||||
/// most `max_ratio` decoded bytes for each file byte, plus 1 MiB. A decoder that sets up the whole
|
||||
/// logical screen before it reads a frame should be given only files that pass this.
|
||||
|
||||
@@ -54,6 +54,15 @@ fn animated(delays_cs: &[u32], repeat: Option<image::codecs::gif::Repeat>) -> Ve
|
||||
out
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn first_frame_compressed_bytes_exclude_extensions_after_the_image_data() {
|
||||
let mut bytes = gif(&[[1, 2, 3], [4, 5, 6]], None, None);
|
||||
assert_eq!(first_frame_compressed_bytes(&bytes), Some(2));
|
||||
bytes.splice(bytes.len() - 1..bytes.len() - 1, [0x21, 0xFE, 1, b'x', 0]);
|
||||
assert_eq!(first_frame_compressed_bytes(&bytes), Some(2));
|
||||
assert_eq!(first_frame_compressed_bytes(b"not a gif"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_first_frames_table_and_transparent_entry() {
|
||||
let g = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 255]];
|
||||
|
||||
Reference in new issue
Block a user