C# System.Drawing - 参数无效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14099246/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:40:12  来源:igfitidea点击:

System.Drawing - Parameter is not valid

c#.net-4.0bitmapsystem.drawing

提问by Djentleman

After some more testing I've found that this problem may be due to the images somehow not being loaded in time to be cloned into bitmaps and displayed. Is this possible or no?

经过一些更多的测试,我发现这个问题可能是由于图像以某种方式没有及时加载以克隆到位图并显示。这是可能的还是不可能的?

NOTE: Yes, there are other questions with this error in the title, but from a bit of a research it seems to be an ambiguous error with many possible causes. I haven't found any questions with the same scenario as mine.

注意:是的,标题中还有其他问题与此错误有关,但从一些研究来看,这似乎是一个含糊不清的错误,有许多可能的原因。我还没有发现任何与我的场景相同的问题。

I'm getting the following error.

我收到以下错误。

System.ArgumentException was unhandled
HResult=-2147024809
Message=Parameter is not valid.
Source=System.Drawing

It arises from this code. seemingly at random (i.e., sometimes it works and sometimes it doesn't. The more times it's run in a row without restarting VS and rebuilding the project, the more likely it is to fail):

它源于这段代码。似乎是随机的(即,有时它起作用,有时不起作用。它在没有重新启动 VS 和重建项目的情况下连续运行的次数越多,它就越有可能失败):

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx) {
    System.Drawing.Rectangle cloneRect;
    string prefix = (anim) ? "A" : "S";
    using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) {
        if (anim) {
            cloneRect = new System.Drawing.Rectangle(BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_AnimSpriteSets[tsIndex].RecWidth, BaseObjects.A_AnimSpriteSets[tsIndex].RecHeight);
        } else {
            cloneRect = new System.Drawing.Rectangle(BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_StaticSpriteSets[tsIndex].RecWidth, BaseObjects.A_StaticSpriteSets[tsIndex].RecHeight);
        }
        return b.Clone(cloneRect, b.PixelFormat);
    }
}

Specifically, the fourth line:

具体来说,第四行:

using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png"))

The simplified objective of the code is to return a bitmap containing a sprite from a spriteset based on a spriteset index and a sprite index. This bitmap is displayed in a PictureBox until it is changed to a different image. I know for a fact that the logic works; that's not the issue here. The .png I'm using to test is 384*256.

代码的简化目标是根据 spriteset 索引和 sprite 索引从 spriteset 返回包含 sprite 的位图。此位图显示在 PictureBox 中,直到它更改为不同的图像。我知道这个逻辑是有效的;这不是这里的问题。我用来测试的 .png 是 384*256。

All the parameters are set properly, all the referenced files are there, everything seems to be in order. Strangest thing of all is that sometimes it works, sometimes it doesn't. This has led me to believe that it may be a memory leak within System.Drawingitself but I can't seem to track it down.

所有参数都设置正确,所有引用的文件都在那里,一切似乎都井井有条。最奇怪的是,有时它起作用,有时不起作用。这让我相信它System.Drawing本身可能是内存泄漏,但我似乎无法追踪它。

EDIT: Updated the code and added the StackTrace. Still having the same issue despite disposing the Bitmaps when they are no longer used (see code below for example of how Bitmap is disposed).

编辑:更新了代码并添加了 StackTrace。尽管在不再使用位图时处理位图,但仍然存在相同的问题(请参阅下面的代码以了解如何处理位图)。

if (Sprite.Image != null) { Sprite.Image.Dispose(); }
    Sprite.Image = GetSprite(true, tsIdx, tileIdx);

StackTrace:

堆栈跟踪:

