- fix spelling errors patched by Debian (please report the issues you
[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);
52f2b10a 20 fill = i_new_fill_opacity(fill, alpha_mult);
773bc121
TC
21 i_fill_destroy(fill);
22
23=head1 DESCRIPTION
24
25Implements the basic general fills, which can be used for filling some
26shapes and for flood fills.
27
28Each fill can implement up to 3 functions:
29
30=over
31
32=item fill_with_color
33
34called for fills on 8-bit images. This can be NULL in which case the
35fill_with_colorf function is called.
36
37=item fill_with_fcolor
38
39called for fills on non-8-bit images or when fill_with_color is NULL.
40
41=item destroy
42
43called by i_fill_destroy() if non-NULL, to release any extra resources
44that the fill may need.
45
46=back
47
48fill_with_color and fill_with_fcolor are basically the same function
49except that the first works with lines of i_color and the second with
50lines of i_fcolor.
51
52If the combines member if non-zero the line data is populated from the
53target image before calling fill_with_*color.
54
55fill_with_color needs to fill the I<data> parameter with the fill
56pixels. If combines is non-zero it the fill pixels should be combined
57with the existing data.
58
59The current fills are:
60
61=over
62
63=item *
64
65solid fill
66
67=item *
68
69hatched fill
70
71=item *
72
73fountain fill
74
75=back
76
77Fountain fill is implemented by L<filters.c>.
78
efdc2568
TC
79Other fills that could be implemented include:
80
81=over
82
83=item *
84
85image - an image tiled over the fill area, with an offset either
86horizontally or vertically.
87
88=item *
89
90checkerboard - combine 2 fills in a checkerboard
91
92=item *
93
94combine - combine the levels of 2 other fills based in the levels of
95an image
96
97=item *
98
99regmach - use the register machine to generate colors
100
101=back
102
773bc121
TC
103=over
104
105=cut
f1ac5027
TC
106*/
107
97ac0a96 108static i_color fcolor_to_color(const i_fcolor *c) {
f1ac5027
TC
109 int ch;
110 i_color out;
111
112 for (ch = 0; ch < MAXCHANNELS; ++ch)
113 out.channel[ch] = SampleFTo8(c->channel[ch]);
976efad5
TC
114
115 return out;
f1ac5027
TC
116}
117
97ac0a96 118static i_fcolor color_to_fcolor(const i_color *c) {
f1ac5027 119 int ch;
976efad5 120 i_fcolor out;
f1ac5027
TC
121
122 for (ch = 0; ch < MAXCHANNELS; ++ch)
123 out.channel[ch] = Sample8ToF(c->channel[ch]);
976efad5
TC
124
125 return out;
f1ac5027
TC
126}
127
efdc2568 128/* alpha combine in with out */
f1ac5027
TC
129#define COMBINE(out, in, channels) \
130 { \
131 int ch; \
132 for (ch = 0; ch < (channels); ++ch) { \
133 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
134 + (in).channel[ch] * (in).channel[3]) / 255; \
135 } \
136 }
137
efdc2568
TC
138/* alpha combine in with out, in this case in is a simple array of
139 samples, potentially not integers - the mult combiner uses doubles
140 for accuracy */
141#define COMBINEA(out, in, channels) \
142 { \
143 int ch; \
144 for (ch = 0; ch < (channels); ++ch) { \
145 (out).channel[ch] = ((out).channel[ch] * (255 - (in)[3]) \
146 + (in)[ch] * (in)[3]) / 255; \
147 } \
148 }
149
f1ac5027
TC
150#define COMBINEF(out, in, channels) \
151 { \
152 int ch; \
153 for (ch = 0; ch < (channels); ++ch) { \
154 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
155 + (in).channel[ch] * (in).channel[3]; \
156 } \
157 }
158
efdc2568
TC
159typedef struct
160{
161 i_fill_t base;
162 i_color c;
163 i_fcolor fc;
164} i_fill_solid_t;
165
f1ac5027 166static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 167 i_color *);
f1ac5027 168static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 169 i_fcolor *);
f1ac5027
TC
170
171static i_fill_solid_t base_solid_fill =
172{
173 {
174 fill_solid,
175 fill_solidf,
176 NULL,
efdc2568
TC
177 NULL,
178 NULL,
f1ac5027
TC
179 },
180};
f1ac5027 181
773bc121
TC
182/*
183=item i_fill_destroy(fill)
6cfee9d1 184=order 90
92bda632 185=category Fills
9167a5c6 186=synopsis i_fill_destroy(fill);
92bda632 187
773bc121
TC
188Call to destroy any fill object.
189
190=cut
191*/
192
f1ac5027
TC
193void
194i_fill_destroy(i_fill_t *fill) {
195 if (fill->destroy)
196 (fill->destroy)(fill);
197 myfree(fill);
198}
199
773bc121
TC
200/*
201=item i_new_fill_solidf(color, combine)
202
92bda632 203=category Fills
9167a5c6 204=synopsis i_fill_t *fill = i_new_fill_solidf(&fcolor, combine);
92bda632 205
773bc121
TC
206Create a solid fill based on a float color.
207
208If combine is non-zero then alpha values will be combined.
209
210=cut
211*/
212
f1ac5027 213i_fill_t *
97ac0a96 214i_new_fill_solidf(const i_fcolor *c, int combine) {
f1ac5027 215 int ch;
f0960b14 216 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
f1ac5027 217
9b1ec2b8 218 *fill = base_solid_fill;
141a6114 219 if (combine) {
efdc2568
TC
220 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
221 }
9b1ec2b8 222
f1ac5027
TC
223 fill->fc = *c;
224 for (ch = 0; ch < MAXCHANNELS; ++ch) {
225 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
226 }
227
228 return &fill->base;
229}
230
773bc121
TC
231/*
232=item i_new_fill_solid(color, combine)
233
92bda632 234=category Fills
9167a5c6 235=synopsis i_fill_t *fill = i_new_fill_solid(&color, combine);
92bda632
TC
236
237Create a solid fill based on an 8-bit color.
773bc121
TC
238
239If combine is non-zero then alpha values will be combined.
240
241=cut
242*/
243
f1ac5027 244i_fill_t *
97ac0a96 245i_new_fill_solid(const i_color *c, int combine) {
f1ac5027 246 int ch;
f0960b14 247 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t)); /* checked 14jul05 tonyc */
f1ac5027 248
9b1ec2b8 249 *fill = base_solid_fill;
141a6114 250 if (combine) {
efdc2568
TC
251 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
252 }
9b1ec2b8 253
f1ac5027
TC
254 fill->c = *c;
255 for (ch = 0; ch < MAXCHANNELS; ++ch) {
256 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
257 }
258
259 return &fill->base;
260}
261
f1ac5027
TC
262static unsigned char
263builtin_hatches[][8] =
264{
265 {
266 /* 1x1 checkerboard */
267 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
268 },
269 {
270 /* 2x2 checkerboard */
271 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
272 },
273 {
274 /* 4 x 4 checkerboard */
275 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
276 },
277 {
278 /* single vertical lines */
279 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
280 },
281 {
282 /* double vertical lines */
283 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
284 },
285 {
286 /* quad vertical lines */
287 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
288 },
289 {
290 /* single hlines */
291 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 },
293 {
294 /* double hlines */
295 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
296 },
297 {
298 /* quad hlines */
299 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
300 },
301 {
302 /* single / */
303 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
304 },
305 {
306 /* single \ */
307 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
308 },
309 {
310 /* double / */
311 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
312 },
313 {
314 /* double \ */
315 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
316 },
317 {
318 /* single grid */
319 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
320 },
321 {
322 /* double grid */
323 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
324 },
325 {
326 /* quad grid */
327 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
328 },
329 {
330 /* single dots */
331 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332 },
333 {
334 /* 4 dots */
335 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
336 },
337 {
338 /* 16 dots */
339 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
340 },
341 {
342 /* simple stipple */
343 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
344 },
345 {
346 /* weave */
347 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
348 },
349 {
350 /* single cross hatch */
351 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
352 },
353 {
354 /* double cross hatch */
355 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
356 },
357 {
358 /* vertical lozenge */
359 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
360 },
361 {
362 /* horizontal lozenge */
363 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
364 },
365 {
366 /* scales overlapping downwards */
7a606d29 367 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
f1ac5027
TC
368 },
369 {
370 /* scales overlapping upwards */
7a606d29 371 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
f1ac5027
TC
372 },
373 {
374 /* scales overlapping leftwards */
7a606d29 375 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
f1ac5027
TC
376 },
377 {
378 /* scales overlapping rightwards */
7a606d29 379 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
f1ac5027
TC
380 },
381 {
382 /* denser stipple */
383 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
384 },
385 {
386 /* L-shaped tiles */
387 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
388 },
cc6483e0
TC
389 {
390 /* wider stipple */
391 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
392 },
f1ac5027
TC
393};
394
395typedef struct
396{
397 i_fill_t base;
398 i_color fg, bg;
399 i_fcolor ffg, fbg;
400 unsigned char hatch[8];
401 int dx, dy;
402} i_fill_hatch_t;
403
404static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 405 i_color *data);
f1ac5027 406static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 407 i_fcolor *data);
773bc121
TC
408static
409i_fill_t *
97ac0a96
TC
410i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg,
411 int combine, int hatch, const unsigned char *cust_hatch,
773bc121
TC
412 int dx, int dy);
413
414/*
415=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
416
92bda632 417=category Fills
9167a5c6 418=synopsis i_fill_t *fill = i_new_fill_hatch(&fg_color, &bg_color, combine, hatch, custom_hatch, dx, dy);
92bda632 419
773bc121
TC
420Creates a new hatched fill with the fg color used for the 1 bits in
421the hatch and bg for the 0 bits. If combine is non-zero alpha values
422will be combined.
f1ac5027 423
773bc121
TC
424If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
425hash definition, with the high-bits to the left.
426
427If cust_hatch is NULL then one of the standard hatches is used.
428
429(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.
430
431=cut
432*/
433i_fill_t *
97ac0a96
TC
434i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
435 const unsigned char *cust_hatch, int dx, int dy) {
773bc121
TC
436 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
437 dx, dy);
438}
439
440/*
441=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
442
92bda632 443=category Fills
9167a5c6 444=synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
92bda632 445
773bc121
TC
446Creates a new hatched fill with the fg color used for the 1 bits in
447the hatch and bg for the 0 bits. If combine is non-zero alpha values
448will be combined.
449
450If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
451hash definition, with the high-bits to the left.
452
453If cust_hatch is NULL then one of the standard hatches is used.
454
455(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
456
457=cut
458*/
459i_fill_t *
97ac0a96
TC
460i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
461 const unsigned char *cust_hatch, int dx, int dy) {
773bc121
TC
462 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
463 dx, dy);
464}
465
f576ce7e 466static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 467 i_color *data);
f576ce7e 468static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 469 i_fcolor *data);
f576ce7e
TC
470struct i_fill_image_t {
471 i_fill_t base;
472 i_img *src;
473 int xoff, yoff;
474 int has_matrix;
475 double matrix[9];
476};
477
9b1ec2b8
TC
478static struct i_fill_image_t
479image_fill_proto =
480 {
481 {
482 fill_image,
483 fill_imagef,
484 NULL
485 }
486 };
487
f576ce7e
TC
488/*
489=item i_new_fill_image(im, matrix, xoff, yoff, combine)
490
92bda632 491=category Fills
9167a5c6 492=synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
92bda632 493
f576ce7e
TC
494Create an image based fill.
495
92bda632
TC
496matrix is an array of 9 doubles representing a transformation matrix.
497
498xoff and yoff are the offset into the image to start filling from.
499
f576ce7e
TC
500=cut
501*/
502i_fill_t *
97ac0a96 503i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
f0960b14 504 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
f576ce7e 505
9b1ec2b8 506 *fill = image_fill_proto;
f576ce7e
TC
507
508 if (combine) {
509 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
510 }
511 else {
512 fill->base.combine = NULL;
513 fill->base.combinef = NULL;
514 }
515 fill->src = im;
516 if (xoff < 0)
517 xoff += im->xsize;
518 fill->xoff = xoff;
519 if (yoff < 0)
520 yoff += im->ysize;
521 fill->yoff = yoff;
522 if (matrix) {
523 fill->has_matrix = 1;
524 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
525 }
526 else
527 fill->has_matrix = 0;
528
529 return &fill->base;
530}
531
52f2b10a
TC
532static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
533 i_color *data);
534static void fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
535 i_fcolor *data);
536
537struct i_fill_opacity_t {
538 i_fill_t base;
539 i_fill_t *other_fill;
540 double alpha_mult;
541};
542
543static struct i_fill_opacity_t
544opacity_fill_proto =
545 {
546 fill_opacity,
547 fill_opacityf,
548 NULL
549 };
550
551i_fill_t *
552i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
553 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
554 *fill = opacity_fill_proto;
555
556 fill->base.combine = base_fill->combine;
557 fill->base.combinef = base_fill->combinef;
558
559 fill->other_fill = base_fill;
560 fill->alpha_mult = alpha_mult;
561
562 return &fill->base;
563}
f576ce7e 564
773bc121
TC
565#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
566
567/*
568=back
569
570=head1 INTERNAL FUNCTIONS
571
572=over
573
574=item fill_solid(fill, x, y, width, channels, data)
575
576The 8-bit sample fill function for non-combining solid fills.
577
578=cut
579*/
580static void
581fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 582 i_color *data) {
9b1ec2b8
TC
583 i_color c = T_SOLID_FILL(fill)->c;
584 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
773bc121 585 while (width-- > 0) {
9b1ec2b8 586 *data++ = c;
773bc121
TC
587 }
588}
589
590/*
591=item fill_solid(fill, x, y, width, channels, data)
592
593The floating sample fill function for non-combining solid fills.
594
595=cut
596*/
597static void
598fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 599 i_fcolor *data) {
773bc121 600 i_fcolor c = T_SOLID_FILL(fill)->fc;
9b1ec2b8 601 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
773bc121 602 while (width-- > 0) {
43c5dacb 603 *data++ = c;
773bc121
TC
604 }
605}
606
9b1ec2b8
TC
607static i_fill_hatch_t
608hatch_fill_proto =
609 {
610 {
611 fill_hatch,
612 fill_hatchf,
613 NULL
614 }
615 };
616
773bc121
TC
617/*
618=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
619
620Implements creation of hatch fill objects.
621
622=cut
623*/
f1ac5027
TC
624static
625i_fill_t *
97ac0a96
TC
626i_new_hatch_low(const i_color *fg, const i_color *bg,
627 const i_fcolor *ffg, const i_fcolor *fbg,
628 int combine, int hatch, const unsigned char *cust_hatch,
f1ac5027 629 int dx, int dy) {
f0960b14 630 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
f1ac5027 631
9b1ec2b8 632 *fill = hatch_fill_proto;
05462f4b
TC
633 /* Some Sun C didn't like the condition expressions that were here.
634 See https://rt.cpan.org/Ticket/Display.html?id=21944
635 */
636 if (fg)
637 fill->fg = *fg;
638 else
639 fill->fg = fcolor_to_color(ffg);
640 if (bg)
641 fill->bg = *bg;
642 else
643 fill->bg = fcolor_to_color(fbg);
644 if (ffg)
645 fill->ffg = *ffg;
646 else
647 fill->ffg = color_to_fcolor(fg);
648 if (fbg)
649 fill->fbg = *fbg;
650 else
651 fill->fbg = color_to_fcolor(bg);
141a6114 652 if (combine) {
efdc2568
TC
653 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
654 }
655 else {
656 fill->base.combine = NULL;
657 fill->base.combinef = NULL;
658 }
f1ac5027
TC
659 if (cust_hatch) {
660 memcpy(fill->hatch, cust_hatch, 8);
661 }
662 else {
663 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
664 hatch = 0;
665 memcpy(fill->hatch, builtin_hatches[hatch], 8);
666 }
667 fill->dx = dx & 7;
668 fill->dy = dy & 7;
669
670 return &fill->base;
671}
672
773bc121
TC
673/*
674=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 675
773bc121 676The 8-bit sample fill function for hatched fills.
f1ac5027 677
b8c2033e 678=cut
773bc121 679*/
f1ac5027 680static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 681 i_color *data) {
f1ac5027
TC
682 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
683 int byte = f->hatch[(y + f->dy) & 7];
684 int xpos = (x + f->dx) & 7;
685 int mask = 128 >> xpos;
04f85f63
TC
686 i_color fg = f->fg;
687 i_color bg = f->bg;
688 int want_channels = channels > 2 ? 4 : 2;
689
690 if (channels < 3) {
691 i_adapt_colors(2, 4, &fg, 1);
692 i_adapt_colors(2, 4, &bg, 1);
693 }
f1ac5027 694
43c5dacb 695 while (width-- > 0) {
052acec4 696 if (byte & mask)
04f85f63 697 *data++ = fg;
052acec4 698 else
04f85f63 699 *data++ = bg;
43c5dacb
TC
700
701 if ((mask >>= 1) == 0)
702 mask = 128;
f1ac5027
TC
703 }
704}
705
773bc121
TC
706/*
707=item fill_hatchf(fill, x, y, width, channels, data)
708
709The floating sample fill function for hatched fills.
710
711=back
712*/
f1ac5027 713static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 714 i_fcolor *data) {
f1ac5027
TC
715 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
716 int byte = f->hatch[(y + f->dy) & 7];
717 int xpos = (x + f->dx) & 7;
718 int mask = 128 >> xpos;
04f85f63
TC
719 i_fcolor fg = f->ffg;
720 i_fcolor bg = f->fbg;
721
722 if (channels < 3) {
723 i_adapt_fcolors(2, 4, &fg, 1);
724 i_adapt_fcolors(2, 4, &bg, 1);
725 }
f1ac5027 726
43c5dacb 727 while (width-- > 0) {
052acec4 728 if (byte & mask)
04f85f63 729 *data++ = fg;
052acec4 730 else
04f85f63 731 *data++ = bg;
43c5dacb
TC
732
733 if ((mask >>= 1) == 0)
734 mask = 128;
efdc2568
TC
735 }
736}
737
f576ce7e
TC
738/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
739/* linear interpolation */
740static i_color interp_i_color(i_color before, i_color after, double pos,
741 int channels) {
742 i_color out;
743 int ch;
744
745 pos -= floor(pos);
746 for (ch = 0; ch < channels; ++ch)
747 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
3efb0915 748 if (channels > 3 && out.channel[3])
f576ce7e
TC
749 for (ch = 0; ch < channels; ++ch)
750 if (ch != 3) {
751 int temp = out.channel[ch] * 255 / out.channel[3];
752 if (temp > 255)
753 temp = 255;
754 out.channel[ch] = temp;
755 }
756
757 return out;
758}
759
760/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
761/* linear interpolation */
762static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
763 int channels) {
764 i_fcolor out;
765 int ch;
766
767 pos -= floor(pos);
768 for (ch = 0; ch < channels; ++ch)
769 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
770 if (out.channel[3])
771 for (ch = 0; ch < channels; ++ch)
772 if (ch != 3) {
773 int temp = out.channel[ch] / out.channel[3];
774 if (temp > 1.0)
775 temp = 1.0;
776 out.channel[ch] = temp;
777 }
778
779 return out;
780}
781
782/*
783=item fill_image(fill, x, y, width, channels, data, work)
784
785=cut
786*/
787static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 788 i_color *data) {
f576ce7e 789 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 790 int i = 0;
cde2dbc7 791 i_color *out = data;
a256aec5 792 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
793
794 if (f->has_matrix) {
795 /* the hard way */
796 while (i < width) {
797 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
798 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
799 double ix = floor(rx / f->src->xsize);
800 double iy = floor(ry / f->src->ysize);
801 i_color c[2][2];
802 i_color c2[2];
803 int dy;
804
805 if (f->xoff) {
806 rx += iy * f->xoff;
807 ix = floor(rx / f->src->xsize);
808 }
809 else if (f->yoff) {
810 ry += ix * f->yoff;
811 iy = floor(ry / f->src->ysize);
812 }
813 rx -= ix * f->src->xsize;
814 ry -= iy * f->src->ysize;
815
816 for (dy = 0; dy < 2; ++dy) {
817 if ((int)rx == f->src->xsize-1) {
818 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
819 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
820 }
821 else {
822 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
823 c[dy]);
824 }
825 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
826 }
cde2dbc7 827 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
828 ++i;
829 }
830 }
831 else {
832 /* the easy way */
833 /* this should be possible to optimize to use i_glin() */
834 while (i < width) {
835 int rx = x+i;
836 int ry = y;
837 int ix = rx / f->src->xsize;
838 int iy = ry / f->src->ysize;
839
840 if (f->xoff) {
841 rx += iy * f->xoff;
842 ix = rx / f->src->xsize;
843 }
844 else if (f->yoff) {
845 ry += ix * f->yoff;
846 iy = ry / f->src->xsize;
847 }
848 rx -= ix * f->src->xsize;
849 ry -= iy * f->src->ysize;
cde2dbc7
TC
850 i_gpix(f->src, rx, ry, out);
851 ++out;
f576ce7e
TC
852 ++i;
853 }
854 }
a256aec5
TC
855 if (f->src->channels != want_channels)
856 i_adapt_colors(want_channels, f->src->channels, data, width);
f576ce7e
TC
857}
858
859/*
a256aec5 860=item fill_imagef(fill, x, y, width, channels, data, work)
f576ce7e
TC
861
862=cut
863*/
864static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 865 i_fcolor *data) {
f576ce7e 866 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 867 int i = 0;
a256aec5 868 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
869
870 if (f->has_matrix) {
a256aec5 871 i_fcolor *work_data = data;
f576ce7e
TC
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 }
a256aec5 904 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
905 ++i;
906 }
907 }
908 else {
a256aec5 909 i_fcolor *work_data = data;
f576ce7e
TC
910 /* the easy way */
911 /* this should be possible to optimize to use i_glin() */
912 while (i < width) {
913 int rx = x+i;
914 int ry = y;
915 int ix = rx / f->src->xsize;
916 int iy = ry / f->src->ysize;
917
918 if (f->xoff) {
919 rx += iy * f->xoff;
920 ix = rx / f->src->xsize;
921 }
922 else if (f->yoff) {
923 ry += ix * f->yoff;
924 iy = ry / f->src->xsize;
925 }
926 rx -= ix * f->src->xsize;
927 ry -= iy * f->src->ysize;
a256aec5
TC
928 i_gpixf(f->src, rx, ry, work_data);
929 ++work_data;
f576ce7e
TC
930 ++i;
931 }
932 }
a256aec5
TC
933 if (f->src->channels != want_channels)
934 i_adapt_fcolors(want_channels, f->src->channels, data, width);
f576ce7e
TC
935}
936
52f2b10a
TC
937static void
938fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
939 i_color *data) {
940 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 941 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
942 i_color *datap = data;
943
944 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
945 while (width--) {
946 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
947 if (new_alpha < 0)
948 datap->channel[alpha_chan] = 0;
949 else if (new_alpha > 255)
950 datap->channel[alpha_chan] = 255;
951 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
952
953 ++datap;
954 }
955}
956static void
957fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
958 i_fcolor *data) {
d0eb6658 959 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 960 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
961 i_fcolor *datap = data;
962
963 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
964
965 while (width--) {
966 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
967 if (new_alpha < 0)
968 datap->channel[alpha_chan] = 0;
969 else if (new_alpha > 1.0)
970 datap->channel[alpha_chan] = 1.0;
971 else datap->channel[alpha_chan] = new_alpha;
972
973 ++datap;
974 }
975}
efdc2568 976
773bc121
TC
977/*
978=back
979
980=head1 AUTHOR
981
982Tony Cook <tony@develop-help.com>
983
984=head1 SEE ALSO
985
986Imager(3)
987
988=cut
989*/