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