Project1
标题: 关于Bitmap#draw_text的压缩比例 [打印本页]
作者: ⑨姐姐 时间: 2018-8-23 08:02
标题: 关于Bitmap#draw_text的压缩比例 关于draw_text,F1帮助是这么写的:
“If the text length exceeds the box's width, the text width will automatically be reduced by up to 60 percent.”
“如果文字长度超过了框的宽度(draw_text里的宽度参数),文字宽度会自动压缩到至多60%。”
这是我的测试结果。数字表示绘制Hello的时候用的宽度参数。可以看到文字被压缩了,但并不是一次性压缩到60%,也不是直接根据宽度连续变化的(因为有的时候压缩比例不变,比如44和46)。
目前RGD在这里的处理暂时还有点问题,不知道有没有人研究过这个缩放,有没有具体的计算公式可以用?
作者: 有丘直方 时间: 2018-8-23 10:52
本帖最后由 有丘直方 于 2018-8-23 11:22 编辑
我感觉EB的RGSS在draw_text的文字压缩处理方面做得不好,不建议走EB的那一套
[line]1[/line]RGSS3测试代码:rows = Graphics.height / Font.default_size
columns = 3
column_width = Graphics.width / columns
text = "Hello"
max_width = 65
bitmap_width = 100
sprites = [ ]
bitmaps = [ ]
( 0 ...( rows * columns) ) .each do |i|
bitmaps[ i] = Bitmap.new ( bitmap_width, Font.default_size )
bitmaps[ i] .draw_text ( 0 , 0 , max_width - i, Font.default_size , text)
bitmaps[ i] .draw_text ( 0 , 0 , bitmap_width, Font.default_size , max_width - i, 2 )
sprites[ i] = Sprite.new
sprites[ i] .bitmap = bitmaps[ i]
sprites[ i] .y = i % rows * Font.default_size
sprites[ i] .x = i / rows * column_width
end
p bitmaps[ 0 ] .text_size ( text) .width
loop { Graphics.update }
rows = Graphics.height / Font.default_size
columns = 3
column_width = Graphics.width / columns
text = "Hello"
max_width = 65
bitmap_width = 100
sprites = [ ]
bitmaps = [ ]
( 0 ...( rows * columns) ) .each do |i|
bitmaps[ i] = Bitmap.new ( bitmap_width, Font.default_size )
bitmaps[ i] .draw_text ( 0 , 0 , max_width - i, Font.default_size , text)
bitmaps[ i] .draw_text ( 0 , 0 , bitmap_width, Font.default_size , max_width - i, 2 )
sprites[ i] = Sprite.new
sprites[ i] .bitmap = bitmaps[ i]
sprites[ i] .y = i % rows * Font.default_size
sprites[ i] .x = i / rows * column_width
end
p bitmaps[ 0 ] .text_size ( text) .width
loop { Graphics.update }
测试结果(这是张544*416大小的图):
控制台输出:帮助文档信息:テキストの長さが矩形の幅を超える場合は、幅を 60% まで自動的に縮小して描画します。
若文字长度超过区域的宽度,文字宽度会自动缩小到 60%。 根据帮助文档所说,当以下代码返回true时width < bitmap.text_size ( text) .width
width < bitmap.text_size ( text) .width
绘制的文字的宽度将会是原来的60%
然而实际上,确实如楼主所说,宽度并不会一下子缩小到60%
从测试结果来看,实际上还没等绘制文字的宽度小于文字宽度时,实际绘制的文字宽度就开始减小了
比如在本次测试中,文字Hello的宽度在正常情况下应该是控制台所说的60,经过测量也确实是60
不过可以看到,当绘制的宽度为61时,文字的宽度就已经开始缩水了,尽管此时还是可以笃定地画的
经过测量,此时文字宽度变成了42,也就是原来的70%
第二次缩水在绘制的文字的宽度为56时出现,变成了36,也就是原来的60%
此时已经达到了帮助文档所说的60%了,但是文字宽度还会再缩小
当绘制宽度为50时,成功缩水到了50%
此后宽度不会再缩水了,因此当绘制文字的宽度小于正常宽度的50%时,文字就会开始残缺
可以看到当宽度为29时,文字残缺了一块
结论:帮助文档完全在瞎写八写,而且文字缩小机制非常愚蠢地浪费大量位图空间
作者: ⑨姐姐 时间: 2018-8-23 12:11
感谢测试结果!
因为一些已有的工程会受到这方面影响,所以只能尽量还原RGSS的默认行为了,请见谅吧。
这些里面我觉得最有趣的是62还能维持100%大小,到61就已经缩小到了70%以下。但是在我那个例子里48->46是缩小到了80%以上。说明比例不是由两者的差或者比值决定的。可能还有一些其他的影响因素甚至常量。这样关系就复杂了……
作者: SailCat 时间: 2018-8-23 23:09
本帖最后由 SailCat 于 2018-8-24 11:00 编辑
看来这是RGSS3的bug, RGSS1和2的表现和有丘直方说的是一样的
(已编辑在楼下)
作者: SixRC 时间: 2018-8-23 23:45
本帖最后由 SixRC 于 2018-8-24 10:23 编辑
缩放机制大致上是这样的
传入宽和字符串
先根据字符串用 GetGlyphOutline 计算出需要的总宽度 假如要描边 把这个宽度加上 2 得到新的总宽
比较传入的宽度和总宽度 若大于等于则跳
若小于则得到缩放系数 = 传入宽/总宽 - 0.15
将缩放系数和 0.6 比较 若小于则调整为 0.6
根据这个系数结合字体高等数据计算新的字体宽再通过 CreateFontIndirect 生成新字体 这我不太懂 对这些函数没有研究
它的公式是 字体宽 = 字体高 * 系数 * 7 / 16 这里的字体宽大概就是一个均宽 是得到具体字数据的一个参数 16 和 7 分别是 GetTextMetrics 得到的 tmHeight 和 tmAveCharWidth 最初默认的字体高和宽?
这个宽会截断为整数 例如 24(高)*0.76*7/16 = 7.98 会截取为 7 作为字宽
所以虽然系数最低是 0.6 但是输出后可能最低不止这样 (即 0.6 不是最终的系数 缩放不是直接缩成 0.6 的)
再重新计算总宽
根据这个结果绘制字体 超出部分不画了
总体来讲就是 传入宽+所需宽 => 缩放系数 => 绘制字的宽度系数 => 输出
作者: ⑨姐姐 时间: 2018-8-24 07:34
经过修正以后我也用上了宽度比例-0.15的计算方法,得到了似乎“比RM更连续变化”的结果。
“四舍五入为整数”这一步比较在意,可能这就是RM在44和46下宽度一样的原因。但这里的转换过程请问是什么样的?零点几的浮点数,莫非是直接转成8位的整数?否则不至于精度损失这么大……
作者: SailCat 时间: 2018-8-24 08:15
本帖最后由 SailCat 于 2018-8-24 09:50 编辑
可以参考下RGSS1和2的draw_text实现,这个是没有上面所说问题的
测试代码如下,注意text_size返回的是60,这点和RGSS3一样
Font.default_size = 24
b = Bitmap.new ( 640 , 480 )
s = Sprite.new
s.bitmap = b
s.x = 0
s.y = 0
75 .downto ( 16 ) do |i|
b.draw_text ( ( 75 - i) / 20 * 210 , ( 75 - i) % 20 * 24 , i, 24 , "Hello" , 0 )
b.draw_text ( ( 75 - i) / 20 * 210 + 100 , ( 75 - i) % 20 * 24 , 24 , 24 , i.to_s , 0 )
end
Font.default_size = 24
b = Bitmap.new ( 640 , 480 )
s = Sprite.new
s.bitmap = b
s.x = 0
s.y = 0
75 .downto ( 16 ) do |i|
b.draw_text ( ( 75 - i) / 20 * 210 , ( 75 - i) % 20 * 24 , i, 24 , "Hello" , 0 )
b.draw_text ( ( 75 - i) / 20 * 210 + 100 , ( 75 - i) % 20 * 24 , 24 , 24 , i.to_s , 0 )
end
另外请注意一下,不到60就开始缩小的原因,是否因为在RGSS3开启了描边模式(默认开启)?
经测试:不到60就开始缩小的原因就是这个
以下描边模式设为true
以下描边模式设为false
作者: SixRC 时间: 2018-8-24 10:14
是直接截断为整数的 24(高)*0.76(系数)*7/16=7.98 截取为 7
是用了 cvttsd2si 这个指令
昨天四舍五入是猜的 原来是直接截断
作者: SailCat 时间: 2018-8-24 10:40
本帖最后由 SailCat 于 2018-8-24 11:02 编辑
反复测试了不同初始字号下的最小字宽(均为显示"Hello")
字号 原始字宽 最小字宽
16 8 4
17 9 5
18 9 5
19 10 6
20 10 6
21 11 6
22 11 6
23 12 7
24 12 7
25 13 7
26 13 7
27 14 8
28 14 8
29 15 9
30 15 9
非等宽字体我没条件测试。手头的vl gothic也是等宽的。
上面字号=30的情况,似乎也不是连续变化,而是15-13-12-10-9
感觉是
100%(15)-90%(13.5即13)-80%(12)-70%(10.5即10)-60%(9)
共5级变化
但在RGSS3中,情况又不一样了
第一个不同是可以看到,第一次缩放就从字宽15直接变成了10,然后9,8,7……
而在RGSS1/2中,字宽的缩放是按百分比依次-10%的
第二个不同是,字宽的下限不仅不是60%,而且远低于60%,连50%也不到
而在RGSS1/2中,字宽的下限是严格的60%(向下取整)
第三个不同是,除第一次缩小的节点是放不下(74)以外,以后的字宽缩小节点,根本和是否放的下没有一毛钱关系
而在RGSS1/2中,字宽缩小的节点一定是放不下
欢迎光临 Project1 (https://rpg.blue/)
Powered by Discuz! X3.1