BRL-CAD
png.c
Go to the documentation of this file.
1 /* P N G . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @file libged/png.c
21  *
22  * The png command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <stdlib.h>
29 #include <ctype.h>
30 #include <string.h>
31 #include <zlib.h>
32 #include <png.h>
33 
34 
35 #include "bu/getopt.h"
36 #include "vmath.h"
37 #include "bn.h"
38 
39 
40 #include "./ged_private.h"
41 
42 
43 static unsigned int size = 512;
44 static unsigned int half_size = 256;
45 
46 static unsigned char bg_red = 255;
47 static unsigned char bg_green = 255;
48 static unsigned char bg_blue = 255;
49 
50 static int
51 draw_png(struct ged *gedp, FILE *fp)
52 {
53  long i;
54  png_structp png_p;
55  png_infop info_p;
56  double out_gamma = 1.0;
57 
58  /* TODO: explain why this is size+1 */
59  size_t num_bytes_per_row = (size+1) * 3;
60  size_t num_bytes = num_bytes_per_row * (size+1);
61  unsigned char **image = (unsigned char **)bu_malloc(sizeof(unsigned char *) * (size+1), "draw_png, image");
62  unsigned char *bytes = (unsigned char *)bu_malloc(num_bytes, "draw_png, bytes");
63 
64  /* Initialize bytes using the background color */
65  if (bg_red == bg_green && bg_red == bg_blue)
66  memset((void *)bytes, bg_red, num_bytes);
67  else {
68  for (i = 0; (size_t)i < num_bytes; i += 3) {
69  bytes[i] = bg_red;
70  bytes[i+1] = bg_green;
71  bytes[i+2] = bg_blue;
72  }
73  }
74 
75  png_p = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
76  if (!png_p) {
77  bu_vls_printf(gedp->ged_result_str, "Could not create PNG write structure\n");
78  return GED_ERROR;
79  }
80 
81  info_p = png_create_info_struct(png_p);
82  if (!info_p) {
83  bu_vls_printf(gedp->ged_result_str, "Could not create PNG info structure\n");
84  bu_free((void *)image, "draw_png, image");
85  bu_free((void *)bytes, "draw_png, bytes");
86 
87  return GED_ERROR;
88  }
89 
90  png_init_io(png_p, fp);
91  png_set_filter(png_p, 0, PNG_FILTER_NONE);
92  png_set_compression_level(png_p, Z_BEST_COMPRESSION);
93  png_set_IHDR(png_p, info_p,
94  size, size, 8,
95  PNG_COLOR_TYPE_RGB,
96  PNG_INTERLACE_NONE,
97  PNG_COMPRESSION_TYPE_DEFAULT,
98  PNG_FILTER_TYPE_DEFAULT);
99  png_set_gAMA(png_p, info_p, out_gamma);
100  png_write_info(png_p, info_p);
101 
102  /* Arrange the rows of data/pixels */
103  for (i = size; i >= 0; --i) {
104  image[i] = (unsigned char *)(bytes + ((size-i) * num_bytes_per_row));
105  }
106 
107  dl_png(gedp->ged_gdp->gd_headDisplay, gedp->ged_gvp->gv_model2view, gedp->ged_gvp->gv_perspective, gedp->ged_gvp->gv_eye_pos, (size_t)size, (size_t)half_size, image);
108 
109  /* Write out pixels */
110  png_write_image(png_p, image);
111  png_write_end(png_p, NULL);
112 
113  bu_free((void *)image, "draw_png, image");
114  bu_free((void *)bytes, "draw_png, bytes");
115 
116  return GED_OK;
117 }
118 
119 
120 int
121 ged_png(struct ged *gedp, int argc, const char *argv[])
122 {
123  FILE *fp;
124  int k;
125  int ret;
126  int r, g, b;
127  static const char *usage = "[-c r/g/b] [-s size] file";
128 
130  GED_CHECK_VIEW(gedp, GED_ERROR);
132  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
133 
134  /* initialize result */
135  bu_vls_trunc(gedp->ged_result_str, 0);
136 
137  /* must be wanting help */
138  if (argc == 1) {
139  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
140  return GED_HELP;
141  }
142 
143  /* Process options */
144  bu_optind = 1;
145  while ((k = bu_getopt(argc, (char * const *)argv, "c:s:")) != -1) {
146  switch (k) {
147  case 'c':
148  /* parse out a delimited rgb color value */
149  if (sscanf(bu_optarg, "%d%*c%d%*c%d", &r, &g, &b) != 3) {
150  bu_vls_printf(gedp->ged_result_str, "%s: bad color - %s", argv[0], bu_optarg);
151  return GED_ERROR;
152  }
153 
154  /* Clamp color values */
155  if (r < 0)
156  r = 0;
157  else if (r > 255)
158  r = 255;
159 
160  if (g < 0)
161  g = 0;
162  else if (g > 255)
163  g = 255;
164 
165  if (b < 0)
166  b = 0;
167  else if (b > 255)
168  b = 255;
169 
170  bg_red = (unsigned char)r;
171  bg_green = (unsigned char)g;
172  bg_blue = (unsigned char)b;
173 
174  break;
175  case 's':
176  if (sscanf(bu_optarg, "%u", &size) != 1) {
177  bu_vls_printf(gedp->ged_result_str, "%s: bad size - %s", argv[0], bu_optarg);
178  return GED_ERROR;
179  }
180 
181  if (size < 50) {
182  bu_vls_printf(gedp->ged_result_str, "%s: bad size - %s, must be greater than or equal to 50\n", argv[0], bu_optarg);
183  return GED_ERROR;
184  }
185 
186  half_size = size * 0.5;
187 
188  break;
189  default:
190  bu_vls_printf(gedp->ged_result_str, "%s: Unrecognized option - %s", argv[0], argv[bu_optind-1]);
191  return GED_ERROR;
192  }
193  }
194 
195  if ((argc - bu_optind) != 1) {
196  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
197  return GED_ERROR;
198  }
199 
200  if ((fp = fopen(argv[bu_optind], "wb")) == NULL) {
201  bu_vls_printf(gedp->ged_result_str, "%s: Error opening file - %s\n", argv[0], argv[bu_optind]);
202  return GED_ERROR;
203  }
204 
205  ret = draw_png(gedp, fp);
206  fclose(fp);
207 
208  return ret;
209 }
210 
211 
212 /*
213  * Local Variables:
214  * tab-width: 8
215  * mode: C
216  * indent-tabs-mode: t
217  * c-file-style: "stroustrup"
218  * End:
219  * ex: shiftwidth=4 tabstop=8
220  */
void usage(struct ged *gedp)
Definition: coil.c:315
#define GED_OK
Definition: ged.h:55
Definition: ged.h:338
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
char * bu_optarg
Definition: globals.c:91
Header file for the BRL-CAD common definitions.
fastf_t gv_perspective
perspective angle
Definition: bview.h:214
int bu_optind
Definition: globals.c:89
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
struct bu_list * gd_headDisplay
head of display list
Definition: ged.h:307
#define GED_ERROR
Definition: ged.h:61
struct bview * ged_gvp
Definition: ged.h:361
int ged_png(struct ged *gedp, int argc, const char *argv[])
Definition: png.c:121
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
void * memset(void *s, int c, size_t n)
#define GED_CHECK_VIEW(_gedp, _flags)
Definition: ged.h:140
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
#define GED_CHECK_DRAWABLE(_gedp, _flags)
Definition: ged.h:129
struct bu_vls * ged_result_str
Definition: ged.h:357
struct ged_drawable * ged_gdp
Definition: ged.h:360
mat_t gv_model2view
Definition: bview.h:222
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
vect_t gv_eye_pos
eye position
Definition: bview.h:216
void dl_png(struct bu_list *hdlp, mat_t model2view, fastf_t perspective, vect_t eye_pos, size_t size, size_t half_size, unsigned char **image)
#define GED_HELP
Definition: ged.h:62
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328