1 package nom.tam.fits.compression.algorithm.plio;
2
3 import java.nio.ByteBuffer;
4 import java.nio.IntBuffer;
5 import java.nio.ShortBuffer;
6
7 import nom.tam.fits.compression.algorithm.api.ICompressor;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 @SuppressWarnings("javadoc")
51 public abstract class PLIOCompress {
52
53 public static class BytePLIOCompressor extends PLIOCompress implements ICompressor<ByteBuffer> {
54
55 private ByteBuffer pixelData;
56
57 @Override
58 public boolean compress(ByteBuffer buffer, ByteBuffer compressed) {
59 pixelData = buffer;
60 compress(compressed.asShortBuffer(), pixelData.limit());
61 return true;
62 }
63
64 @Override
65 public void decompress(ByteBuffer compressed, ByteBuffer buffer) {
66 pixelData = buffer;
67 decompress(compressed.asShortBuffer(), pixelData.limit());
68 }
69
70 @Override
71 protected int nextPixel() {
72 return pixelData.get();
73 }
74
75 @Override
76 protected void put(int index, int pixel) {
77 pixelData.put(index, (byte) pixel);
78 }
79 }
80
81 public static class ShortPLIOCompressor extends PLIOCompress implements ICompressor<ShortBuffer> {
82
83 private ShortBuffer pixelData;
84
85 @Override
86 public boolean compress(ShortBuffer buffer, ByteBuffer compressed) {
87 pixelData = buffer;
88 super.compress(compressed.asShortBuffer(), pixelData.limit());
89 return true;
90 }
91
92 @Override
93 public void decompress(ByteBuffer compressed, ShortBuffer buffer) {
94 pixelData = buffer;
95 decompress(compressed.asShortBuffer(), pixelData.limit());
96 }
97
98 @Override
99 protected int nextPixel() {
100 return pixelData.get();
101 }
102
103 @Override
104 protected void put(int index, int pixel) {
105 pixelData.put(index, (short) pixel);
106 }
107 }
108
109
110
111
112 public static class IntPLIOCompressor extends PLIOCompress implements ICompressor<IntBuffer> {
113
114 private IntBuffer pixelData;
115
116 @Override
117 public boolean compress(IntBuffer buffer, ByteBuffer compressed) {
118 pixelData = buffer;
119 super.compress(compressed.asShortBuffer(), pixelData.limit());
120 return true;
121 }
122
123 @Override
124 public void decompress(ByteBuffer compressed, IntBuffer buffer) {
125 pixelData = buffer;
126 decompress(compressed.asShortBuffer(), pixelData.limit());
127 }
128
129 @Override
130 protected int nextPixel() {
131 return pixelData.get();
132 }
133
134 @Override
135 protected void put(int index, int pixel) {
136 pixelData.put(index, (short) pixel);
137 }
138 }
139
140 private static final int FIRST_VALUE_WITH_13_BIT = 4096;
141
142 private static final int FIRST_VALUE_WITH_14_BIT = 8192;
143
144 private static final int FIRST_VALUE_WITH_15_BIT = 16384;
145
146 private static final int FIRST_VALUE_WITH_16_BIT = 32768;
147
148 private static final int HEADER_SIZE_FIELD1 = 3;
149
150 private static final int HEADER_SIZE_FIELD2 = 4;
151
152 private static final int LAST_VALUE_FITTING_IN_12_BIT = FIRST_VALUE_WITH_13_BIT - 1;
153
154 private static final int MINI_HEADER_SIZE = 3;
155
156 private static final int MINI_HEADER_SIZE_FIELD = 2;
157
158
159
160
161 private static final int N20481 = 20481;
162
163 private static final int OPCODE_1 = 1;
164
165 private static final int OPCODE_2 = 2;
166
167 private static final int OPCODE_3 = 3;
168
169 private static final int OPCODE_4 = 4;
170
171 private static final int OPCODE_5 = 5;
172
173 private static final int OPCODE_6 = 6;
174
175 private static final int OPCODE_7 = 7;
176
177 private static final int OPCODE_8 = 8;
178
179 private static final short[] PLIO_HEADER = {(short) 0, (short) 7, (short) -100, (short) 0, (short) 0, (short) 0,
180 (short) 0};
181
182 private static final int SHIFT_12_BITS = 12;
183
184 private static final int SHIFT_15_BITS = 15;
185
186 private static final int VALUE_OF_BIT_13_AND14_ON = 12288;
187
188
189
190
191
192
193
194
195 protected void compress(ShortBuffer compressedData, int npix) {
196 compressedData.put(PLIO_HEADER);
197 final int xe = npix - 1;
198 int op = PLIO_HEADER.length;
199
200 int pv = Math.max(0, nextPixel());
201 int x1 = 0;
202 int iz = 0;
203 int hi = 1;
204 int nv = 0;
205 for (int ip = 0; ip <= xe; ++ip) {
206 if (ip < xe) {
207
208 nv = Math.max(0, nextPixel());
209 if (nv == pv) {
210 continue;
211 }
212 if (pv == 0) {
213 pv = nv;
214 x1 = ip + 1;
215 continue;
216 }
217 } else if (pv == 0) {
218 x1 = xe + 1;
219 }
220
221 int np = ip - x1 + 1;
222 int nz = x1 - iz;
223 boolean skip = false;
224 if (pv > 0) {
225 int dv = pv - hi;
226 if (dv != 0) {
227 hi = pv;
228 if (Math.abs(dv) > LAST_VALUE_FITTING_IN_12_BIT) {
229 compressedData.put(op, (short) ((pv & LAST_VALUE_FITTING_IN_12_BIT) + FIRST_VALUE_WITH_13_BIT));
230 ++op;
231 compressedData.put(op, (short) (pv / FIRST_VALUE_WITH_13_BIT));
232 ++op;
233 } else {
234 if (dv < 0) {
235 compressedData.put(op, (short) (-dv + VALUE_OF_BIT_13_AND14_ON));
236 } else {
237 compressedData.put(op, (short) (dv + FIRST_VALUE_WITH_14_BIT));
238 }
239 ++op;
240 if (np == 1 && nz == 0) {
241 int v = compressedData.get(op - 1);
242 compressedData.put(op - 1, (short) (v | FIRST_VALUE_WITH_15_BIT));
243 skip = true;
244 }
245 }
246 }
247 }
248 if (!skip) {
249 if (nz > 0) {
250 while (nz > 0) {
251 compressedData.put(op, (short) Math.min(LAST_VALUE_FITTING_IN_12_BIT, nz));
252 ++op;
253 nz += -LAST_VALUE_FITTING_IN_12_BIT;
254 }
255 if (np == 1 && pv > 0) {
256 compressedData.put(op - 1, (short) (compressedData.get(op - 1) + N20481));
257 skip = true;
258 }
259 }
260 }
261 if (!skip) {
262 while (np > 0) {
263 compressedData.put(op, (short) (Math.min(LAST_VALUE_FITTING_IN_12_BIT, np) + FIRST_VALUE_WITH_15_BIT));
264 ++op;
265 np += -LAST_VALUE_FITTING_IN_12_BIT;
266 }
267 }
268 x1 = ip + 1;
269 iz = x1;
270 pv = nv;
271 }
272 compressedData.put(HEADER_SIZE_FIELD1, (short) (op % FIRST_VALUE_WITH_16_BIT));
273 compressedData.put(HEADER_SIZE_FIELD2, (short) (op / FIRST_VALUE_WITH_16_BIT));
274 compressedData.position(op);
275 }
276
277
278
279
280
281
282
283
284
285
286 protected int decompress(ShortBuffer compressedData, int npix) {
287 int llfirt;
288 int lllen;
289 if (!(compressedData.get(2) > 0)) {
290 lllen = (compressedData.get(HEADER_SIZE_FIELD2) << SHIFT_15_BITS) + compressedData.get(HEADER_SIZE_FIELD1);
291 llfirt = compressedData.get(1);
292 } else {
293 lllen = compressedData.get(MINI_HEADER_SIZE_FIELD);
294 llfirt = MINI_HEADER_SIZE;
295 }
296 final int xe = npix;
297 int op = 0;
298 int x1 = 1;
299 int pv = 1;
300 for (int ip = llfirt; ip <= lllen; ++ip) {
301 final int opcode = compressedData.get(ip) / FIRST_VALUE_WITH_13_BIT;
302 final int data = compressedData.get(ip) & LAST_VALUE_FITTING_IN_12_BIT;
303 final int sw0001 = opcode + 1;
304 if (sw0001 == OPCODE_1 || sw0001 == OPCODE_5 || sw0001 == OPCODE_6) {
305 final int x2 = x1 + data - 1;
306 final int i2 = Math.min(x2, xe);
307 final int np = i2 - Math.max(x1, 0) + 1;
308 if (np > 0) {
309 final int otop = op + np - 1;
310 if (!(opcode == OPCODE_4)) {
311 for (int index = op; index <= otop; ++index) {
312 put(index, 0);
313 }
314 if (opcode == OPCODE_5 && i2 == x2) {
315 put(otop, pv);
316 }
317 } else {
318 for (int index = op; index <= otop; ++index) {
319 put(index, pv);
320 }
321 }
322 op = otop + 1;
323 }
324 x1 = x2 + 1;
325 } else if (sw0001 == OPCODE_2) {
326 pv = (compressedData.get(ip + 1) << SHIFT_12_BITS) + data;
327 ++ip;
328 } else if (sw0001 == OPCODE_3) {
329 pv += data;
330 } else if (sw0001 == OPCODE_4) {
331 pv -= data;
332 } else if (sw0001 == OPCODE_7) {
333 pv += data;
334 if (x1 >= 0 && x1 <= xe) {
335 put(op, pv);
336 ++op;
337 }
338 ++x1;
339 } else if (sw0001 == OPCODE_8) {
340 pv -= data;
341 if (x1 >= 0 && x1 <= xe) {
342 put(op, pv);
343 ++op;
344 }
345 ++x1;
346 }
347 if (x1 > xe) {
348 break;
349 }
350 }
351 for (int index = op; index < npix; ++index) {
352 put(index, 0);
353 }
354 return npix;
355 }
356
357 protected abstract int nextPixel();
358
359 protected abstract void put(int index, int pixel);
360
361 }