github.com/lenartj/cfitsio@v0.0.0-20210325092924-ef692a403eb8/image.go (about) 1 package cfitsio 2 3 // #include "go-cfitsio.h" 4 // #include "go-cfitsio-utils.h" 5 import "C" 6 import ( 7 "fmt" 8 "reflect" 9 "unsafe" 10 ) 11 12 // ImageHDU is a Header-Data-Unit extension holding an image as data payload. 13 type ImageHDU struct { 14 f *File 15 header Header 16 } 17 18 // Close closes this HDU, cleaning up cycles for the proper garbage collection. 19 func (hdu *ImageHDU) Close() error { 20 hdu.f = nil 21 return nil 22 } 23 24 // Header returns the Header part of this "Header Data-Unit" block. 25 func (hdu *ImageHDU) Header() Header { 26 return hdu.header 27 } 28 29 // Type returns the HDUType for this HDU. 30 func (hdu *ImageHDU) Type() HDUType { 31 return hdu.header.htype 32 } 33 34 // Name returns the value of the 'EXTNAME' Card (or "" if none) 35 func (hdu *ImageHDU) Name() string { 36 card := hdu.header.Get("EXTNAME") 37 if card == nil { 38 return "" 39 } 40 return card.Value.(string) 41 } 42 43 // Version returns the value of the 'EXTVER' Card (or 1 if none) 44 func (hdu *ImageHDU) Version() int { 45 card := hdu.header.Get("EXTVER") 46 if card == nil { 47 return 1 48 } 49 return card.Value.(int) 50 } 51 52 // Data loads the image data associated with this HDU into data, which should 53 // be a pointer to a slice []T. 54 // cfitsio will return an error if the image payload can not be converted into Ts. 55 // It panics if data isn't addressable. 56 func (hdu *ImageHDU) Data(data interface{}) error { 57 58 rv := reflect.ValueOf(data).Elem() 59 if !rv.CanAddr() { 60 return fmt.Errorf("%T is not addressable", data) 61 } 62 63 err := hdu.load(rv) 64 return err 65 } 66 67 // load loads the image data associated with this HDU into v. 68 func (hdu *ImageHDU) load(v reflect.Value) error { 69 hdr := hdu.Header() 70 naxes := len(hdr.Axes()) 71 if naxes == 0 { 72 return nil 73 } 74 nelmts := 1 75 for _, dim := range hdr.Axes() { 76 nelmts *= int(dim) 77 } 78 if v.Len() != nelmts { 79 return fmt.Errorf("cfitsio: slice length [%v] is not as expected [%v]", v.Len(), nelmts) 80 } 81 82 c_start := C.LONGLONG(0) 83 c_nelmts := C.LONGLONG(nelmts) 84 c_status := C.int(0) 85 c_imgtype := C.int(0) 86 var c_ptr unsafe.Pointer 87 switch data := v.Interface().(type) { 88 case []byte: 89 c_imgtype = C.TBYTE 90 c_ptr = unsafe.Pointer(&data[0]) 91 92 case []int8: 93 c_imgtype = C.TBYTE 94 c_ptr = unsafe.Pointer(&data[0]) 95 96 case []int16: 97 c_imgtype = C.TSHORT 98 c_ptr = unsafe.Pointer(&data[0]) 99 100 case []uint16: 101 c_imgtype = C.TUSHORT 102 c_ptr = unsafe.Pointer(&data[0]) 103 104 case []int32: 105 c_imgtype = C.TINT 106 c_ptr = unsafe.Pointer(&data[0]) 107 108 case []uint32: 109 c_imgtype = C.TUINT 110 c_ptr = unsafe.Pointer(&data[0]) 111 112 case []int64: 113 c_imgtype = C.TLONGLONG 114 c_ptr = unsafe.Pointer(&data[0]) 115 116 case []uint64: 117 c_imgtype = C.TULONGLONG 118 c_ptr = unsafe.Pointer(&data[0]) 119 120 case []float32: 121 c_imgtype = C.TFLOAT 122 c_ptr = unsafe.Pointer(&data[0]) 123 124 case []float64: 125 c_imgtype = C.TDOUBLE 126 c_ptr = unsafe.Pointer(&data[0]) 127 128 default: 129 panic(fmt.Errorf("invalid image type [%T]", v.Interface())) 130 } 131 C.fits_read_img(hdu.f.c, c_imgtype, c_start+1, c_nelmts, nil, c_ptr, nil, &c_status) 132 if c_status > 0 { 133 return to_err(c_status) 134 } 135 136 return nil 137 } 138 139 // Write writes the image to disk 140 // data should be a pointer to a slice []T. 141 func (hdu *ImageHDU) Write(data interface{}) error { 142 var err error 143 rv := reflect.ValueOf(data).Elem() 144 if !rv.CanAddr() { 145 return fmt.Errorf("%T is not addressable", data) 146 } 147 148 hdr := hdu.Header() 149 naxes := len(hdr.Axes()) 150 if naxes == 0 { 151 return nil 152 } 153 nelmts := 1 154 for _, dim := range hdr.Axes() { 155 nelmts *= int(dim) 156 } 157 158 c_start := C.LONGLONG(0) 159 c_nelmts := C.LONGLONG(nelmts) 160 c_status := C.int(0) 161 c_imgtype := C.int(0) 162 var c_ptr unsafe.Pointer 163 164 switch data := rv.Interface().(type) { 165 case []byte: 166 c_imgtype = C.TBYTE 167 c_ptr = unsafe.Pointer(&data[0]) 168 169 case []int8: 170 c_imgtype = C.TBYTE 171 c_ptr = unsafe.Pointer(&data[0]) 172 173 case []int16: 174 c_imgtype = C.TSHORT 175 c_ptr = unsafe.Pointer(&data[0]) 176 177 case []uint16: 178 c_imgtype = C.TUSHORT 179 c_ptr = unsafe.Pointer(&data[0]) 180 181 case []int32: 182 c_imgtype = C.TINT 183 c_ptr = unsafe.Pointer(&data[0]) 184 185 case []uint32: 186 c_imgtype = C.TUINT 187 c_ptr = unsafe.Pointer(&data[0]) 188 189 case []int64: 190 c_imgtype = C.TLONGLONG 191 c_ptr = unsafe.Pointer(&data[0]) 192 193 case []uint64: 194 c_imgtype = C.TULONGLONG 195 c_ptr = unsafe.Pointer(&data[0]) 196 197 case []float32: 198 c_imgtype = C.TFLOAT 199 c_ptr = unsafe.Pointer(&data[0]) 200 201 case []float64: 202 c_imgtype = C.TDOUBLE 203 c_ptr = unsafe.Pointer(&data[0]) 204 205 default: 206 panic(fmt.Errorf("invalid image type [%T]", rv.Interface())) 207 } 208 209 C.fits_write_img(hdu.f.c, c_imgtype, c_start+1, c_nelmts, c_ptr, &c_status) 210 if c_status > 0 { 211 return to_err(c_status) 212 } 213 214 return err 215 } 216 217 // newImageHDU returns the i-th HDU from file f. 218 // if i==0, the returned ImageHDU is actually the primary HDU. 219 func newImageHDU(f *File, hdr Header, i int) (hdu HDU, err error) { 220 switch i { 221 case 0: 222 hdu, err = newPrimaryHDU(f, hdr) 223 default: 224 hdu = &ImageHDU{ 225 f: f, 226 header: hdr, 227 } 228 } 229 return hdu, err 230 } 231 232 func init() { 233 g_hdus[IMAGE_HDU] = newImageHDU 234 } 235 236 // EOF