maybe I'll learn to type one day
[imager.git] / fills.c
CommitLineData
f1ac5027
TC
1#include "image.h"
2#include "imagei.h"
3
4/*
773bc121 5=head1 NAME
f1ac5027 6
773bc121 7fills.c - implements the basic general fills
f1ac5027 8
773bc121
TC
9=head1 SYNOPSIS
10
11 i_fill_t *fill;
12 i_color c1, c2;
13 i_fcolor fc1, fc2;
14 int combine;
15 fill = i_new_fill_solidf(&fc1, combine);
16 fill = i_new_fill_solid(&c1, combine);
17 fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
18 fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
19 i_fill_destroy(fill);
20
21=head1 DESCRIPTION
22
23Implements the basic general fills, which can be used for filling some
24shapes and for flood fills.
25
26Each fill can implement up to 3 functions:
27
28=over
29
30=item fill_with_color
31
32called for fills on 8-bit images. This can be NULL in which case the
33fill_with_colorf function is called.
34
35=item fill_with_fcolor
36
37called for fills on non-8-bit images or when fill_with_color is NULL.
38
39=item destroy
40
41called by i_fill_destroy() if non-NULL, to release any extra resources
42that the fill may need.
43
44=back
45
46fill_with_color and fill_with_fcolor are basically the same function
47except that the first works with lines of i_color and the second with
48lines of i_fcolor.
49
50If the combines member if non-zero the line data is populated from the
51target image before calling fill_with_*color.
52
53fill_with_color needs to fill the I<data> parameter with the fill
54pixels. If combines is non-zero it the fill pixels should be combined
55with the existing data.
56
57The current fills are:
58
59=over
60
61=item *
62
63solid fill
64
65=item *
66
67hatched fill
68
69=item *
70
71fountain fill
72
73=back
74
75Fountain fill is implemented by L<filters.c>.
76
efdc2568
TC
77Other fills that could be implemented include:
78
79=over
80
81=item *
82
83image - an image tiled over the fill area, with an offset either
84horizontally or vertically.
85
86=item *
87
88checkerboard - combine 2 fills in a checkerboard
89
90=item *
91
92combine - combine the levels of 2 other fills based in the levels of
93an image
94
95=item *
96
97regmach - use the register machine to generate colors
98
99=back
100
773bc121
TC
101=over
102
103=cut
f1ac5027
TC
104*/
105
106static i_color fcolor_to_color(i_fcolor *c) {
107 int ch;
108 i_color out;
109
110 for (ch = 0; ch < MAXCHANNELS; ++ch)
111 out.channel[ch] = SampleFTo8(c->channel[ch]);
976efad5
TC
112
113 return out;
f1ac5027
TC
114}
115
116static i_fcolor color_to_fcolor(i_color *c) {
117 int ch;
976efad5 118 i_fcolor out;
f1ac5027
TC
119
120 for (ch = 0; ch < MAXCHANNELS; ++ch)
121 out.channel[ch] = Sample8ToF(c->channel[ch]);
976efad5
TC
122
123 return out;
f1ac5027
TC
124}
125
efdc2568 126/* alpha combine in with out */
f1ac5027
TC
127#define COMBINE(out, in, channels) \
128 { \
129 int ch; \
130 for (ch = 0; ch < (channels); ++ch) { \
131 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
132 + (in).channel[ch] * (in).channel[3]) / 255; \
133 } \
134 }
135
efdc2568
TC
136/* alpha combine in with out, in this case in is a simple array of
137 samples, potentially not integers - the mult combiner uses doubles
138 for accuracy */
139#define COMBINEA(out, in, channels) \
140 { \
141 int ch; \
142 for (ch = 0; ch < (channels); ++ch) { \
143 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
144 + (in)[ch] * (in)[3]) / 255; \
145 } \
146 }
147
f1ac5027
TC
148#define COMBINEF(out, in, channels) \
149 { \
150 int ch; \
151 for (ch = 0; ch < (channels); ++ch) { \
152 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
153 + (in).channel[ch] * (in).channel[3]; \
154 } \
155 }
156
efdc2568
TC
157typedef struct
158{
159 i_fill_t base;
160 i_color c;
161 i_fcolor fc;
162} i_fill_solid_t;
163
f1ac5027 164static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
efdc2568 165 i_color *, i_color *);
f1ac5027 166static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
efdc2568 167 i_fcolor *, i_fcolor *);
f1ac5027 168static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels,
efdc2568 169 i_color *, i_color *);
f1ac5027 170static void fill_solidf_comb(i_fill_t *, int x, int y, int width,
efdc2568 171 int channels, i_fcolor *, i_fcolor *);
f1ac5027
TC
172
173static i_fill_solid_t base_solid_fill =
174{
175 {
176 fill_solid,
177 fill_solidf,
178 NULL,
efdc2568
TC
179 NULL,
180 NULL,
f1ac5027
TC
181 },
182};
183static i_fill_solid_t base_solid_fill_comb =
184{
185 {
186 fill_solid_comb,
187 fill_solidf_comb,
188 NULL,
efdc2568
TC
189 NULL,
190 NULL,
f1ac5027
TC
191 },
192};
193
773bc121
TC
194/*
195=item i_fill_destroy(fill)
196
197Call to destroy any fill object.
198
199=cut
200*/
201
f1ac5027
TC
202void
203i_fill_destroy(i_fill_t *fill) {
204 if (fill->destroy)
205 (fill->destroy)(fill);
206 myfree(fill);
207}
208
773bc121
TC
209/*
210=item i_new_fill_solidf(color, combine)
211
212Create a solid fill based on a float color.
213
214If combine is non-zero then alpha values will be combined.
215
216=cut
217*/
218
f1ac5027
TC
219i_fill_t *
220i_new_fill_solidf(i_fcolor *c, int combine) {
221 int ch;
222 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
223
efdc2568 224 if (combine && c->channel[3] < 1.0) {
f1ac5027 225 *fill = base_solid_fill_comb;
efdc2568
TC
226 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
227 }
f1ac5027
TC
228 else
229 *fill = base_solid_fill;
230 fill->fc = *c;
231 for (ch = 0; ch < MAXCHANNELS; ++ch) {
232 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
233 }
234
235 return &fill->base;
236}
237
773bc121
TC
238/*
239=item i_new_fill_solid(color, combine)
240
241Create a solid fill based.
242
243If combine is non-zero then alpha values will be combined.
244
245=cut
246*/
247
f1ac5027
TC
248i_fill_t *
249i_new_fill_solid(i_color *c, int combine) {
250 int ch;
251 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
252
efdc2568 253 if (combine && c->channel[3] < 255) {
f1ac5027 254 *fill = base_solid_fill_comb;
efdc2568
TC
255 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
256 }
f1ac5027
TC
257 else
258 *fill = base_solid_fill;
259 fill->c = *c;
260 for (ch = 0; ch < MAXCHANNELS; ++ch) {
261 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
262 }
263
264 return &fill->base;
265}
266
f1ac5027
TC
267static unsigned char
268builtin_hatches[][8] =
269{
270 {
271 /* 1x1 checkerboard */
272 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
273 },
274 {
275 /* 2x2 checkerboard */
276 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
277 },
278 {
279 /* 4 x 4 checkerboard */
280 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
281 },
282 {
283 /* single vertical lines */
284 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
285 },
286 {
287 /* double vertical lines */
288 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
289 },
290 {
291 /* quad vertical lines */
292 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
293 },
294 {
295 /* single hlines */
296 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297 },
298 {
299 /* double hlines */
300 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
301 },
302 {
303 /* quad hlines */
304 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
305 },
306 {
307 /* single / */
308 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
309 },
310 {
311 /* single \ */
312 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
313 },
314 {
315 /* double / */
316 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
317 },
318 {
319 /* double \ */
320 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
321 },
322 {
323 /* single grid */
324 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
325 },
326 {
327 /* double grid */
328 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
329 },
330 {
331 /* quad grid */
332 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
333 },
334 {
335 /* single dots */
336 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 },
338 {
339 /* 4 dots */
340 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
341 },
342 {
343 /* 16 dots */
344 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
345 },
346 {
347 /* simple stipple */
348 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
349 },
350 {
351 /* weave */
352 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
353 },
354 {
355 /* single cross hatch */
356 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
357 },
358 {
359 /* double cross hatch */
360 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
361 },
362 {
363 /* vertical lozenge */
364 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
365 },
366 {
367 /* horizontal lozenge */
368 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
369 },
370 {
371 /* scales overlapping downwards */
7a606d29 372 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
f1ac5027
TC
373 },
374 {
375 /* scales overlapping upwards */
7a606d29 376 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
f1ac5027
TC
377 },
378 {
379 /* scales overlapping leftwards */
7a606d29 380 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
f1ac5027
TC
381 },
382 {
383 /* scales overlapping rightwards */
7a606d29 384 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
f1ac5027
TC
385 },
386 {
387 /* denser stipple */
388 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
389 },
390 {
391 /* L-shaped tiles */
392 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
393 },
cc6483e0
TC
394 {
395 /* wider stipple */
396 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
397 },
f1ac5027
TC
398};
399
400typedef struct
401{
402 i_fill_t base;
403 i_color fg, bg;
404 i_fcolor ffg, fbg;
405 unsigned char hatch[8];
406 int dx, dy;
407} i_fill_hatch_t;
408
409static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 410 i_color *data, i_color *work);
f1ac5027 411static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 412 i_fcolor *data, i_fcolor *work);
773bc121
TC
413static
414i_fill_t *
415i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
416 int combine, int hatch, unsigned char *cust_hatch,
417 int dx, int dy);
418
419/*
420=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
421
422Creates a new hatched fill with the fg color used for the 1 bits in
423the hatch and bg for the 0 bits. If combine is non-zero alpha values
424will be combined.
f1ac5027 425
773bc121
TC
426If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
427hash definition, with the high-bits to the left.
428
429If cust_hatch is NULL then one of the standard hatches is used.
430
431(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
432
433=cut
434*/
435i_fill_t *
436i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch,
437 unsigned char *cust_hatch, int dx, int dy) {
438 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
439 dx, dy);
440}
441
442/*
443=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
444
445Creates a new hatched fill with the fg color used for the 1 bits in
446the hatch and bg for the 0 bits. If combine is non-zero alpha values
447will be combined.
448
449If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
450hash definition, with the high-bits to the left.
451
452If cust_hatch is NULL then one of the standard hatches is used.
453
454(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
455
456=cut
457*/
458i_fill_t *
459i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch,
460 unsigned char *cust_hatch, int dx, int dy) {
461 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
462 dx, dy);
463}
464
465#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
466
467/*
468=back
469
470=head1 INTERNAL FUNCTIONS
471
472=over
473
474=item fill_solid(fill, x, y, width, channels, data)
475
476The 8-bit sample fill function for non-combining solid fills.
477
478=cut
479*/
480static void
481fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 482 i_color *data, i_color *work) {
773bc121
TC
483 while (width-- > 0) {
484 *data++ = T_SOLID_FILL(fill)->c;
485 }
486}
487
488/*
489=item fill_solid(fill, x, y, width, channels, data)
490
491The floating sample fill function for non-combining solid fills.
492
493=cut
494*/
495static void
496fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 497 i_fcolor *data, i_fcolor *work) {
773bc121
TC
498 while (width-- > 0) {
499 *data++ = T_SOLID_FILL(fill)->fc;
500 }
501}
502
503/*
504=item fill_solid_comb(fill, x, y, width, channels, data)
505
506The 8-bit sample fill function for combining solid fills.
507
508=cut
509*/
510static void
511fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 512 i_color *data, i_color *work) {
773bc121 513 i_color c = T_SOLID_FILL(fill)->c;
efdc2568
TC
514 int count = width;
515 i_color *wstart = work;
773bc121
TC
516
517 while (width-- > 0) {
efdc2568 518 *work++ = c;
773bc121 519 }
efdc2568 520 (fill->combine)(data, wstart, channels, count);
773bc121
TC
521}
522
523/*
524=item fill_solidf_comb(fill, x, y, width, channels, data)
525
526The floating sample fill function for combining solid fills.
527
528=cut
529*/
530static void
531fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 532 i_fcolor *data, i_fcolor *work) {
773bc121 533 i_fcolor c = T_SOLID_FILL(fill)->fc;
efdc2568
TC
534 int count = width;
535 i_fcolor *wstart = work;
773bc121
TC
536
537 while (width-- > 0) {
efdc2568 538 *work++ = c;
773bc121 539 }
efdc2568 540 (fill->combinef)(data, wstart, channels, count);
773bc121
TC
541}
542
543/*
544=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
545
546Implements creation of hatch fill objects.
547
548=cut
549*/
f1ac5027
TC
550static
551i_fill_t *
552i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
553 int combine, int hatch, unsigned char *cust_hatch,
554 int dx, int dy) {
555 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t));
556
557 fill->base.fill_with_color = fill_hatch;
558 fill->base.fill_with_fcolor = fill_hatchf;
559 fill->base.destroy = NULL;
560 fill->fg = fg ? *fg : fcolor_to_color(ffg);
561 fill->bg = bg ? *bg : fcolor_to_color(fbg);
562 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
563 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
efdc2568
TC
564 if (combine && (fill->ffg.channel[0] < 1 || fill->fbg.channel[0] < 1)) {
565 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
566 }
567 else {
568 fill->base.combine = NULL;
569 fill->base.combinef = NULL;
570 }
f1ac5027
TC
571 if (cust_hatch) {
572 memcpy(fill->hatch, cust_hatch, 8);
573 }
574 else {
575 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
576 hatch = 0;
577 memcpy(fill->hatch, builtin_hatches[hatch], 8);
578 }
579 fill->dx = dx & 7;
580 fill->dy = dy & 7;
581
582 return &fill->base;
583}
584
773bc121
TC
585/*
586=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 587
773bc121 588The 8-bit sample fill function for hatched fills.
f1ac5027 589
773bc121
TC
590=back
591*/
f1ac5027 592static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 593 i_color *data, i_color *work) {
f1ac5027
TC
594 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
595 int byte = f->hatch[(y + f->dy) & 7];
596 int xpos = (x + f->dx) & 7;
597 int mask = 128 >> xpos;
598
efdc2568
TC
599 if (fill->combine) {
600 int count = width;
601 i_color *wstart = work;
f1ac5027 602
efdc2568
TC
603 while (count-- > 0) {
604 *work++ = (byte & mask) ? f->fg : f->bg;
605
606 if ((mask >>= 1) == 0)
607 mask = 128;
f1ac5027 608 }
efdc2568
TC
609 (fill->combine)(data, wstart, channels, width);
610 }
611 else {
612 while (width-- > 0) {
613 *data++ = (byte & mask) ? f->fg : f->bg;
614
615 if ((mask >>= 1) == 0)
616 mask = 128;
f1ac5027 617 }
f1ac5027
TC
618 }
619}
620
773bc121
TC
621/*
622=item fill_hatchf(fill, x, y, width, channels, data)
623
624The floating sample fill function for hatched fills.
625
626=back
627*/
f1ac5027 628static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
efdc2568 629 i_fcolor *data, i_fcolor *work) {
f1ac5027
TC
630 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
631 int byte = f->hatch[(y + f->dy) & 7];
632 int xpos = (x + f->dx) & 7;
633 int mask = 128 >> xpos;
634
efdc2568
TC
635 if (fill->combinef) {
636 int count = width;
637 i_fcolor *wstart = work;
638
639 while (count-- > 0) {
640 *work++ = (byte & mask) ? f->ffg : f->fbg;
641
642 if ((mask >>= 1) == 0)
643 mask = 128;
644 }
645 (fill->combinef)(data, wstart, channels, width);
646 }
647 else {
648 while (width-- > 0) {
649 *data++ = (byte & mask) ? f->ffg : f->fbg;
f1ac5027 650
efdc2568
TC
651 if ((mask >>= 1) == 0)
652 mask = 128;
f1ac5027 653 }
efdc2568
TC
654 }
655}
656
657static void combine_replace(i_color *, i_color *, int, int);
658static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
659static void combine_alphablend(i_color *, i_color *, int, int);
660static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
661static void combine_mult(i_color *, i_color *, int, int);
662static void combine_multf(i_fcolor *, i_fcolor *, int, int);
663static void combine_dissolve(i_color *, i_color *, int, int);
664static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
665static void combine_add(i_color *, i_color *, int, int);
666static void combine_addf(i_fcolor *, i_fcolor *, int, int);
667static void combine_subtract(i_color *, i_color *, int, int);
668static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
669static void combine_diff(i_color *, i_color *, int, int);
670static void combine_difff(i_fcolor *, i_fcolor *, int, int);
671static void combine_darken(i_color *, i_color *, int, int);
672static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
673static void combine_lighten(i_color *, i_color *, int, int);
674static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
675static void combine_hue(i_color *, i_color *, int, int);
676static void combine_huef(i_fcolor *, i_fcolor *, int, int);
677static void combine_sat(i_color *, i_color *, int, int);
678static void combine_satf(i_fcolor *, i_fcolor *, int, int);
679static void combine_value(i_color *, i_color *, int, int);
680static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
681static void combine_color(i_color *, i_color *, int, int);
682static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
683
684struct i_combines {
685 i_fill_combine_f combine;
686 i_fill_combinef_f combinef;
687} combines[] =
688{
689 { /* replace */
690 combine_replace,
691 combine_replacef,
692 },
693 { /* alpha blend */
694 combine_alphablend,
695 combine_alphablendf,
696 },
697 {
698 /* multiply */
699 combine_mult,
700 combine_multf,
701 },
702 {
703 /* dissolve */
704 combine_dissolve,
705 combine_dissolvef,
706 },
707 {
708 /* add */
709 combine_add,
710 combine_addf,
711 },
712 {
713 /* subtract */
714 combine_subtract,
715 combine_subtractf,
716 },
717 {
718 /* diff */
719 combine_diff,
720 combine_difff,
721 },
722 {
723 combine_lighten,
724 combine_lightenf,
725 },
726 {
727 combine_darken,
728 combine_darkenf,
729 },
730 {
731 combine_hue,
732 combine_huef,
733 },
734 {
735 combine_sat,
736 combine_satf,
737 },
738 {
739 combine_value,
740 combine_valuef,
741 },
742 {
743 combine_color,
744 combine_colorf,
745 },
746};
747
748/*
749=item i_get_combine(combine, color_func, fcolor_func)
750
751=cut
752*/
753
754void i_get_combine(int combine, i_fill_combine_f *color_func,
755 i_fill_combinef_f *fcolor_func) {
756 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
757 combine = 0;
758
759 *color_func = combines[combine].combine;
760 *fcolor_func = combines[combine].combinef;
761}
762
763static void combine_replace(i_color *out, i_color *in, int channels, int count) {
764 while (count--) {
765 *out++ = *in++;
766 }
767}
768
769static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
770 while (count--) {
771 *out++ = *in++;
772 }
773}
774
775static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
776 while (count--) {
777 COMBINE(*out, *in, channels);
778 ++out;
779 ++in;
780 }
781}
782
783static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
784 while (count--) {
785 COMBINEF(*out, *in, channels);
786 ++out;
787 ++in;
788 }
789}
790
791static void combine_mult(i_color *out, i_color *in, int channels, int count) {
792 int ch;
793
794 while (count--) {
795 i_color c = *in;
796 double mult[MAXCHANNELS];
797 mult[3] = in->channel[3];
798 for (ch = 0; ch < (channels); ++ch) {
799 if (ch != 3)
800 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
801 }
802 COMBINEA(*out, mult, channels);
803 ++out;
804 ++in;
805 }
806}
807
808static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
809 int ch;
810
811 while (count--) {
812 i_fcolor c = *in;
813 for (ch = 0; ch < channels; ++ch) {
814 if (ch != 3)
815 c.channel[ch] = out->channel[ch] * in->channel[ch];
816 }
817 COMBINEF(*out, c, channels);
818 ++out;
819 ++in;
820 }
821}
822
823static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
824 int ch;
825
826 while (count--) {
827 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
828 COMBINE(*out, *in, channels);
829 ++out;
830 ++in;
831 }
832}
833
834static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
835 int ch;
836
837 while (count--) {
838 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
839 COMBINEF(*out, *in, channels);
840 ++out;
841 ++in;
842 }
843}
844
845static void combine_add(i_color *out, i_color *in, int channels, int count) {
846 int ch;
847
848 while (count--) {
849 i_color c = *in;
850 for (ch = 0; ch < (channels); ++ch) {
851 if (ch != 3) {
852 int total = out->channel[ch] + in->channel[ch];
853 if (total > 255)
854 total = 255;
855 c.channel[ch] = total;
856 }
857 }
858 COMBINE(*out, c, channels);
859 ++out;
860 ++in;
861 }
862}
863
864static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
865 int ch;
866
867 while (count--) {
868 i_fcolor c = *in;
869 for (ch = 0; ch < (channels); ++ch) {
870 if (ch != 3) {
871 double total = out->channel[ch] + in->channel[ch];
872 if (total > 1.0)
873 total = 1.0;
874 out->channel[ch] = total;
875 }
876 }
877 COMBINEF(*out, c, channels);
878 ++out;
879 ++in;
880 }
881}
882
883static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
884 int ch;
885
886 while (count--) {
887 i_color c = *in;
888 for (ch = 0; ch < (channels); ++ch) {
889 if (ch != 3) {
890 int total = out->channel[ch] - in->channel[ch];
891 if (total < 0)
892 total = 0;
893 c.channel[ch] = total;
894 }
895 }
896 COMBINE(*out, c, channels);
897 ++out;
898 ++in;
899 }
900}
901
902static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
903 int ch;
904
905 while (count--) {
906 i_fcolor c = *in;
907 for (ch = 0; ch < channels; ++ch) {
908 if (ch != 3) {
909 double total = out->channel[ch] - in->channel[ch];
910 if (total < 0)
911 total = 0;
912 c.channel[ch] = total;
913 }
914 }
915 COMBINEF(*out, c, channels);
916 ++out;
917 ++in;
918 }
919}
920
921static void combine_diff(i_color *out, i_color *in, int channels, int count) {
922 int ch;
923
924 while (count--) {
925 i_color c = *in;
926 for (ch = 0; ch < (channels); ++ch) {
927 if (ch != 3)
928 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
929 }
930 COMBINE(*out, c, channels)
931 ++out;
932 ++in;
933 }
934}
935
936static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
937 int ch;
938
939 while (count--) {
940 i_fcolor c = *in;
941 for (ch = 0; ch < (channels); ++ch) {
942 if (ch != 3)
943 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
f1ac5027 944 }
efdc2568
TC
945 COMBINEF(*out, c, channels);
946 ++out;
947 ++in;
f1ac5027
TC
948 }
949}
773bc121 950
efdc2568
TC
951static void combine_darken(i_color *out, i_color *in, int channels, int count) {
952 int ch;
953
954 while (count--) {
955 for (ch = 0; ch < channels; ++ch) {
956 if (ch != 3 && out->channel[ch] < in->channel[ch])
957 in->channel[ch] = out->channel[ch];
958 }
959 COMBINE(*out, *in, channels);
960 ++out;
961 ++in;
962 }
963}
964
965static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
966 int ch;
967
968 while (count--) {
969 for (ch = 0; ch < channels; ++ch) {
970 if (ch != 3 && out->channel[ch] < in->channel[ch])
971 in->channel[ch] = out->channel[ch];
972 }
973 COMBINEF(*out, *in, channels);
974 ++out;
975 ++in;
976 }
977}
978
979static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
980 int ch;
981
982 while (count--) {
983 for (ch = 0; ch < channels; ++ch) {
984 if (ch != 3 && out->channel[ch] > in->channel[ch])
985 in->channel[ch] = out->channel[ch];
986 }
987 COMBINE(*out, *in, channels);
988 ++out;
989 ++in;
990 }
991}
992
993static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
994 int ch;
995
996 while (count--) {
997 for (ch = 0; ch < channels; ++ch) {
998 if (ch != 3 && out->channel[ch] > in->channel[ch])
999 in->channel[ch] = out->channel[ch];
1000 }
1001 COMBINEF(*out, *in, channels);
1002 ++out;
1003 ++in;
1004 }
1005}
1006
1007static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1008 while (count--) {
1009 i_color c = *out;
1010 i_rgb_to_hsv(&c);
1011 i_rgb_to_hsv(in);
1012 c.channel[0] = in->channel[0];
1013 i_hsv_to_rgb(&c);
976efad5 1014 c.channel[3] = in->channel[3];
efdc2568
TC
1015 COMBINE(*out, c, channels);
1016 ++out;
1017 ++in;
1018 }
1019}
1020
1021static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1022 while (count--) {
1023 i_fcolor c = *out;
1024 i_rgb_to_hsvf(&c);
1025 i_rgb_to_hsvf(in);
1026 c.channel[0] = in->channel[0];
1027 i_hsv_to_rgbf(&c);
1028 c.channel[3] = in->channel[3];
1029 COMBINEF(*out, c, channels);
1030 ++out;
1031 ++in;
1032 }
1033}
1034
1035static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1036 while (count--) {
1037 i_color c = *out;
1038 i_rgb_to_hsv(&c);
1039 i_rgb_to_hsv(in);
1040 c.channel[1] = in->channel[1];
1041 i_hsv_to_rgb(&c);
1042 c.channel[3] = in->channel[3];
1043 COMBINE(*out, c, channels);
1044 ++out;
1045 ++in;
1046 }
1047}
1048
1049static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1050 while (count--) {
1051 i_fcolor c = *out;
1052 i_rgb_to_hsvf(&c);
1053 i_rgb_to_hsvf(in);
1054 c.channel[1] = in->channel[1];
1055 i_hsv_to_rgbf(&c);
1056 c.channel[3] = in->channel[3];
1057 COMBINEF(*out, c, channels);
1058 ++out;
1059 ++in;
1060 }
1061}
1062
1063static void combine_value(i_color *out, i_color *in, int channels, int count) {
1064 while (count--) {
1065 i_color c = *out;
1066 i_rgb_to_hsv(&c);
1067 i_rgb_to_hsv(in);
1068 c.channel[2] = in->channel[2];
1069 i_hsv_to_rgb(&c);
1070 c.channel[3] = in->channel[3];
1071 COMBINE(*out, c, channels);
1072 ++out;
1073 ++in;
1074 }
1075}
1076
1077static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1078 int count) {
1079 while (count--) {
1080 i_fcolor c = *out;
1081 i_rgb_to_hsvf(&c);
1082 i_rgb_to_hsvf(in);
1083 c.channel[2] = in->channel[2];
1084 i_hsv_to_rgbf(&c);
1085 c.channel[3] = in->channel[3];
1086 COMBINEF(*out, c, channels);
1087 ++out;
1088 ++in;
1089 }
1090}
1091
1092static void combine_color(i_color *out, i_color *in, int channels, int count) {
1093 while (count--) {
1094 i_color c = *out;
1095 i_rgb_to_hsv(&c);
1096 i_rgb_to_hsv(in);
1097 c.channel[0] = in->channel[0];
1098 c.channel[1] = in->channel[1];
1099 i_hsv_to_rgb(&c);
1100 c.channel[3] = in->channel[3];
1101 COMBINE(*out, c, channels);
1102 ++out;
1103 ++in;
1104 }
1105}
1106
1107static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1108 int count) {
1109 while (count--) {
1110 i_fcolor c = *out;
1111 i_rgb_to_hsvf(&c);
1112 i_rgb_to_hsvf(in);
1113 c.channel[0] = in->channel[0];
1114 c.channel[1] = in->channel[1];
1115 i_hsv_to_rgbf(&c);
1116 c.channel[3] = in->channel[3];
1117 COMBINEF(*out, c, channels);
1118 ++out;
1119 ++in;
1120 }
1121}
1122
1123
773bc121
TC
1124/*
1125=back
1126
1127=head1 AUTHOR
1128
1129Tony Cook <tony@develop-help.com>
1130
1131=head1 SEE ALSO
1132
1133Imager(3)
1134
1135=cut
1136*/