From 56f78c09dd3b7e8815a0220afd0b681d8c62b790 Mon Sep 17 00:00:00 2001 From: Hans Meine Date: Mon, 12 Jan 2015 20:00:08 +0100 Subject: [PATCH] =?UTF-8?q?first=20working=20version=20of=203D=20(tiled)?= =?UTF-8?q?=20TIFF=20loader=20-=20added=20TIFFFile::pixelType()=20-=20adde?= =?UTF-8?q?d=20TIFFFile::readTile()=20(very=20thin=20wrapper=20around=20li?= =?UTF-8?q?btiff)=20-=20added=20VolumeInfo::fileType=20of=20=E2=80=9ETILED?= =?UTF-8?q?TIFF=E2=80=9C=20-=20FIXME:=20only=20works=20with=20correct=20ta?= =?UTF-8?q?rget=20datatype=20-=20FIXME:=20does=20not=20cope=20with=20multi?= =?UTF-8?q?-channel=20data=20yet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/vigra/multi_impex.hxx | 50 +++++++++++++++- include/vigra/tiff_file.hxx | 92 ++++++++++++++-------------- src/impex/CMakeLists.txt | 3 +- src/impex/multi_impex.cxx | 22 ++++++- src/impex/tiff_file.cxx | 110 ++++++++++++++++++++++++++++++++++ 5 files changed, 228 insertions(+), 49 deletions(-) diff --git a/include/vigra/multi_impex.hxx b/include/vigra/multi_impex.hxx index 7b560a997..929b7506e 100644 --- a/include/vigra/multi_impex.hxx +++ b/include/vigra/multi_impex.hxx @@ -50,6 +50,7 @@ #include "multi_array.hxx" #include "multi_pointoperators.hxx" #include "sifImport.hxx" +#include "tiff_file.hxx" #ifdef _MSC_VER # include @@ -168,8 +169,9 @@ class VolumeImportInfo Possible values are:
"MULTIPAGE"
Multiple 2D images in a single file (currently only supported by TIFF). +
"TILEDTIFF"
Tiled TIFF (standard conform, but extremly rare, used by MeVisLab).
"SIF"
Andor Technology's .sif format. -
"RAW"
Raw data file, accompanied by a .info file +
"RAW"
Raw data file, accompanied by an .info file
"STACK"
A numbered set of 2D image files, one per slice of the volume.
**/ @@ -491,7 +493,51 @@ void VolumeImportInfo::importImpl(MultiArrayView <3, T, Stride> &volume) const { vigra_precondition(this->shape() == volume.shape(), "importVolume(): Output array must be shaped according to VolumeImportInfo."); - if(fileType_ == "RAW") + if(fileType_ == "TILEDTIFF") + { + TIFFFile f(path_.c_str(), "r"); + + MultiArrayShape<3>::type + zero3D(0, 0, 0), + one3D(1, 1, 1), + imageSize = f.imageSize3D(), + tileSize = f.tileSize3D(), + tileCount = (imageSize + tileSize - one3D) / tileSize; + + MultiArray<3, T> tileBuffer(tileSize); + + // read all tiles; important background info on the libtiff API: + // - all tiles have the same size, i.e. we need to clip at the + // upper boundaries in general + // - although the tiles are also numbered, the can only be + // read by passing an arbitrary(!) coordinate pointing into + // that slice... + MultiArrayShape<3>::type copyPos; + for(copyPos[0] = 0; copyPos[0] < imageSize[0]; copyPos[0] += tileSize[0]) + { + for(copyPos[1] = 0; copyPos[1] < imageSize[1]; copyPos[1] += tileSize[1]) + { + for(copyPos[2] = 0; copyPos[2] < imageSize[2]; copyPos[2] += tileSize[2]) + { + // clip by not always copying tileSize voxels into target volume + MultiArrayShape<3>::type copySize(tileSize); + for(char dim = 0; dim < 3; ++dim) + if(copySize[dim] > imageSize[dim] - copyPos[dim]) + copySize[dim] = imageSize[dim] - copyPos[dim]; + + MultiArrayView<3, T, Stride> + targetVOI(volume.subarray(copyPos, imageSize)); + + // now read and copy (TODO: handle T != pixelType()!) + f.readTile(tileBuffer.data(), copyPos[0], copyPos[1], copyPos[2], 0); + + copyMultiArray(srcMultiArrayRange(tileBuffer.subarray(zero3D, copySize)), + destMultiArray(targetVOI)); + } + } + } + } + else if(fileType_ == "RAW") { std::string dirName, baseName; char oldCWD[2048]; diff --git a/include/vigra/tiff_file.hxx b/include/vigra/tiff_file.hxx index a6fedb022..6140896ec 100644 --- a/include/vigra/tiff_file.hxx +++ b/include/vigra/tiff_file.hxx @@ -6,53 +6,57 @@ namespace vigra { class TIFFFile { public: - typedef TinyVector VolumeSize; - - TIFFFile(const char *filename, const char *mode); - - /** - * There are two possible TIFF file types that require different - * I/O APIs: striped files (which you know well) and tiled files - * (veeeery esoteric). - */ - enum FileType { INVALID = 0, STRIPED = 1, TILED = 2 }; - - /** - * For usual TIFF files (no tile size fields), returns STRIPED. - * Returns TILED iff the TIFF file contains both tile width and - * height tags (and the tile depth tag for 3D files, i.e. if - * there's an image depth tag), INVALID otherwise (some, but not - * all extents specified). - */ - FileType fileType() const - { - return fileType_; - } - - /** - * Returns true for 3D TIFFs, i.e. those with the SGI image/tile depth fields. - */ - bool hasDepth() const - { - return hasDepth_; - } - - VolumeSize imageSize3D() const - { - return imageSize_; - } - - VolumeSize tileSize3D() const - { - return tileSize_; - } + typedef TinyVector VolumeSize; + + TIFFFile(const char *filename, const char *mode); + + /** + * There are two possible TIFF file types that require different + * I/O APIs: striped files (which you know well) and tiled files + * (veeeery esoteric). + */ + enum FileType { INVALID = 0, STRIPED = 1, TILED = 2 }; + + /** + * For usual TIFF files (no tile size fields), returns STRIPED. + * Returns TILED iff the TIFF file contains both tile width and + * height tags (and the tile depth tag for 3D files, i.e. if + * there's an image depth tag), INVALID otherwise (some, but not + * all extents specified). + */ + FileType fileType() const + { + return fileType_; + } + + /** + * Returns true for 3D TIFFs, i.e. those with the SGI image/tile depth fields. + */ + bool hasDepth() const + { + return hasDepth_; + } + + VolumeSize imageSize3D() const + { + return imageSize_; + } + + VolumeSize tileSize3D() const + { + return tileSize_; + } + + tsize_t readTile(tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t sample); + + std::string pixelType() const; private: - TIFF *h_; // TIFF file handle (cf. libtiff library) + TIFF *h_; // TIFF file handle (cf. libtiff library) - TinyVector imageSize_, tileSize_; - FileType fileType_; - bool hasDepth_; + TinyVector imageSize_, tileSize_; + FileType fileType_; + bool hasDepth_; }; } // namespace vigra diff --git a/src/impex/CMakeLists.txt b/src/impex/CMakeLists.txt index bcce34166..3151dc589 100644 --- a/src/impex/CMakeLists.txt +++ b/src/impex/CMakeLists.txt @@ -50,7 +50,8 @@ ADD_LIBRARY(vigraimpex ${LIBTYPE} hdf5_rf_impex.cxx iccjpeg.c imageinfo.cxx - multi_impex.cxx + multi_impex.cxx + tiff_file.cxx jpeg.cxx lz4.c png.cxx diff --git a/src/impex/multi_impex.cxx b/src/impex/multi_impex.cxx index 81c4b6a48..fac2b1361 100644 --- a/src/impex/multi_impex.cxx +++ b/src/impex/multi_impex.cxx @@ -48,7 +48,6 @@ std::string trimString(const std::string &s) } // namespace detail -// find filenames matching the pattern "/base[0-9]+ext" #ifdef _MSC_VER void splitPathFromFilename(const std::string &pathAndName, std::string &path, std::string &name) @@ -74,6 +73,7 @@ void splitPathFromFilename(const std::string &pathAndName, } } +// find filenames matching the pattern "/base[0-9]+ext" (Windows version) VIGRA_EXPORT void findImageSequence(const std::string &name_base, const std::string &name_ext, std::vector & numbers) @@ -153,6 +153,7 @@ void splitPathFromFilename(const std::string &pathAndName, } } +// find filenames matching the pattern "/base[0-9]+ext" (Unix version) void findImageSequence(const std::string &name_base, const std::string &name_ext, std::vector & numbers) @@ -863,7 +864,24 @@ VolumeImportInfo::VolumeImportInfo(const std::string &filename) return; } } - + + // for TIFF files, check for single-file, 3D data, tiled TIFFs first: + if(codecManager().getFileTypeByMagicString(filename) == "TIFF") + { + TIFFFile f(filename.c_str(), "r"); + + shape_ = f.imageSize3D(); + + pixelType_ = f.pixelType(); + numBands_ = 1; // FIXME + + path_ = filename; + + baseName_ = filename; + fileType_ = "TILEDTIFF"; + return; + } + // try multi-page TIFF or image stack if(isImage(filename.c_str())) { diff --git a/src/impex/tiff_file.cxx b/src/impex/tiff_file.cxx index 1710d3086..7ae56d2b2 100644 --- a/src/impex/tiff_file.cxx +++ b/src/impex/tiff_file.cxx @@ -35,4 +35,114 @@ TIFFFile::TIFFFile(const char *filename, const char *mode) } } +tsize_t TIFFFile::readTile(tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t sample) +{ + return TIFFReadTile(h_, buf, x, y, z, sample); +} + +std::string TIFFFile::pixelType() const +{ + // get bits per sample, default to 8 + uint16 bits_per_sample; + if(!TIFFGetField( h_, TIFFTAG_BITSPERSAMPLE, &bits_per_sample)) + bits_per_sample = 8; + + // get pixeltype + if(bits_per_sample == 1) + return "BILEVEL"; + + // try the sampleformat tag + uint16 sampleformat; + if(TIFFGetField(h_, TIFFTAG_SAMPLEFORMAT, &sampleformat)) + { + switch (sampleformat) + { + case SAMPLEFORMAT_UINT: + // added by dangelo, support for UINT 16 & 32 bit + switch(bits_per_sample) + { + case 8: + return "UINT8"; + case 16: + return "UINT16"; + case 32: + return "UINT32"; + } + break; + + case SAMPLEFORMAT_INT: + switch (bits_per_sample) + { + case 8: + return "INT8"; + case 16: + return "INT16"; + case 32: + return "INT32"; + } + break; + + case SAMPLEFORMAT_IEEEFP: + switch (bits_per_sample) + { + case 32: + return "FLOAT"; + case 64: + return "DOUBLE"; + } + break; + + default: + ; + } + } + + // fall back to the (obsolete) datatype tag + uint16 datatype; + if(TIFFGetField(h_, TIFFTAG_DATATYPE, &datatype)) + { + // dangelo: correct parsing of INT/UINT (given in tiff.h) + switch (datatype) + { + case TIFF_BYTE: + return "UINT8"; + case TIFF_SBYTE: + return "INT8"; + case TIFF_SHORT: + return "UINT16"; + case TIFF_SSHORT: + return "INT16"; + case TIFF_LONG: + return "UINT32"; + case TIFF_SLONG: + return "INT32"; + case TIFF_FLOAT: + return "FLOAT"; + case TIFF_DOUBLE: + return "DOUBLE"; + default: + ; + } + } + + // ugly: no useable pixeltype found.. + // e.g. imagemagick writes files without it; try to guess a suitable one here: + switch(bits_per_sample) + { + case 8: + return "UINT8"; + case 16: + return "UINT16"; + case 32: + return "UINT32"; // prefer int over float + case 64: + return "DOUBLE"; + default: + ; + } + + vigra_fail( "TIFFDecoderImpl::init(): Sampleformat or Datatype tag undefined and guessing sampletype from Bits per Sample failed." ); + return ""; +} + } // namespace vigra