package com.jotuntech.sketcher.common; import java.util.zip.DataFormatException; import java.util.zip.Inflater; public class PixelUnpacker { Inflater inflater; private byte[] encodedPixels; public PixelUnpacker() { inflater = new Inflater(true); } public void unpack(byte[] input, int ofs, int len, int[] output) { if(encodedPixels == null || encodedPixels.length < input.length * 6) { encodedPixels = new byte[output.length * 6]; } inflater.reset(); inflater.setInput(input, ofs, len); //Log.debug("Inflating from offset " + ofs + " length " + len); int encodedLength = 0; try { while(!inflater.finished() && encodedLength < encodedPixels.length) { encodedLength += inflater.inflate(encodedPixels, encodedLength, encodedPixels.length - encodedLength); } } catch(DataFormatException e) { throw new RuntimeException(e); } if(encodedLength < output.length * 6) { Log.error("needsInput = " + inflater.needsInput()); throw new RuntimeException("Encoded length " + encodedLength + " is shorter than output length " + output.length * 6 + "."); } int lastAlpha = 0, lastY = 0, lastCb = 256, lastCr = 256; for(int outputOffset = 0, YOffset = output.length, CbOffset = output.length * 2, CrOffset = output.length * 4; outputOffset < output.length; outputOffset++, YOffset++, CbOffset++, CrOffset++) { /* Extract alpha channel delta */ int deltaAlpha = encodedPixels[outputOffset] & 0xFF; /* Differential transform with overflow wrapping */ int alpha = (lastAlpha + deltaAlpha) & 0xFF; lastAlpha = alpha; /* Color channel deltas are always zero when alpha is zero */ if(alpha == 0) { output[outputOffset] = 0; ++CbOffset; ++CrOffset; } else { /* Extract color channel deltas */ int deltaY = encodedPixels[YOffset] & 0xFF; int deltaCb = ((encodedPixels[CbOffset++] & 0xFF) << 8) | (encodedPixels[CbOffset] & 0xFF); int deltaCr = ((encodedPixels[CrOffset++] & 0xFF) << 8) | (encodedPixels[CrOffset] & 0xFF); /* Differental transform with overflow wrapping */ int Y = (lastY + deltaY) & 0xFF; int Cb = (lastCb + deltaCb) & 0x1FF; int Cr = (lastCr + deltaCr) & 0x1FF; lastY = Y; lastCb = Cb; lastCr = Cr; /* Inverse color transform */ Cb -= 256; Cr -= 256; int green = Y - ((Cb + Cr) >> 2); int red = Cr + green; int blue = Cb + green; output[outputOffset] = Pixels.pack(alpha, red, green, blue); } } } }