Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 图形图像速度_C#_Performance_Bitmap_Gdi_Drawimage - Fatal编程技术网

C# 图形图像速度

C# 图形图像速度,c#,performance,bitmap,gdi,drawimage,C#,Performance,Bitmap,Gdi,Drawimage,在我的程序中,我正在编写一个基本的图像编辑器。其中一部分允许用户绘制一个矩形区域,我弹出一个显示,显示缩放了3倍左右的区域(他们可以用鼠标滚轮进一步调整)。如果他们右键单击并拖动此图像,它将在原始图像上移动缩放区域,基本上起到放大镜的作用 问题是,即使在相对较小的位图上,我也发现了一些严重的性能问题。如果显示缩放区域的位图约为400x400,它仍会以鼠标移动的速度更新,并且非常平滑,但如果我将缩放方向盘向上移动到450x450左右,它会立即开始分块,如果是这样的话,每秒只会更新2次。我不明白为什

在我的程序中,我正在编写一个基本的图像编辑器。其中一部分允许用户绘制一个矩形区域,我弹出一个显示,显示缩放了3倍左右的区域(他们可以用鼠标滚轮进一步调整)。如果他们右键单击并拖动此图像,它将在原始图像上移动缩放区域,基本上起到放大镜的作用

问题是,即使在相对较小的位图上,我也发现了一些严重的性能问题。如果显示缩放区域的位图约为400x400,它仍会以鼠标移动的速度更新,并且非常平滑,但如果我将缩放方向盘向上移动到450x450左右,它会立即开始分块,如果是这样的话,每秒只会更新2次。我不明白为什么这么小的增长会导致如此巨大的性能问题。。。好像我达到了内存限制之类的。要缩放的源位图的大小似乎无关紧要,而只是缩放位图的大小

问题是我使用的是Graphics.DrawImage和PictureBox。通过阅读本网站,我发现这两个方面的性能通常都不是很好,但我对GDI的内部工作机制了解不够,无法提高我的速度。我希望你们中的一些人可能知道我的瓶颈在哪里,因为我可能只是以拙劣的方式使用这些工具,或者不知道有更好的工具来代替它

下面是我的鼠标事件和相关函数的一些片段

private void pictureBox_MouseDown(object sender, MouseEventArgs e)
    {

        else if (e.Button == System.Windows.Forms.MouseButtons.Right)
        {
            // slide the zoomed part to look at a different area of the original image
            if (zoomFactor > 1)
            {
                isMovingZoom = true;
                // try saving the graphics object?? are these settings helping at all??
                zoomingGraphics = Graphics.FromImage(displayImage);
                zoomingGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
                zoomingGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
                zoomingGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
                zoomingGraphics.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            }
        }
    }


private void pictureBox_MouseMove(object sender, MouseEventArgs e)
    {
        if (isMovingZoom)
        {
            // some computation on where they moved mouse ommitted here

            zoomRegion.X = originalZoomRegion.X + delta.X;
            zoomRegion.Y = originalZoomRegion.Y + delta.Y;
            zoomRegionEnlarged = scaleToOriginal(zoomRegion);

            // overwrite the existing displayImage to prevent more Bitmaps being allocated
            createZoomedImage(image.Bitmap, zoomRegionEnlarged, zoomFactor, displayImage, zoomingGraphics);
        }
    }

private void createZoomedImage(Bitmap source, Rectangle srcRegion, float zoom, Bitmap output, Graphics outputGraphics)
    {
        Rectangle destRect = new Rectangle(0, 0, (int)(srcRegion.Width * zoom), (int)(srcRegion.Height * zoom));

            outputGraphics.DrawImage(source, destRect, srcRegion, GraphicsUnit.Pixel);

        if (displayImage != originalDisplayImage && displayImage != output)
            displayImage.Dispose();
        setImageInBox(output);
    }

// sets the picture box image, as well as resizes the window to fit
    void setImageInBox(Bitmap bmp)
    {
        pictureBox.Image = bmp;
        displayImage = bmp;
        this.Width = pictureBox.Width + okButton.Width + SystemInformation.FrameBorderSize.Width * 2 + 25;
        this.Height = Math.Max(450, pictureBox.Height) + SystemInformation.CaptionHeight + SystemInformation.FrameBorderSize.Height * 2 + 20;
    }

private void pictureBox_MouseUp(object sender, MouseEventArgs e)
    {
        else if (e.Button == System.Windows.Forms.MouseButtons.Right)
        {
            if (isMovingZoom)
            {
                isMovingZoom = false;
                zoomingGraphics.Dispose();
            }
        }
    }
