C# 在图片框中移动位图

发布于 2024-12-06 00:48:03 字数 1371 浏览 1 评论 0原文

我使用 LockBits 从循环数组创建图像,并缩放到 PictureBox.Width * n 和高度:

using (var bmp = new Bitmap(len, _height, PixelFormat.Format24bppRgb))
{
            var data = bmp.LockBits(new Rectangle(0, 0, len, _height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var bytes = data.Stride * data.Height;
            var rgb = new byte[bytes];
            var ptr = data.Scan0;
            Marshal.Copy(data.Scan0, rgb, 0, bytes);


            // …fill array „rgb“

            Marshal.Copy(rgb, 0, ptr, bytes);
            bmp.UnlockBits(data);

            g = _pictureBox.CreateGraphics();
            g.InterpolationMode = InterpolationMode.Default;
            g.DrawImage(bmp, _pictureBox.Width - len * _scaleWidth, 0, len * _scaleWidth, _pictureBox.Height);
}

在下一次迭代中:

Graphics g;
        using (var bmp = new Bitmap(_pictureBox.Image))
        {
            g = _pictureBox.CreateGraphics();
            g.InterpolationMode = InterpolationMode.Default;
            g.DrawImage(_pictureBox.Image, new RectangleF(0, 0, _pictureBox.Width - len * _scaleWidth, _pictureBox.Height), new RectangleF(len * _scaleWidth, 0, _pictureBox.Width * _scaleWidth - len, _height), GraphicsUnit.Pixel);
        }
        g.Dispose();

简而言之:我剪切并复制了会移动图片的图像部分,但没有得到任何内容。是否可能是因为上一步中的规模? 也许我错了。建议用于移动并添加新位图到末尾的算法。

I create image with LockBits from array in cycle and scale to PictureBox.Width * n and Height:

using (var bmp = new Bitmap(len, _height, PixelFormat.Format24bppRgb))
{
            var data = bmp.LockBits(new Rectangle(0, 0, len, _height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            var bytes = data.Stride * data.Height;
            var rgb = new byte[bytes];
            var ptr = data.Scan0;
            Marshal.Copy(data.Scan0, rgb, 0, bytes);


            // …fill array „rgb“

            Marshal.Copy(rgb, 0, ptr, bytes);
            bmp.UnlockBits(data);

            g = _pictureBox.CreateGraphics();
            g.InterpolationMode = InterpolationMode.Default;
            g.DrawImage(bmp, _pictureBox.Width - len * _scaleWidth, 0, len * _scaleWidth, _pictureBox.Height);
}

In the next iterateration:

Graphics g;
        using (var bmp = new Bitmap(_pictureBox.Image))
        {
            g = _pictureBox.CreateGraphics();
            g.InterpolationMode = InterpolationMode.Default;
            g.DrawImage(_pictureBox.Image, new RectangleF(0, 0, _pictureBox.Width - len * _scaleWidth, _pictureBox.Height), new RectangleF(len * _scaleWidth, 0, _pictureBox.Width * _scaleWidth - len, _height), GraphicsUnit.Pixel);
        }
        g.Dispose();

In short: I cut and copy part of the image that would shift the picture, but do not get anything. Is it possible because of the scale in the previous step?
Maybe I'm wrong. Advise the algorithm for shifting and adding a new Bitmap into an end.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

落花浅忆 2024-12-13 00:48:04

我建议您在 Form 实例中使用 Control.CreateGraphics() 方法,并直接在 Form 上写入,因为 PaintBox 控件非常慢。

尝试使用我的辅助函数,这将允许您使用 Win32 Interop 使用 StretchBlt(拉伸)或 BitBlt(无拉伸)来粘贴位图的一部分:

示例用法:

Graphics graphics = ...;
graphics.GdiDrawImage
(
    image, 
    new Rectangle(
        (int)rectangle.Left, 
        (int)rectangle.Top, 
        (int)rectangle.Width, 
        (int)rectangle.Height
    ), 
    0, 0, image.Width, image.Height
);

源代码:

public static class GraphicsHelper
{
    public static void GdiDrawImage(this Graphics graphics, Bitmap image, Rectangle rectangleDst, int nXSrc, int nYSrc, int nWidth, int nHeight)
    {
        IntPtr hdc = graphics.GetHdc();
        IntPtr memdc = GdiInterop.CreateCompatibleDC(hdc);
        IntPtr bmp = image.GetHbitmap();
        GdiInterop.SelectObject(memdc, bmp);
        GdiInterop.SetStretchBltMode(hdc, 0x04);
        GdiInterop.StretchBlt(hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, nWidth, nHeight, GdiInterop.TernaryRasterOperations.SRCCOPY);
        //GdiInterop.BitBlt(..) put it here, if you did not mention stretching the source image
        GdiInterop.DeleteObject(bmp);
        GdiInterop.DeleteDC(memdc);
        graphics.ReleaseHdc(hdc);
    }
}

public class GdiInterop
{
    /// <summary>
    /// Enumeration for the raster operations used in BitBlt.
    /// In C++ these are actually #define. But to use these
    /// constants with C#, a new enumeration _type is defined.
    /// </summary>
    public enum TernaryRasterOperations
    {
        SRCCOPY = 0x00CC0020, // dest = source
        SRCPAINT = 0x00EE0086, // dest = source OR dest
        SRCAND = 0x008800C6, // dest = source AND dest
        SRCINVERT = 0x00660046, // dest = source XOR dest
        SRCERASE = 0x00440328, // dest = source AND (NOT dest)
        NOTSRCCOPY = 0x00330008, // dest = (NOT source)
        NOTSRCERASE = 0x001100A6, // dest = (NOT src) AND (NOT dest)
        MERGECOPY = 0x00C000CA, // dest = (source AND pattern)
        MERGEPAINT = 0x00BB0226, // dest = (NOT source) OR dest
        PATCOPY = 0x00F00021, // dest = pattern
        PATPAINT = 0x00FB0A09, // dest = DPSnoo
        PATINVERT = 0x005A0049, // dest = pattern XOR dest
        DSTINVERT = 0x00550009, // dest = (NOT dest)
        BLACKNESS = 0x00000042, // dest = BLACK
        WHITENESS = 0x00FF0062, // dest = WHITE
    };

    /// <summary>
    /// Enumeration to be used for those Win32 function 
    /// that return BOOL
    /// </summary>
    public enum Bool
    {
        False = 0,
        True
    };

    /// <summary>
    /// Sets the background color.
    /// </summary>
    /// <param name="hdc">The HDC.</param>
    /// <param name="crColor">Color of the cr.</param>
    /// <returns></returns>
    [DllImport("gdi32.dll")]
    public static extern int SetBkColor(IntPtr hdc, int crColor);

    /// <summary>
    /// CreateCompatibleDC
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

    /// <summary>
    /// DeleteDC
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteDC(IntPtr hdc);

    /// <summary>
    /// SelectObject
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true)]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

    /// <summary>
    /// DeleteObject
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteObject(IntPtr hObject);

    /// <summary>
    /// CreateCompatibleBitmap
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hObject, int width, int height);

    /// <summary>
    /// BitBlt
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

    /// <summary>
    /// StretchBlt
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool StretchBlt(IntPtr hObject, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hObjSource, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, TernaryRasterOperations dwRop);

    /// <summary>
    /// SetStretchBltMode
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool SetStretchBltMode(IntPtr hObject, int nStretchMode);
}

I advice you to use Control.CreateGraphics() method at Form instance, and write on a Form directly, because PaintBox control is quite slow.

Try using my helper function, this will allow you to paste a portion of your bitmap using StretchBlt (stretching) or BitBlt (no stretching) using Win32 Interop:

Sample usage:

Graphics graphics = ...;
graphics.GdiDrawImage
(
    image, 
    new Rectangle(
        (int)rectangle.Left, 
        (int)rectangle.Top, 
        (int)rectangle.Width, 
        (int)rectangle.Height
    ), 
    0, 0, image.Width, image.Height
);

Source code:

public static class GraphicsHelper
{
    public static void GdiDrawImage(this Graphics graphics, Bitmap image, Rectangle rectangleDst, int nXSrc, int nYSrc, int nWidth, int nHeight)
    {
        IntPtr hdc = graphics.GetHdc();
        IntPtr memdc = GdiInterop.CreateCompatibleDC(hdc);
        IntPtr bmp = image.GetHbitmap();
        GdiInterop.SelectObject(memdc, bmp);
        GdiInterop.SetStretchBltMode(hdc, 0x04);
        GdiInterop.StretchBlt(hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, nWidth, nHeight, GdiInterop.TernaryRasterOperations.SRCCOPY);
        //GdiInterop.BitBlt(..) put it here, if you did not mention stretching the source image
        GdiInterop.DeleteObject(bmp);
        GdiInterop.DeleteDC(memdc);
        graphics.ReleaseHdc(hdc);
    }
}

public class GdiInterop
{
    /// <summary>
    /// Enumeration for the raster operations used in BitBlt.
    /// In C++ these are actually #define. But to use these
    /// constants with C#, a new enumeration _type is defined.
    /// </summary>
    public enum TernaryRasterOperations
    {
        SRCCOPY = 0x00CC0020, // dest = source
        SRCPAINT = 0x00EE0086, // dest = source OR dest
        SRCAND = 0x008800C6, // dest = source AND dest
        SRCINVERT = 0x00660046, // dest = source XOR dest
        SRCERASE = 0x00440328, // dest = source AND (NOT dest)
        NOTSRCCOPY = 0x00330008, // dest = (NOT source)
        NOTSRCERASE = 0x001100A6, // dest = (NOT src) AND (NOT dest)
        MERGECOPY = 0x00C000CA, // dest = (source AND pattern)
        MERGEPAINT = 0x00BB0226, // dest = (NOT source) OR dest
        PATCOPY = 0x00F00021, // dest = pattern
        PATPAINT = 0x00FB0A09, // dest = DPSnoo
        PATINVERT = 0x005A0049, // dest = pattern XOR dest
        DSTINVERT = 0x00550009, // dest = (NOT dest)
        BLACKNESS = 0x00000042, // dest = BLACK
        WHITENESS = 0x00FF0062, // dest = WHITE
    };

    /// <summary>
    /// Enumeration to be used for those Win32 function 
    /// that return BOOL
    /// </summary>
    public enum Bool
    {
        False = 0,
        True
    };

    /// <summary>
    /// Sets the background color.
    /// </summary>
    /// <param name="hdc">The HDC.</param>
    /// <param name="crColor">Color of the cr.</param>
    /// <returns></returns>
    [DllImport("gdi32.dll")]
    public static extern int SetBkColor(IntPtr hdc, int crColor);

    /// <summary>
    /// CreateCompatibleDC
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

    /// <summary>
    /// DeleteDC
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteDC(IntPtr hdc);

    /// <summary>
    /// SelectObject
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true)]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

    /// <summary>
    /// DeleteObject
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool DeleteObject(IntPtr hObject);

    /// <summary>
    /// CreateCompatibleBitmap
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr CreateCompatibleBitmap(IntPtr hObject, int width, int height);

    /// <summary>
    /// BitBlt
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

    /// <summary>
    /// StretchBlt
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool StretchBlt(IntPtr hObject, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hObjSource, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, TernaryRasterOperations dwRop);

    /// <summary>
    /// SetStretchBltMode
    /// </summary>
    [DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
    public static extern Bool SetStretchBltMode(IntPtr hObject, int nStretchMode);
}
烟若柳尘 2024-12-13 00:48:04

