NetSurf
convert_image.c
Go to the documentation of this file.
1 /*
2  * Copyright 2009 Daniel Silverstone <dsilvers@netsurf-browser.org>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <stdbool.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <png.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #if PNG_LIBPNG_VER < 10209
27 #define png_set_expand_gray_1_2_4_to_8(png) png_set_gray_1_2_4_to_8(png)
28 #endif
29 
30 static png_structp png;
31 static png_infop info;
32 static int interlace;
33 static size_t rowbytes;
34 static int raw_width, raw_height;
35 static int rowstride;
36 static unsigned char *bitmap_data;
37 static bool is_cursor = true;
38 static int raw_hot_x, raw_hot_y;
39 
40 #define WIDTH (is_cursor?raw_width-1:raw_width)
41 #define HEIGHT (is_cursor?raw_height-1:raw_height)
42 
43 #define HOT_X (is_cursor?raw_hot_x-1:0)
44 #define HOT_Y (is_cursor?raw_hot_y-1:0)
45 
46 #define REAL(v) (is_cursor?v+1:v)
47 
48 #define PPIX_AT(x,y) ((bitmap_data + (rowstride * y)) + (x * 4))
49 
50 #define R_OFF 2
51 #define G_OFF 1
52 #define B_OFF 0
53 #define A_OFF 3
54 
55 #define R_AT(x,y) *(PPIX_AT(x,y) + R_OFF)
56 #define G_AT(x,y) *(PPIX_AT(x,y) + G_OFF)
57 #define B_AT(x,y) *(PPIX_AT(x,y) + B_OFF)
58 #define A_AT(x,y) *(PPIX_AT(x,y) + A_OFF)
59 
60 
61 static void
62 usage(void)
63 {
64  fprintf(stderr, "usage: fb_convert_image input.png output.inc varname\n");
65 }
66 
67 
68 static void
70 {
71  int i;
72  int greenpixels = 0;
73 
74  for (i = 0; i < raw_width; ++i) {
75  if (A_AT(i, 0) == 255) {
76  if (G_AT(i, 0) == 255) {
77  greenpixels++;
78  raw_hot_x = i;
79  }
80  if ((B_AT(i, 0) != 0) || (R_AT(i, 0) != 0)) {
81  is_cursor = false;
82  return;
83  }
84  } else if (A_AT(i, 0) != 0) {
85  is_cursor = false;
86  return;
87  }
88  }
89  if (greenpixels != 1) {
90  is_cursor = false;
91  return;
92  }
93 
94  for (i = 0; i < raw_height; ++i) {
95  if (A_AT(0, i) == 255) {
96  if (G_AT(0, i) == 255) {
97  greenpixels++;
98  raw_hot_y = i;
99  }
100  if ((B_AT(0, i) != 0) || (R_AT(0, i) != 0)) {
101  is_cursor = false;
102  return;
103  }
104  } else if (A_AT(0, i) != 0) {
105  is_cursor = false;
106  return;
107  }
108  }
109  if (greenpixels != 2) {
110  is_cursor = false;
111  return;
112  }
113  printf(" Pointer detected. Adjusted hotspot at %d, %d (0-based)\n",
114  raw_hot_x - 1, raw_hot_y - 1);
115 }
116 
117 
118 static void
119 info_callback(png_structp png, png_infop info)
120 {
121  int bit_depth, color_type, interlace, intent;
122  double gamma;
123  png_uint_32 width, height;
124 
125  /* Read the PNG details */
126  png_get_IHDR(png, info, &width, &height, &bit_depth,
127  &color_type, &interlace, 0, 0);
128 
129  /* Set up our transformations */
130  if (color_type == PNG_COLOR_TYPE_PALETTE)
131  png_set_palette_to_rgb(png);
132  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
134  if (png_get_valid(png, info, PNG_INFO_tRNS))
135  png_set_tRNS_to_alpha(png);
136  if (bit_depth == 16)
137  png_set_strip_16(png);
138  if (color_type == PNG_COLOR_TYPE_GRAY ||
139  color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
140  png_set_gray_to_rgb(png);
141  if (!(color_type & PNG_COLOR_MASK_ALPHA))
142  png_set_filler(png, 0xff, PNG_FILLER_AFTER);
143  /* gamma correction - we use 2.2 as our screen gamma
144  * this appears to be correct (at least in respect to !Browse)
145  * see http://www.w3.org/Graphics/PNG/all_seven.html for a test case
146  */
147  if (png_get_sRGB(png, info, &intent))
148  png_set_gamma(png, 2.2, 0.45455);
149  else {
150  if (png_get_gAMA(png, info, &gamma))
151  png_set_gamma(png, 2.2, gamma);
152  else
153  png_set_gamma(png, 2.2, 0.45455);
154  }
155 
156 
157  png_read_update_info(png, info);
158 
159  rowbytes = png_get_rowbytes(png, info);
160  interlace = (interlace == PNG_INTERLACE_ADAM7);
161  raw_width = width;
162  raw_height = height;
163 
164  rowstride = raw_width * 4;
165  bitmap_data = malloc(rowstride * raw_height);
166 }
167 
168 static unsigned int interlace_start[8] = {0, 16, 0, 8, 0, 4, 0};
169 static unsigned int interlace_step[8] = {28, 28, 12, 12, 4, 4, 0};
170 static unsigned int interlace_row_start[8] = {0, 0, 4, 0, 2, 0, 1};
171 static unsigned int interlace_row_step[8] = {8, 8, 8, 4, 4, 2, 2};
172 
173 static void
174 row_callback(png_structp png, png_bytep new_row,
175  png_uint_32 row_num, int pass)
176 {
177  unsigned long i, j;
178  unsigned int start, step;
179  unsigned char *row = bitmap_data + (rowstride * row_num);
180 
181  if (new_row == 0)
182  return;
183 
184  if (interlace) {
185  start = interlace_start[pass];
186  step = interlace_step[pass];
187  row_num = interlace_row_start[pass] +
188  interlace_row_step[pass] * row_num;
189 
190  /* Copy the data to our current row taking interlacing
191  * into consideration */
192  row = bitmap_data + (rowstride * row_num);
193  for (j = 0, i = start; i < rowbytes; i += step) {
194  row[i++] = new_row[j++];
195  row[i++] = new_row[j++];
196  row[i++] = new_row[j++];
197  row[i++] = new_row[j++];
198  }
199  } else {
200  memcpy(row, new_row, rowbytes);
201  }
202 }
203 
204 static void
205 end_callback(png_structp png, png_infop info)
206 {
207 }
208 
209 
210 int
211 main(int argc, char **argv)
212 {
213  FILE *f;
214  unsigned char buffer[1024];
215  int br;
216  int x, y, c;
217 
218  if (argc != 4) {
219  usage();
220  return 1;
221  }
222 
223  printf(" CONVERT: %s (%s)\n", argv[1], argv[3]);
224 
225  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
226  info = png_create_info_struct(png);
227 
228  png_set_progressive_read_fn(png, NULL, info_callback, row_callback, end_callback);
229 
230  f = fopen(argv[1], "rb");
231  if (f == NULL) {
232  printf(" Unable to open %s\n", argv[1]);
233  return 1;
234  }
235 
236  do {
237  br = fread(buffer, 1, 1024, f);
238  if (br > 0) {
239  png_process_data(png, info, buffer, br);
240  }
241  } while (br > 0);
242 
243  if (br < 0) {
244  printf("Error reading input: %s\n", strerror(errno));
245  fclose(f);
246  return 1;
247  }
248 
249  fclose(f);
250 
251  detect_hotspot();
252 
253  f = fopen(argv[2], "w");
254  if (f == NULL) {
255  printf(" Unable to open %s\n", argv[2]);
256  return 2;
257  }
258 
259  fprintf(f, "/* This file is auto-generated from %s\n", argv[1]);
260  fprintf(f, " *\n * Do not edit this file directly.\n */\n\n");
261  fprintf(f, "#include <sys/types.h>\n\n");
262  fprintf(f, "#include <stdint.h>\n\n");
263  fprintf(f, "#include <stdbool.h>\n\n");
264  fprintf(f, "#include <libnsfb.h>\n\n");
265  fprintf(f, "#include \"netsurf/plot_style.h\"\n");
266  fprintf(f, "#include \"framebuffer/gui.h\"\n");
267  fprintf(f, "#include \"framebuffer/fbtk.h\"\n\n");
268 
269  fprintf(f, "static uint8_t %s_pixdata[] = {\n", argv[3]);
270  for (y = 0; y < HEIGHT; ++y) {
271  unsigned char *rowptr = bitmap_data + (rowstride * y);
272  if (is_cursor) {
273  /* If it's a cursor, skip one row and one column */
274  rowptr += rowstride + 4;
275  }
276  fprintf(f, "\t");
277  for (x = 0; x < WIDTH; ++x) {
278  for (c = 0; c < 4; ++c) {
279  unsigned char b = *rowptr++;
280  fprintf(f, "0x%02x, ", b);
281  }
282  }
283  fprintf(f, "\n");
284  }
285  fprintf(f, "};\n\n");
286 
287  fprintf(f, "struct fbtk_bitmap %s = {\n", argv[3]);
288  fprintf(f, "\t.width\t\t= %d,\n", WIDTH);
289  fprintf(f, "\t.height\t\t= %d,\n", HEIGHT);
290  fprintf(f, "\t.hot_x\t\t= %d,\n", HOT_X);
291  fprintf(f, "\t.hot_y\t\t= %d,\n", HOT_Y);
292  fprintf(f, "\t.pixdata\t= %s_pixdata,\n", argv[3]);
293 
294  fprintf(f, "};\n\n");
295  fclose(f);
296 
297  return 0;
298 }
299 
300 /*
301  * Local Variables:
302  * c-basic-offset:8
303  * End:
304  */
#define A_AT(x, y)
Definition: convert_image.c:58
static void end_callback(png_structp png, png_infop info)
static int raw_hot_y
Definition: convert_image.c:38
Interface to utility string handling.
#define HOT_X
Definition: convert_image.c:43
static unsigned int interlace_row_step[8]
#define WIDTH
Definition: convert_image.c:40
static void usage(void)
Definition: convert_image.c:62
static png_infop info
Definition: convert_image.c:31
static unsigned char * bitmap_data
Definition: convert_image.c:36
static unsigned int interlace_row_start[8]
static void row_callback(png_structp png, png_bytep new_row, png_uint_32 row_num, int pass)
int main(int argc, char **argv)
Normal entry point from OS.
static int raw_hot_x
Definition: convert_image.c:38
static png_structp png
Definition: convert_image.c:30
#define HOT_Y
Definition: convert_image.c:44
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
static int raw_height
Definition: convert_image.c:34
int height
Definition: gui.c:180
#define B_AT(x, y)
Definition: convert_image.c:57
#define HEIGHT
Definition: convert_image.c:41
static void info_callback(png_structp png, png_infop info)
static int interlace
Definition: convert_image.c:32
static unsigned int interlace_step[8]
static int raw_width
Definition: convert_image.c:34
#define R_AT(x, y)
Definition: convert_image.c:55
static int rowstride
Definition: convert_image.c:35
static bool is_cursor
Definition: convert_image.c:37
static void detect_hotspot(void)
Definition: convert_image.c:69
int width
Definition: gui.c:179
#define G_AT(x, y)
Definition: convert_image.c:56
static unsigned int interlace_start[8]
#define png_set_expand_gray_1_2_4_to_8(png)
Definition: convert_image.c:27
static size_t rowbytes
Definition: convert_image.c:33