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

ASP.NET
asp.net GridView控件中模板列CheckBox全选、反选、取消
asp.net GridView 删除时弹出确认对话框(包括内容提示)
asp.net DropDownList 三级联动下拉菜单实现代码
asp DataTable添加列和行的三种方法
Asp.net 页面调用javascript变量的值
asp.net 长文章通过设定的行数分页
asp.net 定时间点执行任务的简易解决办法
asp.net 页面延时五秒,跳转到另外的页面
asp.net 动态输出透明gif图片
asp.net DataList与Repeater用法区别
asp.net Javascript获取CheckBoxList的value
asp.net程序在调式和发布之间图片路径问题的解决方法
asp.net下生成英文字符数字验证码的代码
asp.net 页面版文本框智能提示JSCode (升级版)
ASP.NET URL伪静态重写实现方法
ASP.NET 2.0 中Forms安全认证
asp.net 动态添加多个用户控件
asp.net Repeater显示父子表数据,无闪烁
asp.net 无法获取的内部内容,因为该内容不是文本 的解决方法
asp.net GridView排序简单实现

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-08-14   浏览: 62 ::
收藏到网摘: 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;

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