View Javadoc
1   package nom.tam.fits.compression.algorithm.quant;
2   
3   import java.nio.Buffer;
4   import java.nio.BufferOverflowException;
5   
6   /*
7    * #%L
8    * nom.tam FITS library
9    * %%
10   * Copyright (C) 1996 - 2024 nom-tam-fits
11   * %%
12   * This is free and unencumbered software released into the public domain.
13   *
14   * Anyone is free to copy, modify, publish, use, compile, sell, or
15   * distribute this software, either in source code form or as a compiled
16   * binary, for any purpose, commercial or non-commercial, and by any
17   * means.
18   *
19   * In jurisdictions that recognize copyright laws, the author or authors
20   * of this software dedicate any and all copyright interest in the
21   * software to the public domain. We make this dedication for the benefit
22   * of the public at large and to the detriment of our heirs and
23   * successors. We intend this dedication to be an overt act of
24   * relinquishment in perpetuity of all present and future rights to this
25   * software under copyright law.
26   *
27   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
30   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33   * OTHER DEALINGS IN THE SOFTWARE.
34   * #L%
35   */
36  
37  import java.nio.ByteBuffer;
38  import java.nio.DoubleBuffer;
39  import java.nio.FloatBuffer;
40  import java.nio.IntBuffer;
41  
42  import nom.tam.fits.compression.algorithm.api.ICompressor;
43  
44  /**
45   * (<i>for internal use</i>) Qunatization step processor as part of compression.
46   */
47  @SuppressWarnings({"javadoc", "deprecation"})
48  public class QuantizeProcessor {
49  
50      public static class DoubleQuantCompressor extends QuantizeProcessor implements ICompressor<DoubleBuffer> {
51          public DoubleQuantCompressor(QuantizeOption quantizeOption, ICompressor<IntBuffer> compressor) {
52              super(quantizeOption, compressor);
53          }
54  
55          @Override
56          public boolean compress(DoubleBuffer buffer, ByteBuffer compressed) {
57              return super.compressGeneric(buffer, compressed);
58          }
59  
60          @Override
61          public void decompress(ByteBuffer compressed, DoubleBuffer buffer) {
62              super.decompressGeneric(compressed, buffer);
63          }
64      }
65  
66      /**
67       * TODO this is done very inefficient and should be refactored!
68       */
69      public static class FloatQuantCompressor extends QuantizeProcessor implements ICompressor<FloatBuffer> {
70          public FloatQuantCompressor(QuantizeOption quantizeOption, ICompressor<IntBuffer> compressor) {
71              super(quantizeOption, compressor);
72          }
73  
74          @Override
75          public boolean compress(FloatBuffer buffer, ByteBuffer compressed) {
76              return super.compressGeneric(buffer, compressed);
77          }
78  
79          @Override
80          public void decompress(ByteBuffer compressed, FloatBuffer buffer) {
81              super.decompressGeneric(compressed, buffer);
82          }
83      }
84  
85      private Quantize quantize;
86  
87      protected final QuantizeOption quantizeOption;
88  
89      private final ICompressor<IntBuffer> postCompressor;
90  
91      public QuantizeProcessor(QuantizeOption quantizeOption, ICompressor<IntBuffer> compressor) {
92          this.quantizeOption = quantizeOption;
93          this.postCompressor = compressor;
94          quantize = new Quantize(quantizeOption);
95      }
96  
97      protected QuantizeProcessor(QuantizeOption quantizeOption) {
98          this(quantizeOption, null);
99      }
100 
101     public Quantize getQuantize() {
102         return quantize;
103     }
104 
105     protected boolean compressGeneric(Buffer buffer, ByteBuffer compressed) throws BufferOverflowException {
106         IntBuffer intData = IntBuffer.wrap(new int[quantizeOption.getTileHeight() * quantizeOption.getTileWidth()]);
107         if (!autoQuantize(buffer, intData)) {
108             return false;
109         }
110         intData.rewind();
111         postCompressor.compress(intData, compressed);
112         return true;
113     }
114 
115     protected <BufferType extends Buffer> void decompressGeneric(ByteBuffer compressed, BufferType buffer)
116             throws BufferOverflowException {
117         IntBuffer intData = IntBuffer.wrap(new int[quantizeOption.getTileHeight() * quantizeOption.getTileWidth()]);
118         postCompressor.decompress(compressed, intData);
119         intData.rewind();
120         unquantizeGeneric(intData, buffer);
121     }
122 
123     /**
124      * Quantizes floating-point data into integer representation. The quantization parameters are determined
125      * automatically based on the noise distribution of the input, and are stored in the qunatization options associated
126      * to this class.
127      * 
128      * @param  floating floating-point input
129      * @param  quants   quantized output
130      * 
131      * @return          <code>true</code> if quantization parameters were determined, otherwise <code>false</code>.
132      * 
133      * @since           1.23
134      */
135     protected boolean autoQuantize(Buffer floating, IntBuffer quants) {
136         boolean success = quantize.guessQuantization(floating);
137         if (quants != null) {
138             quantizeGeneric(floating, quants);
139         }
140         return success;
141     }
142 
143     /**
144      * @deprecated         use {@link #autoQuantize(DoubleBuffer, IntBuffer)} instead.
145      * 
146      * @param      doubles input array of doubles
147      * @param      quants  output array of integer quantized data
148      * 
149      * @return             <code>true</code> if successful, or else <code>false</code>.
150      */
151     @Deprecated
152     public boolean quantize(double[] doubles, IntBuffer quants) {
153         return autoQuantize(DoubleBuffer.wrap(doubles, 0, quantizeOption.getTileWidth() * quantizeOption.getTileHeight()),
154                 quants);
155     }
156 
157     private void quantizeGeneric(final Buffer fdata, final IntBuffer intData) throws BufferOverflowException {
158         if (fdata instanceof FloatBuffer) {
159             quantize((FloatBuffer) fdata, intData);
160         } else {
161             quantize((DoubleBuffer) fdata, intData);
162         }
163     }
164 
165     private void unquantizeGeneric(final IntBuffer intData, final Buffer fdata) throws BufferOverflowException {
166         if (fdata instanceof FloatBuffer) {
167             unquantize(intData, (FloatBuffer) fdata);
168         } else {
169             unquantize(intData, (DoubleBuffer) fdata);
170         }
171     }
172 
173     /**
174      * Converts floating point values into quantized integer representation.
175      * 
176      * @param  fdata                   floating-point input
177      * @param  intData                 quantized integer output
178      * 
179      * @throws BufferOverflowException if the output buffer is smaller than the input buffer.
180      * 
181      * @since                          1.23
182      */
183     protected void quantize(final FloatBuffer fdata, final IntBuffer intData) throws BufferOverflowException {
184         quantizeOption.initDither();
185         while (fdata.hasRemaining()) {
186             intData.put(quantizeOption.toInt(fdata.get()));
187         }
188     }
189 
190     /**
191      * Converts quantized integers back into the floating point values they represent.
192      * 
193      * @param  intData                 quantized integer input
194      * @param  fdata                   floating-point output
195      * 
196      * @throws BufferOverflowException if the output buffer is smaller than the input buffer.
197      * 
198      * @since                          1.23
199      */
200     protected void unquantize(final IntBuffer intData, final DoubleBuffer fdata) throws BufferOverflowException {
201         quantizeOption.initDither();
202         while (fdata.hasRemaining()) {
203             fdata.put((float) quantizeOption.toDouble(intData.get()));
204         }
205     }
206 
207     /**
208      * Converts floating point values into quantized integer representation.
209      * 
210      * @param  fdata                   floating-point input
211      * @param  intData                 quantized integer output
212      * 
213      * @throws BufferOverflowException if the output buffer is smaller than the input buffer.
214      * 
215      * @since                          1.23
216      */
217     protected void quantize(final DoubleBuffer fdata, final IntBuffer intData) throws BufferOverflowException {
218         quantizeOption.initDither();
219         while (fdata.hasRemaining()) {
220             intData.put(quantizeOption.toInt(fdata.get()));
221         }
222     }
223 
224     /**
225      * Converts quantized integers back into the floating point values they represent.
226      * 
227      * @param  intData                 quantized integer input
228      * @param  fdata                   floating-point output
229      * 
230      * @throws BufferOverflowException if the output buffer is smaller than the input buffer.
231      * 
232      * @since                          1.23
233      */
234     protected void unquantize(final IntBuffer intData, final FloatBuffer fdata) throws BufferOverflowException {
235         quantizeOption.initDither();
236         while (fdata.hasRemaining()) {
237             fdata.put((float) quantizeOption.toDouble(intData.get()));
238         }
239     }
240 
241 }