I have the following code
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));
}
Where rect is completely inside the image boundaries. According to C# documentation positive Stride means top-down image, while negative means bottom-up. How and why can the Stride member of BitmapData has different sign on different parts of the image?
As far as i understand(according to this, and this) one image can be top-down or bottom-up, but only one of them. In my case i have an image with top-down AND bottom-up parts at the same time.
But how could this happen?
It's certainly possible (permissible) in terms of the specification of API that each time you call LockBits
, the memory aperture you get could be presented differently. You have no access to the bits whatsoever until you lock them, so it's totally up to the implementation how to present those bits to you after you lock them. The API permits a signed Stride
, so the implementation could take advantage of that to the extent it wants to. When you unlock the bits and then lock them again, the API is permitted to present the bits to you at a different address, with a different stride.
So you should probably be prepared for the eventuality that the stride is different between different calls to LockBits
of the same bitmap. (Write your code in a way that supports positive and negative strides.) Honestly, I can't see the advantage of assuming that the memory is arranged with the same stride sign on subsequent LockBits
calls.
As for whether or not that actually happens in the field with a particular implementation is less interesting a question to me. Even if it doesn't happen right now, it could happen with an update that arrives tomorrow because, like I said, it's up to the implementation. But having said that, typically once the original bitmap memory layout is determined, it will likely stay the same for reasons of efficiency. Changing the row order would involve, minimally, copying the bits to a different region of memory, so it's more efficient to leave it alone if possible.
Here's a case where you can observe different strides on the same bitmap. Suppose you have a bitmap stored in a bottom-up format natively on disk. After being read from disk, but being locked in a non-native format, the implementation flips it around after transcoding it to a different (e.g. wider) pixel format. Locking pixels in PixelFormat.Format16bppRgb555
natively might give you bottom up, but then locking them in PixelFormat.Format32bppRgb
might flip the row order and present a buffer with positive stride because that's the way the internal transcoder might work: to always allocate a top-down destination for the new format even if the source format is bottom-up.
See this source code as evidence that this can happen in practice, where it always chooses a positive stride for bitmaps locked in non-native formats even if the source format had a negative stride.
As another example, an implementation may choose to perform a copy/transcode when the locked rectangle doesn't meet some criteria (e.g. multiple of 4 bytes width) resulting in the stride of the buffer allocated for the copied bits, which is potentially different from the original.