1 package nom.tam.fits.compression;
2
3
4
5
6
7
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 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
121
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
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
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
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
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();
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
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();
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();
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();
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
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();
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();
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);
1066
1067
1068
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
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
1117 testImagePlusCompressedImage(
1118 resolveLocalOrRemoteFileName("03h-80dec--C_CVT_2013-12-29-MW1-03h_Light_600SecISO200_000042.fit"));
1119
1120 }
1121
1122 @Test
1123 public void testImagePlusCompressedImage2() throws Exception {
1124
1125 testImagePlusCompressedImage(
1126 resolveLocalOrRemoteFileName("17h-75dec--BINT_C_CVT_2014-06-25-MW1-17h_Light_600SecISO200_000031.fit"));
1127
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 }