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