using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Windows.Media.Imaging; namespace AutoFocusTool.Imaging { /// /// 图像转换工具:把相机的 24bpp BGR 原始字节转成可显示/可保存的位图。 /// 相机原始数据上下颠倒,统一在这里做 FlipY,保证显示、存图、算分用的是同一朝向。 /// public static class ImageConverter { /// /// 24bpp BGR 字节数组 → System.Drawing.Bitmap(已 FlipY 翻正)。 /// 调用方负责 Dispose。 /// public static Bitmap ToBitmap(byte[] bgr24, int width, int height) { var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb); BitmapData data = bmp.LockBits( new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat); // 注意 stride 可能 > width*3(行对齐),逐行拷贝避免错位 int rowBytes = width * 3; if (data.Stride == rowBytes) { Marshal.Copy(bgr24, 0, data.Scan0, Math.Min(bgr24.Length, rowBytes * height)); } else { for (int y = 0; y < height; y++) { Marshal.Copy(bgr24, y * rowBytes, data.Scan0 + y * data.Stride, rowBytes); } } bmp.UnlockBits(data); // 相机数据上下颠倒,翻正 bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); return bmp; } /// /// 24bpp BGR 字节 → WPF BitmapSource(冻结,可跨线程绑定到 Image.Source)。 /// public static BitmapSource ToBitmapSource(byte[] bgr24, int width, int height) { using (var bmp = ToBitmap(bgr24, width, height)) using (var ms = new MemoryStream()) { bmp.Save(ms, ImageFormat.Bmp); ms.Position = 0; var bi = new BitmapImage(); bi.BeginInit(); bi.StreamSource = ms; bi.CacheOption = BitmapCacheOption.OnLoad; bi.EndInit(); bi.Freeze(); return bi; } } /// 保存当前帧为 BMP(已翻正)。 public static void SaveBmp(byte[] bgr24, int width, int height, string path) { using (var bmp = ToBitmap(bgr24, width, height)) { bmp.Save(path, ImageFormat.Bmp); } } } }