【问题标题】:canvas rotates of 180 degrees instead of 90 when I use context.rotate当我使用 context.rotate 时,画布旋转 180 度而不是 90 度
【发布时间】:2020-05-20 04:32:36
【问题描述】:

更新 - 第二部分
我注意到在旋转图像之前进行 ajax 调用时会出现问题。
我这样做:

$.ajax({
    type:'POST',
    beforeSend: function(request) {
        request.setRequestHeader("Authorization", "Bearer {{ app('request')->token }}");
    },
    url: "my-url-to-rotate-image-on-server/90",
    success:function(data) {
        $('#my_id').rotate(90); // the rotate function is the code I wrote below
    },
    error: function(data) { }
});

如果我删除 ajax 调用并只旋转图像,它就可以工作。


我需要将图像旋转 90 度,但图像旋转了 180 度。
这是我在网上找到并使用的代码(一个 jquery 插件):

var p = this.get(0);
p.angle = 90;

if (p.angle >= 0) {
    var rotation = Math.PI * p.angle / 180;
} else {
    var rotation = Math.PI * (360+p.angle) / 180;
}
var costheta = Math.cos(rotation);
var sintheta = Math.sin(rotation);

var canvas = document.createElement('canvas');
var onLoad = false;
if (!p.oImage) {
    canvas.oImage = new Image();
    canvas.oImage.src = p.src;
    canvas.oImage.width = p.width;
    canvas.oImage.height = p.height;
    onLoad = true;
} else {
    canvas.oImage = p.oImage;
}

canvas.style.width = canvas.width = Math.abs(costheta*canvas.oImage.width) + Math.abs(sintheta*canvas.oImage.height);
canvas.style.height = canvas.height = Math.abs(costheta*canvas.oImage.height) + Math.abs(sintheta*canvas.oImage.width);

var context = canvas.getContext('2d');
context.save();
if (rotation <= Math.PI/2) {
    context.translate(sintheta*canvas.oImage.height,0);
} else if (rotation <= Math.PI) {
    context.translate(canvas.width,-costheta*canvas.oImage.height);
} else if (rotation <= 1.5*Math.PI) {
    context.translate(-costheta*canvas.oImage.width,canvas.height);
} else {
    context.translate(0,-sintheta*canvas.oImage.width);
}
context.rotate(rotation);

if (onLoad) {
    canvas.oImage.onload = function() {
        context.drawImage(canvas.oImage, 0, 0, canvas.oImage.width, canvas.oImage.height);
        context.restore();
    };
} else {
    context.drawImage(canvas.oImage, 0, 0, canvas.oImage.width, canvas.oImage.height);
    context.restore();
}

我得到的是画布尺寸被正确旋转(我的意思是,旧的宽度变成了新的高度,反之亦然),但图像旋转了 180 度而不是 90 度。

不知道怎么调试。

更新
我注意到,当图像 src 是 http url 时,就会发生奇怪的行为。
如果图像 src 是 blob,则代码可以完美运行。

