简体   繁体   English

缩放图像以适合替换图像

[英]Scale an image to fit when replacing an image

I'm trying to implement a behaviour by which I can add an initial image to a canvas (placeholder) and then subsequently I can then choose a different image to replace that image - that new image should then scale itself to "fit" within the bounds of the old image. 我正在尝试实现一种行为,通过该行为我可以将初始图像添加到画布(占位符),然后随后我可以选择其他图像来替换该图像-然后,该新图像应按比例缩放以“适合”旧图像的边界。 For example if I choose a portrait image as the "placeholder" and then choose a landscape image to replace it, Id expect the landscape image to first scale its width and maintain aspect ratio, and then vertically align itself within the boundaries of the placeholder dimensions. 例如,如果我选择一个肖像图像作为“占位符”,然后选择一个风景图像来代替它,则我希望该风景图像先缩放其宽度并保持宽高比,然后在占位符尺寸的边界内垂直对齐。

Here is a jsfiddle of what I have working so far: https://jsfiddle.net/cgallagher/co8dg527/1/ 这是到目前为止我正在工作的jsfiddle: https ://jsfiddle.net/cgallagher/co8dg527/1/

and here is the code: 这是代码:

var canvas = new fabric.Canvas('stage');
var cw = canvas.getWidth()
var ch = canvas.getHeight()
var _currentImage;

function setProductImage(url){
    var oldWidth; 
    var oldHeight;
    var oldLeft;
    var oldTop;

    fabric.Image.fromURL(url, function(img) {
      if (_currentImage) {
        oldWidth = _currentImage.getScaledWidth()
        oldHeight = _currentImage.getScaledHeight()
        oldLeft = _currentImage.left
        oldTop = _currentImage.top  
        canvas.remove(_currentImage);  
      }

      _currentImage = img;

      img.set({ 'left': oldLeft || 0 })
      img.set({ 'top': oldTop || 0 })

      if (oldHeight && oldHeight > img.getScaledHeight()){
        img.scaleToWidth(oldWidth);
        img.set({'height': oldHeight })
      } else if (oldWidth > img.getScaledWidth()){
        img.scaleToHeight(oldHeight);
        img.set({'width': oldWidth })
      }

      img.selectable = true
      canvas.add(img).setActiveObject(img);
    });
  }

  function addImage(url){
    setProductImage(url)
    canvas.renderAll()
  }      

You can see that the image does scale the way I'd like but it doesn't then align itself. 您会看到图像确实按我想要的方式缩放,但随后无法对齐。

I'm toying with the idea of dropping a bounding box around the image too and possibly trying to align and scale within that but I'm not sure this is even possible with fabric? 我也想在图像周围放置一个边界框,并可能尝试在其中对齐和缩放,但是我不确定织物是否有可能?

This is what I had done. 这就是我所做的。 When you run scaleToWidth and scaleToHeight the scaleX and scaleY is changing and you need to adjust the oldHeight and oldWidth to the new img.scaleX / img.scalaY I also rewrite _renderFill method from fabric.Image.prototype to create that offset effect. 当您运行scaleToWidthscaleToHeightscaleXscaleY正在改变,你需要在调整oldHeightoldWidthimg.scaleX / img.scalaY我也改写_renderFill从方法fabric.Image.prototype创建抵消效果。 Check here: https://jsfiddle.net/mariusturcu93/co8dg527/37/ 在这里检查: https : //jsfiddle.net/mariusturcu93/co8dg527/37/

Code

<html>
  <head>
    <title>Fabric kicking</title>


    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.0/fabric.js"></script>
    <style>
      #stage {
        border: solid 1px #333;
      }
    </style>
  </head>
  <body>
    <button onclick="addImage('https://s.hs-data.com/bilder/spieler/gross/208995.jpg')">Add image</button>
    <button onclick="addImage('https://cdn.images.express.co.uk/img/dynamic/67/590x/Mateusz-Klich-883903.jpg')">add another image</button>
    <canvas id="stage" width="600" height="600"></canvas>

    <script>

    var canvas = new fabric.Canvas('stage');
    var cw = canvas.getWidth()
    var ch = canvas.getHeight()
    var _currentImage;

    function setProductImage(url){
        var oldWidth; 
        var oldHeight;
        var oldLeft;
        var oldTop;

        fabric.Image.fromURL(url, function(img) {
          if (_currentImage) {
            oldWidth = _currentImage.getScaledWidth()
            oldHeight = _currentImage.getScaledHeight()
            oldLeft = _currentImage.left
            oldTop = _currentImage.top  
            canvas.remove(_currentImage);  
          }

          _currentImage = img;

          img.set({ 'left': oldLeft || 0 })
          img.set({ 'top': oldTop || 0 })

          if (oldHeight && oldHeight > img.getScaledHeight()){

            img.scaleToWidth(oldWidth);
            img.set({'height': oldHeight/img.scaleX})
          } else if (oldWidth > img.getScaledWidth()){

            img.scaleToHeight(oldHeight);
            img.set({'width': oldWidth/img.scaleY })
          }

          img.selectable = true
          canvas.add(img).setActiveObject(img);
        });
      }

      function addImage(url){
        setProductImage(url)
        canvas.renderAll()
      }      
    </script>
    <img src="https://s.hs-data.com/bilder/spieler/gross/208995.jpg" />
    <img src="https://cdn.images.express.co.uk/img/dynamic/67/590x/Mateusz-Klich-883903.jpg" />
  </body>
</html>

fabric.Image.prototype._renderFill rewrite fabric.Image.prototype._renderFill 重写

fabric.Image.prototype._renderFill= (function(renderFill){
    return function(ctx) {

      var w = this.width, h = this.height, sW = w * this._filterScalingX, sH = h * this._filterScalingY,
          x = -w / 2, y = -h / 2, elementToDraw = this._element;

          y = y  + Math.abs((this._element.height-h)/2);
          x = x  + Math.abs((this._element.width-w)/2);
      elementToDraw && ctx.drawImage(elementToDraw,
        this.cropX * this._filterScalingX,
        this.cropY * this._filterScalingY,
        sW,
        sH,
        x, y, w, h);
    }
})()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM