1 #include "declarations.h"
2 
3 #if defined(PROG_HAS_LIBRSVG) && \
4 LIBRSVG_MAJOR_VERSION > 2 || (LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 36)
5 #include <glib.h>
6 #include <librsvg/rsvg.h>
7 #endif
8 
9 #include "image.h"
10 #include "config.mach"
11 
12 /**
13  * @brief Read BMP image expecting 24 or 32 bits per pixel.
14  *
15  * @param[in] s File name to read
16  * @param[in] n Zero to print error message if file does not exist
17  *
18  * @retval Image structure on success
19  * @retval NULL on failure
20  *
21  */
22 
image_bmp_read(char * s,unsigned int n)23 struct t_img *image_bmp_read(char *s, unsigned int n) {
24 	unsigned int f;
25 
26 	struct t_img *r;
27 
28 	if((f = files_open(s, n, FILE_MODE_READ)) == 0) return(NULL);
29 	if((r = image_read_file(f)) == NULL) return(NULL);
30 
31 	if(image_bmp_read_op(r) != 0) {
32 		(void) files_close(f);
33 		(void) image_free(r);
34 
35 		return(NULL);
36 	}
37 
38 	(void) files_close(f);
39 
40 	return(r);
41 }
42 
image_bmp_read_op(struct t_img * r)43 static int image_bmp_read_op(struct t_img *r) {
44 	int32_t w, h;
45 	uint16_t p;
46 	uint32_t c, v;
47 
48 	size_t t;
49 
50 	struct bmp_header *d;
51 
52 	d = (struct bmp_header *) r->c;
53 
54 	if(d->bf_type != endian_le_uint16(IMAGE_BMP_TAG)) {
55 		(void) flush_error();
56 
57 		LOGWARN(
58 			ERROR_SLIGHT, SUBSYSTEM,
59 			_("Image identification tag is not what was expected")
60 		);
61 
62 		return(-1);
63 	}
64 
65 	c = endian_le_uint32(d->bf_offbits);
66 
67 	w = endian_le_int32(d->i.bi_width);
68 	h = endian_le_int32(d->i.bi_height);
69 	v = endian_le_uint32(d->i.bi_compression);
70 	p = endian_le_uint16(d->i.bi_bitcount);
71 
72 	/* Check that image type is supported */
73 	if((v != 0 && v != 3) && (p != 24 && p != 32)) {
74 		(void) flush_error();
75 
76 		LOGWARN(
77 			ERROR_SLIGHT, SUBSYSTEM,
78 			_("Image type is not expected uncompressed truecolor")
79 		);
80 
81 		return(-1);
82 	}
83 
84 	/* All good, get the pixels */
85 	r->w = (int32_t) w;
86 	r->h = (int32_t) abs((int) h);
87 	r->b = (int32_t) p;
88 
89 	t = (size_t) ((r->w * r->h) * sizeof(struct pixel_rgba_8));
90 
91 	APP_MALLOC_RET_VALUE(r->p, t, -1);
92 
93 	(void) image_bmp_read_it(r, c, p, h);
94 
95 	return(0);
96 }
97 
image_bmp_read_it(struct t_img * r,uint32_t c,uint16_t b,int32_t y)98 static void image_bmp_read_it(struct t_img *r, uint32_t c, uint16_t b, int32_t y) {
99 	uint32_t i, j, k, u;
100 
101 	size_t t;
102 
103 	char *e;
104 
105 	struct pixel_bgr_8 *o;
106 	struct pixel_abgr_8 *p;
107 
108 	e = (char *) r->c + c;
109 	t = (size_t) c;
110 
111 	switch(b) {
112 		case 24:
113 			if(y < 0) {
114 				/* Add alpha byte */
115 				for(i = 0; i < (uint32_t) r->h; i++) {
116 					if(t > r->t) break;
117 
118 					o = (struct pixel_bgr_8 *) e + (i * ((r->w + 3) / 4 * 4));
119 					u = i * r->w;
120 
121 					for(j = 0; j < (uint32_t) r->w; j++) {
122 						if(t > r->t) break;
123 
124 						(void) image_read_it_bgr_24(r->p, o, u + j, j);
125 
126 						t += sizeof(struct pixel_bgr_8);
127 					}
128 				}
129 			}
130 			else {
131 				/* Add alpha byte and turn image upside down */
132 				for(i = (uint32_t) r->h, k = 0; i != 0; i--, k++) {
133 					if(t > r->t) break;
134 
135 					o = (struct pixel_bgr_8 *) e + (i * ((r->w + 3) / 4 * 4));
136 					u = k * r->w;
137 
138 					for(j = 0; j < (uint32_t) r->w; j++) {
139 						if(t > r->t) break;
140 
141 						(void) image_read_it_bgr_24(r->p, o, u + j, j);
142 
143 						t += sizeof(struct pixel_bgr_8);
144 					}
145 				}
146 			}
147 
148 			break;
149 		default:
150 			if(y < 0) {
151 				/* Swap alpha byte position */
152 				for(i = 0; i < (uint32_t) r->h; i++) {
153 					if(t > r->t) break;
154 
155 					p = (struct pixel_abgr_8 *) e + (i * r->w);
156 					u = i * r->w;
157 
158 					for(j = 0; j < (uint32_t) r->w; j++) {
159 						if(t > r->t) break;
160 
161 						(void) image_read_it_abgr_32(r->p, p, u + j, j);
162 
163 						t += sizeof(struct pixel_abgr_8);
164 					}
165 				}
166 			}
167 			else {
168 				/* Swap alpha byte position and turn image upside down */
169 				for(i = (uint32_t) r->h, k = 0; i != 0; i--, k++) {
170 					if(t > r->t) break;
171 
172 					p = (struct pixel_abgr_8 *) e + (i * r->w);
173 					u = k * r->w;
174 
175 					for(j = 0; j < (uint32_t) r->w; j++) {
176 						if(t > r->t) break;
177 
178 						(void) image_read_it_abgr_32(r->p, p, u + j, j);
179 
180 						t += sizeof(struct pixel_abgr_8);
181 					}
182 				}
183 			}
184 
185 			break;
186 	}
187 }
188 
189 /**
190  * @brief Read SVG image.
191  *
192  * @param[in] s File name to read
193  * @param[in] n Zero to print error message if file does not exist
194  *
195  * @retval Image structure on success
196  * @retval NULL on failure
197  *
198  */
199 
image_svg_read(char * s,unsigned int n)200 struct t_img *image_svg_read(char *s, unsigned int n) {
201 #if defined(PROG_HAS_LIBRSVG) && \
202 LIBRSVG_MAJOR_VERSION > 2 || (LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 36)
203 	GdkPixbuf *p;
204 	GError *e;
205 
206 	RsvgDimensionData d;
207 	RsvgHandle *r;
208 
209 	cairo_t *c;
210 	cairo_surface_t *f;
211 
212 	struct stat a;
213 
214 	struct t_img *m;
215 
216 	/* Check if file exists */
217 	if(stat((const char *) s, &a) != 0) {
218 		if(n == 0) {
219 			LOGWARN(
220 				ERROR_SLIGHT, SUBSYSTEM,
221 				_("Failed to open file '%s'"),
222 				s
223 			);
224 		}
225 
226 		return(NULL);
227 	}
228 
229 	/* Render the file */
230 	e = NULL;
231 
232 	if((r = rsvg_handle_new_from_file((const gchar *) s, &e)) == NULL) {
233 		if(e != NULL) {
234 			(void) flush_error();
235 
236 			LOGWARN(
237 				ERROR_SLIGHT, SUBSYSTEM,
238 				_("Failed to open file '%s': %s"),
239 				e->message
240 			);
241 		}
242 
243 		return(NULL);
244 	}
245 
246 	(void) rsvg_handle_set_dpi(r, 300.0);
247 	(void) rsvg_handle_get_dimensions(r, &d);
248 
249 	f = cairo_image_surface_create(CAIRO_FORMAT_RGB24, (int) d.width, (int) d.height);
250 
251 	if(cairo_surface_status(f) != CAIRO_STATUS_SUCCESS) {
252 		(void) flush_error();
253 
254 		LOGWARN(
255 			ERROR_SLIGHT, SUBSYSTEM,
256 			_("Failed to create cairo surface: %s"),
257 			(char *) cairo_status_to_string(cairo_surface_status(f))
258 		);
259 
260 		(void) image_svg_read_ca(r);
261 
262 		return(NULL);
263 	}
264 
265 	c = cairo_create(f);
266 
267 	if(cairo_status(c) != CAIRO_STATUS_SUCCESS) {
268 		(void) flush_error();
269 
270 		LOGWARN(
271 			ERROR_SLIGHT, SUBSYSTEM,
272 			_("Failed to create cairo context: %s"),
273 			(char *) cairo_status_to_string(cairo_status(c))
274 		);
275 
276 		(void) cairo_surface_destroy(f);
277 
278 		(void) image_svg_read_ca(r);
279 
280 		return(NULL);
281 	}
282 
283 	(void) cairo_surface_destroy(f);
284 #if defined(CAIRO_ANTIALIAS_BEST)
285 	(void) cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
286 #else
287 	(void) cairo_set_antialias(c, CAIRO_ANTIALIAS_DEFAULT);
288 #endif
289 	if(rsvg_handle_render_cairo(r, c) != TRUE) {
290 		(void) flush_error();
291 
292 		LOGWARN(
293 			ERROR_SLIGHT, SUBSYSTEM,
294 			_("Failed to render to cairo context")
295 		);
296 
297 		(void) image_svg_read_cb(r, c);
298 
299 		return(NULL);
300 	}
301 
302 	if((p = rsvg_handle_get_pixbuf(r)) == NULL) {
303 		(void) flush_error();
304 
305 		LOGWARN(
306 			ERROR_SLIGHT, SUBSYSTEM,
307 			_("Failed to get the pixbuf")
308 		);
309 
310 		(void) image_svg_read_cb(r, c);
311 
312 		return(NULL);
313 	}
314 
315 	(void) rsvg_handle_close(r, &e);
316 
317 	/* Copy SVG pixbuf to own buffer */
318 	if((m = malloc(sizeof(struct t_img))) == NULL) {
319 		LOGWARN(
320 			ERROR_SLIGHT, SUBSYSTEM,
321 			_("Failed to allocate %lu bytes of memory"),
322 			(unsigned long) sizeof(struct t_img)
323 		);
324 	}
325 
326 	if(m != NULL) {
327 		if(image_svg_read_op(m, p) != 0) {
328 			(void) image_free(m);
329 
330 			m = NULL;
331 		}
332 	}
333 
334 	(void) cairo_destroy(c);
335 
336 	(void) g_object_unref((gpointer) r);
337 	(void) g_object_unref((gpointer) p);
338 
339 	return(m);
340 #else
341 	(void) s;
342 	(void) n;
343 
344 	return(NULL);
345 #endif
346 }
347 #if defined(PROG_HAS_LIBRSVG) && \
348 LIBRSVG_MAJOR_VERSION > 2 || (LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 36)
image_svg_read_ca(RsvgHandle * r)349 static void image_svg_read_ca(RsvgHandle *r) {
350 	GError *e;
351 
352 	e = NULL;
353 
354 	(void) rsvg_handle_close(r, &e);
355 
356 	(void) g_object_unref((gpointer) r);
357 }
358 
image_svg_read_cb(RsvgHandle * r,cairo_t * c)359 static void image_svg_read_cb(RsvgHandle *r, cairo_t *c) {
360 	(void) cairo_destroy(c);
361 
362 	(void) image_svg_read_ca(r);
363 }
364 
image_svg_read_op(struct t_img * m,GdkPixbuf * p)365 static int image_svg_read_op(struct t_img *m, GdkPixbuf *p) {
366 	int k, n;
367 
368 	int32_t i, j;
369 	uint32_t o;
370 
371 	size_t t;
372 
373 	const guchar *d, *e, *f;
374 
375 	m->c = NULL;
376 	m->t = 0;
377 
378 	m->w = (int32_t) gdk_pixbuf_get_width(p);
379 	m->h = (int32_t) gdk_pixbuf_get_height(p);
380 	m->b = (int32_t) gdk_pixbuf_get_bits_per_sample(p);
381 
382 	k = gdk_pixbuf_get_rowstride(p);
383 	n = gdk_pixbuf_get_n_channels(p);
384 
385 	t = (size_t) (m->w * m->h * sizeof(struct pixel_rgba_8));
386 
387 	APP_MALLOC_RET_VALUE(m->p, t, -1);
388 
389 	d = gdk_pixbuf_read_pixels(p);
390 
391 	for(i = 0; i < m->h; i++) {
392 		e = d + (i * k);
393 
394 		for(j = 0; j < m->w; j++) {
395 			f = e + (j * n);
396 			o = (i * m->w) + j;
397 
398 			m->p[o].pixel.r = f[0];
399 			m->p[o].pixel.g = f[1];
400 			m->p[o].pixel.b = f[2];
401 			m->p[o].pixel.a = f[3];
402 		}
403 	}
404 
405 	return(0);
406 }
407 #endif
408 
409 /**
410  * @brief Read Truevision TGA image expecting 24 or 32 bits per pixel.
411  *
412  * @param[in] s File name to read
413  * @param[in] n Zero to print error message if file does not exist
414  *
415  * @retval Image structure on success
416  * @retval NULL on failure
417  *
418  */
419 
image_tga_read(char * s,unsigned int n)420 struct t_img *image_tga_read(char *s, unsigned int n) {
421 	unsigned int f;
422 
423 	struct t_img *r;
424 
425 	if((f = files_open(s, n, FILE_MODE_READ)) == 0) return(NULL);
426 	if((r = image_read_file(f)) == NULL) return(NULL);
427 
428 	if(image_tga_read_op(r) != 0) {
429 		(void) files_close(f);
430 		(void) image_free(r);
431 
432 		return(NULL);
433 	}
434 
435 	(void) files_close(f);
436 
437 	return(r);
438 }
439 
image_tga_read_op(struct t_img * r)440 static int image_tga_read_op(struct t_img *r) {
441 	uint8_t c, m, p, v;
442 	uint16_t n, w, h;
443 
444 	size_t t;
445 
446 	struct tga_header *d;
447 
448 	d = (struct tga_header *) r->c;
449 
450 	c = endian_le_uint8(d->d);
451 	m = endian_le_uint8(d->m);
452 	v = endian_le_uint8(d->t);
453 
454 	n = endian_le_uint16(d->c.n);
455 
456 	w = endian_le_uint16(d->i.w);
457 	h = endian_le_uint16(d->i.h);
458 	p = endian_le_uint8(d->i.b);
459 
460 	/* Check that image type is supported */
461 	if((m != 0 || v != IMAGE_TGA_STORAGE_VERBATIM || n != 0) && (p != 24 && p != 32)) {
462 		(void) flush_error();
463 
464 		LOGWARN(
465 			ERROR_SLIGHT, SUBSYSTEM,
466 			_("Image type is not expected uncompressed truecolor")
467 		);
468 
469 		return(-1);
470 	}
471 
472 	/* All good, get the pixels */
473 	r->w = (int32_t) w;
474 	r->h = (int32_t) h;
475 	r->b = (int32_t) p;
476 
477 	t = (size_t) ((r->w * r->h) * sizeof(struct pixel_rgba_8));
478 
479 	APP_MALLOC_RET_VALUE(r->p, t, -1);
480 
481 	(void) image_tga_read_it(r, c, p, endian_le_int16(d->i.y));
482 
483 	return(0);
484 }
485 
image_tga_read_it(struct t_img * r,uint8_t c,uint8_t b,int16_t y)486 static void image_tga_read_it(struct t_img *r, uint8_t c, uint8_t b, int16_t y) {
487 	uint32_t i, j, k, l, u, v;
488 
489 	size_t t;
490 
491 	char *e;
492 
493 	struct pixel_bgr_8 *o;
494 	struct pixel_bgra_8 *p;
495 
496 	e = (char *) r->c + sizeof(struct tga_header) + c;
497 	t = (size_t) (sizeof(struct tga_header) + c);
498 
499 	switch(b) {
500 		case 24:
501 			o = (struct pixel_bgr_8 *) e;
502 
503 			if(y == 0) {
504 				/* Add alpha byte and turn image upside down */
505 				for(i = (uint32_t) r->h, k = 0; i != 0; i--, k++) {
506 					if(t > r->t) break;
507 
508 					u = (i - 1) * r->w;
509 					v = k * r->w;
510 
511 					for(j = 0, l = u; j < (uint32_t) r->w; j++, l++) {
512 						if(t > r->t) break;
513 
514 						(void) image_read_it_bgr_24(r->p, o, v + j, l);
515 
516 						t += sizeof(struct pixel_bgr_8);
517 					}
518 				}
519 			}
520 			else {
521 				/* Add alpha byte */
522 				for(i = 0; i < (uint32_t) r->h; i++) {
523 					if(t > r->t) break;
524 
525 					u = i * r->w;
526 
527 					for(j = 0; j < (uint32_t) r->w; j++) {
528 						if(t > r->t) break;
529 
530 						(void) image_read_it_bgr_24(r->p, o, u + j, u + j);
531 
532 						t += sizeof(struct pixel_bgr_8);
533 					}
534 				}
535 			}
536 
537 			break;
538 		default:
539 			p = (struct pixel_bgra_8 *) e;
540 
541 			if(y == 0) {
542 				/* Swap alpha byte position and turn image upside down */
543 				for(i = (uint32_t) r->h, k = 0; i != 0; i--, k++) {
544 					if(t > r->t) break;
545 
546 					u = (i - 1) * r->w;
547 					v = k * r->w;
548 
549 					for(j = 0, l = u; j < (uint32_t) r->w; j++, l++) {
550 						if(t > r->t) break;
551 
552 						(void) image_read_it_bgra_32(r->p, p, v + j, l);
553 
554 						t += sizeof(struct pixel_bgra_8);
555 					}
556 				}
557 			}
558 			else {
559 				/* Swap alpha byte position */
560 				for(i = 0; i < (uint32_t) r->h; i++) {
561 					if(t > r->t) break;
562 
563 					u = i * r->w;
564 
565 					for(j = 0; j < (uint32_t) r->w; j++) {
566 						if(t > r->t) break;
567 
568 						(void) image_read_it_bgra_32(r->p, p, u + j, u + j);
569 
570 						t += sizeof(struct pixel_bgra_8);
571 					}
572 				}
573 			}
574 
575 			break;
576 	}
577 }
578 
579 /*
580 static void image_read_it_bgr_15(struct pixel_rgba_8 *d, struct pixel_ac_1 *s, uint32_t a, uint32_t b) {
581 #if defined(IS_BIGENDIAN)
582 	d[a].pixel.r = (s[b].pixel.a >> 2) & 0x1f;
583 	d[a].pixel.g = ((s[b].pixel.a << 3) & 0x1c) | ((s[b].pixel.c >> 5) & 0x07);
584 	d[a].pixel.b = (s[b].pixel.c & 0x1f);
585 #else
586 	d[a].pixel.r = (s[b].pixel.c >> 2) & 0x1f;
587 	d[a].pixel.g = ((s[b].pixel.c << 3) & 0x1c) | ((s[b].pixel.a >> 5) & 0x07);
588 	d[a].pixel.b = (s[b].pixel.a & 0x1f);
589 #endif
590 	d[a].pixel.r = (d[a].pixel.r << 3) | (d[a].pixel.r >> 2);
591 	d[a].pixel.g = (d[a].pixel.g << 3) | (d[a].pixel.g >> 2);
592 	d[a].pixel.b = (d[a].pixel.b << 3) | (d[a].pixel.b >> 2);
593 
594 	d[a].pixel.a = 255;
595 }
596 
597 static void image_read_it_bgr_16(struct pixel_rgba_8 *d, struct pixel_ac_1 *s, uint32_t a, uint32_t b) {
598 #if defined(IS_BIGENDIAN)
599 	d[a].pixel.r = (s[b].pixel.a >> 2) & 0x1f;
600 	d[a].pixel.g = ((s[b].pixel.a << 3) & 0x1c) | ((s[b].pixel.c >> 5) & 0x07);
601 	d[a].pixel.b = (s[b].pixel.c & 0x1f);
602 	d[a].pixel.a = 255 * ((s[b].pixel.a & 0x80) >> 0x07);
603 #else
604 	d[a].pixel.r = (s[b].pixel.c >> 2) & 0x1f;
605 	d[a].pixel.g = ((s[b].pixel.c << 3) & 0x1c) | ((s[b].pixel.a >> 5) & 0x07);
606 	d[a].pixel.b = (s[b].pixel.a & 0x1f);
607 	d[a].pixel.a = 255 * ((s[b].pixel.c & 0x80) >> 0x07);
608 #endif
609 	d[a].pixel.r = (d[a].pixel.r << 3) | (d[a].pixel.r >> 2);
610 	d[a].pixel.g = (d[a].pixel.g << 3) | (d[a].pixel.g >> 2);
611 	d[a].pixel.b = (d[a].pixel.b << 3) | (d[a].pixel.b >> 2);
612 }
613 */
614 
image_read_it_bgr_24(struct pixel_rgba_8 * d,struct pixel_bgr_8 * s,uint32_t a,uint32_t b)615 static void image_read_it_bgr_24(struct pixel_rgba_8 *d, struct pixel_bgr_8 *s, uint32_t a, uint32_t b) {
616 #if defined(IS_BIGENDIAN)
617 	d[a].pixel.r = s[b].r;
618 	d[a].pixel.g = s[b].g;
619 	d[a].pixel.b = s[b].b;
620 #else
621 	d[a].pixel.r = s[b].b;
622 	d[a].pixel.g = s[b].g;
623 	d[a].pixel.b = s[b].r;
624 #endif
625 	d[a].pixel.a = 255;
626 }
627 
image_read_it_bgra_32(struct pixel_rgba_8 * d,struct pixel_bgra_8 * s,uint32_t a,uint32_t b)628 static void image_read_it_bgra_32(struct pixel_rgba_8 *d, struct pixel_bgra_8 *s, uint32_t a, uint32_t b) {
629 #if defined(IS_BIGENDIAN)
630 	d[a].pixel.b = s[b].pixel.b;
631 	d[a].pixel.g = s[b].pixel.g;
632 	d[a].pixel.r = s[b].pixel.r;
633 	d[a].pixel.a = s[b].pixel.a;
634 #else
635 	d[a].pixel.b = s[b].pixel.a;
636 	d[a].pixel.g = s[b].pixel.r;
637 	d[a].pixel.r = s[b].pixel.g;
638 	d[a].pixel.a = s[b].pixel.b;
639 #endif
640 }
641 
image_read_it_abgr_32(struct pixel_rgba_8 * d,struct pixel_abgr_8 * s,uint32_t a,uint32_t b)642 static void image_read_it_abgr_32(struct pixel_rgba_8 *d, struct pixel_abgr_8 *s, uint32_t a, uint32_t b) {
643 #if defined(IS_BIGENDIAN)
644 	d[a].pixel.a = s[b].pixel.a;
645 	d[a].pixel.b = s[b].pixel.b;
646 	d[a].pixel.g = s[b].pixel.g;
647 	d[a].pixel.r = s[b].pixel.r;
648 #else
649 	d[a].pixel.a = s[b].pixel.r;
650 	d[a].pixel.b = s[b].pixel.g;
651 	d[a].pixel.g = s[b].pixel.b;
652 	d[a].pixel.r = s[b].pixel.a;
653 #endif
654 }
655 
image_read_file(unsigned int f)656 static struct t_img *image_read_file(unsigned int f) {
657 	void *c;
658 
659 	size_t t;
660 
661 	struct t_img *r;
662 
663 	if((t = files_get_file_size(f)) == 0) {
664 		(void) files_close(f);
665 
666 		return(NULL);
667 	}
668 
669 	if((files_read(f, t)) != 0) {
670 		(void) files_close(f);
671 
672 		return(NULL);
673 	}
674 
675 	if((c = files_get_content(f)) == NULL) {
676 		(void) files_close(f);
677 
678 		return(NULL);
679 	}
680 
681 	if((r = malloc(sizeof(struct t_img))) == NULL) {
682 		LOGWARN(
683 			ERROR_SLIGHT, SUBSYSTEM,
684 			_("Failed to allocate %lu bytes of memory"),
685 			(unsigned long) sizeof(struct t_img)
686 		);
687 
688 		(void) files_close(f);
689 
690 		return(NULL);
691 	}
692 
693 	(void) memset((void *) r, 0, sizeof(struct t_img));
694 
695 	r->p = NULL;
696 
697 	r->c = c;
698 	r->t = t;
699 
700 	return(r);
701 }
702 
703 /**
704  * @brief Read image by format.
705  *
706  * @param[in] s File name to read
707  * @param[in] n Zero to print error message if file does not exist
708  *
709  * @retval Image structure on success
710  * @retval NULL on failure
711  *
712  */
713 
image_read(char * s,unsigned int n)714 struct t_img *image_read(char *s, unsigned int n) {
715 	char *p;
716 
717 	if(s == NULL) return(NULL);
718 
719 	if((p = strrchr((const char *) s, '.')) == NULL) {
720 		(void) flush_error();
721 
722 		LOGWARN(
723 			ERROR_SLIGHT, SUBSYSTEM,
724 			_("Failed to detect image type from its name")
725 		);
726 
727 		return(NULL);
728 	}
729 
730 	switch(image_get_type_by_suffix(++p)) {
731 		case IMAGE_FORMAT_BMP:
732 			return(image_bmp_read(s, n));
733 #if defined(PROG_HAS_LIBRSVG) && \
734 LIBRSVG_MAJOR_VERSION > 2 || (LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION >= 36)
735 		case IMAGE_FORMAT_SVG:
736 			return(image_svg_read(s, n));
737 #endif
738 		case IMAGE_FORMAT_TGA:
739 			return(image_tga_read(s, n));
740 		default:
741 			(void) flush_error();
742 
743 			LOGWARN(
744 				ERROR_SLIGHT, SUBSYSTEM,
745 				_("Image type '%s' is not supported"),
746 				p
747 			);
748 
749 			break;
750 	}
751 
752 	return(NULL);
753 }
754 
755 /**
756  * @brief Free image structure.
757  *
758  * @param[in] r Image structure returned by image_*_read_*()
759  *
760  */
761 
image_free(struct t_img * r)762 void image_free(struct t_img *r) {
763 	if(r != NULL) {
764 		if(r->p != NULL) (void) free(r->p);
765 
766 		(void) free(r);
767 	}
768 }
769 
770 /**
771  * @brief Write BMP image using 32 bits (RGBA) per pixel.
772  *
773  * @param[in] p Image pixel data
774  * @param[in] w Image width in pixels
775  * @param[in] h Image height in pixels
776  * @param[in] s File name to write
777  *
778  * @retval Zero on success
779  * @retval Non-zero on failure
780  *
781  */
782 
783 #if ! defined(PROG_DISABLE_IMAGE)
image_bmp_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)784 int image_bmp_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
785 	unsigned int f;
786 
787 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
788 
789 	if(image_bmp_header((int32_t) w, (int32_t) h, 32, f) != 0) return(-1);
790 	if(image_bmp_channs(p, (int32_t) w, (int32_t) h, f) != 0) return(-1);
791 
792 	(void) files_close(f);
793 
794 	return(0);
795 }
796 
image_bmp_header(int32_t w,int32_t h,uint16_t b,unsigned int f)797 static int image_bmp_header(int32_t w, int32_t h, uint16_t b, unsigned int f) {
798 	struct bmp_header d;
799 
800 	(void) memset((void *) &d, 0, sizeof(d));
801 
802 	d.bf_type = endian_le_uint16(IMAGE_BMP_TAG);
803 
804 	d.bf_size = endian_le_uint32((uint32_t) sizeof(struct bmp_header) + (w * h * sizeof(struct pixel_rgba_8)));
805 	d.bf_offbits = endian_le_uint32((uint32_t) sizeof(struct bmp_header));
806 
807 	d.i.bi_size = endian_le_uint32((uint32_t) sizeof(struct bmp_header_info));
808 
809 	/* Dimensions */
810 	d.i.bi_width = endian_le_int32((int32_t) w);
811 	d.i.bi_height = endian_le_int32((int32_t) h);
812 
813 	/* Storage type */
814 	d.i.bi_planes = endian_le_uint16(1);
815 	d.i.bi_bitcount = endian_le_uint16((uint32_t) b);
816 
817 	d.i.bi_compression = endian_le_uint32(0);
818 	d.i.bi_sizeimage = endian_le_uint32((uint32_t) (w * h * sizeof(struct pixel_rgba_8)));
819 	d.i.bi_xpelspermeter = endian_le_uint32(2835);
820 	d.i.bi_ypelspermeter = endian_le_uint32(2835);
821 
822 	/* Colormap */
823 	d.i.bi_clrused = endian_le_uint32(0);
824 	d.i.bi_clrimportant = endian_le_uint32(0);
825 
826 	return(files_write(f, (void *) &d, sizeof(d)));
827 }
828 
image_bmp_channs(struct pixel_rgba_8 * p,int32_t w,int32_t h,unsigned int f)829 static int image_bmp_channs(struct pixel_rgba_8 *p, int32_t w, int32_t h, unsigned int f) {
830 	uint32_t i, j, k, l;
831 
832 	struct pixel_abgr_8 a;
833 
834 	/* Swap alpha byte position and turn image upside down */
835 	for(i = (uint32_t) h; i != 0; i--) {
836 		k = (i - 1) * w;
837 
838 		for(j = 0; j < (uint32_t) w; j++) {
839 			l = k + j;
840 #if defined(IS_BIGENDIAN)
841 			a.pixel.a = p[l].pixel.b;
842 			a.pixel.b = p[l].pixel.g;
843 			a.pixel.g = p[l].pixel.r;
844 			a.pixel.r = p[l].pixel.a;
845 #else
846 			a.pixel.a = p[l].pixel.a;
847 			a.pixel.b = p[l].pixel.r;
848 			a.pixel.g = p[l].pixel.g;
849 			a.pixel.r = p[l].pixel.b;
850 #endif
851 			if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
852 		}
853 	}
854 
855 	return(0);
856 }
857 #endif
858 
859 /**
860  * @brief Write KISS CEL image using 32 bits (RGBA) per pixel.
861  *
862  * @param[in] p Image pixel data
863  * @param[in] w Image width in pixels
864  * @param[in] h Image height in pixels
865  * @param[in] s File name to write
866  *
867  * @retval Zero on success
868  * @retval Non-zero on failure
869  *
870  */
871 
872 #if ! defined(PROG_DISABLE_IMAGE)
image_cel_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)873 int image_cel_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
874 	unsigned int f;
875 
876 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
877 
878 	if(image_cel_header(IMAGE_CEL_COLOR, (uint16_t) w, (uint16_t) h, 32, f) != 0) return(-1);
879 	if(image_cel_channs(p, w, h, f) != 0) return(-1);
880 
881 	(void) files_close(f);
882 
883 	return(0);
884 }
885 
image_cel_header(int8_t t,uint16_t w,uint16_t h,uint16_t b,unsigned int f)886 static int image_cel_header(int8_t t, uint16_t w, uint16_t h, uint16_t b, unsigned int f) {
887 	struct cel_header d;
888 
889 	(void) memset((void *) &d, 0, sizeof(d));
890 
891 	d.id = endian_le_int32(IMAGE_CEL_TAG);
892 
893 	/* Storage type */
894 	d.type = endian_le_int8(t);
895 	d.bpp = endian_le_int8((int8_t) b);
896 
897 	/* Dimensions */
898 	d.width = endian_le_uint16(w);
899 	d.height = endian_le_uint16(h);
900 	d.xoffset = endian_le_uint16(0);
901 	d.yoffset = endian_le_uint16(0);
902 
903 	return(files_write(f, (void *) &d, sizeof(d)));
904 }
905 
image_cel_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)906 static int image_cel_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
907 	uint32_t i;
908 
909 	struct pixel_argb_8 a;
910 
911 	/* Swap alpha byte position */
912 	for(i = 0; i < (uint32_t) w * h; i++) {
913 #if defined(IS_BIGENDIAN)
914 		a.pixel.a = p[i].pixel.b;
915 		a.pixel.r = p[i].pixel.g;
916 		a.pixel.g = p[i].pixel.r;
917 		a.pixel.b = p[i].pixel.a;
918 #else
919 		a.pixel.a = p[i].pixel.a;
920 		a.pixel.r = p[i].pixel.r;
921 		a.pixel.g = p[i].pixel.g;
922 		a.pixel.b = p[i].pixel.b;
923 #endif
924 		if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
925 	}
926 
927 	return(0);
928 }
929 #endif
930 
931 /**
932  * @brief Write Alias PIX image using 24 bits (RGB) + 8 bits (A) per pixel.
933  *
934  * Alpha bits are stored in separate .matte file.
935  *
936  * @param[in] p Image pixel data
937  * @param[in] w Image width in pixels
938  * @param[in] h Image height in pixels
939  * @param[in] s File name to write
940  *
941  * @retval Zero on success
942  * @retval Non-zero on failure
943  *
944  */
945 
946 #if ! defined(PROG_DISABLE_IMAGE)
image_pix_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)947 int image_pix_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
948 	unsigned int f;
949 
950 	char *e;
951 
952 	size_t t;
953 
954 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
955 
956 	if(image_pix_header((uint16_t) w, (uint16_t) h, 24, f) != 0) return(-1);
957 	if(image_pix_channs(p, w, h, f) != 0) return(-1);
958 
959 	(void) files_close(f);
960 
961 	t = str_len(s, STRING_ASCII) + (sizeof(char) * 8);
962 
963 	APP_MALLOC_RET_VALUE(e, t, -1);
964 
965 	(void) snprintf(e, t, "%s.matte", s);
966 
967 	if((f = files_open(e, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) {
968 		(void) free(e);
969 
970 		return(-1);
971 	}
972 
973 	if(image_pix_header((uint16_t) w, (uint16_t) h, 8, f) != 0) {
974 		(void) free(e);
975 
976 		return(-1);
977 	}
978 
979 	if(image_pix_mattes(p, w, h, f) != 0) {
980 		(void) free(e);
981 
982 		return(-1);
983 	}
984 
985 	(void) files_close(f);
986 	(void) free(e);
987 
988 	return(0);
989 }
990 
image_pix_header(uint16_t w,uint16_t h,uint16_t b,unsigned int f)991 static int image_pix_header(uint16_t w, uint16_t h, uint16_t b, unsigned int f) {
992 	struct pix_header d;
993 
994 	(void) memset((void *) &d, 0, sizeof(d));
995 
996 	/* Dimensions */
997 	d.width = endian_be_uint16(w);
998 	d.height = endian_be_uint16(h);
999 	d.xoffset = endian_be_uint16(0);
1000 	d.yoffset = endian_be_uint16(0);
1001 
1002 	/* Storage type */
1003 	d.bpp = endian_be_uint16(b);
1004 
1005 	return(files_write(f, (void *) &d, sizeof(d)));
1006 }
1007 
image_pix_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1008 static int image_pix_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1009 	uint32_t i, j, k, c;
1010 
1011 	struct pixel_rgba_8 a;
1012 
1013 	/* PIX style RLE compression */
1014 	for(i = 0; i < (uint32_t) h; i++) {
1015 		k = i * w;
1016 		c = 0;
1017 
1018 		a.pixel.r = p[k].pixel.r;
1019 		a.pixel.g = p[k].pixel.g;
1020 		a.pixel.b = p[k].pixel.b;
1021 
1022 		for(j = 0; j < (uint32_t) w; j++) {
1023 			if(c < 255 && (a.pixel.r == p[k + j].pixel.r && a.pixel.g == p[k + j].pixel.g && a.pixel.b == p[k + j].pixel.b)) ++c;
1024 			else {
1025 				a.pixel.a = (uint8_t) c;
1026 				a.pixel.p = endian_le_uint32(a.pixel.p);
1027 
1028 				if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
1029 
1030 				c = 1;
1031 
1032 				a.pixel.r = p[k + j].pixel.r;
1033 				a.pixel.g = p[k + j].pixel.g;
1034 				a.pixel.b = p[k + j].pixel.b;
1035 			}
1036 		}
1037 
1038 		if(c > 0) {
1039 			a.pixel.a = (uint8_t) c;
1040 			a.pixel.p = endian_le_uint32(a.pixel.p);
1041 
1042 			if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
1043 		}
1044 	}
1045 
1046 	return(0);
1047 }
1048 
image_pix_mattes(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1049 static int image_pix_mattes(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1050 	uint32_t i, j, k, c;
1051 
1052 	struct pixel_ca_1 a;
1053 
1054 	/* PIX style RLE compression */
1055 	for(i = 0; i < (uint32_t) h; i++) {
1056 		k = i * w;
1057 		c = 0;
1058 
1059 		a.pixel.c = p[k].pixel.a;
1060 
1061 		for(j = 0; j < (uint32_t) w; j++) {
1062 			if(c < 255 && (a.pixel.c == p[k + j].pixel.a)) ++c;
1063 			else {
1064 				a.pixel.a = (uint8_t) c;
1065 				a.pixel.p = endian_le_uint16(a.pixel.p);
1066 
1067 				if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
1068 
1069 				c = 1;
1070 
1071 				a.pixel.c = p[k + j].pixel.a;
1072 			}
1073 		}
1074 
1075 		if(c > 0) {
1076 			a.pixel.a = (uint8_t) c;
1077 			a.pixel.p = endian_le_uint16(a.pixel.p);
1078 
1079 			if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
1080 		}
1081 	}
1082 
1083 	return(0);
1084 }
1085 #endif
1086 
1087 /**
1088  * @brief Write NetPBM PPM image using 24 bits (RGB) per pixel.
1089  *
1090  * @param[in] p Image pixel data
1091  * @param[in] w Image width in pixels
1092  * @param[in] h Image height in pixels
1093  * @param[in] s File name to write
1094  *
1095  * @retval Zero on success
1096  * @retval Non-zero on failure
1097  *
1098  */
1099 
1100 #if ! defined(PROG_DISABLE_IMAGE)
image_ppm_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)1101 int image_ppm_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
1102 	unsigned int f;
1103 
1104 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
1105 
1106 	if(image_ppm_header((uint16_t) w, (uint16_t) h, 255, f) != 0) return(-1);
1107 	if(image_ppm_channs(p, w, h, f) != 0) return(-1);
1108 
1109 	(void) files_close(f);
1110 
1111 	return(0);
1112 }
1113 
image_ppm_header(uint16_t w,uint16_t h,uint16_t b,unsigned int f)1114 static int image_ppm_header(uint16_t w, uint16_t h, uint16_t b, unsigned int f) {
1115 	char *s, *r, *k;
1116 
1117 	size_t n;
1118 
1119 	time_t m;
1120 
1121 	struct tm *t;
1122 
1123 	APP_MALLOC_RET_VALUE(r, CONFIG_LINE_LENGTH * 8, -1);
1124 
1125 	/* Identifier */
1126 	n = (size_t) snprintf(r, CONFIG_LINE_LENGTH, "%s%c", IMAGE_PPM_TAG, CONFIG_LINE_FEED);
1127 
1128 	/* Creator info */
1129 	if((s = files_get_name(f)) != NULL) {
1130 		if((k = strrchr((const char *) s, CONFIG_PATH_DELIM)) == NULL) k = s;
1131 		else k += sizeof(char);
1132 	}
1133 	else k = "";
1134 
1135 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "# %s%c", k, CONFIG_LINE_FEED);
1136 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "# " APPLICATION_NAME " " APPLICATION_VERSION " (" CONFIG_MACH ")%c", CONFIG_LINE_FEED);
1137 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "# %s%c", node_get_node(), CONFIG_LINE_FEED);
1138 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "# %s%c", node_get_user(), CONFIG_LINE_FEED);
1139 
1140 	if((m = time(NULL)) != (time_t) -1) {
1141 		if((t = localtime(&m)) != NULL) {
1142 			n += (size_t) strftime(r + n, CONFIG_LINE_LENGTH, "# %b %d %H:%M %Y%n", t);
1143 		}
1144 	}
1145 
1146 	/* Dimensions */
1147 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "%u %u%c", (unsigned int) w, (unsigned int) h, CONFIG_LINE_FEED);
1148 	n += (size_t) snprintf(r + n, CONFIG_LINE_LENGTH, "%u%c", (unsigned int) b, CONFIG_LINE_FEED);
1149 
1150 	if(files_write(f, (void *) r, n) != 0) {
1151 		(void) free(r);
1152 
1153 		return(-1);
1154 	}
1155 
1156 	(void) free(r);
1157 
1158 	return(0);
1159 }
1160 
image_ppm_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1161 static int image_ppm_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1162 	uint32_t i;
1163 
1164 	struct pixel_rgb_8 a;
1165 
1166 	/* Get rid of alpha channel */
1167 	for(i = 0; i < (uint32_t) w * h; i++) {
1168 		a.r = p[i].pixel.r;
1169 		a.g = p[i].pixel.g;
1170 		a.b = p[i].pixel.b;
1171 
1172 		if(files_write(f, (void *) &a, sizeof(a)) != 0) return(-1);
1173 	}
1174 
1175 	return(0);
1176 }
1177 #endif
1178 
1179 /**
1180  * @brief Write Sun RAS image using 32 bits (RGBA) per pixel.
1181  *
1182  * @param[in] p Image pixel data
1183  * @param[in] w Image width in pixels
1184  * @param[in] h Image height in pixels
1185  * @param[in] s File name to write
1186  *
1187  * @retval Zero on success
1188  * @retval Non-zero on failure
1189  *
1190  */
1191 
1192 #if ! defined(PROG_DISABLE_IMAGE)
image_ras_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)1193 int image_ras_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
1194 	unsigned int f;
1195 
1196 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
1197 
1198 	if(image_ras_header(IMAGE_RAS_STANDARD, (uint16_t) w, (uint16_t) h, 32, f) != 0) return(-1);
1199 	if(image_ras_channs(p, w, h, f) != 0) return(-1);
1200 
1201 	(void) files_close(f);
1202 
1203 	return(0);
1204 }
1205 
image_ras_header(int8_t t,uint16_t w,uint16_t h,uint16_t b,unsigned int f)1206 static int image_ras_header(int8_t t, uint16_t w, uint16_t h, uint16_t b, unsigned int f) {
1207 	struct ras_header d;
1208 
1209 	(void) memset((void *) &d, 0, sizeof(d));
1210 
1211 	d.ras_magic = endian_be_int32(IMAGE_RAS_TAG);
1212 
1213 	/* Dimensions */
1214 	d.ras_width = endian_be_int32((int32_t) w);
1215 	d.ras_height = endian_be_int32((int32_t) h);
1216 	d.ras_depth = endian_be_int32((int32_t) b);
1217 	d.ras_length = endian_be_int32(d.ras_width * d.ras_height * d.ras_depth);
1218 
1219 	/* Storage type */
1220 	d.ras_type = endian_be_int32((int32_t) t);
1221 
1222 	/* Colormap */
1223 	d.ras_maptype = endian_be_int32(0);
1224 	d.ras_maplength = endian_be_int32(0);
1225 
1226 	return(files_write(f, (void *) &d, sizeof(d)));
1227 }
1228 
image_ras_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1229 static int image_ras_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1230 #if defined(IS_BIGENDIAN)
1231 	uint32_t i;
1232 
1233 	struct pixel_rgba_8 r;
1234 
1235 	for(i = 0; i < (uint32_t) (w * h); i++) {
1236 		r.pixel.p = endian_le_uint32(p[i].pixel.p);
1237 
1238 		if(files_write(f, (void *) &r.pixel.p, sizeof(r.pixel.p)) != 0) return(-1);
1239 	}
1240 
1241 	return(0);
1242 #else
1243 	return(files_write(f, (void *) p, (size_t) w * h * sizeof(struct pixel_rgba_8)));
1244 #endif
1245 }
1246 #endif
1247 
1248 /**
1249  * @brief Write Silicon Graphics RGB image using 32 bits (RGBA) per pixel.
1250  *
1251  * @param[in] p Image pixel data
1252  * @param[in] w Image width in pixels
1253  * @param[in] h Image height in pixels
1254  * @param[in] s File name to write
1255  *
1256  * @retval Zero on success
1257  * @retval Non-zero on failure
1258  *
1259  */
1260 
1261 #if ! defined(PROG_DISABLE_IMAGE)
image_rgb_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)1262 int image_rgb_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
1263 	unsigned int f;
1264 
1265 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
1266 
1267 	if(image_rgb_header(IMAGE_RGB_STORAGE_VERBATIM, (uint16_t) w, (uint16_t) h, 4, 1, f) != 0) return(-1);
1268 	if(image_rgb_channs(p, w, h, f) != 0) return(-1);
1269 
1270 	(void) files_close(f);
1271 
1272 	return(0);
1273 }
1274 
image_rgb_header(int8_t t,uint16_t w,uint16_t h,uint16_t b,int8_t c,unsigned int f)1275 static int image_rgb_header(int8_t t, uint16_t w, uint16_t h, uint16_t b, int8_t c, unsigned int f) {
1276 	char *s, *k;
1277 
1278 	struct rgb_header d;
1279 
1280 	(void) memset((void *) &d, 0, sizeof(d));
1281 
1282 	d.magic = endian_be_int16(IMAGE_RGB_TAG);
1283 
1284 	/* Storage type */
1285 	d.storage = endian_be_int8(t);
1286 	d.bpc = endian_be_int8(c);
1287 
1288 	/* Dimensions */
1289 	d.dimension = endian_be_uint16(3);
1290 	d.xsize = endian_be_uint16(w);
1291 	d.ysize = endian_be_uint16(h);
1292 	d.zsize = endian_be_uint16(b);
1293 
1294 	/* Pixel limits */
1295 	d.pixmin = endian_be_int32(0);
1296 	d.pixmax = endian_be_int32(255);
1297 
1298 	/* Image name */
1299 	if((s = files_get_name(f)) != NULL) {
1300 		if((k = strrchr((const char *) s, CONFIG_PATH_DELIM)) == NULL) k = s;
1301 		else k += sizeof(char);
1302 	}
1303 	else k = "";
1304 
1305 	(void) snprintf((char *) d.imagename, sizeof(d.imagename), "%s", k);
1306 
1307 	/* Colormap */
1308 	d.colormap = endian_be_int32(0);
1309 
1310 	return(files_write(f, (void *) &d, sizeof(d)));
1311 }
1312 
image_rgb_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1313 static int image_rgb_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1314 	uint8_t r, g, b, a;
1315 	uint32_t i, j, k;
1316 
1317 	/* Red channel */
1318 	for(i = (uint32_t) h; i != 0; i--) {
1319 		k = (i - 1) * w;
1320 
1321 		for(j = 0; j < (uint32_t) w; j++) {
1322 			r = p[k + j].pixel.r;
1323 
1324 			if(files_write(f, (void *) &r, sizeof(r)) != 0) return(-1);
1325 		}
1326 	}
1327 
1328 	/* Green channel */
1329 	for(i = (uint32_t) h; i != 0; i--) {
1330 		k = (i - 1) * w;
1331 
1332 		for(j = 0; j < (uint32_t) w; j++) {
1333 			g = p[k + j].pixel.g;
1334 
1335 			if(files_write(f, (void *) &g, sizeof(g)) != 0) return(-1);
1336 		}
1337 	}
1338 
1339 	/* Blue channel */
1340 	for(i = (uint32_t) h; i != 0; i--) {
1341 		k = (i - 1) * w;
1342 
1343 		for(j = 0; j < (uint32_t) w; j++) {
1344 			b = p[k + j].pixel.b;
1345 
1346 			if(files_write(f, (void *) &b, sizeof(b)) != 0) return(-1);
1347 		}
1348 	}
1349 
1350 	/* Alpha channel */
1351 	for(i = (uint32_t) h; i != 0; i--) {
1352 		k = (i - 1) * w;
1353 
1354 		for(j = 0; j < (uint32_t) w; j++) {
1355 			a = p[k + j].pixel.a;
1356 
1357 			if(files_write(f, (void *) &a, sizeof(a)) != 0) return(-1);
1358 		}
1359 	}
1360 
1361 	return(0);
1362 }
1363 #endif
1364 
1365 /**
1366  * @brief Write Autodesk RLA image using 32 bits (RGBA) per pixel.
1367  *
1368  * @param[in] p Image pixel data
1369  * @param[in] w Image width in pixels
1370  * @param[in] h Image height in pixels
1371  * @param[in] s File name to write
1372  *
1373  * @retval Zero on success
1374  * @retval Non-zero on failure
1375  *
1376  */
1377 
1378 #if ! defined(PROG_DISABLE_IMAGE)
image_rla_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)1379 int image_rla_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
1380 	unsigned int f;
1381 
1382 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
1383 
1384 	if(image_rla_header((uint16_t) w, (uint16_t) h, f) != 0) return(-1);
1385 	if(image_rla_offset((uint16_t) h, f) != 0) return(-1);
1386 	if(image_rla_channs(p, w, h, f) != 0) return(-1);
1387 
1388 	(void) files_close(f);
1389 
1390 	return(0);
1391 }
1392 
image_rla_header(uint16_t w,uint16_t h,unsigned int f)1393 static int image_rla_header(uint16_t w, uint16_t h, unsigned int f) {
1394 	unsigned int i;
1395 
1396 	char *s, *k;
1397 
1398 	time_t m;
1399 
1400 	struct tm *t;
1401 	struct rla_header d;
1402 
1403 	(void) memset((void *) &d, 0, sizeof(d));
1404 
1405 	/* Revision */
1406 	d.revision = endian_be_uint16(0xfffe);
1407 
1408 	/* Dimensions */
1409 	d.window.left = endian_be_uint16(0);
1410 	d.window.right = endian_be_uint16(w - 1);
1411 	d.window.bottom = endian_be_uint16(0);
1412 	d.window.top = endian_be_uint16(h - 1);
1413 
1414 	d.active_window.left = d.window.left;
1415 	d.active_window.right = d.window.right;
1416 	d.active_window.bottom = d.window.bottom;
1417 	d.active_window.top = d.window.top;
1418 
1419 	/* Specifications */
1420 	d.frame = endian_be_uint16(1);
1421 	d.field = endian_be_uint16(0);
1422 	d.job_num = endian_be_uint32(0);
1423 
1424 	d.num_chan = endian_be_uint16(3);
1425 	d.chan_bits = endian_be_uint16(8);
1426 	d.storage_type = endian_be_uint16(0);
1427 
1428 	d.num_matte = endian_be_uint16(1);
1429 	d.matte_bits = endian_be_uint16(8);
1430 	d.matte_type = endian_be_uint16(0);
1431 
1432 	d.num_aux = endian_be_uint16(0);
1433 	d.aux_bits = endian_be_uint16(0);
1434 	d.aux_type = endian_be_uint16(0);
1435 
1436 	(void) snprintf((char *) d.chan, sizeof(d.chan), "rgb");
1437 	(void) snprintf((char *) d.gamma, sizeof(d.gamma), "%.4f", 2.2);
1438 
1439 	/* Aspect ratio */
1440 	for(i = 0; ; i++) {
1441 		if(rla_header_aspect_t[i].s == NULL) {
1442 			(void) snprintf((char *) d.aspect, sizeof(d.aspect), "%s_%u_%u", APPLICATION_EXEC, (unsigned int) w, (unsigned int) h);
1443 
1444 			break;
1445 		}
1446 
1447 		if(rla_header_aspect_t[i].w == w && rla_header_aspect_t[i].h == h) {
1448 			(void) snprintf((char *) d.aspect, sizeof(d.aspect), "%s", rla_header_aspect_t[i].s);
1449 
1450 			break;
1451 		}
1452 	}
1453 
1454 	(void) snprintf((char *) d.aspect_ratio, sizeof(d.aspect_ratio), "%.4f", (float) w / h);
1455 
1456 	/* Chromaticity */
1457 	(void) snprintf((char *) d.red_pri, sizeof(d.red_pri), "%.4f %.4f", 0.6400, 0.3300);
1458 	(void) snprintf((char *) d.green_pri, sizeof(d.green_pri), "%.4f %.4f", 0.3000, 0.6000);
1459 	(void) snprintf((char *) d.blue_pri, sizeof(d.blue_pri), "%.4f %.4f", 0.1500, 0.0600);
1460 	(void) snprintf((char *) d.white_pt, sizeof(d.white_pt), "%.4f %.4f", 0.3127, 0.3290);
1461 
1462 	/* Creator info */
1463 	if((s = files_get_name(f)) != NULL) {
1464 		if((k = strrchr((const char *) s, CONFIG_PATH_DELIM)) == NULL) k = s;
1465 		else k += sizeof(char);
1466 	}
1467 	else k = "";
1468 
1469 	(void) snprintf((char *) d.name, sizeof(d.name), "%s", k);
1470 	(void) snprintf((char *) d.program, sizeof(d.program), APPLICATION_NAME " " APPLICATION_VERSION " (" CONFIG_MACH ")");
1471 	(void) snprintf((char *) d.machine, sizeof(d.machine), "%s", node_get_node());
1472 	(void) snprintf((char *) d.user, sizeof(d.user), "%s", node_get_user());
1473 
1474 	/* Creation date and time */
1475 	if((m = time(NULL)) != (time_t) -1) {
1476 		if((t = localtime(&m)) != NULL) (void) strftime((char *) d.date, sizeof(d.date), "%b %d %H:%M %Y", t);
1477 	}
1478 
1479 	/* Offset to next image in file */
1480 	d.next = endian_be_uint32(0);
1481 
1482 	return(files_write(f, (void *) &d, sizeof(d)));
1483 }
1484 
image_rla_offset(uint16_t h,unsigned int f)1485 static int image_rla_offset(uint16_t h, unsigned int f) {
1486 	uint32_t i, a;
1487 
1488 	a = endian_be_uint32(0);
1489 
1490 	for(i = 0; i < (uint32_t) h; i++) {
1491 		if(files_write(f, (void *) &a, sizeof(a)) != 0) return(-1);
1492 	}
1493 
1494 	return(0);
1495 }
1496 
image_rla_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1497 static int image_rla_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1498 	long u, v;
1499 
1500 	int8_t c;
1501 	uint8_t a, g;
1502 	uint16_t d, b;
1503 	uint32_t i, j, t, k, n, e;
1504 
1505 	n = (uint32_t) sizeof(struct rla_header) + (sizeof(uint32_t) * h);
1506 
1507 	for(i = 0; i < (uint32_t) h; i++) {
1508 		/* Add this scanline to offset table */
1509 		e = endian_be_uint32(n);
1510 
1511 		if((u = files_tell(f)) == -1) return(-1);
1512 
1513 		if(files_seek(f, (long) sizeof(struct rla_header) + (sizeof(uint32_t) * i)) != 0) return(-1);
1514 		if(files_write(f, (void *) &e, sizeof(e)) != 0) return(-1);
1515 		if(files_seek(f, u) != 0) return(-1);
1516 
1517 		k = (uint32_t) i * w;
1518 
1519 		/* RLA style RLE compression */
1520 		for(t = 0; t < 4; t++) {
1521 			d = 0;
1522 
1523 			if((v = files_tell(f)) == -1) return(-1);
1524 			if(files_write(f, (void *) &d, sizeof(d)) != 0) return(-1);
1525 
1526 			c = 0;
1527 
1528 			switch(t) {
1529 				case 0:
1530 					a = p[k].pixel.r;
1531 
1532 					break;
1533 				case 1:
1534 					a = p[k].pixel.g;
1535 
1536 					break;
1537 				case 2:
1538 					a = p[k].pixel.b;
1539 
1540 					break;
1541 				default:
1542 					a = p[k].pixel.a;
1543 
1544 					break;
1545 			}
1546 
1547 			for(j = 0; j < (uint32_t) w; j++) {
1548 				switch(t) {
1549 					case 0:
1550 						g = p[k + j].pixel.r;
1551 
1552 						break;
1553 					case 1:
1554 						g = p[k + j].pixel.g;
1555 
1556 						break;
1557 					case 2:
1558 						g = p[k + j].pixel.b;
1559 
1560 						break;
1561 					default:
1562 						g = p[k + j].pixel.a;
1563 
1564 						break;
1565 				}
1566 
1567 				if(c < 126 && (a == g)) ++c;
1568 				else {
1569 					d += (uint16_t) image_rla_channs_op(c, a, f);
1570 
1571 					c = 1;
1572 					a = g;
1573 				}
1574 			}
1575 
1576 			if(c > 0) d += (uint16_t) image_rla_channs_op(c, a, f);
1577 
1578 			n += (uint32_t) d;
1579 			n += (uint32_t) sizeof(d);
1580 
1581 			b = endian_be_uint16(d);
1582 
1583 			if((u = files_tell(f)) == -1) return(-1);
1584 
1585 			if(files_seek(f, v) != 0) return(-1);
1586 			if(files_write(f, (void *) &b, sizeof(b)) != 0) return(-1);
1587 			if(files_seek(f, u) != 0) return(-1);
1588 		}
1589 	}
1590 
1591 	return(0);
1592 }
1593 
image_rla_channs_op(int8_t c,uint8_t a,unsigned int f)1594 static size_t image_rla_channs_op(int8_t c, uint8_t a, unsigned int f) {
1595 	unsigned int i;
1596 
1597 	int8_t n;
1598 
1599 	size_t r;
1600 
1601 	r = 0;
1602 
1603 	if(c < 3) {
1604 		n = -(c);
1605 
1606 		if(files_write(f, (void *) &n, sizeof(n)) != 0) return(r);
1607 
1608 		r += sizeof(n);
1609 
1610 		for(i = 0; i < (unsigned int) c; i++) {
1611 			if(files_write(f, (void *) &a, sizeof(a)) != 0) return(r);
1612 
1613 			r += sizeof(a);
1614 		}
1615 	}
1616 	else {
1617 		n = c - 1;
1618 
1619 		if(files_write(f, (void *) &n, sizeof(n)) != 0) return(r);
1620 
1621 		r += sizeof(n);
1622 
1623 		if(files_write(f, (void *) &a, sizeof(a)) != 0) return(r);
1624 
1625 		r += sizeof(a);
1626 	}
1627 
1628 	return(r);
1629 }
1630 #endif
1631 
1632 /**
1633  * @brief Write Truevision TGA image using 32 bits (RGBA) per pixel.
1634  *
1635  * @param[in] p Image pixel data
1636  * @param[in] w Image width in pixels
1637  * @param[in] h Image height in pixels
1638  * @param[in] s File name to write
1639  *
1640  * @retval Zero on success
1641  * @retval Non-zero on failure
1642  *
1643  */
1644 
1645 #if ! defined(PROG_DISABLE_IMAGE)
image_tga_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s)1646 int image_tga_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s) {
1647 	unsigned int f;
1648 
1649 	uint32_t a;
1650 
1651 	time_t v;
1652 
1653 	v = time(NULL);
1654 	a = (uint32_t) sizeof(struct tga_header) + ((w * h) * sizeof(struct pixel_rgba_8));
1655 
1656 	if((f = files_open(s, FILE_FLAG_NOCOMPRESS, FILE_MODE_WRITE_AND_TRUNCATE)) == 0) return(-1);
1657 
1658 	if(image_tga_write_header(IMAGE_TGA_STORAGE_VERBATIM, (uint16_t) w, (uint16_t) h, 32, f) != 0) return(-1);
1659 	if(image_tga_write_channs(p, w, h, f) != 0) return(-1);
1660 	if(image_tga_write_extens(w, h, v, time(NULL), f) != 0) return(-1);
1661 	if(image_tga_write_footer(a, f) != 0) return(-1);
1662 
1663 	(void) files_close(f);
1664 
1665 	return(0);
1666 }
1667 
image_tga_write_header(uint8_t t,uint16_t w,uint16_t h,uint8_t b,unsigned int f)1668 static int image_tga_write_header(uint8_t t, uint16_t w, uint16_t h, uint8_t b, unsigned int f) {
1669 	struct tga_header d;
1670 
1671 	d.d = endian_le_uint8(0);
1672 	d.m = endian_le_uint8(0);
1673 	d.t = endian_le_uint8(t);
1674 
1675 	d.c.o = endian_le_uint16(0);
1676 	d.c.n = endian_le_uint16(0);
1677 	d.c.b = endian_le_uint8(0);
1678 
1679 	/* Dimensions */
1680 	d.i.x = endian_le_int16(0);
1681 	d.i.y = endian_le_int16(0);
1682 	d.i.w = endian_le_uint16(w);
1683 	d.i.h = endian_le_uint16(h);
1684 	d.i.b = endian_le_uint8(b);
1685 
1686 	/* Attribute bits */
1687 	d.i.a = endian_le_uint8(0);
1688 
1689 	(void) image_tga_write_header_aux(3, &d.i.a);
1690 	(void) image_tga_write_header_ltr(0, &d.i.a);
1691 	(void) image_tga_write_header_ttb(0, &d.i.a);
1692 
1693 	return(files_write(f, (void *) &d, sizeof(d)));
1694 }
1695 
image_tga_write_header_aux(uint8_t a,uint8_t * d)1696 static void image_tga_write_header_aux(uint8_t a, uint8_t *d) {
1697 	*d &= 0xf0;
1698 	*d |= (1 << a);
1699 }
1700 
image_tga_write_header_ltr(uint8_t a,uint8_t * d)1701 static void image_tga_write_header_ltr(uint8_t a, uint8_t *d) {
1702 	*d &= 0xef;
1703 	*d |= (a << 4);
1704 }
1705 
image_tga_write_header_ttb(uint8_t a,uint8_t * d)1706 static void image_tga_write_header_ttb(uint8_t a, uint8_t *d) {
1707 	*d &= 0xdf;
1708 	*d |= (a << 5);
1709 }
1710 
image_tga_write_channs(struct pixel_rgba_8 * p,uint16_t w,uint16_t h,unsigned int f)1711 static int image_tga_write_channs(struct pixel_rgba_8 *p, uint16_t w, uint16_t h, unsigned int f) {
1712 	uint32_t i, j, k, l;
1713 
1714 	struct pixel_bgra_8 a;
1715 
1716 	/* Swap alpha byte position and turn image upside down */
1717 	for(i = (uint32_t) h; i != 0; i--) {
1718 		k = (i - 1) * w;
1719 
1720 		for(j = 0; j < (uint32_t) w; j++) {
1721 			l = k + j;
1722 #if defined(IS_BIGENDIAN)
1723 			a.pixel.b = p[l].pixel.b;
1724 			a.pixel.g = p[l].pixel.g;
1725 			a.pixel.r = p[l].pixel.r;
1726 			a.pixel.a = p[l].pixel.a;
1727 #else
1728 			a.pixel.b = p[l].pixel.a;
1729 			a.pixel.g = p[l].pixel.r;
1730 			a.pixel.r = p[l].pixel.g;
1731 			a.pixel.a = p[l].pixel.b;
1732 #endif
1733 			if(files_write(f, (void *) &a.pixel.p, sizeof(a.pixel.p)) != 0) return(-1);
1734 		}
1735 	}
1736 
1737 	return(0);
1738 }
1739 
image_tga_write_footer(uint32_t a,unsigned int f)1740 static int image_tga_write_footer(uint32_t a, unsigned int f) {
1741 	struct tga_footer d;
1742 
1743 	(void) memset((void *) &d, 0, sizeof(a));
1744 
1745 	d.a = endian_le_uint32(a);
1746 	d.b = endian_le_uint32(0);
1747 
1748 	(void) snprintf((char *) d.s, sizeof(d.s), IMAGE_TGA_FOOTER_SIGNATURE);
1749 
1750 	return(files_write(f, (void *) &d, sizeof(d)));
1751 }
1752 
image_tga_write_extens(uint16_t w,uint16_t h,time_t v,time_t u,unsigned int f)1753 static int image_tga_write_extens(uint16_t w, uint16_t h, time_t v, time_t u, unsigned int f) {
1754 	char *s, *k;
1755 
1756 	time_t m;
1757 
1758 	struct tm *t;
1759 	struct tga_extens d;
1760 
1761 	(void) memset((void *) &d, 0, sizeof(d));
1762 
1763 	d.t = endian_le_uint16((uint16_t) sizeof(struct tga_extens));
1764 
1765 	/* Author name */
1766 	(void) snprintf((char *) d.n, sizeof(d.n), "%s", node_get_user());
1767 
1768 	/* Creation date */
1769 	d.e.m = endian_le_uint16(0);
1770 	d.e.d = endian_le_uint16(0);
1771 	d.e.y = endian_le_uint16(0);
1772 	d.e.h = endian_le_uint16(0);
1773 	d.e.i = endian_le_uint16(0);
1774 	d.e.s = endian_le_uint16(0);
1775 
1776 	if((m = time(NULL)) != (time_t) -1) {
1777 		if((t = localtime(&m)) != NULL) {
1778 			d.e.m = endian_le_uint16((uint16_t) t->tm_mon + 1);
1779 			d.e.d = endian_le_uint16((uint16_t) t->tm_mday);
1780 			d.e.y = endian_le_uint16((uint16_t) t->tm_year + 1900);
1781 			d.e.h = endian_le_uint16((uint16_t) t->tm_hour);
1782 			d.e.i = endian_le_uint16((uint16_t) t->tm_min);
1783 			d.e.s = endian_le_uint16((uint16_t) t->tm_sec);
1784 		}
1785 	}
1786 
1787 	/* Job name and time */
1788 	if((s = files_get_name(f)) != NULL) {
1789 		if((k = strrchr((const char *) s, CONFIG_PATH_DELIM)) == NULL) k = s;
1790 		else k += sizeof(char);
1791 	}
1792 	else k = "";
1793 
1794 	(void) snprintf((char *) d.d, sizeof(d.d), "%s", k);
1795 
1796 	(void) image_tga_write_extens_time(&d, v, u);
1797 
1798 	/* Software id and version */
1799 	(void) snprintf((char *) d.s, sizeof(d.s), APPLICATION_NAME " " APPLICATION_VERSION);
1800 
1801 	d.v.v = endian_le_uint16(0);
1802 	d.v.w = ' ';
1803 
1804 	/* Key color */
1805 	d.k = endian_le_uint32(0);
1806 
1807 	/* Pixel aspect ratio and gamma value */
1808 	(void) image_tga_write_extens_aspect(&d, w, h);
1809 
1810 	/* Offsets */
1811 	d.x = endian_le_uint32(0);
1812 	d.y = endian_le_uint32(0);
1813 	d.l = endian_le_uint32(0);
1814 
1815 	/* Attributes type */
1816 	d.a = endian_le_uint8(3);
1817 
1818 	return(files_write(f, (void *) &d, sizeof(d)));
1819 }
1820 
image_tga_write_extens_aspect(struct tga_extens * d,uint16_t w,uint16_t h)1821 static void image_tga_write_extens_aspect(struct tga_extens *d, uint16_t w, uint16_t h) {
1822 	double r;
1823 
1824 	r = maths_hcf((double) w, (double) h);
1825 
1826 	d->p.n = endian_le_uint16((uint16_t) round((double) w / r));
1827 	d->p.d = endian_le_uint16((uint16_t) round((double) h / r));
1828 
1829 	d->g.n = endian_le_uint16(2);
1830 	d->g.d = endian_le_uint16(2);
1831 }
1832 
image_tga_write_extens_time(struct tga_extens * d,time_t v,time_t u)1833 static void image_tga_write_extens_time(struct tga_extens *d, time_t v, time_t u) {
1834 	time_t t, h;
1835 
1836 	if(v == (time_t) -1 || u == (time_t) -1) {
1837 		d->f.h = endian_le_uint16(0);
1838 		d->f.i = endian_le_uint16(0);
1839 		d->f.s = endian_le_uint16(0);
1840 
1841 		return;
1842 	}
1843 
1844 	t = u - v;
1845 	h = t / (60 * 60);
1846 
1847 	if(h > 65535) h = 65535;
1848 
1849 	d->f.h = endian_le_uint16((uint16_t) h);
1850 	d->f.i = endian_le_uint16((uint16_t) (t % (60 * 60)) / 60);
1851 	d->f.s = endian_le_uint16((uint16_t) t % 60);
1852 }
1853 #endif
1854 
1855 /**
1856  * @brief Write image by format.
1857  *
1858  * @param[in] p Image pixel data
1859  * @param[in] w Image width in pixels
1860  * @param[in] h Image height in pixels
1861  * @param[in] s File name to write
1862  * @param[in] c File format to write (IMAGE_FORMAT_*)
1863  *
1864  * @retval Zero on success
1865  * @retval Non-zero on failure
1866  *
1867  */
1868 
1869 #if ! defined(PROG_DISABLE_IMAGE)
image_write_32(struct pixel_rgba_8 * p,unsigned int w,unsigned int h,char * s,int c)1870 int image_write_32(struct pixel_rgba_8 *p, unsigned int w, unsigned int h, char *s, int c) {
1871 	switch(c) {
1872 		case IMAGE_FORMAT_BMP:
1873 			return(image_bmp_write_32(p, w, h, s));
1874 		case IMAGE_FORMAT_CEL:
1875 			return(image_cel_write_32(p, w, h, s));
1876 		case IMAGE_FORMAT_PIX:
1877 			return(image_pix_write_32(p, w, h, s));
1878 		case IMAGE_FORMAT_PPM:
1879 			return(image_ppm_write_32(p, w, h, s));
1880 		case IMAGE_FORMAT_RAS:
1881 			return(image_ras_write_32(p, w, h, s));
1882 		case IMAGE_FORMAT_RGB:
1883 			return(image_rgb_write_32(p, w, h, s));
1884 		case IMAGE_FORMAT_RLA:
1885 			return(image_rla_write_32(p, w, h, s));
1886 		case IMAGE_FORMAT_TGA:
1887 			return(image_tga_write_32(p, w, h, s));
1888 		default:
1889 			(void) flush_error();
1890 
1891 			LOGWARN(
1892 				ERROR_SLIGHT, SUBSYSTEM,
1893 				_("Image type %d is not supported"),
1894 				c
1895 			);
1896 
1897 			break;
1898 	}
1899 
1900 	return(-1);
1901 }
1902 #endif
1903 
1904 /**
1905  * @brief Get image file name suffix by IMAGE_FORMAT_* tag.
1906  *
1907  * @param[in] c File format (IMAGE_FORMAT_*)
1908  *
1909  * @retval Image file name suffix
1910  *
1911  */
1912 
1913 #if ! defined(PROG_DISABLE_IMAGE)
image_get_suffix_by_type(int c)1914 const char *image_get_suffix_by_type(int c) {
1915 	return(img_suffix[c]);
1916 }
1917 #endif
1918 
image_get_type_by_suffix(char * s)1919 static int image_get_type_by_suffix(char *s) {
1920 	int i;
1921 
1922 	size_t t;
1923 
1924 	if(s == NULL) return(IMAGE_FORMAT_NONE);
1925 
1926 	t = str_len(s, STRING_ASCII);
1927 
1928 	for(i = 1; ; i++) {
1929 		if(img_suffix[i] == NULL) break;
1930 		if(str_len(img_suffix[i], STRING_ASCII) != t) continue;
1931 		if(strncasecmp((const char *) img_suffix[i], (const char *) s, t) == 0) return(i);
1932 	}
1933 
1934 	return(IMAGE_FORMAT_NONE);
1935 }
1936