main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. /*
  2. ****************************************************************************
  3. *
  4. * MODULE: r.out.png
  5. * AUTHOR(S): Bill Brown - USA-CERL
  6. * Alex Shevlakov - sixote@yahoo.com
  7. * Hamish Bowman
  8. * PURPOSE: Export GRASS raster as non-georeferenced PNG image.
  9. * COPYRIGHT: (C) 2000-2010 by the GRASS Development Team
  10. *
  11. * This program is free software under the GNU General Public
  12. * License (>=v2). Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. *****************************************************************************/
  16. /*
  17. * Alex Shevlakov, sixote@yahoo.com, 03/2000
  18. * based on r.out.ppm by
  19. * Written by Bill Brown, USA-CERL March 21, 1994
  20. *
  21. * Use to convert grass raster map to PNG
  22. * uses currently selected region
  23. *
  24. */
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <float.h>
  28. #ifndef _MYINCLUDE_H
  29. #define _MYINCLUDE_H
  30. #include <png.h>
  31. #include "pngfunc.h"
  32. /* #include <pnm.h> this is already included from pngfunc.h */
  33. #endif /* _MYINCLUDE_H */
  34. #include <grass/gis.h>
  35. #include <grass/raster.h>
  36. #include <grass/colors.h>
  37. #include <grass/glocale.h>
  38. typedef int FILEDESC;
  39. /* global functions */
  40. static int write_wld(const char *, const struct Cell_head *);
  41. int main(int argc, char *argv[])
  42. {
  43. struct GModule *module;
  44. struct Option *rast, *png_file, *compr; /* , *bgcolor; */
  45. struct Flag *alpha, *wld_flag;
  46. char *rastermap;
  47. char *basename = NULL, *outfile = NULL;
  48. unsigned char *set, *ored, *ogrn, *oblu;
  49. int def_red, def_grn, def_blu;
  50. CELL *cell_buf;
  51. FCELL *fcell_buf;
  52. DCELL *dcell_buf;
  53. void *voidc;
  54. int rtype, row, col, do_stdout = 0;
  55. size_t rsize;
  56. int png_compr, ret, do_alpha;
  57. struct Cell_head win;
  58. FILEDESC cellfile = 0;
  59. FILE *fp;
  60. /* now goes from pnmtopng.c* -A.Sh */
  61. /*
  62. * pnmtopng.c -
  63. * read a portable anymap and produce a Portable Network Graphics file
  64. *
  65. * derived from pnmtorast.c (c) 1990,1991 by Jef Poskanzer and some
  66. * parts derived from ppmtogif.c by Marcel Wijkstra <wijkstra@fwi.uva.nl>
  67. * thanks to Greg Roelofs <newt@pobox.com> for contributions and bug-fixes
  68. *
  69. * Copyright (C) 1995-1998 by Alexander Lehmann <alex@hal.rhein-main.de>
  70. * and Willem van Schaik <willem@schaik.com>
  71. *
  72. * Permission to use, copy, modify, and distribute this software and its
  73. * documentation for any purpose and without fee is hereby granted, provided
  74. * that the above copyright notice appear in all copies and that both that
  75. * copyright notice and this permission notice appear in supporting
  76. * documentation. This software is provided "as is" without express or
  77. * implied warranty.
  78. */
  79. png_struct *png_ptr;
  80. png_info *info_ptr;
  81. png_byte *line;
  82. png_byte *pp;
  83. /* these variables are declared static because gcc wasn't kidding
  84. * about "variable XXX might be clobbered by `longjmp' or `vfork'"
  85. * (stack corruption observed on Solaris 2.6 with gcc 2.8.1, even
  86. * in the absence of any other error condition) */
  87. static xelval maxmaxval;
  88. static int depth;
  89. static int filter;
  90. /* these guys are initialized to quiet compiler warnings: */
  91. maxmaxval = 255;
  92. depth = 0;
  93. G_gisinit(argv[0]);
  94. module = G_define_module();
  95. G_add_keyword(_("raster"));
  96. G_add_keyword(_("export"));
  97. G_add_keyword("PNG");
  98. module->description =
  99. _("Export a GRASS raster map as a non-georeferenced PNG image.");
  100. rast = G_define_standard_option(G_OPT_R_INPUT);
  101. png_file = G_define_standard_option(G_OPT_F_OUTPUT);
  102. png_file->required = YES;
  103. png_file->description = _("Name for new PNG file (use '-' for stdout)");
  104. compr = G_define_option();
  105. compr->key = "compression";
  106. compr->type = TYPE_INTEGER;
  107. compr->required = NO;
  108. compr->multiple = NO;
  109. compr->options = "0-9";
  110. compr->label = _("Compression level of PNG file");
  111. compr->description = _("(0 = none, 1 = fastest, 9 = best)");
  112. compr->answer = "6";
  113. /* bgcolor = G_define_standard_option(G_OPT_C_BG); */
  114. alpha = G_define_flag();
  115. alpha->key = 't';
  116. alpha->description = _("Make NULL cells transparent");
  117. wld_flag = G_define_flag();
  118. wld_flag->key = 'w';
  119. wld_flag->description = _("Output world file");
  120. /* see what can be done to convert'em -A.Sh.
  121. * gscale = G_define_flag ();
  122. * gscale->key = 'g';
  123. * gscale->description = "Output greyscale instead of color";
  124. */
  125. if (G_parser(argc, argv))
  126. exit(EXIT_FAILURE);
  127. rastermap = rast->answer;
  128. do_alpha = alpha->answer ? TRUE : FALSE;
  129. if (strcmp(png_file->answer, "-") != 0)
  130. basename = G_store(png_file->answer);
  131. else
  132. do_stdout = TRUE;
  133. if (basename) {
  134. G_basename(basename, "png");
  135. outfile = G_malloc(strlen(basename) + 5);
  136. sprintf(outfile, "%s.png", basename);
  137. }
  138. png_compr = atoi(compr->answer);
  139. #ifdef MAYBE_LATER
  140. /* ... if at all */
  141. ret = G_str_to_color(bgcolor->answer, &def_red, &def_grn, &def_blu);
  142. if (ret == 0)
  143. G_fatal_error(_("[%s]: No such color"), bgcolor->answer);
  144. else if (ret == 2) { /* (ret==2) is "none" */
  145. if(!do_alpha)
  146. do_alpha = TRUE;
  147. }
  148. #else
  149. ret = G_str_to_color(DEFAULT_BG_COLOR, &def_red, &def_grn, &def_blu);
  150. #endif
  151. /*G_get_set_window (&win); *//* 10/99 MN: check for current region */
  152. G_get_window(&win);
  153. G_debug(1, "rows = %d, cols = %d", win.rows, win.cols);
  154. /* open raster map for reading */
  155. cellfile = Rast_open_old(rast->answer, "");
  156. cell_buf = Rast_allocate_c_buf();
  157. fcell_buf = Rast_allocate_f_buf();
  158. dcell_buf = Rast_allocate_d_buf();
  159. ored = G_malloc(win.cols);
  160. ogrn = G_malloc(win.cols);
  161. oblu = G_malloc(win.cols);
  162. set = G_malloc(win.cols);
  163. /* open png file for writing */
  164. if (do_stdout)
  165. fp = stdout;
  166. else if (NULL == (fp = fopen(outfile, "w")))
  167. G_fatal_error(_("Unable to open output file <%s>"), outfile);
  168. png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  169. &pnmtopng_jmpbuf_struct,
  170. pnmtopng_error_handler, NULL);
  171. if (png_ptr == NULL) {
  172. fclose(fp);
  173. G_fatal_error("cannot allocate LIBPNG structure");
  174. }
  175. info_ptr = png_create_info_struct(png_ptr);
  176. if (info_ptr == NULL) {
  177. png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
  178. fclose(fp);
  179. G_fatal_error("cannot allocate LIBPNG structure");
  180. }
  181. if (setjmp(pnmtopng_jmpbuf_struct.jmpbuf)) {
  182. png_destroy_write_struct(&png_ptr, &info_ptr);
  183. fclose(fp);
  184. G_fatal_error("setjmp returns error condition (1)");
  185. }
  186. depth = 8; /*really??? */
  187. #ifdef OLDPNG
  188. png_write_init(png_ptr);
  189. png_info_init(info_ptr);
  190. #endif
  191. png_init_io(png_ptr, fp);
  192. png_set_IHDR(png_ptr, info_ptr, win.cols, win.rows, depth,
  193. do_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
  194. PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
  195. PNG_FILTER_TYPE_DEFAULT);
  196. /* explicit filter-type (or none) required */
  197. if ((filter >= 0) && (filter <= 4)) {
  198. png_set_filter(png_ptr, 0, filter);
  199. }
  200. png_set_compression_level(png_ptr, png_compr);
  201. if (do_alpha) {
  202. png_color_16 background_color;
  203. background_color.red = (png_uint_16)def_red;
  204. background_color.green = (png_uint_16)def_grn;
  205. background_color.blue = (png_uint_16)def_blu;
  206. png_set_bKGD(png_ptr, info_ptr, &background_color);
  207. }
  208. G_verbose_message(_("Converting <%s>..."), rast->answer);
  209. {
  210. struct Colors colors;
  211. Rast_read_colors(rast->answer, "", &colors);
  212. rtype = Rast_get_map_type(cellfile);
  213. if (rtype == CELL_TYPE)
  214. voidc = (CELL *) cell_buf;
  215. else if (rtype == FCELL_TYPE)
  216. voidc = (FCELL *) fcell_buf;
  217. else if (rtype == DCELL_TYPE)
  218. voidc = (DCELL *) dcell_buf;
  219. else
  220. G_fatal_error(_("Raster <%s> type mismatch"), rast->answer);
  221. rsize = Rast_cell_size(rtype);
  222. /*if(!gscale->answer){ *//* 24BIT COLOR IMAGE */
  223. if (TRUE) {
  224. /* write the png-info struct */
  225. png_write_info(png_ptr, info_ptr);
  226. /* let libpng take care of, e.g., bit-depth conversions */
  227. png_set_packing(png_ptr);
  228. /* max: 3 color channels, one alpha channel, 16-bit */
  229. line = (png_byte *) G_malloc(win.cols * 8 * sizeof(char));
  230. for (row = 0; row < win.rows; row++) {
  231. G_percent(row, win.rows, 5);
  232. Rast_get_row(cellfile, (void *)voidc, row, rtype);
  233. Rast_lookup_colors((void *)voidc, ored, ogrn, oblu, set,
  234. win.cols, &colors, rtype);
  235. pp = line;
  236. for (col = 0; col < win.cols; col++) {
  237. if (set[col]) {
  238. *pp++ = ored[col];
  239. *pp++ = ogrn[col];
  240. *pp++ = oblu[col];
  241. if (do_alpha) {
  242. if (Rast_is_null_value(
  243. G_incr_void_ptr(voidc, col * rsize), rtype))
  244. *pp++ = 0;
  245. else
  246. *pp++ = 255;
  247. }
  248. }
  249. else {
  250. if (do_alpha) {
  251. *pp++ = ored[col];
  252. *pp++ = ogrn[col];
  253. *pp++ = oblu[col];
  254. *pp++ = 0;
  255. }
  256. else {
  257. *pp++ = (unsigned char)def_red;
  258. *pp++ = (unsigned char)def_grn;
  259. *pp++ = (unsigned char)def_blu;
  260. }
  261. }
  262. }
  263. png_write_row(png_ptr, line);
  264. }
  265. G_percent(row, win.rows, 5); /* finish it off */
  266. }
  267. else { /* GREYSCALE IMAGE */
  268. /*
  269. * info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
  270. *
  271. */
  272. /* pm_message ("don't know yet how to write grey - yumm!!"); */
  273. G_warning("don't know how to write grey scale!");
  274. }
  275. Rast_free_colors(&colors);
  276. }
  277. G_free(cell_buf);
  278. G_free(fcell_buf);
  279. G_free(dcell_buf);
  280. G_free(ored);
  281. G_free(ogrn);
  282. G_free(oblu);
  283. G_free(set);
  284. Rast_close(cellfile);
  285. png_write_end(png_ptr, info_ptr);
  286. /* png_write_destroy (png_ptr); this is no longer supported with libpng, al 11/2000 */
  287. /* flush first because G_free (png_ptr) can segfault due to jmpbuf problems
  288. * in png_write_destroy */
  289. fflush(stdout);
  290. /* G_free (png_ptr); */
  291. /* G_free (info_ptr); */
  292. png_destroy_write_struct(&png_ptr, &info_ptr); /* al 11/2000 */
  293. fclose(fp);
  294. if (wld_flag->answer) {
  295. if(do_stdout)
  296. outfile = G_store("png_map.wld");
  297. else
  298. sprintf(outfile, "%s.wld", basename);
  299. write_wld(outfile, &win);
  300. }
  301. if(basename)
  302. G_free(basename);
  303. if(outfile)
  304. G_free(outfile);
  305. exit(EXIT_SUCCESS);
  306. }
  307. #ifdef __STDC__
  308. static void pnmtopng_error_handler(png_structp png_ptr, png_const_charp msg)
  309. #else
  310. static void pnmtopng_error_handler(png_ptr, msg)
  311. png_structp png_ptr;
  312. png_const_charp msg;
  313. #endif
  314. {
  315. jmpbuf_wrapper *jmpbuf_ptr;
  316. /* this function, aside from the extra step of retrieving the "error
  317. * pointer" (below) and the fact that it exists within the application
  318. * rather than within libpng, is essentially identical to libpng's
  319. * default error handler. The second point is critical: since both
  320. * setjmp() and longjmp() are called from the same code, they are
  321. * guaranteed to have compatible notions of how big a jmp_buf is,
  322. * regardless of whether _BSD_SOURCE or anything else has (or has not)
  323. * been defined. */
  324. G_warning("pnmtopng: fatal libpng error: [%s]", msg);
  325. jmpbuf_ptr = png_get_error_ptr(png_ptr);
  326. if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
  327. G_fatal_error
  328. ("pnmtopng: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
  329. }
  330. longjmp(jmpbuf_ptr->jmpbuf, 1);
  331. }
  332. static int write_wld(const char *fname, const struct Cell_head *win)
  333. {
  334. int width = DBL_DIG;
  335. FILE *ofile;
  336. G_verbose_message(_("Writing world file"));
  337. if (fname == NULL)
  338. G_fatal_error(_("Got null file name"));
  339. if (win == NULL)
  340. G_fatal_error(_("Got null region struct"));
  341. if ((ofile = fopen(fname, "w")) == NULL)
  342. G_fatal_error(_("Unable to open world file for writing"));
  343. fprintf(ofile, "%36.*f \n", width, win->ew_res);
  344. fprintf(ofile, "%36.*f \n", width, 0.0);
  345. fprintf(ofile, "%36.*f \n", width, 0.0);
  346. fprintf(ofile, "%36.*f \n", width, -1 * win->ns_res);
  347. fprintf(ofile, "%36.*f \n", width, win->west + win->ew_res / 2.0);
  348. fprintf(ofile, "%36.*f \n", width, win->north - win->ns_res / 2.0);
  349. fclose(ofile);
  350. return 0;
  351. }