<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      左眼水星

      導航

      C#使用像素數據直接顯示和保存圖像

      概要:本篇將使用Win32函數完成圖像在控件上的顯示,使用直接向文件寫入字節數據的形式完成圖像保存。

      本文也介紹了設備無關的位圖(DIB)的相關知識,是對上一篇文章《在WPF中使用WriteableBitmap對接工業相機及常用操作》中圖像顯示和保存功能的擴展。

      圖像顯示

      圖像的顯示只需要信息頭和像素位兩部分,不需要文件頭。

      這里介紹使用SetStretchBltModeStretchDIBits函數顯示圖像的方法,可以從官方文檔中了解它們的使用細節。它們在C#中的定義如下:

      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern int SetStretchBltMode(IntPtr hdc,int mode);
      
      [DllImport("gdi32.dll", CharSet = CharSet.Auto)]
      public static extern int StretchDIBits(IntPtr hdc,int xDest,int yDest,int DestWidth,int DestHeight,
             int xSrc,int ySrc,int SrcWidth,int SrcHeight,byte[] lpBits,IntPtr lpbmi,UInt32 iUsage,UInt32 rop);

      使用這兩個函數的第一個參數hdc代表由Image控件生成的Graphics對象,它的生成方法如下:

      完整實現如下:

      //將文件頭信息寫入IntPtr中
      int IHSize = Marshal.SizeOf(INFOHEADER);
      byte[] IBuffer = new byte[IHSize];
      pBitmapInfo = Marshal.AllocHGlobal(40);
      Marshal.StructureToPtr(INFOHEADER, pBitmapInfo, false);
      //獲取Image控件對應的Graphics
      IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(MyImage)).Handle;
      Graphics MyImageG = Graphics.FromHwnd(hwnd);
      MyHdc = MyImageG.GetHdc();
      //將像素數據復制到byte數組中
      Marshal.Copy(pPixelOut, PixelData, 0, PixelData.Length);
      SetStretchBltMode(MyHdc, 3);
      StretchDIBits(MyHdc, 0, 0, (int)MyImage.Width, (int)MyImage.Height, 0, 0, PhotoWidth, PhotoHeight,PixelData, pBitmapInfo, 0, 0x00CC0020);

      其中pPixelOut是從工業相機SDK方法得到的像素數據地址。

      BitBlt是一個非常重要的Win32函數,DDB位圖的絕大多數操作最后都離不開這個函數。

      DIB文件格式

      .bmp圖像文件其實是與設備無關的位圖 (DIB) ,它的文件的結構如下所示:

      如果是8位像素格式的圖則還有色彩表部分,16位及以上像素格式的圖不需要色彩。

      所以其實只需要三部分內容就可以生成DIB文件,其中“像素位”指向的就是像素數據。

      文件頭和信息頭

      文件頭BITMAPFILEHEADER和信息頭BITMAPINFOHEADER(BITMAPINFOHADER結構后續已經發展了幾個新版本但是并不常用)定義在wingdi.h中。

      文件頭包含文件類型、文件大小等信息,信息頭包含圖像大小等信息。具體細節可以查看官方文檔。它們用C#定義如下:

      [StructLayout(LayoutKind.Sequential,Pack= 2)]
      struct BITMAPFILEHEADER {
      	internal ushort bftype;
      	internal uint bfsize;
      	internal ushort bfreserved1;
      	internal ushort bfreserved2;
      	internal uint bfOffBits;
      }
      [StructLayout(LayoutKind.Sequential,Pack = 2)]
      struct BITMAPINFOHEADER {
      	internal uint biSize;
      	internal int biWidth;
      	internal int biHeight;
      	internal ushort biPlanes;
      	internal ushort biBitCount;
      	internal uint biCompression;
      	internal uint biSizeImage;
      	internal int biXPelsPerMeter;
      	internal int biYPelsPerMeter;
      	internal uint biClrUsed;
      	internal int biClrImportant;
      }

      還是以PixelFormats.Bgr24像素格式為例,賦值情況如下:

      BITMAPFILEHEADER FILEHEADER=new BITMAPFILEHEADER() {
      	bftype=0x4d42,
      	bfOffBits=54,
      	bfreserved1=0,
      	bfreserved2=0,
      	bfsize=(uint)(WBitmap.PixelWidth*WBitmap.PixelHeight*3+54)
      };
      BITMAPINFOHEADER INFOHEADER=new BITMAPINFOHEADER() {
      	biSize=40,
      	biWidth=WBitmap.PixelWidth,
      	biHeight=WBitmap.PixelHeight,
      	biPlanes=1,
      	biBitCount=24,
      	biClrImportant=0,
      	biSizeImage=0,
      	biXPelsPerMeter=0,
      	biYPelsPerMeter=0,
      	biClrUsed=0,
      	biCompression=0
      };

      bftype值固定是0x4d42,代表這個文件是bmp文件。bfOffBits值固定是54,代表像素數據起始地址的偏移量也就是BITMAPFILEHEADER加BITMAPINFOHEADER的大小,bfreserved1和bfreserved2是保留字段固定為0,bfsize是整個bmp文件的大小。

      biSize固定是40表示BITMAPINFOHEADER結構的大小,biWidth和biHeight是寬和高,biPlanes固定值是1,biBitCount是像素格式的位數,其余均為固定值。

      圖像保存

      要創建bmp圖像,只需將DIB文件的三部分依次寫入文件即可。使用方法如下:

      int FHSize = Marshal.SizeOf(FILEHEADER);
      byte[] FBuffer = new byte[FHSize];
      int IHSize = Marshal.SizeOf(INFOHEADER);
      byte[] IBuffer = new byte[IHSize];
      IntPtr prt=Marshal.AllocHGlobal(FHSize);
      Marshal.StructureToPtr(FILEHEADER,prt,false);
      Marshal.Copy(prt,FBuffer,0,FBuffer.Length);
      Marshal.Release(prt);
      prt=Marshal.AllocHGlobal(IHSize);
      Marshal.StructureToPtr(INFOHEADER,prt,false);
      Marshal.Copy(prt,IBuffer,0,IBuffer.Length);
      Marshal.Release(prt);
      using(FileStream fileStream = File.OpenWrite("C:\\duie.bmp")) {
      	fileStream.Write(FBuffer,0,FBuffer.Length);
      	fileStream.Write(IBuffer,0,IBuffer.Length);
      	for(int i = WBitmap.PixelHeight-1;i>-1;i--) {
      	    int ki = i*WBitmap.PixelWidth*3;
      	    int js = (i+1)*WBitmap.PixelWidth*3;
      	    for(int k = ki;k<js;k++)
                      fileStream.WriteByte(Marshal.ReadByte(WBitmap.BackBuffer,k));
      	}
      }

      注意:在DIB中,圖像的底行是文件的第一行,圖像的頂行是文件的最后一行。所以這里用for循環從底下行開始往上讀字節。

      總結

      使用本文中的方法的好處是不用創建WriteableBitmap或Bitmap對象,可以在WPF和WinForm項目中通用。并且使用了更接近底層的方法相比上一篇文章中的顯示和保存功能有不少的性能提升。

      使用StretchDIBits函數還可以避免上一篇文章中提到的跨線程訪問控件的問題。

      posted on 2024-07-25 18:58  左眼水星  閱讀(274)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 午夜射精日本三级| 国产最新AV在线播放不卡| 无遮挡aaaaa大片免费看| 国产午夜在线观看视频播放| 99久久综合精品五月天| 亚洲国产精品老熟女乱码| 国内极度色诱视频网站| 91精品人妻中文字幕色| 亚洲av成人无码精品电影在线| 欧美一本大道香蕉综合视频| 亚洲国产成人久久77| 中国产无码一区二区三区| 撩起胸让我的?蹭来蹭去| 美女又黄又免费的视频| 亚洲综合一区二区三区视频| 国产精品欧美一区二区三区不卡| 在线成人国产天堂精品av| 精品久久欧美熟妇www| 中文激情一区二区三区四区| 免费AV手机在线观看片| 国产一区二区三区av在线无码观看| 色综合久久精品亚洲国产| 精品综合久久久久久97| 欧美成人精品三级网站| 国产精品久久自在自线不卡| 亚洲人妻系列中文字幕| 四虎在线成人免费观看| 亚洲综合伊人久久大杳蕉| 18禁免费无码无遮挡不卡网站| 国产精品呻吟一区二区三区| 国产一区二区三区高清在线观看| 伊人成色综合人夜夜久久| 国产高清一区二区不卡| 亚洲人成网站18禁止无码| 精品午夜福利无人区乱码| 强d乱码中文字幕熟女1000部| 五月综合激情婷婷六月| 日本公妇乱偷中文字幕| av色国产色拍| 亚洲日产韩国一二三四区| 久久99久久99精品免视看动漫|