Bitmap快速读写(Bitmap中GetPixel和SetPixel效率低)

 

使用: new Bitmap2(bitmap);  //代替原有的Bitmap即可

 版本:20240513

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.VisualStyles;
using BitmapD = System.Drawing.Bitmap;

namespace Sci
{
    public class Bitmap2
    {
        /// <summary>
        /// Bitmap数据源
        /// </summary>
        public BitmapD bitmap;

        /// <summary>
        /// 图像宽度
        /// </summary>
        public int Width;

        /// <summary>
        /// 图像高度
        /// </summary>
        public int Height;

        /// <summary>
        /// 图像保存格式
        /// </summary>
        public PixelFormat PixelFormat;

        /// <summary>
        /// 图像所有像素的颜色值
        /// </summary>
        int[,] Datas = null;

        /// <summary>
        /// 从Bitmap构造Bitmap2
        /// </summary>
        /// <param name="bitmap"></param>
        public Bitmap2(BitmapD bitmap0)          // 执行耗时: 2毫秒0微秒
        {
            this.bitmap = bitmap0;
            Width = bitmap0.Width;                              // 图像宽度
            Height = bitmap0.Height;                            // 图像高度
            PixelFormat = bitmap0.PixelFormat;                  // 图像保存格式

            Datas = ColorsInt2(bitmap0, 0, 0, Width, Height);   // 获取图像所有颜色信息
        }

        ~Bitmap2()
        {
            if (bitmap != null)
            {
                bitmap.Dispose();
                bitmap = null;
            }
        }

        /// <summary>
        /// 摘要:
        ///     获取此 System.Drawing.Bitmap 中指定像素的颜色。
        /// 参数:
        ///   x: 要检索的像素的 x 坐标。
        ///   y: 要检索的像素的 y 坐标。
        /// </summary>
        public Color GetPixel(int x, int y)
        {
            return Color.FromArgb(Datas[x, y]);
        }

        int White = Color.White.ToArgb();
        int Black = Color.Black.ToArgb();

        /// <summary>
        /// 在此Bitmap上,设置指定像素的颜色
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="color"></param>
        public void SetPixel(int x, int y, Color color)
        {
            Datas[x, y] = color.ToArgb();
        }

        /// <summary>
        /// 获取像素对应的Int颜色值
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public int GetPixel_Int(int x, int y)
        {
            return Datas[x, y];
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public BitmapD ToBitmap()   // 执行耗时: 0微秒
        {
            BitmapD tmp = ToBitmap(Datas, Width, Height);
            if (tmp.PixelFormat == PixelFormat) return tmp;
            else
            {
                BitmapD tmp2 = tmp.Clone(new Rectangle(0, 0, tmp.Width, tmp.Height), PixelFormat);  // 与原有格式不相同,则转化回原有格式
                tmp.Dispose();
                return tmp2;
            }
        }

        / <summary>
        / 转化为Drawing.Bitmap
        / </summary>
        / <returns></returns>
        //public BitmapD ToBitmap_SetPixel()          // 执行耗时: 1秒271毫秒72微秒
        //{
        //    BitmapD pic = new BitmapD(Width, Height);

        //    // 获取所有(x, y)坐标位置的像素信息
        //    for (int y = 0; y < Height; y++)
        //    {
        //        for (int x = 0; x < Width; x++)
        //        {
        //            Color color = GetPixel(x, y);
        //            pic.SetPixel(x, y, color);
        //        }
        //    }

        //    return pic;
        //}


        #region Int32颜色值 (从低到高,每8位依次为BGRA)。二维数组

        /// <summary>
        /// 从非托管代码区中快速获取图像指定区域的像素信息 (可用)
        /// </summary>
        public static int[,] ColorsInt2(BitmapD bmp0, int x0, int y0, int width0, int height0)      // 执行耗时: 51毫秒3微秒  // 执行耗时: 19毫秒1微秒 // 执行耗时: 25毫秒1微秒
        {
            bool needTransFormat = bmp0.PixelFormat != PixelFormat.Format32bppArgb ? true : false;  // 是否需要进行格式转化
            BitmapD bmp = !needTransFormat ? bmp0 : bmp0.Clone(new Rectangle(0, 0, bmp0.Width, bmp0.Height), PixelFormat.Format32bppArgb);   // 非Argb格式,转化为该格式

            int width = bmp.Width;
            int height = bmp.Height;
            int[,] colors = new int[width0, height0];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(x0, y0, width0, height0), ImageLockMode.ReadOnly, bmp.PixelFormat);
            try
            {
                IntPtr ptr = bmpData.Scan0;         // 获取在非托管内存中的位置
                int ofs = 0;

                // 获取所有(x, y)坐标位置的像素信息
                for (int y = 0; y < height0; y++)
                {
                    ofs = y * bmpData.Stride;
                    for (int x = 0; x < width0; x++)
                    {
                        //ofs = y * bmpData.Stride + x * 4;     (单句计算当前偏移值)

                        按字节读取(可用)
                        //ofs = y * bmpData.Stride + x * 4;
                        //byte A = Marshal.ReadByte(ptr, ofs + 3);
                        //byte R = Marshal.ReadByte(ptr, ofs + 2);
                        //byte G = Marshal.ReadByte(ptr, ofs + 1);
                        //byte B = Marshal.ReadByte(ptr, ofs + 0);
                        //colors[x, y] = ToColor_Int(A, R, G, B);
                        //ofs += 4;

                        // 按Int32读取
                        colors[x, y] = Marshal.ReadInt32(ptr, ofs);
                        ofs += 4;
                    }
                }

                return colors;
            }
            finally
            {
                // 解锁内存区域
                bmp.UnlockBits(bmpData);
                if (needTransFormat) bmp.Dispose();
            }
        }

        /// <summary>
        /// 转化为Drawing.Bitmap (可用)
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap(int[,] color, int Width, int Height)                         // 执行耗时: 4毫秒0微秒     // 执行耗时: 28毫秒1微秒
        {
            BitmapD bitmap = new BitmapD(Width, Height, PixelFormat.Format32bppArgb);

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            int ofs = 0;
            // 拷贝像素数据到数组
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Marshal.WriteInt32(bmpData.Scan0, ofs, color[x, y]);
                    ofs += 4;
                }
            }

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);

            return bitmap;
        }


        /// <summary>
        /// 获取一维数组中的颜色值
        /// </summary>
        /// <returns></returns>
        public static Color GetCorlor(int[] colors, int Width, int x, int y)
        {
            return Color.FromArgb(colors[y * Width + x]);
        }

        /// <summary>
        /// byte数据转化为Int颜色值
        /// </summary>
        /// <param name="A"></param>
        /// <param name="R"></param>
        /// <param name="G"></param>
        /// <param name="B"></param>
        /// <returns></returns>
        public static int ToColor_Int(byte A, byte R, byte G, byte B)
        {
            int C = 0;
            C = C | A;
            C = C << 8;
            C = C | R;
            C = C << 8;
            C = C | G;
            C = C << 8;
            C = C | B;
            return C;
        }

        #endregion


    }
}

版本:2024-05-12 

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using BitmapD = System.Drawing.Bitmap;

namespace Bitmap2.Sci
{
    public class Bitmap
    {
        /// <summary>
        /// Bitmap数据源
        /// </summary>
        public BitmapD bitmap;

        /// <summary>
        /// 图像宽度
        /// </summary>
        public int Width;

        /// <summary>
        /// 图像高度
        /// </summary>
        public int Height;

        /// <summary>
        /// 图像保存格式
        /// </summary>
        PixelFormat PixelFormat;

        /// <summary>
        /// 单个像素的位数
        /// </summary>
        int PixelBit;

        /// <summary>
        /// 单个像素的字节数
        /// </summary>
        int PixelBytes;

        /// <summary>
        /// 图像数据的总位数
        /// </summary>
        long PixelBitAll;

        /// <summary>
        /// 图像数据的总字节数
        /// </summary>
        int Length;

        /// <summary>
        /// Bitmap托管的内存数据
        /// </summary>
        byte[] Datas = null;

        /// <summary>
        /// 从Bitmap构造Bitmap2
        /// </summary>
        /// <param name="bitmap"></param>
        public Bitmap(BitmapD bitmap0)          // 执行耗时: 2毫秒0微秒
        {
            BitmapD bitmap = TypeFormat(bitmap0);                                // 图像格式化

            this.bitmap = bitmap0;
            Width = bitmap.Width;                                               // 图像宽度
            Height = bitmap.Height;                                             // 图像高度
            PixelFormat = bitmap.PixelFormat;                                   // 图像保存格式
            PixelBit = Image.GetPixelFormatSize(PixelFormat);                   // 单个像素的位数
            PixelBytes = PixelBit / 8;                                          // 单个像素的字节数
            PixelBitAll = Width * Height * PixelBit;                            // 图像数据的总位数
            Length = (int)(PixelBitAll / 8 + (PixelBitAll % 8 > 0 ? 1 : 0));    // 图像数据的总字节数

            GetData();
            bitmap = null;
        }

        ~Bitmap()
        {
            if (bitmap != null)
            {
                bitmap.Dispose();
                bitmap = null;
            }
        }

