【问题标题】:Javascript - get actual rendered font heightJavascript - 获取实际呈现的字体高度
【发布时间】:2016-02-20 01:00:51
【问题描述】:

在我的即时编辑器工具中,我真的很高兴获得文本/字体的实际渲染高度 - (我的意思不是仅仅获得 CSS 字体大小,既不计算也不预设)。

这可以在 javascript 中实现吗?

如果不是直接的,是否可以在画布中以与呈现为常规文本相同的方式呈现字体 - 然后找出?

编辑 - 我的“开发”解决方案:基于建议的链接,我构建了一个纯 JavaScript 代码,它通过画布中的像素并分析像素是否为白色并起作用因此,它几乎不是代码的开发者版本 - 只是输出一些有用的信息并显示如何访问计算数据 - http://jsfiddle.net/DV9Bw/1325/

HTML:

<canvas id="exampleSomePrettyRandomness" width="200" height="60"></canvas>
<div id="statusSomePrettyRandomness"></div>

JS:

function findPos(obj) {
var curleft = 0, curtop = 0;
if (obj.offsetParent) {
    do {
        curleft += obj.offsetLeft;
        curtop += obj.offsetTop;
    } while (obj = obj.offsetParent);
    return { x: curleft, y: curtop };  
}
return undefined;
}


var status = document.getElementById('statusSomePrettyRandomness');
var example = document.getElementById('exampleSomePrettyRandomness');
var context = example.getContext('2d');
context.fillStyle = "rgb(255,255,255)";
context.fillRect(0, 0, 200, 200);
context.fillStyle = "rgb(0,0,0)";
context.font = "30px Arial";
context.fillText("Hello World",0,30);
var pos = findPos(example);
var x = example.pageX - pos.x;
var y = example.pageY - pos.y;
var foundTop = false;
xPos = 0;
yPos = 0;
topY = -1;
bottomY = -1;
var fuse = 1000;
while( fuse-- > 0 ){
//status.innerHTML += yPos+"<br>";
if( yPos == (example.offsetHeight - 2) ){
    xPos++;
    yPos = 0;
    continue;
}
    var data = context.getImageData(xPos, yPos, 1, 1).data;
if( ! foundTop ){
    if( (data[0] != 255) && (data[1] != 255) && (data[2] != 255) ){
        topY = yPos;
        status.innerHTML += "<br>Found top: "+topY+" X:"+xPos+" Color: rgba("+data[0]+","+data[1]+","+data[2]+")"+"<br>";
        foundTop = true;
    }
} else {
    if( (data[0] == 255) && (data[1] == 255) && (data[2] == 255) ){
        bottomY = yPos;
        status.innerHTML += "<br>Found bottom: "+bottomY+" X:"+xPos+"<br>";
        break;
    }
} 
yPos++;
if( yPos > example.offsetHeight ){
    status.innerHTML += ""
        +"Y overflow ("+yPos+">"+example.offsetHeight+")"
        +" - moving X to "+xPos
        +" - reseting Y to "+yPos 
        +"<br>"
    ;
        xPos++; 
    yPos = 0;
}
}
status.innerHTML += "Fuse:"+fuse+", Top:"+topY+", Bottom: "+bottomY+"<br>";
status.innerHTML += "Font height should be: "+(bottomY-topY)+"<br>";

编辑 2: 为什么这不是重复的:我的问题是关于字体或字母的真实渲染高度,“possible duplicate”是关于你需要多少空间打印文本,提供的答案无论如何都不能回答我的确切问题。

【问题讨论】:

  • 我不确定我是否完全明白了你的问题,我很着急,但既然你标记了你的问题 [html5-canvas] 也许this question 它的答案可以帮助你。
  • 我标记了它,因为我猜可能有一个解决方案,可以以与呈现为文本相同的方式绘制字体 - 但在画布中,作为图像像素 - 然后我想我可以以某种方式分析画布像素,因为我知道底色是什么,淹没字体的颜色是什么 :) 现在更清楚了吗?
  • 也许试试这种方法? stackoverflow.com/questions/1134586/…
  • "获取文本/字体的实际渲染高度"应该返回哪个度量单位?
  • @jave.web 试过window.getComputedStyle ?

