- start of external Imager API access:
[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
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
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
TC
224i_fill_t *
225i_new_fill_solidf(i_fcolor *c, int combine) {
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
TC
255i_fill_t *
256i_new_fill_solid(i_color *c, int combine) {
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 *
422i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
423 int combine, int hatch, unsigned char *cust_hatch,
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 *
445i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch,
446 unsigned char *cust_hatch, int dx, int dy) {
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 *
470i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch,
471 unsigned char *cust_hatch, int dx, int dy) {
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 *
502i_new_fill_image(i_img *im, 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 *
615i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
616 int combine, int hatch, unsigned char *cust_hatch,
617 int dx, int dy) {
f0960b14 618 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
f1ac5027
TC
619
620 fill->base.fill_with_color = fill_hatch;
621 fill->base.fill_with_fcolor = fill_hatchf;
622 fill->base.destroy = NULL;
623 fill->fg = fg ? *fg : fcolor_to_color(ffg);
624 fill->bg = bg ? *bg : fcolor_to_color(fbg);
625 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
626 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
141a6114 627 if (combine) {
efdc2568
TC
628 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
629 }
630 else {
631 fill->base.combine = NULL;
632 fill->base.combinef = NULL;
633 }
f1ac5027
TC
634 if (cust_hatch) {
635 memcpy(fill->hatch, cust_hatch, 8);
636 }
637 else {
638 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
639 hatch = 0;
640 memcpy(fill->hatch, builtin_hatches[hatch], 8);
641 }
642 fill->dx = dx & 7;
643 fill->dy = dy & 7;
644
645 return &fill->base;
646}
647
773bc121
TC
648/*
649=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 650
773bc121 651The 8-bit sample fill function for hatched fills.
f1ac5027 652
b8c2033e 653=cut
773bc121 654*/
f1ac5027 655static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 656 i_color *data) {
f1ac5027
TC
657 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
658 int byte = f->hatch[(y + f->dy) & 7];
659 int xpos = (x + f->dx) & 7;
660 int mask = 128 >> xpos;
661
43c5dacb
TC
662 while (width-- > 0) {
663 *data++ = (byte & mask) ? f->fg : f->bg;
664
665 if ((mask >>= 1) == 0)
666 mask = 128;
f1ac5027
TC
667 }
668}
669
773bc121
TC
670/*
671=item fill_hatchf(fill, x, y, width, channels, data)
672
673The floating sample fill function for hatched fills.
674
675=back
676*/
f1ac5027 677static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 678 i_fcolor *data) {
f1ac5027
TC
679 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
680 int byte = f->hatch[(y + f->dy) & 7];
681 int xpos = (x + f->dx) & 7;
682 int mask = 128 >> xpos;
683
43c5dacb
TC
684 while (width-- > 0) {
685 *data++ = (byte & mask) ? f->ffg : f->fbg;
686
687 if ((mask >>= 1) == 0)
688 mask = 128;
efdc2568
TC
689 }
690}
691
f576ce7e
TC
692/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
693/* linear interpolation */
694static i_color interp_i_color(i_color before, i_color after, double pos,
695 int channels) {
696 i_color out;
697 int ch;
698
699 pos -= floor(pos);
700 for (ch = 0; ch < channels; ++ch)
701 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
702 if (out.channel[3])
703 for (ch = 0; ch < channels; ++ch)
704 if (ch != 3) {
705 int temp = out.channel[ch] * 255 / out.channel[3];
706 if (temp > 255)
707 temp = 255;
708 out.channel[ch] = temp;
709 }
710
711 return out;
712}
713
714/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
715/* linear interpolation */
716static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
717 int channels) {
718 i_fcolor 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];
724 if (out.channel[3])
725 for (ch = 0; ch < channels; ++ch)
726 if (ch != 3) {
727 int temp = out.channel[ch] / out.channel[3];
728 if (temp > 1.0)
729 temp = 1.0;
730 out.channel[ch] = temp;
731 }
732
733 return out;
734}
735
736/*
737=item fill_image(fill, x, y, width, channels, data, work)
738
739=cut
740*/
741static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 742 i_color *data) {
f576ce7e 743 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 744 int i = 0;
cde2dbc7 745 i_color *out = data;
f576ce7e
TC
746
747 if (f->has_matrix) {
748 /* the hard way */
749 while (i < width) {
750 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
751 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
752 double ix = floor(rx / f->src->xsize);
753 double iy = floor(ry / f->src->ysize);
754 i_color c[2][2];
755 i_color c2[2];
756 int dy;
757
758 if (f->xoff) {
759 rx += iy * f->xoff;
760 ix = floor(rx / f->src->xsize);
761 }
762 else if (f->yoff) {
763 ry += ix * f->yoff;
764 iy = floor(ry / f->src->ysize);
765 }
766 rx -= ix * f->src->xsize;
767 ry -= iy * f->src->ysize;
768
769 for (dy = 0; dy < 2; ++dy) {
770 if ((int)rx == f->src->xsize-1) {
771 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
772 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
773 }
774 else {
775 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
776 c[dy]);
777 }
778 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
779 }
cde2dbc7 780 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
781 ++i;
782 }
783 }
784 else {
785 /* the easy way */
786 /* this should be possible to optimize to use i_glin() */
787 while (i < width) {
788 int rx = x+i;
789 int ry = y;
790 int ix = rx / f->src->xsize;
791 int iy = ry / f->src->ysize;
792
793 if (f->xoff) {
794 rx += iy * f->xoff;
795 ix = rx / f->src->xsize;
796 }
797 else if (f->yoff) {
798 ry += ix * f->yoff;
799 iy = ry / f->src->xsize;
800 }
801 rx -= ix * f->src->xsize;
802 ry -= iy * f->src->ysize;
cde2dbc7
TC
803 i_gpix(f->src, rx, ry, out);
804 ++out;
f576ce7e
TC
805 ++i;
806 }
807 }
cde2dbc7
TC
808 if (f->src->channels == 3) {
809 /* just set the alpha */
810 for (i = 0; i < width; ++i) {
811 data->channel[3] = 255;
812 data++;
813 }
814 }
815 else if (f->src->channels == 2) {
816 /* copy the alpha to channel 3, duplicate the grey value */
817 for (i = 0; i < width; ++i) {
818 data->channel[3] = data->channel[1];
819 data->channel[1] = data->channel[2] = data->channel[0];
820 data++;
821 }
822 }
823 else if (f->src->channels == 1) {
824 /* set the alpha, duplicate grey */
825 for (i = 0; i < width; ++i) {
826 data->channel[3] = 255;
827 data->channel[1] = data->channel[2] = data->channel[0];
828 data++;
829 }
830 }
f576ce7e
TC
831}
832
833/*
834=item fill_image(fill, x, y, width, channels, data, work)
835
836=cut
837*/
838static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 839 i_fcolor *data) {
f576ce7e 840 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 841 int i = 0;
f576ce7e
TC
842
843 if (f->has_matrix) {
844 /* the hard way */
845 while (i < width) {
846 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
847 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
848 double ix = floor(rx / f->src->xsize);
849 double iy = floor(ry / f->src->ysize);
850 i_fcolor c[2][2];
851 i_fcolor c2[2];
852 int dy;
853
854 if (f->xoff) {
855 rx += iy * f->xoff;
856 ix = floor(rx / f->src->xsize);
857 }
858 else if (f->yoff) {
859 ry += ix * f->yoff;
860 iy = floor(ry / f->src->ysize);
861 }
862 rx -= ix * f->src->xsize;
863 ry -= iy * f->src->ysize;
864
865 for (dy = 0; dy < 2; ++dy) {
866 if ((int)rx == f->src->xsize-1) {
867 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
868 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
869 }
870 else {
871 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
872 c[dy]);
873 }
874 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
875 }
43c5dacb 876 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
877 ++i;
878 }
879 }
880 else {
881 /* the easy way */
882 /* this should be possible to optimize to use i_glin() */
883 while (i < width) {
884 int rx = x+i;
885 int ry = y;
886 int ix = rx / f->src->xsize;
887 int iy = ry / f->src->ysize;
888
889 if (f->xoff) {
890 rx += iy * f->xoff;
891 ix = rx / f->src->xsize;
892 }
893 else if (f->yoff) {
894 ry += ix * f->yoff;
895 iy = ry / f->src->xsize;
896 }
897 rx -= ix * f->src->xsize;
898 ry -= iy * f->src->ysize;
43c5dacb
TC
899 i_gpixf(f->src, rx, ry, data);
900 ++data;
f576ce7e
TC
901 ++i;
902 }
903 }
cde2dbc7
TC
904 if (f->src->channels == 3) {
905 /* just set the alpha */
906 for (i = 0; i < width; ++i) {
907 data->channel[3] = 1.0;
908 data++;
909 }
910 }
911 else if (f->src->channels == 2) {
912 /* copy the alpha to channel 3, duplicate the grey value */
913 for (i = 0; i < width; ++i) {
914 data->channel[3] = data->channel[1];
915 data->channel[1] = data->channel[2] = data->channel[0];
916 data++;
917 }
918 }
919 else if (f->src->channels == 1) {
920 /* set the alpha, duplicate grey */
921 for (i = 0; i < width; ++i) {
922 data->channel[3] = 1.0;
923 data->channel[1] = data->channel[2] = data->channel[0];
924 data++;
925 }
926 }
f576ce7e
TC
927}
928
efdc2568
TC
929static void combine_replace(i_color *, i_color *, int, int);
930static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
931static void combine_alphablend(i_color *, i_color *, int, int);
932static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
933static void combine_mult(i_color *, i_color *, int, int);
934static void combine_multf(i_fcolor *, i_fcolor *, int, int);
935static void combine_dissolve(i_color *, i_color *, int, int);
936static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
937static void combine_add(i_color *, i_color *, int, int);
938static void combine_addf(i_fcolor *, i_fcolor *, int, int);
939static void combine_subtract(i_color *, i_color *, int, int);
940static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
941static void combine_diff(i_color *, i_color *, int, int);
942static void combine_difff(i_fcolor *, i_fcolor *, int, int);
943static void combine_darken(i_color *, i_color *, int, int);
944static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
945static void combine_lighten(i_color *, i_color *, int, int);
946static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
947static void combine_hue(i_color *, i_color *, int, int);
948static void combine_huef(i_fcolor *, i_fcolor *, int, int);
949static void combine_sat(i_color *, i_color *, int, int);
950static void combine_satf(i_fcolor *, i_fcolor *, int, int);
951static void combine_value(i_color *, i_color *, int, int);
952static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
953static void combine_color(i_color *, i_color *, int, int);
954static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
955
b33c08f8 956static struct i_combines {
efdc2568
TC
957 i_fill_combine_f combine;
958 i_fill_combinef_f combinef;
959} combines[] =
960{
961 { /* replace */
962 combine_replace,
963 combine_replacef,
964 },
965 { /* alpha blend */
966 combine_alphablend,
967 combine_alphablendf,
968 },
969 {
970 /* multiply */
971 combine_mult,
972 combine_multf,
973 },
974 {
975 /* dissolve */
976 combine_dissolve,
977 combine_dissolvef,
978 },
979 {
980 /* add */
981 combine_add,
982 combine_addf,
983 },
984 {
985 /* subtract */
986 combine_subtract,
987 combine_subtractf,
988 },
989 {
990 /* diff */
991 combine_diff,
992 combine_difff,
993 },
994 {
995 combine_lighten,
996 combine_lightenf,
997 },
998 {
999 combine_darken,
1000 combine_darkenf,
1001 },
1002 {
1003 combine_hue,
1004 combine_huef,
1005 },
1006 {
1007 combine_sat,
1008 combine_satf,
1009 },
1010 {
1011 combine_value,
1012 combine_valuef,
1013 },
1014 {
1015 combine_color,
1016 combine_colorf,
1017 },
1018};
1019
1020/*
1021=item i_get_combine(combine, color_func, fcolor_func)
1022
1023=cut
1024*/
1025
1026void i_get_combine(int combine, i_fill_combine_f *color_func,
1027 i_fill_combinef_f *fcolor_func) {
1028 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
1029 combine = 0;
1030
1031 *color_func = combines[combine].combine;
1032 *fcolor_func = combines[combine].combinef;
1033}
1034
1035static void combine_replace(i_color *out, i_color *in, int channels, int count) {
1036 while (count--) {
1037 *out++ = *in++;
1038 }
1039}
1040
1041static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1042 while (count--) {
1043 *out++ = *in++;
1044 }
1045}
1046
1047static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
1048 while (count--) {
1049 COMBINE(*out, *in, channels);
1050 ++out;
1051 ++in;
1052 }
1053}
1054
1055static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1056 while (count--) {
1057 COMBINEF(*out, *in, channels);
1058 ++out;
1059 ++in;
1060 }
1061}
1062
1063static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1064 int ch;
1065
1066 while (count--) {
efdc2568
TC
1067 double mult[MAXCHANNELS];
1068 mult[3] = in->channel[3];
1069 for (ch = 0; ch < (channels); ++ch) {
1070 if (ch != 3)
1071 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1072 }
1073 COMBINEA(*out, mult, channels);
1074 ++out;
1075 ++in;
1076 }
1077}
1078
1079static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1080 int ch;
1081
1082 while (count--) {
1083 i_fcolor c = *in;
1084 for (ch = 0; ch < channels; ++ch) {
1085 if (ch != 3)
1086 c.channel[ch] = out->channel[ch] * in->channel[ch];
1087 }
1088 COMBINEF(*out, c, channels);
1089 ++out;
1090 ++in;
1091 }
1092}
1093
1094static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
efdc2568
TC
1095 while (count--) {
1096 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1097 COMBINE(*out, *in, channels);
1098 ++out;
1099 ++in;
1100 }
1101}
1102
1103static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
efdc2568
TC
1104 while (count--) {
1105 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1106 COMBINEF(*out, *in, channels);
1107 ++out;
1108 ++in;
1109 }
1110}
1111
1112static void combine_add(i_color *out, i_color *in, int channels, int count) {
1113 int ch;
1114
1115 while (count--) {
1116 i_color c = *in;
1117 for (ch = 0; ch < (channels); ++ch) {
1118 if (ch != 3) {
1119 int total = out->channel[ch] + in->channel[ch];
1120 if (total > 255)
1121 total = 255;
1122 c.channel[ch] = total;
1123 }
1124 }
1125 COMBINE(*out, c, channels);
1126 ++out;
1127 ++in;
1128 }
1129}
1130
1131static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1132 int ch;
1133
1134 while (count--) {
1135 i_fcolor c = *in;
1136 for (ch = 0; ch < (channels); ++ch) {
1137 if (ch != 3) {
1138 double total = out->channel[ch] + in->channel[ch];
1139 if (total > 1.0)
1140 total = 1.0;
1141 out->channel[ch] = total;
1142 }
1143 }
1144 COMBINEF(*out, c, channels);
1145 ++out;
1146 ++in;
1147 }
1148}
1149
1150static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1151 int ch;
1152
1153 while (count--) {
1154 i_color c = *in;
1155 for (ch = 0; ch < (channels); ++ch) {
1156 if (ch != 3) {
1157 int total = out->channel[ch] - in->channel[ch];
1158 if (total < 0)
1159 total = 0;
1160 c.channel[ch] = total;
1161 }
1162 }
1163 COMBINE(*out, c, channels);
1164 ++out;
1165 ++in;
1166 }
1167}
1168
1169static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1170 int ch;
1171
1172 while (count--) {
1173 i_fcolor c = *in;
1174 for (ch = 0; ch < channels; ++ch) {
1175 if (ch != 3) {
1176 double total = out->channel[ch] - in->channel[ch];
1177 if (total < 0)
1178 total = 0;
1179 c.channel[ch] = total;
1180 }
1181 }
1182 COMBINEF(*out, c, channels);
1183 ++out;
1184 ++in;
1185 }
1186}
1187
1188static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1189 int ch;
1190
1191 while (count--) {
1192 i_color c = *in;
1193 for (ch = 0; ch < (channels); ++ch) {
1194 if (ch != 3)
1195 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1196 }
1197 COMBINE(*out, c, channels)
1198 ++out;
1199 ++in;
1200 }
1201}
1202
1203static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1204 int ch;
1205
1206 while (count--) {
1207 i_fcolor c = *in;
1208 for (ch = 0; ch < (channels); ++ch) {
1209 if (ch != 3)
1210 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
f1ac5027 1211 }
efdc2568
TC
1212 COMBINEF(*out, c, channels);
1213 ++out;
1214 ++in;
f1ac5027
TC
1215 }
1216}
773bc121 1217
efdc2568
TC
1218static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1219 int ch;
1220
1221 while (count--) {
1222 for (ch = 0; ch < channels; ++ch) {
1223 if (ch != 3 && out->channel[ch] < in->channel[ch])
1224 in->channel[ch] = out->channel[ch];
1225 }
1226 COMBINE(*out, *in, channels);
1227 ++out;
1228 ++in;
1229 }
1230}
1231
1232static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1233 int ch;
1234
1235 while (count--) {
1236 for (ch = 0; ch < channels; ++ch) {
1237 if (ch != 3 && out->channel[ch] < in->channel[ch])
1238 in->channel[ch] = out->channel[ch];
1239 }
1240 COMBINEF(*out, *in, channels);
1241 ++out;
1242 ++in;
1243 }
1244}
1245
1246static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1247 int ch;
1248
1249 while (count--) {
1250 for (ch = 0; ch < channels; ++ch) {
1251 if (ch != 3 && out->channel[ch] > in->channel[ch])
1252 in->channel[ch] = out->channel[ch];
1253 }
1254 COMBINE(*out, *in, channels);
1255 ++out;
1256 ++in;
1257 }
1258}
1259
1260static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1261 int ch;
1262
1263 while (count--) {
1264 for (ch = 0; ch < channels; ++ch) {
1265 if (ch != 3 && out->channel[ch] > in->channel[ch])
1266 in->channel[ch] = out->channel[ch];
1267 }
1268 COMBINEF(*out, *in, channels);
1269 ++out;
1270 ++in;
1271 }
1272}
1273
1274static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1275 while (count--) {
1276 i_color c = *out;
1277 i_rgb_to_hsv(&c);
1278 i_rgb_to_hsv(in);
1279 c.channel[0] = in->channel[0];
1280 i_hsv_to_rgb(&c);
976efad5 1281 c.channel[3] = in->channel[3];
efdc2568
TC
1282 COMBINE(*out, c, channels);
1283 ++out;
1284 ++in;
1285 }
1286}
1287
1288static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1289 while (count--) {
1290 i_fcolor c = *out;
1291 i_rgb_to_hsvf(&c);
1292 i_rgb_to_hsvf(in);
1293 c.channel[0] = in->channel[0];
1294 i_hsv_to_rgbf(&c);
1295 c.channel[3] = in->channel[3];
1296 COMBINEF(*out, c, channels);
1297 ++out;
1298 ++in;
1299 }
1300}
1301
1302static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1303 while (count--) {
1304 i_color c = *out;
1305 i_rgb_to_hsv(&c);
1306 i_rgb_to_hsv(in);
1307 c.channel[1] = in->channel[1];
1308 i_hsv_to_rgb(&c);
1309 c.channel[3] = in->channel[3];
1310 COMBINE(*out, c, channels);
1311 ++out;
1312 ++in;
1313 }
1314}
1315
1316static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1317 while (count--) {
1318 i_fcolor c = *out;
1319 i_rgb_to_hsvf(&c);
1320 i_rgb_to_hsvf(in);
1321 c.channel[1] = in->channel[1];
1322 i_hsv_to_rgbf(&c);
1323 c.channel[3] = in->channel[3];
1324 COMBINEF(*out, c, channels);
1325 ++out;
1326 ++in;
1327 }
1328}
1329
1330static void combine_value(i_color *out, i_color *in, int channels, int count) {
1331 while (count--) {
1332 i_color c = *out;
1333 i_rgb_to_hsv(&c);
1334 i_rgb_to_hsv(in);
1335 c.channel[2] = in->channel[2];
1336 i_hsv_to_rgb(&c);
1337 c.channel[3] = in->channel[3];
1338 COMBINE(*out, c, channels);
1339 ++out;
1340 ++in;
1341 }
1342}
1343
1344static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1345 int count) {
1346 while (count--) {
1347 i_fcolor c = *out;
1348 i_rgb_to_hsvf(&c);
1349 i_rgb_to_hsvf(in);
1350 c.channel[2] = in->channel[2];
1351 i_hsv_to_rgbf(&c);
1352 c.channel[3] = in->channel[3];
1353 COMBINEF(*out, c, channels);
1354 ++out;
1355 ++in;
1356 }
1357}
1358
1359static void combine_color(i_color *out, i_color *in, int channels, int count) {
1360 while (count--) {
1361 i_color c = *out;
1362 i_rgb_to_hsv(&c);
1363 i_rgb_to_hsv(in);
1364 c.channel[0] = in->channel[0];
1365 c.channel[1] = in->channel[1];
1366 i_hsv_to_rgb(&c);
1367 c.channel[3] = in->channel[3];
1368 COMBINE(*out, c, channels);
1369 ++out;
1370 ++in;
1371 }
1372}
1373
1374static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1375 int count) {
1376 while (count--) {
1377 i_fcolor c = *out;
1378 i_rgb_to_hsvf(&c);
1379 i_rgb_to_hsvf(in);
1380 c.channel[0] = in->channel[0];
1381 c.channel[1] = in->channel[1];
1382 i_hsv_to_rgbf(&c);
1383 c.channel[3] = in->channel[3];
1384 COMBINEF(*out, c, channels);
1385 ++out;
1386 ++in;
1387 }
1388}
1389
1390
773bc121
TC
1391/*
1392=back
1393
1394=head1 AUTHOR
1395
1396Tony Cook <tony@develop-help.com>
1397
1398=head1 SEE ALSO
1399
1400Imager(3)
1401
1402=cut
1403*/