libcvd-members
[Top][All Lists]
Advanced

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

[libcvd-members] libcvd cvd/internal/load_and_save.h cvd/interna...


From: Edward Rosten
Subject: [libcvd-members] libcvd cvd/internal/load_and_save.h cvd/interna...
Date: Sat, 02 Aug 2008 00:06:04 +0000

CVSROOT:        /cvsroot/libcvd
Module name:    libcvd
Changes by:     Edward Rosten <edrosten>        08/08/02 00:06:04

Modified files:
        cvd/internal   : load_and_save.h 
        cvd/internal/io: tiff.h 
        cvd_src        : image_io.cc 
        pnm_src        : save_postscript.cxx tiff.cxx 

Log message:
        Rewritten TIFF loading to support float images, amongst other things.
        
        This is not yet fully tested, so it is likely that there are some bugs. 
        Get the previous known working version with the tag:
        BEFORE_IMAGE_LOAD_REWRITE_2008_08_01
        
        The switch between compile time types and run time types has been 
replaced with
        compile/run time iteration over a typelist. Currently, only the TIFF 
loading
        mechanism has been written to use the automatic iteration.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd/internal/load_and_save.h?cvsroot=libcvd&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd/internal/io/tiff.h?cvsroot=libcvd&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/libcvd/cvd_src/image_io.cc?cvsroot=libcvd&r1=1.25&r2=1.26
http://cvs.savannah.gnu.org/viewcvs/libcvd/pnm_src/save_postscript.cxx?cvsroot=libcvd&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/libcvd/pnm_src/tiff.cxx?cvsroot=libcvd&r1=1.7&r2=1.8

Patches:
Index: cvd/internal/load_and_save.h
===================================================================
RCS file: /cvsroot/libcvd/libcvd/cvd/internal/load_and_save.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- cvd/internal/load_and_save.h        29 Nov 2005 16:38:50 -0000      1.7
+++ cvd/internal/load_and_save.h        2 Aug 2008 00:06:03 -0000       1.8
@@ -21,8 +21,13 @@
 #ifndef CVD_LOAD_AND_SAVE_H
 #define CVD_LOAD_AND_SAVE_H
 
+#include <vector>
+
 #include <cvd/exceptions.h>
 #include <cvd/image_convert.h>