System.ArgumentException was unhandled
  HResult=-2147024809
  Message=Parameter is not valid.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Bitmap..ctor(String filename)
       at CreationTool.Main.GetSprite(Boolean anim, Int32 tsIndex, Int32 tileIdx) in F:\~\~\CreationTool\Main.cs:line 420
       at CreationTool.Main.Input_EnemySprite_SelectedIndexChanged(Object sender, EventArgs e) in F:\~\~\CreationTool\Main.cs:line 107
       at System.Windows.Forms.ComboBox.OnSelectedIndexChanged(EventArgs e)
       at System.Windows.Forms.ComboBox.set_SelectedIndex(Int32 value)
       at CreationTool.States.State_Enemy.populateForm() in F:\~\~\CreationTool\States\State_Enemy.cs:line 28
       at CreationTool.States.State_Enemy.Load(String name) in F:\~\~\CreationTool\States\State_Enemy.cs:line 22
       at CreationTool.Main.btnLoad_Click(Object sender, EventArgs e) in F:\~\~\CreationTool\Main.cs:line 174
       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 CreationTool.Program.Main() in F:\~\~\CreationTool\Program.cs:line 15
       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.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()

采纳答案by Djentleman

The leaking handles would have eventually led to memory issues but they weren't the problem in this case (thanks to those who pointed them out anyway, learnt something new).

泄漏的句柄最终会导致内存问题,但在这种情况下它们不是问题(感谢那些无论如何指出它们的人,学到了一些新东西)。

The problem was that, due to the way I load the actual images into memory, the images weren't being given enough time to fully load in most of my tests. The ones that succeeded were the ones that allowed enough time for the images to load.

问题是,由于我将实际图像加载到内存中的方式,在我的大多数测试中,图像没有足够的时间来完全加载。成功的是那些允许有足够时间加载图像的那些。

I got around this with a simple try/catch.

我通过一个简单的 try/catch 解决了这个问题。

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx) {
    string prefix;
    System.Drawing.Rectangle cloneRect;
    SpriteSet set;
    if (anim) {
        prefix = "A";
        set = BaseObjects.A_AnimSpriteSets[tsIndex];
    } else {
        prefix = "S";
        set = BaseObjects.A_StaticSpriteSets[tsIndex];
    }
    cloneRect = new System.Drawing.Rectangle(set.StaticRecs[tileIdx].X, set.StaticRecs[tileIdx].Y, set.RecWidth, set.RecHeight);
    try {
        using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) {
            return b.Clone(cloneRect, b.PixelFormat);
        }
    } catch (Exception ex) {
        MessageBox.Show("Error: " + ex.Message + "\n\nCause: " + "SpriteSet not yet loaded.");
        return null;
    }
}

This is all I need for this particular program.

这就是这个特定程序所需的全部内容。

Also, pstrjds, thanks for the cleanup ;) That messiness must have arisen during some refactor. Guess I just forgot about it.

另外,pstrjds,感谢您的清理 ;) 在某些重构过程中一定出现了混乱。猜猜我刚刚忘记了它。

回答by Darin Dimitrov

Wow, this code is leaking handles like hell. You need to dispose all types that implement IDisposable, which is quite a lot of types in the System.Drawing assembly (GDI+):

哇,这段代码像地狱一样泄漏句柄。您需要处理所有实现 的类型IDisposable,这是 System.Drawing 程序集 (GDI+) 中相当多的类型:

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx)
{
    Rectangle cloneRect;
    string prefix = (anim) ? "A" : "S";
    using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png"))
    {
        if (anim)
        {
            cloneRect = new Rectangle(BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_AnimSpriteSets[tsIndex].RecWidth, BaseObjects.A_AnimSpriteSets[tsIndex].RecHeight);
        }
        else
        {
            cloneRect = new Rectangle(BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_StaticSpriteSets[tsIndex].RecWidth, BaseObjects.A_StaticSpriteSets[tsIndex].RecHeight);
        }

        return b.Clone(cloneRect, b.PixelFormat);
    }
}

Also make sure that you have also disposed the bitmap returned by this function by wrapping the caller in a usingstatement:

还要确保您还通过将调用者包装在using语句中来处理此函数返回的位图:

using (Bitmap b = GetSprite(true, 0, 5))
{
    // do whatever you needed to do with the bitmap here
}

回答by user2798923

I found also this trying to look for answers. be aware that it can also throw the exception when:

我也发现这试图寻找答案。请注意,它也可以在以下情况下抛出异常:

stream contains a PNG image file with a single dimension greater than 65,535 pixels.

stream 包含一个单一维度大于 65,535 像素的 PNG 图像文件。

http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx

http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx