]> git.imager.perl.org - imager.git/blob - render.im
Extra ways of calling translate(), shear()
[imager.git] / render.im
1 /*
2 Render utilities
3 */
4 #include "imager.h"
5
6 #define RENDER_MAGIC 0x765AE
7
8 typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
9
10 #code
11
12 static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
13 static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
14
15 static 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
26 void
27 i_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
38 void
39 i_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
47 void
48 i_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
93 static void
94 dump_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
105 static
106 void
107 IM_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
152 static
153 void
154 IM_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 = IM_SAMPLE_MAX - 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