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