gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master d6aa57f 081/125: Text library can write images


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master d6aa57f 081/125: Text library can write images also, besides tables
Date: Sun, 23 Apr 2017 22:36:42 -0400 (EDT)

branch: master
commit d6aa57f961822faa18f85b1040b264883245bc37
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Text library can write images also, besides tables
    
    Until now, the text library was defined to only read/write plain text
    tables (a collection of 1D data). But now, there are also functions to read
    and write 2D (image) data to a plain text file. This was mainly done with
    the motivation to complete ConvertType (so it can read from and write to
    plain text files). But as a library function it is usable in many other
    contexts also.
    
    To be able to write 2D arrays as well as 1D columns in a text files, the
    text table reading/writing functions were modularized (broken up) into
    multiple functions and modified so the same infra-structure can be used.
    
    In the process, some other corrections were also made that are described
    below:
    
     - The FITS functions were renamed to follow a much more clear naming
       convention, for example the old `gal_fits_write_img' function is now
       `gal_fits_img_write'. Similarly, all functions related to FITS images
       start with `gal_fits_img', those starting with header keywords start
       with `gal_fits_key' and so on.
    
     - As part of the previous case, the functions related to the FITS WCS have
       been moved to the `gnuastro/wcs.h' header.
    
     - When no floating point printing format is specified by the user, the
       default format is changed to `%g' (for printf) and `E' (for FITS) to
       allow a more general demonstration of the data at a wider range.
    
     - The default width of printing single precision floating point values was
       updated to 13 (from 12) to allow for the default change above in
       printing the test table of `make check'.
---
 bin/arithmetic/arithmetic.c |    2 +-
 bin/arithmetic/operands.c   |    7 +-
 bin/convertt/convertt.c     |   14 +-
 bin/convertt/ui.c           |   30 +-
 bin/convolve/convolve.c     |   19 +-
 bin/convolve/ui.c           |   15 +-
 bin/header/ui.c             |    2 +-
 bin/imgcrop/crop.c          |    6 +-
 bin/imgcrop/imgcrop.c       |    8 +-
 bin/imgcrop/ui.c            |    6 +-
 bin/mkprof/mkprof.c         |   10 +-
 bin/mkprof/ui.c             |    9 +-
 lib/fits.c                  |  276 +++--------
 lib/gnuastro/fits.h         |   71 ++-
 lib/gnuastro/table.h        |    4 +-
 lib/gnuastro/txt.h          |   19 +-
 lib/gnuastro/wcs.h          |   45 +-
 lib/mesh.c                  |    8 +-
 lib/table.c                 |   16 +-
 lib/txt.c                   | 1090 ++++++++++++++++++++++++++-----------------
 lib/wcs.c                   |  354 +++++++++-----
 21 files changed, 1148 insertions(+), 863 deletions(-)

diff --git a/bin/arithmetic/arithmetic.c b/bin/arithmetic/arithmetic.c
index 9341239..44370c0 100644
--- a/bin/arithmetic/arithmetic.c
+++ b/bin/arithmetic/arithmetic.c
@@ -364,7 +364,7 @@ reversepolish(struct imgarithparams *p)
       /* Put a copy of the WCS structure from the reference image, it
          will be freed while freeing d1. */
       d1->wcs=p->refdata.wcs;
-      gal_fits_write_img(d1, p->cp.output, NULL, PROGRAM_STRING);
+      gal_fits_img_write(d1, p->cp.output, NULL, PROGRAM_STRING);
       if(!p->cp.quiet)
         printf(" - Output written to %s\n", p->cp.output);
     }
diff --git a/bin/arithmetic/operands.c b/bin/arithmetic/operands.c
index 7690e54..7402ceb 100644
--- a/bin/arithmetic/operands.c
+++ b/bin/arithmetic/operands.c
@@ -29,6 +29,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <string.h>
 #include <stdlib.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/array.h>
 
@@ -120,11 +121,11 @@ pop_operand(struct imgarithparams *p, char *operator)
       /* In case this is the first image that is read, then read the WCS
          information.*/
       if(p->popcounter==0)
-        gal_fits_read_wcs(filename, hdu, 0, 0, &p->refdata.nwcs,
-                          &p->refdata.wcs);
+        gal_wcs_read(filename, hdu, 0, 0, &p->refdata.nwcs,
+                     &p->refdata.wcs);
 
       /* Read the input image as a double type array. */
-      data=gal_fits_read_img_hdu(filename, hdu, p->cp.minmapsize);
+      data=gal_fits_img_read(filename, hdu, p->cp.minmapsize);
 
       /* When the reference data structure's dimensionality is non-zero, it
          means that this is not the first image read. So, write its basic
diff --git a/bin/convertt/convertt.c b/bin/convertt/convertt.c
index 0952254..007e7c0 100644
--- a/bin/convertt/convertt.c
+++ b/bin/convertt/convertt.c
@@ -29,6 +29,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <string.h>
 #include <stdlib.h>
 
+#include <gnuastro/txt.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/txtarray.h>
 #include <gnuastro/arithmetic.h>
@@ -37,8 +38,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 #include "main.h"
 
-#include "jpeg.h"
 #include "eps.h"
+#include "jpeg.h"
 
 
 
@@ -167,7 +168,7 @@ convertt_truncate(struct converttparams *p)
 /**************************************************************/
 /**************       Save text and FITS        ***************/
 /**************************************************************/
-void
+static void
 save_with_gnuastro_lib(struct converttparams *p)
 {
   gal_data_t *channel;
@@ -175,15 +176,17 @@ save_with_gnuastro_lib(struct converttparams *p)
   for(channel=p->chll; channel!=NULL; channel=channel->next)
     switch(p->outformat)
       {
+
       case OUT_FORMAT_FITS:
-        gal_fits_write_img(channel, p->cp.output, NULL, PROGRAM_STRING);
+        gal_fits_img_write(channel, p->cp.output, NULL, PROGRAM_STRING);
         break;
 
+
       case OUT_FORMAT_TXT:
-        printf("\n... in save_with_gnuastro_lib ...\n");
-        exit(1);
+        gal_txt_write(p->chll, NULL, p->cp.output, p->cp.dontdelete);
         break;
 
+
       default:
         error(EXIT_FAILURE, 0, "a bug! output format code `%d' not "
               "recognized in `save_with_gnuastro_lib'", p->outformat);
@@ -355,6 +358,7 @@ convertt_scale_to_uchar(struct converttparams *p)
 void
 convertt(struct converttparams *p)
 {
+
   /* Make any of the desired changes to the data. */
   if(p->changeaftertrunc)
     {
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index bc85dc7..249b202 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -28,6 +28,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 
+#include <gnuastro/txt.h>
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
 #include <gnuastro/arithmetic.h>
@@ -451,9 +453,8 @@ ui_make_channels_ll(struct converttparams *p)
                   "for each input FITS image (in the same order)");
 
           /* Read in the array and its WCS information. */
-          data=gal_fits_read_to_type(name->v, hdu, GAL_DATA_TYPE_DOUBLE,
-                                     p->cp.minmapsize);
-          gal_fits_read_wcs(name->v, hdu, 0, 0, &data->nwcs, &data->wcs);
+          data=gal_fits_img_read(name->v, hdu, p->cp.minmapsize);
+          gal_wcs_read(name->v, hdu, 0, 0, &data->nwcs, &data->wcs);
           gal_data_add_existing_to_ll(&p->chll, data);
 
           /* A FITS file only has one channel. */
@@ -507,20 +508,8 @@ ui_make_channels_ll(struct converttparams *p)
       /* Text: */
       else
         {
-          printf("\n\n... Work on txt inputs ...\n");
-          exit(1);
-          /*
-          gal_txtarray_txt_to_array(name->v, &p->ch[p->numch],
-                                    &p->s0[p->numch], &p->s1[p->numch]);
-          df = (d=p->ch[p->numch]) + p->s0[p->numch]*p->s1[p->numch];
-          do if(isnan(*d++)) break; while(d<df);
-          if(d==df)
-            gal_checkset_check_remove_file(GAL_TXTARRAY_LOG, 0);
-          else
-            error(EXIT_FAILURE, 0, "%s contains non-numeric data, see %s",
-                  name->v, GAL_TXTARRAY_LOG);
-          p->bitpixs[p->numch]=DOUBLE_IMG;
-          */
+          data=gal_txt_image_read(name->v, p->cp.minmapsize);
+          gal_data_add_existing_to_ll(&p->chll, data);
           ++p->numch;
         }
     }
@@ -724,8 +713,8 @@ ui_set_output(struct converttparams *p)
          the output is just one of these two suffixes, then we will use
          automatic output to generate the full name, otherwise, we'll just
          take the user's given value as the filename. */
-      if( strcmp(cp->output, "txt") && strcmp(cp->output, ".txt")
-          && strcmp(cp->output, "dat") && strcmp(cp->output, ".dat") )
+      if( !strcmp(cp->output, "txt") || !strcmp(cp->output, ".txt")
+          || !strcmp(cp->output, "dat") || !strcmp(cp->output, ".dat") )
         ui_add_dot_use_automatic_output(p);
 
       /* If output type is not an image, there should only be one color
@@ -739,6 +728,9 @@ ui_set_output(struct converttparams *p)
               "channel to text by specifying the HDU",
               cp->output, p->numch);
     }
+
+  /* Check if the output already exists. */
+  gal_checkset_check_remove_file(cp->output, cp->dontdelete);
 }
 
 
diff --git a/bin/convolve/convolve.c b/bin/convolve/convolve.c
index a918932..19039c1 100644
--- a/bin/convolve/convolve.c
+++ b/bin/convolve/convolve.c
@@ -29,6 +29,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <gsl/gsl_errno.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/threads.h>
 #include <gnuastro/spatialconvolve.h>
@@ -651,13 +652,13 @@ frequencyconvolve(struct convolveparams *p)
       /* Save the padded input image. */
       complextoreal(p->pimg, p->ps0*p->ps1, COMPLEX_TO_REAL_REAL, &tmp);
       data->array=tmp; data->name="input padded";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       free(tmp); data->name=NULL;
 
       /* Save the padded kernel image. */
       complextoreal(p->pker, p->ps0*p->ps1, COMPLEX_TO_REAL_REAL, &tmp);
       data->array=tmp; data->name="kernel padded";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       free(tmp); data->name=NULL;
     }
 
@@ -675,12 +676,12 @@ frequencyconvolve(struct convolveparams *p)
     {
       complextoreal(p->pimg, p->ps0*p->ps1, COMPLEX_TO_REAL_SPEC, &tmp);
       data->array=tmp; data->name="input transformed";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       free(tmp); data->name=NULL;
 
       complextoreal(p->pker, p->ps0*p->ps1, COMPLEX_TO_REAL_SPEC, &tmp);
       data->array=tmp; data->name="kernel transformed";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       free(tmp); data->name=NULL;
     }
 
@@ -702,7 +703,7 @@ frequencyconvolve(struct convolveparams *p)
     {
       complextoreal(p->pimg, p->ps0*p->ps1, COMPLEX_TO_REAL_SPEC, &tmp);
       data->array=tmp; data->name=p->makekernel ? "Divided" : "Multiplied";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       free(tmp); data->name=NULL;
     }
 
@@ -718,7 +719,7 @@ frequencyconvolve(struct convolveparams *p)
   if(p->checkfreqsteps)
     {
       data->array=tmp; data->name="padded output";
-      gal_fits_write_img(data, p->freqstepsname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(data, p->freqstepsname, NULL, PROGRAM_STRING);
       data->name=NULL;
     }
 
@@ -785,13 +786,13 @@ convolve(struct convolveparams *p)
           data=gal_data_alloc(p->mp.img, GAL_DATA_TYPE_FLOAT, ndim, dsize,
                               p->wcs, 0, p->cp.minmapsize, NULL, NULL, NULL);
           data->name="Input";
-          gal_fits_write_img(data, p->meshname, NULL, PROGRAM_STRING);
+          gal_fits_img_write(data, p->meshname, NULL, PROGRAM_STRING);
 
           /* Change the array, type, and name. */
           data->array=meshindexs;
           data->type=GAL_DATA_TYPE_LONG;
           data->name="Mesh indexs";
-          gal_fits_write_img(data, p->meshname, NULL, PROGRAM_STRING);
+          gal_fits_img_write(data, p->meshname, NULL, PROGRAM_STRING);
 
           /* Clean up. */
           data->name=NULL;
@@ -817,7 +818,7 @@ convolve(struct convolveparams *p)
   data->wcs=p->wcs;
   data->unit=p->unit;
   data->name="Convolved";
-  gal_fits_write_img(data, p->cp.output, NULL, PROGRAM_STRING);
+  gal_fits_img_write(data, p->cp.output, NULL, PROGRAM_STRING);
   data->name=NULL;
   gal_data_free(data);
 }
diff --git a/bin/convolve/ui.c b/bin/convolve/ui.c
index 13804a4..fa671f6 100644
--- a/bin/convolve/ui.c
+++ b/bin/convolve/ui.c
@@ -28,6 +28,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 
+#include <gnuastro/wcs.h>
 #include <gnuastro/fits.h>
 #include <gnuastro/table.h>
 #include <gnuastro/linkedlist.h>
@@ -286,8 +287,8 @@ ui_read_kernel(struct convolveparams *p)
   gal_data_t *data;
 
   /* Read the image into file. */
-  data=gal_fits_read_to_type(p->kernelname, p->khdu, GAL_DATA_TYPE_FLOAT,
-                             p->cp.minmapsize);
+  data=gal_fits_img_read_to_type(p->kernelname, p->khdu, GAL_DATA_TYPE_FLOAT,
+                                 p->cp.minmapsize);
 
   /* Put its values into the main program structure. */
   p->ks0=data->dsize[0];
@@ -335,9 +336,9 @@ ui_preparations(struct convolveparams *p)
 
 
   /* Read the input image as a float array and its WCS info. */
-  data=gal_fits_read_to_type(p->filename, p->cp.hdu, GAL_DATA_TYPE_FLOAT,
-                             p->cp.minmapsize);
-  gal_fits_read_wcs(p->filename, p->cp.hdu, 0, 0, &p->nwcs, &p->wcs);
+  data=gal_fits_img_read_to_type(p->filename, p->cp.hdu, GAL_DATA_TYPE_FLOAT,
+                                 p->cp.minmapsize);
+  gal_wcs_read(p->filename, p->cp.hdu, 0, 0, &p->nwcs, &p->wcs);
   p->unit=data->unit;
   data->unit=NULL;
 
