Skip to main content
Loading...

More Rust Posts

async fn encode_gif(frames: Vec<Frame>) -> Result<Vec<Vec<u8>>> {
        fn output_frame(raw: &[u8], format: u8, delay: u32, index: usize, size: (u32, u32)) -> Result<Vec<u8>> {
            let b64 = general_purpose::STANDARD.encode(raw).into_bytes();

            let mut it = b64.chunks(4096).peekable();
            let mut buf = Vec::with_capacity(b64.len() + it.len() * 50);
            let com = if index == 0 {"T"} else {"f"};
            if let Some(first) = it.next() {
                write!(
                    buf,
                    "{}_Gq=2,a={},z={},i=1,C=1,U=1,f={},s={},v={},m={};{}{}\\{}",
                    START,
                    com, // first frame must be static image data
                    delay,
                    format,
                    size.0,
                    size.1,
                    it.peek().is_some() as u8,
                    unsafe { str::from_utf8_unchecked(first) },
                    ESCAPE,
                    CLOSE
                )?;
            }

            while let Some(chunk) = it.next() {
                write!(
                    buf,
                    "{}_Gm={};{}{}\\{}",
                    START,
                    it.peek().is_some() as u8,
                    unsafe { str::from_utf8_unchecked(chunk) },
                    ESCAPE,
                    CLOSE
                )?;
            }

            write!(buf, "{}", CLOSE)?;
            Ok(buf)
        }

        let mut frame_buffer = Vec::new();

        // populate framebuffer for entire gif
        for (index, frame) in frames.into_iter().enumerate() {
            let size = frame.buffer().dimensions();

            fn delay_to_ms(delay: Delay) -> u32 {
                let (num, denom) = delay.numer_denom_ms();
                if denom == 0 { 0 } else { num / denom }
            }
            let delay_ms = delay_to_ms(frame.delay());

            let buf = tokio::task::spawn_blocking(move || match DynamicImage::ImageRgba8(frame.buffer().clone()) {
                DynamicImage::ImageRgb8(v) => output_frame(&v, 24, delay_ms, index, size),
                DynamicImage::ImageRgba8(v) => output_frame(&v, 32, delay_ms, index, size),
                v => output_frame(v.into_rgb8().as_raw(), 24, delay_ms, index, size),
            })
            .await?;
            if buf.is_ok() { frame_buffer.push(buf.unwrap()) }
        };

        // transmit our framebuffer
        Ok(frame_buffer)
    }

    fn animate(id: u32) -> Result<Vec<u8>> {
        let mut buf = Vec::new();
        write!(
            buf,
            "{}_Gq=2,a=a,s=2,i={}{}\\{}", // starts the animation for id=1
            START,
            id,
            ESCAPE,
            CLOSE
        )?;
        write!(buf, "{}", CLOSE)?;
        Ok(buf)
    }