# (A VERY BAD) Image rotation algorithm using libtiff

The following program rotates a tiff image. I pretty much made up the algorithm myself, and it relies on my rather dodgy trigonometry. There are almost certainly computationally less expensive ways of doing this.

Two methods are present, but the main function only uses (rotate_source). This iterates over pixels in the source image and places them in the correct location in the destination image. The alternative is to iterate over the destination image, this ensures there are no missing datapoints at the destination. However, this method is slower, and the result can look worse.

The disadvantage of the faster method is that there maybe gaps is the rotated image. To get round this I have a quick hack called “fill_gaps” which does some very lazy interpolation to fill in the gaps.

You can compile the code as:

```g++ rotation.cpp -ltiff -o rotation
```

And then execute it as:

```./rotation input.tif
```

The program will then write a series of files named imgN.tif where N is an integer. Each of these files will contain a rotated copy of the original image in 0.1 radian increments.

On a Mac you can use the following to get Preview to open all these files in one window, and display them in the correct order:

```ls img*.tif | awk 'BEGIN{FS="g";}{print \$0 " " \$2}' |sort -n -k 2 | awk '{print \$1}' | xargs open
```
```#include "tiffio.h"
#include <iostream>
#include <math.h>
#include <vector>
#include <map>
#include "stringify.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <sstream>
#include <string>
#include <stdexcept>

class BadConversion : public std::runtime_error {
public:
: std::runtime_error(s) {}
};

template<class _type>
inline std::string stringify(_type x)
{
std::ostringstream o;
if (!(o << std::fixed << x))
return o.str();
}

#define TIFFSetR(pixel, x) ((unsigned char *)pixel)[0] = x
#define TIFFSetG(pixel, x) ((unsigned char *)pixel)[1] = x
#define TIFFSetB(pixel, x) ((unsigned char *)pixel)[2] = x
#define TIFFSetA(pixel, x) ((unsigned char *)pixel)[3] = x

using namespace std;

void rotate_point(double x,
double y,
double o_x,
double o_y,
double &r_x,
double &r_y) {

//1. calculate theta
//tan theta = opp (y) / adj (x)

double dx = x - o_x;
double dy = y - o_y;

if(dx < 0) dx = 0-dx;
if(dy < 0) dy = 0-dy;

int q=1;
if((x >  o_x) && (y >= o_y)) q = 1;
if((x >= o_x) && (y <  o_y)) q = 2;
if((x <  o_x) && (y <= o_y)) q = 3;
if((x <= o_x) && (y >  o_y)) q = 4;
double theta;
if(q == 1) theta  = atan(dy/dx);
if(q == 2) theta  = atan(dx/dy);
if(q == 3) theta  = atan(dy/dx);
if(q == 4) theta  = atan(dx/dy);

double     h = sqrt(dx*dx + dy*dy);

if((dy==0) || (dx==0)) theta = 0;

for(;theta < 0;) { theta = 0 - theta; theta = ((2*3.14)/4) - theta; q++; if(q==5) q=1;}

for(;theta > ((2*3.14)/4);) {theta -= ((2*3.14)/4); q--; if(q==0) q=4; }

if(q == 1) { r_y = (sin(theta) * h); r_x = (cos(theta) * h); }
if(q == 2) { r_x = (sin(theta) * h); r_y = (cos(theta) * h); }
if(q == 3) { r_y = (sin(theta) * h); r_x = (cos(theta) * h); }
if(q == 4) { r_x = (sin(theta) * h); r_y = (cos(theta) * h); }

if(q == 1) {r_x = o_x + r_x; r_y = o_y + r_y;}
if(q == 2) {r_x = o_x + r_x; r_y = o_y - r_y;}
if(q == 3) {r_x = o_x - r_x; r_y = o_y - r_y;}
if(q == 4) {r_x = o_x - r_x; r_y = o_y + r_y;}

}

class Image {

public:

Image() {
}

m_image_data.clear();

TIFF* tif = TIFFOpen(input_filename.c_str(), "r");
if (tif) {
uint32 w, h;
size_t npixels;
uint32* raster;

TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
m_width = w;
m_height = h;

raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFReadRGBAImageOriented(tif, w, h, raster,ORIENTATION_TOPLEFT, 0)) {
for(size_t n=0;n<npixels;n++) m_image_data.push_back(raster[n]);
}
_TIFFfree(raster);
}
TIFFClose(tif);
}
}

void save_tiff_rgb(string output_filename) {
TIFF *output_image;

// Open the TIFF file
if((output_image = TIFFOpen(output_filename.c_str(), "w")) == NULL){
cerr << "Unable to write tif file: " << output_filename << endl;
}

// We need to set some values for basic tags before we can add any data
TIFFSetField(output_image, TIFFTAG_IMAGEWIDTH, m_width);
TIFFSetField(output_image, TIFFTAG_IMAGELENGTH, m_height);
TIFFSetField(output_image, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(output_image, TIFFTAG_SAMPLESPERPIXEL, 4);
TIFFSetField(output_image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);

TIFFSetField(output_image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
TIFFSetField(output_image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);

// Write the information to the file
TIFFWriteEncodedStrip(output_image, 0, &m_image_data[0], m_width*m_height * 4);

// Close the file
TIFFClose(output_image);
}

bool is_on_image(size_t x,size_t y) {
if((x < m_width) && (y < m_height)) return true;
return false;
}

uint32_t get(size_t x,size_t y) {
return m_image_data[(y*m_width)+x];
}

void set(size_t x,size_t y,uint32_t value) {
m_image_data[(y*m_width)+x] = value;
}

void zero_image() {
m_image_data = vector<uint32_t>(m_width*m_height,0);
}

Image rotate(size_t o_x,size_t o_y,double radians,uint32_t bg_val) {
}

Image rotate_source(size_t o_x,size_t o_y,double radians,uint32_t bg_val) {

Image new_image; // image to copy data in to

if(m_width > m_height) pad = m_width;
new_image.zero_image();

for(uint32_t cx=0;cx<m_width;cx++) {
for(uint32_t cy=0;cy<m_height;cy++) {
double r_x, r_y;

if(get(cx,cy) != bg_val) {
}
}
}

return new_image;
}

void fill_gaps(uint32_t bg_val) {
for(size_t x=0;x<m_width;x++) {
for(size_t y=0;y<m_height;y++) {
if(get(x,y) == bg_val) {

if(is_on_image(x-1,y-1) && is_on_image(x+1,y+1)) {

int perform_set=0;

if(perform_set < 2) {
}
}
}
}
}
}

Image rotate_dest(size_t o_x,size_t o_y,double radians,uint32_t bg_val) {

Image new_image; // image to copy data in to

if(m_width > m_height) pad = m_width;
new_image.zero_image();

double r_x, r_y;
}
}

return new_image;
}

vector<uint32_t> m_image_data;
size_t m_width;
size_t m_height;
};

int main(int argc, char* argv[]) {

Image i;

int n=0;
for(double r=0;r<(2*3.141);r+=0.1) {
//Image i2 = i.rotate(i.m_width/2,i.m_height/2,1.78525,0);
Image i2 = i.rotate(i.m_width/2,i.m_height/2,r,0);
//Image i2 = i.rotate(0,0,r,0);

for(int x=0;x<10;x++) {
for(int y=0;y<10;y++) {
i2.set(x,y,0xFFFFFFFF);
}
}
i2.fill_gaps(0);
i2.save_tiff_rgb(string("img") + stringify(n) + string(".tif"));
n++;
}
}
```