IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Remplir un PictureBox avec une image extraite d'un fichier


Sujet :

C#

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 10
    Points : 5
    Points
    5
    Par défaut Remplir un PictureBox avec une image extraite d'un fichier
    Hello !
    Je coince sur un souci que j'ai déjà eu en Delphi il y a... 3 ans !

    J'ai un fichier qui contient une image, noyée au milieu d'autres infos, une map TrackMania pour être précis.
    Je souhaite extraire cette image pour l'afficher dans un picturebox.
    Voilà mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
            private void LoadMap_Click(object sender, EventArgs e)
            {
                openMap.Filter = "TM² Map|*.Map.Gbx|TM Map|*.Challenge.Gbx";
                openMap.Title = "Choose your map.";
                if (openMap.ShowDialog() == DialogResult.OK)
                {
                    StreamReader Map = new
                    StreamReader(openMap.FileName);
                    //Extraction de Thumbnail.jpg
                    pictureCustom.Image = Image.FromStream(ExtractThumbnail(Map));
     
                }
            }
            private MemoryStream ExtractThumbnail(StreamReader Map)
            {
                    string MapText = Map.ReadToEnd();
                    int first = MapText.IndexOf("<Thumbnail.jpg>") + 15;
                    int last = MapText.LastIndexOf("</Thumbnail.jpg>");
                    string stringImage = MapText.Substring(first, last - first);
                    byte[] byteArray = Encoding.ASCII.GetBytes(stringImage);
                    MemoryStream streamImage = new MemoryStream(byteArray);
                    streamImage.Seek(0, 0);
                    return streamImage;
            }
    Aucune erreur dans l'éditeur, juste une exception non gérée ou une histoire de paramètre invalide.
    L'idée est de faire fichier -> stream -> string -> stream -> image.
    Il y a peut être plus simple...

    J'avais déjà codé le tout sous Delphi il y a 3 ans mais j'ai paumé tout mon code source pour pouvoir le modifier.

    Je pense que j'aurais le problème inverse dans un moment puisque je devrais prendre le contenu d'un picturebox pour l'insérer dans le fichier à la place de l'image originale...

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Oulà, ça a l'air bizarre ton histoire...

    C'est un fichier XML ? Dans ce cas utilise un parseur XML, plutôt qu'un IndexOf sur le texte...

    Sous quelle forme est l'image dans le fichier ? Ca m'étonnerait qu'elle soit en ASCII, on ne peut pas représenter des données binaires arbitraires en ASCII... ce serait pas encodé en base64 ? Poste un exemple de la partie du fichier qui t'intéresse, qu'on y voit plus clair

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Pas d'entête XML à proprement parler, bien qu'en PHP j'utilise un parser XML pour récupérer une partie des infos.
    L'image est brute dans le fichier. La partie Thumbnail.jpg se contente de poser le début et la fin du flux de l'image.

    Voilà un fichier d'exemple : http://www.dabeuliou.com/SecondRun.Map.Gbx

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    OK je vois... c'est vraiment crado comme format
    Le problème c'est que tu ne peux pas passer par une string pour lire les données : toutes les valeurs d'octets ne correspondent pas forcément à des caractères valides, que ce soit en ASCII ou dans un autre encodage. Tous les caractères non reconnus seront remplacés par "?" dans la chaine de caractères, et donc tu perdras des informations.

    Pour faire ça proprement, il faut chercher le début et la fin de l'image en binaire, donc sans utiliser le StreamReader. Voilà un bout de code qui fonctionne pour le fichier que tu as indiqué :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    static Image GetMapThumbnail(string mapPath)
    {
        using (var stream = File.OpenRead(mapPath))
        {
            var startBytes = Encoding.ASCII.GetBytes("<Thumbnail.jpg>");
            var endBytes = Encoding.ASCII.GetBytes("</Thumbnail.jpg>");
            long startIndex = FindBytes(stream, startBytes) + startBytes.Length;
            long endIndex = FindBytes(stream, endBytes);
            int length = (int)(endIndex - startIndex);
            var bytes = new byte[length];
            stream.Position = startIndex;
            stream.Read(bytes, 0, length);
            var ms = new MemoryStream(bytes);
            var img = Image.FromStream(ms);
            return img;
        }
    }
     
    static long FindBytes(Stream stream, byte[] bytes)
    {
        for (long i = stream.Position; i < stream.Length; i++)
        {
            for (int j = 0; j < bytes.Length; j++)
            {
                if ((byte)stream.ReadByte() != bytes[j])
                    break;
                if (j == bytes.Length - 1)
                    return i;
            }
            stream.Position = i + 1;
        }
        return -1;
    }
    A noter quand même, cette technique n'est pas terriblement performante... on est tout le temps obligé de revenir en arrière dans le flux, ce qui est assez couteux. Pour bien faire il faudrait utiliser un système de cache, mais c'est pas très simple...

    La lib Dvp.NET contient une méthode IndexOfSequence qui permet de chercher une sous-séquence sans jamais revenir en arrière; en combinant ça avec la méthode d'extension AsByteEnumerable (qui renvoie un IEnumerable<byte> à partir d'un flux), il y a peut-être moyen de faire un truc un peu plus performant... à tester !

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Il faut que je reprenne mes travaux précédents.
    Je suis capable de trouver la taille de l'image et l'offset de début de cette image. Je vais regarder si ce n'est pas plus simple dans ce sens là.
    Et ça cadrerait avec ta fonction puisqu'en connaissant la taille de l'image, on peut tout extraire d'un bloc.

    Je vais essayer de tout basculer en Hexa, d'extraire mes infos et de les transformer en flux lisible pour ce que je veux en faire.

    Merci !

    C'est vraiment bête d'avoir perdu les sources précédentes, j'avais trouvé tout ce qu'il fallait et j'aurais pu convertir le Delphi en C#...

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Problème résolu

    Merci BinaryReader !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    private void LoadMap_Click(object sender, EventArgs e)
            {
                openMap.Filter = "TM² Map|*.Map.Gbx|TM Map|*.Challenge.Gbx";
                openMap.Title = "Choose your map.";
                if (openMap.ShowDialog() == DialogResult.OK)
                {
                    FileStream Map;
                    BinaryReader MapHex;
                    byte[] MapHexBuffer;
     
                    Map = new FileStream(openMap.FileName,FileMode.Open);
                    MapHex = new BinaryReader(Map);                
                    Map.Position = 856;
                    MapHexBuffer = MapHex.ReadBytes(6922);
                    MemoryStream streamImage = new MemoryStream(MapHexBuffer);
                    Image FlipMap = Image.FromStream(streamImage);
                    FlipMap.RotateFlip(RotateFlipType.RotateNoneFlipY);
                    pictureMap.Image = FlipMap;
                }
            }
    Ce n'est pas encore dynamique (position du début de l'image et taille de celle ci) mais ça va venir
    J'ouvre le fichier, je le lis avec BinaryReader. Ensuite je positionne le pointeur au début du flux brut de l'image et je le lis jusqu'à la fin.
    J'ai donc un tableau de Bytes qui rentre ensuite parfaitement dans un Image.FromStream.
    Une symétrie verticale parce que l'image est stockée à l'envers et voilà le travail !

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Ah oui c'est sûr que si tu connais les positions de début et de fin c'est plus facile... celà dit tu n'avais pas besoin d'un BinaryReader pour ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    byte[] buffer = new byte[6922];
    using (Stream stream = File.OpenRead(path)
    {
        stream.Position = 856;
        stream.Read(buffer, 0, buffer.Length);
    }
    MemoryStream ms = new MemoryStream(buffer);
    Image img = Image.FromStream(ms);
    Par contre je suis curieux de savoir pourquoi l'image est stockée à l'envers

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 10
    Points : 5
    Points
    5
    Par défaut
    Ce sont les concepteurs du jeu qui sont aussi parfois à l'envers
    Je leur demanderais, mais comme on est en plein bêta test du jeu (qui sort le 14/09) je vais attendre un peu

    Je vais garder ta solution sous le coude parce qu'il me reste encore pas mal à faire et que ça risque de me donner des idées.
    Je raisonne beaucoup trop en hexadécimal en fait... du coup j'ai tendance à rendre les choses complexes

    Finalement c'est sympa C#, on peut faire pas mal de choses en peu de ligne de code.
    Je n'avais pas retouché à la programmation (hors PHP) depuis Delphi 6 et encore avant de l'assembleur sous NASM... c'est dire.

    Merci pour ton aide en tout cas !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Renommer un fichier texte avec une chaine extraite de ce fichier
    Par sebariaz dans le forum Scripts/Batch
    Réponses: 0
    Dernier message: 28/03/2013, 20h18
  2. Remplir un tableau avec une image
    Par happyboon dans le forum Balisage (X)HTML et validation W3C
    Réponses: 1
    Dernier message: 16/10/2012, 13h48
  3. Remplir page A4 avec une image
    Par flamel dans le forum Word
    Réponses: 3
    Dernier message: 18/03/2012, 21h01
  4. Réponses: 1
    Dernier message: 11/10/2011, 22h38
  5. Remplir un Bouton avec une Image
    Par vandrie dans le forum IHM
    Réponses: 1
    Dernier message: 15/10/2007, 05h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo