4 rotate.c - implements image rotations
8 i_img *i_rotate90(i_img *src, int degrees)
12 Implements basic 90 degree rotations of an image.
14 Other rotations will be added as tuits become available.
20 #include <math.h> /* for floor() */
22 i_img *i_rotate90(i_img *src, int degrees) {
29 /* essentially the same as flipxy(..., 2) except that it's not
31 targ = i_sametype(src, src->xsize, src->ysize);
32 if (src->type == i_direct_type) {
33 if (src->bits == i_8_bits) {
34 i_color *vals = mymalloc(src->xsize * sizeof(i_color));
35 for (y = 0; y < src->ysize; ++y) {
37 i_glin(src, 0, src->xsize, y, vals);
38 for (x = 0; x < src->xsize/2; ++x) {
40 vals[x] = vals[src->xsize - x - 1];
41 vals[src->xsize - x - 1] = tmp;
43 i_plin(targ, 0, src->xsize, src->ysize - y - 1, vals);
48 i_fcolor *vals = mymalloc(src->xsize * sizeof(i_fcolor));
49 for (y = 0; y < src->ysize; ++y) {
51 i_glinf(src, 0, src->xsize, y, vals);
52 for (x = 0; x < src->xsize/2; ++x) {
54 vals[x] = vals[src->xsize - x - 1];
55 vals[src->xsize - x - 1] = tmp;
57 i_plinf(targ, 0, src->xsize, src->ysize - y - 1, vals);
63 i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx));
65 for (y = 0; y < src->ysize; ++y) {
67 i_gpal(src, 0, src->xsize, y, vals);
68 for (x = 0; x < src->xsize/2; ++x) {
70 vals[x] = vals[src->xsize - x - 1];
71 vals[src->xsize - x - 1] = tmp;
73 i_ppal(targ, 0, src->xsize, src->ysize - y - 1, vals);
81 else if (degrees == 270 || degrees == 90) {
82 int tx, txstart, txinc;
83 int ty, tystart, tyinc;
88 tystart = src->xsize-1;
92 txstart = src->ysize-1;
97 targ = i_sametype(src, src->ysize, src->xsize);
98 if (src->type == i_direct_type) {
99 if (src->bits == i_8_bits) {
100 i_color *vals = mymalloc(src->xsize * sizeof(i_color));
103 for (y = 0; y < src->ysize; ++y) {
104 i_glin(src, 0, src->xsize, y, vals);
106 for (x = 0; x < src->xsize; ++x) {
107 i_ppix(targ, tx, ty, vals+x);
115 i_fcolor *vals = mymalloc(src->xsize * sizeof(i_fcolor));
118 for (y = 0; y < src->ysize; ++y) {
119 i_glinf(src, 0, src->xsize, y, vals);
121 for (x = 0; x < src->xsize; ++x) {
122 i_ppixf(targ, tx, ty, vals+x);
131 i_palidx *vals = mymalloc(src->xsize * sizeof(i_palidx));
134 for (y = 0; y < src->ysize; ++y) {
135 i_gpal(src, 0, src->xsize, y, vals);
137 for (x = 0; x < src->xsize; ++x) {
138 i_ppal(targ, tx, tx+1, ty, vals+x);
148 i_push_error(0, "i_rotate90() only rotates at 90, 180, or 270 degrees");
153 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
154 /* linear interpolation */
155 static i_color interp_i_color(i_color before, i_color after, double pos,
161 for (ch = 0; ch < channels; ++ch)
162 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
167 /* hopefully this will be inlined (it is with -O3 with gcc 2.95.4) */
168 /* linear interpolation */
169 static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
175 for (ch = 0; ch < channels; ++ch)
176 out.channel[ch] = (1-pos) * before.channel[ch] + pos * after.channel[ch];
181 i_img *i_matrix_transform_bg(i_img *src, int xsize, int ysize, double *matrix,
182 i_color *backp, i_fcolor *fbackp) {
183 i_img *result = i_sametype(src, xsize, ysize);
190 if (src->type == i_direct_type) {
191 if (src->bits == i_8_bits) {
192 i_color *vals = mymalloc(xsize * sizeof(i_color));
200 for (ch = 0; ch < src->channels; ++ch) {
201 fsamp = fbackp->channel[ch];
202 back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255;
206 for (ch = 0; ch < src->channels; ++ch)
207 back.channel[ch] = 0;
210 for (y = 0; y < ysize; ++y) {
211 for (x = 0; x < xsize; ++x) {
212 /* dividing by sz gives us the ability to do perspective
214 sz = x * matrix[6] + y * matrix[7] + matrix[8];
215 if (abs(sz) > 0.0000001) {
216 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
217 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
220 /* anything outside these ranges is either a broken co-ordinate
221 or outside the source */
222 if (abs(sz) > 0.0000001
223 && sx >= -1 && sx < src->xsize
224 && sy >= -1 && sy < src->ysize) {
230 for (i = 0; i < 2; ++i)
231 for (j = 0; j < 2; ++j)
232 if (i_gpix(src, floor(sx)+i, floor(sy)+j, &c[j][i]))
234 for (j = 0; j < 2; ++j)
235 ci2[j] = interp_i_color(c[j][0], c[j][1], sx, src->channels);
236 vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels);
240 for (i = 0; i < 2; ++i)
241 if (i_gpix(src, floor(sx)+i, sy, ci2+i))
243 vals[x] = interp_i_color(ci2[0], ci2[1], sx, src->channels);
249 for (i = 0; i < 2; ++i)
250 if (i_gpix(src, sx, floor(sy)+i, ci2+i))
252 vals[x] = interp_i_color(ci2[0], ci2[1], sy, src->channels);
255 /* all the world's an integer */
256 if (i_gpix(src, sx, sy, vals+x))
265 i_plin(result, 0, xsize, y, vals);
270 i_fcolor *vals = mymalloc(xsize * sizeof(i_fcolor));
277 for (ch = 0; ch < src->channels; ++ch)
278 back.channel[ch] = backp->channel[ch] / 255.0;
281 for (ch = 0; ch < src->channels; ++ch)
282 back.channel[ch] = 0;
285 for (y = 0; y < ysize; ++y) {
286 for (x = 0; x < xsize; ++x) {
287 /* dividing by sz gives us the ability to do perspective
289 sz = x * matrix[6] + y * matrix[7] + matrix[8];
290 if (abs(sz) > 0.0000001) {
291 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
292 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
295 /* anything outside these ranges is either a broken co-ordinate
296 or outside the source */
297 if (abs(sz) > 0.0000001
298 && sx >= -1 && sx < src->xsize
299 && sy >= -1 && sy < src->ysize) {
305 for (i = 0; i < 2; ++i)
306 for (j = 0; j < 2; ++j)
307 if (i_gpixf(src, floor(sx)+i, floor(sy)+j, &c[j][i]))
309 for (j = 0; j < 2; ++j)
310 ci2[j] = interp_i_fcolor(c[j][0], c[j][1], sx, src->channels);
311 vals[x] = interp_i_fcolor(ci2[0], ci2[1], sy, src->channels);
315 for (i = 0; i < 2; ++i)
316 if (i_gpixf(src, floor(sx)+i, sy, ci2+i))
318 vals[x] = interp_i_fcolor(ci2[0], ci2[1], sx, src->channels);
324 for (i = 0; i < 2; ++i)
325 if (i_gpixf(src, sx, floor(sy)+i, ci2+i))
327 vals[x] = interp_i_fcolor(ci2[0], ci2[1], sy, src->channels);
330 /* all the world's an integer */
331 if (i_gpixf(src, sx, sy, vals+x))
340 i_plinf(result, 0, xsize, y, vals);
346 /* don't interpolate for a palette based image */
347 i_palidx *vals = mymalloc(xsize * sizeof(i_palidx));
350 int minval = 256 * 4;
359 for (ch = 0; ch < src->channels; ++ch) {
360 fsamp = fbackp->channel[ch];
361 want_back.channel[ch] = fsamp < 0 ? 0 : fsamp > 1 ? 255 : fsamp * 255;
365 for (ch = 0; ch < src->channels; ++ch)
366 want_back.channel[ch] = 0;
369 /* find the closest color */
370 for (i = 0; i < i_colorcount(src); ++i) {
373 i_getcolors(src, i, &temp, 1);
375 for (ch = 0; ch < src->channels; ++ch) {
376 tempval += abs(want_back.channel[ch] - temp.channel[ch]);
378 if (tempval < minval) {
385 for (y = 0; y < ysize; ++y) {
386 for (x = 0; x < xsize; ++x) {
387 /* dividing by sz gives us the ability to do perspective
389 sz = x * matrix[6] + y * matrix[7] + matrix[8];
390 if (abs(sz) > 0.0000001) {
391 sx = (x * matrix[0] + y * matrix[1] + matrix[2]) / sz;
392 sy = (x * matrix[3] + y * matrix[4] + matrix[5]) / sz;
395 /* anything outside these ranges is either a broken co-ordinate
396 or outside the source */
397 if (abs(sz) > 0.0000001
398 && sx >= -0.5 && sx < src->xsize-0.5
399 && sy >= -0.5 && sy < src->ysize-0.5) {
401 /* all the world's an integer */
404 if (!i_gpal(src, ix, ix+1, iy, vals+x))
411 i_ppal(result, 0, xsize, y, vals);
419 i_img *i_matrix_transform(i_img *src, int xsize, int ysize, double *matrix) {
420 return i_matrix_transform_bg(src, xsize, ysize, matrix, NULL, NULL);
424 i_matrix_mult(double *dest, double *left, double *right) {
428 for (i = 0; i < 3; ++i) {
429 for (j = 0; j < 3; ++j) {
431 for (k = 0; k < 3; ++k) {
432 accum += left[3*i+k] * right[3*k+j];
439 i_img *i_rotate_exact_bg(i_img *src, double amount,
440 i_color *backp, i_fcolor *fbackp) {
441 double xlate1[9] = { 0 };
443 double xlate2[9] = { 0 };
444 double temp[9], matrix[9];
445 int x1, x2, y1, y2, newxsize, newysize;
447 /* first translate the centre of the image to (0,0) */
449 xlate1[2] = src->xsize/2.0;
451 xlate1[5] = src->ysize/2.0;
454 /* rotate around (0.0) */
455 rotate[0] = cos(amount);
456 rotate[1] = sin(amount);
458 rotate[3] = -rotate[1];
459 rotate[4] = rotate[0];
465 x1 = ceil(abs(src->xsize * rotate[0] + src->ysize * rotate[1]));
466 x2 = ceil(abs(src->xsize * rotate[0] - src->ysize * rotate[1]));
467 y1 = ceil(abs(src->xsize * rotate[3] + src->ysize * rotate[4]));
468 y2 = ceil(abs(src->xsize * rotate[3] - src->ysize * rotate[4]));
469 newxsize = x1 > x2 ? x1 : x2;
470 newysize = y1 > y2 ? y1 : y2;
471 /* translate the centre back to the center of the image */
473 xlate2[2] = -newxsize/2;
475 xlate2[5] = -newysize/2;
477 i_matrix_mult(temp, xlate1, rotate);
478 i_matrix_mult(matrix, temp, xlate2);
480 return i_matrix_transform_bg(src, newxsize, newysize, matrix, backp, fbackp);
483 i_img *i_rotate_exact(i_img *src, double amount) {
484 return i_rotate_exact_bg(src, amount, NULL, NULL);
493 Tony Cook <tony@develop-help.com>