Commit | Line | Data |
---|---|---|
9b1ec2b8 TC |
1 | #include "imager.h" |
2 | ||
3 | /* | |
4 | =item i_copyto(dest, src, x1, y1, x2, y2, tx, ty) | |
5 | ||
6 | =category Image | |
7 | ||
8 | Copies image data from the area (x1,y1)-[x2,y2] in the source image to | |
9 | a rectangle the same size with it's top-left corner at (tx,ty) in the | |
10 | destination image. | |
11 | ||
12 | If x1 > x2 or y1 > y2 then the corresponding co-ordinates are swapped. | |
13 | ||
14 | =cut | |
15 | */ | |
16 | ||
17 | void | |
18 | i_copyto(i_img *im, i_img *src, int x1, int y1, int x2, int y2, int tx, int ty) { | |
a827f5b4 | 19 | int y, t, ttx, tty; |
9b1ec2b8 TC |
20 | |
21 | if (x2<x1) { t=x1; x1=x2; x2=t; } | |
22 | if (y2<y1) { t=y1; y1=y2; y2=t; } | |
23 | if (tx < 0) { | |
24 | /* adjust everything equally */ | |
25 | x1 += -tx; | |
26 | x2 += -tx; | |
27 | tx = 0; | |
28 | } | |
29 | if (ty < 0) { | |
30 | y1 += -ty; | |
31 | y2 += -ty; | |
32 | ty = 0; | |
33 | } | |
34 | if (x1 >= src->xsize || y1 >= src->ysize) | |
35 | return; /* nothing to do */ | |
36 | if (x2 > src->xsize) | |
37 | x2 = src->xsize; | |
38 | if (y2 > src->ysize) | |
39 | y2 = src->ysize; | |
40 | if (x1 == x2 || y1 == y2) | |
41 | return; /* nothing to do */ | |
42 | ||
43 | mm_log((1,"i_copyto(im* %p, src %p, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n", | |
44 | im, src, x1, y1, x2, y2, tx, ty)); | |
45 | ||
46 | #code im->bits == i_8_bits | |
47 | IM_COLOR *row = mymalloc(sizeof(IM_COLOR) * (x2-x1)); | |
48 | tty = ty; | |
49 | for(y=y1; y<y2; y++) { | |
50 | ttx = tx; | |
51 | IM_GLIN(src, x1, x2, y, row); | |
52 | if (src->channels != im->channels) | |
53 | IM_ADAPT_COLORS(im->channels, src->channels, row, x2-x1); | |
54 | IM_PLIN(im, tx, tx+x2-x1, tty, row); | |
55 | tty++; | |
56 | } | |
57 | myfree(row); | |
58 | #/code | |
59 | } | |
60 | ||
61 | #define color_to_grey(col) ((col)->rgb.r * 0.222 + (col)->rgb.g * 0.707 + (col)->rgb.b * 0.071) | |
62 | ||
63 | #code | |
64 | void | |
65 | #ifdef IM_EIGHT_BIT | |
66 | i_adapt_colors | |
67 | #else | |
68 | i_adapt_fcolors | |
69 | #endif | |
70 | (int out_channels, int in_channels, IM_COLOR *colors, | |
71 | size_t count) { | |
9b1ec2b8 TC |
72 | if (out_channels == in_channels) |
73 | return; | |
74 | if (count == 0) | |
75 | return; | |
76 | ||
77 | switch (out_channels) { | |
78 | case 1: | |
79 | { | |
80 | switch (in_channels) { | |
81 | case 2: | |
82 | /* apply alpha against a black background */ | |
83 | while (count) { | |
84 | colors->channel[0] = colors->channel[0] * colors->channel[1] / IM_SAMPLE_MAX; | |
85 | ++colors; | |
86 | --count; | |
87 | } | |
88 | return; | |
89 | ||
90 | case 3: | |
91 | /* convert to grey */ | |
92 | while (count) { | |
93 | colors->channel[0] = IM_ROUND(color_to_grey(colors)); | |
94 | ++colors; | |
95 | --count; | |
96 | } | |
97 | return; | |
98 | ||
99 | case 4: | |
100 | while (count) { | |
101 | colors->channel[0] = IM_ROUND(color_to_grey(colors) * colors->channel[3] / IM_SAMPLE_MAX); | |
102 | ++colors; | |
103 | --count; | |
104 | } | |
105 | return; | |
106 | ||
107 | default: | |
108 | i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); | |
109 | return; /* avoid warnings */ | |
110 | } | |
111 | } | |
112 | ||
113 | case 2: | |
114 | { | |
115 | switch (in_channels) { | |
116 | case 1: | |
117 | while (count) { | |
118 | colors->channel[1] = IM_SAMPLE_MAX; | |
119 | ++colors; | |
120 | --count; | |
121 | } | |
122 | return; | |
123 | ||
124 | case 3: | |
125 | while (count) { | |
126 | colors->channel[0] = IM_ROUND(color_to_grey(colors)); | |
127 | colors->channel[1] = IM_SAMPLE_MAX; | |
128 | ++colors; | |
129 | --count; | |
130 | } | |
131 | return; | |
132 | ||
133 | case 4: | |
134 | while (count) { | |
135 | colors->channel[0] = IM_ROUND(color_to_grey(colors)); | |
136 | colors->channel[1] = colors->channel[3]; | |
137 | ++colors; | |
138 | --count; | |
139 | } | |
140 | return; | |
141 | ||
142 | default: | |
143 | i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); | |
144 | return; /* avoid warnings */ | |
145 | } | |
146 | } | |
147 | ||
148 | case 3: | |
149 | { | |
150 | switch (in_channels) { | |
151 | case 1: | |
152 | while (count) { | |
153 | colors->channel[1] = colors->channel[2] = colors->channel[0]; | |
154 | ++colors; | |
155 | --count; | |
156 | } | |
157 | return; | |
158 | ||
159 | case 2: | |
160 | while (count) { | |
161 | int alpha = colors->channel[1]; | |
162 | colors->channel[0] = colors->channel[1] = colors->channel[2] = | |
163 | IM_ROUND(colors->channel[0] * alpha / IM_SAMPLE_MAX); | |
164 | ++colors; | |
165 | --count; | |
166 | } | |
167 | return; | |
168 | ||
169 | case 4: | |
170 | while (count) { | |
171 | int alpha = colors->channel[3]; | |
172 | colors->channel[0] = | |
173 | IM_ROUND(colors->channel[0] * alpha / IM_SAMPLE_MAX); | |
174 | colors->channel[1] = | |
175 | IM_ROUND(colors->channel[1] * alpha / IM_SAMPLE_MAX); | |
176 | colors->channel[2] = | |
177 | IM_ROUND(colors->channel[2] * alpha / IM_SAMPLE_MAX); | |
178 | ++colors; | |
179 | --count; | |
180 | } | |
181 | return; | |
182 | ||
183 | default: | |
184 | i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); | |
185 | return; /* avoid warnings */ | |
186 | } | |
187 | } | |
188 | ||
189 | case 4: | |
190 | { | |
191 | switch (in_channels) { | |
192 | case 1: | |
193 | while (count) { | |
194 | colors->channel[1] = colors->channel[2] = colors->channel[0]; | |
195 | colors->channel[3] = IM_SAMPLE_MAX; | |
196 | ++colors; | |
197 | --count; | |
198 | } | |
199 | return; | |
200 | ||
201 | case 2: | |
202 | while (count) { | |
203 | colors->channel[3] = colors->channel[1]; | |
204 | colors->channel[1] = colors->channel[2] = colors->channel[0]; | |
205 | ++colors; | |
206 | --count; | |
207 | } | |
208 | return; | |
209 | ||
210 | case 3: | |
211 | while (count) { | |
212 | colors->channel[3] = IM_SAMPLE_MAX; | |
213 | ++colors; | |
214 | --count; | |
215 | } | |
216 | return; | |
217 | ||
218 | default: | |
219 | i_fatal(3, "i_adapt_colors: in_channels of %d invalid\n", in_channels); | |
220 | return; /* avoid warnings */ | |
221 | } | |
222 | } | |
223 | ||
224 | default: | |
225 | i_fatal(3, "i_adapt_colors: out_channels of %d invalid\n", out_channels); | |
226 | return; /* avoid warnings */ | |
227 | } | |
228 | } | |
229 | ||
6e4af7d4 TC |
230 | void |
231 | #ifdef IM_EIGHT_BIT | |
232 | i_adapt_colors_bg | |
233 | #else | |
234 | i_adapt_fcolors_bg | |
235 | #endif | |
236 | (int out_channels, int in_channels, IM_COLOR *colors, | |
237 | size_t count, IM_COLOR const *bg) { | |
238 | if (out_channels == in_channels) | |
239 | return; | |
240 | if (count == 0) | |
241 | return; | |
242 | ||
243 | switch (out_channels) { | |
244 | case 2: | |
245 | case 4: | |
246 | IM_ADAPT_COLORS(out_channels, in_channels, colors, count); | |
247 | return; | |
248 | ||
249 | case 1: | |
250 | switch (in_channels) { | |
251 | case 3: | |
252 | IM_ADAPT_COLORS(out_channels, in_channels, colors, count); | |
253 | return; | |
254 | ||
255 | case 2: | |
256 | { | |
257 | /* apply alpha against our given background */ | |
258 | IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); | |
259 | while (count) { | |
260 | colors->channel[0] = | |
261 | (colors->channel[0] * colors->channel[1] + | |
262 | grey_bg * (IM_SAMPLE_MAX - colors->channel[1])) / IM_SAMPLE_MAX; | |
263 | ++colors; | |
264 | --count; | |
265 | } | |
266 | } | |
267 | break; | |
268 | ||
269 | case 4: | |
270 | { | |
271 | IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); | |
272 | while (count) { | |
273 | IM_WORK_T src_grey = IM_ROUND(color_to_grey(colors)); | |
274 | colors->channel[0] = | |
275 | (src_grey * colors->channel[3] | |
276 | + grey_bg * (IM_SAMPLE_MAX - colors->channel[3])) / IM_SAMPLE_MAX; | |
277 | ++colors; | |
278 | --count; | |
279 | } | |
280 | } | |
281 | break; | |
282 | } | |
283 | break; | |
284 | ||
285 | case 3: | |
286 | switch (in_channels) { | |
287 | case 1: | |
288 | IM_ADAPT_COLORS(out_channels, in_channels, colors, count); | |
289 | return; | |
290 | ||
291 | case 2: | |
292 | { | |
293 | while (count) { | |
294 | int ch; | |
295 | IM_WORK_T src_grey = colors->channel[0]; | |
296 | IM_WORK_T src_alpha = colors->channel[1]; | |
297 | for (ch = 0; ch < 3; ++ch) { | |
298 | colors->channel[ch] = | |
299 | (src_grey * src_alpha | |
300 | + bg->channel[ch] * (IM_SAMPLE_MAX - src_alpha)) | |
301 | / IM_SAMPLE_MAX; | |
302 | } | |
303 | ++colors; | |
304 | --count; | |
305 | } | |
306 | } | |
307 | break; | |
308 | ||
309 | case 4: | |
310 | { | |
311 | while (count) { | |
312 | int ch; | |
313 | IM_WORK_T src_alpha = colors->channel[3]; | |
314 | for (ch = 0; ch < 3; ++ch) { | |
315 | colors->channel[ch] = | |
316 | (colors->channel[ch] * src_alpha | |
317 | + bg->channel[ch] * (IM_SAMPLE_MAX - src_alpha)) | |
318 | / IM_SAMPLE_MAX; | |
319 | } | |
320 | ++colors; | |
321 | --count; | |
322 | } | |
323 | } | |
324 | break; | |
325 | } | |
326 | break; | |
327 | } | |
2a31a4b4 TC |
328 | } |
329 | ||
330 | /* | |
331 | =item i_gsamp_bg(im, l, r, y, samples, out_channels, bg) | |
332 | ||
333 | =item i_gsampf_bg(im, l, r, y, samples, out_channels, bg) | |
334 | ||
335 | This is similar to i_adapt_colors_bg() except it can only strip an | |
336 | alpha channel. It cannot be used to convert a source RGB image to | |
337 | greyscale. | |
338 | ||
339 | The samples parameter MUST include enough space for all samples of the | |
340 | source image. | |
341 | ||
342 | =cut | |
343 | */ | |
344 | int | |
345 | #ifdef IM_EIGHT_BIT | |
346 | i_gsamp_bg | |
347 | #else | |
348 | i_gsampf_bg | |
349 | #endif | |
350 | (i_img *im, int l, int r, int y, IM_SAMPLE_T *samples, | |
351 | int out_channels, IM_COLOR const *bg) { | |
352 | if (out_channels == im->channels) | |
353 | return IM_GSAMP(im, l, r, y, samples, NULL, im->channels); | |
354 | ||
355 | switch (out_channels) { | |
356 | case 1: | |
357 | switch (im->channels) { | |
358 | case 2: | |
359 | { | |
360 | int x; | |
361 | IM_SAMPLE_T *inp = samples, *outp = samples; | |
362 | IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg)); | |
363 | int count; | |
364 | ||
365 | count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels); | |
366 | if (!count) | |
367 | return 0; | |
368 | ||
369 | for (x = l; x < r; ++x) { | |
370 | *outp++ = ( inp[0] * inp[1] + | |
371 | grey_bg * (IM_SAMPLE_MAX - inp[1])) / IM_SAMPLE_MAX; | |
372 | inp += 2; | |
373 | } | |
374 | ||
375 | return count; | |
376 | } | |
377 | break; | |
378 | ||
379 | default: | |
380 | i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); | |
381 | break; | |
382 | } | |
383 | break; | |
384 | case 3: | |
385 | switch (im->channels) { | |
386 | case 1: | |
387 | { | |
388 | int channels[3] = { 0, 0, 0 }; | |
389 | return IM_GSAMP(im, l, r, y, samples, channels, out_channels); | |
390 | } | |
391 | case 2: | |
392 | { | |
393 | int x, ch; | |
394 | IM_SAMPLE_T *inp = samples, *outp = samples; | |
395 | int count; | |
396 | int channels[4] = { 0, 0, 0, 1 }; | |
397 | ||
398 | count = IM_GSAMP(im, l, r, y, samples, channels, im->channels); | |
399 | if (!count) | |
400 | return 0; | |
401 | ||
402 | for (x = l; x < r; ++x) { | |
403 | IM_WORK_T alpha = inp[3]; | |
404 | for (ch = 0; ch < 3; ++ch) { | |
405 | *outp++ = ( *inp++ * alpha + | |
406 | bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX; | |
407 | } | |
408 | ++inp; | |
409 | } | |
410 | ||
411 | return count; | |
412 | } | |
413 | ||
414 | case 4: | |
415 | { | |
416 | int x, ch; | |
417 | IM_SAMPLE_T *inp = samples, *outp = samples; | |
418 | int count; | |
419 | ||
420 | count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels); | |
421 | if (!count) | |
422 | return 0; | |
423 | ||
424 | for (x = l; x < r; ++x) { | |
425 | IM_WORK_T alpha = inp[3]; | |
426 | for (ch = 0; ch < 3; ++ch) { | |
427 | *outp++ = ( *inp++ * alpha + | |
428 | bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX; | |
429 | } | |
430 | ++inp; | |
431 | } | |
432 | ||
433 | return count; | |
434 | } | |
435 | break; | |
436 | default: | |
437 | i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); | |
438 | break; | |
439 | } | |
440 | break; | |
441 | ||
442 | default: | |
443 | i_fatal(0, "i_gsamp_bg() can only remove alpha channels"); | |
444 | } | |
6e4af7d4 | 445 | |
2a31a4b4 | 446 | return 0; |
6e4af7d4 TC |
447 | } |
448 | ||
9b1ec2b8 TC |
449 | #/code |
450 |