const ctx = canvas.getContext("2d");
const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const doFor = (count, cb) => { var i = 0; while (i < count && cb(i++) !== true); };
doFor(150,i=>{
ctx.fillStyle = "hsl("+randI(360)+",100%,50%)";
ctx.fillRect(randI(canvas.width),randI(canvas.height),randI(10,20),randI(10,20));
});
ctx.font = "28px Arial black";
ctx.textAlign = "center";
ctx.fillStyle = "black";
ctx.strokeStyle = "white";
ctx.lineWidth = "5";
ctx.lineJoin = "round";
ctx.strokeText("Rotate me!",128,128);
ctx.fillText("Rotate me!",128,128);
// the rotation origin
const ox = 128;
const oy = 128;
// the rotation amount
const rot = Math.PI / 4; // 45 deg
// the rotated x axis
const ax = Math.cos(rot); // 45 deg
const ay = Math.sin(rot); // 45 deg
// get the source pixel data
const imageData = ctx.getImageData(0,0,256,256);
const d32 = new Uint32Array(imageData.data.buffer);
// create a destination pixel array
const rotImageData = new Uint32Array(imageData.data.length/4);
// scan each pixel and row adding pixels to rotImageData from the transformed
// x,y coordinate.
for(y = 0; y < 256; y += 1){
for(x = 0; x < 256; x += 1){
const ind = (x + y * 256);
// transform the current pixel to the rotated pixel
const rx = (x - ox) * ax - (y-oy) * ay + ox;
const ry = (x - ox) * ay + (y-oy) * ax + oy;
// use nearest pixel lookup and get index of original image
const ind1 = ((rx | 0) + (ry | 0) * 256);
rotImageData[ind] = d32[ind1];
}
}
// create a second canvas
var c1 = document.createElement("canvas");
c1.width = 256;
c1.height = 256;
var ctx1 = c1.getContext("2d");
// put the new image data into the imageData array
d32.set(rotImageData);
// and put that on the new canvas
ctx1.putImageData(imageData,0,0);
// add the canvas to the page
document.body.appendChild(c1);
canvas {border : 2px solid black;}
<canvas id="canvas" width=256 height=256></canvas>