问题
When I run my application the following error get's thrown in my face "A generic error occurred in GDI+." I've looked around and seen people have similar errors, but have found no real solution, or it is a real pain in the butt to implement. And those that have not gotten a solution have not posted their code.
So I thought I might as well give it a shot and throw another thread up about how to fix this error. This is my Code & Error
Random r = new Random();
DirectoryInfo di = new DirectoryInfo(folderbrowser.SelectedPath);
FileInfo[] fi = di.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
for (int i = 0; i < imageCount; i++)
{
int img1 = r.Next(imageCount);
int img2 = r.Next(imageCount);
while (img2 == img1)
img2 = r.Next(imageCount);
pic1.Image = Image.FromFile(fi[img1].FullName);
pic2.Image = Image.FromFile(fi[img2].FullName);
Image i1 = pic1.Image;
Image i2 = pic2.Image;
Bitmap bitmap = new Bitmap(i1.Width + i2.Width, 1080);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(i1, 0, 0);
g.DrawImage(i2, i2.Width, 0);
}
bitmap.Save(@"C:\TEST\Image_"+i.ToString());
}
And here's the Error code
System.Runtime.InteropServices.ExternalException was unhandled
Message=A generic error occurred in GDI+.
Source=System.Drawing
ErrorCode=-2147467259
StackTrace:
at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(String filename, ImageFormat format)
at System.Drawing.Image.Save(String filename)
at WallpaperMerger.Form1.btn_merge_Click(Object sender, EventArgs e) in C:\Users\PeppeJ\documents\visual studio 2010\Projects\WallpaperMerger\WallpaperMerger\Form1.cs:line 113
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at WallpaperMerger.Program.Main() in C:\Users\PeppeJ\documents\visual studio 2010\Projects\WallpaperMerger\WallpaperMerger\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
So what do you guys here at StackOverflow think. Am I the same boat as the others and have to type a ridiculously complex code to solve this problem, or have I made a simple mistake and it's easy to correct?
If you want to test it yourself if that might somehow help, here's a link to the Debug Build
Simply tick "Use Multiple Files", select a folder containing image files (C:\Users\Public\Pictures\Sample Pictures) for instance. Hit Merge.
I'd like to add that I use Bitmap.Save in this function, and it works flawlessly.
Bitmap bitmap = new Bitmap(pic1.Image.Width + pic2.Image.Width, 1080);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(pic1.Image, 0, 0);
g.DrawImage(pic2.Image, pic1.Image.Width, 0);
}
if (savepicfile.ShowDialog() == DialogResult.OK)
bitmap.Save(savepicfile.FileName);
In the above function files are loaded like this:
DialogResult result = pic1file.ShowDialog();
if (result == DialogResult.OK)
pic1.Image = Image.FromFile(pic1file.FileName);
Something else worth mentioning is that "picX" is a "System.Windows.Forms.PictureBox" object.
回答1:
In my experience, 99% of the time this error is caused by an issue where either:
- You don't have permission to write the file.
- The file you're trying to write to is locked by another process.
Occasionally I've run into it when:
- I'm drawing GraphicPaths with zero points in them.
- I'm not property disposing of my GDI+ objects. (possibly related to option 2 above)
I'd check the first two things first. If that can be ruled out I can see where you're not properly disposing of a few objects in the code you provided. I'd clean that up. GDI+ isn't particularly cooperative with .NET's GC if you aren't calling Dispose() when you're supposed to.
var r = new Random();
var di = new DirectoryInfo(folderbrowser.SelectedPath);
var fi = di.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
for (var i = 0; i < imageCount; i++)
{
var img1 = r.Next(imageCount);
var img2 = r.Next(imageCount);
while (img2 == img1)
{
img2 = r.Next(imageCount);
}
pic1.Image = Image.FromFile(fi[img1].FullName);
pic2.Image = Image.FromFile(fi[img2].FullName);
var i1 = pic1.Image;
var i2 = pic2.Image;
using (var bitmap = new Bitmap(i1.Width + i2.Width, 1080))
using (var g = Graphics.FromImage(bitmap))
{
g.DrawImage(i1, 0, 0);
g.DrawImage(i2, i2.Width, 0);
bitmap.Save(@"C:\TEST\Image_"+i.ToString());
}
}
EDIT: More ideas (Well, really clarification of number 2 above)...
- If you have a PictureBox or other control in your app referencing the images in your
C:\TEST
directory that you're trying to write, you can see this error. - If you have other code reading the image you're trying to write to you can see this error.
- If an external process, such as your IDE, an image viewer/editor, etc. has the file open you can see this error.
Debugging ideas:
- Try setting a break point on the Save call. When you get to it, use the tips found here to figure out what process might be accessing the file: How do I find out which process is locking a file using .NET?
- Try just deleting the files first to see if it allows you to save if they're not their.
- Try setting full permissions for "Everyone" on the directory you're writing to (Don't leave it like this, though)
- Make sure the width of the image you're trying to save is a number greater than zero. I noticed you're setting that programatically.
- Make sure the width of the image you're trying to save isn't ridiculously huge (an maybe you're running into a memory issue?)
回答2:
I found the answer, the directory "\TEST\" didn't exist. When I created it , it worked flawlessly.
回答3:
I had this exact problem, and what fixed it was to wrap the Bitmap in the using clause; Bitmap needs to be disposed as well
using (Bitmap bmp = new Bitmap())
{
// Bitmap operation
}
回答4:
Try doing the bitmap.Save before you dispose of the Graphics object:
Bitmap bitmap = new Bitmap(i1.Width + i2.Width, 1080);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.DrawImage(i1, 0, 0);
g.DrawImage(i2, i2.Width, 0);
bitmap.Save(@"C:\TEST\Image_"+i.ToString());
}
来源:https://stackoverflow.com/questions/13576806/bitmap-save-generic-error