web-dev-qa-db-fra.com

Comment trouver la raison de l'erreur GDI + générique lors de l'enregistrement d'une image?

Ayant un code qui fonctionne depuis des lustres lors du chargement et du stockage d'images, j'ai découvert que j'avais une seule image qui casse ce code:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);
i.Save(i2Path, ImageFormat.Jpeg);

L'exception est:

System.Runtime.InteropServices.ExternalException s'est produite

Une erreur générique s'est produite dans GDI +.

à System.Drawing.Image.Save (String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
sur System.Drawing.Image.Save (String filename, ImageFormat format)
à ...

Pour autant que je puisse voir, l'image n'a rien de spécial. Il fait environ 250 pixels et peut être ouvert par ex. Visionneuse d'images Windows ou Paint.NET:

enter image description here

(Puisque l'image ci-dessus, après avoir été téléchargée sur Stack Overflow ne produit plus l'erreur, j'ai mis l'image d'origine ici )

Ce que j'ai découvert, c'est qu'en appelant la méthode Save , le fichier image de destination est créé avec zéro octet.

Je ne sais vraiment pas ce qui cause l'erreur.

Mes questions:

  • Pouvez-vous penser à quelque chose de spécial qui empêcherait .NET d'enregistrer l'image?
  • Existe-t-il un moyen (en plus de paniquer) de réduire ce type d'erreurs?
29
Uwe Keim

Bien que je n'aie toujours pas trouvé la raison de la cause exacte de l'erreur lors de l'enregistrement de l'image, j'ai trouvé une solution de contournement à appliquer:

const string i1Path = @"c:\my\i1.jpg";
const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);

var i2 = new Bitmap(i);
i2.Save(i2Path, ImageFormat.Jpeg);

C'est à dire. en copiant l'image en interne dans une instance Bitmap et en enregistrant cette image à la place de l'image d'origine, l'erreur a disparu.

Je suppose qu'en le copiant, les parties erronées qui ont provoqué l'échec de l'appel original Save sont supprimées et/ou normalisées, permettant ainsi à l'opération de sauvegarde de réussir.

saved image i2.jpg

Fait intéressant, l'image ainsi stockée a un fichier sur disque plus petit (16 ko) que sa source d'origine (26 ko).

39
Uwe Keim

Assurez-vous tout d'abord que le dossier souhaité dispose des autorisations de lecture/écriture. La modification des autorisations a résolu ce problème pour moi.

15
Shadmehr Vadoodi

La solution est là, vous devez disposer de l'objet image pour libérer la mémoire sur le serveur. Essayez d'utiliser l'instruction using. Assurez-vous que le répertoire de destination sur le serveur existe également.

7
Azarsa

La raison peut être que l'image est chargée paresseusement et que le processus de chargement n'est pas encore terminé lorsque vous essayez de l'enregistrer.

Suivre ce qui est dit dans ce billet de blog (en supposant que vous êtes allemand par l'image que vous avez liée dans votre question) fournit une solution possible. Aussi cette SO question la réponse acceptée indique que cela est dû au fait que le fichier image dans lequel vous essayez d'enregistrer est verrouillé.

[~ # ~] modifier [~ # ~]
Pour Ulysse Alves, à partir de l'entrée de blog liée: Si vous chargez une image à l'aide de Image.FromFile() elle reste verrouillée jusqu'à ce qu'elle soit éliminée. Cela empêche les appels à Save().

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
pictureBox1.Image.Save("C:\\test\\test2.jpg");

Le code ci-dessus génère une erreur.

Pour le faire fonctionner, vous devez copier l'image. Le code suivant fonctionne:

pictureBox1.Image = Image.FromFile("C:\\test\\test1.jpg");
Image copy = pictureBox1.Image;
copy.Save("C:\\test\\test2.jpg")
5
Thorsten Dittmar

J'ai trouvé cette question car j'ai également rencontré l'erreur similaire et le fichier était en fait créé avec une longueur nulle (si vous ne voyez aucun fichier, vérifiez d'abord les autorisations d'écrire dans le dossier comme d'autres réponses le suggèrent) . Bien que mon code soit légèrement différent (j'utilise stream pour lire l'image de la mémoire, pas du fichier), je pense que ma réponse peut être utile à toute personne confrontée à un problème similaire.

Cela peut sembler contre-intuitif, mais vous ne pouvez pas vraiment disposer du flux de mémoire avant d'avoir terminé avec l'image.

NE FONCTIONNE PAS:

Image patternImage;

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
}

patternImage.Save(patternFile, ImageFormat.Jpeg);

Ne jetez simplement pas le flux avant d'avoir terminé avec l'image.

FONCTIONNE :

using (var ms = new MemoryStream(patternBytes)) {
    patternImage = new Bitmap(ms);
    patternImage.Save(patternFile, ImageFormat.Jpeg);
}

Ce qui est trompeur:

  • Le message d'erreur ne vous dit vraiment rien
  • Vous pouvez voir les propriétés de l'image, comme la largeur et la hauteur, mais vous ne pouvez pas l'enregistrer
3
Mike Keskinov

ma solution était de créer, d'écrire du contenu temporaire (File.WriteAllText) juste avant d'enregistrer le fichier

Voici le code:

var i = Image.FromFile(i1Path);
File.WriteAllText(i2Path, "empty");  // <---- magic goes here
i.Save(i2Path, ImageFormat.Jpeg);

S'il vous plaît essayez de me le faire savoir

3
mr.baby123

Ouvert dans le programme

const string i1Path = @"c:\my\i1.jpg";

const string i2Path = @"c:\my\i2.jpg";

var i = Image.FromFile(i1Path);

i.Save(i2Path, ImageFormat.Jpeg);

i.Dispose();
0
Konstant