File indexing completed on 2025-01-05 04:12:06

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2015 C. Barth Netterfield                             *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *                                                                         *
0006  *   This program is free software; you can redistribute it and/or modify  *
0007  *   it under the terms of the GNU General Public License as published by  *
0008  *   the Free Software Foundation; either version 2 of the License, or     *
0009  *   (at your option) any later version.                                   *
0010  *                                                                         *
0011  ***************************************************************************/
0012 
0013 #include "tiff16source.h"
0014 #include <tiffio.h>
0015 
0016 
0017 #include <QXmlStreamWriter>
0018 #include <QColor>
0019 
0020 
0021 using namespace Kst;
0022 
0023 static const QString tiff16TypeString = "Tiff16 image";
0024 
0025 class Tiff16Source::Config {
0026   public:
0027     Config() {
0028     }
0029 
0030     void read(QSettings *cfg, const QString& fileName = QString()) {
0031       Q_UNUSED(fileName);
0032       cfg->beginGroup(tiff16TypeString);
0033       cfg->endGroup();
0034     }
0035 
0036     void save(QXmlStreamWriter& s) {
0037       Q_UNUSED(s);
0038     }
0039 
0040     void load(const QDomElement& e) {
0041       Q_UNUSED(e);
0042     }
0043 };
0044 
0045 
0046 
0047 //
0048 // Vector interface
0049 //
0050 
0051 class DataInterfaceTiff16Vector : public DataSource::DataInterface<DataVector>
0052 {
0053 public:
0054   DataInterfaceTiff16Vector(unsigned short **z) : _z(z), _frameCount(0) {}
0055 
0056   // read one element
0057   int read(const QString&, DataVector::ReadInfo&);
0058 
0059   // named elements
0060   QStringList list() const { return _vectorList; }
0061   bool isListComplete() const { return true; }
0062   bool isValid(const QString&) const;
0063 
0064   // T specific
0065   const DataVector::DataInfo dataInfo(const QString&, int frame=0) const;
0066   void setDataInfo(const QString&, const DataVector::DataInfo&) {}
0067 
0068   // meta data
0069   QMap<QString, double> metaScalars(const QString&);
0070   QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); }
0071 
0072 
0073   // no interface
0074 
0075   unsigned short **_z;
0076 
0077   QStringList _vectorList;
0078   int _frameCount;
0079 
0080   void init();
0081   void clear();
0082 };
0083 
0084 
0085 void DataInterfaceTiff16Vector::clear()
0086 {
0087   _vectorList.clear();
0088   _frameCount = 0;
0089 }
0090 
0091 
0092 void DataInterfaceTiff16Vector::init()
0093 {
0094   _vectorList.append( "GRAY" );
0095 }
0096 
0097 
0098 const DataVector::DataInfo DataInterfaceTiff16Vector::dataInfo(const QString &field, int frame) const
0099 {
0100   Q_UNUSED(frame)
0101   if (!_vectorList.contains(field))
0102     return DataVector::DataInfo();
0103 
0104   return DataVector::DataInfo(_frameCount, 1);
0105 }
0106 
0107 
0108 
0109 int DataInterfaceTiff16Vector::read(const QString& field, DataVector::ReadInfo& p)
0110 {
0111   int i = 0;
0112   int s = p.startingFrame;
0113   int n = p.numberOfFrames;
0114 
0115   if ( field=="INDEX" ) {
0116     for ( i=0; i<n; ++i ) {
0117       p.data[i] = i + s;
0118     }
0119   } else if ( field=="GRAY" ) {
0120     for ( i = s; i<s+n; ++i ) {
0121       p.data[i-s] = (*_z)[i];
0122     }
0123   }
0124 
0125   return i;
0126 }
0127 
0128 
0129 bool DataInterfaceTiff16Vector::isValid(const QString& field) const {
0130   return  _vectorList.contains( field );
0131 }
0132 
0133 // TODO FRAMES only in vector?
0134 QMap<QString, double> DataInterfaceTiff16Vector::metaScalars(const QString&)
0135 {
0136   QMap<QString, double> m;
0137   m["FRAMES"] = _frameCount;
0138   return m;
0139 }
0140 
0141 
0142 //
0143 // Matrix interface
0144 //
0145 
0146 class DataInterfaceTiff16Matrix : public DataSource::DataInterface<DataMatrix>
0147 {
0148 public:
0149 
0150   DataInterfaceTiff16Matrix(unsigned short **z, int *width, int *height) : _image(z),_width(width),_height(height) {}
0151 
0152   // read one element
0153   int read(const QString&, DataMatrix::ReadInfo&);
0154 
0155   // named elements
0156   QStringList list() const { return _matrixList; }
0157   bool isListComplete() const { return true; }
0158   bool isValid(const QString&) const;
0159 
0160   // T specific
0161   const DataMatrix::DataInfo dataInfo(const QString&, int frame=0) const;
0162   void setDataInfo(const QString&, const DataMatrix::DataInfo&) {}
0163 
0164   // meta data
0165   QMap<QString, double> metaScalars(const QString&) { return QMap<QString, double>(); }
0166   QMap<QString, QString> metaStrings(const QString&) { return QMap<QString, QString>(); }
0167 
0168 
0169   // no interface
0170   unsigned short **_image;
0171   int *_width;
0172   int *_height;
0173 
0174   QStringList _matrixList;
0175 
0176   void init();
0177   void clear();
0178 };
0179 
0180 void DataInterfaceTiff16Matrix::clear()
0181 {
0182   _matrixList.clear();
0183 }
0184 
0185 void DataInterfaceTiff16Matrix::init()
0186 {
0187   _matrixList.append( "GRAY" );
0188 }
0189 
0190 
0191 
0192 const DataMatrix::DataInfo DataInterfaceTiff16Matrix::dataInfo(const QString& matrix, int frame) const
0193 {
0194   Q_UNUSED(frame)
0195   if ( !*_image || (*_width * *_height == 0) || !_matrixList.contains( matrix ) ) {
0196     return DataMatrix::DataInfo();
0197   }
0198 
0199   DataMatrix::DataInfo info;
0200   info.xSize = *_width;
0201   info.ySize = *_height;
0202 
0203   return info;
0204 }
0205 
0206 
0207 int DataInterfaceTiff16Matrix::read(const QString& field, DataMatrix::ReadInfo& p)
0208 {
0209   if ( !*_image ) {
0210     return 0;
0211   }
0212 
0213   int y0 = p.yStart;
0214   int y1 = p.yStart + p.yNumSteps;
0215   int x0 = p.xStart;
0216   int x1 = p.xStart + p.xNumSteps;
0217   double* z = p.data->z;
0218 
0219   int i = 0, j;
0220 
0221   if ( field=="GRAY") {
0222     for (int px = p.xStart; px<x1; ++px ) {
0223       for (int py=y1-1; py>=p.yStart; py-- ) {
0224         j = py * *_width + px;
0225         z[i] = (*_image)[j];
0226         ++i;
0227       }
0228     }
0229   }
0230     // set the suggested matrix transform params: pixel index....
0231   p.data->xMin = x0;
0232   p.data->yMin = y0;
0233   p.data->xStepSize = 1;
0234   p.data->yStepSize = 1;
0235 
0236   return i;
0237 }
0238 
0239 
0240 bool DataInterfaceTiff16Matrix::isValid(const QString& field) const {
0241   return  _matrixList.contains( field );
0242 }
0243 
0244 
0245 
0246 
0247 
0248 //
0249 // Tiff16Source
0250 //
0251 
0252 Tiff16Source::Tiff16Source(Kst::ObjectStore *store, QSettings *cfg, const QString& filename, const QString& type, const QDomElement& e) :
0253   Kst::DataSource(store, cfg, filename, type),
0254   _z(NULL), _config(0L),
0255   iv(new DataInterfaceTiff16Vector(&_z)),
0256   im(new DataInterfaceTiff16Matrix(&_z, &_width, &_height))
0257 {
0258   setInterface(iv);
0259   setInterface(im);
0260 
0261   startUpdating(None);
0262 
0263   _valid = false;
0264   if (!type.isEmpty() && type != tiff16TypeString) {
0265     return;
0266   }
0267 
0268   _config = new Tiff16Source::Config;
0269   _config->read(cfg, filename);
0270   if (!e.isNull()) {
0271     _config->load(e);
0272   }
0273 
0274   if (init()) {
0275     _valid = true;
0276   }
0277   registerChange();
0278 }
0279 
0280 
0281 Tiff16Source::~Tiff16Source() {
0282   delete _config;
0283   delete [] _z;
0284   _z = 0L;
0285   _config = 0L;
0286 }
0287 
0288 
0289 const QString& Tiff16Source::typeString() const {
0290   return tiff16TypeString;
0291 }
0292 
0293 
0294 void Tiff16Source::reset() {
0295   init();
0296   Object::reset();
0297 }
0298 
0299 
0300 bool Tiff16Source::init()
0301 {
0302   //_image = Tiff16();
0303   if (_z) {
0304     delete [] _z;
0305     _z = 0L;
0306   }
0307 
0308   iv->clear();
0309   im->clear();
0310 
0311   TIFF *tif=TIFFOpen(_filename.toAscii(), "r");
0312   if (tif) {
0313     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &_width);
0314     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &_height);
0315 
0316     _z = new unsigned short[_width*_height];
0317 
0318     char *buf = (char *)_z;
0319 
0320     int linesize = TIFFScanlineSize(tif);
0321     for (int i = 0; i < _height; i++) {
0322       TIFFReadScanline(tif, &buf[i * linesize], i, 0);
0323     }
0324   } else {
0325     _width = _height = 0;
0326   }
0327 
0328   iv->init();
0329   im->init();
0330   registerChange();
0331   return true;
0332 }
0333 
0334 
0335 Kst::Object::UpdateType Tiff16Source::internalDataSourceUpdate()
0336 {
0337   int newNF = _width * _height;
0338   bool isnew = newNF != iv->_frameCount;
0339 
0340   iv->_frameCount = newNF;
0341 
0342   return (isnew ? Kst::Object::Updated : Kst::Object::NoChange);
0343 }
0344 
0345 
0346 bool Tiff16Source::isEmpty() const {
0347   return iv->_frameCount < 1;
0348 }
0349 
0350 
0351 QString Tiff16Source::fileType() const {
0352   return tiff16TypeString;
0353 }
0354 
0355 
0356 void Tiff16Source::save(QXmlStreamWriter &streamWriter) {
0357   Kst::DataSource::save(streamWriter);
0358 }
0359 
0360 /* TODO needed?
0361 int Tiff16Source::readScalar(double &S, const QString& scalar) {
0362   if (scalar == "FRAMES") {
0363     S = _frameCount;
0364     return 1;
0365   }
0366   return 0;
0367 }
0368 
0369 
0370 int Tiff16Source::readString(QString &S, const QString& string) {
0371   if (string == "FILE") {
0372     S = _filename;
0373     return 1;
0374   }
0375   return 0;
0376 }
0377 */
0378 
0379 
0380 
0381 
0382 //
0383 // Tiff16SourcePlugin
0384 //
0385 
0386 QString Tiff16SourcePlugin::pluginName() const { return tr("Tiff16 Source Reader"); }
0387 QString Tiff16SourcePlugin::pluginDescription() const { return tr("Tiff16 Source Reader"); }
0388 
0389 
0390 Kst::DataSource *Tiff16SourcePlugin::create(Kst::ObjectStore *store,
0391                                             QSettings *cfg,
0392                                             const QString &filename,
0393                                             const QString &type,
0394                                             const QDomElement &element) const {
0395 
0396   return new Tiff16Source(store, cfg, filename, type, element);
0397 }
0398 
0399 
0400 
0401 QStringList Tiff16SourcePlugin::matrixList(QSettings *cfg,
0402                                              const QString& filename,
0403                                              const QString& type,
0404                                              QString *typeSuggestion,
0405                                              bool *complete) const {
0406 
0407 
0408   if (typeSuggestion) {
0409     *typeSuggestion = tiff16TypeString;
0410   }
0411   if ((!type.isEmpty() && !provides().contains(type)) ||
0412       0 == understands(cfg, filename)) {
0413     if (complete) {
0414       *complete = false;
0415     }
0416     return QStringList();
0417   }
0418   QStringList matrixList;
0419 
0420   if (complete) {
0421     *complete = true;
0422   }
0423 
0424   //if ( !Tiff16Reader::imageFormat( filename ).isEmpty() ) {
0425     matrixList.append( "GRAY" );
0426   //}
0427   return matrixList;
0428 
0429 }
0430 
0431 
0432 QStringList Tiff16SourcePlugin::scalarList(QSettings *cfg,
0433                                             const QString& filename,
0434                                             const QString& type,
0435                                             QString *typeSuggestion,
0436                                             bool *complete) const {
0437 
0438   QStringList scalarList;
0439 
0440   if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) {
0441     if (complete) {
0442       *complete = false;
0443     }
0444     return QStringList();
0445   }
0446 
0447   if (typeSuggestion) {
0448     *typeSuggestion = tiff16TypeString;
0449   }
0450 
0451   scalarList.append("FRAMES");
0452   return scalarList;
0453 
0454 }
0455 
0456 
0457 QStringList Tiff16SourcePlugin::stringList(QSettings *cfg,
0458                                       const QString& filename,
0459                                       const QString& type,
0460                                       QString *typeSuggestion,
0461                                       bool *complete) const {
0462 
0463   QStringList stringList;
0464 
0465   if ((!type.isEmpty() && !provides().contains(type)) || 0 == understands(cfg, filename)) {
0466     if (complete) {
0467       *complete = false;
0468     }
0469     return QStringList();
0470   }
0471 
0472   if (typeSuggestion) {
0473     *typeSuggestion = tiff16TypeString;
0474   }
0475 
0476   stringList.append("FILENAME");
0477   return stringList;
0478 
0479 }
0480 
0481 QStringList Tiff16SourcePlugin::fieldList(QSettings *cfg,
0482                                             const QString& filename,
0483                                             const QString& type,
0484                                             QString *typeSuggestion,
0485                                             bool *complete) const {
0486   Q_UNUSED(type)
0487   Q_UNUSED(cfg)
0488   QStringList fieldList;
0489 
0490   if (complete) {
0491     *complete = true;
0492   }
0493 
0494   if (typeSuggestion) {
0495     *typeSuggestion = tiff16TypeString;
0496   }
0497 
0498   fieldList.append("INDEX");
0499   fieldList.append( "GRAY" );
0500 
0501   return fieldList;
0502 }
0503 
0504 
0505 int Tiff16SourcePlugin::understands(QSettings *cfg, const QString& filename) const {
0506   Q_UNUSED(cfg)
0507 
0508   quint16 spp, bpp, is_tiled;
0509 
0510   if (filename.toLower().endsWith(".tiff") ||
0511       filename.toLower().endsWith(".tif")) {
0512 
0513     TIFF *tif=TIFFOpen(filename.toAscii(), "r");
0514 
0515     if (tif) {
0516       TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bpp);
0517       TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
0518       is_tiled = TIFFIsTiled(tif);
0519 
0520       TIFFClose(tif);
0521 
0522 
0523       if ((bpp == 16) && (spp = 1) && (is_tiled == 0)) {
0524           return 91;
0525       }
0526     }
0527   }
0528   return 0;
0529 }
0530 
0531 
0532 
0533 bool Tiff16SourcePlugin::supportsTime(QSettings *cfg, const QString& filename) const {
0534   //FIXME
0535   Q_UNUSED(cfg)
0536   Q_UNUSED(filename)
0537   return true;
0538 }
0539 
0540 
0541 QStringList Tiff16SourcePlugin::provides() const {
0542   QStringList rc;
0543   rc += tiff16TypeString;
0544   return rc;
0545 }
0546 
0547 
0548 Kst::DataSourceConfigWidget *Tiff16SourcePlugin::configWidget(QSettings *cfg, const QString& filename) const {
0549 
0550   Q_UNUSED(cfg)
0551   Q_UNUSED(filename)
0552   return 0;;
0553 
0554 }
0555 
0556 #ifndef QT5
0557 Q_EXPORT_PLUGIN2(kstdata_tiff16source, Tiff16SourcePlugin)
0558 #endif
0559 
0560 // vim: ts=2 sw=2 et