5

我收到一些带有嵌入 base64 编码图像的 xml 文件,我需要对其进行解码并保存为文件。

可以在下面下载此类文件的未修改(压缩除外)示例:

20091123-125320.zip (60KB)

但是,我收到诸如“Base-64 字符数组的长度无效”和“Base-64 字符串中的无效字符”之类的错误。我在代码中标记了代码中出现错误的行。

文件可能如下所示:

<?xml version="1.0" encoding="windows-1252"?>
<mediafiles>
    <media media-type="image">
      <media-reference mime-type="image/jpeg"/>
      <media-object encoding="base64"><![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]></media-object>
      <media.caption>What up</media.caption>
    </media>
</mediafiles>

和这样处理的代码:

var xd = new XmlDocument();
xd.Load(filename);
var nodes = xd.GetElementsByTagName("media");

foreach (XmlNode node in nodes)
        {
            var mediaObjectNode = node.SelectSingleNode("media-object");
            //The line below is where the errors occur
            byte[] imageBytes = Convert.FromBase64String(mediaObjectNode.InnerText);
            //Do stuff with the bytearray to save the image
        }

xml 数据来自企业报纸系统,所以我很确定文件没问题——而且我处理它们的方式一定有问题,那是错误的。也许编码有问题?

我试过写出 mediaObjectNode.InnerText 的内容,它是 base64 编码的数据 - 所以导航 xml-doc 不是问题。

我一直在谷歌搜索、搜索、stackoverflowing 和哭泣——但没有找到解决方案……救命!

编辑:

添加了一个实际的示例文件(和一个赏金)。请注意,可下载文件的架构略有不同,因为我在上面的示例中对其进行了简化,删除了不相关的内容......

4

7 回答 7

9

第一次拍摄我没有使用任何编程语言,只使用了 Notepad++

我在其中打开了 xml 文件,并将原始 base64 内容复制并粘贴到一个新文件中(不带方括号)。

之后我选择了所有内容(Strg-A)并使用选项扩展 - 哑剧工具 - Base64 解码。这引发了关于错误文本长度的错误(必须是 mod 4)。所以我只是在最后添加了两个等号('=')作为占位符以获得正确的长度。

再次重试,它成功解码为“某物”。只需将文件另存为 .jpg 即可在任何图片查看器中打开它。

所以我想说,你得到的数据有问题。他们只是在末尾没有正确数量的等号来填充可以分成4包的多个符号。

“简单”的方法是添加等号,直到解码不会引发错误。更好的方法是计算字符数(减去 CR/LF!)并一步添加所需的字符。

进一步调查

在对转换函数进行了一些编码和阅读之后,问题是生产者错误地附加了等号。Notepad++ 对大量等号没有问题,但 MS 的转换功能仅适用于零、一个或两个符号。所以如果你用额外的等号填充已经存在的等号,你也会得到一个错误!为了让这该死的东西发挥作用,你必须切断所有现有的标志,计算需要多少并再次添加它们。

只是为了赏金,这是我的代码(不是绝对完美,但足以作为一个好的起点):;-)

    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (XElement element in elements)
        {
            var image = AnotherDecode64(element.Value);
        }
    }

    static byte[] AnotherDecode64(string base64Decoded)
    {
        string temp = base64Decoded.TrimEnd('=');
        int asciiChars = temp.Length - temp.Count(c => Char.IsWhiteSpace(c));
        switch (asciiChars % 4)
        {
            case 1:
                //This would always produce an exception!!
                //Regardless what (or what not) you attach to your string!
                //Better would be some kind of throw new Exception()
                return new byte[0];
            case 0:
                asciiChars = 0;
                break;
            case 2:
                asciiChars = 2;
                break;
            case 3:
                asciiChars = 1;
                break;
        }
        temp += new String('=', asciiChars);

        return Convert.FromBase64String(temp);
    }
于 2009-11-23T13:04:10.397 回答
1

正如 Oliver 所说,base64 字符串无效,删除空格字符后字符串长度必须是 4 的倍数。如果您查看 base64 字符串的结尾(见下文),您会看到该行比其他行短。

RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

如果删除此行,您的程序将运行,但生成的图像将在右下角缺少部分。您需要填充此行,以便整个字符串长度正确。根据我的计算,如果你有 3 个字符,它应该可以工作。

RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=
于 2009-11-23T16:17:37.467 回答
1

图像不正确时删除最后 2 个字符

public Image Base64ToImage(string base64String)
    {
        // Convert Base64 String to byte[]
        byte[] imageBytes=null;
        bool iscatch=true;
        while(iscatch)
        {
            try 
                {           
         imageBytes = Convert.FromBase64String(base64String);
         iscatch = false;

            }
            catch 
            {
                int length=base64String.Length;
                base64String=base64String.Substring(0,length-2);
            }
        }
        MemoryStream ms = new MemoryStream(imageBytes, 0,
          imageBytes.Length);

        // Convert byte[] to Image
        ms.Write(imageBytes, 0, imageBytes.Length);
        Image image = Image.FromStream(ms, true);
        pictureBox1.Image = image;
        return image;
    }
于 2013-10-21T12:31:10.170 回答
0

尝试使用 Linq to XML:

using System.Xml.XPath;

class Program
{
    static void Main(string[] args)
    {
        var elements = XElement
            .Load("test.xml")
            .XPathSelectElements("//media/media-object[@encoding='base64']");
        foreach (var element in elements)
        {
            byte[] image = Convert.FromBase64String(element.Value);
        }
    }
}

更新:

下载 XML 文件并分析media-object节点的值后,很明显它不是一个有效的 base64 字符串:

string value = "PUT HERE THE BASE64 STRING FROM THE XML WITHOUT THE NEW LINES";
byte[] image = Convert.FromBase64String(value);

抛出一个System.FormatException说法,即长度不是有效的 base 64 字符串。当我\n从字符串中删除它不起作用的事件:

var elements = XElement
    .Load("20091123-125320.xml")
    .XPathSelectElements("//media/media-object[@encoding='base64']");
foreach (var element in elements)
{
    string value = element.Value.Replace("\n", "");
    byte[] image = Convert.FromBase64String(value);
}

也抛出System.FormatException

于 2009-11-20T15:38:07.813 回答
0

我在从 XML 文档(特别是 Office OpenXML 包文档)中解码 Base64 编码字符串时也遇到了问题。

事实证明,字符串应用了额外的编码:HTML 编码,所以首先进行 HTML 解码,然后进行 Base64 解码就可以了:

private static byte[] DecodeHtmlBase64String(string value)
{
    return System.Convert.FromBase64String(System.Net.WebUtility.HtmlDecode(value));
}

以防万一其他人偶然发现同样的问题。

于 2013-12-06T13:46:42.977 回答
-1

好吧,这一切都很简单。CDATA本身就是一个节点,所以mediaObjectNode.InnerText实际上会产生<![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]>,这显然不是有效的 Base64 编码数据。

为了使事情正常工作,请使用mediaObjectNode.ChildNodes[0].Value该值并将其传递给Convert.FromBase64String'.

于 2009-11-20T15:36:20.693 回答
-2

字符编码是否正确?该错误听起来像是存在导致无效字符出现在数组中的问题。尝试复制文本并手动解码以查看数据是否确实有效。

(作为记录,windows-1252 与 iso-8859-1 并不完全相同,因此这可能是问题的原因,除非其他损坏源。)

于 2009-11-20T15:35:54.783 回答