]> git.imager.perl.org - imager.git/blob - compose.im
gradgen allocated sizeof(i_color *) per entry rather than sizeof(i_color)
[imager.git] / compose.im
1 #include "imager.h"
2 #include "imrender.h"
3 #include "imageri.h"
4
5 int
6 i_compose_mask(i_img *out, i_img *src, i_img *mask, 
7                i_img_dim out_left, i_img_dim out_top,
8                i_img_dim src_left, i_img_dim src_top,
9                i_img_dim mask_left, i_img_dim mask_top,
10                i_img_dim width, i_img_dim height,
11                int combine,
12                double opacity) {
13   i_render r;
14   i_img_dim dy;
15   i_fill_combine_f combinef_8;
16   i_fill_combinef_f combinef_double;
17   int channel_zero = 0;
18
19   mm_log((1, "i_compose_mask(out %p, src %p, mask %p, out(" i_DFp "), "
20           "src(" i_DFp "), mask(" i_DFp "), size(" i_DFp "),"
21           " combine %d opacity %f\n", out, src, 
22           mask, i_DFcp(out_left, out_top), i_DFcp(src_left, src_top),
23           i_DFcp(mask_left, mask_top), i_DFcp(width, height),
24           combine, opacity));
25
26   i_clear_error();
27   if (out_left >= out->xsize
28       || out_top >= out->ysize
29       || src_left >= src->xsize
30       || src_top >= src->ysize
31       || width <= 0
32       || height <= 0
33       || out_left + width <= 0
34       || out_top + height <= 0
35       || src_left + width <= 0
36       || src_top + height <= 0
37       || mask_left >= mask->xsize
38       || mask_top >= mask->ysize
39       || mask_left + width <= 0
40       || mask_top + height <= 0)
41     return 0;
42
43   if (out_left < 0) {
44     width = out_left + width;
45     src_left -= out_left;
46     mask_left -= out_left;
47     out_left = 0;
48   }
49   if (out_left + width > out->xsize)
50     width = out->xsize - out_left;
51
52   if (out_top < 0) {
53     height = out_top + height;
54     mask_top -= out_top;
55     src_top -= out_top;
56     out_top = 0;
57   }
58   if (out_top + height > out->ysize)
59     height = out->ysize - out_top;
60
61   if (src_left < 0) {
62     width = src_left + width;
63     out_left -= src_left;
64     mask_left -= src_left;
65     src_left = 0;
66   }
67   if (src_left + width > src->xsize)
68     width = src->xsize - src_left;
69
70   if (src_top < 0) {
71     height = src_top + height;
72     out_top -= src_top;
73     mask_top -= src_top;
74     src_top = 0;
75   }
76   if (src_top + height > src->ysize)
77     height = src->ysize - src_top;
78
79   if (mask_left < 0) {
80     width = mask_left + width;
81     out_left -= mask_left;
82     src_left -= mask_left;
83     mask_left = 0;
84   }
85   if (mask_left + width > mask->xsize)
86     width = mask->xsize - mask_left;
87   
88   if (mask_top < 0) {
89     height = mask_top + height;
90     src_top -= mask_top;
91     out_top -= mask_top;
92     mask_top = 0;
93   }
94   if (mask_top + height > mask->ysize)
95     height = mask->ysize - mask_top;
96
97   if (opacity > 1.0)
98     opacity = 1.0;
99   else if (opacity <= 0) {
100     i_push_error(0, "opacity must be positive");
101     return 0;
102   }
103
104   mm_log((1, "after adjustments: (out(" i_DFp "), src(" i_DFp "),"
105           " mask(" i_DFp "), size(" i_DFp ")\n", 
106           i_DFcp(out_left, out_top), i_DFcp(src_left, src_top),
107           i_DFcp(mask_left, mask_top), i_DFcp(width, height)));
108
109   i_get_combine(combine, &combinef_8, &combinef_double);
110
111   i_render_init(&r, out, width);
112 #code out->bits <= 8 && src->bits<= 8 && mask->bits <= 8
113   IM_COLOR *src_line = mymalloc(sizeof(IM_COLOR) * width);
114   IM_SAMPLE_T *mask_line = mymalloc(sizeof(IM_SAMPLE_T) * width);
115   int adapt_channels = out->channels;
116
117   if (adapt_channels == 1 || adapt_channels == 3)
118     ++adapt_channels;
119
120   for (dy = 0; dy < height; ++dy) {
121     IM_GLIN(src, src_left, src_left + width, src_top + dy, src_line);
122     IM_ADAPT_COLORS(adapt_channels, src->channels, src_line, width);
123     IM_GSAMP(mask, mask_left, mask_left + width, mask_top + dy, 
124              mask_line, &channel_zero, 1);
125     if (opacity < 1.0) {
126       i_img_dim i;
127       IM_SAMPLE_T *maskp = mask_line;
128       for (i = 0; i < width; ++i) {
129         *maskp = IM_ROUND(*maskp * opacity);
130         ++maskp;
131       }
132     }
133     IM_RENDER_LINE(&r, out_left, out_top+dy, width, mask_line, src_line,
134                    IM_SUFFIX(combinef));
135   }
136   myfree(src_line);
137   myfree(mask_line);
138   
139 #/code
140   i_render_done(&r);
141
142   return 1;
143 }
144
145 int
146 i_compose(i_img *out, i_img *src,
147           i_img_dim out_left, i_img_dim out_top,
148           i_img_dim src_left, i_img_dim src_top,
149           i_img_dim width, i_img_dim height,
150           int combine,
151           double opacity) {
152   i_render r;
153   i_img_dim dy;
154   i_fill_combine_f combinef_8;
155   i_fill_combinef_f combinef_double;
156
157   mm_log((1, "i_compose(out %p, src %p, out(" i_DFp "), src(" i_DFp "), "
158           "size(" i_DFp "), combine %d opacity %f\n", out, src,
159           i_DFcp(out_left, out_top), i_DFcp(src_left, src_top),
160           i_DFcp(width, height), combine, opacity));
161
162   i_clear_error();
163   if (out_left >= out->xsize
164       || out_top >= out->ysize
165       || src_left >= src->xsize
166       || src_top >= src->ysize
167       || width <= 0
168       || height <= 0
169       || out_left + width <= 0
170       || out_top + height <= 0
171       || src_left + width <= 0
172       || src_top + height <= 0)
173     return 0;
174
175   if (out_left < 0) {
176     width = out_left + width;
177     src_left -= out_left;
178     out_left = 0;
179   }
180   if (out_left + width > out->xsize)
181     width = out->xsize - out_left;
182
183   if (out_top < 0) {
184     height = out_top + height;
185     src_top -= out_top;
186     out_top = 0;
187   }
188   if (out_top + height > out->ysize)
189     height = out->ysize - out_top;
190
191   if (src_left < 0) {
192     width = src_left + width;
193     out_left -= src_left;
194     src_left = 0;
195   }
196   if (src_left + width > src->xsize)
197     width = src->xsize - src_left;
198
199   if (src_top < 0) {
200     height = src_top + height;
201     out_top -= src_top;
202     src_top = 0;
203   }
204   if (src_top + height > src->ysize)
205     height = src->ysize - src_top;
206
207   if (opacity > 1.0)
208     opacity = 1.0;
209   else if (opacity <= 0) {
210     i_push_error(0, "opacity must be positive");
211     return 0;
212   }
213
214   i_get_combine(combine, &combinef_8, &combinef_double);
215
216   i_render_init(&r, out, width);
217 #code out->bits <= 8 && src->bits <= 8
218   IM_COLOR *src_line = mymalloc(sizeof(IM_COLOR) * width);
219   IM_SAMPLE_T *mask_line = NULL;
220   int adapt_channels = out->channels;
221
222   if (opacity != 1.0) {
223     i_img_dim i;
224     IM_SAMPLE_T mask_value = IM_ROUND(opacity * IM_SAMPLE_MAX);
225     mask_line = mymalloc(sizeof(IM_SAMPLE_T) * width);
226
227     for (i = 0; i < width; ++i)
228       mask_line[i] = mask_value;
229   }
230
231   if (adapt_channels == 1 || adapt_channels == 3)
232     ++adapt_channels;
233
234   for (dy = 0; dy < height; ++dy) {
235     IM_GLIN(src, src_left, src_left + width, src_top + dy, src_line);
236     IM_ADAPT_COLORS(adapt_channels, src->channels, src_line, width);
237     IM_RENDER_LINE(&r, out_left, out_top+dy, width, mask_line, src_line,
238                    IM_SUFFIX(combinef));
239   }
240   myfree(src_line);
241   if (mask_line)
242     myfree(mask_line);
243   
244 #/code
245   i_render_done(&r);
246
247   return 1;
248 }