Commit | Line | Data |
---|---|---|
fe415ad2 TC |
1 | #include "imager.h" |
2 | ||
3 | static int | |
4 | rubthru_targ_noalpha(i_img *im, i_img *src, | |
5 | int tx, int ty, | |
6 | int src_minx, int src_miny, | |
7 | int src_maxx, int src_maxy) { | |
8 | int x, y, ttx, tty; | |
9 | int chancount; | |
10 | int chans[3]; | |
11 | int alphachan; | |
12 | int ch; | |
13 | ||
14 | i_clear_error(); | |
15 | ||
16 | if (im->channels == 3 && src->channels == 4) { | |
17 | chancount = 3; | |
18 | chans[0] = 0; chans[1] = 1; chans[2] = 2; | |
19 | alphachan = 3; | |
20 | } | |
21 | else if (im->channels == 3 && src->channels == 2) { | |
22 | chancount = 3; | |
23 | chans[0] = chans[1] = chans[2] = 0; | |
24 | alphachan = 1; | |
25 | } | |
26 | else if (im->channels == 1 && src->channels == 2) { | |
27 | chancount = 1; | |
28 | chans[0] = 0; | |
29 | alphachan = 1; | |
30 | } | |
31 | else { | |
32 | i_push_error(0, "rubthru can only work where (dest, src) channels are (3,4), (4,4), (3,2), (4,2), (1,2) or (2,2)"); | |
33 | return 0; | |
34 | } | |
35 | ||
36 | #code im->bits <= 8 && src->bits <= 8 | |
37 | IM_WORK_T alpha; | |
38 | IM_COLOR pv, orig, dest; | |
39 | ||
40 | tty = ty; | |
41 | for(y = src_miny; y < src_maxy; y++) { | |
42 | ttx = tx; | |
43 | for(x = src_minx; x < src_maxx; x++) { | |
44 | IM_GPIX(src, x, y, &pv); | |
45 | IM_GPIX(im, ttx, tty, &orig); | |
46 | alpha = pv.channel[alphachan]; | |
47 | for (ch = 0; ch < chancount; ++ch) { | |
48 | dest.channel[ch] = (alpha * pv.channel[chans[ch]] | |
49 | + (IM_SAMPLE_MAX - alpha) * orig.channel[ch])/IM_SAMPLE_MAX; | |
50 | } | |
51 | IM_PPIX(im, ttx, tty, &dest); | |
52 | ttx++; | |
53 | } | |
54 | tty++; | |
55 | } | |
56 | #/code | |
57 | return 1; | |
58 | } | |
59 | ||
60 | static int | |
61 | rubthru_targ_alpha(i_img *im, i_img *src, int tx, int ty, | |
62 | int src_minx, int src_miny, | |
63 | int src_maxx, int src_maxy) { | |
64 | int x, y, ttx, tty; | |
65 | int chancount; | |
66 | int chans[3]; | |
67 | int alphachan; | |
68 | int ch; | |
69 | int targ_alpha_chan; | |
70 | ||
71 | if (im->channels == 4 && src->channels == 4) { | |
72 | chancount = 3; | |
73 | chans[0] = 0; chans[1] = 1; chans[2] = 2; | |
74 | alphachan = 3; | |
75 | } | |
76 | else if (im->channels == 4 && src->channels == 2) { | |
77 | chancount = 3; | |
78 | chans[0] = chans[1] = chans[2] = 0; | |
79 | alphachan = 1; | |
80 | } | |
81 | else if (im->channels == 2 && src->channels == 2) { | |
82 | chancount = 1; | |
83 | chans[0] = 0; | |
84 | alphachan = 1; | |
85 | } | |
86 | else { | |
87 | i_push_error(0, "rubthru can only work where (dest, src) channels are (3,4), (4,4), (3,2), (4,2), (1,2) or (2,2)"); | |
88 | return 0; | |
89 | } | |
90 | ||
91 | targ_alpha_chan = im->channels - 1; | |
92 | ||
93 | #code im->bits <= 8 && src->bits <= 8 | |
94 | IM_WORK_T src_alpha, orig_alpha, dest_alpha, remains; | |
95 | IM_COLOR pv, orig, dest; | |
96 | ||
97 | tty = ty; | |
98 | for(y = src_miny; y < src_maxy; y++) { | |
99 | ttx = tx; | |
100 | for(x = src_minx; x < src_maxx; x++) { | |
101 | IM_GPIX(src, x, y, &pv); | |
102 | src_alpha = pv.channel[alphachan]; | |
103 | if (src_alpha) { | |
104 | remains = IM_SAMPLE_MAX - src_alpha; | |
105 | IM_GPIX(im, ttx, tty, &orig); | |
106 | orig_alpha = orig.channel[targ_alpha_chan]; | |
107 | dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX; | |
108 | ||
109 | for (ch = 0; ch < chancount; ++ch) { | |
110 | dest.channel[ch] = | |
111 | ( src_alpha * pv.channel[chans[ch]] | |
112 | + remains * orig.channel[ch] * orig_alpha / IM_SAMPLE_MAX | |
113 | ) / dest_alpha; | |
114 | } | |
115 | /* dest's alpha */ | |
116 | dest.channel[targ_alpha_chan] = dest_alpha; | |
117 | IM_PPIX(im, ttx, tty, &dest); | |
118 | } | |
119 | ttx++; | |
120 | } | |
121 | tty++; | |
122 | } | |
123 | #/code | |
124 | return 1; | |
125 | } | |
126 | ||
127 | /* | |
128 | =item i_rubthru(im, src, tx, ty, src_minx, src_miny, src_maxx, src_maxy ) | |
129 | ||
130 | =category Image | |
131 | ||
132 | Takes the sub image I<src[src_minx, src_maxx)[src_miny, src_maxy)> and | |
133 | overlays it at (I<tx>,I<ty>) on the image object. | |
134 | ||
135 | The alpha channel of each pixel in I<src> is used to control how much | |
136 | the existing colour in I<im> is replaced, if it is 255 then the colour | |
137 | is completely replaced, if it is 0 then the original colour is left | |
138 | unmodified. | |
139 | ||
140 | =cut | |
141 | */ | |
142 | ||
143 | int | |
144 | i_rubthru(i_img *im, i_img *src, int tx, int ty, int src_minx, int src_miny, | |
145 | int src_maxx, int src_maxy) { | |
146 | if (im->channels == 1 || im->channels == 3) | |
147 | return rubthru_targ_noalpha(im, src, tx, ty, src_minx, src_miny, | |
148 | src_maxx, src_maxy); | |
149 | else | |
150 | return rubthru_targ_alpha(im, src, tx, ty, src_minx, src_miny, | |
151 | src_maxx, src_maxy); | |
152 | } |