gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master e220bf1: TIFF files can be used as input


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master e220bf1: TIFF files can be used as input
Date: Mon, 12 Mar 2018 00:35:54 -0400 (EDT)

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

    TIFF files can be used as input
    
    With this commit, Gnuastro contains a library wrapper for the `libtiff'
    library to read TIFF data into memory for use within Gnuastro. As a result,
    ConvertType can now also read TIFF files. Currently writing of TIFF files
    is not yet supported.
    
    Also, I found out that `gal_list_data_add' was not returning the proper
    array! It was returning the last node of the `newnode' list, not the
    first/full list.
    
    A re-run of Autoconf is necessary after pulling this commit.
---
 NEWS                |   9 +
 bin/convertt/ui.c   |  35 ++-
 configure.ac        |  21 +-
 doc/gnuastro.texi   | 127 +++++++++--
 lib/Makefile.am     |   6 +-
 lib/gnuastro/tiff.h |  74 +++++++
 lib/list.c          |   2 +-
 lib/tiff.c          | 605 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 847 insertions(+), 32 deletions(-)

diff --git a/NEWS b/NEWS
index 9757280..bfb38e8 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
 
 ** New features
 
+  ConvertType: TIFF images can also be used as input into ConvertType,
+  therefore libtiff has been added as a new optional dependency.
+
   MakeCatalog: The new `--mean' and `--median' options will calculate the
   mean and median pixel value within an object or clump respectively.
 
@@ -22,6 +25,12 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   cumulative frequency plots to be set outside the minimum or maximum
   values of the dataset.
 
+  Libraries:
+    gal_tiff_name_is_tiff: check if name contains a TIFF suffix.
+    gal_tiff_suffix_is_tiff: check if suffix is a TIFF suffix.
+    gal_tiff_dir_string_read: convert a string to a TIFF directory number.
+    gal_tiff_read: Read the contents of a TIFF `directory' to `gal_data_t'.
+
 ** Removed features
 
 ** Changed features
diff --git a/bin/convertt/ui.c b/bin/convertt/ui.c
index e6a7aec..bdd30bd 100644
--- a/bin/convertt/ui.c
+++ b/bin/convertt/ui.c
@@ -32,6 +32,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <gnuastro/wcs.h>
 #include <gnuastro/list.h>
 #include <gnuastro/fits.h>
+#include <gnuastro/tiff.h>
 #include <gnuastro/table.h>
 #include <gnuastro/blank.h>
 #include <gnuastro/arithmetic.h>
@@ -393,9 +394,9 @@ static void
 ui_make_channels_ll(struct converttparams *p)
 {
   char *hdu=NULL;
-  size_t dsize=0;
   gal_data_t *data;
   gal_list_str_t *name;
+  size_t dsize=0, dirnum;
 
   /* Go through the input files and add the channel(s). */
   p->numch=0;
@@ -431,13 +432,31 @@ ui_make_channels_ll(struct converttparams *p)
         }
 
 
+      /* TIFF: */
+      else if( gal_tiff_name_is_tiff(name->v) )
+        {
+          /* Get the directory value for this channel. */
+          if(p->hdus)
+            {
+              hdu=gal_list_str_pop(&p->hdus);
+              dirnum=gal_tiff_dir_string_read(hdu);
+            }
+          else
+            dirnum=0;
+
+          /* Read the TIFF image into memory. */
+          data=gal_tiff_read(name->v, dirnum, p->cp.minmapsize);
+          p->numch += gal_list_data_number(data);
+          gal_list_data_add(&p->chll, data);
+        }
+
 
       /* JPEG: */
       else if ( nameisjpeg(name->v) )
         {
 #ifndef HAVE_LIBJPEG
           error(EXIT_FAILURE, 0, "you are giving a JPEG input, however, "
-                "when %s was configured libjpeg was not available. To read "
+                "when %s was configured, libjpeg was not available. To read "
                 "from (and write to) JPEG files, libjpeg is required. "
                 "Please install it and configure, make and install %s "
                 "again", PACKAGE_STRING, PACKAGE_STRING);
@@ -654,12 +673,12 @@ ui_set_output(struct converttparams *p)
 #else
       /* Small sanity checks. */
       if(p->quality == GAL_BLANK_UINT8)
-        error(EXIT_FAILURE, 0, "the `--quality' (`-u') option is necessary for 
"
-              "jpeg outputs, but it has not been given");
+        error(EXIT_FAILURE, 0, "the `--quality' (`-u') option is necessary "
+              "for jpeg outputs, but it has not been given");
       if(p->quality > 100)
         error(EXIT_FAILURE, 0, "`%u' is larger than 100. The value to the "
-              "`--quality' (`-u') option must be between 1 and 100 
(inclusive)",
-              p->quality);
+              "`--quality' (`-u') option must be between 1 and 100 "
+              "(inclusive)", p->quality);
 
       /* Preparations. */
       p->outformat=OUT_FORMAT_JPEG;
