FabricJS 设置背景图像大小和位置

FabricJS Setting background image size and position

我在一个项目中使用 FabricJS,我需要能够在其中设置 canvas 的背景图像。 canvas 可以是任意大小,并且可以随时调整大小。最后,无论大小如何,图像都应始终填满 canvas,但绝不能以任何方式扭曲。

因此,例如,如果我有一张 800x600(宽 x 高)canvas 和一张 1200x700 的背景图片,则应将图片缩小到 1029x600,以便它覆盖整个 canvas 而不会失真.

我已经编写了一个函数来计算 canvas 和图像的尺寸并相应地设置图像的大小和位置,但我无法使其正常工作。它大部分时间都有效,但不是 "bullet proof"。有时图像会变形,有时它不会填满整个 canvas.

我需要帮助的是将其重构为一个防弹解决方案,无论 canvas 或图像的大小如何,它始终符合我的尺寸标准。

我创建了一个 fiddle with the code。 fiddle 加载一个 800x600 canvas,然后首先设置一个横向背景图像以演示代码如何不调整图像大小以覆盖 canvas,然后设置一个纵向图像以显示如何它有时会扭曲图像。

这是代码本身:

var canvas = window._canvas = new fabric.Canvas('c'),
    canvasOriginalWidth = 800,
    canvasOriginalHeight = 600,
    canvasWidth = 800,
    canvasHeight = 600,
    canvasScale = .5,
    photoUrlLandscape = 'https://images8.alphacoders.com/292/292379.jpg',
    photoUrlPortrait = 'https://presspack.rte.ie/wp-content/blogs.dir/2/files/2015/04/AMC_TWD_Maggie_Portraits_4817_V1.jpg';

setCanvasSize({height: canvasHeight, width: canvasWidth});
setTimeout(function() {
    setCanvasBackgroundImageUrl(photoUrlLandscape, 0, 0, 1)
}, 50)
setTimeout(function() {
    setCanvasBackgroundImageUrl(photoUrlPortrait, 0, 0, 1)
}, 4000)

function setCanvasSize(canvasSizeObject) {
    canvas.setWidth(canvasSizeObject.width);
    canvas.setHeight(canvasSizeObject.height);
    setZoom();
}
function setZoom() {
    setCanvasZoom();
    canvas.renderAll();
}
function setCanvasZoom() {
    var width = canvasOriginalWidth;
    var height = canvasOriginalHeight;
    var tempWidth = width * canvasScale;
    var tempHeight = height * canvasScale;

    canvas.setWidth(tempWidth);
    canvas.setHeight(tempHeight);
}
function setCanvasBackgroundImageUrl(url, top, left, opacity) {
    if(url && url.length > 0) {
        fabric.Image.fromURL(url, function(img) {
            var aspect, scale;

            if(parseInt(canvasWidth) > parseInt(canvasHeight)) {
                if(img.width >= img.height) {
                    // Landscape canvas, landscape source photo
                    aspect = img.width / img.height;

                    if(img.width >= parseInt(canvasWidth)) {
                        scale = img.width / parseInt(canvasWidth);
                    } else {
                        scale = parseInt(canvasWidth) / img.width;
                    }

                    img.width = parseInt(canvasWidth)
                    img.height = img.height / scale;
                } else {
                    // Landscape canvas, portrait source photo
                    aspect = img.height / img.width;

                    if(img.width >= parseInt(canvasWidth)) {
                        scale = img.width / parseInt(canvasWidth);
                    } else {
                        scale = parseInt(canvasWidth) / img.width;
                    }

                    img.width = parseInt(canvasWidth);
                    img.height = img.height * scale;
                }
            } else {
                if(img.width >= img.height) {
                    // Portrait canvas, landscape source photo
                    aspect = img.width / img.height;

                    if(img.height >= parseInt(canvasHeight)) {
                        scale = img.width / parseInt(canvasHeight);
                    } else {
                        scale = parseInt(canvasHeight) / img.height;
                    }

                    img.width = img.width * scale;
                    img.height = parseInt(canvasHeight)
                } else {
                    // Portrait canvas, portrait source photo
                    aspect = img.height / img.width;

                    if(img.height >= parseInt(canvasHeight)) {
                        scale = img.height / parseInt(canvasHeight);
                    } else {
                        scale = parseInt(canvasHeight) / img.height;
                    }

                    img.width = img.width * scale;
                    img.height = parseInt(canvasHeight);
                }
            }

            canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
                top: parseInt(top) || 0,
                left: parseInt(left) || 0,
                originX: 'left',
                originY: 'top',
                opacity: opacity ? opacity : 1,
                scaleX: canvasScale,
                scaleY: canvasScale
            });

            canvas.renderAll();
            setZoom();
        });
    } else {
        canvas.backgroundImage = 0;
        canvas.setBackgroundImage('', canvas.renderAll.bind(canvas));

        canvas.renderAll();
        setZoom();
    }
};

这是一个 fiddle 可以实现(我认为)您想要实现的目标:

https://jsfiddle.net/whippet71/7s5obuk2/

缩放图像的代码非常简单:

    function scaleAndPositionImage() {
        setCanvasZoom();

        var canvasAspect = canvasWidth / canvasHeight;
        var imgAspect = bgImage.width / bgImage.height;
        var left, top, scaleFactor;

        if (canvasAspect >= imgAspect) {
            var scaleFactor = canvasWidth / bgImage.width;
            left = 0;
            top = -((bgImage.height * scaleFactor) - canvasHeight) / 2;
        } else {
            var scaleFactor = canvasHeight / bgImage.height;
            top = 0;
            left = -((bgImage.width * scaleFactor) - canvasWidth) / 2;

        }

        canvas.setBackgroundImage(bgImage, canvas.renderAll.bind(canvas), {
            top: top,
            left: left,
            originX: 'left',
            originY: 'top',
            scaleX: scaleFactor,
            scaleY: scaleFactor
        });
        canvas.renderAll();

    }

基本上您只想知道图像的纵横比是大于还是小于canvas。一旦知道可以计算出比例因子,最后一步就是计算出如何偏移图像,使其以 canvas.

为中心
fabric.Image.fromURL("image.jpg", function (img) {    
    canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
        scaleX: canvas.width / img.width,
        scaleY: canvas.height / img.height
    });
});

它将图像设置为完整 canvas