TinyTIFF
a lightweight C/C++ library for reading and writing TIFF files
|
This is a lightweight C++ library that allows to read and write TIFF files. It only implements limited support for the features of TIFF. It was developed as a replacement for libTIFF for some very specific cases, where performance in writing (and reading) is much more important than full feature support. TinyTIFF e.g. does not support compression. Also the multi-frame TIFF-support is taylored (actually that is one of the main reasons for this library) to writing sequence of equally dimensioned images fast. The currently supported features are:
The library is built with CMake and supports both find_package(TinyTIFF)
and CMake's FetchContent to include it into other projects. See https://jkriege2.github.io/TinyTIFF/page_useinstructions.html for details
This software is licensed under the term of the GNU Lesser General Public License 3.0 (LGPL 3.0) or above. See TinyTIFF: LGPL >= 3.0 for details.
Some helpful links:
The methods in this file allow to write TIFF files with limited capabilites, but very fast. Usually writing TIFF files with a library like libTIFF is relatively slow, when multiple images are written into a single file. The methods in this files overcome this problem by implementing a tiny writer lib that allows to write a TIFF file where all images have the same properties (size, bit depth, ...). This is a situation thet occurs e.g. in cases where a camera acquires a video that should be saved as TIFF file. The library works like this (write 50 32x32 pixel 8-bit images:
You can also store multi-sample images. Their interpretation has to be specified in the call to TinyTIFFWriter_open()
, e.g. for an RGB-image, use:
Note, that TinyTIFFWriter_writeImage()
expects the image data in the given buff data
is given in interleaved order, i.e. R1G1B1R2G2B2R3G3B3...
and writes it out in the same order. If you specify more or less samples, the same rules apply. You can use the extended method TinyTIFFWriter_writeImageMultiSample()
if your data is not in chunky format, or you want to write the data out in planar form, instead of chunky (e.g. to make the data readable by TinyTIFFReader.
Also it is possibly to specify that one of the extra channels ahall be used as ALPHA information. then you need to call TinyTIFFWriter_open(..., TinyTIFFWriter_RGBA)
or TinyTIFFWriter_open(..., TinyTIFFWriter_GreyscaleAndAlpha)
. All samples additional to the ones covered by the interpretation flag are treated as extraSamples with unspecified type (see TIFF specification for details).
The images are written in big- or little-endian according to your system. The TIFF header is set accordingly, so we do not need to shuffle around bytes when writing, but the created TIFF file may differ from hardware system to hardware system, although the same data is written (once in little-endian, once in big-endian). Currently this library saves all images as unsigned int, but with given bit-depth (8, 16, 32 or 64). Also this library explicitly writes a resolution of 1 in both directions.
Internally this library works like this: TinyTIFFWriter_open() will basically only initialize the internal datastructures and write the TIFF header. It also determines the byte order used by the system and sets the TIFF header acordingly. As the image size is known, the size of every image in the file can be predetermined (we assume a maximum number of TIFF directory entries). The size will be:
MAX_HEADER_ENTRIES*12 + SOME_FREE_SPACE + WIDTH*HEIGHT*SAMPLES(BITS_PER_SAMPLES/8) --------------------------------------- ---------------------------------------- directory/image description data image data
The free space, indicated as SOME_FREE_SPACE is used to store contents of extended fields, like RATIONAL or ARRAY fields. Every image in the file will have this size and unused bytes are set to 0x00. TinyTIFFWriter_writeImage() then works like this: The image description data is first assembled in memory, then the complete image description data and the complete image data is written to the file all together. This reduces the number of file access operations and writes the data in two reltively large chunks which allows the operating system to properly optimize file access. Finally this method will save the position of the NEXT_IFD_OFFSET field in the image header. The NEXT_IFD_OFFSET field is filled with the adress of the next potential image. Finally the method TinyTIFFWriter_close() will write 0x00000000 into the NEXT_IFD_OFFSET of the last image (as saved above) which ends the list of images in the file. This ansatz for writing TIFF files is only about a factor of 2 slower than directly writing binary data into a file. In addition the time needed to write an image stays equal also when writing many images, which is NOT the case for libtiff.
The library was developed due to a problem with libTIFF, when a lot (>1000) frames are written into a TIFF-file. LibTIFF does not need constant time per frame (i.e. the time to write a multi-frame TIFF grows linearly with the number of frames), but the time to write a frame increases with the number of frames. The following performance measurement shows this. It was acquired using tinytiffwriter_speedtest
from this repository and shows the average time required to write one frame (64x64x pixels, 16-bit integer) out of a number (10, 100, 1000, ...) of frames. It compares the performance of libTIFF, TinyTIFFWriter and simply writing the dtaa using fwrite()
("RAW"):
Ryzen 5 3600+, Win10, 32-bit Release-build, writing onto a Harddisk, libTiff 3.8.2 | Ryzen 7 5800H, Win11, 64-bit Release-build, writing onto an SSD, libTiff 4.6.0 |
---|---|
For a microscope developed during my PhD thesis, it was necessary to write 100000 frames and more with acceptable duration. Therefore libTIFF was unusable and TinyTIFFWriter was developed. As can be seen in the graph above. The performance of TinyTIFFWriter and fwrite()
/RAW is comparable, whereas the performance of LibTIFF falls off towards large files on harddisks. On SSDs the performance of libTIFF does not show an increase with number of images, but is still significantly (1.5-3x, note the logarithmic y-axis) faster than libTIFF.
The following image shows another performance measurement, this time for different frame sizes (64x64-4096x4096, acquired on an Ryzen 5 3600+, Win10, 32-bit Release-build, writing onto a Harddisk (not a SSD)):
Ryzen 5 3600+, Win10, 32-bit Release-build, writing onto a Harddisk, libTiff 3.8.2 | Ryzen 7 5800H, Win11, 64-bit Release-build, writing onto an SSD, libTiff 4.6.0 |
---|---|
This suggests that for harddisks the performance of TinyTIFFWriter and fwrite()
are comparable for all image sizes. For larger images, also the performance of libTIFF is in the same range, whereas for small images, libTIFF falls off somewhat. For SSDs, the libraries are closer together, but still TinyTIFFWriter is faster than libTIFF by a factor of 1.5-5x (again note the logarithmic scale on the y-axis!).
The following example code reads all frames in a TIFF:
This simplified example reads the first sample from the first frame in a TIFF file: