After BitmapImage conversion, memory is not freed

I had a problem with the following C # code (test-):

    public static void TestBitmap2ByteArray(BitmapImage bitmap)
    {
        JpegBitmapEncoder encoder = new JpegBitmapEncoder();
        MemoryStream memstream = new MemoryStream();
        encoder.Frames.Add(BitmapFrame.Create(bitmap));
        encoder.Save(memstream);

        memstream.Close();
    }

Every time I call a function, memory is allocated and not freed. In a real project, the method is called very often, and the application runs out of memory.

This is a stripped-down version of the code that returns nothing.

I am using Visual Studio2010 and .net 3.5 SP1.

Help is appreciated. Thank.

+3
source share
2 answers

As described in my other answer, the best way to solve this is to directly access the bitmap image data. BitmapImage inherits from BitmapSource. BitmapSource is great for this, and also works with WPF binding.

BitmapSource , WPF ( MVVM). BitmapSource. / BitmapSource, WPF . "Bitmap", . . (, 4- 30 .. , .)

. :

unsafe {
   byte* imgBytePtr = (byte*)myBitmap.ImageData;
   Int32* imgInt32Ptr = (Int32*)myBitmap.ImageData;
   int height = (int)myBitmap.BitmapSource.Height;
   int width = (int)myBitmap.BitmapSource.Width;
   int bpp = myBitmap.BytesPerPixel;

   // Note: No need to iterate just for copy. A Marshal.Copy() at this point can copy all the bytes into a byte-array if you want.
   // But the best would be if your application could do its work directly in the imgBytePtr[]-array.

   for (int x = 0; x < height; x++)
   {
      for (int y = 0; y < width; y++)
      {
         // Get bytes into RGBA values
         int bytePos = x * (width * bpp) + (y * bpp);
         byte R = imgBytePtr[bytePos + 0];
         byte B = imgBytePtr[bytePos + 1];
         byte G = imgBytePtr[bytePos + 2];
         byte A = imgBytePtr[bytePos + 3];

         // Alternatively get Int32 value of color
         int intPos = x * width + y;
         int intColor = imgIntPtr[intPos];


         // Examples of manipulating data         

         // Remove blue
         imgBytePtr[bytePos + 1] = 0;
         // Alternative remove blue by bitmask
         imgIntPtr[intPos] = imgIntPtr[intPos] & 0xFF00FFFF; 

      }
   }
}
// Now execute Invalidate() and WPF will automagically update bound picture object :)

BitmapSource, BitmapImage, , .

    /// 
    /// This object holds a byte array of the picture as well as a BitmapSource for WPF objects to bind to. Simply call .Invalidate() to update GUI.
    /// 
    public class Bitmap : IDisposable
    {
        // some ideas/code borowed from CL NUI sample CLNUIImage.cs
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool UnmapViewOfFile(IntPtr hMap);
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr hHandle);

        private IntPtr _section = IntPtr.Zero;
        public IntPtr ImageData { get; private set; }
        public InteropBitmap BitmapSource { get; private set; }
        public int BytesPerPixel = 3;

        /// 
        /// Initializes an empty Bitmap
        /// 
        /// Image width
        /// Image height
        /// Image format
        public Bitmap(int width, int height, PixelFormat pixelFormat)
        {
            BytesPerPixel = pixelFormat.BitsPerPixel / 8;
            uint imageSize = (uint)width * (uint)height * (uint)BytesPerPixel;
            // create memory section and map
            _section = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, imageSize, null);
            ImageData = MapViewOfFile(_section, 0xF001F, 0, 0, imageSize);
            BitmapSource = Imaging.CreateBitmapSourceFromMemorySection(_section, width, height, pixelFormat, width * BytesPerPixel, 0) as InteropBitmap;
        }

        /// 
        /// Invalidates the bitmap causing a redraw
        /// 
        public void Invalidate()
        {
            BitmapSource.Invalidate();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
            }
            // free native resources if there are any.
            if (ImageData != IntPtr.Zero)
            {
                UnmapViewOfFile(ImageData);
                ImageData = IntPtr.Zero;
            }
            if (_section != IntPtr.Zero)
            {
                CloseHandle(_section);
                _section = IntPtr.Zero;
            }
        }
    }

+4

, . . , LockBits. , * byte [] * UInt32 [] ( : {}).

, Marshal.Copy, , . LockBits , Marshal.Copy.

, Kinect.

+1

Source: https://habr.com/ru/post/1789970/


All Articles