pktools  2.6.6
Processing Kernel for geospatial data
ImgWriterGdal.cc
1 /**********************************************************************
2 ImgWriterGdal.cc: class to write raster files using GDAL API library
3 Copyright (C) 2008-2012 Pieter Kempeneers
4 
5 This file is part of pktools
6 
7 pktools is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 pktools is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with pktools. If not, see <http://www.gnu.org/licenses/>.
19 ***********************************************************************/
20 #include <iostream>
21 #include <iomanip>
22 #include <time.h>
23 #include <algorithm>
24 #include "ogr_spatialref.h"
25 extern "C" {
26 #include "gdal_alg.h"
27 }
28 #include "ImgWriterGdal.h"
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 //---------------------------------------------------------------------------
35 
36 // ImgWriterGdal::ImgWriterGdal(void)
37 // : m_gds(NULL), m_magic_x(1), m_magic_y(1), m_isGeoRef(false), m_ncol(0), m_nrow(0), m_nband(0), m_interleave("BAND"), m_compression("LZW")
38 // {}
39 
40 ImgWriterGdal::ImgWriterGdal(void){};
41 
42 ImgWriterGdal::~ImgWriterGdal(void)
43 {
44  // delete m_gds;
45 // GDALDumpOpenDatasets(stderr);
46 // GDALDestroyDriverManager();//could still be be used by other objects
47 }
48 
49 //---------------------------------------------------------------------------
50 void ImgWriterGdal::open(const std::string& filename, const ImgReaderGdal& imgSrc, const std::vector<std::string>& options)
51 {
52  // m_isGeoRef=imgSrc.isGeoRef();
53  m_filename=filename;
54  m_ncol=imgSrc.nrOfCol();
55  m_nrow=imgSrc.nrOfRow();
56  m_nband=imgSrc.nrOfBand();
57  // m_type=imgSrc.getDataType();
58  m_options=options;
59  // m_interleave=imgSrc.getInterleave();
60  // m_compression=imgSrc.getCompression();
61  // imgSrc.getMagicPixel(m_magic_x,m_magic_y);
62  setCodec(imgSrc);
63 }
64 
65 // void ImgWriterGdal::open(const std::string& filename, int ncol, int nrow, int nband, const GDALDataType& dataType, const std::string& imageType, const std::string& interleave, const std::string& compression, int magicX, int magicY)
66 // {
67 // m_isGeoRef=false;
68 // m_filename = filename;
69 // m_ncol = ncol;
70 // m_nrow = nrow;
71 // m_nband = nband;
72 // m_type=dataType;
73 // m_interleave = interleave;
74 // m_compression=compression;
75 // m_magic_x=magicX;
76 // m_magic_y=magicY;
77 // setCodec(imageType);
78 // }
79 
80 void ImgWriterGdal::open(const std::string& filename, int ncol, int nrow, int nband, const GDALDataType& dataType, const std::string& imageType, const std::vector<std::string>& options)
81 {
82  // m_isGeoRef=false;
83  m_filename = filename;
84  m_ncol = ncol;
85  m_nrow = nrow;
86  m_nband = nband;
87  // m_type=dataType;
88  // m_interleave = interleave;
89  // m_compression=compression;
90  m_options=options;
91  // m_magic_x=magicX;
92  // m_magic_y=magicY;
93  setCodec(dataType,imageType);
94 }
95 
96 //---------------------------------------------------------------------------
97 void ImgWriterGdal::close(void)
98 {
99  ImgRasterGdal::close();
100  char **papszOptions=NULL;
101  for(std::vector<std::string>::const_iterator optionIt=m_options.begin();optionIt!=m_options.end();++optionIt)
102  papszOptions=CSLAddString(papszOptions,optionIt->c_str());
103  if(papszOptions)
104  CSLDestroy(papszOptions);
105 }
106 
107 //---------------------------------------------------------------------------
108 void ImgWriterGdal::setCodec(const ImgReaderGdal& imgSrc){
109  GDALAllRegister();
110  GDALDriver *poDriver;
111  poDriver = GetGDALDriverManager()->GetDriverByName(imgSrc.getDriverDescription().c_str());
112  if( poDriver == NULL ){
113  std::string errorString="FileOpenError";
114  throw(errorString);
115  }
116  char **papszMetadata;
117  papszMetadata = poDriver->GetMetadata();
118  //todo: try and catch if CREATE is not supported (as in PNG)
119  assert( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ));
120  char **papszOptions=NULL;
121  for(std::vector<std::string>::const_iterator optionIt=m_options.begin();optionIt!=m_options.end();++optionIt)
122  papszOptions=CSLAddString(papszOptions,optionIt->c_str());
123  // char **papszOptions=NULL;
124  // std::ostringstream compressList;
125  // compressList << "COMPRESS=" << m_compression;
126  // papszOptions = CSLAddString(papszOptions,(compressList.str()).c_str());
127  // std::ostringstream interleaveList;
128  // interleaveList << "INTERLEAVE=" << m_interleave;
129  // papszOptions = CSLAddString(papszOptions,(interleaveList.str()).c_str());
130  m_gds=poDriver->Create(m_filename.c_str(),m_ncol,m_nrow,m_nband,imgSrc.getDataType(),papszOptions);
131  // if(imgSrc.isGeoRef()){
132  setProjection(imgSrc.getProjection());
133  double gt[6];
134  imgSrc.getGeoTransform(gt);
135  setGeoTransform(gt);
136  // }
137  m_gds->SetMetadata(imgSrc.getMetadata() );
138  m_gds->SetMetadataItem( "TIFFTAG_DOCUMENTNAME", m_filename.c_str());
139  std::string versionString="pktools ";
140  versionString+=VERSION;
141  versionString+=" by Pieter Kempeneers";
142  m_gds->SetMetadataItem( "TIFFTAG_SOFTWARE", versionString.c_str());
143  time_t rawtime;
144  time ( &rawtime );
145 
146  time_t tim=time(NULL);
147  tm *now=localtime(&tim);
148  std::ostringstream datestream;
149  //date std::string must be 20 characters long...
150  datestream << now->tm_year+1900;
151  if(now->tm_mon+1<10)
152  datestream << ":0" << now->tm_mon+1;
153  else
154  datestream << ":" << now->tm_mon+1;
155  if(now->tm_mday<10)
156  datestream << ":0" << now->tm_mday;
157  else
158  datestream << ":" << now->tm_mday;
159  if(now->tm_hour<10)
160  datestream << " 0" << now->tm_hour;
161  else
162  datestream << " " << now->tm_hour;
163  if(now->tm_min<10)
164  datestream << ":0" << now->tm_min;
165  else
166  datestream << ":" << now->tm_min;
167  if(now->tm_sec<10)
168  datestream << ":0" << now->tm_sec;
169  else
170  datestream << ":" << now->tm_sec;
171  m_gds->SetMetadataItem( "TIFFTAG_DATETIME", datestream.str().c_str());
172 // list<std::string> lmeta;
173 // imgReader.getMetadata(lmeta);
174 // list<std::string>::const_iterator lit=lmeta.begin();
175 // while(lit!=lmeta.end()){
176 // cout << *lit << endl;
177 // ++lit;
178 // }
179  // m_gds->SetMetadataItem( "INTERLEAVE", m_interleave.c_str(), "IMAGE_STRUCTURE" );
180  // m_gds->SetMetadataItem( "COMPRESS", m_compression.c_str(), "IMAGE_STRUCTURE" );
181  if(imgSrc.getColorTable()!=NULL)
182  setColorTable(imgSrc.getColorTable());
183 }
184 
185 void ImgWriterGdal::setCodec(const GDALDataType& dataType, const std::string& imageType)
186 {
187  GDALAllRegister();
188  GDALDriver *poDriver;
189  poDriver = GetGDALDriverManager()->GetDriverByName(imageType.c_str());
190  if( poDriver == NULL ){
191  std::ostringstream s;
192  s << "FileOpenError (" << imageType << ")";
193  throw(s.str());
194  }
195  char **papszMetadata;
196  papszMetadata = poDriver->GetMetadata();
197  //todo: try and catch if CREATE is not supported (as in PNG)
198  assert( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ));
199  char **papszOptions=NULL;
200  for(std::vector<std::string>::const_iterator optionIt=m_options.begin();optionIt!=m_options.end();++optionIt)
201  papszOptions=CSLAddString(papszOptions,optionIt->c_str());
202  // std::ostringstream compressList;
203  // compressList << "COMPRESS=" << m_compression;
204  // papszOptions = CSLAddString(papszOptions,(compressList.str()).c_str());
205  // std::ostringstream interleaveList;
206  // interleaveList << "INTERLEAVE=" << m_interleave;
207  // papszOptions = CSLAddString(papszOptions,(interleaveList.str()).c_str());
208  m_gds=poDriver->Create(m_filename.c_str(),m_ncol,m_nrow,m_nband,dataType,papszOptions);
209 
210  // m_gds->SetMetadataItem( "INTERLEAVE", m_interleave.c_str(), "IMAGE_STRUCTURE" );
211  // m_gds->SetMetadataItem( "COMPRESSION", m_compression.c_str(), "IMAGE_STRUCTURE" );
212  m_gds->SetMetadataItem( "TIFFTAG_DOCUMENTNAME", m_filename.c_str());
213  std::string versionString="pktools ";
214  versionString+=VERSION;
215  versionString+=" by Pieter Kempeneers";
216  m_gds->SetMetadataItem( "TIFFTAG_SOFTWARE", versionString.c_str());
217  time_t rawtime;
218  time ( &rawtime );
219 
220  time_t tim=time(NULL);
221  tm *now=localtime(&tim);
222  std::ostringstream datestream;
223  //date std::string must be 20 characters long...
224  datestream << now->tm_year+1900;
225  if(now->tm_mon+1<10)
226  datestream << ":0" << now->tm_mon+1;
227  else
228  datestream << ":" << now->tm_mon+1;
229  if(now->tm_mday<10)
230  datestream << ":0" << now->tm_mday;
231  else
232  datestream << ":" << now->tm_mday;
233  if(now->tm_hour<10)
234  datestream << " 0" << now->tm_hour;
235  else
236  datestream << " " << now->tm_hour;
237  if(now->tm_min<10)
238  datestream << ":0" << now->tm_min;
239  else
240  datestream << ":" << now->tm_min;
241  if(now->tm_sec<10)
242  datestream << ":0" << now->tm_sec;
243  else
244  datestream << ":" << now->tm_sec;
245  m_gds->SetMetadataItem( "TIFFTAG_DATETIME", datestream.str().c_str());
246 // m_gds->SetMetadataItem( "TIFFTAG_DATETIME", ctime(&rawtime));
247 }
248 
249 void ImgWriterGdal::setMetadata(char** metadata)
250 {
251  assert(m_gds);
252  m_gds->SetMetadata(metadata);
253 }
254 
255 //---------------------------------------------------------------------------
256 void ImgWriterGdal::setGeoTransform(double* gt){
257  // m_isGeoRef=true;
258  m_gt[0]=gt[0];
259  m_gt[1]=gt[1];
260  m_gt[2]=gt[2];
261  m_gt[3]=gt[3];
262  m_gt[4]=gt[4];
263  m_gt[5]=gt[5];
264  if(m_gds)
265  m_gds->SetGeoTransform(m_gt);
266 }
267 
268 // void ImgWriterGdal::setGeoTransform(double ulx, double uly, double deltaX, double deltaY, double rot1, double rot2)
269 // {
270 // m_isGeoRef=true;
271 // m_ulx=ulx;
272 // m_uly=uly;
273 // m_delta_x=deltaX;
274 // m_delta_y=deltaY;
275 // double adfGeoTransform[6];// { 444720, 30, 0, 3751320, 0, -30 };
276 // adfGeoTransform[0]=ulx;
277 // adfGeoTransform[1]=deltaX;
278 // adfGeoTransform[2]=rot1;
279 // adfGeoTransform[3]=uly;
280 // adfGeoTransform[4]=rot2;
281 // adfGeoTransform[5]=-deltaY;//convention of GDAL!
282 // if(m_gds)
283 // m_gds->SetGeoTransform(adfGeoTransform);
284 // }
285 
286 void ImgWriterGdal::copyGeoTransform(const ImgReaderGdal& imgSrc)
287 {
288  setProjection(imgSrc.getProjection());
289  double gt[6];
290  imgSrc.getGeoTransform(gt);
291  setGeoTransform(gt);
292  // imgSrc.getGeoTransform(ulx,uly,deltaX,deltaY,rot1,rot2);
293  // setGeoTransform(ulx,uly,deltaX,deltaY,rot1,rot2);
294 }
295 
296 std::string ImgWriterGdal::setProjectionProj4(const std::string& projection)
297 {
298  // if(!m_isGeoRef)
299  // m_isGeoRef=true;
300 
301  OGRSpatialReference theRef;
302  theRef.SetFromUserInput(projection.c_str());
303  char *wktString;
304  theRef.exportToWkt(&wktString);
305  assert(m_gds);
306  m_gds->SetProjection(wktString);
307  return(wktString);
308 
309  // OGRSpatialReferenceH hSRS;
310  // char *pszResult = NULL;
311 
312  // CPLErrorReset();
313 
314  // hSRS = OSRNewSpatialReference( NULL );
315  // if( OSRSetFromUserInput( hSRS, projection.c_str() ) == OGRERR_NONE )
316  // OSRExportToWkt( hSRS, &pszResult );
317  // else
318  // {
319  // std::ostringstream s;
320  // s << "Error in set projection " << projection;
321  // throw(s.str());
322  // }
323  // std::string theProjection=pszResult;
324  // assert(m_gds);
325  // m_gds->SetProjection(theProjection.c_str());
326  // OSRDestroySpatialReference( hSRS );
327 
328  // return theProjection;
329 }
330 
331 void ImgWriterGdal::setProjection(const std::string& projection)
332 {
333  // if(!m_isGeoRef)
334  // m_isGeoRef=true;
335  OGRSpatialReference oSRS;
336  char *pszSRS_WKT = NULL;
337  assert(m_gds);
338  m_gds->SetProjection(projection.c_str());
339  CPLFree(pszSRS_WKT);
340 }
341 
342 //default projection: ETSR-LAEA
343 // std::string ImgWriterGdal::setProjection(void)
344 // {
345 // std::string theProjection;
346 // OGRSpatialReference oSRS;
347 // char *pszSRS_WKT = NULL;
348 // //// oSRS.importFromEPSG(3035);
349 // oSRS.SetGeogCS("ETRS89","European_Terrestrial_Reference_System_1989","GRS 1980",6378137,298.2572221010042,"Greenwich",0,"degree",0.0174532925199433);
350 // // cout << setprecision(16) << "major axis: " << oSRS.GetSemiMajor(NULL) << endl;//notice that major axis can be set to a different value than the default to the well known standard corresponding to the name (European_Terrestrial_Reference_System_1989), but that new value, while recognized by GetSemiMajor, will not be written in the geotiff tag!
351 // oSRS.SetProjCS( "ETRS89 / ETRS-LAEA" );
352 // oSRS.SetLAEA(52,10,4321000,3210000);
353 // oSRS.exportToWkt( &pszSRS_WKT );
354 // theProjection=pszSRS_WKT;
355 // CPLFree( pszSRS_WKT );
356 // assert(m_gds);
357 // m_gds->SetProjection(theProjection.c_str());
358 // return(theProjection);
359 // }
360 
361 //filename is ascii file containing 5 columns: index R G B ALFA (0:transparent, 255:solid)
362 void ImgWriterGdal::setColorTable(const std::string& filename, int band)
363 {
364  //todo: fool proof table in file (no checking currently done...)
365  std::ifstream ftable(filename.c_str(),std::ios::in);
366  std::string line;
367 // poCT=new GDALColorTable();
368  GDALColorTable colorTable;
369  short nline=0;
370  while(getline(ftable,line)){
371  ++nline;
372  std::istringstream ist(line);
373  GDALColorEntry sEntry;
374  short id;
375  ist >> id >> sEntry.c1 >> sEntry.c2 >> sEntry.c3 >> sEntry.c4;
376 // poCT->SetColorEntry(id,&sEntry);
377  colorTable.SetColorEntry(id,&sEntry);
378  }
379  // assert(nline==colorTable.GetColorEntryCount());
380 // (m_gds->GetRasterBand(band+1))->SetColorTable(poCT);
381  (m_gds->GetRasterBand(band+1))->SetColorTable(&colorTable);
382 }
383 
384 void ImgWriterGdal::setColorTable(GDALColorTable* colorTable, int band)
385 {
386  (m_gds->GetRasterBand(band+1))->SetColorTable(colorTable);
387 }
388 
389 //write an entire image from memory to file
390 bool ImgWriterGdal::writeData(void* pdata, const GDALDataType& dataType, int band) const{
391  //fetch raster band
392  GDALRasterBand *poBand;
393  if(band>=nrOfBand()+1){
394  std::ostringstream s;
395  s << "band (" << band << ") exceeds nrOfBand (" << nrOfBand() << ")";
396  throw(s.str());
397  }
398  poBand = m_gds->GetRasterBand(band+1);//GDAL uses 1 based index
399  poBand->RasterIO(GF_Write,0,0,nrOfCol(),nrOfRow(),pdata,nrOfCol(),nrOfRow(),dataType,0,0);
400  return true;
401 }
402 
403 void ImgWriterGdal::rasterizeOgr(ImgReaderOgr& ogrReader, const std::vector<double>& burnValues, const std::vector<std::string>& layernames ){
404  std::vector<int> bands;
405  std::vector<double> burnBands;//burn values for all bands in a single layer
406  std::vector<double> burnLayers;//burn values for all bands and all layers
407  if(burnValues.empty()){
408  std::string errorString="Error: burn values not provided";
409  throw(errorString);
410  }
411  burnBands=burnValues;
412  while(burnBands.size()<nrOfBand())
413  burnBands.push_back(burnValues[0]);
414  for(int iband=0;iband<nrOfBand();++iband)
415  bands.push_back(iband+1);
416  std::vector<OGRLayerH> layers;
417  int nlayer=0;
418  for(int ilayer=0;ilayer<ogrReader.getLayerCount();++ilayer){
419  std::string currentLayername=ogrReader.getLayer(ilayer)->GetName();
420  if(layernames.size())
421  if(find(layernames.begin(),layernames.end(),currentLayername)==layernames.end())
422  continue;
423  std::cout << "processing layer " << currentLayername << std::endl;
424  layers.push_back((OGRLayerH)ogrReader.getLayer(ilayer));
425  ++nlayer;
426  for(int iband=0;iband<nrOfBand();++iband)
427  burnLayers.insert(burnLayers.end(),burnBands.begin(),burnBands.end());
428  }
429  void *pTransformArg;
430  char **papszOptions;
431  double dfComplete=0.0;
432  const char* pszMessage;
433  void* pProgressArg=NULL;
434  GDALProgressFunc pfnProgress=GDALTermProgress;
435  pfnProgress(dfComplete,pszMessage,pProgressArg);
436  if(GDALRasterizeLayers( (GDALDatasetH)m_gds,nrOfBand(),&(bands[0]),layers.size(),&(layers[0]),NULL,pTransformArg,&(burnLayers[0]),papszOptions,pfnProgress,pProgressArg)!=CE_None){
437  std::cerr << CPLGetLastErrorMsg() << std::endl;
438  exit(1);
439  }
440  else{
441  dfComplete=1.0;
442  pfnProgress(dfComplete,pszMessage,pProgressArg);
443  }
444 }