| 1 | /** @file psImageIO.c
|
|---|
| 2 | *
|
|---|
| 3 | * @brief Contains image I/O routines.
|
|---|
| 4 | *
|
|---|
| 5 | * This file defines the file input/output functions for the psImage structure.
|
|---|
| 6 | *
|
|---|
| 7 | * @author Robert DeSonia, MHPCC
|
|---|
| 8 | *
|
|---|
| 9 | * @version $Revision: 1.15 $ $Name: $
|
|---|
| 10 | * @date $Date: 2004/11/04 01:05:00 $
|
|---|
| 11 | *
|
|---|
| 12 | * Copyright 2004 Maui High Performance Computing Center, University of Hawaii
|
|---|
| 13 | */
|
|---|
| 14 |
|
|---|
| 15 | #include <fitsio.h>
|
|---|
| 16 | #include <unistd.h>
|
|---|
| 17 |
|
|---|
| 18 | #include "psImageIO.h"
|
|---|
| 19 | #include "psError.h"
|
|---|
| 20 | #include "psMemory.h"
|
|---|
| 21 |
|
|---|
| 22 | #include "psImageErrors.h"
|
|---|
| 23 |
|
|---|
| 24 | psImage* psImageReadSection(psImage* output,
|
|---|
| 25 | psS32 col,
|
|---|
| 26 | psS32 row,
|
|---|
| 27 | psS32 numCols,
|
|---|
| 28 | psS32 numRows,
|
|---|
| 29 | psS32 z,
|
|---|
| 30 | char *extname,
|
|---|
| 31 | psS32 extnum,
|
|---|
| 32 | char *filename)
|
|---|
| 33 | {
|
|---|
| 34 | fitsfile *fptr = NULL; /* Pointer to the FITS file */
|
|---|
| 35 | psS32 status = 0; /* CFITSIO file vars */
|
|---|
| 36 | psS32 nAxis = 0;
|
|---|
| 37 | psS32 anynull = 0;
|
|---|
| 38 | psS32 bitPix = 0; /* Pixel type */
|
|---|
| 39 | long nAxes[3];
|
|---|
| 40 | long firstPixel[3]; /* lower-left corner of image subset */
|
|---|
| 41 | long lastPixel[3]; /* upper-right corner of image subset */
|
|---|
| 42 | long increment[3]; /* increment for image subset */
|
|---|
| 43 | char fitsErr[80] = ""; /* CFITSIO error message string */
|
|---|
| 44 | psS32 hduType = IMAGE_HDU;
|
|---|
| 45 | psS32 fitsDatatype = 0;
|
|---|
| 46 | psS32 datatype = 0;
|
|---|
| 47 |
|
|---|
| 48 | if (filename == NULL) {
|
|---|
| 49 | psError(PS_ERR_BAD_PARAMETER_NULL, true,
|
|---|
| 50 | PS_ERRORTEXT_psImageIO_FILENAME_NULL);
|
|---|
| 51 | psFree(output);
|
|---|
| 52 | return NULL;
|
|---|
| 53 | }
|
|---|
| 54 |
|
|---|
| 55 | /* Open the FITS file */
|
|---|
| 56 | (void)fits_open_file(&fptr, filename, READONLY, &status);
|
|---|
| 57 | if (fptr == NULL || status != 0) {
|
|---|
| 58 | fits_get_errstatus(status, fitsErr);
|
|---|
| 59 | psError(PS_ERR_BAD_PARAMETER_VALUE, true,
|
|---|
| 60 | PS_ERRORTEXT_psImageIO_FILENAME_INVALID,
|
|---|
| 61 | filename, fitsErr);
|
|---|
| 62 | psFree(output);
|
|---|
| 63 | return NULL;
|
|---|
| 64 | }
|
|---|
| 65 |
|
|---|
| 66 | /* find the specified extension */
|
|---|
| 67 | if (extname != NULL) {
|
|---|
| 68 | if (fits_movnam_hdu(fptr, hduType, extname, 0, &status) != 0) {
|
|---|
| 69 | fits_get_errstatus(status, fitsErr);
|
|---|
| 70 | status = 0;
|
|---|
| 71 | (void)fits_close_file(fptr, &status);
|
|---|
| 72 | psError(PS_ERR_LOCATION_INVALID, true,
|
|---|
| 73 | PS_ERRORTEXT_psImageIO_EXTNAME_INVALID,
|
|---|
| 74 | extname, filename, fitsErr);
|
|---|
| 75 | psFree(output);
|
|---|
| 76 | return NULL;
|
|---|
| 77 | }
|
|---|
| 78 | } else {
|
|---|
| 79 | if (fits_movabs_hdu(fptr, extnum + 1, &hduType, &status) != 0) {
|
|---|
| 80 | fits_get_errstatus(status, fitsErr);
|
|---|
| 81 | status = 0;
|
|---|
| 82 | (void)fits_close_file(fptr, &status);
|
|---|
| 83 | psError(PS_ERR_LOCATION_INVALID, true,
|
|---|
| 84 | PS_ERRORTEXT_psImageIO_EXTNUM_INVALID,
|
|---|
| 85 | extnum, filename, fitsErr);
|
|---|
| 86 | psFree(output);
|
|---|
| 87 | return NULL;
|
|---|
| 88 | }
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | /* Get the data type 'bitPix' from the FITS image */
|
|---|
| 92 | if (fits_get_img_equivtype(fptr, &bitPix, &status) != 0) {
|
|---|
| 93 | fits_get_errstatus(status, fitsErr);
|
|---|
| 94 | status = 0;
|
|---|
| 95 | (void)fits_close_file(fptr, &status);
|
|---|
| 96 | psError(PS_ERR_IO, true,
|
|---|
| 97 | PS_ERRORTEXT_psImageIO_DATATYPE_UNKNOWN,
|
|---|
| 98 | filename, fitsErr);
|
|---|
| 99 | psFree(output);
|
|---|
| 100 | return NULL;
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | /* Get the dimensions 'nAxis' from the FITS image */
|
|---|
| 104 | if (fits_get_img_dim(fptr, &nAxis, &status) != 0) {
|
|---|
| 105 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 106 | status = 0;
|
|---|
| 107 | (void)fits_close_file(fptr, &status);
|
|---|
| 108 | psError(PS_ERR_IO, true,
|
|---|
| 109 | PS_ERRORTEXT_psImageIO_IMAGE_DIM_UNKNOWN,
|
|---|
| 110 | filename, fitsErr);
|
|---|
| 111 | psFree(output);
|
|---|
| 112 | return NULL;
|
|---|
| 113 | }
|
|---|
| 114 |
|
|---|
| 115 | /* Validate the number of axis */
|
|---|
| 116 | if ((nAxis < 2) || (nAxis > 3)) {
|
|---|
| 117 | status = 0;
|
|---|
| 118 | (void)fits_close_file(fptr, &status);
|
|---|
| 119 | psError(PS_ERR_IO, true,
|
|---|
| 120 | PS_ERRORTEXT_psImageIO_IMAGE_DIMENSION_UNSUPPORTED,
|
|---|
| 121 | nAxis);
|
|---|
| 122 | psFree(output);
|
|---|
| 123 | return NULL;
|
|---|
| 124 | }
|
|---|
| 125 |
|
|---|
| 126 | /* Get the Image size from the FITS file */
|
|---|
| 127 | if (fits_get_img_size(fptr, nAxis, nAxes, &status) != 0) {
|
|---|
| 128 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 129 | status = 0;
|
|---|
| 130 | (void)fits_close_file(fptr, &status);
|
|---|
| 131 | psError(PS_ERR_IO, true,
|
|---|
| 132 | PS_ERRORTEXT_psImageIO_IMAGE_SIZE_UNKNOWN,
|
|---|
| 133 | filename, fitsErr);
|
|---|
| 134 | psFree(output);
|
|---|
| 135 | return NULL;
|
|---|
| 136 | }
|
|---|
| 137 |
|
|---|
| 138 | if (numCols < 1) {
|
|---|
| 139 | numCols += nAxes[0] - col;
|
|---|
| 140 | }
|
|---|
| 141 | if (numRows < 1) {
|
|---|
| 142 | numRows += nAxes[1] - row;
|
|---|
| 143 | }
|
|---|
| 144 |
|
|---|
| 145 | firstPixel[0] = col + 1;
|
|---|
| 146 | firstPixel[1] = row + 1;
|
|---|
| 147 | firstPixel[2] = z + 1;
|
|---|
| 148 |
|
|---|
| 149 | lastPixel[0] = firstPixel[0] + numCols - 1;
|
|---|
| 150 | lastPixel[1] = firstPixel[1] + numRows - 1;
|
|---|
| 151 | lastPixel[2] = z + 1;
|
|---|
| 152 |
|
|---|
| 153 | increment[0] = 1;
|
|---|
| 154 | increment[1] = 1;
|
|---|
| 155 | increment[2] = 1;
|
|---|
| 156 |
|
|---|
| 157 | switch (bitPix) {
|
|---|
| 158 | case BYTE_IMG:
|
|---|
| 159 | datatype = PS_TYPE_U8;
|
|---|
| 160 | fitsDatatype = TBYTE;
|
|---|
| 161 | break;
|
|---|
| 162 | case SBYTE_IMG:
|
|---|
| 163 | datatype = PS_TYPE_S8;
|
|---|
| 164 | fitsDatatype = TSBYTE;
|
|---|
| 165 | break;
|
|---|
| 166 | case USHORT_IMG:
|
|---|
| 167 | datatype = PS_TYPE_U16;
|
|---|
| 168 | fitsDatatype = TUSHORT;
|
|---|
| 169 | break;
|
|---|
| 170 | case SHORT_IMG:
|
|---|
| 171 | datatype = PS_TYPE_S16;
|
|---|
| 172 | fitsDatatype = TSHORT;
|
|---|
| 173 | break;
|
|---|
| 174 | case ULONG_IMG:
|
|---|
| 175 | datatype = PS_TYPE_U32;
|
|---|
| 176 | fitsDatatype = TUINT;
|
|---|
| 177 | break;
|
|---|
| 178 | case LONG_IMG:
|
|---|
| 179 | datatype = PS_TYPE_S32;
|
|---|
| 180 | fitsDatatype = TINT;
|
|---|
| 181 | break;
|
|---|
| 182 | case LONGLONG_IMG:
|
|---|
| 183 | datatype = PS_TYPE_S64;
|
|---|
| 184 | fitsDatatype = TLONGLONG;
|
|---|
| 185 | break;
|
|---|
| 186 | case FLOAT_IMG:
|
|---|
| 187 | datatype = PS_TYPE_F32;
|
|---|
| 188 | fitsDatatype = TFLOAT;
|
|---|
| 189 | break;
|
|---|
| 190 | case DOUBLE_IMG:
|
|---|
| 191 | datatype = PS_TYPE_F64;
|
|---|
| 192 | fitsDatatype = TDOUBLE;
|
|---|
| 193 | break;
|
|---|
| 194 | default:
|
|---|
| 195 | psError(PS_ERR_IO, true,
|
|---|
| 196 | PS_ERRORTEXT_psImageIO_FITS_TYPE_UNSUPPORTED,
|
|---|
| 197 | bitPix, filename);
|
|---|
| 198 | psFree(output);
|
|---|
| 199 | return NULL;
|
|---|
| 200 | }
|
|---|
| 201 | output = psImageRecycle(output, numCols, numRows, datatype);
|
|---|
| 202 | if (fits_read_subset(fptr, fitsDatatype, firstPixel, lastPixel, increment,
|
|---|
| 203 | NULL, output->data.V[0], &anynull, &status) != 0) {
|
|---|
| 204 | psFree(output);
|
|---|
| 205 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 206 | status = 0;
|
|---|
| 207 | (void)fits_close_file(fptr, &status);
|
|---|
| 208 | psError(PS_ERR_IO, true,
|
|---|
| 209 | PS_ERRORTEXT_psImageIO_READ_FAILED,
|
|---|
| 210 | filename, fitsErr);
|
|---|
| 211 | return NULL;
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | (void)fits_close_file(fptr, &status);
|
|---|
| 215 |
|
|---|
| 216 | return output;
|
|---|
| 217 | }
|
|---|
| 218 |
|
|---|
| 219 | psBool psImageWriteSection(psImage* input,
|
|---|
| 220 | psS32 col0,
|
|---|
| 221 | psS32 row0,
|
|---|
| 222 | psS32 z,
|
|---|
| 223 | char *extname,
|
|---|
| 224 | psS32 extnum,
|
|---|
| 225 | char *filename)
|
|---|
| 226 | {
|
|---|
| 227 | psS32 numCols = 0;
|
|---|
| 228 | psS32 numRows = 0;
|
|---|
| 229 |
|
|---|
| 230 | psS32 status = 0; /* CFITSIO status */
|
|---|
| 231 | fitsfile *fptr = NULL; /* pointer to the FITS file */
|
|---|
| 232 | long nAxes[3]; /* Image axis vars */
|
|---|
| 233 | long firstPixel[3]; /* First Pixel to read */
|
|---|
| 234 | long lastPixel[3]; /* Last Pixel to read */
|
|---|
| 235 | char fitsErr[80]; /* FITSIO message string */
|
|---|
| 236 | psS32 datatype = 0; /* the datatype of the image */
|
|---|
| 237 | psS32 bitPix = 0; /* FITS bitPix value */
|
|---|
| 238 | psS32 hduType = IMAGE_HDU; /* the HDU type (image,table, etc.) */
|
|---|
| 239 | double bscale = 1.0;
|
|---|
| 240 | double bzero = 0.0;
|
|---|
| 241 | psBool createNewHDU = false;
|
|---|
| 242 |
|
|---|
| 243 | /* need a valid image to write */
|
|---|
| 244 | if (input == NULL) {
|
|---|
| 245 | psError(PS_ERR_BAD_PARAMETER_NULL, true,
|
|---|
| 246 | PS_ERRORTEXT_psImage_IMAGE_NULL);
|
|---|
| 247 | return false;
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 | numRows = input->numRows;
|
|---|
| 251 | numCols = input->numCols;
|
|---|
| 252 |
|
|---|
| 253 | switch (input->type.type) {
|
|---|
| 254 | case PS_TYPE_U8:
|
|---|
| 255 | bitPix = BYTE_IMG;
|
|---|
| 256 | datatype = TBYTE;
|
|---|
| 257 | break;
|
|---|
| 258 | case PS_TYPE_S8:
|
|---|
| 259 | bitPix = BYTE_IMG;
|
|---|
| 260 | bzero = INT8_MIN;
|
|---|
| 261 | datatype = TSBYTE;
|
|---|
| 262 | break;
|
|---|
| 263 | case PS_TYPE_U16:
|
|---|
| 264 | bitPix = SHORT_IMG;
|
|---|
| 265 | bzero = -1.0f * INT16_MIN;
|
|---|
| 266 | datatype = TUSHORT;
|
|---|
| 267 | break;
|
|---|
| 268 | case PS_TYPE_S16:
|
|---|
| 269 | bitPix = SHORT_IMG;
|
|---|
| 270 | datatype = TSHORT;
|
|---|
| 271 | break;
|
|---|
| 272 | case PS_TYPE_U32:
|
|---|
| 273 | bitPix = LONG_IMG;
|
|---|
| 274 | bzero = -1.0f * INT32_MIN;
|
|---|
| 275 | datatype = TUINT;
|
|---|
| 276 | break;
|
|---|
| 277 | case PS_TYPE_S32:
|
|---|
| 278 | bitPix = LONG_IMG;
|
|---|
| 279 | datatype = TINT;
|
|---|
| 280 | break;
|
|---|
| 281 | case PS_TYPE_F32:
|
|---|
| 282 | bitPix = FLOAT_IMG;
|
|---|
| 283 | datatype = TFLOAT;
|
|---|
| 284 | break;
|
|---|
| 285 | case PS_TYPE_F64:
|
|---|
| 286 | bitPix = DOUBLE_IMG;
|
|---|
| 287 | datatype = TDOUBLE;
|
|---|
| 288 | break;
|
|---|
| 289 | default: {
|
|---|
| 290 | char* typeStr;
|
|---|
| 291 | PS_TYPE_NAME(typeStr,input->type.type);
|
|---|
| 292 | psError(PS_ERR_BAD_PARAMETER_TYPE, true,
|
|---|
| 293 | PS_ERRORTEXT_psImageIO_TYPE_UNSUPPORTED,
|
|---|
| 294 | typeStr);
|
|---|
| 295 | return false;
|
|---|
| 296 | }
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | /* Open the FITS file */
|
|---|
| 300 | if (access(filename, F_OK) == 0) { // file
|
|---|
| 301 | // exists
|
|---|
| 302 | (void)fits_open_file(&fptr, filename, READWRITE, &status);
|
|---|
| 303 | if (fptr == NULL || status != 0) {
|
|---|
| 304 | fits_get_errstatus(status, fitsErr);
|
|---|
| 305 | psError(PS_ERR_BAD_PARAMETER_VALUE, true,
|
|---|
| 306 | PS_ERRORTEXT_psImageIO_FILENAME_INVALID,
|
|---|
| 307 | filename, fitsErr);
|
|---|
| 308 | return false;
|
|---|
| 309 | }
|
|---|
| 310 |
|
|---|
| 311 | /* find the specified extension */
|
|---|
| 312 | if (extname != NULL) {
|
|---|
| 313 | if (fits_movnam_hdu(fptr, hduType, extname, 0, &status) != 0) {
|
|---|
| 314 | fits_get_errstatus(status, fitsErr);
|
|---|
| 315 | status = 0;
|
|---|
| 316 | (void)fits_close_file(fptr, &status);
|
|---|
| 317 | psError(PS_ERR_LOCATION_INVALID, true,
|
|---|
| 318 | PS_ERRORTEXT_psImageIO_EXTNAME_INVALID,
|
|---|
| 319 | extname, filename, fitsErr);
|
|---|
| 320 | return false;
|
|---|
| 321 | }
|
|---|
| 322 | } else {
|
|---|
| 323 | psS32 numHDUs = 0;
|
|---|
| 324 |
|
|---|
| 325 | fits_get_num_hdus(fptr, &numHDUs, &status);
|
|---|
| 326 | if (numHDUs < extnum) {
|
|---|
| 327 | status = 0;
|
|---|
| 328 | (void)fits_close_file(fptr, &status);
|
|---|
| 329 | psError(PS_ERR_LOCATION_INVALID, true,
|
|---|
| 330 | PS_ERRORTEXT_psImageIO_WRITE_EXTNUM_INVALID,
|
|---|
| 331 | extnum, numHDUs);
|
|---|
| 332 | return false;
|
|---|
| 333 | } else if (numHDUs == extnum) {
|
|---|
| 334 | createNewHDU = true;
|
|---|
| 335 | } else if (fits_movabs_hdu(fptr, extnum + 1, &hduType, &status) != 0) {
|
|---|
| 336 | fits_get_errstatus(status, fitsErr);
|
|---|
| 337 | status = 0;
|
|---|
| 338 | (void)fits_close_file(fptr, &status);
|
|---|
| 339 | psError(PS_ERR_LOCATION_INVALID, true,
|
|---|
| 340 | PS_ERRORTEXT_psImageIO_EXTNUM_INVALID,
|
|---|
| 341 | extnum, filename, fitsErr);
|
|---|
| 342 | return false;
|
|---|
| 343 | }
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | } else {
|
|---|
| 347 | // file does not exist
|
|---|
| 348 |
|
|---|
| 349 | (void)fits_create_file(&fptr, filename, &status);
|
|---|
| 350 | if (fptr == NULL || status != 0) {
|
|---|
| 351 | fits_get_errstatus(status, fitsErr);
|
|---|
| 352 | psError(PS_ERR_IO, true,
|
|---|
| 353 | PS_ERRORTEXT_psImageIO_FILENAME_CREATE_FAILED,
|
|---|
| 354 | filename, fitsErr);
|
|---|
| 355 | return false;
|
|---|
| 356 | }
|
|---|
| 357 | createNewHDU = true;
|
|---|
| 358 | }
|
|---|
| 359 |
|
|---|
| 360 | if (createNewHDU) {
|
|---|
| 361 | /* create the mandatory image keywords */
|
|---|
| 362 | nAxes[0] = col0 + numCols;
|
|---|
| 363 | nAxes[1] = row0 + numRows;
|
|---|
| 364 | nAxes[2] = z + 1;
|
|---|
| 365 | if (fits_create_img(fptr, bitPix, 3, nAxes, &status) != 0) {
|
|---|
| 366 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 367 | status = 0;
|
|---|
| 368 | (void)fits_close_file(fptr, &status);
|
|---|
| 369 | psError(PS_ERR_IO, true,
|
|---|
| 370 | PS_ERRORTEXT_psImageIO_CREATE_HDU_FAILED,
|
|---|
| 371 | filename, fitsErr);
|
|---|
| 372 | return false;
|
|---|
| 373 | }
|
|---|
| 374 | // set the bscale/bzero
|
|---|
| 375 | fits_write_key_dbl(fptr, "BZERO", bzero, 12, "Pixel Value Offset", &status);
|
|---|
| 376 | fits_write_key_dbl(fptr, "BSCALE", bscale, 12, "Pixel Value Scale", &status);
|
|---|
| 377 | fits_set_bscale(fptr, bscale, bzero, &status);
|
|---|
| 378 |
|
|---|
| 379 | if (extname != NULL) {
|
|---|
| 380 | /* create the extension for the Primary HDU */
|
|---|
| 381 | if (fits_write_key_str(fptr, "EXTNAME", extname, "Extension Name", &status) != 0) {
|
|---|
| 382 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 383 | status = 0;
|
|---|
| 384 | (void)fits_close_file(fptr, &status);
|
|---|
| 385 | psError(PS_ERR_IO, true,
|
|---|
| 386 | PS_ERRORTEXT_psImageIO_CREATE_EXTENSION_FAILED,
|
|---|
| 387 | filename, fitsErr);
|
|---|
| 388 | return false;
|
|---|
| 389 | }
|
|---|
| 390 | }
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | firstPixel[0] = col0 + 1;
|
|---|
| 394 | firstPixel[1] = row0 + 1;
|
|---|
| 395 | firstPixel[2] = z + 1;
|
|---|
| 396 |
|
|---|
| 397 | lastPixel[0] = firstPixel[0] + numCols - 1;
|
|---|
| 398 | lastPixel[1] = firstPixel[1] + numRows - 1;
|
|---|
| 399 | lastPixel[2] = z + 1;
|
|---|
| 400 |
|
|---|
| 401 | if (fits_write_subset(fptr, datatype, firstPixel, lastPixel, input->data.V[0], &status) != 0) {
|
|---|
| 402 | (void)fits_get_errstatus(status, fitsErr);
|
|---|
| 403 | status = 0;
|
|---|
| 404 | (void)fits_close_file(fptr, &status);
|
|---|
| 405 | psError(PS_ERR_IO, true,
|
|---|
| 406 | PS_ERRORTEXT_psImageIO_WRITE_FAILED,
|
|---|
| 407 | filename, fitsErr);
|
|---|
| 408 | return false;
|
|---|
| 409 | }
|
|---|
| 410 |
|
|---|
| 411 | status = 0;
|
|---|
| 412 | (void)fits_close_file(fptr, &status);
|
|---|
| 413 |
|
|---|
| 414 | return true;
|
|---|
| 415 | }
|
|---|