Live data from Hacker News

Gifski: Optimized GIF Encoder

github.com

41–50 of 65 posts

Re: Gifski: Optimized GIF Encoder

#41

While on the subject of gifs, I'd like to recommend ScreenToGif. As the name suggests it supports screen recording, but the editor is nice for other gifs as well. It's easy to remove duplicate frames, change timing for all or some frames, etc. It can use ffmpeg and gifski for the gif encoding. https://www.screentogif.com/ Also, I just learnt this, gifski has integrated gifsicle for lossy gif compression.

After clicking your link I had instant nostalgia. I used this tool years ago and completely forgot about it. I went to download it, but it appears to be windows only which explains why I stopped using it as I haven't used windows in about a decade.

That said, I'd highly recommend Giphy Capture for recording gifs on mac. It has a very sleek/light UI.

Re: Gifski: Optimized GIF Encoder

#42
post #40

Earlier quoted context omitted.

Many platforms already stopped using gifs, for precisely those reasons. Tumblr silently converts to animated webp when uploading a gif, imgur converts it to mp4, etc.

This is really annoying when trying to share gifs across platforms. I can't export a "gif" (.mp4) from telegram and upload it to Discord and display it like a gif instead of a click-to-play video, even though discord uses .mp4 under the hood as well...

Maybe all it takes for this is a new canonical file extension, i.e. something like .m4g?

The contract for these could be something like "no sound, default playback in a loop, 30 seconds or less; don't render if any of these requirements aren't met" to make sure people don't abuse it for auto-playing videos.

Re: Gifski: Optimized GIF Encoder

