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