summaryrefslogtreecommitdiffstats
path: root/lib/gui/bmp.c
blob: 6bf8cd000fde38b0ad2e77edb429c8db08af5339 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <fb.h>
#include "bmp_layout.h"
#include <asm/byteorder.h>
#include <gui/graphic_utils.h>
#include <init.h>
#include <gui/image_renderer.h>

struct image *bmp_open(char *inbuf, int insize)
{
	struct image *img = calloc(1, sizeof(struct image));
	struct bmp_image *bmp = (struct bmp_image*)inbuf;

	if (!img) {
		free(bmp);
		return ERR_PTR(-ENOMEM);
	}

	img->data = inbuf;
	img->height = le32_to_cpu(bmp->header.height);;
	img->width = le32_to_cpu(bmp->header.width);;
	img->bits_per_pixel = le16_to_cpu(bmp->header.bit_count);

	pr_debug("bmp: %d x %d  x %d data@0x%p\n", img->width, img->height,
		 img->bits_per_pixel, img->data);

	return img;
}

void bmp_close(struct image *img)
{
	free(img->data);
}

static int bmp_renderer(struct screen *sc, struct surface *s, struct image *img)
{
	struct bmp_image *bmp = img->data;
	int bits_per_pixel;
	void *adr, *buf;
	char *image;
	int width = s->width;
	int height = s->height;
	int startx = s->x;
	int starty = s->y;

	if (s->width < 0)
		width = img->width;

	if (s->height < 0)
		height = img->height;

	if (startx < 0) {
		startx = (sc->s.width - width) / 2;
		if (startx < 0)
			startx = 0;
	}

	if (starty < 0) {
		starty = (sc->s.height - height) / 2;
		if (starty < 0)
			starty = 0;
	}

	width = min(width, sc->s.width - startx);
	height = min(height, sc->s.height - starty);

	buf = gui_screen_redering_buffer(sc);

	bits_per_pixel = img->bits_per_pixel;

	if (bits_per_pixel == 8) {
		int x, y;
		struct bmp_color_table_entry *color_table = bmp->color_table;

		for (y = 0; y < height; y++) {
			image = (char *)bmp +
					le32_to_cpu(bmp->header.data_offset);
			image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
			adr = buf + ((y + starty) * sc->s.width + startx) *
					(sc->info.bits_per_pixel >> 3);
			for (x = 0; x < width; x++) {
				int pixel;

				pixel = *image;

				set_rgb_pixel(&sc->info, adr, color_table[pixel].red,
						color_table[pixel].green,
						color_table[pixel].blue);
				adr += sc->info.bits_per_pixel >> 3;

				image += bits_per_pixel >> 3;
			}
		}
	} else if (bits_per_pixel == 24) {
		int x, y;

		for (y = 0; y < height; y++) {
			image = (char *)bmp +
					le32_to_cpu(bmp->header.data_offset);
			image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
			adr = buf + ((y + starty) * sc->s.width + startx) *
					(sc->info.bits_per_pixel >> 3);
			for (x = 0; x < width; x++) {
				char *pixel;

				pixel = image;

				set_rgb_pixel(&sc->info, adr, pixel[2], pixel[1],
						pixel[0]);
				adr += sc->info.bits_per_pixel >> 3;

				image += bits_per_pixel >> 3;
			}
		}
	} else
		printf("bmp: illegal bits per pixel value: %d\n", bits_per_pixel);

	return img->height;
}

static struct image_renderer bmp = {
	.type = filetype_bmp,
	.open = bmp_open,
	.close = bmp_close,
	.renderer = bmp_renderer,
	.keep_file_data = 1,
};

static int bmp_init(void)
{
	return image_renderer_register(&bmp);
}
fs_initcall(bmp_init);