注意:这不是问题的完整答案,但我想为现有答案提供一些有用的信息。

与 Artur Mustafin 的答案相反,我建议不要直接使用 Windows GDI,但要使用 图形 类。在我的测试中,它们的性能比 GDI 函数好得多。

GDI代码取自Artur Mustafin的答案。
测试通过在 Paint 事件中进行绘制,在 1k x 1k Picturebox 中显示 1Mpix (1k x 1k) 位图或 100Mpix (10k x 10k) 位图的图像。
测试是在 Windows 7 Pro x64 SP1、调试模式、Intel Core i7-3630QM CPU @ 2.4 GHz、16 GB RAM 上的 Visual Studio 2015.3 中完成的。

结果:

1000x Graphics.DrawImage() unscaled       of 100M Bitmap:   36.8s (x86),  24.2s (x64).
1000x Graphics.DrawImage() unscaled       of   1M Bitmap:    5.2s (x86),   3.8s (x64).
 100x Graphics.DrawImage() scaled         of 100M Bitmap:   62.8s (x86),  39.0s (x64).
1000x Graphics.DrawImage() scaled         of   1M Bitmap:    5.2s (x86),   3.8s (x64).
 100x GdiDrawImage() StretchBlockTransfer of 100M Bitmap:  OutOfMem@x86,  88.5s (x64).
