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