关于C#中PictureBox加载动态GIF所出现的BUG以及解决方法

近日项目,需要用到动态的GIF做背景。于是从PictureBox继承了一个控件,希望以最少的代码解决动态背景的问题。
 
     起先一切都顺利,用PictureBox的Image属性很快就能够搞定一切,能够支持的图片格式也基本满足要求,遂以为一切大功告成。工作完成,我需要将背景图片等信息保存,然后在另外一个程序中打开、运行(一个设计时效果,一个运行时效果)。然而,再次打开时,程序报错:GDI+中出现一般性错误(Generic error in GDI+),报错的代码是base.Paint(e),也就是执行PictureBox基类的Paint函数时出错。
 
    保存图片的代码是这样的:
              MemoryStream ms = new MemoryStream();
              this.Image.Save(ms, Image.RawFormat);
 
              byte[] serializedObject = ms.ToArray();
              ms.Close();
              XmlElement value = node.OwnerDocument.CreateElement("Image");
              String strImage = Convert.ToBase64String(serializedObject);
              value.AppendChild(node.OwnerDocument.CreateTextNode(strImage));
              bkImage.AppendChild(value);
 
  打开是其逆过程:
            XmlElement value = xmlImage.SelectSingleNode("Image") as XmlElement;
            if (value == null)
                return;
            byte[] dsBytes;
            dsBytes = Convert.FromBase64String(value.InnerText);
            if (dsBytes.Length > 0)
            {
                MemoryStream ms = new MemoryStream(dsBytes);
                this.Image = Image.FromStream(ms);
 
                ms.Close();
            }
 
  自认为这样的代码不会有错的,除非反持续化过程中图片的格式发生了改变。可是跟踪下去,发现持续化前后图片类型的GUID是相同的,由此肯定图片格式没有出错。
 
    那问题在哪里?
 
    VS2005的异常报告里面显示,是在Image.SelectActiveFrame()这个函数里面出错了,查MSDN,没有任何有用的信息。于是Google,一搜才知道,原来不少人都遇到了这个问题。于是兴奋,以为会有很好的解决方法。可惜失望了,遇到这个问题的人不少,可有解决方法的却寥寥无几。似乎我找到的唯一的一个解决办法就是使用Load()函数代替动态创建图片,这显然不能满足我的需求(我需要将图片也保存到XML字段中)。
 
   无奈,只能自己想办法。
 
  找不到问题的原因(不能跟踪,系统代码),就只能猜测。我的思路是:我仅仅保存了Image属性的图片,也许,Image属性还有其它分量。那么,我应当保存整个Image属性,而不仅仅是其引用的图片。
 
于是修改代码,保存属性的代码如下:
            if (this.Image != null)
            {
                bkImage.SetAttribute("IsSet", "1");
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
                PropertyDescriptor ptyImage = properties.Find("Image", false);
                if (ptyImage != null)
                {
                    MemoryStream ms = new MemoryStream();
                    BinaryFormatter format = new BinaryFormatter();
                    object obj = ptyImage.GetValue(this);
                    format.Serialize(ms, obj);
                    ms.Seek(0, 0);
                    byte[] serializedObject = ms.ToArray();
                    ms.Close();
                    XmlElement value = node.OwnerDocument.CreateElement("Image");
                    String strImage = Convert.ToBase64String(serializedObject);
                    value.AppendChild(node.OwnerDocument.CreateTextNode(strImage));
                    bkImage.AppendChild(value);
                }
            }
            else
                bkImage.SetAttribute("IsSet", "0");
 
恢复属性的代码:
             byte[] dsBytes;
            dsBytes = Convert.FromBase64String(value.InnerText);
            if (dsBytes.Length > 0)
            {
                MemoryStream ms = new MemoryStream(dsBytes);
                BinaryFormatter format = new BinaryFormatter();
                object obj = format.Deserialize(ms);
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
                PropertyDescriptor ptyImage = properties.Find("Image", false);
                if (ptyImage != null)
                    ptyImage.SetValue(this, obj);
                ms.Close();
            }
 
编译,通过;运行,保存成功;关闭,再次打开,GIF在动,激动啊!
 
总结:我把整个属性以二进制的形式保存下来,这些内容相当于是从内存里面抠出来的,等到需要的时候再次写回内存,类似于XP里面的休眠机制,能够避免一些系统底层的未知原因导致的错误。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值