正如您所看到的,我不是每次要绘制一些东西时都声明一个新位图,而是重复使用一个旧位图(以及位图的图形对象,尽管我不知道重复调用graphics.FromImage是否会花费很多成本)。我尝试添加秒表来对代码进行基准测试,但我认为DrawImage会将功能传递给另一个线程,因此该功能声称可以相对快速地完成。当我不使用位图和图形对象时,我正在尝试
处理
所有位图和图形对象,并避免在
MouseMove
事件期间重复调用分配/取消分配资源。我使用的是
图片盒
,但我认为这不是问题所在


任何帮助,以加快这段代码或教我什么是发生在DrawImage是感激的!我已经修剪了一些多余的代码,以使其更美观,但是如果我意外地修剪了一些重要的东西,或者没有显示我如何使用可能会导致问题的东西,请让我知道,我将修改帖子。

我处理类似问题的方式是在接收绘制事件时,将整个图像绘制到内存位图中,然后把它扔到窗户上。 这样,所有的视觉闪光都被消除了,它看起来很快,即使它实际上不是

更清楚地说,我没有在鼠标事件处理程序中进行任何绘制。 我只是设置了主绘制处理程序所需的内容,然后执行失效。 因此,绘制将在鼠标事件完成后进行


补充:在评论中回答Tom的问题,我是这样做的。记住,我并不是说它很快,只是说它看起来很快,因为
\e.Graphics.DrawImage(bmToDrawOn,newpoint(0,0))立即显示。它只是从一个图像切换到下一个图像。
用户看不到窗口被清除,然后被重新绘制。
它提供了与双缓冲相同的效果

    Graphics grToDrawOn = null;
    Bitmap bmToDrawOn = null;

    private void DgmWin_Paint(object sender, PaintEventArgs _e){
        int w = ClientRectangle.Width;
        int h = ClientRectangle.Height;
        Graphics gr = _e.Graphics;

        // if the bitmap needs to be made, do so
        if (bmToDrawOn == null) bmToDrawOn = new Bitmap(w, h, gr);
        // if the bitmap needs to be changed in size, do so
        if (bmToDrawOn.Width != w || bmToDrawOn.Height != h){
            bmToDrawOn = new Bitmap(w, h, gr);
        }
        // hook the bitmap into the graphics object
        grToDrawOn = Graphics.FromImage(bmToDrawOn);
        // clear the graphics object before drawing
        grToDrawOn.Clear(Color.White);
        // paint everything
        DoPainting();
        // copy the bitmap onto the real screen
        _e.Graphics.DrawImage(bmToDrawOn, new Point(0,0));
    }

    private void DoPainting(){
        grToDrawOn.blahblah....
    }

您可能无法从这种方法中获得更多的性能。绝对值得花些时间学习
封送.复制
或指针(
锁位
位图数据
,等等)。您正在修补“缩放图形”设置,但真正重要的是“输出图形”。因为这是一个真正画图像的人。它在代码片段中从天而降,很难给出建议。你是说双缓冲吗?我认为这篇文章可能有用——它的工作与双缓冲相同,但它不是切换视频缓冲区,它的速度相当快,只需将块从内存位图传输到窗口即可。我所有的图形都是这样的,而且它看起来总是很快和动态的,即使实际的绘图代码没有那么快,因为你不必看着它写每一行、每一个文本等等。此外,它不必在绘制时进行窗口剪裁。在BLT期间,它一次完成所有操作。您介意说明一下您是如何做到的吗?我也有类似的问题。我已经在绘制内存位图,但我仍在使用Graphics.DrawImage将此位图绘制到我的(双缓冲)面板图形上。我很想知道如何更快地传输内存位图。太棒了,非常感谢!这大概就是我正在做的,我想你可能会使用一些Pinvoke魔法,比如老式的WinAPI BitBlt。出于某种奇怪的原因,我的画并不流畅,我还没有找到瓶颈。我在绘画上画了几千条线,每当onPaint被解雇时,我都会像你一样做事。当我将rubberband选择实现添加到onpaint时,它的变化非常剧烈,并且远远落后于鼠标光标:(@Tom:如果我有那么多线要画,我会开始过滤,因为很多线太小,看不见。无论线有多小,每次呼叫都会有一定的开销。此外,我希望你在绘画例程中没有做太多的
新的
。这是一个可怕的耗时过程。如果我发现自己这样做了,我会尝试重新使用pre-code>虚拟分配的对象。祝你好运!