C#中Image , Bitmap 和 BitmapData

先说Image,Image 就是个图像,不能实例化,提供了位图和源文件操作的函数。本篇文章他就是来打酱油的,这里提供一个Bitmap转成BitmapSource的方法。

 1 [DllImport("gdi32")]
 2 static extern int DeleteObject(IntPtr o);
 3 /// <summary>
 4 /// bitmap转换为bitmapsource 以适应wpf的image
 5 /// </summary>
 6 /// <param name="pic"></param>
 7 /// <returns></returns>
 8 public static BitmapSource GetMapSource(Bitmap pic)
 9 {
10     IntPtr ip = pic.GetHbitmap();
11     BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
12         ip, IntPtr.Zero, Int32Rect.Empty,
13         System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
14     DeleteObject(ip);
15     return bitmapSource;
16 }

接下来说Bitmap和BitmapData。

Bitmap类
Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下:
1. GetPixel方法和SetPixel方法:获取和设置一个图像的指定像素的颜色.
2. PixelFormat属性:返回图像的像素格式.
3. Palette属性:获取和设置图像所使用的颜色调色板.
4. Height Width属性:返回图像的高度和宽度.
5. LockBits方法和UnlockBits方法:分别锁定和解锁系统内存中的位图像素.在基于像素点的图像处理方法中使用LockBits和UnlockBits是一个很好的方式,这两种方法可以使我们指定像素的范围来控制位图的任意一部分,从而消除了通过循环对位图的像素逐个进行处理,每调用LockBits之后都应该调用一次UnlockBits.
BitmapData类
BitmapData对象指定了位图的属性
1. Height属性:被锁定位图的高度.
2. Width属性:被锁定位图的高度.
3. PixelFormat属性:数据的实际像素格式.
4. Scan0属性:被锁定数组的首字节地址,如果整个图像被锁定,则是图像的第一个字节地址.
5. Stride属性:步幅,也称为扫描宽度.

这里要重点说说Stride属性,这个和Width有什么区别呢,可以这么说,如果你的图片大小也就是图片字节是4的整数倍,那么Stride与Width是相等的,否则Stride就是大于Width的最小4的整数倍。在处理过程中,Stride肯定是4的整数倍,这里是个坑啊。。。

                          盗张图,连接写在文章底部

先看看BitmapData的应用,我的场景是,我有一个一维像素点阵数组,里面放的是每个像素点的灰度值,知道宽和高,要转换成bitmap

 1 /// <summary>
 2 /// 像素点阵转换为bitmap
 3 /// </summary>
 4 /// <param name="rawValues">byte[]数组</param>
 5 /// <param name="width">图片的宽度</param>
 6 /// <param name="height">图片的高度</param>
 7 /// <returns>bitmap图片</returns>
 8 public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)
 9 {
10     Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
11     BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
12     //// 获取图像参数
13     //bmpData.Stride = width;
14     int stride = bmpData.Stride;  // 扫描线的宽度
15     int offset = stride - width;  // 显示宽度与扫描线宽度的间隙
16     IntPtr iptr = bmpData.Scan0;  // 获取bmpData的内存起始位置
17     int scanBytes = stride * height;// 用stride宽度,表示这是内存区域的大小
18     //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组
19     int posScan = 0, posReal = 0;// 分别设置两个位置指针,指向源数组和目标数组
20     byte[] pixelValues = new byte[scanBytes];  //为目标数组分配内存
21     for (int x = 0; x < height; x++)
22     {
23         //// 下面的循环节是模拟行扫描
24         for (int y = 0; y < width; y++)
25         {
26             pixelValues[posScan++] = rawValues[posReal++];
27         }
28         posScan += offset;  //行扫描结束,要将目标位置指针移过那段“间隙”
29     }
30     //// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中
31     System.Runtime.InteropServices.Marshal.Copy(pixelValues, 0, iptr, scanBytes);
32     bmp.UnlockBits(bmpData);  // 解锁内存区域
33     //// 下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度
34     ColorPalette tempPalette;
35     using (Bitmap tempBmp = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed))
36     {
37         tempPalette = tempBmp.Palette;
38     }
39     for (int i = 0; i < 256; i++)
40     {
41         tempPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
42     }
43
44     bmp.Palette = tempPalette;
45
46     //// 算法到此结束,返回结果
47     return bmp;
48 }

这代码也是网上找的,具体哪里已经忘记了。至于24位位图数据其实就是 一个像素点有rgb三个值而已,道理一样。

