Open Justinfront opened 9 years ago
Sorry the pixels are pretty small if you grab it and put it on a mac the preview will show difference one looks green top right and the other looks blue, my encoder only works well up to 90x90 ish but colors seem to be correct and filesizes smaller.
I also wanted to ask if the LZW approach you use - does it encode each color channel separately, because it seemed to... c = nextPixel() where nextPixel was return pixAry[curPixel - 1] & 0xff; which looked like it was only one color channel not a whole pixel but I was a bit lost so not sure, whereas my encoder... c = Std.string( encodedPixels[ i ] ); will return 0,1,2,3 the colors indexed from 0. Just trying to get my head round workings.
Just to be clear 0x009966; in any graphics app looks greenish, but in your gif it looks decidedly blue I don't know if it's an issue with UInt8Array or something else but my test code looks valid.
Quality setting of 100 is 100% compression. Try with 0~15 for the highest quality.
Quality does not seem to effect the result. Instead of 0x009966 the square is colored 0x0A91A2
I suspect that the problem lies in the colour quantization. I don't really know the algorithm, but this line in NeuQuant.hx suggests to me that the algorithm wants a minimum picture size of 503 pixels (though that doesn't seem to be an absolute minimum since it still kind of works for those 4-pixel test cases).
I've run a test with an image that just repeats those 4 test colours, but in an image of 504 pixels, and the colours are correct. Images with fewer pixels (500 was my test) also seem to output correct colours, so it doesn't seem like anything below the 503-pixel limit goes wrong, however it seems likely that very small images just don't work for it.
I also found the original website and paper for the quantization algorithm, I've only skimmed it so far but this may be a starting point if you want to look into this further: http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
@chman may also have an opinion
As @KeyMaster- suggests it seems to be a limitation of the NeuQuant algorithm (in this case probably also exacerbated by the fact that the input has only 4 colors).
In support to that idea there's for example this java port that explicitly throws an exception if (width * height) < 503
(search for "too small").
One possible fix would be to run a simpler algorithm to build the palette when the input is smaller than 256 total pixels (as they would surely map to - at most - 256 entries). It would also be faster and more accurate: the output would 100% match the original rgb values.
Well... if anyone's interested I've going down that path and came up with this:
/** Analyzes pixels' colors and builds the color table (does no color-quantization/palette-reduction).
* NOTE: naive substitute of `analyze()` (assumes unique colors to be <= 256).
*/
function simplemapping(pixels:UInt8Array) {
var rgb2index = new Map<Int, Int>(); // maps rgb to index
var index2rgb = []; // reverse look-up
// analyze pixels
var nextIndex = 0;
var k = 0;
for (i in 0...(width * height))
{
var rgb = (pixels[k++] << 16) | (pixels[k++] << 8) | pixels[k++];
var index = rgb2index[rgb];
if (index == null) {
index = nextIndex++;
rgb2index[rgb] = index;
index2rgb[index] = rgb;
}
indexedPixels[i] = index;
}
colorTab = new UInt8Array(nextIndex * 3);
// build color table
k = 0;
for (rgb in index2rgb) {
colorTab[k++] = (rgb >> 16) & 0xFF;
colorTab[k++] = (rgb >> 8) & 0xFF;
colorTab[k++] = rgb & 0xFF;
}
// max 256 unique colors
colorDepth = 8;
paletteSize = 7;
}
Going further one can prescan the image and count the unique colors, and then decide which algorithm to run based on whether it exceeds 256 or not.
See 4 pixel gif here using code below: And what it should look like.
Produced hex
By comparisom I tried encoding 4 pixels with my unfinished gif encoder. I got correct colors and more sensible filesize.
Obviously the snow one is more complete I am just trying to get more understanding of the comparative workings and I am thinking maybe it would be ideal to blend some aspects to get best performance for small images, and also seems to show an issue with color.