commit changes from draw branch
[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)
183
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;
653
43c5dacb 654 while (width-- > 0) {
052acec4
TC
655 if (byte & mask)
656 *data++ = f->fg;
657 else
658 *data++ = f->bg;
43c5dacb
TC
659
660 if ((mask >>= 1) == 0)
661 mask = 128;
f1ac5027
TC
662 }
663}
664
773bc121
TC
665/*
666=item fill_hatchf(fill, x, y, width, channels, data)
667
668The floating sample fill function for hatched fills.
669
670=back
671*/
f1ac5027 672static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 673 i_fcolor *data) {
f1ac5027
TC
674 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
675 int byte = f->hatch[(y + f->dy) & 7];
676 int xpos = (x + f->dx) & 7;
677 int mask = 128 >> xpos;
678
43c5dacb 679 while (width-- > 0) {
052acec4
TC
680 if (byte & mask)
681 *data++ = f->ffg;
682 else
683 *data++ = f->fbg;
43c5dacb
TC
684
685 if ((mask >>= 1) == 0)
686 mask = 128;
efdc2568
TC
687 }
688}
689
f576ce7e
TC
690/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
691/* linear interpolation */
692static i_color interp_i_color(i_color before, i_color after, double pos,
693 int channels) {
694 i_color out;
695 int ch;
696
697 pos -= floor(pos);
698 for (ch = 0; ch < channels; ++ch)
699 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
3efb0915 700 if (channels > 3 && out.channel[3])
f576ce7e
TC
701 for (ch = 0; ch < channels; ++ch)
702 if (ch != 3) {
703 int temp = out.channel[ch] * 255 / out.channel[3];
704 if (temp > 255)
705 temp = 255;
706 out.channel[ch] = temp;
707 }
708
709 return out;
710}
711
712/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
713/* linear interpolation */
714static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
715 int channels) {
716 i_fcolor out;
717 int ch;
718
719 pos -= floor(pos);
720 for (ch = 0; ch < channels; ++ch)
721 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
722 if (out.channel[3])
723 for (ch = 0; ch < channels; ++ch)
724 if (ch != 3) {
725 int temp = out.channel[ch] / out.channel[3];
726 if (temp > 1.0)
727 temp = 1.0;
728 out.channel[ch] = temp;
729 }
730
731 return out;
732}
733
734/*
735=item fill_image(fill, x, y, width, channels, data, work)
736
737=cut
738*/
739static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 740 i_color *data) {
f576ce7e 741 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 742 int i = 0;
cde2dbc7 743 i_color *out = data;
f576ce7e
TC
744
745 if (f->has_matrix) {
746 /* the hard way */
747 while (i < width) {
748 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
749 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
750 double ix = floor(rx / f->src->xsize);
751 double iy = floor(ry / f->src->ysize);
752 i_color c[2][2];
753 i_color c2[2];
754 int dy;
755
756 if (f->xoff) {
757 rx += iy * f->xoff;
758 ix = floor(rx / f->src->xsize);
759 }
760 else if (f->yoff) {
761 ry += ix * f->yoff;
762 iy = floor(ry / f->src->ysize);
763 }
764 rx -= ix * f->src->xsize;
765 ry -= iy * f->src->ysize;
766
767 for (dy = 0; dy < 2; ++dy) {
768 if ((int)rx == f->src->xsize-1) {
769 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
770 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
771 }
772 else {
773 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
774 c[dy]);
775 }
776 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
777 }
cde2dbc7 778 *out++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
779 ++i;
780 }
781 }
782 else {
783 /* the easy way */
784 /* this should be possible to optimize to use i_glin() */
785 while (i < width) {
786 int rx = x+i;
787 int ry = y;
788 int ix = rx / f->src->xsize;
789 int iy = ry / f->src->ysize;
790
791 if (f->xoff) {
792 rx += iy * f->xoff;
793 ix = rx / f->src->xsize;
794 }
795 else if (f->yoff) {
796 ry += ix * f->yoff;
797 iy = ry / f->src->xsize;
798 }
799 rx -= ix * f->src->xsize;
800 ry -= iy * f->src->ysize;
cde2dbc7
TC
801 i_gpix(f->src, rx, ry, out);
802 ++out;
f576ce7e
TC
803 ++i;
804 }
805 }
cde2dbc7
TC
806 if (f->src->channels == 3) {
807 /* just set the alpha */
808 for (i = 0; i < width; ++i) {
809 data->channel[3] = 255;
810 data++;
811 }
812 }
813 else if (f->src->channels == 2) {
814 /* copy the alpha to channel 3, duplicate the grey value */
815 for (i = 0; i < width; ++i) {
816 data->channel[3] = data->channel[1];
817 data->channel[1] = data->channel[2] = data->channel[0];
818 data++;
819 }
820 }
821 else if (f->src->channels == 1) {
822 /* set the alpha, duplicate grey */
823 for (i = 0; i < width; ++i) {
824 data->channel[3] = 255;
825 data->channel[1] = data->channel[2] = data->channel[0];
826 data++;
827 }
828 }
f576ce7e
TC
829}
830
831/*
832=item fill_image(fill, x, y, width, channels, data, work)
833
834=cut
835*/
836static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 837 i_fcolor *data) {
f576ce7e 838 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e 839 int i = 0;
f576ce7e
TC
840
841 if (f->has_matrix) {
842 /* the hard way */
843 while (i < width) {
844 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
845 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
846 double ix = floor(rx / f->src->xsize);
847 double iy = floor(ry / f->src->ysize);
848 i_fcolor c[2][2];
849 i_fcolor c2[2];
850 int dy;
851
852 if (f->xoff) {
853 rx += iy * f->xoff;
854 ix = floor(rx / f->src->xsize);
855 }
856 else if (f->yoff) {
857 ry += ix * f->yoff;
858 iy = floor(ry / f->src->ysize);
859 }
860 rx -= ix * f->src->xsize;
861 ry -= iy * f->src->ysize;
862
863 for (dy = 0; dy < 2; ++dy) {
864 if ((int)rx == f->src->xsize-1) {
865 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
866 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
867 }
868 else {
869 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
870 c[dy]);
871 }
872 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
873 }
43c5dacb 874 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
875 ++i;
876 }
877 }
878 else {
879 /* the easy way */
880 /* this should be possible to optimize to use i_glin() */
881 while (i < width) {
882 int rx = x+i;
883 int ry = y;
884 int ix = rx / f->src->xsize;
885 int iy = ry / f->src->ysize;
886
887 if (f->xoff) {
888 rx += iy * f->xoff;
889 ix = rx / f->src->xsize;
890 }
891 else if (f->yoff) {
892 ry += ix * f->yoff;
893 iy = ry / f->src->xsize;
894 }
895 rx -= ix * f->src->xsize;
896 ry -= iy * f->src->ysize;
43c5dacb
TC
897 i_gpixf(f->src, rx, ry, data);
898 ++data;
f576ce7e
TC
899 ++i;
900 }
901 }
cde2dbc7
TC
902 if (f->src->channels == 3) {
903 /* just set the alpha */
904 for (i = 0; i < width; ++i) {
905 data->channel[3] = 1.0;
906 data++;
907 }
908 }
909 else if (f->src->channels == 2) {
910 /* copy the alpha to channel 3, duplicate the grey value */
911 for (i = 0; i < width; ++i) {
912 data->channel[3] = data->channel[1];
913 data->channel[1] = data->channel[2] = data->channel[0];
914 data++;
915 }
916 }
917 else if (f->src->channels == 1) {
918 /* set the alpha, duplicate grey */
919 for (i = 0; i < width; ++i) {
920 data->channel[3] = 1.0;
921 data->channel[1] = data->channel[2] = data->channel[0];
922 data++;
923 }
924 }
f576ce7e
TC
925}
926
efdc2568 927
773bc121
TC
928/*
929=back
930
931=head1 AUTHOR
932
933Tony Cook <tony@develop-help.com>
934
935=head1 SEE ALSO
936
937Imager(3)
938
939=cut
940*/