UnmanagedBitmap.cs 5.1 KB
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace eyemLib_Sharp
{
    public unsafe class UnmanagedBitmap : IDisposable
    {
        private EyemImage image;
        public EyemImage Image
        {
            get { return image; }
        }
        /// <summary>
        /// 初始化新实例
        /// </summary>
        public UnmanagedBitmap()
        {
            image = new EyemImage();
        }
        /// <summary>
        /// 从指定文件初始化UnmanagedBitmap的新实例(支持BMP、DIB、PNG、PBM、PGM、PPM、EXR、JPEG、JPG、JPE、TIF等格式图像)
        /// </summary>
        /// <param name="fileName">文件名</param>
        public UnmanagedBitmap(string fileName)
        {
            eyemImageRead(fileName, -1, out image);
        }
        /// <summary>
        /// 从Bitmap初始化Unmanaged新实例(GDI不支持除8位以外深度的图像;若要加载不同深度图像请使用从文件名加载)
        /// </summary>
        /// <param name="bitmap"></param>
        public UnmanagedBitmap(Bitmap bitmap)
        {
            image = eyemCvtToEyemImage(bitmap);
        }
        /// <summary>
        /// 隐式转换成EyemImage
        /// </summary>
        /// <param name="operand"></param>
        public static implicit operator EyemImage(UnmanagedBitmap operand)
        {
            return operand.Image;
        }

        ~UnmanagedBitmap()
        {
            Dispose(false);
        }

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

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // dispose managed resources
            }
            //这里特别修改了eyemCvtToEyemImage的内存分配,因此皆可以由此接口释放
            eyemImageFree(ref image);
        }

        #region 接口
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemImageRead(string filename, int iFalgs, out EyemImage tpImage);
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern void eyemImageFree(ref EyemImage tpImage);
        [DllImport("eyemLib.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        private static extern int eyemCvtImageType(EyemImage tpImage, string ccSubType, double alpha, double beta, ref EyemImage tpDstImg);
        /// <summary>
        /// 从进程中的非托管内存分配指定长度的内存
        /// </summary>
        /// <param name="cb">长度</param>
        /// <returns>地址</returns>
        [DllImport("eyemLib.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr eyemMallocMemBlock(int cb);
        /// <summary>
        /// 释放从非托管内存中分配的内存
        /// </summary>
        /// <param name="block">地址</param>
        [DllImport("eyemLib.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void eyemFreeMemBlock(IntPtr block);
        #endregion

        #region EyemImageBitmap相互转换
        public static EyemImage eyemCvtToEyemImage(Bitmap bitmap)
        {
            EyemImage tpImage = new EyemImage();
            //锁定数据区
            BitmapData bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadOnly, bitmap.PixelFormat);
            switch (bitmap.PixelFormat)
            {
                case PixelFormat.Format8bppIndexed:
                    tpImage.iChannels = 1;
                    break;
                case PixelFormat.Format24bppRgb:
                    tpImage.iChannels = 3;
                    break;
                case PixelFormat.Format32bppArgb:
                    tpImage.iChannels = 4;
                    break;
                default:
                    throw new Exception("Image formats are not supported");
            }
            //仅支持8位
            tpImage.iDepth = 0;
            //图像尺寸
            tpImage.iWidth = bitmap.Width; tpImage.iHeight = bitmap.Height;
            //分配内存(此函数分配的内存可由默认接口释放)
            tpImage.vpImage = eyemMallocMemBlock(bd.Stride * bd.Height);
            try
            {
                int pd = ((tpImage.iWidth * tpImage.iChannels) + 3) / 4 * 4;
                long bytesToCopy = tpImage.iWidth * tpImage.iChannels;
                for (int y = 0; y < tpImage.iHeight; y++)
                {
                    long offsetSrc = y * pd;
                    long offsetDst = y * tpImage.iWidth * tpImage.iChannels;
                    Buffer.MemoryCopy((byte*)(bd.Scan0.ToPointer()) + offsetSrc, (byte*)(tpImage.vpImage.ToPointer()) + offsetDst, bytesToCopy, bytesToCopy);
                }
            }
            finally
            {
                bitmap.UnlockBits(bd);
            }
            return tpImage;
        }
        #endregion
    }
}