System.Drawing-参数无效 [英] System.Drawing - Parameter is not valid

查看:183
本文介绍了System.Drawing-参数无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过更多测试后,我发现此问题可能是由于图像无法及时加载以克隆到位图并显示而导致的。

注意:是的,标题中还存在其他与此错误有关的问题,但是从一些研究看来,是一个有许多可能原因的模棱两可的错误。我没有发现与我的情况相同的任何问题。

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.

我遇到以下错误。

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

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

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):

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);
    }
}

具体来说,第四行:

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

代码的简化目标是基于spriteset索引和sprite索引从spriteset返回一个包含sprite的位图。该位图显示在PictureBox中,直到将其更改为其他图像为止。我知道逻辑是可行的。这不是这里的问题。我用来测试的.png是384 * 256。

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.

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

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.Drawing itself but I can't seem to track it down.

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

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).

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()


推荐答案

泄漏的句柄最终会导致内存问题,但在这种情况下并不是问题(感谢那些反正指出它们的人,学到了一些新知识)。

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.

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

I got around this with a simple 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.

另外,pstrjds,感谢您的清理工作;)在某些重构过程中一定会产生混乱。猜猜我只是忘了它。

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

这篇关于System.Drawing-参数无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