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
|
|
|
|
|
|
|
*/ |