Skip to content

Commit

Permalink
Parse repeat count
Browse files Browse the repository at this point in the history
  • Loading branch information
kornelski committed Jan 10, 2024
1 parent e1f608f commit fe91e68
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 3 deletions.
8 changes: 7 additions & 1 deletion src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,20 @@ impl From<EncodingFormatError> for EncodingError {
}

/// Number of repetitions
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Repeat {
/// Finite number of repetitions
Finite(u16),
/// Infinite number of repetitions
Infinite,
}

impl Default for Repeat {
fn default() -> Self {
Self::Finite(0)
}
}

/// Extension data.
pub enum ExtensionData {
/// Control extension. Use `ExtensionData::new_control_ext` to construct.
Expand Down
20 changes: 19 additions & 1 deletion src/reader/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::io;
use std::mem;
use std::default::Default;

use crate::Repeat;
use crate::common::{AnyExtension, Block, DisposalMethod, Extension, Frame};
use crate::reader::DecodeOptions;

Expand Down Expand Up @@ -118,6 +119,8 @@ pub enum Decoded<'a> {
GlobalPalette(Vec<u8>),
/// Index of the background color in the global palette.
BackgroundColor(u8),
/// Loop count is known
Repetitions(Repeat),
/// Palette and optional `Application` extension have been parsed,
/// reached frame data.
HeaderEnd,
Expand Down Expand Up @@ -159,6 +162,7 @@ enum State {
/// Block end, with remaining expected data. NonZero for invalid EOF.
BlockEnd(u8),
ExtensionBlock(AnyExtension),
ApplicationExtension,
SkipBlock(usize),
LocalPalette(usize),
LzwInit(u8),
Expand Down Expand Up @@ -666,12 +670,26 @@ impl StreamingDecoder {
goto!(n, SkipBlock(left - n))
} else if b == 0 {
self.ext.is_block_end = true;
goto!(BlockEnd(b), emit Decoded::BlockFinished(self.ext.id, &self.ext.data))
if self.ext.id.into_known() == Some(Extension::Application) {
goto!(ApplicationExtension, emit Decoded::BlockFinished(self.ext.id, &self.ext.data))
} else {
goto!(BlockEnd(b), emit Decoded::BlockFinished(self.ext.id, &self.ext.data))
}
} else {
self.ext.is_block_end = false;
goto!(SkipBlock(b as usize), emit Decoded::SubBlockFinished(self.ext.id, &self.ext.data))
}
}
ApplicationExtension => {
// the parser removes sub-block lenghts, so app name and data are concatenated
if self.ext.data.len() >= 15 && &self.ext.data[1..13] == b"NETSCAPE2.0\x01" {
let repeat = &self.ext.data[13..15];
let repeat = u16::from(repeat[0]) | u16::from(repeat[1]) << 8;
goto!(0, BlockEnd(0), emit Decoded::Repetitions(if repeat == 0 { Repeat::Infinite } else { Repeat::Finite(repeat) }))
} else {
goto!(0, BlockEnd(0))
}
}
LocalPalette(left) => {
let n = cmp::min(left, buf.len());
if left > 0 {
Expand Down
11 changes: 11 additions & 0 deletions src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::io::prelude::*;
use std::num::NonZeroU64;
use std::convert::{TryFrom, TryInto};

use crate::Repeat;
use crate::common::{Block, Frame};

mod decoder;
Expand Down Expand Up @@ -228,6 +229,7 @@ pub struct Decoder<R: Read> {
color_output: ColorOutput,
memory_limit: MemoryLimit,
bg_color: Option<u8>,
repeat: Repeat,
global_palette: Option<Vec<u8>>,
current_frame: Frame<'static>,
current_frame_data_type: FrameDataType,
Expand Down Expand Up @@ -256,6 +258,7 @@ impl<R> Decoder<R> where R: Read {
bg_color: None,
global_palette: None,
buffer: vec![],
repeat: Repeat::default(),
color_output: options.color_output,
memory_limit: options.memory_limit,
current_frame: Frame::default(),
Expand All @@ -276,6 +279,9 @@ impl<R> Decoder<R> where R: Read {
None
};
},
Some(Decoded::Repetitions(repeat)) => {
self.repeat = repeat;
},
Some(Decoded::HeaderEnd | Decoded::Trailer) => {
break
},
Expand Down Expand Up @@ -501,6 +507,11 @@ impl<R> Decoder<R> where R: Read {
pub fn bg_color(&self) -> Option<usize> {
self.bg_color.map(|v| v as usize)
}

/// Number of loop repetitions
pub fn repeat(&self) -> Repeat {
self.repeat
}
}

struct InterlaceIterator {
Expand Down
5 changes: 4 additions & 1 deletion tests/roundtrip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ fn encode_roundtrip() {
}

fn round_trip_from_image(original: &[u8]) {
let (width, height, global_palette);
let (width, height, global_palette, repeat);
let frames: Vec<_> = {
let mut decoder = Decoder::new(original).unwrap();
width = decoder.width();
height = decoder.height();
repeat = decoder.repeat();
global_palette = decoder
.global_palette()
.unwrap_or_default()
Expand All @@ -22,6 +23,7 @@ fn round_trip_from_image(original: &[u8]) {
};

let mut encoder = Encoder::new(vec![], width, height, &global_palette).unwrap();
encoder.set_repeat(repeat).unwrap();
for frame in &frames {
encoder.write_frame(frame).unwrap();
}
Expand All @@ -31,6 +33,7 @@ fn round_trip_from_image(original: &[u8]) {
let mut decoder = Decoder::new(&buffer[..]).expect("Invalid info encoded");
assert_eq!(decoder.width(), width);
assert_eq!(decoder.height(), height);
assert_eq!(decoder.repeat(), repeat);
assert_eq!(global_palette, decoder.global_palette().unwrap_or_default());
let new_frames: Vec<_> = core::iter::from_fn(move || {
decoder.read_next_frame().unwrap().cloned()
Expand Down

0 comments on commit fe91e68

Please sign in to comment.