How to Rotate an Image with JavaScript

Sometimes, we may need to rotate an image on a web page, like showing a loading animation. In a document-scanning web app, we need to rotate skewed document images or document images scanned in the wrong direction.

In this article, we are going to talk about three ways to rotate an image with JavaScript:

  • CSS’s Transform Property
  • HTML5’s Canvas
  • Dynamic Web TWAIN, a document-scanning SDK

Build an HTML5 Page to Rotate Images

Let’s build an HTML5 page to do this.

New HTML File

Create a new HTML file with the following template:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Rotate an Image with JavaScript</title>
  <style>
  .home {
    display: flex;
    align-items: center;
    flex-direction: column;
  }
  </style>
</head>
<body>
  <div class="home">
    <h2>Rotate an Image</h2>
  </div>
  <script></script>
</body>
</html>

Load an Image File

Add an input element for selecting files and use a button element to trigger it. The image file will be loaded into two image elements, one for displaying the rotated result and one for storing the original image.

HTML:

<button id="loadFileButton">Load a File</button>
<input style="display:none;" type="file" id="file" onchange="loadImageFromFile();" accept=".jpg,.jpeg,.png,.bmp" />
<div class="imageContainer">
  <img id="image"/>
  <img id="imageHidden"/>
</div>
<style>
  .imageContainer {
    max-width: 50%;
  }

  #image {
    max-width: 100%;
  }

  #imageHidden {
    display: none;
  }
</style>

JavaScript:

function loadImageFromFile(){
  let fileInput = document.getElementById("file");
  let files = fileInput.files;
  if (files.length == 0) {
    return;
  }
  let file = files[0];
  fileReader = new FileReader();
  fileReader.onload = function(e){
    document.getElementById("image").src = e.target.result;
    document.getElementById("imageHidden").src = e.target.result;
  };
  fileReader.onerror = function () {
    console.warn('oops, something went wrong.');
  };
  fileReader.readAsDataURL(file);
}

Use CSS to Rotate an Image

We can use the CSS property transform to rotate an HTML element like the following:

element.style.transform = 'rotate(45deg)';

We can also specify the transform-origin CSS property to set the origin of the rotation transform. By default, the origin of a transform is center which we will use.

Let’s implement it in the page.

  1. Add an input element for specifying the rotation angle.

    HTML:

    <label for="degree">Degree (0-360):</label>
    <input type="number" id="degree" name="degree" min="0" max="360" value="0"/>
    
  2. Listen to the change event of the input element to rotate the image with CSS.

    document.getElementById("degree").addEventListener("change",function(e){
      const degree = e.target.value;
      rotateImage(degree);
    })
    
    function rotateImage(degree){
      const image = document.getElementById("image");
      const imageHidden = document.getElementById("imageHidden");
      if (!image.src) {
        return; //no image selected
      }
      image.src = imageHidden.src;
      image.style.transform = 'rotate(' + degree + 'deg)';
    }
    

Using CSS does not actually change the image data, so its processing speed is good. But it may have an overflow problem blocking other elements. We can set the overflow CSS property of its container to auto to avoid blocking other elements but the image will be cut.

Use Canvas to Rotate an Image

HTML5 provides a canvas element which provides a way to manipulate image data. We can use it to actually get a rotated image.

  1. Add a hidden canvas element to the page.

    <canvas id="canvasHidden"></canvas>
    <style>
      #canvasHidden {
        display: none;
      }
    </style>
    
  2. Add a select element to select which rotating method to use.

    <label>
      Method:
      <select id="methodSelect">
        <option>CSS</option>
        <option>Canvas</option>
      </select>
    </label>
    
  3. Rotate an image with canvas when the selected method is “Canvas”.

    if (method == 0) {
      image.src = imageHidden.src;
      image.style.transform = 'rotate(' + degree + 'deg)';
    }else if (method == 1){
      image.style.transform = '';
      rotateImageWithCanvas(degree);
    }
    

Let’s now talk about how to actually rotate an image with canvas.

  1. Get the new size of the rotated image.

    After rotation, the image will have a new size. We have to set the canvas’s size to match the new size. Suppose we need to rotate an image around its center, we can have to following functions to calculate the new size.

    First, get the four corner points and calculate their positions after rotation. Then, get the bounding rect based on the points.

    function getBoundingRect(width,height,degree) {
      let rad = Degree2Rad(degree);
      let points = [{x:0,y:0},{x:width,y:0},{x:width,y:height},{x:0,y:height}];
      let minX = undefined;
      let minY = undefined;
      let maxX = 0;
      let maxY = 0;
      for (let index = 0; index < points.length; index++) {
        const point = points[index];
        const rotatedPoint = getRotatedPoint(point.x,point.y,width/2,height/2,rad);
        if (minX == undefined) {
          minX = rotatedPoint.x;
        }else{
          minX = Math.min(rotatedPoint.x,minX);
        }
        if (minY == undefined) {
          minY = rotatedPoint.y;
        }else{
          minY = Math.min(rotatedPoint.y,minY);
        }
        maxX = Math.max(rotatedPoint.x,maxX);
        maxY = Math.max(rotatedPoint.y,maxY);
      }
      let rectWidth = maxX - minX;
      let rectHeight = maxY - minY;
      let rect = {
        x: minX,
        y: minY,
        width: rectWidth,
        height: rectHeight
      }
      return rect;
    }
    
    function Degree2Rad(degree){
      return degree*Math.PI/180
    }
    
    //https://gamedev.stackexchange.com/questions/86755/how-to-calculate-corner-positions-marks-of-a-rotated-tilted-rectangle
    function getRotatedPoint(x,y,cx,cy,theta){
      let tempX = x - cx;
      let tempY = y - cy;
    
      // now apply rotation
      let rotatedX = tempX*Math.cos(theta) - tempY*Math.sin(theta);
      let rotatedY = tempX*Math.sin(theta) + tempY*Math.cos(theta);
    
      // translate back
      x = rotatedX + cx;
      y = rotatedY + cy;
      let point = {x:x,y:y};
      return point;
    }
    
  2. Set the canvas’s size as the rotated image’s size.

    const canvas = document.getElementById("canvasHidden");
    const imgWidth = imageHidden.naturalWidth;
    const imgHeight = imageHidden.naturalHeight;
    const rect = getBoundingRect(imgWidth,imgHeight,degree);
    canvas.width = rect.width;
    canvas.height = rect.height;
    
  3. Get the context of the canvas to perform actions.

    const ctx = canvas.getContext("2d");
    
  4. Use translate to set the new (0,0) position as the center of the canvas.

    ctx.translate(canvas.width/2,canvas.height/2);
    
  5. Use rotate to set the transformation matrix.

    ctx.rotate(Degree2Rad(degree));
    
  6. Use drawImage to draw the image content.

    ctx.drawImage(imageHidden, -imgWidth/2, -imgHeight/2);
    

    We need to specify the x-axis and y-axis coordinates in the destination canvas at which to place the top-left corner of the source image. So here, since the new origin is the center of the canvas, we need to use -imgWidth/2 and -imgHeight/2.

  7. Display the rotated image.

    image.src = canvas.toDataURL();
    

