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