【问题标题】:Bitmap.Lockbits confusionBitmap.Lockbits 混淆
【发布时间】:2012-06-02 00:47:18
【问题描述】:

MSDN 参考:[1]http://msdn.microsoft.com/en-us/library/5ey6h79d.aspx#Y1178

从链接中它说第一个参数将“指定要锁定的位图部分”,我将其设置为位图的较小部分(位图是 500x500,我的矩形是(0,0,50,50 )) 但是返回的 BitmapData 的步幅为 1500 (=500*3),因此基本上每次扫描仍将水平扫描整个图片。但是,我想要的只是位图的左上角 50x50 部分。

结果如何?

【问题讨论】:

    标签: c# gdi+


    【解决方案1】:

    步幅始终为完整位图,但 Scan0 属性会根据锁定矩形的起点以及 BitmapData 的高度和宽度而有所不同。

    原因是您仍然需要知道位图的实际位宽,以便遍历行(将步幅添加到地址)。

    一个简单的方法是:

    var bitmap = new Bitmap(100, 100);
    
    var data = bitmap.LockBits(new Rectangle(0, 0, 10, 10),
                               ImageLockMode.ReadWrite,
                               bitmap.PixelFormat);
    
    var pt = (byte*)data.Scan0;
    var bpp = data.Stride / bitmap.Width;
    
    for (var y = 0; y < data.Height; y++)
    {
        // This is why real scan-width is important to have!
        var row = pt + (y * data.Stride);
    
        for (var x = 0; x < data.Width; x++)
        {
            var pixel = row + x * bpp;
    
            for (var bit = 0; bit < bpp; bit++)
            {
                var pixelComponent = pixel[bit];
            }
        }
    }
    
    bitmap.UnlockBits(data);
    

    所以它基本上只是锁定整个位图,但给你一个指向位图中矩形左上角像素的指针,并适当地设置扫描的宽度和高度。

    【讨论】:

    • 无法保证位图的步幅等于(宽度 * 每个像素的字节数),因此“var bpp = data.Stride / bitmap.Width;”是错误的(您可以轻松创建具有不同步幅的位图)。您可以使用 (((bitmap.Pixelformat) >> 8) & 255) 获取每个像素的位数,或 (((bitmap.Pixelformat) >> 11) & 31) 获取每个像素的字节数。
    • 另外,如果步幅对您很重要,您可以提供自己的缓冲区并使用 ImageLockMode.UserInputBuffer 提供步幅。
    • @VincentPovirk 不错的提示,但你能解释一下什么时候步幅不会是 width * bpp?
    • 任何时候位图都是用一个跨步的构造函数创建的,比如这个:msdn.microsoft.com/en-us/library/zy1a2d14.aspx(除非用户传递 0 或 width * bpp 来表示跨步)
    • 仅供参考,这里有GetPixelFormatSizemsdn.microsoft.com/en-us/library/…
    猜你喜欢
    • 2014-07-09
    • 1970-01-01
    • 2014-05-06
    • 2015-02-02
    • 2011-05-11
    • 2012-08-15
    • 2019-06-26
    • 2012-04-18
    • 2023-03-29
    相关资源
    最近更新 更多