在图像上绘制字节

5
我正在尝试获取某些字节以写入图像,例如:

" །༉ᵒᵗᵗ͟ᵋༀ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟. . . "

但当我在图像上显示它时,我得到了以下结果...

图像

enter image description here

我尝试更改字符串的编码类型,当我接收到字节并且没有设置字体时,我尝试了所有默认的Microsoft字体以及一些我在互联网上找到的自定义字体。我做错了什么?


编辑:原始代码使用了Graphics.DrawString。我尝试了TextRenderer,结果几乎相同。

图像

http://i.stack.imgur.com/kxhyU.jpg

这是我用来生成图像的代码:

string text = "[rotten4pple]  །༉ᵒᵗᵗ͟ᵋༀ  ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟. . .";

var font = new Font("Arial", 8, FontStyle.Regular);
var bitmap = new Bitmap(1, 1);
var size = Graphics.FromImage(bitmap).MeasureString(text, font);
bitmap = new Bitmap((int)size.Width + 4, (int)size.Height + 4);
using (var gfx = Graphics.FromImage(bitmap))
{
    gfx.Clear(Color.White);
    TextRenderer.DrawText(gfx, cmd.AllArguments, font, new Point(2, 2),
        Color.Black, Color.White);
}

变量cmd.AllArguments被传递到方法中,我认为该字符串使用windows-1252进行编码。

1
你是否尝试过使用它们的Unicode编码,而不是字面字符串?你可以查看Windows中的字符映射表。 - trinaldi
不只是那个字符串,任何类似的字符串都一样,这个例子只是我正在测试的。:/ - Alec Scratch
这是Graphics.DrawString吗? - Theraot
是的,它在一个被清空为白色的空白图像上使用了Graphics.DrawString。 - Alec Scratch
请包含您用于执行原始测试和Theraot测试的实际代码。如果您不展示您的操作,我们就无法告诉您哪里做错了。 - Scott Chamberlain
显示剩余2条评论
1个回答

3

图像处理

不要使用 Graphics.DrawString 处理 Unicode 字符。

你应该改用 TextRenderer.DrawText 方法,例如:

TextRenderer.DrawText(e.Graphics, "こんにちは", this.Font,
            new Point(10, 10), this.ForeColor, this.BackColor, flags);

缺点是您将无法指定一个Brush
我已经测试过了。我认为还有其他问题,因为它在我的电脑上似乎可以工作。这是我的代码:
private void Form1_Paint(object sender, PaintEventArgs e)
{
    var text = " །༉ᵒᵗᵗ͟ᵋༀ  ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟. . . ";
    TextRenderer.DrawText(e.Graphics, "TextRenderer.DrawText" + text , this.Font,
        new Point(10, 10), this.ForeColor, this.BackColor);

    e.Graphics.DrawString("Graphics.DrawString" + text, this.Font,
        new SolidBrush(this.ForeColor), new PointF(10, 30));
}

注意: 字体为 Arial Unicode MS 8.25pt

输出结果:

文本绘制比较


编码

这是原始字符串,以UTF-8存储:

[rotten4pple] །༉ᵒᵗᵗ͟ᵋༀ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟ ͟. . .

这是您获取的错误字符串,以Windows-1252存储:

[rotten4pple] à¼à¼‰áµ’ᵗᵗ͟ᵋༀ 🢠͟ ÍŸ ÍŸ ÍŸ ÍŸ ͟🢠͟ ÍŸ ÍŸ ÍŸ ÍŸ ÍŸ ͟🛠͟ ÍŸ ÍŸ ÍŸ ÍŸ ÍŸðŸ¢. . .

它们二进制相等。 这是两个字符串字节的十六进制表示:

5B 72 6F 74 74 65 6E 34 70 70 6C 65 5D 20 E0 BC
8D E0 BC 89 E1 B5 92 E1 B5 97 E1 B5 97 CD 9F E1
B5 8B E0 BC 80 EF A3 BF 20 F0 9F 90 A2 20 CD 9F
20 CD 9F 20 CD 9F 20 CD 9F 20 CD 9F 20 CD 9F F0
9F 90 A2 20 CD 9F 20 CD 9F 20 CD 9F 20 CD 9F 20
CD 9F 20 CD 9F 20 CD 9F F0 9F 90 9B 20 CD 9F 20
CD 9F 20 CD 9F 20 CD 9F 20 CD 9F 20 CD 9F F0 9F
90 A2 2E 20 2E 20 2E

由于这是二进制值的重新解释而不是重新编码,因此在.NET中使用Encoding.Convert进行转换是不可行的。相反,您应该获取以错误编码方式表示的字符串的二进制表示,并直接将其作为正确编码读取:

var text = cmd.AllArguments;
var bytes = Encoding.GetEncoding(1252).GetBytes(text);
text = Encoding.UTF8.GetString(bytes);

注意事项

您一直在询问API默认使用的编码方式。我不熟悉您正在使用的API,因此可能会受到机器配置的影响。您应该寻找一种重载方式,允许您指定接收UTF-8字符串。

有可能您实际上收到的是byte[],因此您可以直接在其上使用Encoding.UTF8.GetString。如果无法指定编码,则应考虑切换为发送byte[],目的是更好地控制编码。

在这方面,不要使用Encoding.Default,因为它将是机器语言的扩展ASCII码。

顺便说一句,UTF-8是网络传输的一个好选择,不仅因为它与语言和其他区域设置无关,还因为它与字节顺序(字节序)无关。


我尝试了这个,但仍然出现了错误的字符 :/ - Alec Scratch
这个字符串的默认编码是什么?我从一个基于异步TCP的聊天客户端获取所有字符串,我不知道这是否有助于解决问题。 - Alec Scratch
据我所知,@AlecScratch,您应该将字符串作为byte[]发送,另一侧接收此byte[]并将其转换为字符串。在将字符串转换为byte[]和反之亦然时,应考虑编码方式。如果您进行转换但不知道编码方式,则是错误的做法。 - Theraot
我知道我正在使用什么编码,但是字符串的默认编码是什么?我正在使用Windows-1252。 - Alec Scratch
@AlecScratch 我已经发现了编码问题并解决了它,请看更新。 - Theraot
非常感谢!这个方法真的很有效!是的,我发现我从TCP流中读取的字节是1252编码的,当我发现这一点后,我将其切换为UTF8编码,再次感谢你,你帮了我大忙! - Alec Scratch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接