minor fixes
[imagesqueeze.git] / src / main / java / eu / svjatoslav / imagesqueeze / codec / ImageDecoder.java
index 37f3c0e..78bf715 100755 (executable)
@@ -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;
+
+       }
+
 }