moved compressed integer support out of svjatoslavcommons
[imagesqueeze.git] / src / main / java / eu / svjatoslav / imagesqueeze / codec / ImageEncoder.java
index 613064c..5b0e8db 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  * 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.
@@ -21,21 +21,114 @@ import eu.svjatoslav.commons.data.BitOutputStream;
 
 public class ImageEncoder {
 
+       public static int byteToInt(final byte input) {
+               int result = input;
+               if (result < 0)
+                       result = result + 256;
+               return result;
+       }
+
+       public static int decodeValueFromGivenBits(final int encodedBits,
+                       final int range, final int bitCount) {
+               final int negativeBit = encodedBits & 1;
+
+               final int remainingBitCount = bitCount - 1;
+
+               if (remainingBitCount == 0) {
+                       // no more bits remaining to encode actual value
+
+                       if (negativeBit == 0)
+                               return range;
+                       else
+                               return -range;
+
+               } else {
+                       // still one or more bits left, encode value as precisely as
+                       // possible
+
+                       final int encodedValue = (encodedBits >>> 1) + 1;
+
+                       final int realvalueForThisBitcount = 1 << remainingBitCount;
+
+                       // int valueMultiplier = range / realvalueForThisBitcount;
+                       int decodedValue = (range * encodedValue)
+                                       / realvalueForThisBitcount;
+
+                       if (decodedValue > range)
+                               decodedValue = range;
+
+                       if (negativeBit == 0)
+                               return decodedValue;
+                       else
+                               return -decodedValue;
+
+               }
+       }
+
+       public static int encodeValueIntoGivenBits(int value, final int range,
+                       final int bitCount) {
+
+               int negativeBit = 0;
+
+               if (value < 0) {
+                       negativeBit = 1;
+                       value = -value;
+               }
+
+               final int remainingBitCount = bitCount - 1;
+
+               if (remainingBitCount == 0)
+                       return negativeBit;
+               else {
+                       // still one or more bits left, encode value as precisely as
+                       // possible
+
+                       if (value > range)
+                               value = range;
+
+                       final int realvalueForThisBitcount = 1 << remainingBitCount;
+                       // int valueMultiplier = range / realvalueForThisBitcount;
+                       int encodedValue = (value * realvalueForThisBitcount) / range;
+
+                       if (encodedValue >= realvalueForThisBitcount)
+                               encodedValue = realvalueForThisBitcount - 1;
+
+                       encodedValue = (encodedValue << 1) + negativeBit;
+
+                       return encodedValue;
+               }
+       }
+
+       public static void storeIntegerCompressed8(
+                       final BitOutputStream outputStream, final int data)
+                       throws IOException {
+
+               if (data < 256) {
+                       outputStream.storeBits(0, 1);
+                       outputStream.storeBits(data, 8);
+               } else {
+                       outputStream.storeBits(1, 1);
+                       outputStream.storeBits(data, 32);
+               }
+       }
+
        Image image;
        int width, height;
 
        Channel yChannel;
+
        Channel uChannel;
        Channel vChannel;
-
        Approximator approximator;
 
        int bitsForY;
        int bitsForU;
+
        int bitsForV;
 
        // ColorStats colorStats = new ColorStats();
        OperatingContext context = new OperatingContext();
+
        OperatingContext context2 = new OperatingContext();
 
        BitOutputStream bitOutputStream;
@@ -64,28 +157,25 @@ public class ImageEncoder {
                final DataBufferByte dbi = (DataBufferByte) raster.getDataBuffer();
                final byte[] pixels = dbi.getData();
 
-               if (yChannel == null) {
+               if (yChannel == null)
                        yChannel = new Channel(width, height);
-               } else {
+               else
                        yChannel.reset();
-               }
 
-               if (uChannel == null) {
+               if (uChannel == null)
                        uChannel = new Channel(width, height);
-               } else {
+               else
                        uChannel.reset();
-               }
 
-               if (vChannel == null) {
+               if (vChannel == null)
                        vChannel = new Channel(width, height);
-               } else {
+               else
                        vChannel.reset();
-               }
 
                // create YUV map out of RGB raster data
                final Color color = new Color();
 
-               for (int y = 0; y < height; y++) {
+               for (int y = 0; y < height; y++)
                        for (int x = 0; x < width; x++) {
 
                                final int index = (y * width) + x;
@@ -113,7 +203,6 @@ public class ImageEncoder {
                                uChannel.map[index] = (byte) color.u;
                                vChannel.map[index] = (byte) color.v;
                        }
-               }
 
                yChannel.decodedMap[0] = yChannel.map[0];
                uChannel.decodedMap[0] = uChannel.map[0];
@@ -126,15 +215,13 @@ public class ImageEncoder {
                // detect initial step
                int largestDimension;
                int initialStep = 2;
-               if (width > height) {
+               if (width > height)
                        largestDimension = width;
-               } else {
+               else
                        largestDimension = height;
-               }
 
-               while (initialStep < largestDimension) {
+               while (initialStep < largestDimension)
                        initialStep = initialStep * 2;
-               }
 
                rangeGrid(initialStep);
                rangeRoundGrid(2);
@@ -159,13 +246,12 @@ public class ImageEncoder {
                        decodedRangeMap[index] = (byte) computedRange;
 
                        channel.bitCount++;
-                       if (computedRange != inheritedRange) {
+                       if (computedRange != inheritedRange)
                                // brightness range shrinked
                                bitOutputStream.storeBits(1, 1);
-                       } else {
+                       else
                                // brightness range stayed the same
                                bitOutputStream.storeBits(0, 1);
-                       }
 
                        // encode brightness into available amount of bits
                        final int computedBitCount = table
@@ -190,9 +276,8 @@ public class ImageEncoder {
                                        decodedValue = 0;
 
                                decodedMap[index] = (byte) decodedValue;
-                       } else {
+                       } else
                                decodedMap[index] = (byte) averageDecodedValue;
-                       }
 
                } else {
                        decodedRangeMap[index] = (byte) inheritedRange;
@@ -225,7 +310,7 @@ public class ImageEncoder {
 
        public void rangeGridDiagonal(final int offsetX, final int offsetY,
                        final int step) {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int index = (y * width) + x;
@@ -243,12 +328,11 @@ public class ImageEncoder {
                                uChannel.rangeMap[index] = (byte) context.getURange(index);
                                vChannel.rangeMap[index] = (byte) context.getVRange(index);
                        }
-               }
        }
 
        public void rangeGridSquare(final int offsetX, final int offsetY,
                        final int step) {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int index = (y * width) + x;
@@ -266,7 +350,6 @@ public class ImageEncoder {
                                uChannel.rangeMap[index] = (byte) context.getURange(index);
                                vChannel.rangeMap[index] = (byte) context.getVRange(index);
                        }
-               }
        }
 
        public void rangeRoundGrid(final int step) {
@@ -281,7 +364,7 @@ public class ImageEncoder {
 
        public void rangeRoundGridDiagonal(final int offsetX, final int offsetY,
                        final int step) {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int index = (y * width) + x;
@@ -316,12 +399,11 @@ public class ImageEncoder {
                                        vChannel.rangeMap[parentIndex] = (byte) parentVRange;
                                }
                        }
-               }
        }
 
        public void rangeRoundGridSquare(final int offsetX, final int offsetY,
                        final int step) {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int index = (y * width) + x;
@@ -333,11 +415,10 @@ public class ImageEncoder {
                                final int halfStep = step / 2;
 
                                int parentIndex;
-                               if (offsetX > 0) {
+                               if (offsetX > 0)
                                        parentIndex = (y * width) + (x - halfStep);
-                               } else {
+                               else
                                        parentIndex = ((y - halfStep) * width) + x;
-                               }
 
                                int parentYRange = byteToInt(yChannel.rangeMap[parentIndex]);
 
@@ -361,7 +442,6 @@ public class ImageEncoder {
                                }
 
                        }
-               }
        }
 
        public void saveGrid(final int step) throws IOException {
@@ -376,7 +456,7 @@ public class ImageEncoder {
 
        public void saveGridDiagonal(final int offsetX, final int offsetY,
                        final int step) throws IOException {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int halfStep = step / 2;
@@ -394,12 +474,11 @@ public class ImageEncoder {
                                                context2.colorStats.getAverageV());
 
                        }
-               }
        }
 
        public void saveGridSquare(final int offsetX, final int offsetY,
                        final int step) throws IOException {
-               for (int y = offsetY; y < height; y = y + step) {
+               for (int y = offsetY; y < height; y = y + step)
                        for (int x = offsetX; x < width; x = x + step) {
 
                                final int halfStep = step / 2;
@@ -417,7 +496,6 @@ public class ImageEncoder {
                                                context2.colorStats.getAverageV());
 
                        }
-               }
        }
 
        public void savePixel(final int step, final int offsetX, final int offsetY,
@@ -439,17 +517,15 @@ public class ImageEncoder {
 
                int parentIndex;
                if (offsetX > 0) {
-                       if (offsetY > 0) {
+                       if (offsetY > 0)
                                // diagonal approach
                                parentIndex = ((y - halfStep) * width) + (x - halfStep);
-                       } else {
+                       else
                                // take left pixel
                                parentIndex = (y * width) + (x - halfStep);
-                       }
-               } else {
+               } else
                        // take upper pixel
                        parentIndex = ((y - halfStep) * width) + x;
-               }
 
                encodeChannel(approximator.yTable, yChannel, averageDecodedY, index,
                                py, yRange, parentIndex);
@@ -462,87 +538,4 @@ public class ImageEncoder {
 
        }
 
-       public static int byteToInt(final byte input) {
-               int result = input;
-               if (result < 0)
-                       result = result + 256;
-               return result;
-       }
-
-       public static int decodeValueFromGivenBits(final int encodedBits,
-                       final int range, final int bitCount) {
-               final int negativeBit = encodedBits & 1;
-
-               final int remainingBitCount = bitCount - 1;
-
-               if (remainingBitCount == 0) {
-                       // no more bits remaining to encode actual value
-
-                       if (negativeBit == 0) {
-                               return range;
-                       } else {
-                               return -range;
-                       }
-
-               } else {
-                       // still one or more bits left, encode value as precisely as
-                       // possible
-
-                       final int encodedValue = (encodedBits >>> 1) + 1;
-
-                       final int realvalueForThisBitcount = 1 << remainingBitCount;
-
-                       // int valueMultiplier = range / realvalueForThisBitcount;
-                       int decodedValue = (range * encodedValue)
-                                       / realvalueForThisBitcount;
-
-                       if (decodedValue > range)
-                               decodedValue = range;
-
-                       if (negativeBit == 0) {
-                               return decodedValue;
-                       } else {
-                               return -decodedValue;
-                       }
-
-               }
-       }
-
-       public static int encodeValueIntoGivenBits(int value, final int range,
-                       final int bitCount) {
-
-               int negativeBit = 0;
-
-               if (value < 0) {
-                       negativeBit = 1;
-                       value = -value;
-               }
-
-               final int remainingBitCount = bitCount - 1;
-
-               if (remainingBitCount == 0) {
-                       // no more bits remaining to encode actual value
-
-                       return negativeBit;
-
-               } else {
-                       // still one or more bits left, encode value as precisely as
-                       // possible
-
-                       if (value > range)
-                               value = range;
-
-                       final int realvalueForThisBitcount = 1 << remainingBitCount;
-                       // int valueMultiplier = range / realvalueForThisBitcount;
-                       int encodedValue = (value * realvalueForThisBitcount) / range;
-
-                       if (encodedValue >= realvalueForThisBitcount)
-                               encodedValue = realvalueForThisBitcount - 1;
-
-                       encodedValue = (encodedValue << 1) + negativeBit;
-
-                       return encodedValue;
-               }
-       }
-
 }