使用 CropperJS 旋转配件 canvas

Rotating a fitting canvas with CropperJS

背景

我目前正在开发一种裁剪工具,可以使图像适合它要插入的元素。我从 cropperJS 得到的比率总是 1:1,这意味着高度 == 宽度。一旦我从 cropperJS 获得了 x,y,height,width,我就会得到图像要进入的元素的 height/width 比率,并添加图像的后位以使裁剪后的图像与它适合的元素。

问题

我正在尝试为我的自定义裁剪器制作一个旋转工具,而我从 cropperJS 获得的 X、Y 数据就好像图像从未旋转过一样。我创建了一个函数来进行矩阵旋转以获得我认为工作正常的新 X、Y 数据。如果图像旋转 180 度,我旋转 canvas 的工具可以正常工作,但如果旋转 270 度或 90 度,则效果不佳。

代码

这是计算矩阵旋转的较小函数,其中xy是未旋转的坐标,xmym是中心旋转点,a是旋转角度。

function rotate(x, y, xm, ym, a) {
    var cos = Math.cos,
        sin = Math.sin,
        a = a * Math.PI / 180, // Convert to radians
        // Subtract midpoints, so that midpoint is translated to origin
        // and add it in the end again
        xr = (x - xm) * cos(a) - (y - ym) * sin(a) + xm,
        yr = (x - xm) * sin(a) + (y - ym) * cos(a) + ym;

    return [xr, yr];
}

这是进行裁剪的函数,它适用于 0 或 180 度的角度,但不会获得 90 或 270 度的正确坐标度。

var cropPhoto = async (imgSrc,cropData) =>{return new Promise((resolve, reject) => {
    var img = new Image()
    var ctx, canvas
    var ratio = cropData.ratio || 1
    var h = cropData.height
    var w = cropData.width
    var x = cropData.x
    var y = cropData.y
    if ( ratio > 1 ){
        var h = ratio * cropData.height
        y = y - ( (h - cropData.height) / 2 )
    }
    else if ( ratio < 1 ){
        var w = (1 / ratio) * cropData.width
        x = x - ( (w - cropData.width) / 2 )
    }
    img.style.transform = `${cropData.rotate}deg`
    img.src = imgSrc
    img.onload = () => {
        canvas = document.createElement("canvas")
        canvas.height = h
        canvas.width = w
        ctx = canvas.getContext('2d')
        if(cropData.rotate != 0){
            //nv == new values
            //this only works if its 180 degrees
            var nv = rotate(x,y, cropData.image.naturalWidth/2, cropData.image.naturalHeight/2, cropData.rotate)
            x = nv[0] - w
            y = nv[1] - h
        }
        ctx.drawImage(img, x, y, w, h, 0, 0, w, h)
        canvas = cropData.rotate != 0 ? drawRotated(cropData.rotate) : canvas
        canvas.toBlob(blob => {
            try {
                var urlCreator = window.URL || window.webkitURL;
                resolve(urlCreator.createObjectURL(blob))
            } catch (error) {
                reject()
            }
        },"image/png",1)
    }
    var drawRotated = degrees => {
        var newCanvas = document.createElement("canvas")
        if (  [90, 270].indexOf(Math.abs(degrees)) > -1 ){
            newCanvas.height = w
            newCanvas.width = h
        }else{
            newCanvas.height = h
            newCanvas.width = w
        }
        var ctx2 = newCanvas.getContext("2d")
        if ( [90,-270].indexOf(degrees) > -1 ){
            ctx2.translate( h  , 0 )
        }else if ( [-90,270].indexOf(degrees) > -1 ){
            ctx2.translate( 0  , w )
        }else if ( Math.abs(degrees) == 180 ){
            ctx2.translate( w , h )
        }
        ctx2.rotate(degrees*Math.PI/180)
        ctx2.drawImage(canvas, 0 , 0 )
        return newCanvas
    }
})}

imgSrc 是任何标准图像的 URL 字符串。 cropData示例如下:

{
    height: 221
    ratio: 0.48
    rotate: 0
    scaleX: 1
    scaleY: 1
    width: 221
    x: 695
    y: 61
}

我一直在绞尽脑汁想弄清楚为什么图像没有得到 90 或 270 度的坐标,但就是想不通。我相信这与原始图像的纵横比有关,但我不确定。

JSFiddle

您可能只想使用库的输出并以这种方式获取 canvas 数据。在这种情况下,我结婚了一点 CSS 并得到了你想要的。

cropper.getCroppedCanvas().toBlob()

这也为您提供了库的全部灵活性,因此(如图所示)您可以旋转任何角度并执行库允许您执行的任何其他操作。

试试这个 http://jsfiddle.net/103jh75d/10/