/**************************************************************************** * Func: rotate_pgm * * * * Desc: rotate an image some arbitrary angle. New pixels are generated * * using bilinear interpolation * * * * Params: buffer - pointer to image in memory * * fileout - name of output file * * rows - number of rows in source image * * cols - number of columns in source image * * angle - angle of rotation (in degrees) * ****************************************************************************/ void rotate_pgm(image_ptr buffer, char *fileout, int rows, int cols, float angle) { float angle2; /* 90 degrees - angle */ long x,y; /* column and row indices */ int index; /* index into output line buffer */ unsigned long source_add; /* address of source pixels */ float floatx, floaty; /* floating point values of source x and y */ int intx, inty; /* integer value of source x and y */ int centerx, centery; /* center of new image */ float EWweight, NSweight; /* linear weights for interpolation */ float NW, NE, SW, SE; /* northwest, northeast, southwest, southeast*/ float top, bottom; /* interpolated top and bottom values */ float cosine, sine; /* cosine and sine of angle */ unsigned char *line_buff; /* output line buffer */ int new_rows, new_cols; /* number of rows and columns of new image */ FILE *fp; /* output file pointer */ int xdiff, ydiff; /* difference between new and old rows and cols */ /* open new output file */ if((fp=fopen(fileout, "wb")) == NULL) { printf("Unable to open %s for output\n",fileout); exit(1); } while(angle >= 360.0) angle -=360.0; /* miscellaneous trig */ angle *= ((double) 3.14159265/(double) 180.0); /* convert to RADs */ angle2 = 1.570796327 - angle; cosine = cos(angle); sine = sin(angle); /* determine new size of output image */ new_cols = rows * fabs(cos(angle2)) + cols * fabs(cosine); new_rows = rows * fabs(cosine) + cols * fabs(cos(angle2)); centerx = cols/2; centery = rows/2; xdiff = (new_cols - cols)/2; ydiff = (new_rows - rows)/2; /* print out the portable bitmap header */ fprintf(fp, "P5\n%d %d\n255\n", new_cols, new_rows); line_buff = (unsigned char *) malloc(new_cols); for(y=-1*ydiff; y<(new_rows-ydiff); y++) { index = 0; for(x=-1*xdiff; x<(new_cols-xdiff); x++) { floatx = (x-centerx) * cosine + (y-centery) * sine; floatx += centerx; floaty = (y-centery) * cosine - (x-centerx) * sine; floaty += centery; intx = (int) floatx; inty = (int) floaty; /* check if pixel is outside of source image */ if((intx < 0) || (intx >= cols-1) || (inty < 0) || (inty >= rows-1)) line_buff[index++] = 255; else /* interpolate new value */ { EWweight = floatx - (float) intx; NSweight = floaty - (float) inty; source_add = (unsigned long) inty * cols + intx; NW = (float) buffer[source_add]; NE = (float) buffer[source_add+1]; SW = (float) buffer[source_add+cols]; SE = (float) buffer[source_add+cols+1]; top = NW + EWweight*(NE-NW); bottom = SW + EWweight*(SE-SW); line_buff[index++] = (char) (top + NSweight*(bottom-top)); } } fwrite(line_buff, 1, new_cols, fp); } fclose(fp); }