String.length
只会告诉我字符串中有多少个字符。 (事实上,在Ruby 1.9之前,它只会告诉我有多少字节,这些字节甚至更少。)
我真的希望能够找出一个字符串的'en'宽度。例如:
'foo'.width
# => 3
'moo'.width
# => 3.5 # m's, w's, etc. are wide
'foi'.width
# => 2.5 # i's, j's, etc. are narrow
'foo bar'.width
# => 6.25 # spaces are very narrow
如果我能得到字符串的第一个n
en,那就更好了。
'foo'[0, 2.en]
# => "fo"
'filial'[0, 3.en]
# => "fili"
'foo bar baz'[0, 4.5en]
# => "foo b"
如果我可以策划整个事情,那就更好了。有些人认为空间应该是0.25en,有些人认为应该是0.33等等。
答案 0 :(得分:13)
您应该使用RMagick gem使用您想要的字体渲染“Draw”对象(您可以加载.ttf文件等)
代码看起来像这样:
the_text = "TheTextYouWantTheWidthOf"
label = Draw.new
label.font = "Vera" #you can also specify a file name... check the rmagick docs to be sure
label.text_antialias(true)
label.font_style=Magick::NormalStyle
label.font_weight=Magick::BoldWeight
label.gravity=Magick::CenterGravity
label.text(0,0,the_text)
metrics = label.get_type_metrics(the_text)
width = metrics.width
height = metrics.height
您可以在我的按钮制作工具中查看它:http://risingcode.com/button/everybodywangchungtonite
答案 1 :(得分:4)
你可以尝试创建一个标准化的“宽度比例表”来计算一个近似值,基本上你需要存储每个字符的宽度,然后遍历字符串加上宽度。
我找到了这张表here:
Left, Width, Advance values for ArialBD16 'c' through 'm'
Letter Left Width Advance
c 1 7 9
d 1 8 10
e 1 8 9
f 0 6 5
g 0 9 10
h 1 8 10
i 1 2 4
j -1 4 4
k 1 8 9
l 1 2 4
m 1 12 14
如果你想认真对待,我首先要看一下webkit,gecko和OO.org,但我想用于字距调整和大小计算的算法并非易事。
答案 2 :(得分:4)
如果安装了ImageMagick,则可以从命令行访问此信息。
$ convert xc: -font ./.fonts/HelveticaRoundedLTStd-Bd.otf -pointsize 24 -debug annotate -annotate 0 'MyTestString' null: 2>&1
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/RenderFreetype/1155/Annotate
Font ./.fonts/HelveticaRoundedLTStd-Bd.otf; font-encoding none; text-encoding none; pointsize 24
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/GetTypeMetrics/736/Annotate
Metrics: text: MyTestString; width: 157; height: 29; ascent: 18; descent: -7; max advance: 24; bounds: 0,-5 20,17; origin: 158,0; pixels per em: 24,24; underline position: -1.5625; underline thickness: 0.78125
2010-11-02T19:17:48+00:00 0:00.010 0.010u 6.6.5 Annotate convert[22496]: annotate.c/RenderFreetype/1155/Annotate
Font ./.fonts/HelveticaRoundedLTStd-Bd.otf; font-encoding none; text-encoding none; pointsize 24
要从Ruby中执行此操作,请使用反引号:
result = `convert xc: -font #{path_to_font} -pointsize #{size} -debug annotate -annotate 0 '#{string}' null: 2>&1`
if result =~ /width: (\d+);/
$1
end
答案 3 :(得分:4)
使用ttfunk gem从字体文件中读取指标。然后,您可以获得em中的一串文本的宽度。 Here's my pull request to get this example added to the gem.
require 'rubygems'
require 'ttfunk'
require 'valuable'
# Everything you never wanted to know about glyphs:
# http://chanae.walon.org/pub/ttf/ttf_glyphs.htm
# this code is a substantial reworking of:
# https://github.com/prawnpdf/ttfunk/blob/master/examples/metrics.rb
class Font
attr_reader :file
def initialize(path_to_file)
@file = TTFunk::File.open(path_to_file)
end
def width_of( string )
string.split('').map{|char| character_width( char )}.inject{|sum, x| sum + x}
end
def character_width( character )
width_in_units = ( horizontal_metrics.for( glyph_id( character )).advance_width )
width_in_units.to_f / units_per_em
end
def units_per_em
@u_per_em ||= file.header.units_per_em
end
def horizontal_metrics
@hm = file.horizontal_metrics
end
def glyph_id(character)
character_code = character.unpack("U*").first
file.cmap.unicode.first[character_code]
end
end
这是在行动:
>> din = Font.new("#{File.dirname(__FILE__)}/../../fonts/DIN/DINPro-Light.ttf")
>> din.width_of("Hypertension")
=> 5.832
# which is correct! Hypertension in that font takes up about 5.832 em! It's over by maybe ... 0.015.
答案 4 :(得分:1)
这是一个很好的问题!
我正在尝试使用ruby中的pango / cairo来解决它,以获得SVG输出。我可能会使用pango来计算宽度,然后使用一个简单的svg元素。
我使用以下代码:
require "cairo"
require "pango"
paper = Cairo::Paper::A4_LANDSCAPE
TEXT = "Don't you love me anymore?"
def pac(surface)
cr = Cairo::Context.new(surface)
cr.select_font_face("Calibri",
Cairo::FONT_SLANT_NORMAL,
Cairo::FONT_WEIGHT_NORMAL)
cr.set_font_size(12)
extents = cr.text_extents(TEXT)
puts extents
end
Cairo::ImageSurface.new(*paper.size("pt")) do |surface|
cr = pac(surface)
end
答案 5 :(得分:0)
一旦我不得不在两行中显示一个字符串数组(包含即将到来的世界日、当前命名日等),将换行符放在适当的字符串之后,我必须确定字符串的累积宽度,以 Arial 打印。我打开我的文字编辑器,输入字母,然后根据字符在给定字体中的宽度将其分为两类:
w="023456789AÁBCDEFGHJKLMNOÓÖŐPQRSTUÚÜŰWZYaábcdeghksoóöőpqwuúüűzymn".chars.yield_self{|z| z.zip(Array.new(z.size){1.5})}.to_h.merge("1rfiíjltIÍ ".chars.yield_self{|z| z.zip(Array.new(z.size){1})}.to_h)
w.default=1
nntd=["01-21:A vallások világnapja", "01-19:Kanut", "Kenéz", "Margaréta", "Márió", "Máriusz", "Megyer", "Sára", "Szultána", "Vázsony"]
nntd.sort_by!{|z| z.chars.map{|q| w[q]}.sum}.reverse
然后我就能够确定换行符的位置:
ind=nntd.collect.with_index.find_index{|z,i| nntd[0..i].join.chars.map{|q| w[q]}.sum >=nntd.join.chars.map{|q| w[q]}.sum/2}
t=[nntd[0..ind],nntd[ind+1..-1]].map{|z| z.join(",")}.join("\n")
毕竟我得到了一个很好的平衡输出,分为两行:
01-21:A vallasok világnapja,01-19:Margaréta,Szultana Vázsony,Máriusz,Megyer,Kenéz,Kanut,Márió,Sára
这样我就可以眨眼检查即将到来的世界日和当前的命名日。