首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET Micro Framework 進階實戰(四):遠端螢幕截圖與 16-bit 色彩格式深度解析

     編輯:關於.NET

在嵌入式裝置缺乏 HDMI/VGA 輸出、且無法直接連接顯示器的情境下,透過自訂通訊通道將裝置顯示記憶體 (Frame Buffer) 傳回 PC 端重構畫面,是除錯與監控的關鍵技術。本文詳細記錄如何在 .NET Micro Framework (NETMF) 裝置端擷取 16-bit RGB565/RGB555 顯存資料,並在 PC 端透過 Bitmap 掩碼機制修正 RGB/BGR 色序偏差,實現即時遠端截圖。

核心挑戰:16-bit 色彩格式與 RGB/BGR 色序

嵌入式 LCD 常見 16-bit 色深,主要有三種編排:

  • RGB565:R(5 bits) G(6 bits) B(5 bits) —— 綠色多 1 位,人眼對綠最敏感。
  • RGB555:R(5) G(5) B(5),最高位常作保留或 Alpha(1555 模式)。
  • BGR 變體:記憶體排列為 B-G-R 而非 R-G-B,若直接按 RGB 解讀會造成紅藍互換(膚色變藍、天空變紅)。

NETMF Bitmap 建構子支援 PixelFormat.Format16bppRgb565 與 Format16bppRgb555,但無法直接指定 RGB/BGR 順序。解決方案利用 BMP 檔頭 BITMAPINFOHEADER 的 biCompression = BI_BITFIELDS 機制,在檔頭後附加 12 bytes 掩碼(R/G/B Mask),強制指定各色通道在 16-bit 中的位置。

裝置端實作 (Native C++ / CustomProcess.cpp)

1. 定義自訂命令碼

#define Custom_Command_Screenshots 0x02

2. 處理截圖命令:雙階段協議

  • 階段一:取得色彩掩碼 —— PC 端發送 Offset = 0xFFFFFFFF,裝置回傳 6 bytes(R/G/B Mask 各 2 bytes,Little-Endian)。
  • 階段二:分批讀取顯存 —— PC 端指定 Offset 與 Size,裝置透過 LCD_GetFrameBuffer() 取得顯存指標,memcpy 回傳資料。

case Custom_Command_Screenshots:
    UINT32 offset = (inData[4]<<24) | (inData[3]<<16) | (inData[2]<<8) | inData[1];
    UINT16 size = (inData[6]<<8) | inData[5];

    if (offset == 0xFFFFFFFF) // 要求掩碼
    {
        *outLength = 6;
        // 範例:裝置為 BGR555 (B:7C00, G:03E0, R:001F)
        UINT16 R_Mask = 0x001F, G_Mask = 0x03E0, B_Mask = 0x7C00;
        outData[0] = (UINT8)(R_Mask & 0xFF); outData[1] = (UINT8)(R_Mask >> 8);
        outData[2] = (UINT8)(G_Mask & 0xFF); outData[3] = (UINT8)(G_Mask >> 8);
        outData[4] = (UINT8)(B_Mask & 0xFF); outData[5] = (UINT8)(B_Mask >> 8);
    }
    else // 讀取顯存區塊
    {
        UINT8* pScreen = (UINT8*)LCD_GetFrameBuffer();
        *outLength = size;
        memcpy(outData, pScreen + offset, size);
    }
    break;

PC 端插件實作 (C# / MFDeploy Plugin)

核心繪圖邏輯:動態建構帶掩碼的 Bitmap


private void palScreen_Paint(object sender, PaintEventArgs e)
{
    if (LCD_BitsPerPixel == 16)
    {
        // 1. 建立 565 格式空白 Bitmap(預設 RGB 掩碼 0xF800/0x07E0/0x001F)
        LCD_bmp = new Bitmap(LCD_Width, LCD_Height, PixelFormat.Format16bppRgb565);

        // 2. 存成 BMP 記憶體流,修改檔頭掩碼區
        MemoryStream ms = new MemoryStream();
        LCD_bmp.Save(ms, ImageFormat.Bmp);
        ms.Position = 54; // BITMAPINFOHEADER 結束位置 (14+40)

        // 3. 寫入裝置回傳的 R/G/B Mask (各 4 bytes,Little-Endian)
        ms.Write(BitConverter.GetBytes(R_Mask), 0, 4);
        ms.Write(BitConverter.GetBytes(G_Mask), 0, 4);
        ms.Write(BitConverter.GetBytes(B_Mask), 0, 4);

        // 4. 附加實際顯存資料
        ms.Write(LCD_Buffer, 0, LCD_Buffer.Length);
        ms.Flush();

        // 5. 從修改後的流重建 Bitmap,GDI+ 會依掩碼正確解讀色彩
        LCD_bmp = new Bitmap(ms);

        // 6. 裝置座標系可能上下翻轉,需 RotateFlip 修正
        LCD_bmp.RotateFlip(RotateFlipType.Rotate180FlipX);

        e.Graphics.DrawImage(LCD_bmp, 0, 0);
    }
    else // 不支援色深顯示紅叉
    {
        // ... 繪製錯誤指示 ...
    }
}

關鍵技術細節總結

環節關鍵點
顯存取得LCD_GetFrameBuffer() 為 HAL 層函式,需依平台實作(如 SAM9261 映射 LCDC 基址)。
分塊傳輸WireProtocol 封包有大小限制,PC 端需迴圈分批請求 (Offset/Size) 組合完整畫面。
掩碼來源由裝置端開發者提供(最清楚 LCD 控制器配置),避免 PC 端猜測。
BMP 掩碼機制僅 PixelFormat.Format16bppRgb565 對應 BI_BITFIELDS 支援自訂掩碼;555 格式固定 BI_RGB 無法修改,故統一按 565 容器載入再由掩碼修正。
座標翻轉嵌入式顯存常以左上為原點、逐行掃描;GDI+ 同樣左上原點,但部分驅動程式會垂直翻轉寫入,故需 RotateFlip 實測調整。

擴充應用場景

  • 自動化測試驗證:CI 流程中比對截圖與基準圖像,偵測 UI 退化。
  • 遠端技術支援:現場裝置異常時,工程師即時查看畫面指導操作。
  • 無頭裝置監控:無實體螢幕的 IoT 閘道器,定期上傳狀態畫面至雲端儀表板。

此技術展示了 NETMF 透過 WireProtocol 擴充自訂通道,結合 PC 端 GDI+ 進階影像處理,解決跨平台色彩格式不一致的經典案例。同樣原理可擴充至遠端觸控注入、鍵盤模擬、GPIO 狀態視覺化等互動式診斷工具開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved