【问题标题】:Why BitmapData Stride have alternating sign?为什么 BitmapData Stride 有交替符号?
【发布时间】:2022-01-29 00:00:44
【问题描述】:

我有以下代码

        var rect = new Rectangle(x, y, w, h);
        BitmapData data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
        BitmapSource cropppedImage;
        if (data.Stride < 0)
        {
            cropppedImage = BitmapSource.Create(data.Width, data.Height, dpiX, dpiY,
                                            GetPixelFormat(bitmap.PixelFormat), palette, data.Scan0 + data.Stride * data.Height, Math.Abs(data.Stride) * data.Height, Math.Abs(data.Stride));
        }
        else
        {
            cropppedImage = BitmapSource.Create(data.Width, data.Height, dpiX, dpiY,
                                                GetPixelFormat(bitmap.PixelFormat), palette, data.Scan0, Math.Abs(data.Stride) * data.Height, Math.Abs(data.Stride));
        }

其中 rect 完全在图像边界内。 根据 C# 文档,正 Stride 表示自上而下的图像,而负表示自下而上的图像。 BitmapData 的 Stride 成员如何以及为什么在图像的不同部分具有不同的符号?

据我了解(根据thisthis),一张图片可以是自上而下或自下而上的,但只能是其中一张。 在我的情况下,我有一张同时包含自上而下 AND 自下而上部分的图像。

但这怎么会发生呢?

【问题讨论】:

  • docs.microsoft.com/en-us/windows/win32/directshow/… 我认为同一张图片不太可能同时具有自上而下和自下而上的部分。
  • 是的,这解释了两种不同的存储方法。但据我了解,一个 BITMAPINFOHEADER 告诉您 DIB 图像是自上而下或自下而上的,适用于整个图像。就我而言,我在一张图片中同时拥有自上而下和自下而上的部分。
  • 我不确定,但也许在问题中澄清这一点以及显示您在图像的不同部分得到不同符号的代码。从这个问题中我不清楚你实际上为同一张图像得到了两个不同的标志。
  • 好的,感谢您的反馈。

标签: c# bitmapdata


【解决方案1】:

可能(允许)每次调用LockBits的API的规范,你得到的内存孔径可能会有所不同。在锁定它们之前,您无法访问这些位,因此在锁定它们之后如何向您呈现这些位完全取决于实现。 API 允许签名的Stride,因此实现可以在它想要的范围内利用它。当您解锁这些位然后再次锁定它们时,API 可以在不同的地址以不同的步幅将这些位呈现给您。

因此,您可能应该准备好,以防万一对同一位图的LockBits 的不同调用之间的步幅不同。 (以支持正向和负向跨度的方式编写代码。)老实说,我看不出假设内存在随后的LockBits 调用中以相同的跨度符号排列的优势。

至于这是否真的发生在具有特定实现的领域中,对我来说不是一个有趣的问题。即使它现在没有发生,它可能发生在明天到达的更新中,因为就像我说的那样,这取决于实施。但话虽如此,通常一旦确定了原始位图内存布局,出于效率原因,它可能保持不变。更改行顺序至少会涉及将位复制到不同的内存区域,因此如果可能的话,不理会它会更有效。

在这种情况下,您可以在同一个位图上观察到不同的步幅。假设您有一个以自下而上格式本地存储在磁盘上的位图。在从磁盘读取但被锁定为非本机格式后,实现在将其转码为不同的(例如更宽的)像素格式后将其翻转。将像素锁定在PixelFormat.Format16bppRgb555 本身可能会让您自底向上,但随后将它们锁定在PixelFormat.Format32bppRgb 可能会翻转行顺序并呈现一个具有正跨度的缓冲区,因为这是内部转码器可能工作的方式:即使源格式是自下而上的,也要始终为新格式分配自上而下的目标。

请参阅此source code 以证明这可能在实践中发生,即使源格式具有负跨度,它也始终为锁定在非本地格式中的位图选择正跨度。

作为另一个示例,当锁定的矩形不满足某些条件(例如 4 字节宽度的倍数)时,实现可能会选择执行复制/转码,从而导致为复制位分配的缓冲区的步长,即可能与原版不同。

【讨论】:

  • 谢谢,现在至少我知道了一点。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 2014-04-03
  • 2021-06-06
相关资源
最近更新 更多