square / gifencoder

A pure Java library implementing the GIF89a specification. Suitable for use on Android.
Apache License 2.0
664 stars 75 forks source link

1-2 color GIFs are unreadable #11

Closed rendaw closed 5 years ago

rendaw commented 5 years ago

I've tried opening the resultant gif in gimp, chrome, firefox, mpv, and a couple other pieces of software and all of them fail to display the gif - either giving errors or showing nothing.

mpv shows:

$ mpv render1.gif 
Playing: render1.gif
 (+) Video --vid=1 (gif 100x100 10.000fps)
[ffmpeg/video] gif: LZW decode failed
VO: [gpu] 100x100 bgra
[ffmpeg/video] gif: LZW decode failed
[ffmpeg/video] gif: LZW decode failed
V: 00:00:00 / 00:00:01 (0%)
[ffmpeg/video] gif: LZW decode failed

and shows a small (maybe 100x100?) window with the transparent checker pattern.

Am I doing something crazy here? file reports the correct file size, and mpv at least gets the duration correct even if it doesn't show any of the image data.

Here's my minimal reproduction:

package c...t.test4;

import com.squareup.gifencoder.GifEncoder;
import com.squareup.gifencoder.Image;
import com.squareup.gifencoder.ImageOptions;

import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] arg) throws Exception {
        final int width = 100;
        final int height = 100;
        try (
                OutputStream stream = Files.newOutputStream(Paths.get("render1.gif"))
        ) {
            GifEncoder gifEncoder = new GifEncoder(stream, width, height, 0);
            Method addImage = GifEncoder.class.getDeclaredMethod("addImage", Image.class, ImageOptions.class);
            addImage.setAccessible(true);

            ImageOptions options = new ImageOptions();
            com.squareup.gifencoder.Color[][] rgb = new com.squareup.gifencoder.Color[height][width];
            for (int i = 0; i < 50; ++i) {
                for (int y = 0; y < height; ++y) {
                    for (int x = 0; x < width; ++x) {
                        rgb[y][x] = com.squareup.gifencoder.Color.GREEN;
                    }
                }
                addImage.invoke(gifEncoder, Image.fromColors(rgb), options);
            }
            gifEncoder.finishEncoding();
        }
    }
}

On a side note, it would be very nice to have the Image addImage exposed since the data appears to go down that channel anyway and it saves a lot of effort both on converting and dealing with bytes/unsigned nonsense.

I get the same result regardless of what I put in for colors, thought it might have been my image data but I replaced everything with green and get the same result.

Version 0.9.1.

Compiling for Java 8 (1.8), OpenJDK 11, Maven compiler plugin 3.8.0 FWIW.

I also tried Java 8 via Oracle JDK 8.

Trying the code on 0.9.0 gives me this error when opening in mpv:

$ mpv render1.gif 
Playing: render1.gif
[ffmpeg/demuxer] gif: invalid block label
 (+) Video --vid=1 (gif 100x100)
[ffmpeg/video] gif: LZW init failed
Error while decoding frame!
V: 00:00:00 / 00:00:00 (0%)

and it hangs displaying nothing (still responsive to quit key).

dlubarov commented 5 years ago

Yikes, thanks for reporting this. I'm able to reproduce it, but it's been a long time since I looked at the GIF spec, so it may take me a while to debug the issue.

Here's a very minimal repro with a single frame:

import com.squareup.gifencoder.*;
import java.io.*;

public class Main {
  public static void main(String[] arg) throws Exception {
    int width = 64;
    int height = 64;

    try (OutputStream stream = new FileOutputStream("render1.gif")) {
      GifEncoder gifEncoder = new GifEncoder(stream, width, height, 0);
      ImageOptions options = new ImageOptions();
      int[][] rgb = new int[height][width];
      gifEncoder.addImage(rgb, options);
      gifEncoder.finishEncoding();
    }
  }
}

The problem seems to come up when the color table only has one or two colors. When I modified rgb to have 3+ unique colors, it seemed to work.

rendaw commented 5 years ago

Ah, that sounds right. My original data was also simple b/w frames and adding a couple fake colors solved things. Thank you for looking into this!

dlubarov commented 5 years ago

Fixed by @rendaw in #15.

JakeWharton commented 5 years ago

Meta note: @dlubarov Just sent you an invite for write access to the repo so you can manage issues and merge PRs since you're the original author.