/* * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory */ #include /* * * private routines * */ #define MAXEV 10240 /* * * _FunTableBin -- bin a blocked section of data from a table * */ #ifdef ANSI_FUNC static void * _FunTableBin(Fun fun, void *buf, char *plist) #else static void *_FunTableBin(fun, buf, plist) Fun fun; void *buf; char *plist; #endif { int skip; /* temp for skipping data to end of ext */ int offset[2]; /* offset into event record for x, y */ int size[2]; /* size of x, y value in bytes */ int val[2]; /* x, y bin values of this event */ int convert; /* whether we have to convert to native */ int index; /* index into image array for this pixel */ int esize; /* max number of events to read at once */ int dofilt; /* true if we can filter */ int dovcol; /* true if we use a value column */ int voffset; /* offset into event record for vcol */ /* not used, so avoid gcc compiler warning */ /* int vsize; */ /* size of vcol in bytes */ int vtype; /* data type of event vcol */ int imdim; /* total dims of image buffer */ int itsnan; /* if value is a nan */ int transparent; /* allow everything through the filter? */ int *rbuf=NULL; /* valid event flags */ size_t i, j; /* loop counters */ size_t get; /* number of events to read */ size_t got; /* number of events read */ unsigned char *ebuf=NULL; /* event buffer */ unsigned char *eptr; /* current pointer into ebuf */ double block2; /* block * block */ double minval[2]; /* x, y min axis values */ double binsiz[2]; /* x, y bin values */ char *obuf; /* output image buffer */ char *pbuf; /* temp plist buf */ char tbuf[SZ_LINE]; /* ever-present temp buffer */ short sval; /* short val */ unsigned short usval; /* unsigned short val */ int ival; /* int val */ longlong lval; /* 64-bit int val */ unsigned int uival; /* unsigned int vala */ float fval; /* float val */ double dval; /* double val */ double vval; /* value of the event */ /* just in case ... */ if( !_FunValid(fun) ){ gerror(stderr, "invalid funtools handle\n"); return NULL; } /* if we delayed the open before, we have to open now */ if( !fun->header && strchr(fun->mode, 'r') ) _FunFITSOpen(fun, fun->fname, "r"); /* make sure something good can happen */ if( !fun->header || !fun->header->table ){ gerror(stderr, "not a binary table\n"); return NULL; } /* make sure we have binning parameters */ if( (fun->bin[0] < 0) || ((fun->dims > 1) && (fun->bin[1] < 0)) ){ gerror(stderr, "invalid or missing binning column(s) for table\n"); return NULL; } /* make sure we have valid output dimensions */ if( (fun->odim1 <= 0) || ((fun->dims > 1) && (fun->odim2 <= 0)) ){ gerror(stderr, "invalid or zero image dimension(s) for table (%s;%d,%d)\n", fun->bincols ? fun->bincols : "invalid bincols?", fun->odim1, fun->odim2); return NULL; } /* we have to convert to native if the data is not the same as the big-endian-ness of the machine */ convert = (fun->endian != is_bigendian()); /* set x and y info -- whatever columns they actually are */ offset[0] = fun->header->table->col[fun->bin[0]].offset; size[0] = fun->header->table->col[fun->bin[0]].size; minval[0] = fun->min1; binsiz[0] = fun->binsiz1; if( fun->dims > 1 ){ offset[1] = fun->header->table->col[fun->bin[1]].offset; size[1] = fun->header->table->col[fun->bin[1]].size; minval[1] = fun->min2; binsiz[1] = fun->binsiz2; } /* optional value column for binning */ if( fun->vbin >= 0 ){ dovcol = 1; voffset = fun->header->table->col[fun->vbin].offset; /* not used, so avoid gcc compiler warning */ /* vsize = fun->header->table->col[fun->vbin].size; */ vtype = fun->header->table->col[fun->vbin].type; } else{ dovcol = 0; } /* init some convenience variables */ imdim = fun->odim1*MAX(fun->odim2,1); block2 = (double)fun->block*fun->block; transparent = 0; /* see if default data type is to be over-ridden */ pbuf = xstrdup(plist); if( _FunKeyword(pbuf, "bitpix", NULL, tbuf, SZ_LINE) ){ if( (i = atoi(tbuf)) ){ fun->obitpix = i; fun->odtype = fun->obitpix / FT_WORDLEN; } } else if( _FunKeyword(pbuf, "mask", "FUN_MASK", tbuf, SZ_LINE) ){ if( !strcasecmp(tbuf, "transparent") ) transparent = 1; } if( pbuf ) xfree(pbuf); /* allocate output buffer, if necessary */ if( buf ) obuf = buf; else{ obuf = (char *)xcalloc(imdim, ABS(fun->odtype)); if( !obuf ){ gerror(stderr, "can't allocate image buffer (%dx%dx%d)\n", fun->odim1, MAX(fun->odim2,1), ABS(fun->odtype)); return NULL; } } /* create the plist string */ if( convert ) strcpy(tbuf, "convert=true"); else strcpy(tbuf, "convert=false"); /* add the binning key */ if( fun->bincols ){ strcat(tbuf, ","); strcat(tbuf, fun->bincols); } /* add the index flag */ if( fun->idx == 1 ){ strcat(tbuf, ",idx=true"); } else if( fun->idx == -1 ){ strcat(tbuf, ",idx=false"); } /* open the filter, if its not already been done */ if( !fun->filt ){ if( fun->filter && *fun->filter ){ fun->filt = FilterOpen(fun->header, fun->filter, tbuf); /* check for error */ if( fun->filt == NULL ){ fun->filt = NOFILTER; gerror(stderr, "can't open filter: %s\n", fun->filter); return NULL; } } else{ fun->filt = NOFILTER; fun->dofilt = 0; } } /* allocate space for a pile of event records */ for(esize=MIN(MAXEV,(fun->left>0?fun->left:MAXEV)); esize>0; esize /=2){ if( ((ebuf = (unsigned char *)malloc(fun->rawsize*esize)) != NULL) && ((rbuf = (int *)malloc(sizeof(int)*esize)) != NULL) ) break; } /* while there are still events to read ... */ while( fun->left != 0 ){ /* figure out how many to read this time */ if( fun->left > 0 ) get = MIN(esize, fun->left); /* read to EOF */ else get = esize; /* read in a pile of events */ _FunRead(fun, (void *)ebuf, fun->rawsize, get, &got); /* if we got what we asked for ... */ if( got == get ){ /* if we are reading a set number of rows ... */ if( fun->left > 0 ){ /* subtract the number we just got */ fun->left -= got; /* just in case! */ if( fun->left < 0 ) fun->left = 0; } } /* didn't get what we asked for ... */ else{ /* if we are reading a set number of rows ... */ if( fun->left > 0 ){ /* using an index => already filtering, so fewer rows are acceptable */ if( (fun->filt == NOFILTER) || (fun->filt->doidx != 1) ){ /* otherwise its unexpected */ gerror(stderr, "unexpected EOF reading rows\n"); } /* ensure we stop after this iteration */ fun->left = 0; } /* if we are reading til EOF, we just got there */ else{ fun->left = 0; } } /* update how many input events we have read */ fun->io += got; fun->bytes += (got*fun->rawsize); /* filter these events through the co-process */ if( fun->dofilt ) dofilt = FilterEvents(fun->filt, (void *)ebuf, fun->rawsize, (int)got, (void *)rbuf); else dofilt = 0; /* process each event in this batch */ for(eptr=ebuf, i=0; irawsize){ /* if its not a valid event, skip it */ if( dofilt && !transparent && !rbuf[i] ){ continue; } /* get y and x values and convert to int data type for indexing */ for(j=0; j<(size_t)fun->dims; j++){ switch(fun->header->table->col[fun->bin[j]].type){ /* unsigned 8-bit int */ case 'B': val[j] = itlp2i((double)eptr[offset[j]], minval[j], binsiz[j], 'B'); break; /* 16-bit short */ case 'I': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &sval); val[j] = itlp2i((double)sval, minval[j], binsiz[j], 'I'); break; /* unsigned 16-bit int */ case 'U': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &usval); val[j] = itlp2i((double)usval, minval[j], binsiz[j], 'U'); break; /* 32-bit int */ case 'J': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &ival); val[j] = itlp2i((double)ival, minval[j], binsiz[j], 'J'); break; /* unsigned 32-bit int */ case 'K': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &lval); val[j] = itlp2i((double)ival, minval[j], binsiz[j], 'K'); break; /* unsigned 32-bit int */ case 'V': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &uival); val[j] = itlp2i((double)uival, minval[j], binsiz[j], 'V'); break; /* 32-bit float */ case 'E': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &fval); val[j] = itlp2i((double)fval, minval[j], binsiz[j], 'E'); break; /* 64-bit float */ case 'D': ColumnLoad((void *)(eptr+offset[j]), size[j], 1, convert, &dval); val[j] = itlp2i(dval, minval[j], binsiz[j], 'D'); break; case 'X': case 'L': case 'C': case 'A': case 'M': case 'P': default: goto done; } } /* make sure we are in the desired section, and calculate the offset into the image array */ if( fun->dims == 1 ){ if( (val[0] < fun->x0) || (val[0] > fun->x1) ) continue; index = (val[0] - fun->x0)/fun->block; } else{ if( (val[0] < fun->x0) || (val[0] > fun->x1) || (val[1] < fun->y0) || (val[1] > fun->y1) ) continue; index = ((val[1] - fun->y0)/fun->block)*fun->odim1 + (val[0] - fun->x0)/fun->block; } /* make sure its valid */ if( (index<0) || (index>=imdim) ) continue; /* use value column or 1 as event value */ itsnan = 0; if( dovcol ){ /* if vcol is not double, we must do full type convert */ if( vtype != 'D' ){ ft_acht2('D', &vval, vtype, eptr+voffset, 1, convert, 0); } /* for same types, we might have to swap the bytes of the double */ else if( convert ){ swap8((char *)&vval, (char *)(eptr+voffset), 8); } /* otherwise its an easy copy */ else{ memcpy(&vval, eptr+voffset, ft_sizeof(vtype)); } /* value operators */ switch(fun->vop){ case '/': if( vval ){ vval = 1.0/vval; } else{ itsnan = 1; } break; default: break; } if( vval == getnand() ){ itsnan = 1; vval = 0.0; } } else{ vval = 1.0; } /* add this event to the image array */ switch(fun->odtype){ case TY_CHAR: if( !dovcol ){ if( ((unsigned char *)obuf)[index] > (((unsigned char *)obuf)[index]+(unsigned char)vval) ){ fun->overflow++; } else{ ((unsigned char *)obuf)[index] += (unsigned char)vval; } } else{ if(fun->doblank && (((unsigned char *)obuf)[index] == fun->blank)){ ; } else if( itsnan ){ ((unsigned char *)obuf)[index] = fun->blank; } else{ ((unsigned char *)obuf)[index] += (unsigned char)vval; } } break; /* 32-bit int */ case TY_USHORT: if( !dovcol ){ if( ((unsigned short *)obuf)[index] > (((unsigned short *)obuf)[index]+(unsigned short)vval) ){ fun->overflow++; } else{ ((unsigned short *)obuf)[index] += (unsigned short)vval; } } else{ if(fun->doblank && (((unsigned short *)obuf)[index] == fun->blank)){ ; } else if( itsnan ){ ((unsigned short *)buf)[index] = fun->blank; } else{ ((unsigned short *)buf)[index] += (unsigned short)vval; } } break; /* 32-bit int */ case TY_SHORT: if( !dovcol ){ if( ((short *)obuf)[index] > (((short *)obuf)[index]+(short)vval) ){ fun->overflow++; } else{ ((short *)obuf)[index] += (short)vval; } } else{ if( fun->doblank && (((short *)obuf)[index] == fun->blank) ){ ; } else if( itsnan ){ ((short *)obuf)[index] = fun->blank; } else{ ((short *)obuf)[index] += (short)vval; } } break; /* 32-bit int */ case TY_INT: if( !dovcol ){ if( ((int *)obuf)[index] > (((int *)obuf)[index]+(int)vval) ){ fun->overflow++; } else{ ((int *)obuf)[index] += (int)vval; } } else{ if( fun->doblank && (((int *)obuf)[index] == fun->blank) ){ ; } else if( itsnan ){ ((int *)obuf)[index] = fun->blank; } else{ ((int *)obuf)[index] += (int)vval; } } break; /* 64-bit int */ case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif if( !dovcol ){ if(((longlong *)obuf)[index] > (((longlong *)obuf)[index]+(longlong)vval)){ fun->overflow++; } else{ ((longlong *)obuf)[index] += (longlong)vval; } } else{ if( fun->doblank && (((longlong *)obuf)[index] == fun->blank) ){ ; } else if( itsnan ){ ((longlong *)obuf)[index] = fun->blank; } else{ ((longlong *)obuf)[index] += (longlong)vval; } } break; /* 32-bit float */ case TY_FLOAT: if( !dovcol ){ ((float *)obuf)[index] += (float)vval; } else{ if( isnanf(((float *)obuf)[index]) ){ ; } else if( itsnan ){ ((float *)obuf)[index] = getnanf(); } else{ ((float *)obuf)[index] += (float)vval; } } break; /* 64-bit float */ case TY_DOUBLE: if( !dovcol ){ ((double *)obuf)[index] += (double)vval; } else{ if( isnand(((double *)obuf)[index]) ){ ; } else if( itsnan ){ ((double *)obuf)[index] = getnand(); } else{ ((double *)obuf)[index] += (double)vval; } } break; default: goto done; } } } /* binned all events, average each pixel, if necessary */ if( fun->btype == FUN_AVG ){ for(i=0; i<(size_t)imdim; i++){ switch(fun->odtype){ case TY_CHAR: ((unsigned char *)obuf)[i] /= block2; break; case TY_USHORT: ((unsigned short *)obuf)[i] /= block2; break; case TY_SHORT: ((short *)obuf)[i] /= block2; break; case TY_INT: ((int *)obuf)[i] /= block2; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif ((longlong *)obuf)[i] /= block2; break; case TY_FLOAT: ((float *)obuf)[i] /= block2; break; case TY_DOUBLE: ((double *)obuf)[i] /= block2; break; default: break; } } } done: /* free up space */ if( ebuf ) xfree(ebuf); if( rbuf ) xfree(rbuf); /* if we have no more rows left, clean up */ if( !fun->left ){ /* skip to end of extension */ if( fun->bytes ){ /* skip any unread events */ skip = (fun->rawsize*fun->total) - fun->bytes; gskip(fun->gio, (off_t)skip); fun->bytes += skip; /* skip padding */ if( (skip = FT_BLOCK - (fun->bytes % FT_BLOCK)) == FT_BLOCK ) skip = 0; gskip(fun->gio, (off_t)skip); /* reset io flag */ /* fun->io = 0; */ } } /* close filter if done with the filter process */ if( !fun->left && (fun->filt != NOFILTER) ){ FilterClose(fun->filt); fun->filt = NULL; } /* that's good news */ return (void *)obuf; } /* * * _FunImageExtract -- grab a blocked section of data from an array * */ #ifdef ANSI_FUNC static void * _FunImageExtract(Fun fun, void *buf, int rstart, int rstop, char *plist) #else static void *_FunImageExtract(fun, buf, rstart, rstop, plist) Fun fun; void *buf; int rstart; int rstop; char *plist; #endif { int i, j, k; int ox, oy; int convert; int yoff; int doscale=0; size_t got; off_t newpos; char *obuf; char *pbuf; char **bufs; char tbuf[SZ_LINE]; unsigned char cval; unsigned short usval; short sval; int ival; longlong lval; float fval; double dval; double block2; register double val; longlong vall; /* make sure we have something */ if( !_FunValid(fun) ) return NULL; /* if we delayed the open before, we have to open now */ if( !fun->header && strchr(fun->mode, 'r') ) _FunFITSOpen(fun, fun->fname, "r"); /* just in case ... */ if( !fun->header || !fun->header->image ){ gerror(stderr, "data is not a table or an image\n"); return NULL; } /* make sure we have valid dimensions */ if( fun->odim1 <=0 ){ gerror(stderr, "invalid dim1 (%d) from x0,x1=%d,%d\n", fun->odim1, fun->x0, fun->x1); return NULL; } if( (fun->dims > 1) && (fun->odim2 <=0) ){ gerror(stderr, "invalid dim2 (%d) from y0,y1=%d,%d\n", fun->odim2, fun->y0, fun->y1); return NULL; } /* we have to convert to native if the data is not the same as the big-endian-ness of the machine */ convert = (fun->endian != is_bigendian()); /* set up some oft-used variables */ block2 = (double)fun->block*fun->block; /* we cannot handle BLANK==0 */ if( (fun->dtype>=-2) && fun->doblank && (fun->blank==0) ){ gwarning(stderr, "BLANK==0 detected ... disabling NaN checking\n"); fun->doblank = 0; } /* see if default data type is to be over-ridden */ pbuf = xstrdup(plist); if( _FunKeyword(pbuf, "bitpix", NULL, tbuf, SZ_LINE) ){ if( (i = atoi(tbuf)) ){ fun->obitpix = i; fun->odtype = fun->obitpix / FT_WORDLEN; } } /* see if scaling is explicitly turned off */ if( _FunKeyword(pbuf, "bscale", NULL, tbuf, SZ_LINE) ){ if( isfalse(tbuf) ) doscale = -1; } if( pbuf ) xfree(pbuf); /* actually, we only scale if we have scaled int data */ if( (doscale==0) && (fun->scaled&FUN_SCALE_EXISTS) && (fun->dtype>=-2) ){ /* flag that we scaled the input data */ fun->scaled |= FUN_SCALE_APPLIED; doscale = 1; } else doscale = 0; /* make sure we are not out of bounds */ if( rstart < 1 ) rstart = 1; if( rstop < 1 ) rstop = 1; if( rstop > MAX(fun->odim2,1) ) rstop = MAX(fun->odim2,1); /* allocate output buffer, if necessary */ if( buf ) obuf = buf; else{ obuf = (char *)xcalloc(fun->odim1*(rstop-rstart+1), ABS(fun->odtype)); if( !obuf ){ gerror(stderr, "can't allocate image buffer (%dx%dx%d)\n", fun->odim1, (rstop-rstart+1), ABS(fun->odtype)); return NULL; } } /* allocate some row buffers: number of bufs is equal to the block factor */ bufs = (char **)xmalloc(fun->block * sizeof(char *)); for(i=0; iblock; i++){ bufs[i] = (char *)xmalloc((fun->x1-fun->x0+1)*ABS(fun->dtype)); } /* for all rows in the output image (or image section) ... */ for(oy=rstart; oy<=rstop; oy++){ yoff = (oy-rstart) * fun->odim1; /* get input rows associated with this output row (by block factor) */ for(j=0; jblock; i++, j++){ /* calculate specific y line we are processing */ i = (fun->y0 - 1) + ((oy-1) * fun->block) + j; /* calculate the new position into the data */ newpos = ((i*fun->dim1)+(fun->x0-1)) * ABS(fun->dtype); /* skip to new position */ if( gskip(fun->gio, newpos - fun->curpos) < 0 ){ gerror(stderr, "_FunImageExtract can't seek %d bytes into image data\n", newpos - fun->curpos); if( !buf && obuf ) xfree(obuf); return(NULL); } /* read the row */ _gread(fun->gio, bufs[j], ABS(fun->dtype), (fun->x1-fun->x0+1), &got); /* check for EOF */ if( got != (size_t)(fun->x1-fun->x0+1) ){ gerror(stderr, "unexpected EOF reading data\n"); if( !buf && obuf ) xfree(obuf); return(NULL); } /* convert to native, if necessary */ if( convert ) swap_data(bufs[j], got, fun->dtype); /* update the current position */ fun->curpos = newpos + (got * ABS(fun->dtype)); } /* process all pixels in this output row */ for(ox=0; oxodim1; ox++){ /* reset temp value */ val = 0.0; vall = 0; /* for all rows in the input blocks */ for(i=0; iblock; i++){ /* sum the input pixels which make up this output pixel */ for(j=ox*fun->block, k=0; kblock; j++, k++){ switch(fun->dtype){ case TY_CHAR: cval = ((unsigned char **)bufs)[i][j]; if( fun->doblank && (cval == fun->blank) ) goto blank; if( doscale ) val += ((double)cval*fun->bscale)+fun->bzero; else val += (double)cval; break; case TY_USHORT: usval = ((unsigned short **)bufs)[i][j]; if( fun->doblank && (usval == fun->blank) ) goto blank; if( doscale ) val += ((double)usval*fun->bscale)+fun->bzero; else val += (double)usval; break; case TY_SHORT: sval = ((short **)bufs)[i][j]; if( fun->doblank && (sval == fun->blank) ) goto blank; if( doscale ) val += ((double)sval*fun->bscale)+fun->bzero; else val += (double)sval; break; case TY_INT: ival = ((int **)bufs)[i][j]; if( fun->doblank && (ival == fun->blank) ) goto blank; if( doscale ) val += ((double)ival*fun->bscale)+fun->bzero; else val += (double)ival; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif /* argh ... 64-bit does not fit into a double! */ lval = ((longlong **)bufs)[i][j]; if( fun->doblank && (lval == fun->blank) ) goto blank; /* probably going to lose precision here */ if( doscale ) vall += ((double)lval*fun->bscale)+fun->bzero; else vall += lval; break; case TY_FLOAT: fval = ((float **)bufs)[i][j]; if( isnanf(fval) ) goto blank; val += (double)fval; break; case TY_DOUBLE: dval = ((double **)bufs)[i][j]; if( isnand(dval) ) goto blank; val += dval; break; default: break; } } } /* x block loop */ /* take average of this output pixel, if necessary */ if( fun->btype == FUN_AVG ){ val /= block2; vall /= block2; } /* store the resulting value in the output image */ /* argh ... 64-bit does not fit into a double! */ if( fun->dtype == TY_LONG ){ switch(fun->odtype){ case TY_CHAR: ((unsigned char *)obuf)[yoff+ox] = (unsigned char)vall; break; case TY_USHORT: ((unsigned short *)obuf)[yoff+ox] = (unsigned short)vall; break; case TY_SHORT: ((short *)obuf)[yoff+ox] = (short)vall; break; case TY_INT: ((int *)obuf)[yoff+ox] = (int)vall; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif ((longlong *)obuf)[yoff+ox] = (longlong)vall; break; case TY_FLOAT: ((float *)obuf)[yoff+ox] = (float)vall; break; case TY_DOUBLE: ((double *)obuf)[yoff+ox] = (double)vall; break; default: break; } } else{ switch(fun->odtype){ case TY_CHAR: ((unsigned char *)obuf)[yoff+ox] = (unsigned char)val; break; case TY_USHORT: ((unsigned short *)obuf)[yoff+ox] = (unsigned short)val; break; case TY_SHORT: ((short *)obuf)[yoff+ox] = (short)val; break; case TY_INT: ((int *)obuf)[yoff+ox] = (int)val; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif ((longlong *)obuf)[yoff+ox] = (longlong)val; break; case TY_FLOAT: ((float *)obuf)[yoff+ox] = (float)val; break; case TY_DOUBLE: ((double *)obuf)[yoff+ox] = (double)val; break; default: break; } } /* skip the blank assignment */ continue; blank: /* arrive here is we found a blank or nan */ switch(fun->odtype){ case TY_CHAR: ((unsigned char *)obuf)[yoff+ox] = fun->blank; break; case TY_USHORT: ((unsigned short *)obuf)[yoff+ox] = fun->blank; break; case TY_SHORT: ((short *)obuf)[yoff+ox] = fun->blank; break; case TY_INT: ((int *)obuf)[yoff+ox] = fun->blank; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif ((longlong *)obuf)[yoff+ox] = fun->blank; break; case TY_FLOAT: ((float *)obuf)[yoff+ox] = getnanf(); break; case TY_DOUBLE: ((double *)obuf)[yoff+ox] = getnand(); break; default: break; } } /* x loop */ } /* y loop */ /* free allocated space */ for(i=0; iblock; i++){ if( bufs[i] ) xfree(bufs[i]); } if( bufs ) xfree(bufs); /* calculate the position to the end of the data, if we read last line */ if( rstop == MAX(fun->odim2,1) ){ newpos = ((MAX(fun->dim2,1)*fun->dim1)) * ABS(fun->dtype); /* skip to end of data */ gskip(fun->gio, newpos - fun->curpos); /* skip padding as well */ gskip(fun->gio, (off_t)fun->dpad); /* reset current position to end of image */ fun->curpos = newpos + fun->dpad; } return (void *)obuf; } /* * * semi-public routines * */ #ifdef ANSI_FUNC void * _FunImageMask(Fun fun, void *buf, int rstart, int rstop, FilterMask masks, int nmask, char *plist) #else void *_FunImageMask(fun, buf, rstart, rstop, masks, nmask, plist) Fun fun; void *buf; int rstart; int rstop; FilterMask masks; int nmask; char *plist; #endif { int len; int i, n; int pixsize; int rowsize; int flag; int bitpix; int dtype; int x=0, y=0; char *pbuf; char *obuf; char *optr; char tbuf[SZ_LINE]; /* make sure we have something to do */ if( !_FunValid(fun) ) return buf; /* make sure we really want to mask, and figure out which sort of mask */ flag = 0; pbuf = xstrdup(plist); if( _FunKeyword(pbuf, "mask", "FUN_MASK", tbuf, SZ_LINE) ){ if( isfalse(tbuf) ){ if( pbuf ) xfree(pbuf); return buf; } /* 'all' means we change each pixel, setting pixels to 0 outside, and setting pixels to region value inside */ else if( !strcasecmp(tbuf, "all") ){ /* if we are allocating the buffer, we can change bitpix as well */ if( !buf && _FunKeyword(pbuf, "bitpix", NULL, tbuf, SZ_LINE) ){ if( (i = atoi(tbuf)) ){ fun->obitpix = i; fun->odtype = fun->obitpix / FT_WORDLEN; } } flag = 1; } } if( pbuf ) xfree(pbuf); bitpix = fun->obitpix; dtype = fun->odtype; /* make sure we are not out of bounds */ if( rstart < 1 ) rstart = 1; if( rstop > MAX(fun->odim2,1) ) rstop = MAX(fun->odim2,1); /* allocate output buffer, if necessary */ if( buf ) obuf = buf; else{ obuf = (char *)xcalloc(fun->odim1*(rstop-rstart+1), ABS(dtype)); if( !obuf ){ gerror(stderr, "can't allocate image buffer (%dx%dx%d)\n", fun->odim1, (rstop-rstart+1), ABS(fun->odtype)); return NULL; } } /* this is the size of a single pixel in bytes */ pixsize = ABS(bitpix/FT_WORDLEN); /* this is the number of bytes per line */ rowsize = fun->odim1 * pixsize; /* clear y rows before first row containing a mask segment */ if( nmask ){ for(y=rstart; y<=MIN(masks[0].y-1,rstop); y++){ optr = (char *)obuf + ((y-rstart) * rowsize); memset(optr, 0, rowsize); } } /* process all mask segments */ for(n=0; n rstop ) break; /* blank out rows before the y row associated with this mask segment */ for(; y0 ) memset(optr, 0, len); x = masks[n].xstart; /* if flag is set, we set the pixel values to be the region id */ if( flag ){ optr = (char *)obuf + ((y-rstart) * rowsize) + ((x-1) * pixsize); for(x=masks[n].xstart; x<=masks[n].xstop; x++){ switch(dtype){ case TY_CHAR: *((char *)optr) = (char)masks[n].region; optr += pixsize; break; case TY_USHORT: *((unsigned short *)optr) = (unsigned short)masks[n].region; optr += pixsize; break; case TY_SHORT: *((short *)optr) = (short)masks[n].region; optr += pixsize; break; case TY_INT: *((int *)optr) = (int)masks[n].region; optr += pixsize; break; case TY_LONG: #if HAVE_LONG_LONG == 0 gerror(stderr, "64-bit data support not built (long long not available)\n"); #endif *((longlong *)optr) = (longlong)masks[n].region; optr += pixsize; break; case TY_FLOAT: *((float *)optr) = (float)masks[n].region; optr += pixsize; break; case TY_DOUBLE: *((double *)optr) = (double)masks[n].region; optr += pixsize; break; default: break; } } } /* position after end of segment */ x = masks[n].xstop+1; /* if we have another mask segment with the same y, we keep going */ if( ((n+1) < nmask) && (masks[n+1].y == y) ) n++; else break; } /* clear the rest of the columns for this y row */ optr = (char *)obuf + ((y-rstart) * rowsize) + ((x-1) * pixsize); if( (len = (fun->odim1 - x + 1) * pixsize) >0 ) memset(optr, 0, len); /* bump to next y row */ y++; } /* clear y rows after last row containing a mask segment */ for(y = (nmask ? MAX(rstart,masks[nmask-1].y+1) : rstart); y<=rstop; y++){ optr = (char *)obuf + ((y-rstart) * rowsize); memset(optr, 0, rowsize); } /* return result */ return obuf; } /* * * _FunImagePutHeader -- writes header to file * used by FunImagePut and sometimes FunFlush (if no Put was done) * */ #ifdef ANSI_FUNC int _FunImagePutHeader(Fun fun, int dim1, int dim2, int bitpix) #else int _FunImagePutHeader(fun, dim1, dim2, bitpix) Fun fun; int dim1, dim2, bitpix; #endif { int i; int extver=1; int domerge=0; char *extname="IMAGE"; FITSHead merge; /* if no operation has been performed, we have no header */ if( !fun->ops ){ /* if we do not have header info yet, we should be able to copy it */ if( !fun->header ){ /* copy header from reference image */ if( fun->ifun ) _FunCopy2ImageHeader(fun->ifun, fun); /* use passed dims and bitpix, if possible */ if( dim1 && bitpix ){ /* note that we may not have a header yet -- make one here */ if( !fun->header ){ fun->header = ft_headinit(NULL, 0); ft_headsetl(fun->header, "SIMPLE", 0, 1, "FITS STANDARD", 1); } /* add the passed dim and bitpix values */ ft_headseti(fun->header, "BITPIX", 0, bitpix, "Bits/pixel", 1); if( dim2 ){ ft_headseti(fun->header, "NAXIS", 0, 2, "2-D image", 1); ft_headseti(fun->header, "NAXIS", 1, dim1, "Axis 1 dimension", 1); ft_headseti(fun->header, "NAXIS", 2, dim2, "Axis 2 dimension", 1); } else{ ft_headseti(fun->header, "NAXIS", 0, 1, "1-D image", 1); ft_headseti(fun->header, "NAXIS", 1, dim1, "Axis 1 dimension", 1); } ft_headsetl(fun->header, "EXTEND", 0, 1, "Standard extensions might follow", 1); /* synchronize the header and the cards after any changes */ ft_syncdata(fun->header); /* fill in values */ if( dim2 ){ fun->dims = 2; fun->dim1 = dim1; fun->dim2 = dim2; } else{ fun->dims = 1; fun->dim1 = dim1; fun->dim2 = 1; } fun->bitpix = bitpix; _FunImageSize(fun); } /* hmmm ... could not make a header of any sort */ if( !fun->header ) return 0; /* flag that we need to merge in user params before writing */ domerge = 1; } /* if something is already written, this is an image extension */ if( fun->primio || gtell(fun->gio)>0 ){ /* required after naxis */ ft_headseti(fun->header, "PCOUNT", 0, 0, "Random parameter count", 1); ft_headseti(fun->header, "GCOUNT", 0, 1, "Group count", 1); /* convert first card to a FITS image extension */ ft_cardfmt((FITSCard)fun->header->cards, "XTENSION", 0, FT_STRING, "IMAGE", 0, "FITS Image Extension"); if( !ft_headfind(fun->header, "EXTNAME", 0, 0) ) ft_headsets(fun->header, "EXTNAME", 0, extname, "Ext. name", 1); if( !ft_headfind(fun->header, "EXTVER", 0, 0) ) ft_headseti(fun->header, "EXTVER", 0, extver, "Ext. version", 1); /* delete EXTEND keyword, which is for primary only */ if( ft_headfind(fun->header, "EXTEND", 0, 0) ) ft_headdel(fun->header, "EXTEND", 0); } else{ /* flag that we have written the primary header */ fun->primio++; } /* if the data are floats, we must delete BSCALE and BZERO */ if( fun->bitpix < 0 ){ if( ft_headfind(fun->header, "BSCALE", 0, 0) ) ft_headdel(fun->header, "BSCALE", 0); if( ft_headfind(fun->header, "BZERO", 0, 0) ) ft_headdel(fun->header, "BZERO", 0); } /* merge in user-specified params with overwrite */ if( domerge && fun->theader ){ merge = ft_headmerge(fun->header, fun->theader, 1); ft_headfree(fun->theader, 1); fun->theader = NULL; ft_headfree(fun->header, 1); fun->header = merge; ft_syncdata(fun->header); } /* for a 1D image, we have to delete 2D header params */ if( fun->dims == 1 ){ ft_headdel(fun->header, "NAXIS", 2); /* remove 2D WCS header parameters */ for(i=0; i<=2; i++){ ft_headdel(fun->header, "CTYPE", i); ft_headdel(fun->header, "CRVAL", i); ft_headdel(fun->header, "CRPIX", i); ft_headdel(fun->header, "CDELT", i); ft_headdel(fun->header, "LTV", i); ft_headdel(fun->header, "LTM1_", i); ft_headdel(fun->header, "LTM2_", i); ft_headdel(fun->header, "CD1_", i); ft_headdel(fun->header, "CD2_", i); ft_headdel(fun->header, "CD3_", i); } } /* save file position for later updating */ fun->headpos = gtell(fun->gio); /* write the header */ ft_headwrite(fun->gio, fun->header); /* we just wrote the header */ fun->ops |= OP_WRHEAD; } /* good news */ return 1; } /* * * public routines * */ #ifdef ANSI_FUNC void * FunImageGet (Fun fun, void *buf, char *plist) #else void *FunImageGet (fun, buf, plist) Fun fun; void *buf; char *plist; #endif { int domask; int doimage; int imagetable; char *pbuf; char *s; void *obuf=NULL; char paint[SZ_LINE]; char debug[SZ_LINE]; char tbuf[SZ_LINE]; /* sanity checks */ if( !_FunValid(fun) ){ gerror(stderr, "data does not contain a valid header\n"); return NULL; } /* if we delayed the open before, we have to open now */ if( !fun->header && strchr(fun->mode, 'r') ) _FunFITSOpen(fun, fun->fname, "r"); /* sanity checks */ if( !fun->header ){ gerror(stderr, "data does not contain a valid header\n"); return NULL; } pbuf = xstrdup(plist); domask = 1; doimage = 1; imagetable = 0; if( _FunKeyword(pbuf, "mask", "FUN_MASK", tbuf, SZ_LINE) ){ if( isfalse(tbuf) ) domask = 0; /* mask=all => no data, just make the mask */ else if( !strcasecmp(tbuf, "all") ) doimage = 0; /* mask=image => we want to use image masking on a table */ else if( !strcasecmp(tbuf, "image") ) imagetable = 1; } if( _FunKeyword(pbuf, "paint", "FILTER_PAINT", tbuf, SZ_LINE) ){ strncpy(paint, tbuf, SZ_LINE); } else{ *paint = '\0'; } if( _FunKeyword(pbuf, "debug", "FILTER_DEBUG", tbuf, SZ_LINE) ){ strncpy(debug, tbuf, SZ_LINE); } else{ *debug = '\0'; } if( pbuf ) xfree(pbuf); /* pick the appropriate routine for tables and/or images */ if( doimage ){ if( fun->header->image ){ obuf = _FunImageExtract(fun, buf, 1, MAX(fun->odim2,1), plist); } else if( fun->header->table ){ obuf = _FunTableBin(fun, buf, plist); /* if mask=image, we remask using image binning, otherwise not */ if( !imagetable ) domask = 0; } /* don't bother masking if we have no image */ if( obuf == NULL ) domask = 0; } /* filter resulting image, if we have one */ if( domask ){ if( fun->filter && *fun->filter ) s = fun->filter; else if( !doimage ) s = "field"; else s = NULL; if( s ){ /* open the filter, first time through */ if( !fun->filt ){ /* make up filter plist string */ strncpy(tbuf, "type=image", SZ_LINE-1); /* add the binning key */ if( fun->bincols ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, fun->bincols, SZ_LINE-1); } /* add paint mode */ if( *paint ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, "paint=", SZ_LINE-1); strncat(tbuf, paint, SZ_LINE-1); } /* add debug flag */ if( *debug ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, "debug=", SZ_LINE-1); strncat(tbuf, debug, SZ_LINE-1); } fun->filt = FilterOpen(fun->header, s, tbuf); if( fun->filt && (fun->filt != NOFILTER) ){ fun->nmask = FilterImage(fun->filt, fun->x0, fun->x1, fun->y0, fun->y1, fun->block, &(fun->masks), NULL); } } /* perform the filter, if necessary */ if( fun->filt && (fun->filt != NOFILTER) ){ obuf = _FunImageMask(fun, obuf, 1, MAX(fun->odim2,1), fun->masks, fun->nmask, plist); } /* close filters, free masks */ if( fun->filt && (fun->filt != NOFILTER) ){ FilterClose(fun->filt); fun->filt = NULL; } if( fun->masks ){ xfree(fun->masks); fun->masks = NULL; } fun->nmask = 0; } } /* we just read an image */ fun->ops |= OP_RDIMAGE; /* return result */ return obuf; } #ifdef ANSI_FUNC void * FunImageRowGet (Fun fun, void *buf, int rstart, int rstop, char *plist) #else void *FunImageRowGet (fun, buf, rstart, rstop, plist) Fun fun; void *buf; int rstart; int rstop; char *plist; #endif { int domask; int doimage; char *pbuf; void *obuf=NULL; char paint[SZ_LINE]; char debug[SZ_LINE]; char tbuf[SZ_LINE]; /* sanity checks */ if( !_FunValid(fun) ){ gerror(stderr, "data does not contain a valid header\n"); return NULL; } /* if we delayed the open before, we have to open now */ if( !fun->header && strchr(fun->mode, 'r') ) _FunFITSOpen(fun, fun->fname, "r"); /* sanity checks */ if( !fun->header ){ gerror(stderr, "data does not contain a valid header\n"); return NULL; } pbuf = xstrdup(plist); domask = 1; doimage = 1; if( _FunKeyword(pbuf, "mask", "FUN_MASK", tbuf, SZ_LINE) ){ if( isfalse(tbuf) ) domask = 0; else if( !strcasecmp(tbuf, "all") ) doimage = 0; } if( _FunKeyword(pbuf, "paint", "FILTER_PAINT", tbuf, SZ_LINE) ){ strncpy(paint, tbuf, SZ_LINE); } else{ *paint = '\0'; } if( _FunKeyword(pbuf, "debug", "FILTER_DEBUG", tbuf, SZ_LINE) ){ strncpy(debug, tbuf, SZ_LINE); } else{ *debug = '\0'; } if( pbuf ) xfree(pbuf); /* pick the appropriate routine for tables and/or images */ if( doimage ){ if( fun->header->image ){ obuf = _FunImageExtract(fun, buf, rstart, rstop, plist); } /* we do not get lines for tables (they are not sorted) */ else if( fun->header->table ){ obuf = NULL; domask = 0; } else{ obuf = NULL; } if( obuf == NULL ) domask = 0; } /* filter resulting image, if we have one */ if( domask ){ if( fun->filter && *fun->filter ){ /* open the filter, first time through */ if( !fun->filt ){ /* make up filter plist string */ strncpy(tbuf, "type=image", SZ_LINE-1); /* add the binning key */ if( fun->bincols ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, fun->bincols, SZ_LINE-1); } /* add paint mode */ if( *paint ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, "paint=", SZ_LINE-1); strncat(tbuf, paint, SZ_LINE-1); } /* add debug flag */ if( *debug ){ strncat(tbuf, ",", SZ_LINE-1); strncat(tbuf, "debug=", SZ_LINE-1); strncat(tbuf, debug, SZ_LINE-1); } fun->filt = FilterOpen(fun->header, fun->filter, tbuf); if( fun->filt && (fun->filt != NOFILTER) ){ fun->nmask = FilterImage(fun->filt, fun->x0, fun->x1, fun->y0, fun->y1, fun->block, &(fun->masks), NULL); } } /* perform the filter, if necessary */ if( fun->filt && (fun->filt != NOFILTER) ){ obuf = _FunImageMask(fun, obuf, rstart, rstop, fun->masks, fun->nmask, plist); } } } /* we just read an image row */ fun->ops |= OP_RDIMAGE; /* return result */ return obuf; } #ifdef ANSI_FUNC static int _FunImagePut (Fun fun, void *buf, int rstart, int rstop, int dim1, int dim2, int bitpix, char *plist) #else static int _FunImagePut (fun, buf, rstart, rstop, dim1, dim2, bitpix, plist) Fun fun; void *buf; int rstart; int rstop; int dim1; int dim2; int bitpix; char *plist; #endif { char tbuf[SZ_LINE]; char *pbuf; char *zbuf; int convert; int dlen; int dpad; int tdim; off_t newpos; /* sanity checks */ if( !_FunValid(fun) ) return 0; /* this extension is an image */ fun->type = FUN_IMAGE; /* put header */ if( !_FunImagePutHeader(fun, dim1, dim2, bitpix) ) return 0; /* fill in the blanks, if necessary */ if( (dim1 == 0) && (dim2 == 0) && (bitpix == 0) ){ bitpix = fun->bitpix; dim1 = fun->dim1; dim2 = fun->dim2; } /* see if we override the normal data conversion */ pbuf = xstrdup(plist); if( _FunKeyword(pbuf, "convert", NULL, tbuf, SZ_LINE) ) convert = istrue(tbuf); else convert = !is_bigendian(); if( pbuf ) xfree(pbuf); /* determine if we are writing one line or the whole image */ if( !rstart ) tdim = dim1 * MAX(dim2,1); else tdim = dim1 * (rstop-rstart+1); /* convert to IEEE, if necessary */ if( convert ) swap_data(buf, tdim, bitpix/FT_WORDLEN); /* determine data size */ dlen = tdim * ABS(bitpix/FT_WORDLEN); /* we need to skip to the right row */ if( rstart ){ newpos = ((rstart-1) * dim1) * ABS(fun->dtype); if( gskip(fun->gio, newpos - fun->curpos) < 0 ){ gerror(stderr, "FunImagePut can't seek %d bytes into image data\n", newpos - fun->curpos); return 0; } fun->curpos = newpos; } /* write the data */ gwrite(fun->gio, buf, sizeof(char), dlen); /* update the current position */ fun->curpos += dlen; /* and the current number of bytes read */ fun->bytes += dlen; /* write the padding, if we just wrote the last row (or full image) */ if( !rstart || (rstop == MAX(dim2,1)) ){ if( (dpad = FT_BLOCK - (fun->bytes % FT_BLOCK)) != FT_BLOCK ){ zbuf = xcalloc(dpad, sizeof(char)); gwrite(fun->gio, zbuf, sizeof(char), dpad); if( zbuf ) xfree(zbuf); /* update current position */ fun->curpos += dpad; fun->bytes += dpad; } } /* we just wrote an image */ fun->ops |= OP_WRIMAGE; /* success */ return 1; } #ifdef ANSI_FUNC int FunImagePut (Fun fun, void *buf, int dim1, int dim2, int bitpix, char *plist) #else int FunImagePut (fun, buf, dim1, dim2, bitpix, plist) Fun fun; void *buf; int dim1; int dim2; int bitpix; char *plist; #endif { return _FunImagePut(fun, buf, 0, 0, dim1, dim2, bitpix, plist); } #ifdef ANSI_FUNC int FunImageRowPut (Fun fun, void *buf, int rstart, int rstop, int dim1, int dim2, int bitpix, char *plist) #else int FunImageRowPut (fun, buf, rstart, rstop, dim1, dim2, bitpix, plist) Fun fun; void *buf; int rstart; int rstop; int dim1; int dim2; int bitpix; char *plist; #endif { return _FunImagePut(fun, buf, rstart, rstop, dim1, dim2, bitpix, plist); }