HTML5 Canvas旋转图像

Max*_*ino 61 html canvas image rotation html5-canvas

jQuery('#carregar').click(function(){
var canvas  = document.getElementById('canvas');
var image   = document.getElementById('image');
var element = canvas.getContext("2d");
element.clearRect(0, 0, canvas.width, canvas.height);
element.drawImage(image, 0, 0, 300, 300);
});
Run Code Online (Sandbox Code Playgroud)

jsfiddle.net/braziel/nWyDE/

我有一个问题是将图像向右或向左旋转90°.

我在画布上使用了一个图像,同一个屏幕将有几个画布等于示例的画布,但我把它尽可能地靠近项目.

我问,当我点击"向左旋转"和"向右旋转"时,如何向左或向右旋转图像90°?

我在网上尝试了几个代码,但都没有用.

mar*_*rkE 126

您可以使用canvas'context.translate&context.rotate来旋转图像

在此输入图像描述

这是一个绘制按指定度数旋转的图像的函数:

function drawRotated(degrees){
    context.clearRect(0,0,canvas.width,canvas.height);

    // save the unrotated context of the canvas so we can restore it later
    // the alternative is to untranslate & unrotate after drawing
    context.save();

    // move to the center of the canvas
    context.translate(canvas.width/2,canvas.height/2);

    // rotate the canvas to the specified degrees
    context.rotate(degrees*Math.PI/180);

    // draw the image
    // since the context is rotated, the image will be rotated also
    context.drawImage(image,-image.width/2,-image.width/2);

    // we’re done with the rotating so restore the unrotated context
    context.restore();
}
Run Code Online (Sandbox Code Playgroud)

这是代码和小提琴:http: //jsfiddle.net/m1erickson/6ZsCz/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var angleInDegrees=0;

    var image=document.createElement("img");
    image.onload=function(){
        ctx.drawImage(image,canvas.width/2-image.width/2,canvas.height/2-image.width/2);
    }
    image.src="houseicon.png";

    $("#clockwise").click(function(){ 
        angleInDegrees+=30;
        drawRotated(angleInDegrees);
    });

    $("#counterclockwise").click(function(){ 
        angleInDegrees-=30;
        drawRotated(angleInDegrees);
    });

    function drawRotated(degrees){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        ctx.save();
        ctx.translate(canvas.width/2,canvas.height/2);
        ctx.rotate(degrees*Math.PI/180);
        ctx.drawImage(image,-image.width/2,-image.width/2);
        ctx.restore();
    }


}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=300 height=300></canvas><br>
    <button id="clockwise">Rotate right</button>
    <button id="counterclockwise">Rotate left</button>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

  • 此代码适用于方形图像.对于矩形图像,图像被错误地裁剪(参见http://jsfiddle.net/6ZsCz/803/).如果你改变ctx.drawImage(image,-image.width/2,-image.width/2); 是ctx.drawImage(image,-image.width/2,-image.height/2)然后它适用于所有大小的图像. (11认同)
  • 好.下面是一个示例,其中画布适合图像,图像的一部分不会丢失:http://jsfiddle.net/6ZsCz/804/. (7认同)
  • @markE:本月第三次你帮了我:-D (2认同)

Bli*_*n67 34

最快的2D上下文图像旋转方法

通用图像旋转,位置和比例.

// no need to use save and restore between calls as it sets the transform rather 
// than multiply it like ctx.rotate ctx.translate ctx.scale and ctx.transform
// Also combining the scale and origin into the one call makes it quicker
// x,y position of image center
// scale scale of image
// rotation in radians.
function drawImage(image, x, y, scale, rotation){
    ctx.setTransform(scale, 0, 0, scale, x, y); // sets scale and origin
    ctx.rotate(rotation);
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
} 
Run Code Online (Sandbox Code Playgroud)

如果要控制旋转点,请使用下一个功能

// same as above but cx and cy are the location of the point of rotation
// in image pixel coordinates
function drawImageCenter(image, x, y, cx, cy, scale, rotation){
    ctx.setTransform(scale, 0, 0, scale, x, y); // sets scale and origin
    ctx.rotate(rotation);
    ctx.drawImage(image, -cx, -cy);
} 
Run Code Online (Sandbox Code Playgroud)

要重置2D上下文转换

ctx.setTransform(1,0,0,1,0,0); // which is much quicker than save and restore
Run Code Online (Sandbox Code Playgroud)

因此将图像向左旋转(逆时针)90度

drawImage(image, canvas.width / 2, canvas.height / 2, 1, - Math.PI / 2);
Run Code Online (Sandbox Code Playgroud)

因此,将图像向右(顺时针)旋转90度

drawImage(image, canvas.width / 2, canvas.height / 2, 1, Math.PI / 2);
Run Code Online (Sandbox Code Playgroud)

示例绘制500个图像翻译旋转缩放

var image = new Image;
image.src = "https://i.stack.imgur.com/C7qq2.png?s=328&g=1";
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.style.position = "absolute";
canvas.style.top = "0px";
canvas.style.left = "0px";
document.body.appendChild(canvas);
var w,h;
function resize(){ w = canvas.width = innerWidth; h = canvas.height = innerHeight;}
resize();
window.addEventListener("resize",resize);
function rand(min,max){return Math.random() * (max ?(max-min) : min) + (max ? min : 0) }
function DO(count,callback){ while (count--) { callback(count) } }
const sprites = [];
DO(500,()=>{
    sprites.push({
       x : rand(w), y : rand(h),
       xr : 0, yr : 0, // actual position of sprite
       r : rand(Math.PI * 2),
       scale : rand(0.1,0.25),
       dx : rand(-2,2), dy : rand(-2,2),
       dr : rand(-0.2,0.2),
    });
});
function drawImage(image, spr){
    ctx.setTransform(spr.scale, 0, 0, spr.scale, spr.xr, spr.yr); // sets scales and origin
    ctx.rotate(spr.r);
    ctx.drawImage(image, -image.width / 2, -image.height / 2);
}
function update(){
    var ihM,iwM;
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0,0,w,h);
    if(image.complete){
      var iw = image.width;
      var ih = image.height;
      for(var i = 0; i < sprites.length; i ++){
          var spr = sprites[i];
          spr.x += spr.dx;
          spr.y += spr.dy;
          spr.r += spr.dr;
          iwM = iw * spr.scale * 2 + w;
          ihM = ih * spr.scale * 2 + h;
          spr.xr = ((spr.x % iwM) + iwM) % iwM - iw * spr.scale;
          spr.yr = ((spr.y % ihM) + ihM) % ihM - ih * spr.scale;
          drawImage(image,spr);
      }
    }    
    requestAnimationFrame(update);
}
requestAnimationFrame(update);
Run Code Online (Sandbox Code Playgroud)