同样,我们也可以根据图片得到他的灰度数组

 1 //8位位图得到除去文件头信息的一位灰度数组
 2
 3
 4 BitmapData bmpData = map.LockBits(new System.Drawing.Rectangle(0, 0, map.Width, map.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
 5
 6 //// 获取图像参数
 7
 8 int stride = bmpData.Stride;  // 扫描线的宽度
 9
10 int offset = stride - map.Width;  // 显示宽度与扫描线宽度的间隙
11
12 IntPtr iptr = bmpData.Scan0;  // 获取bmpData的内存起始位置
13
14 int scanBytes = stride * map.Height;// 用stride宽度,表示这是内存区域的大小
15
16 //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组
17
18 mapdata = new byte[scanBytes];  //为目标数组分配内存
19
20 System.Runtime.InteropServices.Marshal.Copy(iptr, mapdata, 0, scanBytes); //copy内存中数据到数组中

这里对与bitmapdata的操作方式是ReadOnly

为什么说stride是坑呢,因为在工作中,我有一个大小不为4的整数倍的文件,通过上面方法将他们转为图片,然后操作之后我需要存回去,继续存成文件的形式,如果你直接存回去你会发现你的文件变大了。这时候就需要避开stride。其实stride占据的空间什么都没有做,我们如何遍历构建图片,就如何反遍历回数组就可以了

public static byte[] GetMapData(byte[] MapData,int width,int height)
{
    var length = MapData.Length;
    if(width==length/height)
    {
        return MapData;
    }
    int offset=length/height-width;
    var scanBytes = width * height;
    byte[] RawMapData = new byte[scanBytes];
    int posScan = 0, posReal = 0;
    for(int x=0;x<height;x++)
    {
        for (int y=0;y<width;y++)
        {
            RawMapData[posScan++] = MapData[posReal++];
        }
        posReal += offset;
    }
    return RawMapData;
}

至于24位位图转8位位图,还是看这位博主的博客,他总结了很多,我还是觉得opencv比较快捷方便。

http://blog.csdn.net/jiangxinyu/article/details/6222302

另外还看到了一下c#处理图片的方法,比如光照,雾化,浮雕等,请移步下面链接

http://www.pin5i.com/showtopic-20228.html

种一棵树最好的时间是十年前,其次是现在。

时间: 2024-10-13 15:55:44

C#中Image , Bitmap 和 BitmapData的相关文章

C#中的bitmap类和图像像素值获取方法

一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetPixel方法和SetPixel方法:获取和设置一个图像的指定像素的颜色. 2. PixelFormat属性:返回图像的像素格式. 3. Palette属性:获取和设置图像所使用的颜色调色板. 4. Height Width属性:返回图像的高度和宽度. 5. LockBits方法和UnlockBits

android 在HTML中显示bitmap

逻辑:将bitmap转化为Base64,通过调用HTML中的JS,显示到HTML中 (1)android代码 public String bitmaptoString(Bitmap bitmap) { // 将Bitmap转换成Base64字符串 StringBuffer string = new StringBuffer(); ByteArrayOutputStream bStream = new ByteArrayOutputStream(); try { bitmap.compress(C

四十六、android中的Bitmap

四十六.android中的Bitmap: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304940.html 四十七.实现调用Android手机的拍照功能: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304970.html

从资源文件中获取Bitmap

从资源文件中获取Bitmap: [1]先获取Resource,然后可以通过资源ID获取Drawable Drawable d = r.getDrawable(R.drawable.xxx)); [2]通过资源ID获取资源文件的数据流,再获取Bitmap InputStream is = r.openRawResource(R.drawable.xxx); Bitmap bitmap ; ①使用BitmapDrawable: BitmapDrawable bd = new BitmapDrawab

Android技术6:Android中对于Bitmap的处理

很多Android应用在运行时,会遇到运行缓慢,不流畅等影响用户体验问题,这有一部分原因与图片有密切关系.当android应用需要加载较大较多的照片时,经常反应迟缓,甚至由于OOM,造成系统奔溃.下面将提供一种可行的解决方案. 1.获取图片的宽高属性 1 BitmapFactory.Options options=new BitmapFactory.Options(); 2 options.inJustDecodeBounds=true; 3 BitmapFactory.decodeFile(f

代码中使用bitmap资源并加载到控件上

1.从res/drawable/XX.jpg里引用图片资源: 1. Resources res = getResources(); Bitmap inDrawable= BitmapFactory.decodeResource(res, R.drawable.user_img_grey); userImgButton.setImageBitmap(inDrawable ); 2.从本地sd卡的文件路径中使用图片资源: UserImgPath=Environment.getExternalStor

MIUI添加内存调试工具:查看进程中的Bitmap信息

Android开发中的内存管理一直是令人头痛的事情.其中占用内存最大的一般是Bitmap. 在上周五发布的MIUI开发版中,我添加了查看内存里Bitmap信息的功能.大家开发app的时候可以使用这个功能来查看分析app中的Bitmap情况. 使用方法:adb shell dumpsys gfxinfo [package name] [-b] [-e] adb shell dumpsys gfxinfo是Android原有的功能.我在此之上添加了一些参数来输出Bitmap信息. -b会输出进程中所

Android应用开发中对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常.所以,对于图片的内存优化,是Android应用开发中比较重要的内容. 1) 要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间.那为什么还需

[ActionScript 3.0] AS3中的位图(BitmapData)应用

1.位图使用(模糊)滤镜 //创建一个矩形区域的BitmapData var bmd:BitmapData = new BitmapData(80, 30, false, 0xffffff); //画个红色的矩形 var rect:Rectangle = new Rectangle(20, 10, 40, 10); bmd.fillRect(rect, 0xFF0000); //找到红色矩形的右上顶点 var pt:Point = new Point(rect.left, rect.top);