diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fe35621476..c20f79499c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -73,7 +73,7 @@ build-image:
- echo "FROM debian:testing" > Dockerfile
- echo "RUN apt-get update" >> Dockerfile
- echo "RUN apt-get install -y --no-install-recommends \\" >> Dockerfile
- - echo "appstream at-spi2-core automake autopoint build-essential desktop-file-utils ffmpeg gettext ghostscript gi-docgen git glib-networking gobject-introspection graphviz graphviz-dev hicolor-icon-theme iso-codes libaa1-dev libappstream-glib-dev libbz2-dev libdbus-glib-1-dev libexif-dev libgexiv2-dev libgirepository1.0-dev libgs-dev libgtk-3-bin libgtk-3-dev libgudev-1.0-dev libheif-dev libjson-glib-dev libjxl-dev liblcms2-dev liblzma-dev libmng-dev libmypaint-dev libopenexr-dev libpoppler-glib-dev libraw-dev libraw20 librsvg2-dev libspiro-dev libsuitesparse-dev libtiff-dev libtiff5-dev libtool libumfpack5 libwebp-dev libwmf-dev libxmu-dev libxpm-dev luajit meson mypaint-brushes poppler-data python3 python3-pip valac xauth xsltproc xvfb xz-utils yelp-tools" >> Dockerfile
+ - echo "appstream at-spi2-core automake autopoint build-essential desktop-file-utils ffmpeg gettext ghostscript gi-docgen git glib-networking gobject-introspection graphviz graphviz-dev hicolor-icon-theme iso-codes libaa1-dev libappstream-glib-dev libbz2-dev libcfitsio-dev libdbus-glib-1-dev libexif-dev libgexiv2-dev libgirepository1.0-dev libgs-dev libgtk-3-bin libgtk-3-dev libgudev-1.0-dev libheif-dev libjson-glib-dev libjxl-dev liblcms2-dev liblzma-dev libmng-dev libmypaint-dev libopenexr-dev libpoppler-glib-dev libraw-dev libraw20 librsvg2-dev libspiro-dev libsuitesparse-dev libtiff-dev libtiff5-dev libtool libumfpack5 libwebp-dev libwmf-dev libxmu-dev libxpm-dev luajit meson mypaint-brushes poppler-data python3 python3-pip valac xauth xsltproc xvfb xz-utils yelp-tools" >> Dockerfile
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:build-debian-latest --cache=true --cache-ttl=120h
diff --git a/build/flatpak/org.gimp.GIMP-nightly.json b/build/flatpak/org.gimp.GIMP-nightly.json
index 6a225d8cf2..75645981e1 100644
--- a/build/flatpak/org.gimp.GIMP-nightly.json
+++ b/build/flatpak/org.gimp.GIMP-nightly.json
@@ -790,6 +790,26 @@
}
]
},
+ {
+ "name": "cfitsio",
+ "config-opts": [
+ "--enable-reentrant"
+ ],
+ "make-args": ["shared"],
+ "cleanup": [
+ "/include",
+ "/lib/*.a",
+ "/lib/*.la",
+ "/lib/pkgconfig"
+ ],
+ "sources": [
+ {
+ "type": "archive",
+ "url": "http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio-4.2.0.tar.gz",
+ "sha256": "eba53d1b3f6e345632bb09a7b752ec7ced3d63ec5153a848380f3880c5d61889"
+ }
+ ]
+ },
{
"name": "babl",
"buildsystem": "meson",
diff --git a/build/windows/gitlab-ci/build-deps-crossroad.sh b/build/windows/gitlab-ci/build-deps-crossroad.sh
index 6974aca34b..3334093702 100644
--- a/build/windows/gitlab-ci/build-deps-crossroad.sh
+++ b/build/windows/gitlab-ci/build-deps-crossroad.sh
@@ -28,6 +28,7 @@ fi
crossroad install appstream-glib \
atk \
+ cfitsio \
drmingw \
gexiv2 \
glib2 \
diff --git a/build/windows/gitlab-ci/build-gimp-msys2.sh b/build/windows/gitlab-ci/build-gimp-msys2.sh
index 19cfc8354a..cc1b346c13 100644
--- a/build/windows/gitlab-ci/build-gimp-msys2.sh
+++ b/build/windows/gitlab-ci/build-gimp-msys2.sh
@@ -33,6 +33,7 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-atk \
mingw-w64-$MSYS2_ARCH-brotli \
mingw-w64-$MSYS2_ARCH-cairo \
+ mingw-w64-$MSYS2_ARCH-cfitsio \
mingw-w64-$MSYS2_ARCH-drmingw \
mingw-w64-$MSYS2_ARCH-gexiv2 \
mingw-w64-$MSYS2_ARCH-ghostscript \
diff --git a/configure.ac b/configure.ac
index d392af41d6..0c589bb8e8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2206,6 +2206,13 @@ fi
AM_CONDITIONAL(HAVE_DX_DINPUT, test "x$have_dx_dinput" = xyes)
+###################
+# Check for cfitsio
+###################
+
+PKG_CHECK_MODULES(CFITSIO, [cfitsio],, [add_deps_error([cfitsio])])
+MIME_TYPES="$MIME_TYPES;image/fits"
+
####################
# Check for libgudev
diff --git a/meson.build b/meson.build
index 61306587af..0eef5b256a 100644
--- a/meson.build
+++ b/meson.build
@@ -1000,6 +1000,11 @@ if directx_sdk_path != '' and platform_windows
endif
conf.set('HAVE_DX_DINPUT', directx.found())
+cfitsio_dep = dependency('cfitsio', required: true)
+if cfitsio_dep.found()
+ MIMEtypes += 'image/fits'
+endif
+
################################################################################
# Email sending
diff --git a/plug-ins/file-fits/Makefile.am b/plug-ins/file-fits/Makefile.am
index 0ea58fea99..ddc7ccf6b7 100644
--- a/plug-ins/file-fits/Makefile.am
+++ b/plug-ins/file-fits/Makefile.am
@@ -25,9 +25,7 @@ libexecdir = $(gimpplugindir)/plug-ins/file-fits
libexec_PROGRAMS = file-fits
file_fits_SOURCES = \
- fits.c \
- fits-io.c \
- fits-io.h
+ fits.c
AM_CPPFLAGS = \
-I$(top_srcdir) \
@@ -47,4 +45,5 @@ LDADD = \
$(GEGL_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
+ $(CFITSIO_LIBS) \
$(file_fits_RC)
diff --git a/plug-ins/file-fits/fits-io.c b/plug-ins/file-fits/fits-io.c
deleted file mode 100644
index 713a220fe2..0000000000
--- a/plug-ins/file-fits/fits-io.c
+++ /dev/null
@@ -1,2503 +0,0 @@
-/******************************************************************************/
-/* Peter Kirchgessner */
-/* e-mail: peter@kirchgessner.net */
-/* WWW : http://www.kirchgessner.net */
-/******************************************************************************/
-/* #BEG-HDR */
-/* */
-/* Package : FITS reading/writing library */
-/* Modul-Name : fitsrw.c */
-/* Description : Support of reading/writing FITS-files */
-/* Function(s) : fits_new_filestruct - (local) initialize file structure*/
-/* fits_new_hdulist - (local) initialize hdulist struct*/
-/* fits_delete_filestruct - (local) delete file structure */
-/* fits_delete_recordlist - (local) delete record list */
-/* fits_delete_hdulist - (local) delete hdu list */
-/* fits_nan_32 - (local) check IEEE NaN values */
-/* fits_nan_64 - (local) check IEEE NaN values */
-/* fits_get_error - get error message */
-/* fits_set_error - (local) set error message */
-/* fits_drop_error - (local) remove an error message */
-/* fits_open - open a FITS file */
-/* fits_close - close a FITS file */
-/* fits_add_hdu - add a HDU to a FITS file */
-/* fits_add_card - add a card to the HDU */
-/* fits_print_header - print a single FITS header */
-/* fits_read_header - (local) read in FITS header */
-/* fits_write_header - write a FITS header */
-/* fits_decode_header - (local) decode a header */
-/* fits_eval_pixrange - (local) evaluate range of pixels */
-/* fits_decode_card - decode a card */
-/* fits_search_card - search a card in a record list */
-/* fits_image_info - get information about image */
-/* fits_seek_image - position to an image */
-/* fits_read_pixel - read pixel values from file */
-/* fits_to_pgmraw - convert FITS-file to PGM-file */
-/* pgmraw_to_fits - convert PGM-file to FITS-file */
-/* */
-/* Author : P. Kirchgessner */
-/* Date of Gen. : 12-Apr-97 */
-/* Last modified : 25-Aug-06 */
-/* Version : 0.12 */
-/* Compiler Opt. : */
-/* Changes : */
-/* #MOD-0001, nn, 20-Dec-97, Initialize some variables */
-/* #MOD-0002, pk, 16-Aug-06, Fix problems with internationalization */
-/* */
-/* #END-HDR */
-/******************************************************************************/
-/* References: */
-/* - NOST, Definition of the Flexible Image Transport System (FITS), */
-/* September 29, 1995, Standard, NOST 100-1.1 */
-/* (ftp://nssdc.gsfc.nasa.gov/pub/fits/fits_standard_ps.Z) */
-/* - The FITS IMAGE Extension. A Proposal. J.D. Ponz, R.W. Thompson, */
-/* J.R. Munoz, Feb. 7, 1992 */
-/* (ftp://www.cv.nrao.edu/fits/documents/standards/image.ps.gz) */
-/* */
-/******************************************************************************/
-
-#define VERSION 0.12
-
-/******************************************************************************/
-/* FITS reading/writing library */
-/* Copyright (C) 1997 Peter Kirchgessner */
-/* (email: peter@kirchgessner.net, WWW: http://www.kirchgessner.net) */
-/* The library was developed for a FITS-plug-in to GIMP, the GNU Image */
-/* Manipulation Program. But it is completely independent to that (beside use */
-/* of glib). If someone finds it useful for other purposes, try to keep it */
-/* independent from your application. */
-/******************************************************************************/
-/* */
-/* 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 3 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, see . */
-/******************************************************************************/
-
-#include "config.h"
-
-#include
-#include
-#include
-
-#include
-#include
-
-#include "fits-io.h"
-
-
-/* Declaration of local functions */
-
-static FitsFile * fits_new_filestruct (void);
-static FitsHduList * fits_new_hdulist (void);
-static void fits_delete_filestruct (FitsFile *ff);
-static void fits_delete_recordlist (FitsRecordList *rl);
-static void fits_delete_hdulist (FitsHduList *hl);
-static gint fits_nan_32 (guchar *value);
-static gint fits_nan_64 (guchar *value);
-static void fits_set_error (const char *errmsg);
-static void fits_drop_error (void);
-static FitsRecordList * fits_read_header (FILE *fp,
- gint *nrec);
-static FitsHduList * fits_decode_header (FitsRecordList *hdr,
- glong hdr_offset,
- glong dat_offset);
-static gint fits_eval_pixrange (FILE *fp,
- FitsHduList *hdu);
-
-
-/* Error handling like a FIFO */
-#define FITS_MAX_ERROR 16
-#define FITS_ERROR_LENGTH 256
-
-static gint fits_n_error = 0;
-static gchar fits_error[FITS_MAX_ERROR][FITS_ERROR_LENGTH];
-
-/* What byte ordering for IEEE-format we are running on ? */
-static gint fits_ieee32_intel = 0;
-static gint fits_ieee32_motorola = 0;
-static gint fits_ieee64_intel = 0;
-static gint fits_ieee64_motorola = 0;
-
-/* Macros */
-#define FITS_RETURN(msg, val) { fits_set_error (msg); return (val); }
-#define FITS_VRETURN(msg) { fits_set_error (msg); return; }
-
-/* Get pixel values from memory. p must be an (guchar *) */
-#define FITS_GETBITPIX16(p,val) val = ((p[0] << 8) | (p[1]))
-#define FITS_GETBITPIX32(p,val) val = \
- ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
-
-/* Get floating point values from memory. p must be an (guchar *). */
-/* The floating point values must directly correspond */
-/* to machine representation. Otherwise it does not work. */
-#define FITS_GETBITPIXM32(p,val) \
- { if (fits_ieee32_intel) {guchar uc[4]; \
- uc[0] = p[3]; uc[1] = p[2]; uc[2] = p[1]; uc[3] = p[0]; \
- val = *(FitsBitpixM32 *)uc; } \
- else if (fits_ieee32_motorola) { val = *(FitsBitpixM32 *)p; } \
- else if (fits_ieee64_motorola) {FitsBitpixM64 m64; \
- guchar *uc= (guchar *)&m64; \
- uc[0]=p[0]; uc[1]=p[1]; uc[2]=p[2]; uc[3]=p[3]; uc[4]=uc[5]=uc[6]=uc[7]=0; \
- val = (FitsBitpixM32)m64; } \
- else if (fits_ieee64_intel) {FitsBitpixM64 i64; \
- guchar *uc= (guchar *)&i64; \
- uc[0]=uc[1]=uc[2]=uc[3]=0; uc[7]=p[0]; uc[6]=p[1]; uc[5]=p[2]; uc[4]=p[3]; \
- val = (FitsBitpixM32)i64;} }
-
-#define FITS_GETBITPIXM64(p,val) \
- { if (fits_ieee64_intel) {guchar uc[8]; \
- uc[0] = p[7]; uc[1] = p[6]; uc[2] = p[5]; uc[3] = p[4]; \
- uc[4] = p[3]; uc[5] = p[2]; uc[6] = p[1]; uc[7] = p[0]; \
- val = *(FitsBitpixM64 *)uc; } else val = *(FitsBitpixM64 *)p; }
-
-#define FITS_WRITE_BOOLCARD(fp,key,value) \
-{ gchar card[81]; \
- g_snprintf (card, sizeof (card), \
- "%-8.8s= %20s%50s", key, value ? "T" : "F", " "); \
- fwrite (card, 1, 80, fp); }
-
-#define FITS_WRITE_LONGCARD(fp,key,value) \
-{ gchar card[81]; \
- g_snprintf (card, sizeof (card), \
- "%-8.8s= %20ld%50s", key, (long)value, " "); \
- fwrite (card, 1, 80, fp); }
-
-#define FITS_WRITE_DOUBLECARD(fp,key,value) \
-{ gchar card[81], dbl[21], *istr; \
- g_ascii_dtostr (dbl, sizeof(dbl), (gdouble)value); \
- istr = strstr (dbl, "e"); \
- if (istr) *istr = 'E'; \
- g_snprintf (card, sizeof (card), \
- "%-8.8s= %20.20s%50s", key, dbl, " "); \
- fwrite (card, 1, 80, fp); }
-
-#define FITS_WRITE_STRINGCARD(fp,key,value) \
-{ gchar card[81]; int k;\
- g_snprintf (card, sizeof (card), \
- "%-8.8s= \'%s", key, value); \
- for (k = strlen (card); k < 81; k++) card[k] = ' '; \
- k = strlen (key); if (k < 8) card[19] = '\''; else card[11+k] = '\''; \
- fwrite (card, 1, 80, fp); }
-
-#define FITS_WRITE_CARD(fp,value) \
-{ gchar card[81]; \
- g_snprintf (card, sizeof (card), \
- "%-80.80s", value); \
- fwrite (card, 1, 80, fp); }
-
-
-/* Macro to convert a double value to a string using '.' as decimal point */
-#define FDTOSTR(buf,val) g_ascii_dtostr (buf, sizeof(buf), (gdouble)(val))
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_scanfdouble - (local) scan a string for a double value */
-/* */
-/* Parameters: */
-/* const char *buf [I] : the string to scan */
-/* double *value [O] : where to write the double value to */
-/* */
-/* Scan a string for a double value represented in "C" locale. */
-/* On success 1 is returned. On failure 0 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static gboolean
-fits_scanfdouble (const gchar *buf,
- gdouble *value)
-{
- gboolean retval = FALSE;
- gchar *bufcopy = g_strdup (buf);
-
- /* We should use g_ascii_strtod. This also allows scanning of hexadecimal */
- /* values like 0x02. But we want the behaviour of sscanf ("0x02","%lf",...*/
- /* that gives 0.0 in this case. So check the string if we have a hex-value*/
-
- if (bufcopy)
- {
- gchar *bufptr = bufcopy;
-
- /* Remove leading white space */
- g_strchug (bufcopy);
-
- /* Skip leading sign character */
- if ((*bufptr == '-') || (*bufptr == '+'))
- bufptr++;
-
- /* Start of hex value ? Take this as 0.0 */
- if ((bufptr[0] == '0') && (g_ascii_toupper (bufptr[1]) == 'X'))
- {
- *value = 0.0;
- retval = TRUE;
- }
- else
- {
- if (*bufptr == '.') /* leading decimal point ? Skip it */
- bufptr++;
-
- if (g_ascii_isdigit (*bufptr)) /* Expect the complete string is decimal */
- {
- gchar *endptr;
- gdouble gvalue = g_ascii_strtod (bufcopy, &endptr);
-
- if (errno == 0)
- {
- *value = gvalue;
- retval = TRUE;
- }
- }
- }
-
- g_free (bufcopy);
- }
-
- return retval;
-}
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_new_filestruct - (local) initialize file structure */
-/* */
-/* Parameters: */
-/* -none- */
-/* */
-/* Returns a pointer to an initialized fits file structure. */
-/* On failure, a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static FitsFile *
-fits_new_filestruct (void)
-{
- return g_new0 (FitsFile, 1);
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_new_hdulist - (local) initialize hdulist structure */
-/* */
-/* Parameters: */
-/* -none- */
-/* */
-/* Returns a pointer to an initialized hdulist structure. */
-/* On failure, a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static FitsHduList *
-fits_new_hdulist (void)
-{
- return g_new0 (FitsHduList, 1);
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_delete_filestruct - (local) delete file structure */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : pointer to fits file structure */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Frees all memory allocated by the file structure. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static void
-fits_delete_filestruct (FitsFile *ff)
-{
- if (ff == NULL)
- return;
-
- fits_delete_hdulist (ff->hdu_list);
- ff->hdu_list = NULL;
-
- g_free (ff);
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_delete_recordlist - (local) delete record list */
-/* */
-/* Parameters: */
-/* FitsRecordList *rl [I] : record list to delete */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static void
-fits_delete_recordlist (FitsRecordList *rl)
-{
- while (rl != NULL)
- {
- FitsRecordList *next;
-
- next = rl->next_record;
- rl->next_record = NULL;
- g_free (rl);
-
- rl = next;
- }
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_delete_hdulist - (local) delete hdu list */
-/* */
-/* Parameters: */
-/* FitsHduList *hl [I] : hdu list to delete */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static void
-fits_delete_hdulist (FitsHduList *hl)
-{
- while (hl != NULL)
- {
- FitsHduList *next;
-
- fits_delete_recordlist (hl->header_record_list);
- next = hl->next_hdu;
- hl->next_hdu = NULL;
- g_free (hl);
-
- hl = next;
- }
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_nan_32 - (local) check for IEEE NaN values (32 bit) */
-/* */
-/* Parameters: */
-/* unsigned char *v [I] : value to check */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function returns 1 if the value is a NaN. Otherwise 0 is returned. */
-/* The byte sequence at v must start with the sign/eponent byte. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static int
-fits_nan_32 (guchar *v)
-{
- register gulong k;
-
- k = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
- k &= 0x7fffffff; /* Don't care about the sign bit */
-
- /* See NOST Definition of the Flexible Image Transport System (FITS), */
- /* Appendix F, IEEE special formats. */
- return (((k >= 0x7f7fffff) && (k <= 0x7fffffff)) ||
- ((k >= 0x00000001) && (k <= 0x00800000)));
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_nan_64 - (local) check for IEEE NaN values (64 bit) */
-/* */
-/* Parameters: */
-/* unsigned char *v [I] : value to check */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function returns 1 if the value is a NaN. Otherwise 0 is returned. */
-/* The byte sequence at v must start with the sign/eponent byte. */
-/* (currently we ignore the low order 4 bytes of the mantissa. Therefore */
-/* this function is the same as for 32 bits). */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static int
-fits_nan_64 (guchar *v)
-{
- register gulong k;
-
- k = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
- k &= 0x7fffffff; /* Don't care about the sign bit */
-
- /* See NOST Definition of the Flexible Image Transport System (FITS), */
- /* Appendix F, IEEE special formats. */
- return (((k >= 0x7f7fffff) && (k <= 0x7fffffff)) ||
- ((k >= 0x00000001) && (k <= 0x00800000)));
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_get_error - get an error message */
-/* */
-/* Parameters: */
-/* -none- */
-/* */
-/* If an error message has been set, a pointer to the message is returned. */
-/* Otherwise a NULL pointer is returned. */
-/* An inquired error message is removed from the error FIFO. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gchar *
-fits_get_error (void)
-{
- static gchar errmsg[FITS_ERROR_LENGTH];
- gint k;
-
- if (fits_n_error <= 0)
- return NULL;
-
- strcpy (errmsg, fits_error[0]);
-
- for (k = 1; k < fits_n_error; k++)
- strcpy (fits_error[k-1], fits_error[k]);
-
- fits_n_error--;
-
- return errmsg;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_set_error - (local) set an error message */
-/* */
-/* Parameters: */
-/* char *errmsg [I] : Error message to set */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Places the error message in the FIFO. If the FIFO is full, */
-/* the message is discarded. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static void
-fits_set_error (const gchar *errmsg)
-{
- if (fits_n_error < FITS_MAX_ERROR)
- g_strlcpy (fits_error[fits_n_error], errmsg, FITS_ERROR_LENGTH);
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_drop_error - (local) remove an error message */
-/* */
-/* Parameters: */
-/* -none- */
-/* */
-/* Removes the last error message from the error message FIFO */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static void
-fits_drop_error (void)
-{
- if (fits_n_error > 0)
- fits_n_error--;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_open - open a FITS file */
-/* */
-/* Parameters: */
-/* char *filename [I] : name of file to open */
-/* char *openmode [I] : mode to open the file ("r", "w") */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* On success, a FitsFile-pointer is returned. On failure, a NULL- */
-/* pointer is returned. */
-/* The functions scans through the file loading each header and analyzing */
-/* them. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-FitsFile *
-fits_open (const gchar *filename,
- const gchar *openmode)
-
-{
- gint reading, writing, n_rec, n_hdr;
- glong fpos_header, fpos_data;
- FILE *fp;
- FitsFile *ff;
- FitsRecordList *hdrlist;
- FitsHduList *hdulist = NULL;
- FitsHduList *last_hdulist = NULL;
-
- /* Check the IEEE-format we are running on */
- {
- gfloat one32 = 1.0;
- gdouble one64 = 1.0;
- guchar *op32 = (guchar *) &one32;
- guchar *op64 = (guchar *) &one64;
-
- if (sizeof (float) == 4)
- {
- fits_ieee32_intel = (op32[3] == 0x3f);
- fits_ieee32_motorola = (op32[0] == 0x3f);
- }
-
- if (sizeof (double) == 8)
- {
- fits_ieee64_intel = (op64[7] == 0x3f);
- fits_ieee64_motorola = (op64[0] == 0x3f);
- }
- }
-
- if ((filename == NULL) || (*filename == '\0') || (openmode == NULL))
- FITS_RETURN ("fits_open: Invalid parameters", NULL);
-
- reading = (strcmp (openmode, "r") == 0);
- writing = (strcmp (openmode, "w") == 0);
- if ((!reading) && (!writing))
- FITS_RETURN ("fits_open: Invalid openmode", NULL);
-
- fp = g_fopen (filename, reading ? "rb" : "wb");
- if (fp == NULL)
- FITS_RETURN ("fits_open: g_fopen() failed", NULL);
-
- ff = fits_new_filestruct ();
- if (ff == NULL)
- {
- fclose (fp);
- FITS_RETURN ("fits_open: No more memory", NULL);
- }
-
- ff->fp = fp;
- ff->openmode = *openmode;
-
- if (writing)
- return ff;
-
- for (n_hdr = 0; ; n_hdr++) /* Read through all HDUs */
- {
- fpos_header = ftell (fp); /* Save file position of header */
- hdrlist = fits_read_header (fp, &n_rec);
-
- if (hdrlist == NULL)
- {
- if (n_hdr > 0) /* At least one header must be present. */
- fits_drop_error (); /* If we got a header already, drop the error */
- break;
- }
- fpos_data = ftell (fp); /* Save file position of data */
-
- /* Decode the header */
- hdulist = fits_decode_header (hdrlist, fpos_header, fpos_data);
- if (hdulist == NULL)
- {
- fits_delete_recordlist (hdrlist);
- break;
- }
- ff->n_hdu++;
- ff->n_pic += hdulist->numpic;
-
- if (hdulist->used.blank_value)
- ff->blank_used = TRUE;
-
- if (hdulist->used.nan_value)
- ff->nan_used = TRUE;
-
- if (n_hdr == 0)
- ff->hdu_list = hdulist;
- else
- last_hdulist->next_hdu = hdulist;
-
- last_hdulist = hdulist;
-
- /* Evaluate the range of pixel data */
- fits_eval_pixrange (fp, hdulist);
-
- /* Reposition to start of next header */
- if (fseek (fp, hdulist->data_offset + hdulist->data_size, SEEK_SET) < 0)
- break;
- }
-
- return ff;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_close - close a FITS file */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS file pointer */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-void
-fits_close (FitsFile *ff)
-{
- if (ff == NULL)
- FITS_VRETURN ("fits_close: Invalid parameter");
-
- fclose (ff->fp);
-
- fits_delete_filestruct (ff);
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_add_hdu - add a HDU to the file */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS file pointer */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Adds a new HDU to the list kept in ff. A pointer to the new HDU is */
-/* returned. On failure, a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-FitsHduList *
-fits_add_hdu (FitsFile *ff)
-{
- FitsHduList *newhdu, *hdu;
-
- if (ff->openmode != 'w')
- FITS_RETURN ("fits_add_hdu: file not open for writing", NULL);
-
- newhdu = fits_new_hdulist ();
- if (newhdu == NULL)
- return NULL;
-
- if (ff->hdu_list == NULL)
- {
- ff->hdu_list = newhdu;
- }
- else
- {
- hdu = ff->hdu_list;
- while (hdu->next_hdu != NULL)
- hdu = hdu->next_hdu;
- hdu->next_hdu = newhdu;
- }
-
- return newhdu;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_add_card - add a card to the HDU */
-/* */
-/* Parameters: */
-/* FitsHduList *hdulist [I] : HDU listr */
-/* char *card [I] : card to add */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The card must follow the standards of FITS. The card must not use a */
-/* keyword that is written using *hdulist itself. On success 0 is returned. */
-/* On failure -1 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gint
-fits_add_card (FitsHduList *hdulist,
- const gchar *card)
-{
- gint k;
-
- if (hdulist->naddcards >= FITS_NADD_CARDS)
- return -1;
-
- k = strlen (card);
- if (k < FITS_CARD_SIZE)
- {
- memset (&(hdulist->addcards[hdulist->naddcards][k]), ' ',
- FITS_CARD_SIZE - k);
- memcpy (hdulist->addcards[(hdulist->naddcards)++], card, k);
- }
- else
- {
- memcpy (hdulist->addcards[(hdulist->naddcards)++], card, FITS_CARD_SIZE);
- }
-
- return 0;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_print_header - print the internal representation */
-/* of a single header */
-/* Parameters: */
-/* FitsHduList *hdr [I] : pointer to the header */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-void
-fits_print_header (FitsHduList *hdr)
-{
- gint k;
- gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
-
- if (hdr->used.simple)
- printf ("Content of SIMPLE-header:\n");
- else
- printf ("Content of XTENSION-header %s:\n", hdr->xtension);
-
- printf ("header_offset : %ld\n", hdr->header_offset);
- printf ("data_offset : %ld\n", hdr->data_offset);
- printf ("data_size : %ld\n", hdr->data_size);
- printf ("used data_size: %ld\n", hdr->udata_size);
- printf ("bytes p.pixel : %d\n", hdr->bpp);
- printf ("pixmin : %s\n", FDTOSTR (buf, hdr->pixmin));
- printf ("pixmax : %s\n", FDTOSTR (buf, hdr->pixmax));
-
- printf ("naxis : %d\n", hdr->naxis);
- for (k = 1; k <= hdr->naxis; k++)
- printf ("naxis%-3d : %d\n", k, hdr->naxisn[k-1]);
-
- printf ("bitpix : %d\n", hdr->bitpix);
-
- if (hdr->used.blank)
- printf ("blank : %ld\n", hdr->blank);
- else
- printf ("blank : not used\n");
-
- if (hdr->used.datamin)
- printf ("datamin : %s\n", FDTOSTR (buf, hdr->datamin));
- else
- printf ("datamin : not used\n");
-
- if (hdr->used.datamax)
- printf ("datamax : %s\n", FDTOSTR (buf, hdr->datamax));
- else
- printf ("datamax : not used\n");
-
- if (hdr->used.gcount)
- printf ("gcount : %ld\n", hdr->gcount);
- else
- printf ("gcount : not used\n");
-
- if (hdr->used.pcount)
- printf ("pcount : %ld\n", hdr->pcount);
- else
- printf ("pcount : not used\n");
-
- if (hdr->used.bscale)
- printf ("bscale : %s\n", FDTOSTR (buf, hdr->bscale));
- else
- printf ("bscale : not used\n");
-
- if (hdr->used.bzero)
- printf ("bzero : %s\n", FDTOSTR (buf, hdr->bzero));
- else
- printf ("bzero : not used\n");
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_read_header - (local) read FITS header */
-/* */
-/* Parameters: */
-/* FILE *fp [I] : file pointer */
-/* int *nrec [O] : number of records read */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Reads in all header records up to the record that keeps the END-card. */
-/* A pointer to the record list is returned on success. */
-/* On failure, a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static FitsRecordList *
-fits_read_header (FILE *fp,
- gint *nrec)
-{
- gchar record[FITS_RECORD_SIZE];
- FitsRecordList *start_list = NULL;
- FitsRecordList *cu_record = NULL;
- FitsRecordList *new_record;
- FitsData *fdat;
- gint k, simple, xtension;
-
- *nrec = 0;
-
- k = fread (record, 1, FITS_RECORD_SIZE, fp);
- if (k != FITS_RECORD_SIZE)
- FITS_RETURN ("fits_read_header: Error in read of first record", NULL);
-
- simple = (strncmp (record, "SIMPLE ", 8) == 0);
- xtension = (strncmp (record, "XTENSION", 8) == 0);
- if ((!simple) && (!xtension))
- FITS_RETURN ("fits_read_header: Missing keyword SIMPLE or XTENSION", NULL);
-
- if (simple)
- {
- fdat = fits_decode_card (record, FITS_DATA_TYPE_FBOOL);
- if (fdat && !fdat->fbool)
- fits_set_error ("fits_read_header (warning): keyword SIMPLE does not "
- "have value T");
- }
-
- for (;;) /* Process all header records */
- {
- new_record = g_new0 (FitsRecordList, 1);
- memcpy (new_record->data, record, FITS_RECORD_SIZE);
- new_record->next_record = NULL;
- (*nrec)++;
-
- if (start_list == NULL) /* Add new record to the list */
- start_list = new_record;
- else
- cu_record->next_record = new_record;
-
- cu_record = new_record;
-
- /* Was this the last record ? */
- if (fits_search_card (cu_record, "END") != NULL)
- break;
-
- k = fread (record, 1, FITS_RECORD_SIZE, fp);
- if (k != FITS_RECORD_SIZE)
- FITS_RETURN ("fits_read_header: Error in read of record", NULL);
- }
-
- return start_list;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_write_header - write a FITS header */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS-file pointer */
-/* FitsHduList [I] : pointer to header */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Writes a header to the file. On success, 0 is returned. On failure, */
-/* -1 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gint
-fits_write_header (FitsFile *ff,
- FitsHduList *hdulist)
-{
- gint numcards;
- gint k;
-
- if (ff->openmode != 'w')
- FITS_RETURN ("fits_write_header: file not open for writing", -1);
-
- numcards = 0;
-
- if (hdulist->used.simple)
- {
- FITS_WRITE_BOOLCARD (ff->fp, "SIMPLE", 1);
- numcards++;
- }
- else if (hdulist->used.xtension)
- {
- FITS_WRITE_STRINGCARD (ff->fp, "XTENSION", hdulist->xtension);
- numcards++;
- }
-
- FITS_WRITE_LONGCARD (ff->fp, "BITPIX", hdulist->bitpix);
- numcards++;
-
- FITS_WRITE_LONGCARD (ff->fp, "NAXIS", hdulist->naxis);
- numcards++;
-
- for (k = 0; k < hdulist->naxis; k++)
- {
- gchar naxisn[16];
-
- g_snprintf (naxisn, sizeof (naxisn), "NAXIS%d", k+1);
- FITS_WRITE_LONGCARD (ff->fp, naxisn, hdulist->naxisn[k]);
- numcards++;
- }
-
- if (hdulist->used.extend)
- {
- FITS_WRITE_BOOLCARD (ff->fp, "EXTEND", hdulist->extend);
- numcards++;
- }
-
- if (hdulist->used.groups)
- {
- FITS_WRITE_BOOLCARD (ff->fp, "GROUPS", hdulist->groups);
- numcards++;
- }
-
- if (hdulist->used.pcount)
- {
- FITS_WRITE_LONGCARD (ff->fp, "PCOUNT", hdulist->pcount);
- numcards++;
- }
-
- if (hdulist->used.gcount)
- {
- FITS_WRITE_LONGCARD (ff->fp, "GCOUNT", hdulist->gcount);
- numcards++;
- }
-
- if (hdulist->used.bzero)
- {
- FITS_WRITE_DOUBLECARD (ff->fp, "BZERO", hdulist->bzero);
- numcards++;
- }
-
- if (hdulist->used.bscale)
- {
- FITS_WRITE_DOUBLECARD (ff->fp, "BSCALE", hdulist->bscale);
- numcards++;
- }
-
- if (hdulist->used.datamin)
- {
- FITS_WRITE_DOUBLECARD (ff->fp, "DATAMIN", hdulist->datamin);
- numcards++;
- }
-
- if (hdulist->used.datamax)
- {
- FITS_WRITE_DOUBLECARD (ff->fp, "DATAMAX", hdulist->datamax);
- numcards++;
- }
-
- if (hdulist->used.blank)
- {
- FITS_WRITE_LONGCARD (ff->fp, "BLANK", hdulist->blank);
- numcards++;
- }
-
- /* Write additional cards */
- if (hdulist->naddcards > 0)
- {
- fwrite (hdulist->addcards, FITS_CARD_SIZE, hdulist->naddcards, ff->fp);
- numcards += hdulist->naddcards;
- }
-
- FITS_WRITE_CARD (ff->fp, "END");
- numcards++;
-
- k = (numcards * FITS_CARD_SIZE) % FITS_RECORD_SIZE;
- if (k) /* Must the record be filled up ? */
- {
- while (k++ < FITS_RECORD_SIZE)
- putc (' ', ff->fp);
- }
-
- return ferror (ff->fp) ? -1 : 0;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_decode_header - (local) decode a header */
-/* */
-/* Parameters: */
-/* FitsRecordList *hdr [I] : the header record list */
-/* long hdr_offset [I] : fileposition of header */
-/* long dat_offset [I] : fileposition of data (end of header) */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function decodes the mostly used data within the header and generates */
-/* a FitsHduList-entry. On failure, a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static FitsHduList *
-fits_decode_header (FitsRecordList *hdr,
- glong hdr_offset,
- glong dat_offset)
-{
- FitsHduList *hdulist;
- FitsData *fdat;
- gchar errmsg[80], key[9];
- gint k, bpp, random_groups;
- glong mul_axis, data_size, bitpix_supported;
-
-#define FITS_DECODE_CARD(mhdr,mkey,mfdat,mtyp) \
- { strcpy (key, mkey); \
- mfdat = fits_decode_card (fits_search_card (mhdr, mkey), mtyp); \
- if (mfdat == NULL) goto err_missing; }
-
-#define FITS_TRY_CARD(mhdr,mhdu,mkey,mvar,mtyp,unionvar) \
- { FitsData *mfdat = fits_decode_card (fits_search_card (mhdr,mkey), mtyp); \
- mhdu->used.mvar = (mfdat != NULL); \
- if (mhdu->used.mvar) mhdu->mvar = mfdat->unionvar; }
-
- hdulist = fits_new_hdulist ();
- if (hdulist == NULL)
- FITS_RETURN ("fits_decode_header: Not enough memory", NULL);
-
- /* Initialize the header data */
- hdulist->header_offset = hdr_offset;
- hdulist->data_offset = dat_offset;
-
- hdulist->used.simple = (strncmp (hdr->data, "SIMPLE ", 8) == 0);
- hdulist->used.xtension = (strncmp (hdr->data, "XTENSION", 8) == 0);
-
- if (hdulist->used.xtension)
- {
- fdat = fits_decode_card (fits_search_card (hdr, "XTENSION"),
- FITS_DATA_TYPE_FSTRING);
- if (fdat != NULL)
- {
- strcpy (hdulist->xtension, fdat->fstring);
- }
- else
- {
- strcpy (errmsg, "No valid XTENSION header found.");
- goto err_return;
- }
- }
-
- FITS_DECODE_CARD (hdr, "NAXIS", fdat, FITS_DATA_TYPE_FLONG);
- hdulist->naxis = fdat->flong;
-
- FITS_DECODE_CARD (hdr, "BITPIX", fdat, FITS_DATA_TYPE_FLONG);
- bpp = hdulist->bitpix = (gint) fdat->flong;
- if ((bpp != 8) && (bpp != 16) && (bpp != 32) &&
- (bpp != -32) && (bpp != -64))
- {
- strcpy (errmsg, "fits_decode_header: Invalid BITPIX-value");
- goto err_return;
- }
-
- if (bpp < 0)
- bpp = -bpp;
-
- bpp /= 8;
- hdulist->bpp = bpp;
-
- FITS_TRY_CARD (hdr, hdulist, "GCOUNT", gcount, FITS_DATA_TYPE_FLONG, flong);
- FITS_TRY_CARD (hdr, hdulist, "PCOUNT", pcount, FITS_DATA_TYPE_FLONG, flong);
-
- FITS_TRY_CARD (hdr, hdulist, "GROUPS", groups, FITS_DATA_TYPE_FLONG, fbool);
- random_groups = hdulist->used.groups && hdulist->groups;
-
- FITS_TRY_CARD (hdr, hdulist, "EXTEND", extend, FITS_DATA_TYPE_FBOOL, fbool);
-
- if (hdulist->used.xtension) /* Extension requires GCOUNT and PCOUNT */
- {
- if (! hdulist->used.gcount || ! hdulist->used.pcount)
- {
- strcpy (errmsg, "fits_decode_header: Missing GCOUNT/PCOUNT for XTENSION");
- goto err_return;
- }
- }
-
- mul_axis = 1;
-
- /* Find all NAXISx-cards */
- for (k = 1; k <= FITS_MAX_AXIS; k++)
- {
- gchar naxisn[16];
-
- g_snprintf (naxisn, sizeof (naxisn), "NAXIS%-3d", k);
- fdat = fits_decode_card (fits_search_card (hdr, naxisn),
- FITS_DATA_TYPE_FLONG);
- if (fdat == NULL)
- {
- k--; /* Save the last NAXISk read */
- break;
- }
-
- hdulist->naxisn[k-1] = (int)fdat->flong;
-
- if (hdulist->naxisn[k-1] < 0)
- {
- strcpy (errmsg, "fits_decode_header: Negative value in NAXISn");
- goto err_return;
- }
-
- if ((k == 1) && random_groups)
- {
- if (hdulist->naxisn[0] != 0)
- {
- strcpy (errmsg, "fits_decode_header: Random groups with NAXIS1 != 0");
- goto err_return;
- }
- }
- else
- {
- mul_axis *= hdulist->naxisn[k - 1];
- }
- }
-
- if ((hdulist->naxis > 0) && (k < hdulist->naxis))
- {
- strcpy (errmsg, "fits_decode_card: Not enough NAXISn-cards");
- goto err_return;
- }
-
- /* If we have only one dimension, just set the second to size one. */
- /* So we don't have to check for naxis < 2 in some places. */
- if (hdulist->naxis < 2)
- hdulist->naxisn[1] = 1;
-
- if (hdulist->naxis < 1)
- {
- mul_axis = 0;
- hdulist->naxisn[0] = 1;
- }
-
- if (hdulist->used.xtension)
- data_size = bpp * hdulist->gcount * (hdulist->pcount + mul_axis);
- else
- data_size = bpp * mul_axis;
-
- hdulist->udata_size = data_size; /* Used data size without padding */
-
- /* Datasize must be a multiple of the FITS logical record size */
- data_size = (data_size + FITS_RECORD_SIZE - 1) / FITS_RECORD_SIZE;
- data_size *= FITS_RECORD_SIZE;
- hdulist->data_size = data_size;
-
- FITS_TRY_CARD (hdr, hdulist, "BLANK", blank, FITS_DATA_TYPE_FLONG, flong);
-
- FITS_TRY_CARD (hdr, hdulist, "DATAMIN", datamin, FITS_DATA_TYPE_FDOUBLE, fdouble);
- FITS_TRY_CARD (hdr, hdulist, "DATAMAX", datamax, FITS_DATA_TYPE_FDOUBLE, fdouble);
-
- FITS_TRY_CARD (hdr, hdulist, "BZERO", bzero, FITS_DATA_TYPE_FDOUBLE, fdouble);
- FITS_TRY_CARD (hdr, hdulist, "BSCALE", bscale, FITS_DATA_TYPE_FDOUBLE, fdouble);
-
- /* Evaluate number of interpretable images for this HDU */
- hdulist->numpic = 0;
-
- /* We must support this format */
- bitpix_supported = (hdulist->bitpix > 0)
- || ( (hdulist->bitpix == -64)
- && (fits_ieee64_intel || fits_ieee64_motorola))
- || ( (hdulist->bitpix == -32)
- && ( fits_ieee32_intel || fits_ieee32_motorola
- || fits_ieee64_intel || fits_ieee64_motorola));
-
- if (bitpix_supported)
- {
- if (hdulist->used.simple)
- {
- if (hdulist->naxis > 0)
- {
- hdulist->numpic = 1;
- for (k = 3; k <= hdulist->naxis; k++)
- hdulist->numpic *= hdulist->naxisn[k - 1];
- }
- }
- else if (hdulist->used.xtension &&
- (strncmp (hdulist->xtension, "IMAGE", 5) == 0))
- {
- if (hdulist->naxis > 0)
- {
- hdulist->numpic = 1;
- for (k = 3; k <= hdulist->naxis; k++)
- hdulist->numpic *= hdulist->naxisn[k - 1];
- }
- }
- }
- else
- {
- gchar msg[160];
-
- g_snprintf (msg, sizeof (msg),
- "fits_decode_header: IEEE floating point format required for "
- "BITPIX=%d\nis not supported on this machine",
- hdulist->bitpix);
- fits_set_error (msg);
- }
-
- hdulist->header_record_list = hdr; /* Add header records to the list */
-
- return hdulist;
-
- err_missing:
- g_snprintf (errmsg, sizeof (errmsg),
- "fits_decode_header: missing/invalid %s card", key);
-
- err_return:
- fits_delete_hdulist (hdulist);
- fits_set_error (errmsg);
-
- return NULL;
-
-#undef FITS_DECODE_CARD
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_eval_pixrange - (local) evaluate range of pixel data */
-/* */
-/* Parameters: */
-/* FILE *fp [I] : file pointer */
-/* FitsHduList *hdu [I] : pointer to header */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The Function sets the values hdu->pixmin and hdu->pixmax. On success 0 */
-/* is returned. On failure, -1 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-static gint
-fits_eval_pixrange (FILE *fp,
- FitsHduList *hdu)
-{
- register gint maxelem;
-#define FITSNPIX 4096
- guchar pixdat[FITSNPIX];
- gint nelem, bpp;
- gboolean blank_found = FALSE;
- gboolean nan_found = FALSE;
-
- if (fseek (fp, hdu->data_offset, SEEK_SET) < 0)
- FITS_RETURN ("fits_eval_pixrange: can't position file", -1);
-
- bpp = hdu->bpp; /* Number of bytes per pixel */
- nelem = hdu->udata_size / bpp; /* Number of data elements */
-
- switch (hdu->bitpix)
- {
- case 8:
- {
- register FitsBitpix8 pixval;
- register guchar *ptr;
- FitsBitpix8 minval = 255;
- FitsBitpix8 maxval = 0;
-
- while (nelem > 0)
- {
- maxelem = sizeof (pixdat) / bpp;
- if (nelem < maxelem)
- maxelem = nelem;
-
- nelem -= maxelem;
- if (fread ((gchar *) pixdat, bpp, maxelem, fp) != maxelem)
- FITS_RETURN ("fits_eval_pixrange: error on read bitpix 8 data", -1);
-
- ptr = pixdat;
- if (hdu->used.blank)
- {
- FitsBitpix8 blankval = (FitsBitpix8) hdu->blank;
-
- while (maxelem-- > 0)
- {
- pixval = (FitsBitpix8)*(ptr++);
-
- if (pixval != blankval)
- {
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- else
- {
- blank_found = TRUE;
- }
- }
- }
- else
- {
- while (maxelem-- > 0)
- {
- pixval = (FitsBitpix8)*(ptr++);
-
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- }
- }
-
- hdu->pixmin = minval;
- hdu->pixmax = maxval;
- break;
- }
-
- case 16:
- {
- register FitsBitpix16 pixval;
- register guchar *ptr;
- FitsBitpix16 minval = 0x7fff;
- FitsBitpix16 maxval = ~0x7fff;
-
- while (nelem > 0)
- {
- maxelem = sizeof (pixdat) / bpp;
- if (nelem < maxelem)
- maxelem = nelem;
-
- nelem -= maxelem;
- if (fread ((gchar *) pixdat, bpp, maxelem, fp) != maxelem)
- FITS_RETURN ("fits_eval_pixrange: error on read bitpix 16 data", -1);
-
- ptr = pixdat;
- if (hdu->used.blank)
- {
- FitsBitpix16 blankval = (FitsBitpix16) hdu->blank;
-
- while (maxelem-- > 0)
- {
- FITS_GETBITPIX16 (ptr, pixval);
- ptr += 2;
-
- if (pixval != blankval)
- {
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- else
- {
- blank_found = TRUE;
- }
- }
- }
- else
- {
- while (maxelem-- > 0)
- {
- FITS_GETBITPIX16 (ptr, pixval);
- ptr += 2;
-
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- }
- }
-
- hdu->pixmin = minval;
- hdu->pixmax = maxval;
- break;
- }
-
- case 32:
- {
- register FitsBitpix32 pixval;
- register guchar *ptr;
- FitsBitpix32 minval = 0x7fffffff;
- FitsBitpix32 maxval = ~0x7fffffff;
-
- while (nelem > 0)
- {
- maxelem = sizeof (pixdat)/bpp;
- if (nelem < maxelem)
- maxelem = nelem;
-
- nelem -= maxelem;
- if (fread ((gchar *) pixdat, bpp, maxelem, fp) != maxelem)
- FITS_RETURN ("fits_eval_pixrange: error on read bitpix 32 data", -1);
-
- ptr = pixdat;
- if (hdu->used.blank)
- {
- FitsBitpix32 blankval = (FitsBitpix32)hdu->blank;
-
- while (maxelem-- > 0)
- {
- FITS_GETBITPIX32 (ptr, pixval);
- ptr += 4;
-
- if (pixval != blankval)
- {
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- else
- {
- blank_found = TRUE;
- }
- }
- }
- else
- {
- while (maxelem-- > 0)
- {
- FITS_GETBITPIX32 (ptr, pixval);
- ptr += 4;
-
- if (pixval < minval)
- minval = pixval;
- else if (pixval > maxval)
- maxval = pixval;
- }
- }
- }
-
- hdu->pixmin = minval;
- hdu->pixmax = maxval;
- break;
- }
-
- case -32:
- {
- register FitsBitpixM32 pixval = 0;
- register guchar *ptr;
- FitsBitpixM32 minval = 0;
- FitsBitpixM32 maxval = 0;
- gboolean first = TRUE;
-
- while (nelem > 0)
- {
- maxelem = sizeof (pixdat) / bpp;
- if (nelem < maxelem)
- maxelem = nelem;
-
- nelem -= maxelem;
- if (fread ((gchar *) pixdat, bpp, maxelem, fp) != maxelem)
- FITS_RETURN ("fits_eval_pixrange: error on read bitpix -32 data", -1);
-
- ptr = pixdat;
- while (maxelem-- > 0)
- {
- if (! fits_nan_32 (ptr))
- {
- FITS_GETBITPIXM32 (ptr, pixval);
- ptr += 4;
-
- if (first)
- {
- first = FALSE;
- minval = maxval = pixval;
- }
- else if (pixval < minval)
- {
- minval = pixval;
- }
- else if (pixval > maxval)
- {
- maxval = pixval;
- }
- }
- else
- {
- nan_found = TRUE;
- }
- }
- }
-
- hdu->pixmin = minval;
- hdu->pixmax = maxval;
- break;
- }
-
- case -64:
- {
- register FitsBitpixM64 pixval;
- register guchar *ptr;
- FitsBitpixM64 minval = 0;
- FitsBitpixM64 maxval = 0;
- gboolean first = TRUE;
-
- while (nelem > 0)
- {
- maxelem = sizeof (pixdat) / bpp;
- if (nelem < maxelem)
- maxelem = nelem;
-
- nelem -= maxelem;
- if (fread ((gchar *) pixdat, bpp, maxelem, fp) != maxelem)
- FITS_RETURN ("fits_eval_pixrange: error on read bitpix -64 data", -1);
-
- ptr = pixdat;
- while (maxelem-- > 0)
- {
- if (! fits_nan_64 (ptr))
- {
- FITS_GETBITPIXM64 (ptr, pixval);
- ptr += 8;
-
- if (first)
- {
- first = FALSE;
- minval = maxval = pixval;
- }
- else if (pixval < minval)
- {
- minval = pixval;
- }
- else if (pixval > maxval)
- {
- maxval = pixval;
- }
- }
- else
- {
- nan_found = TRUE;
- }
- }
- }
-
- hdu->pixmin = minval;
- hdu->pixmax = maxval;
- break;
- }
- }
-
- if (nan_found)
- hdu->used.nan_value = TRUE;
-
- if (blank_found)
- hdu->used.blank_value = TRUE;
-
- return 0;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_decode_card - decode a card */
-/* */
-/* Parameters: */
-/* const char *card [I] : pointer to card image */
-/* FitsDataType data_type [I] : datatype to decode */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* Decodes a card and returns a pointer to the union, keeping the data. */
-/* If card is NULL or on failure, a NULL-pointer is returned. */
-/* If the card does not have the value indicator, an error is generated, */
-/* but its tried to decode the card. The data is only valid up to the next */
-/* call of the function. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-FitsData *
-fits_decode_card (const gchar *card,
- FitsDataType data_type)
-{
- static FitsData data;
- glong l_long;
- gdouble l_double;
- gchar l_card[FITS_CARD_SIZE + 1];
- gchar msg[256];
- gchar *cp, *dst, *end;
- gint ErrCount = 0;
-
- if (card == NULL)
- return NULL;
-
- memcpy (l_card, card, FITS_CARD_SIZE);
- l_card[FITS_CARD_SIZE] = '\0';
-
- if (strncmp (card+8, "= ", 2) != 0)
- {
- g_snprintf (msg, sizeof (msg),
- "fits_decode_card (warning): Missing value indicator "
- "'= ' for %8.8s", l_card);
- fits_set_error (msg);
- ErrCount++;
- }
-
- switch (data_type)
- {
- case FITS_DATA_TYPE_BITPIX_8:
- data.bitpix8 = (FitsBitpix8) (l_card[10]);
- break;
-
- case FITS_DATA_TYPE_BITPIX_16:
- if (sscanf (l_card + 10, "%ld", &l_long) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_BITPIX_16");
- ErrCount++;
- break;
- }
- data.bitpix16 = (FitsBitpix16) l_long;
- break;
-
- case FITS_DATA_TYPE_BITPIX_32:
- if (sscanf (l_card + 10, "%ld", &l_long) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_BITPIX_32");
- ErrCount++;
- break;
- }
- data.bitpix32 = (FitsBitpix32) l_long;
- break;
-
- case FITS_DATA_TYPE_BITPIX_M32:
- if (fits_scanfdouble (l_card + 10, &l_double) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_BITPIX_M32");
- ErrCount++;
- break;
- }
- data.bitpixm32 = (FitsBitpixM32) l_double;
- break;
-
- case FITS_DATA_TYPE_BITPIX_M64:
- if (fits_scanfdouble (l_card + 10, &l_double) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_BITPIX_M64");
- ErrCount++;
- break;
- }
- data.bitpixm64 = (FitsBitpixM64) l_double;
- break;
-
- case FITS_DATA_TYPE_FBOOL:
- cp = l_card + 10;
- while (*cp == ' ')
- cp++;
-
- if (*cp == 'T')
- {
- data.fbool = 1;
- }
- else if (*cp == 'F')
- {
- data.fbool = 0;
- }
- else
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_FBOOL");
- ErrCount++;
- break;
- }
- break;
-
- case FITS_DATA_TYPE_FLONG:
- if (sscanf (l_card + 10, "%ld", &l_long) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_FLONG");
- ErrCount++;
- break;
- }
- data.flong = (FitsBitpix32) l_long;
- break;
-
- case FITS_DATA_TYPE_FDOUBLE:
- if (fits_scanfdouble (l_card + 10, &l_double) != 1)
- {
- fits_set_error ("fits_decode_card: error decoding FITS_DATA_TYPE_FDOUBLE");
- ErrCount++;
- break;
- }
- data.fdouble = (FitsBitpixM32) l_double;
- break;
-
- case FITS_DATA_TYPE_FSTRING:
- cp = l_card + 10;
- if (*cp != '\'')
- {
- fits_set_error ("fits_decode_card: missing \' decoding FITS_DATA_TYPE_FSTRING");
- ErrCount++;
- break;
- }
-
- dst = data.fstring;
- cp++;
- end = l_card + FITS_CARD_SIZE - 1;
- for (;;) /* Search for trailing quote */
- {
- if (*cp != '\'') /* All characters but quote are used. */
- {
- *(dst++) = *cp;
- }
- else /* Maybe there is a quote in the string */
- {
- if (cp >= end)
- break; /* End of card ? finished */
-
- if (*(cp+1) != '\'')
- break;
-
- *(dst++) = *(cp++);
- }
-
- if (cp >= end)
- break;
-
- cp++;
- }
-
- *dst = '\0';
- break;
- }
-
- return (ErrCount == 0) ? &data : NULL;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_search_card - search a card in the record list */
-/* */
-/* Parameters: */
-/* FitsRecordList *rl [I] : record list to search */
-/* char *keyword [I] : keyword identifying the card */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* A card is searched in the record list. Only the first eight characters of */
-/* keyword are significant. If keyword is less than 8 characters, its filled */
-/* with blanks. */
-/* If the card is found, a pointer to the card is returned. */
-/* The pointer does not point to a null-terminated string. Only the next */
-/* 80 bytes are allowed to be read. */
-/* On failure a NULL-pointer is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gchar *
-fits_search_card (FitsRecordList *rl,
- gchar *keyword)
-{
- gint key_len, k;
- gchar key[9];
-
- key_len = strlen (keyword);
- if (key_len > 8)
- key_len = 8;
- if (key_len == 0)
- FITS_RETURN ("fits_search_card: Invalid parameter", NULL);
-
- strcpy (key, " ");
- memcpy (key, keyword, key_len);
-
- while (rl != NULL)
- {
- gchar *card = (gchar *) rl->data;
-
- for (k = 0; k < FITS_RECORD_SIZE / FITS_CARD_SIZE; k++)
- {
- if (strncmp (card, key, 8) == 0)
- return (card);
-
- card += FITS_CARD_SIZE;
- }
-
- rl = rl->next_record;
- }
-
- return NULL;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_image_info - get information about an image */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS file structure */
-/* int picind [I] : Index of picture in file (1,2,...) */
-/* int *hdupicind [O] : Index of picture in HDU (1,2,...) */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function returns on success a pointer to a FitsHduList. hdupicind */
-/* then gives the index of the image within the HDU. */
-/* On failure, NULL is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-FitsHduList *
-fits_image_info (FitsFile *ff,
- gint picind,
- gint *hdupicind)
-{
- FitsHduList *hdulist;
- gint firstpic, lastpic;
-
- if (ff == NULL)
- FITS_RETURN ("fits_image_info: ff is NULL", NULL);
-
- if (ff->openmode != 'r')
- FITS_RETURN ("fits_image_info: file not open for reading", NULL);
-
- if ((picind < 1) || (picind > ff->n_pic))
- FITS_RETURN ("fits_image_info: picind out of range", NULL);
-
- firstpic = 1;
- for (hdulist = ff->hdu_list; hdulist != NULL; hdulist = hdulist->next_hdu)
- {
- if (hdulist->numpic <= 0)
- continue;
-
- lastpic = firstpic + hdulist->numpic - 1;
-
- if (picind <= lastpic) /* Found image in current HDU ? */
- break;
-
- firstpic = lastpic + 1;
- }
-
- *hdupicind = picind - firstpic + 1;
-
- return hdulist;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_seek_image - position to a specific image */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS file structure */
-/* int picind [I] : Index of picture to seek (1,2,...) */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function positions the file pointer to a specified image. */
-/* The function returns on success a pointer to a FitsHduList. This pointer */
-/* must also be used when reading data from the image. */
-/* On failure, NULL is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-FitsHduList *
-fits_seek_image (FitsFile *ff,
- gint picind)
-{
- FitsHduList *hdulist;
- gint hdupicind;
- glong offset, pic_size;
-
- hdulist = fits_image_info (ff, picind, &hdupicind);
- if (hdulist == NULL)
- return NULL;
-
- pic_size = hdulist->bpp * hdulist->naxisn[0] * hdulist->naxisn[1];
- offset = hdulist->data_offset + (hdupicind - 1) * pic_size;
- if (fseek (ff->fp, offset, SEEK_SET) < 0)
- FITS_RETURN ("fits_seek_image: Unable to position to image", NULL);
-
- return hdulist;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_read_pixel - read pixel values from a file */
-/* */
-/* Parameters: */
-/* FitsFile *ff [I] : FITS file structure */
-/* FitsHduList *hdulist [I] : pointer to hdulist that describes image */
-/* int npix [I] : number of pixel values to read */
-/* FitsPixTransform *trans [I]: pixel transformation */
-/* void *buf [O] : buffer where to place transformed pixels */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function reads npix pixel values from the file, transforms them */
-/* checking for blank/NaN pixels and stores the transformed values in buf. */
-/* The number of transformed pixels is returned. If the returned value is */
-/* less than npix (or even -1), an error has occurred. */
-/* hdulist must be a pointer returned by fits_seek_image(). Before starting */
-/* to read an image, fits_seek_image() must be called. Even for successive */
-/* images. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gint
-fits_read_pixel (FitsFile *ff,
- FitsHduList *hdulist,
- gint npix,
- FitsPixTransform *trans,
- void *buf)
-{
- gdouble offs, scale;
- gdouble datadiff, pixdiff;
- guchar pixbuffer[4096];
- guchar *pix;
- glong creplace;
- gint transcount = 0;
- glong tdata, tmin, tmax;
- gint maxelem;
-
- if (ff->openmode != 'r')
- return -1; /* Not open for reading */
-
- if (trans->dsttyp != 'k')
- return -1; /* Currently we only return types equivalent to the image format */
-
- if (npix <= 0)
- return npix;
-
- datadiff = trans->datamax - trans->datamin;
- pixdiff = trans->pixmax - trans->pixmin;
-
- offs = trans->datamin - trans->pixmin * datadiff / pixdiff;
- scale = datadiff / pixdiff;
-
- tmin = (glong) trans->datamin;
- tmax = (glong) trans->datamax;
-
- creplace = (glong) trans->replacement;
-
- switch (hdulist->bitpix)
- {
- case 8:
- {
- guchar *cdata = (guchar *) buf;
- while (npix > 0) /* For all pixels to read */
- {
- FitsBitpix8 bp8, bp8blank;
-
- maxelem = sizeof (pixbuffer) / hdulist->bpp;
- if (maxelem > npix)
- maxelem = npix;
-
- if (fread ((gchar *) pixbuffer, hdulist->bpp,
- maxelem, ff->fp) != maxelem)
- return -1;
-
- npix -= maxelem;
-
- pix = pixbuffer;
-
- if (hdulist->used.blank)
- {
- bp8blank = (FitsBitpix8) hdulist->blank;
-
- while (maxelem--)
- {
- bp8 = (FitsBitpix8) * (pix++);
-
- if (bp8 == bp8blank) /* Is it a blank pixel ? */
- {
- *(cdata++) = (guchar) creplace;
- }
- else /* Do transform */
- {
- tdata = (glong) (bp8 * scale + offs);
- tdata = CLAMP (tdata, tmin, tmax);
-
- *(cdata++) = (guchar) tdata;
- }
-
- transcount++;
- }
- }
- else
- {
- while (maxelem--)
- {
- bp8 = (FitsBitpix8) * (pix++);
-
- tdata = (glong) (bp8 * scale + offs);
- tdata = CLAMP (tdata, tmin, tmax);
-
- *(cdata++) = (guchar) tdata;
-
- transcount++;
- }
- }
- }
- }
- break;
-
- case 16:
- {
- FitsBitpix16 *cdata = (FitsBitpix16 *) buf;
- while (npix > 0) /* For all pixels to read */
- {
- FitsBitpix16 bp16, bp16blank;
-
- maxelem = sizeof (pixbuffer) / hdulist->bpp;
- if (maxelem > npix)
- maxelem = npix;
-
- if (fread ((gchar *) pixbuffer, hdulist->bpp,
- maxelem, ff->fp) != maxelem)
- return -1;
-
- npix -= maxelem;
-
- pix = pixbuffer;
- if (hdulist->used.blank)
- {
- bp16blank = (FitsBitpix16) hdulist->blank;
-
- while (maxelem--)
- {
- FITS_GETBITPIX16 (pix, bp16);
-
- if (bp16 == bp16blank)
- {
- *(cdata++) = (FitsBitpix16) creplace;
- }
- else
- {
- tdata = (glong) (bp16 * scale + offs);
-
- if (tdata < tmin)
- tdata = tmin;
- else if (tdata > tmax)
- tdata = tmax;
-
- *(cdata++) = (FitsBitpix16) tdata;
- }
-
- transcount++;
- pix += 2;
- }
- }
- else
- {
- while (maxelem--)
- {
- FITS_GETBITPIX16 (pix, bp16);
-
- tdata = (glong) (bp16 * scale + offs);
- if (tdata < tmin)
- tdata = tmin;
- else if (tdata > tmax)
- tdata = tmax;
-
- *(cdata++) = (FitsBitpix16) tdata;
-
- transcount++;
- pix += 2;
- }
- }
- }
- }
- break;
-
- case 32:
- {
- FitsBitpix32 *cdata = (FitsBitpix32 *) buf;
- while (npix > 0) /* For all pixels to read */
- {
- FitsBitpix32 bp32, bp32blank;
-
- maxelem = sizeof (pixbuffer) / hdulist->bpp;
- if (maxelem > npix)
- maxelem = npix;
-
- if (fread ((gchar *) pixbuffer, hdulist->bpp,
- maxelem, ff->fp) != maxelem)
- return -1;
-
- npix -= maxelem;
-
- pix = pixbuffer;
- if (hdulist->used.blank)
- {
- bp32blank = (FitsBitpix32) hdulist->blank;
-
- while (maxelem--)
- {
- FITS_GETBITPIX32 (pix, bp32);
-
- if (bp32 == bp32blank)
- {
- *(cdata++) = (FitsBitpix32) creplace;
- }
- else
- {
- tdata = (glong) (bp32 * scale + offs);
- if (tdata < tmin)
- tdata = tmin;
- else if (tdata > tmax)
- tdata = tmax;
-
- *(cdata++) = (FitsBitpix32) tdata;
- }
-
- transcount++;
- pix += 4;
- }
- }
- else
- {
- while (maxelem--)
- {
- FITS_GETBITPIX32 (pix, bp32);
-
- tdata = (glong) (bp32 * scale + offs);
- tdata = CLAMP (tdata, tmin, tmax);
-
- *(cdata++) = (FitsBitpix32) tdata;
-
- transcount++;
- pix += 4;
- }
- }
- }
- }
- break;
-
- case -32:
- {
- FitsBitpixM32 *cdata = (FitsBitpixM32 *) buf;
- while (npix > 0) /* For all pixels to read */
- {
- FitsBitpixM32 bpm32 = 0;
-
- maxelem = sizeof (pixbuffer) / hdulist->bpp;
- if (maxelem > npix)
- maxelem = npix;
-
- if (fread ((gchar *) pixbuffer, hdulist->bpp,
- maxelem, ff->fp) != maxelem)
- return -1;
-
- npix -= maxelem;
-
- pix = pixbuffer;
- while (maxelem--)
- {
- if (fits_nan_32 (pix)) /* An IEEE special value ? */
- {
- *(cdata++) = trans->replacement;
- }
- else /* Do transform */
- {
- FITS_GETBITPIXM32 (pix, bpm32);
-
- bpm32 = bpm32 * scale + offs;
- bpm32 = CLAMP (bpm32, trans->datamin, trans->datamax);
-
- *(cdata++) = bpm32;
- }
-
- transcount++;
- pix += 4;
- }
- }
- }
- break;
-
- case -64:
- {
- FitsBitpixM64 *cdata = (FitsBitpixM64 *) buf;
- while (npix > 0) /* For all pixels to read */
- {
- FitsBitpixM64 bpm64;
-
- maxelem = sizeof (pixbuffer) / hdulist->bpp;
- if (maxelem > npix)
- maxelem = npix;
-
- if (fread ((gchar *) pixbuffer, hdulist->bpp,
- maxelem, ff->fp) != maxelem)
- return -1;
-
- npix -= maxelem;
-
- pix = pixbuffer;
- while (maxelem--)
- {
- if (fits_nan_64 (pix))
- {
- *(cdata++) = trans->replacement;
- }
- else
- {
- FITS_GETBITPIXM64 (pix, bpm64);
-
- bpm64 = bpm64 * scale + offs;
- bpm64 = CLAMP (bpm64, trans->datamin, trans->datamax);
-
- *(cdata++) = bpm64;
- }
-
- transcount++;
- pix += 8;
- }
- }
- }
- break;
- }
-
- return transcount;
-}
-
-
-#ifndef FITS_NO_DEMO
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : fits_to_pgmraw - convert FITS-file to raw PGM-file */
-/* */
-/* Parameters: */
-/* char *fitsfile [I] : name of fitsfile */
-/* char *pgmfile [I] : name of pgmfile */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function converts a FITS-file to a raw PGM-file. The PGM-file will */
-/* be upside down, because the orientation for storing the image is */
-/* different. On success, 0 is returned. On failure, -1 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gint
-fits_to_pgmraw (gchar *fitsfile,
- gchar *pgmfile)
-{
- FitsFile *fitsin = NULL;
- FILE *pgmout = NULL;
- FitsHduList *hdu;
- FitsPixTransform trans;
- gint retval = -1, nbytes, maxbytes;
- gchar buffer[1024];
-
- fitsin = fits_open (fitsfile, "r"); /* Open FITS-file for reading */
- if (fitsin == NULL)
- goto err_return;
-
- if (fitsin->n_pic < 1)
- goto err_return; /* Any picture in it ? */
-
- hdu = fits_seek_image (fitsin, 1); /* Position to the first image */
- if (hdu == NULL)
- goto err_return;
-
- if (hdu->naxis < 2)
- goto err_return; /* Enough dimensions ? */
-
- pgmout = g_fopen (pgmfile, "wb");
- if (pgmout == NULL)
- goto err_return;
-
- /* Write PGM header with width/height */
- fprintf (pgmout, "P5\n%d %d\n255\n", hdu->naxisn[0], hdu->naxisn[1]);
-
- /* Set up transformation for FITS pixel values to 0...255 */
- /* It maps trans.pixmin to trans.datamin and trans.pixmax to trans.datamax. */
- /* Values out of range [datamin, datamax] are clamped */
- trans.pixmin = hdu->pixmin;
- trans.pixmax = hdu->pixmax;
- trans.datamin = 0.0;
- trans.datamax = 255.0;
- trans.replacement = 0.0; /* Blank/NaN replacement value */
- trans.dsttyp = 'c'; /* Output type is character */
-
- nbytes = hdu->naxisn[0]*hdu->naxisn[1];
- while (nbytes > 0)
- {
- maxbytes = sizeof (buffer);
- if (maxbytes > nbytes)
- maxbytes = nbytes;
-
- /* Read pixels and transform them */
- if (fits_read_pixel (fitsin, hdu, maxbytes, &trans, buffer) != maxbytes)
- goto err_return;
-
- if (fwrite (buffer, 1, maxbytes, pgmout) != maxbytes)
- goto err_return;
-
- nbytes -= maxbytes;
- }
-
- retval = 0;
-
- err_return:
-
- if (fitsin)
- fits_close (fitsin);
-
- if (pgmout)
- fclose (pgmout);
-
- return retval;
-}
-
-
-/*****************************************************************************/
-/* #BEG-PAR */
-/* */
-/* Function : pgmraw to fits - convert raw PGM-file to FITS-file */
-/* */
-/* Parameters: */
-/* char *pgmfile [I] : name of pgmfile */
-/* char *fitsfile [I] : name of fitsfile */
-/* ( mode : I=input, O=output, I/O=input/output ) */
-/* */
-/* The function converts a raw PGM-file to a FITS-file. The FITS-file will */
-/* be upside down, because the orientation for storing the image is */
-/* different. On success, 0 is returned. On failure, -1 is returned. */
-/* */
-/* #END-PAR */
-/*****************************************************************************/
-
-gint
-pgmraw_to_fits (gchar *pgmfile,
- gchar *fitsfile)
-{
- FitsFile *fitsout = NULL;
- FILE *pgmin = NULL;
- FitsHduList *hdu;
- gchar buffer[1024];
- gint width, height, numbytes, maxbytes;
- gint retval = -1;
-
- fitsout = fits_open (fitsfile, "w");
- if (fitsout == NULL)
- goto err_return;
-
- pgmin = g_fopen (pgmfile, "r");
- if (pgmin == NULL)
- goto err_return;
-
- /* Read signature of PGM file */
- if (fgets (buffer, sizeof (buffer), pgmin) == NULL)
- goto err_return;
-
- if ((buffer[0] != 'P') || (buffer[1] != '5'))
- goto err_return;
-
- /* Skip comments up to width/height */
- do
- {
- if (fgets (buffer, sizeof (buffer), pgmin) == NULL)
- goto err_return;
- }
- while (buffer[0] == '#');
-
- if (sscanf (buffer, "%d%d", &width, &height) != 2)
- goto err_return;
-
- if ((width < 1) || (height < 1))
- goto err_return;
-
- /* Skip comments up to maxval */
- do
- {
- if (fgets (buffer, sizeof (buffer), pgmin) == NULL)
- goto err_return;
- }
- while (buffer[0] == '#');
-
- /* Ignore maxval */
-
- hdu = fits_add_hdu (fitsout); /* Create a HDU for the FITS file */
- if (hdu == NULL)
- goto err_return;
-
- hdu->used.simple = 1; /* Set proper values */
- hdu->bitpix = 8;
- hdu->naxis = 2;
- hdu->naxisn[0] = width;
- hdu->naxisn[1] = height;
- hdu->used.datamin = 1;
- hdu->datamin = 0.0;
- hdu->used.datamax = 1;
- hdu->datamax = 255.0;
- hdu->used.bzero = 1;
- hdu->bzero = 0.0;
- hdu->used.bscale = 1;
- hdu->bscale = 1.0;
-
- fits_add_card (hdu, "");
- fits_add_card (hdu,
- "HISTORY THIS FITS FILE WAS GENERATED BY FITSRW "
- "USING PGMRAW_TO_FITS");
-
- /* Write the header. Blocking is done automatically */
- if (fits_write_header (fitsout, hdu) < 0)
- goto err_return;
-
- /* The primary array plus blocking must be written manually */
- numbytes = width * height;
-
- while (numbytes > 0)
- {
- maxbytes = sizeof (buffer);
- if (maxbytes > numbytes)
- maxbytes = numbytes;
-
- if (fread (buffer, 1, maxbytes, pgmin) != maxbytes)
- goto err_return;
-
- if (fwrite (buffer, 1, maxbytes, fitsout->fp) != maxbytes)
- goto err_return;
-
- numbytes -= maxbytes;
- }
-
- /* Do blocking */
- numbytes = (width * height) % FITS_RECORD_SIZE;
- if (numbytes)
- {
- while (numbytes++ < FITS_RECORD_SIZE)
- if (putc (0, fitsout->fp) == EOF)
- goto err_return;
- }
-
- retval = 0;
-
- err_return:
-
- if (fitsout)
- fits_close (fitsout);
-
- if (pgmin)
- fclose (pgmin);
-
- return retval;
-}
-
-#endif /* ! FITS_NO_DEMO */
diff --git a/plug-ins/file-fits/fits-io.h b/plug-ins/file-fits/fits-io.h
deleted file mode 100644
index 8732db1763..0000000000
--- a/plug-ins/file-fits/fits-io.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/******************************************************************************/
-/* Peter Kirchgessner */
-/* e-mail: pkirchg@aol.com */
-/* WWW : http://members.aol.com/pkirchg */
-/******************************************************************************/
-/* #BEG-HDR */
-/* */
-/* Package : FITS reading/writing library */
-/* Modul-Name : fitsrw.h */
-/* Description : Include file for FITS-r/w-library */
-/* Function(s) : */
-/* Author : P. Kirchgessner */
-/* Date of Gen. : 12-Apr-97 */
-/* Last modified : 17-May-97 */
-/* Version : 0.10 */
-/* Compiler Opt. : */
-/* Changes : */
-/* */
-/* #END-HDR */
-/******************************************************************************/
-
-#ifndef __FITS_IO_H__
-#define __FITS_IO_H__
-
-#define FITS_CARD_SIZE 80
-#define FITS_RECORD_SIZE 2880
-#define FITS_MAX_AXIS 999
-
-#define FITS_NADD_CARDS 128
-
-/* Data representations */
-
-typedef guchar FitsBitpix8;
-typedef gint16 FitsBitpix16;
-typedef gint32 FitsBitpix32;
-typedef float FitsBitpixM32;
-typedef double FitsBitpixM64;
-typedef gint32 FitsBool;
-typedef gint32 FitsLong;
-typedef double FitsDouble;
-typedef char FitsString[FITS_CARD_SIZE];
-
-typedef enum
-{
- FITS_DATA_TYPE_BITPIX_8,
- FITS_DATA_TYPE_BITPIX_16,
- FITS_DATA_TYPE_BITPIX_32,
- FITS_DATA_TYPE_BITPIX_M32,
- FITS_DATA_TYPE_BITPIX_M64,
- FITS_DATA_TYPE_FBOOL,
- FITS_DATA_TYPE_FLONG,
- FITS_DATA_TYPE_FDOUBLE,
- FITS_DATA_TYPE_FSTRING
-} FitsDataType;
-
-typedef union
-{
- FitsBitpix8 bitpix8;
- FitsBitpix16 bitpix16;
- FitsBitpix32 bitpix32;
- FitsBitpixM32 bitpixm32;
- FitsBitpixM64 bitpixm64;
- FitsBool fbool;
- FitsLong flong;
- FitsDouble fdouble;
- FitsString fstring;
-} FitsData;
-
-
-/* How to transform FITS pixel values */
-
-typedef struct _FitsPixTransform FitsPixTransform;
-
-struct _FitsPixTransform
-{
- gdouble pixmin, pixmax; /* Pixel values [pixmin,pixmax] should be mapped */
- gdouble datamin, datamax; /* to [datamin,datamax] */
- gdouble replacement; /* datavalue to use for blank or NaN pixels */
- gchar dsttyp; /* Destination typ ('c' = char) */
-};
-
-
-/* Record list */
-
-typedef struct _FitsRecordList FitsRecordList;
-
-struct _FitsRecordList
-{
- gchar data[FITS_RECORD_SIZE];
- FitsRecordList *next_record;
-};
-
-
-/* Header and Data Unit List */
-
-typedef struct _FitsHduList FitsHduList;
-
-struct _FitsHduList
-{
- glong header_offset; /* Offset of header in the file */
- glong data_offset; /* Offset of data in the file */
- glong data_size; /* Size of data in the HDU (including pad)*/
- glong udata_size; /* Size of used data in the HDU (excl. pad) */
- gint bpp; /* Bytes per pixel */
- gint numpic; /* Number of interpretable images in HDU */
- gint naddcards; /* Number of additional cards */
- gchar addcards[FITS_NADD_CARDS][FITS_CARD_SIZE];
- struct
- {
- gboolean nan_value; /* NaN's found in data ? */
- gboolean blank_value; /* Blanks found in data ? */
- /* Flags specifying if some cards are used */
- gchar blank; /* The corresponding data below is only */
- gchar datamin; /* valid, if the flag is set. */
- gchar datamax;
- gchar simple; /* This indicates a simple HDU */
- gchar xtension; /* This indicates an extension */
- gchar gcount;
- gchar pcount;
- gchar bzero;
- gchar bscale;
- gchar groups;
- gchar extend;
- } used;
- gdouble pixmin, pixmax; /* Minimum/Maximum pixel values */
- /* Some decoded data of the HDU: */
- gint naxis; /* Number of axes */
- gint naxisn[FITS_MAX_AXIS]; /* Sizes of axes (NAXIS1 --> naxisn[0]) */
- gint bitpix; /* Data representation (8,16,32,-16,-32) */
- /* When using the following data, */
- /* the used-flags must be checked before. */
- glong blank; /* Blank value */
- gdouble datamin, datamax; /* Minimum/Maximum physical data values */
- gchar xtension[FITS_CARD_SIZE];/* Type of extension */
- glong gcount, pcount; /* Used by XTENSION */
- gdouble bzero, bscale; /* Transformation values */
- gint groups; /* Random groups indicator */
- gint extend; /* Extend flag */
-
- FitsRecordList *header_record_list; /* Header records read in */
-
- FitsHduList *next_hdu;
-};
-
-
-typedef struct _FitsFile FitsFile;
-
-struct _FitsFile
-{
- FILE *fp; /* File pointer to fits file */
- gchar openmode; /* Mode the file was opened (0, 'r', 'w') */
-
- gint n_hdu; /* Number of HDUs in file */
- gint n_pic; /* Total number of interpretable pictures */
- gboolean nan_used; /* NaN's used in the file ? */
- gboolean blank_used; /* Blank's used in the file ? */
-
- FitsHduList *hdu_list; /* Header and Data Unit List */
-};
-
-
-/* User callable functions of the FITS-library */
-
-FitsFile * fits_open (const gchar *filename,
- const gchar *openmode);
-void fits_close (FitsFile *ff);
-FitsHduList * fits_add_hdu (FitsFile *ff);
-gint fits_add_card (FitsHduList *hdulist,
- const gchar *card);
-gint fits_write_header (FitsFile *ff,
- FitsHduList *hdulist);
-FitsHduList * fits_image_info (FitsFile *ff,
- gint picind,
- gint *hdupicind);
-FitsHduList * fits_seek_image (FitsFile *ff,
- gint picind);
-void fits_print_header (FitsHduList *hdr);
-FitsData * fits_decode_card (const gchar *card,
- FitsDataType data_type);
-gchar * fits_search_card (FitsRecordList *rl,
- gchar *keyword);
-gint fits_read_pixel (FitsFile *ff,
- FitsHduList *hdulist,
- gint npix,
- FitsPixTransform *trans,
- void *buf);
-
-gchar * fits_get_error (void);
-
-
-/* Demo functions */
-
-#define FITS_NO_DEMO
-gint fits_to_pgmraw (gchar *fitsfile,
- gchar *pgmfile);
-gint pgmraw_to_fits (gchar *pgmfile,
- gchar *fitsfile);
-
-#endif /* __FITS_IO_H__ */
diff --git a/plug-ins/file-fits/fits.c b/plug-ins/file-fits/fits.c
index 416944eb8c..955ea6d15b 100644
--- a/plug-ins/file-fits/fits.c
+++ b/plug-ins/file-fits/fits.c
@@ -44,7 +44,7 @@
#include
#include
-#include "fits-io.h"
+#include
#include "libgimp/stdplugins-intl.h"
@@ -74,6 +74,15 @@ struct _FitsClass
GType fits_get_type (void) G_GNUC_CONST;
+typedef struct
+{
+ gint naxis;
+ glong naxisn[3];
+ gint bitpix;
+ gint bpp;
+ gint datatype;
+} FitsHduData;
+
static GList * fits_query_procedures (GimpPlugIn *plug_in);
static GimpProcedure * fits_create_procedure (GimpPlugIn *plug_in,
const gchar *name);
@@ -101,13 +110,7 @@ static gint save_image (GFile *file,
GimpDrawable *drawable,
GError **error);
-static FitsHduList * create_fits_header (FitsFile *ofp,
- guint width,
- guint height,
- guint channels,
- guint bitpix);
-
-static gint save_fits (FitsFile *ofp,
+static gint save_fits (GFile *file,
GimpImage *image,
GimpDrawable *drawable);
@@ -121,15 +124,9 @@ static GimpImage * create_new_image (GFile *file,
GimpLayer **layer,
GeglBuffer **buffer);
-static GimpImage * load_fits (GFile *file,
- FitsFile *ifp,
- GObject *config,
- guint picnum,
- guint ncompose);
-
static gboolean load_dialog (GimpProcedure *procedure,
GObject *config);
-static void show_fits_errors (void);
+static void show_fits_errors (gint status);
G_DEFINE_TYPE (Fits, fits, GIMP_TYPE_PLUG_IN)
@@ -177,17 +174,18 @@ fits_create_procedure (GimpPlugIn *plug_in,
fits_load, NULL, NULL);
gimp_procedure_set_menu_label (procedure,
- N_("Flexible Image Transport System"));
+ _("Flexible Image Transport System"));
gimp_procedure_set_documentation (procedure,
- "Load file of the FITS file format",
- "Load file of the FITS file format "
- "(Flexible Image Transport System)",
+ _("Load file of the FITS file format"),
+ _("Load file of the FITS file format "
+ "(Flexible Image Transport System)"),
name);
gimp_procedure_set_attribution (procedure,
"Peter Kirchgessner",
- "Peter Kirchgessner (peter@kirchgessner.net)",
- "1997");
+ "Peter Kirchgessner (peter@kirchgessner.net), "
+ "Alex Sa.",
+ "1997 - 2023");
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
"image/x-fits");
@@ -197,22 +195,16 @@ fits_create_procedure (GimpPlugIn *plug_in,
"0,string,SIMPLE");
GIMP_PROC_AUX_ARG_INT (procedure, "replace",
- "Replace",
- "Replacement for undefined pixels",
+ _("Replacement for undefined pixels"),
+ _("Replacement for undefined pixels"),
0, 255, 0,
G_PARAM_READWRITE);
- GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "use-data-min-max",
- "Use data min max",
- "Use DATAMIN/DATAMAX-scaling if possible",
- FALSE,
- G_PARAM_READWRITE);
-
- GIMP_PROC_AUX_ARG_BOOLEAN (procedure, "compose",
- "Compose",
- "Image composing",
- FALSE,
- G_PARAM_READWRITE);
+ GIMP_PROC_AUX_ARG_INT (procedure, "use-data-min-max",
+ _("Pixel value scaling"),
+ _("Use DATAMIN/DATAMAX-scaling if possible"),
+ 0, 1, 0,
+ G_PARAM_READWRITE);
}
else if (! strcmp (name, SAVE_PROC))
{
@@ -223,17 +215,18 @@ fits_create_procedure (GimpPlugIn *plug_in,
gimp_procedure_set_image_types (procedure, "RGB, GRAY, INDEXED");
gimp_procedure_set_menu_label (procedure,
- N_("Flexible Image Transport System"));
+ _("Flexible Image Transport System"));
gimp_procedure_set_documentation (procedure,
- "Export file in the FITS file format",
- "FITS exporting handles all image "
- "types except those with alpha channels.",
+ _("Export file in the FITS file format"),
+ _("FITS exporting handles all image "
+ "types except those with alpha channels."),
name);
gimp_procedure_set_attribution (procedure,
"Peter Kirchgessner",
- "Peter Kirchgessner (peter@kirchgessner.net)",
- "1997");
+ "Peter Kirchgessner (peter@kirchgessner.net), "
+ "Alex Sa.",
+ "1997 - 2023");
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
"image/x-fits");
@@ -271,9 +264,6 @@ fits_load (GimpProcedure *procedure,
image = load_image (file, G_OBJECT (config), run_mode, &error);
- /* Write out error messages of FITS-Library */
- show_fits_errors ();
-
if (! image)
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
@@ -301,9 +291,11 @@ fits_save (GimpProcedure *procedure,
const GimpValueArray *args,
gpointer run_data)
{
- GimpPDBStatusType status = GIMP_PDB_SUCCESS;
- GimpExportReturn export = GIMP_EXPORT_CANCEL;
- GError *error = NULL;
+ GimpImage *duplicate_image;
+ GimpItem **flipped_drawables;
+ GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+ GimpExportReturn export = GIMP_EXPORT_CANCEL;
+ GError *error = NULL;
gegl_init (NULL, NULL);
@@ -338,10 +330,17 @@ fits_save (GimpProcedure *procedure,
error);
}
- if (! save_image (file, image, drawables[0], &error))
- {
- status = GIMP_PDB_EXECUTION_ERROR;
- }
+ /* Flip image vertical since FITS writes from bottom to top */
+ duplicate_image = gimp_image_duplicate (image);
+ gimp_image_flip (duplicate_image, GIMP_ORIENTATION_VERTICAL);
+ flipped_drawables =
+ gimp_image_get_selected_drawables (duplicate_image, &n_drawables);
+
+ if (! save_image (file, image, GIMP_DRAWABLE (flipped_drawables[0]), &error))
+ status = GIMP_PDB_EXECUTION_ERROR;
+
+ gimp_image_delete (duplicate_image);
+ g_free (flipped_drawables);
if (export == GIMP_EXPORT_EXPORT)
{
@@ -358,19 +357,35 @@ load_image (GFile *file,
GimpRunMode run_mode,
GError **error)
{
- GimpImage *image;
- GimpImage **image_list;
- GimpImage **nl;
- guint picnum;
- gint k, n_images, max_images, hdu_picnum;
- gint compose;
- FILE *fp;
- FitsFile *ifp;
- FitsHduList *hdu;
- gboolean compose_arg;
+ GimpImage *image = NULL;
+ GimpLayer *layer;
+ GeglBuffer *buffer;
+ FILE *fp;
+ fitsfile *ifp;
+ FitsHduData hdu;
+ gint n_pics;
+ gint count = 1;
+ gint width;
+ gint height;
+ gint row_length;
+ int status = 0;
+ glong fpixel[3] = {1, 1, 1};
+ GimpImageBaseType itype = GIMP_GRAY;
+ GimpImageType dtype = GIMP_GRAYA_IMAGE;
+ GimpPrecision iprecision = GIMP_PRECISION_U16_NON_LINEAR;
+ const Babl *type = NULL;
+ const Babl *format = NULL;
+ gdouble *pixels;
+ gdouble datamin = 1.0E30f;
+ gdouble datamax = -1.0E30f;
+ gint channels = 1;
+ gint replace;
+ gdouble replace_val = 0;
+ gboolean use_datamin;
g_object_get (config,
- "compose", &compose_arg,
+ "replace", &replace,
+ "use-data-min-max", &use_datamin,
NULL);
fp = g_fopen (g_file_peek_path (file), "rb");
@@ -385,85 +400,207 @@ load_image (GFile *file,
fclose (fp);
- ifp = fits_open (g_file_peek_path (file), "r");
+ if (fits_open_diskfile (&ifp, g_file_peek_path (file), READONLY, &status))
+ show_fits_errors (status);
if (! ifp)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
- "%s", _("Error during open of FITS file"));
+ "%s", _("Error during opening of FITS file"));
return NULL;
}
- if (ifp->n_pic <= 0)
+ /* Get first item */
+ fits_get_num_hdus (ifp, &n_pics, &status);
+
+ if (status)
+ show_fits_errors (status);
+
+ if (n_pics <= 0)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
"%s", _("FITS file keeps no displayable images"));
- fits_close (ifp);
+ fits_close_file (ifp, &status);
return NULL;
}
- image_list = g_new (GimpImage *, 10);
- n_images = 0;
- max_images = 10;
-
- for (picnum = 1; picnum <= ifp->n_pic; )
+ while (count <= n_pics)
{
- /* Get image info to see if we can compose them */
- hdu = fits_image_info (ifp, picnum, &hdu_picnum);
- if (hdu == NULL)
- break;
+ hdu.naxis = 0;
- /* Get number of FITS-images to compose */
- compose = (compose_arg && (hdu_picnum == 1) && (hdu->naxis == 3) &&
- (hdu->naxisn[2] > 1) && (hdu->naxisn[2] <= 4));
+ fits_movabs_hdu (ifp, count, NULL, &status);
- if (compose)
- compose = hdu->naxisn[2];
- else
- compose = 1; /* Load as GRAY */
+ fits_get_img_param (ifp, 3, &hdu.bitpix, &hdu.naxis, hdu.naxisn,
+ &status);
- image = load_fits (file, ifp, config, picnum, compose);
+ width = hdu.naxisn[0];
+ height = hdu.naxisn[1];
- /* Write out error messages of FITS-Library */
- show_fits_errors ();
+ /* Skip if invalid dimensions; possibly header data */
+ if (hdu.naxis < 2)
+ {
+ count++;
+ continue;
+ }
+
+ type = babl_type ("double");
+ switch (hdu.bitpix)
+ {
+ case 8:
+ iprecision = GIMP_PRECISION_U8_LINEAR;
+ if (replace)
+ replace_val = 255;
+ break;
+ case 16:
+ iprecision = GIMP_PRECISION_U16_NON_LINEAR;
+ if (replace)
+ replace_val = G_MAXSHORT;
+ break;
+ case 32:
+ iprecision = GIMP_PRECISION_U32_LINEAR;
+ if (replace)
+ replace_val = G_MAXINT;
+ break;
+ case -32:
+ iprecision = GIMP_PRECISION_FLOAT_LINEAR;
+ if (replace)
+ replace_val = G_MAXFLOAT;
+ break;
+ case -64:
+ iprecision = GIMP_PRECISION_DOUBLE_LINEAR;
+ if (replace)
+ replace_val = G_MAXDOUBLE;
+ break;
+ }
+
+ if (hdu.naxis == 2)
+ {
+ itype = GIMP_GRAY;
+ dtype = GIMP_GRAYA_IMAGE;
+ format = babl_format_new (babl_model ("Y'"),
+ type,
+ babl_component ("Y'"),
+ NULL);
+ }
+ else if (hdu.naxisn[2])
+ {
+ /* Original RGB format */
+ if (hdu.naxisn[0] == 3)
+ {
+ width = hdu.naxisn[1];
+ height = hdu.naxisn[2];
+ }
+ channels = 3;
+
+ itype = GIMP_RGB;
+ dtype = GIMP_RGB_IMAGE;
+ format = babl_format_new (babl_model ("R'G'B'"),
+ type,
+ babl_component ("R'"),
+ babl_component ("G'"),
+ babl_component ("B'"),
+ NULL);
+ }
+
+ /* If RGB FITS image, we need to increase the size by the number of channels */
+ pixels = (gdouble *) malloc (width * sizeof (gdouble) * channels);
if (! image)
- break;
-
- if (n_images == max_images)
{
- nl = (GimpImage **) g_realloc (image_list,
- (max_images + 10) * sizeof (GimpImage *));
- if (nl == NULL)
+ image = create_new_image (file, count, width, height,
+ itype, dtype, iprecision,
+ &layer, &buffer);
+ }
+ else
+ {
+ layer = gimp_layer_new (image, _("FITS HDU"), width, height,
+ dtype, 100,
+ gimp_image_get_default_new_layer_mode (image));
+ gimp_image_insert_layer (image, layer, NULL, 0);
+ buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
+ }
+
+ row_length = width * channels;
+
+ /* Calculate min/max pixel value for normalizing */
+ for (fpixel[1] = height; fpixel[1] >= 1; fpixel[1]--)
+ {
+ if (fits_read_pix (ifp, TDOUBLE, fpixel, row_length, NULL,
+ pixels, NULL, &status))
break;
- image_list = nl;
- max_images += 10;
+ for (gint ii = 0; ii < row_length; ii++)
+ {
+ if (pixels[ii] < datamin)
+ datamin = pixels[ii];
+
+ if (pixels[ii] > datamax)
+ datamax = pixels[ii];
+ }
}
- image_list[n_images++] = image;
+ if (status)
+ show_fits_errors (status);
- picnum += compose;
- }
-
- /* Write out error messages of FITS-Library */
- show_fits_errors ();
-
- fits_close (ifp);
-
- /* Display images in reverse order. The last will be displayed by GIMP itself*/
- if (run_mode != GIMP_RUN_NONINTERACTIVE)
- {
- for (k = n_images-1; k >= 1; k--)
+ /* Read pixel values in */
+ for (fpixel[1] = height; fpixel[1] >= 1; fpixel[1]--)
{
- gimp_image_undo_enable (image_list[k]);
- gimp_image_clean_all (image_list[k]);
- gimp_display_new (image_list[k]);
+ gdouble *temp =
+ (gdouble *) malloc (width * sizeof (gdouble) * channels);
+
+ if (fits_read_pix (ifp, TDOUBLE, fpixel, row_length, &replace_val,
+ pixels, NULL, &status))
+ break;
+
+ if (datamin < datamax)
+ {
+ for (gint ii = 0; ii < row_length; ii++)
+ pixels[ii] = (pixels[ii] - datamin) / (datamax - datamin);
+ }
+
+ if (hdu.naxisn[2] && hdu.naxisn[2] == 3) /* Packed RGB format */
+ {
+ /* Cover planes to RGB format */
+ for (gint ii = 0; ii < (row_length / 3); ii++)
+ {
+ temp[(ii * 3)] = pixels[ii];
+ temp[(ii * 3) + 1] = pixels[ii + (row_length / 3)];
+ temp[(ii * 3) + 2] = pixels[ii + ((row_length / 3) * 2)];
+ }
+ }
+ else
+ {
+ temp = pixels;
+ }
+
+ gegl_buffer_set (buffer,
+ GEGL_RECTANGLE (0, height - fpixel[1],
+ width, 1), 0,
+ format, temp, GEGL_AUTO_ROWSTRIDE);
}
+ if (status)
+ show_fits_errors (status);
+
+ g_object_unref (buffer);
+ if (pixels)
+ g_free (pixels);
+
+ count++;
}
- image = (n_images > 0) ? image_list[0] : NULL;
- g_free (image_list);
+ /* As there might be different sized layers,
+ * we need to resize the canvas afterwards */
+ gimp_image_resize_to_layers (image);
+
+ fits_close_file (ifp, &status);
+
+ if (! image)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "%s", _("FITS file keeps no displayable images"));
+ fits_close_file (ifp, &status);
+ return NULL;
+ }
return image;
}
@@ -474,7 +611,6 @@ save_image (GFile *file,
GimpDrawable *drawable,
GError **error)
{
- FitsFile *ofp;
GimpImageType drawable_type;
gint retval;
@@ -504,20 +640,9 @@ save_image (GFile *file,
gimp_progress_init_printf (_("Exporting '%s'"),
gimp_file_get_utf8_name (file));
- /* Open the output file. */
- ofp = fits_open (g_file_peek_path (file), "w");
- if (! ofp)
- {
- g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
- _("Could not open '%s' for writing: %s"),
- gimp_file_get_utf8_name (file), g_strerror (errno));
- return (FALSE);
- }
- retval = save_fits (ofp, image, drawable);
-
- fits_close (ofp);
+ retval = save_fits (file, image, drawable);
return retval;
}
@@ -549,394 +674,23 @@ create_new_image (GFile *file,
return image;
}
-
-/* Load FITS image. ncompose gives the number of FITS-images which have
- * to be composed together. This will result in different GIMP image types:
- * 1: GRAY, 2: GRAYA, 3: RGB, 4: RGBA
- */
-static GimpImage *
-load_fits (GFile *file,
- FitsFile *ifp,
- GObject *config,
- guint picnum,
- guint ncompose)
-{
- register guchar *dest, *src;
- guchar *data, *data_end, *linebuf;
- int width, height, tile_height, scan_lines;
- int i, j, max_scan;
- double a, b;
- GimpImage *image;
- GimpLayer *layer;
- GeglBuffer *buffer;
- GimpImageBaseType itype;
- GimpImageType dtype;
- GimpPrecision iprecision;
- gint err = 0;
- FitsHduList *hdulist;
- FitsPixTransform trans;
- double datamax, replacetransform;
- const Babl *type, *format;
- gint replace;
- gboolean use_datamin;
-
- g_object_get (config,
- "replace", &replace,
- "use-data-min-max", &use_datamin,
- NULL);
-
- hdulist = fits_seek_image (ifp, (int)picnum);
- if (hdulist == NULL)
- return NULL;
-
- width = hdulist->naxisn[0]; /* Set the size of the FITS image */
- height = hdulist->naxisn[1];
-
- switch (hdulist->bitpix)
- {
- case 8:
- iprecision = GIMP_PRECISION_U8_NON_LINEAR;
- type = babl_type ("u8");
- datamax = 255.0;
- replacetransform = 1.0;
- break;
- case 16:
- iprecision = GIMP_PRECISION_U16_NON_LINEAR; /* FIXME precision */
- type = babl_type ("u16");
- datamax = 65535.0;
- replacetransform = 257;
- break;
- case 32:
- iprecision = GIMP_PRECISION_U32_LINEAR;
- type = babl_type ("u32");
- datamax = 4294967295.0;
- replacetransform = 16843009;
- break;
- case -32:
- iprecision = GIMP_PRECISION_FLOAT_LINEAR;
- type = babl_type ("float");
- datamax = 1.0;
- replacetransform = 1.0 / 255.0;
- break;
- case -64:
- iprecision = GIMP_PRECISION_DOUBLE_LINEAR;
- type = babl_type ("double");
- datamax = 1.0;
- replacetransform = 1.0 / 255.0;
- break;
- default:
- return NULL;
- }
-
- if (ncompose == 2)
- {
- itype = GIMP_GRAY;
- dtype = GIMP_GRAYA_IMAGE;
- format = babl_format_new (babl_model ("Y'A"),
- type,
- babl_component ("Y'"),
- babl_component ("A"),
- NULL);
- }
- else if (ncompose == 3)
- {
- itype = GIMP_RGB;
- dtype = GIMP_RGB_IMAGE;
- format = babl_format_new (babl_model ("R'G'B'"),
- type,
- babl_component ("R'"),
- babl_component ("G'"),
- babl_component ("B'"),
- NULL);
- }
- else if (ncompose == 4)
- {
- itype = GIMP_RGB;
- dtype = GIMP_RGBA_IMAGE;
- format = babl_format_new (babl_model ("R'G'B'A"),
- type,
- babl_component ("R'"),
- babl_component ("G'"),
- babl_component ("B'"),
- babl_component ("A"),
- NULL);
- }
- else
- {
- ncompose = 1;
- itype = GIMP_GRAY;
- dtype = GIMP_GRAY_IMAGE;
- format = babl_format_new (babl_model ("Y'"),
- type,
- babl_component ("Y'"),
- NULL);
- }
-
- image = create_new_image (file, picnum, width, height,
- itype, dtype, iprecision,
- &layer, &buffer);
-
- tile_height = gimp_tile_height ();
-
- data = g_malloc (tile_height * width * ncompose * hdulist->bpp);
- if (data == NULL)
- return NULL;
-
- data_end = data + tile_height * width * ncompose * hdulist->bpp;
-
- /* If the transformation from pixel value to data value has been
- * specified, use it
- */
- if (use_datamin &&
- hdulist->used.datamin && hdulist->used.datamax &&
- hdulist->used.bzero && hdulist->used.bscale)
- {
- a = (hdulist->datamin - hdulist->bzero) / hdulist->bscale;
- b = (hdulist->datamax - hdulist->bzero) / hdulist->bscale;
-
- if (a < b)
- trans.pixmin = a, trans.pixmax = b;
- else
- trans.pixmin = b, trans.pixmax = a;
- }
- else
- {
- trans.pixmin = hdulist->pixmin;
- trans.pixmax = hdulist->pixmax;
- }
-
- trans.datamin = 0.0;
- trans.datamax = datamax;
- trans.replacement = replace * replacetransform;
- trans.dsttyp = 'k';
-
- /* FITS stores images with bottom row first. Therefore we have to
- * fill the image from bottom to top.
- */
-
- if (ncompose == 1)
- {
- dest = data + tile_height * width * hdulist->bpp;
- scan_lines = 0;
-
- for (i = 0; i < height; i++)
- {
- /* Read FITS line */
- dest -= width * hdulist->bpp;
- if (fits_read_pixel (ifp, hdulist, width, &trans, dest) != width)
- {
- err = 1;
- break;
- }
-
- scan_lines++;
-
- if ((i % 20) == 0)
- gimp_progress_update ((gdouble) (i + 1) / (gdouble) height);
-
- if ((scan_lines == tile_height) || ((i + 1) == height))
- {
- gegl_buffer_set (buffer,
- GEGL_RECTANGLE (0, height - i - 1,
- width, scan_lines), 0,
- format, dest, GEGL_AUTO_ROWSTRIDE);
-
- scan_lines = 0;
- dest = data + tile_height * width * hdulist->bpp;
- }
-
- if (err)
- break;
- }
- }
- else /* multiple images to compose */
- {
- gint channel;
-
- linebuf = g_malloc (width * hdulist->bpp);
- if (linebuf == NULL)
- return NULL;
-
- for (channel = 0; channel < ncompose; channel++)
- {
- dest = data + tile_height * width * hdulist->bpp * ncompose + channel * hdulist->bpp;
- scan_lines = 0;
-
- for (i = 0; i < height; i++)
- {
- if ((channel > 0) && ((i % tile_height) == 0))
- {
- /* Reload a region for follow up channels */
- max_scan = tile_height;
-
- if (i + tile_height > height)
- max_scan = height - i;
-
- gegl_buffer_get (buffer,
- GEGL_RECTANGLE (0, height - i - max_scan,
- width, max_scan), 1.0,
- format, data_end - max_scan * width * hdulist->bpp * ncompose,
- GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
- }
-
- /* Read FITS scanline */
- dest -= width * ncompose * hdulist->bpp;
- if (fits_read_pixel (ifp, hdulist, width, &trans, linebuf) != width)
- {
- err = 1;
- break;
- }
- j = width;
- src = linebuf;
- while (j--)
- {
- memcpy (dest, src, hdulist->bpp);
- src += hdulist->bpp;
- dest += ncompose * hdulist->bpp;
- }
- dest -= width * ncompose * hdulist->bpp;
- scan_lines++;
-
- if ((i % 20) == 0)
- gimp_progress_update ((gdouble) (channel * height + i + 1) /
- (gdouble) (height * ncompose));
-
- if ((scan_lines == tile_height) || ((i + 1) == height))
- {
- gegl_buffer_set (buffer,
- GEGL_RECTANGLE (0, height - i - 1,
- width, scan_lines), 0,
- format, dest - channel * hdulist->bpp, GEGL_AUTO_ROWSTRIDE);
-
- scan_lines = 0;
- dest = data + tile_height * width * ncompose * hdulist->bpp + channel * hdulist->bpp;
- }
-
- if (err)
- break;
- }
- }
-
- g_free (linebuf);
- }
-
- g_free (data);
-
- if (err)
- g_message (_("EOF encountered on reading"));
-
- g_object_unref (buffer);
-
- gimp_progress_update (1.0);
-
- return err ? NULL : image;
-}
-
-
-static FitsHduList *
-create_fits_header (FitsFile *ofp,
- guint width,
- guint height,
- guint channels,
- guint bitpix)
-{
- FitsHduList *hdulist;
- gint print_ctype3 = 0; /* The CTYPE3-card may not be FITS-conforming */
-
- static const char *ctype3_card[] =
- {
- NULL, NULL, NULL, /* bpp = 0: no additional card */
- "COMMENT Image type within GIMP: GIMP_GRAY_IMAGE",
- NULL,
- NULL,
- "COMMENT Image type within GIMP: GIMP_GRAYA_IMAGE (gray with alpha channel)",
- "COMMENT Sequence for NAXIS3 : GRAY, ALPHA",
- "CTYPE3 = 'GRAYA ' / GRAY IMAGE WITH ALPHA CHANNEL",
- "COMMENT Image type within GIMP: GIMP_RGB_IMAGE",
- "COMMENT Sequence for NAXIS3 : RED, GREEN, BLUE",
- "CTYPE3 = 'RGB ' / RGB IMAGE",
- "COMMENT Image type within GIMP: GIMP_RGBA_IMAGE (rgb with alpha channel)",
- "COMMENT Sequence for NAXIS3 : RED, GREEN, BLUE, ALPHA",
- "CTYPE3 = 'RGBA ' / RGB IMAGE WITH ALPHA CHANNEL"
- };
-
- hdulist = fits_add_hdu (ofp);
- if (hdulist == NULL)
- return NULL;
-
- hdulist->used.simple = 1;
- hdulist->bitpix = bitpix;
- hdulist->naxis = (channels == 1) ? 2 : 3;
- hdulist->naxisn[0] = width;
- hdulist->naxisn[1] = height;
- hdulist->naxisn[2] = channels;
- hdulist->used.datamin = 1;
- hdulist->datamin = 0.0;
- hdulist->used.datamax = 1;
- hdulist->used.bzero = 1;
- hdulist->bzero = 0.0;
- hdulist->used.bscale = 1;
- hdulist->bscale = 1.0;
-
- switch (bitpix)
- {
- case 8:
- hdulist->datamax = 255;
- break;
- case 16:
- hdulist->datamax = 65535;
- break;
- case 32:
- hdulist->datamax = 4294967295.0; /* .0 to silence gcc */
- break;
- case -32:
- hdulist->datamax = 1.0;
- break;
- case -64:
- hdulist->datamax = 1.0;
- break;
- default:
- return NULL;
- }
-
- fits_add_card (hdulist, "");
- fits_add_card (hdulist,
- "HISTORY THIS FITS FILE WAS GENERATED BY GIMP USING FITSRW");
- fits_add_card (hdulist, "");
- fits_add_card (hdulist,
- "COMMENT FitsRW is (C) Peter Kirchgessner (peter@kirchgessner.net), but available");
- fits_add_card (hdulist,
- "COMMENT under the GNU general public licence.");
- fits_add_card (hdulist,
- "COMMENT For sources see http://www.kirchgessner.net");
- fits_add_card (hdulist, "");
- fits_add_card (hdulist, ctype3_card[channels * 3]);
-
- if (ctype3_card[channels * 3 + 1] != NULL)
- fits_add_card (hdulist, ctype3_card[channels * 3 + 1]);
-
- if (print_ctype3 && (ctype3_card[channels * 3 + 2] != NULL))
- fits_add_card (hdulist, ctype3_card[channels * 3 + 2]);
-
- fits_add_card (hdulist, "");
-
- return hdulist;
-}
-
-
/* Save direct colors (GRAY, GRAYA, RGB, RGBA) */
static gint
-save_fits (FitsFile *ofp,
+save_fits (GFile *file,
GimpImage *image,
GimpDrawable *drawable)
{
- gint height, width, i, j, channel, channelnum;
- gint tile_height, bpp, bpsl, bitpix, bpc;
- long nbytes;
- guchar *data, *src;
+ fitsfile *fptr;
+ gint status = 0;
+ gint height, width, channelnum;
+ gint bitpix;
+ gint naxis = 2;
+ glong naxes[3];
+ gint export_type;
+ gint nelements;
+ void *data = NULL;
GeglBuffer *buffer;
const Babl *format, *type;
- FitsHduList *hdu;
buffer = gimp_drawable_get_buffer (drawable);
@@ -946,30 +700,36 @@ save_fits (FitsFile *ofp,
format = gegl_buffer_get_format (buffer);
type = babl_format_get_type (format, 0);
+ naxes[0] = width;
+ naxes[1] = height;
+ nelements = width * height;
+
if (type == babl_type ("u8"))
{
- bitpix = 8;
+ bitpix = 8;
+ export_type = TBYTE;
}
else if (type == babl_type ("u16"))
{
- bitpix = 16;
+ bitpix = 16;
+ export_type = TSHORT;
}
else if (type == babl_type ("u32"))
{
- bitpix = 32;
+ bitpix = 32;
+ export_type = TLONG;
}
- else if (type == babl_type ("half"))
+ else if (type == babl_type ("half") ||
+ type == babl_type ("float"))
{
- bitpix = -32;
- type = babl_type ("float");
- }
- else if (type == babl_type ("float"))
- {
- bitpix = -32;
+ bitpix = -32;
+ type = babl_type ("float");
+ export_type = TFLOAT;
}
else if (type == babl_type ("double"))
{
- bitpix = -64;
+ bitpix = -64;
+ export_type = TDOUBLE;
}
else
{
@@ -1001,6 +761,8 @@ save_fits (FitsFile *ofp,
babl_component ("G'"),
babl_component ("B'"),
NULL);
+ naxis = 3;
+ naxes[2] = 3;
break;
case GIMP_RGBA_IMAGE:
@@ -1012,140 +774,197 @@ save_fits (FitsFile *ofp,
babl_component ("B'"),
babl_component ("A"),
NULL);
+ naxis = 4;
+ naxes[2] = 4;
break;
}
channelnum = babl_format_get_n_components (format);
- bpp = babl_format_get_bytes_per_pixel (format);
-
- bpc = bpp / channelnum; /* Bytes per channel */
- bpsl = width * bpp; /* Bytes per scanline */
-
- tile_height = gimp_tile_height ();
/* allocate a buffer for retrieving information from the pixel region */
- src = data = (guchar *) g_malloc (width * height * bpp);
+ if (export_type == TFLOAT)
+ data = (gfloat *) g_malloc (width * height * sizeof (gfloat) * channelnum);
+ else if (export_type == TDOUBLE)
+ data = (gdouble *) g_malloc (width * height * sizeof (gdouble) *
+ channelnum);
+ else
+ data = (guchar *) g_malloc (width * height * sizeof (guchar *) *
+ (bitpix / 8) * channelnum);
- hdu = create_fits_header (ofp, width, height, channelnum, bitpix);
- if (hdu == NULL)
- return FALSE;
-
- if (fits_write_header (ofp, hdu) < 0)
- return FALSE;
-
- nbytes = 0;
- for (channel = 0; channel < channelnum; channel++)
+ /* CFITSIO can't overwrite files unless you start the filename
+ * with a "!". Instead, we'll try to open the existing file
+ * in READWRITE mode, clear it, and then recreate it.
+ */
+ if (fits_create_file (&fptr, g_file_peek_path (file), &status))
{
- for (i = 0; i < height; i++)
+ /* You have to set status back to 0 - subsequent successful
+ functions do not remove the error value */
+ status = 0;
+
+ if (fits_open_file (&fptr, g_file_peek_path (file), READWRITE, &status))
{
- if ((i % tile_height) == 0)
- {
- gint scan_lines;
+ show_fits_errors (status);
+ return FALSE;
+ }
+ fits_delete_file (fptr, &status);
- scan_lines = (i + tile_height-1 < height) ?
- tile_height : (height - i);
-
- gegl_buffer_get (buffer,
- GEGL_RECTANGLE (0, height - i - scan_lines,
- width, scan_lines), 1.0,
- format, data,
- GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
-
- src = data + bpsl * (scan_lines - 1) + channel * bpc;
- }
-
- if (channelnum == 1 && bitpix == 8) /* One channel and 8 bit? Write the scanline */
- {
- fwrite (src, bpc, width, ofp->fp);
- src += bpsl;
- }
- else /* Multiple channels or high bit depth */
- {
- /* Write out bytes for current channel */
- /* FIXME: Don't assume a little endian arch */
- switch (bitpix)
- {
- case 8:
- for (j = 0; j < width; j++)
- {
- putc (*src, ofp->fp);
- src += bpp;
- }
- break;
- case 16:
- for (j = 0; j < width; j++)
- {
- *((guint16*)src) += 32768;
- putc (*(src + 1), ofp->fp);
- putc (*(src + 0), ofp->fp);
- src += bpp;
- }
- break;
- case 32:
- for (j = 0; j < width; j++)
- {
- *((guint32*)src) += 2147483648.0; /* .0 to silence gcc */
- putc (*(src + 3), ofp->fp);
- putc (*(src + 2), ofp->fp);
- putc (*(src + 1), ofp->fp);
- putc (*(src + 0), ofp->fp);
- src += bpp;
- }
- break;
- case -32:
- for (j = 0; j < width; j++)
- {
- putc (*(src + 3), ofp->fp);
- putc (*(src + 2), ofp->fp);
- putc (*(src + 1), ofp->fp);
- putc (*(src + 0), ofp->fp);
- src += bpp;
- }
- break;
- case -64:
- for (j = 0; j < width; j++)
- {
- putc (*(src + 7), ofp->fp);
- putc (*(src + 6), ofp->fp);
- putc (*(src + 5), ofp->fp);
- putc (*(src + 4), ofp->fp);
- putc (*(src + 3), ofp->fp);
- putc (*(src + 2), ofp->fp);
- putc (*(src + 1), ofp->fp);
- putc (*(src + 0), ofp->fp);
- src += bpp;
- }
- break;
- default:
- return FALSE;
- }
- }
-
- nbytes += width * bpc;
- src -= 2 * bpsl;
-
- if ((i % 20) == 0)
- gimp_progress_update ((gdouble) (i + channel * height) /
- (gdouble) (height * channelnum));
+ if (fits_create_file (&fptr, g_file_peek_path (file), &status))
+ {
+ show_fits_errors (status);
+ return FALSE;
}
}
- nbytes = nbytes % FITS_RECORD_SIZE;
- if (nbytes)
+ if (fits_create_img (fptr, bitpix, naxis, naxes, &status))
{
- while (nbytes++ < FITS_RECORD_SIZE)
- putc (0, ofp->fp);
+ show_fits_errors (status);
+ return FALSE;
+ }
+
+ /* FITS uses signed 16/32 integers, so we need to convert the unsigned
+ * values to that range via an offset */
+ if (bitpix == 16 || bitpix == 32)
+ {
+ GeglBufferIterator *iter;
+
+ iter = gegl_buffer_iterator_new (buffer,
+ GEGL_RECTANGLE (0, 0, width, height), 0,
+ format,
+ GEGL_BUFFER_READWRITE,
+ GEGL_ABYSS_NONE, 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ gint length = iter->length;
+
+ if (bitpix == 16)
+ {
+ gushort *pixel = iter->items[0].data;
+ gushort offset = pow (2, 15);
+
+ while (length--)
+ {
+ for (gint i = 0; i < channelnum; i++)
+ pixel[i] -= offset;
+
+ pixel += channelnum;
+ }
+ }
+ else
+ {
+ guint32 *pixel = iter->items[0].data;
+ guint32 offset = pow (2, 31);
+
+ while (length--)
+ {
+ for (gint i = 0; i < channelnum; i++)
+ pixel[i] -= offset;
+
+ pixel += channelnum;
+ }
+ }
+ }
+ }
+
+ /* Grayscale images can be exported as-is. RGB images must be
+ * converted into planes of RRR...GGG...BBB... */
+ if (naxis == 2)
+ {
+ gegl_buffer_get (buffer,
+ GEGL_RECTANGLE (0, 0, width, height), 1.0,
+ format, data,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ if (fits_write_img (fptr, export_type, 1, nelements, data, &status))
+ {
+ show_fits_errors (status);
+ return FALSE;
+ }
+ }
+ else
+ {
+ gdouble *rgb_data;
+ gdouble *rgb_output;
+ const Babl *rgb_format;
+ const Babl *output_format = babl_format ("Y' double");
+ const Babl *converted_format;
+
+ rgb_format = (channelnum == 3) ? babl_format ("R'G'B' double") :
+ babl_format ("R'G'B'A double");
+
+ /* We export a single channel at a time, so we need a
+ * an output format with a single channel */
+ converted_format = babl_format_new (babl_model ("Y'"), type,
+ babl_component ("Y'"),
+ NULL);
+
+ rgb_data = (gdouble *) g_malloc (width * height * sizeof (gdouble) *
+ channelnum);
+ rgb_output = (gdouble *) g_malloc (width * height * sizeof (gdouble));
+ gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0,
+ rgb_format, rgb_data,
+ GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ for (gint rgb = 0; rgb < channelnum; rgb++)
+ {
+ gint offset = 0;
+ gint src_offset = 0;
+ void *converted_output = NULL;
+
+ for (gint i = 0; i < height - 1; i++)
+ {
+ for (gint j = 0; j < (width * channelnum); j += channelnum)
+ {
+ rgb_output[(j / channelnum) + offset] =
+ rgb_data[j + src_offset + rgb];
+ }
+
+ src_offset += width * channelnum;
+ offset += width;
+ }
+
+ if (export_type == TFLOAT)
+ converted_output = (gfloat *) g_malloc (width * height *
+ sizeof (gfloat));
+ else if (export_type == TDOUBLE)
+ converted_output = (gdouble *) g_malloc (width * height *
+ sizeof (gdouble));
+ else
+ converted_output = (guchar *) g_malloc (width * height *
+ sizeof (guchar *) *
+ (bitpix / 8));
+
+ babl_process (babl_fish (output_format, converted_format),
+ rgb_output, converted_output, nelements);
+
+ if (fits_write_img (fptr, export_type, 1, nelements,
+ converted_output, &status))
+ {
+ show_fits_errors (status);
+ return FALSE;
+ }
+
+ g_free (converted_output);
+ }
+
+ g_free (rgb_data);
+ g_free (rgb_output);
}
g_free (data);
g_object_unref (buffer);
+ /* Add history of file update */
+ fits_write_history (fptr,
+ "THIS FITS FILE WAS GENERATED BY GIMP USING CFITSIO",
+ &status);
+
gimp_progress_update (1.0);
- if (ferror (ofp->fp))
+ if (fits_close_file (fptr, &status))
{
- g_message (_("Write error occurred"));
+ show_fits_errors (status);
return FALSE;
}
@@ -1160,7 +979,6 @@ load_dialog (GimpProcedure *procedure,
GObject *config)
{
GtkWidget *dialog;
- GtkWidget *vbox;
GtkListStore *store;
GtkWidget *frame;
gboolean run;
@@ -1171,31 +989,26 @@ load_dialog (GimpProcedure *procedure,
GIMP_PROCEDURE_CONFIG (config),
_("Open FITS File"));
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
- gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
- vbox, TRUE, TRUE, 0);
- gtk_widget_show (vbox);
+ gimp_window_set_transient (GTK_WINDOW (dialog));
- store = gimp_int_store_new (_("_Black"), 0,
- _("_White"), 255,
+ store = gimp_int_store_new (_("Black"), 0,
+ _("White"), 255,
NULL);
- frame = gimp_prop_int_radio_frame_new (config, "replace",
- _("Replacement for undefined pixels"),
- GIMP_INT_STORE (store));
- gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ frame = gimp_procedure_dialog_get_int_radio (GIMP_PROCEDURE_DIALOG (dialog),
+ "replace",
+ GIMP_INT_STORE (store));
+ gtk_widget_set_margin_bottom (frame, 12);
- frame = gimp_prop_boolean_radio_frame_new (config, "use-data-min-max",
- _("Pixel value scaling"),
- _("By _DATAMIN/DATAMAX"),
- _("_Automatic"));
- gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ store = gimp_int_store_new (_("Automatic"), 0,
+ _("By DATAMIN/DATAMAX"), 1,
+ NULL);
+ frame = gimp_procedure_dialog_get_int_radio (GIMP_PROCEDURE_DIALOG (dialog),
+ "use-data-min-max",
+ GIMP_INT_STORE (store));
+ gtk_widget_set_margin_bottom (frame, 12);
- frame = gimp_prop_boolean_radio_frame_new (config, "compose",
- _("Image Composing"),
- "NA_XIS=3, NAXIS3=2,...,4",
- C_("composing", "_None"));
- gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
+ NULL);
gtk_widget_show (dialog);
@@ -1207,11 +1020,11 @@ load_dialog (GimpProcedure *procedure,
}
static void
-show_fits_errors (void)
+show_fits_errors (gint status)
{
- const gchar *msg;
+ gchar status_str[FLEN_STATUS];
/* Write out error messages of FITS-Library */
- while ((msg = fits_get_error ()) != NULL)
- g_message ("%s", msg);
-}
+ fits_get_errstatus (status, status_str);
+ g_message ("FITS: %s\n", status_str);
+}
\ No newline at end of file
diff --git a/plug-ins/file-fits/meson.build b/plug-ins/file-fits/meson.build
index 239e674edc..aa31fa0469 100644
--- a/plug-ins/file-fits/meson.build
+++ b/plug-ins/file-fits/meson.build
@@ -1,7 +1,6 @@
plugin_name = 'file-fits'
plugin_sources = [
- 'fits-io.c',
'fits.c',
]
@@ -21,7 +20,10 @@ endif
executable(plugin_name,
plugin_sources,
- dependencies: libgimpui_dep,
+ dependencies: [
+ libgimpui_dep,
+ cfitsio_dep,
+ ],
install: true,
install_dir: gimpplugindir / 'plug-ins' / plugin_name,
)