none
Icon verliert Transparenz RRS feed

  • Frage

  • Hallo

    Ich habe ein Programm geschrieben, in dem ich Icons verwende.
    Diese Icons kann der Benutzer auf verschiedene Wege in das Programm laden.
    Diese Icons werden dann von mir in Textform gespeichert und eben bei Bedarf
    aus diesem Text zurück geladen und angezeigt.

    Die Quellen für die Icons sind hierbei unter anderem:

    • Icon Datei direkt von der "Festplatte" laden über OpenFileDialog (Nur! *.ico Files)
    • Icon von einer Webseite extrahieren (FavIcon)

    Soweit funktioniert das genau so wie es soll und die Icons werden sowohl im Datagrid,
    also auch in PictureBoxen richtig angezeigt

    Nun wollte ich die Iconquelle noch um einen Punkt erweitern und auch die Möglichkeit bieten,
    Icons auch von *.exe Dateien auszulesen bzw. eben das Systemicon zu einer Datei zu verwenden.

    Nun habe ich eben das Icon bei einer nicht Icondatei mit 

    Icon.ExtractAssociatedIcon(IconPath)

    ausgelesen und ganz genau so verwendet wie die anderen Icons auch.
    Das ganze Funktioniert an sich auch genau so wie es soll.
    Allerdings nur so lange, bis ich die Icons wieder neu lade, also aus dem gespeichertem String heraus.
    Dann nämlich verliert das Icon scheinbar seine Transparenz und wird mit schwarzem Hintergrund angezeigt.

    Ich habe hierbei jetzt natürlich selber schon im Internet geschaut, aber nicht wirklich eine passende Hilfe bzw. Lösung gefunden.

    Ich habe schon versucht:

    • Das Icon mit SHGetFileInfo zu laden 
    • Die extrahierten Icons über Bitmap neu zu erstellen, sogar neu zu zeichnen
    • Das Icon nach der Extraktion gleich mal zu speichern und dann das Icon neu zu laden

    Alles mit dem gleichen (miss)Erfolg, die Transparenz bleibt weg und der Hintergrund schwarz.
    Ich bekomme einfach nicht heraus warum und auch an welcher Stelle das passiert.
    Wird das Icon schon "falsch" extrahiert, also anders als die "original" Icondateien,
    oder liegt es an irgend einem Zwischenschritt.

    Zum umwandeln in einen String und zurück verwende ich folgende Funktionen:

           public static string GetImageAsString(System.Drawing.Icon ico)
            {
                string ret = null;
    
                if (ico != null)
                {
                    System.Drawing.IconConverter ic = new System.Drawing.IconConverter();
                    ret = Convert.ToBase64String(((byte[])ic.ConvertTo(ico, typeof(byte[]))), Base64FormattingOptions.InsertLineBreaks);
                }
                return ret;
            }
    
            public static System.Drawing.Icon GetImageFromString(String Stream)
            {
                if (Stream != null && Stream != string.Empty)
                {
                    byte[] buffer = Convert.FromBase64String(Stream);
                    System.Drawing.IconConverter ic = new System.Drawing.IconConverter();
                    return ic.ConvertFrom(buffer) as System.Drawing.Icon;
                }
                else
                    return null;
            }

    Bleibt noch zu sagen, dass ich immer das Original Icon speichere, also nicht bearbeitet,
    oder schon mal Konvertiert. Weil manchmal brauche ich es halt als Bitmap, oder eben in einer bestimmten Größe.
    Hierzu macht man dann eben zum Beispiel mal:

    (new System.Drawing.Icon(_Ico, new System.Drawing.Size(16, 16)).ToBitmap();
    Icon wico = new System.Drawing.Icon(ico, new System.Drawing.Size(16, 16));


    Jetzt hoffe ich halt, dass mir hier jemand helfen kann.
    Sei es weil er das Problem kennt, oder eben eine Vermutung hat.
    (Vielleicht auch "nur" wie ich das Icon wieder "reparieren" kann.)

    Wie auch immer, so bin ich auch wie immer für jegliche Hilfe dankbar.

    Habt schon jetzt vielen Dank
    Gruß
    Christian 



    Freitag, 22. Juni 2018 00:07

Alle Antworten

  • Hallo Christian.

    Nimmst Du dabei eine eigene Anwendungsdatei (*.exe) und hast vorher ein dir bekanntes Icon als Resource angefügt?

    Bist Du sicher, dass bei den anderen Icons die Transparenz erhalten bleibt? Möglich wäre auch, dass dort nur zufällig eine passende Transparenzfarbe gewählt wurde, bei der ein Transparenzverlust, bei dem von dir gewählten Hintergrund nicht auffällt.


    - Gruß Florian

    Freitag, 22. Juni 2018 08:18
  • Hallo Florian

    Ich habe sowohl eigene, also auch Systemanwendungen versucht, wie z.B. das Icon von explorer.exe.
    Auch hier wird nach der Umwandlung in String und zurück der Hintergrund schwarz.

    Wie gesagt aber eben nur bei den so ausgelesenen Icons. Sowohl die aus der EXE,
    wie aber auch die wenn z.B. das Icon für eine Textdatei ausgelesen wird.

    Ich stelle aber gerade fest, dass ich zumindest bei der Verwendung von ExtractAssociatedIcon
    sehr wohl das Icon umwandle, weil es eben sonst "immer" zu groß ist, also nicht 16*16.
    Habe gestern einfach zu viel ausprobiert, da ist das unter gegangen.
    Allerdings beim verwenden von SHGetFileInfo nehme ich das Icon, ohne Umwandlung
    und auch hier das gleiche Resultat mit schwarzem Hintergrund.

    Wohl gemerkt noch mal, erst nach dem neu laden aus dem String.
    Bei direktem verwenden ist alles OK.

    Hier also mal die Varianten.

    return System.Drawing.Icon.FromHandle(new Bitmap(Icon.ExtractAssociatedIcon(IconPath).ToBitmap(), 16, 16).GetHicon());
    
    return new Icon(Icon.FromHandle(Icon.ExtractAssociatedIcon(IconPath).Handle), 16, 16);

    Wobei nur die erste Zeile überhaupt einen Erfolg für die Größe gibt und ich mag mich täuschen,
    auch einen Verlust der Qualität, weil eben das Bild einfach grafisch verkleinert wird und eben nicht
    das passende Icon ausgelesen wird.
    Die zweite Zeile ändert gar nichts, das Icon bleibt groß.

    Dann halt noch die Variante über SHGetFileInfo 

            private const uint SHGFI_ICON = 0x100;
            private const uint SHGFI_LARGEICON = 0x0; // Large icon
            private const uint SHGFI_SMALLICON = 0x1; // Small icon
    
            [StructLayout(LayoutKind.Sequential)]
            private struct ShellFileInfo
            {
                public IntPtr hIcon;
                public IntPtr iIcon;
                public uint dwAttributes;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string szDisplayName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
                public string szTypeName;
            };
    
            [DllImport("shell32.dll")]
            private static extern IntPtr SHGetFileInfo(string filePath, uint dwFileAttributes, ref ShellFileInfo psfi, uint cbSizeFileInfo, uint uFlags);
    
            [System.Runtime.InteropServices.DllImportAttribute("SHELL32.dll")]
            private static extern IntPtr ExtractIcon(int hInstance, string fileName, int iconIndex, uint uFlags);
    
    
            public static Icon GetIcon(string FullFilePath)
            {
                return GetIcon(new FileInfo(FullFilePath));
            }
    
            public static Icon GetIcon(FileInfo fileInfo)
            {
                Icon ret = null;
                ShellFileInfo shinfo = new ShellFileInfo();
                IntPtr smallImg = SHGetFileInfo(fileInfo.FullName, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI_ICON | SHGFI_SMALLICON);
                ret =(Icon) Icon.FromHandle(shinfo.hIcon).Clone();
    
                return ret;
            }

    Diese Variante ist mir im Moment auch lieber, weil ich eben das Icon gleich in 16*16 und anscheinend
    originaler / guter Qualität bekomme, ohne umwandeln.
    Nur wie gesagt, nach dem Speichern und Laden das Problem mit dem schwarzen Hintergrund.

    Danke und Gruß
    Christian 


    Freitag, 22. Juni 2018 10:51
  • Hallo noch mal.

    Also ich habe nun noch mal ganz schön rumprobiert und geforscht.
    Probleme habe ich wie schon gesagt und vermutet, nur mit den Icons,
    die ich vom "System" auslesen lasse, also entweder über SHGetFileInfo,
    oder eben über ExtractAssociatedIcon
    Wobei ich jetzt mal davon ausgehe, dass ExtractAssociatedIcon eh intern dann
    die SHGetFileInfo Funktion verwendet.
    Die Umwandlung in einen String, über einen Stream hat auf eingelesene Icons
    über Datei laden von der Festplatte keinen Einfluss, sie bleiben immer gleich.
    Auch mit verschiedenen Hintergründen getestet und erneutem abspeichern und
    in einem Viewer betrachten.

    Allerdings ist es aber eben bei den Extrahierten Icons definitiv so, dass sie scheinbar
    schon "defekt", oder in einer abgespeckten Version geliefert werden.
    Denn wenn ich diese auslese und ohne Umwege sofort auf die Festplatte speichere,
    dann hat die gespeicherte Version schon schwarzen Hintergrund und Qualitätsverlust.

    Da ich mit diesen Icons aber wenn ich sie nicht speicher, sie normal anzeigen lassen kann,
    ohne Probleme und Verluste, liegt es scheinbar an der Umwandlung in einen Stream.
    Denn das ist das einzige, was sowohl beim Speichern, als auch beim Umwandeln in einen
    String immer gemacht werden muss.
    Entweder werden hier Informationen nicht mit umgewandelt, oder aber fehlende Informationen
    kommen hierdurch dann erst zum tragen.

    Wo nun genau der "Verlust" Stattfindet, konnte ich eben noch nicht herausfinden.
    Auch und das ist halt viel schlimmer, habe ich keine Speichermethode, die eben funktioniert gefunden.
    Weil selbst die Icon.Save() Methode macht ja das gleiche Problem, auf Grund des zu verwendenden Streams. Auf diese Weise kann man das halt auch ganz leicht nachvollziehen, einfach Icon mit z.B. ExtractAssociatedIcon auslesen und dann mit Icon.Save() abspeichern.
    Dann sollte man in dem gespeicherten Icon die Verluste schon in der Vorschau erkennen.
    Ob man nun die Extrahierten Icons reparieren/modifizieren kann, dass sie der Umwandlung in einen Stream standhalten, da hätte ich nicht mal einen Ansatz, denn mit Grafikformaten und deren Aufbau habe ich mich einfach noch nie beschäftigt. Vielleicht muss man auch spezielle Streams verwenden, oder sie speziell einstellen, ich weiß es nicht und habe es bisher auch nicht herausfinden können.

    In sofern bin ich also immer noch für jegliche Hilfe dankbar, die mich vielleicht weiter bringt.

    Vielen Dank und Gruß
    Christian 



    Montag, 25. Juni 2018 11:06