将图像以二进制数据形式写入文本文件 C#

9
我需要创建一个文件,将图像作为文本嵌入到其中的某些记录中。我在编写图像文本时遇到了一些问题。我从SQL数据库(图像类型)中作为字节数组获取图像,然后通过遍历每个字节并将该字节的ASCII等效项写入文件来将该图像写入文本文件中。
在我能将该图像写入文本文件之前,我必须将其转换为CCITT4格式的TIFF(它以前是jpeg)。为了确保这样做正确,我还将流保存为TIFF并在“AsTiffTagViewer”中查看它,这显示了压缩是正确的。我能够在正确的查看器中查看tiff;但是,当从文件中获取文本时,我无法查看图像。
以下是代码:
byte[] frontImage = (byte[])imageReader["front_image"];
MemoryStream frontMS = new MemoryStream(frontImage);
Image front = Image.FromStream(frontMS);
Bitmap frontBitmap = new Bitmap(front);
Bitmap bwFront = ConvertToBitonal(frontBitmap);
bwFront.SetResolution(200, 200);
MemoryStream newFrontMS = new MemoryStream();
bwFront.Save(newFrontMS, ici, ep);
bwFront.Save("c:\\Users\\aarong\\Desktop\\C#DepositFiles\\" + checkReader["image_id"].ToString() + "f.tiff", ici, ep);
frontImage = newFrontMS.ToArray();   
String frontBinary = toASCII(frontImage); 

private String toASCII(byte[] image)
{
    String returnValue = "";
    foreach (byte imageByte in image)
    {
        returnValue += Convert.ToChar(imageByte);
    }
    return returnValue;
}   

正在写入的是frontBinary。有人知道哪里出了问题吗?保存的TIFF格式是正确的,但完全相同的字节数组,在写成ASCII文本时没有被正确地写入。

谢谢。

编辑 通过使用BinaryWriter(byte[])正确地将图像写入文本,该问题已得到解决。 感谢大家的帮助!

5个回答

17

首先,ASCII 只有七位。但是,我不认为您的代码实际上使用 ASCII。它隐式地使用了 ISO-8859-1。

永远不要将文本视为二进制或反之亦然。这 总是会导致问题。

将二进制转换为 ASCII 文本的最佳方法是使用 Base64:

string text = Convert.ToBase64String(frontImage);
byte[] data = Convert.FromBaseString(text);

另外请注意,如果您的代码确实能工作,它仍然会非常低效 - 请了解一下StringBuilder,然后考虑一下您的代码与其半等价。

Encoding.GetEncoding(28591).GetString(data);

不过,base64绝对是在文本和二进制数据之间无损转换的最佳选择。当然,你需要将其转换回二进制以便再次查看TIFF。

请注意,您尚未显示如何保存或加载数据-您可能也会遇到问题。实际上,我怀疑如果您能够准确地保存字符串,可能已经有幸保留了数据,具体取决于您对其进行的操作...但无论如何,请使用base64。


嗨Jon,非常感谢您的解释。还要感谢您提供有关StringBuilders的信息...我一定会使用它们,而不是我的无谓低效的连接。我很快就会尝试您的建议,并告诉您结果如何。 - Aaron
嗨Jon,我再次向您问好。我要发送文件的供应商刚刚告诉我,base64不是正确的格式,而应该使用“Intel格式”。我的联系人告诉我,文本应该以“II”开头,这就是我使用旧方法时的情况。如果我回到旧方法,文本仍然不正确。我正在使用StreamWriter对象实际写入文件,并且我进行了一些研究,发现可能BinaryWriter是正确的选择。也许这是一个潜在的问题? - Aaron
看看能否得到一个绝对精确的文件格式 - 不仅仅是名称,而是完整的规范。如果它被认为是一个文本文件,那么它不应该包含任意的二进制数据位。 - Jon Skeet
嗨,Jon。我使用了BinaryWriter.Write(byte[])将图像写入了.data文件和.tiff文件。我使用Beyond Compare比较了这两个文件,它们没有任何区别。为了确认,我回到了之前的写图像方式,发现有很多不同之处。希望现在我已经正确地写入了这张图片。再次感谢您的帮助!当C#深度第二版出版时,我一定会购买的 :)。 - Aaron
太好了。谢谢你提供的信息!我会告诉你一切进展如何。 - Aaron
显示剩余5条评论

0
将二进制数据转换为文本数据的一种方法是使用StreamReader并提供所需的编码。正如Jon上面提到的那样,使用ASCII是不明智的,但是如果有人确实想要将二进制流传输到其他文本编码中,这里有一些代码可以实现。
public static String GetString(System.IO.Stream inStream)
{
    string str = string.Empty;
    using (StreamReader reader = new StreamReader(inStream, System.Text.ASCIIEncoding.ASCII)) // or any other encoding.
    {
        str = reader.ReadToEnd();
    }
    return str;
}

2
不,那仍然是一个非常糟糕的想法 - 因为文本和二进制数据就像这样不能很好地一起使用,特别是在使用ASCIIEncoding时,它会清除每个字节的最高位。 - Jon Skeet
我只是提供了他所要求的二进制数据转换为ASCII码,而不对目的或最终结果进行评判。 - Will Charczuk
虽然我认为如果我知道这样做会丢失数据(甚至没有说它会发生),给某人完全按照他们的要求提供服务并不是一个好主意。显然,这与OP的更大目标背道而驰。 - Jon Skeet
理解想要将无用或垃圾帖子从某处清除的心情,我会清理此帖以展示如何流式传输任何二进制到文本编码,尽管在这种情况下ASCII是不好的。 - Will Charczuk

0

你使用文本而不是二进制文件有特定的原因吗?

将二进制数据存储在文本文件中总是一个坏主意,因为编码可能会将字节转换为另一种表示形式,并且像换行符这样的特殊字符也可能被特殊处理和转换。

要么将数据作为字节数组存储在二进制文件中,要么使用适当的二进制到ASCII转换,例如Jon的Base64提案,或者可能使用逗号分隔的十六进制值列表。


0

如果您只是将图像数据写入文件,则根本不应将其写为文本,而应将其写为二进制数据。

如果您在文件中混合使用文本和二进制数据,则不应将二进制数据转换为文本。它可能适用于某些特定的编码方式来回转换,但肯定无法使用任何编码方式将其转换为Unicode字符(使用Convert.ToChar)。

请采用另一种方法。使用适当的Encoding对象的GetBytes方法将文本编码为二进制数据,以便您只有二进制数据可写入文件。


将二进制数据转换为文本,使用base64(或类似的方法 - 例如,您可以使用base16)是可以的。听起来输出必须是另一个工具可以加载的记录格式 - 这表明他无法真正定义整个文件格式,因为这会建议更改为以二进制形式编写所有内容。 - Jon Skeet

0

你可能正在以Unicode格式读取数据库,这将改变图像中的某些二进制值。

您可以使用System.IO.File类上的方法以二进制和文本形式进行读取/保存。这些方法可能会与上述Base64选项一起帮助解决问题。


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