EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013
-
12 mai 2013 à 12:32
EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013
-
14 mai 2013 à 17:58
Bonjour à tous,
Je suis confronté au fameux message 'Une erreur générique s'est produite dans GDI+' lorsque je veux sauver une image issue d'un picturebox. Et je ne comprends pas pourquoi j'ai ce message d'erreur. Pour faire simple j'ai résumé mon problème en une toute petite procédure en la débarrassant de toutes les lignes qui ne concernent pas le problème:
Cette procédure plante sur le save:
Dim Fichier_lu As String = "E:\Dossier_Entree\Photo1.jpg"
Dim Fichier_ecrit As String = "E:\Dossier_Sortie\Photo2.jpg"
PictureBox1.Load(Fichier_lu)
PictureBox1.Image.Save(Fichier_ecrit, System.Drawing.Imaging.ImageFormat.Jpeg)
La même procédure avec un fichier Tif en entrée ne plante pas:
Dim Fichier_lu As String = "E:\Dossier_Entree\Image1.tif"
Dim Fichier_ecrit As String = "E:\Dossier_Sortie\Photo2.jpg"
PictureBox1.Load(Fichier_lu)
PictureBox1.Image.Save(Fichier_ecrit, System.Drawing.Imaging.ImageFormat.Jpeg)
Le plantage parait absurde! Quelqu'un pourrait-il m'expliquer pourquoi ce code ne fonctionne pas?
Le but de mon programme est de permettre à l'utilisateur de sélectionner une image (photo, plan, ...) et de la ranger dans un dossier client en la complétant éventuellement par des marques (flèches, texte, ...). S'il y a modification de l'image, il n'y a pas plantage!
foliv57
Messages postés420Date d'inscriptionvendredi 17 novembre 2006StatutMembreDernière intervention15 juillet 20149 13 mai 2013 à 16:23
Bonjour,
Essayez ceci :
Dim Fichier_lu As String = "E:\Dossier_Entree\Photo1.jpg"
Dim Fichier_ecrit As String = "E:\Dossier_Sortie\Photo2.jpg"
PictureBox1.Image = Image.FromFile(Fichier_lu)
PictureBox1.Image.Save(Fichier_ecrit, System.Drawing.Imaging.ImageFormat.Jpeg)
Un picturebox ne doit se contenter que d'un affichage car le fichier utilisé reste ouvert. Travaille plutôt avec les flux et les objets de type Image ou Bitmap.
Dim monimage As Image
Using monstream As New IO.FileStream("monimage.jpg", IO.FileMode.Open)
monimage = Image.FromStream(monstream)
End Using
picturebox1.image = monimage
monimage.Save("manouvelleimage.jpg", Drawing.Imaging.ImageFormat.Jpeg)
Je passe sur les gestions d'erreur à réaliser bien entendu.
EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013 12 mai 2013 à 15:20
Bonjour,
Merci pour la réponse rapide. Cependant, je ne comprends pas bien pourquoi ça fonctionne avec un fichier TIF en entrée et pas avec un JPG.
J'ai précisément utilisé la méthode load parce qu'en utilisant un Stream, celui-ci devait rester ouvert en permanence, et que cela ne m'arrange pas.
Pour résoudre mon problème, j'utilise une astuce stupide. Je remplace le premier pixel de l'image par un pixel de même couleur, et ensuite la méthode save fonctionne. De toutes façons, ou la documentation pour utiliser les picturebox est mal faite, ou ça pue le bug à plein nez. Je ne sais pas pourquoi, mais je pense que c'est un peu des deux!
Mais je reste toujours intéressé par une explication du phénomène.
EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013 12 mai 2013 à 19:02
Ce code fonctionne de la même façon que le mien: même erreur avec un fichier JPG, pas d'erreur avec un fichier TIF.
Je pense que le problème ne vient pas d'une ressource verrouillée.
Pour moi (mais je peux me tromper) il y a des caractéristiques de l'image du fichier en entrée non mémorisées dans le cas d'un jpeg, mais bien renseignées dans le cas d'un tif. Le fait de travailler sur l'image par l'intermédiaire d'un graphics rétablit les paramètres manquants:
Dim img As Image = CType(PictureBox1.Image, Image)
Dim gr As Graphics
gr = Graphics.FromImage(img)
' manipulations.... gr.DrawRectangle , ...
PictureBox1.Image = img
gr.Dispose()
car après ces lignes de code, la méthode save fonctionne toujours.
EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013 13 mai 2013 à 07:38
Le problème exposé par ce lien est un peu différent, car il traite de plantage sur l'enregistrement de fichier tif multipage.
Dans mon cas le plantage se fait sur le save au format JPG d'un fichier déjà en JPG, sans aucune transformation.
Comme la commande de mon client était urgente, j'ai utilisé la petite astuce indiquée précédemment, mais j'avoue que j'aimerai comprendre...
foliv57
Messages postés420Date d'inscriptionvendredi 17 novembre 2006StatutMembreDernière intervention15 juillet 20149 14 mai 2013 à 11:56
Juste pour info à banana,
Le problème vient justement de la libération des ressources du flux.
La méthode "picturebox.Load" fait exactement l'action donnée dans votre exemple
Dim monimage As Image
Using monstream As New IO.FileStream("monimage.jpg", IO.FileMode.Open)
monimage = Image.FromStream(monstream)
End Using
picturebox1.image = monimage
monimage.Save("manouvelleimage.jpg", Drawing.Imaging.ImageFormat.Jpeg)
Elle ouvre un Stream, fait un Image.FromStream est libère le flux avec un "End Using" avant d'affecter l'image au picturebox.
Malheureusement la méthode "Image.Save" génère justement l'erreur GDI+ si le flux est fermé (End Using). Donc votre exemple fonctionne si le Save est fait dans le Using
Dim monimage As Image
Using monstream As New IO.FileStream("monimage.jpg", IO.FileMode.Open)
monimage = Image.FromStream(monstream)
picturebox1.image = monimage
monimage.Save("manouvelleimage.jpg", Drawing.Imaging.ImageFormat.Jpeg)
End Using
Par contre la méthode "Image.FromFile" n'accède pas au fichier de la même manière. Le problème était donc bien un problème de flux, mais du au fait qu'il est libéré.
La seul chose que je n'ai pas encore clairement identifiée, c'est pourquoi la méthode "Image.Save" fonctionne si la source est un tif et que le flux est libéré.
foliv57
Messages postés420Date d'inscriptionvendredi 17 novembre 2006StatutMembreDernière intervention15 juillet 20149 14 mai 2013 à 14:52
Et pour conclure, dixit MSDN (comme quoi il ne fallait pas chercher bien loin).
Vous devez garder le flux ouvert pendant la durée de vie de Image.
Donc je fini avec un petit exemple pour les personnes qui auraient besoin de travailler sur l'image avec le flux fermé (exemple: modifier et enregistrer l'image avec le même chemin car Image.FromFile ne le permet pas vu qu'il garde un handle ouvert)
Dim img As Image
Using fs As New FileStream("D:\Dossier_Entree\Test.jpg", FileMode.Open, FileAccess.Read)
'Chargement de l'image depuis le flux et création d'une copie déconnecté à
'l'aide de la classe Bitmap qui hérite de la classe Image
img = New Bitmap(Image.FromStream(fs))
End Using 'Fermeture du flux
'Sauvegarde sans erreur GDI+
img.Save("D:\Dossier_Sortie\Test.jpg", Imaging.ImageFormat.Jpeg
Je dois avouer que ça ressemble plus à un tour de passe-passe qu'à une solution, mais ça dépanne.
D'ailleurs je suppose que l'objet Image peut sauvegarder soit à partir du flux original, soit à partir d'une table d'octets représentant une copie de l'originale. Ce qui expliquerai peut-être pourquoi cela fonction immédiatement avec les tif. Ce format est peut-être mis instantanément dans la table d'octets au chargement.
Ce transfert se fait surement aussi lors de la modification de l'image, d'ou le fait que la sauvegarde fonctionne si on passe par un objet Graphics et qu'on modifie l'originale.
Ce dernier paragraphe n'est que des suppositions basées sur le fait que la classe Image dispose d'un variable privée nommée "rawData" de type "Byte()" qui, sous certaine conditions, est utilisée dans la méthode Save à la place du handle original.
EISDCC
Messages postés12Date d'inscriptionmardi 3 août 2004StatutMembreDernière intervention14 mai 2013 14 mai 2013 à 17:58
Merci pour ces précisions.
J'avais bien vu MSDN, mais je ne pouvais pas garder le flux ouvert, car cela verrouille la ressource, et le logiciel fonctionnant en réseau, cela bloquait d'autres utilisateurs sur certains traitements.
Encore merci à tous