C# Image.Save exception";GDI&\x2B;中发生了一般错误&引用;保存到MemoryStream时

C# Image.Save exception";GDI&\x2B;中发生了一般错误&引用;保存到MemoryStream时,c#,image,gdi+,C#,Image,Gdi+,我有一个服务器客户端应用程序,我想从服务器上获取一个屏幕截图,但是在行bitmap.Save(ms,System.Drawing.Imaging.ImageFormat.Png)我得到了这个异常:GDI+中发生了一个通用错误。 private Socket ScreenSocket; private MemoryStream ms; public void ConnectScreenShot(IPEndPoint ep) { if (ScreenS

我有一个服务器客户端应用程序,我想从服务器上获取一个屏幕截图,但是在行
bitmap.Save(ms,System.Drawing.Imaging.ImageFormat.Png)
我得到了这个异常:
GDI+中发生了一个通用错误。

    private Socket ScreenSocket;
    private MemoryStream ms;
    public void ConnectScreenShot(IPEndPoint ep)
    {
        if (ScreenSocket != null)
        {
            ScreenSocket.Dispose();
            ScreenSocket = null;
        }
        if (ms != null)
        {
            ms.Dispose();
            ms = null;
        }
        ScreenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        ScreenSocket.Connect(ep);
        ms = new MemoryStream();
        Rectangle bounds = Screen.GetBounds(Point.Empty);
        using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
        {
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(Point.Empty, Point.Empty, bitmap.Size);
            }
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        }
    }
为什么会发生这种情况?我该如何解决

更新:当我使用
ImageFormat.Jpeg
而不是
ImageFormat.Png
时,它可以工作,但我仍然需要一个Png格式。

你说:

我想从服务器上得到一个屏幕截图

与GDI+相关的错误表明运行此代码的上下文可能是服务上下文(如IIS),而不是桌面。对吗?如果是这样,你希望在截图中返回什么

作为记录,以下(最小)代码可以正常工作:

    var ms = new MemoryStream();
    Rectangle bounds = Screen.GetBounds(Point.Empty);
    using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
    {
        using (Graphics g = Graphics.FromImage(bitmap))
        {
            g.CopyFromScreen(Point.Empty, Point.Empty, bitmap.Size);
        }
        bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
    }

bitmap
ms
都包含预期的数据。因此,我认为您需要提供有关此代码在何处以及以何种方式运行的信息。

它以这种方式与我一起工作:

  • 当客户想要接收屏幕截图时,在开始传输之前,您需要知道图像大小。
    调用
    GetScreenShotSize()
    获取图像的大小

  • 获得尺寸后,调用
    GetScreenShot()
    接收图像数据

我使用了
using(MemoryStream ms=new MemoryStream())
所以现在PNG格式可以工作了

    private Image img = null;
    public long GetScreenShotSize()
    {
        Rectangle bounds = Screen.GetBounds(Point.Empty);
        using (Bitmap bmp = new Bitmap(bounds.Width, bounds.Height))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
            }
            using (MemoryStream ms = new MemoryStream())
            {
                bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                img = Image.FromStream(ms);
                return ms.Length;
            }
        }
    }
    public void GetScreenShot(IPEndPoint ep)
    {
        using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
        {
            socket.Connect(ep);
            using (MemoryStream ms = new MemoryStream())
            {
                img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                socket.Send(ms.ToArray(), SocketFlags.None);
            }
            img.Dispose();
            img = null;
        }
    }

对我来说,我使用的是
Image.Save(Stream,ImageCodecInfo,EncoderParameters)
,这显然是导致GDI+
中发生的臭名昭著的
一般错误的原因

我试图使用
EncoderParameter
以100%的质量保存JPEG。这在“我的机器”(doh!)上运行得很好,而不是在生产上

当我使用
Image.Save(Stream,ImageFormat)
时,错误消失了!所以像个白痴一样,我继续使用后者,尽管它在默认质量上节省了它们,我假设只有50%


希望这些信息能帮助到别人。

我知道这是一篇老文章,但我也想添加这些信息,以防像我这样的人将来遇到这个问题

我无法保存.PNG图像和它,因为IIS应用程序池帐户无权访问此密钥

HKEY_CLASSES_ROOT\CLSID{FAE3D380-FEA4-4623-8C75-C6B61110B681}


当您使用png图形时,这是必需的。

不确定这是否有用。但是,您是否可以在
CopyFromScreen
之后将图形对象传递回?或者你的方法必须是无效的?或者实际上可能只是你的位图对象。@meanbunny我不确定我是否明白你的意思,但CopyFromScreen不是我的方法,它是Graphics.CopyFromScreen方法!是的,我想我的重点是,如果这是你的意图,你打算如何将你的位图返回给你的客户。不管怎样,这里有一个帖子可能会对你有所帮助。或者这个问题没有足够的文档记录来冒险回答。如果这是Windows 2008 Server核心,它肯定不会正常工作。这是一个WCF服务,如果我将该行更改为
bitmap.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg),我可以获得一个屏幕截图并成功发送它但当ImageFormat为Png时,我会出现该错误。请尝试使用
块将所有内容移出
。似乎存在过早关闭流的问题。最终,这取决于您想用
ms
做什么。这种孤立的代码总是很困难的。你能翻译你的注释和函数名吗?虽然这个答案可能是正确的和有用的,但是如果你在答案中加入一些解释来解释它是如何帮助解决问题的,那就更好了。如果有一个变化(可能是无关的)导致它停止工作,并且用户需要了解它曾经是如何工作的,这在将来会变得特别有用。@PaulTomkiel
//Aqui-se-me-cae.Aqui-se-me-cae.Aqui
的意思是
//这里它失败了。这里它失败了。这里
abrirConexion();
cmd = new SqlCommand(" INSERT INTO [SICRE_BI].[Credito_CCSS].[bi_img](Descripcion,img) VALUES (@nom_img,@img)",cn);                                
cmd.Parameters.Add("@Descripcion", SqlDbType.NChar);
cmd.Parameters.Add("@img", SqlDbType.Image);

cmd.Parameters["@Descripcion"].Value = descripcion;

System.IO.MemoryStream ms = new System.IO.MemoryStream();

pbImagen.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);//Aqui se me cae.Aqui se me cae.Aqui .

cmd.Parameters["@img"].Value = ms.GetBuffer();    //ms.GetBuffer();

cmd.ExecuteNonQuery();
return true;