Laden...

Bild liegt als String vor, wie darstellen?

Erstellt von Nexus633 vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.959 Views
N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren
Bild liegt als String vor, wie darstellen?

Hallo´liebe leute,
ich stehe vor einem Problem. Ich habe ein Bild als String und möchte dieses Bild nun Darstellen. Ich habe schon einige ansätze probiert.

Fehlermeldung:
Fehler: Image.FromStream(ms); - Ungültieger Parameter

Das habe ich aktuell versucht:

Versuch 1.


byte[] imageBytes = Encoding.UTF8.GetBytes(Controller.LoadCpuImage());
byte[] byteArray = GetImageBytesFromOLEField(imageBytes);
using (MemoryStream ms = new MemoryStream())
{
    ms.Write(byteArray, 0, byteArray.Length);
    ms.Position = 0;
    ImageBoxCpu.Image = Image.FromStream(ms, false, false);
}

Versuch 2.


var result = String.Join("", Controller.LoadCpuImage().Select(b => b > '0' && b < '9' ? b.ToString() : String.Format(@"\u{0:x4}", b)));

byte[] imageBytes = Encoding.UTF8.GetBytes(result);

using (MemoryStream ms = new MemoryStream())
{
    ms.Write(imageBytes, 0, imageBytes.Length);
    ms.Position = 0;
    ImageBoxCpu.Image = Image.FromStream(ms);
}



 private byte[] GetImageBytesFromOLEField(byte[] oleFieldBytes)
        {

            const string BITMAP_ID_BLOCK = "BM";

            const string JPG_ID_BLOCK = "\u00FF\u00D8\u00FF";

            const string PNG_ID_BLOCK_HDR = "\u0089PNG\r\n\u001a\n\0\0\0\rIHDR\0\0\u0003";

            const string PNG_ID_BLOCK = "\u0089PNG\r\n\u001a\n";

            const string GIF_ID_BLOCK = "GIF8";

            const string TIFF_ID_BLOCK = "II*\u0000";



            byte[] imageBytes;



            // Get a UTF7 Encoded string version

            Encoding u8 = Encoding.UTF7;

            string strTemp = u8.GetString(oleFieldBytes);



            // Get the first 300 characters from the string

            string strVTemp = strTemp.Substring(0, 300);



            // Search for the block

            int iPos = -1;

            if (strVTemp.IndexOf(BITMAP_ID_BLOCK) != -1)

                iPos = strVTemp.IndexOf(BITMAP_ID_BLOCK);

            else if (strVTemp.IndexOf(JPG_ID_BLOCK) != -1)

                iPos = strVTemp.IndexOf(JPG_ID_BLOCK);

            else if (strVTemp.IndexOf(PNG_ID_BLOCK_HDR) != -1)

                iPos = strVTemp.IndexOf(PNG_ID_BLOCK_HDR);

            else if (strVTemp.IndexOf(GIF_ID_BLOCK) != -1)

                iPos = strVTemp.IndexOf(GIF_ID_BLOCK);

            else if (strVTemp.IndexOf(TIFF_ID_BLOCK) != -1)

                iPos = strVTemp.IndexOf(TIFF_ID_BLOCK);

            else if (strVTemp.IndexOf(PNG_ID_BLOCK) != -1)

                iPos = strVTemp.IndexOf(PNG_ID_BLOCK);

            else

                throw new Exception("Unable to determine header size for the OLE Object");



            // From the position above get the new image

            if (iPos == -1)

                throw new Exception("Unable to determine header size for the OLE Object");



            //Array.Copy(

            imageBytes = new byte[oleFieldBytes.LongLength - iPos];

            MemoryStream ms = new MemoryStream();

            ms.Write(oleFieldBytes, iPos, oleFieldBytes.Length - iPos);

            imageBytes = ms.ToArray();

            ms.Close();

            ms.Dispose();

            return imageBytes;

        }

Der String ist 24513 Zeichen lang daher werde ich nur einen ausschnitt anhängen-

"\u0089PNG\r\n\u001a\n\0\0\0\rIHDR\0\0\u0003 \0\0\0È\b\u0002\0\0\0\u009fí\u0012M\0\0\0\u0006bKGD\0ÿ\0ÿ\0ÿ ½§\u0093\0\0 \0IDATx\u009cí\u009d}P\u0014WºÿÏø\u0012\u008d0à*\u0013^6JF\u0083\u001a \u0098\u0014r£\u0094Ê\u0010ÄP[zoR˾äÞ-Öº%+\u001bcUÖìjîn\u0095\u00187u\u008dn¼\u009bÊÊ\u008dZhÝÕZ7Ù¤v\u0013\*¤¤Â\u0018(I)\u0094/\u0089¸ÃUæ\na\u0080À usw.... ... .... .... ... "

