当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > .Net中图片的快速处理

ASP.NET
使用函数传递参数来执行相应的数据库操作
如何实现在窗体和窗体之间进行传递数据
ASP.NET中文显示之两种解决方法
ASP.NET、JSP及PHP之间的抉择
ASP.NET 2.0发送电子邮件中存在的问题
谈谈HtmlControl与WebControl的区别与用途
从ASP.NET 1.1升级到ASP.NET 2.0要考虑的Cookie问题
通过系统配置来提高ASP.NET应用程序的稳定性
妙用ASP2.0中的URL映射改变网址
AJAX实现web页面中级联菜单的设计
ASP.NET跨页面传值技巧总结
再议ASP.NET DataGrid控件中的“添加新行”功能
Geometry 对象浅析
重构CollapsibleSplitter
如何利用.NET Framework使用RSS feed
ASP.NET获取IP与MAC地址的方法
在ASP.NET 2.0中使用样式、主题和皮肤
ASP.NET中为GridView添加删除提示框
ASP.NET 2.0,无刷新页面新境界
看看一个.net版对话框控件

ASP.NET 中的 .Net中图片的快速处理


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-08-14   浏览: 57 ::
收藏到网摘: n/a

在图片处理过程中,我们经常需要对图片逐像素进行处理,比如为了使图片某一向量的颜色加深或者减淡,或者为了使图像变化成黑白颜色,这个时候我们需要取出每个点上的像素进行计算,再赋值到图像指定的位置。在.Net中,官方提供了Image.GetPixel(int x, int y)的方法供开发人员获取指定位置的像素,同时提供了Image.SetPixel(int x, int y, Color color)的方法来给指定位置的像素赋值。但是这个方法性能很差,假设存在一张1024*768的图片,逐像素操作并予以缓存的话亦至少需要1027*768次GetPixel和SetPixel,处理速度将慢到无法忍受。因此本方案将使用对内存直接读取和赋值的方式来提高图片处理的速度。

这里首先要介绍一个类System.Drawing.Imaging.BitmapData,直接实例化这个类没有用处,我们需要将一个Bitmap锁定到内存中,来获取一个BitmapData的实例。方法如下:

使用Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format)或者它的另一个重载Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData)来将图像数据锁定到内存中,以此来获取一个与指定图片相关联的BitmapData实例。

在BitmapData中有一个重要的属性Scan0,它是一个指针,指向了图片数据所在内存的第一个位置。使用内存跟踪,将Scan0的值填入地址中,可以看到内存的分配情况(Format32bppArgb颜色深度):

这些值与图片像素的对应关系是这样的:

现在我们可以使用System.Runtime.InteropServices.Marshal.WriteByte(IntPtr ptr, byte val)的方法来更改指定位置的像素值了,修改后只要再调用一次Bitmap.UnlockBits(BitmapData bitmapdata)来解锁内存就可以了,例如:

以下为引用的内容:
        private void LockUnlockBitsExample(PaintEventArgs e)
        {
            Bitmap bmp 
= new Bitmap("c:\\fakePhoto.jpg");
            Rectangle rect 
= new Rectangle(00, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData 
=
                bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
                bmp.PixelFormat);
            IntPtr ptr 
= bmpData.Scan0;
            
int bytes = bmp.Width * bmp.Height * 3;
            
byte[] rgbValues = new byte[bytes];
            
for (int counter = 0; counter < rgbValues.Length; counter += 3)
            {
                Marshal.WriteByte(ptr, counter, 
255);
            }
            bmp.UnlockBits(bmpData);
            e.Graphics.DrawImage(bmp, 
00);
        }

此示例将图片上所有像素的Red向量设置为255。运行此实例可以看到图片变色了。

每次调用System.Runtime.InteropServices.Marshal.WriteByte(IntPtr ptr, byte val)的方法并不方便,因此我们构造一个ColorBgra类用来储存这4个颜色向量,它的主要代码是这样的(参考自Paint.Net提供的源码):

以下为引用的内容:
    [StructLayout(LayoutKind.Explicit)]
    
public struct ColorBgra
    {
        [FieldOffset(
0)]
        
public byte B;
 
        [FieldOffset(
1)]
        
public byte G;
 
        [FieldOffset(
2)]
        
public byte R;
 
        [FieldOffset(
3)]
        
public byte A;

        
/// <summary>
        
/// Lets you change B, G, R, and A at the same time.
        
/// </summary>
        [FieldOffset(0)]
        
public uint Bgra;
        
public override string ToString()
        {
            
return "B: " + B + ", G: " + G + ", R: " + R + ", A: " + A;
        }
    }

使用这个类在声明为unsafe的上下文中就可以通过计算偏移量的办法寻址找到指定位置像素的地址(指针),例如在Format32bppArgb颜色深度的图片中可以这样计算:

以下为引用的内容:
        public unsafe ColorBgra* GetPointAddress(int x, int y)
        {
            
return y * 4 + x;
        }

将计算返回的指针赋给ColorBgra*。之后使用如下方法:

以下为引用的内容:
                    color->= i;
                    color 
->= i;
                    color 
->= i;
                    color 
->= i;

直接把值写入内存中,实现对图片像素的快速操作。