2 * Imagesqueeze - Image codec optimized for photos.
3 * Copyright (C) 2012, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU General Public License
7 * as published by the Free Software Foundation.
10 package eu.svjatoslav.imagesqueeze.codec;
12 import eu.svjatoslav.commons.data.BitInputStream;
13 import eu.svjatoslav.commons.data.BitOutputStream;
15 import java.io.IOException;
23 private int[] range = new int[100];
24 private int[] switchThreshold = new int[100];
25 private int[] bitCount = new int[100];
27 private int[] bitCountForRange = new int[256];
28 private int[] proposedRangeForActualRange = new int[256];
29 private int[] proposedRangeForActualRangeLow = new int[256];
30 private int[] proposedRangeForActualRangeHigh = new int[256];
31 private byte[] proposedDecreasedRange = new byte[256];
33 private int usedEntries = 0;
36 * @param switchThreshold - switch to this range when actual range in equal or below
39 public void addEntry(int range, int switchThreshold, int bitcount) {
45 if (switchThreshold < 0)
47 if (switchThreshold > 255)
48 switchThreshold = 255;
55 this.range[usedEntries] = range;
56 this.switchThreshold[usedEntries] = switchThreshold;
57 this.bitCount[usedEntries] = bitcount;
61 public void computeLookupTables() {
62 int currentCheckPointer = 0;
64 for (int i = 0; i < 256; i++) {
66 if (range[currentCheckPointer] == i)
67 currentCheckPointer++;
69 if (currentCheckPointer > 0)
70 bitCountForRange[i] = bitCount[currentCheckPointer - 1];
72 bitCountForRange[i] = 0;
76 for (int i = 0; i < 256; i++) {
81 for (seek = 0; seek < usedEntries; seek++)
82 if (switchThreshold[seek] >= i)
86 proposedRangeForActualRange[i] = range[seek];
88 proposedRangeForActualRangeLow[i] = 0;
90 proposedRangeForActualRangeLow[i] = switchThreshold[seek - 1] + 1;
91 proposedRangeForActualRangeHigh[i] = switchThreshold[seek];
94 currentCheckPointer = usedEntries - 2;
95 for (int i = 255; i >= 0; i--) {
96 if (range[currentCheckPointer] == i)
97 currentCheckPointer--;
99 if (currentCheckPointer < 0)
100 proposedDecreasedRange[i] = 0;
102 proposedDecreasedRange[i] = (byte) (range[currentCheckPointer]);
107 public void load(final BitInputStream inputStream) throws IOException {
110 final int availableEntries = ImageDecoder
111 .readIntegerCompressed8(inputStream);
113 for (int i = 0; i < availableEntries; i++)
114 addEntry(inputStream.readBits(8), inputStream.readBits(8),
115 inputStream.readBits(4));
118 public int proposeBitcountForRange(int range) {
123 return bitCountForRange[range];
126 public int proposeDecreasedRange(int range) {
132 return ImageEncoder.byteToInt(proposedDecreasedRange[range]);
135 public int proposeRangeForRange(final int actualRange, int inheritedRange) {
137 if (inheritedRange > 255)
138 inheritedRange = 255;
139 if (inheritedRange < 0)
142 if (proposedRangeForActualRangeLow[inheritedRange] <= actualRange)
143 return inheritedRange;
145 return proposeDecreasedRange(inheritedRange);
148 public void reset() {
149 range = new int[100];
150 switchThreshold = new int[100];
151 bitCount = new int[100];
153 bitCountForRange = new int[256];
154 proposedRangeForActualRange = new int[256];
155 proposedRangeForActualRangeLow = new int[256];
156 proposedRangeForActualRangeHigh = new int[256];
157 proposedDecreasedRange = new byte[256];
162 public void save(final BitOutputStream outputStream) throws IOException {
163 ImageEncoder.storeIntegerCompressed8(outputStream, usedEntries);
165 for (int i = 0; i < usedEntries; i++) {
166 outputStream.storeBits(range[i], 8);
167 outputStream.storeBits(switchThreshold[i], 8);
168 outputStream.storeBits(bitCount[i], 4);