add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
[imager.git] / paste.im
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) {
19   int y, t, ttx, tty;
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) {
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, 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   }
445
446   return 0;
447 }
448
449 #/code
450