Various changes:
[imager.git] / render.im
CommitLineData
9c106321
TC
1/*
2Render utilities
3*/
4#include "imager.h"
5
6#define RENDER_MAGIC 0x765AE
7
8typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
9
10#code
11
12static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
13static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
14
15static render_color_f IM_SUFFIX(render_color_tab)[] =
16 {
17 NULL,
18 IM_SUFFIX(render_color_13),
19 IM_SUFFIX(render_color_alpha),
20 IM_SUFFIX(render_color_13),
21 IM_SUFFIX(render_color_alpha),
22 };
23
24#/code
25
26void
27i_render_init(i_render *r, i_img *im, int width) {
28 r->magic = RENDER_MAGIC;
29 r->im = im;
30 r->width = width;
31 r->line_8 = NULL;
32 r->line_double = NULL;
33#code im->bits <= 8
34 r->IM_SUFFIX(line) = mymalloc(sizeof(i_fcolor) * width);
35#/code
36}
37
38void
39i_render_done(i_render *r) {
40 if (r->line_8)
41 myfree(r->line_8);
42 else
43 myfree(r->line_double);
44 r->magic = 0;
45}
46
47void
48i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
49 i_color const *color) {
50 i_img *im = r->im;
51 if (y < 0 || y >= im->ysize)
52 return;
53 if (x < 0) {
54 width += x;
55 src -= x;
56 x = 0;
57 }
58 if (x + width > im->xsize) {
59 width = im->xsize - x;
60 }
61 if (x >= im->xsize || x + width <= 0 || width <= 0)
62 return;
63
64 /* avoid as much work as we can */
65 while (width > 0 && *src == 0) {
66 --width;
67 ++src;
68 ++x;
69 }
70 while (width > 0 && src[width-1] == 0) {
71 --width;
72 }
73 if (!width)
74 return;
75
76 /* make sure our line buffer is big enough */
77 if (width > r->width) {
78 int new_width = r->width * 2;
79 if (new_width < width)
80 new_width = width;
81
82 if (r->line_8)
83 r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
84 else
85 r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
86 }
87
88#code r->im->bits <= 8
89 (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color);
90#/code
91}
92
93static void
94dump_src(const char *note, unsigned char const *src, int width) {
95 int i;
96 printf("%s - %p/%d\n", note, src, width);
97 for (i = 0; i < width; ++i) {
98 printf("%02x ", src[i]);
99 }
100 putchar('\n');
101}
102
103#code
104
105static
106void
107IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
108 unsigned char const *src, i_color const *color) {
109 i_img *im = r->im;
110 IM_COLOR *linep = r->IM_SUFFIX(line);
111 int ch, channels = im->channels;
112 int fetch_offset;
113#undef STORE_COLOR
114#ifdef IM_EIGHT_BIT
115#define STORE_COLOR (*color)
116#else
117 i_fcolor fcolor;
118
119 for (ch = 0; ch < channels; ++ch) {
120 fcolor.channel[ch] = color->channel[ch] / 255.0;
121 }
122#define STORE_COLOR fcolor
123#endif
124
125 fetch_offset = 0;
126 while (fetch_offset < width && *src == 0xFF) {
127 *linep++ = STORE_COLOR;
128 ++src;
129 ++fetch_offset;
130 }
131 IM_GLIN(im, x+fetch_offset, x+width, y, linep);
132 while (fetch_offset < width) {
133#ifdef IM_EIGHT_BIT
134 IM_WORK_T alpha = *src++;
135#else
136 IM_WORK_T alpha = *src++ / 255.0;
137#endif
138 if (alpha == IM_SAMPLE_MAX)
139 *linep = STORE_COLOR;
140 else if (alpha) {
141 for (ch = 0; ch < channels; ++ch) {
142 linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha)
143 + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX;
144 }
145 }
146 ++linep;
147 ++fetch_offset;
148 }
149 IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
150}
151
152static
153void
154IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
155 unsigned char const *src, i_color const *color) {
156 IM_COLOR *linep = r->IM_SUFFIX(line);
157 int ch;
158 int alpha_channel = r->im->channels - 1;
159 int fetch_offset;
160#undef STORE_COLOR
161#ifdef IM_EIGHT_BIT
162#define STORE_COLOR (*color)
163#else
164 i_fcolor fcolor;
165
166 for (ch = 0; ch < r->im->channels; ++ch) {
167 fcolor.channel[ch] = color->channel[ch] / 255.0;
168 }
169#define STORE_COLOR fcolor
170#endif
171
172 fetch_offset = 0;
173 while (fetch_offset < width && *src == 0xFF) {
174 *linep++ = STORE_COLOR;
175 ++src;
176 ++fetch_offset;
177 }
178 IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
179 while (fetch_offset < width) {
180#ifdef IM_EIGHT_BIT
181 IM_WORK_T src_alpha = *src++;
182#else
183 IM_WORK_T src_alpha = *src++ / 255.0;
184#endif
185 if (src_alpha == IM_SAMPLE_MAX)
186 *linep = STORE_COLOR;
187 else if (src_alpha) {
188 IM_WORK_T remains = - src_alpha;
189 IM_WORK_T orig_alpha = linep->channel[alpha_channel];
190 IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
191 for (ch = 0; ch < alpha_channel; ++ch) {
192 linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch]
193 + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX
194 ) / dest_alpha;
195 }
196 linep->channel[alpha_channel] = dest_alpha;
197 }
198 ++linep;
199 ++fetch_offset;
200 }
201 IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
202}
203
204#/code