add assertions for callers to i_new_hatch_low() in fills.c
[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;
05462f4b
TC
650 /* Some Sun C didn't like the condition expressions that were here.
651 See https://rt.cpan.org/Ticket/Display.html?id=21944
652 */
653 if (fg)
654 fill->fg = *fg;
655 else
656 fill->fg = fcolor_to_color(ffg);
657 if (bg)
658 fill->bg = *bg;
659 else
660 fill->bg = fcolor_to_color(fbg);
661 if (ffg)
662 fill->ffg = *ffg;
663 else
664 fill->ffg = color_to_fcolor(fg);
665 if (fbg)
666 fill->fbg = *fbg;
667 else
668 fill->fbg = color_to_fcolor(bg);
141a6114 669 if (combine) {
efdc2568
TC
670 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
671 }
672 else {
673 fill->base.combine = NULL;
674 fill->base.combinef = NULL;
675 }
f1ac5027
TC
676 if (cust_hatch) {
677 memcpy(fill->hatch, cust_hatch, 8);
678 }
679 else {
58ec1fde
TC
680 if (hatch >= sizeof(builtin_hatches)/sizeof(*builtin_hatches)
681 || hatch < 0) {
f1ac5027 682 hatch = 0;
58ec1fde 683 }
f1ac5027
TC
684 memcpy(fill->hatch, builtin_hatches[hatch], 8);
685 }
686 fill->dx = dx & 7;
687 fill->dy = dy & 7;
688
689 return &fill->base;
690}
691
773bc121
TC
692/*
693=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 694
773bc121 695The 8-bit sample fill function for hatched fills.
f1ac5027 696
b8c2033e 697=cut
773bc121 698*/
50c75381
TC
699static void
700fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
701 int channels, i_color *data) {
f1ac5027
TC
702 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
703 int byte = f->hatch[(y + f->dy) & 7];
704 int xpos = (x + f->dx) & 7;
705 int mask = 128 >> xpos;
04f85f63
TC
706 i_color fg = f->fg;
707 i_color bg = f->bg;
04f85f63
TC
708
709 if (channels < 3) {
710 i_adapt_colors(2, 4, &fg, 1);
711 i_adapt_colors(2, 4, &bg, 1);
712 }
f1ac5027 713
43c5dacb 714 while (width-- > 0) {
052acec4 715 if (byte & mask)
04f85f63 716 *data++ = fg;
052acec4 717 else
04f85f63 718 *data++ = bg;
43c5dacb
TC
719
720 if ((mask >>= 1) == 0)
721 mask = 128;
f1ac5027
TC
722 }
723}
724
773bc121
TC
725/*
726=item fill_hatchf(fill, x, y, width, channels, data)
727
728The floating sample fill function for hatched fills.
729
12db268a 730=cut
773bc121 731*/
50c75381
TC
732static void
733fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
734 int channels, i_fcolor *data) {
f1ac5027
TC
735 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
736 int byte = f->hatch[(y + f->dy) & 7];
737 int xpos = (x + f->dx) & 7;
738 int mask = 128 >> xpos;
04f85f63
TC
739 i_fcolor fg = f->ffg;
740 i_fcolor bg = f->fbg;
741
742 if (channels < 3) {
743 i_adapt_fcolors(2, 4, &fg, 1);
744 i_adapt_fcolors(2, 4, &bg, 1);
745 }
f1ac5027 746
43c5dacb 747 while (width-- > 0) {
052acec4 748 if (byte & mask)
04f85f63 749 *data++ = fg;
052acec4 750 else
04f85f63 751 *data++ = bg;
43c5dacb
TC
752
753 if ((mask >>= 1) == 0)
754 mask = 128;
efdc2568
TC
755 }
756}
757
f576ce7e
TC
758/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
759/* linear interpolation */
760static i_color interp_i_color(i_color before, i_color after, double pos,
761 int channels) {
762 i_color out;
763 int ch;
764
765 pos -= floor(pos);
766 for (ch = 0; ch < channels; ++ch)
767 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
0435f257
TC
768 if (channels > 3 && out.channel[3]) {
769 for (ch = 0; ch < channels; ++ch) {
f576ce7e
TC
770 if (ch != 3) {
771 int temp = out.channel[ch] * 255 / out.channel[3];
772 if (temp > 255)
773 temp = 255;
774 out.channel[ch] = temp;
775 }
0435f257
TC
776 }
777 }
f576ce7e
TC
778
779 return out;
780}
781
782/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
783/* linear interpolation */
784static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
785 int channels) {
786 i_fcolor out;
787 int ch;
788
789 pos -= floor(pos);
790 for (ch = 0; ch < channels; ++ch)
791 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
0435f257
TC
792 if (out.channel[3]) {
793 for (ch = 0; ch < channels; ++ch) {
f576ce7e
TC
794 if (ch != 3) {
795 int temp = out.channel[ch] / out.channel[3];
796 if (temp > 1.0)
797 temp = 1.0;
798 out.channel[ch] = temp;
799 }
0435f257
TC
800 }
801 }
f576ce7e
TC
802
803 return out;
804}
805
806/*
807=item fill_image(fill, x, y, width, channels, data, work)
808
809=cut
810*/
50c75381
TC
811static void
812fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
813 int channels, i_color *data) {
f576ce7e 814 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
50c75381 815 i_img_dim i = 0;
cde2dbc7 816 i_color *out = data;
a256aec5 817 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
818
819 if (f->has_matrix) {
820 /* the hard way */
821 while (i < width) {
822 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
823 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
824 double ix = floor(rx / f->src->xsize);
825 double iy = floor(ry / f->src->ysize);
826 i_color c[2][2];
827 i_color c2[2];
50c75381 828 i_img_dim dy;
f576ce7e
TC
829
830 if (f->xoff) {
831 rx += iy * f->xoff;
832 ix = floor(rx / f->src->xsize);
833 }
834 else if (f->yoff) {
835 ry += ix * f->yoff;
836 iy = floor(ry / f->src->ysize);
837 }
838 rx -= ix * f->src->xsize;
839 ry -= iy * f->src->ysize;
840
841 for (dy = 0; dy < 2; ++dy) {
8d14daab
TC
842 if ((i_img_dim)rx == f->src->xsize-1) {
843 i_gpix(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
844 i_gpix(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
f576ce7e
TC
845 }
846 else {
8d14daab 847 i_glin(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
f576ce7e
TC
848 c[dy]);
849 }
850 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
851 }
cde2dbc7 852 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
853 ++i;
854 }
855 }
856 else {
857 /* the easy way */
858 /* this should be possible to optimize to use i_glin() */
859 while (i < width) {
50c75381
TC
860 i_img_dim rx = x+i;
861 i_img_dim ry = y;
862 i_img_dim ix = rx / f->src->xsize;
863 i_img_dim iy = ry / f->src->ysize;
f576ce7e
TC
864
865 if (f->xoff) {
866 rx += iy * f->xoff;
867 ix = rx / f->src->xsize;
868 }
869 else if (f->yoff) {
870 ry += ix * f->yoff;
73236585 871 iy = ry / f->src->ysize;
f576ce7e
TC
872 }
873 rx -= ix * f->src->xsize;
874 ry -= iy * f->src->ysize;
cde2dbc7
TC
875 i_gpix(f->src, rx, ry, out);
876 ++out;
f576ce7e
TC
877 ++i;
878 }
879 }
a256aec5
TC
880 if (f->src->channels != want_channels)
881 i_adapt_colors(want_channels, f->src->channels, data, width);
f576ce7e
TC
882}
883
884/*
a256aec5 885=item fill_imagef(fill, x, y, width, channels, data, work)
f576ce7e
TC
886
887=cut
888*/
50c75381
TC
889static void
890fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
891 int channels, i_fcolor *data) {
f576ce7e 892 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
50c75381 893 i_img_dim i = 0;
a256aec5 894 int want_channels = channels > 2 ? 4 : 2;
f576ce7e
TC
895
896 if (f->has_matrix) {
a256aec5 897 i_fcolor *work_data = data;
f576ce7e
TC
898 /* the hard way */
899 while (i < width) {
900 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
901 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
902 double ix = floor(rx / f->src->xsize);
903 double iy = floor(ry / f->src->ysize);
904 i_fcolor c[2][2];
905 i_fcolor c2[2];
50c75381 906 i_img_dim dy;
f576ce7e
TC
907
908 if (f->xoff) {
909 rx += iy * f->xoff;
910 ix = floor(rx / f->src->xsize);
911 }
912 else if (f->yoff) {
913 ry += ix * f->yoff;
914 iy = floor(ry / f->src->ysize);
915 }
916 rx -= ix * f->src->xsize;
917 ry -= iy * f->src->ysize;
918
919 for (dy = 0; dy < 2; ++dy) {
8d14daab
TC
920 if ((i_img_dim)rx == f->src->xsize-1) {
921 i_gpixf(f->src, f->src->xsize-1, ((i_img_dim)ry+dy) % f->src->ysize, &c[dy][0]);
922 i_gpixf(f->src, 0, ((i_img_dim)ry+dy) % f->src->xsize, &c[dy][1]);
f576ce7e
TC
923 }
924 else {
8d14daab 925 i_glinf(f->src, (i_img_dim)rx, (i_img_dim)rx+2, ((i_img_dim)ry+dy) % f->src->ysize,
f576ce7e
TC
926 c[dy]);
927 }
928 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
929 }
a256aec5 930 *work_data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
931 ++i;
932 }
933 }
934 else {
a256aec5 935 i_fcolor *work_data = data;
f576ce7e
TC
936 /* the easy way */
937 /* this should be possible to optimize to use i_glin() */
938 while (i < width) {
50c75381
TC
939 i_img_dim rx = x+i;
940 i_img_dim ry = y;
941 i_img_dim ix = rx / f->src->xsize;
942 i_img_dim iy = ry / f->src->ysize;
f576ce7e
TC
943
944 if (f->xoff) {
945 rx += iy * f->xoff;
946 ix = rx / f->src->xsize;
947 }
948 else if (f->yoff) {
949 ry += ix * f->yoff;
950 iy = ry / f->src->xsize;
951 }
952 rx -= ix * f->src->xsize;
953 ry -= iy * f->src->ysize;
a256aec5
TC
954 i_gpixf(f->src, rx, ry, work_data);
955 ++work_data;
f576ce7e
TC
956 ++i;
957 }
958 }
a256aec5
TC
959 if (f->src->channels != want_channels)
960 i_adapt_fcolors(want_channels, f->src->channels, data, width);
f576ce7e
TC
961}
962
52f2b10a 963static void
50c75381
TC
964fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
965 int channels, i_color *data) {
52f2b10a 966 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 967 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
968 i_color *datap = data;
969
970 (f->other_fill->f_fill_with_color)(f->other_fill, x, y, width, channels, data);
971 while (width--) {
972 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
973 if (new_alpha < 0)
974 datap->channel[alpha_chan] = 0;
975 else if (new_alpha > 255)
976 datap->channel[alpha_chan] = 255;
977 else datap->channel[alpha_chan] = (int)(new_alpha + 0.5);
978
979 ++datap;
980 }
981}
982static void
50c75381
TC
983fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
984 int channels, i_fcolor *data) {
d0eb6658 985 struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
e958b64e 986 int alpha_chan = channels > 2 ? 3 : 1;
52f2b10a
TC
987 i_fcolor *datap = data;
988
989 (f->other_fill->f_fill_with_fcolor)(f->other_fill, x, y, width, channels, data);
990
991 while (width--) {
992 double new_alpha = datap->channel[alpha_chan] * f->alpha_mult;
993 if (new_alpha < 0)
994 datap->channel[alpha_chan] = 0;
995 else if (new_alpha > 1.0)
996 datap->channel[alpha_chan] = 1.0;
997 else datap->channel[alpha_chan] = new_alpha;
998
999 ++datap;
1000 }
1001}
efdc2568 1002
773bc121
TC
1003/*
1004=back
1005
1006=head1 AUTHOR
1007
1008Tony Cook <tony@develop-help.com>
1009
1010=head1 SEE ALSO
1011
1012Imager(3)
1013
1014=cut
1015*/