Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating GIF from JPEG frames? #44

Open
captainviet opened this issue Jan 14, 2018 · 4 comments
Open

Creating GIF from JPEG frames? #44

captainviet opened this issue Jan 14, 2018 · 4 comments

Comments

@captainviet
Copy link

Hi,

I'm new to Rust, yet I need to write a piece of Rust code to create a GIF file from a series of JPEG screenshots.

Currently my generated GIF is glitchy, the content seems enlarged and the colors don't look right.
I'm wondering whether this is related to the compatibility of JPEG as frames for GIF, or because I'm using the wrong palette for the GIF Encoder? I'm learning so comments are welcome! Thanks in advance!

A brief summary for the code below:

  • screenshot() returns an image::RgbaImage
  • the width and height of each of the image (and the derived Frame) is fixed
  • the color_map is set to [ FF, FF, FF, FF, 00, 00 ] (which I supposed is R, G, B, and A enabled? Pardon me as I cannot find any reference to the palette parameter)
  • the individual JPEG images are correctly generated
  • the GIF is created with frames derived from the JPEG images
extern crate image;
extern crate time;
extern crate gif;
extern crate screenshot;

use image as im;
use std::fs::File;
use std::thread;
use std::time::Duration;
use time::PreciseTime as tpt;
use gif::{Frame, Encoder, Repeat, SetParameter};
use std::borrow::Cow;
use screenshot::screenshot;

fn main() {
    let mut image = File::create("sample.gif").unwrap();
    let img: im::RgbaImage = screenshot();
    println!("Len: {}", img.len());
    println!("Original: {}x{}", img.width(), img.height());
    let width: u16 = img.width() as u16;
    let height: u16 = img.height() as u16;
    println!("Compressed: {}x{}", width, height);
    let color_map = &[0xFF, 0xFF, 0xFF, 0xFF, 0, 0];
    let mut encoder = Encoder::new(&mut image, width, height, color_map).unwrap();
    encoder.set(Repeat::Infinite).unwrap();
    for i in 0..6 {
        let start = tpt::now();
        let img: im::RgbaImage = screenshot();
        let mid1 = tpt::now();
        println!("Getting raw buffer...");
        let pixes: &mut [u8] = &mut img.into_raw();
        println!("Getting frame...");
        //let mut frame = Frame::from_rgba(width, height, pixes);
        let mut frame = Frame::default();
        frame.width = width;
        frame.height = height;
        frame.buffer = Cow::Borrowed(pixes);
        println!("Writing frame...");
        encoder.write_frame(&frame).unwrap();
        let end = tpt::now();
        println!("Duration: {} {}", start.to(mid1).num_milliseconds(), mid1.to(end).num_milliseconds());
    }
}
@nwin
Copy link
Contributor

nwin commented Jan 15, 2018

The color map maps the raw pixel values (0–255) onto rgb triplets. Frame::from_rgba will solve this for you.

This will make the image considerably larger as it then uses a local color map for every frame one strategy would be to extract the color map from the first frame and use it as a global color map. And create the successive frames like you did.

@captainviet
Copy link
Author

Hi @nwin ,

Actually my first attempt was using Frame::from_rgba. The reason I try to find an alternative is because the performance of this method is terrible: 2 minutes to convert each JPEG images to a frame.

Regarding the color map, I don't know what it is in the first place, so I've searched the documentation but I cannot find any method to get that property. I may have missed something, so for clarification is there anyway to extract the color map from an RgbaImage or similar entities?

@HeroicKatora
Copy link
Member

Actually my first attempt was using Frame::from_rgba. The reason I try to find an alternative is because the performance of this method is terrible: 2 minutes to convert each JPEG images to a frame.

Encoding performance of lzw, the current implementation of LZW encoding, was terrible. It's going to be much faster with the next release where that implementation is switched.

@kornelski
Copy link
Contributor

kornelski commented Nov 10, 2020

BTW, the performance bottleneck is not in LZW, but in color_quant. This algorithm (neuquant) performs quite a lot of work per pixel. You could use another quantization algorithm, e.g. imagequant that is faster (mediancut scales sub-linearly with number of unique colors).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants