File Coverage

render.im
Criterion Covered Total %
statement 571 674 84.7
branch 507 740 68.5
condition n/a
subroutine n/a
pod n/a
total 1078 1414 76.2


line stmt bran cond sub pod time code
1             /*
2             Render utilities
3             */
4             #include "imager.h"
5              
6             #define RENDER_MAGIC 0x765AE
7              
8             typedef void (*render_color_f)(i_render *, i_img_dim, i_img_dim, i_img_dim, unsigned char const *src, i_color const *color);
9              
10             #define i_has_alpha(channels) ((channels) == 2 || (channels) == 4)
11              
12             #define i_color_channels(channels) (i_has_alpha(channels) ? (channels)-1 : (channels))
13              
14             #code
15              
16             static void IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
17             static void IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
18              
19             static render_color_f IM_SUFFIX(render_color_tab)[] =
20             {
21             NULL,
22             IM_SUFFIX(render_color_13),
23             IM_SUFFIX(render_color_alpha),
24             IM_SUFFIX(render_color_13),
25             IM_SUFFIX(render_color_alpha),
26             };
27              
28             static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
29             static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
30             /* the copy variant copies the source alpha to the the output alpha channel */
31             static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
32              
33             static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
34             static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
35              
36             #/code
37              
38             /*
39             =item i_render_new(im, width)
40             =category Blit tools
41              
42             Allocate a new C object and initialize it.
43              
44             =cut
45             */
46              
47             i_render *
48 0           i_render_new(i_img *im, i_img_dim width) {
49 0           i_render *r = mymalloc(sizeof(i_render));
50              
51 0           i_render_init(r, im, width);
52              
53 0           return r;
54             }
55              
56             /*
57             =item i_render_delete(r)
58             =category Blit tools
59              
60             Release an C object.
61              
62             =cut
63             */
64              
65             void
66 0           i_render_delete(i_render *r) {
67 0           i_render_done(r);
68 0           myfree(r);
69 0           }
70              
71             void
72 184           i_render_init(i_render *r, i_img *im, i_img_dim width) {
73 184           r->magic = RENDER_MAGIC;
74 184           r->im = im;
75 184           r->line_width = width;
76 184           r->line_8 = NULL;
77 184           r->line_double = NULL;
78 184           r->fill_width = width;
79 184           r->fill_line_8 = NULL;
80 184           r->fill_line_double = NULL;
81 184           }
82              
83             void
84 184           i_render_done(i_render *r) {
85 184 100         if (r->line_8)
86 110           myfree(r->line_8);
87 184 100         if (r->line_double)
88 72           myfree(r->line_double);
89 184 100         if (r->fill_line_8)
90 86           myfree(r->fill_line_8);
91 184 100         if (r->fill_line_double)
92 55           myfree(r->fill_line_double);
93 184           r->magic = 0;
94 184           }
95              
96             static void
97 137188           alloc_line(i_render *r, i_img_dim width, i_img_dim eight_bit) {
98 137188 50         if (width > r->line_width) {
99 0           i_img_dim new_width = r->line_width * 2;
100 0 0         if (new_width < width)
101 0           new_width = width;
102              
103 0 0         if (eight_bit) {
104 0 0         if (r->line_8)
105 0           r->line_8 = myrealloc(r->line_8, sizeof(i_color) * new_width);
106             else
107 0           r->line_8 = mymalloc(sizeof(i_color) * new_width);
108 0 0         if (r->line_double) {
109 0           myfree(r->line_double);
110 0           r->line_double = NULL;
111             }
112             }
113             else {
114 0 0         if (r->line_double)
115 0           r->line_double = myrealloc(r->line_double, sizeof(i_fcolor) * new_width);
116             else
117 0           r->line_double = mymalloc(sizeof(i_fcolor) * new_width);
118 0 0         if (r->line_8) {
119 0           myfree(r->line_8);
120 0           r->line_double = NULL;
121             }
122             }
123              
124 0           r->line_width = new_width;
125             }
126             else {
127 137188 100         if (eight_bit) {
128 135526 100         if (!r->line_8)
129 110           r->line_8 = mymalloc(sizeof(i_color) * r->line_width);
130 135526 50         if (r->line_double) {
131 0           myfree(r->line_double);
132 135526           r->line_double = NULL;
133             }
134             }
135             else {
136 1662 100         if (!r->line_double)
137 72           r->line_double = mymalloc(sizeof(i_fcolor) * r->line_width);
138 1662 50         if (r->line_8) {
139 0           myfree(r->line_8);
140 0           r->line_8 = NULL;
141             }
142             }
143             }
144 137188           }
145              
146             static void
147 135595           alloc_fill_line(i_render *r, i_img_dim width, int eight_bit) {
148 135595 50         if (width > r->fill_width) {
149 0           i_img_dim new_width = r->fill_width * 2;
150 0 0         if (new_width < width)
151 0           new_width = width;
152              
153 0 0         if (eight_bit) {
154 0 0         if (r->line_8)
155 0           r->fill_line_8 = myrealloc(r->fill_line_8, sizeof(i_color) * new_width);
156             else
157 0           r->fill_line_8 = mymalloc(sizeof(i_color) * new_width);
158 0 0         if (r->fill_line_double) {
159 0           myfree(r->fill_line_double);
160 0           r->fill_line_double = NULL;
161             }
162             }
163             else {
164 0 0         if (r->fill_line_double)
165 0           r->fill_line_double = myrealloc(r->fill_line_double, sizeof(i_fcolor) * new_width);
166             else
167 0           r->fill_line_double = mymalloc(sizeof(i_fcolor) * new_width);
168 0 0         if (r->fill_line_8) {
169 0           myfree(r->fill_line_8);
170 0           r->fill_line_double = NULL;
171             }
172             }
173              
174 0           r->fill_width = new_width;
175             }
176             else {
177 135595 100         if (eight_bit) {
178 134559 100         if (!r->fill_line_8)
179 86           r->fill_line_8 = mymalloc(sizeof(i_color) * r->fill_width);
180 134559 50         if (r->fill_line_double) {
181 0           myfree(r->fill_line_double);
182 134559           r->fill_line_double = NULL;
183             }
184             }
185             else {
186 1036 100         if (!r->fill_line_double)
187 55           r->fill_line_double = mymalloc(sizeof(i_fcolor) * r->fill_width);
188 1036 50         if (r->fill_line_8) {
189 0           myfree(r->fill_line_8);
190 0           r->fill_line_8 = NULL;
191             }
192             }
193             }
194 135595           }
195              
196             /*
197             =item i_render_color(r, x, y, width, source, color)
198             =category Blit tools
199              
200             Render the given color with the coverage specified by C to
201             C.
202              
203             Renders in normal combine mode.
204              
205             =cut
206             */
207              
208             void
209 340           i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
210             unsigned char const *src, i_color const *color) {
211 340           i_img *im = r->im;
212 340 50         if (y < 0 || y >= im->ysize)
    50          
213 0           return;
214 340 50         if (x < 0) {
215 0           width += x;
216 0           src -= x;
217 0           x = 0;
218             }
219 340 50         if (x + width > im->xsize) {
220 0           width = im->xsize - x;
221             }
222 340 50         if (x >= im->xsize || x + width <= 0 || width <= 0)
    50          
    50          
223 0           return;
224              
225             /* avoid as much work as we can */
226 350 50         while (width > 0 && *src == 0) {
    100          
227 10           --width;
228 10           ++src;
229 10           ++x;
230             }
231 690 50         while (width > 0 && src[width-1] == 0) {
    100          
232 350           --width;
233             }
234 340 50         if (!width)
235 0           return;
236              
237 340           alloc_line(r, width, r->im->bits <= 8);
238              
239 340 50         #code r->im->bits <= 8
240             /*if (r->IM_SUFFIX(line) == NULL)
241             r->IM_SUFFIX(line) = mymalloc(sizeof(IM_COLOR) * r->width);*/
242 340           (IM_SUFFIX(render_color_tab)[im->channels])(r, x, y, width, src, color);
243             #/code
244             }
245              
246             /*
247             =item i_render_fill(r, x, y, width, source, fill)
248             =category Blit tools
249              
250             Render the given fill with the coverage in C through
251             C.
252              
253             =cut
254             */
255              
256             void
257 135595           i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
258             unsigned char const *src, i_fill_t *fill) {
259 135595           i_img *im = r->im;
260 135595           int fill_channels = im->channels;
261            
262 135595 100         if (fill_channels == 1 || fill_channels == 3)
    100          
263 135347           ++fill_channels;
264              
265 135595 50         if (y < 0 || y >= im->ysize)
    50          
266 0           return;
267 135595 50         if (x < 0) {
268 0           width += x;
269 0           src -= x;
270 0           x = 0;
271             }
272 135595 50         if (x + width > im->xsize) {
273 0           width = im->xsize - x;
274             }
275 135595 50         if (x >= im->xsize || x + width <= 0 || width <= 0)
    50          
    50          
276 0           return;
277              
278 135595 100         if (src) {
279             /* avoid as much work as we can */
280 664 50         while (width > 0 && *src == 0) {
    100          
281 1           --width;
282 1           ++src;
283 1           ++x;
284             }
285 704 50         while (width > 0 && src[width-1] == 0) {
    100          
286 41           --width;
287             }
288             }
289 135595 50         if (!width)
290 0           return;
291              
292 135595 100         alloc_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL);
    100          