1000x GdiDrawImage() StretchBlockTransfer of   1M Bitmap:   12.9s (x86),  11.5s (x64).
 100x GdiDrawImage() BitBlockTransfer     of 100M Bitmap:  OutOfMem@x86,  49.7s (x64).
1000x GdiDrawImage() BitBlockTransfer     of   1M Bitmap:    7.2s (x86),   5.8s (x64).

测试代码:

public partial class FormPictureboxPaint : Form
{
  private Bitmap m_oBitmap;

  public FormPictureboxPaint ()
  {
    InitializeComponent ();

    string sFile = Application.StartupPath + @"\..\..\..\bitmap.png";  // The bitmap file contains an image with 10k x 10k pixels.
    m_oBitmap = new Bitmap (sFile);

    if (false)  // CHANGE TO TRUE IF TESTING WITH 1k x 1k BITMAPS
    {
      var oBitmap = new Bitmap (m_oBitmap, new Size (1000, 1000));

      m_oBitmap.Dispose ();
      m_oBitmap = null;
      GC.Collect ();
      GC.WaitForFullGCComplete ();
      GC.WaitForPendingFinalizers ();

      m_oBitmap = oBitmap;
    }
  }

  private void pictureBox1_Paint (object sender, PaintEventArgs e)
  {
    var oGraphics = e.Graphics;
    DateTime dtNow = DateTime.Now;

    // UNCOMMENT THE FOLLOWING LINES FOR TESTS WITH DrawImage
    // COMMENT THE FOLLOWING LINES FOR TESTS WITH GDI
    //for (int ixCnt = 0; ixCnt < 1000; ixCnt++)
    //  PictureboxPaint01 (oGraphics);

    // COMMENT THE FOLLOWING LINES FOR TESTS WITH DrawImage
    // UNCOMMENT THE FOLLOWING LINES FOR TESTS WITH GDI
    for (int ixCnt = 0; ixCnt < 100; ixCnt++)
      PictureboxPaint02 (oGraphics);

    TimeSpan ts = (DateTime.Now - dtNow);
  }

