move fits read/write to new-style
This commit is contained in:
parent
a2ed2edb5d
commit
0137186205
@ -13,7 +13,8 @@
|
||||
im_moreeq*(), im_remainder*(), im_and*(), im_or*(), im_eor*(), im_shift*(),
|
||||
im_pow*(), im_exp*(), im_ifthenelse(), im_blend(), im_c2amph(), im_c2rect(),
|
||||
im_bandmean(), im_c2real(), im_c2imag(), im_ri2c(), im_jpeg*2vips(),
|
||||
im_vips2jpeg*(), im_tiff2vips(), im_vips2tiff(), im_exr2vips()
|
||||
im_vips2jpeg*(), im_tiff2vips(), im_vips2tiff(), im_exr2vips(),
|
||||
im_fits2vips(), im_vips2fits()
|
||||
redone as classes
|
||||
- added argument priorites to help control arg ordering
|
||||
- generate has a 'stop' param to signal successful early termination
|
||||
|
9
TODO
9
TODO
@ -1,9 +1,18 @@
|
||||
- fits bandjoin is rubbish
|
||||
|
||||
perhaps we should always allocate the output in the loader? it's make fits
|
||||
bandjoin simpler
|
||||
|
||||
|
||||
|
||||
|
||||
- "header fred.png" does not work, since header uses im_open() which uses
|
||||
VipsForeign
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- make the old format/vips.c into a stub as well?
|
||||
|
||||
move format/* to deprecated
|
||||
|
@ -492,6 +492,12 @@ if test x"$with_cfitsio" != "xno"; then
|
||||
])
|
||||
fi
|
||||
|
||||
if test x"$with_cfitsio" = x"yes"; then
|
||||
AM_CONDITIONAL(HAVE_CFITSIO, true)
|
||||
else
|
||||
AM_CONDITIONAL(HAVE_CFITSIO, false)
|
||||
fi
|
||||
|
||||
# pangoft2
|
||||
AC_ARG_WITH([pangoft2],
|
||||
AS_HELP_STRING([--without-pangoft2],
|
||||
|
@ -19,6 +19,20 @@ EXTRA_DIST += \
|
||||
openexrload.c
|
||||
endif
|
||||
|
||||
if HAVE_CFITSIO
|
||||
libforeign_la_SOURCES += \
|
||||
fits.h \
|
||||
fits.c \
|
||||
fitssave.c \
|
||||
fitsload.c
|
||||
else
|
||||
EXTRA_DIST += \
|
||||
fits.h \
|
||||
fits.c \
|
||||
fitssave.c \
|
||||
fitsload.c
|
||||
endif
|
||||
|
||||
if HAVE_TIFF
|
||||
libforeign_la_SOURCES += \
|
||||
tiff.h \
|
||||
|
739
libvips/foreign/fits.c
Normal file
739
libvips/foreign/fits.c
Normal file
@ -0,0 +1,739 @@
|
||||
/* Read FITS files with cfitsio
|
||||
*
|
||||
* 26/10/10
|
||||
* - from matlab.c
|
||||
* 27/10/10
|
||||
* - oops, forgot to init status in close
|
||||
* 30/11/10
|
||||
* - set RGB16/GREY16 if appropriate
|
||||
* - allow up to 10 dimensions as long as they are empty
|
||||
* 27/1/11
|
||||
* - lazy read
|
||||
* 31/1/11
|
||||
* - read in planes and combine with im_bandjoin()
|
||||
* - read whole tiles with fits_read_subset() when we can
|
||||
* 17/3/11
|
||||
* - renames, updates etc. ready for adding fits write
|
||||
* - fits write!
|
||||
* 21/3/11
|
||||
* - read/write metadata as whole records to avoid changing things
|
||||
* - cast input to a supported format
|
||||
* - bandsplit for write
|
||||
* 13/12/11
|
||||
* - redo as a set of fns ready for wrapping in a new-style class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#include <fitsio.h>
|
||||
|
||||
#include "fits.h"
|
||||
|
||||
/*
|
||||
|
||||
TODO
|
||||
|
||||
- ask Doug for a test colour image
|
||||
|
||||
found WFPC2u5780205r_c0fx.fits on the fits samples page,
|
||||
but it's tiny
|
||||
|
||||
- test performance
|
||||
|
||||
- vips__fits_read() makes rather ugly bandjoins, fix
|
||||
|
||||
*/
|
||||
|
||||
/* vips only supports 3 dimensions, but we allow up to MAX_DIMENSIONS as long
|
||||
* as the higher dimensions are all empty. If you change this value, change
|
||||
* fits2vips_get_header() as well.
|
||||
*/
|
||||
#define MAX_DIMENSIONS (10)
|
||||
|
||||
/* What we track during a cfitsio-file read or write.
|
||||
*/
|
||||
typedef struct {
|
||||
char *filename;
|
||||
VipsImage *image;
|
||||
|
||||
fitsfile *fptr;
|
||||
int datatype;
|
||||
int naxis;
|
||||
long long int naxes[MAX_DIMENSIONS];
|
||||
|
||||
GMutex *lock; /* Lock fits_*() calls with this */
|
||||
|
||||
/* Set this to -1 to read all bands, or a +ve int to read a specific
|
||||
* band.
|
||||
*/
|
||||
int band_select;
|
||||
|
||||
/* We split bands up for write into this buffer.
|
||||
*/
|
||||
PEL *buffer;
|
||||
} VipsFits;
|
||||
|
||||
const char *vips__fits_suffs[] = { ".fits", NULL };
|
||||
|
||||
static void
|
||||
vips_fits_error( int status )
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
fits_get_errstatus( status, buf );
|
||||
vips_error( "fits", "%s", buf );
|
||||
}
|
||||
|
||||
/* Shut down. Can be called many times.
|
||||
*/
|
||||
static void
|
||||
vips_fits_close( VipsFits *fits )
|
||||
{
|
||||
VIPS_FREE( fits->filename );
|
||||
VIPS_FREEF( g_mutex_free, fits->lock );
|
||||
|
||||
if( fits->fptr ) {
|
||||
int status;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_close_file( fits->fptr, &status ) )
|
||||
vips_fits_error( status );
|
||||
|
||||
fits->fptr = NULL;
|
||||
}
|
||||
|
||||
VIPS_FREE( fits->buffer );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_fits_close_cb( VipsImage *image, VipsFits *fits )
|
||||
{
|
||||
vips_fits_close( fits );
|
||||
}
|
||||
|
||||
static VipsFits *
|
||||
vips_fits_new_read( const char *filename, VipsImage *out, int band_select )
|
||||
{
|
||||
VipsFits *fits;
|
||||
int status;
|
||||
|
||||
if( !(fits = VIPS_NEW( out, VipsFits )) )
|
||||
return( NULL );
|
||||
|
||||
fits->filename = vips_strdup( NULL, filename );
|
||||
fits->image = out;
|
||||
fits->fptr = NULL;
|
||||
fits->lock = NULL;
|
||||
fits->band_select = band_select;
|
||||
fits->buffer = NULL;
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( vips_fits_close_cb ), fits );
|
||||
|
||||
status = 0;
|
||||
if( fits_open_file( &fits->fptr, filename, READONLY, &status ) ) {
|
||||
vips_error( "fits", _( "unable to open \"%s\"" ), filename );
|
||||
vips_fits_error( status );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
fits->lock = g_mutex_new();
|
||||
|
||||
return( fits );
|
||||
}
|
||||
|
||||
/* fits image types -> VIPS band formats. VIPS doesn't have 64-bit int, so no
|
||||
* entry for LONGLONG_IMG (64).
|
||||
*/
|
||||
static int fits2vips_formats[][3] = {
|
||||
{ BYTE_IMG, VIPS_FORMAT_UCHAR, TBYTE },
|
||||
{ SHORT_IMG, VIPS_FORMAT_USHORT, TUSHORT },
|
||||
{ LONG_IMG, VIPS_FORMAT_UINT, TUINT },
|
||||
{ FLOAT_IMG, VIPS_FORMAT_FLOAT, TFLOAT },
|
||||
{ DOUBLE_IMG, VIPS_FORMAT_DOUBLE, TDOUBLE }
|
||||
};
|
||||
|
||||
static int
|
||||
vips_fits_get_header( VipsFits *fits, VipsImage *out )
|
||||
{
|
||||
int status;
|
||||
int bitpix;
|
||||
|
||||
int width, height, bands, format, type;
|
||||
int keysexist;
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_get_img_paramll( fits->fptr,
|
||||
10, &bitpix, &fits->naxis, fits->naxes, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis );
|
||||
for( i = 0; i < fits->naxis; i++ )
|
||||
VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
width = 1;
|
||||
height = 1;
|
||||
bands = 1;
|
||||
switch( fits->naxis ) {
|
||||
/* If you add more dimensions here, adjust data read below. See also
|
||||
* the definition of MAX_DIMENSIONS above.
|
||||
*/
|
||||
case 10:
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
for( i = fits->naxis; i > 3; i-- )
|
||||
if( fits->naxes[i - 1] != 1 ) {
|
||||
vips_error( "fits",
|
||||
"%s", _( "dimensions above 3 "
|
||||
"must be size 1" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
case 3:
|
||||
bands = fits->naxes[2];
|
||||
|
||||
case 2:
|
||||
height = fits->naxes[1];
|
||||
|
||||
case 1:
|
||||
width = fits->naxes[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
vips_error( "fits", _( "bad number of axis %d" ), fits->naxis );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Are we in one-band mode?
|
||||
*/
|
||||
if( fits->band_select != -1 )
|
||||
bands = 1;
|
||||
|
||||
/* Get image format. We want the 'raw' format of the image, our caller
|
||||
* can convert using the meta info if they want.
|
||||
*/
|
||||
for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ )
|
||||
if( fits2vips_formats[i][0] == bitpix )
|
||||
break;
|
||||
if( i == VIPS_NUMBER( fits2vips_formats ) ) {
|
||||
vips_error( "fits", _( "unsupported bitpix %d\n" ),
|
||||
bitpix );
|
||||
return( -1 );
|
||||
}
|
||||
format = fits2vips_formats[i][1];
|
||||
fits->datatype = fits2vips_formats[i][2];
|
||||
|
||||
if( bands == 1 ) {
|
||||
if( format == VIPS_FORMAT_USHORT )
|
||||
type = VIPS_INTERPRETATION_GREY16;
|
||||
else
|
||||
type = VIPS_INTERPRETATION_B_W;
|
||||
}
|
||||
else if( bands == 3 ) {
|
||||
if( format == VIPS_FORMAT_USHORT )
|
||||
type = VIPS_INTERPRETATION_RGB16;
|
||||
else
|
||||
type = VIPS_INTERPRETATION_RGB;
|
||||
}
|
||||
else
|
||||
type = VIPS_INTERPRETATION_MULTIBAND;
|
||||
|
||||
vips_image_init_fields( out,
|
||||
width, height, bands,
|
||||
format,
|
||||
VIPS_CODING_NONE, type, 1.0, 1.0 );
|
||||
vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
|
||||
|
||||
/* Read all keys into meta.
|
||||
*/
|
||||
if( fits_get_hdrspace( fits->fptr, &keysexist, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
for( i = 0; i < keysexist; i++ ) {
|
||||
char record[81];
|
||||
char vipsname[100];
|
||||
|
||||
if( fits_read_record( fits->fptr, i + 1, record, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips: setting meta on vips image:\n" );
|
||||
VIPS_DEBUG_MSG( " record == \"%s\"\n", record );
|
||||
|
||||
/* FITS lets keys repeat. For example, HISTORY appears many
|
||||
* times, each time with a fresh line of history attached. We
|
||||
* have to include the key index in the vips name we assign.
|
||||
*/
|
||||
|
||||
vips_snprintf( vipsname, 100, "fits-%d", i );
|
||||
vips_image_set_string( out, vipsname, record );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__fits_read_header( const char *filename, VipsImage *out )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips_header: reading \"%s\"\n", filename );
|
||||
|
||||
if( !(fits = vips_fits_new_read( filename, out, -1 )) ||
|
||||
vips_fits_get_header( fits, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
fits2vips_generate( VipsRegion *out,
|
||||
void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
Rect *r = &out->valid;
|
||||
|
||||
PEL *q;
|
||||
int z;
|
||||
int status;
|
||||
|
||||
long fpixel[MAX_DIMENSIONS];
|
||||
long lpixel[MAX_DIMENSIONS];
|
||||
long inc[MAX_DIMENSIONS];
|
||||
|
||||
status = 0;
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips_generate: "
|
||||
"generating left = %d, top = %d, width = %d, height = %d\n",
|
||||
r->left, r->top, r->width, r->height );
|
||||
|
||||
/* Special case: the region we are writing to is exactly the width we
|
||||
* need, ie. we can read a rectangular area into it.
|
||||
*/
|
||||
if( VIPS_REGION_LSKIP( out ) == VIPS_REGION_SIZEOF_LINE( out ) ) {
|
||||
VIPS_DEBUG_MSG( "fits2vips_generate: block read\n" );
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
fpixel[z] = 1;
|
||||
fpixel[0] = r->left + 1;
|
||||
fpixel[1] = r->top + 1;
|
||||
fpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
lpixel[z] = 1;
|
||||
lpixel[0] = VIPS_RECT_RIGHT( r );
|
||||
lpixel[1] = VIPS_RECT_BOTTOM( r );
|
||||
lpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
inc[z] = 1;
|
||||
|
||||
q = (PEL *) VIPS_REGION_ADDR( out, r->left, r->top );
|
||||
|
||||
/* Break on ffgsv() for this call.
|
||||
*/
|
||||
g_mutex_lock( fits->lock );
|
||||
if( fits_read_subset( fits->fptr, fits->datatype,
|
||||
fpixel, lpixel, inc,
|
||||
NULL, q, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
g_mutex_unlock( fits->lock );
|
||||
return( -1 );
|
||||
}
|
||||
g_mutex_unlock( fits->lock );
|
||||
}
|
||||
else {
|
||||
int y;
|
||||
|
||||
for( y = r->top; y < VIPS_RECT_BOTTOM( r ); y ++ ) {
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
fpixel[z] = 1;
|
||||
fpixel[0] = r->left + 1;
|
||||
fpixel[1] = y + 1;
|
||||
fpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
lpixel[z] = 1;
|
||||
lpixel[0] = VIPS_RECT_RIGHT( r );
|
||||
lpixel[1] = y + 1;
|
||||
lpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
inc[z] = 1;
|
||||
|
||||
q = (PEL *) VIPS_REGION_ADDR( out, r->left, y );
|
||||
|
||||
/* Break on ffgsv() for this call.
|
||||
*/
|
||||
g_mutex_lock( fits->lock );
|
||||
if( fits_read_subset( fits->fptr, fits->datatype,
|
||||
fpixel, lpixel, inc,
|
||||
NULL, q, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
g_mutex_unlock( fits->lock );
|
||||
return( -1 );
|
||||
}
|
||||
g_mutex_unlock( fits->lock );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
fits2vips( const char *filename, VipsImage *out, int band_select )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
/* The -1 mode is just for reading the header.
|
||||
*/
|
||||
g_assert( band_select >= 0 );
|
||||
|
||||
if( !(fits = vips_fits_new_read( filename, out, band_select )) )
|
||||
return( -1 );
|
||||
if( vips_fits_get_header( fits, out ) ||
|
||||
vips_image_generate( out,
|
||||
NULL, fits2vips_generate, NULL, fits, NULL ) ) {
|
||||
vips_fits_close( fits );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Don't vips_fits_close(), we need it to stick around for the
|
||||
* generate.
|
||||
*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__fits_read( const char *filename, VipsImage *out )
|
||||
{
|
||||
VipsImage *t;
|
||||
int n_bands;
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips: reading \"%s\"\n", filename );
|
||||
|
||||
/* fits is naturally a band-separated format. For single-band images
|
||||
* we can just read out. For many bands we read each band out
|
||||
* separately then join them.
|
||||
*/
|
||||
|
||||
t = vips_image_new();
|
||||
vips_object_local( out, t );
|
||||
if( vips__fits_read_header( filename, t ) )
|
||||
return( -1 );
|
||||
n_bands = t->Bands;
|
||||
|
||||
if( n_bands == 1 ) {
|
||||
t = vips_image_new();
|
||||
vips_object_local( out, t );
|
||||
if( fits2vips( filename, t, 0 ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
VipsImage *acc;
|
||||
int i;
|
||||
|
||||
acc = NULL;
|
||||
for( i = 0; i < n_bands; i++ ) {
|
||||
t = vips_image_new();
|
||||
vips_object_local( out, t );
|
||||
if( fits2vips( filename, t, i ) )
|
||||
return( -1 );
|
||||
|
||||
if( !acc )
|
||||
acc = t;
|
||||
else {
|
||||
if( vips_bandjoin2( acc, t, &acc, NULL ) )
|
||||
return( -1 );
|
||||
vips_object_local( out, acc );
|
||||
}
|
||||
}
|
||||
|
||||
t = acc;
|
||||
}
|
||||
|
||||
if( vips_image_write( t, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__fits_isfits( const char *filename )
|
||||
{
|
||||
fitsfile *fptr;
|
||||
int status;
|
||||
|
||||
VIPS_DEBUG_MSG( "isfits: testing \"%s\"\n", filename );
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_open_image( &fptr, filename, READONLY, &status ) ) {
|
||||
VIPS_DEBUG_MSG( "isfits: error reading \"%s\"\n", filename );
|
||||
#ifdef VIPS_DEBUG
|
||||
vips_fits_error( status );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
fits_close_file( fptr, &status );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
static VipsFits *
|
||||
vips_fits_new_write( VipsImage *in, const char *filename )
|
||||
{
|
||||
VipsFits *fits;
|
||||
int status;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( !(fits = VIPS_NEW( in, VipsFits )) )
|
||||
return( NULL );
|
||||
fits->filename = vips_strdup( in, filename );
|
||||
fits->image = in;
|
||||
fits->fptr = NULL;
|
||||
fits->lock = NULL;
|
||||
fits->band_select = -1;
|
||||
fits->buffer = NULL;
|
||||
g_signal_connect( in, "close",
|
||||
G_CALLBACK( vips_fits_close_cb ), fits );
|
||||
|
||||
if( !(fits->filename = vips_strdup( NULL, filename )) )
|
||||
return( NULL );
|
||||
|
||||
/* We need to be able to hold one scanline of one band.
|
||||
*/
|
||||
if( !(fits->buffer = VIPS_ARRAY( NULL,
|
||||
VIPS_IMAGE_SIZEOF_ELEMENT( in ) * in->Xsize, PEL )) )
|
||||
return( NULL );
|
||||
|
||||
/* fits_create_file() will fail if there's a file of thet name, unless
|
||||
* we put a "!" in front ofthe filename. This breaks conventions with
|
||||
* the rest of vips, so just unlink explicitly.
|
||||
*/
|
||||
g_unlink( filename );
|
||||
|
||||
if( fits_create_file( &fits->fptr, filename, &status ) ) {
|
||||
vips_error( "fits",
|
||||
_( "unable to write to \"%s\"" ), filename );
|
||||
vips_fits_error( status );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
fits->lock = g_mutex_new();
|
||||
|
||||
return( fits );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_fits_write_meta( VipsImage *image,
|
||||
const char *field, GValue *value, void *a )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
|
||||
int status;
|
||||
const char *value_str;
|
||||
|
||||
status = 0;
|
||||
|
||||
/* We want fields which start "fits-".
|
||||
*/
|
||||
if( !vips_isprefix( "fits-", field ) )
|
||||
return( NULL );
|
||||
|
||||
/* The value should be a refstring, since we wrote it in fits2vips
|
||||
* above ^^.
|
||||
*/
|
||||
value_str = vips_value_get_ref_string( value, NULL );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_fits_write_meta: setting meta on fits image:\n" );
|
||||
VIPS_DEBUG_MSG( " value == \"%s\"\n", value_str );
|
||||
|
||||
if( fits_write_record( fits->fptr, value_str, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( a );
|
||||
}
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_fits_set_header( VipsFits *fits, VipsImage *in )
|
||||
{
|
||||
int status;
|
||||
int bitpix;
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
|
||||
fits->naxis = 3;
|
||||
fits->naxes[0] = in->Xsize;
|
||||
fits->naxes[1] = in->Ysize;
|
||||
fits->naxes[2] = in->Bands;
|
||||
|
||||
for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ )
|
||||
if( fits2vips_formats[i][1] == in->BandFmt )
|
||||
break;
|
||||
if( i == VIPS_NUMBER( fits2vips_formats ) ) {
|
||||
vips_error( "fits",
|
||||
_( "unsupported BandFmt %d\n" ), in->BandFmt );
|
||||
return( -1 );
|
||||
}
|
||||
bitpix = fits2vips_formats[i][0];
|
||||
fits->datatype = fits2vips_formats[i][2];
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis );
|
||||
for( i = 0; i < fits->naxis; i++ )
|
||||
VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] );
|
||||
VIPS_DEBUG_MSG( "bitpix = %d\n", bitpix );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
if( fits_create_imgll( fits->fptr, bitpix, fits->naxis,
|
||||
fits->naxes, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_image_map( in,
|
||||
(VipsImageMapFn) vips_fits_write_meta, fits ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_fits_write( VipsRegion *region, VipsRect *area, void *a )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
VipsImage *image = fits->image;
|
||||
int es = VIPS_IMAGE_SIZEOF_ELEMENT( image );
|
||||
int ps = VIPS_IMAGE_SIZEOF_PEL( image );
|
||||
|
||||
int status;
|
||||
int y, b, x, k;
|
||||
|
||||
status = 0;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_fits_write: "
|
||||
"writing left = %d, top = %d, width = %d, height = %d\n",
|
||||
area->left, area->top, area->width, area->height );
|
||||
|
||||
/* We need to write a band at a time. We can't bandsplit in vips,
|
||||
* since vips_sink_disc() can't loop over many images at once, sadly.
|
||||
*/
|
||||
|
||||
for( y = 0; y < area->height; y++ ) {
|
||||
PEL *p = (PEL *) VIPS_REGION_ADDR( region,
|
||||
area->left, area->top + y );
|
||||
|
||||
for( b = 0; b < image->Bands; b++ ) {
|
||||
PEL *p1, *q;
|
||||
long fpixel[3];
|
||||
|
||||
p1 = p + b * es;
|
||||
q = fits->buffer;
|
||||
|
||||
for( x = 0; x < area->width; x++ ) {
|
||||
for( k = 0; k < es; k++ )
|
||||
q[k] = p1[k];
|
||||
|
||||
q += es;
|
||||
p1 += ps;
|
||||
}
|
||||
|
||||
fpixel[0] = area->left + 1;
|
||||
fpixel[1] = area->top + y + 1;
|
||||
fpixel[2] = b + 1;
|
||||
|
||||
/* No need to lock, write functions are single-threaded.
|
||||
*/
|
||||
|
||||
if( fits_write_pix( fits->fptr, fits->datatype,
|
||||
fpixel, area->width, fits->buffer,
|
||||
&status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
vips__fits_write( VipsImage *in, const char *filename )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips2fits: writing \"%s\"\n", filename );
|
||||
|
||||
if( !(fits = vips_fits_new_write( in, filename )) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_fits_set_header( fits, fits->image ) ||
|
||||
vips_sink_disc( fits->image, vips_fits_write, fits ) ) {
|
||||
vips_fits_close( fits );
|
||||
return( -1 );
|
||||
}
|
||||
vips_fits_close( fits );
|
||||
|
||||
return( 0 );
|
||||
}
|
49
libvips/foreign/fits.h
Normal file
49
libvips/foreign/fits.h
Normal file
@ -0,0 +1,49 @@
|
||||
/* defs for fits read/write
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Copyright (C) 1991-2005 The National Gallery
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIPS_FITS_H
|
||||
#define VIPS_FITS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
extern const char *vips__fits_suffs[];
|
||||
|
||||
int vips__fits_isfits( const char *filename );
|
||||
int vips__fits_read_header( const char *filename, VipsImage *out );
|
||||
int vips__fits_read( const char *filename, VipsImage *out );
|
||||
|
||||
int vips__fits_write( VipsImage *in, const char *filename );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*VIPS_FITS_H*/
|
119
libvips/foreign/fitsload.c
Normal file
119
libvips/foreign/fitsload.c
Normal file
@ -0,0 +1,119 @@
|
||||
/* load fits from a file
|
||||
*
|
||||
* 5/12/11
|
||||
* - from openslideload.c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/buf.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "fits.h"
|
||||
|
||||
typedef struct _VipsForeignLoadFits {
|
||||
VipsForeignLoad parent_object;
|
||||
|
||||
/* Filename for load.
|
||||
*/
|
||||
char *filename;
|
||||
|
||||
} VipsForeignLoadFits;
|
||||
|
||||
typedef VipsForeignLoadClass VipsForeignLoadFitsClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsForeignLoadFits, vips_foreign_load_fits,
|
||||
VIPS_TYPE_FOREIGN_LOAD );
|
||||
|
||||
static int
|
||||
vips_foreign_load_fits_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadFits *fits = (VipsForeignLoadFits *) load;
|
||||
|
||||
if( vips__fits_read_header( fits->filename, load->out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_fits_load( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadFits *fits = (VipsForeignLoadFits *) load;
|
||||
|
||||
if( vips__fits_read( fits->filename, load->real ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_fits_class_init( VipsForeignLoadFitsClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "fitsload";
|
||||
object_class->description = _( "load a FITS image" );
|
||||
|
||||
foreign_class->suffs = vips__fits_suffs;
|
||||
|
||||
load_class->is_a = vips__fits_isfits;
|
||||
load_class->header = vips_foreign_load_fits_header;
|
||||
load_class->load = vips_foreign_load_fits_load;
|
||||
|
||||
VIPS_ARG_STRING( class, "filename", 1,
|
||||
_( "Filename" ),
|
||||
_( "Filename to load from" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignLoadFits, filename ),
|
||||
NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_fits_init( VipsForeignLoadFits *fits )
|
||||
{
|
||||
}
|
130
libvips/foreign/fitssave.c
Normal file
130
libvips/foreign/fitssave.c
Normal file
@ -0,0 +1,130 @@
|
||||
/* save to fits
|
||||
*
|
||||
* 2/12/11
|
||||
* - wrap a class around the fits writer
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG_VERBOSE
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
#include "fits.h"
|
||||
|
||||
typedef struct _VipsForeignSaveFits {
|
||||
VipsForeignSave parent_object;
|
||||
|
||||
/* Filename for save.
|
||||
*/
|
||||
char *filename;
|
||||
|
||||
} VipsForeignSaveFits;
|
||||
|
||||
typedef VipsForeignSaveClass VipsForeignSaveFitsClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsForeignSaveFits, vips_foreign_save_fits,
|
||||
VIPS_TYPE_FOREIGN_SAVE );
|
||||
|
||||
static int
|
||||
vips_foreign_save_fits_build( VipsObject *object )
|
||||
{
|
||||
VipsForeignSave *save = (VipsForeignSave *) object;
|
||||
VipsForeignSaveFits *fits = (VipsForeignSaveFits *) object;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_foreign_save_fits_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips__fits_write( save->ready, fits->filename ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Save a bit of typing.
|
||||
*/
|
||||
#define UC VIPS_FORMAT_UCHAR
|
||||
#define C VIPS_FORMAT_CHAR
|
||||
#define US VIPS_FORMAT_USHORT
|
||||
#define S VIPS_FORMAT_SHORT
|
||||
#define UI VIPS_FORMAT_UINT
|
||||
#define I VIPS_FORMAT_INT
|
||||
#define F VIPS_FORMAT_FLOAT
|
||||
#define X VIPS_FORMAT_COMPLEX
|
||||
#define D VIPS_FORMAT_DOUBLE
|
||||
#define DX VIPS_FORMAT_DPCOMPLEX
|
||||
|
||||
static int bandfmt_fits[10] = {
|
||||
/* UC C US S UI I F X D DX */
|
||||
UC, UC, US, US, UI, UI, F, X, D, DX
|
||||
};
|
||||
|
||||
static void
|
||||
vips_foreign_save_fits_class_init( VipsForeignSaveFitsClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
|
||||
VipsForeignSaveClass *save_class = (VipsForeignSaveClass *) class;
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "fitssave";
|
||||
object_class->description = _( "save image to fits file" );
|
||||
object_class->build = vips_foreign_save_fits_build;
|
||||
|
||||
foreign_class->suffs = vips__fits_suffs;
|
||||
|
||||
save_class->saveable = VIPS_SAVEABLE_ANY;
|
||||
save_class->format_table = bandfmt_fits;
|
||||
|
||||
VIPS_ARG_STRING( class, "filename", 1,
|
||||
_( "Filename" ),
|
||||
_( "Filename to save to" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveFits, filename ),
|
||||
NULL );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_fits_init( VipsForeignSaveFits *fits )
|
||||
{
|
||||
}
|
@ -1154,6 +1154,8 @@ vips_foreign_write_options( VipsImage *in, const char *filename )
|
||||
void
|
||||
vips_foreign_operation_init( void )
|
||||
{
|
||||
extern GType vips_foreign_load_fits_get_type( void );
|
||||
extern GType vips_foreign_save_fits_get_type( void );
|
||||
extern GType vips_foreign_load_openexr_get_type( void );
|
||||
extern GType vips_foreign_load_openslide_get_type( void );
|
||||
extern GType vips_foreign_load_jpeg_file_get_type( void );
|
||||
@ -1183,6 +1185,11 @@ vips_foreign_operation_init( void )
|
||||
vips_foreign_load_openslide_get_type();
|
||||
#endif /*HAVE_OPENSLIDE*/
|
||||
|
||||
#ifdef HAVE_CFITSIO
|
||||
vips_foreign_load_fits_get_type();
|
||||
vips_foreign_save_fits_get_type();
|
||||
#endif /*HAVE_CFITSIO*/
|
||||
|
||||
#ifdef HAVE_OPENEXR
|
||||
vips_foreign_load_openexr_get_type();
|
||||
#endif /*HAVE_OPENEXR*/
|
||||
@ -1600,3 +1607,53 @@ vips_openslideload( const char *filename, VipsImage **out, ... )
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_fitsload:
|
||||
* @filename: file to load
|
||||
* @out: decompressed image
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Read a FITS image file into a VIPS image.
|
||||
*
|
||||
* See also: vips_image_new_from_file().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_fitsload( const char *filename, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "fitsload", ap, filename, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_fitssave:
|
||||
* @in: image to save
|
||||
* @filename: file to write to
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* Write a VIPS image to a file as FITS.
|
||||
*
|
||||
* See also: vips_image_write_file().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_fitssave( VipsImage *in, const char *filename, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, filename );
|
||||
result = vips_call_split( "fitssave", ap, in, filename );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
@ -1,24 +1,7 @@
|
||||
/* Read FITS files with cfitsio
|
||||
*
|
||||
* 26/10/10
|
||||
* - from matlab.c
|
||||
* 27/10/10
|
||||
* - oops, forgot to init status in close
|
||||
* 30/11/10
|
||||
* - set RGB16/GREY16 if appropriate
|
||||
* - allow up to 10 dimensions as long as they are empty
|
||||
* 27/1/11
|
||||
* - lazy read
|
||||
* 31/1/11
|
||||
* - read in planes and combine with im_bandjoin()
|
||||
* - read whole tiles with fits_read_subset() when we can
|
||||
* 17/3/11
|
||||
* - renames, updates etc. ready for adding fits write
|
||||
* - fits write!
|
||||
* 21/3/11
|
||||
* - read/write metadata as whole records to avoid changing things
|
||||
* - cast input to a supported format
|
||||
* - bandsplit for write
|
||||
* 13/12/11
|
||||
* - just a compat stub now
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -47,32 +30,11 @@
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#ifndef HAVE_CFITSIO
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
/* We call this from format_dispatch.c so we need a stub.
|
||||
*/
|
||||
int
|
||||
im_fits2vips( const char *filename, VipsImage *out )
|
||||
{
|
||||
im_error( "im_fits2vips", "%s",
|
||||
_( "FITS support disabled" ) );
|
||||
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#else /*HAVE_CFITSIO*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -81,741 +43,37 @@ im_fits2vips( const char *filename, VipsImage *out )
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
#include <fitsio.h>
|
||||
|
||||
/*
|
||||
|
||||
TODO
|
||||
|
||||
- ask Doug for a test colour image
|
||||
|
||||
found WFPC2u5780205r_c0fx.fits on the fits samples page,
|
||||
but it's tiny
|
||||
|
||||
- test performance
|
||||
|
||||
*/
|
||||
|
||||
/* vips only supports 3 dimensions, but we allow up to MAX_DIMENSIONS as long
|
||||
* as the higher dimensions are all empty. If you change this value, change
|
||||
* fits2vips_get_header() as well.
|
||||
*/
|
||||
#define MAX_DIMENSIONS (10)
|
||||
|
||||
/* What we track during a cfitsio-file read or write.
|
||||
*/
|
||||
typedef struct {
|
||||
char *filename;
|
||||
VipsImage *image;
|
||||
|
||||
fitsfile *fptr;
|
||||
int datatype;
|
||||
int naxis;
|
||||
long long int naxes[MAX_DIMENSIONS];
|
||||
|
||||
GMutex *lock; /* Lock fits_*() calls with this */
|
||||
|
||||
/* Set this to -1 to read all bands, or a +ve int to read a specific
|
||||
* band.
|
||||
*/
|
||||
int band_select;
|
||||
|
||||
/* We split bands up for write into this buffer.
|
||||
*/
|
||||
PEL *buffer;
|
||||
} VipsFits;
|
||||
|
||||
static void
|
||||
vips_fits_error( int status )
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
fits_get_errstatus( status, buf );
|
||||
im_error( "fits", "%s", buf );
|
||||
}
|
||||
|
||||
/* Shut down. Can be called many times.
|
||||
*/
|
||||
static void
|
||||
vips_fits_close( VipsFits *fits )
|
||||
{
|
||||
VIPS_FREE( fits->filename );
|
||||
VIPS_FREEF( g_mutex_free, fits->lock );
|
||||
|
||||
if( fits->fptr ) {
|
||||
int status;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_close_file( fits->fptr, &status ) )
|
||||
vips_fits_error( status );
|
||||
|
||||
fits->fptr = NULL;
|
||||
}
|
||||
|
||||
VIPS_FREE( fits->buffer );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_fits_close_cb( VipsImage *image, VipsFits *fits )
|
||||
{
|
||||
vips_fits_close( fits );
|
||||
}
|
||||
|
||||
static VipsFits *
|
||||
vips_fits_new_read( const char *filename, VipsImage *out, int band_select )
|
||||
{
|
||||
VipsFits *fits;
|
||||
int status;
|
||||
|
||||
if( !(fits = VIPS_NEW( out, VipsFits )) )
|
||||
return( NULL );
|
||||
|
||||
fits->filename = im_strdup( NULL, filename );
|
||||
fits->image = out;
|
||||
fits->fptr = NULL;
|
||||
fits->lock = NULL;
|
||||
fits->band_select = band_select;
|
||||
fits->buffer = NULL;
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( vips_fits_close_cb ), fits );
|
||||
|
||||
status = 0;
|
||||
if( fits_open_file( &fits->fptr, filename, READONLY, &status ) ) {
|
||||
im_error( "fits", _( "unable to open \"%s\"" ), filename );
|
||||
vips_fits_error( status );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
fits->lock = g_mutex_new();
|
||||
|
||||
return( fits );
|
||||
}
|
||||
|
||||
/* fits image types -> VIPS band formats. VIPS doesn't have 64-bit int, so no
|
||||
* entry for LONGLONG_IMG (64).
|
||||
*/
|
||||
static int fits2vips_formats[][3] = {
|
||||
{ BYTE_IMG, VIPS_FORMAT_UCHAR, TBYTE },
|
||||
{ SHORT_IMG, VIPS_FORMAT_USHORT, TUSHORT },
|
||||
{ LONG_IMG, VIPS_FORMAT_UINT, TUINT },
|
||||
{ FLOAT_IMG, VIPS_FORMAT_FLOAT, TFLOAT },
|
||||
{ DOUBLE_IMG, VIPS_FORMAT_DOUBLE, TDOUBLE }
|
||||
};
|
||||
|
||||
static int
|
||||
vips_fits_get_header( VipsFits *fits, VipsImage *out )
|
||||
{
|
||||
int status;
|
||||
int bitpix;
|
||||
|
||||
int width, height, bands, format, type;
|
||||
int keysexist;
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_get_img_paramll( fits->fptr,
|
||||
10, &bitpix, &fits->naxis, fits->naxes, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis );
|
||||
for( i = 0; i < fits->naxis; i++ )
|
||||
VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
width = 1;
|
||||
height = 1;
|
||||
bands = 1;
|
||||
switch( fits->naxis ) {
|
||||
/* If you add more dimensions here, adjust data read below. See also
|
||||
* the definition of MAX_DIMENSIONS above.
|
||||
*/
|
||||
case 10:
|
||||
case 9:
|
||||
case 8:
|
||||
case 7:
|
||||
case 6:
|
||||
case 5:
|
||||
case 4:
|
||||
for( i = fits->naxis; i > 3; i-- )
|
||||
if( fits->naxes[i - 1] != 1 ) {
|
||||
im_error( "fits", "%s", _( "dimensions above 3 "
|
||||
"must be size 1" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
case 3:
|
||||
bands = fits->naxes[2];
|
||||
|
||||
case 2:
|
||||
height = fits->naxes[1];
|
||||
|
||||
case 1:
|
||||
width = fits->naxes[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
im_error( "fits", _( "bad number of axis %d" ), fits->naxis );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Are we in one-band mode?
|
||||
*/
|
||||
if( fits->band_select != -1 )
|
||||
bands = 1;
|
||||
|
||||
/* Get image format. We want the 'raw' format of the image, our caller
|
||||
* can convert using the meta info if they want.
|
||||
*/
|
||||
for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ )
|
||||
if( fits2vips_formats[i][0] == bitpix )
|
||||
break;
|
||||
if( i == VIPS_NUMBER( fits2vips_formats ) ) {
|
||||
im_error( "fits", _( "unsupported bitpix %d\n" ),
|
||||
bitpix );
|
||||
return( -1 );
|
||||
}
|
||||
format = fits2vips_formats[i][1];
|
||||
fits->datatype = fits2vips_formats[i][2];
|
||||
|
||||
if( bands == 1 ) {
|
||||
if( format == VIPS_FORMAT_USHORT )
|
||||
type = VIPS_INTERPRETATION_GREY16;
|
||||
else
|
||||
type = VIPS_INTERPRETATION_B_W;
|
||||
}
|
||||
else if( bands == 3 ) {
|
||||
if( format == VIPS_FORMAT_USHORT )
|
||||
type = VIPS_INTERPRETATION_RGB16;
|
||||
else
|
||||
type = VIPS_INTERPRETATION_RGB;
|
||||
}
|
||||
else
|
||||
type = VIPS_INTERPRETATION_MULTIBAND;
|
||||
|
||||
im_initdesc( out,
|
||||
width, height, bands,
|
||||
im_bits_of_fmt( format ), format,
|
||||
VIPS_CODING_NONE, type, 1.0, 1.0, 0, 0 );
|
||||
|
||||
/* Read all keys into meta.
|
||||
*/
|
||||
if( fits_get_hdrspace( fits->fptr, &keysexist, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
for( i = 0; i < keysexist; i++ ) {
|
||||
char record[81];
|
||||
char vipsname[100];
|
||||
|
||||
if( fits_read_record( fits->fptr, i + 1, record, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips: setting meta on vips image:\n" );
|
||||
VIPS_DEBUG_MSG( " record == \"%s\"\n", record );
|
||||
|
||||
/* FITS lets keys repeat. For example, HISTORY appears many
|
||||
* times, each time with a fresh line of history attached. We
|
||||
* have to include the key index in the vips name we assign.
|
||||
*/
|
||||
|
||||
im_snprintf( vipsname, 100, "fits-%d", i );
|
||||
if( im_meta_set_string( out, vipsname, record ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
fits2vips_header( const char *filename, VipsImage *out )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips_header: reading \"%s\"\n", filename );
|
||||
|
||||
if( !(fits = vips_fits_new_read( filename, out, -1 )) ||
|
||||
vips_fits_get_header( fits, out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
fits2vips_generate( VipsRegion *out, void *seq, void *a, void *b )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
Rect *r = &out->valid;
|
||||
|
||||
PEL *q;
|
||||
int z;
|
||||
int status;
|
||||
|
||||
long fpixel[MAX_DIMENSIONS];
|
||||
long lpixel[MAX_DIMENSIONS];
|
||||
long inc[MAX_DIMENSIONS];
|
||||
|
||||
status = 0;
|
||||
|
||||
VIPS_DEBUG_MSG( "fits2vips_generate: "
|
||||
"generating left = %d, top = %d, width = %d, height = %d\n",
|
||||
r->left, r->top, r->width, r->height );
|
||||
|
||||
/* Special case: the region we are writing to is exactly the width we
|
||||
* need, ie. we can read a rectangular area into it.
|
||||
*/
|
||||
if( VIPS_REGION_LSKIP( out ) == VIPS_REGION_SIZEOF_LINE( out ) ) {
|
||||
VIPS_DEBUG_MSG( "fits2vips_generate: block read\n" );
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
fpixel[z] = 1;
|
||||
fpixel[0] = r->left + 1;
|
||||
fpixel[1] = r->top + 1;
|
||||
fpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
lpixel[z] = 1;
|
||||
lpixel[0] = VIPS_RECT_RIGHT( r );
|
||||
lpixel[1] = VIPS_RECT_BOTTOM( r );
|
||||
lpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
inc[z] = 1;
|
||||
|
||||
q = (PEL *) VIPS_REGION_ADDR( out, r->left, r->top );
|
||||
|
||||
/* Break on ffgsv() for this call.
|
||||
*/
|
||||
g_mutex_lock( fits->lock );
|
||||
if( fits_read_subset( fits->fptr, fits->datatype,
|
||||
fpixel, lpixel, inc,
|
||||
NULL, q, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
g_mutex_unlock( fits->lock );
|
||||
return( -1 );
|
||||
}
|
||||
g_mutex_unlock( fits->lock );
|
||||
}
|
||||
else {
|
||||
int y;
|
||||
|
||||
for( y = r->top; y < VIPS_RECT_BOTTOM( r ); y ++ ) {
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
fpixel[z] = 1;
|
||||
fpixel[0] = r->left + 1;
|
||||
fpixel[1] = y + 1;
|
||||
fpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
lpixel[z] = 1;
|
||||
lpixel[0] = VIPS_RECT_RIGHT( r );
|
||||
lpixel[1] = y + 1;
|
||||
lpixel[2] = fits->band_select + 1;
|
||||
|
||||
for( z = 0; z < MAX_DIMENSIONS; z++ )
|
||||
inc[z] = 1;
|
||||
|
||||
q = (PEL *) VIPS_REGION_ADDR( out, r->left, y );
|
||||
|
||||
/* Break on ffgsv() for this call.
|
||||
*/
|
||||
g_mutex_lock( fits->lock );
|
||||
if( fits_read_subset( fits->fptr, fits->datatype,
|
||||
fpixel, lpixel, inc,
|
||||
NULL, q, NULL, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
g_mutex_unlock( fits->lock );
|
||||
return( -1 );
|
||||
}
|
||||
g_mutex_unlock( fits->lock );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
fits2vips( const char *filename, VipsImage *out, int band_select )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
/* The -1 mode is just for reading the header.
|
||||
*/
|
||||
g_assert( band_select >= 0 );
|
||||
|
||||
if( !(fits = vips_fits_new_read( filename, out, band_select )) )
|
||||
return( -1 );
|
||||
if( vips_fits_get_header( fits, out ) ||
|
||||
im_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ) ||
|
||||
im_generate( out,
|
||||
NULL, fits2vips_generate, NULL, fits, NULL ) ) {
|
||||
vips_fits_close( fits );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Don't vips_fits_close(), we need it to stick around for the
|
||||
* generate.
|
||||
*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_fits2vips:
|
||||
* @filename: file to load
|
||||
* @out: image to write to
|
||||
*
|
||||
* Read a FITS image file into a VIPS image.
|
||||
*
|
||||
* See also: im_vips2fits(), #VipsFormat.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
im_fits2vips( const char *filename, VipsImage *out )
|
||||
{
|
||||
VipsImage *t;
|
||||
int n_bands;
|
||||
|
||||
VIPS_DEBUG_MSG( "im_fits2vips: reading \"%s\"\n", filename );
|
||||
|
||||
/* fits is naturally a band-separated format. For single-band images,
|
||||
* we can just read out. For many bands, we read each band out
|
||||
* separately then join them.
|
||||
*/
|
||||
|
||||
if( !(t = vips_image_new()) ||
|
||||
vips_object_local( out, t ) ||
|
||||
fits2vips_header( filename, t ) )
|
||||
if( vips_fitsload( filename, &t, NULL ) )
|
||||
return( -1 );
|
||||
n_bands = t->Bands;
|
||||
|
||||
if( n_bands == 1 ) {
|
||||
if( !(t = vips_image_new()) ||
|
||||
vips_object_local( out, t ) ||
|
||||
fits2vips( filename, t, 0 ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
VipsImage *acc;
|
||||
int i;
|
||||
|
||||
acc = NULL;
|
||||
for( i = 0; i < n_bands; i++ ) {
|
||||
if( !(t = vips_image_new()) ||
|
||||
vips_object_local( out, t ) ||
|
||||
fits2vips( filename, t, i ) )
|
||||
return( -1 );
|
||||
|
||||
if( !acc )
|
||||
acc = t;
|
||||
else {
|
||||
VipsImage *t2;
|
||||
|
||||
if( !(t2 = vips_image_new()) ||
|
||||
vips_object_local( out, t2 ) ||
|
||||
im_bandjoin( acc, t, t2 ) )
|
||||
return( -1 );
|
||||
acc = t2;
|
||||
}
|
||||
}
|
||||
|
||||
t = acc;
|
||||
}
|
||||
|
||||
/* fits has inverted y.
|
||||
*/
|
||||
if( im_flipver( t, out ) )
|
||||
if( vips_image_write( t, out ) ) {
|
||||
g_object_unref( t );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( t );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
isfits( const char *filename )
|
||||
{
|
||||
fitsfile *fptr;
|
||||
int status;
|
||||
|
||||
VIPS_DEBUG_MSG( "isfits: testing \"%s\"\n", filename );
|
||||
|
||||
status = 0;
|
||||
|
||||
if( fits_open_image( &fptr, filename, READONLY, &status ) ) {
|
||||
VIPS_DEBUG_MSG( "isfits: error reading \"%s\"\n", filename );
|
||||
#ifdef VIPS_DEBUG
|
||||
vips_fits_error( status );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
fits_close_file( fptr, &status );
|
||||
|
||||
return( 1 );
|
||||
}
|
||||
|
||||
/* Save a bit of typing.
|
||||
*/
|
||||
#define UC IM_BANDFMT_UCHAR
|
||||
#define C IM_BANDFMT_CHAR
|
||||
#define US IM_BANDFMT_USHORT
|
||||
#define S IM_BANDFMT_SHORT
|
||||
#define UI IM_BANDFMT_UINT
|
||||
#define I IM_BANDFMT_INT
|
||||
#define F IM_BANDFMT_FLOAT
|
||||
#define X IM_BANDFMT_COMPLEX
|
||||
#define D IM_BANDFMT_DOUBLE
|
||||
#define DX IM_BANDFMT_DPCOMPLEX
|
||||
|
||||
/* Type promotion for fits write. fits only has the unsigned int types, plus
|
||||
* float and double.
|
||||
*/
|
||||
static int vips_fits_bandfmt[10] = {
|
||||
/* UC C US S UI I F X D DX */
|
||||
UC, UC, US, US, UI, UI, F, X, D, DX
|
||||
};
|
||||
|
||||
static VipsFits *
|
||||
vips_fits_new_write( VipsImage *in, const char *filename )
|
||||
{
|
||||
VipsImage *flip;
|
||||
VipsImage *type;
|
||||
VipsFits *fits;
|
||||
int status;
|
||||
|
||||
status = 0;
|
||||
|
||||
if( im_check_noncomplex( "im_vips2fits", in ) ||
|
||||
im_check_uncoded( "im_vips2fits", in ) )
|
||||
return( NULL );
|
||||
|
||||
/* Cast to a supported format.
|
||||
*/
|
||||
if( !(type = vips_image_new()) ||
|
||||
vips_object_local( in, type ) ||
|
||||
im_clip2fmt( in, type, vips_fits_bandfmt[in->BandFmt] ) )
|
||||
return( NULL );
|
||||
in = type;
|
||||
|
||||
/* FITS has (0,0) in the bottom left, we need to flip.
|
||||
*/
|
||||
if( !(flip = vips_image_new()) ||
|
||||
vips_object_local( in, flip ) ||
|
||||
im_flipver( in, flip ) )
|
||||
return( NULL );
|
||||
in = flip;
|
||||
|
||||
if( !(fits = VIPS_NEW( in, VipsFits )) )
|
||||
return( NULL );
|
||||
fits->filename = im_strdup( NULL, filename );
|
||||
fits->image = in;
|
||||
fits->fptr = NULL;
|
||||
fits->lock = NULL;
|
||||
fits->band_select = -1;
|
||||
fits->buffer = NULL;
|
||||
g_signal_connect( in, "close",
|
||||
G_CALLBACK( vips_fits_close_cb ), fits );
|
||||
|
||||
if( !(fits->filename = im_strdup( NULL, filename )) )
|
||||
return( NULL );
|
||||
|
||||
/* We need to be able to hold one scanline of one band.
|
||||
*/
|
||||
if( !(fits->buffer = VIPS_ARRAY( NULL,
|
||||
VIPS_IMAGE_SIZEOF_ELEMENT( in ) * in->Xsize, PEL )) )
|
||||
return( NULL );
|
||||
|
||||
/* fits_create_file() will fail if there's a file of thet name, unless
|
||||
* we put a "!" in front ofthe filename. This breaks conventions with
|
||||
* the rest of vips, so just unlink explicitly.
|
||||
*/
|
||||
g_unlink( filename );
|
||||
|
||||
if( fits_create_file( &fits->fptr, filename, &status ) ) {
|
||||
im_error( "fits", _( "unable to write to \"%s\"" ), filename );
|
||||
vips_fits_error( status );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
fits->lock = g_mutex_new();
|
||||
|
||||
return( fits );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_fits_write_meta( VipsImage *image,
|
||||
const char *field, GValue *value, void *a )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
|
||||
int status;
|
||||
const char *value_str;
|
||||
|
||||
status = 0;
|
||||
|
||||
/* We want fields which start "fits-".
|
||||
*/
|
||||
if( !im_isprefix( "fits-", field ) )
|
||||
return( NULL );
|
||||
|
||||
/* The value should be a refstring, since we wrote it in fits2vips
|
||||
* above ^^.
|
||||
*/
|
||||
value_str = im_ref_string_get( value );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_fits_write_meta: setting meta on fits image:\n" );
|
||||
VIPS_DEBUG_MSG( " value == \"%s\"\n", value_str );
|
||||
|
||||
if( fits_write_record( fits->fptr, value_str, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( a );
|
||||
}
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_fits_set_header( VipsFits *fits, VipsImage *in )
|
||||
{
|
||||
int status;
|
||||
int bitpix;
|
||||
int i;
|
||||
|
||||
status = 0;
|
||||
|
||||
fits->naxis = 3;
|
||||
fits->naxes[0] = in->Xsize;
|
||||
fits->naxes[1] = in->Ysize;
|
||||
fits->naxes[2] = in->Bands;
|
||||
|
||||
for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ )
|
||||
if( fits2vips_formats[i][1] == in->BandFmt )
|
||||
break;
|
||||
if( i == VIPS_NUMBER( fits2vips_formats ) ) {
|
||||
im_error( "fits", _( "unsupported BandFmt %d\n" ),
|
||||
in->BandFmt );
|
||||
return( -1 );
|
||||
}
|
||||
bitpix = fits2vips_formats[i][0];
|
||||
fits->datatype = fits2vips_formats[i][2];
|
||||
|
||||
#ifdef VIPS_DEBUG
|
||||
VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis );
|
||||
for( i = 0; i < fits->naxis; i++ )
|
||||
VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] );
|
||||
VIPS_DEBUG_MSG( "bitpix = %d\n", bitpix );
|
||||
#endif /*VIPS_DEBUG*/
|
||||
|
||||
if( fits_create_imgll( fits->fptr, bitpix, fits->naxis,
|
||||
fits->naxes, &status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( im_header_map( in,
|
||||
(im_header_map_fn) vips_fits_write_meta, fits ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_fits_write( VipsRegion *region, VipsRect *area, void *a )
|
||||
{
|
||||
VipsFits *fits = (VipsFits *) a;
|
||||
VipsImage *image = fits->image;
|
||||
int es = VIPS_IMAGE_SIZEOF_ELEMENT( image );
|
||||
int ps = VIPS_IMAGE_SIZEOF_PEL( image );
|
||||
|
||||
int status;
|
||||
int y, b, x, k;
|
||||
|
||||
status = 0;
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_fits_write: "
|
||||
"writing left = %d, top = %d, width = %d, height = %d\n",
|
||||
area->left, area->top, area->width, area->height );
|
||||
|
||||
/* We need to write a band at a time. We can't bandsplit in vips,
|
||||
* since vips_sink_disc() can't loop over many images at once, sadly.
|
||||
*/
|
||||
|
||||
for( y = 0; y < area->height; y++ ) {
|
||||
PEL *p = (PEL *) VIPS_REGION_ADDR( region,
|
||||
area->left, area->top + y );
|
||||
|
||||
for( b = 0; b < image->Bands; b++ ) {
|
||||
PEL *p1, *q;
|
||||
long fpixel[3];
|
||||
|
||||
p1 = p + b * es;
|
||||
q = fits->buffer;
|
||||
|
||||
for( x = 0; x < area->width; x++ ) {
|
||||
for( k = 0; k < es; k++ )
|
||||
q[k] = p1[k];
|
||||
|
||||
q += es;
|
||||
p1 += ps;
|
||||
}
|
||||
|
||||
fpixel[0] = area->left + 1;
|
||||
fpixel[1] = area->top + y + 1;
|
||||
fpixel[2] = b + 1;
|
||||
|
||||
/* No need to lock, write functions are single-threaded.
|
||||
*/
|
||||
|
||||
if( fits_write_pix( fits->fptr, fits->datatype,
|
||||
fpixel, area->width, fits->buffer,
|
||||
&status ) ) {
|
||||
vips_fits_error( status );
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_vips2fits:
|
||||
* @in: image to write
|
||||
* @filename: file to write to
|
||||
*
|
||||
* Write @in to @filename in FITS format.
|
||||
*
|
||||
* See also: im_fits2vips(), #VipsFormat.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
im_vips2fits( VipsImage *in, const char *filename )
|
||||
{
|
||||
VipsFits *fits;
|
||||
|
||||
VIPS_DEBUG_MSG( "im_vips2fits: writing \"%s\"\n", filename );
|
||||
|
||||
if( !(fits = vips_fits_new_write( in, filename )) )
|
||||
if( vips_fitssave( in, filename, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_fits_set_header( fits, fits->image ) ||
|
||||
vips_sink_disc( fits->image, vips_fits_write, fits ) ) {
|
||||
vips_fits_close( fits );
|
||||
return( -1 );
|
||||
}
|
||||
vips_fits_close( fits );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
isfits( const char *name )
|
||||
{
|
||||
return( vips_foreign_is_a( "fitsload", name ) );
|
||||
}
|
||||
|
||||
static const char *fits_suffs[] = { ".fits", NULL };
|
||||
|
||||
/* fits format adds no new members.
|
||||
@ -833,7 +91,7 @@ vips_format_fits_class_init( VipsFormatFitsClass *class )
|
||||
object_class->description = _( "FITS" );
|
||||
|
||||
format_class->is_a = isfits;
|
||||
format_class->header = fits2vips_header;
|
||||
format_class->header = im_fits2vips;
|
||||
format_class->load = im_fits2vips;
|
||||
format_class->save = im_vips2fits;
|
||||
format_class->suffs = fits_suffs;
|
||||
@ -846,4 +104,3 @@ vips_format_fits_init( VipsFormatFits *object )
|
||||
|
||||
G_DEFINE_TYPE( VipsFormatFits, vips_format_fits, VIPS_TYPE_FORMAT );
|
||||
|
||||
#endif /*HAVE_CFITSIO*/
|
||||
|
@ -323,6 +323,11 @@ int vips_tiffsave( VipsImage *in, const char *filename, ... )
|
||||
int vips_openexrload( const char *filename, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
int vips_fitsload( const char *filename, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_fitssave( VipsImage *in, const char *filename, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
Loading…
Reference in New Issue
Block a user