1 /*
2
3 silcmap_bitmap.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2003 - 2004 Pekka Riikonen
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include "silcincludes.h"
21 #include "silcclient.h"
22 #include <math.h>
23 #include "silcmap.h"
24 #include "data.h"
25
26 /******* Bitmap Routines *****************************************************/
27
28 /* Load a bitmap file. The file is the map image that is loaded into
29 the SilcMap context. This is no perfect PPM loader. */
30
31 bool silc_map_load_ppm(SilcMap map, const char *filename)
32 {
33 int fd;
34 char type[3];
35 unsigned char header[80];
36 int ret, retval = TRUE, i;
37
38 SILC_LOG_DEBUG(("Load PPM '%s'", filename));
39
40 fd = open(filename, O_RDONLY, 0600);
41 if (fd < 0) {
42 fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
43 return FALSE;
44 }
45
46 /* Read file header */
47 memset(header, 0, sizeof(header));
48 ret = read(fd, (void *)header, sizeof(header) - 1);
49 if (ret < 0) {
50 fprintf(stderr, "read: %s: %s\n", strerror(errno), filename);
51 return FALSE;
52 }
53
54 /* Read width and height */
55 ret = sscanf(header, "%s %ld %ld %ld\n", type,
56 (unsigned long *)&map->width,
57 (unsigned long *)&map->height,
58 (unsigned long *)&map->maxcolor);
59 if (ret < 4) {
60 fprintf(stderr, "Invalid PPM file");
61 retval = FALSE;
62 goto out;
63 }
64
65 for (i = sizeof(header) - 1; i >= 0; i--)
66 if (header[i] == '\n' || header[i] == ' ')
67 break;
68 lseek(fd, i + 1, SEEK_SET);
69
70 /* Read the picture */
71 map->bitmap_size = map->width * 3 * map->height;
72 map->bitmap = silc_malloc(map->bitmap_size);
73 ret = read(fd, map->bitmap, map->bitmap_size);
74 if (ret < 0) {
75 fprintf(stderr, "read: %s\n", strerror(errno));
76 retval = FALSE;
77 goto out;
78 }
79
80 out:
81 close(fd);
82 return retval;
83 }
84
85 /* Write the map into a bitmap file. */
86
87 bool silc_map_write_ppm(SilcMap map, const char *filename)
88 {
89 int fd;
90 int retval = TRUE;
91 char header[80];
92
93 SILC_LOG_DEBUG(("Write PPM '%s'", filename));
94
95 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0600);
96 if (fd < 0) {
97 fprintf(stderr, "open: %s: %s\n", strerror(errno), filename);
98 return FALSE;
99 }
100
101 /* Write the header */
102 memset(header, 0, sizeof(header));
103 snprintf(header, sizeof(header) - 1, "P6 %ld %ld %ld\n",
104 (unsigned long)map->width,
105 (unsigned long)map->height,
106 (unsigned long)map->maxcolor);
107 write(fd, header, strlen(header));
108
109 /* Write the bitmap */
110 write(fd, map->bitmap, map->bitmap_size);
111 close(fd);
112
113 return retval;
114 }
115
116 /* Cut the map into a `width' * `height' size chunk at `x' and `y'. This
117 returns the allocated map bitmap into `ret_bitmap'. The original map
118 is not modified. */
119
120 bool silc_map_cut(SilcMap map, SilcInt32 x, SilcInt32 y,
121 SilcUInt32 width, SilcUInt32 height,
122 SilcMap *ret_map)
123 {
124 int i;
125
126 SILC_LOG_DEBUG(("cut"));
127
128 /* Sanity checks */
129 if (height > map->height - y) {
130 fprintf(stderr, "Requesting too much height: %ld\n",
131 (unsigned long)height);
132 return FALSE;
133 }
134 if (width > map->width - x) {
135 fprintf(stderr, "Requesting too much width: %ld\n",
136 (unsigned long)width);
137 return FALSE;
138 }
139
140 /* Compute coordinates in the bitmap */
141 y = (map->width * 3) * y;
142 x = (x * 3);
143
144 /* Allocate new SilcMap context */
145 *ret_map = silc_calloc(1, sizeof(**ret_map));
146 (*ret_map)->width = width;
147 (*ret_map)->height = height;
148 (*ret_map)->maxcolor = map->maxcolor;
149 (*ret_map)->bitmap_size = (width * 3) * height;
150 (*ret_map)->bitmap = silc_malloc((*ret_map)->bitmap_size);
151
152 /* Copy the requested area */
153 for (i = 0; i < height; i++) {
154 memcpy((*ret_map)->bitmap + (i * width * 3),
155 map->bitmap + y + x, width * 3);
156
157 /* Next line */
158 y += (map->width * 3);
159 }
160
161 return TRUE;
162 }
163
164 /* Draw a bitmap indicated by `bitmap' of size of `width' * 'height'
165 into the SilcMap context into the coordinates `x' and `y' (the upper left
166 corner of the bitmap will be at x and y). The `bitmap' must be RGB
167 color bitmap. */
168
169 bool silc_map_draw(SilcMap map,
170 SilcInt32 x, SilcInt32 y,
171 const unsigned char *bitmap,
172 SilcUInt32 width, SilcUInt32 height)
173 {
174 int i, k;
175 unsigned char val;
176
177 /* Compute coordinates in the bitmap */
178 y = (map->width * 3) * y;
179 x = (x * 3);
180
181 /* Draw the bitmap into the map bitmap */
182 for (i = 0; i < height; i++) {
183 for (k = 0; k < width; k++) {
184 val = bitmap[i * (width * 3) + (k * 3)];
185 map->bitmap[y + x + (k * 3) ] = val; /* R */
186
187 val = bitmap[i * (width * 3) + (k * 3) + 1];
188 map->bitmap[y + x + (k * 3) + 1] = val; /* G */
189
190 val = bitmap[i * (width * 3) + (k * 3) + 2];
191 map->bitmap[y + x + (k * 3) + 2] = val; /* B */
192 }
193
194 /* Next line */
195 y += (map->width * 3);
196 }
197
198 return TRUE;
199 }
200
201 /* Same as silc_map_draw but the `bitmap' is a grayscale bitmap
202 and the RGB color information is provided as argument to this function. */
203
204 bool silc_map_draw_raw(SilcMap map,
205 SilcInt32 x, SilcInt32 y,
206 const unsigned char *bitmap,
207 SilcUInt32 width, SilcUInt32 height,
208 SilcInt16 r, SilcInt16 g, SilcInt16 b)
209 {
210 int i, k;
211 unsigned char val;
212
213 /* Compute coordinates in the bitmap */
214 y = (map->width * 3) * y;
215 x = (x * 3);
216
217 /* Draw the bitmap into the map bitmap */
218 for (i = 0; i < height; i++) {
219 for (k = 0; k < width; k++) {
220 val = bitmap[i * width + k];
221 if (val != 0) {
222 map->bitmap[y + x + (k * 3) ] = r; /* R */
223 map->bitmap[y + x + (k * 3) + 1] = g; /* G */
224 map->bitmap[y + x + (k * 3) + 2] = b; /* B */
225 }
226 }
227
228 /* Next line */
229 y += (map->width * 3);
230 }
231
232 return TRUE;
233 }
234
235 /* Draw a straight line between points a and b. The coordinates for the
236 points are provided as arguments. The `width' is the line width in
237 pixels. The RGB color for the line can be provided too. Implements
238 DDA algorithm. */
239
240 bool silc_map_draw_line(SilcMap map, SilcUInt32 width,
241 SilcInt32 a_x, SilcInt32 a_y,
242 SilcInt32 b_x, SilcInt32 b_y,
243 SilcInt16 r, SilcInt16 g, SilcInt16 b)
244 {
245 unsigned char p[3] = { r, g, b };
246 int xdiff, ydiff, i;
247 double x, y, slox, sloy;
248
249 SILC_LOG_DEBUG(("draw_line"));
250
251 /* Compute the difference of points */
252 xdiff = b_x - a_x;
253 ydiff = b_y - a_y;
254 if (!xdiff && !ydiff)
255 return FALSE;
256
257 /* Draw the line */
258 if (abs(xdiff) > abs(ydiff)) {
259 sloy = (double)ydiff / (double)xdiff;
260 y = a_y + 0.5; /* rounding */
261 if (xdiff > 0) {
262 for (x = a_x; x <= b_x; x++) {
263 for (i = 0; i < width; i++)
264 silc_map_draw(map, x + i, floor(y), p, 1, 1);
265 y += sloy;
266 }
267 } else {
268 for (x = a_x; x >= b_x; x--) {
269 for (i = 0; i < width; i++)
270 silc_map_draw(map, x + i, floor(y), p, 1, 1);
271 y -= sloy;
272 }
273 }
274 } else {
275 slox = (double)xdiff / (double)ydiff;
276 x = a_x + 0.5; /* rounding */
277 if (ydiff > 0) {
278 for (y = a_y; y <= b_y; y++) {
279 for (i = 0; i < width; i++)
280 silc_map_draw(map, floor(x + i), y, p, 1, 1);
281 x += slox;
282 }
283 } else {
284 for (y = a_y; y >= b_y; y--) {
285 for (i = 0; i < width; i++)
286 silc_map_draw(map, floor(x + i), y, p, 1, 1);
287 x -= slox;
288 }
289 }
290 }
291
292 return TRUE;
293 }
294
295 /* Print the text string `text' on the bitmap at `x' and `y'. The color
296 for the text can be provided as argument. */
297
298 bool silc_map_draw_text(SilcMap map, const char *text,
299 SilcInt32 x, SilcInt32 y,
300 SilcInt16 r, SilcInt16 g, SilcInt16 b)
301 {
302 int k, w;
303 int c;
304
305 SILC_LOG_DEBUG(("draw_text"));
306
307 /* Write the text. */
308 w = 0;
309 for (k = 0; k < strlen(text); k++) {
310 c = text[k] - 33;
311 silc_map_draw_raw(map, x + w, y,
312 map->font.font[c].data,
313 map->font.font[c].width,
314 map->font.height, r, g, b);
315 w += map->font.font[c].width;
316 }
317
318 return TRUE;
319 }
320
321 /* Draw circle on the bitmap map at `x' and `y'. The center of the
322 circle will be at the `x' and `y'. If the `label' is provided the
323 text will appear with the circle at `lposx' and `lposy' in relation
324 with the circle. */
325
326 bool silc_map_draw_circle(SilcMap map, SilcInt32 x, SilcInt32 y,
327 SilcInt16 r, SilcInt16 g, SilcInt16 b,
328 const char *label, SilcInt32 lposx, SilcInt32 lposy,
329 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
330 {
331 bool ret;
332
333 SILC_LOG_DEBUG(("draw_circle"));
334
335 y = y - (silc_map_circle.height / 2);
336 x = x - (silc_map_circle.width / 2);
337
338 ret = silc_map_draw_raw(map, x, y,
339 silc_map_circle.data,
340 silc_map_circle.width, silc_map_circle.height,
341 r, g, b);
342 if (!ret)
343 return FALSE;
344
345 if (label)
346 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
347
348 return ret;
349 }
350
351 /* Draw rectangle on the bitmap map at `x' and `y'. The center of the
352 rectangle will be at the `x' and `y'. If the `label' is provided the
353 text will appear with the circle at `lposx' and `lposy' in relation
354 with the circle. */
355
356 bool silc_map_draw_rectangle(SilcMap map, SilcInt32 x, SilcInt32 y,
357 SilcInt16 r, SilcInt16 g, SilcInt16 b,
358 const char *label,
359 SilcInt32 lposx, SilcInt32 lposy,
360 SilcInt16 lr, SilcInt16 lg, SilcInt16 lb)
361 {
362 bool ret;
363
364 SILC_LOG_DEBUG(("draw_rectangle"));
365
366 y = y - (silc_map_rectangle.height / 2);
367 x = x - (silc_map_rectangle.width / 2);
368
369 ret = silc_map_draw_raw(map, x, y,
370 silc_map_rectangle.data, silc_map_rectangle.width,
371 silc_map_rectangle.height,
372 r, g, b);
373 if (!ret)
374 return FALSE;
375
376 if (label)
377 ret = silc_map_draw_text(map, label, x + lposx, y - lposy, lr, lg, lb);
378
379 return ret;
380 }
381
382 /* Parses the degree position string. For example, longitude 40 23 10,
383 as in 40 degrees, 23 minutes and 10 seconds east. Negative degree is to
384 West. For latitude positive is north and negative south. */
385
386 double silc_map_parse_pos(char *pos)
387 {
388 double d = 0, m = 0, s = 0;
389 int ret;
390
391 ret = sscanf(pos, "%lf %lf %lf", &d, &m, &s);
392 if (ret < 1) {
393 fprintf(stderr, "Malfromed position string '%s'\n", pos);
394 return 0;
395 }
396
397 if (d < 0) {
398 m = (m < 0 ? m : -m);
399 s = (s < 0 ? s : -s);
400 }
401
402 return ((d < 0 ? -1 : d > 0 ? 1 : 0) *
403 abs(d) + (m / 60) + (s / 3600));
404 }
405
406 /* Converts longitude into position in the bitmap */
407
408 int silc_map_lon2x(SilcMap map, char *longitude)
409 {
410 double meridian, aspmul, lon;
411
412 /* Parse position string */
413 lon = silc_map_parse_pos(longitude);
414
415 /* Compute "aspect ratio multiplier" to get the position in the map. */
416 meridian = (double)map->width / (double)2.0;
417 aspmul = meridian / 180.0;
418
419 /* Compute the position in the bitmap map */
420 return (int)(double)(meridian + (lon * aspmul));
421 }
422
423 /* Converts latitude into position in the bitmap */
424
425 int silc_map_lat2y(SilcMap map, char *latitude)
426 {
427 double meridian, aspmul, lat;
428
429 /* Parse position string */
430 lat = silc_map_parse_pos(latitude);
431
432 /* Compute "aspect ratio multiplier" to get the position in the map. */
433 meridian = (double)map->height / (double)2.0;
434 aspmul = meridian / 90.0;
435
436 /* Compute the position in the bitmap map */
437 return (int)(double)(meridian - (lat * aspmul));
438 }
439
440 /* Parses RGB color string. */
441
442 bool silc_map_parse_color(const char *color,
443 SilcInt16 *r, SilcInt16 *g, SilcInt16 *b)
444 {
445 int ret;
446 int rr, gg, bb;
447
448 ret = sscanf(color, "%d %d %d", &rr, &gg, &bb);
449 if (ret < 3) {
450 fprintf(stderr, "Invalid color string: %s\n", color);
451 return FALSE;
452 }
453
454 *r = (SilcInt16)rr;
455 *g = (SilcInt16)gg;
456 *b = (SilcInt16)bb;
457
458 return TRUE;
459 }
460
461 /* Loads a font file. The font file format is the following:
462
463 height\n
464 width
465 font data
466 width
467 font data
468 etc.
469
470 If this function is called multiple times the new font replaces the
471 old font. */
472
473 bool silc_map_load_font(SilcMap map, const char *filename)
474 {
475 FILE *fp;
476 int i, x, y;
477
478 /* Load the file */
479 fp = fopen(filename, "r");
480 if (!fp) {
481 fprintf(stderr, "fopen: %s: %s\n", strerror(errno), filename);
482 return FALSE;
483 }
484
485 /* Read the font height */
486 i = fscanf(fp, "%d\n", &map->font.height);
487 if (i < 1)
488 return FALSE;
489
490 /* Read the font data */
491 for (i = 0; i < 94; i++) {
492 map->font.font[i].width = fgetc(fp);
493
494 for (y = 0; y < map->font.height; y++)
495 for (x = 0; x < map->font.font[i].width; x++)
496 map->font.font[i].data[(y * map->font.font[i].width) + x] = fgetc(fp);
497 }
498
499 return TRUE;
500 }
501
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse