4e714f4c8743b521caaf617058b3909d2c91e2de
[imagesqueeze.git] / src / main / java / eu / svjatoslav / imagesqueeze / codec / Table.java
1 package eu.svjatoslav.imagesqueeze.codec;
2
3 import java.io.IOException;
4
5 /**
6  * Quick lookup table.
7  */
8
9 public class Table implements Comparable<Table>{
10
11         int [] range = new int[100];    
12         int [] switchTreshold = new int[100];
13         int [] bitcount = new int[100];
14
15
16         int [] bitCountForRange = new int[256];
17         int [] proposedRangeForActualRange = new int[256];
18         int [] proposedRangeForActualRangeLow = new int[256];
19         int [] proposedRangeForActualRangeHigh = new int[256];
20         byte [] proposedDecreasedRange = new byte[256];
21
22
23         int usedEntries = 0;
24
25
26         public void computeLookupTables(){
27                 int currentCheckPointer = 0;
28
29                 for (int i=0; i<256; i++){
30
31                         if (range[currentCheckPointer] == i){
32                                 currentCheckPointer++;
33                         }
34
35                         if (currentCheckPointer > 0){
36                                 bitCountForRange[i] = bitcount[currentCheckPointer-1];                          
37                         } else {
38                                 bitCountForRange[i] = 0;
39                         }
40
41                 }
42
43                 for (int i=0; i<256; i++){
44
45                         int seek;
46                         seekLoop:{
47                                 for (seek = 0; seek < usedEntries; seek ++){
48
49                                         if (switchTreshold[seek] >= i) break seekLoop;
50
51                                 }
52                         }
53
54                         proposedRangeForActualRange[i] = range[seek];           
55                         if (seek == 0){
56                                 proposedRangeForActualRangeLow[i] = 0;          
57                         } else {
58                                 proposedRangeForActualRangeLow[i] = switchTreshold[seek-1]+1;                                           
59                         }
60                         proposedRangeForActualRangeHigh[i] = switchTreshold[seek];                              
61                 }
62
63
64                 currentCheckPointer = usedEntries - 2;
65                 for (int i=255; i >= 0; i--){           
66                         if (range[currentCheckPointer] == i) currentCheckPointer--;
67
68                         if (currentCheckPointer < 0){
69                                 proposedDecreasedRange[i] = 0;
70                         } else {
71                                 proposedDecreasedRange[i] = (byte)(range[currentCheckPointer]);                         
72                         }
73                 }
74
75         }
76
77         /**
78          * @param switchTreshold - switch to this range when actual range in equal or below this treshold
79          */
80         public void addEntry(int range, int switchTreshold, int bitcount){
81                 if (range < 0) range = 0;
82                 if (range > 255) range = 255;
83
84                 if (switchTreshold < 0) switchTreshold = 0;
85                 if (switchTreshold > 255) switchTreshold = 255;
86
87                 if (bitcount < 0) bitcount = 0;
88                 if (bitcount > 8) bitcount = 8;
89
90                 
91                 this.range[usedEntries] = range;
92                 this.switchTreshold[usedEntries] = switchTreshold;
93                 this.bitcount[usedEntries] = bitcount;
94                 usedEntries++;
95         }
96
97
98         
99         
100         public int proposeRangeForRange(int actualRange, int inheritedRange){
101
102                 if (inheritedRange > 255) inheritedRange = 255;
103                 if (inheritedRange < 0) inheritedRange = 0;
104
105                 if (proposedRangeForActualRangeLow[inheritedRange] <= actualRange){
106                         return inheritedRange;
107                 }
108
109                 return proposeDecreasedRange(inheritedRange);
110         }
111
112
113         public int proposeDecreasedRange(int range){
114                 if (range > 255) range = 255;
115                 if (range < 0) range = 0;
116
117                 return ImageEncoder.byteToInt(proposedDecreasedRange[range]);
118         }
119
120
121         public int proposeBitcountForRange(int range){
122                 if (range > 255) range = 255;
123                 if (range < 0) range = 0;
124                 int proposal = bitCountForRange[range];
125                 return proposal;
126         }
127
128         /**
129          * Compares two tables.
130          * Ignores table initialization.
131          */
132         public int compareTo(Table o) {
133                 if (usedEntries < o.usedEntries) return -1;
134                 if (usedEntries > o.usedEntries) return 1;
135
136                 for (int i=0; i<usedEntries; i++){
137                         if (range[i] < o.range[i]) return -1;
138                         if (range[i] > o.range[i]) return 1;
139
140                         if (switchTreshold[i] < o.switchTreshold[i]) return -1;
141                         if (switchTreshold[i] > o.switchTreshold[i]) return 1;
142
143                         if (bitcount[i] < o.bitcount[i]) return -1;
144                         if (bitcount[i] > o.bitcount[i]) return 1;
145                 }
146
147                 return 0;
148         }
149
150         public void save(BitOutputStream outputStream) throws IOException {
151                 outputStream.storeIntegerCompressed8(usedEntries);
152
153                 for (int i=0; i < usedEntries; i++){
154                         outputStream.storeBits(this.range[i], 8);
155                         outputStream.storeBits(this.switchTreshold[i], 8);
156                         outputStream.storeBits(this.bitcount[i], 4);
157                 }
158         }
159         
160         public void reset(){
161                 range = new int[100];   
162                 switchTreshold = new int[100];
163                 bitcount = new int[100];
164
165
166                 bitCountForRange = new int[256];
167                 proposedRangeForActualRange = new int[256];
168                 proposedRangeForActualRangeLow = new int[256];
169                 proposedRangeForActualRangeHigh = new int[256];
170                 proposedDecreasedRange = new byte[256];
171
172                 usedEntries = 0;
173         }
174         
175         public void load(BitInputStream inputStream) throws IOException {
176                 reset();
177                 
178                 int availableEntries = inputStream.readIntegerCompressed8();
179                 
180                 for (int i=0; i < availableEntries; i++){
181                         addEntry(inputStream.readBits(8), inputStream.readBits(8), inputStream.readBits(4));                    
182                 }
183         }
184
185
186
187 }