Home · Pages · Index · Overviews

Image I/O Module Reference

I/O of Tiff-encoded multi-channel images and stacks. More...

 #include <image.h>

Structures

  Layer_Bundle : struct
num_layers : int
layers : Array *[]
Number of layers in the layer list
layers[i] is the image of the i'th layer for i in [0,num_layers-1]

  Series_Bundle : struct
prefix : string
suffix : string
padded : boolean
num_width : int
first_num : int
 
Bundle names are "%s%0*d%s",prefix,num_width,#,suffix
  or possibly "%s%d%s",prefix,#,suffix if padded is false.
  Tries both when reading.
 

Enumerated Scalars

  Image_Compress : { DONT_PRESS LZW_PRESS PACKBITS_PRESS }
 

Routines

string Image_Error ()
void Image_Error_Release ()

Array * Read_ImageG (string file_name, int layer)
Layer_Bundle * Read_Images (string file_name, Layer_Bundle *images RM)
boolean Write_Image (string file_name, Array *array, Image_Compress comp)
boolean Write_Images (string file_name, Layer_Bundle *images, Image_Compress comp)

Series_Bundle * Parse_Series_Name (Series_Bundle *files RM, string file_name)

Array * Read_SeriesG (Series_Bundle *files M, int layer)
Layer_Bundle * Read_All_Series (Series_Bundle *files M, Layer_Bundle *images RM)
boolean Write_Series (Series_Bundle *files, Array *image, Image_Compress comp)
boolean Write_All_Series (Series_Bundle *files, Layer_Bundle *images, Image_Compress comp)

Detailed Description

