]> git.imager.perl.org - imager.git/blame - rubthru.im
update Changes
[imager.git] / rubthru.im
CommitLineData
fe415ad2
TC
1#include "imager.h"
2
3static int
4rubthru_targ_noalpha(i_img *im, i_img *src,
8d14daab
TC
5 i_img_dim tx, i_img_dim ty,
6 i_img_dim src_minx, i_img_dim src_miny,
7 i_img_dim src_maxx, i_img_dim src_maxy) {
8 i_img_dim x, y, ttx, tty;
fe415ad2
TC
9 int alphachan;
10 int ch;
8d14daab 11 i_img_dim width = src_maxx - src_minx;
9b1ec2b8 12 int want_channels;
fe415ad2
TC
13
14 i_clear_error();
15
9b1ec2b8
TC
16 if (im->channels == 3 && (src->channels == 4 || src->channels == 2)) {
17 want_channels = 4;
fe415ad2
TC
18 alphachan = 3;
19 }
9b1ec2b8
TC
20 else if (im->channels == 1 && (src->channels == 4 || src->channels == 2)) {
21 want_channels = 2;
fe415ad2
TC
22 alphachan = 1;
23 }
24 else {
9b1ec2b8
TC
25 i_copyto(im, src, src_minx, src_miny, src_maxx, src_maxy, tx, ty);
26 return 1;
fe415ad2
TC
27 }
28
29#code im->bits <= 8 && src->bits <= 8
30 IM_WORK_T alpha;
9b1ec2b8
TC
31 IM_COLOR *src_line, *dest_line;
32
33 src_line = mymalloc(sizeof(IM_COLOR) * width);
34 dest_line = mymalloc(sizeof(IM_COLOR) * width);
fe415ad2
TC
35
36 tty = ty;
37 for(y = src_miny; y < src_maxy; y++) {
9b1ec2b8
TC
38 IM_COLOR *srcp = src_line;
39 IM_COLOR *destp = dest_line;
fe415ad2 40 ttx = tx;
9b1ec2b8
TC
41 IM_GLIN(src, src_minx, src_maxx, y, src_line);
42 IM_GLIN(im, tx, tx + width, tty, dest_line);
43 if (src->channels != want_channels)
44 IM_ADAPT_COLORS(want_channels, src->channels, src_line, width);
45
fe415ad2 46 for(x = src_minx; x < src_maxx; x++) {
9b1ec2b8
TC
47 alpha = srcp->channel[alphachan];
48 for (ch = 0; ch < im->channels; ++ch) {
49 IM_WORK_T samp = (alpha * srcp->channel[ch]
50 + (IM_SAMPLE_MAX - alpha) * destp->channel[ch])/IM_SAMPLE_MAX;
51 destp->channel[ch] = IM_LIMIT(samp);
fe415ad2 52 }
9b1ec2b8
TC
53 ++srcp;
54 ++destp;
fe415ad2 55 }
9b1ec2b8 56 IM_PLIN(im, tx, tx + width, tty, dest_line);
fe415ad2
TC
57 tty++;
58 }
9b1ec2b8
TC
59 myfree(src_line);
60 myfree(dest_line);
fe415ad2 61#/code
9b1ec2b8 62
fe415ad2
TC
63 return 1;
64}
65
66static int
8d14daab
TC
67rubthru_targ_alpha(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty,
68 i_img_dim src_minx, i_img_dim src_miny,
69 i_img_dim src_maxx, i_img_dim src_maxy) {
70 i_img_dim x, y, ttx, tty;
9b1ec2b8 71 int want_channels;
fe415ad2
TC
72 int alphachan;
73 int ch;
74 int targ_alpha_chan;
8d14daab 75 i_img_dim width = src_maxx - src_minx;
fe415ad2 76
9b1ec2b8 77 if (im->channels == 4 && (src->channels == 4 || src->channels == 2)) {
fe415ad2 78 alphachan = 3;
9b1ec2b8 79 want_channels = 4;
fe415ad2 80 }
9b1ec2b8 81 else if (im->channels == 2 && (src->channels == 4 || src->channels == 2)) {
fe415ad2 82 alphachan = 1;
9b1ec2b8 83 want_channels = 2;
fe415ad2
TC
84 }
85 else {
9b1ec2b8
TC
86 i_copyto(im, src, src_minx, src_miny, src_maxx, src_maxy, tx, ty);
87 return 1;
fe415ad2
TC
88 }
89
90 targ_alpha_chan = im->channels - 1;
91
92#code im->bits <= 8 && src->bits <= 8
93 IM_WORK_T src_alpha, orig_alpha, dest_alpha, remains;
9b1ec2b8
TC
94 IM_COLOR *src_line, *dest_line;
95
96 src_line = mymalloc(sizeof(IM_COLOR) * width);
97 dest_line = mymalloc(sizeof(IM_COLOR) * width);
fe415ad2
TC
98
99 tty = ty;
100 for(y = src_miny; y < src_maxy; y++) {
8d14daab 101 i_img_dim min_x, max_x;
9b1ec2b8
TC
102 IM_COLOR *srcp = src_line;
103 IM_COLOR *destp = dest_line;
104 IM_GLIN(src, src_minx, src_maxx, y, src_line);
105 if (src->channels != want_channels)
106 IM_ADAPT_COLORS(want_channels, src->channels, src_line, width);
107 min_x = src_minx;
108 max_x = src_maxx;
109
110 while (min_x < max_x && srcp->channel[alphachan] == 0) {
111 ++min_x;
112 ++srcp;
113 }
114 while (max_x > min_x && src_line[max_x-1].channel[alphachan] == 0) {
115 --max_x;
116 }
117
118 if (max_x > min_x) {
8d14daab
TC
119 i_img_dim work_left = tx + min_x - src_minx;
120 i_img_dim work_width = max_x - min_x;
9b1ec2b8
TC
121 ttx = work_left;
122 IM_GLIN(im, work_left, work_left + work_width, tty, dest_line);
123
17d9fe35 124 for(x = min_x; x < max_x; x++) {
9b1ec2b8
TC
125 src_alpha = srcp->channel[alphachan];
126 if (src_alpha) {
127 remains = IM_SAMPLE_MAX - src_alpha;
128 orig_alpha = destp->channel[targ_alpha_chan];
129 dest_alpha = src_alpha + (remains * orig_alpha) / IM_SAMPLE_MAX;
130
131 for (ch = 0; ch < im->channels-1; ++ch) {
132 IM_WORK_T samp =
133 ( src_alpha * srcp->channel[ch]
134 + remains * destp->channel[ch] * orig_alpha / IM_SAMPLE_MAX
135 ) / dest_alpha;
136 destp->channel[ch] = IM_LIMIT(samp);
137 }
138 /* dest's alpha */
139 destp->channel[targ_alpha_chan] = dest_alpha;
140 }
141 ++srcp;
142 ++destp;
143 ttx++;
fe415ad2 144 }
9b1ec2b8 145 IM_PLIN(im, work_left, work_left + work_width, tty, dest_line);
fe415ad2
TC
146 }
147 tty++;
148 }
9b1ec2b8
TC
149 myfree(dest_line);
150 myfree(src_line);
fe415ad2
TC
151#/code
152 return 1;
153}
154
155/*
5715f7c3 156=item i_rubthru(C<im>, C<src>, C<tx>, C<ty>, C<src_minx>, C<src_miny>, C<src_maxx>, C<src_maxy>)
fe415ad2
TC
157
158=category Image
159
5715f7c3
TC
160Takes the sub image C<src>[C<src_minx>, C<src_maxx>)[C<src_miny>, C<src_maxy>)> and
161overlays it at (C<tx>,C<ty>) on the image object.
fe415ad2 162
5715f7c3
TC
163The alpha channel of each pixel in C<src> is used to control how much
164the existing color in C<im> is replaced, if it is 255 then the color
165is completely replaced, if it is 0 then the original color is left
fe415ad2
TC
166unmodified.
167
168=cut
169*/
170
171int
8d14daab
TC
172i_rubthru(i_img *im, i_img *src, i_img_dim tx, i_img_dim ty, i_img_dim src_minx, i_img_dim src_miny,
173 i_img_dim src_maxx, i_img_dim src_maxy) {
9b1ec2b8
TC
174 if (src_minx < 0) {
175 tx -= src_minx;
176 src_minx = 0;
177 }
178 if (src_miny < 0) {
179 ty -= src_miny;
180 src_miny = 0;
181 }
182 if (tx < 0) {
183 src_minx -= tx;
184 tx = 0;
185 }
186 if (ty < 0) {
187 src_miny -= ty;
188 ty = 0;
189 }
190 if (src_maxx > src->xsize) {
191 src_maxx = src->xsize;
192 }
193 if (src_maxy > src->ysize) {
194 src_maxy = src->ysize;
195 }
196 if (tx >= im->xsize || ty >= im->ysize
197 || src_minx >= src_maxx || src_miny >= src_maxy) {
198 i_clear_error();
0d670555
TC
199 /* just do nothing, attempting to rubthrough outside the target isn't
200 worth being an error */
201 return 1;
9b1ec2b8
TC
202 }
203
fe415ad2
TC
204 if (im->channels == 1 || im->channels == 3)
205 return rubthru_targ_noalpha(im, src, tx, ty, src_minx, src_miny,
206 src_maxx, src_maxy);
207 else
208 return rubthru_targ_alpha(im, src, tx, ty, src_minx, src_miny,
209 src_maxx, src_maxy);
210}