4

I'm trying to get my application to export animated gifs, however, once the colors exceed 256, the quantization algorithm kicks in and things get, wrong.

Here's the file I have being converted, and what the algorithm converts it to:

enter image description here

The quantization algorithm I'm using is this, Quantize.java, it's apparently a Java port of the quantization used in ImageMagick so I feel like it should be reliable?

I'm using it like so:

protected int[][] pixels;  // 2D array of RGB pixels of image
protected byte[] indexedPixels;

// ...

/**
 * Analyzes image colors and creates color map.
 */
protected void analyzePixels()
{
    // Quantize the pixels, get reduced color map and indexed array.
    // -------------------------------------------------------------
    colorPalette = Quantize.quantizeImage(pixels, 256);

    // Create indexed pixels array.
    // ----------------------------
    int i = 0;

    for (int x = 0, xSize = pixels.length; x < xSize; ++x)
    {
        for (int y = 0, ySize = pixels[x].length; y < ySize; ++y)
            indexedPixels[i++] = (byte) pixels[x][y];
    }
}

Note - Here's what the algorithm converts it to when I set the static final boolean QUICK to false:

enter image description here

It looks different, but still not right.

I'd really love to get this algorithm working, since it's fast(er) and produces smaller files than the alternatives (NeuQuant). Am I doing everything right or is this just how the algorithm works?

yesbutmaybeno
  • 1,078
  • 13
  • 31
  • What do you expect the line `indexedPixels[i++] = (byte) pixels[x][y];` to do? – Douglas Zare Mar 27 '15 at 22:11
  • 1
    @DouglasZare The line `colorPalette = Quantize.quantizeImage(pixels, 256);` converts the contents of pixels[][] into indices of colorMap[], essentially pointing each pixel to a color in colorMap[]. The line you refer to I'm just emptying it from a 2D array into a 1D byte array since that's what is expected of the LZWEncoder I'm using. – yesbutmaybeno Mar 27 '15 at 22:52
  • Wow, that's quite a side effect of quantizeImage. By colorMap[], you mean colorPalette? Are you making sure to undo the cast of each index from int to byte, rather than simply casting it back to to int? For example, the color number 200 (as an int) becomes -56 (as a byte). – Douglas Zare Mar 27 '15 at 23:15
  • @DouglasZare Man that seemed like a great answer. I just tried it (got rid of bytes all together, stuck with just ints) but the results were exactly the same. The indexedPixels[] array looks more correct now though, no negative numbers and contents go from 0-255. – yesbutmaybeno Mar 29 '15 at 17:18

2 Answers2

0

You need to add a dither algorithm.. google it.. I believe Java has some algorithms built in, but a straight Java sample from wikipedia worked for me. As I wanted to muck with the raw byte-arrays and int-arrays for greater efficiency than just using getPixel/setPixel

M. Maraist
  • 432
  • 4
  • 7
  • I haven't tried this, but a dithering algorithm would prevent the image from being red (as in the first example in OP)? That doesn't seem right. It seems like the Quantize algorithm I'm using is wrong, as NeuQuant does work accurately enough, however is 5x slower with 3x filesize. – yesbutmaybeno Mar 30 '15 at 21:49
0

I ended up abandoning Quantize.java and found Java Imaging Utilities (http://sourceforge.net/projects/jiu/) which provides some nice color/image quantizing options. They're not perfect results, but are bearable.

yesbutmaybeno
  • 1,078
  • 13
  • 31