位图保存“通用错误”

3
当我运行我的应用程序时,会出现以下错误提示:"GDI+中发生了一般性错误"。我查看了一些类似的错误,但没有找到真正的解决方案或者实施起来非常麻烦。那些没有得到解决方案的人也没有发布他们的代码。
所以我认为我可以尝试发一个帖子,讨论如何解决这个错误。以下是我的代码和错误信息。
            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());                   
            }

这里是错误代码

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: 

在这里,您们StackOverflow的大家认为我和其他人一样,必须打入极其复杂的代码来解决这个问题吗?还是我犯了一个简单的错误,很容易纠正呢?如果您想自己测试一下,可能会有所帮助,请点击这里Debug Build。只需勾选“使用多个文件”,选择包含图像文件的文件夹(例如C:\ Users \ Public \ Pictures \ Sample Pictures),然后点击合并。 我想补充说明的是,在此功能中,我使用了Bitmap.Save,并且它运行得非常流畅。
        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);

在上述函数中,文件是这样加载的:
    DialogResult result = pic1file.ShowDialog();
    if (result == DialogResult.OK)
        pic1.Image = Image.FromFile(pic1file.FileName);

值得一提的是,“picX”是一个“System.Windows.Forms.PictureBox”对象。

你有写入 C:\TEST 的权限吗? - Bryan Crosby
我有一个管理员帐户(W7),UAC已完全禁用,我可以创建文件。我还在另一个地方使用Bitmap.Save(我将把该函数添加到主贴中)。 - PeppeJ
.NET框架版本是多少? - akatakritos
4个回答

5
根据我的经验,99%的情况下,此错误是由以下问题之一引起的:
  1. 您没有写入该文件的权限。
  2. 您要写入的文件被另一个进程锁定。
偶尔,我会在以下情况下遇到此错误:
  • 我正在绘制零点的GraphicPaths。
  • 我没有正确地处理我的GDI+对象。(可能与上述第2个选项有关)
我建议首先检查前两个问题。如果可以排除这些问题,我可以看到您在提供的代码中没有正确处理一些对象。我会清理它们。如果您没有按照规定调用Dispose(),则GDI+与.NET的GC不太合作。
        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());
            }                   
        }

编辑:更多想法(实际上是澄清以上第2个问题)...

  • 如果你的应用程序中有一个PictureBox或其他控件,引用了你尝试写入的C:\TEST目录中的图像,你可能会看到这个错误。
  • 如果你有其他代码读取你试图写入的图片,你也可能会看到这个错误。
  • 如果外部进程,例如你的IDE、图像查看器/编辑器等正在打开该文件,你也可以看到此错误。

调试思路:

  • 尝试在Save函数调用上设置断点。当你到达它时,使用这里找到的提示来确定哪个进程可能正在访问该文件。
  • 尝试先删除文件,看看是否能够保存,如果它们不存在。
  • 尝试为你要写入的目录上的“Everyone”设置完全权限(不过不要保持这样)。
  • 确保你要保存的图像的宽度是大于零的数字。我注意到你在程序中设置它。
  • 确保你要保存的图像的宽度不是非常巨大的(也许你遇到了内存问题?)。

这看起来和“akatakritos”建议的没有什么不同,但我还是尝试了一下,但没有任何区别。 - PeppeJ
看起来没有什么不同?也许你跳过了第一部分。这种错误在GDI+开发中很常见,而且真的很难进行故障排除。就像我上面说的,很有可能是权限问题或文件被“某个东西”锁定的问题(另一个进程?当前应用程序中的竞争条件?)。当所有其他方法都失败时,就该重写一段代码了。 - Ben Lesh
我复制粘贴了它以确保无误,我非常怀疑这与权限有关,而更可能是你提到的第二个原因。请再次查看原始帖子,我已经编辑了一些可能有用的信息。 - PeppeJ
有没有其他东西可以访问 C:\TEST\whatever 中的文件?任何东西都行?你的应用程序?IDE?还是其他什么?如果在那一行设置一个断点,然后从 Visual Studio 的“立即”窗口保存,你还会收到错误吗? - Ben Lesh
此外,删除所有现有文件并查看是否仍然出现错误。 - Ben Lesh
我添加了一些更多的想法。希望其中一个能够帮助到您。在我的职业生涯中,我花费了数年时间与通用 GDI+ 错误作斗争......它总是有点不同。这是最糟糕的错误。 - Ben Lesh

2
我曾经遇到过这个问题,解决方法是将Bitmap放在using语句块中。Bitmap也需要被处理掉。
using (Bitmap bmp = new Bitmap()) 
{
    // Bitmap operation
}

2
我找到了答案,目录“\TEST\”不存在。我创建了它之后,它就完美地工作了。

1
遇到了同样的问题。在找到你的答案之前花了1个小时 :-) - apocalypse

1
尝试在释放 Graphics 对象之前执行 bitmap.Save:
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()); 
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接