Wie kann ich das zu einem bild wandeln ?

Ich hoffe ihr könnt mir helfen.

LG

16.835 Beiträge seit 2008
vor 5 Jahren

Suchst Du das ?
Convert image path to base64 string
Das funktioniert auch wieder in die andere Richtung mit den gleichen Klassen (steht auch in dem Link).

Ansonsten solltest Du genauer erklären was Du willst.
Keiner hier kann an dem Ausschnitt erkennen, was der String wirklich darstellt.

N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Hallo,
danke für die schnelle Antwort. Nein das suche ich nicht. Ich bekomme mittels einer RestAbfrage ein Bild als string gesendet was das format hat was ich unten beschrieben hatte.

diesen string will ich als bild wieder datrstellen. Leider klappt es nicht. 😃

Mehr als den fehler ungültiger Parameter kann ich nennen da kein anderer fehler kommt.-
Bei deinem Link wird nach einer Datei gefragt. Wenn ich dort den string verwende, kommt folgender fehler - Ungültige Zeichen

N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Keiner hier kann an dem Ausschnitt erkennen, was der String wirklich darstellt.

der String ist knapp 25k zeichen lang, soll ich den wirklich posten ?

16.835 Beiträge seit 2008
vor 5 Jahren

Nein, sicher nicht; das habe ich auch nicht gesagt.
Aber da Du nicht sagen willst, was der String darstellt, muss ich raten und denken, dass das hier einfach eine Binärdarstellung eines Bildes ist - wie das ganze encodiert ist, ist dann nochmal ne andere Sache.

Sofern dessen Annahme richtig ist, dann bist Du prinzipiell auf dem korrekten Weg um mit Hilfe von GetBytes an das Bild zu kommen.
Ob Du UTF8 hier brauchst oder ASCII - weiß ich nicht; könnte natürlich auch Unicode sein. Aber REST spricht üblicherweise für UTF8.

Image.FromStream funktioniert zudem nur, wenn in dem Stream genau ein Bild drin steckt.
Sollten in dem String auch irgendwelche Header-Informationen stecken, dann müssten diese erst entfernt werden.
Und irgendwas steckt wohl zusätzlich zum eigentlich Bild drin - sonst würde es nicht knallen 😉

Aber da enden dann meine hellseherischen Kräfte um zu sagen, ob der String so valide ist bzw. welchen Teil des Strings Du brauchst.

PS: Warum hast Du denn das Bild überhaupt nur als String? Jeder REST Client sollte auch Binaries als Rückgabe anbieten können, wenn das Bild schon roh zurück kommt.

N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Ich habe die lösung gefunden. Das bild wird mir als string geben warum weiß ich nicht. Ich entwickel aktuell ein Proxmox Client. Proxmox gibt es mir so 😃

Ich habe aber festgestellt das



byte[] imageByte = response.Data.Image.Select(x => (byte)x).ToArray();
string base64String = Convert.ToBase64String(imageByte);

return Image.FromStream(new MemoryStream(Convert.FromBase64String(base64String)));

ausreicht. Die einfachsten dinge kommen immer zum schluss 😃

Ich danke dir dennoch für die anteilnahme. 😃

edit: das Base64 ist sinnlos 😃



byte[] imageByte = response.Data.Image.Select(x => (byte)x).ToArray();

return Image.FromStream(new MemoryStream(imageByte));

16.835 Beiträge seit 2008
vor 5 Jahren

Du wandelst ein Byte Array in einen String. Diesen String wieder in ein Byte Array und lädst davon das Bild.... 🤔
Verzichte doch auf das Base64? Das is vermutlich hier unnötig.

.Select(x => (byte)x).ToArray()

Wenn x bereits ein Byte ist, wovon ich hier ausgehe, ist auch das unnötig.
Der Code sagt quasi "nimm alle Bauklötze aus Kiste A und pack sie identisch wieder in Kiste B".

Reicht nicht..?

C#-Code:
byte[] imageByte = response.Data.Image;
return Image.FromStream(new MemoryStream(imageByte));
N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Nein leider reicht das nicht, das war das erste was ich probierte. Leider nimmt er das nicht. Ungültiger Parameter kommt als exception 😦

Das Base64 habe ich direkt nach dem Post entfernt und als edit nachgetragen.

C
2.121 Beiträge seit 2010
vor 5 Jahren

