From 4f6c72557ecd84d0ac3739119bed66547c5835a8 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Tue, 10 Mar 2026 19:19:52 +0100 Subject: [PATCH] gif: support interlaced decoding --- nihav-commonfmt/src/codecs/gif.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/nihav-commonfmt/src/codecs/gif.rs b/nihav-commonfmt/src/codecs/gif.rs index 2810db3..570d4d2 100644 --- a/nihav-commonfmt/src/codecs/gif.rs +++ b/nihav-commonfmt/src/codecs/gif.rs @@ -162,12 +162,22 @@ struct GIFDecoder { lpal: [u8; 768], frame: Vec, dbuf: Vec, + ibuf: Vec, width: usize, height: usize, lzw: LZWState, transp: Option, } +fn deinterlace(sbuf: &[u8], dbuf: &mut [u8], width: usize) { + let mut row_iter = sbuf.chunks_exact(width); + for &(step, off) in [(8, 0), (8, 4), (4, 2), (2, 1)].iter() { + for drow in dbuf.chunks_mut(width).skip(off).step_by(step) { + drow.copy_from_slice(row_iter.next().unwrap()); + } + } +} + impl GIFDecoder { fn new() -> Self { Self { @@ -176,6 +186,7 @@ impl GIFDecoder { lpal: [0; 768], frame: Vec::new(), dbuf: Vec::new(), + ibuf: Vec::new(), width: 0, height: 0, lzw: LZWState::new(), @@ -238,10 +249,16 @@ impl NADecoder for GIFDecoder { let csize = 3 << ((flags & 7) + 1); br.read_buf(&mut self.lpal[..csize])?; } + let interlaced = (flags & 0x40) != 0; let start = br.tell() as usize; self.dbuf.resize(width * height, 0); self.lzw.unpack(&src[start..], &mut self.dbuf)?; + if interlaced { + self.ibuf.resize(width * height, 0); + deinterlace(&self.dbuf, &mut self.ibuf, width); + std::mem::swap(&mut self.dbuf, &mut self.ibuf); + } if let Some(tpix) = self.transp { for (dline, sline) in self.frame.chunks_exact_mut(self.width).skip(top) -- 2.39.5