  private void PictureboxPaint01 (Graphics i_oGraphics)
  {
    //_oGraphics.DrawImage (m_oBitmap, new Point ());
    i_oGraphics.DrawImage (m_oBitmap, new Rectangle (0, 0, 1000, 1000));
  }

  private void PictureboxPaint02 (Graphics i_oGraphics)
  {
    // from https://stackoverflow.com/a/7481071
    i_oGraphics.GdiDrawImage
    (
        m_oBitmap,
        new Rectangle (
            (int)pictureBox1.Left,
            (int)pictureBox1.Top,
            (int)pictureBox1.Width,
            (int)pictureBox1.Height
        ),
        0, 0, m_oBitmap.Width, m_oBitmap.Height
    );
  }
}

public static class GraphicsHelper
{
  public static void GdiDrawImage (this Graphics graphics, Bitmap image, Rectangle rectangleDst, int nXSrc, int nYSrc, int nWidth, int nHeight)
  {
    IntPtr hdc = graphics.GetHdc ();
    IntPtr memdc = GdiInterop.CreateCompatibleDC (hdc);
    IntPtr bmp = image.GetHbitmap ();
    GdiInterop.SelectObject (memdc, bmp);
    GdiInterop.SetStretchBltMode (hdc, 0x04);
    GdiInterop.StretchBlt (hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, nWidth, nHeight, GdiInterop.TernaryRasterOperations.SRCCOPY);
    //GdiInterop.BitBlt (hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, GdiInterop.TernaryRasterOperations.SRCCOPY); //put it here, if you did not mention stretching the source image
    GdiInterop.DeleteObject (bmp);
    GdiInterop.DeleteDC (memdc);
    graphics.ReleaseHdc (hdc);
  }
}

