Search code examples
c#bitmapinterpolationdrawimagelockbits

C# Move bitmap in picturebox


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.


Solution

  • 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);
    }