【问题标题】:WPF BitmapImage sliced in twoWPF BitmapImage 一分为二
【发布时间】:2015-09-03 19:34:40
【问题描述】:

我在 WPF 应用程序中搞乱位图。我在后台线程上收到一个字节数组,转换器将其更改为 bitmapSource 以进行绑定。

但是,如果我尝试直接在内存中创建 bitmapSource 并显示它,它会将图像一分为二。我没有丰富的位图经验,但足以让我始终显示图像。

奇怪的是,如果我先写出文件,然后再读回,它就可以工作。

File.WriteAllBytes(@"C:\woot2.bmp", bytes);

var bmp = new BitmapImage(new Uri(@"C:\woot2.bmp"));
var height = bmp.Height;                       // 480.0
var width = bmp.Width;                         // 640.0
var format = bmp.Format;                       // Indexed8
var dpix = bmp.DpiX;                           // 96.0
var dpiY = bmp.DpiY;                           // 96.0
var pallete = bmp.Palette;                     // Gray256
var cacheOption = bmp.CacheOption;             // Default
var createOptions = bmp.CreateOptions;         // None
return bmp;

[

我检查了高度、宽度、pixelFormat、pixelPalette、dpi 等都与我读入的文件匹配,但它仍然显示不正确。甚至检查了文件的标题。

我已经使用 PngBitmapEncoder 尝试了 BitmapImages、BitmapSources、WriteableBitmaps,但我仍然得到相同的结果。我觉得要么我错过了一些基本的东西,要么有一个错误。我以为切片是错误的,但没有歪斜,

我在图片中显示它:

<Image Width="640" Height="480" 
     Source="{Binding VisionImage, Mode=OneWay,UpdateSourceTrigger=PropertyChanged, 
     Converter={StaticResource VisionImageConverter} }"></Image>

这是我目前必须转换的代码

var width = 640;
var height = 480;
var dpiX = 96;
var dpiY = 96;
var pixelFormat = PixelFormats.Indexed8;
var palleteFormat = BitmapPalettes.Gray256;
var stride = 4* (((width*pixelFormat.BitsPerPixel) + 31)/32);
return  BitmapSource.Create(width, height, dpiX, dpiY, 
                       pixelFormat, palleteFormat, bytes, stride);

有什么想法吗?

【问题讨论】:

  • 如果问题是关于传递给bytesFile.WriteAllBytes(@"C:\woot2.bmp", bytes);,那么您有一个编码的BMP 缓冲区,而不是原始像素缓冲区。您不应使用它调用 BitmapSource.Create。而是从字节数组创建一个 MemoryStream 并将其分配给 BitmapImage 的StreamSource 属性。
  • 我也试过位图图像(这肯定是 new BitmapImage(new Uri("....")) 使用的,只是原始字节?
  • 顺便说一句,你的步幅公式是错误的,应该是 bytesPerPixel = (bitsPerPixel + 7) / 8 然后是 stride = width * bytesPerPixel
  • 嗯,真的吗?看到这个公式在很多地方都使用过,而且它最终是 640,对于我的文件大小来说,每个像素一个字节应该是正确的

标签: c# wpf bitmap


【解决方案1】:

显然字节数组不包含原始像素数据,而是一个编码的BMP缓冲区,所以你不能通过BitmapSource.Create创建BitmapSource。

您应该从编码的 BMP 缓冲区创建一个 BitmapImage,如下所示:

var bitmapImage = new BitmapImage();
using (var stream = new MemoryStream(bytes))
{
    bitmapImage.BeginInit();
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    bitmapImage.StreamSource = stream;
    bitmapImage.EndInit();
}

或者像这样创建一个 BitmapFrame:

BitmapFrame bitmapFrame;
using (var stream = new MemoryStream(bytes))
{
    bitmapFrame = BitmapFrame.Create(stream,
        BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}

【讨论】:

  • 我已经尝试过这个完全相同的代码并得到了完全相同的结果 :( 不过我会尝试位图框选项,谢谢
  • 我想我只是不明白如何写出文件并且它看起来很完美,但是当我使用完全相同的字节直接在我的代码中创建它时它搞砸了
【解决方案2】:

好的,所以这个问题的答案很简单。我不是只给它像素数组,而是给它整个位图文件数组。我认为当您从文件创建 bitmapImage 时,它​​必须在内部使用 bitmapDecoder。这就是为什么写入文件然后再读取它的原因。

所以我可以计算文件的像素偏移量,然后复制我需要的字节,但我选择将数组包装在内存流中并使用 BmpBitmapDecoder,因为它更简单

using(var ms = new MemoryStream(bytes))
{
     var decoder = new BmpBitmapDecoder(ms, BitmapCreateOptions.DelayCreation, BitmapCacheOption.OnDemand);
     return new WriteableBitmap(decoder.Frames.FirstOrDefault());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多