Ste*_*ing 26

另一种解决方案适用于方形图像.这是一个适用于任何维度图像的解决方案.画布将始终适合图像而不是其他可能导致部分图像被裁剪掉的解决方案.

var canvas;

var angleInDegrees=0;

var image=document.createElement("img");
image.onload=function(){

    drawRotated(0);
}
image.src="http://greekgear.files.wordpress.com/2011/07/bob-barker.jpg";

$("#clockwise").click(function(){ 
    angleInDegrees+=90 % 360;
    drawRotated(angleInDegrees);
});

$("#counterclockwise").click(function(){ 
    if(angleInDegrees == 0)
        angleInDegrees = 270;
    else
        angleInDegrees-=90 % 360;
    drawRotated(angleInDegrees);
});

function drawRotated(degrees){
    if(canvas) document.body.removeChild(canvas);

    canvas = document.createElement("canvas");
    var ctx=canvas.getContext("2d");
    canvas.style.width="20%";

    if(degrees == 90 || degrees == 270) {
        canvas.width = image.height;
        canvas.height = image.width;
    } else {
        canvas.width = image.width;
        canvas.height = image.height;
    }

    ctx.clearRect(0,0,canvas.width,canvas.height);
    if(degrees == 90 || degrees == 270) {
        ctx.translate(image.height/2,image.width/2);
    } else {
        ctx.translate(image.width/2,image.height/2);
   }
    ctx.rotate(degrees*Math.PI/180);
    ctx.drawImage(image,-image.width/2,-image.height/2);

    document.body.appendChild(canvas);
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/6ZsCz/1588/


cas*_*mia 6

这是全度图像旋转代码。我建议您检查 jsfiddle 中的以下示例应用程序。

https://jsfiddle.net/casamia743/xqh48gno/

在此输入图像描述

该示例应用程序的流程是

  1. 加载图像,计算boundaryRad
  2. 创建临时画布
  3. 将画布上下文原点移动到投影矩形的关节位置
  4. 使用输入度数旋转画布上下文
  5. 使用canvas.toDataURL方法制作图像blob
  6. 使用图像 blob,创建新的图像元素并渲染

function init() {
  ...
  image.onload = function() {
     app.boundaryRad = Math.atan(image.width / image.height);
  }
  ...
}



/**
 * NOTE : When source rect is rotated at some rad or degrees, 
 * it's original width and height is no longer usable in the rendered page.
 * So, calculate projected rect size, that each edge are sum of the 
 * width projection and height projection of the original rect.
 */
function calcProjectedRectSizeOfRotatedRect(size, rad) {
  const { width, height } = size;

  const rectProjectedWidth = Math.abs(width * Math.cos(rad)) + Math.abs(height * Math.sin(rad));
  const rectProjectedHeight = Math.abs(width * Math.sin(rad)) + Math.abs(height * Math.cos(rad));

  return { width: rectProjectedWidth, height: rectProjectedHeight };
}

/**
 * @callback rotatedImageCallback
 * @param {DOMString} dataURL - return value of canvas.toDataURL()
 */

/**
 * @param {HTMLImageElement} image 
 * @param {object} angle
 * @property {number} angle.degree 
 * @property {number} angle.rad
 * @param {rotatedImageCallback} cb
 * 
 */
function getRotatedImage(image, angle, cb) {
  const canvas = document.createElement('canvas');
  const { degree, rad: _rad } = angle;

  const rad = _rad || degree * Math.PI / 180 || 0;
  debug('rad', rad);

  const { width, height } = calcProjectedRectSizeOfRotatedRect(
    { width: image.width, height: image.height }, rad
  );
  debug('image size', image.width, image.height);
  debug('projected size', width, height);

  canvas.width = Math.ceil(width);
  canvas.height = Math.ceil(height);

  const ctx = canvas.getContext('2d');
  ctx.save();

  const sin_Height = image.height * Math.abs(Math.sin(rad))
  const cos_Height = image.height * Math.abs(Math.cos(rad))
  const cos_Width = image.width * Math.abs(Math.cos(rad))
  const sin_Width = image.width * Math.abs(Math.sin(rad))

  debug('sin_Height, cos_Width', sin_Height, cos_Width);
  debug('cos_Height, sin_Width', cos_Height, sin_Width);

  let xOrigin, yOrigin;

  if (rad < app.boundaryRad) {
    debug('case1');
    xOrigin = Math.min(sin_Height, cos_Width);
    yOrigin = 0;
  } else if (rad < Math.PI / 2) {
    debug('case2');
    xOrigin = Math.max(sin_Height, cos_Width);
    yOrigin = 0;
  } else if (rad < Math.PI / 2 + app.boundaryRad) {
    debug('case3');
    xOrigin = width;
    yOrigin = Math.min(cos_Height, sin_Width);
  } else if (rad < Math.PI) {
    debug('case4');
    xOrigin = width;
    yOrigin = Math.max(cos_Height, sin_Width);
  } else if (rad < Math.PI + app.boundaryRad) {
    debug('case5');
    xOrigin = Math.max(sin_Height, cos_Width);
    yOrigin = height;
  } else if (rad < Math.PI / 2 * 3) {
    debug('case6');
    xOrigin = Math.min(sin_Height, cos_Width);
    yOrigin = height;
  } else if (rad < Math.PI / 2 * 3 + app.boundaryRad) {
    debug('case7');
    xOrigin = 0;
    yOrigin = Math.max(cos_Height, sin_Width);
  } else if (rad < Math.PI * 2) {
    debug('case8');
    xOrigin = 0;
    yOrigin = Math.min(cos_Height, sin_Width);
  }

  debug('xOrigin, yOrigin', xOrigin, yOrigin)

  ctx.translate(xOrigin, yOrigin)
  ctx.rotate(rad);
  ctx.drawImage(image, 0, 0);
  if (DEBUG) drawMarker(ctx, 'red');

  ctx.restore();

  const dataURL = canvas.toDataURL('image/jpg');

  cb(dataURL);
}

function render() {
    getRotatedImage(app.image, {degree: app.degree}, renderResultImage)
}
Run Code Online (Sandbox Code Playgroud)


Cpn*_*nch 5

这是绘制旋转和缩放图像的最简单代码:

function drawImage(ctx, image, x, y, w, h, degrees){
  ctx.save();
  ctx.translate(x+w/2, y+h/2);
  ctx.rotate(degrees*Math.PI/180.0);
  ctx.translate(-x-w/2, -y-h/2);
  ctx.drawImage(image, x, y, w, h);
  ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)

  • @oldboy 画布在这里不旋转。旋转应用于画布内工作的上下文 (2认同)
  • @oldboy我认为你误解了这个概念。ctxs.drawImage 仅绘制。 (2认同)

ale*_*eha 5

正如@markE 在他的回答中提到的

另一种方法是在绘制后取消翻译和旋转

它比上下文保存和恢复快得多。

这是一个例子

// translate and rotate
this.context.translate(x,y);
this.context.rotate(radians);
this.context.translate(-x,-y);

this.context.drawImage(...);    

// untranslate and unrotate
this.context.translate(x, y);
this.context.rotate(-radians);
this.context.translate(-x,-y);
Run Code Online (Sandbox Code Playgroud)