[RT #68508] do error diffusion on gray scale if the supplied palette is all gray
[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, int x1, int y1, int x2, int y2, int tx, int ty) {
21   int 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, x1 %d, y1 %d, x2 %d, y2 %d, tx %d, ty %d)\n",
46           im, src, x1, y1, x2, y2, tx, ty));
47
48 #code im->bits == i_8_bits
49   IM_COLOR *row = mymalloc(sizeof(IM_COLOR) * (x2-x1));
50   tty = ty;
51   for(y=y1; y<y2; y++) {
52     ttx = tx;
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, int l, int r, int 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         int x;
372         IM_SAMPLE_T *inp = samples, *outp = samples;
373         IM_WORK_T grey_bg = IM_ROUND(color_to_grey(bg));
374         int 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         int x, ch;
405         IM_SAMPLE_T *inp = samples, *outp = samples;
406         int count;
407         int channels[4] = { 0, 0, 0, 1 };
408
409         count = IM_GSAMP(im, l, r, y, samples, channels, im->channels);
410         if (!count)
411           return 0;
412         
413         for (x = l; x < r; ++x) {
414           IM_WORK_T alpha = inp[3];
415           for (ch = 0; ch < 3; ++ch) {
416             *outp++ = ( *inp++ * alpha +
417                         bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX;
418           }
419           ++inp;
420         }
421
422         return count;
423       }
424
425     case 4:
426       {
427         int x, ch;
428         IM_SAMPLE_T *inp = samples, *outp = samples;
429         int count;
430
431         count = IM_GSAMP(im, l, r, y, samples, NULL, im->channels);
432         if (!count)
433           return 0;
434         
435         for (x = l; x < r; ++x) {
436           IM_WORK_T alpha = inp[3];
437           for (ch = 0; ch < 3; ++ch) {
438             *outp++ = ( *inp++ * alpha +
439                         bg->channel[ch] * (IM_SAMPLE_MAX - alpha)) / IM_SAMPLE_MAX;
440           }
441           ++inp;
442         }
443
444         return count;
445       }
446       break;
447     default:
448       i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
449       break;
450     }
451     break;
452
453   default:
454     i_fatal(0, "i_gsamp_bg() can only remove alpha channels");
455   }
456
457   return 0;
458 }
459
460 #/code
461