X-Git-Url: http://www2.svjatoslav.eu/gitweb/?p=imagesqueeze.git;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Feu%2Fsvjatoslav%2Fimagesqueeze%2Fcodec%2FImageDecoder.java;h=24c1e276663fbf677a341bbec2a439253e86bbdd;hp=53f2d9125be148544ad2dcf95fe5873065dc324c;hb=7b3e2cbabc6df4010fb50b129933ad91ada21e62;hpb=db43b283d3a8180a8496f7cc309ddaffc74deee4;ds=sidebyside diff --git a/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java b/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java index 53f2d91..24c1e27 100755 --- a/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java +++ b/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java @@ -13,239 +13,231 @@ package eu.svjatoslav.imagesqueeze.codec; * Compressed image pixels decoder. */ +import eu.svjatoslav.commons.data.BitInputStream; + import java.awt.image.DataBufferByte; import java.awt.image.WritableRaster; import java.io.IOException; -import eu.svjatoslav.commons.data.BitInputStream; - -public class ImageDecoder { - - public static int readIntegerCompressed8(final BitInputStream inputStream) - throws IOException { - - if (inputStream.readBits(1) == 0) - return inputStream.readBits(8); - else - return inputStream.readBits(32); - } - - int width, height; - - Image image; - byte[] decodedYRangeMap; - - byte[] decodedYMap; - byte[] decodedURangeMap; - - byte[] decodedUMap; - byte[] decodedVRangeMap; - - byte[] decodedVMap; - - Color tmpColor = new Color(); - Approximator approximator; - - BitInputStream bitInputStream; - ColorStats colorStats = new ColorStats(); - - OperatingContext context = new OperatingContext(); - - public ImageDecoder(final Image image, final BitInputStream bitInputStream) { - approximator = new Approximator(); - - this.image = image; - this.bitInputStream = bitInputStream; - - width = image.metaData.width; - height = image.metaData.height; - - decodedYRangeMap = new byte[width * height]; - decodedYRangeMap[0] = (byte) (255); - decodedYMap = new byte[width * height]; - - decodedURangeMap = new byte[width * height]; - decodedURangeMap[0] = (byte) (255); - decodedUMap = new byte[width * height]; - - decodedVRangeMap = new byte[width * height]; - decodedVRangeMap[0] = (byte) (255); - decodedVMap = new byte[width * height]; - - } - - public void decode() throws IOException { - approximator.load(bitInputStream); - approximator.computeLookupTables(); - - final WritableRaster raster = image.bufferedImage.getRaster(); - final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer(); - final byte[] pixels = dbi.getData(); +class ImageDecoder { - // load top-, left-most pixel. - decodedYMap[0] = (byte) bitInputStream.readBits(8); - decodedUMap[0] = (byte) bitInputStream.readBits(8); - decodedVMap[0] = (byte) bitInputStream.readBits(8); + private final int width; + private final int height; + private final Image image; + private final byte[] decodedYRangeMap; + private final byte[] decodedYMap; + private final byte[] decodedURangeMap; + private final byte[] decodedUMap; + private final byte[] decodedVRangeMap; + private final byte[] decodedVMap; + private final Approximator approximator; + private final BitInputStream bitInputStream; + private final OperatingContext context = new OperatingContext(); - final Color color = new Color(); - color.y = ImageEncoder.byteToInt(decodedYMap[0]); - color.u = ImageEncoder.byteToInt(decodedUMap[0]); - color.v = ImageEncoder.byteToInt(decodedVMap[0]); + public ImageDecoder(final Image image, final BitInputStream bitInputStream) { + approximator = new Approximator(); - color.YUV2RGB(); + this.image = image; + this.bitInputStream = bitInputStream; - pixels[0] = (byte) color.r; - pixels[0 + 1] = (byte) color.g; - pixels[0 + 2] = (byte) color.b; + width = image.metaData.width; + height = image.metaData.height; - // detect initial step - int largestDimension; - int initialStep = 2; - if (width > height) - largestDimension = width; - else - largestDimension = height; + decodedYRangeMap = new byte[width * height]; + decodedYRangeMap[0] = (byte) (255); + decodedYMap = new byte[width * height]; - while (initialStep < largestDimension) - initialStep = initialStep * 2; + decodedURangeMap = new byte[width * height]; + decodedURangeMap[0] = (byte) (255); + decodedUMap = new byte[width * height]; - grid(initialStep, pixels); - } + decodedVRangeMap = new byte[width * height]; + decodedVRangeMap[0] = (byte) (255); + decodedVMap = new byte[width * height]; - public void grid(final int step, final byte[] pixels) throws IOException { + } - gridDiagonal(step / 2, step / 2, step, pixels); - gridSquare(step / 2, 0, step, pixels); - gridSquare(0, step / 2, step, pixels); + public static int readIntegerCompressed8(final BitInputStream inputStream) + throws IOException { - if (step > 2) - grid(step / 2, pixels); - } + if (inputStream.readBits(1) == 0) + return inputStream.readBits(8); + else + return inputStream.readBits(32); + } - public void gridDiagonal(final int offsetX, final int offsetY, - final int step, final byte[] pixels) throws IOException { + public void decode() throws IOException { + approximator.load(bitInputStream); + approximator.computeLookupTables(); - for (int y = offsetY; y < height; y = y + step) - for (int x = offsetX; x < width; x = x + step) { + final WritableRaster raster = image.bufferedImage.getRaster(); + final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer(); + final byte[] pixels = dbi.getData(); - final int halfStep = step / 2; + // load top-, left-most pixel. + decodedYMap[0] = (byte) bitInputStream.readBits(8); + decodedUMap[0] = (byte) bitInputStream.readBits(8); + decodedVMap[0] = (byte) bitInputStream.readBits(8); - context.initialize(image, decodedYMap, decodedUMap, decodedVMap); - context.measureNeighborEncode(x - halfStep, y - halfStep); - context.measureNeighborEncode(x + halfStep, y - halfStep); - context.measureNeighborEncode(x - halfStep, y + halfStep); - context.measureNeighborEncode(x + halfStep, y + halfStep); + final Color color = new Color(); + color.y = ImageEncoder.byteToInt(decodedYMap[0]); + color.u = ImageEncoder.byteToInt(decodedUMap[0]); + color.v = ImageEncoder.byteToInt(decodedVMap[0]); - loadPixel(step, offsetX, offsetY, x, y, pixels, - context.colorStats.getAverageY(), - context.colorStats.getAverageU(), - context.colorStats.getAverageV()); + color.YUV2RGB(); - } - } + pixels[0] = (byte) color.r; + pixels[0 + 1] = (byte) color.g; + pixels[0 + 2] = (byte) color.b; - public void gridSquare(final int offsetX, final int offsetY, - final int step, final byte[] pixels) throws IOException { + // detect initial step + int largestDimension; + int initialStep = 2; + if (width > height) + largestDimension = width; + else + largestDimension = height; + + while (initialStep < largestDimension) + initialStep = initialStep * 2; - for (int y = offsetY; y < height; y = y + step) - for (int x = offsetX; x < width; x = x + step) { + grid(initialStep, pixels); + } + + private void grid(final int step, final byte[] pixels) throws IOException { + + gridDiagonal(step / 2, step / 2, step, pixels); + gridSquare(step / 2, 0, step, pixels); + gridSquare(0, step / 2, step, pixels); - final int halfStep = step / 2; - - context.initialize(image, decodedYMap, decodedUMap, decodedVMap); - context.measureNeighborEncode(x - halfStep, y); - context.measureNeighborEncode(x + halfStep, y); - context.measureNeighborEncode(x, y - halfStep); - context.measureNeighborEncode(x, y + halfStep); - - loadPixel(step, offsetX, offsetY, x, y, pixels, - context.colorStats.getAverageY(), - context.colorStats.getAverageU(), - context.colorStats.getAverageV()); - - } - } - - private int loadChannel(final byte[] decodedRangeMap, - final byte[] decodedMap, final Table table, - final int averageDecodedValue, final int index, - final int parentIndex) throws IOException { - int decodedValue = averageDecodedValue; - - final int inheritedRange = ImageEncoder - .byteToInt(decodedRangeMap[parentIndex]); - int computedRange = inheritedRange; - - final int bitCount = table.proposeBitcountForRange(inheritedRange); - int computedRangeBitCount = 0; - if (bitCount > 0) { - - final int rangeDecreases = bitInputStream.readBits(1); - if (rangeDecreases != 0) - computedRange = table.proposeDecreasedRange(inheritedRange); - - decodedRangeMap[index] = (byte) computedRange; - computedRangeBitCount = table - .proposeBitcountForRange(computedRange); - - if (computedRangeBitCount > 0) { - - final int encodedDifference = bitInputStream - .readBits(computedRangeBitCount); - - final int decodedDifference = ImageEncoder - .decodeValueFromGivenBits(encodedDifference, - computedRange, computedRangeBitCount); - - decodedValue = averageDecodedValue - decodedDifference; - if (decodedValue > 255) - decodedValue = 255; - if (decodedValue < 0) - decodedValue = 0; - } - } else - decodedRangeMap[index] = (byte) inheritedRange; - decodedMap[index] = (byte) decodedValue; - return decodedValue; - } + if (step > 2) + grid(step / 2, pixels); + } + + private void gridDiagonal(final int offsetX, final int offsetY, + final int step, final byte[] pixels) throws IOException { + + for (int y = offsetY; y < height; y = y + step) + for (int x = offsetX; x < width; x = x + step) { + + final int halfStep = step / 2; + + context.initialize(image, decodedYMap, decodedUMap, decodedVMap); + context.measureNeighborEncode(x - halfStep, y - halfStep); + context.measureNeighborEncode(x + halfStep, y - halfStep); + context.measureNeighborEncode(x - halfStep, y + halfStep); + context.measureNeighborEncode(x + halfStep, y + halfStep); + + loadPixel(step, offsetX, offsetY, x, y, pixels, + context.colorStats.getAverageY(), + context.colorStats.getAverageU(), + context.colorStats.getAverageV()); + + } + } + + private void gridSquare(final int offsetX, final int offsetY, + final int step, final byte[] pixels) throws IOException { + + for (int y = offsetY; y < height; y = y + step) + for (int x = offsetX; x < width; x = x + step) { + + final int halfStep = step / 2; + + context.initialize(image, decodedYMap, decodedUMap, decodedVMap); + context.measureNeighborEncode(x - halfStep, y); + context.measureNeighborEncode(x + halfStep, y); + context.measureNeighborEncode(x, y - halfStep); + context.measureNeighborEncode(x, y + halfStep); + + loadPixel(step, offsetX, offsetY, x, y, pixels, + context.colorStats.getAverageY(), + context.colorStats.getAverageU(), + context.colorStats.getAverageV()); + + } + } + + private int loadChannel(final byte[] decodedRangeMap, + final byte[] decodedMap, final Table table, + final int averageDecodedValue, final int index, + final int parentIndex) throws IOException { + int decodedValue = averageDecodedValue; + + final int inheritedRange = ImageEncoder + .byteToInt(decodedRangeMap[parentIndex]); + int computedRange = inheritedRange; + + final int bitCount = table.proposeBitcountForRange(inheritedRange); + int computedRangeBitCount; + if (bitCount > 0) { + + final int rangeDecreases = bitInputStream.readBits(1); + if (rangeDecreases != 0) + computedRange = table.proposeDecreasedRange(inheritedRange); + + decodedRangeMap[index] = (byte) computedRange; + computedRangeBitCount = table + .proposeBitcountForRange(computedRange); + + if (computedRangeBitCount > 0) { + + final int encodedDifference = bitInputStream + .readBits(computedRangeBitCount); + + final int decodedDifference = ImageEncoder + .decodeValueFromGivenBits(encodedDifference, + computedRange, computedRangeBitCount); + + decodedValue = averageDecodedValue - decodedDifference; + if (decodedValue > 255) + decodedValue = 255; + if (decodedValue < 0) + decodedValue = 0; + } + } else + decodedRangeMap[index] = (byte) inheritedRange; + decodedMap[index] = (byte) decodedValue; + return decodedValue; + } - public void loadPixel(final int step, final int offsetX, final int offsetY, - final int x, final int y, final byte[] pixels, - final int averageDecodedY, final int averageDecodedU, - final int averageDecodedV) throws IOException { - - final int index = (y * width) + x; - - final int halfStep = step / 2; - - int parentIndex; - if (offsetX > 0) { - if (offsetY > 0) - // diagonal approach - parentIndex = ((y - halfStep) * width) + (x - halfStep); - else - // take left pixel - parentIndex = (y * width) + (x - halfStep); - } else - // take upper pixel - parentIndex = ((y - halfStep) * width) + x; - - final int colorBufferIndex = index * 3; - - final Color color = new Color(); - color.y = loadChannel(decodedYRangeMap, decodedYMap, - approximator.yTable, averageDecodedY, index, parentIndex); - color.u = loadChannel(decodedURangeMap, decodedUMap, - approximator.uTable, averageDecodedU, index, parentIndex); - color.v = loadChannel(decodedVRangeMap, decodedVMap, - approximator.vTable, averageDecodedV, index, parentIndex); - - color.YUV2RGB(); - - pixels[colorBufferIndex] = (byte) color.r; - pixels[colorBufferIndex + 1] = (byte) color.g; - pixels[colorBufferIndex + 2] = (byte) color.b; - - } + private void loadPixel(final int step, final int offsetX, final int offsetY, + final int x, final int y, final byte[] pixels, + final int averageDecodedY, final int averageDecodedU, + final int averageDecodedV) throws IOException { + + final int index = (y * width) + x; + + final int halfStep = step / 2; + + int parentIndex; + if (offsetX > 0) { + if (offsetY > 0) + // diagonal approach + parentIndex = ((y - halfStep) * width) + (x - halfStep); + else + // take left pixel + parentIndex = (y * width) + (x - halfStep); + } else + // take upper pixel + parentIndex = ((y - halfStep) * width) + x; + + final int colorBufferIndex = index * 3; + + final Color color = new Color(); + color.y = loadChannel(decodedYRangeMap, decodedYMap, + approximator.yTable, averageDecodedY, index, parentIndex); + color.u = loadChannel(decodedURangeMap, decodedUMap, + approximator.uTable, averageDecodedU, index, parentIndex); + color.v = loadChannel(decodedVRangeMap, decodedVMap, + approximator.vTable, averageDecodedV, index, parentIndex); + + color.YUV2RGB(); + + pixels[colorBufferIndex] = (byte) color.r; + pixels[colorBufferIndex + 1] = (byte) color.g; + pixels[colorBufferIndex + 2] = (byte) color.b; + + } }