#43
Love this thing! It enabled me to add a “Convert to GIF” for videos in my Clop app (https://lowtechguys.com/clop) in just a few lines of code. The GIF gets encoded at its optimal size by default so I didn’t have to do a second optimization step.

I also like that the author spent time to add an easy way to build a static binary, which I need in order to ship gifski inside the app.

Compressing all these static binaries so I can ship them in Clop with a [1] https://github.com/ckolivas/lrzip

Re: Gifski: Optimized GIF Encoder

#44
post #42
post #40

Earlier quoted context omitted.

This is really annoying when trying to share gifs across platforms. I can't export a "gif" (.mp4) from telegram and upload it to Discord and display it like a gif instead of a click-to-play video, even though discord uses .mp4 under the hood as well...

Maybe all it takes for this is a new canonical file extension, i.e. something like .m4g? The contract for these could be something like "no sound, default playback in a loop, 30 seconds or less; don't render if any of these requirements aren't met" to make sure people don't abuse it for auto-playing videos.

It's really more of a browser issue, a GIF you can just right click and download, but they don't make that option available for videos.

Re: Gifski: Optimized GIF Encoder

#45
If you don't want to use something more composed like this, the main trick gifski is doing is using a two-pass approach to generate a palette for the gif. You can do this pretty easily with just ffmpeg / ffprobe. Here's my personal script I use for generation:

    #!/bin/sh

    SCALE=500
    FPS=15
    SCALEPROVIDED=false
    
    for arg in "$@"
    do
        case $arg in
            -s=*|--size=*)
            SCALE="${arg#*=}"
            SCALEPROVIDED=true
            shift 
            ;;
            -f=*|--fps=*)
            FPS="${arg#*=}"
            shift 
            ;;
        esac
    done
    
    palette="/tmp/palette.png"

    # Look at the width/height of the video
    width=`ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=s=x:p=0 $1`
    height=`ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 $1`
    
    # Get the max
    max=$(( width > height ? width : height))
    
    # If we havent provided a scale, and the max size is lower than the default, set it to the lower value
    if [ "$SCALEPROVIDED" == true ]
    then
        minScale=$SCALE
    else
        minScale=$(( SCALE 
Example usage is something like:

    gif input.mov
But you can also optionally specify framerate, size, and output name:

    gif -s=800 -f=22 input.mov my-800px-22fps-gif.gif

Re: Gifski: Optimized GIF Encoder

#46
My image optimization trio as of now:

- GIF: gifski (squeeze out the best possible out of the ancient format)

- PNG: pngquant (lossy but respectful of what many PNGs are: lots of flat surfaces + limited color palette, transparency)

- JPG: jpegli (writing this post mostly to share the news about this one, it's new from libjxl learnings, approximately as good qualitatively as Guetzli, but 1000x faster -actual number, not an exaggeration-. It's amazing! https://github.com/libjxl/libjxl/tree/main/lib/jpegli )

Below's my lil' `image-opt` helper making for a nice workflow to optimize any gif/jpg/png file(s) :)

  #!/usr/bin/env bash
  set -euo pipefail
  
  dbg() { if [ "${DEBUG:=false}" = 'true' ]; then echo "$@"; fi }
  die() { echo "Error: $*" 1>&2; zenity --error --text="$*"; exit 1; }
  
  if ! command -v pngquant > /dev/null; then die 'You must install pngquant'; fi
  if ! command -v cjpegli > /dev/null; then die 'You must install cjpegli'; fi
  if ! command -v gifsicle > /dev/null; then die 'You must install gifsicle'; fi
  
  for filename in "${@:1}"; do
    if [ -d "$filename" ]; then
      echo && echo "ℹ File '$filename' is a directory. Skipping."
      continue
    fi
    if [ ! -f "$filename" ]; then
      echo && echo "ℹ File '$filename' does not exist. Skipping."
      continue
    fi
  
    extension_raw="${filename##*.}"
    extension="${extension_raw,,}"  # Convert to lowercase
    if [[ "$extension" != 'jpg' && "$extension" != 'png' && "$extension" != 'gif' ]]; then
      echo && echo "ℹ Skipping file $filename due to unsupported extension: .$extension"
      continue
    fi
  
    filename_noext="${filename%.*}"
    filename_original="${filename_noext}_beforeOpt.${extension_raw}"
    filename_final="${filename_noext}.${extension}"
    dbg "filename($filename), filename_noext($filename_noext), extension($extension), filename_original($filename_original)"
  
    echo && echo " Compressing $filename ..."
    mv "$filename" "$filename_original"
    if [ "$extension" == 'jpg' ]; then
      cjpegli "$filename_original" "${filename_noext}_q50.${extension}" -q 50
      cjpegli "$filename_original" "${filename_noext}_q60.${extension}" -q 60
      cjpegli "$filename_original" "${filename_noext}_q70.${extension}" -q 70
      cjpegli "$filename_original" "${filename_noext}_q80.${extension}" -q 80
      cjpegli "$filename_original" "${filename_noext}_q90.${extension}" -q 90
    elif [ "$extension" == 'png' ]; then
      pngquant --strip --force --verbose --output "$filename_final" "$filename_original"
    elif [ "$extension" == 'gif' ]; then
      # https://kornel.ski/lossygif , set --lossy to 20 for light compression, 200 for heavy
      gifsicle -O3 --lossy=50 --verbose --output "$filename_final" "$filename_original"
    fi
    gio trash "$filename_original"
  done
  
  sync

Re: Gifski: Optimized GIF Encoder

#47
post #45

If you don't want to use something more composed like this, the main trick gifski is doing is using a two-pass approach to generate a palette for the gif. You can do this pretty easily with just ffmpeg / ffprobe. Here's my personal script I use for generation: #!/bin/sh SCALE=500 FPS=15 SCALEPROVIDED=false for arg in "$@" do case $arg in -s=*|--size=*) SCALE="${arg#*=}" SCALEPROVIDED=true shift ;; -f=*|--fps=*) FPS="…

gifski works in a single pass, and streams its output.

    ffmpeg -i input.mov -f yuv4mpegpipe | gifski --width=500 -o out.gif -

Re: Gifski: Optimized GIF Encoder

#48
post #40

Earlier quoted context omitted.

Many platforms already stopped using gifs, for precisely those reasons. Tumblr silently converts to animated webp when uploading a gif, imgur converts it to mp4, etc.

This is really annoying when trying to share gifs across platforms. I can't export a "gif" (.mp4) from telegram and upload it to Discord and display it like a gif instead of a click-to-play video, even though discord uses .mp4 under the hood as well...

GIF = Graphics Interchange Format

_speechless at the irony

Re: Gifski: Optimized GIF Encoder

#49
post #42

Earlier quoted context omitted.

Maybe all it takes for this is a new canonical file extension, i.e. something like .m4g? The contract for these could be something like "no sound, default playback in a loop, 30 seconds or less; don't render if any of these requirements aren't met" to make sure people don't abuse it for auto-playing videos.

It's really more of a browser issue, a GIF you can just right click and download, but they don't make that option available for videos.

That option does actually exist for "plain" HTML5 tags, as far as I know. It's just that most videos aren't hosted as simple as that, and are effectively stitched together out of multiple MPEG-DASH, HLS etc. fragments – or the site uses a custom video player.

In both cases, the result is a lack of a right-click-to-save option.

Re: Gifski: Optimized GIF Encoder

#50

I've tried an absurd amount of video-to-gif tools and Gifski somehow is orders of magnitude better quality than all of them

I just ran a test on a ~4 second hires screen recording in Gifski and GIF Brewery 3 (which is what I've been using for years).

Gifski took 11 seconds, and GIF Brewery took 59. Both apps set to maximum quality, 50fps, no resizing. The Gifski version is a little bigger at 5.5mb vs 4.2mb but also looks a bit better.

I embed short screen recording GIFs into GitLab/GitHub several times a week as it's just a better user experience vs real video files on those platforms. I'm definitely switching tools! I wish I had known about this sooner.

Post reply on HN