correct an old bug link
[imager.git] / paste.im
1 #include "imager.h"
2 #include "imageri.h"
3
4 /*
5 =item i_copyto(C<dest>, C<src>, C<x1>, C<y1>, C<x2>, C<y2>, C<tx>, C<ty>)
6
7 =category Image
8
9 Copies image data from the area (C<x1>,C<y1>)-[C<x2>,C<y2>] in the
10 source image to a rectangle the same size with it's top-left corner at
11 (C<tx>,C<ty>) in the destination image.
12
13 If C<x1> > C<x2> or C<y1> > C<y2> then the corresponding co-ordinates
14 are swapped.
15
16 =cut
17 */
18
19 void
20 i_copyto(i_img *im, i_img *src, i_img_dim x1, i_img_dim y1, i_img_dim x2, i_img_dim y2, i_img_dim tx, i_img_dim ty) {
21   i_img_dim y, t, tty;
22   
23   if (x2<x1) { t=x1; x1=x2; x2=t; }
24   if (y2<y1) { t=y1; y1=y2; y2=t; }
25   if (tx < 0) {
26     /* adjust everything equally */
27     x1 += -tx;
28     x2 += -tx;
29     tx = 0;
30   }
31   if (ty < 0) {
32     y1 += -ty;
33     y2 += -ty;
34     ty = 0;
35   }
36   if (x1 >= src->xsize || y1 >= src->ysize)
37     return; /* nothing to do */
38   if (x2 > src->xsize)
39     x2 = src->xsize;
40   if (y2 > src->ysize)
41     y2 = src->ysize;
42   if (x1 == x2 || y1 == y2)
43     return; /* nothing to do */
44
45   mm_log((1,"i_copyto(im* %p, src %p, p1(" i_DFp "), p2(" i_DFp "), t("
46           i_DFp "))\n",
47           im, src, i_DFcp(x1, y1), i_DFcp(x2, y2), i_DFcp(tx, ty)));
48
49 #code im->bits == i_8_bits
50   IM_COLOR *row = mymalloc(sizeof(IM_COLOR) * (x2-x1));
51   tty = ty;
52   for(y=y1; y<y2; y++) {
53     IM_GLIN(src, x1, x2, y, row);
54     if (src->channels != im->channels)
55       IM_ADAPT_COLORS(im->channels, src->channels, row, x2-x1);
56     IM_PLIN(im, tx, tx+x2-x1, tty, row);
57     tty++;
58   }
59   myfree(row);
60 #/code
61 }
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) {
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
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   }
328 }
329
330 /*
331 =item i_gsamp_bg(im, l, r, y, samples, out_channels, background)
332
333 =category Drawing
334
335 Like C<i_gsampf()> but applies the source image color over a supplied
336 background color.
337
338 This is intended for output to image formats that don't support alpha
339 channels.
340
341 =cut
342
343 =item i_gsampf_bg(im, l, r, y, samples, out_channels, background)
344
345 =category Drawing
346
347 Like C<i_gsampf()> but applies the source image color over a supplied
348 background color.
349
350 This is intended for output to image formats that don't support alpha
351 channels.
352
353 =cut
354 */
355 int
356 #ifdef IM_EIGHT_BIT
357 i_gsamp_bg
358 #else
359 i_gsampf_bg
360 #endif
361 (i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, IM_SAMPLE_T *samples, 
362  int out_channels, IM_COLOR const *bg) {
363   if (out_channels == im->channels)
364     return IM_GSAMP(im, l, r, y, samples, NULL, im->channels);
365   
366   switch (out_channels) {
367   case 1:
368     switch (im->channels) {
369     case 2:
370       {
371         i_img_dim x;
372         IM_SAMPLE_T *inp = samples, *outp = samples;
373         IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg));
374         i_img_dim count;
375
376         count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels);
377         if (!count)
378           return 0;
379         
380         for (x = l; x < r; ++x) {
381           *outp++ = ( inp[0] * inp[1] +
382                       grey_bg * (IM_SAMPLE_MAX - inp[1])) / IM_SAMPLE_MAX;
383           inp += 2;
384         }
385
386         return count;
387       }
388       break;
389
390     default:
391       i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
392       break;
393     }
394     break;
395   case 3:
396     switch (im->channels) {
397     case 1:
398       {
399         int channels[3] = { 0, 0, 0 };
400         return IM_GSAMP(im, l, r, y, samples, channels, out_channels);
401       }
402     case 2:
403       {
404         i_img_dim x;
405         int ch;
406         IM_SAMPLE_T *inp = samples, *outp = samples;
407         i_img_dim 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         i_img_dim x;
429         int ch;
430         IM_SAMPLE_T *inp = samples, *outp = samples;
431         i_img_dim count;
432
433         count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels);
434         if (!count)
435           return 0;
436         
437         for (x = l; x < r; ++x) {
438           IM_WORK_T alpha = inp[3];
439           for (ch = 0; ch < 3; ++ch) {
440             *outp++ = ( *inp++ * alpha +
441                         bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX;
442           }
443           ++inp;
444         }
445
446         return count;
447       }
448       break;
449     default:
450       i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
451       break;
452     }
453     break;
454
455   default:
456     i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
457   }
458
459   return 0;
460 }
461
462 #/code
463