0

How can i rotate a image 45 degrees contained in an ImageData object?

https://developer.mozilla.org/en/docs/Web/API/ImageData

I do not want to do that with canvas i just want for ImageData.

Aflred
  • 4,435
  • 6
  • 30
  • 43
  • 1
    by flip you mean rotate? – vol7ron Jul 15 '17 at 14:22
  • yes, i just want to rotate the representation of the image in imageData 45 degrees. – Aflred Jul 15 '17 at 14:25
  • imageData IS the underlying pixel data of a canvas, so you will need canvas for that purpose anyway. If you just want to rotate an image, wouldn't the CSS-rule transform: rotate(45deg); do fine? – Zomry Jul 15 '17 at 14:29
  • For rotation on canvas, see this answer: https://stackoverflow.com/questions/17411991/html5-canvas-rotate-image – Zomry Jul 15 '17 at 14:31
  • ok it seems you guys are incredible.I updated my question. – Aflred Jul 15 '17 at 15:11

1 Answers1

1

Scan line rendering.

Why in imageData?? it is very slow

You can use a scan line renderer. This scans across the new (destination) row by row, calculating the x,y coordinate of the pixel at that point and then setting the color to match.

The example rotates the image via the image data array. the Rotation amount and the rotation center are set and a very simple matrix (ax,ay,ox,oy) is created to rotate a scan pixel (x,y) into a lookup pixel (rx,ry). The solution is a nearest neighbour lookup, but you can create a bilinear, or tri etc by interpreting the pixel colors via the fractional remainder of the rx,ry pixel locations.

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>
Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136
  • This is exactly what i wanted, the reason i want imageData is because i am doing some seamcarving in web workers and the example i got from github only handled seamcarving vertically.Hope your answer and my 'seamcarving' keyword will help others. – Aflred Jul 15 '17 at 15:32
  • @Aflred You can get better performance if you use 32 bit buffers, was not sure if you had experience with typed arrays so left as was, but sounds like you know what you are doing so have changed answer to the more efficient form. – Blindman67 Jul 15 '17 at 15:38
  • I tried with a image that has 1.5 ratio, triedto flip it and it will not work.https://jsfiddle.net/cqf2q5su/ please replace my image with a image locally, canvas wont accept a image from the internet. – Aflred Jul 15 '17 at 20:29
  • @Aflred Sorry I do not understand what you are trying to do. Flip as in mirror? or rotate as in turn? The scan line algorithm will handle any image aspect and can do any form of transformation to the image. You fiddle has many errors, the for loops scan the coordinates of the destination image, not the source. If you change the destination image dimensions you need to create a imageData object for that new image you cant just copy the data into the source imageData object. – Blindman67 Jul 15 '17 at 21:25