簡體   English   中英

WPF 從 Base64String 加載的位圖圖像未顯示

[英]WPF BitmapImage loaded from Base64String not showing

我正在嘗試制作屏幕共享應用程序。 作為第一步,我嘗試使用屏幕截圖共享主機的屏幕。 為了連接主機和客戶端,我使用的是 SignalR。 身份驗證完成后,我正在為主機啟動一個計時器,該計時器將在它過去時截取屏幕截圖。 截圖代碼如下:

public static byte[] TakeScreenshot(int width = 0, int height = 0)
    {
        var bmp = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
                           Screen.PrimaryScreen.Bounds.Height,
                           PixelFormat.Format32bppArgb);

        // Create a graphics object from the bitmap.
        var gfxScreenshot = Graphics.FromImage(bmp);

        // Take the screenshot from the upper left corner to the right bottom corner.
        gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                    Screen.PrimaryScreen.Bounds.Y,
                                    0,
                                    0,
                                    Screen.PrimaryScreen.Bounds.Size,
                                    CopyPixelOperation.SourceCopy);

        if (width != 0 && height != 0)
            bmp = new Bitmap(bmp, new Size(width, height));

        using (var stream = new MemoryStream())
        {
            bmp.Save(stream, ImageFormat.Jpeg);
            return stream.ToArray();
        }
    }

計時器的經過處理程序:

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        var bytes = ImageHelper.TakeScreenshot();
        string imageString = Convert.ToBase64String(bytes);
        Communicator.Instance.Produce(new BroadcastDataComm() { DataType = DataType.Image, Data = imageString }, _connectedHost);
    }

屏幕截圖將作為字節數組接收,然后轉換為 Base64String 以便通過 SignalR 廣播。 When the authentication is done I am creating a new WPF window (in the parent Xaml.cs class) and show it, then, all the clients authenticated to the host will receive the produced message and send the base64string to the new window:

ScreenSharingWindow _window = new ScreenSharingWindow();
    private void AuthenticateSuccess(string id)
    {
        ConnectionId = $"Connected to: {id}";
        _connectedHost = id;
        Dispatcher.Invoke(() => _window.Show());
        _timer.Start();
    }

    private void ScreenshotReceived(BroadcastDataComm ss)
    {
        if (!(ss.Data is string imgString))
            return;


        Dispatcher.Invoke(()=> _window.ImageData = imgString);
    }

Finally, I am creating a Bitmap object from the string using those 2 properties in the new window and using a converter on that object so I can bind the XAML's Image control to it:

    private Bitmap _image;
    public Bitmap Image
    {
        get => _image;
        set
        {
            _image = value;
            NotifyPropertyChanged();
            Image.Save(@"C:\Users\roudy\Desktop\test.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
        }
    }

    private string _imageData;
    public string ImageData
    {
        get => _imageData;
        set
        {
            _imageData = value;
            NotifyPropertyChanged();

            var ms = new MemoryStream(Convert.FromBase64String(ImageData));
            Image = new Bitmap(ms);
        }
    }
public class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Bitmap bmp)
            return ImageSourceFromBitmap(bmp);
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject([In] IntPtr hObject);

    public BitmapSource ImageSourceFromBitmap(Bitmap bmp)
    {
        var handle = bmp.GetHbitmap();
        try
        {
            var ret = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            return ret;
        }
        finally { DeleteObject(handle); }
    }
}

我在屬性的設置器中添加了 Image.Save(...) 以確保按預期接收圖像並且它工作正常,並且當我檢查桌面中的縮略圖時,我可以看到圖像正確更新。 但由於某種原因,它只是拒絕在 WPF 控件中顯示。 我試圖從文件中創建一個 bitmap 並且它工作正常,因此綁定和轉換器是正確的。

為什么控件上不顯示圖像? 謝謝你。

編輯:為了檢查綁定是否正確,我剛剛從新窗口的構造函數中創建了 bitmap 並注釋掉了父 window 設置屬性的部分。 父 window 中的新處理程序將是:

private void ScreenshotReceived(BroadcastDataComm ss)
    {
        if (!(ss.Data is string imgString))
            return;


        //Dispatcher.Invoke(()=> _window.ImageData = imgString);
    }

和新窗口的構造函數:

public ScreenSharingWindow()
    {
        InitializeComponent();
        DataContext = this;
        Image = new Bitmap(@"C:\Users\roudy\Desktop\SaveIcon.png");
    }

注意:當我嘗試從“ImageData”屬性中的文件加載 bitmap 時,它也不起作用,所以當它從父 window 更改時(通過 Z358E3E185C2'2A6A339BE30FD 顯示它沒有),這似乎是一個線程問題

問題來自 SignalR。 我正在運行同一個項目的 2 個實例,屏幕截圖被發送到主機而不是客戶端,客戶端需要它來創建一個新的 window,這導致圖像為空白。 感謝@Clemens 讓調試變得更容易,而無需轉換器和更多復雜性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM