如何在动态 canvas 上计算文本对象的边界框

How to calculate bounding box of text object on dynamic canvas

我正在尝试计算 html canvas 上文本对象的像素高度和宽度。我已经尝试了下面看到的一些代码,但我一直得到错误的结果。有没有更简洁的方法来计算这个?动态 canvas 需要根据匹配文本的长度和大小进行调整。

  1. px 高度和宽度需要正确计算。最左上角像素到最右下角像素。
  2. canvas 需要调整大小以最小化计算时间并考虑包括“\n”在内的文本数量。我试过了

canvas.setWidth(400+text.getBoundingRectWidth()); canvas.setHeight(400+text.getBoundingRectHeight());

但我不确定它是否有效。

我如何重写此代码以使 canvas 大小动态并适应可以更改的文本(例如,在文本区域中写文章的人)?

如何正确计算文本的大小?

如果有人重写此代码以正确满足我的上述规范,我可以提供奖励(金钱、礼品卡、免费披萨等)。我花了很多时间试图解决这个问题。

正在研究: Calculate bounding box of arbitrary pixel-based drawing 看起来很有前途。

这是 JSBIN(基于 Fabric.js: Get text bounding box width and heighthttp://jsbin.com/zoqolik/3/edit?html,css,js,console,output

fabric.Object.prototype.objectCaching = false;
var txt = '\n'+'Adklfmask'+'\n'+'asdfsd'+'\n'+'asdfsd'+'\n'+'asdfsd'+"\n";


var canvas = new fabric.Canvas('canvas');
var text = new fabric.IText(txt, { 
    left: 200, 
    top: 200, 
    fontFamily: 'Princess Sofia',
    padding: 5,
    fontSize: 35,
    lineHeight: 2.5,
    textAlign: 'center'
});

canvas.add(text);
canvas.renderAll();

var ctx = canvas.getContext();

var hei = Math.ceil(300+text.getBoundingRectHeight());
var wid = Math.ceil(300+text.getBoundingRectWidth());

function setWidth(width) {
  var canvas = document.getElementById("canvas");  
  canvas.width = width;
}
function setHeight(height) {
  var canvas = document.getElementById("canvas");  
  canvas.height = height;
}
canvas.setWidth(400+text.getBoundingRectWidth());
canvas.setHeight(400+text.getBoundingRectHeight());

// get/draw bounding box
var bbox = getBoundingBox(ctx, 0, 0, wid, hei);
console.log(bbox.width + ' x ' + bbox.height);
drawBoundingBox(ctx, bbox);


function getBoundingBox(ctx, left, top, width, height) {
    var ret = {};

    // Get the pixel data from the canvas
    var data = ctx.getImageData(left, top, width, height).data;
    console.log(data);
    var first = false; 
    var last = false;
    var right = false;
    var left = false;
    var r = height;
    var w = 0;
    var c = 0;
    var d = 0;

    // 1. get bottom
    while(!last && r) {
        r--;
        for(c = 0; c < width; c++) {
            if(data[r * width * 4 + c * 4 + 3]) {
                console.log('last', r);
                last = r+1;
                ret.bottom = r+1;
                break;
            }
        }
    }

    // 2. get top
    r = 0;
    var checks = [];
    while(!first && r < last) {

        for(c = 0; c < width; c++) {
            if(data[r * width * 4 + c * 4 + 3]) {
                console.log('first', r);
                first = r-1;
                ret.top = r-1;
                ret.height = last - first - 1;
                break;
            }
        }
        r++;
    }

    // 3. get right
    c = width;
    while(!right && c) {
        c--;
        for(r = 0; r < height; r++) {
            if(data[r * width * 4 + c * 4 + 3]) {
                console.log('right', c);
                right = c+1;
                ret.right = c+1;
                break;
            }
        }
    }

    // 4. get left
    c = 0;
    while(!left && c < right) {

        for(r = 0; r < height; r++) {
            if(data[r * width * 4 + c * 4 + 3]) {
                console.log('left', c-1);
                left = c;
                ret.left = c;
                ret.width = right - left - 1;
                break;
            }
        }
        c++;

        // If we've got it then return the height
        if(left) {
            return ret;    
        }
    }

    // We screwed something up...  What do you expect from free code?
    return false;
}

而不是

canvas.setWidth(400+text.getBoundingRectWidth());
canvas.setHeight(400+text.getBoundingRectHeight());

使用

var textSize = ctx.measureText(text);
canvas.setWidth(400+textSize.width);
canvas.setHeight(400+textSize.height);