export_band.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /****************************************************************************
  2. *
  3. * MODULE: r.out.gdal
  4. * AUTHOR(S): Vytautas Vebra <olivership@gmail.com>
  5. * PURPOSE: Exports GRASS raster to GDAL suported formats;
  6. * based on GDAL library.
  7. *
  8. * COPYRIGHT: (C) 2006-2009 by the GRASS Development Team
  9. *
  10. * This program is free software under the GNU General Public
  11. * License (>=v2). Read the file COPYING that comes with GRASS
  12. * for details.
  13. *
  14. *****************************************************************************/
  15. #include <grass/gis.h>
  16. #include <grass/raster.h>
  17. #include <grass/glocale.h>
  18. #include <gdal.h>
  19. #include <cpl_string.h>
  20. #include <cpl_port.h>
  21. #include "local_proto.h"
  22. int exact_range_check(double, double, GDALDataType, const char *);
  23. /* exact check for each band
  24. * returns 0 on success
  25. * -1 if given nodata value was present in data
  26. * -2 if selected GDAL datatype could not hold all values
  27. * */
  28. int exact_checks(GDALDataType export_datatype,
  29. const char *name, const char *mapset,
  30. struct Cell_head *cellhead, RASTER_MAP_TYPE maptype,
  31. double nodataval, const char *nodatakey,
  32. int default_nodataval)
  33. {
  34. double dfCellMin;
  35. double dfCellMax;
  36. int fd;
  37. int cols = cellhead->cols;
  38. int rows = cellhead->rows;
  39. int ret = 0;
  40. /* Open GRASS raster */
  41. fd = Rast_open_old(name, mapset);
  42. /* Create GRASS raster buffer */
  43. void *bufer = Rast_allocate_buf(maptype);
  44. if (bufer == NULL) {
  45. G_warning(_("Unable to allocate buffer for reading raster map"));
  46. return -1;
  47. }
  48. /* the following routine must be kept identical to export_band */
  49. /* Copy data form GRASS raster to GDAL raster */
  50. int row, col;
  51. int n_nulls = 0, nodatavalmatch = 0;
  52. dfCellMin = TYPE_FLOAT64_MAX;
  53. dfCellMax = TYPE_FLOAT64_MIN;
  54. /* Better use selected GDAL datatype instead of
  55. * the best match with GRASS raster map types ? */
  56. if (maptype == FCELL_TYPE) {
  57. FCELL fnullval = (FCELL) nodataval;
  58. G_debug(1, "FCELL nodata val: %f", fnullval);
  59. for (row = 0; row < rows; row++) {
  60. Rast_get_row(fd, bufer, row, maptype);
  61. for (col = 0; col < cols; col++) {
  62. FCELL fval = ((FCELL *) bufer)[col];
  63. if (Rast_is_f_null_value(&fval)) {
  64. ((FCELL *) bufer)[col] = fnullval;
  65. n_nulls++;
  66. }
  67. else {
  68. if (fval == fnullval) {
  69. nodatavalmatch = 1;
  70. }
  71. if (!CPLIsInf(fval)) {
  72. /* ignore inf */
  73. if (dfCellMin > fval)
  74. dfCellMin = fval;
  75. if (dfCellMax < fval)
  76. dfCellMax = fval;
  77. }
  78. }
  79. }
  80. G_percent(row + 1, rows, 2);
  81. }
  82. }
  83. else if (maptype == DCELL_TYPE) {
  84. DCELL dnullval = (DCELL) nodataval;
  85. G_debug(1, "DCELL nodata val: %f", dnullval);
  86. for (row = 0; row < rows; row++) {
  87. Rast_get_row(fd, bufer, row, maptype);
  88. for (col = 0; col < cols; col++) {
  89. DCELL dval = ((DCELL *) bufer)[col];
  90. if (Rast_is_d_null_value(&dval)) {
  91. ((DCELL *) bufer)[col] = dnullval;
  92. n_nulls++;
  93. }
  94. else {
  95. if (dval == dnullval) {
  96. nodatavalmatch = 1;
  97. }
  98. if (!CPLIsInf(dval)) {
  99. /* ignore inf */
  100. if (dfCellMin > dval)
  101. dfCellMin = dval;
  102. if (dfCellMax < dval)
  103. dfCellMax = dval;
  104. }
  105. }
  106. }
  107. G_percent(row + 1, rows, 2);
  108. }
  109. }
  110. else {
  111. CELL inullval = (CELL) nodataval;
  112. G_debug(1, "CELL nodata val: %d", inullval);
  113. for (row = 0; row < rows; row++) {
  114. Rast_get_row(fd, bufer, row, maptype);
  115. for (col = 0; col < cols; col++) {
  116. if (Rast_is_c_null_value(&((CELL *) bufer)[col])) {
  117. ((CELL *) bufer)[col] = inullval;
  118. n_nulls++;
  119. }
  120. else {
  121. if (((CELL *) bufer)[col] == inullval) {
  122. nodatavalmatch = 1;
  123. }
  124. if (dfCellMin > ((CELL *) bufer)[col])
  125. dfCellMin = ((CELL *) bufer)[col];
  126. if (dfCellMax < ((CELL *) bufer)[col])
  127. dfCellMax = ((CELL *) bufer)[col];
  128. }
  129. }
  130. G_percent(row + 1, rows, 2);
  131. }
  132. }
  133. G_debug(1, "min %g max %g", dfCellMin, dfCellMax);
  134. /* can the GDAL datatype hold the data range to be exported ? */
  135. /* f-flag does not override */
  136. if (exact_range_check(dfCellMin, dfCellMax, export_datatype, name)) {
  137. G_warning("Raster export results in data loss.");
  138. ret = -2;
  139. }
  140. G_message(_("Using GDAL data type <%s>"), GDALGetDataTypeName(export_datatype));
  141. /* a default nodata value was used and NULL cells were present */
  142. if (n_nulls && default_nodataval) {
  143. if (maptype == CELL_TYPE)
  144. G_important_message(_("Input raster map contains cells with NULL-value (no-data). "
  145. "The value %d will be used to represent no-data values in the input map. "
  146. "You can specify a nodata value with the %s option."),
  147. (int)nodataval, nodatakey);
  148. else
  149. G_important_message(_("Input raster map contains cells with NULL-value (no-data). "
  150. "The value %g will be used to represent no-data values in the input map. "
  151. "You can specify a nodata value with the %s option."),
  152. nodataval, nodatakey);
  153. }
  154. /* the nodata value was present in the exported data */
  155. if (nodatavalmatch && n_nulls) {
  156. /* default nodataval didn't work */
  157. if (default_nodataval) {
  158. G_warning(_("The default nodata value is present in raster"
  159. "band <%s> and would lead to data loss. Please specify a "
  160. "custom nodata value with the %s parameter."),
  161. name, nodatakey);
  162. }
  163. /* user-specified nodataval didn't work */
  164. else {
  165. G_warning(_("The user given nodata value %g is present in raster"
  166. "band <%s> and would lead to data loss. Please specify a "
  167. "different nodata value with the %s parameter."),
  168. nodataval, name, nodatakey);
  169. }
  170. ret = -1;
  171. }
  172. Rast_close(fd);
  173. G_free(bufer);
  174. return ret;
  175. }
  176. /* actual raster band export
  177. * returns 0 on success
  178. * -1 on raster data read/write error
  179. * */
  180. int export_band(GDALDatasetH hMEMDS, int band,
  181. const char *name, const char *mapset,
  182. struct Cell_head *cellhead, RASTER_MAP_TYPE maptype,
  183. double nodataval, int suppress_main_colortable,
  184. int no_metadata, int writenodata)
  185. {
  186. struct Colors sGrassColors;
  187. GDALColorTableH hCT;
  188. int iColor;
  189. int bHaveMinMax;
  190. double dfCellMin;
  191. double dfCellMax;
  192. struct FPRange sRange;
  193. int fd;
  194. int cols = cellhead->cols;
  195. int rows = cellhead->rows;
  196. int ret = 0;
  197. char value[200];
  198. char *units;
  199. /* Open GRASS raster */
  200. fd = Rast_open_old(name, mapset);
  201. /* Get raster band */
  202. GDALRasterBandH hBand = GDALGetRasterBand(hMEMDS, band);
  203. if (hBand == NULL) {
  204. G_warning(_("Unable to get raster band"));
  205. return -1;
  206. }
  207. if (!no_metadata)
  208. GDALSetDescription(hBand, name);
  209. units = Rast_read_units(name, mapset);
  210. if (units)
  211. GDALSetRasterUnitType(hBand, units);
  212. /* Get min/max values. */
  213. if (Rast_read_fp_range(name, mapset, &sRange) == -1) {
  214. bHaveMinMax = FALSE;
  215. }
  216. else {
  217. bHaveMinMax = TRUE;
  218. Rast_get_fp_range_min_max(&sRange, &dfCellMin, &dfCellMax);
  219. }
  220. /* use default color rules if no color rules are given */
  221. if (Rast_read_colors(name, mapset, &sGrassColors) >= 0) {
  222. int maxcolor, i;
  223. CELL min, max;
  224. char key[200];
  225. int rcount;
  226. Rast_get_c_color_range(&min, &max, &sGrassColors);
  227. if (bHaveMinMax) {
  228. if (max < dfCellMax) {
  229. maxcolor = max;
  230. }
  231. else {
  232. maxcolor = (int)ceil(dfCellMax);
  233. }
  234. if (maxcolor > GRASS_MAX_COLORS) {
  235. maxcolor = GRASS_MAX_COLORS;
  236. G_warning("Too many values, color table cut to %d entries",
  237. maxcolor);
  238. }
  239. }
  240. else {
  241. if (max < GRASS_MAX_COLORS) {
  242. maxcolor = max;
  243. }
  244. else {
  245. maxcolor = GRASS_MAX_COLORS;
  246. G_warning("Too many values, color table set to %d entries",
  247. maxcolor);
  248. }
  249. }
  250. rcount = Rast_colors_count(&sGrassColors);
  251. G_debug(3, "dfCellMin: %f, dfCellMax: %f, maxcolor: %d", dfCellMin,
  252. dfCellMax, maxcolor);
  253. if (!suppress_main_colortable) {
  254. hCT = GDALCreateColorTable(GPI_RGB);
  255. for (iColor = 0; iColor <= maxcolor; iColor++) {
  256. int nRed, nGreen, nBlue;
  257. GDALColorEntry sColor;
  258. if (Rast_get_c_color(&iColor, &nRed, &nGreen, &nBlue,
  259. &sGrassColors)) {
  260. sColor.c1 = nRed;
  261. sColor.c2 = nGreen;
  262. sColor.c3 = nBlue;
  263. sColor.c4 = 255;
  264. G_debug(3,
  265. "Rast_get_c_color: Y, rcount %d, nRed %d, nGreen %d, nBlue %d",
  266. rcount, nRed, nGreen, nBlue);
  267. GDALSetColorEntry(hCT, iColor, &sColor);
  268. }
  269. else {
  270. sColor.c1 = 0;
  271. sColor.c2 = 0;
  272. sColor.c3 = 0;
  273. sColor.c4 = 0;
  274. G_debug(3,
  275. "Rast_get_c_color: N, rcount %d, nRed %d, nGreen %d, nBlue %d",
  276. rcount, nRed, nGreen, nBlue);
  277. GDALSetColorEntry(hCT, iColor, &sColor);
  278. }
  279. }
  280. GDALSetRasterColorTable(hBand, hCT);
  281. }
  282. if (!no_metadata) {
  283. if (rcount > 0) {
  284. /* Create metadata entries for color table rules */
  285. sprintf(value, "%d", rcount);
  286. GDALSetMetadataItem(hBand, "COLOR_TABLE_RULES_COUNT", value,
  287. NULL);
  288. }
  289. /* Add the rules in reverse order */
  290. /* This can cause a GDAL warning with many rules, something like
  291. * Warning 1: Lost metadata writing to GeoTIFF ... too large to fit in tag. */
  292. for (i = rcount - 1; i >= 0; i--) {
  293. DCELL val1, val2;
  294. unsigned char r1, g1, b1, r2, g2, b2;
  295. Rast_get_fp_color_rule(&val1, &r1, &g1, &b1, &val2, &r2, &g2, &b2,
  296. &sGrassColors, i);
  297. sprintf(key, "COLOR_TABLE_RULE_RGB_%d", rcount - i - 1);
  298. sprintf(value, "%e %e %d %d %d %d %d %d", val1, val2, r1, g1, b1,
  299. r2, g2, b2);
  300. GDALSetMetadataItem(hBand, key, value, NULL);
  301. }
  302. }
  303. }
  304. /* Create GRASS raster buffer */
  305. void *bufer = Rast_allocate_buf(maptype);
  306. if (bufer == NULL) {
  307. G_warning(_("Unable to allocate buffer for reading raster map"));
  308. return -1;
  309. }
  310. /* the following routine must be kept identical to exact_checks */
  311. /* Copy data form GRASS raster to GDAL raster */
  312. int row, col;
  313. int n_nulls = 0;
  314. /* Better use selected GDAL datatype instead of
  315. * the best match with GRASS raster map types ? */
  316. if (maptype == FCELL_TYPE) {
  317. /* Source datatype understandable by GDAL */
  318. GDALDataType datatype = GDT_Float32;
  319. FCELL fnullval = (FCELL) nodataval;
  320. G_debug(1, "FCELL nodata val: %f", fnullval);
  321. for (row = 0; row < rows; row++) {
  322. Rast_get_row(fd, bufer, row, maptype);
  323. for (col = 0; col < cols; col++) {
  324. if (Rast_is_f_null_value(&((FCELL *) bufer)[col])) {
  325. ((FCELL *) bufer)[col] = fnullval;
  326. if (n_nulls == 0) {
  327. GDALSetRasterNoDataValue(hBand, nodataval);
  328. }
  329. n_nulls++;
  330. }
  331. }
  332. if (GDALRasterIO
  333. (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype,
  334. 0, 0) >= CE_Failure) {
  335. G_warning(_("Unable to write GDAL raster file"));
  336. return -1;
  337. }
  338. G_percent(row + 1, rows, 2);
  339. }
  340. }
  341. else if (maptype == DCELL_TYPE) {
  342. GDALDataType datatype = GDT_Float64;
  343. DCELL dnullval = (DCELL) nodataval;
  344. G_debug(1, "DCELL nodata val: %f", dnullval);
  345. for (row = 0; row < rows; row++) {
  346. Rast_get_row(fd, bufer, row, maptype);
  347. for (col = 0; col < cols; col++) {
  348. if (Rast_is_d_null_value(&((DCELL *) bufer)[col])) {
  349. ((DCELL *) bufer)[col] = dnullval;
  350. if (n_nulls == 0) {
  351. GDALSetRasterNoDataValue(hBand, nodataval);
  352. }
  353. n_nulls++;
  354. }
  355. }
  356. if (GDALRasterIO
  357. (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype,
  358. 0, 0) >= CE_Failure) {
  359. G_warning(_("Unable to write GDAL raster file"));
  360. return -1;
  361. }
  362. G_percent(row + 1, rows, 2);
  363. }
  364. }
  365. else {
  366. GDALDataType datatype = GDT_Int32;
  367. CELL inullval = (CELL) nodataval;
  368. G_debug(1, "CELL nodata val: %d", inullval);
  369. for (row = 0; row < rows; row++) {
  370. Rast_get_row(fd, bufer, row, maptype);
  371. for (col = 0; col < cols; col++) {
  372. if (Rast_is_c_null_value(&((CELL *) bufer)[col])) {
  373. ((CELL *) bufer)[col] = inullval;
  374. if (n_nulls == 0) {
  375. GDALSetRasterNoDataValue(hBand, nodataval);
  376. }
  377. n_nulls++;
  378. }
  379. }
  380. if (GDALRasterIO
  381. (hBand, GF_Write, 0, row, cols, 1, bufer, cols, 1, datatype,
  382. 0, 0) >= CE_Failure) {
  383. G_warning(_("Unable to write GDAL raster file"));
  384. return -1;
  385. }
  386. G_percent(row + 1, rows, 2);
  387. }
  388. }
  389. if (writenodata && n_nulls == 0)
  390. GDALSetRasterNoDataValue(hBand, nodataval);
  391. Rast_close(fd);
  392. G_free(bufer);
  393. return ret;
  394. }
  395. int exact_range_check(double min, double max, GDALDataType datatype,
  396. const char *name)
  397. {
  398. switch (datatype) {
  399. case GDT_Byte:
  400. if (min < TYPE_BYTE_MIN || max > TYPE_BYTE_MAX) {
  401. G_warning(_("Selected GDAL datatype does not cover data range."));
  402. G_warning(_("GDAL datatype: %s, range: %d - %d"),
  403. GDALGetDataTypeName(datatype), TYPE_BYTE_MIN,
  404. TYPE_BYTE_MAX);
  405. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  406. return 1;
  407. }
  408. else
  409. return 0;
  410. case GDT_UInt16:
  411. if (min < TYPE_UINT16_MIN || max > TYPE_UINT16_MAX) {
  412. G_warning(_("Selected GDAL datatype does not cover data range."));
  413. G_warning(_("GDAL datatype: %s, range: %d - %d"),
  414. GDALGetDataTypeName(datatype), TYPE_UINT16_MIN,
  415. TYPE_UINT16_MAX);
  416. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  417. return 1;
  418. }
  419. else
  420. return 0;
  421. case GDT_Int16:
  422. case GDT_CInt16:
  423. if (min < TYPE_INT16_MIN || max > TYPE_INT16_MAX) {
  424. G_warning(_("Selected GDAL datatype does not cover data range."));
  425. G_warning(_("GDAL datatype: %s, range: %d - %d"),
  426. GDALGetDataTypeName(datatype), TYPE_INT16_MIN,
  427. TYPE_INT16_MAX);
  428. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  429. return 1;
  430. }
  431. else
  432. return 0;
  433. case GDT_Int32:
  434. case GDT_CInt32:
  435. if (min < TYPE_INT32_MIN || max > TYPE_INT32_MAX) {
  436. G_warning(_("Selected GDAL datatype does not cover data range."));
  437. G_warning(_("GDAL datatype: %s, range: %d - %d"),
  438. GDALGetDataTypeName(datatype), TYPE_INT32_MIN,
  439. TYPE_INT32_MAX);
  440. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  441. return 1;
  442. }
  443. else
  444. return 0;
  445. case GDT_UInt32:
  446. if (min < TYPE_UINT32_MIN || max > TYPE_UINT32_MAX) {
  447. G_warning(_("Selected GDAL datatype does not cover data range."));
  448. G_warning(_("GDAL datatype: %s, range: %u - %u"),
  449. GDALGetDataTypeName(datatype), TYPE_UINT32_MIN,
  450. TYPE_UINT32_MAX);
  451. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  452. return 1;
  453. }
  454. else
  455. return 0;
  456. case GDT_Float32:
  457. case GDT_CFloat32:
  458. /* support export of inf / -inf ? */
  459. if ((float)min !=TYPE_FLOAT32_MIN && (float)max != TYPE_FLOAT32_MAX &&
  460. (min < TYPE_FLOAT32_MIN || max > TYPE_FLOAT32_MAX)) {
  461. G_warning(_("Selected GDAL datatype does not cover data range."));
  462. G_warning(_("GDAL datatype: %s, range: %.7g - %.7g"),
  463. GDALGetDataTypeName(datatype), TYPE_FLOAT32_MIN,
  464. TYPE_FLOAT32_MAX);
  465. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  466. return 1;
  467. }
  468. else
  469. return 0;
  470. case GDT_Float64:
  471. case GDT_CFloat64:
  472. /* not possible because DCELL is FLOAT64, not 128bit floating point, but anyway... */
  473. /* support export of inf / -inf ? */
  474. if (min < TYPE_FLOAT64_MIN || max > TYPE_FLOAT64_MAX) {
  475. G_warning(_("Selected GDAL datatype does not cover data range."));
  476. G_warning(_("GDAL datatype: %s, range: %.16g - %.16g"),
  477. GDALGetDataTypeName(datatype), TYPE_FLOAT64_MIN,
  478. TYPE_FLOAT64_MAX);
  479. G_warning(_("Raster map <%s> range: %g - %g"), name, min, max);
  480. return 1;
  481. }
  482. else
  483. return 0;
  484. default:
  485. return 0;
  486. }
  487. }