main.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. ****************************************************************************
  3. *
  4. * MODULE: r.composite
  5. * AUTHOR(S): Glynn Clements - glynn.clements@virgin.net
  6. * PURPOSE: Combine red, green and blue layers into a single
  7. * layer using a quantisation of the RGB color space.
  8. * Using Floyd-Steinberg dithering
  9. *
  10. * COPYRIGHT: (C) 2001-2008 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <grass/gis.h>
  21. #include <grass/raster.h>
  22. #include <grass/glocale.h>
  23. struct band
  24. {
  25. struct Option *opt_name;
  26. struct Option *opt_levels;
  27. char *name;
  28. int levels;
  29. int maxlev;
  30. int offset;
  31. int file;
  32. int type;
  33. int size;
  34. unsigned char *array[3];
  35. short *floyd[2];
  36. struct Colors colors;
  37. };
  38. static char *const color_names[3] = { "red", "green", "blue" };
  39. static struct band B[3];
  40. static int closest;
  41. static void make_color_cube(struct Colors *colors);
  42. static int quantize(int c, int x);
  43. int main(int argc, char **argv)
  44. {
  45. struct GModule *module;
  46. struct Option *opt_out;
  47. struct Option *opt_lev;
  48. struct Flag *flg_d;
  49. struct Flag *flg_c;
  50. int dither;
  51. char *out_name;
  52. int out_file;
  53. CELL *out_array;
  54. struct Colors out_colors;
  55. int levels;
  56. int atrow, atcol;
  57. struct Cell_head window;
  58. unsigned char *dummy, *nulls;
  59. int i, j;
  60. struct History history;
  61. G_gisinit(argv[0]);
  62. module = G_define_module();
  63. G_add_keyword(_("raster"));
  64. G_add_keyword(_("composite"));
  65. G_add_keyword("RGB");
  66. module->description =
  67. _("Combines red, green and blue raster maps into "
  68. "a single composite raster map.");
  69. for (i = 0; i < 3; i++) {
  70. struct Option *opt;
  71. char buff[80];
  72. B[i].opt_name = opt = G_define_standard_option(G_OPT_R_INPUT);
  73. sprintf(buff, "%s", color_names[i]);
  74. opt->key = G_store(buff);
  75. opt->answer = NULL;
  76. sprintf(buff, _("Name of raster map to be used for <%s>"),
  77. color_names[i]);
  78. opt->description = G_store(buff);
  79. }
  80. opt_lev = G_define_option();
  81. opt_lev->key = "levels";
  82. opt_lev->type = TYPE_INTEGER;
  83. opt_lev->required = NO;
  84. opt_lev->options = "1-256";
  85. opt_lev->answer = "32";
  86. opt_lev->description =
  87. _("Number of levels to be used for each component");
  88. opt_lev->guisection = _("Levels");
  89. for (i = 0; i < 3; i++) {
  90. struct Option *opt;
  91. char buff[80];
  92. B[i].opt_levels = opt = G_define_option();
  93. sprintf(buff, "level_%s", color_names[i]);
  94. opt->key = G_store(buff);
  95. opt->type = TYPE_INTEGER;
  96. opt->required = NO;
  97. opt->options = "1-256";
  98. sprintf(buff, _("Number of levels to be used for <%s>"),
  99. color_names[i]);
  100. opt->description = G_store(buff);
  101. opt->guisection = _("Levels");
  102. }
  103. opt_out = G_define_standard_option(G_OPT_R_OUTPUT);
  104. flg_d = G_define_flag();
  105. flg_d->key = 'd';
  106. flg_d->description = _("Dither");
  107. flg_c = G_define_flag();
  108. flg_c->key = 'c';
  109. flg_c->description = _("Use closest color");
  110. if (G_parser(argc, argv))
  111. exit(EXIT_FAILURE);
  112. levels = atoi(opt_lev->answer);
  113. dither = flg_d->answer;
  114. closest = flg_c->answer;
  115. /* read in current window */
  116. G_get_window(&window);
  117. dummy = G_malloc(window.cols);
  118. nulls = G_malloc(window.cols);
  119. for (i = 0; i < 3; i++) {
  120. struct band *b = &B[i];
  121. /* Get name of layer to be used */
  122. b->name = b->opt_name->answer;
  123. /* Make sure map is available */
  124. b->file = Rast_open_old(b->name, "");
  125. b->type = Rast_get_map_type(b->file);
  126. b->size = Rast_cell_size(b->type);
  127. /* Reading color lookup table */
  128. if (Rast_read_colors(b->name, "", &b->colors) == -1)
  129. G_fatal_error(_("Unable to read color file of raster map <%s>"), b->name);
  130. for (j = 0; j < 3; j++)
  131. b->array[j] = (i == j)
  132. ? G_malloc(window.cols)
  133. : dummy;
  134. b->levels = b->opt_levels->answer ? atoi(b->opt_levels->answer)
  135. : levels;
  136. b->maxlev = b->levels - 1;
  137. b->offset = 128 / b->maxlev;
  138. if (dither)
  139. for (j = 0; j < 2; j++)
  140. b->floyd[j] = G_calloc(window.cols + 2, sizeof(short));
  141. }
  142. /* open output files */
  143. out_name = opt_out->answer;
  144. out_file = Rast_open_c_new(out_name);
  145. out_array = Rast_allocate_c_buf();
  146. /* Make color table */
  147. make_color_cube(&out_colors);
  148. G_message(_("Writing raster map <%s>..."), out_name);
  149. for (atrow = 0; atrow < window.rows; atrow++) {
  150. G_percent(atrow, window.rows, 2);
  151. for (i = 0; i < 3; i++) {
  152. struct band *b = &B[i];
  153. Rast_get_row_colors(b->file, atrow, &b->colors,
  154. b->array[0],
  155. b->array[1], b->array[2], nulls);
  156. if (dither) {
  157. short *tmp = b->floyd[0];
  158. b->floyd[0] = b->floyd[1];
  159. for (atcol = 0; atcol < window.cols + 2; atcol++)
  160. tmp[atcol] = 0;
  161. b->floyd[1] = tmp;
  162. }
  163. }
  164. for (atcol = 0; atcol < window.cols; atcol++) {
  165. int val[3];
  166. if (nulls[atcol]) {
  167. Rast_set_c_null_value(&out_array[atcol], 1);
  168. continue;
  169. }
  170. for (i = 0; i < 3; i++) {
  171. struct band *b = &B[i];
  172. int v = b->array[i][atcol];
  173. if (dither) {
  174. int r, w, d;
  175. v += b->floyd[0][atcol + 1] / 16;
  176. v = (v < 0) ? 0 : (v > 255) ? 255 : v;
  177. r = quantize(i, v);
  178. w = r * 255 / b->maxlev;
  179. d = v - w;
  180. b->floyd[0][atcol + 2] += 7 * d;
  181. b->floyd[1][atcol + 0] += 3 * d;
  182. b->floyd[1][atcol + 1] += 5 * d;
  183. b->floyd[1][atcol + 2] += 1 * d;
  184. val[i] = r;
  185. }
  186. else
  187. val[i] = quantize(i, v);
  188. }
  189. out_array[atcol] = (CELL)
  190. (val[2] * B[1].levels + val[1]) * B[0].levels + val[0];
  191. }
  192. Rast_put_row(out_file, out_array, CELL_TYPE);
  193. }
  194. G_percent(window.rows, window.rows, 1);
  195. /* Close the input files */
  196. for (i = 0; i < 3; i++)
  197. Rast_close(B[i].file);
  198. /* Close the output file */
  199. Rast_close(out_file);
  200. Rast_write_colors(out_name, G_mapset(), &out_colors);
  201. Rast_short_history(out_name, "raster", &history);
  202. Rast_command_history(&history);
  203. Rast_write_history(out_name, &history);
  204. G_done_msg(_("Raster map <%s> created."), out_name);
  205. exit(EXIT_SUCCESS);
  206. }
  207. static int quantize(int c, int x)
  208. {
  209. return closest
  210. ? (x + B[c].offset) * B[c].maxlev / 256 : x * B[c].levels / 256;
  211. }
  212. static void make_color_cube(struct Colors *colors)
  213. {
  214. int nr = B[0].levels;
  215. int ng = B[1].levels;
  216. int nb = B[2].levels;
  217. int mr = B[0].maxlev;
  218. int mg = B[1].maxlev;
  219. int mb = B[2].maxlev;
  220. int g, b;
  221. int i = 0;
  222. Rast_init_colors(colors);
  223. G_message(_("Creating color table for output raster map..."));
  224. for (b = 0; b < nb; b++) {
  225. G_percent(b, nb, 5);
  226. for (g = 0; g < ng; g++) {
  227. int blu = b * 255 / mb;
  228. int grn = g * 255 / mg;
  229. CELL i0 = i;
  230. CELL i1 = i + mr;
  231. Rast_add_c_color_rule(&i0, 0, grn, blu,
  232. &i1, 255, grn, blu, colors);
  233. i += nr;
  234. }
  235. }
  236. G_percent(nb, nb, 1);
  237. }