0.84 release
[imager.git] / fills.c
CommitLineData
92bda632
TC
1#include "imager.h"
2#include "imageri.h"
f1ac5027
TC
3
4/*
773bc121 5=head1 NAME
f1ac5027 6
773bc121 7fills.c - implements the basic general fills
f1ac5027 8
773bc121
TC
9=head1 SYNOPSIS
10
11 i_fill_t *fill;
12 i_color c1, c2;
13 i_fcolor fc1, fc2;
14 int combine;
15 fill = i_new_fill_solidf(&fc1, combine);
16 fill = i_new_fill_solid(&c1, combine);
17 fill = i_new_fill_hatchf(&fc1, &fc2, combine, hatch, cust_hash, dx, dy);
18 fill = i_new_fill_hatch(&c1, &c2, combine, hatch, cust_hash, dx, dy);
f576ce7e 19 fill = i_new_fill_image(im, matrix, xoff, yoff, combine);
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
50c75381
TC
166static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
167 int channels, i_color *);
168static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
169 int channels, 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
50c75381
TC
404static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
405 i_img_dim width, int channels, i_color *data);
406static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
407 i_img_dim width, int channels, 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/*
5715f7c3 415=item i_new_fill_hatch(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
773bc121 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
5715f7c3
TC
420Creates a new hatched fill with the C<fg> color used for the 1 bits in
421the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
422values will be combined.
f1ac5027 423
5715f7c3 424If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
773bc121
TC
425hash definition, with the high-bits to the left.
426
5715f7c3 427If C<cust_hatch> is NULL then one of the standard hatches is used.
773bc121 428
5715f7c3
TC
429(C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
430adjoining areas out of alignment, or to align the origin of a hatch
431with the the side of a filled area.
773bc121
TC
432
433=cut
434*/
435i_fill_t *
97ac0a96
TC
436i_new_fill_hatch(const i_color *fg, const i_color *bg, int combine, int hatch,
437 const unsigned char *cust_hatch, int dx, int dy) {
773bc121
TC
438 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
439 dx, dy);
440}
441
442/*
5715f7c3 443=item i_new_fill_hatchf(C<fg>, C<bg>, C<combine>, C<hatch>, C<cust_hatch>, C<dx>, C<dy>)
773bc121 444
92bda632 445=category Fills
9167a5c6 446=synopsis i_fill_t *fill = i_new_fill_hatchf(&fg_fcolor, &bg_fcolor, combine, hatch, custom_hatch, dx, dy);
92bda632 447
5715f7c3
TC
448Creates a new hatched fill with the C<fg> color used for the 1 bits in
449the hatch and C<bg> for the 0 bits. If C<combine> is non-zero alpha
450values will be combined.
773bc121 451
5715f7c3 452If C<cust_hatch> is non-NULL it should be a pointer to 8 bytes of the
773bc121
TC
453hash definition, with the high-bits to the left.
454
5715f7c3 455If C<cust_hatch> is NULL then one of the standard hatches is used.
773bc121 456
5715f7c3
TC
457(C<dx>, C<dy>) are an offset into the hatch which can be used to hatch
458adjoining areas out of alignment, or to align the origin of a hatch
459with the the side of a filled area.
773bc121
TC
460
461=cut
462*/
463i_fill_t *
97ac0a96
TC
464i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch,
465 const unsigned char *cust_hatch, int dx, int dy) {
773bc121
TC
466 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
467 dx, dy);
468}
469
50c75381
TC
470static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
471 i_img_dim width, int channels, i_color *data);
472static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
473 i_img_dim width, int channels, i_fcolor *data);
f576ce7e
TC
474struct i_fill_image_t {
475 i_fill_t base;
476 i_img *src;
477 int xoff, yoff;
478 int has_matrix;
479 double matrix[9];
480};
481
9b1ec2b8
TC
482static struct i_fill_image_t
483image_fill_proto =
484 {
485 {
486 fill_image,
487 fill_imagef,
488 NULL
489 }
490 };
491
f576ce7e 492/*
5715f7c3 493=item i_new_fill_image(C<im>, C<matrix>, C<xoff>, C<yoff>, C<combine>)
f576ce7e 494
92bda632 495=category Fills
9167a5c6 496=synopsis i_fill_t *fill = i_new_fill_image(src_img, matrix, x_offset, y_offset, combine);
92bda632 497
f576ce7e
TC
498Create an image based fill.
499
92bda632
TC
500matrix is an array of 9 doubles representing a transformation matrix.
501
5715f7c3 502C<xoff> and C<yoff> are the offset into the image to start filling from.
92bda632 503
f576ce7e
TC
504=cut
505*/
506i_fill_t *
97ac0a96 507i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combine) {
f0960b14 508 struct i_fill_image_t *fill = mymalloc(sizeof(*fill)); /* checked 14jul05 tonyc */
f576ce7e 509
9b1ec2b8 510 *fill = image_fill_proto;
f576ce7e
TC
511
512 if (combine) {
513 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
514 }
515 else {
516 fill->base.combine = NULL;
517 fill->base.combinef = NULL;
518 }
519 fill->src = im;
520 if (xoff < 0)
521 xoff += im->xsize;
522 fill->xoff = xoff;
523 if (yoff < 0)
524 yoff += im->ysize;
525 fill->yoff = yoff;
526 if (matrix) {
527 fill->has_matrix = 1;
528 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
529 }
530 else
531 fill->has_matrix = 0;
532
533 return &fill->base;
534}
535
50c75381
TC
536static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
537 i_img_dim width, int channels, i_color *data);
538static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
539 i_img_dim width, int channels, i_fcolor *data);
52f2b10a
TC
540
541struct i_fill_opacity_t {
542 i_fill_t base;
543 i_fill_t *other_fill;
544 double alpha_mult;
545};
546
547static struct i_fill_opacity_t
548opacity_fill_proto =
549 {
550 fill_opacity,
551 fill_opacityf,
552 NULL
553 };
554
555i_fill_t *
556i_new_fill_opacity(i_fill_t *base_fill, double alpha_mult) {
557 struct i_fill_opacity_t *fill = mymalloc(sizeof(*fill));
558 *fill = opacity_fill_proto;
559
560 fill->base.combine = base_fill->combine;
561 fill->base.combinef = base_fill->combinef;
562
563 fill->other_fill = base_fill;
564 fill->alpha_mult = alpha_mult;
565
8c194049
TC
566 if (!base_fill->f_fill_with_color) {
567 /* base fill only does floating, so we only do that too */
568 fill->base.f_fill_with_color = NULL;
569 }
570
52f2b10a
TC
571 return &fill->base;
572}
f576ce7e 573
773bc121
TC
574#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
575
576/*
577=back
578
579=head1 INTERNAL FUNCTIONS
580
581=over
582
583=item fill_solid(fill, x, y, width, channels, data)
584
585The 8-bit sample fill function for non-combining solid fills.
586
587=cut
588*/
589static void
50c75381
TC
590fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
591 int channels, i_color *data) {
9b1ec2b8
TC
592 i_color c = T_SOLID_FILL(fill)->c;
593 i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
773bc121 594 while (width-- > 0) {
9b1ec2b8 595 *data++ = c;
773bc121
TC
596 }
597}
598
599/*
600=item fill_solid(fill, x, y, width, channels, data)
601
602The floating sample fill function for non-combining solid fills.
603
604=cut
605*/
606static void
50c75381
TC
607fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
608 int channels, i_fcolor *data) {
773bc121 609 i_fcolor c = T_SOLID_FILL(fill)->fc;
9b1ec2b8 610 i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
773bc121 611 while (width-- > 0) {
43c5dacb 612 *data++ = c;
773bc121
TC
613 }
614}
615
9b1ec2b8
TC
616static i_fill_hatch_t
617hatch_fill_proto =
618 {
619 {
620 fill_hatch,
621 fill_hatchf,
622 NULL
623 }
624 };
625
773bc121
TC
626/*
627=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
628
629Implements creation of hatch fill objects.
630
631=cut
632*/
f1ac5027
TC
633static
634i_fill_t *
97ac0a96
TC
635i_new_hatch_low(const i_color *fg, const i_color *bg,
636 const i_fcolor *ffg, const i_fcolor *fbg,
637 int combine, int hatch, const unsigned char *cust_hatch,
f1ac5027 638 int dx, int dy) {
f0960b14 639 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t)); /* checked 14jul05 tonyc */
f1ac5027 640
9b1ec2b8 641 *fill = hatch_fill_proto;
05462f4b
TC
642 /* Some Sun C didn't like the condition expressions that were here.
643 See https://rt.cpan.org/Ticket/Display.html?id=21944
644 */
645 if (fg)
646 fill->fg = *fg;
647 else
648 fill->fg = fcolor_to_color(ffg);
649 if (bg)
650 fill->bg = *bg;
651 else
652 fill->bg = fcolor_to_color(fbg);
653 if (ffg)
654 fill->ffg = *ffg;
655 else
656 fill->ffg = color_to_fcolor(fg);
657 if (fbg)
658 fill->fbg = *fbg;
659 else
660 fill->fbg = color_to_fcolor(bg);
141a6114 661 if (combine) {
efdc2568
TC
662 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
663 }
664 else {
665 fill->base.combine = NULL;
666 fill->base.combinef = NULL;
667 }
f1ac5027
TC
668 if (cust_hatch) {
669 memcpy(fill->hatch, cust_hatch, 8);
670 }
671 else {
672 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
673 hatch = 0;
674 memcpy(fill->hatch, builtin_hatches[hatch], 8);
675 }
676 fill->dx = dx & 7;
677 fill->dy = dy & 7;
678
679 return &fill->base;
680}
681
773bc121
TC
682/*
683=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 684
773bc121 685The 8-bit sample fill function for hatched fills.
f1ac5027 686
b8c2033e 687=cut
773bc121 688*/
50c75381
TC
689static void
690fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
691 int channels, i_color *data) {
f1ac5027
TC
692 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
693 int byte = f->hatch[(y + f->dy) & 7];
694 int xpos = (x + f->dx) & 7;
695 int mask = 128 >> xpos;
04f85f63
TC
696 i_color fg = f->fg;
697 i_color bg = f->bg;
698 int want_channels = channels > 2 ? 4 : 2;
699
700 if (channels < 3) {
701 i_adapt_colors(2, 4, &fg, 1);
702 i_adapt_colors(2, 4, &bg, 1);
703 }
f1ac5027 704
43c5dacb 705 while (width-- > 0) {
052acec4 706 if (byte & mask)
04f85f63 707 *data++ = fg;
052acec4 708 else
04f85f63 709 *data++ = bg;
43c5dacb
TC
710
711 if ((mask >>= 1) == 0)
712 mask = 128;
f1ac5027
TC
713 }
714}
715
773bc121
TC
716/*
717=item fill_hatchf(fill, x, y, width, channels, data)
718
719The floating sample fill function for hatched fills.
720
721=back
722*/
50c75381
TC
723static void
724fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
725 int channels, i_fcolor *data) {
f1ac5027
TC
726 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
727 int byte = f->hatch[(y + f->dy) & 7];
728 int xpos = (x + f->dx) & 7;
729 int mask = 128 >> xpos;
04f85f63
TC
730 i_fcolor fg = f->ffg;
731 i_fcolor bg = f->fbg;
732
733 if (channels < 3) {
734 i_adapt_fcolors(2, 4, &fg, 1);
735 i_adapt_fcolors(2, 4, &bg, 1);
736 }
f1ac5027 737
43c5dacb 738 while (width-- > 0) {
052acec4 739 if (byte & mask)
04f85f63 740 *data++ = fg;
052acec4 741 else
04f85f63 742 *data++ = bg;
43c5dacb
TC
743
744 if ((mask >>= 1) == 0)
745 mask = 128;
efdc2568
TC
746 }
747}
748
f576ce7e
TC
749/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
750/* linear interpolation */
751static i_color interp_i_color(i_color before, i_color after, double pos,
752 int channels) {
753 i_color out;
754 int ch;
755
756 pos -= floor(pos);
757 for (ch = 0; ch < channels; ++ch)
758 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
3efb0915 759 if (channels > 3 && out.channel[3])
f576ce7e
TC
760 for (ch = 0; ch < channels; ++ch)
761 if (ch != 3) {
762 int temp = out.channel[ch] * 255 / out.channel[3];
763 if (temp > 255)
764 temp = 255;
765 out.channel[ch] = temp;
766 }
767
768 return out;
769}
770
771/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
772/* linear interpolation */
773static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
774 int channels) {
775 i_fcolor out;
776 int ch;
777
778 pos -= floor(pos);
779 for (ch = 0; ch < channels; ++ch)
780 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
781 if (out.channel[3])
782 for (ch = 0; ch < channels; ++ch)
783 if (ch != 3) {
784 int temp = out.channel[ch] / out.channel[3];
785 if (temp > 1.0)
786 temp = 1.0;
787 out.channel[ch] = temp;
788 }
789
790 return out;
791}
792
793/*
794=item fill_image(fill, x, y, width, channels, data, work)
795
796=cut
797*/
50c75381
TC
798static void
799fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
800 int channels, i_color *data) {
f576ce7e 801 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
50c75381 802 i_img_dim i = 0;
cde2dbc7 803 i_color *out = data;
a256aec5 804 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
805
806 if (f->has_matrix) {
807 /* the hard way */
808 while (i < width) {
809 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
810 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
811 double ix = floor(rx / f->src->xsize);
812 double iy = floor(ry / f->src->ysize);
813 i_color c[2][2];
814 i_color c2[2];
50c75381 815 i_img_dim dy;
f576ce7e
TC
816
817 if (f->xoff) {
818 rx += iy * f->xoff;
819 ix = floor(rx / f->src->xsize);
820 }
821 else if (f->yoff) {
822 ry += ix * f->yoff;
823 iy = floor(ry / f->src->ysize);
824 }
825 rx -= ix * f->src->xsize;
826 ry -= iy * f->src->ysize;
827
828 for (dy = 0; dy < 2; ++dy) {
829 if ((int)rx == f->src->xsize-1) {
830 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
831 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
832 }
833 else {
834 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
835 c[dy]);
836 }
837 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
838 }
cde2dbc7 839 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
840 ++i;
841 }
842 }
843 else {
844 /* the easy way */
845 /* this should be possible to optimize to use i_glin() */
846 while (i < width) {
50c75381
TC
847 i_img_dim rx = x+i;
848 i_img_dim ry = y;
849 i_img_dim ix = rx / f->src->xsize;
850 i_img_dim iy = ry / f->src->ysize;
f576ce7e
TC
851
852 if (f->xoff) {
853 rx += iy * f->xoff;
854 ix = rx / f->src->xsize;
855 }
856 else if (f->yoff) {
857 ry += ix * f->yoff;
858 iy = ry / f->src->xsize;
859 }
860 rx -= ix * f->src->xsize;
861 ry -= iy * f->src->ysize;
cde2dbc7
TC
862 i_gpix(f->src, rx, ry, out);
863 ++out;
f576ce7e
TC
864 ++i;
865 }
866 }
a256aec5
TC
867 if (f->src->channels != want_channels)
868 i_adapt_colors(want_channels, f->src->channels, data, width);
f576ce7e
TC
869}
870
871/*
a256aec5 872=item fill_imagef(fill, x, y, width, channels, data, work)
f576ce7e
TC
873
874=cut
875*/
50c75381
TC
876static void
877fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
878 int channels, i_fcolor *data) {
f576ce7e 879 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
50c75381 880 i_img_dim i = 0;
a256aec5 881 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
882
883 if (f->has_matrix) {
a256aec5 884 i_fcolor *work_data = data;
f576ce7e
TC
885 /* the hard way */
886 while (i < width) {
887 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
888 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
889 double ix = floor(rx / f->src->xsize);
890 double iy = floor(ry / f->src->ysize);
891 i_fcolor c[2][2];
892 i_fcolor c2[2];
50c75381 893 i_img_dim dy;
f576ce7e
TC
894
895 if (f->xoff) {
896 rx += iy * f->xoff;
897 ix = floor(rx / f->src->xsize);
898 }
899 else if (f->yoff) {
900 ry += ix * f->yoff;
901 iy = floor(ry / f->src->ysize);
902 }
903 rx -= ix * f->src->xsize;
904 ry -= iy * f->src->ysize;
905
906 for (dy = 0; dy < 2; ++dy) {
907 if ((int)rx == f->src->xsize-1) {
908 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
909 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
910 }
911 else {
912 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
913 c[dy]);
914 }
915 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
916 }
a256aec5 917 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
918 ++i;
919 }
920 }
921 else {
a256aec5 922 i_fcolor *work_data = data;
f576ce7e
TC
923 /* the easy way */
924 /* this should be possible to optimize to use i_glin() */
925 while (i < width) {
50c75381
TC
926 i_img_dim rx = x+i;
927 i_img_dim ry = y;
928 i_img_dim ix = rx / f->src->xsize;
929 i_img_dim iy = ry / f->src->ysize;
f576ce7e
TC
930
931 if (f->xoff) {
932 rx += iy * f->xoff;
933 ix = rx / f->src->xsize;
934 }
935 else if (f->yoff) {
936 ry += ix * f->yoff;
937 iy = ry / f->src->xsize;
938 }
939 rx -= ix * f->src->xsize;
940 ry -= iy * f->src->ysize;
a256aec5
TC
941 i_gpixf(f->src, rx, ry, work_data);
942 ++work_data;
f576ce7e
TC
943 ++i;
944 }
945 }
a256aec5
TC
946 if (f->src->channels != want_channels)
947 i_adapt_fcolors(want_channels, f->src->channels, data, width);
f576ce7e
TC
948}
949
52f2b10a 950static void
50c75381
TC
951fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
952 int channels, i_color *data) {
52f2b10a 953 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 954 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
955 i_color *datap = data;
956
957 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
958 while (width--) {
959 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
960 if (new_alpha < 0)
961 datap->channel[alpha_chan] = 0;
962 else if (new_alpha > 255)
963 datap->channel[alpha_chan] = 255;
964 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
965
966 ++datap;
967 }
968}
969static void
50c75381
TC
970fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
971 int channels, i_fcolor *data) {
d0eb6658 972 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 973 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
974 i_fcolor *datap = data;
975
976 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
977
978 while (width--) {
979 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
980 if (new_alpha < 0)
981 datap->channel[alpha_chan] = 0;
982 else if (new_alpha > 1.0)
983 datap->channel[alpha_chan] = 1.0;
984 else datap->channel[alpha_chan] = new_alpha;
985
986 ++datap;
987 }
988}
efdc2568 989
773bc121
TC
990/*
991=back
992
993=head1 AUTHOR
994
995Tony Cook <tony@develop-help.com>
996
997=head1 SEE ALSO
998
999Imager(3)
1000
1001=cut
1002*/