switch to using size_t and i_img_dim strictly
[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, ttx, 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     ttx = tx;
54     IM_GLIN(src, x1, x2, y, row);
55     if (src->channels != im->channels)
56       IM_ADAPT_COLORS(im->channels, src->channels, row, x2-x1);
57     IM_PLIN(im, tx, tx+x2-x1, tty, row);
58     tty++;
59   }
60   myfree(row);
61 #/code
62 }
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) {
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
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   }
329 }
330
331 /*
332 =item i_gsamp_bg(im, l, r, y, samples, out_channels, background)
333
334 =category Drawing
335
336 Like C<i_gsampf()> but applies the source image color over a supplied
337 background color.
338
339 This is intended for output to image formats that don't support alpha
340 channels.
341
342 =cut
343
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.
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, i_img_dim l, i_img_dim r, i_img_dim 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         i_img_dim x;
373         IM_SAMPLE_T *inp = samples, *outp = samples;
374         IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg));
375         i_img_dim 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         i_img_dim x;
406         int ch;
407         IM_SAMPLE_T *inp = samples, *outp = samples;
408         i_img_dim count;
409         int channels[4] = { 0, 0, 0, 1 };
410
411         count = IM_GSAMP(im, l, r, y, samples, channels, im->channels);
412         if (!count)
413           return 0;
414         
415         for (x = l; x < r; ++x) {
416           IM_WORK_T alpha = inp[3];
417           for (ch = 0; ch < 3; ++ch) {
418             *outp++ = ( *inp++ * alpha +
419                         bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX;
420           }
421           ++inp;
422         }
423
424         return count;
425       }
426
427     case 4:
428       {
429         i_img_dim x;
430         int ch;
431         IM_SAMPLE_T *inp = samples, *outp = samples;
432         i_img_dim count;
433
434         count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels);
435         if (!count)
436           return 0;
437         
438         for (x = l; x < r; ++x) {
439           IM_WORK_T alpha = inp[3];
440           for (ch = 0; ch < 3; ++ch) {
441             *outp++ = ( *inp++ * alpha +
442                         bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX;
443           }
444           ++inp;
445         }
446
447         return count;
448       }
449       break;
450     default:
451       i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
452       break;
453     }
454     break;
455
456   default:
457     i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
458   }
459
460   return 0;
461 }
462
463 #/code
464