+#include <cvd/internal/convert_pixel_types.h>
+#include <cvd/internal/name_CVD_rgb_types.h>
+
 namespace CVD {
 
        namespace Exceptions
@@ -90,6 +95,7 @@
                        struct ReadTypeMismatch: public All
                        {
                                ReadTypeMismatch(bool read8); ///< Constructor 
is passed <code>true</code> if it was trying to read 8-bit data
+                               ReadTypeMismatch(const std::string& available, 
const std::string& requested);
                        };
                        
                        /// An error occurred in one of the helper libraries
@@ -134,6 +140,108 @@
          {
            static const bool use_16bit = save_default_<C, 
CVD::Pixel::traits<typename 
CVD::Pixel::Component<C>::type>::integral>::use_16bit;
          };
+
+
+               
////////////////////////////////////////////////////////////////////////////////
        
+               //Mechanisms for generic image loading
+               //
+               // Image readers are duck-types and must provide the following:
+               // typedef  Types         Typelist containing types which can 
be loaded
+               // string   datatype()    Stringified name of datatype on disk
+               // string   name()        Name of the reader (JPEG, TIFF, etc)
+               // ImageRef size()        size()
+               // void get_raw_pixel_lines(T, int nlines) Where T is available 
for everything in Types
+               // Constructor accepting istream;
+
+               
+               //Basic typelist.
+               struct Head{};
+               template<class A, class B> struct TypeList
+               {
+                       typedef A Type;
+                       typedef B Next;
+               };
+               
+
+               
////////////////////////////////////////////////////////////////////////////////
+               //
+               // Read data and process if necessary. 
+               // In the case where the in-memory and on-disk datatypes match, 
no processing 
+               // is performed.
+               template<class PixelType, class DiskPixelType, class 
ImageLoader> struct read_and_maybe_process
+               {
+                       static void exec(BasicImage<PixelType>& im, 
ImageLoader& r)
+                       {
+                               std::vector<DiskPixelType> rowbuf(r.size().x);
+
+                               for(int row = 0; row < r.size().y; row++)
+                               {
+                                       r.get_raw_pixel_lines(&rowbuf[0], 1);
+                                       Pixel::ConvertPixels<DiskPixelType, 
PixelType>::convert(&rowbuf[0], im[row], r.size().x);
+                               }
+                       }
+               };
+
+               template<class PixelType, class ImageLoader> struct 
read_and_maybe_process<PixelType, PixelType, ImageLoader>
+               {
+                       static void exec(BasicImage<PixelType>& im, 
ImageLoader& r)
+                       {
+                               r.get_raw_pixel_lines(im.data(), r.size().y);
+                       }
+               };
+
+               
////////////////////////////////////////////////////////////////////////////////
        
+               //
+               // Iterate over the typelist, and decide which type to load. 
+               //
+               template<class PixelType, class ImageLoader, class List > 
struct Reader
+               {       
+                       static void read(BasicImage<PixelType>& im, 
ImageLoader& r)
+                       {
+                               if(r.datatype() == PNM::type_name<typename 
List::Type>::name())
+                               {
+                                       read_and_maybe_process<PixelType, 
typename List::Type, ImageLoader>::exec(im, r);
+                               }
+                               else
+                                       Reader<PixelType, ImageLoader, typename 
List::Next>::read(im, r);
+                       }
+               };
+
+               template<class PixelType, class ImageLoader> struct 
Reader<PixelType, ImageLoader, Head>
+               {
+                       static void read(BasicImage<PixelType>&, ImageLoader& r)
+                       {       
+                               throw 
Exceptions::Image_IO::UnsupportedImageSubType(r.name(), r.datatype() + " not 
yet supported");
+                       }
+               };
+
+               
+               
////////////////////////////////////////////////////////////////////////////////
        
+               //
+               // Driver functions for loading images.
+               //
+
+               template<class T, class ImageLoader> void 
readImage(BasicImage<T>& im, ImageLoader& r)
+               {
+                       Reader<T, ImageLoader, typename 
ImageLoader::Types>::read(im, r);
+               }
+
+               template <class T, class ImageLoader> void 
readImage(BasicImage<T>& im, std::istream& in)
+               {
+                       ImageLoader loader(in);
+                       ImageRef size = loader.size();
+                       if (im.size() != size)
+                               throw 
Exceptions::Image_IO::ImageSizeMismatch(size, im.size());
+
+                       readImage(im, loader);
+               }
+
+               template <class T, class ImageLoader> void readImage(Image<T>& 
im, std::istream& in)
+               {
+                 ImageLoader loader(in);
+                 im.resize(loader.size());
+                 readImage(im, loader);
+               }
        }
 
 

Index: cvd/internal/io/tiff.h
===================================================================
RCS file: /cvsroot/libcvd/libcvd/cvd/internal/io/tiff.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- cvd/internal/io/tiff.h      12 May 2008 17:52:01 -0000      1.3
+++ cvd/internal/io/tiff.h      2 Aug 2008 00:06:03 -0000       1.4
@@ -22,145 +22,78 @@
 #define PNM_TIFF
 
 #include <iostream>
+#include <memory>
 #include <vector>
 #include <string>
-#include <stdarg.h>
 #include <cvd/image.h>
 #include <cvd/internal/load_and_save.h>
-#include <cvd/internal/convert_pixel_types.h>
+
 namespace CVD
 {
 namespace TIFF
 {
 
-#include <tiffio.h>
+       using CVD::Internal::TypeList;
+       using CVD::Internal::Head;
+
+       class TIFFPimpl;
 
-       class tiff_in 
+       class tiff_reader
        {
                public:
-                       tiff_in(std::istream&);
-                       void get_raw_pixel_lines(unsigned char*, unsigned long 
nlines);
-                       void get_raw_pixel_lines(unsigned short*, unsigned long 
nlines);
-                       ~tiff_in();
-                       int channels(){return m_channels;}
-                       long  x_size() const {return xs;}
-                       long  y_size() const {return ys;}
-                       long  elements_per_line() const {return xs * 
m_channels;}
-                       bool is_2_byte()const {return m_is_2_byte;}
+                       tiff_reader(std::istream&);
+                       ~tiff_reader();
                        
-               private:
-                       long    xs, ys;
-                       int     m_channels;
-                       bool m_is_2_byte;
-
-                       TIFF* tif;
-                       std::streamoff start, length;
-                       std::istream&   i;
-                       unsigned int row;
-                       
-                       bool use_cooked_rgba_interface;
-                       bool inverted_grey;
-                       uint32 *raster_data;
-                       
-                       static tsize_t write(thandle_t vis, tdata_t data, 
tsize_t count);
-                       static tsize_t read(thandle_t vis, tdata_t data, 
tsize_t count);
-                       static toff_t seek(thandle_t vis, toff_t off, int dir);
-                       static toff_t size(thandle_t vis);
-                       static int close(thandle_t vis);
-                       static int map(thandle_t, tdata_t*, toff_t*);
-                       static void unmap(thandle_t, tdata_t, toff_t);
-
-
-       };
-       
-       template <class T, class S, int N> struct TIFFReader;
-
-       template <class T, class S> struct TIFFReader<T,S,1> {
-         static void read(BasicImage<T>& im, tiff_in& tiff) {
-               std::vector<S> rowbuf(tiff.x_size());
-           for (int r=0; r<tiff.y_size(); r++) {
-             tiff.get_raw_pixel_lines(&rowbuf[0], 1);
-             Pixel::ConvertPixels<S,T>::convert(&rowbuf[0], im[r], 
tiff.x_size());
-           }       
-         }
-       };
-       template <class T, class S> struct TIFFReader<T,S,3> {
-         static void read(BasicImage<T>& im, tiff_in& tiff) {
-               std::vector<Rgb<S> > rowbuf(tiff.x_size());
-           for (int r=0; r<tiff.y_size(); r++) {
-             tiff.get_raw_pixel_lines((S*)&rowbuf[0], 1);
-             Pixel::ConvertPixels<Rgb<S>,T>::convert(&rowbuf[0], im[r], 
tiff.x_size());
-           }       
-         }
-       };
+                       ImageRef size();
 
-       template <class T, class S> struct TIFFReader<T,S,4> {
-         static void read(BasicImage<T>& im, tiff_in& tiff) {
-               std::vector<Rgba<S> > rowbuf(tiff.x_size());
-           for (int r=0; r<tiff.y_size(); r++) {
-             tiff.get_raw_pixel_lines((S*)&rowbuf[0], 1);
-             Pixel::ConvertPixels<Rgba<S>,T>::convert(&rowbuf[0], im[r], 
tiff.x_size());
-           }       
-         }
-       };
+                       void get_raw_pixel_lines(unsigned char*, unsigned long 
nlines);
+                       void get_raw_pixel_lines(unsigned short*, unsigned long 
nlines);
+                       void get_raw_pixel_lines(float*, unsigned long nlines);
+                       void get_raw_pixel_lines(double*, unsigned long nlines);
 
-       template <class S> struct TIFFReader<S,S,1> {
-         static void read(BasicImage<S>& im, tiff_in& tiff) {
-           tiff.get_raw_pixel_lines(im.data(), tiff.y_size());
-         }
-       };
+                       void get_raw_pixel_lines(Rgb<unsigned char>*, unsigned 
long nlines);
+                       void get_raw_pixel_lines(Rgb<unsigned short>*, unsigned 
long nlines);
+                       void get_raw_pixel_lines(Rgb<float>*, unsigned long 
nlines);
+                       void get_raw_pixel_lines(Rgb<double>*, unsigned long 
nlines);
+
+                       void get_raw_pixel_lines(Rgba<unsigned char>*, unsigned 
long nlines);
+                       void get_raw_pixel_lines(Rgba<unsigned short>*, 
unsigned long nlines);
+                       void get_raw_pixel_lines(Rgba<float>*, unsigned long 
nlines);
+                       void get_raw_pixel_lines(Rgba<double>*, unsigned long 
nlines);
+
+                       std::string datatype();
+                       std::string name();
+
+
+                       typedef TypeList<byte, 
+                                       TypeList<unsigned short,
+                                       TypeList<float,
+                                       TypeList<double,
+                                       TypeList<Rgb<byte>, 
+                                       TypeList<Rgb<unsigned short>, 
+                                       TypeList<Rgb<float>, 
+                                       TypeList<Rgb<double>, 
+                                       TypeList<Rgba<byte>, 
+                                       TypeList<Rgba<unsigned short>, 
+                                       TypeList<Rgba<float>, 
+                                       TypeList<Rgba<double>, 
+                                                             Head> > > > > > > 
> > > > > Types;
 
-       template <class S> struct TIFFReader<Rgb<S>,S,3> {
-         static void read(BasicImage<Rgb<S> >& im, tiff_in& tiff) {
-           tiff.get_raw_pixel_lines((S*)im.data(), tiff.y_size());
-         }
+               private:
+                       TIFFPimpl* t; 
        };
 
-       template <class S> struct TIFFReader<Rgba<S>,S,4> {
-         static void read(BasicImage<Rgba<S> >& im, tiff_in& tiff) {
-           tiff.get_raw_pixel_lines((S*)im.data(), tiff.y_size());
-         }
-       };
 
        template <class T> void readTIFF(BasicImage<T>& im, std::istream& in)
        {
-         tiff_in tiff(in);
-         ImageRef size(tiff.x_size(), tiff.y_size());
-         if (im.size() != size)
-           throw Exceptions::Image_IO::ImageSizeMismatch(size, im.size());
-         readTIFF(im, tiff);
+               CVD::Internal::readImage<T, tiff_reader>(im, in);
        }
 
        template <class T> void readTIFF(Image<T>& im, std::istream& in)
        {
-         tiff_in tiff(in);
-         ImageRef size(tiff.x_size(), tiff.y_size());
-         im.resize(size);
-         readTIFF(im, tiff);
+               CVD::Internal::readImage<T, tiff_reader>(im, in);
        }
 
-       template <class T> void readTIFF(BasicImage<T>& im, tiff_in& tiff)
-       {
-         if (tiff.is_2_byte()) {
-           if (tiff.channels() == 4)
-             TIFFReader<T,unsigned short,4>::read(im,tiff);
-           else if (tiff.channels() == 3)
-             TIFFReader<T,unsigned short,3>::read(im,tiff);
-           else if (tiff.channels() == 1)
-             TIFFReader<T,unsigned short,1>::read(im,tiff);
-           else if (tiff.channels() == 2)
-             throw Exceptions::Image_IO::UnsupportedImageSubType("TIFF", 
"Grey-alpha not yet supported");
-         } else {
-           if (tiff.channels() == 4)
-             TIFFReader<T,byte,4>::read(im,tiff);
-           else if (tiff.channels() == 3)
-             TIFFReader<T,byte,3>::read(im,tiff);
-           else if (tiff.channels() == 1)
-             TIFFReader<T,byte,1>::read(im,tiff);
-           else if (tiff.channels() == 2)
-             throw Exceptions::Image_IO::UnsupportedImageSubType("TIFF", 
"Grey-alpha not yet supported");
-         }
-       }
 }
 }
 #endif

Index: cvd_src/image_io.cc
===================================================================
RCS file: /cvsroot/libcvd/libcvd/cvd_src/image_io.cc,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- cvd_src/image_io.cc 23 Apr 2008 15:34:23 -0000      1.25
+++ cvd_src/image_io.cc 2 Aug 2008 00:06:03 -0000       1.26
@@ -70,6 +70,11 @@
        what = "Error writing " + s;
 }
 