【问题讨论】:

    标签: javascript image html5-canvas image-rotation


    【解决方案1】:

    window.addEventListener('load', onDocLoaded, false);
    
    function onDocLoaded(evt)
    {
    	let img = document.querySelector('img');
    	let width = img.naturalWidth, height=img.naturalHeight;
    	let canvas = document.createElement('canvas');
    	canvas.width = height;
    	canvas.height = width;
    	let ctx = canvas.getContext('2d');
    	ctx.rotate(Math.PI/2);
    	ctx.translate(0,-height);
    	ctx.drawImage(img,0,0);
    	document.body.appendChild(canvas);
    }
    body
    {
    	background-color: #333;
    }
    &lt;img id='theImage' src='https://i.stack.imgur.com/Zqh6Am.png'/&gt;

    【讨论】:

      【解决方案2】:

      当使用 cos(0)、sin(0) 而不是北时,0 度指向东方,这就是为什么你认为这实际上是正确的却不起作用。

      当您向东添加 90 度时,它正确地指向南方,给人的印象是它已经旋转了 180 度。

      如果您希望 0 度指向北方。我们知道它是 90 度,那么这就是将角度减去 90 度的问题。

      你在哪里

       p.angle = 90;
      

      替换为...

       const POINT_NORTH = -90;
       p.angle = POINT_NORTH + 90;
      

      【讨论】:

      • 是的,从你想要的角度减去 90。
      【解决方案3】:

      您从网上获取的代码(应该带有参考/归属)非常老派(至少 5 岁)。最重要的是,代码质量很差。

      请注意,二维上下文 translatescalerotatetransform 是累积的。如果您调用ctx.rotate(Math.PI/2)(90 度)然后再次调用它ctx.rotate(Math.PI/2),您实际上已旋转Math.PI(180 度)。然而,代码每次都会创建一个新的画布,因此这不会成为双重旋转的原因。为什么会发生这种情况在代码中并不明显。

      画布上的旋转是顺时针方向。 0 度是 3 点钟。

      加载并旋转90度

      分离关注点并使用现代 JS。加载图片和显示图片应该是独立的函数

      首先是一个旋转图像并适合画布的函数

      // Rotates image 90 and sets canvas size to fit rotated image
      function drawImageRot90(ctx, image) {
          ctx.canvas.style.width = (ctx.canvas.width = image.height) + "px";
          ctx.canvas.style.height = (ctx.canvas.height = image.width) + "px";
          ctx.setTransform(0, 1, -1, 0, ctx.canvas.width, 0);  // overwrite existing transform
          ctx.drawImage(image, 0, 0);
          ctx.setTransform(1, 0, 0, 1, 0, 0);                  // reset default transform
      }
      

      然后是加载图像的函数。该函数返回一个承诺,该承诺将在加载时传递图像。

      // Return promise to provide loaded image as described in details AKA `p`
      function loadImage(details) {
          return new Promise(loaded => {
              if (!details.oImage) {
                  const img = new Image;
                  img.src = details.src
                  img.addEventListener("load",() => {
                          img.width = details.width;
                          img.height = details.height;
                          loaded(img);
                      }, {once: true}
                  );
              } else {
                  loaded(details.oImage);
              }
          });
      }
      

      把它放在一起

      loadImage(this.get(0))
          .then((img) => {
              const canvas = document.createElement("canvas");
              drawImageRot90(canvas.getContext("2d"), img);
          })
          
      

      90步旋转功能

      function drawImageRot(ang, ctx, image) { // ang must be 0, 90, 180, 270 or will default 180
          if (ang === 90 || ang === 270) {
              ctx.canvas.style.width = (ctx.canvas.width = image.height) + "px";
              ctx.canvas.style.height = (ctx.canvas.height = image.width) + "px";
              if (ang === 90) { ctx.setTransform(0, 1, -1, 0, ctx.canvas.width, 0) } 
              else { ctx.setTransform(0, -1, 1, 0, 0, ctx.canvas.height) }
          } else {
              ctx.canvas.style.width = (ctx.canvas.width = image.width) + "px";
              ctx.canvas.style.height = (ctx.canvas.height = image.height) + "px";
              if (ang === 0) { ctx.setTransform(1, 0, 0, 1, 0, 0) }
              else { ctx.setTransform(-1, 0, 0, -1, ctx.canvas.width, ctx.canvas.height) }
          }
          ctx.drawImage(image, 0, 0);
          ctx.setTransform(1, 0, 0, 1, 0, 0);   // reset default transform
      }
      

      【讨论】:

        猜你喜欢
        • 2021-11-28
        • 2019-08-23
        • 2014-07-23
        • 2013-04-22
        • 2017-02-02
        • 1970-01-01
        • 1970-01-01
        • 2013-02-09
        • 2010-10-16
        相关资源
        最近更新 更多