1

我是在论坛发帖的新手,因为我通常可以通过搜索来帮助自己,但我真的被困在这里......

我已经编写了一个 ASP.NET C# WebApp,它还需要将客户端串行 com 接口合并到一个基本上进行实时扫描的设备中,并通过串行 (USB) 接口将扫描的图像流式传输(这些图像需要不断刷新,大约每 100 毫秒,因此基本上创建了“动画”效果)

为了让它在客户端运行,我编写了一个小的 Silverlight 应用程序。在浏览器中运行,使用以下代码,使用 Backgroundworker 尝试将串行通信与 UI 分开,并从收到的字节数组中刷新 Silverlight 图像控件。

我有非常相似的代码在 WinForms 中 100% 工作,我在 Silverlight 中唯一的问题是,我的图像控件中没有显示任何图像。

下面是相关的 WinForms 代码和相应的 Silverlight 代码。

我目前的怀疑是图像永远不会被渲染,因为 Silverlight 只允许 PixelFormat 为 32bppArgb,我需要使用 PixelFormat.Format8bppIndexed,按照下面的 WinForms CreateBitmap() 方法。

如果这确实是问题,我找不到任何方法在 Silverlight 中创建这种格式的位图。

/////////////// WINFORMS CODE (Timer1 Interval = 100ms) //////////////////

private void timer1_Tick(object sender, EventArgs e)
{
    BackgroundWorker bw = new BackgroundWorker();

     bw.WorkerReportsProgress = true;

    bw.DoWork += new DoWorkEventHandler(
    delegate(object o, DoWorkEventArgs args)
    {
        BackgroundWorker b = o as BackgroundWorker;

        int BytesToRead = COMport.Read(ReceiveBuffer);

        for (int i = 0; i < BytesToRead; i++)
        {

                //Code that copies ReceiveBuffer to byte[] LiveImgArr

                Bitmap liveBMP = CreateBitmap(LiveImgArr, imgWidth, imgHeight);
                bw.ReportProgress(i, liveBMP);        

        }

    });


    bw.ProgressChanged += new ProgressChangedEventHandler(
    delegate(object o, ProgressChangedEventArgs args)
    {
        pictureBox1.Image = (Bitmap)args.UserState;

    });

    bw.RunWorkerAsync();
}


private Bitmap CreateBitmap(byte[] buffer, int width, int height)
{
    Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);

    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
    System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpData.Scan0, width * height);
    bmp.UnlockBits(bmpData);

    ColorPalette pal = bmp.Palette;
    for (int i = 0; i < 256; i++)
    {
        pal.Entries[i] = Color.FromArgb(i, i, i);
    }
    bmp.Palette = pal;

    return bmp;
}


//////////////////////////////////////// END /////////////////////////////////////////

//////////////////////////////// SilverLight Code ///////////////////////////////////


public void StartTimer()//object o, RoutedEventArgs sender)
{
    System.Windows.Threading.DispatcherTimer CommsTimer = new System.Windows.Threading.DispatcherTimer();
    CommsTimer.Interval = new TimeSpan(0, 0, 0, 0, 100); // 100 Milliseconds 
    CommsTimer.Tick += new EventHandler(CommsTimer_Tick);
    CommsTimer.Start();
}

public void CommsTimer_Tick(object o, EventArgs sender)
{

    BackgroundWorker bw = new BackgroundWorker();

    bw.WorkerReportsProgress = true;

    bw.DoWork += new DoWorkEventHandler(
    delegate(object b, DoWorkEventArgs args)
    {
        BackgroundWorker obw = b as BackgroundWorker;

        int BytesToRead = COMport.Read(ReceiveBuffer);

        for (int i = 0; i < BytesToRead; i++)
        {

               //Code that copies ReceiveBuffer to byte[] LiveImgArr

                bw.ReportProgress(i, LiveImgArr);

            }

        }

    });


    bw.ProgressChanged += new ProgressChangedEventHandler(
    delegate(object j, ProgressChangedEventArgs args)
    {


        byte[] imgByte = (byte[])args.UserState;

        using (MemoryStream ms = new MemoryStream(imgByte, 0, imgByte.Length))
        {

            BitmapImage bmp = new BitmapImage();

            bmp.SetSource(ms);
            this.image1.Source = bmp;
        }

    });

    //////////////////////////////////////// END //////////////////////////////////////////

    ///////////////////////////////// NEW CODE AS PER CLEMENTS/////////////////////////////
    bw.ProgressChanged += new ProgressChangedEventHandler(
    delegate(object j, ProgressChangedEventArgs args)
    {
        byte[] imgByte = (byte[])args.UserState;

        WriteableBitmap wbmp = new WriteableBitmap(208, 208);
        int[] wbmpArray = wbmp.Pixels;

        for (int pixelIndex = 0; pixelIndex < imgByte.Length; pixelIndex++)
        {
            byte alpha = 128;
            byte red = 255;
            byte green = 255;
            byte blue = 255;

            double scaleAlpha = alpha / 255.0;

            // we are not using scaleAlpha here
            //wbmp.Pixels[pixelIndex] =
            //        (alpha << 24)
            //        | (red << 16)
            //        | (green << 8)
            //        | blue;

            // notice the alpha value is NOT scaled
            // it’s also very important to scale BEFORE
            // shifting the values
            wbmp.Pixels[pixelIndex] =
                    (alpha << 24)
                    | ((byte)(red * scaleAlpha) << 16)
                    | ((byte)(green * scaleAlpha) << 8)
                    | (byte)(blue * scaleAlpha);
        }

        wbmp.Invalidate();

        this.image1.Source = wbmp;

        //ImageBrush imgBrush = new ImageBrush();
        //imgBrush.ImageSource = wbmp;
        //imgRect.Fill = imgBrush;

    });
4

1 回答 1

0

BitmapImage.SetSource仅接受包含编码图像缓冲区(PNG 或 JPEG)的流。

为了直接设置像素数据,您必须使用WriteableBitmap而不是BitmapImage. 从类文档中的备注部分:

• 使用WriteableBitmap(Int32, Int32) 构造一个最初为空但有尺寸的WriteableBitmap。

• 从Pixels 中获取像素数组。

• 循环遍历数组,将单个像素值设置为整数值,计算为预乘 ARGB32。

• 呼叫无效。

• 要在 UI 中显示图像,请将 WriteableBitmap 用作图像控件(如 Image)的源,或用作 ImageBrush 的源图像。

以下代码仅使用整数算术用蓝色和从左到右从 0 到 100% 的不透明度渐变填充 WriteableBitmap:

var bitmap = new WriteableBitmap(500, 500);
int red = 0;
int green = 0;
int blue = 255;

for (int i = 0; i < bitmap.PixelWidth * bitmap.PixelHeight; i++)
{
    int x = i % bitmap.PixelWidth;
    int alpha = x * 256 / bitmap.PixelWidth;

    bitmap.Pixels[i] =
        (alpha << 24) |
        ((red * alpha / 256) << 16) |
        ((green * alpha / 256) << 8) |
        (blue * alpha / 256);
}

bitmap.Invalidate();
image.Source = bitmap;
于 2013-09-07T20:11:27.507 回答