Added preliminary support for adding image based fonts.
[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);
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
107static i_color fcolor_to_color(i_fcolor *c) {
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
117static i_fcolor color_to_fcolor(i_color *c) {
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 169static void fill_solid_comb(i_fill_t *, int x, int y, int width, int channels,
43c5dacb 170 i_color *);
f1ac5027 171static void fill_solidf_comb(i_fill_t *, int x, int y, int width,
43c5dacb 172 int channels, i_fcolor *);
f1ac5027
TC
173
174static i_fill_solid_t base_solid_fill =
175{
176 {
177 fill_solid,
178 fill_solidf,
179 NULL,
efdc2568
TC
180 NULL,
181 NULL,
f1ac5027
TC
182 },
183};
184static i_fill_solid_t base_solid_fill_comb =
185{
186 {
187 fill_solid_comb,
188 fill_solidf_comb,
189 NULL,
efdc2568
TC
190 NULL,
191 NULL,
f1ac5027
TC
192 },
193};
194
773bc121
TC
195/*
196=item i_fill_destroy(fill)
197
198Call to destroy any fill object.
199
200=cut
201*/
202
f1ac5027
TC
203void
204i_fill_destroy(i_fill_t *fill) {
205 if (fill->destroy)
206 (fill->destroy)(fill);
207 myfree(fill);
208}
209
773bc121
TC
210/*
211=item i_new_fill_solidf(color, combine)
212
213Create a solid fill based on a float color.
214
215If combine is non-zero then alpha values will be combined.
216
217=cut
218*/
219
f1ac5027
TC
220i_fill_t *
221i_new_fill_solidf(i_fcolor *c, int combine) {
222 int ch;
223 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
224
141a6114 225 if (combine) {
f1ac5027 226 *fill = base_solid_fill_comb;
efdc2568
TC
227 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
228 }
f1ac5027
TC
229 else
230 *fill = base_solid_fill;
231 fill->fc = *c;
232 for (ch = 0; ch < MAXCHANNELS; ++ch) {
233 fill->c.channel[ch] = SampleFTo8(c->channel[ch]);
234 }
235
236 return &fill->base;
237}
238
773bc121
TC
239/*
240=item i_new_fill_solid(color, combine)
241
242Create a solid fill based.
243
244If combine is non-zero then alpha values will be combined.
245
246=cut
247*/
248
f1ac5027
TC
249i_fill_t *
250i_new_fill_solid(i_color *c, int combine) {
251 int ch;
252 i_fill_solid_t *fill = mymalloc(sizeof(i_fill_solid_t));
253
141a6114 254 if (combine) {
f1ac5027 255 *fill = base_solid_fill_comb;
efdc2568
TC
256 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
257 }
f1ac5027
TC
258 else
259 *fill = base_solid_fill;
260 fill->c = *c;
261 for (ch = 0; ch < MAXCHANNELS; ++ch) {
262 fill->fc.channel[ch] = Sample8ToF(c->channel[ch]);
263 }
264
265 return &fill->base;
266}
267
f1ac5027
TC
268static unsigned char
269builtin_hatches[][8] =
270{
271 {
272 /* 1x1 checkerboard */
273 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
274 },
275 {
276 /* 2x2 checkerboard */
277 0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0x33, 0x33,
278 },
279 {
280 /* 4 x 4 checkerboard */
281 0xF0, 0xF0, 0xF0, 0xF0, 0x0F, 0x0F, 0x0F, 0x0F,
282 },
283 {
284 /* single vertical lines */
285 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
286 },
287 {
288 /* double vertical lines */
289 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
290 },
291 {
292 /* quad vertical lines */
293 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
294 },
295 {
296 /* single hlines */
297 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
298 },
299 {
300 /* double hlines */
301 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
302 },
303 {
304 /* quad hlines */
305 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
306 },
307 {
308 /* single / */
309 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
310 },
311 {
312 /* single \ */
313 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
314 },
315 {
316 /* double / */
317 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88,
318 },
319 {
320 /* double \ */
321 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11,
322 },
323 {
324 /* single grid */
325 0xFF, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
326 },
327 {
328 /* double grid */
329 0xFF, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88,
330 },
331 {
332 /* quad grid */
333 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA, 0xFF, 0xAA,
334 },
335 {
336 /* single dots */
337 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
338 },
339 {
340 /* 4 dots */
341 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
342 },
343 {
344 /* 16 dots */
345 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
346 },
347 {
348 /* simple stipple */
349 0x48, 0x84, 0x00, 0x00, 0x84, 0x48, 0x00, 0x00,
350 },
351 {
352 /* weave */
353 0x55, 0xFD, 0x05, 0xFD, 0x55, 0xDF, 0x50, 0xDF,
354 },
355 {
356 /* single cross hatch */
357 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, 0x01,
358 },
359 {
360 /* double cross hatch */
361 0xAA, 0x44, 0xAA, 0x11, 0xAA, 0x44, 0xAA, 0x11,
362 },
363 {
364 /* vertical lozenge */
365 0x11, 0x11, 0x11, 0xAA, 0x44, 0x44, 0x44, 0xAA,
366 },
367 {
368 /* horizontal lozenge */
369 0x88, 0x70, 0x88, 0x07, 0x88, 0x70, 0x88, 0x07,
370 },
371 {
372 /* scales overlapping downwards */
7a606d29 373 0x80, 0x80, 0x41, 0x3E, 0x08, 0x08, 0x14, 0xE3,
f1ac5027
TC
374 },
375 {
376 /* scales overlapping upwards */
7a606d29 377 0xC7, 0x28, 0x10, 0x10, 0x7C, 0x82, 0x01, 0x01,
f1ac5027
TC
378 },
379 {
380 /* scales overlapping leftwards */
7a606d29 381 0x83, 0x84, 0x88, 0x48, 0x38, 0x48, 0x88, 0x84,
f1ac5027
TC
382 },
383 {
384 /* scales overlapping rightwards */
7a606d29 385 0x21, 0x11, 0x12, 0x1C, 0x12, 0x11, 0x21, 0xC1,
f1ac5027
TC
386 },
387 {
388 /* denser stipple */
389 0x44, 0x88, 0x22, 0x11, 0x44, 0x88, 0x22, 0x11,
390 },
391 {
392 /* L-shaped tiles */
393 0xFF, 0x84, 0x84, 0x9C, 0x94, 0x9C, 0x90, 0x90,
394 },
cc6483e0
TC
395 {
396 /* wider stipple */
397 0x80, 0x40, 0x20, 0x00, 0x02, 0x04, 0x08, 0x00,
398 },
f1ac5027
TC
399};
400
401typedef struct
402{
403 i_fill_t base;
404 i_color fg, bg;
405 i_fcolor ffg, fbg;
406 unsigned char hatch[8];
407 int dx, dy;
408} i_fill_hatch_t;
409
410static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 411 i_color *data);
f1ac5027 412static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 413 i_fcolor *data);
773bc121
TC
414static
415i_fill_t *
416i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
417 int combine, int hatch, unsigned char *cust_hatch,
418 int dx, int dy);
419
420/*
421=item i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
422
423Creates a new hatched fill with the fg color used for the 1 bits in
424the hatch and bg for the 0 bits. If combine is non-zero alpha values
425will be combined.
f1ac5027 426
773bc121
TC
427If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
428hash definition, with the high-bits to the left.
429
430If cust_hatch is NULL then one of the standard hatches is used.
431
432(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.
433
434=cut
435*/
436i_fill_t *
437i_new_fill_hatch(i_color *fg, i_color *bg, int combine, int hatch,
438 unsigned char *cust_hatch, int dx, int dy) {
439 return i_new_hatch_low(fg, bg, NULL, NULL, combine, hatch, cust_hatch,
440 dx, dy);
441}
442
443/*
444=item i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
445
446Creates a new hatched fill with the fg color used for the 1 bits in
447the hatch and bg for the 0 bits. If combine is non-zero alpha values
448will be combined.
449
450If cust_hatch is non-NULL it should be a pointer to 8 bytes of the
451hash definition, with the high-bits to the left.
452
453If cust_hatch is NULL then one of the standard hatches is used.
454
455(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.
456
457=cut
458*/
459i_fill_t *
460i_new_fill_hatchf(i_fcolor *fg, i_fcolor *bg, int combine, int hatch,
461 unsigned char *cust_hatch, int dx, int dy) {
462 return i_new_hatch_low(NULL, NULL, fg, bg, combine, hatch, cust_hatch,
463 dx, dy);
464}
465
f576ce7e 466static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 467 i_color *data);
f576ce7e 468static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 469 i_fcolor *data);
f576ce7e
TC
470struct i_fill_image_t {
471 i_fill_t base;
472 i_img *src;
473 int xoff, yoff;
474 int has_matrix;
475 double matrix[9];
476};
477
478/*
479=item i_new_fill_image(im, matrix, xoff, yoff, combine)
480
481Create an image based fill.
482
483=cut
484*/
485i_fill_t *
486i_new_fill_image(i_img *im, double *matrix, int xoff, int yoff, int combine) {
487 struct i_fill_image_t *fill = mymalloc(sizeof(*fill));
488
489 fill->base.fill_with_color = fill_image;
490 fill->base.fill_with_fcolor = fill_imagef;
491 fill->base.destroy = NULL;
492
493 if (combine) {
494 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
495 }
496 else {
497 fill->base.combine = NULL;
498 fill->base.combinef = NULL;
499 }
500 fill->src = im;
501 if (xoff < 0)
502 xoff += im->xsize;
503 fill->xoff = xoff;
504 if (yoff < 0)
505 yoff += im->ysize;
506 fill->yoff = yoff;
507 if (matrix) {
508 fill->has_matrix = 1;
509 memcpy(fill->matrix, matrix, sizeof(fill->matrix));
510 }
511 else
512 fill->has_matrix = 0;
513
514 return &fill->base;
515}
516
517
773bc121
TC
518#define T_SOLID_FILL(fill) ((i_fill_solid_t *)(fill))
519
520/*
521=back
522
523=head1 INTERNAL FUNCTIONS
524
525=over
526
527=item fill_solid(fill, x, y, width, channels, data)
528
529The 8-bit sample fill function for non-combining solid fills.
530
531=cut
532*/
533static void
534fill_solid(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 535 i_color *data) {
773bc121
TC
536 while (width-- > 0) {
537 *data++ = T_SOLID_FILL(fill)->c;
538 }
539}
540
541/*
542=item fill_solid(fill, x, y, width, channels, data)
543
544The floating sample fill function for non-combining solid fills.
545
546=cut
547*/
548static void
549fill_solidf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 550 i_fcolor *data) {
773bc121
TC
551 while (width-- > 0) {
552 *data++ = T_SOLID_FILL(fill)->fc;
553 }
554}
555
556/*
557=item fill_solid_comb(fill, x, y, width, channels, data)
558
559The 8-bit sample fill function for combining solid fills.
560
561=cut
562*/
563static void
564fill_solid_comb(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 565 i_color *data) {
773bc121
TC
566 i_color c = T_SOLID_FILL(fill)->c;
567
568 while (width-- > 0) {
43c5dacb 569 *data++ = c;
773bc121
TC
570 }
571}
572
573/*
574=item fill_solidf_comb(fill, x, y, width, channels, data)
575
576The floating sample fill function for combining solid fills.
577
578=cut
579*/
580static void
581fill_solidf_comb(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 582 i_fcolor *data) {
773bc121
TC
583 i_fcolor c = T_SOLID_FILL(fill)->fc;
584
585 while (width-- > 0) {
43c5dacb 586 *data++ = c;
773bc121
TC
587 }
588}
589
590/*
591=item i_new_hatch_low(fg, bg, ffg, fbg, combine, hatch, cust_hatch, dx, dy)
592
593Implements creation of hatch fill objects.
594
595=cut
596*/
f1ac5027
TC
597static
598i_fill_t *
599i_new_hatch_low(i_color *fg, i_color *bg, i_fcolor *ffg, i_fcolor *fbg,
600 int combine, int hatch, unsigned char *cust_hatch,
601 int dx, int dy) {
602 i_fill_hatch_t *fill = mymalloc(sizeof(i_fill_hatch_t));
603
604 fill->base.fill_with_color = fill_hatch;
605 fill->base.fill_with_fcolor = fill_hatchf;
606 fill->base.destroy = NULL;
607 fill->fg = fg ? *fg : fcolor_to_color(ffg);
608 fill->bg = bg ? *bg : fcolor_to_color(fbg);
609 fill->ffg = ffg ? *ffg : color_to_fcolor(fg);
610 fill->fbg = fbg ? *fbg : color_to_fcolor(bg);
141a6114 611 if (combine) {
efdc2568
TC
612 i_get_combine(combine, &fill->base.combine, &fill->base.combinef);
613 }
614 else {
615 fill->base.combine = NULL;
616 fill->base.combinef = NULL;
617 }
f1ac5027
TC
618 if (cust_hatch) {
619 memcpy(fill->hatch, cust_hatch, 8);
620 }
621 else {
622 if (hatch > sizeof(builtin_hatches)/sizeof(*builtin_hatches))
623 hatch = 0;
624 memcpy(fill->hatch, builtin_hatches[hatch], 8);
625 }
626 fill->dx = dx & 7;
627 fill->dy = dy & 7;
628
629 return &fill->base;
630}
631
773bc121
TC
632/*
633=item fill_hatch(fill, x, y, width, channels, data)
f1ac5027 634
773bc121 635The 8-bit sample fill function for hatched fills.
f1ac5027 636
b8c2033e 637=cut
773bc121 638*/
f1ac5027 639static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 640 i_color *data) {
f1ac5027
TC
641 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
642 int byte = f->hatch[(y + f->dy) & 7];
643 int xpos = (x + f->dx) & 7;
644 int mask = 128 >> xpos;
645
43c5dacb
TC
646 while (width-- > 0) {
647 *data++ = (byte & mask) ? f->fg : f->bg;
648
649 if ((mask >>= 1) == 0)
650 mask = 128;
f1ac5027
TC
651 }
652}
653
773bc121
TC
654/*
655=item fill_hatchf(fill, x, y, width, channels, data)
656
657The floating sample fill function for hatched fills.
658
659=back
660*/
f1ac5027 661static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 662 i_fcolor *data) {
f1ac5027
TC
663 i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
664 int byte = f->hatch[(y + f->dy) & 7];
665 int xpos = (x + f->dx) & 7;
666 int mask = 128 >> xpos;
667
43c5dacb
TC
668 while (width-- > 0) {
669 *data++ = (byte & mask) ? f->ffg : f->fbg;
670
671 if ((mask >>= 1) == 0)
672 mask = 128;
efdc2568
TC
673 }
674}
675
f576ce7e
TC
676/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
677/* linear interpolation */
678static i_color interp_i_color(i_color before, i_color after, double pos,
679 int channels) {
680 i_color out;
681 int ch;
682
683 pos -= floor(pos);
684 for (ch = 0; ch < channels; ++ch)
685 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
686 if (out.channel[3])
687 for (ch = 0; ch < channels; ++ch)
688 if (ch != 3) {
689 int temp = out.channel[ch] * 255 / out.channel[3];
690 if (temp > 255)
691 temp = 255;
692 out.channel[ch] = temp;
693 }
694
695 return out;
696}
697
698/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
699/* linear interpolation */
700static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
701 int channels) {
702 i_fcolor out;
703 int ch;
704
705 pos -= floor(pos);
706 for (ch = 0; ch < channels; ++ch)
707 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
708 if (out.channel[3])
709 for (ch = 0; ch < channels; ++ch)
710 if (ch != 3) {
711 int temp = out.channel[ch] / out.channel[3];
712 if (temp > 1.0)
713 temp = 1.0;
714 out.channel[ch] = temp;
715 }
716
717 return out;
718}
719
720/*
721=item fill_image(fill, x, y, width, channels, data, work)
722
723=cut
724*/
725static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 726 i_color *data) {
f576ce7e 727 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e
TC
728 int i = 0;
729 i_color c;
730
731 if (f->has_matrix) {
732 /* the hard way */
733 while (i < width) {
734 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
735 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
736 double ix = floor(rx / f->src->xsize);
737 double iy = floor(ry / f->src->ysize);
738 i_color c[2][2];
739 i_color c2[2];
740 int dy;
741
742 if (f->xoff) {
743 rx += iy * f->xoff;
744 ix = floor(rx / f->src->xsize);
745 }
746 else if (f->yoff) {
747 ry += ix * f->yoff;
748 iy = floor(ry / f->src->ysize);
749 }
750 rx -= ix * f->src->xsize;
751 ry -= iy * f->src->ysize;
752
753 for (dy = 0; dy < 2; ++dy) {
754 if ((int)rx == f->src->xsize-1) {
755 i_gpix(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
756 i_gpix(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
757 }
758 else {
759 i_glin(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
760 c[dy]);
761 }
762 c2[dy] = interp_i_color(c[dy][0], c[dy][1], rx, f->src->channels);
763 }
43c5dacb 764 *data++ = interp_i_color(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
765 ++i;
766 }
767 }
768 else {
769 /* the easy way */
770 /* this should be possible to optimize to use i_glin() */
771 while (i < width) {
772 int rx = x+i;
773 int ry = y;
774 int ix = rx / f->src->xsize;
775 int iy = ry / f->src->ysize;
776
777 if (f->xoff) {
778 rx += iy * f->xoff;
779 ix = rx / f->src->xsize;
780 }
781 else if (f->yoff) {
782 ry += ix * f->yoff;
783 iy = ry / f->src->xsize;
784 }
785 rx -= ix * f->src->xsize;
786 ry -= iy * f->src->ysize;
43c5dacb
TC
787 i_gpix(f->src, rx, ry, data);
788 ++data;
f576ce7e
TC
789 ++i;
790 }
791 }
f576ce7e
TC
792}
793
794/*
795=item fill_image(fill, x, y, width, channels, data, work)
796
797=cut
798*/
799static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
43c5dacb 800 i_fcolor *data) {
f576ce7e 801 struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
f576ce7e
TC
802 int i = 0;
803 i_fcolor c;
804
805 if (f->has_matrix) {
806 /* the hard way */
807 while (i < width) {
808 double rx = f->matrix[0] * (x+i) + f->matrix[1] * y + f->matrix[2];
809 double ry = f->matrix[3] * (x+i) + f->matrix[4] * y + f->matrix[5];
810 double ix = floor(rx / f->src->xsize);
811 double iy = floor(ry / f->src->ysize);
812 i_fcolor c[2][2];
813 i_fcolor c2[2];
814 int dy;
815
816 if (f->xoff) {
817 rx += iy * f->xoff;
818 ix = floor(rx / f->src->xsize);
819 }
820 else if (f->yoff) {
821 ry += ix * f->yoff;
822 iy = floor(ry / f->src->ysize);
823 }
824 rx -= ix * f->src->xsize;
825 ry -= iy * f->src->ysize;
826
827 for (dy = 0; dy < 2; ++dy) {
828 if ((int)rx == f->src->xsize-1) {
829 i_gpixf(f->src, f->src->xsize-1, ((int)ry+dy) % f->src->ysize, &c[dy][0]);
830 i_gpixf(f->src, 0, ((int)ry+dy) % f->src->xsize, &c[dy][1]);
831 }
832 else {
833 i_glinf(f->src, (int)rx, (int)rx+2, ((int)ry+dy) % f->src->ysize,
834 c[dy]);
835 }
836 c2[dy] = interp_i_fcolor(c[dy][0], c[dy][1], rx, f->src->channels);
837 }
43c5dacb 838 *data++ = interp_i_fcolor(c2[0], c2[1], ry, f->src->channels);
f576ce7e
TC
839 ++i;
840 }
841 }
842 else {
843 /* the easy way */
844 /* this should be possible to optimize to use i_glin() */
845 while (i < width) {
846 int rx = x+i;
847 int ry = y;
848 int ix = rx / f->src->xsize;
849 int iy = ry / f->src->ysize;
850
851 if (f->xoff) {
852 rx += iy * f->xoff;
853 ix = rx / f->src->xsize;
854 }
855 else if (f->yoff) {
856 ry += ix * f->yoff;
857 iy = ry / f->src->xsize;
858 }
859 rx -= ix * f->src->xsize;
860 ry -= iy * f->src->ysize;
43c5dacb
TC
861 i_gpixf(f->src, rx, ry, data);
862 ++data;
f576ce7e
TC
863 ++i;
864 }
865 }
f576ce7e
TC
866}
867
efdc2568
TC
868static void combine_replace(i_color *, i_color *, int, int);
869static void combine_replacef(i_fcolor *, i_fcolor *, int, int);
870static void combine_alphablend(i_color *, i_color *, int, int);
871static void combine_alphablendf(i_fcolor *, i_fcolor *, int, int);
872static void combine_mult(i_color *, i_color *, int, int);
873static void combine_multf(i_fcolor *, i_fcolor *, int, int);
874static void combine_dissolve(i_color *, i_color *, int, int);
875static void combine_dissolvef(i_fcolor *, i_fcolor *, int, int);
876static void combine_add(i_color *, i_color *, int, int);
877static void combine_addf(i_fcolor *, i_fcolor *, int, int);
878static void combine_subtract(i_color *, i_color *, int, int);
879static void combine_subtractf(i_fcolor *, i_fcolor *, int, int);
880static void combine_diff(i_color *, i_color *, int, int);
881static void combine_difff(i_fcolor *, i_fcolor *, int, int);
882static void combine_darken(i_color *, i_color *, int, int);
883static void combine_darkenf(i_fcolor *, i_fcolor *, int, int);
884static void combine_lighten(i_color *, i_color *, int, int);
885static void combine_lightenf(i_fcolor *, i_fcolor *, int, int);
886static void combine_hue(i_color *, i_color *, int, int);
887static void combine_huef(i_fcolor *, i_fcolor *, int, int);
888static void combine_sat(i_color *, i_color *, int, int);
889static void combine_satf(i_fcolor *, i_fcolor *, int, int);
890static void combine_value(i_color *, i_color *, int, int);
891static void combine_valuef(i_fcolor *, i_fcolor *, int, int);
892static void combine_color(i_color *, i_color *, int, int);
893static void combine_colorf(i_fcolor *, i_fcolor *, int, int);
894
b33c08f8 895static struct i_combines {
efdc2568
TC
896 i_fill_combine_f combine;
897 i_fill_combinef_f combinef;
898} combines[] =
899{
900 { /* replace */
901 combine_replace,
902 combine_replacef,
903 },
904 { /* alpha blend */
905 combine_alphablend,
906 combine_alphablendf,
907 },
908 {
909 /* multiply */
910 combine_mult,
911 combine_multf,
912 },
913 {
914 /* dissolve */
915 combine_dissolve,
916 combine_dissolvef,
917 },
918 {
919 /* add */
920 combine_add,
921 combine_addf,
922 },
923 {
924 /* subtract */
925 combine_subtract,
926 combine_subtractf,
927 },
928 {
929 /* diff */
930 combine_diff,
931 combine_difff,
932 },
933 {
934 combine_lighten,
935 combine_lightenf,
936 },
937 {
938 combine_darken,
939 combine_darkenf,
940 },
941 {
942 combine_hue,
943 combine_huef,
944 },
945 {
946 combine_sat,
947 combine_satf,
948 },
949 {
950 combine_value,
951 combine_valuef,
952 },
953 {
954 combine_color,
955 combine_colorf,
956 },
957};
958
959/*
960=item i_get_combine(combine, color_func, fcolor_func)
961
962=cut
963*/
964
965void i_get_combine(int combine, i_fill_combine_f *color_func,
966 i_fill_combinef_f *fcolor_func) {
967 if (combine < 0 || combine > sizeof(combines) / sizeof(*combines))
968 combine = 0;
969
970 *color_func = combines[combine].combine;
971 *fcolor_func = combines[combine].combinef;
972}
973
974static void combine_replace(i_color *out, i_color *in, int channels, int count) {
975 while (count--) {
976 *out++ = *in++;
977 }
978}
979
980static void combine_replacef(i_fcolor *out, i_fcolor *in, int channels, int count) {
981 while (count--) {
982 *out++ = *in++;
983 }
984}
985
986static void combine_alphablend(i_color *out, i_color *in, int channels, int count) {
987 while (count--) {
988 COMBINE(*out, *in, channels);
989 ++out;
990 ++in;
991 }
992}
993
994static void combine_alphablendf(i_fcolor *out, i_fcolor *in, int channels, int count) {
995 while (count--) {
996 COMBINEF(*out, *in, channels);
997 ++out;
998 ++in;
999 }
1000}
1001
1002static void combine_mult(i_color *out, i_color *in, int channels, int count) {
1003 int ch;
1004
1005 while (count--) {
1006 i_color c = *in;
1007 double mult[MAXCHANNELS];
1008 mult[3] = in->channel[3];
1009 for (ch = 0; ch < (channels); ++ch) {
1010 if (ch != 3)
1011 mult[ch] = (out->channel[ch] * in->channel[ch]) * (1.0 / 255);
1012 }
1013 COMBINEA(*out, mult, channels);
1014 ++out;
1015 ++in;
1016 }
1017}
1018
1019static void combine_multf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1020 int ch;
1021
1022 while (count--) {
1023 i_fcolor c = *in;
1024 for (ch = 0; ch < channels; ++ch) {
1025 if (ch != 3)
1026 c.channel[ch] = out->channel[ch] * in->channel[ch];
1027 }
1028 COMBINEF(*out, c, channels);
1029 ++out;
1030 ++in;
1031 }
1032}
1033
1034static void combine_dissolve(i_color *out, i_color *in, int channels, int count) {
1035 int ch;
1036
1037 while (count--) {
1038 if (in->channel[3] > rand() * (255.0 / RAND_MAX))
1039 COMBINE(*out, *in, channels);
1040 ++out;
1041 ++in;
1042 }
1043}
1044
1045static void combine_dissolvef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1046 int ch;
1047
1048 while (count--) {
1049 if (in->channel[3] > rand() * (1.0 / RAND_MAX))
1050 COMBINEF(*out, *in, channels);
1051 ++out;
1052 ++in;
1053 }
1054}
1055
1056static void combine_add(i_color *out, i_color *in, int channels, int count) {
1057 int ch;
1058
1059 while (count--) {
1060 i_color c = *in;
1061 for (ch = 0; ch < (channels); ++ch) {
1062 if (ch != 3) {
1063 int total = out->channel[ch] + in->channel[ch];
1064 if (total > 255)
1065 total = 255;
1066 c.channel[ch] = total;
1067 }
1068 }
1069 COMBINE(*out, c, channels);
1070 ++out;
1071 ++in;
1072 }
1073}
1074
1075static void combine_addf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1076 int ch;
1077
1078 while (count--) {
1079 i_fcolor c = *in;
1080 for (ch = 0; ch < (channels); ++ch) {
1081 if (ch != 3) {
1082 double total = out->channel[ch] + in->channel[ch];
1083 if (total > 1.0)
1084 total = 1.0;
1085 out->channel[ch] = total;
1086 }
1087 }
1088 COMBINEF(*out, c, channels);
1089 ++out;
1090 ++in;
1091 }
1092}
1093
1094static void combine_subtract(i_color *out, i_color *in, int channels, int count) {
1095 int ch;
1096
1097 while (count--) {
1098 i_color c = *in;
1099 for (ch = 0; ch < (channels); ++ch) {
1100 if (ch != 3) {
1101 int total = out->channel[ch] - in->channel[ch];
1102 if (total < 0)
1103 total = 0;
1104 c.channel[ch] = total;
1105 }
1106 }
1107 COMBINE(*out, c, channels);
1108 ++out;
1109 ++in;
1110 }
1111}
1112
1113static void combine_subtractf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1114 int ch;
1115
1116 while (count--) {
1117 i_fcolor c = *in;
1118 for (ch = 0; ch < channels; ++ch) {
1119 if (ch != 3) {
1120 double total = out->channel[ch] - in->channel[ch];
1121 if (total < 0)
1122 total = 0;
1123 c.channel[ch] = total;
1124 }
1125 }
1126 COMBINEF(*out, c, channels);
1127 ++out;
1128 ++in;
1129 }
1130}
1131
1132static void combine_diff(i_color *out, i_color *in, int channels, int count) {
1133 int ch;
1134
1135 while (count--) {
1136 i_color c = *in;
1137 for (ch = 0; ch < (channels); ++ch) {
1138 if (ch != 3)
1139 c.channel[ch] = abs(out->channel[ch] - in->channel[ch]);
1140 }
1141 COMBINE(*out, c, channels)
1142 ++out;
1143 ++in;
1144 }
1145}
1146
1147static void combine_difff(i_fcolor *out, i_fcolor *in, int channels, int count) {
1148 int ch;
1149
1150 while (count--) {
1151 i_fcolor c = *in;
1152 for (ch = 0; ch < (channels); ++ch) {
1153 if (ch != 3)
1154 c.channel[ch] = fabs(out->channel[ch] - in->channel[ch]);
f1ac5027 1155 }
efdc2568
TC
1156 COMBINEF(*out, c, channels);
1157 ++out;
1158 ++in;
f1ac5027
TC
1159 }
1160}
773bc121 1161
efdc2568
TC
1162static void combine_darken(i_color *out, i_color *in, int channels, int count) {
1163 int ch;
1164
1165 while (count--) {
1166 for (ch = 0; ch < channels; ++ch) {
1167 if (ch != 3 && out->channel[ch] < in->channel[ch])
1168 in->channel[ch] = out->channel[ch];
1169 }
1170 COMBINE(*out, *in, channels);
1171 ++out;
1172 ++in;
1173 }
1174}
1175
1176static void combine_darkenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1177 int ch;
1178
1179 while (count--) {
1180 for (ch = 0; ch < channels; ++ch) {
1181 if (ch != 3 && out->channel[ch] < in->channel[ch])
1182 in->channel[ch] = out->channel[ch];
1183 }
1184 COMBINEF(*out, *in, channels);
1185 ++out;
1186 ++in;
1187 }
1188}
1189
1190static void combine_lighten(i_color *out, i_color *in, int channels, int count) {
1191 int ch;
1192
1193 while (count--) {
1194 for (ch = 0; ch < channels; ++ch) {
1195 if (ch != 3 && out->channel[ch] > in->channel[ch])
1196 in->channel[ch] = out->channel[ch];
1197 }
1198 COMBINE(*out, *in, channels);
1199 ++out;
1200 ++in;
1201 }
1202}
1203
1204static void combine_lightenf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1205 int ch;
1206
1207 while (count--) {
1208 for (ch = 0; ch < channels; ++ch) {
1209 if (ch != 3 && out->channel[ch] > in->channel[ch])
1210 in->channel[ch] = out->channel[ch];
1211 }
1212 COMBINEF(*out, *in, channels);
1213 ++out;
1214 ++in;
1215 }
1216}
1217
1218static void combine_hue(i_color *out, i_color *in, int channels, int count) {
1219 while (count--) {
1220 i_color c = *out;
1221 i_rgb_to_hsv(&c);
1222 i_rgb_to_hsv(in);
1223 c.channel[0] = in->channel[0];
1224 i_hsv_to_rgb(&c);
976efad5 1225 c.channel[3] = in->channel[3];
efdc2568
TC
1226 COMBINE(*out, c, channels);
1227 ++out;
1228 ++in;
1229 }
1230}
1231
1232static void combine_huef(i_fcolor *out, i_fcolor *in, int channels, int count) {
1233 while (count--) {
1234 i_fcolor c = *out;
1235 i_rgb_to_hsvf(&c);
1236 i_rgb_to_hsvf(in);
1237 c.channel[0] = in->channel[0];
1238 i_hsv_to_rgbf(&c);
1239 c.channel[3] = in->channel[3];
1240 COMBINEF(*out, c, channels);
1241 ++out;
1242 ++in;
1243 }
1244}
1245
1246static void combine_sat(i_color *out, i_color *in, int channels, int count) {
1247 while (count--) {
1248 i_color c = *out;
1249 i_rgb_to_hsv(&c);
1250 i_rgb_to_hsv(in);
1251 c.channel[1] = in->channel[1];
1252 i_hsv_to_rgb(&c);
1253 c.channel[3] = in->channel[3];
1254 COMBINE(*out, c, channels);
1255 ++out;
1256 ++in;
1257 }
1258}
1259
1260static void combine_satf(i_fcolor *out, i_fcolor *in, int channels, int count) {
1261 while (count--) {
1262 i_fcolor c = *out;
1263 i_rgb_to_hsvf(&c);
1264 i_rgb_to_hsvf(in);
1265 c.channel[1] = in->channel[1];
1266 i_hsv_to_rgbf(&c);
1267 c.channel[3] = in->channel[3];
1268 COMBINEF(*out, c, channels);
1269 ++out;
1270 ++in;
1271 }
1272}
1273
1274static void combine_value(i_color *out, i_color *in, int channels, int count) {
1275 while (count--) {
1276 i_color c = *out;
1277 i_rgb_to_hsv(&c);
1278 i_rgb_to_hsv(in);
1279 c.channel[2] = in->channel[2];
1280 i_hsv_to_rgb(&c);
1281 c.channel[3] = in->channel[3];
1282 COMBINE(*out, c, channels);
1283 ++out;
1284 ++in;
1285 }
1286}
1287
1288static void combine_valuef(i_fcolor *out, i_fcolor *in, int channels,
1289 int count) {
1290 while (count--) {
1291 i_fcolor c = *out;
1292 i_rgb_to_hsvf(&c);
1293 i_rgb_to_hsvf(in);
1294 c.channel[2] = in->channel[2];
1295 i_hsv_to_rgbf(&c);
1296 c.channel[3] = in->channel[3];
1297 COMBINEF(*out, c, channels);
1298 ++out;
1299 ++in;
1300 }
1301}
1302
1303static void combine_color(i_color *out, i_color *in, int channels, int count) {
1304 while (count--) {
1305 i_color c = *out;
1306 i_rgb_to_hsv(&c);
1307 i_rgb_to_hsv(in);
1308 c.channel[0] = in->channel[0];
1309 c.channel[1] = in->channel[1];
1310 i_hsv_to_rgb(&c);
1311 c.channel[3] = in->channel[3];
1312 COMBINE(*out, c, channels);
1313 ++out;
1314 ++in;
1315 }
1316}
1317
1318static void combine_colorf(i_fcolor *out, i_fcolor *in, int channels,
1319 int count) {
1320 while (count--) {
1321 i_fcolor c = *out;
1322 i_rgb_to_hsvf(&c);
1323 i_rgb_to_hsvf(in);
1324 c.channel[0] = in->channel[0];
1325 c.channel[1] = in->channel[1];
1326 i_hsv_to_rgbf(&c);
1327 c.channel[3] = in->channel[3];
1328 COMBINEF(*out, c, channels);
1329 ++out;
1330 ++in;
1331 }
1332}
1333
1334
773bc121
TC
1335/*
1336=back
1337
1338=head1 AUTHOR
1339
1340Tony Cook <tony@develop-help.com>
1341
1342=head1 SEE ALSO
1343
1344Imager(3)
1345
1346=cut
1347*/