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