Logo Search packages:      
Sourcecode: labplot version File versions

qtiffio.cc

// Ver: 1.2
//
// Read TIFF image files with Qt
// Copyright (c) 1999 by Markus L. Noga <markus@noga.de>
//  
// Reader improvement to read 8 and 24 bits by Dmitry Fedorov
// Write TIFF image files with Qt 
// Copyright (c) 2001-2002 by Dmitry V. Fedorov <www.dimin.net>
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 

#ifdef HAVE_TIFF

#include <stdio.h>
#include <stdlib.h>
#include <qglobal.h>

#include <qmessagebox.h>

#ifdef _WS_WIN_
  #define MAP_FAILED 1
  #include "lib/tiffio.h"
#else
  #include <sys/types.h>
  #include <sys/mman.h>
  #include <tiffio.h>
#endif

#include <qimage.h>
#include <qfile.h>

#include "qtiffio.h"

//! QIODevice / libtiff read wrapper
//
static tsize_t tiff_read(thandle_t handle,tdata_t data,tsize_t size) 
{
  QIODevice *iod=(QIODevice*) handle;
  return (tsize_t) iod->readBlock((char*) data,size);
}

//! QIODevice / libtiff write wrapper
//
static tsize_t tiff_write(thandle_t handle,tdata_t data,tsize_t size) 
{
  QIODevice *iod=(QIODevice*) handle;
  return (tsize_t) iod->writeBlock((const char*) data,size);
  //iod->flush();
}

//! QIODevice / libtiff seek wrapper
/*! \returns the current file position. libtiff wants that.
*/
static toff_t tiff_seek(thandle_t handle, toff_t offset, int whence) 
{
  QIODevice *iod=(QIODevice*) handle;

  if(whence==SEEK_SET)
    iod->at(offset);
  else if(whence==SEEK_CUR)
    iod->at(iod->at()+offset);
  else if(whence==SEEK_END)
    iod->at(iod->size()+offset);
  else
    return 0; // -1 dima
  
  return iod->at();
}

//! QIODevice / libtiff close wrapper
/*! This is a dummy, the IO device's owner will close it.
*/
static int tiff_close(thandle_t handle) {
  QIODevice *iod=(QIODevice*) handle;
  iod->flush();
  iod->close();
  return 0;
}

//! QIODevice / libtiff size wrapper
//
static toff_t tiff_size(thandle_t handle) {
  QIODevice *iod=(QIODevice*) handle;
  return iod->size();
}

//! QIODevice / libtiff mmap wrapper
/*! \warning always returns MAP_FAILED.
*/
static int tiff_mmap(thandle_t handle,tdata_t* data,toff_t* size) {
  handle=handle; data=data; size=size;

// originally returns MAP_FAILED defined in sys/mman.h  as "(void *) -1", whatever that means
// we use a more convenient value here
  return -1;
}

//! QIODevice / libtiff write wrapper
/*! \warning because you can't mmap, this is a dummy.
*/
static void tiff_unmap(thandle_t handle, tdata_t data, toff_t size) {
  handle=handle; data=data; size=size;
}