标签: javascript html5-canvas font-size text-size


【解决方案1】:

我不知道有任何方法会返回 height 等文本的 measureText(目前确实返回 width)。

但是,理论上您可以简单地在画布中绘制文本,然后 trim the surrounding transparent pixels 然后测量画布高度..

这是一个示例(高度将记录在控制台中):

// Create a blank canvas (by not filling a background color).
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// Fill it with some coloured text.. (black is default)
ctx.font = "48px serif";
ctx.textBaseline = "hanging";
ctx.fillText("Hello world", 0, 0);

// Remove the surrounding transparent pixels
// result is an actual canvas element
var result = trim(canvas);

// you could query it's width, draw it, etc..
document.body.appendChild(result);

// get the height of the trimmed area
console.log(result.height);

// Trim Canvas Pixels Method
// https://gist.github.com/remy/784508
function trim(c) {

  var ctx = c.getContext('2d'),

    // create a temporary canvas in which we will draw back the trimmed text
    copy = document.createElement('canvas').getContext('2d'),

    // Use the Canvas Image Data API, in order to get all the
    // underlying pixels data of that canvas. This will basically
    // return an array (Uint8ClampedArray) containing the data in the
    // RGBA order. Every 4 items represent one pixel.
    pixels = ctx.getImageData(0, 0, c.width, c.height),

    // total pixels
    l = pixels.data.length,
    
    // main loop counter and pixels coordinates
    i, x, y,

    // an object that will store the area that isn't transparent
    bound = { top: null, left: null, right: null, bottom: null };

  // for every pixel in there
  for (i = 0; i < l; i += 4) {

    // if the alpha value isn't ZERO (transparent pixel)
    if (pixels.data[i+3] !== 0) {

      // find it's coordinates
      x = (i / 4) % c.width;
      y = ~~((i / 4) / c.width);
  
      // store/update those coordinates
      // inside our bounding box Object

      if (bound.top === null) {
        bound.top = y;
      }
      
      if (bound.left === null) {
        bound.left = x; 
      } else if (x < bound.left) {
        bound.left = x;
      }
      
      if (bound.right === null) {
        bound.right = x; 
      } else if (bound.right < x) {
        bound.right = x;
      }
      
      if (bound.bottom === null) {
        bound.bottom = y;
      } else if (bound.bottom < y) {
        bound.bottom = y;
      }
    }
  }
  
  // actual height and width of the text
  // (the zone that is actually filled with pixels)
  var trimHeight = bound.bottom - bound.top,
      trimWidth = bound.right - bound.left,

      // get the zone (trimWidth x trimHeight) as an ImageData
      // (Uint8ClampedArray of pixels) from our canvas
      trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
  
  // Draw back the ImageData into the canvas
  copy.canvas.width = trimWidth;
  copy.canvas.height = trimHeight;
  copy.putImageData(trimmed, 0, 0);

  // return the canvas element
  return copy.canvas;
}
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

图像数据 API:https://developer.mozilla.org/en-US/docs/Web/API/ImageData

【讨论】:

  • 我真的不需要宽度 - 我只需要高度 :)
  • @jave.web 我已经更新了我的答案以包含一个工作示例。
  • 谢谢,经过测试,手动测量 - 有效。但我无法真正理解代码的作用 - 会很好并评论一下吗? :)
  • @jave.web 我已经添加了一些 cmets,尽管我知道有人可以更好地解释它:)
  • 谢谢,现在我明白了它是如何工作的——对我来说,神秘的线是检查 alpha 通道——好主意 :)——但仍有一些东西对我来说仍然是个谜,那就是计算像素坐标 - 你能解释一下吗? :) (2 行,按位 not(~) 和 modulo(%) 运算符)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 1970-01-01
  • 2013-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多