@@ -427,8 +428,8 @@ ui_preparations(struct convolveparams *p)
         }
       else
         {
-          data=gal_fits_read_float_kernel(p->kernelname, p->khdu,
-                                          p->cp.minmapsize);
+          data=gal_fits_img_read_kernel(p->kernelname, p->khdu,
+                                        p->cp.minmapsize);
           p->ks0=data->dsize[0];
           p->ks1=data->dsize[1];
           p->kernel=data->array;
diff --git a/bin/header/ui.c b/bin/header/ui.c
index ec9022b..93ada8b 100644
--- a/bin/header/ui.c
+++ b/bin/header/ui.c
@@ -417,7 +417,7 @@ ui_fill_fits_headerll(struct gal_linkedlist_stll *input,
         }
 
 
-      gal_fits_add_to_key_ll(output, type, keyname, 0,
+      gal_fits_key_add_to_ll(output, type, keyname, 0,
                              fvalue, vfree, comment, 0, unit);
       free(original);
     }
diff --git a/bin/imgcrop/crop.c b/bin/imgcrop/crop.c
index 317dcf8..bda80de 100644
--- a/bin/imgcrop/crop.c
+++ b/bin/imgcrop/crop.c
@@ -785,14 +785,14 @@ onecrop(struct cropparams *crp)
          image, so increment crp->imgcount and save the information of
          this image. */
       sprintf(basename, "ICF%zu", ++crp->numimg);
-      gal_fits_file_name_in_keywords(basename, img->name, &headers);
+      gal_fits_key_write_filename(basename, img->name, &headers);
       sprintf(regionkey, "%sPIX", basename);
       sprintf(region, "%ld:%ld,%ld:%ld", fpixel_i[0], lpixel_i[0],
               fpixel_i[1], lpixel_i[1]);
-      gal_fits_add_to_key_ll_end(&headers, TSTRING, regionkey, 0, region, 0,
+      gal_fits_key_add_to_ll_end(&headers, TSTRING, regionkey, 0, region, 0,
                                  "Range of pixels used for this output.", 0,
                                  NULL);
-      gal_fits_update_keys(ofp, &headers);
+      gal_fits_key_write(ofp, &headers);
 
 
       /* Free the allocated array. */
diff --git a/bin/imgcrop/imgcrop.c b/bin/imgcrop/imgcrop.c
index 65a3a4c..3027787 100644
--- a/bin/imgcrop/imgcrop.c
+++ b/bin/imgcrop/imgcrop.c
@@ -201,7 +201,7 @@ imgmodecrop(void *inparam)
   /* The whole catalog is from one image, so you can get the
      information here:*/
   img=&p->imgs[crp->in_ind];
-  crp->infits=gal_fits_read_hdu(img->name, p->cp.hdu, 0);
+  crp->infits=gal_fits_hdu_open(img->name, p->cp.hdu, 0);
 
   /* Go over all the outputs that are assigned to this thread: */
   for(i=0;crp->indexs[i]!=GAL_THREADS_NON_THRD_INDEX;++i)
@@ -222,7 +222,7 @@ imgmodecrop(void *inparam)
           crp->centerfilled=iscenterfilled(crp);
 
           /* Add the final headers and close output FITS image: */
-          gal_fits_write_keys_version(crp->outfits, NULL, PROGRAM_STRING);
+          gal_fits_key_write_version(crp->outfits, NULL, PROGRAM_STRING);
           status=0;
           if( fits_close_file(crp->outfits, &status) )
             gal_fits_io_error(status, "CFITSIO could not close "
@@ -293,7 +293,7 @@ wcsmodecrop(void *inparam)
         if(radecoverlap(crp))
           {
             /* Open the input FITS file. */
-            crp->infits=gal_fits_read_hdu(p->imgs[crp->in_ind].name,
+            crp->infits=gal_fits_hdu_open(p->imgs[crp->in_ind].name,
                                           p->cp.hdu, 0);
 
             /* If a name isn't set yet, set it. */
@@ -316,7 +316,7 @@ wcsmodecrop(void *inparam)
         {
           crp->centerfilled=iscenterfilled(crp);
 
-          gal_fits_write_keys_version(crp->outfits, NULL, PROGRAM_STRING);
+          gal_fits_key_write_version(crp->outfits, NULL, PROGRAM_STRING);
           status=0;
           if( fits_close_file(crp->outfits, &status) )
             gal_fits_io_error(status, "CFITSIO could not close the "
diff --git a/bin/imgcrop/ui.c b/bin/imgcrop/ui.c
index 48b560c..23f530f 100644
--- a/bin/imgcrop/ui.c
+++ b/bin/imgcrop/ui.c
@@ -706,10 +706,10 @@ ui_preparations(struct imgcropparams *p)
       status=0;
       img=&p->imgs[--input_counter];
       gal_linkedlist_pop_from_stll(&p->inputs, &img->name);
-      tmpfits=gal_fits_read_hdu(img->name, p->cp.hdu, 0);
+      tmpfits=gal_fits_hdu_open(img->name, p->cp.hdu, 0);
       gal_fits_img_info(tmpfits, &p->type, &img->ndim, &img->dsize);
-      gal_fits_read_wcs_from_pointer(tmpfits, &img->nwcs, &img->wcs,
-                                     p->hstartwcs, p->hendwcs);
+      gal_wcs_read_from_fitsptr(tmpfits, &img->nwcs, &img->wcs,
+                                p->hstartwcs, p->hendwcs);
       if(img->wcs)
         {
           gal_wcs_decompose_pc_cdelt(img->wcs);
diff --git a/bin/mkprof/mkprof.c b/bin/mkprof/mkprof.c
index 00239e3..2f4e0a1 100644
--- a/bin/mkprof/mkprof.c
+++ b/bin/mkprof/mkprof.c
@@ -139,7 +139,7 @@ saveindividual(struct mkonthread *mkp)
   /* Write the array to file (a separately built PSF doesn't need WCS
      coordinates). */
   if(ibq->ispsf && p->psfinimg==0)
-    gal_fits_write_img(data, filename, NULL, PROGRAM_STRING);
+    gal_fits_img_write(data, filename, NULL, PROGRAM_STRING);
   else
     {
       /* Save the correct CRPIX values: */
@@ -147,9 +147,9 @@ saveindividual(struct mkonthread *mkp)
       crpix[1] = p->crpix[1] - os*(mkp->fpixel_i[1]-1);
 
       /* Write the image. */
-      gal_fits_write_img_wcs_string(data, filename, p->wcsheader,
-                                    p->wcsnkeyrec, crpix, NULL,
-                                    PROGRAM_STRING);
+      gal_fits_img_write_corr_wcs_str(data, filename, p->wcsheader,
+                                      p->wcsnkeyrec, crpix, NULL,
+                                      PROGRAM_STRING);
     }
   ibq->indivcreated=1;
 
@@ -522,7 +522,7 @@ mkprof_write(struct mkprofparams *p)
         }
 
       /* Write the final image into a FITS file. */
-      gal_fits_write_img(towrite, p->mergedimgname, NULL, PROGRAM_STRING);
+      gal_fits_img_write(towrite, p->mergedimgname, NULL, PROGRAM_STRING);
 
       /* Clean up */
       gal_data_free(towrite);
diff --git a/bin/mkprof/ui.c b/bin/mkprof/ui.c
index db92037..31542f7 100644
--- a/bin/mkprof/ui.c
+++ b/bin/mkprof/ui.c
@@ -645,8 +645,9 @@ ui_prepare_canvas(struct mkprofparams *p)
                               p->cp.minmapsize, NULL, NULL, NULL);
       else
         {
-          p->out=gal_fits_read_to_type(p->backname, p->backhdu,
-                                       GAL_DATA_TYPE_FLOAT, p->cp.minmapsize);
+          p->out=gal_fits_img_read_to_type(p->backname, p->backhdu,
+                                           GAL_DATA_TYPE_FLOAT,
+                                           p->cp.minmapsize);
           p->naxes[0]=p->out->dsize[1];
           p->naxes[1]=p->out->dsize[0];
         }
@@ -657,8 +658,8 @@ ui_prepare_canvas(struct mkprofparams *p)
       p->shift[0]=p->shift[1]=0;
 
       /* Read the WCS structure of the background image. */
-      gal_fits_read_wcs(p->backname, p->backhdu, 0, 0, &p->out->nwcs,
-                        &p->out->wcs);
+      gal_wcs_read(p->backname, p->backhdu, 0, 0, &p->out->nwcs,
+                   &p->out->wcs);
 
     }
   else
diff --git a/lib/fits.c b/lib/fits.c
index 2bb8ea3..1b4ea9d 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -469,7 +469,7 @@ gal_fits_datatype_to_type(int datatype)
 /**********                  HDU                   ************/
 /**************************************************************/
 void
-gal_fits_num_hdus(char *filename, int *numhdu)
+gal_fits_hdu_num(char *filename, int *numhdu)
 {
   int status=0;
   fitsfile *fptr;
@@ -494,7 +494,7 @@ gal_fits_num_hdus(char *filename, int *numhdu)
 /* Check the desired HDU in a FITS image and also if it has the
    desired type. */
 fitsfile *
-gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1)
+gal_fits_hdu_open(char *filename, char *hdu, unsigned char img0_tab1)
 {
   char *ffname;
   fitsfile *fptr;
@@ -631,7 +631,7 @@ gal_fits_hdu_type(char *filename, char *hdu)
    then the status value will be KEY_NO_EXIST (from CFITSIO).
  */
 void
-gal_fits_read_keywords_fptr(fitsfile *fptr, gal_data_t *keysll,
+gal_fits_key_read_from_ptr(fitsfile *fptr, gal_data_t *keysll,
                             int readcomment, int readunit)
 {
   void *valueptr;
@@ -718,8 +718,8 @@ gal_fits_read_keywords_fptr(fitsfile *fptr, gal_data_t 
*keysll,
 /* Same as `gal_fits_read_keywords_fptr', but accepts the filename and HDU
    as input instead of an already opened CFITSIO `fitsfile' pointer. */
 void
-gal_fits_read_keywords(char *filename, char *hdu, gal_data_t *keysll,
-                       int readcomment, int readunit)
+gal_fits_key_read(char *filename, char *hdu, gal_data_t *keysll,
+                  int readcomment, int readunit)
 {
   size_t len;
   int status=0;
@@ -739,7 +739,7 @@ gal_fits_read_keywords(char *filename, char *hdu, 
gal_data_t *keysll,
     gal_fits_io_error(status, "reading this FITS file");
 
   /* Read the keywords. */
-  gal_fits_read_keywords_fptr(fptr, keysll, readcomment, readunit);
+  gal_fits_key_read_from_ptr(fptr, keysll, readcomment, readunit);
 
   /* Close the FITS file. */
   fits_close_file(fptr, &status);
@@ -758,7 +758,7 @@ gal_fits_read_keywords(char *filename, char *hdu, 
gal_data_t *keysll,
    it is important to know before hand if they were allocated or
    not. If not, they don't need to be freed. */
 void
-gal_fits_add_to_key_ll(struct gal_fits_key_ll **list, int type,
+gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, int type,
                        char *keyname, int kfree, void *value, int vfree,
                        char *comment, int cfree, char *unit)
 {
@@ -788,7 +788,7 @@ gal_fits_add_to_key_ll(struct gal_fits_key_ll **list, int 
type,
 
 
 void
-gal_fits_add_to_key_ll_end(struct gal_fits_key_ll **list, int type,
+gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, int type,
                            char *keyname, int kfree, void *value, int vfree,
                            char *comment, int cfree, char *unit)
 {
@@ -828,8 +828,8 @@ gal_fits_add_to_key_ll_end(struct gal_fits_key_ll **list, 
int type,
 
 
 void
-gal_fits_file_name_in_keywords(char *keynamebase, char *filename,
-                               struct gal_fits_key_ll **list)
+gal_fits_key_write_filename(char *keynamebase, char *filename,
+                            struct gal_fits_key_ll **list)
 {
   char *keyname, *value;
   size_t numkey=1, maxlength;
@@ -865,7 +865,7 @@ gal_fits_file_name_in_keywords(char *keynamebase, char 
*filename,
          length was copied. */
       if(value[maxlength-1]=='\0')
         {
-          gal_fits_add_to_key_ll_end(list, TSTRING, keyname, 1,
+          gal_fits_key_add_to_ll_end(list, TSTRING, keyname, 1,
                                      value, 1, NULL, 0, NULL);
           break;
         }
@@ -887,7 +887,7 @@ gal_fits_file_name_in_keywords(char *keynamebase, char 
*filename,
                   filename, maxlength);
 
           /* Convert the last useful character and save the file name.*/
-          gal_fits_add_to_key_ll_end(list, TSTRING, keyname, 1,
+          gal_fits_key_add_to_ll_end(list, TSTRING, keyname, 1,
                                      value, 1, NULL, 0, NULL);
           i+=j+1;
         }
@@ -898,10 +898,9 @@ gal_fits_file_name_in_keywords(char *keynamebase, char 
*filename,
 
 
 
-/* Write the WCS and begin the part on this particular program's
-   key words. */
+/* Write the WCS header string into a FITS files*/
 void
-gal_fits_add_wcs_to_header(fitsfile *fptr, char *wcsheader, int nkeyrec)
+gal_fits_key_write_wcsstr(fitsfile *fptr, char *wcsstr, int nkeyrec)
 {
   size_t i;
   int h, status=0;
@@ -925,7 +924,7 @@ gal_fits_add_wcs_to_header(fitsfile *fptr, char *wcsheader, 
int nkeyrec)
 
   /* Write the keywords one by one: */
   for(h=0;h<nkeyrec-1;++h)
-    fits_write_record(fptr, &wcsheader[h*80], &status);
+    fits_write_record(fptr, &wcsstr[h*80], &status);
   gal_fits_io_error(status, NULL);
 }
 
@@ -937,7 +936,7 @@ gal_fits_add_wcs_to_header(fitsfile *fptr, char *wcsheader, 
int nkeyrec)
    file. Every keyword that is written is freed, that is why we need
    the pointer to the linked list (to correct it after we finish). */
 void
-gal_fits_update_keys(fitsfile *fptr, struct gal_fits_key_ll **keylist)
+gal_fits_key_write(fitsfile *fptr, struct gal_fits_key_ll **keylist)
 {
   int status=0;
   struct gal_fits_key_ll *tmp, *ttmp;
@@ -981,8 +980,8 @@ gal_fits_update_keys(fitsfile *fptr, struct gal_fits_key_ll 
**keylist)
 
 
 void
-gal_fits_write_keys_version(fitsfile *fptr, struct gal_fits_key_ll *headers,
-                            char *program_name)
+gal_fits_key_write_version(fitsfile *fptr, struct gal_fits_key_ll *headers,
+                           char *program_name)
 {
   size_t i;
   int status=0;
@@ -1015,7 +1014,7 @@ gal_fits_write_keys_version(fitsfile *fptr, struct 
gal_fits_key_ll *headers,
               program_name ? program_name : PACKAGE_NAME);
       for(i=strlen(titlerec);i<79;++i) titlerec[i]=' ';
       fits_write_record(fptr, titlerec, &status);
-      gal_fits_update_keys(fptr, &headers);
+      gal_fits_key_write(fptr, &headers);
     }
 
 
@@ -1086,141 +1085,6 @@ gal_fits_write_keys_version(fitsfile *fptr, struct 
gal_fits_key_ll *headers,
 
 
 /*************************************************************
- ***********       Read WCS from FITS pointer      ***********
- *************************************************************/
-/* Read the WCS information from the header. Unfortunately, WCS lib is
-   not thread safe, so it needs a mutex. In case you are not using
-   multiple threads, just pass a NULL pointer as the mutex.
-
-   After you finish with this WCS, you should free the space with:
-
-   status = wcsvfree(&nwcs,&wcs);
-
-   If the WCS structure is not recognized, then this function will
-   return a NULL pointer for the wcsprm structure and a zero for
-   nwcs. It will also report the fact to the user in stderr.
-
-   ===================================
-   WARNING: wcspih IS NOT THREAD SAFE!
-   ===================================
-   Don't call this function within a thread or use a mutex.
-*/
-void
-gal_fits_read_wcs_from_pointer(fitsfile *fptr, int *nwcs, struct wcsprm **wcs,
-                               size_t hstartwcs, size_t hendwcs)
-{
-  /* Declaratins: */
-  int nkeys=0, status=0;
-  char *fullheader, *to, *from;
-  int relax    = WCSHDR_all; /* Macro: use all informal WCS extensions. */
-  int ctrl     = 0;          /* Don't report why a keyword wasn't used. */
-  int nreject  = 0;          /* Number of keywords rejected for syntax. */
-
-  /* CFITSIO function: */
-  if( fits_hdr2str(fptr, 1, NULL, 0, &fullheader, &nkeys, &status) )
-    gal_fits_io_error(status, NULL);
-
-  /* Only consider the header keywords in the current range: */
-  if(hendwcs>hstartwcs)
-    {
-      /* Mark the last character in the desired region. */
-      fullheader[hendwcs*(FLEN_CARD-1)]='\0';
-      /*******************************************************/
-      /******************************************************
-      printf("%s\n", fullheader);
-      ******************************************************/
-      /*******************************************************/
-
-      /* Shift all the characters to the start of the string. */
-      if(hstartwcs)                /* hstartwcs!=0 */
-        {
-          to=fullheader;
-          from=&fullheader[hstartwcs*(FLEN_CARD-1)-1];
-          while(*from++!='\0') *to++=*from;
-        }
-
-      nkeys=hendwcs-hstartwcs;
-
-      /*******************************************************/
-      /******************************************************
-      printf("\n\n\n###############\n\n\n\n\n\n");
-      printf("%s\n", &fullheader[1*(FLEN_CARD-1)]);
-      exit(0);
-      ******************************************************/
-      /*******************************************************/
-    }
-
-  /* WCSlib function */
-  status=wcspih(fullheader, nkeys, relax, ctrl, &nreject, nwcs, wcs);
-  if(status)
-    {
-      fprintf(stderr, "\n##################\n"
-              "WCSLIB Warning: wcspih ERROR %d: %s.\n"
-              "##################\n",
-              status, wcs_errmsg[status]);
-      *wcs=NULL; *nwcs=0;
-    }
-  if (fits_free_memory(fullheader, &status) )
-    gal_fits_io_error(status, "problem in fitsarrayvv.c for freeing "
-                           "the memory used to keep all the headers");
-
-  /* Set the internal structure: */
-  status=wcsset(*wcs);
-  if(status)
-    {
-      fprintf(stderr, "\n##################\n"
-              "WCSLIB Warning: wcsset ERROR %d: %s.\n"
-              "##################\n",
-            status, wcs_errmsg[status]);
-      *wcs=NULL; *nwcs=0;
-    }
-
-  /* Initialize the wcsprm struct
-  if ((status = wcsset(*wcs)))
-    error(EXIT_FAILURE, 0, "wcsset ERROR %d: %s.\n", status,
-          wcs_errmsg[status]);
-  */
-}
-
-
-
-
-
-void
-gal_fits_read_wcs(char *filename, char *hdu, size_t hstartwcs,
-                  size_t hendwcs, int *nwcs, struct wcsprm **wcs)
-{
-  int status=0;
-  fitsfile *fptr;
-
-  /* Check HDU for realistic conditions: */
-  fptr=gal_fits_read_hdu(filename, hdu, 0);
-
-  /* Read the WCS information: */
-  gal_fits_read_wcs_from_pointer(fptr, nwcs, wcs, hstartwcs, hendwcs);
-
-  /* Close the FITS file: */
-  fits_close_file(fptr, &status);
-  gal_fits_io_error(status, NULL);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/*************************************************************
  ***********            Array functions            ***********
  *************************************************************/
 
@@ -1256,14 +1120,9 @@ gal_fits_img_info(fitsfile *fptr, int *type, size_t 
*ndim, size_t **dsize)
 
 
 
-/* Read a FITS image into an array corresponding to fitstype and also
-   save the size of the array.
-
-   If the image has any null pixels, their number is returned by this
-   function. The value that is placed for those pixels is defined by
-   the macros in fitsarrayvv.h and depends on the type of the data.*/
+/* Read a FITS image HDU into a Gnuastro data structure. */
 gal_data_t *
-gal_fits_read_img_hdu(char *filename, char *hdu, size_t minmapsize)
+gal_fits_img_read(char *filename, char *hdu, size_t minmapsize)
 {
   void *blank;
   int anyblank;
@@ -1276,7 +1135,7 @@ gal_fits_read_img_hdu(char *filename, char *hdu, size_t 
minmapsize)
 
 
   /* Check HDU for realistic conditions: */
-  fptr=gal_fits_read_hdu(filename, hdu, 0);
+  fptr=gal_fits_hdu_open(filename, hdu, 0);
 
 
   /* Get the info and allocate the data structure. */
@@ -1307,7 +1166,7 @@ gal_fits_read_img_hdu(char *filename, char *hdu, size_t 
minmapsize)
                         NULL, 0, -1, "EXTNAME", NULL, NULL);
   gal_data_add_to_ll(&keysll, NULL, GAL_DATA_TYPE_STRING, 1, &dsize_key,
                         NULL, 0, -1, "BUNIT", NULL, NULL);
-  gal_fits_read_keywords_fptr(fptr, keysll, 0, 0);
+  gal_fits_key_read_from_ptr(fptr, keysll, 0, 0);
   if(keysll->status==0)       {str=keysll->array;       unit=*str; }
   if(keysll->next->status==0) {str=keysll->next->array; name=*str; }
 
@@ -1345,13 +1204,13 @@ gal_fits_read_img_hdu(char *filename, char *hdu, size_t 
minmapsize)
    this input to be a special type. For such cases, this function can be
    used to convert the input file to the desired type. */
 gal_data_t *
-gal_fits_read_to_type(char *inputname, char *hdu, int type,
-                      size_t minmapsize)
+gal_fits_img_read_to_type(char *inputname, char *hdu, int type,
+                          size_t minmapsize)
 {
   gal_data_t *in, *converted;
 
   /* Read the specified input image HDU. */
-  in=gal_fits_read_img_hdu(inputname, hdu, minmapsize);
+  in=gal_fits_img_read(inputname, hdu, minmapsize);
 
   /* If the input had another type, convert it to float. */
   if(in->type!=type)
@@ -1370,7 +1229,7 @@ gal_fits_read_to_type(char *inputname, char *hdu, int 
type,
 
 
 gal_data_t *
-gal_fits_read_float_kernel(char *filename, char *hdu, size_t minmapsize)
+gal_fits_img_read_kernel(char *filename, char *hdu, size_t minmapsize)
 {
   size_t i;
   int check=0;
@@ -1379,8 +1238,8 @@ gal_fits_read_float_kernel(char *filename, char *hdu, 
size_t minmapsize)
   float *f, *fp, tmp;
 
   /* Read the image as a float */
-  kernel=gal_fits_read_to_type(filename, hdu, GAL_DATA_TYPE_FLOAT,
-                               minmapsize);
+  kernel=gal_fits_img_read_to_type(filename, hdu, GAL_DATA_TYPE_FLOAT,
+                                   minmapsize);
 
   /* Check if the size along each dimension of the kernel is an odd
      number. If they are all an odd number, then the for each dimension,
@@ -1426,12 +1285,12 @@ gal_fits_read_float_kernel(char *filename, char *hdu, 
size_t minmapsize)
    WCS information) into a FITS file, but will not close it. Instead it
    will pass along the FITS pointer for further modification. */
 fitsfile *
-gal_fits_write_img_fitsptr(gal_data_t *data, char *filename)
+gal_fits_img_write_to_ptr(gal_data_t *data, char *filename)
 {
   size_t i;
   void *blank;
+  char *wcsstr;
   fitsfile *fptr;
-  char *wcsheader;
   long fpixel=1, *naxes;
   int nkeyrec, status=0, datatype=gal_fits_type_to_datatype(data->type);
 
@@ -1501,11 +1360,11 @@ gal_fits_write_img_fitsptr(gal_data_t *data, char 
*filename)
       gal_wcs_decompose_pc_cdelt(data->wcs);
 
       /* Convert the WCS information to text. */
-      status=wcshdo(WCSHDO_safe, data->wcs, &nkeyrec, &wcsheader);
+      status=wcshdo(WCSHDO_safe, data->wcs, &nkeyrec, &wcsstr);
       if(status)
         error(EXIT_FAILURE, 0, "wcshdo ERROR %d: %s", status,
               wcs_errmsg[status]);
-      gal_fits_add_wcs_to_header(fptr, wcsheader, nkeyrec);
+      gal_fits_key_write_wcsstr(fptr, wcsstr, nkeyrec);
     }
 
   /* Report any errors if we had any */
@@ -1519,17 +1378,17 @@ gal_fits_write_img_fitsptr(gal_data_t *data, char 
*filename)
 
 
 void
-gal_fits_write_img(gal_data_t *data, char *filename,
+gal_fits_img_write(gal_data_t *data, char *filename,
                    struct gal_fits_key_ll *headers, char *program_string)
 {
   int status=0;
   fitsfile *fptr;
 
   /* Write the data array into a FITS file and keep it open: */
-  fptr=gal_fits_write_img_fitsptr(data, filename);
+  fptr=gal_fits_img_write_to_ptr(data, filename);
 
   /* Write all the headers and the version information. */
-  gal_fits_write_keys_version(fptr, headers, program_string);
+  gal_fits_key_write_version(fptr, headers, program_string);
 
   /* Close the FITS file. */
   fits_close_file(fptr, &status);
@@ -1553,10 +1412,10 @@ gal_fits_write_img(gal_data_t *data, char *filename,
         writing FITS images in parallel, we can't write the header keywords
         in each thread.   */
 void
-gal_fits_write_img_wcs_string(gal_data_t *data, char *filename,
-                              char *wcsheader, int nkeyrec, double *crpix,
-                              struct gal_fits_key_ll *headers,
-                              char *program_string)
+gal_fits_img_write_corr_wcs_str(gal_data_t *data, char *filename,
+                                char *wcsstr, int nkeyrec, double *crpix,
+                                struct gal_fits_key_ll *headers,
+                                char *program_string)
 {
   int status=0;
   fitsfile *fptr;
@@ -1567,10 +1426,10 @@ gal_fits_write_img_wcs_string(gal_data_t *data, char 
*filename,
           "accept inputs with no WCS.");
 
   /* Write the data array into a FITS file and keep it open. */
-  fptr=gal_fits_write_img_fitsptr(data, filename);
+  fptr=gal_fits_img_write_to_ptr(data, filename);
 
   /* Write the WCS headers into the FITS file. */
-  gal_fits_add_wcs_to_header(fptr, wcsheader, nkeyrec);
+  gal_fits_key_write_wcsstr(fptr, wcsstr, nkeyrec);
 
   /* Update the CRPIX keywords. Note that we don't want to change the
      values in the WCS information of gal_data_t. Because, it often happens
@@ -1586,7 +1445,7 @@ gal_fits_write_img_wcs_string(gal_data_t *data, char 
*filename,
     }
 
   /* Write all the headers and the version information. */
-  gal_fits_write_keys_version(fptr, headers, program_string);
+  gal_fits_key_write_version(fptr, headers, program_string);
 
   /* Close the file and return. */
   fits_close_file(fptr, &status);
@@ -1618,7 +1477,7 @@ gal_fits_write_img_wcs_string(gal_data_t *data, char 
*filename,
 /* Get the size of a table HDU. CFITSIO doesn't use size_t, also we want to
    check status here.*/
 void
-gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols)
+gal_fits_tab_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols)
 {
   long lnrows;
   int incols, status=0;
@@ -1638,7 +1497,7 @@ gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, 
size_t *ncols)
 
 
 int
-gal_fits_table_type(fitsfile *fptr)
+gal_fits_tab_type(fitsfile *fptr)
 {
   int status=0;
   char value[FLEN_VALUE];
@@ -1832,8 +1691,8 @@ fits_correct_bin_table_int_types(gal_data_t *allcols, int 
tfields,
 
 /* See the descriptions of `gal_table_info'. */
 gal_data_t *
-gal_fits_table_info(char *filename, char *hdu, size_t *numcols,
-                    size_t *numrows, int *tabletype)
+gal_fits_tab_info(char *filename, char *hdu, size_t *numcols,
+                  size_t *numrows, int *tabletype)
 {
   long repeat;
   int tfields;        /* The maximum number of fields in FITS is 999 */
@@ -1846,9 +1705,9 @@ gal_fits_table_info(char *filename, char *hdu, size_t 
*numcols,
   char keyname[FLEN_KEYWORD]="XXXXXXXXXXXXX", value[FLEN_VALUE], *val;
 
   /* Open the FITS file and get the basic information. */
-  fptr=gal_fits_read_hdu(filename, hdu, 1);
-  *tabletype=gal_fits_table_type(fptr);
-  gal_fits_table_size(fptr, numrows, numcols);
+  fptr=gal_fits_hdu_open(filename, hdu, 1);
+  *tabletype=gal_fits_tab_type(fptr);
+  gal_fits_tab_size(fptr, numrows, numcols);
 
   /* Read the total number of fields, then allocate space for the data
      structure array and store the information within it. */
@@ -2046,9 +1905,9 @@ gal_fits_table_info(char *filename, char *hdu, size_t 
*numcols,
    low-level function, so the output data linked list is the inverse of the
    input indexs linked list. You can use */
 gal_data_t *
-gal_fits_table_read(char *filename, char *hdu, size_t numrows,
-                    gal_data_t *allcols, struct gal_linkedlist_sll *indexll,
-                    int minmapsize)
+gal_fits_tab_read(char *filename, char *hdu, size_t numrows,
+                  gal_data_t *allcols, struct gal_linkedlist_sll *indexll,
+                  int minmapsize)
 {
   size_t i=0;
   void *blank;
@@ -2060,7 +1919,7 @@ gal_fits_table_read(char *filename, char *hdu, size_t 
numrows,
   struct gal_linkedlist_sll *ind;
 
   /* Open the FITS file */
-  fptr=gal_fits_read_hdu(filename, hdu, 1);
+  fptr=gal_fits_hdu_open(filename, hdu, 1);
 
   /* Pop each index and read/store the array. */
   for(ind=indexll; ind!=NULL; ind=ind->next)
@@ -2233,20 +2092,33 @@ fits_table_prepare_arrays(gal_data_t *cols, size_t 
numcols, int tabletype,
    have NULL values) must have it. */
 static void
 fits_write_tnull_tcomm(fitsfile *fptr, gal_data_t *col, int tabletype,
-                        size_t colnum)
+                       size_t colnum, char *tform)
 {
   void *blank;
   int status=0;
-  char *keyname, *bcomment;
+  char *c, *keyname, *bcomment;
 
   /* Write the NULL value */
   switch(tabletype)
     {
     case GAL_TABLE_FORMAT_AFITS:
+
+      /* Print the keyword and value. */
       asprintf(&keyname, "TNULL%zu", colnum);
       blank=gal_data_blank_as_string(col->type, col->disp_width);
+
+      /* When in exponential form (`tform' starting with `E'), CFITSIO
+         writes a NaN value as `NAN', but when in floating point form
+         (`tform' starting with `F'), it writes it as `nan'. So in the
+         former case, we need to convert the string to upper case. */
+      if(tform[0]=='E' || tform[0]=='e')
+        for(c=blank; *c!='\0'; ++c) *c=toupper(*c);
+
+      /* Write in the header. */
       fits_write_key(fptr, TSTRING, keyname, blank,
                      "blank value for this column", &status);
+
+      /* Clean up. */
       free(keyname);
       free(blank);
       break;
@@ -2295,8 +2167,8 @@ fits_write_tnull_tcomm(fitsfile *fptr, gal_data_t *col, 
int tabletype,
 /* Write the given columns (a linked list of `gal_data_t') into a FITS
    table.*/
 void
-gal_fits_table_write(gal_data_t *cols, char *comments, int tabletype,
-                     char *filename, int dontdelete)
+gal_fits_tab_write(gal_data_t *cols, char *comments, int tabletype,
+                   char *filename, int dontdelete)
 {
   void *blank;
   fitsfile *fptr;
@@ -2347,14 +2219,14 @@ gal_fits_table_write(gal_data_t *cols, char *comments, 
int tabletype,
     {
       /* Write the blank value into the header and return a pointer to
          it. Otherwise, */
-      fits_write_tnull_tcomm(fptr, col, tabletype, i+1);
+      fits_write_tnull_tcomm(fptr, col, tabletype, i+1, tform[i]);
 
       /* Set the blank pointer if its necessary, note that strings don't
          need a blank pointer in a FITS ASCII table.*/
       blank = ( gal_data_has_blank(col)
                 ? gal_data_alloc_blank(col->type) : NULL );
       if(tabletype==GAL_TABLE_FORMAT_AFITS && col->type==GAL_DATA_TYPE_STRING)
-        blank=NULL;
+        { if(blank) free(blank); blank=NULL; }
 
       /* Write the full column into the table. */
       fits_write_colnull(fptr, gal_fits_type_to_datatype(col->type),
@@ -2368,7 +2240,7 @@ gal_fits_table_write(gal_data_t *cols, char *comments, 
int tabletype,
 
 
   /* Write all the headers and the version information. */
-  gal_fits_write_keys_version(fptr, NULL, NULL);
+  gal_fits_key_write_version(fptr, NULL, NULL);
 
 
   /* Clean up and close the FITS file. Note that each element in the
diff --git a/lib/gnuastro/fits.h b/lib/gnuastro/fits.h
index a8d519b..7efb132 100644
--- a/lib/gnuastro/fits.h
+++ b/lib/gnuastro/fits.h
@@ -139,10 +139,10 @@ gal_fits_datatype_to_type(int type);
 /**************************************************************/
 
 void
-gal_fits_num_hdus(char *filename, int *numhdu);
+gal_fits_hdu_num(char *filename, int *numhdu);
 
 fitsfile *
-gal_fits_read_hdu(char *filename, char *hdu, unsigned char img0_tab1);
+gal_fits_hdu_open(char *filename, char *hdu, unsigned char img0_tab1);
 
 int
 gal_fits_hdu_type(char *filename, char *hdu);
@@ -154,51 +154,36 @@ gal_fits_hdu_type(char *filename, char *hdu);
 /**********            Header keywords             ************/
 /**************************************************************/
 void
-gal_fits_read_keywords_fptr(fitsfile *fptr, gal_data_t *keysll,
-                            int readcomment, int readunit);
+gal_fits_key_read_from_ptr(fitsfile *fptr, gal_data_t *keysll,
+                           int readcomment, int readunit);
 
 void
-gal_fits_read_keywords(char *filename, char *hdu, gal_data_t *keysll,
+gal_fits_key_read(char *filename, char *hdu, gal_data_t *keysll,
                        int readcomment, int readunit);
 
 void
-gal_fits_add_to_key_ll(struct gal_fits_key_ll **list, int datatype,
+gal_fits_key_add_to_ll(struct gal_fits_key_ll **list, int datatype,
                        char *keyname, int kfree, void *value, int vfree,
                        char *comment, int cfree, char *unit);
 
 void
-gal_fits_add_to_key_ll_end(struct gal_fits_key_ll **list, int datatype,
+gal_fits_key_add_to_ll_end(struct gal_fits_key_ll **list, int datatype,
                            char *keyname, int kfree, void *value, int vfree,
                            char *comment, int cfree, char *unit);
 
 void
-gal_fits_file_name_in_keywords(char *keynamebase, char *filename,
-                               struct gal_fits_key_ll **list);
+gal_fits_key_write_filename(char *keynamebase, char *filename,
+                            struct gal_fits_key_ll **list);
 
 void
-gal_fits_add_wcs_to_header(fitsfile *fptr, char *wcsheader, int nkeyrec);
+gal_fits_key_write_wcsstr(fitsfile *fptr, char *wcsstr, int nkeyrec);
 
 void
-gal_fits_update_keys(fitsfile *fptr, struct gal_fits_key_ll **keylist);
+gal_fits_key_write(fitsfile *fptr, struct gal_fits_key_ll **keylist);
 
 void
-gal_fits_write_keys_version(fitsfile *fptr, struct gal_fits_key_ll *headers,
-                            char *program_string);
-
-
-
-
-
-/*************************************************************
- ***********       Read WCS from FITS pointer      ***********
- *************************************************************/
-void
-gal_fits_read_wcs_from_pointer(fitsfile *fptr, int *nwcs, struct wcsprm **wcs,
-                               size_t hstartwcs, size_t hendwcs);
-
-void
-gal_fits_read_wcs(char *filename, char *hdu, size_t hstartwcs,
-                  size_t hendwcs, int *nwcs, struct wcsprm **wcs);
+gal_fits_key_write_version(fitsfile *fptr, struct gal_fits_key_ll *headers,
+                           char *program_string);
 
 
 
@@ -211,27 +196,27 @@ void
 gal_fits_img_info(fitsfile *fptr, int *type, size_t *ndim, size_t **dsize);
 
 gal_data_t *
-gal_fits_read_img_hdu(char *filename, char *hdu, size_t minmapsize);
+gal_fits_img_read(char *filename, char *hdu, size_t minmapsize);
 
 gal_data_t *
-gal_fits_read_to_type(char *inputname, char *inhdu, int type,
-                      size_t minmapsize);
+gal_fits_img_read_to_type(char *inputname, char *inhdu, int type,
+                          size_t minmapsize);
 
 gal_data_t *
-gal_fits_read_float_kernel(char *filename, char *hdu, size_t minmapsize);
+gal_fits_img_read_kernel(char *filename, char *hdu, size_t minmapsize);
 
 fitsfile *
-gal_fits_write_img_fitsptr(gal_data_t *data, char *filename);
+gal_fits_img_write_to_ptr(gal_data_t *data, char *filename);
 
 void
-gal_fits_write_img(gal_data_t *data, char *filename,
+gal_fits_img_write(gal_data_t *data, char *filename,
                    struct gal_fits_key_ll *headers, char *program_string);
 
 void
-gal_fits_write_img_wcs_string(gal_data_t *data, char *filename,
-                              char *wcsheader, int nkeyrec, double *crpix,
-                              struct gal_fits_key_ll *headers,
-                              char *program_string);
+gal_fits_img_write_corr_wcs_str(gal_data_t *data, char *filename,
+                                char *wcsheader, int nkeyrec, double *crpix,
+                                struct gal_fits_key_ll *headers,
+                                char *program_string);
 
 
 
@@ -241,22 +226,22 @@ gal_fits_write_img_wcs_string(gal_data_t *data, char 
*filename,
 /**********                  Table                 ************/
 /**************************************************************/
 void
-gal_fits_table_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols);
+gal_fits_tab_size(fitsfile *fitsptr, size_t *nrows, size_t *ncols);
 
 int
-gal_fits_table_type(fitsfile *fptr);
+gal_fits_tab_type(fitsfile *fptr);
 
 gal_data_t *
-gal_fits_table_info(char *filename, char *hdu, size_t *numcols,
+gal_fits_tab_info(char *filename, char *hdu, size_t *numcols,
                     size_t *numrows, int *tabletype);
 
 gal_data_t *
-gal_fits_table_read(char *filename, char *hdu, size_t numrows,
+gal_fits_tab_read(char *filename, char *hdu, size_t numrows,
                     gal_data_t *colinfo, struct gal_linkedlist_sll *indexll,
                     int minmapsize);
 
 void
-gal_fits_table_write(gal_data_t *cols, char *comments, int tabletype,
+gal_fits_tab_write(gal_data_t *cols, char *comments, int tabletype,
                      char *filename, int dontdelete);
 
 
diff --git a/lib/gnuastro/table.h b/lib/gnuastro/table.h
index ef06086..a5d95d8 100644
--- a/lib/gnuastro/table.h
+++ b/lib/gnuastro/table.h
@@ -59,7 +59,7 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 #define GAL_TABLE_DEF_STR_WIDTH       6
 #define GAL_TABLE_DEF_INT_WIDTH       6
 #define GAL_TABLE_DEF_LINT_WIDTH      10
-#define GAL_TABLE_DEF_FLT_WIDTH       12
+#define GAL_TABLE_DEF_FLT_WIDTH       13
 #define GAL_TABLE_DEF_DBL_WIDTH       18
 
 #define GAL_TABLE_DEF_INT_PRECISION   0
@@ -164,8 +164,6 @@ gal_table_write(gal_data_t *cols, char *comments, int 
tableformat,
 
 
 
-
-
 __END_C_DECLS    /* From C++ preparations */
 
 #endif           /* __GAL_TABLE_H__ */
diff --git a/lib/gnuastro/txt.h b/lib/gnuastro/txt.h
index 1f82e95..86a54a5 100644
--- a/lib/gnuastro/txt.h
+++ b/lib/gnuastro/txt.h
@@ -64,15 +64,23 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 #define GAL_TXT_MAX_FMT_LENGTH 20
 
 
+
+
+
 /* Status of a line: */
 enum gal_txt_line_status_enums
 {
+  GAL_TXT_LINESTAT_INVALID,
+
   GAL_TXT_LINESTAT_BLANK,
   GAL_TXT_LINESTAT_COMMENT,
   GAL_TXT_LINESTAT_DATAROW,
 };
 
 
+
+
+
 /* Functions */
 int
 gal_txt_line_stat(char *line);
@@ -82,13 +90,14 @@ gal_txt_table_info(char *filename, size_t *numcols, size_t 
*numrows);
 
 gal_data_t *
 gal_txt_table_read(char *filename, size_t numrows, gal_data_t *colinfo,
-                   struct gal_linkedlist_sll *indexll, int minmapsize);
-
-void
-gal_txt_table_write(gal_data_t *cols, char *comment, char *filename,
-                    int dontdelete);
+                   struct gal_linkedlist_sll *indexll, size_t minmapsize);
 
+gal_data_t *
+gal_txt_image_read(char *filename, size_t minmapsize);
 
+void
+gal_txt_write(gal_data_t *cols, char *comment, char *filename,
+              int dontdelete);
 
 
 
diff --git a/lib/gnuastro/wcs.h b/lib/gnuastro/wcs.h
index 9c8f6de..117df70 100644
--- a/lib/gnuastro/wcs.h
+++ b/lib/gnuastro/wcs.h
@@ -25,6 +25,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 /* Include other headers if necessary here. Note that other header files
    must be included before the C++ preparations below */
+#include <fitsio.h>
 #include <wcslib/wcs.h>
 
 
@@ -47,19 +48,32 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 __BEGIN_C_DECLS  /* From C++ preparations */
 
 
-double *
-gal_wcs_array_from_wcsprm(struct wcsprm *wcs);
 
+
+
+/*************************************************************
+ ***********               Read WCS                ***********
+ *************************************************************/
 void
-gal_wcs_decompose_pc_cdelt(struct wcsprm *wcs);
+gal_wcs_read_from_fitsptr(fitsfile *fptr, int *nwcs, struct wcsprm **wcs,
+                          size_t hstartwcs, size_t hendwcs);
 
 void
-gal_wcs_xy_array_to_radec(struct wcsprm *wcs, double *xy, double *radec,
-                          size_t number, size_t width);
+gal_wcs_read(char *filename, char *hdu, size_t hstartwcs,
+             size_t hendwcs, int *nwcs, struct wcsprm **wcs);
+
+
+
+
+
+/**************************************************************/
+/**********              Utilities                 ************/
+/**************************************************************/
+double *
+gal_wcs_array_from_wcsprm(struct wcsprm *wcs);
 
 void
-gal_wcs_world_to_img(struct wcsprm *wcs, double *ra, double *dec,
-                     double **x, double **y, size_t size);
+gal_wcs_decompose_pc_cdelt(struct wcsprm *wcs);
 
 double
 gal_wcs_angular_distance_deg(double r1, double d1, double r2, double d2);
@@ -72,6 +86,23 @@ gal_wcs_pixel_area_arcsec2(struct wcsprm *wcs);
 
 
 
+
+
+/**************************************************************/
+/**********              Conversion                ************/
+/**************************************************************/
+void
+gal_wcs_xy_array_to_radec(struct wcsprm *wcs, double *xy, double *radec,
+                          size_t number, size_t width);
+
+void
+gal_wcs_world_to_img(struct wcsprm *wcs, double *ra, double *dec,
+                     double **x, double **y, size_t size);
+
+
+
+
+
 __END_C_DECLS    /* From C++ preparations */
 
 #endif           /* __GAL_WCS_H__ */
diff --git a/lib/mesh.c b/lib/mesh.c
index 166c2a8..2fdf5b4 100644
--- a/lib/mesh.c
+++ b/lib/mesh.c
@@ -477,14 +477,14 @@ gal_mesh_value_file(struct gal_mesh_params *mp, char 
*filename,
       data.array=mp->fgarray1;
       data.dsize[0]=mp->gs0*mp->nch2;
       data.dsize[1]=mp->gs1*mp->nch1;
-      gal_fits_write_img(&data, filename, NULL, spack_string);
+      gal_fits_img_write(&data, filename, NULL, spack_string);
       if(mp->ngarrays==2)
         {
           /* Note that gal_mesh_full_garray will correct both the meshs if
              there are two.*/
           data.name=extname2;
           data.array=mp->fgarray2;
-          gal_fits_write_img(&data, filename, NULL, spack_string);
+          gal_fits_img_write(&data, filename, NULL, spack_string);
         }
     }
   else
@@ -495,12 +495,12 @@ gal_mesh_value_file(struct gal_mesh_params *mp, char 
*filename,
       data.name=extname1;
       data.dsize[0]=mp->s0;
       data.dsize[1]=mp->s1;
-      gal_fits_write_img(&data, filename, NULL, spack_string);
+      gal_fits_img_write(&data, filename, NULL, spack_string);
       if(mp->ngarrays==2)
         {
           data.array=tmp2;
           data.name=extname2;
-          gal_fits_write_img(&data, filename, NULL, spack_string);
+          gal_fits_img_write(&data, filename, NULL, spack_string);
         }
       free(tmp1);
       free(tmp2);
diff --git a/lib/table.c b/lib/table.c
index 9ed5e76..c81fff8 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -375,7 +375,7 @@ gal_table_col_print_info(gal_data_t *col, int tableformat, 
char *fmt,
         case GAL_TABLE_DISPLAY_FMT_GENERAL:
           fmt[0] = tableformat==GAL_TABLE_FORMAT_TXT ? 'g' : 'E'; break;
         default:
-          fmt[0] = tableformat==GAL_TABLE_FORMAT_TXT ? 'f' : 'F'; break;
+          fmt[0] = tableformat==GAL_TABLE_FORMAT_TXT ? 'g' : 'E'; break;
         }
       width = ( col->disp_width<=0
                 ? ( col->type==GAL_DATA_TYPE_FLOAT
@@ -473,7 +473,7 @@ gal_table_info(char *filename, char *hdu, size_t *numcols, 
size_t *numrows,
 {
   /* Get the table format and size (number of columns and rows). */
   if(gal_fits_name_is_fits(filename))
-    return gal_fits_table_info(filename, hdu, numcols, numrows, tableformat);
+    return gal_fits_tab_info(filename, hdu, numcols, numrows, tableformat);
   else
     {
       *tableformat=GAL_TABLE_FORMAT_TXT;
@@ -791,8 +791,8 @@ gal_table_read(char *filename, char *hdu, struct 
gal_linkedlist_stll *cols,
 
     case GAL_TABLE_FORMAT_AFITS:
     case GAL_TABLE_FORMAT_BFITS:
-      out=gal_fits_table_read(filename, hdu, numrows, allcols, indexll,
-                              minmapsize);
+      out=gal_fits_tab_read(filename, hdu, numrows, allcols, indexll,
+                            minmapsize);
       break;
 
     default:
@@ -846,11 +846,11 @@ gal_table_write(gal_data_t *cols, char *comments, int 
tableformat,
   if(filename)
     {
       if(gal_fits_name_is_fits(filename))
-        gal_fits_table_write(cols, comments, tableformat, filename,
-                             dontdelete);
+        gal_fits_tab_write(cols, comments, tableformat, filename,
+                           dontdelete);
       else
-        gal_txt_table_write(cols, comments, filename, dontdelete);
+        gal_txt_write(cols, comments, filename, dontdelete);
     }
   else
-    gal_txt_table_write(cols, comments, filename, dontdelete);
+    gal_txt_write(cols, comments, filename, dontdelete);
 }
diff --git a/lib/txt.c b/lib/txt.c
index 77f76a5..cb63681 100644
--- a/lib/txt.c
+++ b/lib/txt.c
@@ -47,6 +47,22 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /************************************************************************/
 /***************           Get table information          ***************/
 /************************************************************************/
+
+/* Format of table. Currently these constants are internal to this library,
+   we don't want to crowd the name space of the user by having them in the
+   header file. */
+enum txt_formats_code
+{
+    TXT_FORMAT_INVALID,
+
+    TXT_FORMAT_TABLE,
+    TXT_FORMAT_IMAGE,
+};
+
+
+
+
+
 /* Return one of the `txt_line_stat' constant values. */
 int
 gal_txt_line_stat(char *line)
@@ -102,7 +118,8 @@ txt_trim_space(char *str)
 
 
 
-/* Each column information comment should have a format like this:
+/* Each information comment should have a format like this (replace
+   `Column' with `Image' for 2D arrays):
 
       # Column N: NAME [UNITS, TYPE, BLANK] COMMENT
 
@@ -133,21 +150,22 @@ txt_trim_space(char *str)
   be before column 7.
 */
 static void
-txt_info_from_comment(char *line, gal_data_t **colsll)
+txt_info_from_comment(char *line, gal_data_t **datall, char *comm_start)
 {
   char *tailptr;
   gal_data_t *tmp;
   int index, strw=0;
-  int type=GAL_DATA_TYPE_DOUBLE; /* Default type. */
+  size_t len=strlen(comm_start);
+  int type=GAL_DATA_TYPE_DOUBLE;                     /* Default type. */
   char *number=NULL, *name=NULL, *comment=NULL;
   char *inbrackets=NULL, *unit=NULL, *typestr=NULL, *blank=NULL;
 
-  /* Only read this comment if it follows the convention: */
-  if( !strncmp(line, "# Column ", 9) )
+  /* Only read this comment line if it follows the convention: */
+  if( !strncmp(line, comm_start, len) )
     {
-      /* Set the name, inbrackets, and comments string in the first pass
-         through the line. */
-      number=line+9;
+      /* Set `name', `inbrackets', and `comment' in the first pass through
+         the line. */
+      number=line+len;
       while(*line!='\0')
         {
           switch(*line)
@@ -177,6 +195,8 @@ txt_info_from_comment(char *line, gal_data_t **colsll)
       index=strtol(number, &tailptr, 0);
       if(*tailptr!='\0' || index<=0) return;
 
+
+
       /* If there was no name (the line is just `# Column N:'), then ignore
          the line. Relying on the column count from the first line is more
          robust and less prone to human error, for example typing a number
@@ -185,7 +205,7 @@ txt_info_from_comment(char *line, gal_data_t **colsll)
       if(name==NULL) return;
 
       /* If this is a repeated index, ignore it. */
-      for(tmp=*colsll; tmp!=NULL; tmp=tmp->next)
+      for(tmp=*datall; tmp!=NULL; tmp=tmp->next)
         if(tmp->status==index)
           return;
 
@@ -234,18 +254,18 @@ txt_info_from_comment(char *line, gal_data_t **colsll)
          into the array by `gal_table_read_blank'. To keep the name, unit,
          and comment strings, trim the white space before and after each
          before using them here.  */
-      gal_data_add_to_ll(colsll, NULL, type, 0, NULL, NULL, 0, -1, name,
+      gal_data_add_to_ll(datall, NULL, type, 0, NULL, NULL, 0, -1, name,
                          txt_trim_space(unit), txt_trim_space(comment) );
 
       /* Put the number of this column into the status variable of the data
          structure. If the type is string, then also copy the width into
          the structure. */
-      (*colsll)->status=index;
-      (*colsll)->disp_width = type==GAL_DATA_TYPE_STRING ? strw : 0;
+      (*datall)->status=index;
+      (*datall)->disp_width = type==GAL_DATA_TYPE_STRING ? strw : 0;
 
       /* Write the blank value into the array. Note that this is not the
          final column, we are just collecting information now. */
-      gal_table_read_blank(*colsll, txt_trim_space(blank));
+      gal_table_read_blank(*datall, txt_trim_space(blank));
     }
 }
 
@@ -253,14 +273,19 @@ txt_info_from_comment(char *line, gal_data_t **colsll)
 
 
 
-/* The input ASCII table might not have had information in its comments, or
-   the information might not have been complete. So we need to go through
-   the first row of data also. */
-void
-txt_info_from_first_row(char *line, gal_data_t **colsll)
+/* In the case of a table, the input might not have had information in its
+   comments, or the information might not have been complete. So we need to
+   go through the first row of data also. In the case of the image, this is
+   necessary, because we need to find the second dimension value.
+
+   This function will return the number of tokens in the first row of the
+   given text file. If the file is a text table with string columns, the
+   contents of the string column will be counted as one token.*/
+static size_t
+txt_info_from_first_row(char *line, gal_data_t **datall, int format)
 {
-  size_t n=0, maxcnum=0;
   gal_data_t *col, *prev, *tmp;
+  size_t n=0, maxcnum=0, numtokens;
   char *token, *end=line+strlen(line);
 
   /* Remove the new line character from the end of the line. If the last
@@ -271,14 +296,21 @@ txt_info_from_first_row(char *line, gal_data_t **colsll)
 
   /* Get the maximum number of columns read from the comment
      information. */
-  for(col=*colsll; col!=NULL; col=col->next)
+  for(col=*datall; col!=NULL; col=col->next)
     maxcnum = maxcnum>col->status ? maxcnum : col->status;
 
   /* Go over the line check/fill the column information. */
   while(++n)
     {
-      /* Check if there is information for this column. */
-      for(col=*colsll; col!=NULL; col=col->next) if(col->status==n) break;
+      /* When we are dealing with a text table, check if there is
+         information for this column. For a text image, only the number of
+         tokens is important (as the second dimension of the image), so
+         just assume there no information. */
+      if(format==TXT_FORMAT_TABLE)
+        for(col=*datall; col!=NULL; col=col->next) {if(col->status==n) break;}
+      else
+        col=NULL;
+
 
       /* If there is information for this column, then check if it is a
          string, and if so, don't use `strtok_r' (because it might have
@@ -321,22 +353,44 @@ txt_info_from_first_row(char *line, gal_data_t **colsll)
           token=strtok_r(n==1?line:NULL, GAL_TXT_DELIMITERS, &line);
           if(token==NULL) break;
 
-          /* A token exists, so set this column to the default double type
-             with no information, then set its status value to the column
-             number. */
-          gal_data_add_to_ll(colsll, NULL, GAL_DATA_TYPE_DOUBLE, 0, NULL,
-                             NULL, 0, -1, NULL, NULL, NULL);
-          (*colsll)->status=n;
+          /* A token exists. For a table, define a new element in the
+             linked list and set the column to the default double type with
+             no information, then set its status value to the column
+             number. So, for a table, this should be done on every
+             column. But for an image, this should only be done once (when
+             `datall' has not been defined yet, for example in the column
+             information). */
+          if( *datall==NULL || format==TXT_FORMAT_TABLE )
+            {
+              gal_data_add_to_ll(datall, NULL, GAL_DATA_TYPE_DOUBLE, 0,
+                                 NULL, NULL, 0, -1, NULL, NULL, NULL);
+              (*datall)->status=n;
+            }
         }
     }
 
-  /* If the number of columns given by the comments is larger than the
-     actual number of lines, remove those that have larger numbers from the
-     linked list before things get complicated outside of this function. */
+
+  /* When looking at a text table, `n' is the number of columns (elements
+     in the linked list). But when looking at an image, it is the size of
+     the second dimension. To unify things from this step forwards, we will
+     thus keep the value of `n' until this point in another variable (that
+     will be returned finally), and for an image, change `n' to 1. This is
+     necsesary in case the user has for example given two column
+     information comments on an image plain text file.
+
+     Note that `n' counts from 1, so the total number of tokens is one less
+     than `n'.*/
+  numtokens=n-1;
+  if(format==TXT_FORMAT_IMAGE) n=1;
+
+  /* If the number of columns/images given by the comments is larger than
+     the actual number of lines, remove those that have larger numbers from
+     the linked list before things get complicated outside of this
+     function. */
   if(maxcnum>n)
     {
       prev=NULL;
-      col=*colsll;
+      col=*datall;
       while(col!=NULL)
         {
           if(col->status > n) /* Column has no data (was only in comments) */
@@ -354,7 +408,7 @@ txt_info_from_first_row(char *line, gal_data_t **colsll)
                   - When there actually was a previous element
                     (`prev!=NULL'), then we must correct it's next
                     pointer. Otherwise we will break up the chain.*/
-              if(prev) prev->next=col->next; else *colsll=col->next;
+              if(prev) prev->next=col->next; else *datall=col->next;
               tmp=col->next;
               gal_data_free(col);
               col=tmp;
@@ -366,6 +420,9 @@ txt_info_from_first_row(char *line, gal_data_t **colsll)
             }
         }
     }
+
+  /* Return the total number of columns/second-img-dimension. */
+  return numtokens;
 }
 
 
@@ -376,47 +433,68 @@ txt_info_from_first_row(char *line, gal_data_t **colsll)
    enforce minimum standard requirements on the user, things were allowed
    to be read very loosely, for example some columns can be not defined
    (and will thus be read as a double type), or they don't necessarily have
-   to be given in the same order as the table. So we just pushed each new
-   read/set column into a linked list. Now the job is done, and we want to
-   convert that linked list into an array of data structures for more
-   easier random access during the selection of the columns. */
+   to be given in the same order as the table (in which case, the first
+   non-commented line provides basic information like how many columns
+   there are). So we just pushed each new read/set column into a linked
+   list.
+
+   With this function, we convert that badly orderd linked list into a
+   clean and ordered array for much more easier random access during the
+   selection/reading of the data in the columns.
+
+   After this function, the list is freed. */
 static gal_data_t *
-txt_infoll_to_array(gal_data_t *colsll, size_t *numcols)
+txt_infoll_to_array(gal_data_t *datall, size_t *numdata)
 {
-  size_t numc=0;
-  gal_data_t *col, *allcols;
+  size_t numc=0, ind;
+  gal_data_t *data, *dataarr;
 
   /* First find the total number of columns. */
-  for(col=colsll;col!=NULL;col=col->next)
-    numc = numc > col->status ? numc : col->status;
-
-  /* Now, allocate the array and put in the values. */
-  allcols=gal_data_calloc_dataarray(numc);
-
-  /* Put each column into its proper place in the array. After the copy,
-     all the (possibly) allocated spaces in the linked list are set to
-     NULL, because we didn't initialize the array of column information in
-     the allocation above and we don't want to re-allocate everything
-     (because freeing the linked list will free them also). */
-  for(col=colsll;col!=NULL;col=col->next)
+  for(data=datall; data!=NULL; data=data->next) ++numc;
+
+  /* Conversion to an arry is only necessary when there is more than one
+     element in the list. */
+  if(numc>1)
     {
-      /* Note that the status value counts from 1. */
-      allcols[col->status-1].name       = col->name;     col->name=NULL;
-      allcols[col->status-1].unit       = col->unit;     col->unit=NULL;
-      allcols[col->status-1].array      = col->array;    col->array=NULL;
-      allcols[col->status-1].dsize      = col->dsize;    col->dsize=NULL;
-      allcols[col->status-1].comment    = col->comment;  col->comment=NULL;
-
-      allcols[col->status-1].type       = col->type;
-      allcols[col->status-1].ndim       = col->ndim;
-      allcols[col->status-1].size       = col->size;
-      allcols[col->status-1].disp_width = col->disp_width;
+      /* Now, allocate the array and put in the values. */
+      dataarr=gal_data_calloc_dataarray(numc);
+
+      /* Put each dataset/column into its proper place in the array.  */
+      while(datall!=NULL)
+        {
+          /* Pop the top element. */
+          data=gal_data_pop_from_ll(&datall);
+
+          /* The `status' value is the number of the column (counting from
+             1, not 0). */
+          ind=data->status-1;
+
+          /* Put all the information from `data' into the respective part
+             of the array. About the pointers, instead of having to
+             allocate them again, we will just set them to NULL so
+             `gal_data_free' doesn't remove them.*/
+          dataarr[ind].name       = data->name;    data->name=NULL;
+          dataarr[ind].unit       = data->unit;    data->unit=NULL;
+          dataarr[ind].array      = data->array;   data->array=NULL;
+          dataarr[ind].dsize      = data->dsize;   data->dsize=NULL;
+          dataarr[ind].comment    = data->comment; data->comment=NULL;
+
+          dataarr[ind].type       = data->type;
+          dataarr[ind].ndim       = data->ndim;
+          dataarr[ind].size       = data->size;
+          dataarr[ind].disp_width = data->disp_width;
+
+          /* Clean up. */
+          gal_data_free(data);
+        }
     }
+  else
+    dataarr=datall;
 
   /* Return the array of all column information and put the number of
      columns into the given pointer. */
-  *numcols=numc;
-  return allcols;
+  *numdata=numc;
+  return dataarr;
 }
 
 
@@ -425,22 +503,34 @@ txt_infoll_to_array(gal_data_t *colsll, size_t *numcols)
 
 /* Return the information about a text file table. If there were no
    readable rows, it will return NULL.*/
-gal_data_t *
-gal_txt_table_info(char *filename, size_t *numcols, size_t *numrows)
+static gal_data_t *
+txt_get_info(char *filename, int format, size_t *numdata, size_t *dsize)
 {
   FILE *fp;
-  char *line;
+  size_t numtokens;
   int firstlinedone=0;
-  gal_data_t *colsll=NULL, *allcols;
+  gal_data_t *datall=NULL, *dataarr;
+  char *line, *format_err, *comm_start;
   size_t linelen=10; /* `linelen' will be increased by `getline'. */
 
 
+  /* Set the constant strings */
+  switch(format)
+    {
+    case TXT_FORMAT_TABLE: format_err="table"; comm_start="# Column "; break;
+    case TXT_FORMAT_IMAGE: format_err="image"; comm_start="# Image ";  break;
+    default:
+      error(EXIT_FAILURE, 0, "code %d not recognized in `txt_get_info'",
+            format);
+    }
+
+
   /* Open the file. */
   errno=0;
   fp=fopen(filename, "r");
   if(fp==NULL)
-    error(EXIT_FAILURE, errno, "%s: could't open to read as a text table",
-          filename);
+    error(EXIT_FAILURE, errno, "%s: could't open to read as a plain text %s",
+          filename, format_err);
 
 
   /* Allocate the space necessary to keep each line as we parse it. Note
@@ -449,40 +539,42 @@ gal_txt_table_info(char *filename, size_t *numcols, 
size_t *numrows)
   errno=0;
   line=malloc(linelen*sizeof *line);
   if(line==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for line in `gal_txt_table_info'",
+    error(EXIT_FAILURE, errno, "%zu bytes for line in `txt_get_info'",
           linelen*sizeof *line);
 
 
   /* Read the comments of the line for possible information about the
-     lines, but also confirm the info by trying to read the first
+     lines, but also confirm/complete the info by parsing the first
      uncommented line. */
-  *numrows=0;
+  dsize[0]=0;
   while( getline(&line, &linelen, fp) != -1 )
     switch( gal_txt_line_stat(line) )
       {
-      case GAL_TXT_LINESTAT_COMMENT:
         /* Line is a comment, see if it has formatted information. */
-        txt_info_from_comment(line, &colsll);
+      case GAL_TXT_LINESTAT_COMMENT:
+        txt_info_from_comment(line, &datall, comm_start);
         break;
 
         /* Line is actual data, use it to fill in the gaps.  */
       case GAL_TXT_LINESTAT_DATAROW:
-        ++(*numrows);
+        ++dsize[0];
         if(firstlinedone==0)
           {
             firstlinedone=1;
-            txt_info_from_first_row(line, &colsll);
+            numtokens=txt_info_from_first_row(line, &datall, format);
+            if(format==TXT_FORMAT_IMAGE) dsize[1]=numtokens;
           }
         break;
 
-        /* We also have the case of GAL_TXT_LINESTAT_BLANK */
+        /* We also have the case of GAL_TXT_LINESTAT_BLANK.  */
       }
 
 
-  /* If there were rows in the file, then write the unorganized gathered
-     information (linked list) into an organized array for easy processing
-     by later steps.  */
-  allcols = *numrows ? txt_infoll_to_array(colsll, numcols) : NULL;
+  /* The final dataset linked list can have any order (depending on how the
+     user gave column information in tables for example). So here, we will
+     convert the list into a nicely sorted array, note that this function
+     frees list as part of the process. */
+  dataarr=txt_infoll_to_array(datall, numdata);
 
 
   /* Clean up. Note that even if there were no usable columns, there might
@@ -490,18 +582,39 @@ gal_txt_table_info(char *filename, size_t *numcols, 
size_t *numrows)
      case. If the list is indeed empty, then `gal_data_free_ll' won't do
      anything. */
   free(line);
-  gal_data_free_ll(colsll);
 
 
   /* Close the file. */
   errno=0;
   if(fclose(fp))
-    error(EXIT_FAILURE, errno, "%s: couldn't close file after reading ASCII "
-          "table information", filename);
+    error(EXIT_FAILURE, errno, "%s: couldn't close file after reading plain "
+          "text %s information", filename, format_err);
 
 
   /* Return the array of column information. */
-  return allcols;
+  return dataarr;
+}
+
+
+
+
+
+/* Get the information of each column in a text file */
+gal_data_t *
+gal_txt_table_info(char *filename, size_t *numcols, size_t *numrows)
+{
+  return txt_get_info(filename, TXT_FORMAT_TABLE, numcols, numrows);
+}
+
+
+
+
+
+/* Get the information of a 2D array in a text file. */
+gal_data_t *
+gal_txt_image_info(char *filename, size_t *numimg, size_t *dsize)
+{
+  return txt_get_info(filename, TXT_FORMAT_IMAGE, numimg, dsize);
 }
 
 
@@ -523,37 +636,142 @@ gal_txt_table_info(char *filename, size_t *numcols, 
size_t *numrows)
 
 
 
+
 /************************************************************************/
 /***************             Read a txt table             ***************/
 /************************************************************************/
 static void
-txt_fill_columns(char *line, char **tokens, size_t maxcolnum,
-                 gal_data_t *colinfo, gal_data_t *out, size_t rowind,
-                 size_t lineno, char *filename)
+txt_read_token(gal_data_t *data, gal_data_t *info, char *token,
+               size_t i, char *filename, size_t lineno, size_t colnum)
 {
-  size_t n=0;
+  char *tailptr;
+  char         **str=data->array, **strb;
+  unsigned char  *uc=data->array,   *ucb;
+  char            *c=data->array,    *cb;
+  unsigned short *us=data->array,   *usb;
+  short           *s=data->array,    *sb;
+  unsigned int   *ui=data->array,   *uib;
+  int            *ii=data->array,    *ib;
+  unsigned long  *ul=data->array,   *ulb;
+  long            *l=data->array,    *lb;
+  LONGLONG        *L=data->array,    *Lb;
+  float           *f=data->array,    *fb;
+  double          *d=data->array,    *db;
+
+  /* Read the proper token into the column. */
+  switch(data->type)
+    {
+    case GAL_DATA_TYPE_STRING:
+      gal_checkset_allocate_copy(txt_trim_space(token), &str[i]);
+      if( (strb=info->array) && !strcmp( *strb, str[i] ) )
+        {
+          free(str[i]);
+          gal_checkset_allocate_copy(GAL_DATA_BLANK_STRING, &str[i]);
+        }
+      break;
+
+    case GAL_DATA_TYPE_UCHAR:
+      uc[i]=strtol(token, &tailptr, 0);
+      if( (ucb=info->array) && *ucb==uc[i] )
+        uc[i]=GAL_DATA_BLANK_UCHAR;
+      break;
+
+    case GAL_DATA_TYPE_CHAR:
+      c[i]=strtol(token, &tailptr, 0);
+      if( (cb=info->array) && *cb==c[i] )
+        c[i]=GAL_DATA_BLANK_CHAR;
+      break;
+
+    case GAL_DATA_TYPE_USHORT:
+      us[i]=strtol(token, &tailptr, 0);
+      if( (usb=info->array) && *usb==us[i] )
+        us[i]=GAL_DATA_BLANK_USHORT;
+      break;
+
+    case GAL_DATA_TYPE_SHORT:
+      s[i]=strtol(token, &tailptr, 0);
+      if( (sb=info->array) && *sb==s[i] )
+        s[i]=GAL_DATA_BLANK_SHORT;
+      break;
+
+    case GAL_DATA_TYPE_UINT:
+      ui[i]=strtol(token, &tailptr, 0);
+      if( (uib=info->array) && *uib==ui[i] )
+        ui[i]=GAL_DATA_BLANK_UINT;
+      break;
+
+    case GAL_DATA_TYPE_INT:
+      ii[i]=strtol(token, &tailptr, 0);
+      if( (ib=info->array) && *ib==ii[i] )
+        ii[i]=GAL_DATA_BLANK_INT;
+      break;
+
+    case GAL_DATA_TYPE_ULONG:
+      ul[i]=strtoul(token, &tailptr, 0);
+      if( (ulb=info->array) && *ulb==ul[i] )
+        ul[i]=GAL_DATA_BLANK_ULONG;
+      break;
+
+    case GAL_DATA_TYPE_LONG:
+      l[i]=strtol(token, &tailptr, 0);
+      if( (lb=info->array) && *lb==l[i] )
+        l[i]=GAL_DATA_BLANK_LONG;
+      break;
+
+    case GAL_DATA_TYPE_LONGLONG:
+      L[i]=strtoll(token, &tailptr, 0);
+      if( (Lb=info->array) && *Lb==L[i] )
+        L[i]=GAL_DATA_BLANK_LONGLONG;
+      break;
+
+      /* For the blank value of floating point types, we need to make
+         sure it isn't a NaN, because a NaN value will fail on any
+         condition check (even `=='). If it isn't NaN, then we can
+         compare the values. */
+    case GAL_DATA_TYPE_FLOAT:
+      f[i]=strtod(token, &tailptr);
+      if( (fb=info->array)
+          && ( (isnan(*fb) && isnan(f[i])) || *fb==f[i] ) )
+        f[i]=GAL_DATA_BLANK_FLOAT;
+      break;
+
+    case GAL_DATA_TYPE_DOUBLE:
+      d[i]=strtod(token, &tailptr);
+      if( (db=info->array)
+          && ( (isnan(*db) && isnan(d[i])) || *db==d[i] ) )
+        d[i]=GAL_DATA_BLANK_DOUBLE;
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "type code %d not recognized in "
+            "`txt_fill_columns'", data->type);
+    }
+
+  /* If a number couldn't be read properly, then report an error. */
+  if(data->type!=GAL_DATA_TYPE_STRING && *tailptr!='\0')
+    error_at_line(EXIT_FAILURE, 0, filename, lineno, "column %zu "
+                  "(`%s') couldn't be read as a `%s' number",
+                  colnum, token, gal_data_type_as_string(data->type, 1) );
+}
+
+
+
+
+
+static void
+txt_fill(char *line, char **tokens, size_t maxcolnum, gal_data_t *info,
+         gal_data_t *out, size_t rowind, char *filename, size_t lineno)
+{
+  size_t i, n=0;
+  gal_data_t *data;
   int notenoughcols=0;
-  gal_data_t *col;
-  char *tailptr, *end=line+strlen(line);
-
-  char         **str, **strb;
-  unsigned char  *uc,   *ucb;
-  char            *c,    *cb;
-  unsigned short *us,   *usb;
-  short           *s,    *sb;
-  unsigned int   *ui,   *uib;
-  int             *i,    *ib;
-  unsigned long  *ul,   *ulb;
-  long            *l,    *lb;
-  LONGLONG        *L,    *Lb;
-  float           *f,    *fb;
-  double          *d,    *db;
+  char *end=line+strlen(line);
 
   /* See explanations in `txt_info_from_row'. */
   *(end-1)='\0';
 
   /* Start parsing the line. Note that `n' and `maxcolnum' start from
-     one. So we need column `maxcolnum'.*/
+     one. */
   while(++n)
     {
       /* Break out of the parsing if we don't need the columns any
@@ -563,7 +781,7 @@ txt_fill_columns(char *line, char **tokens, size_t 
maxcolnum,
 
       /* Set the pointer to the start of this token/column. See
          explanations in `txt_info_from_row'. */
-      if( colinfo[n-1].type == GAL_DATA_TYPE_STRING )
+      if( info[n-1].type == GAL_DATA_TYPE_STRING )
         {
           /* Remove any delimiters and stop at the first non-delimiter. If
              we have reached the end of the line then its an error, because
@@ -573,7 +791,7 @@ txt_fill_columns(char *line, char **tokens, size_t 
maxcolnum,
 
           /* Everything is good, set the pointer and increment the line to
              the end of the allocated space for this string. */
-          line = (tokens[n]=line) + colinfo[n-1].disp_width;
+          line = (tokens[n]=line) + info[n-1].disp_width;
           if(line<end) *line++='\0';
         }
       else
@@ -600,120 +818,25 @@ txt_fill_columns(char *line, char **tokens, size_t 
maxcolnum,
 
   /* Read the desired tokens into the columns that need them. Note that
      when a blank value is defined for the column, the column's array
-     pointer (`colinfo[col->status-1]') is not NULL and points to the blank
+     pointer (`info[col->status-1]') is not NULL and points to the blank
      value. For strings, this will actually be a string. */
-  for(col=out; col!=NULL; col=col->next)
+  switch(out->ndim)
     {
-      /* Read the proper token into the column. */
-      switch(col->type)
-        {
-        case GAL_DATA_TYPE_STRING:
-          str=col->array;
-          gal_checkset_allocate_copy(txt_trim_space(tokens[col->status]),
-                                     &str[rowind]);
-          if( (strb=colinfo[col->status-1].array)
-              && !strcmp( *strb, str[rowind] ) )
-            {
-              free(str[rowind]);
-              gal_checkset_allocate_copy(GAL_DATA_BLANK_STRING,
-                                         &str[rowind]);
-            }
-          break;
-
-        case GAL_DATA_TYPE_UCHAR:
-          uc=col->array;
-          uc[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (ucb=colinfo[col->status-1].array) && *ucb==uc[rowind] )
-            uc[rowind]=GAL_DATA_BLANK_UCHAR;
-          break;
-
-        case GAL_DATA_TYPE_CHAR:
-          c=col->array;
-          c[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (cb=colinfo[col->status-1].array) && *cb==c[rowind] )
-            c[rowind]=GAL_DATA_BLANK_CHAR;
-          break;
-
-        case GAL_DATA_TYPE_USHORT:
-          us=col->array;
-          us[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (usb=colinfo[col->status-1].array) && *usb==us[rowind] )
-            us[rowind]=GAL_DATA_BLANK_USHORT;
-          break;
-
-        case GAL_DATA_TYPE_SHORT:
-          s=col->array;
-          s[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (sb=colinfo[col->status-1].array) && *sb==s[rowind] )
-            s[rowind]=GAL_DATA_BLANK_SHORT;
-          break;
-
-        case GAL_DATA_TYPE_UINT:
-          ui=col->array;
-          ui[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (uib=colinfo[col->status-1].array) && *uib==ui[rowind] )
-            ui[rowind]=GAL_DATA_BLANK_UINT;
-          break;
-
-        case GAL_DATA_TYPE_INT:
-          i=col->array;
-          i[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (ib=colinfo[col->status-1].array) && *ib==i[rowind] )
-            i[rowind]=GAL_DATA_BLANK_INT;
-          break;
-
-        case GAL_DATA_TYPE_ULONG:
-          ul=col->array;
-          ul[rowind]=strtoul(tokens[col->status], &tailptr, 0);
-          if( (ulb=colinfo[col->status-1].array) && *ulb==ul[rowind] )
-            ul[rowind]=GAL_DATA_BLANK_ULONG;
-          break;
-
-        case GAL_DATA_TYPE_LONG:
-          l=col->array;
-          l[rowind]=strtol(tokens[col->status], &tailptr, 0);
-          if( (lb=colinfo[col->status-1].array) && *lb==l[rowind] )
-            l[rowind]=GAL_DATA_BLANK_LONG;
-          break;
-
-        case GAL_DATA_TYPE_LONGLONG:
-          L=col->array;
-          L[rowind]=strtoll(tokens[col->status], &tailptr, 0);
-          if( (Lb=colinfo[col->status-1].array) && *Lb==L[rowind] )
-            L[rowind]=GAL_DATA_BLANK_LONGLONG;
-          break;
-
-        /* For the blank value of floating point types, we need to make
-           sure it isn't a NaN, because a NaN value will fail on any
-           condition check (even `=='). If it isn't NaN, then we can
-           compare the values. */
-        case GAL_DATA_TYPE_FLOAT:
-          f=col->array;
-          f[rowind]=strtod(tokens[col->status], &tailptr);
-          if( (fb=colinfo[col->status-1].array)
-              && ( (isnan(*fb) && isnan(f[rowind])) || *fb==f[rowind] ) )
-            f[rowind]=GAL_DATA_BLANK_FLOAT;
-          break;
-
-        case GAL_DATA_TYPE_DOUBLE:
-          d=col->array;
-          d[rowind]=strtod(tokens[col->status], &tailptr);
-          if( (db=colinfo[col->status-1].array)
-              && ( (isnan(*db) && isnan(d[rowind])) || *db==d[rowind] ) )
-            d[rowind]=GAL_DATA_BLANK_DOUBLE;
-          break;
-
-        default:
-          error(EXIT_FAILURE, 0, "type code %d not recognized in "
-                "`txt_fill_columns'", col->type);
-        }
-
-      /* If a number couldn't be read properly, then report an error. */
-      if(col->type!=GAL_DATA_TYPE_STRING && *tailptr!='\0')
-        error_at_line(EXIT_FAILURE, 0, filename, lineno, "column %d "
-                      "(`%s') couldn't be read as a `%s' number",
-                      col->status, tokens[col->status],
-                      gal_data_type_as_string(col->type, 1) );
+    case 1:
+      for(data=out; data!=NULL; data=data->next)
+        txt_read_token(data, &info[data->status-1], tokens[data->status],
+                       rowind, filename, lineno, data->status);
+      break;
+
+    case 2:
+      for(i=0;i<out->dsize[1];++i)
+        txt_read_token(out, info, tokens[i+1], rowind * out->dsize[1] + i,
+                       filename, lineno, i+1);
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "`txt_fill' only works for 1 and 2 "
+            "dimensional datasets");
     }
 }
 
@@ -721,18 +844,17 @@ txt_fill_columns(char *line, char **tokens, size_t 
maxcolnum,
 
 
 
-gal_data_t *
-gal_txt_table_read(char *filename, size_t numrows, gal_data_t *colinfo,
-                   struct gal_linkedlist_sll *indexll, int minmapsize)
+static gal_data_t *
+gal_txt_read(char *filename, size_t *dsize, gal_data_t *info,
+             struct gal_linkedlist_sll *indexll, int minmapsize, int format)
 {
   FILE *fp;
   char *line;
-  size_t dsize;
   char **tokens;
   gal_data_t *out=NULL;
   struct gal_linkedlist_sll *ind;
-  size_t maxcolnum=0, rowind=0, lineno=0;
-  size_t linelen=10; /* `linelen' will be increased by `getline'. */
+  size_t maxcolnum=0, rowind=0, lineno=0, ndim;
+  size_t linelen=10;        /* `linelen' will be increased by `getline'. */
 
   /* Open the file. */
   errno=0;
@@ -741,7 +863,6 @@ gal_txt_table_read(char *filename, size_t numrows, 
gal_data_t *colinfo,
     error(EXIT_FAILURE, errno, "%s: could't open to read as a text table",
           filename);
 
-
   /* Allocate the space necessary to keep a copy of each line as we parse
      it. Note that `getline' is going to later `realloc' this space to fit
      the line length. */
@@ -751,19 +872,44 @@ gal_txt_table_read(char *filename, size_t numrows, 
gal_data_t *colinfo,
     error(EXIT_FAILURE, errno, "%zu bytes for `line' in `gal_txt_table_read'",
           linelen*sizeof *line);
 
-
   /* Allocate all the desired columns for output. We will be reading the
      text file line by line, and writing in the necessary values of each
      row individually. */
-  for(ind=indexll; ind!=NULL; ind=ind->next)
+  switch(format)
     {
-      dsize=numrows;
-      maxcolnum = maxcolnum>ind->v+1 ? maxcolnum : ind->v+1;
-      gal_data_add_to_ll(&out, NULL, colinfo[ind->v].type, 1, &dsize, NULL,
-                         0, minmapsize, colinfo[ind->v].name,
-                         colinfo[ind->v].unit, colinfo[ind->v].comment);
-      out->disp_width=colinfo[ind->v].disp_width;
-      out->status=ind->v+1;
+
+    /* This is a table. */
+    case TXT_FORMAT_TABLE:
+      for(ind=indexll; ind!=NULL; ind=ind->next)
+        {
+          ndim=1;
+          maxcolnum = maxcolnum>ind->v+1 ? maxcolnum : ind->v+1;
+          gal_data_add_to_ll(&out, NULL, info[ind->v].type, ndim, dsize,
+                             NULL, 0, minmapsize, info[ind->v].name,
+                             info[ind->v].unit, info[ind->v].comment);
+          out->disp_width=info[ind->v].disp_width;
+          out->status=ind->v+1;
+        }
+      break;
+
+
+    /* This is an image. */
+    case TXT_FORMAT_IMAGE:
+      if(info->next)
+        error(EXIT_FAILURE, 0, "currently reading only one image (2d "
+              "array) from a text file is possible, the `info' input to "
+              "`gal_txt_read' has more than one element");
+      ndim=2;
+      maxcolnum=dsize[1];
+      out=gal_data_alloc(NULL, info->type, ndim, dsize, NULL, 0, minmapsize,
+                         info->name, info->unit, info->comment);
+      break;
+
+
+    /* Not recognized. */
+    default:
+      error(EXIT_FAILURE, 0, "format code %d not recognized in "
+            "`gal_txt_read'", format);
     }
 
   /* Allocate the space to keep the pointers to each token in the
@@ -777,17 +923,15 @@ gal_txt_table_read(char *filename, size_t numrows, 
gal_data_t *colinfo,
     error(EXIT_FAILURE, errno, "%zu bytes for `tokens' in "
           "`gal_txt_table_read'", (maxcolnum+1)*sizeof *tokens);
 
-
   /* Read the data columns. */
   while( getline(&line, &linelen, fp) != -1 )
     {
       ++lineno;
       if( gal_txt_line_stat(line) == GAL_TXT_LINESTAT_DATAROW )
-        txt_fill_columns(line, tokens, maxcolnum, colinfo, out, rowind++,
-                         lineno, filename);
+        txt_fill(line, tokens, maxcolnum, info, out, rowind++,
+                 filename, lineno);
     }
 
-
   /* Clean up and close the file. */
   errno=0;
   if(fclose(fp))
@@ -804,6 +948,41 @@ gal_txt_table_read(char *filename, size_t numrows, 
gal_data_t *colinfo,
 
 
 
+gal_data_t *
+gal_txt_table_read(char *filename, size_t numrows, gal_data_t *colinfo,
+                   struct gal_linkedlist_sll *indexll, size_t minmapsize)
+{
+  return gal_txt_read(filename, &numrows, colinfo, indexll, minmapsize,
+                      TXT_FORMAT_TABLE);
+}
+
+
+
+
+
+gal_data_t *
+gal_txt_image_read(char *filename, size_t minmapsize)
+{
+  size_t numimg, dsize[2];
+  gal_data_t *img, *imginfo;
+  struct gal_linkedlist_sll *indexll=NULL;
+
+  /* Get the image information. */
+  imginfo=gal_txt_image_info(filename, &numimg, dsize);
+
+  /* Read the table. */
+  img=gal_txt_read(filename, dsize, imginfo, indexll, minmapsize,
+                   TXT_FORMAT_IMAGE);
+
+  /* Clean up and return. */
+  gal_data_free(imginfo);
+  return img;
+}
+
+
+
+
+
 
 
 
@@ -818,27 +997,33 @@ gal_txt_table_read(char *filename, size_t numrows, 
gal_data_t *colinfo,
 
 
 /************************************************************************/
-/***************          Write a txt table               ***************/
+/***************              Write to txt                ***************/
 /************************************************************************/
-/* Make an array of two strings for each column (in practice a two
-   dimensional array with 2 columns and a row for each input column). */
+/* Make an array of 3 strings for each column (in practice a two
+   dimensional array with 3 columns in a row for each input column). The
+   columns are:
+
+     Column 0: Printf format string.
+     Column 1: Gnuastro type string (in plain text format).
+     Column 2: Blank value string.
+*/
 #define FMTS_COLS 3
 static char **
-make_fmts_for_printf(gal_data_t *cols, size_t numcols, int leftadjust,
-                     size_t *len)
+make_fmts_for_printf(gal_data_t *datall, int leftadjust, size_t *len)
 {
-  size_t i=0;
   char **fmts;
-  gal_data_t *col;
+  gal_data_t *data;
+  size_t i=0, num=0;
   char fmt[2], lng[3];
 
 
   /* Allocate space for the output. */
+  for(data=datall;data!=NULL;data=data->next) ++num;
   errno=0;
-  fmts=malloc(FMTS_COLS*numcols*sizeof *fmts);
+  fmts=malloc(FMTS_COLS*num*sizeof *fmts);
   if(fmts==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for fmts in `gal_txt_write'",
-          FMTS_COLS*numcols*sizeof *fmts);
+    error(EXIT_FAILURE, errno, "%zu bytes for fmts in `make_fmts_for_printf'",
+          FMTS_COLS*num*sizeof *fmts);
 
 
   /* Initialize the length to 0. */
@@ -846,7 +1031,7 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, int 
leftadjust,
 
 
   /* Go over all the columns and make their formats. */
-  for(col=cols;col!=NULL;col=col->next)
+  for(data=datall;data!=NULL;data=data->next)
     {
       /* First allocate the necessary space to keep the string. */
       errno=0;
@@ -861,50 +1046,51 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, 
int leftadjust,
 
       /* If we have a blank value, get the blank value as a string and
          adjust the width */
-      if(gal_data_has_blank(col)==0)
+      if(gal_data_has_blank(data)==0)
         fmts[i*FMTS_COLS+2]=NULL;
       else
         {
           /* Set the blank value. */
-          if(col->type==GAL_DATA_TYPE_STRING)
+          if(data->type==GAL_DATA_TYPE_STRING)
             gal_checkset_allocate_copy(GAL_DATA_BLANK_STRING,
                                        &fmts[i*FMTS_COLS+2]);
           else
-            fmts[i*FMTS_COLS+2]=gal_data_blank_as_string(col->type, 0);
+            fmts[i*FMTS_COLS+2]=gal_data_blank_as_string(data->type, 0);
         }
 
 
       /* Fill in the printing paramters. */
-      gal_table_col_print_info(col, GAL_TABLE_FORMAT_TXT, fmt, lng);
+      gal_table_col_print_info(data, GAL_TABLE_FORMAT_TXT, fmt, lng);
 
 
       /* Adjust the width if a blank string was defined. */
       if(fmts[i*FMTS_COLS+2])
-        col->disp_width = ( strlen(fmts[i*FMTS_COLS+2]) > col->disp_width
-                            ? strlen(fmts[i*FMTS_COLS+2])
-                            : col->disp_width );
+        data->disp_width = ( strlen(fmts[i*FMTS_COLS+2]) > data->disp_width
+                             ? strlen(fmts[i*FMTS_COLS+2])
+                             : data->disp_width );
 
 
       /* Print the result into the allocated string and add its length to
          the final length of the overall format statement. The space in the
          end of `fmts[i*2]' is to ensure that the columns don't merge, even
          if the printed string is larger than the expected width. */
-      if(col->disp_precision > 0)
+      if(data->disp_precision > 0)
         *len += 1 + sprintf(fmts[i*FMTS_COLS], "%%%s%d.%d%s%s ",
-                            leftadjust ? "-" : "", col->disp_width,
-                            col->disp_precision, lng, fmt);
+                            leftadjust ? "-" : "", data->disp_width,
+                            data->disp_precision, lng, fmt);
       else
         *len += 1 + sprintf(fmts[i*FMTS_COLS], "%%%s%d%s%s ",
-                            leftadjust ? "-" : "", col->disp_width, lng, fmt);
+                            leftadjust ? "-" : "", data->disp_width,
+                            lng, fmt);
 
 
       /* Set the string for the Gnuastro type. For strings, we also need to
          write the maximum number of characters.*/
-      if(col->type==GAL_DATA_TYPE_STRING)
+      if(data->type==GAL_DATA_TYPE_STRING)
         sprintf(fmts[i*FMTS_COLS+1], "%s%d",
-                gal_data_type_as_string(col->type, 0), col->disp_width);
+                gal_data_type_as_string(data->type, 0), data->disp_width);
       else
-        strcpy(fmts[i*FMTS_COLS+1], gal_data_type_as_string(col->type, 0));
+        strcpy(fmts[i*FMTS_COLS+1], gal_data_type_as_string(data->type, 0));
 
 
       /* Increment the column counter. */
@@ -919,196 +1105,255 @@ make_fmts_for_printf(gal_data_t *cols, size_t numcols, 
int leftadjust,
 
 
 
-void
-gal_txt_table_write(gal_data_t *cols, char *comment, char *filename,
-                    int dontdelete)
+static void
+txt_print_value(FILE *fp, void *array, int type, size_t ind, char *fmt)
+{
+  switch(type)
+    {
+      /* Numerical types. */
+    case GAL_DATA_TYPE_UCHAR:
+      fprintf(fp, fmt, ((unsigned char *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_CHAR:
+    case GAL_DATA_TYPE_LOGICAL:
+      fprintf(fp, fmt, ((char *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_USHORT:
+      fprintf(fp, fmt, ((unsigned short *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_SHORT:
+      fprintf(fp, fmt, ((short *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_UINT:
+      fprintf(fp, fmt, ((unsigned int *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_INT:
+      fprintf(fp, fmt, ((int *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_ULONG:
+      fprintf(fp, fmt, ((unsigned long *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_LONG:
+      fprintf(fp, fmt, ((long *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_LONGLONG:
+      fprintf(fp, fmt, ((LONGLONG *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_FLOAT:
+      fprintf(fp, fmt, ((float *)array)[ind]);
+      break;
+
+    case GAL_DATA_TYPE_DOUBLE:
+      fprintf(fp, fmt, ((double *)array)[ind]);
+      break;
+
+      /* Special consideration for strings. */
+    case GAL_DATA_TYPE_STRING:
+      if( !strcmp( ((char **)array)[ind], GAL_DATA_BLANK_STRING ) )
+        fprintf(fp, fmt, GAL_DATA_BLANK_STRING);
+      else
+        fprintf(fp, fmt, ((char **)array)[ind]);
+      break;
+
+    default:
+      error(EXIT_FAILURE, 0, "type code %d not recognized for "
+            "col->type in `txt_print_value'", type);
+    }
+}
+
+
+
+
+
+static FILE *
+txt_open_file_write_info(gal_data_t *datall, char **fmts, char *comment,
+                         char *filename, int dontdelete)
 {
   FILE *fp;
-  char *nstr;
-  gal_data_t *col;
-  char **fmts, *tmp;
-  size_t i, j, numcols=0, fmtlen;
+  gal_data_t *data;
+  char *tmp, *nstr;
+  size_t i, j, num=0;
   int nlen, nw=0, uw=0, tw=0, bw=0;
 
+  /* Check the file and open it. */
+  gal_checkset_check_remove_file(filename, dontdelete);
+  errno=0;
+  fp=fopen(filename, "w");
+  if(fp==NULL)
+    error(EXIT_FAILURE, errno, "%s: couldn't be open to write text "
+          "table", filename);
 
-  /* Find the number of columns, do a small sanity check, and get the
-     maximum width of the name and unit string if they are present. */
-  for(col=cols;col!=NULL;col=col->next)
-    {
-      /* Count. */
-      ++numcols;
-
-      /* Make sure the columns are 1 dimensional. */
-      if(cols->ndim!=1)
-        error(EXIT_FAILURE, 0, "columns to print as an ASCII file must have "
-              "only one dimension. column %zu of the given set has %zu "
-              "dimensions", numcols, cols->ndim);
-
-      /* Make sure sizes match. */
-      if(cols->size!=col->size)
-        error(EXIT_FAILURE, 0, "to print a set of columns, as an ASCII "
-              "table, they must currently all have the same number of "
-              "elements/rows. The inputs to `gal_txt_write' have different "
-              "sizes: the first column has %zu, while column %zu as %zu "
-              "elements", cols->size, numcols, col->size);
-      if( col->name && strlen(col->name)>nw ) nw=strlen(col->name);
-      if( col->unit && strlen(col->unit)>uw ) uw=strlen(col->unit);
-    }
 
+  /* Write the comments if there were any. */
+  if(comment) fprintf(fp, "%s\n", comment);
 
-  /* Prepare the necessary formats for each column, then allocate the space
-     for the full list and concatenate all the separate inputs into it. */
-  fmts=make_fmts_for_printf(cols, numcols, 1, &fmtlen);
-  for(i=0;i<numcols;++i)
+
+  /* Get the maximum width for each information field. */
+  for(data=datall;data!=NULL;data=data->next)
     {
-      if( (tmp=fmts[ i*FMTS_COLS+1 ]) )
+      ++num;
+      if( data->name && strlen(data->name)>nw ) nw=strlen(data->name);
+      if( data->unit && strlen(data->unit)>uw ) uw=strlen(data->unit);
+    }
+  for(i=0;i<num;++i)
+    {
+      if( (tmp=fmts[ i*FMTS_COLS+1 ]) )            /* If it isn't NULL. */
         tw = strlen(tmp) > tw ? strlen(tmp) : tw;
-      if( (tmp=fmts[ i*FMTS_COLS+2 ]) )
+      if( (tmp=fmts[ i*FMTS_COLS+2 ]) )            /* If it isn't NULL. */
         bw = strlen(tmp) > bw ? strlen(tmp) : bw;
     }
 
 
-  /* Set the output FILE pointer: if it isn't NULL, its an actual file,
-     otherwise, its the standard output. */
-  if(filename)
+  /* Write the column information if the output is a file. When the
+     output is directed to standard output (the command-line), it is
+     most probably intended for piping into another program (for
+     example AWK for further processing, or sort, or anything) so the
+     user already has the column information and is probably going to
+     change them, so they are just a nuisance.
+
+     When there are more than 9 columns, we don't want to have cases
+     like `# Column 1 :' (note the space between `1' and `:', this
+     space won't exist for the 2 digit colum numbers).
+
+     To do this, we are first allocating and printing a string long
+     enough to keep the final column's `N:'. Then, for each column, we
+     print only the number into the allocated space and put the `:' in
+     manually immediately after the number. Note that the initial
+     `asprintf' put a `\0' in the allocated space, so we can safely
+     over-write the one that `sprintf' puts with a `:' for the columns
+     that have the same number of digits as the final column. */
+  i=0;
+  asprintf(&nstr, "%zu:", num);
+  nlen=strlen(nstr);
+  for(data=datall; data!=NULL; data=data->next)
     {
-      gal_checkset_check_remove_file(filename, dontdelete);
-      errno=0;
-      fp=fopen(filename, "w");
-      if(fp==NULL)
-        error(EXIT_FAILURE, errno, "%s: couldn't be open to write text "
-              "table", filename);
-
-
-      /* Write the comments if there were any. */
-      if(comment) fprintf(fp, "%s\n", comment);
-
-
-      /* Write the column information if the output is a file. When the
-         output is directed to standard output (the command-line), it is
-         most probably intended for piping into another program (for
-         example AWK for further processing, or sort, or anything) so the
-         user already has the column information and is probably going to
-         change them, so they are just a nuisance.
-
-         When there are more than 9 columns, we don't want to have cases
-         like `# Column 1 :' (note the space between `1' and `:', this
-         space won't exist for the 2 digit colum numbers).
-
-         To do this, we are first allocating and printing a string long
-         enough to keep the final column's `N:'. Then, for each column, we
-         print only the number into the allocated space and put the `:' in
-         manually immediately after the number. Note that the initial
-         `asprintf' put a `\0' in the allocated space, so we can safely
-         over-write the one that `sprintf' puts with a `:' for the columns
-         that have the same number of digits as the final column. */
-      i=0;
-      asprintf(&nstr, "%zu:", numcols);
-      nlen=strlen(nstr);
-      for(col=cols; col!=NULL; col=col->next)
-        {
-          /* Print the number into the number string, then add the `:'
-             immediately after the number. */
-          sprintf(nstr, "%zu", i+1);
-          for(j=1;j<nlen;++j)
-            if(!isdigit(nstr[j])) nstr[j] = isdigit(nstr[j-1]) ? ':' : ' ';
-
-          /* Now print the full column information. */
-          fprintf(fp, "# Column %s %-*s [%-*s,%-*s,%-*s] %s\n",
-                  nstr,
-                  nw, col->name    ? col->name    : "",
-                  uw, col->unit    ? col->unit    : "",
-                  tw, fmts[i*FMTS_COLS+1] ? fmts[i*FMTS_COLS+1] : "",
-                  bw, fmts[i*FMTS_COLS+2] ? fmts[i*FMTS_COLS+2] : "",
-                  col->comment ? col->comment : "");
-          ++i;
-        }
+      /* Print the number into the number string, then add the `:'
+         immediately after the number. */
+      sprintf(nstr, "%zu", i+1);
+      for(j=1;j<nlen;++j)
+        if(!isdigit(nstr[j])) nstr[j] = isdigit(nstr[j-1]) ? ':' : ' ';
+
+      /* Now print the full information. */
+      fprintf(fp, "# %s %s %-*s [%-*s,%-*s,%-*s] %s\n",
+              datall->ndim==1 ? "Column" : "Image", nstr,
+              nw, data->name ? data->name    : "",
+              uw, data->unit ? data->unit    : "",
+              tw, fmts[i*FMTS_COLS+1] ? fmts[i*FMTS_COLS+1] : "",
+              bw, fmts[i*FMTS_COLS+2] ? fmts[i*FMTS_COLS+2] : "",
+              data->comment ? data->comment : "");
+      ++i;
+    }
 
 
-      /* Clean up */
-      free(nstr);
-    }
-  else      /* Output wasn't a file, so set it to standard output */
-    fp=stdout;
+  /* Clean up and return. */
+  free(nstr);
+  return fp;
+}
 
 
-  /* Print the output */
-  for(i=0;i<cols->size;++i)                   /* Loop over each row.    */
-    {
-      j=0;
-      for(col=cols;col!=NULL;col=col->next)   /* Loop over each column. */
-        {
-          switch(col->type)
-            {
 
-            /* Numerical types. */
-            case GAL_DATA_TYPE_UCHAR:
-              fprintf(fp, fmts[j*FMTS_COLS],
-                      ((unsigned char *)col->array)[i]);
-              break;
 
-            case GAL_DATA_TYPE_CHAR:
-            case GAL_DATA_TYPE_LOGICAL:
-              fprintf(fp, fmts[j*FMTS_COLS], ((char *)col->array)[i]);
-              break;
 
-            case GAL_DATA_TYPE_USHORT:
-              fprintf(fp, fmts[j*FMTS_COLS],
-                      ((unsigned short *)col->array)[i]);
-              break;
-            case GAL_DATA_TYPE_SHORT:
-              fprintf(fp, fmts[j*FMTS_COLS], ((short *)col->array)[i]);
-              break;
+void
+gal_txt_write(gal_data_t *datall, char *comment, char *filename,
+              int dontdelete)
+{
+  FILE *fp;
+  char **fmts;
+  gal_data_t *data, *next2d;
+  size_t i, j, num=0, fmtlen;
 
-            case GAL_DATA_TYPE_UINT:
-              fprintf(fp, fmts[j*FMTS_COLS], ((unsigned int *)col->array)[i]);
-              break;
 
-            case GAL_DATA_TYPE_INT:
-              fprintf(fp, fmts[j*FMTS_COLS], ((int *)col->array)[i]);
-              break;
+  /* Currently only 1 and 2 dimension datasets are acceptable. */
+  if( datall->ndim!=1 && datall->ndim!=2 )
+    error(EXIT_FAILURE, 0, "currently `gal_txt_write' only supports 1 and "
+          "2 dimensional datasets. The input dataset has %zu dimensions",
+          datall->ndim);
 
-            case GAL_DATA_TYPE_ULONG:
-              fprintf(fp, fmts[j*FMTS_COLS],
-                      ((unsigned long *)col->array)[i]);
-              break;
 
-            case GAL_DATA_TYPE_LONG:
-              fprintf(fp, fmts[j*FMTS_COLS], ((long *)col->array)[i]);
-              break;
+  /* For a 2D dataset, we currently don't accept a list, we can only print
+     one column. So keep the next pointer separately and restore it after
+     the job of this function is finished. */
+  if(datall->ndim==2)
+    {
+      next2d=datall->next;
+      datall->next=NULL;
+    }
 
-            case GAL_DATA_TYPE_LONGLONG:
-              fprintf(fp, fmts[j*FMTS_COLS], ((LONGLONG *)col->array)[i]);
-              break;
 
-            case GAL_DATA_TYPE_FLOAT:
-              fprintf(fp, fmts[j*FMTS_COLS], ((float *)col->array)[i]);
-              break;
+  /* Find the number of columns, do a small sanity check, and get the
+     maximum width of the name and unit string if they are present. */
+  for(data=datall;data!=NULL;data=data->next)
+    {
+      /* Count. */
+      ++num;
+
+      /* Check if the dimensionality and size is the same for all the
+         elements. */
+      if( datall!=data && gal_data_dsize_is_different(datall, data) )
+        error(EXIT_FAILURE, 0, "the input list of datasets to "
+              "`gal_txt_write' must have the same sizes (dimentionality "
+              "and length along each dimension).");
+    }
 
-            case GAL_DATA_TYPE_DOUBLE:
-              fprintf(fp, fmts[j*FMTS_COLS], ((double *)col->array)[i]);
-              break;
 
-            /* Special consideration for strings. */
-            case GAL_DATA_TYPE_STRING:
-              if( !strcmp( ((char **)col->array)[i], GAL_DATA_BLANK_STRING ) )
-                fprintf(fp, "%-*s ", col->disp_width, GAL_DATA_BLANK_STRING);
-              else
-                fprintf(fp, fmts[j*FMTS_COLS], ((char **)col->array)[i]);
-              break;
+  /* Prepare the necessary formats for each column, then allocate the space
+     for the full list and concatenate all the separate inputs into it. */
+  fmts=make_fmts_for_printf(datall, 1, &fmtlen);
 
-            default:
-              error(EXIT_FAILURE, 0, "type code %d not recognized for "
-                    "col->type in `gal_txt_write'", col->type);
-            }
-          ++j;
+
+  /* Set the output FILE pointer: if it isn't NULL, its an actual file,
+     otherwise, its the standard output. */
+  fp = ( filename
+         ? txt_open_file_write_info(datall, fmts, comment, filename,
+                                    dontdelete)
+         : stdout );
+
+
+  /* Print the dataset */
+  switch(datall->ndim)
+    {
+    case 1:
+      for(i=0;i<datall->size;++i)                        /* Row.    */
+        {
+          j=0;
+          for(data=datall;data!=NULL;data=data->next)    /* Column. */
+            txt_print_value(fp, data->array, data->type, i,
+                            fmts[j++ * FMTS_COLS]);
+          fprintf(fp, "\n");
         }
-      fprintf(fp, "\n");
+      break;
+
+
+    case 2:
+      for(i=0;i<datall->dsize[0];++i)
+        {
+          for(j=0;j<datall->dsize[1];++j)
+            txt_print_value(fp, datall->array, datall->type,
+                            i*datall->dsize[1]+j, fmts[0]);
+          fprintf(fp, "\n");
+        }
+      break;
+
+
+    default:
+      error(EXIT_FAILURE, 0, "a bug! datall->ndim=%zu is not recognized "
+            "in `gal_txt_write'", datall->ndim);
     }
 
 
+
   /* Clean up. */
-  for(i=0;i<numcols;++i)
+  for(i=0;i<num;++i)
     {
       free(fmts[i*FMTS_COLS]);
       free(fmts[i*FMTS_COLS+1]);
@@ -1125,4 +1370,7 @@ gal_txt_table_write(gal_data_t *cols, char *comment, char 
*filename,
         error(EXIT_FAILURE, errno, "%s: couldn't close file after writing "
               "of text table", filename);
     }
+
+  /* Restore the next pointer for a 2D dataset. */
+  if(datall->ndim==2) datall->next=next2d;
 }
diff --git a/lib/wcs.c b/lib/wcs.c
index bf899bf..cf8f615 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -38,6 +38,149 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 
 
 
+
+
+
+
+
+/*************************************************************
+ ***********               Read WCS                ***********
+ *************************************************************/
+/* Read the WCS information from the header. Unfortunately, WCS lib is
+   not thread safe, so it needs a mutex. In case you are not using
+   multiple threads, just pass a NULL pointer as the mutex.
+
+   After you finish with this WCS, you should free the space with:
+
+   status = wcsvfree(&nwcs,&wcs);
+
+   If the WCS structure is not recognized, then this function will
+   return a NULL pointer for the wcsprm structure and a zero for
+   nwcs. It will also report the fact to the user in stderr.
+
+   ===================================
+   WARNING: wcspih IS NOT THREAD SAFE!
+   ===================================
+   Don't call this function within a thread or use a mutex.
+*/
+void
+gal_wcs_read_from_fitsptr(fitsfile *fptr, int *nwcs, struct wcsprm **wcs,
+                          size_t hstartwcs, size_t hendwcs)
+{
+  /* Declaratins: */
+  int nkeys=0, status=0;
+  char *fullheader, *to, *from;
+  int relax    = WCSHDR_all; /* Macro: use all informal WCS extensions. */
+  int ctrl     = 0;          /* Don't report why a keyword wasn't used. */
+  int nreject  = 0;          /* Number of keywords rejected for syntax. */
+
+  /* CFITSIO function: */
+  if( fits_hdr2str(fptr, 1, NULL, 0, &fullheader, &nkeys, &status) )
+    gal_fits_io_error(status, NULL);
+
+  /* Only consider the header keywords in the current range: */
+  if(hendwcs>hstartwcs)
+    {
+      /* Mark the last character in the desired region. */
+      fullheader[hendwcs*(FLEN_CARD-1)]='\0';
+      /*******************************************************/
+      /******************************************************
+      printf("%s\n", fullheader);
+      ******************************************************/
+      /*******************************************************/
+
+      /* Shift all the characters to the start of the string. */
+      if(hstartwcs)                /* hstartwcs!=0 */
+        {
+          to=fullheader;
+          from=&fullheader[hstartwcs*(FLEN_CARD-1)-1];
+          while(*from++!='\0') *to++=*from;
+        }
+
+      nkeys=hendwcs-hstartwcs;
+
+      /*******************************************************/
+      /******************************************************
+      printf("\n\n\n###############\n\n\n\n\n\n");
+      printf("%s\n", &fullheader[1*(FLEN_CARD-1)]);
+      exit(0);
+      ******************************************************/
+      /*******************************************************/
+    }
+
+  /* WCSlib function */
+  status=wcspih(fullheader, nkeys, relax, ctrl, &nreject, nwcs, wcs);
+  if(status)
+    {
+      fprintf(stderr, "\n##################\n"
+              "WCSLIB Warning: wcspih ERROR %d: %s.\n"
+              "##################\n",
+              status, wcs_errmsg[status]);
+      *wcs=NULL; *nwcs=0;
+    }
+  if (fits_free_memory(fullheader, &status) )
+    gal_fits_io_error(status, "problem in fitsarrayvv.c for freeing "
+                           "the memory used to keep all the headers");
+
+  /* Set the internal structure: */
+  status=wcsset(*wcs);
+  if(status)
+    {
+      fprintf(stderr, "\n##################\n"
+              "WCSLIB Warning: wcsset ERROR %d: %s.\n"
+              "##################\n",
+            status, wcs_errmsg[status]);
+      *wcs=NULL; *nwcs=0;
+    }
+
+  /* Initialize the wcsprm struct
+  if ((status = wcsset(*wcs)))
+    error(EXIT_FAILURE, 0, "wcsset ERROR %d: %s.\n", status,
+          wcs_errmsg[status]);
+  */
+}
+
+
+
+
+
+void
+gal_wcs_read(char *filename, char *hdu, size_t hstartwcs,
+             size_t hendwcs, int *nwcs, struct wcsprm **wcs)
+{
+  int status=0;
+  fitsfile *fptr;
+
+  /* Check HDU for realistic conditions: */
+  fptr=gal_fits_hdu_open(filename, hdu, 0);
+
+  /* Read the WCS information: */
+  gal_wcs_read_from_fitsptr(fptr, nwcs, wcs, hstartwcs, hendwcs);
+
+  /* Close the FITS file: */
+  fits_close_file(fptr, &status);
+  gal_fits_io_error(status, NULL);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**************************************************************/
 /**********              Utilities                 ************/
 /**************************************************************/
@@ -138,6 +281,110 @@ gal_wcs_decompose_pc_cdelt(struct wcsprm *wcs)
 
 
 
+/* The distance (along a great circle) on a sphere between two points
+   is calculated here. Since the pixel sides are usually very small,
+   we won't be using the direct formula:
+
+   cos(distance)=sin(d1)*sin(d2)+cos(d1)*cos(d2)*cos(r1-r2)
+
+   We will be using the haversine formula which better considering
+   floating point errors (from Wikipedia:)
+
+   sin^2(distance)/2=sin^2( (d1-d2)/2 )+cos(d1)*cos(d2)*sin^2( (r1-r2)/2 )
+
+   Inputs and outputs are all in degrees.
+*/
+double
+gal_wcs_angular_distance_deg(double r1, double d1, double r2, double d2)
+{
+  /* Convert degrees to radians. */
+  double r1r=r1*M_PI/180, d1r=d1*M_PI/180;
+  double r2r=r2*M_PI/180, d2r=d2*M_PI/180;
+
+  /* To make things easier to read: */
+  double a=sin( (d1r-d2r)/2 );
+  double b=sin( (r1r-r2r)/2 );
+
+  /* Return the result: */
+  return 2*asin( sqrt( a*a + cos(d1r)*cos(d2r)*b*b) ) * 180/M_PI;
+}
+
+
+
+
+/* Return the pixel scale of the image in both dimentions in degrees. */
+double *
+gal_wcs_pixel_scale_deg(struct wcsprm *wcs)
+{
+  gsl_vector S;
+  gsl_matrix A, V;
+  size_t n=wcs->naxis;
+  double *a, *v, *pixscale;
+
+  /* Allocate space for the `v' and `pixscale' arrays. */
+  errno=0; v=malloc(n*n*sizeof *v);
+  if(v==NULL)
+    error(EXIT_FAILURE, errno, "%zu bytes for `v' in "
+          "`gal_wcs_pixel_scale_deg'", n*n*sizeof *v);
+  errno=0; pixscale=malloc(n*sizeof *pixscale);
+  if(pixscale==NULL)
+    error(EXIT_FAILURE, errno, "%zu bytes for `pixscale' in "
+          "`gal_wcs_pixel_scale_deg'", n*sizeof *pixscale);
+
+  /* Write the full matrix into an array, irrespective of what type it was
+     stored in the wcsprm structure (`PCi_j' style or `CDi_j' style). */
+  a=gal_wcs_array_from_wcsprm(wcs);
+
+  /* Fill in the necessary GSL vector and Matrix structures. */
+  S.size=n;     S.stride=1;                S.data=pixscale;
+  V.size1=n;    V.size2=n;    V.tda=n;     V.data=v;
+  A.size1=n;    A.size2=n;    A.tda=n;     A.data=a;
+
+  /* Run GSL's Singular Value Decomposition, using one-sided Jacobi
+     orthogonalization which computes the singular (scale) values to a
+     higher relative accuracy.*/
+  gsl_linalg_SV_decomp_jacobi(&A, &V, &S);
+
+  /* Clean up and return. */
+  free(a);
+  free(v);
+  return pixscale;
+}
+
+
+
+
+
+/* Report the arcsec^2 area of the pixels in the image based on the
+   WCS information in that image. We first use the angular distance of
+   two edges of one pixel in radians. Then the radians are multiplied
+   to give stradians and finally, the stradians are converted to
+   arcsec^2. */
+double
+gal_wcs_pixel_area_arcsec2(struct wcsprm *wcs)
+{
+  double out;
+  double *pixscale;
+
+  /* A small sanity check. Later, when higher dimensions are necessary, we
+     can find which ones correlate to RA and Dec and use them to find the
+     pixel area in arcsec^2. */
+  if(wcs->naxis!=2)
+    error(EXIT_FAILURE, 0, "`gal_wcs_pixel_area_arcsec2' can currently "
+          "calculate the area only when the image has 2 dimensions.");
+
+  /* Get the pixel scales along each axis in degrees, then multiply. */
+  pixscale=gal_wcs_pixel_scale_deg(wcs);
+
+  /* Clean up and return the result. */
+  out = pixscale[0] * pixscale[1] * 3600.0f * 3600.0f;
+  free(pixscale);
+  return out;
+}
+
+
+
+
 
 
 
@@ -154,7 +401,7 @@ gal_wcs_decompose_pc_cdelt(struct wcsprm *wcs)
 
 
 /**************************************************************/
-/**********              XY to RADEC               ************/
+/**********              Conversion                ************/
 /**************************************************************/
 /* Use the X and Y columns in a larger array to fill the RA and Dec columns
    in that same array. `xy' points to the first element in the X column and
@@ -254,108 +501,3 @@ gal_wcs_world_to_img(struct wcsprm *wcs, double *ra, 
double *dec,
   free(world);
   free(pixcrd);
 }
-
-
-
-
-
-/* The distance (along a great circle) on a sphere between two points
-   is calculated here. Since the pixel sides are usually very small,
-   we won't be using the direct formula:
-
-   cos(distance)=sin(d1)*sin(d2)+cos(d1)*cos(d2)*cos(r1-r2)
-
-   We will be using the haversine formula which better considering
-   floating point errors (from Wikipedia:)
-
-   sin^2(distance)/2=sin^2( (d1-d2)/2 )+cos(d1)*cos(d2)*sin^2( (r1-r2)/2 )
-
-   Inputs and outputs are all in degrees.
-*/
-double
-gal_wcs_angular_distance_deg(double r1, double d1, double r2, double d2)
-{
-  /* Convert degrees to radians. */
-  double r1r=r1*M_PI/180, d1r=d1*M_PI/180;
-  double r2r=r2*M_PI/180, d2r=d2*M_PI/180;
-
-  /* To make things easier to read: */
-  double a=sin( (d1r-d2r)/2 );
-  double b=sin( (r1r-r2r)/2 );
-
-  /* Return the result: */
-  return 2*asin( sqrt( a*a + cos(d1r)*cos(d2r)*b*b) ) * 180/M_PI;
-}
-
-
-
-
-/* Return the pixel scale of the image in both dimentions in degrees. */
-double *
-gal_wcs_pixel_scale_deg(struct wcsprm *wcs)
-{
-  gsl_vector S;
-  gsl_matrix A, V;
-  size_t n=wcs->naxis;
-  double *a, *v, *pixscale;
-
-  /* Allocate space for the `v' and `pixscale' arrays. */
-  errno=0; v=malloc(n*n*sizeof *v);
-  if(v==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for `v' in "
-          "`gal_wcs_pixel_scale_deg'", n*n*sizeof *v);
-  errno=0; pixscale=malloc(n*sizeof *pixscale);
-  if(pixscale==NULL)
-    error(EXIT_FAILURE, errno, "%zu bytes for `pixscale' in "
-          "`gal_wcs_pixel_scale_deg'", n*sizeof *pixscale);
-
-  /* Write the full matrix into an array, irrespective of what type it was
-     stored in the wcsprm structure (`PCi_j' style or `CDi_j' style). */
-  a=gal_wcs_array_from_wcsprm(wcs);
-
-  /* Fill in the necessary GSL vector and Matrix structures. */
-  S.size=n;     S.stride=1;                S.data=pixscale;
-  V.size1=n;    V.size2=n;    V.tda=n;     V.data=v;
-  A.size1=n;    A.size2=n;    A.tda=n;     A.data=a;
-
-  /* Run GSL's Singular Value Decomposition, using one-sided Jacobi
-     orthogonalization which computes the singular (scale) values to a
-     higher relative accuracy.*/
-  gsl_linalg_SV_decomp_jacobi(&A, &V, &S);
-
-  /* Clean up and return. */
-  free(a);
-  free(v);
-  return pixscale;
-}
-
-
-
-
-
-/* Report the arcsec^2 area of the pixels in the image based on the
-   WCS information in that image. We first use the angular distance of
-   two edges of one pixel in radians. Then the radians are multiplied
-   to give stradians and finally, the stradians are converted to
-   arcsec^2. */
-double
-gal_wcs_pixel_area_arcsec2(struct wcsprm *wcs)
-{
-  double out;
-  double *pixscale;
-
-  /* A small sanity check. Later, when higher dimensions are necessary, we
-     can find which ones correlate to RA and Dec and use them to find the
-     pixel area in arcsec^2. */
-  if(wcs->naxis!=2)
-    error(EXIT_FAILURE, 0, "`gal_wcs_pixel_area_arcsec2' can currently "
-          "calculate the area only when the image has 2 dimensions.");
-
-  /* Get the pixel scales along each axis in degrees, then multiply. */
-  pixscale=gal_wcs_pixel_scale_deg(wcs);
-
-  /* Clean up and return the result. */
-  out = pixscale[0] * pixscale[1] * 3600.0f * 3600.0f;
-  free(pixscale);
-  return out;
-}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]