Click here to Skip to main content
15,928,281 members
Articles / Programming Languages / C
Tip/Trick

Rotate GIF by shear

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
27 Jun 2024CPOL3 min read 1.7K   3   4
Rotates a GIF image by the shearing method.
We present a program to rotate a GIF file using the shearing method, which is suitable for colour-indeced images as it does not require interpolation of pixel values.

Introduction

Rotating an image is a common requirement, especially GIFs with transparency. However a rotation matrix cannt be used because it requires interpolation of pixels, which is not possible in a colour indexed image. However rotation is possible using the shearing method.

Background

To rotate a point we must apply sine and cosine to the x and y components. Specifically

x' = x cos(theta) - y sin(theta)

y' = x sin(theta) + y cos(theta)

And so it is possible to rotate an image by iterating over the destination pixels, applying the reverse of this equation (theta = -theta), and finding the right point in the source image. However  the sample point is vanishingly unlikely to hit a pixel exactly. And so we must interpolate the four closet pixels to obtain the output pixel. If we don't do this, and choose the nearest, we will get strange artifacts as source pixels are doubled and dropped, technically termed "aliasing".

With a true colour image, interpolation is relatively simple (as long as we don't demand mathematically perfect results), But with a colour-indexed image, such as a GIF file, it is impossible, as we only have a restricted set of pixels to choose from. So using the rotation matrix method, we have to accept aliasing.

However it is possible to avoid this. by using another algorithm for rotation. A rotation is equivalent to three shear transforms. To rotate an image by 180 degrees, we can shear the entire width, shear the entire height, and then shear the entire width again. This should be easy to visualise, and gives you an intuitive understanding of the algorithm. It also works for other values.

There are some provisios. I's only possible to rotate by whole pixels. So for a finite image, small rotations are disallowed. And the image rows and columns are broken up into runs of source pixels, which is itself  source of aliasing. However results are relatively good, and the method is established. 

The code is packaged as a working program. GIF images are rectagular, and is only possible to rotate geometry in the incircle without changing the dimensions of the image. So the program is suitable for GIFs with transparency. The alternative of expanding the dimensions would quickly lead to runaway inflation of image size.

Using the code

The code is all pure ANSI C. Just type

gcc *.c

to obtain the executable.

C++
/**
  Rotate an image, using the shearing method.

Params:
  binary - the binary or colour-indexed image
  width - image width
  height - image height
  cx - centre x, y co-ordinates (pass in 1.5, 1.5 for the centre of a 3x3 image)
  cy - centre x, y co-ordinates (pass in 1.5, 1.5 for the centre of a 3x3 image)
  theta - angle to rotate by
  out[out] - buffer for output (can't be the same as input)
  
Returns: 0 for success

  Conventional image rotation by the matrix method causes destination pixels to be
    sub-samples of source pixels. This isn't a problem with continous tone images where
    the new pixel values can be obtained by interpolation. However with binary or
    colour-index images, interpolation isn't possible. The shearing method preserves the
    pixels, at some cost in rotational accuracy.

  */
int rotatebyshear(unsigned char *binary, int width, int height, double cx, double cy, double theta, unsigned char *out)
{
    double alpha;
    double beta;
    int dpx;
    int tx, ty;
    int x, y;

    assert(binary != out);
    theta = fmod(theta, 2 * PI);

    if(theta >= -PI/2 && theta <= PI/2)
    {
      alpha = -tan(theta/2);
      beta = sin(theta);

      for(y=0;y<height;y++)
      {
         dpx = (int) floor(alpha * (y - cy) + 0.5);
         for(x=0;x<width;x++)
         {
           ty = y + (int) floor(beta * (x + dpx - cx) + 0.5);
           tx = x + dpx + (int) floor(alpha * (ty - cy) + 0.5);
           if(tx >= 0 && tx < width && ty >= 0 && ty < height)
             out[y*width+x] = binary[ty*width+tx];
           else
             out[y*width+x] = 0;
         }
      }
    }
    else
    {
        alpha = -tan( (theta + PI) / 2);
        beta = sin(theta + PI);
        for(y=0;y<height;y++)
        {
         dpx = (int) floor(alpha * (y - cy) + 0.5);
         for(x=0;x<width;x++)
         {
           ty = y + (int) floor(beta * (x + dpx - cx) + 0.5);
           tx = x + dpx + (int) floor(alpha * (ty - cy) + 0.5);
           tx = (int) (cx-(tx - cx));
           ty = (int) (cy-(ty - cy));
           if(tx >= 0 && tx < width && ty >= 0 && ty < height)
             out[y*width+x] = binary[ty*width+tx];
           else
             out[y*width+x] = 0;
         }
      }
    }

    return 0;
}

This is the function you want.

The shear transformation is given by the matrix

1 sx
0 1

And is one of the basic simple transforms.

 

Results

Lena 256 GIF Lena rotated
Lena 256 colours Lena rotated

The results are not perfect. You see severe "jaggies" on Lena's hat and left cheek, and of course the image edges themselves are aliased. But all the pixels are retained. There is no banding or diminution of quality In the continuous tone areas.

Points of Interest

You might wonder where we obtained such a high quality 256 colour Lena, with no mach banding at all on the shoulder. Of course we used the Principal Component Analysis algorithm.

History

The code is part of the binary image library, on github

https://github.com/MalcolmMcLean/binaryimagelibrary

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
I started programming when we were taught Basic on the Commodore Pet at school, and was immediately hooked. But my parents were not generous with money, and it was a while before I saved up enough money to buy a second-hand ZX81. Then a friend gave me "Machine Code on your ZX81" by Toni Baker (not "Tony", a lady), and that book changed my life, because it enabled me to master something that most adults couldn't do. And I realised the power of good textbooks and self study. I have written two books on programming in consequence.

Then I want to Oxford to study English Literature, and programming came to an end, except for a brief course on Snobol, and statistical analysis of grammar words (words like "and" and "he"). But the expected job with the Civil Service did not materialise, I needed to earn a living somehow, and so it was to games programming that I turned. But I was never entirely happy as a game programmer. Whilst I enjoy programming games, I'm not so fond of playing them, except for Dungeons and Dragons style games. And for a games programmer, that's a big handicap.

I've got other interests aside from programming, and after I had collected a big pile of cash from games programming, I decided to spend it on doing a second degree, at Leeds University, in biology. That then led naturally to a PhD in computational biochemistry, working on the protein folding problem, and that turned me into a really good programmer.

However there's only one faculty position for every 10 PhDs, and I was one of the unlucky nine, and so I found a job doing graphics programming. Which I kept until unfortunately ill health forced me to give up work. And I am now a full time hobby programmer.

And my main project is Baby X and its attendant subsystems.


Comments and Discussions

 
QuestionAlternatives Pin
YDaoust1-Jul-24 3:32
YDaoust1-Jul-24 3:32 
QuestionWhy not use the GIF transforms? Pin
Richard MacCutchan1-Jul-24 0:44
mveRichard MacCutchan1-Jul-24 0:44 
The Win32 library provides standard transformation features to do this Using Coordinate Spaces and Transformations - Win32 apps | Microsoft Learn[^].
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA28-Jun-24 22:36
professionalȘtefan-Mihai MOGA28-Jun-24 22:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.