View Javadoc
1   package nom.tam.image.compression.hdu;
2   
3   import java.util.Map;
4   
5   import nom.tam.fits.HeaderCard;
6   import nom.tam.fits.HeaderCardException;
7   import nom.tam.fits.header.Compression;
8   import nom.tam.fits.header.GenericKey;
9   import nom.tam.fits.header.IFitsHeader;
10  import nom.tam.fits.header.IFitsHeader.VALUE;
11  import nom.tam.util.Cursor;
12  
13  /*
14   * #%L
15   * nom.tam FITS library
16   * %%
17   * Copyright (C) 1996 - 2024 nom-tam-fits
18   * %%
19   * This is free and unencumbered software released into the public domain.
20   *
21   * Anyone is free to copy, modify, publish, use, compile, sell, or
22   * distribute this software, either in source code form or as a compiled
23   * binary, for any purpose, commercial or non-commercial, and by any
24   * means.
25   *
26   * In jurisdictions that recognize copyright laws, the author or authors
27   * of this software dedicate any and all copyright interest in the
28   * software to the public domain. We make this dedication for the benefit
29   * of the public at large and to the detriment of our heirs and
30   * successors. We intend this dedication to be an overt act of
31   * relinquishment in perpetuity of all present and future rights to this
32   * software under copyright law.
33   *
34   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
35   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
36   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
37   * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
38   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
39   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
40   * OTHER DEALINGS IN THE SOFTWARE.
41   * #L%
42   */
43  
44  import static nom.tam.fits.header.Checksum.CHECKSUM;
45  import static nom.tam.fits.header.Checksum.DATASUM;
46  import static nom.tam.fits.header.Compression.ZBITPIX;
47  import static nom.tam.fits.header.Compression.ZBLANK;
48  import static nom.tam.fits.header.Compression.ZBLOCKED;
49  import static nom.tam.fits.header.Compression.ZCMPTYPE;
50  import static nom.tam.fits.header.Compression.ZCTYPn;
51  import static nom.tam.fits.header.Compression.ZDATASUM;
52  import static nom.tam.fits.header.Compression.ZDITHER0;
53  import static nom.tam.fits.header.Compression.ZEXTEND;
54  import static nom.tam.fits.header.Compression.ZFORMn;
55  import static nom.tam.fits.header.Compression.ZGCOUNT;
56  import static nom.tam.fits.header.Compression.ZHECKSUM;
57  import static nom.tam.fits.header.Compression.ZIMAGE;
58  import static nom.tam.fits.header.Compression.ZNAMEn;
59  import static nom.tam.fits.header.Compression.ZNAXIS;
60  import static nom.tam.fits.header.Compression.ZNAXISn;
61  import static nom.tam.fits.header.Compression.ZPCOUNT;
62  import static nom.tam.fits.header.Compression.ZQUANTIZ;
63  import static nom.tam.fits.header.Compression.ZSIMPLE;
64  import static nom.tam.fits.header.Compression.ZTABLE;
65  import static nom.tam.fits.header.Compression.ZTENSION;
66  import static nom.tam.fits.header.Compression.ZTHEAP;
67  import static nom.tam.fits.header.Compression.ZTILELEN;
68  import static nom.tam.fits.header.Compression.ZTILEn;
69  import static nom.tam.fits.header.Compression.ZVALn;
70  import static nom.tam.fits.header.Standard.BITPIX;
71  import static nom.tam.fits.header.Standard.EXTNAME;
72  import static nom.tam.fits.header.Standard.GCOUNT;
73  import static nom.tam.fits.header.Standard.NAXIS;
74  import static nom.tam.fits.header.Standard.NAXISn;
75  import static nom.tam.fits.header.Standard.PCOUNT;
76  import static nom.tam.fits.header.Standard.TFORMn;
77  import static nom.tam.fits.header.Standard.THEAP;
78  import static nom.tam.fits.header.Standard.XTENSION;
79  
80  /**
81   * Mapping of header keywords between compressed and uncompressed representation. For example, the keyword NAXIS1 in the
82   * uncompressed HDU is remapped to ZNAXIS1 in the compressed HDU so it does not interfere with the different layout of
83   * the compressed HDU vs the layout of the original one.
84   */
85  @SuppressWarnings("deprecation")
86  enum CompressedCard {
87      MAP_ANY(null) {
88  
89          @Override
90          protected void backupCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
91              // unhandled card so just copy it to the uncompressed header
92              headerIterator.add(card.copy());
93          }
94  
95          @Override
96          protected void restoreCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
97              // unhandled card so just copy it to the uncompressed header
98              headerIterator.add(card.copy());
99          }
100     },
101     MAP_BITPIX(BITPIX), MAP_CHECKSUM(CHECKSUM), MAP_DATASUM(DATASUM), MAP_EXTNAME(EXTNAME) {
102 
103         @Override
104         protected void backupCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
105             if (!card.getValue().equals("COMPRESSED_IMAGE")) {
106                 super.backupCard(card, headerIterator);
107             }
108         }
109     },
110     MAP_GCOUNT(GCOUNT), MAP_NAXIS(NAXIS), MAP_NAXISn(NAXISn), MAP_PCOUNT(PCOUNT), MAP_ZFORMn(ZFORMn) {
111 
112         @Override
113         protected void backupCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
114             String newKey = uncompressedHeaderKey().n(GenericKey.getN(card.getKey())).key();
115             headerIterator.add(new HeaderCard(newKey, card.getValue(String.class, ""), card.getComment()));
116         }
117 
118         @Override
119         protected void restoreCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
120             String newKey = compressedHeaderKey().n(GenericKey.getN(card.getKey())).key();
121             headerIterator.add(new HeaderCard(newKey, card.getValue(String.class, ""), card.getComment()));
122         }
123 
124     },
125 
126     MAP_TFORMn(TFORMn), MAP_XTENSION(XTENSION), MAP_ZBITPIX(ZBITPIX), MAP_ZBLANK(ZBLANK), //
127     MAP_ZTILELEN(ZTILELEN), MAP_ZCTYPn(ZCTYPn), MAP_ZBLOCKED(ZBLOCKED), MAP_ZCMPTYPE(ZCMPTYPE), //
128     MAP_ZDATASUM(ZDATASUM), MAP_ZDITHER0(ZDITHER0), MAP_ZEXTEND(ZEXTEND), MAP_ZGCOUNT(ZGCOUNT), //
129     MAP_ZHECKSUM(ZHECKSUM), MAP_ZIMAGE(ZIMAGE), MAP_ZTABLE(ZTABLE), MAP_ZNAMEn(ZNAMEn), //
130     MAP_ZNAXIS(ZNAXIS), MAP_THEAP(THEAP),
131 
132     MAP_ZNAXISn(ZNAXISn) {
133 
134         @Override
135         protected void backupCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
136             String newKey = uncompressedHeaderKey().n(GenericKey.getN(card.getKey())).key();
137             headerIterator.add(new HeaderCard(newKey, card.getValue(Integer.class, 0), card.getComment()));
138         }
139 
140         @Override
141         protected void restoreCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
142             String newKey = compressedHeaderKey().n(GenericKey.getN(card.getKey())).key();
143             headerIterator.add(new HeaderCard(newKey, card.getValue(Integer.class, 0), card.getComment()));
144         }
145 
146     },
147 
148     MAP_ZPCOUNT(ZPCOUNT), MAP_ZTHEAP(ZTHEAP), MAP_ZQUANTIZ(ZQUANTIZ), MAP_ZSIMPLE(ZSIMPLE), MAP_ZTENSION(
149             ZTENSION), MAP_ZTILEn(ZTILEn), MAP_ZVALn(ZVALn);
150 
151     private final IFitsHeader compressedHeaderKey;
152 
153     private final IFitsHeader uncompressedHeaderKey;
154 
155     public static void backup(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
156         CompressedCard mapping = selectMapping(CompressedImageHDU.UNCOMPRESSED_HEADER_MAPPING, card);
157         mapping.backupCard(card, headerIterator);
158     }
159 
160     public static void restore(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
161         CompressedCard mapping = selectMapping(CompressedImageHDU.COMPRESSED_HEADER_MAPPING, card);
162         mapping.restoreCard(card, headerIterator);
163     }
164 
165     protected static CompressedCard selectMapping(Map<IFitsHeader, CompressedCard> mappings, HeaderCard card) {
166         IFitsHeader key = GenericKey.lookup(card.getKey());
167         if (key != null) {
168             CompressedCard mapping = mappings.get(key);
169             if (mapping != null) {
170                 return mapping;
171             }
172         }
173         return MAP_ANY;
174     }
175 
176     CompressedCard(IFitsHeader header) {
177         compressedHeaderKey = header;
178         if (header instanceof Compression) {
179             uncompressedHeaderKey = ((Compression) compressedHeaderKey).getUncompressedKey();
180 
181         } else {
182             uncompressedHeaderKey = null;
183         }
184         CompressedImageHDU.UNCOMPRESSED_HEADER_MAPPING.put(header, this);
185         if (uncompressedHeaderKey != null) {
186             CompressedImageHDU.COMPRESSED_HEADER_MAPPING.put(uncompressedHeaderKey, this);
187         }
188     }
189 
190     private void addHeaderCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator, IFitsHeader targetKey)
191             throws HeaderCardException {
192         if (targetKey != null) {
193             if (targetKey.valueType() == VALUE.INTEGER) {
194                 headerIterator.add(new HeaderCard(targetKey.key(), card.getValue(Integer.class, 0), card.getComment()));
195             } else if (targetKey.valueType() == VALUE.STRING) {
196                 headerIterator.add(new HeaderCard(targetKey.key(), card.getValue(), card.getComment()));
197             } else if (targetKey.valueType() == VALUE.LOGICAL) {
198                 headerIterator.add(new HeaderCard(targetKey.key(), card.getValue(Boolean.class, false), card.getComment()));
199             }
200         }
201     }
202 
203     /**
204      * default behaviour is to ignore the card and by that to exclude it from the uncompressed header if it does not
205      * have a uncompressed equivalent..
206      *
207      * @param  card                the card from the compressed header
208      * @param  headerIterator      the iterator for the uncompressed header.
209      *
210      * @throws HeaderCardException if the card could not be copied
211      */
212     protected void backupCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
213         IFitsHeader uncompressedKey = uncompressedHeaderKey;
214         addHeaderCard(card, headerIterator, uncompressedKey);
215     }
216 
217     protected IFitsHeader compressedHeaderKey() {
218         return compressedHeaderKey;
219     }
220 
221     protected void restoreCard(HeaderCard card, Cursor<String, HeaderCard> headerIterator) throws HeaderCardException {
222         addHeaderCard(card, headerIterator, compressedHeaderKey);
223     }
224 
225     protected IFitsHeader uncompressedHeaderKey() {
226         return uncompressedHeaderKey;
227     }
228 }