View Javadoc
1   package nom.tam.fits.compression;
2   
3   /*
4    * #%L
5    * nom.tam FITS library
6    * %%
7    * Copyright (C) 1996 - 2024 nom-tam-fits
8    * %%
9    * This is free and unencumbered software released into the public domain.
10   *
11   * Anyone is free to copy, modify, publish, use, compile, sell, or
12   * distribute this software, either in source code form or as a compiled
13   * binary, for any purpose, commercial or non-commercial, and by any
14   * means.
15   *
16   * In jurisdictions that recognize copyright laws, the author or authors
17   * of this software dedicate any and all copyright interest in the
18   * software to the public domain. We make this dedication for the benefit
19   * of the public at large and to the detriment of our heirs and
20   * successors. We intend this dedication to be an overt act of
21   * relinquishment in perpetuity of all present and future rights to this
22   * software under copyright law.
23   *
24   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
29   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30   * OTHER DEALINGS IN THE SOFTWARE.
31   * #L%
32   */
33  
34  import java.awt.BorderLayout;
35  import java.awt.Color;
36  import java.awt.Graphics2D;
37  import java.awt.image.BufferedImage;
38  import java.io.BufferedInputStream;
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.FileNotFoundException;
42  import java.io.FileOutputStream;
43  import java.io.IOException;
44  import java.io.InputStream;
45  import java.lang.reflect.Array;
46  import java.nio.FloatBuffer;
47  import java.nio.IntBuffer;
48  import java.nio.ShortBuffer;
49  import java.util.Random;
50  import java.util.stream.IntStream;
51  
52  import javax.swing.ImageIcon;
53  import javax.swing.JFrame;
54  import javax.swing.JLabel;
55  import javax.swing.WindowConstants;
56  
57  import org.junit.jupiter.api.Assertions;
58  import org.junit.jupiter.api.BeforeEach;
59  import org.junit.jupiter.api.Test;
60  
61  import nom.tam.fits.BasicHDU;
62  import nom.tam.fits.Fits;
63  import nom.tam.fits.FitsException;
64  import nom.tam.fits.FitsFactory;
65  import nom.tam.fits.Header;
66  import nom.tam.fits.HeaderCard;
67  import nom.tam.fits.ImageData;
68  import nom.tam.fits.ImageHDU;
69  import nom.tam.fits.compression.algorithm.hcompress.HCompressorOption;
70  import nom.tam.fits.compression.algorithm.quant.QuantizeOption;
71  import nom.tam.fits.compression.algorithm.rice.RiceCompressOption;
72  import nom.tam.fits.header.Compression;
73  import nom.tam.fits.header.Standard;
74  import nom.tam.fits.util.BlackBoxImages;
75  import nom.tam.image.StandardImageTiler;
76  import nom.tam.image.compression.hdu.CompressedImageHDU;
77  import nom.tam.util.ArrayFuncs;
78  import nom.tam.util.FitsOutputStream;
79  import nom.tam.util.SafeClose;
80  
81  @SuppressWarnings({"javadoc", "deprecation"})
82  public class ReadWriteProvidedCompressedImageTest {
83  
84      private ImageHDU m13;
85  
86      private short[][] m13_data;
87  
88      private float[][] m13_data_real;
89  
90      private ImageHDU m13real;
91  
92      private final boolean showImage = false;
93  
94      private static int assertionCounter = 1;
95  
96      @BeforeEach
97      public void setDefaults() {
98          FitsFactory.setDefaults();
99      }
100 
101     private void assert_float_image(float[][] actual, float[][] expected, float delta) {
102         Assertions.assertEquals(expected.length, actual.length);
103         IntStream.range(0, expected.length).parallel()
104                 .forEach(axis0 -> Assertions.assertArrayEquals(expected[axis0], actual[axis0], delta));
105     }
106 
107     private void assert_int_image(int[][] actual, int[][] expected) {
108         Assertions.assertEquals(expected.length, actual.length);
109         IntStream.range(0, expected.length).parallel()
110                 .forEach(axis0 -> Assertions.assertArrayEquals(expected[axis0], actual[axis0]));
111     }
112 
113     private void assert_short_image(short[][] actual, short[][] expected) {
114         Assertions.assertEquals(expected.length, actual.length);
115         IntStream.range(0, expected.length).parallel()
116                 .forEach(axis0 -> Assertions.assertArrayEquals(expected[axis0], actual[axis0]));
117     }
118 
119     /**
120      * This is an Assertions.assertion for a special case when a loss full algorithm is used and a quantification with
121      * null checks. The will result in wrong null values, because some of the values representing blank will be lost.
122      */
123     private void assertArrayEquals(double[] expected, double[] actual, double delta, boolean checkNaN) {
124         Assertions.assertEquals(expected.length, actual.length);
125         for (int index = 0; index < actual.length; index++) {
126             double d1 = expected[index];
127             double d2 = actual[index];
128             if (Double.isNaN(d1) || Double.isNaN(d2)) {
129                 if (checkNaN) {
130                     Assertions.assertTrue(Double.isNaN(d1) == Double.isNaN(d2)); //
131                 }
132             } else {
133                 Assertions.assertEquals(d1, d2, delta);
134             }
135         }
136     }
137 
138     private void assertArrayEquals(float[][] expected, float[][] actual, float delta) {
139         Assertions.assertEquals(expected.length, actual.length);
140         for (int index = 0; index < actual.length; index++) {
141             Assertions.assertArrayEquals(expected[index], actual[index], delta);
142         }
143     }
144 
145     /**
146      * Assertions.assert two files files (one compressed and one uncompressed and use as little memory as possible.
147      */
148     @SuppressWarnings("unchecked")
149     private <T>
150 
151             void assertCompressedToUncompressedImage(String fileName, String unCompfileName, Class<T> clazz,
152                     IHDUAsserter<T> reader) throws Exception {
153 
154         // System.out.println(" checking file: " + fileName);
155 
156         try (Fits f = new Fits(fileName); Fits unFits = new Fits(unCompfileName)) {
157             ImageHDU hdu = readHDU(unFits, ImageHDU.class);
158             unFits.deleteHDU(0);
159             CompressedImageHDU uncompHdu = readHDU(f, CompressedImageHDU.class);
160 
161             f.deleteHDU(0);
162             while (hdu != null && uncompHdu != null) {
163                 T compressedData = (T) uncompHdu.asImageHDU().getData().getData();
164                 T orgData = (T) hdu.getData().getData();
165 
166                 // show travis something is going on
167                 System.out.println("Asserting image data! " + (assertionCounter++));
168                 reader.assertData(orgData, compressedData);
169 
170                 hdu = readHDU(unFits, ImageHDU.class);
171                 if (hdu != null) {
172                     unFits.deleteHDU(0);
173                 }
174                 uncompHdu = readHDU(f, CompressedImageHDU.class);
175                 if (uncompHdu != null) {
176                     f.deleteHDU(0);
177                 }
178             }
179             Assertions.assertFalse(hdu != null || uncompHdu != null);
180         }
181 
182         // System.out.println(" done.");
183     }
184 
185     private void assertData(float[][] data) {
186         for (int x = 0; x < 300; x++) {
187             for (int y = 0; y < 300; y++) {
188                 Assertions.assertEquals(m13_data_real[x][y], data[x][y], 1f);
189             }
190         }
191     }
192 
193     private void assertData(short[][] data) {
194         for (int x = 0; x < 300; x++) {
195             for (int y = 0; y < 300; y++) {
196                 Assertions.assertEquals(m13_data[x][y], data[x][y]);
197             }
198         }
199     }
200 
201     private void assertFloatImage(FloatBuffer result, float[][] expected, float delta) {
202         float[] real = new float[expected[0].length];
203         for (float[] expectedPart : expected) {
204             result.get(real);
205             Assertions.assertEquals(expectedPart.length, real.length);
206             for (int subindex = 0; subindex < expectedPart.length; subindex++) {
207                 float expectedFloat = expectedPart[subindex];
208                 float realFloat = real[subindex];
209                 if (!Float.isNaN(expectedFloat) && !Float.isNaN(realFloat)) {
210                     Assertions.assertEquals(expectedFloat, realFloat, delta);
211                 }
212             }
213         }
214     }
215 
216     private void assertIntImage(IntBuffer result, int[][] expected) {
217         int[] real = new int[expected[0].length];
218         for (int index = 0; index < real.length; index++) {
219             int[] expectedPart = expected[index];
220             result.get(real);
221             Assertions.assertEquals(expectedPart.length, real.length);
222             for (int subindex = 0; subindex < expectedPart.length; subindex++) {
223                 int expectedFloat = expectedPart[subindex];
224                 int realFloat = real[subindex];
225                 Assertions.assertEquals(expectedFloat, realFloat, "pixel differes at " + subindex + "x" + index);
226             }
227         }
228     }
229 
230     @Test
231     public void blackboxTest_c4s_060126_182642_zri() throws Exception {
232         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("c4s_060126_182642_zri.fits.fz"), //
233                 resolveLocalOrRemoteFileName("c4s_060126_182642_zri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
234 
235                     @Override
236                     public void assertData(short[][] expected, short[][] actual) {
237                         assert_short_image(actual, expected);
238                     }
239                 });
240     }
241 
242     @Test
243     public void blackboxTest_c4s_060127_070751_cri() throws Exception {
244         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("c4s_060127_070751_cri.fits.fz"), //
245                 resolveLocalOrRemoteFileName("c4s_060127_070751_cri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
246 
247                     @Override
248                     public void assertData(short[][] expected, short[][] actual) {
249                         assert_short_image(actual, expected);
250                     }
251                 });
252     }
253 
254     @Test
255     public void blackboxTest_kwi_041217_212603_fri() throws Exception {
256         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("kwi_041217_212603_fri.fits.fz"), //
257                 resolveLocalOrRemoteFileName("kwi_041217_212603_fri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
258 
259                     @Override
260                     public void assertData(short[][] expected, short[][] actual) {
261                         assert_short_image(actual, expected);
262                     }
263                 });
264     }
265 
266     @Test
267     public void blackboxTest_kwi_041217_213100_fri() throws Exception {
268         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("kwi_041217_213100_fri.fits.fz"), //
269                 resolveLocalOrRemoteFileName("kwi_041217_213100_fri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
270 
271                     @Override
272                     public void assertData(short[][] expected, short[][] actual) {
273                         assert_short_image(actual, expected);
274                     }
275                 });
276     }
277 
278     @Test
279     public void blackboxTest_psa_140305_191552_zri() throws Exception {
280         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("psa_140305_191552_zri.fits.fz"), //
281                 resolveLocalOrRemoteFileName("psa_140305_191552_zri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
282 
283                     @Override
284                     public void assertData(short[][] expected, short[][] actual) {
285                         assert_short_image(actual, expected);
286                     }
287                 });
288     }
289 
290     @Test
291     public void blackboxTest_psa_140305_194520_fri() throws Exception {
292         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("psa_140305_194520_fri.fits.fz"), //
293                 resolveLocalOrRemoteFileName("psa_140305_194520_fri.fits"), short[][].class, new IHDUAsserter<short[][]>() {
294 
295                     @Override
296                     public void assertData(short[][] expected, short[][] actual) {
297                         assert_short_image(actual, expected);
298                     }
299                 });
300     }
301 
302     @Test
303     public void blackboxTest_tu1134529() throws Exception {
304         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("tu1134529.fits.fz"), //
305                 resolveLocalOrRemoteFileName("tu1134529.fits"), int[][].class, new IHDUAsserter<int[][]>() {
306 
307                     @Override
308                     public void assertData(int[][] expected, int[][] actual) {
309                         assert_int_image(actual, expected);
310                     }
311                 });
312 
313     }
314 
315     @Test
316     public void blackboxTest_tu1134531() throws Exception {
317         assertCompressedToUncompressedImage(resolveLocalOrRemoteFileName("tu1134531.fits.fz"), //
318                 resolveLocalOrRemoteFileName("tu1134531.fits"), float[][].class, new IHDUAsserter<float[][]>() {
319 
320                     @Override
321                     public void assertData(float[][] expected, float[][] actual) {
322                         assert_float_image(actual, expected, 15f);
323                     }
324                 });
325     }
326 
327     @Test
328     public void blackboxTest1_1() throws Exception {
329         FloatBuffer result = (FloatBuffer) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits.fz"),
330                 1);
331         float[][] expected = (float[][]) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits"), 0);
332         result.rewind();
333         assertFloatImage(result, expected, 6f);
334     }
335 
336     @Test
337     public void blackboxTest1_2() throws Exception {
338         IntBuffer result = (IntBuffer) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits.fz"), 2);
339         int[][] expected = (int[][]) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits"), 1);
340         result.rewind();
341         assertIntImage(result, expected);
342     }
343 
344     @Test
345     public void blackboxTest1_3() throws Exception {
346         FloatBuffer result = (FloatBuffer) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits.fz"),
347                 3);
348         float[][] expected = (float[][]) readAll(resolveLocalOrRemoteFileName("DECam_00149774_40_DESX0332-2742.fits"), 2);
349         result.rewind();
350         assertFloatImage(result, expected, 0.0005f);
351     }
352 
353     @Test
354     public void blackboxTest2() throws Exception {
355         FloatBuffer result = (FloatBuffer) readAll(resolveLocalOrRemoteFileName("unpack_vlos_mag.fits.fz"), 1);
356         float[][] expected = (float[][]) readAll(resolveLocalOrRemoteFileName("unpack_vlos_mag.fits"), 0);
357         result.rewind();
358         assertFloatImage(result, expected, 6500f);
359     }
360 
361     @Test
362     public void blackboxTest3() throws Exception {
363         int lastpix = 0;
364         byte bytevalue = (byte) 0x80;
365         lastpix = lastpix | (bytevalue << 24);
366 
367         IntBuffer result = (IntBuffer) readAll(resolveLocalOrRemoteFileName("hmi.fits.fz"), 1);
368         int[][] expected = (int[][]) readAll(resolveLocalOrRemoteFileName("hmi.fits"), 1);
369         result.rewind();
370         assertIntImage(result, expected);
371 
372     }
373 
374     private void dispayImage(short[][] data) {
375         JFrame frame = new JFrame("FrameDemo");
376         frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
377         frame.pack();
378         frame.setVisible(true);
379 
380         BufferedImage img = (BufferedImage) frame.createImage(300, 300);
381 
382         Graphics2D g = img.createGraphics(); // Get a Graphics2D object
383 
384         for (int y = 0; y < 300; y++) {
385             for (int x = 0; x < 300; x++) {
386                 float grayScale = data[x][y] / 4000f;
387                 g.setColor(new Color(grayScale, grayScale, grayScale));
388                 g.drawRect(x, y, 1, 1);
389             }
390         }
391         ImageIcon icon = new ImageIcon(img);
392         JLabel label = new JLabel(icon);
393         frame.getContentPane().add(label, BorderLayout.CENTER);
394         frame.repaint();
395         frame.pack();
396         frame.setVisible(true);
397     }
398 
399     private HeaderCard findCompressOption(Header header, String key) {
400         int index = 1;
401         while (true) {
402             HeaderCard card = header.getCard(Compression.ZNAMEn.n(index));
403             if (card.getValue().equals(key)) {
404                 return header.findCard(Compression.ZVALn.n(index));
405             }
406             index++;
407         }
408     }
409 
410     private boolean isEmptyImage(BasicHDU<?> result) throws FitsException {
411         return result instanceof ImageHDU && ((ImageHDU) result).getData().getData() == null;
412     }
413 
414     private Object readAll(String fileName, int index) throws Exception {
415         Object data = null;
416 
417         try (Fits f = new Fits(fileName)) {
418             BasicHDU<?> hdu = f.getHDU(index);
419             if (hdu instanceof CompressedImageHDU) {
420                 CompressedImageHDU bhdu = (CompressedImageHDU) hdu;
421                 data = bhdu.getUncompressedData();
422             }
423             if (hdu instanceof ImageHDU) {
424                 ImageHDU bhdu = (ImageHDU) hdu;
425                 data = bhdu.getData().getData();
426             }
427         }
428         return data;
429     }
430 
431     private ImageHDU readCompressedHdu(String fileName, int index) throws Exception {
432         try (Fits f = new Fits(fileName)) {
433             BasicHDU<?> hdu = f.getHDU(index);
434             if (hdu instanceof CompressedImageHDU) {
435                 CompressedImageHDU bhdu = (CompressedImageHDU) hdu;
436                 return bhdu.asImageHDU();
437             }
438         }
439         return null;
440     }
441 
442     @Test
443     public void readGzip() throws Exception {
444         Object result = readAll("src/test/resources/nom/tam/image/provided/m13_gzip.fits", 1);
445 
446         short[][] data = new short[300][300];
447         ArrayFuncs.copyInto(((ShortBuffer) result).array(), data);
448         assertData(data);
449         if (showImage) {
450             dispayImage(data);
451         }
452     }
453 
454     @Test
455     public void readHCompressed() throws Exception {
456         Object result = readAll("src/test/resources/nom/tam/image/provided/m13_hcomp.fits", 1);
457         short[][] data = new short[300][300];
458         ArrayFuncs.copyInto(((ShortBuffer) result).array(), data);
459         assertData(data);
460         if (showImage) {
461             dispayImage(data);
462         }
463     }
464 
465     @SuppressWarnings("unchecked")
466     private <T> T readHDU(Fits fits, Class<T> clazz) throws FitsException, IOException {
467         BasicHDU<?> result = fits.readHDU();
468         while (result != null && (isEmptyImage(result) || !clazz.isAssignableFrom(result.getClass()))) {
469             result = fits.readHDU();
470         }
471         return (T) result;
472     }
473 
474     @Test
475     public void readPLIO() throws Exception {
476         Object result = readAll("src/test/resources/nom/tam/image/provided/m13_plio.fits", 1);
477         short[][] data = new short[300][300];
478         ArrayFuncs.copyInto(((ShortBuffer) result).array(), data);
479         assertData(data);
480         if (showImage) {
481             dispayImage(data);
482         }
483     }
484 
485     @Test
486     public void readReal() throws Exception {
487         Object result = readAll("src/test/resources/nom/tam/image/provided/m13real_rice.fits", 1);
488         float[][] data = new float[300][300];
489         ArrayFuncs.copyInto(((FloatBuffer) result).array(), data);
490         assertData(data);
491     }
492 
493     @Test
494     public void readRice() throws Exception {
495         Object result = readAll("src/test/resources/nom/tam/image/provided/m13_rice.fits", 1);
496 
497         short[][] data = new short[300][300];
498         ArrayFuncs.copyInto(((ShortBuffer) result).array(), data);
499         assertData(data);
500         if (showImage) {
501             dispayImage(data);
502         }
503     }
504 
505     @Test
506     public void readRiceAsImageHDU() throws Exception {
507         ImageHDU image = readCompressedHdu("src/test/resources/nom/tam/image/provided/m13_rice.fits", 1);
508 
509         short[][] data = (short[][]) image.getData().getData();
510         if (showImage) {
511             dispayImage(data);
512         }
513         "to set a breakpoint ;-)".toString();
514         doTile("readRiceAsImageHDU", data, image.getTiler(), 0, 0, 20, 20);
515     }
516 
517     private void doTile(String test, Object data, StandardImageTiler t, int x, int y, int nx, int ny) throws Exception {
518         Class<?> baseClass = ArrayFuncs.getBaseClass(data);
519         Object tile = Array.newInstance(baseClass, nx * ny);
520         t.getTile(tile, new int[] {y, x}, new int[] {ny, nx});
521 
522         float sum0 = 0;
523         float sum1 = 0;
524         int length = Array.getLength(tile);
525         for (int i = 0; i < nx; i++) {
526             for (int j = 0; j < ny; j++) {
527                 int tileOffset = i + j * nx;
528                 if (tileOffset >= length) {
529                     Assertions.fail("tile offset wrong");
530                 }
531                 sum0 += ((Number) Array.get(tile, tileOffset)).doubleValue();
532                 sum1 += ((Number) Array.get(Array.get(data, j + y), i + x)).doubleValue();
533             }
534         }
535         Assertions.assertEquals(sum0, sum1, 0, "Tiler" + test);
536     }
537 
538     private String resolveLocalOrRemoteFileName(String fileName) {
539         return BlackBoxImages.getBlackBoxImage(fileName);
540     }
541 
542     @BeforeEach
543     public void setup() throws Exception {
544         try (Fits f = new Fits("src/test/resources/nom/tam/image/provided/m13.fits")) {
545             m13 = (ImageHDU) f.getHDU(0);
546             m13_data = (short[][]) m13.getData().getData();
547         }
548         try (Fits f = new Fits("src/test/resources/nom/tam/image/provided/m13real.fits")) {
549             m13real = (ImageHDU) f.getHDU(0);
550             m13_data_real = (float[][]) m13real.getData().getData();
551         }
552     }
553 
554     @Test
555     public void testBlanksInCompressedFloatImage() throws Exception {
556         try {
557             new File("target/testBlanksInCompressedFloatImage.fits").delete();
558             new File("target/testBlanksInCompressedFloatImage.fits.fz").delete();
559         } catch (Exception e) {
560             // ignore
561         }
562 
563         double[][] data = new double[100][100];
564         double value = -1000.0d;
565         int blanks = 0;
566         for (int index1 = 0; index1 < 100; index1++) {
567             for (int index2 = 0; index2 < 100; index2++) {
568                 value += 0.12345d;
569                 if (blanks++ % 20 == 0) {
570                     data[index1][index2] = Double.NaN;
571                 } else {
572                     data[index1][index2] = value;
573                 }
574             }
575         }
576 
577         try (Fits f = new Fits();
578                 FitsOutputStream bdos = new FitsOutputStream(
579                         new FileOutputStream("target/testBlanksInCompressedFloatImage.fits"))) {
580             ImageData imageData = new ImageData(data);
581             ImageHDU hdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
582             f.addHDU(hdu);
583             f.write(bdos);
584         }
585 
586         try (Fits f = new Fits();
587                 FitsOutputStream bdos = new FitsOutputStream(
588                         new FileOutputStream("target/testBlanksInCompressedFloatImage.fits.fz"))) {
589             ImageData imageData = new ImageData(data);
590             ImageHDU hdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
591             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(hdu, 100, 15);
592             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
593                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
594                     .getCompressOption(HCompressorOption.class)//
595                     /**/.setScale(4);
596             compressedHdu//
597                     .getCompressOption(QuantizeOption.class)//
598                     /**/.setQlevel(1.0)/**/.setCheckNull(true);
599             compressedHdu.compress();
600             f.addHDU(compressedHdu);
601             f.write(bdos);
602         }
603 
604         try (Fits f = new Fits("target/testBlanksInCompressedFloatImage.fits.fz")) {
605             f.readHDU();
606             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
607             double[][] actual = (double[][]) hdu.asImageHDU().getData().getData();
608             for (int index = 0; index < actual.length; index++) {
609                 Assertions.assertArrayEquals(data[index], actual[index], 0f);
610             }
611         }
612     }
613 
614     @Test
615     public void testGzipFallbackCompressed() throws Exception {
616         short[][] array = new short[][] {{1000, -2000, 3000, -3000, 4000}, {1000, -2000, 3000, -3000, 4000},
617                 {1000, -2000, 3000, -3000, 4000}, {1000, -2000, 3000, -3000, 4000}, {1000, -2000, 3000, -3000, 4000}};
618 
619         try (Fits f = new Fits()) {
620             ImageHDU image = (ImageHDU) Fits.makeHDU(array);
621             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(image, 5, 1);
622             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
623                     .getCompressOption(RiceCompressOption.class)//
624                     /**/.setBlockSize(32);
625             compressedHdu.compress();
626             f.addHDU(compressedHdu);
627             FitsOutputStream bdos = null;
628             try {
629                 bdos = new FitsOutputStream(new FileOutputStream("target/write_fallback.fits.fz"));
630                 f.write(bdos);
631             } finally {
632                 SafeClose.close(bdos);
633             }
634         }
635 
636         try (Fits f = new Fits("target/write_fallback.fits.fz")) {
637             f.readHDU(); // the primary
638             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
639             short[][] actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
640             Assertions.assertArrayEquals(array, actualShortArray);
641         }
642     }
643 
644     @Test
645     public void testSomeBlanksInCompressedFloatImage() throws Exception {
646         double[][] data = newTestImageWithSomeBlanks("");
647 
648         try (Fits f = new Fits();
649                 FitsOutputStream bdos = new FitsOutputStream(
650                         new FileOutputStream("target/testSomeBlanksInCompressedFloatImage.fits.fz"))) {
651             ImageData imageData = new ImageData(data);
652             ImageHDU hdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
653             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(hdu, 100, 15);
654             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
655                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
656                     .getCompressOption(HCompressorOption.class)//
657                     /**/.setScale(4);
658             compressedHdu//
659                     .getCompressOption(QuantizeOption.class)//
660                     /**/.setQlevel(1.0)/**/.setCheckNull(true);
661             compressedHdu.compress();
662             f.addHDU(compressedHdu);
663             f.write(bdos);
664             Assertions.assertEquals(Compression.COMPRESSED_DATA_COLUMN,
665                     compressedHdu.getHeader().findCard(Standard.TTYPEn.n(1)).getValue());
666         }
667         try (Fits f = new Fits("target/testSomeBlanksInCompressedFloatImage.fits.fz")) {
668             f.readHDU();
669             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
670             double[][] actual = (double[][]) hdu.asImageHDU().getData().getData();
671             for (int index = 0; index < actual.length; index++) {
672                 assertArrayEquals(data[index], actual[index], 1d, false);
673             }
674         }
675     }
676 
677     @Test
678     public void testUnknownCompression() throws Exception {
679         try (Fits f = new Fits()) {
680             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13, -1, 15);
681             Assertions.assertThrows(IllegalStateException.class, () -> compressedHdu.setCompressAlgorithm("NIX"));
682         }
683     }
684 
685     @Test
686     public void testMissingTileSize() throws Exception {
687 
688         try (Fits f = new Fits()) {
689             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13, -1, 15);
690             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
691                     .setQuantAlgorithm((String) null)//
692                     .getCompressOption(HCompressorOption.class)//
693                     /**/.setScale(1);
694             compressedHdu.compress();
695             f.addHDU(compressedHdu);
696             Assertions.assertTrue(compressedHdu.isHeader());
697             compressedHdu.getHeader().deleteKey(Compression.ZTILEn.n(1));
698             FitsOutputStream bdos = null;
699             try {
700                 bdos = new FitsOutputStream(new FileOutputStream("target/write_m13_own_h.fits.fz"));
701                 f.write(bdos);
702             } finally {
703                 SafeClose.close(bdos);
704             }
705         }
706 
707         try (Fits f = new Fits("target/write_m13_own_h.fits.fz")) {
708             f.readHDU();// the primary
709             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
710             short[][] actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
711             Assertions.assertArrayEquals(m13_data, actualShortArray);
712         }
713     }
714 
715     @Test
716     public void writeHcompress() throws Exception {
717 
718         try (Fits f = new Fits()) {
719             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13, 300, 15);
720             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
721                     .setQuantAlgorithm((String) null)//
722                     .getCompressOption(HCompressorOption.class)//
723                     /**/.setScale(1);
724             compressedHdu.compress();
725             f.addHDU(compressedHdu);
726             compressedHdu = CompressedImageHDU.fromImageHDU(m13, 300, 1);
727             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
728                     .setQuantAlgorithm((String) null)//
729                     .getCompressOption(HCompressorOption.class)//
730                     /**/.setScale(1);
731             compressedHdu.compress();
732             f.addHDU(compressedHdu);
733             compressedHdu = CompressedImageHDU.fromImageHDU(m13, 100, 300);
734             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
735                     .setQuantAlgorithm((String) null)//
736                     .getCompressOption(HCompressorOption.class)//
737                     /**/.setSmooth(true)//
738                     /**/.setScale(1);
739             compressedHdu.compress();
740             f.addHDU(compressedHdu);
741             FitsOutputStream bdos = null;
742             try {
743                 bdos = new FitsOutputStream(new FileOutputStream("target/write_m13_own_h.fits.fz"));
744                 f.write(bdos);
745             } finally {
746                 SafeClose.close(bdos);
747             }
748         }
749 
750         try (Fits f = new Fits("target/write_m13_own_h.fits.fz")) {
751             f.readHDU();// the primary
752             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
753             short[][] actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
754             Assertions.assertArrayEquals(m13_data, actualShortArray);
755             hdu = (CompressedImageHDU) f.readHDU();
756             actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
757             Assertions.assertArrayEquals(m13_data, actualShortArray);
758             hdu = (CompressedImageHDU) f.readHDU();
759             actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
760             Assertions.assertArrayEquals(m13_data, actualShortArray);
761         }
762     }
763 
764     @Test
765     public void writeHcompressFloat() throws Exception {
766 
767         try (Fits f = new Fits()) {
768             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 300, 15);
769             HCompressorOption option = compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
770                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
771                     .getCompressOption(QuantizeOption.class)//
772                     /**/.setQlevel(1.0)//
773                     .getCompressOption(HCompressorOption.class)//
774                     /**/.setScale(1);
775             // ansure same instances of the options
776             Assertions.assertSame(compressedHdu.getCompressOption(HCompressorOption.class), option);
777             Assertions.assertSame(compressedHdu.getCompressOption(QuantizeOption.class),
778                     compressedHdu.getCompressOption(QuantizeOption.class));
779             compressedHdu.compress();
780             f.addHDU(compressedHdu);
781             compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 300, 1);
782             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
783                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
784                     .getCompressOption(HCompressorOption.class)//
785                     /**/.setScale(1);
786             compressedHdu.getCompressOption(QuantizeOption.class).setQlevel(1.0);
787             compressedHdu.compress();
788             f.addHDU(compressedHdu);
789             compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 100, 300);
790             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
791                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
792                     .getCompressOption(HCompressorOption.class)//
793                     /**/.setSmooth(true)//
794                     /**/.setScale(1);
795             compressedHdu.getCompressOption(QuantizeOption.class).setQlevel(1.0);
796             compressedHdu.compress();
797             f.addHDU(compressedHdu);
798             FitsOutputStream bdos = null;
799             try {
800                 bdos = new FitsOutputStream(new FileOutputStream("target/write_m13real_own_h.fits.fz"));
801                 f.write(bdos);
802             } finally {
803                 SafeClose.close(bdos);
804             }
805         }
806 
807         try (Fits f = new Fits("target/write_m13real_own_h.fits.fz")) {
808             f.readHDU();
809             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
810             float[][] actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
811             assertArrayEquals(m13_data_real, actualShortArray, 9f);
812             hdu = (CompressedImageHDU) f.readHDU();
813             actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
814             assertArrayEquals(m13_data_real, actualShortArray, .000000000001f);
815             hdu = (CompressedImageHDU) f.readHDU();
816             actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
817             assertArrayEquals(m13_data_real, actualShortArray, 6f);
818         }
819     }
820 
821     @Test
822     public void writeRice() throws Exception {
823 
824         try (Fits f = new Fits()) {
825             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13, 300, 15);
826             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
827                     .setQuantAlgorithm((String) null)//
828                     .getCompressOption(RiceCompressOption.class)//
829                     /**/.setBlockSize(32)//
830                     /**/.setBytePix(2);
831             compressedHdu.compress();
832             f.addHDU(compressedHdu);
833             compressedHdu = CompressedImageHDU.fromImageHDU(m13, 300, 1);
834             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
835                     .setQuantAlgorithm((String) null)//
836                     .getCompressOption(RiceCompressOption.class)//
837                     /**/.setBlockSize(32)//
838                     /**/.setBytePix(2);
839             compressedHdu.compress();
840             f.addHDU(compressedHdu);
841             compressedHdu = CompressedImageHDU.fromImageHDU(m13, 100, 300);
842             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
843                     .setQuantAlgorithm((String) null)//
844                     .getCompressOption(RiceCompressOption.class)//
845                     /**/.setBlockSize(32)//
846                     /**/.setBytePix(2);
847             compressedHdu.compress();
848             f.addHDU(compressedHdu);
849             FitsOutputStream bdos = null;
850             try {
851                 bdos = new FitsOutputStream(new FileOutputStream("target/write_m13_own.fits.fz"));
852                 f.write(bdos);
853             } finally {
854                 SafeClose.close(bdos);
855             }
856         }
857 
858         try (Fits f = new Fits("target/write_m13_own.fits.fz")) {
859             f.readHDU();// the primary
860 
861             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
862             Assertions.assertEquals("2", findCompressOption(hdu.getHeader(), Compression.BYTEPIX).getValue());
863             short[][] actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
864             Assertions.assertArrayEquals(m13_data, actualShortArray);
865 
866             hdu = (CompressedImageHDU) f.readHDU();
867             Assertions.assertEquals("2", findCompressOption(hdu.getHeader(), Compression.BYTEPIX).getValue());
868             actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
869             Assertions.assertArrayEquals(m13_data, actualShortArray);
870 
871             hdu = (CompressedImageHDU) f.readHDU();
872             Assertions.assertEquals("2", findCompressOption(hdu.getHeader(), Compression.BYTEPIX).getValue());
873             actualShortArray = (short[][]) hdu.asImageHDU().getData().getData();
874             Assertions.assertArrayEquals(m13_data, actualShortArray);
875 
876         }
877     }
878 
879     @Test
880     public void writeRiceSpeciaIntOverflow() throws Exception {
881         ImageHDU uncompressed = null;
882         int[][] expectedIntData;
883 
884         try (Fits f = new Fits(resolveLocalOrRemoteFileName("hmi.fits"))) {
885             uncompressed = (ImageHDU) f.getHDU(1);
886             expectedIntData = (int[][]) uncompressed.getData().getData();
887             f.close();
888         }
889 
890         try (Fits f = new Fits()) {
891             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(uncompressed, uncompressed.getAxes()[0], 4);
892             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
893                     .setQuantAlgorithm((String) null)//
894                     .getCompressOption(RiceCompressOption.class)//
895                     /**/.setBlockSize(32)//
896                     /**/.setBytePix(4);
897             compressedHdu.compress();
898             f.addHDU(compressedHdu);
899 
900             try (FitsOutputStream bdos = new FitsOutputStream(new FileOutputStream("target/hmi.fits.fz"))) {
901                 f.write(bdos);
902             }
903         }
904 
905         try (Fits f = new Fits("target/hmi.fits.fz")) {
906             f.readHDU();// the primary
907             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
908             Assertions.assertEquals("4", findCompressOption(hdu.getHeader(), Compression.BYTEPIX).getValue());
909             ImageHDU asImageHDU = hdu.asImageHDU();
910             int[][] actualIntArray = (int[][]) asImageHDU.getData().getData();
911 
912             Assertions.assertArrayEquals(expectedIntData, actualIntArray);
913             Assertions.assertNull(asImageHDU.getHeader().getStringValue(Standard.TFIELDS.key()));
914             Assertions.assertNull(asImageHDU.getHeader().getStringValue(Standard.TTYPEn.n(1).key()));
915         }
916     }
917 
918     @Test
919     public void writeRiceFloat() throws Exception {
920         try (Fits f = new Fits()) {
921             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 300, 15);
922             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
923                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
924                     .getCompressOption(QuantizeOption.class)//
925                     /**/.setQlevel(1.0)//
926                     /**/.getCompressOption(RiceCompressOption.class)//
927                     /*  */.setBlockSize(32);
928             compressedHdu.compress();
929             f.addHDU(compressedHdu);
930             compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 300, 1);
931             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
932                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
933                     .getCompressOption(RiceCompressOption.class)//
934                     /**/.setBlockSize(32);
935             compressedHdu.getCompressOption(QuantizeOption.class).setQlevel(1.0);
936             compressedHdu.compress();
937             f.addHDU(compressedHdu);
938             compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 100, 300);
939             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
940                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
941                     .getCompressOption(RiceCompressOption.class)//
942                     /**/.setBlockSize(32);
943             compressedHdu.getCompressOption(QuantizeOption.class).setQlevel(1.0);
944             compressedHdu.compress();
945             f.addHDU(compressedHdu);
946             FitsOutputStream bdos = null;
947             try {
948                 bdos = new FitsOutputStream(new FileOutputStream("target/write_m13real_own.fits.fz"));
949                 f.write(bdos);
950             } finally {
951                 SafeClose.close(bdos);
952             }
953         }
954 
955         try (Fits f = new Fits("target/write_m13real_own.fits.fz")) {
956             f.readHDU();
957             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
958             float[][] actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
959             assertArrayEquals(m13_data_real, actualShortArray, 9f);
960             hdu = (CompressedImageHDU) f.readHDU();
961             actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
962             assertArrayEquals(m13_data_real, actualShortArray, 15f);
963             hdu = (CompressedImageHDU) f.readHDU();
964             actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
965             assertArrayEquals(m13_data_real, actualShortArray, 6f);
966         }
967     }
968 
969     @Test
970     public void writeRiceFloatWithForceNoLoss() throws Exception {
971 
972         try (Fits f = new Fits()) {
973             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13real, 300, 15);
974             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
975                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
976                     .forceNoLoss(140, 140, 20, 20)//
977                     .getCompressOption(QuantizeOption.class)//
978                     /**/.setQlevel(1.0)//
979                     .getCompressOption(RiceCompressOption.class)//
980                     /**/.setBlockSize(32);
981             compressedHdu.compress();
982             f.addHDU(compressedHdu);
983 
984             try (FitsOutputStream bdos = new FitsOutputStream(
985                     new FileOutputStream("target/write_m13real_own_noloss.fits.fz"))) {
986                 f.write(bdos);
987             }
988         }
989 
990         try (Fits f = new Fits("target/write_m13real_own_noloss.fits.fz")) {
991             f.readHDU();
992             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
993             float[][] actualShortArray = (float[][]) hdu.asImageHDU().getData().getData();
994             assertArrayEquals(m13_data_real, actualShortArray, 3.5f);
995 
996             for (int x = 140; x < 160; x++) {
997                 for (int y = 140; y < 160; y++) {
998                     Assertions.assertEquals(actualShortArray[x][y], m13_data_real[x][y], 0.0f);
999                 }
1000             }
1001         }
1002     }
1003 
1004     @Test
1005     public void writeRiceDouble() throws Exception {
1006         double[][] m13_double_data = (double[][]) ArrayFuncs.convertArray(m13_data_real, double.class);
1007         ImageData imagedata = ImageHDU.encapsulate(m13_double_data);
1008         ImageHDU m13_double = new ImageHDU(ImageHDU.manufactureHeader(imagedata), imagedata);
1009 
1010         try (Fits f = new Fits()) {
1011             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(m13_double, 300, 15);
1012             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_RICE_1)//
1013                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
1014                     .getCompressOption(QuantizeOption.class)//
1015                     /**/.setQlevel(1.0)//
1016                     .getCompressOption(RiceCompressOption.class)//
1017                     /**/.setBlockSize(32);
1018             compressedHdu.compress();
1019             f.addHDU(compressedHdu);
1020 
1021             try (FitsOutputStream bdos = new FitsOutputStream(new FileOutputStream("target/write_m13double.fits.fz"))) {
1022                 f.write(bdos);
1023             }
1024         }
1025 
1026         try (Fits f = new Fits("target/write_m13double.fits.fz")) {
1027             f.readHDU();
1028             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
1029             double[][] actualShortArray = (double[][]) hdu.asImageHDU().getData().getData();
1030             for (int index = 0; index < actualShortArray.length; index++) {
1031                 assertArrayEquals(m13_double_data[index], actualShortArray[index], 3.5d, false);
1032             }
1033         }
1034     }
1035 
1036     @Test
1037     public void writeRiceFloatWithNullPixelMask() throws Exception {
1038         double[][] data = newTestImageWithSomeBlanks("ForNull");
1039 
1040         try (Fits f = new Fits();
1041                 FitsOutputStream bdos = new FitsOutputStream(
1042                         new FileOutputStream("target/testSomeBlanksInCompressedFloatImage.fits.fz"))) {
1043             ImageData imageData = new ImageData(data);
1044             ImageHDU hdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
1045             CompressedImageHDU compressedHdu = CompressedImageHDU.fromImageHDU(hdu, 100, 15);
1046             compressedHdu.setCompressAlgorithm(Compression.ZCMPTYPE_HCOMPRESS_1)//
1047                     .setQuantAlgorithm(Compression.ZQUANTIZ_SUBTRACTIVE_DITHER_2)//
1048                     .preserveNulls(Compression.ZCMPTYPE_RICE_1)//
1049                     .getCompressOption(QuantizeOption.class)//
1050                     /**/.setQlevel(1.0)/**/.setCheckNull(true)//
1051                     .getCompressOption(HCompressorOption.class)//
1052                     /**/.setScale(4);
1053             compressedHdu.compress();
1054             f.addHDU(compressedHdu);
1055             f.write(bdos);
1056             Assertions.assertEquals(Compression.COMPRESSED_DATA_COLUMN,
1057                     compressedHdu.getHeader().findCard(Standard.TTYPEn.n(1)).getValue());
1058         }
1059 
1060         try (Fits f = new Fits("target/testSomeBlanksInCompressedFloatImage.fits.fz")) {
1061             f.readHDU();
1062             CompressedImageHDU hdu = (CompressedImageHDU) f.readHDU();
1063             double[][] actual = (double[][]) hdu.asImageHDU().getData().getData();
1064             for (int index = 0; index < actual.length; index++) {
1065                 assertArrayEquals(data[index], actual[index], 1d, true); // TODO
1066                 // set
1067                 // to
1068                 // true
1069             }
1070         }
1071     }
1072 
1073     protected double[][] newTestImageWithSomeBlanks(String suffix)
1074             throws FitsException, IOException, FileNotFoundException {
1075         try {
1076             new File("target/testSomeBlanksInCompressedFloatImage" + suffix + ".fits").delete();
1077             new File("target/testSomeBlanksInCompressedFloatImage" + suffix + ".fits.fz").delete();
1078         } catch (Exception e) {
1079             // ignore
1080         }
1081 
1082         double[][] data = new double[100][100];
1083         double value = -1000.0d;
1084         int blanks = 0;
1085         Random random = new Random();
1086         for (int index1 = 0; index1 < 100; index1++) {
1087             for (int index2 = 0; index2 < 100; index2++) {
1088                 data[index1][index2] = value;
1089                 if (blanks++ % 20 == 0) {
1090                     data[index1][index2] = Double.NaN;
1091                 } else {
1092                     data[index1][index2] = value;
1093                     value += 0.12345d + random.nextDouble() / 1000d;
1094                 }
1095             }
1096         }
1097         Fits f = null;
1098         FitsOutputStream bdos = null;
1099         try {
1100             f = new Fits();
1101             bdos = new FitsOutputStream(
1102                     new FileOutputStream("target/testSomeBlanksInCompressedFloatImage" + suffix + ".fits"));
1103             ImageData imageData = new ImageData(data);
1104             ImageHDU hdu = new ImageHDU(ImageHDU.manufactureHeader(imageData), imageData);
1105             f.addHDU(hdu);
1106             f.write(bdos);
1107         } finally {
1108             SafeClose.close(bdos);
1109             SafeClose.close(f);
1110         }
1111         return data;
1112     }
1113 
1114     @Test
1115     public void testImagePlusCompressedImage1() throws Exception {
1116         // Test using a FITS file with junk at the end...
1117         testImagePlusCompressedImage(
1118                 resolveLocalOrRemoteFileName("03h-80dec--C_CVT_2013-12-29-MW1-03h_Light_600SecISO200_000042.fit"));
1119         // No exception thrown
1120     }
1121 
1122     @Test
1123     public void testImagePlusCompressedImage2() throws Exception {
1124         // Test using a FITS file with junk at the end...
1125         testImagePlusCompressedImage(
1126                 resolveLocalOrRemoteFileName("17h-75dec--BINT_C_CVT_2014-06-25-MW1-17h_Light_600SecISO200_000031.fit"));
1127         // No exception thrown
1128     }
1129 
1130     private void testImagePlusCompressedImage(String imageFile) throws Exception {
1131         BasicHDU<?>[] fitsFileHDU = null;
1132         try (InputStream fileStream = new BufferedInputStream(new FileInputStream(imageFile));
1133                 Fits fitsFile = new Fits(fileStream)) {
1134             fitsFileHDU = fitsFile.read();
1135             for (BasicHDU<?> element : fitsFileHDU) {
1136                 if (element.getHeader().containsKey("ZIMAGE")) {
1137                     if (element.getHeader().getBooleanValue("ZIMAGE")) {
1138                         CompressedImageHDU hdu = (CompressedImageHDU) element;
1139                         hdu.asImageHDU();
1140                     }
1141                 }
1142             }
1143         }
1144     }
1145 
1146     @Test
1147     public void testDitherDecompress() throws Exception {
1148         ImageHDU im = null;
1149 
1150         try (Fits fits = new Fits("../blackbox-images/fpack.fits.fz")) {
1151             fits.readHDU();
1152             im = ((CompressedImageHDU) fits.readHDU()).asImageHDU();
1153             fits.close();
1154         }
1155 
1156         try (Fits fits = new Fits("../blackbox-images/funpack.fits")) {
1157             ImageHDU ref = (ImageHDU) fits.readHDU();
1158 
1159             assertArrayEquals((float[][]) ref.getData().getData(), (float[][]) im.getData().getData(), 0.01f);
1160             fits.close();
1161         }
1162     }
1163 }