A Tiff-encoded file contains a sequence of one or more image file descriptors (IFD's) each of which contains any number of channels each of which is a 2D array, all of the same shape. A 3D stack is not explicitly supported but the common convention is that if a tiff file contains a sequence of IFD's all of which encode the same channels and arrays of the same dimensions and types, then the sequence of IFD's gives each successive z-plane of a 3D stack in each channel. Each channel's array can contain signed or unsigned integers of some specific number of bits, or a 32-bit floating point number. Each channel also has a photometric interpretation which in effect can be one of RED, GREEN, BLUE, ALPHA, MAPPED, or PLAIN, with the restriction that the only channel that can be MAPPED is the first. (Tiff actually uses a somewhat baroque and complicated set of tags to encode (or not) these interpretations, but in effect the list just given is the information that is present.)

We divide the sequence of channels in an IFD into layers as follows: 4 channels in sequence that together constitute a RED, GREEN, BLUE, and ALPHA channel (the order is not important), form an RGBA layer, 3 channels in sequence that consitute a RED, GREEN, and BLUE channel, form an RGB layer, and any other channel is a PLAIN layer. The layers are read off in sequence, always taking RGBA over RGB over PLAIN as the next layer. For example, if an IFD has a sequence "RABGRA" then it has 3 layers, the first is RGBA, and the second and third are considered PLAIN despite having interpretations RED and ALPHA. As another example, "MGBRG", has 3 layers, the second is RGB, the third is PLAIN, and the first will be RGB as it will be the result of applying the color map to the first channel. The examples are convoluted in order to clarify how channels are grouped into layers, in most cases the channel sequences are straightforward, e.g. PRGBP.

The routines in the Image module, read and write the 2D or 3D layers of a tiff-encoded file into or from an Array of the corresponding kind, type, and scale. One should be aware of the following subtleties:

  1. The scale of an array is actually operative here: the values of a 12-bit UINT16_TYPE array will be written as 12-bit numbers to the tiff file, which in turn, when read, will produce an array with a scale of 12.
  2. The text field of the first layer array is written to a JF_ANO_BLOCK tag upon a write and this tag is loaded into the text field of the first layer array when read. There is no limitation on the size of a text field, so one can in principle encode arbitrarily complex meta-data about an image in this field in an ASCII-oriented format such as XML.
  3. The software will also read LSM files produced by Zeiss microscopes. The format is a small variation on the tiff format. LSM's frequently contain thumbnails as well as the primary image. These are ignored so that just the "primary" stack is read.
  4. All the read routines may return NULL if they can't open a file or if the tiff contents are improperly formated. Similarly, the write routines will return true if they cannot open a file for writing. In such an error event, one may get a descriptive string of the problem by calling Image_Error, right after the error occurs. In order for this to be thread-safe, if multiple threads encounter an error, only one of the threads (which is unspecified) records a descriptive string. One must subsequently "release" the recorded error (with Image_Error_Release) in order for a thread to record a new error, if one occurs. So an error message must be released even when one's application is not threaded.

Read_Image reads a single specified layer from a specified file and returns the result as a 2D or 3D array of either PLAIN_KIND, RGB_KIND, or RGBA_KIND according to the number of IFDs in the file and the series of channel kinds in each IFD. Read_Images reads all the layers in a file and returns them in a Layer_Bundle structure. Write_Image writes a single 2D or 3D array as a Tiff file compressing it according to the Image_Compress value passed to it. Write_Images writes a set of either 2D or 3D arrays as supplied in a Layer_Bundle to a single file, compressing them as indicated.

Occasionally, especially with older data sets, the individual planes of a 3D stack are recorded as separate files with a number series in their names. To facilitate this situation Mylib provides the "(Read/Write)_(All_)Series" routines (Read_Series, Read_All_Series, Write_Series, Write_All_Series) that are analogous to the "(Read/Write)_Image(s)" routines above save that they read or write a numbered series of files. The key is the routine Parse_Series_Name which parses the first name in such a series and fills in a Series_Bundle structure that can then be given to the IO routines to read or write the series.


Structure Documentation

Layer_Bundle : struct
num_layers: int
layers: Array *[]

Used to encode a set of 2D or 3D arrays that can be read from or written to a tiff file as a series of layers. num_layers is the number of arrays or layers in the set, and layers[i] is a pointer to the ith array in the set, where i ∈ [0,num_layers-1]. All the arrays are either 2D or 3D and have the same dimensions. The arrays can be of any kind except COMPLEX_KIND and are of any type except FLOAT64_TYPE. The arrays in the set do not need to be of the same kind, type, or scale.

Series_Bundle : struct
prefix: string
suffix: string
padded: boolean
num_width: int
first_num: int

Used to repesent an unbounded series of file names that is most easily explained with a couple of examples. Suppose prefix = "x", suffix = ".tif", and first_num = 8. If padded is false, then the sequence of names modeled is: "x8.tif", "x9.tif", "x10.tif", .... On the otherhand, if padded is true and num_width = 3, then the sequence of names modeled is: "x008.tif", "x009.tif", "x010.tif", ...


Enumerated Scalars Documentation

Image_Compress: { DONT_PRESS LZW_PRESS PACKBITS_PRESS }

Values that indicate what kind of compression should be applied to a data being written in the tiff format. DONT_PRESS indicates no compression. PACKBITS_PRESS indicates Packbits compression which is a lossless run-length encoding scheme. Lastly, LZW_PRESS indicates Lempel-Ziv-Welch compression which is a very effective lossless repeat compression scheme.


Routine Documentation

string Image_Error ()
void Image_Error_Release ()

All the routines that read layers may return NULL if they can't open a file or if the tiff contents are improperly formated. Similarly, the write routines will return true if they cannot open a file for writing. In such an error event, one may get a descriptive string of the problem by calling Image_Error, right after the error occurs. In order for this to be thread-safe, if multiple threads encounter an error, only one of the threads (which is unspecified) records a descriptive string. One must subsequently "release" the recorded error with Image_Error_Release in order for a thread to record a new error, if one occurs. So an error message must be released even when one's application is not threaded.

Array * Read_ImageG (string file_name, int layer)

Read layer layer from file file_name returning a newly generated 2D array if the file contains a single IFD, and a newly generated 3D array otherwise. The layer is color mapped if the tiff channel kind indicates it should be.

Layer_Bundle * Read_Images (string file_name, Layer_Bundle *images RM)

Read all the layers from file file_name and return the result in images.

The bundle images should be a semantically valid Layer_Bundle on input, i.e. if num_layers > 0 then layers should be a vector of at least num_layers pointers to arrays, and exactly the first num_layers of these pointers should be to valid Array objects. The simplist way to establish a semantically valid bundle is to set num_layers to 0 and layers to NULL. This routine will take the bundle and modify it so that it reflects the number of layers in the file and so that layers points at an array for each layer read, where arrays are freed, created, and or modified as necessary to produce the result. The user is responsible for managing the array objects in the bundle and the vector layers that points at the arrays.

boolean Write_Image (string file_name, Array *array, Image_Compress comp)

Write array to a file file_name in the tiff format. The array must be 2D or 3D and cannot be of COMPLEX_KIND or FLOAT64_TYPE. The file is compressed (or not) according to the value of comp. Writing an LZW compressed file takes almost 3 times longer than an uncompressed file, but does result in the file being 30-50% of the uncompressed size. Packbits compression is faster run-length compression, but does not compress as effectively.

boolean Write_Images (string file_name, Layer_Bundle *images, Image_Compress comp)

Write the arrays in images to the file file_name in tiff format. The arrays in images must all be either 2D or 3D, and all have the same dimensions. The arrays can be of different kinds and types, but may not be of COMPLEX_KIND or FLOAT64_TYPE. The data in the file is compressed according to the value of the parameter comp.

Series_Bundle * Parse_Series_Name (Series_Bundle *files RM, string file_name)

Parse the string file_name assuming it is of the form "<prefix><first_num><suffix>" and fills in the supplied Series_Bundle files with the constituent parts where num_width is the length of the string matched to first_num and padded is true if the number begins with a 0.

Array * Read_SeriesG (Series_Bundle *files M, int layer)

Read the specified layer from the series of 2D tiff images specified by the Series_Bundle files into a newly generated 3D Array that is returned as the result. The routine will look for a series of files as specified by files, with the field padded set to both true and false, and it will load the longer series. For example, if files has prefix = "x", suffix = ".tif", num_first = 8, and num_width = 3, then the routine will look for the series "x8.tif", "x9.tif", ... and for the series "x008.tif", "x009.tif" ... in the file system and create the image corresponding to the longer of the two series, setting padded accordingly (which incidentally is the only way in which files is modified by the routine).

Layer_Bundle * Read_All_Series (Series_Bundle *files M, Layer_Bundle *images RM)

Read all the layers from the series of 2D tiff images specified by files, filling images with the array read exactly as for Read_Images. The identification of the series of images to read according to files is as for Read_Series immediately above.

boolean Write_Series (Series_Bundle *files, Array *image, Image_Compress comp)

Write the supplied array to the seres of 2D tiff images specified by files, compressed according to the value of comp. Unlike the read analog of this routine, the padded field of files is operative and determines whether the number sequence is 0-padded or not.

boolean Write_All_Series (Series_Bundle *files, Layer_Bundle *images, Image_Compress comp)

Write the arrays in images to the series of 2D tiff images specified by files, compressed according to the value of comp. The arrays in images must all be either 2D or 3D, and all have the same dimensions. The arrays can be of different kinds and types, but may not be of COMPLEX_KIND or FLOAT64_TYPE.