123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640 |
- /****************************************************************************
- *
- * MODULE: r.in.bin
- * AUTHOR(S): Jacques Bouchard, France (bouchard@onera.fr)
- * Bob Covill <bcovill tekmap.ns.ca>
- * Markus Metz
- * PURPOSE: Import binary files
- * COPYRIGHT: (C) 2000 - 2014 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <math.h>
- #include <sys/stat.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #include "gmt_grd.h"
- enum fliphv {
- FLIP_H = 1,
- FLIP_V = 2,
- };
- static void swap_2(void *p)
- {
- unsigned char *q = p;
- unsigned char t;
- t = q[0]; q[0] = q[1]; q[1] = t;
- }
- static void swap_4(void *p)
- {
- unsigned char *q = p;
- unsigned char t;
- t = q[0]; q[0] = q[3]; q[3] = t;
- t = q[1]; q[1] = q[2]; q[2] = t;
- }
- static void swap_8(void *p)
- {
- unsigned char *q = p;
- unsigned char t;
- t = q[0]; q[0] = q[7]; q[7] = t;
- t = q[1]; q[1] = q[6]; q[6] = t;
- t = q[2]; q[2] = q[5]; q[5] = t;
- t = q[3]; q[3] = q[4]; q[4] = t;
- }
- static void read_int(FILE *fp, int swap_flag, int *x)
- {
- if (fread(x, 4, 1, fp) != 1)
- G_fatal_error(_("Error reading data"));
- if (swap_flag)
- swap_4(x);
- }
- static void read_double(FILE *fp, int swap_flag, double *x)
- {
- if (fread(x, 8, 1, fp) != 1)
- G_fatal_error(_("Error reading data"));
- if (swap_flag)
- swap_8(x);
- }
- static void read_gmt_header(struct GRD_HEADER *header, int swap_flag, FILE *fp)
- {
- read_int(fp, swap_flag, &header->nx);
- read_int(fp, swap_flag, &header->ny);
- read_int(fp, swap_flag, &header->node_offset);
- read_double(fp, swap_flag, &header->x_min);
- read_double(fp, swap_flag, &header->x_max);
- read_double(fp, swap_flag, &header->y_min);
- read_double(fp, swap_flag, &header->y_max);
- read_double(fp, swap_flag, &header->z_min);
- read_double(fp, swap_flag, &header->z_max);
- read_double(fp, swap_flag, &header->x_inc);
- read_double(fp, swap_flag, &header->y_inc);
- read_double(fp, swap_flag, &header->z_scale_factor);
- read_double(fp, swap_flag, &header->z_add_offset);
- fread(&header->x_units, sizeof(char[GRD_UNIT_LEN]), 1, fp);
- fread(&header->y_units, sizeof(char[GRD_UNIT_LEN]), 1, fp);
- fread(&header->z_units, sizeof(char[GRD_UNIT_LEN]), 1, fp);
- fread(&header->title, sizeof(char[GRD_TITLE_LEN]), 1, fp);
- fread(&header->command, sizeof(char[GRD_COMMAND_LEN]), 1, fp);
- fread(&header->remark, sizeof(char[GRD_REMARK_LEN]), 1, fp);
- }
- static void get_gmt_header(const struct GRD_HEADER *header, struct Cell_head *region)
- {
- region->cols = header->nx;
- region->rows = header->ny;
- region->west = header->x_min;
- region->east = header->x_max;
- region->south = header->y_min;
- region->north = header->y_max;
- region->ew_res = header->x_inc;
- region->ns_res = header->y_inc;
- }
- static void convert_cell(
- DCELL *out_cell, unsigned char *in_cell,
- int is_fp, int is_signed, int bytes, int swap_flag)
- {
- if (swap_flag) {
- switch (bytes) {
- case 1: break;
- case 2: swap_2(in_cell); break;
- case 4: swap_4(in_cell); break;
- case 8: swap_8(in_cell); break;
- }
- }
- if (is_fp) {
- switch (bytes) {
- case 4:
- *out_cell = (DCELL) *(float *) in_cell;
- break;
- case 8:
- *out_cell = (DCELL) *(double *) in_cell;
- break;
- }
- }
- else if (is_signed) {
- switch (bytes) {
- case 1:
- *out_cell = (DCELL) *(signed char *) in_cell;
- break;
- case 2:
- *out_cell = (DCELL) *(short *) in_cell;
- break;
- case 4:
- *out_cell = (DCELL) *(int *) in_cell;
- break;
- #ifdef HAVE_LONG_LONG_INT
- case 8:
- *out_cell = (DCELL) *(long long *) in_cell;
- break;
- #endif
- }
- }
- else {
- switch (bytes) {
- case 1:
- *out_cell = (DCELL) *(unsigned char *) in_cell;
- break;
- case 2:
- *out_cell = (DCELL) *(unsigned short *) in_cell;
- break;
- case 4:
- *out_cell = (DCELL) *(unsigned int *) in_cell;
- break;
- #ifdef HAVE_LONG_LONG_INT
- case 8:
- *out_cell = (DCELL) *(unsigned long long *) in_cell;
- break;
- #endif
- }
- }
- }
- static void convert_row(
- DCELL *raster, unsigned char *in_buf, int ncols,
- int is_fp, int is_signed, int bytes, int swap_flag,
- double null_val, int flip)
- {
- unsigned char *ptr = in_buf;
- int i, i2;
- for (i = 0; i < ncols; i++) {
- DCELL x;
- convert_cell(&x, ptr, is_fp, is_signed, bytes, swap_flag);
- i2 = i;
- if (flip & FLIP_H)
- i2 = ncols - i - 1;
- if (x == null_val)
- Rast_set_d_null_value(&raster[i2], 1);
- else
- raster[i2] = x;
- ptr += bytes;
- }
- }
- int main(int argc, char *argv[])
- {
- struct GModule *module;
- struct
- {
- struct Option *input;
- struct Option *output;
- struct Option *null;
- struct Option *bytes;
- struct Option *hbytes;
- struct Option *bands;
- struct Option *order;
- struct Option *title;
- struct Option *north;
- struct Option *south;
- struct Option *east;
- struct Option *west;
- struct Option *rows;
- struct Option *cols;
- struct Option *flip;
- } parm;
- struct
- {
- struct Flag *float_in;
- struct Flag *double_in;
- struct Flag *gmt_hd;
- struct Flag *sign;
- struct Flag *swap;
- } flag;
- char *desc = NULL;
- const char *input;
- const char *outpre;
- char output[GNAME_MAX];
- const char *title;
- double null_val = 0.0/0.0;
- int is_fp;
- int is_signed;
- int bytes, hbytes;
- int band, nbands, bsize;
- int order;
- int swap_flag;
- int i, flip;
- struct Cell_head cellhd;
- int nrows, ncols;
- int grass_nrows, grass_ncols;
- unsigned char *in_buf;
- DCELL *out_buf;
- RASTER_MAP_TYPE map_type;
- int fd;
- FILE *fp;
- off_t file_size, band_off;
- struct GRD_HEADER header;
- int row;
- struct History history;
- off_t expected;
- G_gisinit(argv[0]);
- /* Set description */
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("import"));
- module->description =
- _("Import a binary raster file into a GRASS raster map layer.");
- flag.float_in = G_define_flag();
- flag.float_in->key = 'f';
- flag.float_in->description =
- _("Import as floating-point data (default: integer)");
- flag.double_in = G_define_flag();
- flag.double_in->key = 'd';
- flag.double_in->description =
- _("Import as double-precision floating-point data (default: integer)");
- flag.sign = G_define_flag();
- flag.sign->key = 's';
- flag.sign->description = _("Signed data (two's complement)");
- flag.sign->guisection = _("Settings");
- flag.swap = G_define_flag();
- flag.swap->key = 'b';
- flag.swap->description = _("Byte swap the data during import");
- flag.swap->guisection = _("Settings");
- flag.gmt_hd = G_define_flag();
- flag.gmt_hd->key = 'h';
- flag.gmt_hd->description = _("Get region info from GMT style header");
- flag.gmt_hd->guisection = _("Bounds");
- parm.input = G_define_standard_option(G_OPT_F_BIN_INPUT);
- parm.input->description = _("Name of binary raster file to be imported");
- parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
- parm.output->description = _("Output name or prefix if several bands are imported");
- parm.title = G_define_option();
- parm.title->key = "title";
- parm.title->key_desc = "phrase";
- parm.title->type = TYPE_STRING;
- parm.title->required = NO;
- parm.title->description = _("Title for resultant raster map");
- parm.bytes = G_define_option();
- parm.bytes->key = "bytes";
- parm.bytes->type = TYPE_INTEGER;
- parm.bytes->required = NO;
- parm.bytes->options = "1,2,4,8";
- parm.bytes->description = _("Number of bytes per cell");
- parm.bytes->guisection = _("Settings");
- parm.hbytes = G_define_option();
- parm.hbytes->key = "header";
- parm.hbytes->type = TYPE_INTEGER;
- parm.hbytes->required = NO;
- parm.hbytes->answer = "0";
- parm.hbytes->description = _("Header size in bytes");
- parm.hbytes->guisection = _("Settings");
- parm.bands = G_define_option();
- parm.bands->key = "bands";
- parm.bands->type = TYPE_INTEGER;
- parm.bands->required = NO;
- parm.bands->answer = "1";
- parm.bands->label = _("Number of bands in input file");
- parm.bands->description = _("Bands must be in band-sequential order");
- parm.bands->guisection = _("Settings");
- parm.order = G_define_option();
- parm.order->key = "order";
- parm.order->type = TYPE_STRING;
- parm.order->required = NO;
- parm.order->options = "big,little,native,swap";
- parm.order->description = _("Output byte order");
- parm.order->answer = "native";
- parm.north = G_define_option();
- parm.north->key = "north";
- parm.north->type = TYPE_DOUBLE;
- parm.north->required = NO;
- parm.north->description =
- _("Northern limit of geographic region (outer edge)");
- parm.north->guisection = _("Bounds");
- parm.south = G_define_option();
- parm.south->key = "south";
- parm.south->type = TYPE_DOUBLE;
- parm.south->required = NO;
- parm.south->description =
- _("Southern limit of geographic region (outer edge)");
- parm.south->guisection = _("Bounds");
- parm.east = G_define_option();
- parm.east->key = "east";
- parm.east->type = TYPE_DOUBLE;
- parm.east->required = NO;
- parm.east->description =
- _("Eastern limit of geographic region (outer edge)");
- parm.east->guisection = _("Bounds");
- parm.west = G_define_option();
- parm.west->key = "west";
- parm.west->type = TYPE_DOUBLE;
- parm.west->required = NO;
- parm.west->description =
- _("Western limit of geographic region (outer edge)");
- parm.west->guisection = _("Bounds");
- parm.rows = G_define_option();
- parm.rows->key = "rows";
- parm.rows->type = TYPE_INTEGER;
- parm.rows->required = NO;
- parm.rows->description = _("Number of rows");
- parm.rows->guisection = _("Bounds");
- parm.cols = G_define_option();
- parm.cols->key = "cols";
- parm.cols->type = TYPE_INTEGER;
- parm.cols->required = NO;
- parm.cols->description = _("Number of columns");
- parm.cols->guisection = _("Bounds");
- parm.null = G_define_option();
- parm.null->key = "anull";
- parm.null->type = TYPE_DOUBLE;
- parm.null->required = NO;
- parm.null->description = _("Set Value to NULL");
- parm.null->guisection = _("Settings");
- parm.flip = G_define_option();
- parm.flip->key = "flip";
- parm.flip->type = TYPE_STRING;
- parm.flip->required = NO;
- parm.flip->options = "h,v";
- parm.flip->multiple = YES;
- parm.flip->label = _("Flip input horizontal and/or vertical");
- G_asprintf(&desc,
- "h;%s;v;%s",
- _("Flip input horizontal (East - West)"),
- _("Flip input vertical (North - South)"));
- parm.flip->descriptions = desc;
- parm.flip->guisection = _("Settings");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- input = parm.input->answer;
- outpre = parm.output->answer;
- title = parm.title->answer;
- nbands = atoi(parm.bands->answer);
- if (nbands < 1)
- G_fatal_error(_("Option %s must be > 0"), parm.bands->key);
- hbytes = atoi(parm.hbytes->answer);
- if (hbytes < 0)
- G_fatal_error(_("Option %s must be >= 0"), parm.hbytes->key);
- if (G_strcasecmp(parm.order->answer, "big") == 0)
- order = 0;
- else if (G_strcasecmp(parm.order->answer, "little") == 0)
- order = 1;
- else if (G_strcasecmp(parm.order->answer, "native") == 0)
- order = G_is_little_endian() ? 1 : 0;
- else if (G_strcasecmp(parm.order->answer, "swap") == 0)
- order = G_is_little_endian() ? 0 : 1;
- if (flag.swap->answer) {
- if (strcmp(parm.order->answer, "native") != 0)
- G_fatal_error(_("-%c and %s= are mutually exclusive"),
- flag.swap->key, parm.order->key);
- order = G_is_little_endian() ? 0 : 1;
- }
- if (flag.gmt_hd->answer && parm.flip->answer)
- G_fatal_error(_("-%c and %s= are mutually exclusive"),
- flag.gmt_hd->key, parm.flip->key);
- if (flag.gmt_hd->answer && hbytes > 0)
- G_warning(_("Option %s= is ignored if -%c is set"),
- parm.hbytes->key, flag.gmt_hd->key);
- if (flag.gmt_hd->answer && nbands > 1)
- G_warning(_("Option %s= is ignored if -%c is set"),
- parm.bands->key, flag.gmt_hd->key);
- swap_flag = order == (G_is_little_endian() ? 0 : 1);
- is_signed = !!flag.sign->answer;
- flip = 0;
- if (parm.flip->answers) {
- for (i = 0; parm.flip->answers[i]; i++) {
- if (parm.flip->answers[i][0] == 'h')
- flip |= FLIP_H;
- if (parm.flip->answers[i][0] == 'v')
- flip |= FLIP_V;
- }
- }
- is_fp = 0;
- bytes = 0;
- if (parm.bytes->answer)
- bytes = atoi(parm.bytes->answer);
- if (flag.float_in->answer && flag.double_in->answer)
- G_fatal_error(_("-%c and -%c are mutually exclusive"),
- flag.float_in->key, flag.double_in->key);
- if (flag.float_in->answer) {
- if (bytes && bytes < 4)
- G_fatal_error(_("-%c incompatible with %s=%d; must be 4 or 8"),
- flag.float_in->key, parm.bytes->key, bytes);
- if (!bytes)
- bytes = 4;
- is_fp = 1;
- }
- if (flag.double_in->answer) {
- if (bytes && bytes != 8)
- G_fatal_error(_("-%c incompatible with %s=%d; must be 8"),
- flag.double_in->key, parm.bytes->key, bytes);
- if (!bytes)
- bytes = 8;
- is_fp = 1;
- }
- if (!is_fp && !bytes)
- G_fatal_error(_("%s= required for integer data"), parm.bytes->key);
- #ifndef HAVE_LONG_LONG_INT
- if (!is_fp && bytes > 4)
- G_fatal_error(_("Integer input doesn't support %s=8 in this build"),
- parm.bytes->key);
- #endif
- if (bytes != 1 && bytes != 2 && bytes != 4 && bytes != 8)
- G_fatal_error(_("%s= must be 1, 2, 4 or 8"), parm.bytes->key);
- if (parm.null->answer && G_strcasecmp(parm.null->answer, "nan") != 0)
- null_val = atof(parm.null->answer);
- cellhd.zone = G_zone();
- cellhd.proj = G_projection();
- if (!flag.gmt_hd->answer) {
- /* NO GMT header */
- int num_bounds;
- if (!parm.rows->answer || !parm.cols->answer)
- G_fatal_error(_("Either -%c or %s= and %s= must be given"),
- flag.gmt_hd->key, parm.rows->key, parm.cols->key);
- num_bounds = !!parm.north->answer + !!parm.south->answer +
- !!parm.east->answer + !!parm.west->answer;
- if (num_bounds != 0 && num_bounds != 4)
- G_fatal_error(_("Either all or none of %s=, %s=, %s= and %s= must be given"),
- parm.north->key, parm.south->key,
- parm.east->key, parm.west->key);
- cellhd.rows = atoi(parm.rows->answer);
- cellhd.cols = atoi(parm.cols->answer);
- if (num_bounds > 0) {
- if (!G_scan_northing(parm.north->answer, &cellhd.north, cellhd.proj))
- G_fatal_error(_("Illegal north coordinate <%s>"), parm.north->answer);
- if (!G_scan_northing(parm.south->answer, &cellhd.south, cellhd.proj))
- G_fatal_error(_("Illegal south coordinate <%s>"), parm.south->answer);
- if (!G_scan_easting(parm.east->answer, &cellhd.east, cellhd.proj))
- G_fatal_error(_("Illegal east coordinate <%s>"), parm.east->answer);
- if (!G_scan_easting(parm.west->answer, &cellhd.west, cellhd.proj))
- G_fatal_error(_("Illegal west coordinate <%s>"), parm.west->answer);
- }
- }
- fp = fopen(input, "rb");
- if (!fp)
- G_fatal_error(_("Unable to open <%s>"), input);
- /* Find File Size in Byte and Check against byte size */
- G_fseek(fp, 0, SEEK_END);
- file_size = G_ftell(fp);
- G_fseek(fp, 0, SEEK_SET);
- /* Read binary GMT style header */
- if (flag.gmt_hd->answer) {
- read_gmt_header(&header, swap_flag, fp);
- get_gmt_header(&header, &cellhd);
- hbytes = 892;
- nbands = 1;
- }
- /* Adjust Cell Header to New Values */
- G_adjust_Cell_head(&cellhd, 1, 1);
- if (cellhd.proj == PROJECTION_LL && cellhd.ew_res / cellhd.ns_res > 10.)
- /* TODO: find a reasonable value */
- G_warning(
- _("East-West (ewres: %f) and North-South (nwres: %f) "
- "resolution differ significantly. "
- "Did you assign %s= and %s= correctly?"),
- cellhd.ew_res, cellhd.ns_res, parm.east->key, parm.west->key);
- grass_nrows = nrows = cellhd.rows;
- grass_ncols = ncols = cellhd.cols;
- Rast_set_window(&cellhd);
- if (grass_nrows != Rast_window_rows())
- G_fatal_error("rows changed from %d to %d",
- grass_nrows, Rast_window_rows());
- if (grass_ncols != Rast_window_cols())
- G_fatal_error("cols changed from %d to %d",
- grass_ncols, Rast_window_cols());
- expected = (off_t) ncols * nrows * bytes * nbands + hbytes;
- if (file_size != expected) {
- G_warning(_("File Size %"PRI_OFF_T" ... Total Bytes %"PRI_OFF_T),
- file_size, expected);
- G_fatal_error(_("Bytes do not match file size"));
- }
- in_buf = G_malloc(ncols * bytes);
- out_buf = Rast_allocate_d_buf();
- map_type = is_fp ? (bytes > 4 ? DCELL_TYPE : FCELL_TYPE) : CELL_TYPE;
- in_buf = G_malloc(ncols * bytes);
- out_buf = Rast_allocate_d_buf();
- bsize = log10(nbands) + 1;
- if (!flag.gmt_hd->answer && hbytes > 0)
- G_fseek(fp, hbytes, SEEK_SET);
- for (band = 1; band <= nbands; band++) {
-
- if (nbands > 1) {
- G_message(_("Importing band %d..."), band);
- sprintf(output, "%s%0*d", outpre, bsize, band);
- }
- else
- sprintf(output, "%s", outpre);
- fd = Rast_open_new(output, map_type);
-
- band_off = (off_t)nrows * ncols * bytes * (band - 1) + hbytes;
- for (row = 0; row < grass_nrows; row++) {
- G_percent(row, nrows, 2);
- if (flip & FLIP_V) {
- G_fseek(fp, (off_t) (grass_nrows - row - 1) * ncols * bytes + band_off,
- SEEK_SET);
- }
- if (fread(in_buf, bytes, ncols, fp) != ncols)
- G_fatal_error(_("Error reading data"));
- convert_row(out_buf, in_buf, ncols, is_fp, is_signed,
- bytes, swap_flag, null_val, flip);
- Rast_put_d_row(fd, out_buf);
- }
- G_percent(row, nrows, 2); /* finish it off */
- Rast_close(fd);
- G_debug(1, "Creating support files for %s", output);
- if (title)
- Rast_put_cell_title(output, title);
- Rast_short_history(output, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(output, &history);
- }
- fclose(fp);
- return EXIT_SUCCESS;
- }
|