123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- /*
- ****************************************************************************
- *
- * MODULE: r.out.png
- * AUTHOR(S): Bill Brown - USA-CERL
- * Alex Shevlakov - sixote@yahoo.com
- * Hamish Bowman
- * PURPOSE: Export GRASS raster as non-georeferenced PNG image.
- * COPYRIGHT: (C) 2000-2010 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.
- *
- *****************************************************************************/
- /*
- * Alex Shevlakov, sixote@yahoo.com, 03/2000
- * based on r.out.ppm by
- * Written by Bill Brown, USA-CERL March 21, 1994
- *
- * Use to convert grass raster map to PNG
- * uses currently selected region
- *
- */
- #include <string.h>
- #include <stdlib.h>
- #include <float.h>
- #ifndef _MYINCLUDE_H
- #define _MYINCLUDE_H
- #include <png.h>
- #include "pngfunc.h"
- /* #include <pnm.h> this is already included from pngfunc.h */
- #endif /* _MYINCLUDE_H */
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/colors.h>
- #include <grass/glocale.h>
- typedef int FILEDESC;
- /* global functions */
- static int write_wld(const char *, const struct Cell_head *);
- int main(int argc, char *argv[])
- {
- struct GModule *module;
- struct Option *rast, *png_file, *compr; /* , *bgcolor; */
- struct Flag *alpha, *wld_flag;
- char *rastermap;
- char *basename = NULL, *outfile = NULL;
- unsigned char *set, *ored, *ogrn, *oblu;
- int def_red, def_grn, def_blu;
- CELL *cell_buf;
- FCELL *fcell_buf;
- DCELL *dcell_buf;
- void *voidc;
- int rtype, row, col, do_stdout = 0;
- size_t rsize;
- int png_compr, ret, do_alpha;
- struct Cell_head win;
- FILEDESC cellfile = 0;
- FILE *fp;
- /* now goes from pnmtopng.c* -A.Sh */
- /*
- * pnmtopng.c -
- * read a portable anymap and produce a Portable Network Graphics file
- *
- * derived from pnmtorast.c (c) 1990,1991 by Jef Poskanzer and some
- * parts derived from ppmtogif.c by Marcel Wijkstra <wijkstra@fwi.uva.nl>
- * thanks to Greg Roelofs <newt@pobox.com> for contributions and bug-fixes
- *
- * Copyright (C) 1995-1998 by Alexander Lehmann <alex@hal.rhein-main.de>
- * and Willem van Schaik <willem@schaik.com>
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. This software is provided "as is" without express or
- * implied warranty.
- */
- png_struct *png_ptr;
- png_info *info_ptr;
- png_byte *line;
- png_byte *pp;
- /* these variables are declared static because gcc wasn't kidding
- * about "variable XXX might be clobbered by `longjmp' or `vfork'"
- * (stack corruption observed on Solaris 2.6 with gcc 2.8.1, even
- * in the absence of any other error condition) */
- static xelval maxmaxval;
- static int depth;
- static int filter;
- /* these guys are initialized to quiet compiler warnings: */
- maxmaxval = 255;
- depth = 0;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("export"));
- G_add_keyword("PNG");
- module->description =
- _("Export a GRASS raster map as a non-georeferenced PNG image.");
- rast = G_define_standard_option(G_OPT_R_INPUT);
- png_file = G_define_standard_option(G_OPT_F_OUTPUT);
- png_file->required = YES;
- png_file->description = _("Name for new PNG file (use '-' for stdout)");
- compr = G_define_option();
- compr->key = "compression";
- compr->type = TYPE_INTEGER;
- compr->required = NO;
- compr->multiple = NO;
- compr->options = "0-9";
- compr->label = _("Compression level of PNG file");
- compr->description = _("(0 = none, 1 = fastest, 9 = best)");
- compr->answer = "6";
- /* bgcolor = G_define_standard_option(G_OPT_C_BG); */
- alpha = G_define_flag();
- alpha->key = 't';
- alpha->description = _("Make NULL cells transparent");
- wld_flag = G_define_flag();
- wld_flag->key = 'w';
- wld_flag->description = _("Output world file");
- /* see what can be done to convert'em -A.Sh.
- * gscale = G_define_flag ();
- * gscale->key = 'g';
- * gscale->description = "Output greyscale instead of color";
- */
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- rastermap = rast->answer;
- do_alpha = alpha->answer ? TRUE : FALSE;
- if (strcmp(png_file->answer, "-") != 0)
- basename = G_store(png_file->answer);
- else
- do_stdout = TRUE;
- if (basename) {
- G_basename(basename, "png");
- outfile = G_malloc(strlen(basename) + 5);
- sprintf(outfile, "%s.png", basename);
- }
- png_compr = atoi(compr->answer);
- #ifdef MAYBE_LATER
- /* ... if at all */
- ret = G_str_to_color(bgcolor->answer, &def_red, &def_grn, &def_blu);
- if (ret == 0)
- G_fatal_error(_("[%s]: No such color"), bgcolor->answer);
- else if (ret == 2) { /* (ret==2) is "none" */
- if(!do_alpha)
- do_alpha = TRUE;
- }
- #else
- ret = G_str_to_color(DEFAULT_BG_COLOR, &def_red, &def_grn, &def_blu);
- #endif
- /*G_get_set_window (&win); *//* 10/99 MN: check for current region */
- G_get_window(&win);
- G_debug(1, "rows = %d, cols = %d", win.rows, win.cols);
- /* open raster map for reading */
- cellfile = Rast_open_old(rast->answer, "");
- cell_buf = Rast_allocate_c_buf();
- fcell_buf = Rast_allocate_f_buf();
- dcell_buf = Rast_allocate_d_buf();
- ored = G_malloc(win.cols);
- ogrn = G_malloc(win.cols);
- oblu = G_malloc(win.cols);
- set = G_malloc(win.cols);
- /* open png file for writing */
- if (do_stdout)
- fp = stdout;
- else if (NULL == (fp = fopen(outfile, "w")))
- G_fatal_error(_("Unable to open output file <%s>"), outfile);
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
- &pnmtopng_jmpbuf_struct,
- pnmtopng_error_handler, NULL);
- if (png_ptr == NULL) {
- fclose(fp);
- G_fatal_error("cannot allocate LIBPNG structure");
- }
- info_ptr = png_create_info_struct(png_ptr);
- if (info_ptr == NULL) {
- png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
- fclose(fp);
- G_fatal_error("cannot allocate LIBPNG structure");
- }
- if (setjmp(pnmtopng_jmpbuf_struct.jmpbuf)) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- fclose(fp);
- G_fatal_error("setjmp returns error condition (1)");
- }
- depth = 8; /*really??? */
- #ifdef OLDPNG
- png_write_init(png_ptr);
- png_info_init(info_ptr);
- #endif
- png_init_io(png_ptr, fp);
- png_set_IHDR(png_ptr, info_ptr, win.cols, win.rows, depth,
- do_alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
- /* explicit filter-type (or none) required */
- if ((filter >= 0) && (filter <= 4)) {
- png_set_filter(png_ptr, 0, filter);
- }
- png_set_compression_level(png_ptr, png_compr);
- if (do_alpha) {
- png_color_16 background_color;
- background_color.red = (png_uint_16)def_red;
- background_color.green = (png_uint_16)def_grn;
- background_color.blue = (png_uint_16)def_blu;
- png_set_bKGD(png_ptr, info_ptr, &background_color);
- }
- G_verbose_message(_("Converting <%s>..."), rast->answer);
- {
- struct Colors colors;
- Rast_read_colors(rast->answer, "", &colors);
- rtype = Rast_get_map_type(cellfile);
- if (rtype == CELL_TYPE)
- voidc = (CELL *) cell_buf;
- else if (rtype == FCELL_TYPE)
- voidc = (FCELL *) fcell_buf;
- else if (rtype == DCELL_TYPE)
- voidc = (DCELL *) dcell_buf;
- else
- G_fatal_error(_("Raster <%s> type mismatch"), rast->answer);
- rsize = Rast_cell_size(rtype);
- /*if(!gscale->answer){ *//* 24BIT COLOR IMAGE */
- if (TRUE) {
- /* write the png-info struct */
- png_write_info(png_ptr, info_ptr);
- /* let libpng take care of, e.g., bit-depth conversions */
- png_set_packing(png_ptr);
- /* max: 3 color channels, one alpha channel, 16-bit */
- line = (png_byte *) G_malloc(win.cols * 8 * sizeof(char));
- for (row = 0; row < win.rows; row++) {
- G_percent(row, win.rows, 5);
- Rast_get_row(cellfile, (void *)voidc, row, rtype);
- Rast_lookup_colors((void *)voidc, ored, ogrn, oblu, set,
- win.cols, &colors, rtype);
- pp = line;
- for (col = 0; col < win.cols; col++) {
- if (set[col]) {
- *pp++ = ored[col];
- *pp++ = ogrn[col];
- *pp++ = oblu[col];
- if (do_alpha) {
- if (Rast_is_null_value(
- G_incr_void_ptr(voidc, col * rsize), rtype))
- *pp++ = 0;
- else
- *pp++ = 255;
- }
- }
- else {
- if (do_alpha) {
- *pp++ = ored[col];
- *pp++ = ogrn[col];
- *pp++ = oblu[col];
- *pp++ = 0;
- }
- else {
- *pp++ = (unsigned char)def_red;
- *pp++ = (unsigned char)def_grn;
- *pp++ = (unsigned char)def_blu;
- }
- }
- }
- png_write_row(png_ptr, line);
- }
- G_percent(row, win.rows, 5); /* finish it off */
- }
- else { /* GREYSCALE IMAGE */
- /*
- * info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
- *
- */
- /* pm_message ("don't know yet how to write grey - yumm!!"); */
- G_warning("don't know how to write grey scale!");
- }
- Rast_free_colors(&colors);
- }
- G_free(cell_buf);
- G_free(fcell_buf);
- G_free(dcell_buf);
- G_free(ored);
- G_free(ogrn);
- G_free(oblu);
- G_free(set);
- Rast_close(cellfile);
- png_write_end(png_ptr, info_ptr);
- /* png_write_destroy (png_ptr); this is no longer supported with libpng, al 11/2000 */
- /* flush first because G_free (png_ptr) can segfault due to jmpbuf problems
- * in png_write_destroy */
- fflush(stdout);
- /* G_free (png_ptr); */
- /* G_free (info_ptr); */
- png_destroy_write_struct(&png_ptr, &info_ptr); /* al 11/2000 */
- fclose(fp);
- if (wld_flag->answer) {
- if(do_stdout)
- outfile = G_store("png_map.wld");
- else
- sprintf(outfile, "%s.wld", basename);
- write_wld(outfile, &win);
- }
- if(basename)
- G_free(basename);
- if(outfile)
- G_free(outfile);
- exit(EXIT_SUCCESS);
- }
- #ifdef __STDC__
- static void pnmtopng_error_handler(png_structp png_ptr, png_const_charp msg)
- #else
- static void pnmtopng_error_handler(png_ptr, msg)
- png_structp png_ptr;
- png_const_charp msg;
- #endif
- {
- jmpbuf_wrapper *jmpbuf_ptr;
- /* this function, aside from the extra step of retrieving the "error
- * pointer" (below) and the fact that it exists within the application
- * rather than within libpng, is essentially identical to libpng's
- * default error handler. The second point is critical: since both
- * setjmp() and longjmp() are called from the same code, they are
- * guaranteed to have compatible notions of how big a jmp_buf is,
- * regardless of whether _BSD_SOURCE or anything else has (or has not)
- * been defined. */
- G_warning("pnmtopng: fatal libpng error: [%s]", msg);
- jmpbuf_ptr = png_get_error_ptr(png_ptr);
- if (jmpbuf_ptr == NULL) { /* we are completely hosed now */
- G_fatal_error
- ("pnmtopng: EXTREMELY fatal error: jmpbuf unrecoverable; terminating.");
- }
- longjmp(jmpbuf_ptr->jmpbuf, 1);
- }
- static int write_wld(const char *fname, const struct Cell_head *win)
- {
- int width = DBL_DIG;
- FILE *ofile;
- G_verbose_message(_("Writing world file"));
- if (fname == NULL)
- G_fatal_error(_("Got null file name"));
- if (win == NULL)
- G_fatal_error(_("Got null region struct"));
- if ((ofile = fopen(fname, "w")) == NULL)
- G_fatal_error(_("Unable to open world file for writing"));
- fprintf(ofile, "%36.*f \n", width, win->ew_res);
- fprintf(ofile, "%36.*f \n", width, 0.0);
- fprintf(ofile, "%36.*f \n", width, 0.0);
- fprintf(ofile, "%36.*f \n", width, -1 * win->ns_res);
- fprintf(ofile, "%36.*f \n", width, win->west + win->ew_res / 2.0);
- fprintf(ofile, "%36.*f \n", width, win->north - win->ns_res / 2.0);
- fclose(ofile);
- return 0;
- }
|