C#中Image , Bitmap 和 BitmapData
先说Image,Image 就是个图像,不能实例化,提供了位图和源文件操作的函数。本篇文章他就是来打酱油的,这里提供一个Bitmap转成BitmapSource的方法。
[DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
/// <summary>
/// bitmap转换为bitmapsource 以适应wpf的image
/// </summary>
/// <param name="pic"></param>
/// <returns></returns>
public static BitmapSource GetMapSource(Bitmap pic)
{
IntPtr ip = pic.GetHbitmap();
BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
DeleteObject(ip);
return bitmapSource;
}
接下来说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
/// <summary>
/// 像素点阵转换为bitmap
/// </summary>
/// <param name="rawValues">byte[]数组</param>
/// <param name="width">图片的宽度</param>
/// <param name="height">图片的高度</param>
/// <returns>bitmap图片</returns>
public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)
{
Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
BitmapData bmpData = bmp.LockBits(new System.Drawing.Rectangle(, , width, height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
//// 获取图像参数
//bmpData.Stride = width;
int stride = bmpData.Stride; // 扫描线的宽度
int offset = stride - width; // 显示宽度与扫描线宽度的间隙
IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置
int scanBytes = stride * height;// 用stride宽度,表示这是内存区域的大小
//// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组
int posScan = , posReal = ;// 分别设置两个位置指针,指向源数组和目标数组
byte[] pixelValues = new byte[scanBytes]; //为目标数组分配内存
for (int x = ; x < height; x++)
{
//// 下面的循环节是模拟行扫描
for (int y = ; y < width; y++)
{
pixelValues[posScan++] = rawValues[posReal++];
}
posScan += offset; //行扫描结束,要将目标位置指针移过那段“间隙”
}
//// 用Marshal的Copy方法,将刚才得到的内存字节数组复制到BitmapData中
System.Runtime.InteropServices.Marshal.Copy(pixelValues, , iptr, scanBytes);
bmp.UnlockBits(bmpData); // 解锁内存区域
//// 下面的代码是为了修改生成位图的索引表,从伪彩修改为灰度
ColorPalette tempPalette;
using (Bitmap tempBmp = new Bitmap(, , System.Drawing.Imaging.PixelFormat.Format8bppIndexed))
{
tempPalette = tempBmp.Palette;
}
for (int i = ; i < ; i++)
{
tempPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
} bmp.Palette = tempPalette; //// 算法到此结束,返回结果
return bmp;
}
这代码也是网上找的,具体哪里已经忘记了。至于24位位图数据其实就是 一个像素点有rgb三个值而已,道理一样。
同样,我们也可以根据图片得到他的灰度数组
//8位位图得到除去文件头信息的一位灰度数组 BitmapData bmpData = map.LockBits(new System.Drawing.Rectangle(, , map.Width, map.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); //// 获取图像参数 int stride = bmpData.Stride; // 扫描线的宽度 int offset = stride - map.Width; // 显示宽度与扫描线宽度的间隙 IntPtr iptr = bmpData.Scan0; // 获取bmpData的内存起始位置 int scanBytes = stride * map.Height;// 用stride宽度,表示这是内存区域的大小 //// 下面把原始的显示大小字节数组转换为内存中实际存放的字节数组 mapdata = new byte[scanBytes]; //为目标数组分配内存 System.Runtime.InteropServices.Marshal.Copy(iptr, mapdata, , 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 = , posReal = ;
for(int x=;x<height;x++)
{
for (int y=;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
种一棵树最好的时间是十年前,其次是现在。
C#中Image , Bitmap 和 BitmapData的更多相关文章
- C#中的bitmap类和图像像素值获取方法
一.Bitmap类 Bitmap对象封装了GDI+中的一个位图,此位图由图形图像及其属性的像素数据组成.因此Bitmap是用于处理由像素数据定义的图像的对象.该类的主要方法和属性如下: 1. GetP ...
- android 在你的UI中显示Bitmap - 开发文档翻译
由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明“转”,那么均为原创,转贴请注明本博客链接链接 Displaying Bitmaps in Your UI 在你的UI中显示Bitmap ...
- 四十六、android中的Bitmap
四十六.android中的Bitmap: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304940.html 四十七.实现调用Android ...
- WPF中的Bitmap与byte
原文:WPF中的Bitmap与byte public MainWindow() { InitializeComponent(); byte[] b = GetPictureData(@"F: ...
- MIUI添加内存调试工具:查看进程中的Bitmap信息
Android开发中的内存管理一直是令人头痛的事情.其中占用内存最大的一般是Bitmap. 在上周五发布的MIUI开发版中,我添加了查看内存里Bitmap信息的功能.大家开发app的时候可以使用这 ...
- android中可以使用bitmap的平铺,镜像平铺等减小图片带来的apk过大的问题
bitmap的平铺.镜像drawable文件夹中新建bitmap,其中的tileMode属性 tileMode 属性就是用于定义背景的显示模式: disabled 默认值,表示不使用平铺 cla ...
- JDK中的BitMap实现之BitSet源码分析
前提 本文主要内容是分析JDK中的BitMap实现之java.util.BitSet的源码实现,基于JDK11编写,其他版本的JDK不一定合适. 文中的图比特低位实际应该是在右边,但是为了提高阅读体验 ...
- Bitmap 的bitmapdata和texture区别
Texture:纹理类是对不同平台不同的图片资源的封装在HTML5中,资源是一个HTMLElement对象在OpenGL / WebGL中,资源是一个提交GPU后获取的纹理idTexture类封装了这 ...
- [ActionScript 3.0] AS3中的位图(BitmapData)应用
1.位图使用(模糊)滤镜 //创建一个矩形区域的BitmapData var bmd:BitmapData = new BitmapData(80, 30, false, 0xffffff); //画 ...
随机推荐
- android View 自动 GONE 问题
首先说一下 view visibility VISIBLE.INVISIBLE.GONE的区别: 可见(visible) XML文件:android:visibility="visible& ...
- oracle 索引失效原因
转自 http://www.cnblogs.com/orientsun/archive/2012/07/05/2577351.html Oracle 索引的目标是避免全表扫描,提高查询效率,但有些时 ...
- Eclipse 工作目录被破坏,导致Eclipse 打不开
由于之前一直使用的的是 visual studio 的开发工具,对 java 的 Eclipse 工具比较陌生,在使用 eclipse 的过程中误删了工作目录的部分文件,导致在在下次启动 eclips ...
- 学习练习 使用Servlet实现用户注册功能
package com.hanqi.www; import java.io.IOException; import javax.servlet.ServletException; import jav ...
- iptable原理
http://www.cnblogs.com/littlehann/p/3708222.html http://seanlook.com/2014/02/23/iptables-understand/ ...
- ios开发经典语录锦集
原文链接: iPhone开发经典语录集锦 前言:iPhone是个极具艺术性的平台,相信大家在开发过程中一定有很多感触,希望能写出来一起交流,所以开了这个帖子,以后还会维护. 如果大家和我一样有感触的话 ...
- 图片无法显示,载入制定url失败
今天要做一个图片列表,因为是临时用的,就把图片存放在了img/linshi文件夹下,但是在网页上总是显示不了,提示载入制定url失败, 找了半天,把图片放在上级目录,img下立刻就能访问了.
- c#音乐播放器(欣赏)
设置界面 Mini模式 播放器使用C#编写,用到了大量的自定义控件,播放是调用windows API. 现在只是完成了本地音乐功能,下一步我将要做歌词同步及网络音乐 当然,完成以后我将一步一步教大家做 ...
- POJ C++程序设计 编程题#4 字符串操作
编程题#4: 字符串操作 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描述 给 ...
- DataTable.Select
转载请注明出处:http://www.cnblogs.com/havedream/p/4453297.html 方法:DataTable.Select 作用:获取 DataRow 对象的数组. 重载: ...