summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorSu Laus <sulau@freenet.de>2022-12-19 21:30:42 +0000
committerEven Rouault <even.rouault@spatialys.com>2022-12-19 21:30:42 +0000
commitdc3369a7947b949a283d267b68524e4f931b3b49 (patch)
treedb692267e17de83098934b8352c8b3dc85cb9766 /doc
parenta34d7ddee23f91f4277f80c5645f2e1b918ec8b4 (diff)
downloadlibtiff-git-dc3369a7947b949a283d267b68524e4f931b3b49.tar.gz
manpage: Add multi page TIFF and SubIFDs description and read / write example.
Diffstat (limited to 'doc')
-rw-r--r--doc/functions/TIFFOpen.rst24
-rw-r--r--doc/functions/TIFFReadDirectory.rst1
-rw-r--r--doc/functions/TIFFSetDirectory.rst24
-rw-r--r--doc/functions/TIFFWriteDirectory.rst10
-rw-r--r--doc/index.rst1
-rw-r--r--doc/multi_page.rst211
-rw-r--r--doc/terms.rst25
7 files changed, 265 insertions, 31 deletions
diff --git a/doc/functions/TIFFOpen.rst b/doc/functions/TIFFOpen.rst
index 23eb12a2..db79d7bc 100644
--- a/doc/functions/TIFFOpen.rst
+++ b/doc/functions/TIFFOpen.rst
@@ -50,17 +50,19 @@ Description
and returns a handle to be used in subsequent calls to routines in
:program:`libtiff`. If the open operation fails, then
:c:macro:`NULL` (0) is returned. The *mode* parameter specifies if
-the file is to be opened for reading (``r``), writing (``w``), or
+the file is to be opened for reading (``r``) or (``r+``), writing (``w``), or
appending (``a``) and, optionally, whether to override certain
-default aspects of library operation (see below).
+default aspects of library operation (see below Options_).
+
+The *mode* (``r``) opens only an **existing** file for reading and (``r+``)
+for reading and writing.
When a file is opened for appending, existing data will not
be touched; instead new data will be written as additional subfiles.
If an existing file is opened for writing, all previous data is
overwritten.
If a file is opened for reading, the first TIFF directory in the file
-is automatically read (also see :c:func:`TIFFSetDirectory` for reading
-directories other than the first).
+is automatically read.
If a file is opened for writing or appending, a default directory
is automatically created for writing subsequent data.
This directory has all the default values specified in TIFF Revision 6.0:
@@ -78,16 +80,13 @@ This directory has all the default values specified in TIFF Revision 6.0:
To alter these values, or to define values for additional fields,
:c:func:`TIFFSetField` must be used.
-A file can also be opened for reading and writing with *mode* (``r+``).
-In this case, the first TIFF directory in the file is automatically read,
-but calls to :c:func:`TIFFSetField` are put into a fresh directory, which
-will be appended when the file is closed.
-
:c:func:`TIFFOpenW` opens a TIFF file with a Unicode filename, for read/writing.
:c:func:`TIFFFdOpen` is like :c:func:`TIFFOpen` except that it opens a
TIFF file given an open file descriptor *fd*.
The file's name and mode must reflect that of the open descriptor.
+Even for write-only mode, ``libtiff`` needs read permissions because
+some of its functions need to read back the partially written TIFF file.
The object associated with the file descriptor **must support random access**.
In order to close a TIFF file opened with :c:func:`TIFFFdOpen`
first :c:func:`TIFFCleanup` should be called to free the internal
@@ -154,10 +153,15 @@ Options
-------
The open mode parameter can include the following flags in
-addition to the ``r``, ``w``, and ``a`` flags.
+addition to the ``r``, ``r+``, ``w``, and ``a`` flags.
Note however that option flags must follow the read-write-append
specification.
+Note 2: Also for ``w`` the file will be opened with *read access* rights
+because ``libtiff`` needs to read back the partially written TIFF file
+for some of its functions.
+
+
``l``:
When creating a new file force information be written with
diff --git a/doc/functions/TIFFReadDirectory.rst b/doc/functions/TIFFReadDirectory.rst
index 3ffaf7b8..7a1fc038 100644
--- a/doc/functions/TIFFReadDirectory.rst
+++ b/doc/functions/TIFFReadDirectory.rst
@@ -142,4 +142,5 @@ See also
:doc:`TIFFquery` (3tiff),
:doc:`TIFFWriteDirectory` (3tiff),
:doc:`TIFFSetDirectory` (3tiff),
+:doc:`/multi_page`,
:doc:`libtiff` (3tiff)
diff --git a/doc/functions/TIFFSetDirectory.rst b/doc/functions/TIFFSetDirectory.rst
index 61aea5c4..5d1212f7 100644
--- a/doc/functions/TIFFSetDirectory.rst
+++ b/doc/functions/TIFFSetDirectory.rst
@@ -20,28 +20,15 @@ Description
:c:func:`TIFFSetDirectory` changes the current directory and reads its
contents with :c:func:`TIFFReadDirectory`. The parameter *dirnum*
specifies the subfile/directory as an integer number, with the first
-directory numbered zero.
+directory numbered zero.
+:c:func:`TIFFSetDirectory()` only works with main-IFD chains because
+allways starts with the first main-IFD and thus is able to reset
+the SubIFD reading chain to the main-IFD chain.
:c:func:`TIFFSetSubDirectory` acts like :c:func:`TIFFSetDirectory`,
except the directory is specified as a file offset instead of an index;
this is required for accessing subdirectories linked through a
-``SubIFD`` tag.
-
-In the case of several SubIFDs of a main image, there are two possibilities
-that are not even mutually exclusive.
-
-a. The ``SubIFD`` tag contains an array with all offsets of the SubIFDs.
-b. The ``SubIFDs`` are concatenated with their ``NextIFD`` parameters
- to a SubIFD chain.
-
-LibTiff does support SubIFD chains partially. When a ``SubIFD`` tag is
-activated with :c:func:`TIFFSetSubDirectory()`, :c:func:`TIFFReadDirectory()`
-is able to parse through the SubIFD chain. The *tif_curdir* is just
-incremented from its current value and thus gets arbitrary values
-when parsing through SubIFD chains.
-:c:func:`TIFFSetDirectory()` only works with main-IFD chains because
-allways starts with the first main-IFD and thus is able to reset
-the SubIFD reading chain to the main-IFD chain.
+``SubIFD`` tag. (see :ref:`MultiPage SubIFD <SubIFDAccess>`)
Directory query functions :c:func:`TIFFCurrentDirectory`,
:c:func:`TIFFCurrentDirOffset`, :c:func:`TIFFLastDirectory` and
@@ -80,4 +67,5 @@ See also
:doc:`TIFFCustomDirectory` (3tiff),
:doc:`TIFFWriteDirectory` (3tiff),
:doc:`TIFFReadDirectory` (3tiff),
+:doc:`/multi_page`,
:doc:`libtiff` (3tiff)
diff --git a/doc/functions/TIFFWriteDirectory.rst b/doc/functions/TIFFWriteDirectory.rst
index 8682d5f0..00bac0b1 100644
--- a/doc/functions/TIFFWriteDirectory.rst
+++ b/doc/functions/TIFFWriteDirectory.rst
@@ -24,9 +24,12 @@ Description
-----------
:c:func:`TIFFWriteDirectory` will write the contents of the current
-directory to the file and setup to create a new subfile in the same
-file. Applications only need to call :c:func:`TIFFWriteDirectory`
-when writing multiple subfiles to a single TIFF file.
+directory (IFD) to the file and setup to create a new directory (IFD)
+using :c:func:`TIFFCreateDirectory`.
+Applications only need to call :c:func:`TIFFWriteDirectory`
+when writing multiple subfiles (images) to a single TIFF file.
+This is called "multi-page TIFF" or "multi-image TIFF"
+(see :doc:`/multi_page`).
:c:func:`TIFFWriteDirectory` is automatically called by
:c:func:`TIFFClose` and :c:func:`TIFFFlush` to write a modified
directory if the file is open for writing.
@@ -133,4 +136,5 @@ See also
:doc:`TIFFSetDirectory` (3tiff),
:doc:`TIFFReadDirectory` (3tiff),
:doc:`TIFFError` (3tiff),
+:doc:`/multi_page`,
:doc:`libtiff` (3tiff)
diff --git a/doc/index.rst b/doc/index.rst
index b33cdd1f..abec6622 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -46,6 +46,7 @@ The following sections are included in this documentation:
build
terms
libtiff
+ multi_page
functions
internals
addingtags
diff --git a/doc/multi_page.rst b/doc/multi_page.rst
new file mode 100644
index 00000000..d4e5dcd5
--- /dev/null
+++ b/doc/multi_page.rst
@@ -0,0 +1,211 @@
+Multi Page / Multi Image TIFF
+=============================
+
+There may be more than one :ref:`Image File Directory (IFD) <ImageFileDirectory>`
+in a TIFF file. Each IFD defines a :ref:`subfile <SubFile>`.
+
+One potential use of *subfiles* is to describe related images,
+such as the pages of a facsimile transmission or reduced-resolution images
+of the first full-resolution image.
+Such files are also named "*multi-page* TIFF" or "*multi-image* TIFF".
+
+There are two mechanisms for storing multiple images in a TIFF file:
+
+1. A **main-IFD chain**, where the images are stored in linked IFDs (directories).
+ This mechanism is widely used.
+2. A **SubIFD chain**, where additional images are stored within the SubIFD tag
+ of a main-IFD. Such child images provide extra information for the parent image
+ - such as a subsampled version of the parent image.
+ SubIFD chains are rarely supported.
+ For SubIFD refer also to
+ `Adobe PageMaker® 6.0 TIFF Technical Notes <https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf>`_
+
+.. _SubIFDAccess:
+
+Sub IFD chains
+--------------
+
+In the case of several SubIFDs of a main image, there are two possibilities
+that are not even mutually exclusive.
+
+a. The ``SubIFD`` tag contains an array with all offsets of the SubIFDs.
+b. The SubIFDs are concatenated with their ``NextIFD`` parameters
+ to a SubIFD chain.
+
+LibTiff does support SubIFD chains partially. When the first
+``SubIFD`` tag is activated and read with :c:func:`TIFFSetSubDirectory()`,
+the following can be parsed with :c:func:`TIFFReadDirectory()`.
+The *tif_curdir* is just incremented from its current value
+and thus gets arbitrary values when parsing through SubIFD chains.
+When the SubIFDs are not chained, each offset
+within the SubIFD array has to be activated and read individually.
+:c:func:`TIFFSetDirectory()` only works with main-IFD chains because
+allways starts with the first main-IFD and thus is able to reset
+the SubIFD reading chain to the main-IFD chain.
+
+Writing Multi Page TIFF
+-----------------------
+
+The following example code shows how to write multi-page TIFF
+as main-IFD chain and as SubIFD chain.
+``libtiff`` writes SubIFDs as an array of IFDs that are not chained
+additionally, as Adobe PageMaker® 6.0 TIFF Technical Notes suggests.
+
+.. highlight:: c
+
+::
+
+ #include <tiffio.h>
+
+ int main(int argc, const char **argv)
+ {
+ TIFF *tiff;
+
+ /* Define the number of pages/images (main-IFDs) you are going to write */
+ int number_of_images = 3;
+
+ /* Define the number of sub - IFDs you are going to write */
+ #define NUMBER_OF_SUBIFDs 2
+ int number_of_sub_IFDs = NUMBER_OF_SUBIFDs;
+ toff_t sub_IFDs_offsets[NUMBER_OF_SUBIFDs] = {
+ 0UL}; /* array for SubIFD tag */
+ int blnWriteSubIFD = 0;
+
+ if (!(tiff = TIFFOpen("multiPageTiff2.tif", "w")))
+ return 1;
+
+ for (int i = 0; i < number_of_images; i++)
+ {
+ char pixel[1] = {128};
+
+ TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, 1);
+ TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, 1);
+ TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+
+ /* For the last but one multi-page image, add a SubIFD e.g. for a
+ * thumbnail */
+ if (number_of_images - 2 == i)
+ blnWriteSubIFD = 1;
+
+ if (blnWriteSubIFD)
+ {
+ /* Now here is the trick: the next n directories written
+ * will be sub-IFDs of the main-IFD (where n is number_of_sub_IFDs
+ * specified when you set the TIFFTAG_SUBIFD field.
+ * The SubIFD offset array sub_IFDs_offsets is filled automatically
+ * with the proper offset values by the following number_of_sub_IFDs
+ * TIFFWriteDirectory() calls and updated in the related main-IFD
+ * with the last call.
+ */
+ if (!TIFFSetField(tiff, TIFFTAG_SUBIFD, number_of_sub_IFDs,
+ sub_IFDs_offsets))
+ return 1;
+ }
+
+ /* Write dummy pixel to image */
+ if (TIFFWriteScanline(tiff, pixel, 0, 0) < 0)
+ return 1;
+ /* Write image / directory to file */
+ if (!TIFFWriteDirectory(tiff))
+ return 1;
+
+ if (blnWriteSubIFD)
+ {
+ /* A SubIFD tag has been written for that main-IFD and this
+ * triggers that pervious TIFFWriteDirectory() to switch to the
+ * SubIFD-chain for the next number_of_sub_IFDs writings.
+ * Thus, only the thumbnail images need to be
+ * set up and written to file using TIFFWriteDirectory().
+ * The last of this TIFFWriteDirectory() calls will setup
+ * the next fresh main-IFD.
+ */
+ for (int i = 0; i < number_of_sub_IFDs; i++)
+ {
+ TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, 1);
+ TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, 1);
+ TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ /* SUBFILETYPE tag is not mandatory for SubIFD writing, but a
+ * good idea to indicate thumbnails */
+ if (!TIFFSetField(tiff, TIFFTAG_SUBFILETYPE,
+ FILETYPE_REDUCEDIMAGE))
+ return 1;
+
+ /* Write dummy pixel to thumbnail image */
+ pixel[0] = 64;
+ if (TIFFWriteScanline(tiff, pixel, 0, 0) < 0)
+ return 1;
+ /* Writes now in the SubIFD chain */
+ if (!TIFFWriteDirectory(tiff))
+ return 1;
+
+ blnWriteSubIFD = 0;
+ }
+ }
+ }
+ TIFFClose(tiff);
+ return 0;
+ }
+
+Reading Multi Page TIFF
+-----------------------
+
+For a reading example see code of `tools/tiffinfo.c` or below:
+
+.. highlight:: c
+
+::
+
+ /* Reading of multi-page and SubIFD images (subfiles) */
+ if (!(tiff = TIFFOpen(filename, "r")))
+ return 1;
+
+ tdir_t currentDirNumber = TIFFCurrentDirectory(tiff);
+
+ /* The first directory is already read through TIFFOpen() */
+ int blnRead = 0;
+ do
+ {
+ /*Check if there are SubIFD subfiles */
+ void *ptr;
+ if (TIFFGetField(tiff, TIFFTAG_SUBIFD, &number_of_sub_IFDs, &ptr))
+ {
+ /* Copy SubIFD array from pointer */
+ memcpy(sub_IFDs_offsets, ptr,
+ number_of_sub_IFDs * sizeof(sub_IFDs_offsets[0]));
+
+ for (int i = 0; i < number_of_sub_IFDs; i++)
+ {
+ /* Read first SubIFD directory */
+ if (!TIFFSetSubDirectory(tiff, sub_IFDs_offsets[i]))
+ return 1;
+ /* Check if there is a SubIFD chain behind the first one from
+ * the array, as specified by Adobe */
+ while (TIFFReadDirectory(tiff))
+ /* analyse subfile */
+ ;
+ }
+ /* Go back to main-IFD chain and re-read that main-IFD directory */
+ if (!TIFFSetDirectory(tiff, currentDirNumber))
+ return 1;
+ }
+ /* Read next main-IFD directory (subfile) */
+ blnRead = TIFFReadDirectory(tiff);
+ currentDirNumber = TIFFCurrentDirectory(tiff);
+ } while (blnRead);
+ TIFFClose(tiff);
+
+
+
+
+See also
+--------
+
+:doc:`terms`,
+:doc:`/functions/TIFFSetDirectory` (3tiff),
+:doc:`/functions/TIFFWriteDirectory` (3tiff),
+`Adobe PageMaker® 6.0 TIFF Technical Notes <https://www.awaresystems.be/imaging/tiff/specification/TIFFPM6.pdf>`_,
+`Example from StackOverflow <https://stackoverflow.com/questions/11959617/in-a-tiff-create-a-sub-ifd-with-thumbnail-libtiff>`_ \ No newline at end of file
diff --git a/doc/terms.rst b/doc/terms.rst
index d20d80ed..3d4012a6 100644
--- a/doc/terms.rst
+++ b/doc/terms.rst
@@ -35,6 +35,31 @@ Codec:
Software that implements the decoding and encoding algorithms
of a compression scheme.
+.. _ImageFileDirectory:
+
+Image File Directory (IFD):
+ An Image File Directory - in short also *directory* -
+ contains information about the image,
+ as well as pointers (offsets) to the actual image data
+ within the on-disk file.
+ An IFD points either to the next IFD or shows with a ''0''
+ that it is the last IFD in the IFD-chain.
+
+Multi Images per TIFF file:
+ There may be more than one IFD in a TIFF file.
+ Each IFD defines a *subfile*.
+ One potential use of *subfiles* is to describe related images,
+ such as the pages of a facsimile transmission.
+ Such files are also named "*multi-page* TIFF" or "*multi-image* TIFF".
+ Refer also to :doc:`/multi_page`.
+
+.. _SubFile:
+
+Subfile:
+ *Subfile* is a term in the TIFF 6.0 specification for
+ an image and its associated *Image File Directory (IFD)*
+ in a TIFF file containing one or more images.
+
In order to better understand how TIFF works (and consequently this
software) it is important to recognize the distinction between the
physical organization of image data as it is stored in a TIFF and how