+Exceptions::Image_IO::ReadTypeMismatch::ReadTypeMismatch(const string& avail, 
const string& req)
+{
+       what = "Image input: Attempting to read " + req + " data from a file 
containing " + avail;
+}
+
 Exceptions::Image_IO::ReadTypeMismatch::ReadTypeMismatch(const bool read8)
 {
        what = string("Image input: Attempting to read ") + (read8?"8":"16") + 
"bit data from " + (read8?"16":"8")  + "bit file (probably an internal error).";

Index: pnm_src/save_postscript.cxx
===================================================================
RCS file: /cvsroot/libcvd/libcvd/pnm_src/save_postscript.cxx,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- pnm_src/save_postscript.cxx 12 Jun 2008 13:04:15 -0000      1.9
+++ pnm_src/save_postscript.cxx 2 Aug 2008 00:06:03 -0000       1.10
@@ -81,7 +81,7 @@
        unsigned long int num = 0;
        
        for(int i=0; i <n; i++)
-               num |= buf[i] << ((3-i) * 8);
+               num |= ((unsigned long)buf[i]) << ((3-i) * 8);
        
        if(num == 0)
                return "z";

Index: pnm_src/tiff.cxx
===================================================================
RCS file: /cvsroot/libcvd/libcvd/pnm_src/tiff.cxx,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- pnm_src/tiff.cxx    25 Apr 2008 22:37:15 -0000      1.7
+++ pnm_src/tiff.cxx    2 Aug 2008 00:06:03 -0000       1.8
@@ -27,54 +27,90 @@
 #include <iostream>
 
 using namespace CVD;
-using namespace TIFF;
+using namespace CVD::TIFF;
 using namespace CVD::Exceptions::Image_IO;
 using namespace std;
 
-tsize_t tiff_in::read(thandle_t vis, tdata_t data, tsize_t count)
+////////////////////////////////////////////////////////////////////////////////
+//
+// Private implementation of TIFF reading
+//
+
+class CVD::TIFF::TIFFPimpl
+{
+       public:
+               TIFFPimpl(istream&);
+               ~TIFFPimpl();
+               ImageRef size();
+               string datatype();
+               template<class C> void get_raw_pixel_lines(C* data, unsigned 
long n);
+
+       private:
+               istream& i;
+               unsigned long row;
+               ImageRef my_size;
+               string   type;
+               streamoff length;
+               ::TIFF* tif;
+               bool use_cooked_rgba_interface;
+               bool inverted_grey;
+
+               vector<uint32> raster_data;
+
+               static tsize_t write(thandle_t vis, tdata_t data, tsize_t 
count);
+               static tsize_t read(thandle_t vis, tdata_t data, tsize_t count);
+               static toff_t seek(thandle_t vis, toff_t off, int dir);
+               static toff_t size(thandle_t vis);
+               static int close(thandle_t vis);
+               static int map(thandle_t, tdata_t*, toff_t*);
+               static void unmap(thandle_t, tdata_t, toff_t);
+};
+
+
+tsize_t TIFFPimpl::read(thandle_t vis, tdata_t data, tsize_t count)
 {
-       tiff_in* i = (tiff_in*)vis;
+       TIFFPimpl* i = (TIFFPimpl*)vis;
        i->i.read((char*)data, count);
        return i->i.gcount();
 }
 
 //tsize_t tiff_in::write(thandle_t vis, tdata_t data, tsize_t count)
-tsize_t tiff_in::write(thandle_t, tdata_t, tsize_t)
+tsize_t TIFFPimpl::write(thandle_t, tdata_t, tsize_t)
 {
        return 0;
 }
 
-toff_t tiff_in::seek(thandle_t vis, toff_t off, int dir)
+toff_t TIFFPimpl::seek(thandle_t vis, toff_t off, int dir)
 {
-       tiff_in* i = (tiff_in*)vis;
+       TIFFPimpl* i = (TIFFPimpl*)vis;
 
        if(dir == SEEK_SET)
-               i->i.seekg(i->start +  off, ios_base::beg);
+               i->i.seekg(off, ios_base::beg);
        else if(dir == SEEK_CUR)
                i->i.seekg(off, ios_base::cur);
        else if(dir == SEEK_END)
                i->i.seekg(off, ios_base::end);
 
-       return i->i.tellg() - i->start;
+       return i->i.tellg();
 }
 
-toff_t tiff_in::size(thandle_t vis)
+toff_t TIFFPimpl::size(thandle_t vis)
 {
-       tiff_in* ii = (tiff_in*)vis;
+       TIFFPimpl* ii = (TIFFPimpl*)vis;
        return ii->length;
 }
 
-int tiff_in::close(thandle_t)
+int TIFFPimpl::close(thandle_t)
 {
        return 0;
 }
 
-int tiff_in::map(thandle_t, tdata_t*, toff_t*)
+int TIFFPimpl::map(thandle_t, tdata_t*, toff_t*)
 {
        return 0;
 }
 
-void tiff_in::unmap(thandle_t, tdata_t, toff_t)
+void TIFFPimpl::unmap(thandle_t, tdata_t, toff_t)
 {
 }
 
@@ -89,85 +125,89 @@
                error_msg[n-1] = 0;
 }
 
