github.com/astrogo/cfitsio@v0.1.0/hdu.go (about) 1 package cfitsio 2 3 // #include <stdio.h> 4 // #include "go-cfitsio.h" 5 import "C" 6 import ( 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "unsafe" 12 ) 13 14 // HDUType is the type of a "Header-Data Unit" (IMAGE_HDU, ASCII_TBL or BINARY_TBL) 15 type HDUType int 16 17 const ( 18 IMAGE_HDU HDUType = C.IMAGE_HDU // Primary Array or IMAGE HDU 19 ASCII_TBL HDUType = C.ASCII_TBL // ASCII table HDU 20 BINARY_TBL HDUType = C.BINARY_TBL // Binary table HDU 21 ANY_HDU HDUType = C.ANY_HDU // matches any HDU type 22 ) 23 24 func (hdu HDUType) String() string { 25 switch hdu { 26 case IMAGE_HDU: 27 return "IMAGE_HDU" 28 case ASCII_TBL: 29 return "ASCII_TBL" 30 case BINARY_TBL: 31 return "BINARY_TBL" 32 case ANY_HDU: 33 return "ANY_HDU" 34 default: 35 panic(fmt.Errorf("invalid HDUType value (%v)", int(hdu))) 36 } 37 } 38 39 // HDU represents a "Header-Data Unit" block 40 type HDU interface { 41 Close() error 42 Header() Header 43 Type() HDUType 44 Name() string 45 Version() int 46 Data(data interface{}) error 47 } 48 49 // hduMaker creates a HDU of correct underlying type according to Header hdr and index i 50 type hduMaker func(f *File, hdr Header, i int) (HDU, error) 51 52 // g_hdus is a global registry of hduMaker, indexed by HDUType (ASCII_TBL, BINARY_TBL, IMAGE_HDU) 53 var g_hdus = make(map[HDUType]hduMaker) 54 55 // readHDU reads the i-th HDU (index: 0-based!) from file 56 func (f *File) readHDU(i int) (HDU, error) { 57 var err error 58 hdr, err := readHeader(f, i) 59 if err != nil { 60 return nil, err 61 } 62 63 return g_hdus[hdr.htype](f, hdr, i) 64 } 65 66 // SeekHDU moves to a different HDU in the file, according to whence: 67 // 0 means relative to origin of the file, 68 // 1 means relative to current position. 69 func (f *File) SeekHDU(hdu int, whence int) error { 70 _, err := f.seekHDU(hdu, whence) 71 return err 72 } 73 74 // seekHDU moves to a different HDU in the file, according to whence: 75 // 0 means relative to origin of the file, 76 // 1 means relative to current position. 77 func (f *File) seekHDU(hdu int, whence int) (HDUType, error) { 78 c_htype := C.int(0) 79 c_status := C.int(0) 80 81 switch whence { 82 case 0: 83 c_hdu := C.int(hdu + 1) // 0-based index to 1-based index 84 C.fits_movabs_hdu(f.c, c_hdu, &c_htype, &c_status) 85 case 1: 86 c_hdu := C.int(hdu) // index is relative 87 C.fits_movrel_hdu(f.c, c_hdu, &c_htype, &c_status) 88 default: 89 return 0, fmt.Errorf("invalid whence value (%d)", whence) 90 } 91 92 if c_status > 0 { 93 return 0, to_err(c_status) 94 } 95 return HDUType(c_htype), nil 96 } 97 98 // SeekHDUByName moves to a different HDU in the file 99 func (f *File) SeekHDUByName(hdu HDUType, extname string, extvers int) error { 100 c_hdu := C.int(hdu) 101 c_name := C.CString(extname) 102 defer C.free(unsafe.Pointer(c_name)) 103 c_vers := C.int(extvers) 104 c_status := C.int(0) 105 106 C.fits_movnam_hdu(f.c, c_hdu, c_name, c_vers, &c_status) 107 if c_status > 0 { 108 return to_err(c_status) 109 } 110 111 return nil 112 } 113 114 // CHDU returns the current HDU 115 func (f *File) CHDU() HDU { 116 ihdu := f.HDUNum() 117 return f.hdus[ihdu] 118 } 119 120 // HDU returns the i-th HDU 121 func (f *File) HDU(i int) HDU { 122 return f.hdus[i] 123 } 124 125 // NumHDUs returns the total number of HDUs in the FITS file. 126 // This returns the number of completely defined HDUs in the file. If a new HDU has just been added to the FITS file, then that last HDU will only be counted if it has been closed, or if data has been written to the HDU. The current HDU remains unchanged by this routine. 127 func (f *File) NumHDUs() (int, error) { 128 c_n := C.int(0) 129 c_status := C.int(0) 130 C.fits_get_num_hdus(f.c, &c_n, &c_status) 131 if c_status > 0 { 132 return 0, to_err(c_status) 133 } 134 135 return int(c_n), nil 136 } 137 138 // HDUNum returns the number of the current HDU (CHDU) in the FITS file (where the primary array = 1). This function returns the HDU number rather than a status value. 139 // Note: 0-based index 140 func (f *File) HDUNum() int { 141 142 c_n := C.int(0) 143 C.fits_get_hdu_num(f.c, &c_n) 144 return int(c_n) - 1 // 1-based index to 0-based index 145 } 146 147 // HDUType returns the type of the current HDU in the FITS file. The possible values for hdutype are: IMAGE_HDU, ASCII_TBL, or BINARY_TBL. 148 func (f *File) HDUType() (HDUType, error) { 149 c_hdu := C.int(0) 150 c_status := C.int(0) 151 C.fits_get_hdu_type(f.c, &c_hdu, &c_status) 152 if c_status > 0 { 153 return 0, to_err(c_status) 154 } 155 156 return HDUType(c_hdu), nil 157 } 158 159 // Copy all or part of the HDUs in the FITS file associated with infptr and append them to the end of the FITS file associated with outfptr. If 'previous' is true, then any HDUs preceding the current HDU in the input file will be copied to the output file. Similarly, 'current' and 'following' determine whether the current HDU, and/or any following HDUs in the input file will be copied to the output file. Thus, if all 3 parameters are true, then the entire input file will be copied. On exit, the current HDU in the input file will be unchanged, and the last HDU in the output file will be the current HDU. 160 func (f *File) Copy(out *File, previous, current, following bool) error { 161 c_previous := C.int(0) 162 if previous { 163 c_previous = C.int(1) 164 } 165 c_current := C.int(0) 166 if current { 167 c_current = C.int(1) 168 } 169 c_following := C.int(0) 170 if following { 171 c_following = C.int(1) 172 } 173 c_status := C.int(0) 174 C.fits_copy_file(f.c, out.c, c_previous, c_current, c_following, &c_status) 175 if c_status > 0 { 176 return to_err(c_status) 177 } 178 return nil 179 } 180 181 // CopyHDU copies the current HDU from the FITS file associated with infptr and append it to the end of the FITS file associated with outfptr. Space may be reserved for MOREKEYS additional keywords in the output header. 182 func CopyHDU(dst, src *File, morekeys int) error { 183 c_morekeys := C.int(morekeys) 184 c_status := C.int(0) 185 C.fits_copy_hdu(src.c, dst.c, c_morekeys, &c_status) 186 if c_status > 0 { 187 return to_err(c_status) 188 } 189 return nil 190 } 191 192 // WriteHDU writes the current HDU in the input FITS file to the output FILE stream (e.g. stdout). 193 func WriteHDU(w io.Writer, src *File) error { 194 tmp, err := ioutil.TempFile("", "go-cfitsio-") 195 if err != nil { 196 return err 197 } 198 fname := tmp.Name() 199 tmp.Close() 200 os.Remove(fname) 201 202 c_name := C.CString(fname) 203 defer C.free(unsafe.Pointer(c_name)) 204 c_mode := C.CString("w") 205 defer C.free(unsafe.Pointer(c_mode)) 206 fstream := C.fopen(c_name, c_mode) 207 c_status := C.int(0) 208 C.fits_write_hdu(src.c, fstream, &c_status) 209 if c_status > 0 { 210 return to_err(c_status) 211 } 212 C.fclose(fstream) 213 214 tmp, err = os.Open(fname) 215 if err != nil { 216 return err 217 } 218 defer tmp.Close() 219 defer os.Remove(fname) 220 221 _, err = io.Copy(w, tmp) 222 return err 223 } 224 225 // EOF