@@ -667,6 +686,10 @@ ui_set_output(struct converttparams *p)
         ui_add_dot_use_automatic_output(p);
 #endif
     }
+  else if( gal_tiff_name_is_tiff(cp->output) )
+      error(EXIT_FAILURE, 0, "writing TIFF files is not yet supported, "
+            "please get in touch with us at %s so we implement it",
+            PACKAGE_BUGREPORT);
   else if(nameiseps(cp->output))
     {
       p->outformat=OUT_FORMAT_EPS;
diff --git a/configure.ac b/configure.ac
index c169f54..77b2559 100644
--- a/configure.ac
+++ b/configure.ac
@@ -287,8 +287,6 @@ AM_CONDITIONAL([COND_HASHELP2MAN], [test "x$has_help2man" = 
"xyes"])
 
 
 
-
-
 # Check libjpeg:
 AC_SEARCH_LIBS([jpeg_stdio_dest], [jpeg],
                [has_libjpeg=yes], [has_libjpeg=no])
@@ -301,6 +299,18 @@ AM_CONDITIONAL([COND_HASLIBJPEG], [test "x$has_libjpeg" = 
"xyes"])
 
 
 
+# Check libtiff:
+AC_SEARCH_LIBS([TIFFOpen], [tiff],
+               [has_libtiff=yes], [has_libtiff=no])
+AS_IF([test "x$has_libtiff" = "xyes"],
+      [AC_DEFINE([HAVE_LIBTIFF], [], [Has libtiff])],
+      [anywarnings=yes])
+AM_CONDITIONAL([COND_HASLIBTIFF], [test "x$has_libtiff" = "xyes"])
+
+
+
+
+
 # Check libgit2:
 AC_SEARCH_LIBS([git_libgit2_init], [git2],
                [has_libgit2=1], [has_libgit2=0])
@@ -650,7 +660,12 @@ AS_IF([test x$enable_guide_message = xyes],
         AS_ECHO([])
         AS_IF([test "x$has_libjpeg" = "xno"],
               [AS_ECHO(["  - libjpeg, could not be linked with in your library 
search path."])
-               AS_ECHO(["    If JPEG outputs are desired from ConvertType, it 
will warn"])
+               AS_ECHO(["    If JPEG inputs/outputs are given to ConvertType, 
it will warn"])
+               AS_ECHO(["    you and abort with an error."])
+               AS_ECHO([]) ])
+        AS_IF([test "x$has_libtiff" = "xno"],
+              [AS_ECHO(["  - libtiff, could not be linked with in your library 
search path."])
+               AS_ECHO(["    If TIFF inputs/outputs are given to ConvertType, 
it will warn"])
                AS_ECHO(["    you and abort with an error."])
                AS_ECHO([]) ])
         AS_IF([test "x$has_libgit2" = "x0"],
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 7a385fe..659a8fa 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -556,6 +556,7 @@ Gnuastro library
 * Linked lists::                Various types of linked lists.
 * FITS files::                  Working with FITS data.
 * World Coordinate System::     Dealing with the world coordinate system.
+* TIFF files::                  Functions for using TIFF files.
 * Text files::                  Functions to work on Text files.
 * Table input output::          Reading and writing table columns.
 * Arithmetic on datasets::      Arithmetic operations on a dataset.
@@ -3931,15 +3932,26 @@ headers} for a discussion.
 @item libjpeg
 @pindex libjpeg
 @cindex JPEG format
-libjpeg is only used by ConvertType to read from and write to JPEG
-images. @url{http://www.ijg.org/, libjpeg} is a very basic library
-that provides tools to read and write JPEG images, most of the
-GNU/Linux graphic programs and libraries use it. Therefore you most
+libjpeg is only used by ConvertType to read from and write to JPEG images,
+see @ref{Recognized file formats}. @url{http://www.ijg.org/, libjpeg} is a
+very basic library that provides tools to read and write JPEG images, most
+Unix-like graphic programs and libraries use it. Therefore you most
 probably already have it installed.
address@hidden://libjpeg-turbo.virtualgl.org/, libjpeg-turbo} is an
-alternative to libjpeg. It uses SIMD instructions for ARM based
-systems that significantly decreases the processing time of JPEG
-compression and decompression algorithms.
address@hidden://libjpeg-turbo.virtualgl.org/, libjpeg-turbo} is an alternative
+to libjpeg. It uses SIMD instructions for ARM based systems that
+significantly decreases the processing time of JPEG compression and
+decompression algorithms.
+
address@hidden libtiff
address@hidden libtiff
address@hidden TIFF format
+libtiff is used by ConvertType and the libraries to read TIFF images, see
address@hidden file formats}. @url{http://www.simplesystems.org/libtiff/,
+libtiff} is a very basic library that provides tools to read and write TIFF
+images, most Unix-like operating system graphic programs and libraries use
+it. Therefore even if you don't have it installed, it must be easily
+available in your package manager.
+
 
 @item GPL Ghostscript
 @cindex GPL Ghostscript
@@ -8386,6 +8398,26 @@ The file name endings that are recognized as a JPEG file 
for input
 are: @file{.jpg}, @file{.JPG}, @file{.jpeg}, @file{.JPEG},
 @file{.jpe}, @file{.jif}, @file{.jfif} and @file{.jfi}.
 
address@hidden TIFF
address@hidden TIFF format
+TIFF (or Tagged Image File Format) was originally designed as a common
+format for scanners in the early 90s and since then it has grown to become
+very general. In many aspects, the TIFF stanard is similar to the FITS
+image standard: it can allow data of many types (see @ref{Numeric data
+types}), and also allows multiple images to be stored in a single file
+(each image in the file is called a `directory' in the TIFF
+standard). However, unlike FITS, it can only store images, it has no
+constructs for tables. Another (inconvenient) difference with the FITS
+standard is that keyword names are stored as numbers, not human-readable
+text.
+
+However, outside of astronomy, because of its support of different numeric
+data types, many fields use TIFF images for accurate (for example 16-bit
+integer or floating point for example) imaging data.
+
+Currently ConvertType can only read TIFF images, if you are interested in
+writing TIFF images, please get in touch with us.
+
 @item EPS
 @cindex EPS
 @cindex PostScript
@@ -8649,13 +8681,22 @@ Input:
 @item -h STR/INT
 @itemx --hdu=STR/INT
 In ConvertType, it is possible to call the HDU option multiple times for
-the different input FITS files (corresponding to different color channels)
-in the same order that they are called on the command-line. Except for the
-fact that multiple calls are possible, this option is identical to the
-common @option{--hdu} in @ref{Input output options}. The number of calls to
-this option cannot be less than the number of input FITS files, but if
-there are more, the extra HDUs will be ignored, note that they will be read
-in the order described in @ref{Configuration file precedence}.
+the different input FITS or TIFF files in the same order that they are
+called on the command-line. Note that in the TIFF standard, one `directory'
+(similar to a FITS HDU) may contain multiple color channels (for example
+when the image is in RGB).
+
+Except for the fact that multiple calls are possible, this option is
+identical to the common @option{--hdu} in @ref{Input output options}. The
+number of calls to this option cannot be less than the number of input FITS
+or TIFF files, but if there are more, the extra HDUs will be ignored, note
+that they will be read in the order described in @ref{Configuration file
+precedence}.
+
+Unlike CFITSIO, libtiff (which is used to read TIFF files) only recognizes
+numbers (counting from zero, similar to CFITSIO) for `directory'
+identification. Hence the concept of names is not defined for the
+directories and the values to this option for TIFF files must be numbers.
 @end table
 
 @noindent
@@ -19060,6 +19101,7 @@ documentation will correspond to your installed version.
 * Linked lists::                Various types of linked lists.
 * FITS files::                  Working with FITS data.
 * World Coordinate System::     Dealing with the world coordinate system.
+* TIFF files::                  Functions for using TIFF files.
 * Text files::                  Functions to work on Text files.
 * Table input output::          Reading and writing table columns.
 * Arithmetic on datasets::      Arithmetic operations on a dataset.
@@ -21783,7 +21825,7 @@ formats, see @ref{Table input output}.
 
 
 
address@hidden World Coordinate System, Text files, FITS files, Gnuastro library
address@hidden World Coordinate System, TIFF files, FITS files, Gnuastro library
 @subsection World Coordinate System (@file{wcs.h})
 
 The FITS standard defines the world coordinate system (WCS) as a mechanism
@@ -21928,15 +21970,62 @@ description of @code{gal_wcs_world_to_img} for more 
details.
 
 
 
address@hidden Text files, Table input output, World Coordinate System, 
Gnuastro library
address@hidden TIFF files, Text files, World Coordinate System, Gnuastro library
address@hidden TIFF files
+
+Outside of astronomy, the TIFF standard is arguably the most commonly used
+format to store high-precision data/images. Unlike FITS however, the TIFF
+standard only supports images (not tables), but like FITS, it has support
+for all standard data types (see @ref{Numeric data types}) which is the
+primary reason other fields use it.
+
+Another similarity of the TIFF and FITS standards is that TIFF supports
+multiple images in one file. The TIFF standard calls each one of these
+images (and their accompanying meta-data) a `directory' (roughly equivalent
+to the FITS extensions). Unlike FITS however, the directories can only be
+identified by their number (counting from zero), recall that in FITS you
+can also use the extension name to identify it.
+
+The functions described here allow easy reading (and later writing) of TIFF
+files within Gnuastro or for users of Gnuastro's libraries. Currently only
+reading is supported, but if you are interested, please get in touch with
+us.
+
address@hidden {int} gal_tiff_name_is_tiff (char @code{*name})
+Return @code{1} if @code{name} has a TIFF suffix. This can be used to make
+sure that a given input file is TIFF. See @code{gal_tiff_suffix_is_tiff}
+for a list of recognized suffixes.
address@hidden deftypefun
+
address@hidden {int} gal_tiff_suffix_is_tiff (char @code{*name})
+Return @code{1} if @code{suffix} is a recognized TIFF suffix. The
+recognized suffixes are @file{tif}, @file{tiff}, @file{TIFF} and
address@hidden
address@hidden deftypefun
+
address@hidden {size_t} gal_tiff_dir_string_read (char @code{*string})
+Return the number within @code{string} as a @code{size_t} number to
+identify a TIFF directory. Note that the directories start counting from
+zero.
address@hidden deftypefun
+
address@hidden {gal_data_t *} gal_tiff_read (char @code{*filename}, size_t 
@code{dir}, size_t @code{minmapsize})
+Read the @code{dir} directory within the TIFF file @code{filename} and
+return the contents of that TIFF directory as @code{gal_data_t}. If the
+directory's image contains multiple channels, the output will be a list
+(see @ref{List of gal_data_t}).
address@hidden deftypefun
+
+
+
address@hidden Text files, Table input output, TIFF files, Gnuastro library
 @subsection Text files (@file{txt.h})
 
 FITS files are the primary data container in astronomy. FITS indeed as many
 useful features, but the most universal and portable format for data
 storage are plain text files. They can be viewed and edited on any text
 editor or even on the command-line. Therefore the functions in this section
-are defined to simplify reading from and writing to plain text
-files.
+are defined to simplify reading from and writing to plain text files.
 
 Lines are one of the most basic buiding blocks (delimiters) of a text
 file. Some operating systems like Microsoft Windows, terminate their ASCII
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0ee4e9d..1226a88 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -59,7 +59,7 @@ libgnuastro_la_SOURCES = arithmetic.c arithmetic-and.c 
arithmetic-bitand.c \
   arithmetic-or.c arithmetic-plus.c binary.c blank.c box.c checkset.c      \
   convolve.c cosmology.c data.c fits.c git.c interpolate.c list.c match.c  \
   options.c permutation.c polygon.c qsort.c dimension.c statistics.c       \
-  table.c tableintern.c threads.c tile.c timing.c txt.c type.c wcs.c
+  table.c tableintern.c threads.c tiff.c tile.c timing.c txt.c type.c wcs.c
 
 
 
@@ -76,8 +76,8 @@ pkginclude_HEADERS = gnuastro/config.h 
$(headersdir)/arithmetic.h         \
   $(headersdir)/interpolate.h $(headersdir)/list.h $(headersdir)/match.h  \
   $(headersdir)/permutation.h $(headersdir)/polygon.h                     \
   $(headersdir)/qsort.h $(headersdir)/statistics.h $(headersdir)/table.h  \
-  $(headersdir)/threads.h $(headersdir)/tile.h $(headersdir)/txt.h        \
-  $(headersdir)/type.h $(headersdir)/wcs.h
+  $(headersdir)/threads.h $(headersdir)/tiff.h $(headersdir)/tile.h       \
+  $(headersdir)/txt.h $(headersdir)/type.h $(headersdir)/wcs.h
 
 
 
diff --git a/lib/gnuastro/tiff.h b/lib/gnuastro/tiff.h
new file mode 100644
index 0000000..443dac8
--- /dev/null
+++ b/lib/gnuastro/tiff.h
@@ -0,0 +1,74 @@
+/*********************************************************************
+tiff -- functions to read and write TIFF files.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2015-2018, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#ifndef __GAL_TIFF_H__
+#define __GAL_TIFF_H__
+
+
+/* Include other headers if necessary here. Note that other header files
+   must be included before the C++ preparations below */
+#include <gnuastro/list.h>
+
+
+
+/* C++ Preparations */
+#undef __BEGIN_C_DECLS
+#undef __END_C_DECLS
+#ifdef __cplusplus
+# define __BEGIN_C_DECLS extern "C" {
+# define __END_C_DECLS }
+#else
+# define __BEGIN_C_DECLS                /* empty */
+# define __END_C_DECLS                  /* empty */
+#endif
+/* End of C++ preparations */
+
+
+
+
+
+/* Actual header contants (the above were for the Pre-processor). */
+__BEGIN_C_DECLS  /* From C++ preparations */
+
+
+
+
+
+/* Functions */
+int
+gal_tiff_name_is_tiff(char *name);
+
+int
+gal_tiff_suffix_is_tiff(char *name);
+
+size_t
+gal_tiff_dir_string_read(char *string);
+
+gal_data_t *
+gal_tiff_read(char *filename, size_t dir, size_t minmapsize);
+
+
+
+
+__END_C_DECLS    /* From C++ preparations */
+
+#endif           /* __GAL_TIFF_H__ */
diff --git a/lib/list.c b/lib/list.c
index b84e1c9..9af66fd 100644
--- a/lib/list.c
+++ b/lib/list.c
@@ -1199,7 +1199,7 @@ gal_list_data_add(gal_data_t **list, gal_data_t *newnode)
 
   /* Set the next element of toadd and update what list points to.*/
   toadd->next=*list;
-  *list=toadd;
+  *list=newnode;
 }
 
 
diff --git a/lib/tiff.c b/lib/tiff.c
new file mode 100644
index 0000000..acfc8ba
--- /dev/null
+++ b/lib/tiff.c
@@ -0,0 +1,605 @@
+/*********************************************************************
+tiff -- functions to read and write TIFF files.
+This is part of GNU Astronomy Utilities (Gnuastro) package.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2015-2018, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <error.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_LIBTIFF
+  #include <tiffio.h>
+#endif
+
+#include <gnuastro/fits.h>
+#include <gnuastro/data.h>
+#include <gnuastro/list.h>
+#include <gnuastro/tiff.h>
+
+
+
+
+
+
+
+
+
+
+/*************************************************************
+ **************      Acceptable TIFF names      **************
+ *************************************************************/
+int
+gal_tiff_name_is_tiff(char *name)
+{
+  size_t len;
+  len=strlen(name);
+  if ( ( len>=3 && strcmp(&name[len-3], "tif") == 0 )
+       || ( len>=3 && strcmp(&name[len-3], "TIF") == 0 )
+       || ( len>=4 && strcmp(&name[len-4], "tiff") == 0 )
+       || ( len>=4 && strcmp(&name[len-4], "TIFF") == 0 ) )
+    return 1;
+  else
+    return 0;
+}
+
+
+
+
+
+int
+gal_tiff_suffix_is_tiff(char *name)
+{
+  if (strcmp(name, "tif") == 0   || strcmp(name, ".tif") == 0
+      || strcmp(name, "TIF") == 0 || strcmp(name, ".TIF") == 0
+      || strcmp(name, "tiff") == 0 || strcmp(name, ".tiff") == 0
+      || strcmp(name, "TIFF") == 0 || strcmp(name, ".TIFF") == 0 )
+    return 1;
+  else
+    return 0;
+}
+
+
+
+
+
+/* Users may define the TIFF directory to read as a string, in that case,
+   this function can be used to convert it to a `size_t' for use in
+   `gal_tiff_read'.  */
+size_t
+gal_tiff_dir_string_read(char *string)
+{
+  long dir;
+  char *tailptr=NULL;
+
+  /* Read the given directory string. */
+  errno=0;
+  dir=strtol(string, &tailptr, 0);
+  if(tailptr==string)
+    error(EXIT_FAILURE, 0, "%s: `%s' couldn't be read as an integer",
+          __func__, string);
+  if(errno)
+    error(EXIT_FAILURE, errno, "%s: reading %s", __func__, string);
+  if(dir<0)
+    error(EXIT_FAILURE, 0, "%s: %ld is a negative integer, it must be "
+          "positive", __func__, dir);
+
+  /* Return the result. */
+  return dir;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*************************************************************
+ **************        Read a JPEG image        **************
+ *************************************************************/
+#ifdef HAVE_LIBTIFF
+static void
+tiff_read_tag(TIFF *tif, ttag_t tag, void *out, char *filename, size_t dir)
+{
+  /* Read the tag */
+  if( !TIFFGetField(tif, tag, out) )
+    error(EXIT_FAILURE, 0, "%s: %s (dir %zu): tag %d couldn't be fetched",
+          __func__, filename, dir, tag);
+}
+
+
+
+
+
+/* Convert the TIFF type code into Gnuastro's type code.*/
+static uint8_t
+tiff_type_read(TIFF *tif, char *filename, size_t dir)
+{
+  uint16_t bitspersample, sampleformat;
+
+  /* Read the number of bits and the corresponding type. */
+  tiff_read_tag(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample, filename, dir);
+
+  /* Read the formatting of each pixel. If no such keyword exists, use the
+     value of `SAMPLEFORMAT_UINT'. */
+  if( TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat) != 1 )
+    sampleformat=SAMPLEFORMAT_UINT;
+
+  /* Read the datatype. */
+  switch(sampleformat)
+    {
+    /* Unsigned integer types. */
+    case SAMPLEFORMAT_UINT:
+      switch(bitspersample)
+        {
+        case 8:  return GAL_TYPE_UINT8;
+        case 16: return GAL_TYPE_UINT16;
+        case 32: return GAL_TYPE_UINT32;
+        case 64: return GAL_TYPE_UINT64;
+        default:
+          error(EXIT_FAILURE, 0, "%s: %s (dir %zu): %u-bit samples not "
+                "recognized for UNSIGNED-int format", __func__, filename,
+                dir, bitspersample);
+        }
+      break;
+
+    /* Signed integer types. */
+    case SAMPLEFORMAT_INT:
+      switch(bitspersample)
+        {
+        case 8:  return GAL_TYPE_INT8;
+        case 16: return GAL_TYPE_INT16;
+        case 32: return GAL_TYPE_INT32;
+        case 64: return GAL_TYPE_INT64;
+        default:
+          error(EXIT_FAILURE, 0, "%s: %s (dir %zu): %u-bit samples not "
+                "recognized for SIGNED-int format", __func__, filename,
+                dir, bitspersample);
+        }
+      break;
+
+
+    /* Floating point types. */
+    case SAMPLEFORMAT_IEEEFP:
+      switch(bitspersample)
+        {
+        case 32: return GAL_TYPE_FLOAT32;
+        case 64: return GAL_TYPE_FLOAT64;
+        default:
+          error(EXIT_FAILURE, 0, "%s: %s (dir %zu): %u-bit samples not "
+                "recognized for floating point format", __func__, filename,
+                dir, bitspersample);
+        }
+      break;
+
+
+    /* The reported value is not recognized. */
+    default:
+      error(EXIT_FAILURE, 0, "%s: %s (dir %zu): value %u not recognized "
+            "for SAMPLEFORMAT tag", __func__, filename, dir, sampleformat);
+    }
+
+  /* Control should never reach here, but to avoid compiler warnings (and
+     hard to find bugs when it does reach here), we'll just return an
+     invalid type. */
+  return GAL_TYPE_INVALID;
+}
+
+
+
+
+
+/* Get the basic TIFF image information. */
+static void
+tiff_img_info(TIFF *tif, uint8_t *type, size_t *ndim, size_t *dsize,
+              size_t *numch, char *filename, size_t dir)
+{
+  size_t d=0;
+  uint16_t u16;
+  uint32_t u32;
+
+  /* Based on if `IMAGEDEPTH' is defined in the TIFF header, set the
+     dimensions. */
+  if( TIFFGetField(tif, TIFFTAG_IMAGEDEPTH, &u32) )
+    dsize[ d++ ]=u32;
+
+  /* Read the other sizes. Note that in the TIFF standard, IMAGELENGTH is
+     the vertical length of the image and IMAGEWIDTH is the horizontal
+     length. */
+  tiff_read_tag(tif, TIFFTAG_IMAGELENGTH, &u32, filename, dir);
+  dsize[ d++ ]=u32;
+  tiff_read_tag(tif, TIFFTAG_IMAGEWIDTH, &u32, filename, dir);
+  dsize[ d++ ]=u32;
+
+  /* Write the dimensions. */
+  *ndim=d;
+
+  /* Read the type of the image. */
+  *type=tiff_type_read(tif, filename, dir);
+
+  /* Read the number of channels in the image. */
+  *numch = TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &u16) ? u16 : 1;
+}
+
+
+
+
+
+/* Based on the `TIFFReadContigStripData' function of `tools/tiffinfo.c' of
+   Libtiff's source. */
+void
+tiff_read_contig_strip_data(TIFF *tif, char *filename, size_t dir,
+                            gal_data_t *out, size_t numch)
+{
+  tstrip_t strip;
+  size_t ostart=0;
+  unsigned char *buf;
+  uint32_t row, rowsperstrip = (uint32_t)-1;
+  size_t nrow, scanline=TIFFScanlineSize(tif);
+  uint32 h=out->ndim==2?out->dsize[0]:out->dsize[1];
+
+  /* Allocate the buffer. */
+  errno=0;
+  buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+  if(buf==NULL)
+    error(EXIT_FAILURE, errno, "%s: %s (dir %zu): couldn't allocate "
+          "necessary space to load image (%zu bytes)", __func__, filename,
+          dir, scanline);
+
+  /* Parse over the rows and read everything. */
+  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+  for(row=0; row<h; row+=rowsperstrip)
+    {
+      /* Read the part of the image into the buffer. */
+      strip = TIFFComputeStrip(tif, row, 0);
+      nrow  = (row+rowsperstrip > h ? h-row : rowsperstrip);
+      if( TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0 )
+        error(EXIT_FAILURE, 0, "%s: %s (dir %zu): couldn't read data",
+              __func__, filename, dir);
+
+      /* Copy the contents of the buffer to the output array. Note that
+         `ostart' is the byte count already, so the type is
+         irrelevant. Thus, we can read `out->array' as a `char *'
+         pointer.*/
+      memcpy( (char *)(out->array)+ostart, buf, nrow*scanline);
+      ostart+=nrow*scanline;
+    }
+
+  /* Clean up. */
+  _TIFFfree(buf);
+}
+
+
+
+
+
+/* Based on the `TIFFReadSeparateStripData' function of `tools/tiffinfo.c'
+   of Libtiff's source. */
+static void
+tiff_read_separate_strip_data(TIFF* tif, char *filename, size_t dir,
+                              gal_data_t *out)
+{
+  tsample_t s;
+  gal_data_t *ch;
+  tstrip_t strip;
+  unsigned char *buf;
+  uint32_t rowsperstrip = (uint32_t)-1;
+  size_t nrow, scanline = TIFFScanlineSize(tif);
+  size_t ostart=0, numch=gal_list_data_number(out);
+  uint32 row, h=out->ndim==2?out->dsize[0]:out->dsize[1];
+
+  /* Allocate the buffer. */
+  errno=0;
+  buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+  if(buf==NULL)
+    error(EXIT_FAILURE, errno, "%s: %s (dir %zu): couldn't allocate "
+          "necessary space to load image (%zu bytes)", __func__, filename,
+          dir, scanline);
+
+  /* Parse over the dataset and read them into the output. */
+  TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+  for(row=0; row<h; row+=rowsperstrip)
+    {
+      /* Restart the channel list. */
+      ch=out;
+
+      /* Go over each channel. */
+      for(s=0; s<numch; s++)
+        {
+          /* Read this part of the data into the buffer. */
+          strip = TIFFComputeStrip(tif, row, s);
+          nrow = (row+rowsperstrip > h ? h-row : rowsperstrip);
+          if( TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0 )
+            error(EXIT_FAILURE, 0, "%s: %s (dir %zu): couldn't read data",
+                  __func__, filename, dir);
+
+          /* Write the buffer into the output array. */
+          memcpy( (char *)(ch->array)+ostart, buf, nrow*scanline);
+
+          /* Go onto the next channel. */
+          ch=ch->next;
+        }
+
+      /* Increment the starting pointer. */
+      ostart+=nrow*scanline;
+    }
+
+  /* Clean up. */
+  _TIFFfree(buf);
+}
+
+
+
+
+
+/* The data have been read contiguously (the pixels for each color are
+   beside each other). We need to separate the color channels into
+   different datasets. We will also use this chance to reverse the order of
+   the rows */
+static gal_data_t *
+tiff_separate_channels_reverse(gal_data_t *out, size_t numch,
+                               size_t minmapsize)
+{
+  size_t k, l, i, j;
+  gal_data_t *tch, *ch=NULL;
+  size_t so=gal_type_sizeof(out->type);
+  size_t width=out->dsize[1]*so/numch, lwidth=out->dsize[1]*so;
+
+  /* A small sanity check. */
+  if(out->ndim==3)
+    error(EXIT_FAILURE, 0, "%s: currently only 2D datasets are supported, "
+          "please get in touch with us at %s to add 3D support", __func__,
+          PACKAGE_BUGREPORT);
+
+
+  /* Make the separated datasets (temporarily fix the extra width). */
+  out->dsize[1] /= numch;
+  for(k=0; k<numch; ++k)
+    gal_list_data_add_alloc(&ch, NULL, out->type, out->ndim, out->dsize,
+                            NULL, 0, minmapsize, NULL, NULL, NULL);
+  out->dsize[1] *= numch;
+
+
+  /* Parse over the rows and write them in the output. */
+  for(i=0;i<out->dsize[0];++i)
+    {
+      /* `j' is the output row. */
+      j=out->dsize[0]-1-i;
+
+      /* `k' is the element in each row and `l' is the color/channel. */
+      for(k=0;k<ch->dsize[1];++k)
+        {
+          /* Initialize the color/channel counter ocpy the elements. */
+          l=0;
+          for(tch=ch; tch!=NULL; tch=tch->next)
+            {
+              /* Elements of the `j'th row into the `i'th. */
+              memcpy( (char *)(tch->array) + i*width  + k*so,
+                      (char *)(out->array) + j*lwidth + k*numch*so + so*l,
+                      so);
+
+              /* Increment the color. */
+              ++l;
+            }
+        }
+    }
+
+  /* Clean up and return. */
+  return ch;
+}
+
+
+
+
+
+/* The standard TIFF format is up-side-down when viewed in FITS (which is
+   the base of Gnuastro also). So we need to reverse the array for an
+   identical orientation. */
+static void
+tiff_reverse_rows(gal_data_t *out)
+{
+  gal_data_t *ch=out;
+  size_t c, i, j, numch=gal_list_data_number(out);
+  size_t width=out->dsize[1]*gal_type_sizeof(out->type);
+  void *tmp=gal_data_malloc_array(out->type, out->dsize[1], __func__, "tmp");
+
+  /* A small sanity check. */
+  if(out->ndim==3)
+    error(EXIT_FAILURE, 0, "%s: currently only 2D datasets are supported, "
+          "please get in touch with us at %s to add 3D support", __func__,
+          PACKAGE_BUGREPORT);
+
+  /* Parse over the rows and reverse them. */
+  for(c=0;c<numch;++c)
+    {
+      /* Initialize the parsing counters. */
+      i=0;
+      j=out->dsize[0]-1;
+
+      /* Go over the channel. */
+      while(j>i)
+        {
+          /* Copy the `i'th row into a temporary array. */
+          memcpy(tmp, (char *)(ch->array)+i*width, width);
+
+          /* Put the `j'th row into the `i'th row. */
+          memcpy( (char *)(ch->array)+i*width, (char *)(ch->array)+j*width,
+                  width );
+
+          /* Put the `tmp' row into `j'. */
+          memcpy( (char *)(ch->array)+j*width, tmp, width);
+
+          /* Increment the points. */
+          ++i;
+          --j;
+        }
+
+      /* Go to the next channel. */
+      ch=ch->next;
+    }
+
+  /* Clean up. */
+  free(tmp);
+}
+
+
+
+
+
+/* Read the data following the `TIFFReadData' of Libtiff's
+   `tools/tiffinfo.c' in the libtiff source code. */
+static gal_data_t *
+tiff_img_read(TIFF *tif, char *filename, size_t dir, size_t minmapsize)
+{
+  uint8_t type;
+  uint16_t config;
+  gal_data_t *sep, *out=NULL;
+  size_t i, ndim, numch, dsize[3];
+
+
+  /* Get the basic image information. */
+  tiff_img_info(tif, &type, &ndim, dsize, &numch, filename, dir);
+
+
+  /* Find the planar state of the input: are the channels separate or
+     contiguous? Based on that, allocate the output data structure. */
+  TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
+  if( config==PLANARCONFIG_CONTIG )
+    {
+      /* We'll multiply the last dimension's length by the number of
+         channels to keep the contiguous color information in one array. */
+      dsize[ndim-1] *= numch;
+      out=gal_data_alloc(NULL, type, ndim, dsize, NULL, 0, minmapsize,
+                         NULL, NULL, NULL);
+    }
+  else
+    for(i=0; i<numch; ++i)
+      gal_list_data_add_alloc(&out, NULL, type, ndim, dsize, NULL, 0,
+                              minmapsize, NULL, NULL, NULL);
+
+
+  /* The reading of the dataset depends on how it is organized, so first
+     we'll look into the `planarconfig' field. */
+  if( TIFFIsTiled(tif) )
+    {
+      if(config==PLANARCONFIG_CONTIG)
+        error(EXIT_FAILURE, 0, "%s: %s (dir %zu) is a contiguous tiled TIFF "
+              "file which is not yet supported in Gnuastro, please get in "
+              "touch with us at %s to add this feature", __func__, filename,
+              dir, PACKAGE_BUGREPORT);
+      else
+        error(EXIT_FAILURE, 0, "%s: %s (dir %zu) is a non-contiguous tiled "
+              "TIFF file which is not yet supported in Gnuastro, please "
+              "get in touch with us at %s to add this feature", __func__,
+              filename, dir, PACKAGE_BUGREPORT);
+    }
+  else
+    {
+      if(config==PLANARCONFIG_CONTIG)
+        tiff_read_contig_strip_data(tif, filename, dir, out, numch);
+      else
+        tiff_read_separate_strip_data(tif, filename, dir, out);
+    }
+
+
+  /* When there are more than one channels and the colors are stored
+     contiguously, we need to break up the array into multiple arrays. When
+     any of these conditions don't hold, the channels are already
+     separated, we just need to reverse them.*/
+  if( numch>1 && config==PLANARCONFIG_CONTIG )
+    {
+      sep=tiff_separate_channels_reverse(out, numch, minmapsize);
+      gal_data_free(out);
+      out=sep;
+    }
+  else
+    tiff_reverse_rows(out);
+
+
+  /* Return the output. */
+  return out;
+}
+#endif
+
+
+
+
+
+gal_data_t *
+gal_tiff_read(char *filename, size_t dir, size_t minmapsize)
+{
+#ifdef HAVE_LIBTIFF
+  TIFF *tif;
+  gal_data_t *out;
+  size_t dircount=0;
+
+  /* Open the TIFF file. */
+  tif=TIFFOpen(filename, "r");
+  if(tif==NULL)
+    error(EXIT_FAILURE, 0, "%s: `%s' couldn't be opened for reading",
+          __func__, filename);
+
+  /* If anything other than the first directory (value of zero) is
+     requested, then change the directories. */
+  if(dir)
+    {
+      if( TIFFSetDirectory(tif, dir)==0 )
+        {
+          /* For an informative error message, count how many directories
+             are in the TIFF file. */
+          do ++dircount; while( TIFFReadDirectory(tif) );
+
+          /* Close the TIFF file and return. */
+          TIFFClose(tif);
+          error(EXIT_FAILURE, 0, "%s: `%s' has %zu director%s, and "
+                "directories are counted from 0. You have asked for "
+                "directory %zu", __func__, filename, dircount,
+                dircount==1?"y":"ies", dir);
+        }
+    }
+
+  /* Read the image. */
+  out=tiff_img_read(tif, filename, dir, minmapsize);
+
+  /* Close file, clean up and return. */
+  TIFFClose(tif);
+  return out;
+#else
+  error(EXIT_FAILURE, 0, "%s: libtiff was not found during the "
+    "configuration of %s. To read from (and write to) TIFF files, "
+    "libtiff is required. Please install libtiff and configure, make "
+    "and install %s again", __func__, PACKAGE_STRING, PACKAGE_STRING);
+#endif
+}



reply via email to

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