Use Dynamic Web TWAIN to Rotate an Image

Dynamic Web TWAIN is a document scanning SDK making it possible to scan documents in the browser. It provides various image processing methods. We can use its RotateEx method to rotate an image.

The advantage of using it is that it can be used to batch process a large volume of images as the processing is done using a native process.

Here are the steps to use it:

  1. Include Dynamic Web TWAIN in the page.

    <script src="https://unpkg.com/dwt@18.4.2/dist/dynamsoft.webtwain.min.js"></script>
    
  2. Add Dynamic Web TWAIN as a new rotation method.

    <label>
      Method:
      <select id="methodSelect">
        <option>CSS</option>
        <option>Canvas</option>
        <option>Dynamic Web TWAIN</option>
      </select>
    </label>
    
  3. When it is selected as the method for rotation, initialize an instance of Web TWAIN and use it to rotate the image. You can apply for its license here.

    let DWObject;
    Dynamsoft.DWT.AutoLoad = false;
    Dynamsoft.DWT.ProductKey = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; //one-day trial
    Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.4.2/dist";
    async function rotateImage(degree){
      const method = document.getElementById("methodSelect").selectedIndex;
      const image = document.getElementById("image");
      const imageHidden = document.getElementById("imageHidden");
      if (!image.src) {
        return;
      }
      if (method == 0) {
        image.src = imageHidden.src;
        image.style.transform = 'rotate(' + degree + 'deg)';
      }else if (method == 1){
        image.style.transform = '';
        rotateImageWithCanvas(degree);
      }else if (method == 2){
        image.style.transform = '';
        if (!DWObject) {
          await init();
        }
        rotateImageWithDWT(degree);
      }
    }
    function init(){
      return new Promise((resolve, reject) => {
        const title = document.querySelector("h2").innerText;
        document.querySelector("h2").innerText = "Loading Dynamic Web TWAIN...";
        Dynamsoft.DWT.CreateDWTObjectEx(
        {
          WebTwainId: 'dwtcontrol'
        },
        function(obj) {
          DWObject = obj;
          document.querySelector("h2").innerText = title;
          resolve();
        },
        function(err) {
          console.log(err);
          document.querySelector("h2").innerText = "Failed to load Dynamic Web TWAIN";
          reject(err);
        }
      );
      })
    }
        
    function rotateImageWithDWT(degree){
      return new Promise(async (resolve, reject) => {
        if (DWObject) {
          DWObject.RemoveAllImages();
          let file = document.getElementById("file").files[0];
          let buffer = await file.arrayBuffer();
          DWObject.LoadImageFromBinary(buffer,
          function(){
            const method = document.getElementById("interpolationMethodSelect").selectedOptions[0].value;
            DWObject.RotateEx(0,degree,false,method,
            function(){
              document.getElementById("image").src = DWObject.GetImageURL(0);
            },
            function(errorCode, errorString){
              reject(errorString);
            });
          },
          function(errorCode, errorString){
            reject(errorString);
          })
             
        }else{
          reject();
        }
      })
    }
    
  4. New pixels have to be added during rotation which is called interpolation. Dynamic Web TWAIN provides several algorithms to do this.

    A select element is added for this.

    <div class="dwtcontrols">
      <label>
        Interpolation Method:
        <select id="interpolationMethodSelect">
          <option value="1">Nearest Neighbour</option>
          <option value="2">Bilinear</option>
          <option value="3">Bicubic</option>
          <option value="5" selected>Best Quality</option>
        </select>
      </label>
    </div>
    
  5. Web TWAIN also has a function to detect the skew angle of a document image. We can use it to determine the angle for rotation.

    DWObject.GetSkewAngle(
      0,
      function(angle) {
        document.getElementById("degree").value = 360+angle;
        rotateImage(360+angle);
      },
      function(errorCode, errorString) {
        console.log(errorString);
      }
    );
    

What You Should Know About Dynamic Web TWAIN

Source Code

You can find all the code in the following repo:

https://github.com/tony-xlh/Rotate-Image-JavaScript