Graphics.DrawImage大图像的替代方案

本文关键字:方案 图像 DrawImage Graphics | 更新日期: 2023-09-27 18:24:56

我正试图在图像上绘制一个反转颜色的十字线("加号"),以显示图像中选定点的位置。我就是这样做的:

private static void DrawInvertedCrosshair(Graphics g, Image img, PointF location, float length, float width)
{
    float halfLength = length / 2f;
    float halfWidth = width / 2f;
    Rectangle absHorizRect = Rectangle.Round(new RectangleF(location.X - halfLength, location.Y - halfWidth, length, width));
    Rectangle absVertRect = Rectangle.Round(new RectangleF(location.X - halfWidth, location.Y - halfLength, width, length));
    ImageAttributes attributes = new ImageAttributes();
    float[][] invertMatrix =
    { 
        new float[] {-1,  0,  0,  0,  0 },
        new float[] { 0, -1,  0,  0,  0 },
        new float[] { 0,  0, -1,  0,  0 },
        new float[] { 0,  0,  0,  1,  0 },
        new float[] { 1,  1,  1,  0,  1 }
    };
    ColorMatrix matrix = new ColorMatrix(invertMatrix);
    attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
    g.DrawImage(img, absHorizRect, absHorizRect.X, absHorizRect.Y, absHorizRect.Width, absHorizRect.Height, GraphicsUnit.Pixel, attributes);
    g.DrawImage(img, absVertRect, absVertRect.X, absVertRect.Y, absVertRect.Width, absVertRect.Height, GraphicsUnit.Pixel, attributes);
}

它如预期的那样工作,然而,它真的很慢。我希望用户能够用鼠标移动选定的位置,只要光标移动,就可以将位置设置为光标的位置。不幸的是,在我的电脑上,对于大图像,它每秒只能更新一次。

因此,我正在寻找一种替代使用Graphics.DrawImage来反转图像区域的方法。是否有任何方法可以在速度与所选区域区域而非整个图像区域成比例的情况下执行此操作?

Graphics.DrawImage大图像的替代方案

听起来你在关注错误的问题。绘制图像是缓慢的,而不是绘制"十字线"。

如果你不帮忙,大图像肯定会非常昂贵。而System.Drawing让它变得非常,很容易不帮上忙。为了使图像绘制速度更快,你想做的两件基本事情是可以实现的:

  • 避免强制图像绘制代码重新缩放图像。相反,只做一次,这样就可以直接一对一地绘制图像,而无需重新缩放。这样做的最佳时间是在加载图像时。可能在控件的Resize事件处理程序中再次出现。

  • 注意图像的像素格式。长镜头拍摄速度最快的是像素格式,它与图像存储在视频适配器中的方式直接兼容。因此,图像数据可以直接复制到视频RAM,而不必调整每个单独的像素。这种格式在99%的现代机器上都是PixelFormat.Format32pPArgb。这是一个巨大的差异,它比所有其他的快倍。

一种简单的辅助方法,可以在不处理纵横比的情况下实现这两种功能:

private static Bitmap Resample(Image img, Size size) {
    var bmp = new Bitmap(size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    using (var gr = Graphics.FromImage(bmp)) {
        gr.DrawImage(img, new Rectangle(Point.Empty, size));
    }
    return bmp;
}

在图形g上绘制一次图像,然后直接在图形g而不是图像上绘制十字线。您可以选择跟踪用户单击的位置,以便根据需要将它们保存在图像中或其他位置。