2 * Imagesqueeze - Image codec. Copyright ©2012-2019, Svjatoslav Agejenko, svjatoslav@svjatoslav.eu
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 3 of the GNU Lesser General Public License
6 * or later as published by the Free Software Foundation.
9 package eu.svjatoslav.imagesqueeze.codec;
11 import eu.svjatoslav.commons.data.BitInputStream;
12 import eu.svjatoslav.commons.data.BitOutputStream;
14 import java.io.IOException;
22 private int[] range = new int[100];
23 private int[] switchThreshold = new int[100];
24 private int[] bitCount = new int[100];
26 private int[] bitCountForRange = new int[256];
27 private int[] proposedRangeForActualRange = new int[256];
28 private int[] proposedRangeForActualRangeLow = new int[256];
29 private int[] proposedRangeForActualRangeHigh = new int[256];
30 private byte[] proposedDecreasedRange = new byte[256];
32 private int usedEntries = 0;
35 * @param switchThreshold - switch to this range when actual range in equal or below
38 public void addEntry(int range, int switchThreshold, int bitcount) {
44 if (switchThreshold < 0)
46 if (switchThreshold > 255)
47 switchThreshold = 255;
54 this.range[usedEntries] = range;
55 this.switchThreshold[usedEntries] = switchThreshold;
56 this.bitCount[usedEntries] = bitcount;
60 public void computeLookupTables() {
61 int currentCheckPointer = 0;
63 for (int i = 0; i < 256; i++) {
65 if (range[currentCheckPointer] == i)
66 currentCheckPointer++;
68 if (currentCheckPointer > 0)
69 bitCountForRange[i] = bitCount[currentCheckPointer - 1];
71 bitCountForRange[i] = 0;
75 for (int i = 0; i < 256; i++) {
80 for (seek = 0; seek < usedEntries; seek++)
81 if (switchThreshold[seek] >= i)
85 proposedRangeForActualRange[i] = range[seek];
87 proposedRangeForActualRangeLow[i] = 0;
89 proposedRangeForActualRangeLow[i] = switchThreshold[seek - 1] + 1;
90 proposedRangeForActualRangeHigh[i] = switchThreshold[seek];
93 currentCheckPointer = usedEntries - 2;
94 for (int i = 255; i >= 0; i--) {
95 if (range[currentCheckPointer] == i)
96 currentCheckPointer--;
98 if (currentCheckPointer < 0)
99 proposedDecreasedRange[i] = 0;
101 proposedDecreasedRange[i] = (byte) (range[currentCheckPointer]);
106 public void load(final BitInputStream inputStream) throws IOException {
109 final int availableEntries = ImageDecoder
110 .readIntegerCompressed8(inputStream);
112 for (int i = 0; i < availableEntries; i++)
113 addEntry(inputStream.readBits(8), inputStream.readBits(8),
114 inputStream.readBits(4));
117 public int proposeBitcountForRange(int range) {
122 return bitCountForRange[range];
125 public int proposeDecreasedRange(int range) {
131 return ImageEncoder.byteToInt(proposedDecreasedRange[range]);
134 public int proposeRangeForRange(final int actualRange, int inheritedRange) {
136 if (inheritedRange > 255)
137 inheritedRange = 255;
138 if (inheritedRange < 0)
141 if (proposedRangeForActualRangeLow[inheritedRange] <= actualRange)
142 return inheritedRange;
144 return proposeDecreasedRange(inheritedRange);
147 public void reset() {
148 range = new int[100];
149 switchThreshold = new int[100];
150 bitCount = new int[100];
152 bitCountForRange = new int[256];
153 proposedRangeForActualRange = new int[256];
154 proposedRangeForActualRangeLow = new int[256];
155 proposedRangeForActualRangeHigh = new int[256];
156 proposedDecreasedRange = new byte[256];
161 public void save(final BitOutputStream outputStream) throws IOException {
162 ImageEncoder.storeIntegerCompressed8(outputStream, usedEntries);
164 for (int i = 0; i < usedEntries; i++) {
165 outputStream.storeBits(range[i], 8);
166 outputStream.storeBits(switchThreshold[i], 8);
167 outputStream.storeBits(bitCount[i], 4);