Domanda

Ricevo dei file xml con incorporato con codifica base64 immagini, che ho bisogno di decodificare e salvare come file.

Un non modificato (oltre zippato) esempio di un file può essere scaricato qui di seguito:

20091123-125320.zip (60 KB)

Tuttavia, ottenere gli errori come "lunghezza non valida per Base-64 array di char" e "carattere non Valido in una stringa Base 64".Ho segnato la linea di codice in cui ricevo un errore nel codice.

Un file potrebbe assomigliare a questo:

<?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>

E il codice del processo come questo:

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
        }

I dati xml da un'impresa di giornale sistema, quindi sono abbastanza sicuro che i file sono ok - e ci deve essere qualcosa nel modo di trattarli, che è semplicemente sbagliato.Forse un problema con la codifica?

Ho provato a scrivere il contenuto di mediaObjectNode.InnerText, ed è codificato base64 dati, così la navigazione xml-doc non è il problema.

Sono stato googling, abbuffate, stackoverflowing e piangere - e non ha trovato soluzione...Aiuto!

Edit:

Aggiunto un esempio reale di file (e un bounty).Siete pregati di notare che il file scaricabile è un po ' diverso schema, dato che ho semplificato nell'esempio di cui sopra, la rimozione di roba inutile...

È stato utile?

Soluzione

Per un primo colpo non ho usato qualsiasi linguaggio di programmazione, solo Notepad ++

Ho aperto il file XML all'interno e copiare e incollato il contenuto Base64 grezzo in un nuovo file (senza parentesi quadre).

In seguito ho selezionato tutto (Ctrl-A) e utilizza l'opzione Estensioni - Mime Strumenti - Base64 decodifica. Questo ha gettato un errore circa la lunghezza del testo sbagliata (deve essere mod 4). Così ho appena aggiunto due segni di uguale ( '=') come segnaposto alla fine per ottenere la lunghezza corretta.

Un altro dei tentativi e decodificato con successo in 'qualcosa'. Basta salvare il file in formato .jpg e si apre come un fascino in qualsiasi visualizzatore di immagini.

Quindi direi, c'è qualcosa di sbagliato con i dati che si ottengono. Essi semplicemente non hanno i numeri giusti di segni di uguale, alla fine di riempire fino a un certo numero di segni che possono essere rompere in pacchetti di 4.

Il modo più 'facile' sarebbe quella di aggiungere il segno di uguale fino alla decodifica non genera un errore. Il modo migliore sarebbe quello di contare il numero di caratteri (meno CR / LFS!) E aggiungere quelli necessari in un unico passaggio.

Ulteriori indagini

Dopo un po 'la codifica e la lettura di la funzione di conversione , il problema è un allegando sbagliata di un segno uguale dal produttore. ++ Notepad non ha alcun problema con tonnellate di segni di uguale, ma la funzione Convert da MS funziona solo con lo zero, uno o due segni. Quindi, se si riempie il già esistente con l'aggiunta di segni uguali si ottiene un errore troppo! Per ottenere questo dannato a lavorare, è necessario tagliare tutti i segni esistenti, calcolare quanto sono necessari e aggiungerli nuovamente.

Proprio per la generosità, qui è il mio codice (non assoluta perfetto, ma sufficiente per un buon punto di partenza):; -)

    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);
    }

Altri suggerimenti

La stringa base64 non vale come Oliver ha già detto, la lunghezza della corda deve essere multipli di 4 dopo rimozione caratteri spazio bianco. Se si guarda poi alla fine della stringa base64 (vedi sotto) si vedrà la linea è più corta rispetto al resto.

RRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

Se si rimuove questa linea, il programma funzionerà, ma l'immagine risultante avrà una sezione mancante nell'angolo in basso a destra. Hai bisogno di pad di questa linea in modo che la lunghezza complessiva stringa è corect. Da miei calcoli, se tu avessi 3 caratteri dovrebbe funzionare.

RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX//Z=

rimuovere ultimi 2 caratteri, mentre l'immagine non e ' corretto

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;
    }

Prova a usare 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);
        }
    }
}

UPDATE:

Dopo aver scaricato il file XML e analizzare il valore del nodo media-object è chiaro che non si tratta di una stringa base64 valida:

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

getta un System.FormatException dicendo che la lunghezza non è una base di 64 stringa valida. Evento quando rimuovo il \n dalla stringa che non funziona:

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);
}

tiri anche System.FormatException.

Ho anche avuto un problema con Base64 decodifica stringa dal documento XML (in particolare Ufficio OpenXML documento pacchetto) codificati.

Si è scoperto che aveva stringa di codifica supplementare applicato: la codifica HTML, così facendo prima decodifica HTML e quindi Base64 decodifica ha fatto il trucco:

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

Nel caso in cui qualcun altro inciampa sulla stessa questione.

Bene, è tutto molto semplice. CDATA è un nodo stesso, così mediaObjectNode.InnerText produce effettivamente <![CDATA[/9j/4AAQ[...snip...]P4Vm9zOR//Z=]]>, che non è ovviamente dati Base64 codifica validi.

Per far funzionare le cose, l'uso mediaObjectNode.ChildNodes[0].Value e passare tale valore al Convert.FromBase64String'.

Il personaggio è codifica corretta? L'errore suona come se ci fosse un problema che causa i caratteri non validi per appaiono nella matrice. Provare a copiare il testo e decodifica manualmente per vedere se i dati sono davvero validi.

(Per la cronaca, windows-1252 non è esattamente la stessa di iso-8859-1, in modo che possa essere la causa di un problema, salvo altre fonti di corruzione.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top