github.com/sbinet/go-cfitsio@v0.0.0-20140625105338-0307f985659e/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