public class GdiInterop
{
  public enum TernaryRasterOperations
  {
    SRCCOPY = 0x00CC0020, // dest = source
  };

  public enum Bool
  {
    False = 0,
    True
  };

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern IntPtr CreateCompatibleDC (IntPtr hDC);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool DeleteDC (IntPtr hdc);

  [DllImport ("gdi32.dll", ExactSpelling = true)]
  public static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool DeleteObject (IntPtr hObject);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool BitBlt (IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool StretchBlt (IntPtr hObject, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hObjSource, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, TernaryRasterOperations dwRop);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool SetStretchBltMode (IntPtr hObject, int nStretchMode);
}

Notice: This is no full answer to the question, but I want to provide some useful information to the existing answer.

In contrast to the answer of Artur Mustafin, I suggest not to use the Windows GDI directly, but to use the .net methods of the Graphics class. In my tests they have performed a lot better than the GDI functions.

The GDI code is taken from the answer of Artur Mustafin.
The test was displaying an image of 1Mpix (1k x 1k) Bitmap or 100Mpix (10k x 10k) Bitmap in 1k x 1k Picturebox by drawing in the Paint event.
The tests were done in Visual Studio 2015.3 on Windows 7 Pro x64 SP1, Debug mode, on an Intel Core i7-3630QM CPU @ 2.4 GHz, 16 GB RAM.

Results:

1000x Graphics.DrawImage() unscaled       of 100M Bitmap:   36.8s (x86),  24.2s (x64).
1000x Graphics.DrawImage() unscaled       of   1M Bitmap:    5.2s (x86),   3.8s (x64).
 100x Graphics.DrawImage() scaled         of 100M Bitmap:   62.8s (x86),  39.0s (x64).
1000x Graphics.DrawImage() scaled         of   1M Bitmap:    5.2s (x86),   3.8s (x64).
 100x GdiDrawImage() StretchBlockTransfer of 100M Bitmap:  OutOfMem@x86,  88.5s (x64).
1000x GdiDrawImage() StretchBlockTransfer of   1M Bitmap:   12.9s (x86),  11.5s (x64).
 100x GdiDrawImage() BitBlockTransfer     of 100M Bitmap:  OutOfMem@x86,  49.7s (x64).
1000x GdiDrawImage() BitBlockTransfer     of   1M Bitmap:    7.2s (x86),   5.8s (x64).

Test code:

public partial class FormPictureboxPaint : Form
{
  private Bitmap m_oBitmap;

