[C#] Enregistrer une image en cours d'utilisation

Résolu
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011 - 6 juin 2011 à 13:52
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 - 10 juin 2011 à 16:04
Bonjour à tous !

J'ai un petit problème pour enregistrer une image bitmap sur le même nom et dans le même dossier que l'image d'origine.

Pour une meilleur explication, je crée un programme qui permet de faire de la stéganographie. J'ouvre une image bitmap, puis je stock du texte ou une image dans celle-ci.

A l'enregistrement, je n'arrive pas à enregistrer sur le même nom, le programme me dit que l'image est en cours d'utilisation. J'ai essayé de résoudre ce problème par plusieurs moyen, mais rien n'y fait

A la lecture de l'image source pour pouvoir la changer par la suite, j'ai ce code :
Bitmap ImgFile = new Bitmap(strFilePath);
Bitmap ImgTmp = (Bitmap)ImgFile.Clone();
ImgFile.Dispose();


J'ai essayer de le faire comme ceci pour fermer l'image et utiliser un clone de celle-ci. Mais ça ne marche pas


Est-ce que vous auriez une solution pour enregistrer une image sur le même nom que celle d'origine ?

Je vous laisse toute la partie du code qui pose problème :
    /// <summary>
    /// Inscrit dans l'image le texte donné en paramètre dans l'image donnée en paramètre
    /// </summary>
    /// Texte à inclure


    /// Chemin vers l'image


    public void IncludeText(String strFilePath, String strInclude)
    {
      // Crée une image depuis la class Bitmap
      Bitmap ImgFile = new Bitmap(strFilePath);
      Bitmap ImgTmp = (Bitmap)ImgFile.Clone();
      ImgFile.Dispose();

      // Taille maximum du texte possible
      Int32 intMaxSize = ((ImgTmp.Height - 1) * (ImgTmp.Width - 1)) / 8;

      // Teste si le texte est trop long, si oui, affiche un message d'erreur
      if (strInclude.Length > intMaxSize) 
      { 
        System.Windows.MessageBox.Show("Le texte écrit est trop long !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      // Teste si l'encodage de l'image est le bon, si non, affiche un message d'erreur
      if (ImgTmp.PixelFormat != PixelFormat.Format24bppRgb)
      {
        System.Windows.MessageBox.Show("Mauvais encodage de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      Int32 x;                              // Variable de boucle
      Byte byTemp = 0;                      // Variable temporaire
      Byte R = 0;                           // Couleur Rouge
      Byte G = 0;                           // Couleur Vert
      Byte B = 0;                           // Couleur Bleu
      Point ptCurrentPoint = Point.Empty;   // Position actuelle dans l'image
      Color coCurrentColor = Color.Empty;   // Couleur actuelle du pixel

      // Inscrit le carractère de fin
      strInclude += FIN;

      // Boucle pour inscrire le texte dans l'image
      for (x = 0; x < strInclude.Length; x++)
      {
        // Prend le premier caractère est le stock dans la variable temporaire
        byTemp = (Byte)strInclude[x];

        // Stock la position du pixel selon l'avancement de l'écriture
        ptCurrentPoint.X = x % ImgTmp.Width;
        ptCurrentPoint.Y = x / ImgTmp.Width;

        // Séléctionne le pixel au point X;Y
        coCurrentColor = ImgTmp.GetPixel(ptCurrentPoint.X, ptCurrentPoint.Y);

        // Change la couleur du pixel pour inscrire le carractère
        R = (Byte)(coCurrentColor.R & 248 | (byTemp & 7));
        G = (Byte)(coCurrentColor.G & 248 | (byTemp & 56) >> 3);
        B = (Byte)(coCurrentColor.B & 252 | (byTemp & 192) >> 6);

        // Enregistre le nouveau pixel
        ImgTmp.SetPixel(ptCurrentPoint.X, ptCurrentPoint.Y, Color.FromArgb(R, G, B));
      }

      // Enregistre l'image
      try { ImgTmp.Save(strFilePath); }
      catch
      {
        System.Windows.MessageBox.Show("Erreur lors de l'enregistrement de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }
    } // Fin IncludeText



Merci bien,
SlyK

9 réponses

sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
6 juin 2011 à 14:14
Bonjour,

ce n'est pas possible d'enregistrer une image en même temps qu'on la lit.
il faut utiliser une subterfuge !

avant d'ouvrir ton image, il faut en créer une copie temporaire... ensuite tu pourras l'enregistrer à la place de l'originale.


Sébastien FERRAND
Ingénieur Concepteur Senior
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
1
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011
6 juin 2011 à 14:40
Re !

Merci bien pour ta réponse

Donc c'est bien ça, il n'y a pas de moyen sans passer par un fichier temporaire

Voici le code que j'utilise donc pour inscrire le texte, il marche mais il y a un autre problème décrit plus bas :
    /// <summary>
    /// Inscrit dans l'image le texte donné en paramètre dans l'image donnée en paramètre
    /// </summary>
    /// Texte à inclure


    /// Chemin vers l'image


    /// Chemin vers l'image temporaire


    public void IncludeText(String strFilePath, String strTmpPath, String strInclude)
    {
      // Supprime le fichier temporaire si il existe
      if (File.Exists(strTmpPath)) { File.Delete(strTmpPath); }

      // Copie l'image dans le répertoire temporaire
      File.Copy(strFilePath, strTmpPath);

      // Crée une image depuis la class Bitmap
      Bitmap ImgFile = new Bitmap(strTmpPath);

      // Taille maximum du texte possible
      Int32 intMaxSize = ((ImgFile.Height - 1) * (ImgFile.Width - 1)) / 8;

      // Teste si le texte est trop long, si oui, affiche un message d'erreur
      if (strInclude.Length > intMaxSize) 
      { 
        System.Windows.MessageBox.Show("Le texte écrit est trop long !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      // Teste si l'encodage de l'image est le bon, si non, affiche un message d'erreur
      if (ImgFile.PixelFormat != PixelFormat.Format24bppRgb)
      {
        System.Windows.MessageBox.Show("Mauvais encodage de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      Int32 x;                              // Variable de boucle
      Byte byTemp = 0;                      // Variable temporaire
      Byte R = 0;                           // Couleur Rouge
      Byte G = 0;                           // Couleur Vert
      Byte B = 0;                           // Couleur Bleu
      Point ptCurrentPoint = Point.Empty;   // Position actuelle dans l'image
      Color coCurrentColor = Color.Empty;   // Couleur actuelle du pixel

      // Inscrit le carractère de fin
      strInclude += FIN;

      // Boucle pour inscrire le texte dans l'image
      for (x = 0; x < strInclude.Length; x++)
      {
        // Prend le premier caractère est le stock dans la variable temporaire
        byTemp = (Byte)strInclude[x];

        // Stock la position du pixel selon l'avancement de l'écriture
        ptCurrentPoint.X = x % ImgFile.Width;
        ptCurrentPoint.Y = x / ImgFile.Width;

        // Séléctionne le pixel au point X;Y
        coCurrentColor = ImgFile.GetPixel(ptCurrentPoint.X, ptCurrentPoint.Y);

        // Change la couleur du pixel pour inscrire le carractère
        R = (Byte)(coCurrentColor.R & 248 | (byTemp & 7));
        G = (Byte)(coCurrentColor.G & 248 | (byTemp & 56) >> 3);
        B = (Byte)(coCurrentColor.B & 252 | (byTemp & 192) >> 6);

        // Enregistre le nouveau pixel
        ImgFile.SetPixel(ptCurrentPoint.X, ptCurrentPoint.Y, Color.FromArgb(R, G, B));
      }

      // Enregistre l'image
      try { ImgFile.Save(strFilePath); ImgFile.Dispose(); File.Delete(strTmpPath); }
      catch
      {
        System.Windows.MessageBox.Show("Erreur lors de l'enregistrement de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }
    } // Fin IncludeText


Après avoir fait ceci, le preview de mon image m'embête pour les même problème de droit, je dois donc crée deux fichier temporaire ?
Un pour la modification de l'image et un pour le preview ?

Sans le preview, l'inscription marche très bien.
Je précise que je code avec du WPF.


Merci bien,
SlyK
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
6 juin 2011 à 15:09
je te propose une "petite" modification :

/// <summary>
    /// Inscrit dans l'image le texte donné en paramètre dans l'image donnée en paramètre
    /// </summary>
    /// Texte à inclure


    /// Chemin vers l'image


    /// Chemin vers l'image temporaire


    public void IncludeText(String strFilePath, String strTmpPath, String strInclude)
    {
      // Supprime le fichier temporaire si il existe
      if (File.Exists(strTmpPath)) { File.Delete(strTmpPath); }

      // Copie l'image dans le répertoire temporaire
      File.Copy(strFilePath, strTmpPath);

      // Crée une image depuis la class Bitmap
      using(Bitmap ImgFile = new Bitmap(strTmpPath)) {

      // Taille maximum du texte possible
      Int32 intMaxSize = ((ImgFile.Height - 1) * (ImgFile.Width - 1)) / 8;

      // Teste si le texte est trop long, si oui, affiche un message d'erreur
      if (strInclude.Length > intMaxSize) 
      { 
        System.Windows.MessageBox.Show("Le texte écrit est trop long !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      // Teste si l'encodage de l'image est le bon, si non, affiche un message d'erreur
      if (ImgFile.PixelFormat != PixelFormat.Format24bppRgb)
      {
        System.Windows.MessageBox.Show("Mauvais encodage de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }

      Int32 x;                              // Variable de boucle
      Byte byTemp = 0;                      // Variable temporaire
      Byte R = 0;                           // Couleur Rouge
      Byte G = 0;                           // Couleur Vert
      Byte B = 0;                           // Couleur Bleu
      Point ptCurrentPoint = Point.Empty;   // Position actuelle dans l'image
      Color coCurrentColor = Color.Empty;   // Couleur actuelle du pixel

      // Inscrit le carractère de fin
      strInclude += FIN;

      // Boucle pour inscrire le texte dans l'image
      for (x = 0; x < strInclude.Length; x++)
      {
        // Prend le premier caractère est le stock dans la variable temporaire
        byTemp = (Byte)strInclude[x];

        // Stock la position du pixel selon l'avancement de l'écriture
        ptCurrentPoint.X = x % ImgFile.Width;
        ptCurrentPoint.Y = x / ImgFile.Width;

        // Séléctionne le pixel au point X;Y
        coCurrentColor = ImgFile.GetPixel(ptCurrentPoint.X, ptCurrentPoint.Y);

        // Change la couleur du pixel pour inscrire le carractère
        R = (Byte)(coCurrentColor.R & 248 | (byTemp & 7));
        G = (Byte)(coCurrentColor.G & 248 | (byTemp & 56) >> 3);
        B = (Byte)(coCurrentColor.B & 252 | (byTemp & 192) >> 6);

        // Enregistre le nouveau pixel
        ImgFile.SetPixel(ptCurrentPoint.X, ptCurrentPoint.Y, Color.FromArgb(R, G, B));
      }

      // Enregistre l'image
      try { 
             ImgFile.Save(strFilePath); 
             ImgFile.Dispose(); 
             File.Delete(strTmpPath); }
      catch
      {
        System.Windows.MessageBox.Show("Erreur lors de l'enregistrement de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
        return;
      }
      }
    } // Fin IncludeText



Ne jamais oublier le using() lorsque l'on travaille avec des images.

Sébastien FERRAND
Ingénieur Concepteur Senior
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
0
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011
6 juin 2011 à 15:27
Re !

Effectivement, ça marche pour la première inscription.

Par contre si je veux réinscrire la même image directement, ça ne marche pas.

Il me sort cette erreur.
Interception de System.Runtime.InteropServices.ExternalException
  Message=Une erreur générique s'est produite dans GDI+.
  Source=System.Drawing
  ErrorCode=-2147467259
  StackTrace:
       à System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
       à System.Drawing.Image.Save(String filename, ImageFormat format)
       à System.Drawing.Image.Save(String filename)
       à HideMe.BitmapFile.IncludeText(String strFilePath, String strTmpPath, String strInclude)
  InnerException:


J'ai fais quelques recherches sur le numéro de l'erreur (2147467259) mais sans succès.


Merci bien,
SlyK
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
6 juin 2011 à 16:46
à quelle moment intervient la seconde erreur ?


Sébastien FERRAND
Ingénieur Concepteur Senior
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
0
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011
7 juin 2011 à 13:18
Re !

L'erreur arrive à la sauvegarde de l'image.
        try { ImgFile.Save(strFilePath); ImgFile.Dispose(); File.Delete(strTmpPath); }
        catch
        {
          System.Windows.MessageBox.Show("Erreur lors de l'enregistrement de l'image !", "Erreur", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
          return;
        }


Le truc qui est bizarre, c'est que l'enregistrement marche une fois, par la suite, il ne marche plus. Si je prend le focus sur une autre fenêtre, par exemple l'explorer, et que je reviens sur mon programme, la l'écriture marche

Je ne sais pas pourquoi mais c'est le cas


Merci bien,
SlyK
0
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011
7 juin 2011 à 13:25
Maintenant, j'arrive à inscrire seulement 1 fois sur 14.

Tout les 14 cliques sur le bouton "Écrire", l'inscription marche
0
SlyK1012 Messages postés 6 Date d'inscription mercredi 23 février 2011 Statut Membre Dernière intervention 10 juin 2011
10 juin 2011 à 08:34
Re !

J'ai trouvé la solution, enfaite il me manquait juste un dispose() à un endroit

Merci quand même.


Cdlt,
SlyK
0
sebmafate Messages postés 4936 Date d'inscription lundi 17 février 2003 Statut Membre Dernière intervention 14 février 2014 37
10 juin 2011 à 16:04
désolé... j'avais zappé ton thread...


Sébastien FERRAND
Ingénieur Concepteur Senior
Microsoft Visual C# MVP 2004 - 2009
Blog Photo
0
Rejoignez-nous