//! QImageIO read handler for TIFF files.
//
static void read_tiff_image(QImageIO *iio) {
  QImage img;
  int state=-1;

  unsigned size = 0;
  uint32 height = 0; 
  uint32 width = 0; 
      uint16 bitspersample = 1;
      uint16 samplesperpixel = 1;
      uint32 rowsperstrip;  
      uint16 photometric = PHOTOMETRIC_MINISWHITE;
      uint16 compression = COMPRESSION_NONE;
      //uint32 x = 0;
      uint32 y = 0;


  // pass on file name if known
  const char *fileName;
  QFile *f = (QFile*)(iio->ioDevice());
  
  if (f != 0) fileName = f->name();
  else fileName = "QIODevice";

  // open without memory mapping.
  //
  TIFF *tif=TIFFClientOpen(fileName,"rm",
                           (thandle_t) (iio->ioDevice()),
                           tiff_read,
                           tiff_write,
                           tiff_seek,
                           tiff_close,
                           tiff_size,
                           tiff_mmap,
                           tiff_unmap );
  
  if(tif) 
  {

            TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
            TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
            TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
            TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
            TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);   
            TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
    size=width*height;

    if (bitspersample*samplesperpixel != 8)
    {

      uint32 *bits=(uint32*) _TIFFmalloc(size * sizeof (uint32));
    
      if(bits) {
        if (TIFFReadRGBAImage(tif, width, height, bits, 0)) {

          // successfully read. now convert.
          img.create(width,height,32);

          // no #ifdef because qRed is inline,
          // but the compiler will optimize this out.
          if(TIFFGetR(0x1234567)==qRed  (0x1234567) &&
             TIFFGetG(0x1234567)==qGreen(0x1234567) &&
             TIFFGetB(0x1234567)==qBlue (0x1234567)    ) 
          {
            // just mirror on x axis.
            for(unsigned y=0; y<height; y++) memcpy(img.scanLine(height-1-y),bits+y*width,width*4);
          } 
          else 
          {
            // swap bytes
            uint32 *inp=bits;
            for(unsigned y=0; y<height; y++) 
            {
              QRgb *row=(QRgb*) (img.scanLine(height-1-y));
              for(unsigned x=0; x<width; x++) 
              {
                const uint32 col=*(inp++);
                row[x]=qRgb(TIFFGetR(col), TIFFGetG(col), TIFFGetB(col) ) | (TIFFGetA(col)<<24);
              }
            }
          }
          iio->setImage(img);
          state=0;
        }
        _TIFFfree(bits);
      }
    } // if RGB
    else // Here we got 8 bits
    {
      img.create(width, height, 8, 256, QImage::IgnoreEndian);

      //*********************************************************
      // INIT PALETTE
      //*********************************************************
      int i;
      QColor color;

                  if (photometric == PHOTOMETRIC_PALETTE)
      { // palette
                    uint16 *red;
                    uint16 *green;
                    uint16 *blue;
                    
                    TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); 
        for (i=(1 << bitspersample)-1; i>=0; i--)
        {
          color.setRgb(red[i], green[i], blue[i]);
          img.setColor(i, color.rgb());
        }
      }
      else
      { 
        // if greyscale images
        //if (photometric == PHOTOMETRIC_MINISBLACK) 
        for (i=0; i<256; i++)
        {
          color.setRgb(i, i, i);
          img.setColor(i, color.rgb());
        }
      }
      
      //*********************************************************
      // READ TIFF BITS
      //*********************************************************
      for(y=0; y<height; y++) TIFFReadScanline(tif, img.scanLine(y), y, 0); 

      iio->setImage(img);
      state=0;
    } // if 8 bits


    TIFFClose(tif);
  } // if tif
  iio->setStatus(state);
}
       
//! QImageIO write handler for TIFF files.
//
static void write_tiff_image(QImageIO *iio) 
{
  QImage img;
  int state=-1;

  const char *fileName;
  QFile *f = (QFile*)(iio->ioDevice());
  if (f != 0) fileName = f->name();
  else fileName = "QIODevice";
  img = iio->image();


  TIFF *out=TIFFClientOpen(fileName,"w",
                           (thandle_t) (iio->ioDevice()),
                           tiff_read,
                           tiff_write,
                           tiff_seek,
                           tiff_close,
                           tiff_size,
                           tiff_mmap,
                           tiff_unmap );
  
  if(out) 
  {
            uint32 height;
            uint32 width;
            uint32 rowsperstrip = (uint32) -1;
            uint16 bitspersample;
            uint16 samplesperpixel;
            uint16 photometric = PHOTOMETRIC_RGB;
            uint16 compression;

            uint32 x, y;

            width = img.width();
            height = img.height();
            bitspersample = img.depth();
            samplesperpixel = ((bitspersample == 24) || (bitspersample == 32)) ? 3 : 1;

    if (img.depth()>=24) photometric = PHOTOMETRIC_RGB;
    if ((img.depth()<24)&&(img.isGrayscale()!=TRUE)) photometric = PHOTOMETRIC_PALETTE;
    if ((img.depth()<24)&&(img.isGrayscale()==TRUE)) photometric = PHOTOMETRIC_MINISBLACK;

    // handle standard width/height/bpp stuff
            TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
            TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
            TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
            TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, ((bitspersample == 32) ? 24 : bitspersample) / samplesperpixel);
            TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
            TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);     // single image plane 
            TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
            TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(out, rowsperstrip));

    // handle metrics
    //TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
            //TIFFSetField(out, TIFFTAG_XRESOLUTION, 0.0254*30.0);
            //TIFFSetField(out, TIFFTAG_YRESOLUTION, 0.0254*30.0);

            // only one page
    TIFFSetField(out, TIFFTAG_SUBFILETYPE, 0);

    TIFFFlushData(out);

            // palettes (image colormaps are automatically scaled to 16-bits)
            if (photometric == PHOTOMETRIC_PALETTE) {
                  uint16 *r, *g, *b;
                  uint16 nColors = img.numColors();

                  r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * nColors);
                  g = r + nColors;
                  b = g + nColors;

                  for (int i = nColors - 1; i >= 0; i--) 
      {
                        r[i] = (uint16) qRed(img.color(i));
                        g[i] = (uint16) qGreen(img.color(i));
                        b[i] = (uint16) qBlue(img.color(i));
                  }

                  TIFFSetField(out, TIFFTAG_COLORMAP, r, g, b);

                  _TIFFfree(r);
            }
    
    //f->flush();
    //TIFFFlushData(out);
            
    // compression
            switch(bitspersample) {
                  case 1 :
                        compression = COMPRESSION_CCITTFAX4;
                        break;

                  case 8 :
                  case 24 :
                  case 32 :
                        compression = COMPRESSION_PACKBITS;
                        break;

                  default :
                        compression = COMPRESSION_NONE;
                        break;
            }

            TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
    //f->flush();
    TIFFFlushData(out);

            // read the DIB lines from bottom to top
            // and save them in the TIF
            // -------------------------------------
    
            switch(bitspersample) {                   
                  case 1 :
                  case 4 :
                  case 8 :
                  {
                        for (y = 0; y < height; y++) {
                              BYTE *bits = img.scanLine(y);
                              TIFFWriteScanline(out,bits, y, 0);
          f->flush();
                        }
                        break;
                  }                       

                  case 24:
      case 32:
                  {
                        BYTE *buffer = (BYTE *)calloc(width,3);
        QRgb *bufIn;

                        for (y = 0; y < height; y++) 
        {
                              // TIFFs store color data RGB instead of BGR
          BYTE *pBuf = buffer;
          bufIn = (QRgb*) img.scanLine(y);
          for (x=0; x<width; x++) 
          {
            pBuf[0] = (BYTE) qRed(*(bufIn+x));
            pBuf[1] = (BYTE) qGreen(*(bufIn+x));
            pBuf[2] = (BYTE) qBlue(*(bufIn+x));
            pBuf += 3;
          }
  
                              // write the scanline to disc
                              TIFFWriteScanline(out, buffer, y, 0);
          f->flush();
                        }
        free(buffer);
                        break;
                  }
            }
    TIFFFlushData(out);
    f->flush();
    TIFFClose(out);
    state=0;
      }
  
  iio->setStatus(state);
}
       
//! Add TIFF format capability to QImage.
//
void qInitTiffIO() {
  // Qt regexps don't cut it - we're missing an OR-Operator.
  QImageIO::defineIOHandler("TIFF", "^[MI][MI][\\x01*][\\x01*]", 0, read_tiff_image, write_tiff_image);
}

#endif

Generated by  Doxygen 1.6.0   Back to index