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=78bf71515c3447dd2b77165cef6117802dc259fc;hp=37f3c0e4c6ac0f37081717fd485038f7ada83752;hb=be13f5e7ec2b5e610db95ab2950a35a4e64c9a71;hpb=c7d0b8e1723045c0df086d9214a35f54db47684c diff --git a/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java b/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java index 37f3c0e..78bf715 100755 --- a/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java +++ b/src/main/java/eu/svjatoslav/imagesqueeze/codec/ImageDecoder.java @@ -1,3 +1,12 @@ +/* + * Imagesqueeze - Image codec optimized for photos. + * Copyright (C) 2012, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + */ + package eu.svjatoslav.imagesqueeze.codec; /** @@ -8,77 +17,77 @@ import java.awt.image.DataBufferByte; import java.awt.image.WritableRaster; import java.io.IOException; +import eu.svjatoslav.commons.data.BitInputStream; + public class ImageDecoder { int width, height; Image image; - byte [] decodedYRangeMap; - byte [] decodedYMap; + byte[] decodedYRangeMap; + byte[] decodedYMap; - byte [] decodedURangeMap; - byte [] decodedUMap; + byte[] decodedURangeMap; + byte[] decodedUMap; - byte [] decodedVRangeMap; - byte [] decodedVMap; + byte[] decodedVRangeMap; + byte[] decodedVMap; Color tmpColor = new Color(); - + Approximator approximator; BitInputStream bitInputStream; - + ColorStats colorStats = new ColorStats(); OperatingContext context = new OperatingContext(); - - public ImageDecoder (Image image, BitInputStream bitInputStream) { + + public ImageDecoder(final Image image, final BitInputStream bitInputStream) { approximator = new Approximator(); - this.image = image; + this.image = image; this.bitInputStream = bitInputStream; width = image.metaData.width; height = image.metaData.height; decodedYRangeMap = new byte[width * height]; - decodedYRangeMap[0] = (byte)(255); + decodedYRangeMap[0] = (byte) (255); decodedYMap = new byte[width * height]; decodedURangeMap = new byte[width * height]; - decodedURangeMap[0] = (byte)(255); + decodedURangeMap[0] = (byte) (255); decodedUMap = new byte[width * height]; decodedVRangeMap = new byte[width * height]; - decodedVRangeMap[0] = (byte)(255); + decodedVRangeMap[0] = (byte) (255); decodedVMap = new byte[width * height]; } - public void decode() throws IOException { approximator.load(bitInputStream); approximator.computeLookupTables(); - - WritableRaster raster = image.bufferedImage.getRaster(); - DataBufferByte dbi = (DataBufferByte)raster.getDataBuffer(); - byte [] pixels = dbi.getData(); - - // load top-, left-most pixel. - decodedYMap[0] = (byte)bitInputStream.readBits(8); - decodedUMap[0] = (byte)bitInputStream.readBits(8); - decodedVMap[0] = (byte)bitInputStream.readBits(8); - - Color color = new Color(); + + final WritableRaster raster = image.bufferedImage.getRaster(); + final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer(); + final byte[] pixels = dbi.getData(); + + // load top-, left-most pixel. + decodedYMap[0] = (byte) bitInputStream.readBits(8); + decodedUMap[0] = (byte) bitInputStream.readBits(8); + decodedVMap[0] = (byte) bitInputStream.readBits(8); + + final Color color = new Color(); color.y = ImageEncoder.byteToInt(decodedYMap[0]); color.u = ImageEncoder.byteToInt(decodedUMap[0]); color.v = ImageEncoder.byteToInt(decodedVMap[0]); - + color.YUV2RGB(); - - pixels[0] = (byte)color.r; - pixels[0+1] = (byte)color.g; - pixels[0+2] = (byte)color.b; - + pixels[0] = (byte) color.r; + pixels[0 + 1] = (byte) color.g; + pixels[0 + 2] = (byte) color.b; + // detect initial step int largestDimension; int initialStep = 2; @@ -87,146 +96,157 @@ public class ImageDecoder { } else { largestDimension = height; } - - while (initialStep < largestDimension){ + + while (initialStep < largestDimension) { initialStep = initialStep * 2; } grid(initialStep, pixels); } - - public void grid(int step, byte [] pixels) throws IOException { + 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); - if (step > 2) grid(step / 2, pixels); - } - - - public void gridSquare(int offsetX, int offsetY, int step, byte [] pixels) throws IOException{ - - for (int y = offsetY; y < height; y = y + step){ - for (int x = offsetX; x < width; x = x + step){ - - - 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()); - - } - } + if (step > 2) { + grid(step / 2, pixels); + } } + public void gridDiagonal(final int offsetX, final int offsetY, + final int step, final byte[] pixels) throws IOException { - public void gridDiagonal(int offsetX, int offsetY, int step, byte [] pixels) throws IOException{ + for (int y = offsetY; y < height; y = y + step) { + for (int x = offsetX; x < width; x = x + step) { - for (int y = offsetY; y < height; y = y + step){ - for (int x = offsetX; x < width; x = x + step){ - - int halfStep = step / 2; + 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, + + loadPixel(step, offsetX, offsetY, x, y, pixels, context.colorStats.getAverageY(), context.colorStats.getAverageU(), context.colorStats.getAverageV()); - } - } + } + } } + public void gridSquare(final int offsetX, final int offsetY, + final int step, final byte[] pixels) throws IOException { - public void loadPixel(int step, int offsetX, int offsetY, int x, int y, byte[] pixels, - int averageDecodedY, int averageDecodedU, int averageDecodedV) - throws IOException{ - - int index = (y * width) + x; + for (int y = offsetY; y < height; y = y + step) { + for (int x = offsetX; x < width; x = x + step) { - int halfStep = step / 2; + 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; - } - - - - int colorBufferIndex = index * 3; + 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); - 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; + loadPixel(step, offsetX, offsetY, x, y, pixels, + context.colorStats.getAverageY(), + context.colorStats.getAverageU(), + context.colorStats.getAverageV()); + } + } } - - private int loadChannel(byte [] decodedRangeMap, byte [] decodedMap, Table table, int averageDecodedValue, int index, - int parentIndex) throws IOException { + 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; - int inheritedRange = ImageEncoder.byteToInt(decodedRangeMap[parentIndex]); + final int inheritedRange = ImageEncoder + .byteToInt(decodedRangeMap[parentIndex]); int computedRange = inheritedRange; - int bitCount = table.proposeBitcountForRange(inheritedRange); + final int bitCount = table.proposeBitcountForRange(inheritedRange); int computedRangeBitCount = 0; - if ( bitCount > 0){ + if (bitCount > 0) { - int rangeDecreases = bitInputStream.readBits(1); - if (rangeDecreases != 0){ + final int rangeDecreases = bitInputStream.readBits(1); + if (rangeDecreases != 0) { computedRange = table.proposeDecreasedRange(inheritedRange); - } + } - decodedRangeMap[index] = (byte)computedRange; - computedRangeBitCount = table.proposeBitcountForRange(computedRange); + decodedRangeMap[index] = (byte) computedRange; + computedRangeBitCount = table + .proposeBitcountForRange(computedRange); - if (computedRangeBitCount > 0){ + if (computedRangeBitCount > 0) { - int encodedDifference = bitInputStream.readBits(computedRangeBitCount); + final int encodedDifference = bitInputStream + .readBits(computedRangeBitCount); - int decodedDifference = ImageEncoder.decodeValueFromGivenBits(encodedDifference, computedRange, computedRangeBitCount); + final int decodedDifference = ImageEncoder + .decodeValueFromGivenBits(encodedDifference, + computedRange, computedRangeBitCount); decodedValue = averageDecodedValue - decodedDifference; - if (decodedValue > 255) decodedValue = 255; - if (decodedValue < 0) decodedValue = 0; + if (decodedValue > 255) { + decodedValue = 255; + } + if (decodedValue < 0) { + decodedValue = 0; + } } } else { - decodedRangeMap[index] = (byte)inheritedRange; + decodedRangeMap[index] = (byte) inheritedRange; } - decodedMap[index] = (byte)decodedValue; + 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; + + } + }