USGS

Isis 3.0 Object Programmers' Reference

Home

TiffImporter.cpp
1 #include <iostream>
2 #include <iomanip>
3 
4 #include <QDebug>
5 #include <QDomDocument>
6 #include <QDomElement>
7 #include <QDomNode>
8 
9 #include "TiffImporter.h"
10 
11 #include "Angle.h"
12 #include "FileName.h"
13 #include "IException.h"
14 #include "IString.h"
15 #include "ProjectionFactory.h"
16 #include "Pvl.h"
17 #include "PvlGroup.h"
18 #include "PvlTranslationManager.h"
19 #include "TProjection.h"
20 
21 namespace Isis {
28 
29  // Open the TIFF image
30  m_image = NULL;
31  if ((m_image = XTIFFOpen(inputName.expanded().toAscii().data(), "r")) == NULL) {
33  QString("Could not open TIFF image [") + inputName.expanded().toAscii().data() + "]", _FILEINFO_);
34  }
35 
36  // Get its constant dimensions. Note, height seems to get reset to 0 if
37  // called before setting width.
38  uint32 height;
39  TIFFGetField(m_image, TIFFTAG_IMAGELENGTH, &height);
40  setLines(height);
41 
42  uint32 width;
43  TIFFGetField(m_image, TIFFTAG_IMAGEWIDTH, &width);
44  setSamples(width);
45 
46  TIFFGetField(m_image, TIFFTAG_SAMPLESPERPIXEL, &m_samplesPerPixel);
47 
48  // Setup the width and height of the image
49  unsigned long imagesize = lines() * samples();
50  m_raster = NULL;
51  if ((m_raster = (uint32 *) malloc(sizeof(uint32) * imagesize)) == NULL) {
53  "Could not allocate enough memory", _FILEINFO_);
54  }
55 
56  // Read the image into the memory buffer
57  if (TIFFReadRGBAImage(m_image, samples(), lines(), m_raster, 0) == 0) {
59  "Could not read image", _FILEINFO_);
60  }
61 
62  // Deal with photometric interpretations
63  if (TIFFGetField(m_image, TIFFTAG_PHOTOMETRIC, &m_photo) == 0) {
65  "Image has an undefined photometric interpretation", _FILEINFO_);
66  }
67 
68  // Get the geotiff info (if available)
69  m_geotiff = NULL;
70  m_geotiff = GTIFNew(m_image);
71 
73  }
74 
75 
80  free(m_raster);
81  m_raster = NULL;
82 
83  GTIFFree(m_geotiff);
84  m_geotiff = NULL;
85 
86  XTIFFClose(m_image);
87  m_image = NULL;
88  }
89 
90 
105 
106  Pvl outPvl;
107  outPvl.addGroup(PvlGroup("Mapping"));
108 
109  geocode_t modelType;
110  geocode_t rasterType;
111  geocode_t coordSysType;
112 
113  if ((GTIFKeyGet(m_geotiff, GTModelTypeGeoKey, &modelType, 0, 1) == 1) &&
114  ((modelType == 1) || (modelType == 2))) { // 1=ModelTypeProjected, 2=ModelTypeGeographic
115 
116  if ((GTIFKeyGet(m_geotiff, GTRasterTypeGeoKey, &rasterType, 0, 1) == 1) &&
117  (rasterType == 1 || rasterType == 2)) { // Area || Point
118 
119  // See if this geogiff uses a coded projection. That is, the projection parameters are not
120  // explicitly set. A code in the GEOTIF tag indicates a set of parameters for this
121  // projection.
122  if (GTIFKeyGet(m_geotiff, ProjectedCSTypeGeoKey, &coordSysType, 0, 1) == 1) {
123 
124  // Get the mapping group data for this code: proj name, clat, clon, ...
125  FileName transFile((QString) "$base/translations/geotiff/" +
126  toString(coordSysType) + ".trn");
127  if (transFile.fileExists()) {
128  Pvl tmp;
129  tmp += PvlKeyword("Code", toString(coordSysType));
130  PvlTranslationManager geoTiffCodeTranslater(tmp, transFile.expanded());
131  geoTiffCodeTranslater.Auto(outPvl);
132  }
133  }
134 
135  // The following is here for when this gets generalized to handle non coded projections
136  // (i.e., the real proj parameters have values and the code is not used)
137  else if (1 == 0) {
138  geocode_t geoCode;
139  if (GTIFKeyGet(m_geotiff, GeographicTypeGeoKey, &geoCode, 0, 1) == 1) {
140  std::cout << "GeographicTypeGeoKey = " << geoCode << std::endl;
141  }
142  else {
143  std::cout << "no GeographicTypeGeoKey" << std::endl;
144  }
145 
146  if (GTIFKeyGet(m_geotiff, GeogAngularUnitsGeoKey, &geoCode, 0, 1) == 1) {
147  std::cout << "GeogAngularUnitsGeoKey = " << geoCode << std::endl;
148  }
149  else {
150  std::cout << "no GeogAngularUnitsGeoKey" << std::endl;
151  }
152 
153  if (GTIFKeyGet(m_geotiff, GeogEllipsoidGeoKey, &geoCode, 0, 1) == 1) {
154  std::cout << "GeogEllipsoidGeoKey = " << geoCode << std::endl;
155  }
156  else {
157  std::cout << "no GeogEllipsoidGeoKey" << std::endl;
158  }
159 
160  if (GTIFKeyGet(m_geotiff, GeogSemiMajorAxisGeoKey, &geoCode, 0, 1) == 1) {
161  std::cout << "GeogSemiMajorAxisGeoKey = " << geoCode << std::endl;
162  }
163  else {
164  std::cout << "no GeogSemiMajorAxisGeoKey" << std::endl;
165  }
166 
167  if (GTIFKeyGet(m_geotiff, GeogSemiMinorAxisGeoKey, &geoCode, 0, 1) == 1) {
168  std::cout << "GeogSemiMinorAxisGeoKey = " << geoCode << std::endl;
169  }
170  else {
171  std::cout << "no GeogSemiMinorAxisGeoKey" << std::endl;
172  }
173 
174  if (GTIFKeyGet(m_geotiff, GeogInvFlatteningGeoKey, &geoCode, 0, 1) == 1) {
175  std::cout << "GeogInvFlatteningGeoKey = " << geoCode << std::endl;
176  }
177  else {
178  std::cout << "no GeogInvFlatteningGeoKey" << std::endl;
179  }
180 
181  if (GTIFKeyGet(m_geotiff, ProjCoordTransGeoKey, &geoCode, 0, 1) == 1) {
182  std::cout << "ProjCoordTransGeoKey = " << geoCode << std::endl;
183  }
184  else {
185  std::cout << "no ProjCoordTransGeoKey" << std::endl;
186  }
187 
188  if (GTIFKeyGet(m_geotiff, ProjLinearUnitsGeoKey, &geoCode, 0, 1) == 1) {
189  std::cout << "ProjLinearUnitsGeoKey = " << geoCode << std::endl;
190  }
191  else {
192  std::cout << "no ProjLinearUnitsGeoKey" << std::endl;
193  }
194 
195  if (GTIFKeyGet(m_geotiff, ProjStdParallel1GeoKey, &geoCode, 0, 1) == 1) {
196  std::cout << "ProjStdParallel1GeoKey = " << geoCode << std::endl;
197  }
198  else {
199  std::cout << "no ProjStdParallel1GeoKey" << std::endl;
200  }
201 
202  if (GTIFKeyGet(m_geotiff, ProjStdParallel2GeoKey, &geoCode, 0, 1) == 1) {
203  std::cout << "ProjStdParallel2GeoKey = " << geoCode << std::endl;
204  }
205  else {
206  std::cout << "no ProjStdParallel2GeoKey" << std::endl;
207  }
208 
209  if (GTIFKeyGet(m_geotiff, ProjNatOriginLongGeoKey, &geoCode, 0, 1) == 1) {
210  std::cout << "ProjNatOriginLongGeoKey = " << geoCode << std::endl;
211  }
212  else {
213  std::cout << "no ProjNatOriginLongGeoKey" << std::endl;
214  }
215 
216  if (GTIFKeyGet(m_geotiff, ProjNatOriginLatGeoKey, &geoCode, 0, 1) == 1) {
217  std::cout << "ProjNatOriginLatGeoKey = " << geoCode << std::endl;
218  }
219  else {
220  std::cout << "no ProjNatOriginLatGeoKey" << std::endl;
221  }
222 
223  if (GTIFKeyGet(m_geotiff, ProjFalseEastingGeoKey, &geoCode, 0, 1) == 1) {
224  std::cout << "ProjFalseEastingGeoKey = " << geoCode << std::endl;
225  }
226  else {
227  std::cout << "no ProjFalseEastingGeoKey" << std::endl;
228  }
229 
230  if (GTIFKeyGet(m_geotiff, ProjFalseNorthingGeoKey, &geoCode, 0, 1) == 1) {
231  std::cout << "ProjFalseNorthingGeoKey = " << geoCode << std::endl;
232  }
233  else {
234  std::cout << "no ProjFalseNorthingGeoKey" << std::endl;
235  }
236 
237  if (GTIFKeyGet(m_geotiff, ProjFalseOriginLongGeoKey, &geoCode, 0, 1) == 1) {
238  std::cout << "ProjFalseOriginLongGeoKey = " << geoCode << std::endl;
239  }
240  else {
241  std::cout << "no ProjFalseOriginLongGeoKey" << std::endl;
242  }
243 
244  if (GTIFKeyGet(m_geotiff, ProjFalseOriginLatGeoKey, &geoCode, 0, 1) == 1) {
245  std::cout << "ProjFalseOriginLatGeoKey = " << geoCode << std::endl;
246  }
247  else {
248  std::cout << "no ProjFalseOriginLatGeoKey" << std::endl;
249  }
250 
251  if (GTIFKeyGet(m_geotiff, ProjFalseOriginEastingGeoKey, &geoCode, 0, 1) == 1) {
252  std::cout << "ProjFalseOriginEastingGeoKey = " << geoCode << std::endl;
253  }
254  else {
255  std::cout << "no ProjFalseOriginEastingGeoKey" << std::endl;
256  }
257 
258  if (GTIFKeyGet(m_geotiff, ProjFalseOriginNorthingGeoKey, &geoCode, 0, 1) == 1) {
259  std::cout << "ProjFalseOriginNorthingGeoKey = " << geoCode << std::endl;
260  }
261  else {
262  std::cout << "no ProjFalseOriginNorthingGeoKey" << std::endl;
263  }
264 
265  if (GTIFKeyGet(m_geotiff, ProjCenterLongGeoKey, &geoCode, 0, 1) == 1) {
266  std::cout << "ProjCenterLongGeoKey = " << geoCode << std::endl;
267  }
268  else {
269  std::cout << "no ProjCenterLongGeoKey" << std::endl;
270  }
271 
272  if (GTIFKeyGet(m_geotiff, ProjCenterLatGeoKey, &geoCode, 0, 1) == 1) {
273  std::cout << "ProjCenterLatGeoKey = " << geoCode << std::endl;
274  }
275  else {
276  std::cout << "no ProjCenterLatGeoKey" << std::endl;
277  }
278 
279  if (GTIFKeyGet(m_geotiff, ProjCenterEastingGeoKey, &geoCode, 0, 1) == 1) {
280  std::cout << "ProjCenterEastingGeoKey = " << geoCode << std::endl;
281  }
282  else {
283  std::cout << "no ProjCenterEastingGeoKey" << std::endl;
284  }
285 
286  if (GTIFKeyGet(m_geotiff, ProjCenterNorthingGeoKey, &geoCode, 0, 1) == 1) {
287  std::cout << "ProjCenterNorthingGeoKey = " << geoCode << std::endl;
288  }
289  else {
290  std::cout << "no ProjCenterNorthingGeoKey" << std::endl;
291  }
292 
293  if (GTIFKeyGet(m_geotiff, ProjScaleAtNatOriginGeoKey, &geoCode, 0, 1) == 1) {
294  std::cout << "ProjScaleAtNatOriginGeoKey = " << geoCode << std::endl;
295  }
296  else {
297  std::cout << "no ProjScaleAtNatOriginGeoKey" << std::endl;
298  }
299 
300  if (GTIFKeyGet(m_geotiff, ProjAzimuthAngleGeoKey, &geoCode, 0, 1) == 1) {
301  std::cout << "ProjAzimuthAngleGeoKey = " << geoCode << std::endl;
302  }
303  else {
304  std::cout << "no ProjAzimuthAngleGeoKey" << std::endl;
305  }
306 
307  if (GTIFKeyGet(m_geotiff, ProjStraightVertPoleLongGeoKey, &geoCode, 0, 1) == 1) {
308  std::cout << "ProjStraightVertPoleLongGeoKey = " << geoCode << std::endl;
309  }
310  else {
311  std::cout << "no ProjStraightVertPoleLongGeoKey" << std::endl;
312  }
313 
314  if (GTIFKeyGet(m_geotiff, VerticalUnitsGeoKey, &geoCode, 0, 1) == 1) {
315  std::cout << "VerticalUnitsGeoKey = " << geoCode << std::endl;
316  }
317  else {
318  std::cout << "no VerticalUnitsGeoKey" << std::endl;
319  }
320  } // End of individual GEOTIFF projection parameters
321 
322  // There are some projections parameters that are not in the GEO part of the TIFF, get them
323 
324  // Get the Tiff Tiepoint tag and convert those to Upper Left X & Y
325  outPvl = upperLeftXY(outPvl);
326 
327  // Get the Tiff PixelScale tag and convert it to resolution and scale
328  outPvl = resolution(outPvl);
329 
330  // Get the GDAL minimum and maximum lats and lons
331  outPvl = gdalItems(outPvl);
332 
333  } // End of raster type
334 
335 
336  // Test the projection
337  // If any things goes wrong just ignore the projection and move on
338  try {
339  TProjection *proj = NULL;
340  proj = (TProjection *) ProjectionFactory::Create(outPvl);
341 
342  PvlGroup &mapGroup = outPvl.findGroup("Mapping");
343  double pixelResolution = mapGroup["PixelResolution"];
344  double trueScaleLat = proj->TrueScaleLatitude();
345  double localRadius = proj->LocalRadius(trueScaleLat);
346 
347  double scale = (2.0 * Isis::PI * localRadius) / (360.0 * pixelResolution);
348  mapGroup += PvlKeyword("Scale", toString(scale), "pixels/degree");
349  }
350  catch (IException &e) {
351  outPvl.findGroup("Mapping").clear();
352  }
353  }
354 
355  return outPvl.findGroup("Mapping");
356  }
357 
358 
365  Pvl TiffImporter::gdalItems(const Pvl &inLab) const {
366 
367  Pvl newLab = inLab;
368  PvlGroup &map = newLab.findGroup("Mapping");
369 
370  // Get the GDALMetadata tag (42112) to get the lat/lon boundry
371  char *gdalMetadataBuf;
372  short int gdalMetadataCount = 0;
373 
374  if (TIFFGetField(m_image, 42112, &gdalMetadataCount, &gdalMetadataBuf) == 1) {
375 
376  QString gdalMetadataQstring(gdalMetadataBuf);
377 
378  QDomDocument gdalDoc("GDALMetaData");
379  if (gdalDoc.setContent(gdalMetadataQstring)) {
380  QDomElement gdalRoot = gdalDoc.documentElement();
381  if (gdalRoot.tagName() == "GDALMetadata") {
382 
383  QDomNode gdalNode = gdalRoot.firstChild();
384  while (!gdalNode.isNull()) {
385  QDomElement gdalElement = gdalNode.toElement();
386  if (!gdalElement.isNull() ) {
387  if (gdalElement.tagName() == "Item") {
388  if (gdalElement.attribute("name", "") == "WEST_LONGITUDE") {
389  QString westLon = gdalElement.text();
390  map += PvlKeyword("MinimumLongitude", toString(Angle(westLon).degrees()));
391  }
392  else if (gdalElement.attribute("name", "") == "EAST_LONGITUDE") {
393  QString eastLon = gdalElement.text();
394  map += PvlKeyword("MaximumLongitude", toString(Angle(eastLon).degrees()));
395  }
396  else if (gdalElement.attribute("name", "") == "SOUTH_LATITUDE") {
397  QString southLat = gdalElement.text();
398  map += PvlKeyword("MinimumLatitude", toString(Angle(southLat).degrees()));
399  }
400  else if (gdalElement.attribute("name", "") == "NORTH_LATITUDE") {
401  QString northLat = gdalElement.text();
402  map += PvlKeyword("MaximumLatitude", toString(Angle(northLat).degrees()));
403  }
404  }
405  }
406 
407  gdalNode = gdalNode.nextSibling();
408  }
409  }
410  }
411  }
412 
413  return newLab;
414  }
415 
416 
424  Pvl TiffImporter::upperLeftXY(const Pvl &inLab) const {
425 
426  Pvl newLab = inLab;
427  PvlGroup &map = newLab.findGroup("Mapping");
428 
429  double *tiePoints = NULL;
430  short int tieCount = 0;
431  if (TIFFGetField(m_image, TIFFTAG_GEOTIEPOINTS, &tieCount, &tiePoints) == 1) {
432 
433  // The expected tiepoints are TIFF(i, j, k, x, y, z) = ISIS(sample, line, 0, X, Y, 0)
434  // Make sure the (x, y) refer to the (0, 0)
435  if (tiePoints[0] == 0.0 && tiePoints[1] == 0.0) {
436  double x = 0.0;
437  if (map.hasKeyword("FalseEasting")) {
438  x = (double)map["FalseEasting"] + tiePoints[3];
439  map.deleteKeyword("FalseEasting");
440  }
441 
442  double y = 0.0;
443  if (map.hasKeyword("FalseNorthing")) {
444  y = (double)map["FalseNorthing"] + tiePoints[4];
445  map.deleteKeyword("FalseNorthing");
446  }
447 
448  map += PvlKeyword("UpperLeftCornerX", toString(x), "meters");
449  map += PvlKeyword("UpperLeftCornerY", toString(y), "meters");
450  }
451  else {
452  QString msg = "The upper left X and Y can not be calculated. Unsupported tiepoint "
453  "type in Tiff file (i.e., not ( 0.0, 0.0))";
455  }
456  }
457 
458  return newLab;
459  }
460 
461 
469  Pvl TiffImporter::resolution(const Pvl &inLab) const {
470 
471  Pvl newLab = inLab;
472  PvlGroup &map = newLab.findGroup("Mapping");
473 
474  // Get the Tiff PixelScale tag and convert it to resolution
475  double *scales = NULL;
476  short int scaleCount = 0;
477  if (TIFFGetField(m_image, TIFFTAG_GEOPIXELSCALE, &scaleCount, &scales) == 1) {
478 
479  // The expected scales are TIFF(x, y, z) = ISIS(sample, line, 0)
480  // Make sure the (x, y) are the same but not zero (0) for ISIS
481  if ((scaleCount == 3) && (scales[0] > 0.0 && scales[1] > 0.0) && (scales[0] == scales[1])) {
482  map += PvlKeyword("PixelResolution", toString(scales[0]), "meters");
483  }
484  else {
485  QString msg = "The pixel resolution could not be retrieved from the TIFF file. Unsupported "
486  "PixelScale tag values.";
488  }
489  }
490 
491  return newLab;
492  }
493 
494 
505  return m_samplesPerPixel;
506  }
507 
508 
516  return
517  m_photo == PHOTOMETRIC_MINISWHITE ||
518  m_photo == PHOTOMETRIC_MINISBLACK;
519  }
520 
521 
528  bool TiffImporter::isRgb() const {
529  return !isGrayscale() && samplesPerPixel() <= 3;
530  }
531 
532 
539  bool TiffImporter::isArgb() const {
540  return !isGrayscale() && samplesPerPixel() > 3;
541  }
542 
543 
551  void TiffImporter::updateRawBuffer(int line, int band) const {
552  }
553 
554 
565  int TiffImporter::getPixel(int s, int l) const {
566  l = lines() - l - 1;
567  int index = l * samples() + s;
568  return m_raster[index];
569  }
570 
571 
581  int TiffImporter::getGray(int pixel) const {
582  return convertRgbToGray(pixel);
583  }
584 
585 
593  int TiffImporter::getRed(int pixel) const {
594  return TIFFGetR(pixel);
595  }
596 
597 
605  int TiffImporter::getGreen(int pixel) const {
606  return TIFFGetG(pixel);
607  }
608 
609 
617  int TiffImporter::getBlue(int pixel) const {
618  return TIFFGetB(pixel);
619  }
620 
621 
629  int TiffImporter::getAlpha(int pixel) const {
630  return TIFFGetA(pixel);
631  }
632 };
633