在C#中将字符串转换为图像

12

我试图在 C# 中将 Unicode 字符串转换为图像。每次运行时,我都会在这一行上遇到错误。

Image image = Image.FromStream(ms, true, true);

出现了ArgumentException未被用户代码处理。参数无效。有什么想法为什么会发生这种情况吗?以下是其余的函数。

public Image stringToImage(string inputString)
    {
        byte[] imageBytes = Encoding.Unicode.GetBytes(inputString);
        MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);

        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true, true);

        return image;
    }

你想将文本转换为图像吗?或者输入的“字符串”包含一些原始的图像数据。 - mipe34
抱歉,应该澄清一下。 - user2528880
2
根据您的使用情况,您可以将图像转换为Base64字符串,如此处所示http://www.dailycoding.com/Posts/convert_image_to_base64_string_and_base64_string_to_image.aspx - keyboardP
字符串是如何编码的? - Jodrell
3
顺便提一句,将你的MemoryStream放在一个using语句块内,因为目前存在资源泄漏的问题。 - 3Dave
显示剩余2条评论
5个回答

8

Unicode并不能编码所有表示图像所需的字节序列。

byte[] -> String -> byte[] 这一转换对于许多给定字节序列来说是行不通的。你需要始终使用 byte[]

例如,如果你读取字节,将其转换为UTF-16,则可能会将字节序列丢弃为无效。以下是UTF-16中一个无效字节序列的示例:

代码点U+D800到U+DFFF[编辑] Unicode标准永久地保留这些代码点值,用于UTF-16编码的前导和尾随代理,并且它们永远不会分配一个字符,因此没有理由对它们进行编码。 官方Unicode标准规定,包括UTF-16在内的所有UTF形式都无法编码这些代码点。


如果你有原始的图像数据,最好创建一个适当大小的图像,将这些数据写入其帧缓冲区,然后持久化该图像。 - Jeff Foster
1
同意,不应该尝试将原始图像数据编码为字符串存储,UTF16(C#的Unicode字符串字节编码)存在非法序列和不可能的值,您否则希望用于存储字节。如果您确实有包含字符而不是字节数据的实际字符串,则需要使用绘图API将文本绘制到图像上。 - antiduh

5
希望这能帮到您:

可能对您有所帮助:

public Bitmap stringToImage(string inputString)
{
   byte[] imageBytes = Encoding.Unicode.GetBytes(inputString);
   using (MemoryStream ms = new MemoryStream(imageBytes))
   {
       return new Bitmap(ms);
   }
}

1
最后一行让我遇到了问题。 - user2528880

3

把写入MemoryStream的调用移除。接受字节数组的构造函数会自动将字节数组的内容放入流中,否则你的流中会有两份原始数据。此外,Write的调用会让流的位置在流的末尾,因此FromStream调用无法读取任何数据。

正确的写法是:

public Image stringToImage(string inputString)
{
    byte[] imageBytes = Encoding.Unicode.GetBytes(inputString);

    // Don't need to use the constructor that takes the starting offset and length
    // as we're using the whole byte array.
    MemoryStream ms = new MemoryStream(imageBytes);

    Image image = Image.FromStream(ms, true, true);

    return image;
}

你从哪里获取源字符串? - Jon Benedicto
被转换成字符串的图像 - user2528880
1
它是如何转换为字符串的?用于将原始字节编码为字符串的编码必须与用于将字符串转换回原始字节的解码匹配。 - Jon Benedicto
不确定,我正在从Active Directory中提取它。我会尽力找出来。 - user2528880
尝试使用Encoding.Default.GetBytes代替。数据可能作为ANSI字符流传输,而不是Unicode。 - Jon Benedicto

3
你从LDAP中获取的是一个字符串类型的图像?我很确定,如果是这样,该字符串实际上应该是base64编码的,并且包含表示实际字符而非图像数据的字节。
你能否提供一小段你所获取的字符串?
如果是真的,你需要将该字符串通过解码base64转换成一个byte[]数组,然后使用该byte[]数组来生成图像。结合@JonBenedicto的代码:
public Image stringToImage(string inputString)
{
    byte[] imageBytes = Convert.FromBase64String(inputString);
    MemoryStream ms = new MemoryStream(imageBytes);

    Image image = Image.FromStream(ms, true, true);

    return image;
}

可能是这样,但每当我尝试使用base64时,都会出现以下错误:“输入不是有效的Base-64字符串,因为它包含一个非Base-64字符,超过两个填充字符或填充字符中有一个非法字符。” - user2528880

0

使用字符串可能会丢失数据,我将只发布将图像转换为字节数组和再次将数组转换为图像的示例,以及将图像转换为字节数组,转换为字符串并再次转换回来的示例,而不会丢失数据。

            MemoryStream ms = new MemoryStream();
            Image.FromFile(@"C:\..\..\..\img.jpg").Save(ms,ImageFormat.Jpeg);
            byte[] bytes = ms.ToArray();
            MemoryStream ms1 = new MemoryStream(bytes);
            Image NewImage = Image.FromStream(ms1);
            NewImage.Save(@"C:\..\..\..\img1.jpg");

尝试这个,它可能会帮助你产生所需的结果。

如果想要进行字符串和二进制之间的转换,最好使用base64。

            MemoryStream ms = new MemoryStream();
            Image.FromFile(@"C:\..\..\..\img.jpg").Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg);
            byte[] bytes = ms.ToArray();
            string byteString = Convert.ToBase64String(bytes);
            byte[] NewBytes = Convert.FromBase64String(byteString);
            MemoryStream ms1 = new MemoryStream(NewBytes);
            Image NewImage = Image.FromStream(ms1);

这应该会给你所需的结果。

 MemoryStream ms = new MemoryStream();
    Image.FromFile(@"C:\..\..\..\img.jpg").Save(ms,ImageFormat.Jpeg);
    byte[] bytes = ms.ToArray();
    string byteString = Convert.ToBase64String(bytes);

然后当您将此字符串传递到您的方法中时...

    public Image stringToImage(string inputString)
    {
         byte[] NewBytes = Convert.FromBase64String(inputString);
         MemoryStream ms1 = new MemoryStream(NewBytes);
         Image NewImage = Image.FromStream(ms1);

         return NewImage;
     }

1
那看起来似乎可行,但我不想保存文件。我想在内存中完成所有操作。 - user2528880
那么在第一个例子中,你只需要不执行最后一行代码,在第二个例子中就像你所做的那样。 - terrybozzio
Base64是将字节数据转换为字符串时,不丢失数据的最安全方式,尤其是当该数据不是原始编码文本时。 - terrybozzio
每当我尝试使用base64时,都会出现以下错误提示:“输入不是有效的Base-64字符串,因为它包含一个非Base-64字符、超过两个填充字符或填充字符中有一个非法字符。” - user2528880

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