| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
/* |
|
2
|
|
|
|
|
|
|
=head1 NAME |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
rotate.im - implements image rotations |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
i_img *i_rotate90(i_img *src, int degrees) |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
Implements basic 90 degree rotations of an image. |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Other rotations will be added as tuits become available. |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=cut |
|
17
|
|
|
|
|
|
|
*/ |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
#include "imager.h" |
|
20
|
|
|
|
|
|
|
#include "imageri.h" |
|
21
|
|
|
|
|
|
|
#include /* for floor() */ |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#define ROT_DEBUG(x) |
|
24
|
|
|
|
|
|
|
|
|
25
|
26
|
|
|
|
|
|
i_img *i_rotate90(i_img *src, int degrees) { |
|
26
|
|
|
|
|
|
|
i_img *targ; |
|
27
|
|
|
|
|
|
|
i_img_dim x, y; |
|
28
|
|
|
|
|
|
|
|
|
29
|
26
|
|
|
|
|
|
i_clear_error(); |
|
30
|
|
|
|
|
|
|
|
|
31
|
26
|
100
|
|
|
|
|
if (degrees == 180) { |
|
32
|
|
|
|
|
|
|
/* essentially the same as flipxy(..., 2) except that it's not |
|
33
|
|
|
|
|
|
|
done in place */ |
|
34
|
5
|
|
|
|
|
|
targ = i_sametype(src, src->xsize, src->ysize); |
|
35
|
5
|
100
|
|
|
|
|
if (src->type == i_direct_type) { |
|
36
|
3
|
50
|
|
|
|
|
#code src->bits <= 8 |
|
37
|
3
|
|
|
|
|
|
IM_COLOR *vals = mymalloc(src->xsize * sizeof(IM_COLOR)); |
|
38
|
291
|
100
|
|
|
|
|
for (y = 0; y < src->ysize; ++y) { |
|
|
|
0
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
IM_COLOR tmp; |
|
40
|
288
|
|
|
|
|
|
IM_GLIN(src, 0, src->xsize, y, vals); |
|
41
|
15274
|
100
|
|
|
|
|
for (x = 0; x < src->xsize/2; ++x) { |
|
|
|
0
|
|
|
|
|
|
|
42
|
14986
|
|
|
|
|
|
tmp = vals[x]; |
|
43
|
14986
|
|
|
|
|
|
vals[x] = vals[src->xsize - x - 1]; |
|
44
|
14986
|
|
|
|
|
|
vals[src->xsize - x - 1] = tmp; |
|
45
|
|
|
|
|
|
|
} |
|
46
|
288
|
|
|
|
|
|
IM_PLIN(targ, 0, src->xsize, src->ysize - y - 1, vals); |
|
47
|
|
|
|
|
|
|
} |
|
48
|
3
|
|
|
|
|
|
myfree(vals); |
|
49
|
|
|
|
|
|
|
#/code |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
else { |
|
52
|
2
|
|
|
|
|
|
i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx)); |
|
53
|
|
|
|
|
|
|
|
|
54
|
172
|
100
|
|
|
|
|
for (y = 0; y < src->ysize; ++y) { |
|
55
|
|
|
|
|
|
|
i_palidx tmp; |
|
56
|
170
|
50
|
|
|
|
|
i_gpal(src, 0, src->xsize, y, vals); |
|
57
|
10200
|
100
|
|
|
|
|
for (x = 0; x < src->xsize/2; ++x) { |
|
58
|
10030
|
|
|
|
|
|
tmp = vals[x]; |
|
59
|
10030
|
|
|
|
|
|
vals[x] = vals[src->xsize - x - 1]; |
|
60
|
10030
|
|
|
|
|
|
vals[src->xsize - x - 1] = tmp; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
170
|
50
|
|
|
|
|
i_ppal(targ, 0, src->xsize, src->ysize - y - 1, vals); |
|
63
|
|
|
|
|
|
|
} |
|
64
|
|
|
|
|
|
|
|
|
65
|
2
|
|
|
|
|
|
myfree(vals); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
|
|
68
|
5
|
|
|
|
|
|
return targ; |
|
69
|
|
|
|
|
|
|
} |
|
70
|
21
|
100
|
|
|
|
|
else if (degrees == 270 || degrees == 90) { |
|
|
|
50
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
i_img_dim tx, txstart, txinc; |
|
72
|
|
|
|
|
|
|
i_img_dim ty, tystart, tyinc; |
|
73
|
|
|
|
|
|
|
|
|
74
|
21
|
100
|
|
|
|
|
if (degrees == 270) { |
|
75
|
10
|
|
|
|
|
|
txstart = 0; |
|
76
|
10
|
|
|
|
|
|
txinc = 1; |
|
77
|
10
|
|
|
|
|
|
tystart = src->xsize-1; |
|
78
|
10
|
|
|
|
|
|
tyinc = -1; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
else { |
|
81
|
11
|
|
|
|
|
|
txstart = src->ysize-1; |
|
82
|
11
|
|
|
|
|
|
txinc = -1; |
|
83
|
11
|
|
|
|
|
|
tystart = 0; |
|
84
|
11
|
|
|
|
|
|
tyinc = 1; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
21
|
|
|
|
|
|
targ = i_sametype(src, src->ysize, src->xsize); |
|
87
|
21
|
100
|
|
|
|
|
if (src->type == i_direct_type) { |
|
88
|
13
|
50
|
|
|
|
|
#code src->bits <= 8 |
|
89
|
13
|
|
|
|
|
|
IM_COLOR *vals = mymalloc(src->xsize * sizeof(IM_COLOR)); |
|
90
|
|
|
|
|
|
|
|
|
91
|
13
|
|
|
|
|
|
tx = txstart; |
|
92
|
1381
|
100
|
|
|
|
|
for (y = 0; y < src->ysize; ++y) { |
|
|
|
0
|
|
|
|
|
|
|
93
|
1368
|
|
|
|
|
|
IM_GLIN(src, 0, src->xsize, y, vals); |
|
94
|
1368
|
|
|
|
|
|
ty = tystart; |
|
95
|
144228
|
100
|
|
|
|
|
for (x = 0; x < src->xsize; ++x) { |
|
|
|
0
|
|
|
|
|
|
|
96
|
142860
|
|
|
|
|
|
IM_PPIX(targ, tx, ty, vals+x); |
|
97
|
142860
|
|
|
|
|
|
ty += tyinc; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
1368
|
|
|
|
|
|
tx += txinc; |
|
100
|
|
|
|
|
|
|
} |
|
101
|
13
|
|
|
|
|
|
myfree(vals); |
|
102
|
|
|
|
|
|
|
#/code |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
else { |
|
105
|
8
|
|
|
|
|
|
i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx)); |
|
106
|
|
|
|
|
|
|
|
|
107
|
8
|
|
|
|
|
|
tx = txstart; |
|
108
|
820
|
100
|
|
|
|
|
for (y = 0; y < src->ysize; ++y) { |
|
109
|
812
|
50
|
|
|
|
|
i_gpal(src, 0, src->xsize, y, vals); |
|
110
|
812
|
|
|
|
|
|
ty = tystart; |
|
111
|
81052
|
100
|
|
|
|
|
for (x = 0; x < src->xsize; ++x) { |
|
112
|
80240
|
50
|
|
|
|
|
i_ppal(targ, tx, tx+1, ty, vals+x); |
|
113
|
80240
|
|
|
|
|
|
ty += tyinc; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
812
|
|
|
|
|
|
tx += txinc; |
|
116
|
|
|
|
|
|
|
} |
|
117
|
8
|
|
|
|
|
|
myfree(vals); |
|
118
|
|
|
|
|
|
|
} |
|
119
|
21
|
|
|
|
|
|
return targ; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
else { |
|
122
|
0
|
|
|
|
|
|
i_push_error(0, "i_rotate90() only rotates at 90, 180, or 270 degrees"); |
|
123
|
0
|
|
|
|
|
|
return NULL; |
|
124
|
|
|
|
|
|
|
} |
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
/* linear interpolation */ |
|
128
|
182452
|
|
|
|
|
|
static i_color interp_i_color(i_color before, i_color after, double pos, |
|
129
|
|
|
|
|
|
|
int channels) { |
|
130
|
|
|
|
|
|
|
i_color out; |
|
131
|
|
|
|
|
|
|
int ch; |
|
132
|
|
|
|
|
|
|
|
|
133
|
354458
|
50
|
|
|
|
|
if (channels == 1 || channels == 3) { |
|
|
|
100
|
|
|
|
|
|
|
134
|
688024
|
100
|
|
|
|
|
for (ch = 0; ch < channels; ++ch) |
|
135
|
516018
|
|
|
|
|
|
out.channel[ch] = ((1-pos) * before.channel[ch] + pos * after.channel[ch]) + 0.5; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
else { |
|
138
|
20892
|
|
|
|
|
|
int total_cover = (1-pos) * before.channel[channels-1] |
|
139
|
10446
|
|
|
|
|
|
+ pos * after.channel[channels-1]; |
|
140
|
|
|
|
|
|
|
|
|
141
|
10446
|
50
|
|
|
|
|
total_cover = I_LIMIT_8(total_cover); |
|
142
|
10446
|
100
|
|
|
|
|
if (total_cover) { |
|
143
|
10260
|
|
|
|
|
|
double before_alpha = before.channel[channels-1] / 255.0; |
|
144
|
10260
|
|
|
|
|
|
double after_alpha = after.channel[channels-1] / 255.0; |
|
145
|
10260
|
|
|
|
|
|
double total_alpha = before_alpha * (1-pos) + after_alpha * pos; |
|
146
|
|
|
|
|
|
|
|
|
147
|
41040
|
100
|
|
|
|
|
for (ch = 0; ch < channels-1; ++ch) { |
|
148
|
92340
|
|
|
|
|
|
int out_level = ((1-pos) * before.channel[ch] * before_alpha + |
|
149
|
61560
|
|
|
|
|
|
pos * after.channel[ch] * after_alpha) / total_alpha + 0.5; |
|
150
|
|
|
|
|
|
|
|
|
151
|
30780
|
50
|
|
|
|
|
out.channel[ch] = I_LIMIT_8(out_level); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
else { |
|
155
|
744
|
100
|
|
|
|
|
for (ch = 0; ch < channels-1; ++ch) |
|
156
|
558
|
|
|
|
|
|
out.channel[ch] = 0; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
10446
|
|
|
|
|
|
out.channel[channels-1] = total_cover; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
182452
|
|
|
|
|
|
return out; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
/* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */ |
|
166
|
|
|
|
|
|
|
/* linear interpolation */ |
|
167
|
61430
|
|
|
|
|
|
static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos, |
|
168
|
|
|
|
|
|
|
int channels) { |
|
169
|
|
|
|
|
|
|
i_fcolor out; |
|
170
|
|
|
|
|
|
|
int ch; |
|
171
|
|
|
|
|
|
|
|
|
172
|
122860
|
50
|
|
|
|
|
if (channels == 1 || channels == 3) { |
|
|
|
50
|
|
|
|
|
|
|
173
|
245720
|
100
|
|
|
|
|
for (ch = 0; ch < channels; ++ch) |
|
174
|
184290
|
|
|
|
|
|
out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch]; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
else { |
|
177
|
0
|
|
|
|
|
|
double total_cover = (1-pos) * before.channel[channels-1] |
|
178
|
0
|
|
|
|
|
|
+ pos * after.channel[channels-1]; |
|
179
|
|
|
|
|
|
|
|
|
180
|
0
|
0
|
|
|
|
|
total_cover = I_LIMIT_DOUBLE(total_cover); |
|
|
|
0
|
|
|
|
|
|
|
181
|
0
|
0
|
|
|
|
|
if (total_cover) { |
|
182
|
0
|
|
|
|
|
|
double before_alpha = before.channel[channels-1]; |
|
183
|
0
|
|
|
|
|
|
double after_alpha = after.channel[channels-1]; |
|
184
|
0
|
|
|
|
|
|
double total_alpha = before_alpha * (1-pos) + after_alpha * pos; |
|
185
|
|
|
|
|
|
|
|
|
186
|
0
|
0
|
|
|
|
|
for (ch = 0; ch < channels-1; ++ch) { |
|
187
|
0
|
|
|
|
|
|
double out_level = ((1-pos) * before.channel[ch] * before_alpha + |
|
188
|
0
|
|
|
|
|
|
pos * after.channel[ch] * after_alpha) / total_alpha; |
|
189
|
|
|
|
|
|
|
|
|
190
|
0
|
0
|
|
|
|
|
out.channel[ch] = I_LIMIT_DOUBLE(out_level); |
|
|
|
0
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
else { |
|
194
|
0
|
0
|
|
|
|
|
for (ch = 0; ch < channels-1; ++ch) |
|
195
|
0
|
|
|
|
|
|
out.channel[ch] = 0; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
0
|
|
|
|
|
|
out.channel[channels-1] = total_cover; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
61430
|
|
|
|
|
|
return out; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
13
|
|
|
|
|
|
i_img *i_matrix_transform_bg(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix, |
|
205
|
|
|
|
|
|
|
const i_color *backp, const i_fcolor *fbackp) { |
|
206
|
13
|
|
|
|
|
|
i_img *result = i_sametype(src, xsize, ysize); |
|
207
|
|
|
|
|
|
|
i_img_dim x, y; |
|
208
|
|
|
|
|
|
|
int ch; |
|
209
|
|
|
|
|
|
|
i_img_dim i, j; |
|
210
|
|
|
|
|
|
|
double sx, sy, sz; |
|
211
|
|
|
|
|
|
|
|
|
212
|
13
|
100
|
|
|
|
|
if (src->type == i_direct_type) { |
|
213
|
12
|
100
|
|
|
|
|
#code src->bits <= 8 |
|
214
|
12
|
|
|
|
|
|
IM_COLOR *vals = mymalloc(xsize * sizeof(IM_COLOR)); |
|
215
|
|
|
|
|
|
|
IM_COLOR back; |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
#ifdef IM_EIGHT_BIT |
|
218
|
10
|
100
|
|
|
|
|
if (backp) { |
|
219
|
5
|
|
|
|
|
|
back = *backp; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
5
|
50
|
|
|
|
|
else if (fbackp) { |
|
222
|
0
|
0
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) { |
|
223
|
|
|
|
|
|
|
i_fsample_t fsamp; |
|
224
|
0
|
|
|
|
|
|
fsamp = fbackp->channel[ch]; |
|
225
|
0
|
0
|
|
|
|
|
back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255; |
|
|
|
0
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
#else |
|
229
|
|
|
|
|
|
|
#define interp_i_color interp_i_fcolor |
|
230
|
2
|
50
|
|
|
|
|
if (fbackp) { |
|
231
|
0
|
|
|
|
|
|
back = *fbackp; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
2
|
100
|
|
|
|
|
else if (backp) { |
|
234
|
4
|
100
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) |
|
235
|
3
|
|
|
|
|
|
back.channel[ch] = backp->channel[ch] / 255.0; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
#endif |
|
238
|
|
|
|
|
|
|
else { |
|
239
|
26
|
100
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) |
|
|
|
100
|
|
|
|
|
|
|
240
|
20
|
|
|
|
|
|
back.channel[ch] = 0; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
1014
|
100
|
|
|
|
|
for (y = 0; y < ysize; ++y) { |
|
|
|
100
|
|
|
|
|
|
|
244
|
123560
|
100
|
|
|
|
|
for (x = 0; x < xsize; ++x) { |
|
|
|
100
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
/* dividing by sz gives us the ability to do perspective |
|
246
|
|
|
|
|
|
|
transforms */ |
|
247
|
122558
|
|
|
|
|
|
sz = x * matrix[6] + y * matrix[7] + matrix[8]; |
|
248
|
122558
|
50
|
|
|
|
|
if (fabs(sz) > 0.0000001) { |
|
|
|
50
|
|
|
|
|
|
|
249
|
122558
|
|
|
|
|
|
sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz; |
|
250
|
122558
|
|
|
|
|
|
sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
else { |
|
253
|
0
|
|
|
|
|
|
sx = sy = 0; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
/* anything outside these ranges is either a broken co-ordinate |
|
257
|
|
|
|
|
|
|
or outside the source */ |
|
258
|
122558
|
50
|
|
|
|
|
if (fabs(sz) > 0.0000001 |
|
|
|
50
|
|
|
|
|
|
|
259
|
122558
|
100
|
|
|
|
|
&& sx >= -1 && sx < src->xsize |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
260
|
205352
|
100
|
|
|
|
|
&& sy >= -1 && sy < src->ysize) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
261
|
94392
|
|
|
|
|
|
double fsx = floor(sx); |
|
262
|
94392
|
|
|
|
|
|
double fsy = floor(sy); |
|
263
|
94392
|
|
|
|
|
|
i_img_dim bx = fsx; |
|
264
|
94392
|
|
|
|
|
|
i_img_dim by = fsy; |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, "map " i_DFp " to %g,%g\n", i_DFcp(x, y), sx, sy)); |
|
267
|
94392
|
100
|
|
|
|
|
if (sx != fsx) { |
|
|
|
50
|
|
|
|
|
|
|
268
|
90304
|
|
|
|
|
|
double dx = sx - fsx; |
|
269
|
90304
|
100
|
|
|
|
|
if (sy != fsy) { |
|
|
|
100
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
IM_COLOR c[2][2]; |
|
271
|
|
|
|
|
|
|
IM_COLOR ci2[2]; |
|
272
|
76450
|
|
|
|
|
|
double dy = sy - fsy; |
|
273
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, " both non-int\n")); |
|
274
|
229350
|
100
|
|
|
|
|
for (i = 0; i < 2; ++i) |
|
|
|
100
|
|
|
|
|
|
|
275
|
458700
|
100
|
|
|
|
|
for (j = 0; j < 2; ++j) |
|
|
|
100
|
|
|
|
|
|
|
276
|
305800
|
100
|
|
|
|
|
if (IM_GPIX(src, bx+i, by+j, &c[j][i])) |
|
|
|
100
|
|
|
|
|
|
|
277
|
5525
|
|
|
|
|
|
c[j][i] = back; |
|
278
|
229350
|
100
|
|
|
|
|
for (j = 0; j < 2; ++j) |
|
|
|
100
|
|
|
|
|
|
|
279
|
152900
|
|
|
|
|
|
ci2[j] = interp_i_color(c[j][0], c[j][1], dx, src->channels); |
|
280
|
76450
|
|
|
|
|
|
vals[x] = interp_i_color(ci2[0], ci2[1], dy, src->channels); |
|
281
|
|
|
|
|
|
|
} |
|
282
|
|
|
|
|
|
|
else { |
|
283
|
|
|
|
|
|
|
IM_COLOR ci2[2]; |
|
284
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, " y int, x non-int\n")); |
|
285
|
41562
|
100
|
|
|
|
|
for (i = 0; i < 2; ++i) |
|
|
|
100
|
|
|
|
|
|
|
286
|
27708
|
100
|
|
|
|
|
if (IM_GPIX(src, bx+i, sy, ci2+i)) |
|
|
|
50
|
|
|
|
|
|
|
287
|
171
|
|
|
|
|
|
ci2[i] = back; |
|
288
|
90304
|
|
|
|
|
|
vals[x] = interp_i_color(ci2[0], ci2[1], dx, src->channels); |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
else { |
|
292
|
4088
|
100
|
|
|
|
|
if (sy != fsy) { |
|
|
|
0
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
IM_COLOR ci2[2]; |
|
294
|
678
|
|
|
|
|
|
double dy = sy - fsy; |
|
295
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, " x int, y non-int\n")); |
|
296
|
2034
|
100
|
|
|
|
|
for (i = 0; i < 2; ++i) |
|
|
|
0
|
|
|
|
|
|
|
297
|
1356
|
100
|
|
|
|
|
if (IM_GPIX(src, bx, by+i, ci2+i)) |
|
|
|
0
|
|
|
|
|
|
|
298
|
1
|
|
|
|
|
|
ci2[i] = back; |
|
299
|
678
|
|
|
|
|
|
vals[x] = interp_i_color(ci2[0], ci2[1], dy, src->channels); |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
else { |
|
302
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, " both int\n")); |
|
303
|
|
|
|
|
|
|
/* all the world's an integer */ |
|
304
|
3410
|
50
|
|
|
|
|
if (IM_GPIX(src, bx, by, vals+x)) |
|
|
|
0
|
|
|
|
|
|
|
305
|
0
|
|
|
|
|
|
vals[x] = back; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
else { |
|
310
|
28166
|
|
|
|
|
|
vals[x] = back; |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
} |
|
313
|
1002
|
|
|
|
|
|
IM_PLIN(result, 0, xsize, y, vals); |
|
314
|
|
|
|
|
|
|
} |
|
315
|
12
|
|
|
|
|
|
myfree(vals); |
|
316
|
|
|
|
|
|
|
#undef interp_i_color |
|
317
|
|
|
|
|
|
|
#/code |
|
318
|
|
|
|
|
|
|
} |
|
319
|
|
|
|
|
|
|
else { |
|
320
|
|
|
|
|
|
|
/* don't interpolate for a palette based image */ |
|
321
|
1
|
|
|
|
|
|
i_palidx *vals = mymalloc(xsize * sizeof(i_palidx)); |
|
322
|
1
|
|
|
|
|
|
i_palidx back = 0; |
|
323
|
1
|
|
|
|
|
|
int minval = 256 * 4; |
|
324
|
|
|
|
|
|
|
i_img_dim ix, iy; |
|
325
|
|
|
|
|
|
|
i_color want_back; |
|
326
|
|
|
|
|
|
|
i_fsample_t fsamp; |
|
327
|
|
|
|
|
|
|
|
|
328
|
1
|
50
|
|
|
|
|
if (backp) { |
|
329
|
0
|
|
|
|
|
|
want_back = *backp; |
|
330
|
|
|
|
|
|
|
} |
|
331
|
1
|
50
|
|
|
|
|
else if (fbackp) { |
|
332
|
0
|
0
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) { |
|
333
|
0
|
|
|
|
|
|
fsamp = fbackp->channel[ch]; |
|
334
|
0
|
0
|
|
|
|
|
want_back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255; |
|
|
|
0
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
} |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
else { |
|
338
|
4
|
100
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) |
|
339
|
3
|
|
|
|
|
|
want_back.channel[ch] = 0; |
|
340
|
|
|
|
|
|
|
} |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
/* find the closest color */ |
|
343
|
57
|
50
|
|
|
|
|
for (i = 0; i < i_colorcount(src); ++i) { |
|
|
|
100
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
i_color temp; |
|
345
|
|
|
|
|
|
|
int tempval; |
|
346
|
56
|
50
|
|
|
|
|
i_getcolors(src, i, &temp, 1); |
|
347
|
56
|
|
|
|
|
|
tempval = 0; |
|
348
|
224
|
100
|
|
|
|
|
for (ch = 0; ch < src->channels; ++ch) { |
|
349
|
168
|
|
|
|
|
|
tempval += abs(want_back.channel[ch] - temp.channel[ch]); |
|
350
|
|
|
|
|
|
|
} |
|
351
|
56
|
100
|
|
|
|
|
if (tempval < minval) { |
|
352
|
1
|
|
|
|
|
|
back = i; |
|
353
|
1
|
|
|
|
|
|
minval = tempval; |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
|
|
357
|
106
|
100
|
|
|
|
|
for (y = 0; y < ysize; ++y) { |
|
358
|
13860
|
100
|
|
|
|
|
for (x = 0; x < xsize; ++x) { |
|
359
|
|
|
|
|
|
|
/* dividing by sz gives us the ability to do perspective |
|
360
|
|
|
|
|
|
|
transforms */ |
|
361
|
13755
|
|
|
|
|
|
sz = x * matrix[6] + y * matrix[7] + matrix[8]; |
|
362
|
13755
|
50
|
|
|
|
|
if (fabs(sz) > 0.0000001) { |
|
363
|
13755
|
|
|
|
|
|
sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz; |
|
364
|
13755
|
|
|
|
|
|
sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz; |
|
365
|
|
|
|
|
|
|
} |
|
366
|
|
|
|
|
|
|
else { |
|
367
|
0
|
|
|
|
|
|
sx = sy = 0; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
/* anything outside these ranges is either a broken co-ordinate |
|
371
|
|
|
|
|
|
|
or outside the source */ |
|
372
|
13755
|
50
|
|
|
|
|
if (fabs(sz) > 0.0000001 |
|
373
|
13755
|
100
|
|
|
|
|
&& sx >= -0.5 && sx < src->xsize-0.5 |
|
|
|
100
|
|
|
|
|
|
|
374
|
12505
|
100
|
|
|
|
|
&& sy >= -0.5 && sy < src->ysize-0.5) { |
|
|
|
100
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
/* all the world's an integer */ |
|
377
|
10027
|
|
|
|
|
|
ix = (i_img_dim)(sx+0.5); |
|
378
|
10027
|
|
|
|
|
|
iy = (i_img_dim)(sy+0.5); |
|
379
|
10027
|
50
|
|
|
|
|
if (!i_gpal(src, ix, ix+1, iy, vals+x)) |
|
|
|
50
|
|
|
|
|
|
|
380
|
0
|
|
|
|
|
|
vals[i] = back; |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
else { |
|
383
|
3728
|
|
|
|
|
|
vals[x] = back; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
} |
|
386
|
105
|
50
|
|
|
|
|
i_ppal(result, 0, xsize, y, vals); |
|
387
|
|
|
|
|
|
|
} |
|
388
|
1
|
|
|
|
|
|
myfree(vals); |
|
389
|
|
|
|
|
|
|
} |
|
390
|
|
|
|
|
|
|
|
|
391
|
13
|
|
|
|
|
|
return result; |
|
392
|
|
|
|
|
|
|
} |
|
393
|
|
|
|
|
|
|
|
|
394
|
0
|
|
|
|
|
|
i_img *i_matrix_transform(i_img *src, i_img_dim xsize, i_img_dim ysize, const double *matrix) { |
|
395
|
0
|
|
|
|
|
|
return i_matrix_transform_bg(src, xsize, ysize, matrix, NULL, NULL); |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
static void |
|
399
|
20
|
|
|
|
|
|
i_matrix_mult(double *dest, const double *left, const double *right) { |
|
400
|
|
|
|
|
|
|
int i, j, k; |
|
401
|
|
|
|
|
|
|
double accum; |
|
402
|
|
|
|
|
|
|
|
|
403
|
80
|
100
|
|
|
|
|
for (i = 0; i < 3; ++i) { |
|
404
|
240
|
100
|
|
|
|
|
for (j = 0; j < 3; ++j) { |
|
405
|
180
|
|
|
|
|
|
accum = 0.0; |
|
406
|
720
|
100
|
|
|
|
|
for (k = 0; k < 3; ++k) { |
|
407
|
540
|
|
|
|
|
|
accum += left[3*i+k] * right[3*k+j]; |
|
408
|
|
|
|
|
|
|
} |
|
409
|
180
|
|
|
|
|
|
dest[3*i+j] = accum; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
} |
|
412
|
20
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
#define numfmt "%23g" |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
ROT_DEBUG(static void dump_mat(const char *name, double *f) { |
|
417
|
|
|
|
|
|
|
fprintf(stderr, "%s:\n " numfmt " " numfmt " " numfmt "\n" |
|
418
|
|
|
|
|
|
|
" " numfmt " " numfmt " " numfmt "\n" |
|
419
|
|
|
|
|
|
|
" " numfmt " " numfmt " " numfmt "\n", |
|
420
|
|
|
|
|
|
|
name, f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8]); |
|
421
|
|
|
|
|
|
|
}) |
|
422
|
|
|
|
|
|
|
|
|
423
|
10
|
|
|
|
|
|
i_img *i_rotate_exact_bg(i_img *src, double amount, |
|
424
|
|
|
|
|
|
|
const i_color *backp, const i_fcolor *fbackp) { |
|
425
|
10
|
|
|
|
|
|
double xlate1[9] = { 0 }; |
|
426
|
|
|
|
|
|
|
double rotate[9]; |
|
427
|
10
|
|
|
|
|
|
double xlate2[9] = { 0 }; |
|
428
|
|
|
|
|
|
|
double temp[9], matrix[9]; |
|
429
|
|
|
|
|
|
|
i_img_dim x1, x2, y1, y2, newxsize, newysize; |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, "rotate angle %.20g\n", amount)); |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
/* first translate the centre of the image to (0,0) */ |
|
434
|
10
|
|
|
|
|
|
xlate1[0] = 1; |
|
435
|
10
|
|
|
|
|
|
xlate1[2] = (src->xsize-1)/2.0; |
|
436
|
10
|
|
|
|
|
|
xlate1[4] = 1; |
|
437
|
10
|
|
|
|
|
|
xlate1[5] = (src->ysize-1)/2.0; |
|
438
|
10
|
|
|
|
|
|
xlate1[8] = 1; |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
ROT_DEBUG(dump_mat("xlate1", xlate1)); |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
/* rotate around (0.0) */ |
|
443
|
10
|
|
|
|
|
|
rotate[0] = cos(amount); |
|
444
|
10
|
|
|
|
|
|
rotate[1] = sin(amount); |
|
445
|
10
|
|
|
|
|
|
rotate[2] = 0; |
|
446
|
10
|
|
|
|
|
|
rotate[3] = -rotate[1]; |
|
447
|
10
|
|
|
|
|
|
rotate[4] = rotate[0]; |
|
448
|
10
|
|
|
|
|
|
rotate[5] = 0; |
|
449
|
10
|
|
|
|
|
|
rotate[6] = 0; |
|
450
|
10
|
|
|
|
|
|
rotate[7] = 0; |
|
451
|
10
|
|
|
|
|
|
rotate[8] = 1; |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
ROT_DEBUG(dump_mat("rotate", rotate)); |
|
454
|
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, "cos %g sin %g\n", rotate[0], rotate[1])); |
|
456
|
|
|
|
|
|
|
|
|
457
|
10
|
|
|
|
|
|
x1 = ceil(fabs(src->xsize * rotate[0] + src->ysize * rotate[1]) - 0.0001); |
|
458
|
10
|
|
|
|
|
|
x2 = ceil(fabs(src->xsize * rotate[0] - src->ysize * rotate[1]) - 0.0001); |
|
459
|
10
|
|
|
|
|
|
y1 = ceil(fabs(src->xsize * rotate[3] + src->ysize * rotate[4]) - 0.0001); |
|
460
|
10
|
|
|
|
|
|
y2 = ceil(fabs(src->xsize * rotate[3] - src->ysize * rotate[4]) - 0.0001); |
|
461
|
|
|
|
|
|
|
ROT_DEBUG(fprintf(stderr, "x1 y1 " i_DFp " x2 y2 " i_DFp "\n", i_DFcp(x1, y1), i_DFcp(x2, y2))); |
|
462
|
10
|
|
|
|
|
|
newxsize = x1 > x2 ? x1 : x2; |
|
463
|
10
|
|
|
|
|
|
newysize = y1 > y2 ? y1 : y2; |
|
464
|
|
|
|
|
|
|
/* translate the centre back to the center of the image */ |
|
465
|
10
|
|
|
|
|
|
xlate2[0] = 1; |
|
466
|
10
|
|
|
|
|
|
xlate2[2] = -(newxsize-1)/2.0; |
|
467
|
10
|
|
|
|
|
|
xlate2[4] = 1; |
|
468
|
10
|
|
|
|
|
|
xlate2[5] = -(newysize-1)/2.0; |
|
469
|
10
|
|
|
|
|
|
xlate2[8] = 1; |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
ROT_DEBUG(dump_mat("xlate2", xlate2)); |
|
472
|
|
|
|
|
|
|
|
|
473
|
10
|
|
|
|
|
|
i_matrix_mult(temp, xlate1, rotate); |
|
474
|
10
|
|
|
|
|
|
i_matrix_mult(matrix, temp, xlate2); |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
ROT_DEBUG(dump_mat("matrxi", matrix)); |
|
477
|
|
|
|
|
|
|
|
|
478
|
10
|
|
|
|
|
|
return i_matrix_transform_bg(src, newxsize, newysize, matrix, backp, fbackp); |
|
479
|
|
|
|
|
|
|
} |
|
480
|
|
|
|
|
|
|
|
|
481
|
0
|
|
|
|
|
|
i_img *i_rotate_exact(i_img *src, double amount) { |
|
482
|
0
|
|
|
|
|
|
return i_rotate_exact_bg(src, amount, NULL, NULL); |
|
483
|
|
|
|
|
|
|
} |
|
484
|
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
/* |
|
487
|
|
|
|
|
|
|
=back |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=head1 AUTHOR |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Tony Cook |
|
492
|
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Imager(3) |
|
496
|
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=cut |
|
498
|
|
|
|
|
|
|
*/ |