summaryrefslogtreecommitdiffstats
path: root/plug-ins/file-fits
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 16:23:22 +0000
commite42129241681dde7adae7d20697e7b421682fbb4 (patch)
treeaf1fe815a5e639e68e59fabd8395ec69458b3e5e /plug-ins/file-fits
parentInitial commit. (diff)
downloadgimp-e42129241681dde7adae7d20697e7b421682fbb4.tar.xz
gimp-e42129241681dde7adae7d20697e7b421682fbb4.zip
Adding upstream version 2.10.22.upstream/2.10.22upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'plug-ins/file-fits')
-rw-r--r--plug-ins/file-fits/Makefile.am50
-rw-r--r--plug-ins/file-fits/Makefile.in1004
-rw-r--r--plug-ins/file-fits/fits-io.c2506
-rw-r--r--plug-ins/file-fits/fits-io.h199
-rw-r--r--plug-ins/file-fits/fits.c1222
5 files changed, 4981 insertions, 0 deletions
diff --git a/plug-ins/file-fits/Makefile.am b/plug-ins/file-fits/Makefile.am
new file mode 100644
index 0000000..0ea58fe
--- /dev/null
+++ b/plug-ins/file-fits/Makefile.am
@@ -0,0 +1,50 @@
+## Process this file with automake to produce Makefile.in
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+
+if OS_WIN32
+mwindows = -mwindows
+endif
+
+if HAVE_WINDRES
+include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
+file_fits_RC = file-fits.rc.o
+endif
+
+AM_LDFLAGS = $(mwindows)
+AM_CFLAGS = -fno-strict-aliasing
+
+libexecdir = $(gimpplugindir)/plug-ins/file-fits
+
+libexec_PROGRAMS = file-fits
+
+file_fits_SOURCES = \
+ fits.c \
+ fits-io.c \
+ fits-io.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(file_fits_RC)
diff --git a/plug-ins/file-fits/Makefile.in b/plug-ins/file-fits/Makefile.in
new file mode 100644
index 0000000..afc57b4
--- /dev/null
+++ b/plug-ins/file-fits/Makefile.in
@@ -0,0 +1,1004 @@
+# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Version resources for Microsoft Windows
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+libexec_PROGRAMS = file-fits$(EXEEXT)
+subdir = plug-ins/file-fits
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4macros/gtk-doc.m4 \
+ $(top_srcdir)/m4macros/intltool.m4 \
+ $(top_srcdir)/m4macros/libtool.m4 \
+ $(top_srcdir)/m4macros/ltoptions.m4 \
+ $(top_srcdir)/m4macros/ltsugar.m4 \
+ $(top_srcdir)/m4macros/ltversion.m4 \
+ $(top_srcdir)/m4macros/lt~obsolete.m4 \
+ $(top_srcdir)/acinclude.m4 $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(libexecdir)"
+PROGRAMS = $(libexec_PROGRAMS)
+am_file_fits_OBJECTS = fits.$(OBJEXT) fits-io.$(OBJEXT)
+file_fits_OBJECTS = $(am_file_fits_OBJECTS)
+file_fits_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+file_fits_DEPENDENCIES = $(libgimpui) $(libgimpwidgets) \
+ $(libgimpconfig) $(libgimp) $(libgimpcolor) $(libgimpmath) \
+ $(libgimpbase) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(file_fits_RC)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/fits-io.Po ./$(DEPDIR)/fits.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(file_fits_SOURCES)
+DIST_SOURCES = $(file_fits_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build/windows/gimprc-plug-ins.rule \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = $(gimpplugindir)/plug-ins/file-fits
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+@OS_WIN32_TRUE@mwindows = -mwindows
+@HAVE_WINDRES_TRUE@GIMPPLUGINRC = $(top_builddir)/build/windows/gimp-plug-ins.rc
+@HAVE_WINDRES_TRUE@file_fits_RC = file-fits.rc.o
+AM_LDFLAGS = $(mwindows)
+AM_CFLAGS = -fno-strict-aliasing
+file_fits_SOURCES = \
+ fits.c \
+ fits-io.c \
+ fits-io.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir) \
+ $(GTK_CFLAGS) \
+ $(GEGL_CFLAGS) \
+ -I$(includedir)
+
+LDADD = \
+ $(libgimpui) \
+ $(libgimpwidgets) \
+ $(libgimpconfig) \
+ $(libgimp) \
+ $(libgimpcolor) \
+ $(libgimpmath) \
+ $(libgimpbase) \
+ $(GTK_LIBS) \
+ $(GEGL_LIBS) \
+ $(RT_LIBS) \
+ $(INTLLIBS) \
+ $(file_fits_RC)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/build/windows/gimprc-plug-ins.rule $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plug-ins/file-fits/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plug-ins/file-fits/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/build/windows/gimprc-plug-ins.rule $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-libexecPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
+
+clean-libexecPROGRAMS:
+ @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+file-fits$(EXEEXT): $(file_fits_OBJECTS) $(file_fits_DEPENDENCIES) $(EXTRA_file_fits_DEPENDENCIES)
+ @rm -f file-fits$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(file_fits_OBJECTS) $(file_fits_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fits-io.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fits.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(libexecdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libexecPROGRAMS clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/fits-io.Po
+ -rm -f ./$(DEPDIR)/fits.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libexecPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/fits-io.Po
+ -rm -f ./$(DEPDIR)/fits.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libexecPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libexecPROGRAMS clean-libtool \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-libexecPROGRAMS \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-libexecPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# `windres` seems a very stupid tool and it breaks with double shlashes
+# in parameter paths. Strengthen the rule a little.
+@HAVE_WINDRES_TRUE@%.rc.o:
+@HAVE_WINDRES_TRUE@ $(WINDRES) --define ORIGINALFILENAME_STR="$*$(EXEEXT)" \
+@HAVE_WINDRES_TRUE@ --define INTERNALNAME_STR="$*" \
+@HAVE_WINDRES_TRUE@ --define TOP_SRCDIR="`echo $(top_srcdir) | sed 's*//*/*'`" \
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_srcdir)/app | sed 's%/\+%/%'`" \
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_builddir)/app | sed 's%/\+%/%'`"\
+@HAVE_WINDRES_TRUE@ -I"`echo $(top_builddir) | sed 's%/\+%/%'`"\
+@HAVE_WINDRES_TRUE@ $(GIMPPLUGINRC) $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plug-ins/file-fits/fits-io.c b/plug-ins/file-fits/fits-io.c
new file mode 100644
index 0000000..9d429b7
--- /dev/null
+++ b/plug-ins/file-fits/fits-io.c
@@ -0,0 +1,2506 @@
+/******************************************************************************/
+/* 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 VERSIO 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 <https://www.gnu.org/licenses/>. */
+/******************************************************************************/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#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)
+ {
+ strncpy (fits_error[fits_n_error], errmsg, FITS_ERROR_LENGTH);
+ fits_error[fits_n_error++][FITS_ERROR_LENGTH-1] = '\0';
+ }
+}
+
+
+/*****************************************************************************/
+/* #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: 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
new file mode 100644
index 0000000..8732db1
--- /dev/null
+++ b/plug-ins/file-fits/fits-io.h
@@ -0,0 +1,199 @@
+/******************************************************************************/
+/* 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
new file mode 100644
index 0000000..b843a68
--- /dev/null
+++ b/plug-ins/file-fits/fits.c
@@ -0,0 +1,1222 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ * FITS file plugin
+ * reading and writing code Copyright (C) 1997 Peter Kirchgessner
+ * e-mail: peter@kirchgessner.net, WWW: http://www.kirchgessner.net
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Event history:
+ * V 1.00, PK, 05-May-97: Creation
+ * V 1.01, PK, 19-May-97: Problem with compilation on Irix fixed
+ * V 1.02, PK, 08-Jun-97: Bug with saving gray images fixed
+ * V 1.03, PK, 05-Oct-97: Parse rc-file
+ * V 1.04, PK, 12-Oct-97: No progress bars for non-interactive mode
+ * V 1.05, nn, 20-Dec-97: Initialize image_ID in run()
+ * V 1.06, PK, 21-Nov-99: Internationalization
+ * Fix bug with gimp_export_image()
+ * (moved it from load to save)
+ * V 1.07, PK, 16-Aug-06: Fix problems with internationalization
+ * (writing 255,0 instead of 255.0)
+ * Fix problem with not filling up properly last record
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <errno.h>
+
+#include <glib/gstdio.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "fits-io.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define LOAD_PROC "file-fits-load"
+#define SAVE_PROC "file-fits-save"
+#define PLUG_IN_BINARY "file-fits"
+#define PLUG_IN_ROLE "gimp-file-fits"
+
+
+/* Load info */
+typedef struct
+{
+ gint replace; /* replacement for blank/NaN-values */
+ gint use_datamin; /* Use DATAMIN/MAX-scaling if possible */
+ gint compose; /* compose images with naxis==3 */
+} FITSLoadVals;
+
+
+/* Declare some local functions.
+ */
+static void query (void);
+static void run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals);
+
+static gint32 load_image (const gchar *filename,
+ GError **error);
+static gint save_image (const gchar *filename,
+ gint32 image_ID,
+ gint32 drawable_ID,
+ GError **error);
+
+static FitsHduList * create_fits_header (FitsFile *ofp,
+ guint width,
+ guint height,
+ guint channels,
+ guint bitpix);
+
+static gint save_fits (FitsFile *ofp,
+ gint32 image_ID,
+ gint32 drawable_ID);
+
+static gint32 create_new_image (const gchar *filename,
+ guint pagenum,
+ guint width,
+ guint height,
+ GimpImageBaseType itype,
+ GimpImageType dtype,
+ GimpPrecision iprecision,
+ gint32 *layer_ID,
+ GeglBuffer **buffer);
+
+static void check_load_vals (void);
+
+static gint32 load_fits (const gchar *filename,
+ FitsFile *ifp,
+ guint picnum,
+ guint ncompose);
+
+static gboolean load_dialog (void);
+static void show_fits_errors (void);
+
+
+static FITSLoadVals plvals =
+{
+ 0, /* Replace with black */
+ 0, /* Do autoscale on pixel-values */
+ 0 /* Don't compose images */
+};
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+ NULL, /* init_proc */
+ NULL, /* quit_proc */
+ query, /* query_proc */
+ run, /* run_proc */
+};
+
+/* The run mode */
+static GimpRunMode l_run_mode;
+
+
+MAIN ()
+
+static void
+query (void)
+
+{
+ static const GimpParamDef load_args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+ { GIMP_PDB_STRING, "filename", "The name of the file to load" },
+ { GIMP_PDB_STRING, "raw-filename", "The name of the file to load" },
+ };
+ static const GimpParamDef load_return_vals[] =
+ {
+ { GIMP_PDB_IMAGE, "image", "Output image" },
+ };
+
+ static const GimpParamDef save_args[] =
+ {
+ { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+ { GIMP_PDB_IMAGE, "image", "Input image" },
+ { GIMP_PDB_DRAWABLE, "drawable", "Drawable to export" },
+ { GIMP_PDB_STRING, "filename", "The name of the file to export the image in" },
+ { GIMP_PDB_STRING, "raw-filename", "The name of the file to export the image in" },
+ };
+
+ gimp_install_procedure (LOAD_PROC,
+ "load file of the FITS file format",
+ "load file of the FITS file format "
+ "(Flexible Image Transport System)",
+ "Peter Kirchgessner",
+ "Peter Kirchgessner (peter@kirchgessner.net)",
+ "1997",
+ N_("Flexible Image Transport System"),
+ NULL,
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (load_args),
+ G_N_ELEMENTS (load_return_vals),
+ load_args, load_return_vals);
+
+ gimp_register_file_handler_mime (LOAD_PROC, "image/x-fits");
+ gimp_register_magic_load_handler (LOAD_PROC,
+ "fit,fits",
+ "",
+ "0,string,SIMPLE");
+
+ gimp_install_procedure (SAVE_PROC,
+ "export file in the FITS file format",
+ "FITS exporting handles all image types except "
+ "those with alpha channels.",
+ "Peter Kirchgessner",
+ "Peter Kirchgessner (peter@kirchgessner.net)",
+ "1997",
+ N_("Flexible Image Transport System"),
+ "RGB, GRAY, INDEXED",
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (save_args), 0,
+ save_args, NULL);
+
+ gimp_register_file_handler_mime (SAVE_PROC, "image/x-fits");
+ gimp_register_save_handler (SAVE_PROC, "fit,fits", "");
+}
+
+
+static void
+run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ static GimpParam values[2];
+ GimpRunMode run_mode;
+ GimpPDBStatusType status = GIMP_PDB_SUCCESS;
+ gint32 image_ID;
+ gint32 drawable_ID;
+ GimpExportReturn export = GIMP_EXPORT_CANCEL;
+ GError *error = NULL;
+
+ INIT_I18N ();
+ gegl_init (NULL, NULL);
+
+ l_run_mode = run_mode = (GimpRunMode)param[0].data.d_int32;
+
+ *nreturn_vals = 1;
+ *return_vals = values;
+
+ values[0].type = GIMP_PDB_STATUS;
+ values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+
+ if (strcmp (name, LOAD_PROC) == 0)
+ {
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ /* Possibly retrieve data */
+ gimp_get_data (LOAD_PROC, &plvals);
+
+ if (!load_dialog ())
+ status = GIMP_PDB_CANCEL;
+ break;
+
+ case GIMP_RUN_NONINTERACTIVE:
+ if (nparams != 3)
+ status = GIMP_PDB_CALLING_ERROR;
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ /* Possibly retrieve data */
+ gimp_get_data (LOAD_PROC, &plvals);
+ break;
+
+ default:
+ break;
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ check_load_vals ();
+ image_ID = load_image (param[1].data.d_string, &error);
+
+ /* Write out error messages of FITS-Library */
+ show_fits_errors ();
+
+ if (image_ID != -1)
+ {
+ *nreturn_vals = 2;
+ values[1].type = GIMP_PDB_IMAGE;
+ values[1].data.d_image = image_ID;
+ }
+ else
+ {
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+
+ /* Store plvals data */
+ if (status == GIMP_PDB_SUCCESS)
+ gimp_set_data (LOAD_PROC, &plvals, sizeof (FITSLoadVals));
+ }
+ }
+ else if (strcmp (name, SAVE_PROC) == 0)
+ {
+ image_ID = param[1].data.d_int32;
+ drawable_ID = param[2].data.d_int32;
+
+ /* eventually export the image */
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ case GIMP_RUN_WITH_LAST_VALS:
+ gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+ export = gimp_export_image (&image_ID, &drawable_ID, "FITS",
+ GIMP_EXPORT_CAN_HANDLE_RGB |
+ GIMP_EXPORT_CAN_HANDLE_GRAY |
+ GIMP_EXPORT_CAN_HANDLE_INDEXED);
+
+ if (export == GIMP_EXPORT_CANCEL)
+ {
+ values[0].data.d_status = GIMP_PDB_CANCEL;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (run_mode)
+ {
+ case GIMP_RUN_INTERACTIVE:
+ break;
+
+ case GIMP_RUN_NONINTERACTIVE:
+ /* Make sure all the arguments are there! */
+ if (nparams != 5)
+ status = GIMP_PDB_CALLING_ERROR;
+ break;
+
+ case GIMP_RUN_WITH_LAST_VALS:
+ break;
+
+ default:
+ break;
+ }
+
+ if (status == GIMP_PDB_SUCCESS)
+ {
+ if (! save_image (param[3].data.d_string, image_ID, drawable_ID,
+ &error))
+ status = GIMP_PDB_EXECUTION_ERROR;
+ }
+
+ if (export == GIMP_EXPORT_EXPORT)
+ gimp_image_delete (image_ID);
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ if (status != GIMP_PDB_SUCCESS && error)
+ {
+ *nreturn_vals = 2;
+ values[1].type = GIMP_PDB_STRING;
+ values[1].data.d_string = error->message;
+ }
+
+ values[0].data.d_status = status;
+}
+
+
+static gint32
+load_image (const gchar *filename,
+ GError **error)
+{
+ gint32 image_ID, *image_list, *nl;
+ guint picnum;
+ gint k, n_images, max_images, hdu_picnum;
+ gint compose;
+ FILE *fp;
+ FitsFile *ifp;
+ FitsHduList *hdu;
+
+ fp = g_fopen (filename, "rb");
+ if (!fp)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not open '%s' for reading: %s"),
+ gimp_filename_to_utf8 (filename), g_strerror (errno));
+ return -1;
+ }
+ fclose (fp);
+
+ ifp = fits_open (filename, "r");
+ if (ifp == NULL)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "%s", _("Error during open of FITS file"));
+ return -1;
+ }
+ if (ifp->n_pic <= 0)
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "%s", _("FITS file keeps no displayable images"));
+ fits_close (ifp);
+ return -1;
+ }
+
+ image_list = g_new (gint32, 10);
+ n_images = 0;
+ max_images = 10;
+
+ for (picnum = 1; picnum <= ifp->n_pic; )
+ {
+ /* Get image info to see if we can compose them */
+ hdu = fits_image_info (ifp, picnum, &hdu_picnum);
+ if (hdu == NULL) break;
+
+ /* Get number of FITS-images to compose */
+ compose = ( plvals.compose && (hdu_picnum == 1) && (hdu->naxis == 3)
+ && (hdu->naxisn[2] > 1) && (hdu->naxisn[2] <= 4));
+ if (compose)
+ compose = hdu->naxisn[2];
+ else
+ compose = 1; /* Load as GRAY */
+
+ image_ID = load_fits (filename, ifp, picnum, compose);
+
+ /* Write out error messages of FITS-Library */
+ show_fits_errors ();
+
+ if (image_ID == -1) break;
+ if (n_images == max_images)
+ {
+ nl = (gint32 *)g_realloc (image_list, (max_images+10)*sizeof (gint32));
+ if (nl == NULL) break;
+ image_list = nl;
+ max_images += 10;
+ }
+ image_list[n_images++] = image_ID;
+
+ 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 (l_run_mode != GIMP_RUN_NONINTERACTIVE)
+ {
+ for (k = n_images-1; k >= 1; k--)
+ {
+ gimp_image_undo_enable (image_list[k]);
+ gimp_image_clean_all (image_list[k]);
+ gimp_display_new (image_list[k]);
+ }
+ }
+
+ image_ID = (n_images > 0) ? image_list[0] : -1;
+ g_free (image_list);
+
+ return (image_ID);
+}
+
+
+static gint
+save_image (const gchar *filename,
+ gint32 image_ID,
+ gint32 drawable_ID,
+ GError **error)
+{
+ FitsFile *ofp;
+ GimpImageType drawable_type;
+ gint retval;
+
+ drawable_type = gimp_drawable_type (drawable_ID);
+
+ /* Make sure we're not exporting an image with an alpha channel */
+ if (gimp_drawable_has_alpha (drawable_ID))
+ {
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "%s",
+ _("FITS export cannot handle images with alpha channels"));
+ return FALSE;
+ }
+
+ switch (drawable_type)
+ {
+ case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE:
+ case GIMP_GRAY_IMAGE: case GIMP_GRAYA_IMAGE:
+ case GIMP_RGB_IMAGE: case GIMP_RGBA_IMAGE:
+ break;
+ default:
+ g_message (_("Cannot operate on unknown image types."));
+ return (FALSE);
+ break;
+ }
+
+ gimp_progress_init_printf (_("Exporting '%s'"),
+ gimp_filename_to_utf8 (filename));
+
+ /* Open the output file. */
+ ofp = fits_open (filename, "w");
+ if (!ofp)
+ {
+ g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+ _("Could not open '%s' for writing: %s"),
+ gimp_filename_to_utf8 (filename), g_strerror (errno));
+ return (FALSE);
+ }
+
+ retval = save_fits (ofp,image_ID, drawable_ID);
+
+ fits_close (ofp);
+
+ return (retval);
+}
+
+
+/* Check (and correct) the load values plvals */
+static void
+check_load_vals (void)
+{
+ if (plvals.replace > 255) plvals.replace = 255;
+}
+
+
+/* Create an image. Sets layer_ID, drawable and rgn. Returns image_ID */
+static gint32
+create_new_image (const gchar *filename,
+ guint pagenum,
+ guint width,
+ guint height,
+ GimpImageBaseType itype,
+ GimpImageType dtype,
+ GimpPrecision iprecision,
+ gint32 *layer_ID,
+ GeglBuffer **buffer)
+{
+ gint32 image_ID;
+ char *tmp;
+
+ image_ID = gimp_image_new_with_precision (width, height, itype, iprecision);
+
+ if ((tmp = g_malloc (strlen (filename) + 64)) != NULL)
+ {
+ sprintf (tmp, "%s-img%ld", filename, (long)pagenum);
+ gimp_image_set_filename (image_ID, tmp);
+ g_free (tmp);
+ }
+ else
+ gimp_image_set_filename (image_ID, filename);
+
+ gimp_image_undo_disable (image_ID);
+ *layer_ID = gimp_layer_new (image_ID, _("Background"), width, height,
+ dtype, 100,
+ gimp_image_get_default_new_layer_mode (image_ID));
+ gimp_image_insert_layer (image_ID, *layer_ID, -1, 0);
+
+ *buffer = gimp_drawable_get_buffer (*layer_ID);
+
+ return image_ID;
+}
+
+
+/* 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 gint32
+load_fits (const gchar *filename,
+ FitsFile *ifp,
+ 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;
+ gint32 layer_ID, image_ID;
+ GeglBuffer *buffer;
+ GimpImageBaseType itype;
+ GimpImageType dtype;
+ GimpPrecision iprecision;
+ gint err = 0;
+ FitsHduList *hdulist;
+ FitsPixTransform trans;
+ double datamax, replacetransform;
+ const Babl *type, *format;
+
+ hdulist = fits_seek_image (ifp, (int)picnum);
+ if (hdulist == NULL)
+ return -1;
+
+ width = hdulist->naxisn[0]; /* Set the size of the FITS image */
+ height = hdulist->naxisn[1];
+
+ switch (hdulist->bitpix)
+ {
+ case 8:
+ iprecision = GIMP_PRECISION_U8_GAMMA;
+ type = babl_type ("u8");
+ datamax = 255.0;
+ replacetransform = 1.0;
+ break;
+ case 16:
+ iprecision = GIMP_PRECISION_U16_GAMMA; /* 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 -1;
+ }
+
+ 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_ID = create_new_image (filename, picnum, width, height,
+ itype, dtype, iprecision,
+ &layer_ID, &buffer);
+
+ tile_height = gimp_tile_height ();
+
+ data = g_malloc (tile_height * width * ncompose * hdulist->bpp);
+ if (data == NULL)
+ return -1;
+
+ data_end = data + tile_height * width * ncompose * hdulist->bpp;
+
+ /* If the transformation from pixel value to data value has been
+ * specified, use it
+ */
+ if (plvals.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 = plvals.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 -1;
+
+ 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 ? -1 : image_ID;
+}
+
+
+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,
+ gint32 image_ID,
+ gint32 drawable_ID)
+{
+ gint height, width, i, j, channel, channelnum;
+ gint tile_height, bpp, bpsl, bitpix, bpc;
+ long nbytes;
+ guchar *data, *src;
+ GeglBuffer *buffer;
+ const Babl *format, *type;
+ FitsHduList *hdu;
+
+ buffer = gimp_drawable_get_buffer (drawable_ID);
+
+ width = gegl_buffer_get_width (buffer);
+ height = gegl_buffer_get_height (buffer);
+
+ format = gegl_buffer_get_format (buffer);
+ type = babl_format_get_type (format, 0);
+
+ if (type == babl_type ("u8"))
+ {
+ bitpix = 8;
+ }
+ else if (type == babl_type ("u16"))
+ {
+ bitpix = 16;
+ }
+ else if (type == babl_type ("u32"))
+ {
+ bitpix = 32;
+ }
+ else if (type == babl_type ("half"))
+ {
+ bitpix = -32;
+ type = babl_type ("float");
+ }
+ else if (type == babl_type ("float"))
+ {
+ bitpix = -32;
+ }
+ else if (type == babl_type ("double"))
+ {
+ bitpix = -64;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ switch (gimp_drawable_type (drawable_ID))
+ {
+ case GIMP_GRAY_IMAGE:
+ format = babl_format_new (babl_model ("Y'"),
+ type,
+ babl_component ("Y'"),
+ NULL);
+ break;
+
+ case GIMP_GRAYA_IMAGE:
+ format = babl_format_new (babl_model ("Y'A"),
+ type,
+ babl_component ("Y'"),
+ babl_component ("A"),
+ NULL);
+ break;
+
+ case GIMP_RGB_IMAGE:
+ case GIMP_INDEXED_IMAGE:
+ format = babl_format_new (babl_model ("R'G'B'"),
+ type,
+ babl_component ("R'"),
+ babl_component ("G'"),
+ babl_component ("B'"),
+ NULL);
+ break;
+
+ case GIMP_RGBA_IMAGE:
+ case GIMP_INDEXEDA_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);
+ 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);
+
+ 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++)
+ {
+ for (i = 0; i < height; i++)
+ {
+ if ((i % tile_height) == 0)
+ {
+ gint scan_lines;
+
+ 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));
+ }
+ }
+
+ nbytes = nbytes % FITS_RECORD_SIZE;
+ if (nbytes)
+ {
+ while (nbytes++ < FITS_RECORD_SIZE)
+ putc (0, ofp->fp);
+ }
+
+ g_free (data);
+
+ g_object_unref (buffer);
+
+ gimp_progress_update (1.0);
+
+ if (ferror (ofp->fp))
+ {
+ g_message (_("Write error occurred"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Load interface functions */
+
+static gboolean
+load_dialog (void)
+{
+ GtkWidget *dialog;
+ GtkWidget *vbox;
+ GtkWidget *frame;
+ gboolean run;
+
+ gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+ dialog = gimp_dialog_new (_("Load FITS File"), PLUG_IN_ROLE,
+ NULL, 0,
+ gimp_standard_help_func, LOAD_PROC,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_Open"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ gimp_window_set_transient (GTK_WINDOW (dialog));
+
+ 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);
+
+ frame = gimp_int_radio_group_new (TRUE, _("Replacement for undefined pixels"),
+ G_CALLBACK (gimp_radio_button_update),
+ &plvals.replace, plvals.replace,
+
+ _("_Black"), 0, NULL,
+ _("_White"), 255, NULL,
+
+ NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ frame =
+ gimp_int_radio_group_new (TRUE, _("Pixel value scaling"),
+ G_CALLBACK (gimp_radio_button_update),
+ &plvals.use_datamin, plvals.use_datamin,
+
+ _("_Automatic"), FALSE, NULL,
+ _("By _DATAMIN/DATAMAX"), TRUE, NULL,
+
+ NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ frame =
+ gimp_int_radio_group_new (TRUE, _("Image Composing"),
+ G_CALLBACK (gimp_radio_button_update),
+ &plvals.compose, plvals.compose,
+
+ C_("composing", "_None"), FALSE, NULL,
+ "NA_XIS=3, NAXIS3=2,...,4", TRUE, NULL,
+
+ NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ gtk_widget_show (dialog);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ gtk_widget_destroy (dialog);
+
+ return run;
+}
+
+static void
+show_fits_errors (void)
+{
+ const gchar *msg;
+
+ /* Write out error messages of FITS-Library */
+ while ((msg = fits_get_error ()) != NULL)
+ g_message ("%s", msg);
+}