293 135595 100         alloc_fill_line(r, width, r->im->bits <= 8 && fill->f_fill_with_color != NULL);
    100          
294              
295 135595 100         #code r->im->bits <= 8 && fill->f_fill_with_color
    100          
296 135595 100         if (IM_FILL_COMBINE(fill)) {
    100          
297 1050           IM_COLOR *srcc = r->IM_SUFFIX(fill_line);
298 1050           IM_COLOR *destc = r->IM_SUFFIX(line);
299 1050           IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(fill_line));
300 1050           if (src) {
301 35           unsigned char const *srcc = src;
302 35           IM_COLOR *fillc = r->IM_SUFFIX(fill_line);
303 35           i_img_dim work_width = width;
304 1253 100         while (work_width) {
    0          
305 1218 100         if (*srcc == 0) {
    0          
306 210           fillc->channel[fill_channels-1] = 0;
307             }
308 1008 100         else if (*srcc != 255) {
    0          
309 134           fillc->channel[fill_channels-1] =
310 134           fillc->channel[fill_channels-1] * *srcc / 255;
311             }
312 1218           --work_width;
313 1218           ++srcc;
314 1218           ++fillc;
315             }
316             }
317 1050           IM_GLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
318 1050           IM_FILL_COMBINE(fill)(destc, srcc, r->im->channels, width);
319             }
320             else {
321 134545 100         if (src) {
    100          
322 628           i_img_dim work_width = width;
323 628           IM_COLOR *srcc = r->IM_SUFFIX(fill_line);
324 628           IM_COLOR *destc = r->IM_SUFFIX(line);
325             int ch;
326              
327 628           IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(fill_line));
328 628           IM_GLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
329 58250 100         while (work_width) {
    100          
330 57622 100         if (*src == 255) {
    100          
331             /* just replace it */
332 46236           *destc = *srcc;
333             }
334 11386 100         else if (*src) {
    100          
335 13724 100         for (ch = 0; ch < im->channels; ++ch) {
    100          
336 20586           IM_WORK_T work = (destc->channel[ch] * (255 - *src)
337 10293           + srcc->channel[ch] * *src) / 255.0;
338 10293 50         destc->channel[ch] = IM_LIMIT(work);
    50          
    50          
339             }
340             }
341            
342 57622           ++srcc;
343 57622           ++destc;
344 57622           ++src;
345 57622           --work_width;
346             }
347             }
348             else { /* if (src) */
349 133917           IM_FILL_FILLER(fill)(fill, x, y, width, fill_channels, r->IM_SUFFIX(line));
350             }
351             }
352 135595           IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
353             #/code
354             }
355              
356             #if 0
357              
358             /* for debuggin */
359              
360             static void
361             dump_src(const char *note, unsigned char const *src, i_img_dim width) {
362             i_img_dim i;
363             printf("%s - %p/%" i_DF "\n", note, src, i_DFc(width));
364             for (i = 0; i < width; ++i) {
365             printf("%02x ", src[i]);
366             }
367             putchar('\n');
368             }
369              
370             #endif
371              
372             #code
373              
374             /*
375             =item i_render_line(r, x, y, width, source, fill)
376             =category Blit tools
377              
378             Render the given fill with the coverage in C through
379             C.
380              
381             =cut
382              
383             =item i_render_linef(r, x, y, width, source, fill)
384             =category Blit tools
385              
386             Render the given fill with the coverage in C through
387             C.
388              
389             =cut
390             */
391              
392             void
393 1253           IM_RENDER_LINE(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
394             const IM_SAMPLE_T *src, IM_COLOR *line,
395             IM_FILL_COMBINE_F combine) {
396 1253           i_img *im = r->im;
397 1253           int src_chans = im->channels;
398              
399             /* src must always have an alpha channel */
400 1253 50         if (src_chans == 1 || src_chans == 3)
    50          
    50          
    100          
401 1252           ++src_chans;
402              
403 1253 50         if (y < 0 || y >= im->ysize)
    50          
    50          
    50          
404 0           return;
405 1253 50         if (x < 0) {
    50          
406 0           src -= x;
407 0           line -= x;
408 0           width += x;
409 0           x = 0;
410             }
411 1253 50         if (x + width > im->xsize)
    50          
412 0           width = r->im->xsize - x;
413              
414             #ifdef IM_EIGHT_BIT
415 627           alloc_line(r, width, 1);
416             #else
417 626           alloc_line(r, width, 0);
418             #endif
419              
420 1253           if (combine) {
421 1253 100         if (src) {
    100          
422 822           i_img_dim work_width = width;
423 822           IM_COLOR *linep = line;
424 822           const IM_SAMPLE_T *srcp = src;
425 822           int alpha_chan = src_chans - 1;
426            
427 31894 100         while (work_width) {
    100          
428 31072 100         if (*srcp) {
    100          
429 27950 100         if (*srcp != IM_SAMPLE_MAX)
    100          
430 27950           linep->channel[alpha_chan] =
431 7690           linep->channel[alpha_chan] * *srcp / IM_SAMPLE_MAX;
432             }
433             else {
434 3122           linep->channel[alpha_chan] = 0;
435             }
436 31072           --work_width;
437 31072           ++srcp;
438 31072           ++linep;
439             }
440             }
441 1253           IM_GLIN(im, x, x+width, y, r->IM_SUFFIX(line));
442 1253           combine(r->IM_SUFFIX(line), line, im->channels, width);
443 1253           IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
444             }
445             else {
446 0 0         if (src) {
    0          
447 0           i_img_dim work_width = width;
448 0           IM_COLOR *srcc = line;
449 0           IM_COLOR *destc = r->IM_SUFFIX(line);
450              
451 0           IM_GLIN(im, x, x+width, y, r->IM_SUFFIX(line));
452 0 0         while (work_width) {
    0          
453 0 0         if (*src == 255) {
    0          
454             /* just replace it */
455 0           *destc = *srcc;
456             }
457 0 0         else if (*src) {
    0          
458             int ch;
459 0 0         for (ch = 0; ch < im->channels; ++ch) {
    0          
460 0           IM_WORK_T work = (destc->channel[ch] * (IM_SAMPLE_MAX - *src)
461 0           + srcc->channel[ch] * *src) / IM_SAMPLE_MAX;
462 0 0         destc->channel[ch] = IM_LIMIT(work);
    0          
    0          
463             }
464             }
465            
466 0           ++srcc;
467 0           ++destc;
468 0           ++src;
469 0           --work_width;
470             }
471 0           IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
472             }
473             else {
474 0           IM_PLIN(im, x, x+width, y, line);
475             }
476             }
477             }
478              
479             static
480             void
481 320           IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y,
482             i_img_dim width, unsigned char const *src,
483             i_color const *color) {
484 320           i_img *im = r->im;
485 320           IM_COLOR *linep = r->IM_SUFFIX(line);
486 320           int ch, channels = im->channels;
487             i_img_dim fetch_offset;
488 320           int color_alpha = color->channel[im->channels];
489             #undef STORE_COLOR
490             #ifdef IM_EIGHT_BIT
491             #define STORE_COLOR (*color)
492             #else
493             i_fcolor fcolor;
494              
495 0 0         for (ch = 0; ch < channels; ++ch) {
496 0           fcolor.channel[ch] = color->channel[ch] / 255.0;
497             }
498             #define STORE_COLOR fcolor
499             #endif
500            
501 320           fetch_offset = 0;
502 320 0         if (color_alpha == 0xFF) {
    50          
503 930 0         while (fetch_offset < width && *src == 0xFF) {
    0          
    100          
    100          
504 610           *linep++ = STORE_COLOR;
505 610           ++src;
506 610           ++fetch_offset;
507             }
508             }
509 320           IM_GLIN(im, x+fetch_offset, x+width, y, linep);
510 19236 0         while (fetch_offset < width) {
    100          
511             #ifdef IM_EIGHT_BIT
512 18916           IM_WORK_T alpha = *src++ * color_alpha / 255;
513             #else
514 0           IM_WORK_T alpha = *src++ * color_alpha / (255.0 * 255.0);
515             #endif
516 18916 0         if (alpha == IM_SAMPLE_MAX)
    100          
517 17782           *linep = STORE_COLOR;
518 1134 0         else if (alpha) {
    50          
519 4536 0         for (ch = 0; ch < channels; ++ch) {
    100          
520 6804           linep->channel[ch] = (linep->channel[ch] * (IM_SAMPLE_MAX - alpha)
521 3402           + STORE_COLOR.channel[ch] * alpha) / IM_SAMPLE_MAX;
522             }
523             }
524 18916           ++linep;
525 18916           ++fetch_offset;
526             }
527 320           IM_PLIN(im, x, x+width, y, r->IM_SUFFIX(line));
528 320           }
529              
530             static
531             void
532 20           IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y,
533             i_img_dim width, unsigned char const *src,
534             i_color const *color) {
535 20           IM_COLOR *linep = r->IM_SUFFIX(line);
536             int ch;
537 20           int alpha_channel = r->im->channels - 1;
538             i_img_dim fetch_offset;
539 20           int color_alpha = color->channel[alpha_channel];
540             #undef STORE_COLOR
541             #ifdef IM_EIGHT_BIT
542             #define STORE_COLOR (*color)
543             #else
544             i_fcolor fcolor;
545              
546 0 0         for (ch = 0; ch < r->im->channels; ++ch) {
547 0           fcolor.channel[ch] = color->channel[ch] / 255.0;
548             }
549             #define STORE_COLOR fcolor
550             #endif
551              
552 20           fetch_offset = 0;
553 20 0         if (color->channel[alpha_channel] == 0xFF) {
    50          
554 20 0         while (fetch_offset < width && *src == 0xFF) {
    0          
    50          
    50          
555 0           *linep++ = STORE_COLOR;
556 0           ++src;
557 0           ++fetch_offset;
558             }
559             }
560 20           IM_GLIN(r->im, x+fetch_offset, x+width, y, linep);
561 362 0         while (fetch_offset < width) {
    100          
562             #ifdef IM_EIGHT_BIT
563 342           IM_WORK_T src_alpha = *src++ * color_alpha / 255;
564             #else
565 0           IM_WORK_T src_alpha = *src++ * color_alpha / (255.0 * 255.0);
566             #endif
567 342 0         if (src_alpha == IM_SAMPLE_MAX)
    100          
568 278           *linep = STORE_COLOR;
569 64 0         else if (src_alpha) {
    50          
570 64           IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha;
571 64           IM_WORK_T orig_alpha = linep->channel[alpha_channel];
572 64           IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
573 256 0         for (ch = 0; ch < alpha_channel; ++ch) {
    100          
574 384           linep->channel[ch] = ( src_alpha * STORE_COLOR.channel[ch]
575 192           + remains * linep->channel[ch] * orig_alpha / IM_SAMPLE_MAX
576 192           ) / dest_alpha;
577             }
578 64           linep->channel[alpha_channel] = dest_alpha;
579             }
580 342           ++linep;
581 342           ++fetch_offset;
582             }
583 20           IM_PLIN(r->im, x, x+width, y, r->IM_SUFFIX(line));
584             #undef STORE_COLOR
585 20           }
586              
587             /* combine a line of image data with an output line, both the input
588             and output lines include an alpha channel.
589              
590             Both input and output lines have I of data, channels
591             should be either 2 or 4.
592             */
593              
594             static void
595 57           IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in,
596             int channels, i_img_dim count) {
597             int ch;
598 57           int alpha_channel = channels - 1;
599            
600 530 100         while (count) {
    100          
601 473           IM_WORK_T src_alpha = in->channel[alpha_channel];
602            
603 473 50         if (src_alpha == IM_SAMPLE_MAX)
    100          
604 3           *out = *in;
605 470 100         else if (src_alpha) {
    100          
606 407           IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha;
607 407           IM_WORK_T orig_alpha = out->channel[alpha_channel];
608 407           IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
609            
610 1628 100         for (ch = 0; ch < alpha_channel; ++ch) {
    100          
611 2442           out->channel[ch] = ( src_alpha * in->channel[ch]
612 1221           + remains * out->channel[ch] * orig_alpha / IM_SAMPLE_MAX
613 1221           ) / dest_alpha;
614             }
615 407           out->channel[alpha_channel] = dest_alpha;
616             }
617              
618 473           ++out;
619 473           ++in;
620 473           --count;
621             }
622 57           }
623              
624             /* combine a line of image data with an output line. The input line
625             includes an alpha channel, the output line has no alpha channel.
626            
627             The input line has I+1 of color data. The output line
628             has I of color data.
629             */
630              
631             static void
632 2042           IM_SUFFIX(combine_line_noalpha)
633             (IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
634             int ch;
635              
636 110101 100         while (count) {
    100          
637 108059           IM_WORK_T src_alpha = in->channel[channels];
638            
639 108059 100         if (src_alpha == IM_SAMPLE_MAX)
    100          
640 42506           *out = *in;
641 65553 100         else if (src_alpha) {
    100          
642             IM_WORK_T remains;
643            
644 40492           remains = IM_SAMPLE_MAX - src_alpha;
645 161968 100         for (ch = 0; ch < channels; ++ch) {
    100          
646 242952           out->channel[ch] = ( in->channel[ch] * src_alpha
647 121476           + out->channel[ch] * remains) / IM_SAMPLE_MAX;
648             }
649             }
650            
651 108059           ++out;
652 108059           ++in;
653 108059           --count;
654             }
655 2042           }
656              
657             /* combine a line of image data with an output line, both the input
658             and output lines include an alpha channel.
659              
660             Both input and output lines have I of data, channels
661             should be either 2 or 4.
662              
663             This variant does not modify the output alpha channel.
664             */
665              
666             static void
667 64           IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in,
668             int channels, i_img_dim count) {
669             int ch;
670 64           int alpha_channel = channels - 1;
671            
672 320 100         while (count) {
    100          
673 256           IM_WORK_T src_alpha = in->channel[alpha_channel];
674            
675 256 50         if (src_alpha == IM_SAMPLE_MAX)
    50          
676 0           *out = *in;
677 256 50         else if (src_alpha) {
    50          
678 256           IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha;
679 256           IM_WORK_T orig_alpha = out->channel[alpha_channel];
680 256           IM_WORK_T dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
681            
682 1024 100         for (ch = 0; ch < alpha_channel; ++ch) {
    100          
683 1536           out->channel[ch] = ( src_alpha * in->channel[ch]
684 768           + remains * out->channel[ch] * orig_alpha / IM_SAMPLE_MAX
685 768           ) / dest_alpha;
686             }
687             }
688              
689 256           ++out;
690 256           ++in;
691 256           --count;
692             }
693 64           }
694              
695             static void
696 1767           IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
697 1767 50         if (channels == 2 || channels == 4)
    100          
    50          
    100          
698 57           IM_SUFFIX(combine_line_alpha)(out, in, channels, count);
699             else
700 1710           IM_SUFFIX(combine_line_noalpha)(out, in, channels, count);
701 1767           }
702              
703             static void
704 396           IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
705 396 50         if (channels == 2 || channels == 4)
    100          
    50          
    100          
706 64           IM_SUFFIX(combine_line_alpha_na)(out, in, channels, count);
707             else
708 332           IM_SUFFIX(combine_line_noalpha)(out, in, channels, count);
709 396           }
710              
711             static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
712             static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
713             static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
714             static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
715             static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
716             static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
717             static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
718             static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
719             static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
720             static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
721             static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
722             static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
723              
724             static const IM_FILL_COMBINE_F IM_SUFFIX(combines)[] =
725             {
726             NULL,
727             IM_SUFFIX(combine_alphablend),
728             IM_SUFFIX(combine_mult),
729             IM_SUFFIX(combine_dissolve),
730             IM_SUFFIX(combine_add),
731             IM_SUFFIX(combine_subtract),
732             IM_SUFFIX(combine_diff),
733             IM_SUFFIX(combine_lighten),
734             IM_SUFFIX(combine_darken),
735             IM_SUFFIX(combine_hue),
736             IM_SUFFIX(combine_sat),
737             IM_SUFFIX(combine_value),
738             IM_SUFFIX(combine_color)
739             };
740              
741             #/code
742              
743             /*
744             =item i_get_combine(combine, color_func, fcolor_func)
745              
746             =cut
747             */
748              
749 72           void i_get_combine(int combine, i_fill_combine_f *color_func,
750             i_fill_combinef_f *fcolor_func) {
751 72 50         if (combine < 0 || combine >= sizeof(combines_8) / sizeof(*combines_8))
    50          
752 0           combine = 0;
753              
754 72           *color_func = combines_8[combine];
755 72           *fcolor_func = combines_double[combine];
756 72           }
757              
758             #code
759              
760             /*
761             Three good references for implementing combining modes:
762              
763             http://www.w3.org/TR/2004/WD-SVG12-20041027/rendering.html
764             referenced as [svg1.2]
765              
766             http://gimp-savvy.com/BOOK/index.html?node55.html
767             ("The Blending Modes", if it changes)
768             referenced as [savvy]
769              
770             http://www.pegtop.net/delphi/articles/blendmodes/
771             referenced as [pegtop]
772              
773             Where differences exist, I follow the SVG practice, the gimp
774             practice, and lastly pegtop.
775             */
776              
777              
778             static void
779 1767           IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
780 1767           IM_SUFFIX(combine_line)(out, in, channels, count);
781 1767           }
782              
783             /*
784             Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
785             Da' = Sa.Da + Sa.(1 - Da) + Da.(1 - Sa)
786             = Sa + Da - Sa.Da
787              
788             When Da=1
789              
790             Dc' = Sc.Sa.Dc + Dc.(1 - Sa)
791             */
792             static void
793 24           IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
794             int ch;
795 24           IM_COLOR *inp = in;
796 24           IM_COLOR *outp = out;
797 24           i_img_dim work_count = count;
798 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
799              
800 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
801 80 100         while (work_count--) {
    100          
802 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
803 64           IM_WORK_T src_alpha = inp->channel[color_channels];
804            
805 64 50         if (src_alpha) {
    50          
806 128           IM_WORK_T dest_alpha = src_alpha + orig_alpha
807 64           - (src_alpha * orig_alpha) / IM_SAMPLE_MAX;
808            
809 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
810 192           outp->channel[ch] =
811 192           (inp->channel[ch] * src_alpha * outp->channel[ch] / IM_SAMPLE_MAX
812 192           * orig_alpha
813 192           + inp->channel[ch] * src_alpha * (IM_SAMPLE_MAX - orig_alpha)
814 192           + outp->channel[ch] * orig_alpha * (IM_SAMPLE_MAX - src_alpha))
815 192           / IM_SAMPLE_MAX / dest_alpha;
816             }
817 64           outp->channel[color_channels] = dest_alpha;
818             }
819 64           ++outp;
820 64           ++inp;
821             }
822             }
823             else {
824 40 100         while (work_count--) {
    100          
825 32           IM_WORK_T src_alpha = inp->channel[color_channels];
826 32           IM_WORK_T remains = IM_SAMPLE_MAX - src_alpha;
827            
828 32 50         if (src_alpha) {
    50          
829 128 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
830 96           outp->channel[ch] =
831 96           (src_alpha * inp->channel[ch] * outp->channel[ch] / IM_SAMPLE_MAX
832 96           + outp->channel[ch] * remains) / IM_SAMPLE_MAX;
833             }
834             }
835 32           ++outp;
836 32           ++inp;
837             }
838             }
839 24           }
840              
841             static void
842 24           IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
843 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
844             int ch;
845              
846 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
847 80 100         while (count--) {
    100          
848 64 100         if (in->channel[channels-1] > rand() * ((double)IM_SAMPLE_MAX / RAND_MAX)) {
    100          
849 108 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
850 81           out->channel[ch] = in->channel[ch];
851             }
852 27           out->channel[color_channels] = IM_SAMPLE_MAX;
853             }
854 64           ++out;
855 64           ++in;
856             }
857             }
858             else {
859 40 100         while (count--) {
    100          
860 32 100         if (in->channel[channels] > rand() * ((double)IM_SAMPLE_MAX / RAND_MAX)) {
    100          
861 60 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
862 45           out->channel[ch] = in->channel[ch];
863             }
864             }
865 32           ++out;
866 32           ++in;
867             }
868             }
869 24           }
870              
871             /*
872             Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
873             = Sca + Dca
874             Da' = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
875             = Sa + Da
876             */
877              
878             static void
879 24           IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
880             int ch;
881 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
882 24           i_img_dim work_count = count;
883 24           IM_COLOR *inp = in;
884 24           IM_COLOR *outp = out;
885              
886 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
887 80 100         while (work_count--) {
    100          
888 64           IM_WORK_T src_alpha = inp->channel[color_channels];
889 64 50         if (src_alpha) {
    50          
890 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
891 64           IM_WORK_T dest_alpha = src_alpha + orig_alpha;
892 64 50         if (dest_alpha > IM_SAMPLE_MAX)
    50          
893 64           dest_alpha = IM_SAMPLE_MAX;
894 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
895 192           IM_WORK_T total = (outp->channel[ch] * orig_alpha + inp->channel[ch] * src_alpha) / dest_alpha;
896 192 50         if (total > IM_SAMPLE_MAX)
    50          
897 0           total = IM_SAMPLE_MAX;
898 192           outp->channel[ch] = total;
899             }
900 64           outp->channel[color_channels] = dest_alpha;
901             }
902            
903 64           ++outp;
904 64           ++inp;
905             }
906             }
907             else {
908 40 100         while (work_count--) {
    100          
909 32           IM_WORK_T src_alpha = inp->channel[color_channels];
910 32 50         if (src_alpha) {
    50          
911 128 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
912 96           IM_WORK_T total = outp->channel[ch] + inp->channel[ch] * src_alpha / IM_SAMPLE_MAX;
913 96 50         if (total > IM_SAMPLE_MAX)
    50          
914 0           total = IM_SAMPLE_MAX;
915 96           outp->channel[ch] = total;
916             }
917             }
918            
919 32           ++outp;
920 32           ++inp;
921             }
922             }
923 24           }
924              
925             /*
926             [pegtop] documents this as max(A+B-256, 0) while [savvy] documents
927             it as max(A-B, 0). [svg1.2] doesn't cover it.
928              
929             [savvy] doesn't document how it works with an alpha channel. GIMP
930             actually seems to calculate the final value then use the alpha
931             channel to apply that to the target.
932             */
933             static void
934 24           IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
935             int ch;
936 24           IM_COLOR const *inp = in;
937 24           IM_COLOR *outp = out;
938 24           i_img_dim work_count = count;
939 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
940              
941 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
942 80 100         while (work_count--) {
    100          
943 64           IM_WORK_T src_alpha = inp->channel[color_channels];
944 64 50         if (src_alpha) {
    50          
945 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
946 64           IM_WORK_T dest_alpha = src_alpha + orig_alpha;
947 64 50         if (dest_alpha > IM_SAMPLE_MAX)
    50          
948 64           dest_alpha = IM_SAMPLE_MAX;
949 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
950 192           IM_WORK_T total =
951 192           (outp->channel[ch] * orig_alpha - inp->channel[ch] * src_alpha)
952             / dest_alpha;
953 192 50         if (total < 0)
    100          
954 176           total = 0;
955 192           outp->channel[ch] = total;
956             }
957 64           outp->channel[color_channels] = dest_alpha;
958             }
959 64           ++outp;
960 64           ++inp;
961             }
962             }
963             else {
964 40 100         while (work_count--) {
    100          
965 32           IM_WORK_T src_alpha = inp->channel[color_channels];
966 32 50         if (src_alpha) {
    50          
967 128 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
968 96           IM_WORK_T total = outp->channel[ch] - inp->channel[ch] * src_alpha / IM_SAMPLE_MAX;
969 96 50         if (total < 0)
    100          
970 80           total = 0;
971 96           outp->channel[ch] = total;
972             }
973             }
974 32           ++outp;
975 32           ++inp;
976             }
977             }
978 24           }
979              
980             #ifdef IM_EIGHT_BIT
981             #define IM_abs(x) abs(x)
982             #else
983             #define IM_abs(x) fabs(x)
984             #endif
985              
986             /*
987             Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
988             = Sca + Dca - 2.min(Sca.Da, Dca.Sa)
989             Da' = Sa + Da - Sa.Da
990             */
991             static void
992 296           IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
993             int ch;
994 296           IM_COLOR const *inp = in;
995 296           IM_COLOR *outp = out;
996 296           i_img_dim work_count = count;
997 296 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
998              
999 312 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
1000 80 100         while (work_count--) {
    100          
1001 64           IM_WORK_T src_alpha = inp->channel[color_channels];
1002 64 50         if (src_alpha) {
    50          
1003 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
1004 128           IM_WORK_T dest_alpha = src_alpha + orig_alpha
1005 64           - src_alpha * orig_alpha / IM_SAMPLE_MAX;
1006 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1007 192           IM_WORK_T src = inp->channel[ch] * src_alpha;
1008 192           IM_WORK_T orig = outp->channel[ch] * orig_alpha;
1009 192           IM_WORK_T src_da = src * orig_alpha;
1010 192           IM_WORK_T dest_sa = orig * src_alpha;
1011 96 50         IM_WORK_T diff = src_da < dest_sa ? src_da : dest_sa;
1012 192           outp->channel[ch] = (src + orig - 2 * diff / IM_SAMPLE_MAX) / dest_alpha;
1013             }
1014 64           outp->channel[color_channels] = dest_alpha;
1015             }
1016 64           ++inp;
1017 64           ++outp;
1018             }
1019             }
1020             else {
1021 8877 100         while (work_count--) {
    100          
1022 8597           IM_WORK_T src_alpha = inp->channel[color_channels];
1023 8597 50         if (src_alpha) {
    100          
1024 33548 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1025 25161           IM_WORK_T src = inp->channel[ch] * src_alpha;
1026 25161           IM_WORK_T orig = outp->channel[ch] * IM_SAMPLE_MAX;
1027 25161           IM_WORK_T src_da = src * IM_SAMPLE_MAX;
1028 25161           IM_WORK_T dest_sa = orig * src_alpha;
1029 48 50         IM_WORK_T diff = src_da < dest_sa ? src_da : dest_sa;
1030 25161           outp->channel[ch] = (src + orig - 2 * diff / IM_SAMPLE_MAX) / IM_SAMPLE_MAX;
1031             }
1032             }
1033 8597           ++inp;
1034 8597           ++outp;
1035             }
1036             }
1037 296           }
1038              
1039             #undef IM_abs
1040              
1041             /*
1042             Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca(1 - Sa)
1043             Da' = Sa + Da - Sa.Da
1044              
1045             To hoist some code:
1046              
1047             Dca' = min(Sc.Sa.Da, Dc.Da.Sa) + Sca - Sca.Da + Dca - Dca.Sa
1048             = Sa.Da.min(Sc, Dc) + Sca - Sca.Da + Dca - Dca.Sa
1049              
1050             When Da=1:
1051              
1052             Dca' = min(Sca.1, Dc.1.Sa) + Sca.(1 - 1) + Dc.1(1 - Sa)
1053             = min(Sca, Dc.Sa) + Dc(1-Sa)
1054             = Sa.min(Sc, Dc) + Dc - Dc.Sa
1055             Da' = Sa + 1 - Sa.1
1056             = 1
1057             */
1058             static void
1059 24           IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels,
1060             i_img_dim count) {
1061             int ch;
1062 24           IM_COLOR const *inp = in;
1063 24           IM_COLOR *outp = out;
1064 24           i_img_dim work_count = count;
1065 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
1066              
1067 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
1068 80 100         while (work_count--) {
    100          
1069 64           IM_WORK_T src_alpha = inp->channel[color_channels];
1070              
1071 64 50         if (src_alpha) {
    50          
1072 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
1073 128           IM_WORK_T dest_alpha = src_alpha + orig_alpha
1074 64           - src_alpha * orig_alpha / IM_SAMPLE_MAX;
1075 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1076 192           IM_WORK_T Sca = inp->channel[ch] * src_alpha;
1077 192           IM_WORK_T Dca = outp->channel[ch] * orig_alpha;
1078 192           IM_WORK_T ScaDa = Sca * orig_alpha;
1079 192           IM_WORK_T DcaSa = Dca * src_alpha;
1080 96 50         IM_WORK_T minc = ScaDa < DcaSa ? ScaDa : DcaSa;
1081 192           outp->channel[ch] =
1082             (
1083 192           minc + (Sca + Dca) * IM_SAMPLE_MAX
1084 192           - ScaDa - DcaSa
1085 192           ) / (IM_SAMPLE_MAX * dest_alpha);
1086             }
1087 64           outp->channel[color_channels] = dest_alpha;
1088             }
1089 64           ++outp;
1090 64           ++inp;
1091             }
1092             }
1093             else {
1094 40 100         while (work_count--) {
    100          
1095 32           IM_WORK_T src_alpha = inp->channel[color_channels];
1096              
1097 32 50         if (src_alpha) {
    50          
1098 128 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1099 192           IM_WORK_T minc = outp->channel[ch] < inp->channel[ch]
1100 48 50         ? outp->channel[ch] : inp->channel[ch];
1101 96           outp->channel[ch] =
1102             (
1103 144           src_alpha * minc +
1104 96           outp->channel[ch] * ( IM_SAMPLE_MAX - src_alpha )
1105 96           ) / IM_SAMPLE_MAX;
1106             }
1107             }
1108 32           ++outp;
1109 32           ++inp;
1110             }
1111             }
1112 24           }
1113              
1114             static void
1115 24           IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
1116             int ch;
1117 24           IM_COLOR const *inp = in;
1118 24           IM_COLOR *outp = out;
1119 24           i_img_dim work_count = count;
1120 24 50         int color_channels = i_color_channels(channels);
    100          
    50          
    100          
1121              
1122 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
1123 80 100         while (work_count--) {
    100          
1124 64           IM_WORK_T src_alpha = inp->channel[color_channels];
1125              
1126 64 50         if (src_alpha) {
    50          
1127 64           IM_WORK_T orig_alpha = outp->channel[color_channels];
1128 128           IM_WORK_T dest_alpha = src_alpha + orig_alpha
1129 64           - src_alpha * orig_alpha / IM_SAMPLE_MAX;
1130 256 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1131 192           IM_WORK_T Sca = inp->channel[ch] * src_alpha;
1132 192           IM_WORK_T Dca = outp->channel[ch] * orig_alpha;
1133 192           IM_WORK_T ScaDa = Sca * orig_alpha;
1134 192           IM_WORK_T DcaSa = Dca * src_alpha;
1135 96 50         IM_WORK_T maxc = ScaDa > DcaSa ? ScaDa : DcaSa;
1136 192           outp->channel[ch] =
1137             (
1138 192           maxc + (Sca + Dca) * IM_SAMPLE_MAX
1139 192           - ScaDa - DcaSa
1140 192           ) / (IM_SAMPLE_MAX * dest_alpha);
1141             }
1142 64           outp->channel[color_channels] = dest_alpha;
1143             }
1144 64           ++outp;
1145 64           ++inp;
1146             }
1147             }
1148             else {
1149 40 100         while (work_count--) {
    100          
1150 32           IM_WORK_T src_alpha = inp->channel[color_channels];
1151              
1152 32 50         if (src_alpha) {
    50          
1153 128 100         for (ch = 0; ch < color_channels; ++ch) {
    100          
1154 192           IM_WORK_T maxc = outp->channel[ch] > inp->channel[ch]
1155 48 50         ? outp->channel[ch] : inp->channel[ch];
1156 96           outp->channel[ch] =
1157             (
1158 144           src_alpha * maxc +
1159 96           outp->channel[ch] * ( IM_SAMPLE_MAX - src_alpha )
1160 96           ) / IM_SAMPLE_MAX;
1161             }
1162             }
1163 32           ++outp;
1164 32           ++inp;
1165             }
1166             }
1167 24           }
1168              
1169             #if IM_EIGHT_BIT
1170             #define IM_RGB_TO_HSV i_rgb_to_hsv
1171             #define IM_HSV_TO_RGB i_hsv_to_rgb
1172             #else
1173             #define IM_RGB_TO_HSV i_rgb_to_hsvf
1174             #define IM_HSV_TO_RGB i_hsv_to_rgbf
1175             #endif
1176              
1177             static void
1178 24           IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
1179 24 50         if (channels > 2) {
    50          
1180 24           IM_COLOR *inp = in;
1181 24           IM_COLOR const *outp = out;
1182 24           i_img_dim work_count = count;
1183              
1184 40 50         if (i_has_alpha(channels)) {
    100          
    50          
    100          
1185 80 100         while (work_count--) {
    100          
1186 64           IM_COLOR c = *inp;
1187 64           IM_RGB_TO_HSV(&c);
1188             /* only transfer hue if there's saturation */
1189 64 50         if (c.channel[1] && inp->channel[3] && outp->channel[3]) {
    50          
    50          
    50          
1190 64           *inp = *outp;
1191 64           IM_RGB_TO_HSV(inp);
1192             /* and no point in setting the target hue if the target has no sat */
1193 128 50         if (inp->channel[1]) {
    50          
1194 64           inp->channel[0] = c.channel[0];
1195 64           IM_HSV_TO_RGB(inp);
1196 64           inp->channel[3] = c.channel[3];
1197             }
1198             else {
1199 0           inp->channel[3] = 0;
1200             }
1201             }
1202             else {
1203 0           inp->channel[3] = 0;
1204             }
1205            
1206 64           ++outp;
1207 64           ++inp;
1208             }
1209             }
1210             else {
1211 40 100         while (work_count--) {
    100          
1212 32           IM_COLOR c = *inp;
1213 32           IM_RGB_TO_HSV(&c);
1214             /* only transfer hue if there's saturation */
1215 32 50         if (c.channel[1] && inp->channel[3]) {
    50          
1216 32           *inp = *outp;
1217 32           IM_RGB_TO_HSV(inp);
1218             /* and no point in setting the target hue if the target has no sat */
1219 64 50         if (inp->channel[1]) {
    50          
1220 32           inp->channel[0] = c.channel[0];
1221 32           IM_HSV_TO_RGB(inp);
1222 32           inp->channel[3] = c.channel[3];
1223             }
1224             }
1225             else {
1226 0           inp->channel[3] = 0;
1227             }
1228            
1229 32           ++outp;
1230 32           ++inp;
1231             }
1232             }
1233              
1234 24           IM_SUFFIX(combine_line_na)(out, in, channels, count);
1235             }
1236 24           }
1237              
1238             static void
1239 24           IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
1240 24 50         if (channels > 2) {
    50          
1241 24           IM_COLOR *inp = in;
1242 24           IM_COLOR const *outp = out;
1243 24           i_img_dim work_count = count;
1244              
1245 120 100         while (work_count--) {
    100          
1246 96           IM_COLOR c = *inp;
1247 96           *inp = *outp;
1248 96           IM_RGB_TO_HSV(&c);
1249 96           IM_RGB_TO_HSV(inp);
1250 96           inp->channel[1] = c.channel[1];
1251 96           IM_HSV_TO_RGB(inp);
1252 96           inp->channel[3] = c.channel[3];
1253 96           ++outp;
1254 96           ++inp;
1255             }
1256              
1257 24           IM_SUFFIX(combine_line_na)(out, in, channels, count);
1258             }
1259 24           }
1260              
1261             static void
1262 24           IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
1263 24 50         if (channels > 2) {
    50          
1264 24           IM_COLOR *inp = in;
1265 24           IM_COLOR const *outp = out;
1266 24           i_img_dim work_count = count;
1267              
1268 120 100         while (work_count--) {
    100          
1269 96           IM_COLOR c = *inp;
1270 96           *inp = *outp;
1271 96           IM_RGB_TO_HSV(&c);
1272 96           IM_RGB_TO_HSV(inp);
1273 96           inp->channel[2] = c.channel[2];
1274 96           IM_HSV_TO_RGB(inp);
1275 96           inp->channel[3] = c.channel[3];
1276 96           ++outp;
1277 96           ++inp;
1278             }
1279             }
1280              
1281             /* all images have a "value channel" - for greyscale it's the only
1282             colour channel */
1283 24           IM_SUFFIX(combine_line_na)(out, in, channels, count);
1284 24           }
1285              
1286             static void
1287 324           IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
1288 324 50         if (channels > 2) {
    50          
1289 324           IM_COLOR *inp = in;
1290 324           IM_COLOR const *outp = out;
1291 324           i_img_dim work_count = count;
1292              
1293 45420 100         while (work_count--) {
    100          
1294 45096           IM_COLOR c = *inp;
1295 45096           *inp = *outp;
1296 45096           IM_RGB_TO_HSV(&c);
1297 45096           IM_RGB_TO_HSV(inp);
1298 45096           inp->channel[0] = c.channel[0];
1299 45096           inp->channel[1] = c.channel[1];
1300 45096           IM_HSV_TO_RGB(inp);
1301 45096           inp->channel[3] = c.channel[3];
1302 45096           ++outp;
1303 45096           ++inp;
1304             }
1305              
1306 324           IM_SUFFIX(combine_line_na)(out, in, channels, count);
1307             }
1308 324           }
1309              
1310             #undef IM_RGB_TO_HSV
1311             #undef IM_HSV_TO_RGB
1312              
1313             #/code