        /// <summary>
        /// 图像类型格式化为1位、8位、24位、或32位
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private BitmapD TypeFormat(BitmapD bitmap)
        {
            int PixelBit = Image.GetPixelFormatSize(bitmap.PixelFormat);                            // 单个像素的位数
            if (PixelBit == 1 || PixelBit == 8 || PixelBit == 24 || PixelBit == 32) return bitmap;  // 
            else
            {
                PixelFormat type = PixelBit < 8 ? PixelFormat.Format8bppIndexed : PixelFormat.Format32bppArgb;
                BitmapD tmp = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), type);  // 将其它位数的图像转化为8位或32位
                return tmp;
            }
        }

        /// <summary>
        /// 获取图像对应的数据信息
        /// </summary>
        private void GetData()
        {
            Datas = new byte[Length];

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, PixelFormat);

            // 拷贝像素数据到数组
            Marshal.Copy(bmpData.Scan0, Datas, 0, Length);      

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);    
        }

        /// <summary>
        /// 获取像素位置处的数据
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private byte[] GetPixelBytes(int x, int y)
        {
            byte[] Bytes = new byte[PixelBytes];
            long sourceIndex = (y * Width + x) * PixelBytes;        // 获取坐标(x,y)位置处,像素对应的数据位置
            Array.Copy(Datas, sourceIndex, Bytes, 0, PixelBytes);   // 获取像素对应数据

            return Bytes;
        }

        /// <summary>
        /// 获取二进制位信息
        /// </summary>
        /// <param name="x">列</param>
        /// <param name="y">行</param>
        /// <returns></returns>
        private bool GetBit(int x, int y)
        {
            int bitIndex = (y * Width + x);         // bit, 像素位置
            int b = Datas[bitIndex / 8] ;           // bit, 所在字节位置的字节数据
            int bitIndex2 = bitIndex % 8;           // bit, 在字节中的位置
            if(bitIndex2 > 0) b = b << bitIndex2;   // bit,移动到最左侧
            b = b >> 7;                             // bit,移动到最右侧

            return b == 1;
        }
        
        /// <summary>
        /// 摘要:
        ///     获取此 System.Drawing.Bitmap 中指定像素的颜色。
        /// 参数:
        ///   x: 要检索的像素的 x 坐标。
        ///   y: 要检索的像素的 y 坐标。
        /// </summary>
        public Color GetPixel(int x, int y)
        {
            if (PixelBit == 1) return GetBit(x, y) ? Color.White : Color.Black;                         // 1位黑白图像
            else
            {
                byte[] bytes = GetPixelBytes(x, y);
                if (bytes.Length == 4) return Color.FromArgb(bytes[3], bytes[2], bytes[1], bytes[0]);   // 4字节ARGB图像
                else if (bytes.Length == 3) return Color.FromArgb(bytes[2], bytes[1], bytes[0]);        // 3字节RGB图像
                else return Color.FromArgb(bytes[0], bytes[0], bytes[0]);                               // 1字节灰度图像
            }
        }

        int White = Color.White.ToArgb();
        int Black = Color.Black.ToArgb();

        /// <summary>
        /// 获取像素对应的Int颜色值
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public int GetPixel_Int(int x, int y)
        {
            if (PixelBit == 1) return GetBit(x, y) ? White : Black;                         // 1位黑白图像
            else
            {
                byte[] bytes = GetPixelBytes(x, y);
                if (bytes.Length == 4) return ToColor_Int(bytes[3], bytes[2], bytes[1], bytes[0]);   // 4字节ARGB图像
                else if (bytes.Length == 3) return ToColor_Int(255, bytes[2], bytes[1], bytes[0]);   // 3字节RGB图像
                else return ToColor_Int(255, bytes[0], bytes[0], bytes[0]);                          // 1字节灰度图像
            }
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public BitmapD ToBitmap()   // 执行耗时: 0微秒
        {
            return ToBitmap(Datas, Width, Height);
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public BitmapD ToBitmap32()                     // 执行耗时: 138毫秒7微秒
        {
            int[] colors = new int[Width * Height];
            int i = 0;

            // 获取所有(x, y)坐标位置的像素信息
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Color color = GetPixel(x, y);
                    colors[i++] = color.ToArgb();
                }
            }
            return ToBitmap(colors, Width, Height);
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public BitmapD ToBitmapInt()                 // 执行耗时: 145毫秒8微秒
        {
            int[] colors = new int[Width * Height];
            int i = 0;

            // 获取所有(x, y)坐标位置的像素信息
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    colors[i++] = GetPixel_Int(x, y);
                }
            }
            return ToBitmap(colors, Width, Height);
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public BitmapD ToBitmap_SetPixel()          // 执行耗时: 1秒271毫秒72微秒
        {
            BitmapD pic = new BitmapD(Width, Height);

            // 获取所有(x, y)坐标位置的像素信息
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Color color = GetPixel(x, y);
                    pic.SetPixel(x, y, color);
                }
            }

            return pic;
        }

        #region 从内存中,一次获取所有像素

        #region byte颜色值

        /// <summary>
        /// 从内存中快速获取图像像素数据(因图像有很多种格式,直接获取数据,用处不大)
        /// </summary>
        /// <param name="bmp"></param>
        /// <returns></returns>
        private byte[] pixInfo(BitmapD bmp)
        {
            int width = bmp.Width;
            int height = bmp.Height;

            int pixelBits = Image.GetPixelFormatSize(bmp.PixelFormat);  // 图像像素的保存位数
            int allBits = width * height * pixelBits;                   // 图像数据的总位数
            int allBytes = allBits / 8 + (allBits % 8 > 0 ? 1 : 0);     // 图像数据的总字节数

            byte[] datas = new byte[allBytes];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);

            IntPtr ptr = bmpData.Scan0;                     // 获取数据,非托管内存指针起点
            Marshal.Copy(ptr, datas, 0, datas.Length);      // 拷贝像素数据到数组

            // 解锁内存区域
            bmp.UnlockBits(bmpData);

            return datas;
        }

        /// <summary>
        /// 转化为Drawing.Bitmap
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap(byte[] colors, int Width, int Height)        // 执行耗时: 0微秒
        {
            BitmapD bitmap = new BitmapD(Width, Height, PixelFormat.Format32bppArgb);

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            // 复制图像数据到图像对应的内存中
            Marshal.Copy(colors, 0, bmpData.Scan0, colors.Length);

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);

            return bitmap;
        }

        #endregion

        #region 获取Color颜色值、从Color生成图像

        /// <summary>
        /// 从非托管代码区中快速获取图像所有像素信息(可用)
        /// </summary>
        public static Color[,] Colors(BitmapD bmp0)     // 执行耗时: 140毫秒8微秒  // 执行耗时: 52毫秒2微秒  // 执行耗时: 43毫秒2微秒
        {
            int pixelBits = Image.GetPixelFormatSize(bmp0.PixelFormat);
            BitmapD bmp = pixelBits == 32 ? bmp0 : bmp0.Clone(new Rectangle(0, 0, bmp0.Width, bmp0.Height), PixelFormat.Format32bppArgb);

            int width = bmp.Width;
            int height = bmp.Height;
            Color[,] colors = new Color[width, height];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);
            try
            {
                byte[] datas = new byte[width * height * 4];
                Marshal.Copy(bmpData.Scan0, datas, 0, datas.Length);      // 拷贝像素数据到数组

                int i = 0;

                // 获取所有(x, y)坐标位置的像素信息
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        colors[x, y] = Color.FromArgb(datas[i + 3], datas[i + 2], datas[i + 1], datas[i + 0]);
                        i = i + 4;
                    }
                }
                return colors;
            }
            finally
            {
                // 解锁内存区域
                bmp.UnlockBits(bmpData);
                if (pixelBits != 32) bmp.Dispose();
            }
        }

        /// <summary>
        /// 从非托管代码区中快速获取图像指定区域的像素信息
        /// </summary>
        public static Color[,] Colors(BitmapD bmp0, int x0, int y0, int width0, int height0)    // 执行耗时: 51毫秒3微秒
        {
            int pixelBits = Image.GetPixelFormatSize(bmp0.PixelFormat);
            BitmapD bmp = pixelBits == 32 ? bmp0 : bmp0.Clone(new Rectangle(0, 0, bmp0.Width, bmp0.Height), PixelFormat.Format32bppArgb);

            int width = bmp.Width;
            int height = bmp.Height;
            Color[,] colors = new Color[width0, height0];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(x0, y0, width0, height0), ImageLockMode.ReadOnly, bmp.PixelFormat);
            try
            {
                IntPtr ptr = bmpData.Scan0;         // 获取在非托管内存中的位置
                
                // 获取所有(x, y)坐标位置的像素信息
                for (int y = 0; y < height0; y++)
                {
                    for (int x = 0; x < width0; x++)
                    {
                        int ofs = y * bmpData.Stride + x * 4;

                        byte A = Marshal.ReadByte(ptr, ofs + 3);
                        byte R = Marshal.ReadByte(ptr, ofs + 2);
                        byte G = Marshal.ReadByte(ptr, ofs + 1);
                        byte B = Marshal.ReadByte(ptr, ofs + 0);

                        colors[x, y] = Color.FromArgb(A, R, G, B);
                    }
                }

                return colors;
            }
            finally
            {
                // 解锁内存区域
                bmp.UnlockBits(bmpData);
                if(pixelBits != 32) bmp.Dispose();
            }
        }

        /// <summary>
        /// 转化为Drawing.Bitmap (可用)
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap(Color[,] color, int Width, int Height)       // 执行耗时: 74毫秒4微秒
        {
            BitmapD bitmap = new BitmapD(Width, Height, PixelFormat.Format32bppArgb);

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            int ofs = 0;
            // 拷贝像素数据到数组
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    //Color c = color[x, y];
                    //Marshal.WriteInt32(bmpData.Scan0, ofs, ToColor_Int(c.A, c.R, c.G, c.B));

                    Marshal.WriteInt32(bmpData.Scan0, ofs, color[x, y].ToArgb());
                    ofs += 4;
                }
            }

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);

            return bitmap;
        }

        /// <summary>
        /// 转化为Drawing.Bitmap(可用)
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap_SetPixel(Color[,] color, int Width, int Height)       // 执行耗时: 1秒237毫秒70微秒
        {
            BitmapD pic = new BitmapD(Width, Height);

            // 获取所有(x, y)坐标位置的像素信息
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    pic.SetPixel(x, y, color[x, y]);
                }
            }

            return pic;
        }

        #endregion

        #region Int32颜色值 (从低到高,每8位依次为BGRA)。二维数组

        /// <summary>
        /// 从非托管代码区中快速获取图像指定区域的像素信息 (可用)
        /// </summary>
        public static int[,] ColorsInt2(BitmapD bmp0, int x0, int y0, int width0, int height0)    // 执行耗时: 51毫秒3微秒  // 执行耗时: 19毫秒1微秒 // 执行耗时: 25毫秒1微秒
        {
            int pixelBits = Image.GetPixelFormatSize(bmp0.PixelFormat);
            BitmapD bmp = pixelBits == 32 ? bmp0 : bmp0.Clone(new Rectangle(0, 0, bmp0.Width, bmp0.Height), PixelFormat.Format32bppArgb);

            int width = bmp.Width;
            int height = bmp.Height;
            int[,] colors = new int[width0, height0];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(x0, y0, width0, height0), ImageLockMode.ReadOnly, bmp.PixelFormat);
            try
            {
                IntPtr ptr = bmpData.Scan0;         // 获取在非托管内存中的位置
                int ofs = 0;

                // 获取所有(x, y)坐标位置的像素信息
                for (int y = 0; y < height0; y++)
                {
                    ofs = y * bmpData.Stride;
                    for (int x = 0; x < width0; x++)
                    {
                        //ofs = y * bmpData.Stride + x * 4;     (单句计算当前偏移值)

                        按字节读取(可用)
                        //ofs = y * bmpData.Stride + x * 4;
                        //byte A = Marshal.ReadByte(ptr, ofs + 3);
                        //byte R = Marshal.ReadByte(ptr, ofs + 2);
                        //byte G = Marshal.ReadByte(ptr, ofs + 1);
                        //byte B = Marshal.ReadByte(ptr, ofs + 0);
                        //colors[x, y] = ToColor_Int(A, R, G, B);
                        //ofs += 4;

                        // 按Int32读取
                        colors[x, y] = Marshal.ReadInt32(ptr, ofs);
                        ofs += 4;
                    }
                }

                return colors;
            }
            finally
            {
                // 解锁内存区域
                bmp.UnlockBits(bmpData);
                if (pixelBits != 32) bmp.Dispose();
            }
        }

        /// <summary>
        /// 转化为Drawing.Bitmap (可用)
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap(int[,] color, int Width, int Height)             // 执行耗时: 4毫秒0微秒     // 执行耗时: 28毫秒1微秒
        {
            BitmapD bitmap = new BitmapD(Width, Height, PixelFormat.Format32bppArgb);

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            int ofs = 0;
            // 拷贝像素数据到数组
            for (int y = 0; y < Height; y++)
            {
                for (int x = 0; x < Width; x++)
                {
                    Marshal.WriteInt32(bmpData.Scan0, ofs, color[x, y]);
                    ofs += 4;
                }
            }

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);

            return bitmap;
        }

        #endregion

        #region Int32颜色值 (从低到高,每8位依次为BGRA)。一维数组

        /// <summary>
        /// 从非托管代码区中快速获取图像指定区域的像素信息(可用)
        /// </summary>
        public static int[] ColorsInt(BitmapD bmp0, int x0, int y0, int width0, int height0)    // 执行耗时: 51毫秒3微秒        // 执行耗时: 22毫秒1微秒  // 执行耗时: 23毫秒1微秒 // 执行耗时: 4毫秒0微秒
        {
            int pixelBits = Image.GetPixelFormatSize(bmp0.PixelFormat);
            BitmapD bmp = pixelBits == 32 ? bmp0 : bmp0.Clone(new Rectangle(0, 0, bmp0.Width, bmp0.Height), PixelFormat.Format32bppArgb);

            int[] colors = new int[width0 * height0];

            // 锁定位图的内存区域
            BitmapData bmpData = bmp.LockBits(new Rectangle(x0, y0, width0, height0), ImageLockMode.ReadOnly, bmp.PixelFormat);


            if (x0 == 0 && y0 == 0 && width0 == bmp0.Width && height0 == bmp0.Height)
            {
                Marshal.Copy(bmpData.Scan0, colors, 0, colors.Length);          // 整体复制
            }
            else
            {
                int ofs = 0;
                int i = 0;
                for (int y = 0; y < height0; y++)
                {
                    ofs = (y + y0) * bmpData.Stride;        // 等效, ofs = (y + y0) * bmp.Width * 4;  获取的是每行开始处的字节偏移值(一个像素,4个字节)
                    
                    for (int x = 0; x < width0; x++)
                    {
                        colors[i++] = Marshal.ReadInt32(bmpData.Scan0, ofs);    // 逐个像素进行复制
                        ofs += 4;
                    }
                }
            }

            // 解锁内存区域
            bmp.UnlockBits(bmpData);
            if (pixelBits != 32) bmp.Dispose();

            return colors;
        }

        /// <summary>
        /// 转化为Drawing.Bitmap(可用)
        /// </summary>
        /// <returns></returns>
        public static BitmapD ToBitmap(int[] colors, int Width, int Height)     // 执行耗时: 0微秒        // 执行耗时: 2毫秒0微秒
        {
            BitmapD bitmap = new BitmapD(Width, Height, PixelFormat.Format32bppArgb);

            // 锁定位图的内存区域
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);

            // 复制图像数据到图像对应的内存中
            Marshal.Copy(colors, 0, bmpData.Scan0, colors.Length); 

            // 解锁内存区域
            bitmap.UnlockBits(bmpData);

            return bitmap;
        }

        /// <summary>
        /// 获取一维数组中的颜色值
        /// </summary>
        public static byte[] GetCorlor_Byte(int[] colors, int Width, int x, int y)  // 等效Color.Argb()
        {
            int color = colors[y * Width + x];

            byte B = (byte)(color & 255);
            color = color >> 8;
            byte G = (byte)(color & 255);
            color = color >> 8;
            byte R = (byte)(color & 255);
            color = color >> 8;
            byte A = (byte)(color & 255);

            return new byte[] { A, R, G, B };
        }

        /// <summary>
        /// 获取一维数组中的颜色值
        /// </summary>
        public static int GetCorlor_Int(int[] colors, int Width, int x, int y)
        {
            return colors[y * Width + x]; 
        }

        /// <summary>
        /// 获取一维数组中的颜色值
        /// </summary>
        /// <returns></returns>
        public static Color GetCorlor(int[] colors, int Width, int x, int y)
        {
            return Color.FromArgb(colors[y * Width + x]);
        }

        /// <summary>
        /// byte数据转化为Int颜色值
        /// </summary>
        /// <param name="A"></param>
        /// <param name="R"></param>
        /// <param name="G"></param>
        /// <param name="B"></param>
        /// <returns></returns>
        public static int ToColor_Int(byte A, byte R, byte G, byte B)
        {
            int C = 0;
            C = C | A;
            C = C << 8; 
            C = C | R;
            C = C << 8;
            C = C | G;
            C = C << 8;
            C = C | B;
            return C;
        }

        #endregion

        #endregion


    }
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Bitmap2.Sci
{
    /// <summary>
    /// 统计代码运行时长(用于记录代码执行耗时信息)
    /// </summary>
    public class LogTime
    {
        /// <summary>
        /// 示例
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void example(object sender, EventArgs e)
        {
            LogTime.Start();

            // 待统计时长的代码...
            string timeStr = LogTime.CurrentStackTrace();
            MessageBox.Show(timeStr);

            LogTime.End("自定义注释信息");     // LogTime.End();
        }

        static Dictionary<string, long> timeDic = new Dictionary<string, long>();

        /// <summary>
        /// 记录log的开始时间
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public static void Start(int num = 0)
        {
            string key = CurrentMethod(2) + System.Threading.Thread.CurrentThread.ManagedThreadId + "_" + num;  // 获取调用Start()函数的函数名
            timeDic.Add(key, DateTime.Now.Ticks);                                                               // 记录当前调用时间
        }

        /// <summary>
        /// 记录指定log的结束时间
        /// </summary>
        public static void End(int num = 0, string msg = "")
        {
            long curTime = DateTime.Now.Ticks;

            int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
            string key = CurrentMethod(2) + threadId + "_" + num;                                   // 获取调用End()函数的函数名

            if (timeDic.ContainsKey(key))
            {
                long preTime = timeDic[key];                                                        // 获取Start()函数的调用时间
                if (msg.Length > 0) msg = "(" + msg + ")";
                string info = " " + CurrentMethod(2) + msg + " -> 执行耗时: " + getTimeSpan(curTime, preTime);  // 生成耗时信息
                ThreadPool.QueueUserWorkItem((state) => { Write(info, threadId); });                // 记录至log中
                timeDic.Remove(key);
            }
        }

        /// <summary>
        /// 记录指定log的结束时间
        /// </summary>
        public static void End(string msg)
        {
            End(0, msg);
        }

        /// <summary>
        /// 获取调用当前函数的方法名(索引1),
        /// </summary>
        /// <returns></returns>
        public static string CurrentMethod(int index = 1)
        {
            StackTrace stackTrace = new StackTrace();
            StackFrame stackFrame = stackTrace.GetFrame(index);
            return ToString(stackFrame, true);
        }

        /// <summary>
        /// 获取当前调用堆栈信息
        /// </summary>
        /// <returns></returns>
        public static string CurrentStackTrace()
        {
            return ToString(new StackTrace());
        }

        private static string ToString(StackTrace stackTrace, bool simple = false)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < stackTrace.FrameCount; i++)
            {
                StackFrame stackFrame = stackTrace.GetFrame(i);
                sb.AppendLine(ToString(stackFrame, simple));
            }
            return sb.ToString();
        }

        private static string ToString(StackFrame stackFrame, bool simple = false)
        {
            if (simple) return stackFrame.GetMethod() + " ";
            else return stackFrame.GetFileName() + " -> " + stackFrame.GetMethod() + ",行号:" + stackFrame.GetFileLineNumber() + ",列号:" + stackFrame.GetFileColumnNumber();
        }

        static int[] unit = { 1000, 1000, 60, 60, 60, 24, 365 };
        static string[] unitName = { "微秒", "毫秒", "秒", "分", "时", "天", "年" };

        /// <summary>
        /// 获取耗时时长
        /// </summary>
        /// <param name="curTime"></param>
        /// <param name="preTime"></param>
        /// <returns></returns>
        private static string getTimeSpan(long curTime, long preTime)
        {
            long tickSpan = (curTime - preTime) / 10;
            if (tickSpan < 0) tickSpan = -tickSpan;

            string timeStr = "";
            for (int i = 0; i < unit.Length; i++)
            {
                int unitI = unit[i];
                if (tickSpan % unitI >= 0) timeStr = (tickSpan % unitI) + unitName[i] + timeStr;
                if (tickSpan > unitI) tickSpan = tickSpan / unitI;
                else break;
            }
            return timeStr;
        }

        /// <summary>
        /// 向TimeLog中添加信息
        /// </summary>
        /// <param name="info"></param>
        /// <param name="newLine"></param>
        /// <param name="time"></param>
        /// <returns></returns>
        public static bool Write(string info, int threadid = 0, bool newLine = true, bool time = true)
        {
            try
            {
                string logPath = Application.StartupPath + "\\LogTime";
                if (!Directory.Exists(logPath))
                {
                    Directory.CreateDirectory(logPath);
                }
                string threadId = (threadid == 0 ? System.Threading.Thread.CurrentThread.ManagedThreadId : threadid) + "";
                logPath = logPath + "\\" + DateTime.Now.ToString("yyyyMMdd_HH") + ((DateTime.Now.Minute / 5 * 5) + "").PadLeft(2, '0') + "00_" + threadId + ".txt"; // 每5分钟,输出至一个log文件中,不同线程输出至不同文件中

                string data = info;
                if (time) data = "[" + DateTime.Now.ToString("HH:mm:ss") + "] " + data;
                if (newLine) data = "\r\n" + data;

                File.AppendAllText(logPath, data, Encoding.Unicode);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

    }
}



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Bitmap2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //LogTime.example(null, null);

            Test4();

        }


        private void Test4()
        {
            Sci.LogTime.Start(1);
            string picPath = "pic\\2.png";
            Bitmap pic = Bitmap.FromFile(picPath) as Bitmap;                                // 执行耗时: 29毫秒1微秒
            Sci.LogTime.End(1, "载入图像");

            //Sci.LogTime.Start(2);
            //int[] colors = Sci.Bitmap.ColorsInt(pic, 0, 0, pic.Width, pic.Height);
            //Sci.LogTime.End(2, "Sci.Bitmap.Colors(pic, 0, 0, pic.Width, pic.Height)");

            //Sci.LogTime.Start(3);
            //Bitmap pic3 = Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height);
            //Sci.LogTime.End(3, "Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height)");

            Sci.LogTime.Start(2);
            int[] colors = Sci.Bitmap.ColorsInt(pic, pic.Width / 4, pic.Height / 4, pic.Width / 2, pic.Height / 2);
            Sci.LogTime.End(2, "Sci.Bitmap.Colors(pic, 0, 0, pic.Width, pic.Height)");

            Sci.LogTime.Start(3);
            Bitmap pic3 = Sci.Bitmap.ToBitmap(colors, pic.Width / 2, pic.Height / 2);
            Sci.LogTime.End(3, "Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height)");

            Sci.LogTime.Start(4);
            pic3.Save(picPath + "_2.png");
            Sci.LogTime.End(4, "保存图像");

        }


        private void Test3()
        {
            Sci.LogTime.Start(1);
            string picPath = "pic\\2.png";
            Bitmap pic = Bitmap.FromFile(picPath) as Bitmap;
            Sci.LogTime.End(1, "载入图像");

            Sci.LogTime.Start(2);
            int[,] colors = Sci.Bitmap.ColorsInt2(pic, pic.Width / 4, pic.Height / 4, pic.Width / 2, pic.Height / 2);
            Sci.LogTime.End(2, "Sci.Bitmap.Colors(pic, 0, 0, pic.Width, pic.Height)");

            Sci.LogTime.Start(3);
            Bitmap pic3 = Sci.Bitmap.ToBitmap(colors, pic.Width / 2, pic.Height / 2);
            Sci.LogTime.End(3, "Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height)");

            //Sci.LogTime.Start(2);
            //int[,] colors = Sci.Bitmap.ColorsInt2(pic, 0, 0, pic.Width, pic.Height);
            //Sci.LogTime.End(2, "Sci.Bitmap.Colors(pic, 0, 0, pic.Width, pic.Height)");

            //Sci.LogTime.Start(3);
            //Bitmap pic3 = Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height);
            //Sci.LogTime.End(3, "Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height)");

            Sci.LogTime.Start(4);
            pic3.Save(picPath + "_2.png");
            Sci.LogTime.End(4, "保存图像");

        }

        private void Test2()
        {
            Sci.LogTime.Start(1);
            string picPath = "pic\\2.png";
            Bitmap pic = Bitmap.FromFile(picPath) as Bitmap;
            Sci.LogTime.End(1, "载入图像");

            Sci.LogTime.Start(2);
            Color[,] colors = Sci.Bitmap.Colors(pic);
            Sci.LogTime.End(2, "Sci.Bitmap.Colors(pic)");

            Sci.LogTime.Start(3);
            Bitmap pic3 = Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height);
            Sci.LogTime.End(3, "Sci.Bitmap.ToBitmap(colors, pic.Width, pic.Height)");

            Sci.LogTime.Start(4);
            pic3.Save(picPath + "_2.png");
            Sci.LogTime.End(4, "保存图像");

        }

        private void Test1()
        {
            Sci.LogTime.Start(1);
            string picPath = "pic\\2.png";
            Bitmap pic = Bitmap.FromFile(picPath) as Bitmap;
            Sci.LogTime.End(1, "载入图像");

            Sci.LogTime.Start(2);
            Sci.Bitmap pic2 = new Sci.Bitmap(pic);
            Sci.LogTime.End(2, "获取图像所有像素信息");

            //Sci.LogTime.Start(3);
            //Bitmap pic3 = pic2.ToBitmap32();
            //Sci.LogTime.End(3, "像素信息转化回图像");

            //Sci.LogTime.Start(3);
            //Bitmap pic3 = pic2.ToBitmap33();
            //Sci.LogTime.End(3, "像素信息转化回图像");

            Sci.LogTime.Start(3);
            Bitmap pic3 = pic2.ToBitmap_SetPixel();
            Sci.LogTime.End(3, "像素信息转化回图像");

            Sci.LogTime.Start(4);
            pic3.Save(picPath + "_2.png");
            Sci.LogTime.End(4, "保存图像");
        }
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值