1 package nom.tam.fits.compression.algorithm.rice;
2
3 import java.nio.Buffer;
4 import java.nio.ByteBuffer;
5 import java.nio.IntBuffer;
6 import java.nio.ShortBuffer;
7 import java.util.logging.Logger;
8
9 import nom.tam.fits.compression.algorithm.api.ICompressor;
10 import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.DoubleQuantCompressor;
11 import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.FloatQuantCompressor;
12 import nom.tam.util.FitsIO;
13 import nom.tam.util.type.ElementType;
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
51
52
53
54
55
56
57
58
59 @SuppressWarnings({"deprecation", "javadoc"})
60 public abstract class RiceCompressor<T extends Buffer> implements ICompressor<T> {
61
62 public static class ByteRiceCompressor extends RiceCompressor<ByteBuffer> {
63
64 private ByteBuffer pixelBuffer;
65
66
67
68
69
70
71 public ByteRiceCompressor() {
72 this(new RiceCompressOption());
73 }
74
75 public ByteRiceCompressor(RiceCompressOption option) {
76 super(option);
77 }
78
79 @Override
80 public boolean compress(ByteBuffer buffer, ByteBuffer writeBuffer) {
81 pixelBuffer = buffer;
82 super.compress(buffer.limit(), pixelBuffer.get(pixelBuffer.position()), new BitBuffer(writeBuffer));
83 return true;
84 }
85
86 @Override
87 public void decompress(ByteBuffer readBuffer, ByteBuffer buffer) {
88 pixelBuffer = buffer;
89 super.decompressBuffer(readBuffer, buffer.limit());
90 }
91
92 @Override
93 protected int nextPixel() {
94 return pixelBuffer.get();
95 }
96
97 @Override
98 protected void nextPixel(int pixel) {
99 pixelBuffer.put((byte) pixel);
100 }
101 }
102
103 public static class DoubleRiceCompressor extends DoubleQuantCompressor {
104
105 public DoubleRiceCompressor(RiceQuantizeCompressOption options) throws ClassCastException {
106 super(options, new IntRiceCompressor((RiceCompressOption) options.getCompressOption()));
107 }
108 }
109
110 public static class FloatRiceCompressor extends FloatQuantCompressor {
111
112 public FloatRiceCompressor(RiceQuantizeCompressOption options) throws ClassCastException {
113 super(options, new IntRiceCompressor((RiceCompressOption) options.getCompressOption()));
114 }
115 }
116
117 public static class IntRiceCompressor extends RiceCompressor<IntBuffer> {
118
119 private IntBuffer pixelBuffer;
120
121
122
123
124
125
126 public IntRiceCompressor() {
127 this(new RiceCompressOption());
128 }
129
130 public IntRiceCompressor(RiceCompressOption option) {
131 super(option);
132 }
133
134 @Override
135 public boolean compress(IntBuffer buffer, ByteBuffer writeBuffer) {
136 pixelBuffer = buffer;
137 super.compress(buffer.limit(), pixelBuffer.get(pixelBuffer.position()), new BitBuffer(writeBuffer));
138 return true;
139 }
140
141 @Override
142 public void decompress(ByteBuffer readBuffer, IntBuffer buffer) {
143 pixelBuffer = buffer;
144 super.decompressBuffer(readBuffer, buffer.limit());
145 }
146
147 @Override
148 protected int nextPixel() {
149 return pixelBuffer.get();
150 }
151
152 @Override
153 protected void nextPixel(int pixel) {
154 pixelBuffer.put(pixel);
155 }
156 }
157
158 public static class ShortRiceCompressor extends RiceCompressor<ShortBuffer> {
159
160 private ShortBuffer pixelBuffer;
161
162
163
164
165
166
167 public ShortRiceCompressor() {
168 this(new RiceCompressOption());
169 }
170
171 public ShortRiceCompressor(RiceCompressOption option) {
172 super(option);
173 }
174
175 @Override
176 public boolean compress(ShortBuffer buffer, ByteBuffer writeBuffer) {
177 pixelBuffer = buffer;
178 super.compress(buffer.limit(), pixelBuffer.get(pixelBuffer.position()), new BitBuffer(writeBuffer));
179 return true;
180 }
181
182 @Override
183 public void decompress(ByteBuffer readBuffer, ShortBuffer buffer) {
184 pixelBuffer = buffer;
185 super.decompressBuffer(readBuffer, buffer.limit());
186 }
187
188 @Override
189 protected int nextPixel() {
190 return pixelBuffer.get();
191 }
192
193 @Override
194 protected void nextPixel(int pixel) {
195 pixelBuffer.put((short) pixel);
196 }
197 }
198
199
200
201
202 private static final long UNSIGNED_BYTE_MASK = 0xFFL;
203
204
205
206
207 private static final long UNSIGNED_SHORT_MASK = 0xFFFFL;
208
209
210
211
212 private static final long UNSIGNED_INTEGER_MASK = 0xFFFFFFFFL;
213
214
215
216
217 private static final Logger LOG = Logger.getLogger(RiceCompressor.class.getName());
218
219 private static final int BITS_OF_1_BYTE = 8;
220
221 private static final int BITS_PER_BYTE = 8;
222
223 private static final int BYTE_MASK = 0xff;
224
225 private static final int FS_BITS_FOR_BYTE = 3;
226
227 private static final int FS_BITS_FOR_INT = 5;
228
229 private static final int FS_BITS_FOR_SHORT = 4;
230
231 private static final int FS_MAX_FOR_BYTE = 6;
232
233 private static final int FS_MAX_FOR_INT = 25;
234
235 private static final int FS_MAX_FOR_SHORT = 14;
236
237
238
239
240
241
242
243 private static final int[] NONZERO_COUNT = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
244 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
245 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
246 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
247 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
248 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
249 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
250 8, 8, 8, 8, 8, 8, 8, 8, 8};
251
252
253 private final int bBits;
254
255 private final int bitsPerPixel;
256
257 private final int blockSize;
258
259 private final int fsBits;
260
261 private final int fsMax;
262
263 private RiceCompressor(RiceCompressOption option) throws UnsupportedOperationException {
264 blockSize = option.getBlockSize();
265 if (option.getBytePix() == ElementType.BYTE.size()) {
266 fsBits = FS_BITS_FOR_BYTE;
267 fsMax = FS_MAX_FOR_BYTE;
268 bitsPerPixel = FitsIO.BITS_OF_1_BYTE;
269 } else if (option.getBytePix() == ElementType.SHORT.size()) {
270 fsBits = FS_BITS_FOR_SHORT;
271 fsMax = FS_MAX_FOR_SHORT;
272 bitsPerPixel = FitsIO.BITS_OF_2_BYTES;
273 } else if (option.getBytePix() == ElementType.INT.size()) {
274 fsBits = FS_BITS_FOR_INT;
275 fsMax = FS_MAX_FOR_INT;
276 bitsPerPixel = FitsIO.BITS_OF_4_BYTES;
277 } else {
278 throw new UnsupportedOperationException("Implemented for 1/2/4 bytes only");
279 }
280
281
282
283
284 bBits = 1 << fsBits;
285 }
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301 private long undoMappingAndDifferencing(long lastpix, long diff) {
302 diff &= UNSIGNED_INTEGER_MASK;
303 if ((diff & 1) == 0) {
304 diff = diff >>> 1;
305 } else {
306 diff = diff >>> 1 ^ UNSIGNED_INTEGER_MASK;
307 }
308 lastpix = diff + lastpix & UNSIGNED_INTEGER_MASK;
309 nextPixel((int) lastpix);
310 return lastpix;
311 }
312
313
314
315
316
317
318
319
320 protected void compress(final int dataLength, int firstPixel, BitBuffer buffer) {
321
322 int lastpix = firstPixel;
323
324 buffer.putInt(firstPixel, bitsPerPixel);
325 int thisblock = blockSize;
326 for (int i = 0; i < dataLength; i += blockSize) {
327
328 if (dataLength - i < blockSize) {
329 thisblock = dataLength - i;
330 }
331
332
333
334
335
336
337
338 long[] diff = new long[blockSize];
339 double pixelsum = 0.0;
340 int nextpix;
341
342
343
344 for (int j = 0; j < thisblock; j++) {
345 nextpix = nextPixel();
346 long pdiff = (nextpix - lastpix);
347 diff[j] = (pdiff < 0 ? (pdiff << 1) ^ UNSIGNED_INTEGER_MASK : pdiff << 1) & UNSIGNED_INTEGER_MASK;
348 pixelsum += diff[j];
349 lastpix = nextpix;
350 }
351
352
353
354
355 double dpsum = (pixelsum - thisblock / 2d - 1d) / thisblock;
356 if (dpsum < 0) {
357 dpsum = 0.0;
358 }
359 long psum = (long) dpsum >> 1;
360 int fs;
361 for (fs = 0; psum > 0; fs++) {
362 psum >>= 1;
363 }
364
365
366
367
368 if (fs >= fsMax) {
369
370
371
372
373 buffer.putInt(fsMax + 1, fsBits);
374 for (int j = 0; j < thisblock; j++) {
375 buffer.putLong(diff[j], bBits);
376 }
377 } else if (fs == 0 && pixelsum == 0) {
378
379
380
381
382 buffer.putInt(0, fsBits);
383 } else {
384
385 buffer.putInt(fs + 1, fsBits);
386 int fsmask = (1 << fs) - 1;
387
388
389
390 int bitsToGo = buffer.missingBitsInCurrentByte();
391 int bitBuffer = buffer.bitbuffer() >> bitsToGo;
392 buffer.movePosition(bitsToGo - BITS_OF_1_BYTE);
393 for (int j = 0; j < thisblock; j++) {
394 int v = (int) diff[j];
395 int top = v >> fs;
396
397
398
399 if (bitsToGo >= top + 1) {
400 bitBuffer <<= top + 1;
401 bitBuffer |= 1;
402 bitsToGo -= top + 1;
403 } else {
404 bitBuffer <<= bitsToGo;
405 buffer.putByte((byte) (bitBuffer & BYTE_MASK));
406 for (top -= bitsToGo; top >= BITS_OF_1_BYTE; top -= BITS_OF_1_BYTE) {
407 buffer.putByte((byte) 0);
408 }
409 bitBuffer = 1;
410 bitsToGo = BITS_OF_1_BYTE - 1 - top;
411 }
412
413
414
415
416
417 if (fs > 0) {
418 bitBuffer <<= fs;
419 bitBuffer |= v & fsmask;
420 bitsToGo -= fs;
421 while (bitsToGo <= 0) {
422 buffer.putByte((byte) (bitBuffer >> -bitsToGo & BYTE_MASK));
423 bitsToGo += BITS_OF_1_BYTE;
424 }
425 }
426 }
427 buffer.putByte((byte) (bitBuffer & BYTE_MASK), BITS_OF_1_BYTE - bitsToGo);
428 }
429 }
430 buffer.close();
431 }
432
433
434
435
436
437
438
439 protected void decompressBuffer(final ByteBuffer readBuffer, final int nx) {
440
441
442 long lastpix = 0L;
443 if (bitsPerPixel == ElementType.BYTE.bitPix()) {
444 lastpix = readBuffer.get() & UNSIGNED_BYTE_MASK;
445 } else if (bitsPerPixel == ElementType.SHORT.bitPix()) {
446 lastpix = readBuffer.getShort() & UNSIGNED_SHORT_MASK;
447 } else {
448
449 lastpix = readBuffer.getInt() & UNSIGNED_INTEGER_MASK;
450 }
451 long b = readBuffer.get() & BYTE_MASK;
452 int nbits = BITS_PER_BYTE;
453 for (int i = 0; i < nx;) {
454
455 nbits -= fsBits;
456 while (nbits < 0) {
457 b = b << BITS_PER_BYTE | readBuffer.get() & BYTE_MASK;
458 nbits += BITS_PER_BYTE;
459 }
460 long fs = (b >>> nbits) - 1L;
461
462 b &= (1 << nbits) - 1;
463
464 int imax = i + blockSize;
465 if (imax > nx) {
466 imax = nx;
467 }
468 if (fs < 0) {
469
470 for (; i < imax; i++) {
471 nextPixel((int) lastpix);
472 }
473 } else if (fs == fsMax) {
474
475 for (; i < imax; i++) {
476 int k = bBits - nbits;
477 long diff = b << k;
478 for (k -= BITS_PER_BYTE; k >= 0; k -= BITS_PER_BYTE) {
479 b = readBuffer.get() & BYTE_MASK;
480 diff |= b << k;
481 }
482 if (nbits > 0) {
483 b = readBuffer.get() & BYTE_MASK;
484 diff |= b >>> -k;
485 b &= (1 << nbits) - 1L;
486 } else {
487 b = 0;
488 }
489 lastpix = undoMappingAndDifferencing(lastpix, diff);
490 }
491 } else {
492
493 for (; i < imax; i++) {
494
495 while (b == 0) {
496 nbits += BITS_PER_BYTE;
497 b = readBuffer.get() & BYTE_MASK;
498 }
499 long nzero = nbits - NONZERO_COUNT[(int) (b & BYTE_MASK)];
500 nbits -= nzero + 1;
501
502 b ^= 1 << nbits;
503
504 nbits -= fs;
505 while (nbits < 0) {
506 b = b << BITS_PER_BYTE | readBuffer.get() & BYTE_MASK;
507 nbits += BITS_PER_BYTE;
508 }
509 long diff = nzero << fs | b >> nbits;
510 b &= (1 << nbits) - 1L;
511
512 lastpix = undoMappingAndDifferencing(lastpix, diff);
513 }
514 }
515 }
516 if (readBuffer.limit() > readBuffer.position()) {
517 LOG.warning("decompressing left over some extra bytes got: " + readBuffer.limit() + " but needed only "
518 + readBuffer.position());
519 }
520
521 }
522
523 protected abstract int nextPixel();
524
525 protected abstract void nextPixel(int pixel);
526
527 }