various
[imager.git] / fills.c
CommitLineData
f1ac5027
TC
1#include "image.h"
2#include "imagei.h"
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);
19 i_fill_destroy(fill);
20
21=head1 DESCRIPTION
22
23Implements the basic general fills, which can be used for filling some
24shapes and for flood fills.
25
26Each fill can implement up to 3 functions:
27
28=over
29
30=item fill_with_color
31
32called for fills on 8-bit images. This can be NULL in which case the
33fill_with_colorf function is called.
34
35=item fill_with_fcolor
36
37called for fills on non-8-bit images or when fill_with_color is NULL.
38
39=item destroy
40
41called by i_fill_destroy() if non-NULL, to release any extra resources
42that the fill may need.
43
44=back
45
46fill_with_color and fill_with_fcolor are basically the same function
47except that the first works with lines of i_color and the second with
48lines of i_fcolor.
49
50If the combines member if non-zero the line data is populated from the
51target image before calling fill_with_*color.
52
53fill_with_color needs to fill the I<data> parameter with the fill
54pixels. If combines is non-zero it the fill pixels should be combined
55with the existing data.
56
57The current fills are:
58
59=over
60
61=item *
62
63solid fill
64
65=item *
66
67hatched fill
68
69=item *
70
71fountain fill
72
73=back
74
75Fountain fill is implemented by L<filters.c>.
76
77=over
78
79=cut
f1ac5027
TC
80*/
81
82static i_color fcolor_to_color(i_fcolor *c) {
83 int ch;
84 i_color out;
85
86 for (ch = 0; ch < MAXCHANNELS; ++ch)
87 out.channel[ch] = SampleFTo8(c->channel[ch]);
88}
89
90static i_fcolor color_to_fcolor(i_color *c) {
91 int ch;
92 i_color out;
93
94 for (ch = 0; ch < MAXCHANNELS; ++ch)
95 out.channel[ch] = Sample8ToF(c->channel[ch]);
96}
97
98typedef struct
99{
100 i_fill_t base;
101 i_color c;
102 i_fcolor fc;
103} i_fill_solid_t;
104
105#define COMBINE(out, in, channels) \
106 { \
107 int ch; \
108 for (ch = 0; ch < (channels); ++ch) { \
109 (out).channel[ch] = ((out).channel[ch] * (255 - (in).channel[3]) \
110 + (in).channel[ch] * (in).channel[3]) / 255; \
111 } \
112 }
113
114#define COMBINEF(out, in, channels) \
115 { \
116 int ch; \
117 for (ch = 0; ch < (channels); ++ch) { \
118 (out).channel[ch] = (out).channel[ch] * (1.0 - (in).channel[3]) \
119 + (in).channel[ch] * (in).channel[3]; \
120 } \
121 }
122
123static void fill_solid(i_fill_t *, int x, int y, int width, int channels,
124 i_color *);
125static void fill_solidf(i_fill_t *, int x, int y, int width, int channels,
126 i_fcolor *);
127static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels,
128 i_color *);
129static void fill_solidf_comb(i_fill_t *, int x, int y, int width,
130 int channels, i_fcolor *);
131
132static i_fill_solid_t base_solid_fill =
133{
134 {
135 fill_solid,
136 fill_solidf,
137 NULL,
138 0
139 },
140};
141static i_fill_solid_t base_solid_fill_comb =
142{
143 {
144 fill_solid_comb,
145 fill_solidf_comb,
146 NULL,
147 1
148 },
149};
150
773bc121
TC
151/*
152=item i_fill_destroy(fill)
153
154Call to destroy any fill object.
155
156=cut
157*/
158
f1ac5027
TC
159void
160i_fill_destroy(i_fill_t *fill) {
161 if (fill->destroy)
162 (fill->destroy)(fill);
163 myfree(fill);
164}
165
773bc121
TC
166/*
167=item i_new_fill_solidf(color, combine)
168
169Create a solid fill based on a float color.
170
171If combine is non-zero then alpha values will be combined.
172
173=cut
174*/
175
f1ac5027
TC
176i_fill_t *
177i_new_fill_solidf(i_fcolor *c, int combine) {
178 int ch;
179 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
180
181 if (combine && c->channel[3] < 1.0)
182 *fill = base_solid_fill_comb;
183 else
184 *fill = base_solid_fill;
185 fill->fc = *c;
186 for (ch = 0; ch < MAXCHANNELS; ++ch) {
187 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
188 }
189
190 return &fill->base;
191}
192
773bc121
TC
193/*
194=item i_new_fill_solid(color, combine)
195
196Create a solid fill based.
197
198If combine is non-zero then alpha values will be combined.
199
200=cut
201*/
202
f1ac5027
TC
203i_fill_t *
204i_new_fill_solid(i_color *c, int combine) {
205 int ch;
206 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
207
208 if (combine && c->channel[3] < 255)
209 *fill = base_solid_fill_comb;
210 else
211 *fill = base_solid_fill;
212 fill->c = *c;
213 for (ch = 0; ch < MAXCHANNELS; ++ch) {
214 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
215 }
216
217 return &fill->base;
218}
219
f1ac5027
TC
220static unsigned char
221builtin_hatches[][8] =
222{
223 {
224 /* 1x1 checkerboard */
225 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
226 },
227 {
228 /* 2x2 checkerboard */
229 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
230 },
231 {
232 /* 4 x 4 checkerboard */
233 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
234 },
235 {
236 /* single vertical lines */
237 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
238 },
239 {
240 /* double vertical lines */
241 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
242 },
243 {
244 /* quad vertical lines */
245 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
246 },
247 {
248 /* single hlines */
249 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250 },
251 {
252 /* double hlines */
253 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
254 },
255 {
256 /* quad hlines */
257 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
258 },
259 {
260 /* single / */
261 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
262 },
263 {
264 /* single \ */
265 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
266 },
267 {
268 /* double / */
269 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
270 },
271 {
272 /* double \ */
273 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
274 },
275 {
276 /* single grid */
277 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
278 },
279 {
280 /* double grid */
281 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
282 },
283 {
284 /* quad grid */
285 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
286 },
287 {
288 /* single dots */
289 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
290 },
291 {
292 /* 4 dots */
293 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
294 },
295 {
296 /* 16 dots */
297 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
298 },
299 {
300 /* simple stipple */
301 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
302 },
303 {
304 /* weave */
305 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
306 },
307 {
308 /* single cross hatch */
309 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
310 },
311 {
312 /* double cross hatch */
313 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
314 },
315 {
316 /* vertical lozenge */
317 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
318 },
319 {
320 /* horizontal lozenge */
321 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
322 },
323 {
324 /* scales overlapping downwards */
7a606d29 325 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
f1ac5027
TC
326 },
327 {
328 /* scales overlapping upwards */
7a606d29 329 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
f1ac5027
TC
330 },
331 {
332 /* scales overlapping leftwards */
7a606d29 333 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
f1ac5027
TC
334 },
335 {
336 /* scales overlapping rightwards */
7a606d29 337 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
f1ac5027
TC
338 },
339 {
340 /* denser stipple */
341 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
342 },
343 {
344 /* L-shaped tiles */
345 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
346 },
cc6483e0
TC
347 {
348 /* wider stipple */
349 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
350 },
f1ac5027
TC
351};
352
353typedef struct
354{
355 i_fill_t base;
356 i_color fg, bg;
357 i_fcolor ffg, fbg;
358 unsigned char hatch[8];
359 int dx, dy;
360} i_fill_hatch_t;
361
362static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
363 i_color *data);
364static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
365 i_fcolor *data);
773bc121
TC
366static
367i_fill_t *
368i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
369 int combine, int hatch, unsigned char *cust_hatch,
370 int dx, int dy);
371
372/*
373=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
374
375Creates a new hatched fill with the fg color used for the 1 bits in
376the hatch and bg for the 0 bits. If combine is non-zero alpha values
377will be combined.
f1ac5027 378
773bc121
TC
379If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
380hash definition, with the high-bits to the left.
381
382If cust_hatch is NULL then one of the standard hatches is used.
383
384(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
385
386=cut
387*/
388i_fill_t *
389i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch,
390 unsigned char *cust_hatch, int dx, int dy) {
391 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
392 dx, dy);
393}
394
395/*
396=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
397
398Creates a new hatched fill with the fg color used for the 1 bits in
399the hatch and bg for the 0 bits. If combine is non-zero alpha values
400will be combined.
401
402If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
403hash definition, with the high-bits to the left.
404
405If cust_hatch is NULL then one of the standard hatches is used.
406
407(dx, dy) are an offset into the hatch which can be used to unalign adjoining areas, or to align the origin of a hatch with the the side of a filled area.
408
409=cut
410*/
411i_fill_t *
412i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch,
413 unsigned char *cust_hatch, int dx, int dy) {
414 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
415 dx, dy);
416}
417
418#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
419
420/*
421=back
422
423=head1 INTERNAL FUNCTIONS
424
425=over
426
427=item fill_solid(fill, x, y, width, channels, data)
428
429The 8-bit sample fill function for non-combining solid fills.
430
431=cut
432*/
433static void
434fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
435 i_color *data) {
436 while (width-- > 0) {
437 *data++ = T_SOLID_FILL(fill)->c;
438 }
439}
440
441/*
442=item fill_solid(fill, x, y, width, channels, data)
443
444The floating sample fill function for non-combining solid fills.
445
446=cut
447*/
448static void
449fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
450 i_fcolor *data) {
451 while (width-- > 0) {
452 *data++ = T_SOLID_FILL(fill)->fc;
453 }
454}
455
456/*
457=item fill_solid_comb(fill, x, y, width, channels, data)
458
459The 8-bit sample fill function for combining solid fills.
460
461=cut
462*/
463static void
464fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
465 i_color *data) {
466 i_color c = T_SOLID_FILL(fill)->c;
467
468 while (width-- > 0) {
469 COMBINE(*data, c, channels);
470 ++data;
471 }
472}
473
474/*
475=item fill_solidf_comb(fill, x, y, width, channels, data)
476
477The floating sample fill function for combining solid fills.
478
479=cut
480*/
481static void
482fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
483 i_fcolor *data) {
484 i_fcolor c = T_SOLID_FILL(fill)->fc;
485
486 while (width-- > 0) {
487 COMBINEF(*data, c, channels);
488 ++data;
489 }
490}
491
492/*
493=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
494
495Implements creation of hatch fill objects.
496
497=cut
498*/
f1ac5027
TC
499static
500i_fill_t *
501i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
502 int combine, int hatch, unsigned char *cust_hatch,
503 int dx, int dy) {
504 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t));
505
506 fill->base.fill_with_color = fill_hatch;
507 fill->base.fill_with_fcolor = fill_hatchf;
508 fill->base.destroy = NULL;
509 fill->fg = fg ? *fg : fcolor_to_color(ffg);
510 fill->bg = bg ? *bg : fcolor_to_color(fbg);
511 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
512 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
513 fill->base.combines =
514 combine && (fill->ffg.channel[0] < 1 || fill->fbg.channel[0] < 1);
515 if (cust_hatch) {
516 memcpy(fill->hatch, cust_hatch, 8);
517 }
518 else {
519 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
520 hatch = 0;
521 memcpy(fill->hatch, builtin_hatches[hatch], 8);
522 }
523 fill->dx = dx & 7;
524 fill->dy = dy & 7;
525
526 return &fill->base;
527}
528
773bc121
TC
529/*
530=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 531
773bc121 532The 8-bit sample fill function for hatched fills.
f1ac5027 533
773bc121
TC
534=back
535*/
f1ac5027
TC
536static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
537 i_color *data) {
538 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
539 int byte = f->hatch[(y + f->dy) & 7];
540 int xpos = (x + f->dx) & 7;
541 int mask = 128 >> xpos;
542
543 while (width-- > 0) {
544 i_color c = (byte & mask) ? f->fg : f->bg;
545
546 if (f->base.combines) {
547 COMBINE(*data, c, channels);
548 }
549 else {
550 *data = c;
551 }
552 ++data;
553 if ((mask >>= 1) == 0)
554 mask = 128;
555 }
556}
557
773bc121
TC
558/*
559=item fill_hatchf(fill, x, y, width, channels, data)
560
561The floating sample fill function for hatched fills.
562
563=back
564*/
f1ac5027
TC
565static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
566 i_fcolor *data) {
567 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
568 int byte = f->hatch[(y + f->dy) & 7];
569 int xpos = (x + f->dx) & 7;
570 int mask = 128 >> xpos;
571
572 while (width-- > 0) {
573 i_fcolor c = (byte & mask) ? f->ffg : f->fbg;
574
575 if (f->base.combines) {
576 COMBINE(*data, c, channels);
577 }
578 else {
579 *data = c;
580 }
581 ++data;
582 if ((mask >>= 1) == 0)
583 mask = 128;
584 }
585}
773bc121
TC
586
587/*
588=back
589
590=head1 AUTHOR
591
592Tony Cook <tony@develop-help.com>
593
594=head1 SEE ALSO
595
596Imager(3)
597
598=cut
599*/