为什么 BitmapData Stride 有交替符号?

Why BitmapData Stride have alternating sign?

我有以下代码

        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 成员如何以及为什么在图像的不同部分有不同的符号?

据我了解(根据this, and this)一张图片可以是自上而下或自下而上,但只能是其中之一。 在我的例子中,我有一个自上而下的图像 AND 同时自下而上的部分。

可是怎么会这样呢?

肯定可能(允许)在API的规范中,每次调用LockBits,得到的内存孔径可能是呈现不同。在锁定它们之前,您无法访问这些位,因此完全取决于实现如何在锁定它们后向您呈现这些位。 API 允许带符号的 Stride,因此实现可以根据需要利用它。当您解锁这些位然后再次锁定它们时,API 被允许以不同的步幅在不同的地址向您呈现这些位。

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

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

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

将此 source code 视为这在实践中可能发生的证据,它始终为锁定在 non-native 格式中的位图选择正步幅,即使源格式具有负步幅也是如此。

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