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++/CLI Discussion :

Récupérer une image depuis un IntPtr


Sujet :

C++/CLI

  1. #1
    Membre confirmé Avatar de Baud10
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2006
    Messages : 66
    Par défaut Récupérer une image depuis un IntPtr
    Bonjour,

    J'utilise la librarie FMOD pour lire des fichiers audio et j'aimerai récupérer les ID3 Tag v2. J'y arrive, mais je n'arrive pas a récupérer l'image (si elle existe) dans le fichier.

    Je sais qu'elle est enregistré dans un TAG appelé "APIC" et de type FMOD.TAGDATATYPE.BINARY.

    J'arrive a récupérer le FMOD.TAG qui est censé contenir la photo.
    tagphoto.datalen retourne 48108 (48 ko ça parait beaucoup pour un JPG de petite taille ?).

    Pour récupérer les tag string (artiste, album, titre), je dois faire: Marshal.PtrToStringAnsi(montag.data). Mais s'il s'agit d'un type BINARY je ne sais pas quoi faire.

    Je ne suis pas expert en la matière, si quelqu'un pouvait me donner un coup de pouce pour arriver jusqu'a une Image/Bitmap

    Pourquoi d'ailleurs, le site officiel parle du tag PIC au lieu de APIC? (http://www.id3.org/id3v2-00)

    Merci d'avance

  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
    Par défaut
    Il faudrait voir dans la documentation ce que représente ce IntPtr... ça pourrait par exemple être un HBITMAP (handle Windows pour une image), auquel cas tu pourrais récupérer l'image en faisant juste ça :

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    Image img = Image.FromHBitmap(montag.data);

    Si c'est l'addresse des données de l'image, je vois 2 options :

    - utiliser un UnmanagedMemoryStream et l'utiliser pour créer l'image avec Image.FromStream. Sans doute la solution la plus efficace, mais l'inconvénient c'est que ça utilise des pointeurs et que ça ne peut donc s'utiliser que dans du code unsafe

    - Copier les données dans un buffer managé avec Marshal.Copy, créer un MemoryStream sur ce buffer, et créer l'image avec Image.FromStream. Un peu moins rapide puisqu'il faut d'abord copier les données, mais plus sûr...

  3. #3
    Membre confirmé Avatar de Baud10
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2006
    Messages : 66
    Par défaut
    Le UnmanagedMemoryStream fonctionne. J'ai eu du mal mais ça fonctionne.

    J'avais tenté une alternative avec
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GCHandle gc = GCHandle.FromIntPtr(newtag.data);
    mais j'obtiens inévitablement l'erreur fatale
    ExecutionEngineException...
    Bref, mon gros souci maintenant est que avant l'image, je récupère le header, d'une taille variable (d'après mes observations soit 13, soit 14 octets, puis a ajouter a ça, une chaine allant jusqu'a 64 octets)... Je galère a trouver pourquoi des fois 13 et des fois 14 ^^

  4. #4
    Membre confirmé Avatar de Baud10
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Mai 2006
    Messages : 66
    Par défaut
    Je pense avoir résolu mes problèmes...
    Je poste mon code a toute fins utiles, j'imagine que vous en trouverez a redire...

    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
    34
    35
    36
    37
    38
    39
    unsafe
                            {
                                try
                                {
     
                                    // on recherche la présence du TAG APIC
                                    TAG newtag = GetTag("APIC", snd);
                                    if (newtag.datalen > 0 && newtag.datatype == TAGDATATYPE.BINARY) // il est présent et non vide
                                    {
                                        // on charge dans un flux le tag
                                        UnmanagedMemoryStream stream = new UnmanagedMemoryStream((byte*)newtag.data, newtag.datalen);
     
                                        // l'entête mesure au minimum 12 + une chaine (compise entre 0 à 63 octets + \0 final)
                                        int tailleEntete = 12, tailleChaine = 1;
     
                                        // on créé un tableau de travail qui contiendra le tag
                                        byte[] managed = new byte[newtag.datalen];
                                        // on charge le flux dans notre tableau
                                        stream.Read(managed, 0, (int)newtag.datalen);
                                        // si l'octet N°10 vaut 101, alors la taille de l'entête n'est pas 12 mais 13
                                        if (managed[9] == 101) tailleEntete = 13;
                                        // on essai de lire la suite après l'entête : la chaine
                                        stream.Seek(tailleEntete, SeekOrigin.Begin);
                                        // on cherche l'octet qui vaut zéro à partir de ce point, qui indique la fin de la chaine
                                        for (; tailleChaine < managed.Length; tailleChaine++)
                                        {
                                            if (stream.ReadByte() == 0)
                                                break;
                                        }
                                        // on créé un flux qui ne contiendra que l'image (sans l'entête du TAG)
                                        MemoryStream mem = new MemoryStream(managed, tailleEntete + tailleChaine, (int)newtag.datalen - (tailleEntete + tailleChaine));
                                        // on affiche le champ image
                                        image.Visible = true;
                                        // on rempli le champ image avec l'image contenue dans le flux
                                        image.Image = Image.FromStream(mem);
                                    }
                                }
                                catch (Exception ex) { MessageBox.Show("Impossible de charger la miniature"); }
                            }

  5. #5
    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
    Par défaut
    Citation Envoyé par Baud10 Voir le message
    J'avais tenté une alternative avec GCHandle gc = GCHandle.FromIntPtr(newtag.data); mais j'obtiens inévitablement l'erreur fatale ExecutionEngineException...
    oula... GCHandle c'est un handle du garbage collector vers un objet managé. Ca n'a rien à voir avec un pointeur de mémoire non managée.... Donc forcément ça risque pas de marcher

    Sinon, j'ai pas analysé ton code en détail, mais pense à refermer les Streams que tu crées... le plus simple c'est de les utiliser dans un bloc using, comme ça tu es sûr qu'ils sont refermés même en cas d'erreur

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

Discussions similaires

  1. Récupérer une image depuis le systeme de fichier
    Par momedalhouma dans le forum JSF
    Réponses: 5
    Dernier message: 18/06/2014, 02h31
  2. Réponses: 3
    Dernier message: 06/08/2013, 12h43
  3. [MySQL] Récupérer une image depuis phpMyAdmin
    Par bonomsoleil dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 17/12/2008, 08h55
  4. Réponses: 3
    Dernier message: 10/11/2008, 11h58

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