代码之家  ›  专栏  ›  技术社区  ›  Junior

如何从MIME内容创建图像?

  •  3
  • Junior  · 技术社区  · 5 年前

    C# 在.NETCore2.2框架之上。

    我能够解析请求并获得每条消息的MIME正文。但是,我不知道如何使用正文的内容创建文件。

    下面是原始MIMI消息的开头示例 enter image description here

    我尝试将正文作为字符串写入文件,但没有成功

    string body = GetMimeBody(message);
    File.WriteAllText("image_from_string" + MimeTypeMap.GetExtension(contentType), bytes);
    

    byte[] 像这样,但仍然不起作用

    byte[] bytes = Encoding.ASCII.GetBytes(body);
    File.WriteAllBytes("image_from_ascii_bytes" + MimeTypeMap.GetExtension(contentType), bytes);
    
    byte[] bytes = Encoding.Default.GetBytes(body);
    File.WriteAllBytes("image_from_default_bytes" + MimeTypeMap.GetExtension(contentType), bytes);
    
    
    byte[] bytes = Encoding.UTF8.GetBytes(body);
    File.WriteAllBytes("image_from_utf8_bytes" + MimeTypeMap.GetExtension(contentType), bytes);
    

    “不工作”是指图像无法正确打开。照片查看器显示“图像似乎已损坏或损坏。”

    更新

    下面是代码和解析部分

    var responseContentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
    string splitter = string.Format("--{0}", GetBoundary(responseContentType));
    string content = await response.Content.ReadAsStringAsync();
    var messages = content.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
    
    foreach (var message in messages)
    {
        var mimiParts = message.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
        if (mimiParts.Length == 0)
        {
            continue;
        }
    
        string contentId = Str.GetValue("Content-ID", mimiParts, ':');
        string objectId = Str.GetValue("Object-ID", mimiParts, ':');
        string contentType = Str.GetValue("Content-Type", mimiParts, ':');
    
        if (string.IsNullOrWhiteSpace(contentId) || string.IsNullOrWhiteSpace(objectId) || string.IsNullOrWhiteSpace(contentType))
        {
            continue;
        }
    
        string body = mimiParts[mimiParts.Length - 1];
    
        var filename = string.Format("{0}_{1}{2}", contentId, objectId, MimeTypeMap.GetExtension(contentType));
    
        var decoded = System.Net.WebUtility.HtmlDecode(data);
        File.WriteAllText("image_from_html_decoded_bytes" + filename, decoded);
    }
    

    public class Str
    {
        public static string GetValue(string startWith, string[] lines, char splitter = '=')
        {
            foreach (var line in lines)
            {
                var value = line.Trim();
    
                if (!value.StartsWith(startWith, StringComparison.CurrentCultureIgnoreCase) || !line.Contains(splitter))
                {
                    continue;
                }
    
                return value.Split(splitter)[1].Trim();
            }
    
            return string.Empty;
        }
    }
    

    下面是一个屏幕截图,显示了 mimiParts 变量 enter image description here

    更新2

    MimeKit

    var responseContentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
    
    if (!ContentType.TryParse(responseContentType, out ContentType documentContentType))
    {
        return;
    }
    
    var stream = await response.Content.ReadAsStreamAsync();
    
    MimeEntity entity = MimeEntity.Load(documentContentType, stream);
    Multipart messages = entity as Multipart;
    
    if (messages == null)
    {
        throw new Exception("Unable to cast entity to Multipart");
    }
    
    foreach (MimeEntity message in messages)
    {
        string contentId = message.Headers["Content-ID"];
        string objectId = message.Headers["Object-ID"];
        string contentType = message.Headers["Content-Type"];
    
        if (string.IsNullOrWhiteSpace(contentId) || string.IsNullOrWhiteSpace(objectId) || string.IsNullOrWhiteSpace(contentType))
        {
            continue;
        }
    
        var filename = string.Format("{0}_{1}{2}", contentId, objectId, MimeTypeMap.GetExtension(contentType));
    
        message.WriteTo(filename);
    }
    
    2 回复  |  直到 5 年前
        1
  •  3
  •   jstedfast    5 年前

    MimeEntity.WriteTo (file) 不幸的是,将包括导致损坏错误的MIME头。

    您需要做的是将MimeEntity强制转换为MimePart,然后保存 解码 内容使用 MimePart.Content.DecodeTo (stream) :

    var responseContentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault();
    
    if (!ContentType.TryParse(responseContentType, out ContentType documentContentType))
    {
        return;
    }
    
    var stream = await response.Content.ReadAsStreamAsync();
    
    MimeEntity entity = MimeEntity.Load(documentContentType, stream);
    Multipart multipart = entity as Multipart;
    
    if (multipart == null)
    {
        throw new Exception("Unable to cast entity to Multipart");
    }
    
    foreach (MimePart part in multipart.OfType<MimePart> ())
    {
        string contentType = part.ContentType.MimeType;
        string contentId = part.ContentId;
        string objectId = part.Headers["Object-ID"];
    
        if (string.IsNullOrWhiteSpace(contentId) || string.IsNullOrWhiteSpace(objectId) || string.IsNullOrWhiteSpace(contentType))
        {
            continue;
        }
    
        var filename = string.Format("{0}_{1}{2}", contentId, objectId, MimeTypeMap.GetExtension(contentType));
    
        using (var output = File.Create (filename))
            part.Content.DecodeTo (output);
    }
    
        2
  •  2
  •   Alexander Gräf    5 年前

    MIME编码很难,将服务器发送的字节作为字符串处理已经是一个错误。在新线将其拆分会产生更多的问题。二进制表示0x00和0xff之间的每个值都有效。但是Unicode和ASCII有不同的有效字节范围,尤其是转换它们是有问题的。NET内部字符串类将每个字符解释为两个字节。HttpContent.ReadAsStringAsync运行时,它会尝试将从服务器接收到的每个单字节解释为双字节Unicode字符。我很确定你将无法从数据丢失中恢复。

    • 使用像HxD这样的十六进制编辑器将图像的一个好副本与您从应用程序中写出的图像进行比较,并寻找差异。至少如果你想坚持自己的代码。但我确信您仍然需要从字符串操作切换到流操作。
    • 使用已创建的MIME解析库。一个例子是 MimeKit

    作为参考,以下是JPG的前10个字节的样子:

    FF D8 FF E0 00 10 4A 46 49 46      ÿØÿà..JFIF