//#define ADDRESS_MODE
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BitmapDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void LockUnlockBitsExample(PaintEventArgs e)
{
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
int x = 30;
int y = 40;
Rectangle rect = new Rectangle(x, y, bmp.Width-2*x, bmp.Height-2*y);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
#if ADDRESS_MODE
unsafe
{
byte* ptr = (byte*)bmpData.Scan0;
int row = 0;
int col = 0;
//ptr[row * bmpData.Stride + col * 3 + 2] = 0xff;
for (row = 0; row < rect.Height; ++row)
{
for (col = 0; col < rect.Width; ++col)
{
ptr[row * bmpData.Stride + col * 3 + 2] = 0xff;
}
}
//for (int c = 0; c < rect.Width; ++c )
//{
// ptr[(row + 1) * bmpData.Stride + c * 3 + 2] = 0xff;
//}
}
#else
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmpData.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
#endif
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
//e.Graphics.DrawImage(bmp, 0, 150);
e.Graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
LockUnlockBitsExample(e);
}
}
}
总结
Bitmap对象是对GDI+的.NET封装。
(byte*)bmpData.Scan0为锁定区域首字节的地址,bmpData.Stride为扫描宽度。
锁定区域的内存是一块连续存储空间,其大小为Math.Abs(bmpData.Stride) * bmpData.Height。
unsafe private void buttonTest_Click(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap("demo.bmp");
this.pictureBoxLeft.Image = bitmap;
IntPtr p = Marshal.AllocHGlobal(300 * 500 * 4);
UInt32* pUInt32 = (UInt32*)p;
for (int i = 0; i < 300 * 500; ++i)
*(pUInt32 + i) = 0xffff0000;
BitmapData bitmapData = new BitmapData();
bitmapData.Width = 500;
bitmapData.Height = 300;
bitmapData.Stride = 4 * bitmapData.Width;
bitmapData.PixelFormat = PixelFormat.Format32bppArgb;
bitmapData.Scan0 = p;
// Lock a 50x30 rectangular portion of the bitmap for writing.
Rectangle rect = new Rectangle(20, 10, 500, 300);
BitmapData bmpData = bitmap.LockBits(
rect,
ImageLockMode.WriteOnly | ImageLockMode.UserInputBuffer,
PixelFormat.Format32bppArgb,
bitmapData);
// Commit the changes and unlock the 50x30 portion of the bitmap.
bitmap.UnlockBits(bmpData);
this.pictureBoxRight.Image = bitmap;
Marshal.FreeHGlobal(p);
p = IntPtr.Zero;
}
------------------------------------------------------------------------------------
https://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx
The Bitmap::LockBits method locks a rectangular portion of this bitmap and provides a temporary buffer that you can use to read or write pixel data in a specified format. Any pixel data that you write to the buffer is copied to theBitmap object when you call Bitmap::UnlockBits.
------------------------------------------------------------------------------------
资料
http://timothyqiu.com/archives/lockbits-in-gdiplus/
http://msdn.microsoft.com/en-us/library/windows/desktop/ms536298(v=vs.85).aspx
使用lockbits方法处理图像
http://blog.sina.com.cn/s/blog_4e3e2ce4010009on.html
GDI/GDI+(1): 将Bitmap导出为Byte[]