  public FormPictureboxPaint ()
  {
    InitializeComponent ();

    string sFile = Application.StartupPath + @"\..\..\..\bitmap.png";  // The bitmap file contains an image with 10k x 10k pixels.
    m_oBitmap = new Bitmap (sFile);

    if (false)  // CHANGE TO TRUE IF TESTING WITH 1k x 1k BITMAPS
    {
      var oBitmap = new Bitmap (m_oBitmap, new Size (1000, 1000));

      m_oBitmap.Dispose ();
      m_oBitmap = null;
      GC.Collect ();
      GC.WaitForFullGCComplete ();
      GC.WaitForPendingFinalizers ();

      m_oBitmap = oBitmap;
    }
  }

  private void pictureBox1_Paint (object sender, PaintEventArgs e)
  {
    var oGraphics = e.Graphics;
    DateTime dtNow = DateTime.Now;

    // UNCOMMENT THE FOLLOWING LINES FOR TESTS WITH DrawImage
    // COMMENT THE FOLLOWING LINES FOR TESTS WITH GDI
    //for (int ixCnt = 0; ixCnt < 1000; ixCnt++)
    //  PictureboxPaint01 (oGraphics);

    // COMMENT THE FOLLOWING LINES FOR TESTS WITH DrawImage
    // UNCOMMENT THE FOLLOWING LINES FOR TESTS WITH GDI
    for (int ixCnt = 0; ixCnt < 100; ixCnt++)
      PictureboxPaint02 (oGraphics);

    TimeSpan ts = (DateTime.Now - dtNow);
  }

  private void PictureboxPaint01 (Graphics i_oGraphics)
  {
    //_oGraphics.DrawImage (m_oBitmap, new Point ());
    i_oGraphics.DrawImage (m_oBitmap, new Rectangle (0, 0, 1000, 1000));
  }

  private void PictureboxPaint02 (Graphics i_oGraphics)
  {
    // from https://stackoverflow.com/a/7481071
    i_oGraphics.GdiDrawImage
    (
        m_oBitmap,
        new Rectangle (
            (int)pictureBox1.Left,
            (int)pictureBox1.Top,
            (int)pictureBox1.Width,
            (int)pictureBox1.Height
        ),
        0, 0, m_oBitmap.Width, m_oBitmap.Height
    );
  }
}

public static class GraphicsHelper
{
  public static void GdiDrawImage (this Graphics graphics, Bitmap image, Rectangle rectangleDst, int nXSrc, int nYSrc, int nWidth, int nHeight)
  {
    IntPtr hdc = graphics.GetHdc ();
    IntPtr memdc = GdiInterop.CreateCompatibleDC (hdc);
    IntPtr bmp = image.GetHbitmap ();
    GdiInterop.SelectObject (memdc, bmp);
    GdiInterop.SetStretchBltMode (hdc, 0x04);
    GdiInterop.StretchBlt (hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, nWidth, nHeight, GdiInterop.TernaryRasterOperations.SRCCOPY);
    //GdiInterop.BitBlt (hdc, rectangleDst.Left, rectangleDst.Top, rectangleDst.Width, rectangleDst.Height, memdc, nXSrc, nYSrc, GdiInterop.TernaryRasterOperations.SRCCOPY); //put it here, if you did not mention stretching the source image
    GdiInterop.DeleteObject (bmp);
    GdiInterop.DeleteDC (memdc);
    graphics.ReleaseHdc (hdc);
  }
}

public class GdiInterop
{
  public enum TernaryRasterOperations
  {
    SRCCOPY = 0x00CC0020, // dest = source
  };

  public enum Bool
  {
    False = 0,
    True
  };

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern IntPtr CreateCompatibleDC (IntPtr hDC);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool DeleteDC (IntPtr hdc);

  [DllImport ("gdi32.dll", ExactSpelling = true)]
  public static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool DeleteObject (IntPtr hObject);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool BitBlt (IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool StretchBlt (IntPtr hObject, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest, IntPtr hObjSource, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, TernaryRasterOperations dwRop);

  [DllImport ("gdi32.dll", ExactSpelling = true, SetLastError = true)]
  public static extern Bool SetStretchBltMode (IntPtr hObject, int nStretchMode);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文