Kommen deine Daten wirklich als \u0089... String an oder zeigt das der Debugger so? Was für einzelne Zeichen sind in dem String?
Hast du den so abgespeichert wie er ist, als png Datei, und das dann angesehen? Ich glaube auch dass du da viel zu viel hin und her wandelst. Der Anfang deines Strings sieht aus wie eine textuelle Repräsentation eines png Bilds.
Woher ist die Funktion LoadCpuImage und welchen Rückgabetyp hat die?

In der Zeile var result = String.Join(.... setzt du ausdrücklich das Format \uxxxx, du machst also selbst eine Stringdarstellung von Binärdaten, machst dann aus den einzelnen Zeichen \ und u und was danach kommt wieder einen String und denkst dann das wäre dein Bild.

N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Der debugger zeigt mir den datenstrom so an.
ich habe das problem aber bereits gelöst. 😃

um es genacu zu zeigen


        public Image LoadCpuImage(List<FormatRrd> formatRrd, FormatRrdTime time = FormatRrdTime.hour, FormatRrdUsed formatRrdUsed = FormatRrdUsed.MAX)
        {
            string format= "";
            foreach (FormatRrd rrd in formatRrd)
                format+= rrd.ToString() + ',';
            var request = LoadImage($"nodes/ProxmoxApiServer/rrd", format, time.ToString(), formatRrdUsed.ToString());
            var response = RestClient.Execute<Rrd>(request);

            byte[] imageByte = response.Data.ImageByte;

            return Image.FromStream(new MemoryStream(imageByte));
        }

        private RestRequest LoadImage(string resource, string ds, string timeframe, string cf = null)
        {
            var request = new RestRequest(resource, Method.GET) { RequestFormat = DataFormat.Json };
            request.AddCookie("PVEAuthCookie", Ticket.ticket);
            request.AddParameter("ds", ds);
            request.AddParameter("timeframe", timeframe);
            if(cf != null)
                request.AddParameter("cf", cf);
            request.RootElement = "data";
            return request;
        }


    public class Rrd
    {
        
        public string Filename { get; set; }
        public string Image { get; set; }

        public byte[] ImageByte
        {
            get { return Image.Select(x => (byte)x).ToArray(); }
        }
    }

C
2.121 Beiträge seit 2010
vor 5 Jahren

Wenns funktioniert ist es schon mal gut. Aber Bilddaten haben wirklich nirgends etwas als String zu suchen.
Das hier

public string Image { get; set; }

verunsichert jeden der das liest. Auch dich in ein paar Monaten, wenn du ein besseres Verständnis von dem hast was du da tust..

N
Nexus633 Themenstarter:in
54 Beiträge seit 2015
vor 5 Jahren

Wenns funktioniert ist es schon mal gut. Aber Bilddaten haben wirklich nirgends etwas als String zu suchen.
Das hier

public string Image { get; set; }  

verunsichert jeden der das liest. Auch dich in ein paar Monaten, wenn du ein besseres Verständnis von dem hast was du da tust..

Nein haben Sie auch nicht, es wird aber als solches übergeben, daher


var response = RestClient.Execute<Rrd>(request);

speichert der RestClient es als String. Ich hätte es ja sonst direkt als Byte[] verarbeitet.
Ich verarbeite es weiter unten dann als Byte[]

16.835 Beiträge seit 2008
vor 5 Jahren

Was "Rrd" heissen soll weiß spätestens in zwei Tagen nur noch Du. 😉

Soll das ein Austauschobjekt zwischen API und Dir sein? Vermutlich würde da ein Name wie "PromoxRrdRequestResult besser passen.
[Artikel] C#: Richtlinien für die Namensvergabe
In diesem Fall sollten auch nur die Properties enthalten sein, die die Gegenseite wirklich schickt.
Sprich aus ImageByte sollte besser eine Methode sein, die GetImageAsBytes() heisst; oder als Erweiterungsmethode.
Du hast Glück dass RestClient so implementiert ist, dass er nicht vorhandene Properties ignoriert.

Für mich sieht das nicht nach einem REST Service aus, sondern nach einem stink normalen HTTP Service aus, der mit Json arbeitet.
Für REST ist schon mehr standardkonformes Arbeiten notwendig.

Hast Du ein Link zur API Spezifikation dieser Abfrage?
Vermute immer noch, dass hier mit dem String was im Argen ist - vielleicht aber auch in der Spezifikation; normalerweise würde man nie Bilder als String zurück geben.
Der RestClient kann auch problemlos, sofern es die API anbietet, mit Byte Arrays umgehen - ich verwende den RestClient auch 😉