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