-void tiff_in::get_raw_pixel_lines(unsigned char* data, unsigned long nlines)
+
+//Compile-error free geryscale inverter.
+//Does nothing for unknown types
+template<class C> void invert(C* data, long num)
 {
-       if(m_is_2_byte)
-               throw ReadTypeMismatch(1);
+       for(long n=0; n< num; n++)
+               data[n] =  Pixel::traits<C>::max_intensity - data[n];
+}
        
-       if(!use_cooked_rgba_interface)
-       {
-               for(unsigned long i=0; i < nlines; i++, row++, 
data+=xs*m_channels)
-               {
-                               int r = TIFFReadScanline(tif, (void*)data, row);
-                               if(r == -1)
-                                       throw MalformedImage(error_msg);
+void attempt_invert(...) {}
+void attempt_invert(unsigned char* data, long num) { invert(data, num);}
+void attempt_invert(unsigned short* data, long num) { invert(data, num);}
+void attempt_invert(float* data, long num) { invert(data, num);}
+void attempt_invert(double* data, long num) { invert(data, num);}
 
-                               if(inverted_grey)
-                               {
-                                       for(long j=0; j < xs; j+=m_channels)
-                                               data[j] = 255 - data[j];
-                               }
-               }
-       }
-       else
-       {
-               if(row+nlines > (unsigned long)ys)
+
+
+template<class T> void TIFFPimpl::get_raw_pixel_lines(T* d, unsigned long 
nlines)
+{
+       if(datatype() != PNM::type_name<T>::name())
+               throw ReadTypeMismatch(datatype(), PNM::type_name<T>::name());
+
+       if(row+nlines > (unsigned long)my_size.y)
                        throw InternalLibraryError("CVD", "Read past end of 
image.");
 
-               uint32* raster = raster_data + row*xs;
-               uint32* end = raster + nlines * xs;
+       if(use_cooked_rgba_interface)
+       {
+               uint32* raster = &raster_data[row*my_size.x];
+               uint32* end = raster + nlines * my_size.x;
+
+               //We will only ever get here if the type is Rgba
+               Rgba<unsigned char>* data = reinterpret_cast<Rgba<unsigned 
char>* >(d);
        
-               for(;raster < end; raster++)
+               for(;raster < end; raster++, data++)
                {
-                       *data++ = TIFFGetR(*raster);
-                       *data++ = TIFFGetG(*raster);
-                       *data++ = TIFFGetB(*raster);
-                       *data++ = TIFFGetA(*raster);
+                       data->red   = TIFFGetR(*raster);
+                       data->green = TIFFGetG(*raster);
+                       data->blue  = TIFFGetB(*raster);
+                       data->alpha = TIFFGetA(*raster);
                }
 
                row += nlines;  
        }
-}
-
-void tiff_in::get_raw_pixel_lines(unsigned short* data, unsigned long nlines)
-{
-       if(!m_is_2_byte)
-               throw ReadTypeMismatch(0);
-
-       for(unsigned long i=0; i < nlines; i++, row++, data+=xs*m_channels)
+       else
+       {       
+               for(unsigned long i=0; i < nlines; i++, row++, d+=my_size.x)
        {
-               int r = TIFFReadScanline(tif, (void*)data, row);
-               if(r == -1)
+                       if(TIFFReadScanline(tif, (void*)d, row) == -1)
                        throw MalformedImage(error_msg);
 
                if(inverted_grey)
-               {
-                       for(long j=0; j < xs; j++)
-                               data[j] = 255 - data[j];
+                               attempt_invert(d, my_size.x);
                }
        }
 }
 
-tiff_in::~tiff_in()
+string TIFFPimpl::datatype()
+{
+       return type;
+}
+
+ImageRef TIFFPimpl::size()
+{
+       return my_size;
+}
+
+TIFFPimpl::~TIFFPimpl()
 {      
        TIFFClose(tif);
-       delete[] raster_data;
 }
 
 
-tiff_in::tiff_in(istream& is)
-:i(is),row(0),raster_data(0)
+TIFFPimpl::TIFFPimpl(istream& is)
+:i(is),row(0)
 {
        TIFFSetErrorHandler(tiff_error_handler);
-       start = i.tellg();
-
-       if(start == -1)
-               throw UnseekableIstream("TIFF");
        
+       //Find out the file size, and the suitability of the stream
        i.seekg(0, ios_base::end);
-
-       length = i.tellg() - start;
-       i.seekg(start, ios_base::beg);
+       length = i.tellg();
+       if(length == -1)
+               throw UnseekableIstream("TIFF");
+       i.seekg(0, ios_base::beg);
 
 
        tif = TIFFClientOpen("std::istream", "r", this, 
@@ -177,45 +217,98 @@
        if(tif == NULL)
                throw MalformedImage(error_msg);
 
-       unsigned int  w=0, h=0, bps=0, spp=0, photo=0, pl_type=0;
+       //Libtiff types
+       uint32 w=0, h=0;
+       uint16 bitspersample=0, spp=0, sampleformat=0, photo=0, pl_type=0;
+
 
                TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
        TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);     
-       TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps);
+       TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
        TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
        TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photo); 
        TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &pl_type);
 
-       xs = w;
-       ys = h;
-       m_channels = 4;
-       use_cooked_rgba_interface=1;
-       m_is_2_byte = 0;
-
-       //We can use out own reading interface if:
-
-       if((photo == PHOTOMETRIC_RGB  || photo == PHOTOMETRIC_MINISWHITE || 
photo == PHOTOMETRIC_MINISBLACK) &&                         
-               (spp <= 4) &&
-               (pl_type == PLANARCONFIG_CONTIG) &&                             
//Data is contiguous (not nasty planar stuff)
-               (bps == 8 || bps == 16))                                        
        //8 or 16 bits per sample
-       {
-               use_cooked_rgba_interface = 0;
-               m_is_2_byte = (bps == 16);
-               m_channels = spp;
-               inverted_grey = (photo == PHOTOMETRIC_MINISWHITE);
+       //Read the sample format. If it is missing, then it
+       //defaults to unsigned int as per the spec.
+       if(TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat) == 0)
+               sampleformat = SAMPLEFORMAT_UINT;
+
+
+       my_size.x = w;
+       my_size.y = h;
+       use_cooked_rgba_interface=1; //This is the default
+       inverted_grey=0;
+
+       //Can we use our own interface?
+       //The alternative is the cooked RGBA interface which assumes all
+       //the world is 8 bits RGBA. This will load almost all images, but 
+       //special features, such as higher bit depths will be lost.
+       //Also, the entire image has to be loaded at once, so this can use large
+       //amounts of memory.
+       if((photo == PHOTOMETRIC_RGB  || photo == PHOTOMETRIC_MINISWHITE || 
photo == PHOTOMETRIC_MINISBLACK))
+       {       
+               //We stand a chane here...
+               if(photo == PHOTOMETRIC_MINISWHITE)
+                       inverted_grey=1;
+
+               //Figure out the basic datatype
+               if(sampleformat == SAMPLEFORMAT_UINT)
+               {
+                       if(bitspersample == 8)
+                               type = PNM::type_name<unsigned char>::name();
+                       else if(bitspersample == 16)
+                               type = PNM::type_name<unsigned short>::name();
+                       else 
+                               goto keep_cooked;
+               }
+               else if(sampleformat == SAMPLEFORMAT_IEEEFP)
+               {
+                       if(bitspersample == 32)
+                               type = PNM::type_name<float>::name();
+                       else if(bitspersample == 64)
+                               type = PNM::type_name<double>::name();
+                       else 
+                               goto keep_cooked;
+               }
+               else
+                       goto keep_cooked;
+               
+               //Figure out the colourspace
+               if(spp == 1)
+                       type = type;
+               else if(spp == 2)
+                       type = "CVD::GreyAlpha<" + type  + ">";
+               else if(spp == 3)
+                       type = "CVD::Rgb<" + type  + ">";
+               else if(spp == 4)
+                       type = "CVD::Rgba<" + type  + ">";
+               else 
+                       goto keep_cooked;
+
+               use_cooked_rgba_interface=0;
        }
 
+       keep_cooked:;
+       if(use_cooked_rgba_interface == 1)
+       {       
+               //The format is "complex" and we don't know how to read it.
+               type = "CVD::Rgb<unsigned char>";
+               inverted_grey=0;
+       }
+
+
        if(use_cooked_rgba_interface)
        {
-               raster_data = new uint32[xs*ys];
+               raster_data.resize(my_size.x, my_size.y);
 
                #ifdef CVD_INTERNAL_HAVE_TIFF_ORIENTED
                        //Read the whole image
-                       if(TIFFReadRGBAImageOriented(tif, xs, ys, raster_data, 
0, ORIENTATION_TOPLEFT) == -1)
+                       if(TIFFReadRGBAImageOriented(tif, my_size.x, my_size.y, 
&raster_data[0], 0, ORIENTATION_TOPLEFT) == -1)
                                throw MalformedImage(error_msg);
                #else
                        //Read the whole (upside-down) image
-                       if(TIFFReadRGBAImage(tif, xs, ys, raster_data, 0) == -1)
+                       if(TIFFReadRGBAImage(tif, my_size.x, my_size.y, 
&raster_data[0], 0) == -1)
                                throw MalformedImage(error_msg);
                        
                        //Flip the image, a row pair at a time
@@ -236,3 +329,44 @@
 }
 
 
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Implementation of public parts of TIFF reading
+//
+
+tiff_reader::tiff_reader(istream& i)
+:t(new TIFFPimpl(i))
+{}
+
+tiff_reader::~tiff_reader()
+{
+       delete t;
+};
+
+string tiff_reader::datatype()
+{
+       return t->datatype();
+}
+
+string tiff_reader::name()
+{
+       return "TIFF";
+}
+
+ImageRef tiff_reader::size()
+{
+       return t->size();
+};
+
+//Mechanically generate the pixel reading calls.
+#define GENF(X)\
+void tiff_reader::get_raw_pixel_lines(X*d, unsigned long 
n){t->get_raw_pixel_lines(d, n);}\
+void tiff_reader::get_raw_pixel_lines(Rgb<X>*d, unsigned long 
n){t->get_raw_pixel_lines(d, n);}\
+void tiff_reader::get_raw_pixel_lines(Rgba<X>*d, unsigned long 
n){t->get_raw_pixel_lines(d, n);}
+
+GENF(unsigned char)
+GENF(unsigned short)
+GENF(float)
+GENF(double)




reply via email to

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