export_band.c 15 KB

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