Added some source code docs
[imager.git] / fills.c
1 #include "image.h"
2 #include "imagei.h"
3
4 /*
5 =head1 NAME
6
7 fills.c - implements the basic general fills
8
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
23 Implements the basic general fills, which can be used for filling some
24 shapes and for flood fills.
25
26 Each fill can implement up to 3 functions:
27
28 =over
29
30 =item fill_with_color
31
32 called for fills on 8-bit images.  This can be NULL in which case the
33 fill_with_colorf function is called.
34
35 =item fill_with_fcolor
36
37 called for fills on non-8-bit images or when fill_with_color is NULL.
38
39 =item destroy
40
41 called by i_fill_destroy() if non-NULL, to release any extra resources
42 that the fill may need.
43
44 =back
45
46 fill_with_color and fill_with_fcolor are basically the same function
47 except that the first works with lines of i_color and the second with
48 lines of i_fcolor.
49
50 If the combines member if non-zero the line data is populated from the
51 target image before calling fill_with_*color.
52
53 fill_with_color needs to fill the I<data> parameter with the fill
54 pixels.  If combines is non-zero it the fill pixels should be combined
55 with the existing data.
56
57 The current fills are:
58
59 =over
60
61 =item *
62
63 solid fill
64
65 =item *
66
67 hatched fill
68
69 =item *
70
71 fountain fill
72
73 =back
74
75 Fountain fill is implemented by L<filters.c>.
76
77 =over
78
79 =cut
80 */
81
82 static 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
90 static 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
98 typedef 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
123 static void fill_solid(i_fill_t *, int x, int y, int width, int channels, 
124                        i_color *);
125 static void fill_solidf(i_fill_t *, int x, int y, int width, int channels, 
126                         i_fcolor *);
127 static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels, 
128                             i_color *);
129 static void fill_solidf_comb(i_fill_t *, int x, int y, int width, 
130                              int channels, i_fcolor *);
131
132 static i_fill_solid_t base_solid_fill =
133 {
134   {
135     fill_solid,
136     fill_solidf,
137     NULL,
138     0
139   },
140 };
141 static 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
151 /*
152 =item i_fill_destroy(fill)
153
154 Call to destroy any fill object.
155
156 =cut
157 */
158
159 void
160 i_fill_destroy(i_fill_t *fill) {
161   if (fill->destroy)
162     (fill->destroy)(fill);
163   myfree(fill);
164 }
165
166 /*
167 =item i_new_fill_solidf(color, combine)
168
169 Create a solid fill based on a float color.
170
171 If combine is non-zero then alpha values will be combined.
172
173 =cut
174 */
175
176 i_fill_t *
177 i_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
193 /*
194 =item i_new_fill_solid(color, combine)
195
196 Create a solid fill based.
197
198 If combine is non-zero then alpha values will be combined.
199
200 =cut
201 */
202
203 i_fill_t *
204 i_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
220 static unsigned char
221 builtin_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 */
325     0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
326   },
327   {
328     /* scales overlapping upwards */
329     0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
330   },
331   {
332     /* scales overlapping leftwards */
333     0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
334   },
335   {
336     /* scales overlapping rightwards */
337     0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
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   },
347   {
348     /* wider stipple */
349     0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
350   },
351 };
352
353 typedef 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
362 static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, 
363                        i_color *data);
364 static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, 
365                         i_fcolor *data);
366 static
367 i_fill_t *
368 i_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
375 Creates a new hatched fill with the fg color used for the 1 bits in
376 the hatch and bg for the 0 bits.  If combine is non-zero alpha values
377 will be combined.
378
379 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
380 hash definition, with the high-bits to the left.
381
382 If 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 */
388 i_fill_t *
389 i_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
398 Creates a new hatched fill with the fg color used for the 1 bits in
399 the hatch and bg for the 0 bits.  If combine is non-zero alpha values
400 will be combined.
401
402 If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
403 hash definition, with the high-bits to the left.
404
405 If 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 */
411 i_fill_t *
412 i_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
429 The 8-bit sample fill function for non-combining solid fills.
430
431 =cut
432 */
433 static void
434 fill_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
444 The floating sample fill function for non-combining solid fills.
445
446 =cut
447 */
448 static void
449 fill_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
459 The 8-bit sample fill function for combining solid fills.
460
461 =cut
462 */
463 static void
464 fill_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
477 The floating sample fill function for combining solid fills.
478
479 =cut
480 */
481 static void
482 fill_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
495 Implements creation of hatch fill objects.
496
497 =cut
498 */
499 static
500 i_fill_t *
501 i_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
529 /*
530 =item fill_hatch(fill, x, y, width, channels, data)
531
532 The 8-bit sample fill function for hatched fills.
533
534 =back
535 */
536 static 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
558 /*
559 =item fill_hatchf(fill, x, y, width, channels, data)
560
561 The floating sample fill function for hatched fills.
562
563 =back
564 */
565 static 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 }
586
587 /*
588 =back
589
590 =head1 AUTHOR
591
592 Tony Cook <tony@develop-help.com>
593
594 =head1 SEE ALSO
595
596 Imager(3)
597
598 =cut
599 */