您好,欢迎访问一九零五行业门户网

C# GDI+编程(四)

截屏
grahpics类里的copyfromscreen函数,可以把屏幕拷贝到graphics对象里。如果graphics对象是从窗口form里创建的,那么屏幕就直接
显示在窗口里。看例子:给窗口添加一个按钮,然后给这个按钮添加单击事件处理函数。
函数里的代码如下:
private void button1_click(object sender, eventargs e)
 {
  this.creategraphics().copyfromscreen(50,50, 0, 0, this.size,copypixeloperation.sourcecopy);
 }
第一个参数和第二个参数,指明是从屏幕的哪里开始复制,而后面的0,0,就是把屏幕复制到窗口里了,从窗口哪里开始显示。
this.size是要复制的大小(宽高)。
是vc++里的。这里只不过换了种说法而已。最终的结果还是一样的。
之前的graphics对象创建,都是通过窗口的, 这次我们通过图片来创建graphics对象,这样我们就可以在图片上进行绘制了。
而图片对象的创建,并不是只有加载文件这一个方式。我们可以创建一个“空”位图(通过构造函数),这种位图里面没有具体的数据,或者说里面的默认数据,没有用而已,我们只是需要这么个容器。在里面绘图,添加数据进去。
例子:截屏并把图片保存为文件
private void button1_click(object sender, eventargs e)
{
  //创建bitmap图片,800宽,600高,这么个大小的容器。
 bitmap bmp = new bitmap(800, 600);
 //从图片里创建grahpics对象
 graphics gr = graphics.fromimage(bmp);
 //拷贝屏幕到bitmap
 gr.copyfromscreen(0, 0, 0, 0, new size(800, 600), copypixeloperation.sourcecopy);
 //保存为图片文件
 bmp.save(d:\\screen.jpg);
}
怎么样,够简单的吧,四行代码就完成了屏幕截图,并保存为文件,vc++可是要很多行代码。另bitmap是从image类里派生出来的。
双缓冲一次性绘图
 直接看一个没有使用双缓冲的例子吧,鼠标在窗口内移动的时候,左上角的矩形就显示鼠标当前的位置
    public partial class form1 : form
    {
        public form1()
        {
            initializecomponent();
            this.mousemove += formmousemove;
        }
        private void formmousemove(object sender, mouseeventargs e)
        {
            graphics gr = this.creategraphics();
            rectangle rect = new rectangle(0, 0, 100, 35);
            //填充矩形
            lineargradientbrush brush =
                new lineargradientbrush(rect, color.fromargb(44, 55, 66), color.fromargb(123, 150, 189),
                lineargradientmode.horizontal);
            gr.fillrectangle(brush, rect);
            //画矩形
            pen pen = new pen(color.green, 2);
            gr.drawrectangle(pen, rect);
            //显示文本
            gr.textrenderinghint = system.drawing.text.textrenderinghint.antialias;
            string str = string.format(鼠标位置:\n{0},{1}, e.x, e.y);
            gr.drawstring(str, new font(黑体, 11),brushes.white, rect);
        }
    }
可以看到,当鼠标移动的时候,左上角的矩形明显闪烁了,这是因为进行了三次绘制,填充矩形,画矩形,显示文本。才导致的。
当绘制的次数越多,这个闪烁就越明显。
而这三次绘制最终只要得到一个结果,也就是得到一张图片,那么我们就可以使用双缓冲来完成了,先把要绘制的图形绘制到bitmap里面。然后再把bitmap绘制到窗口就行了。
看例子:
        private void formmousemove(object sender, mouseeventargs e)
        {
            graphics graphics = this.creategraphics();
            //从bitmap里创建graphics对象
            bitmap bmp=new bitmap(100,35);
            graphics gr = graphics.fromimage(bmp);
            rectangle rect = new rectangle(0, 0, 100, 35);
            //填充矩形
            lineargradientbrush brush =
                new lineargradientbrush(rect, color.fromargb(44, 55, 66), color.fromargb(123, 150, 189),
                lineargradientmode.horizontal);
            gr.fillrectangle(brush, rect);
            //画矩形
            pen pen = new pen(color.green, 2);
            gr.drawrectangle(pen, rect);
            //显示文本
            gr.textrenderinghint = system.drawing.text.textrenderinghint.antialias;
            string str = string.format(鼠标位置:\n{0},{1}, e.x, e.y);
            gr.drawstring(str, new font(黑体, 11),brushes.white, rect);
            //一次性绘制
            graphics.drawimage(bmp, 0, 0);
        }
获取窗口(控件)的bitmap
drawtobitmap函数,可以把窗口或控件的外观绘制到bitmap里。它属于control类,而窗口类和控件类都是从control类派生出来的。
看例子:(一个按钮单击事件处理函数的代码)
private void button1_click(object sender, eventargs e)
{
 bitmap bmp = new bitmap(width, height);
 this.drawtobitmap(bmp, new rectangle(0, 0, width, height));
 bmp.save(d:\\form.jpg);
}
drawtobitmap的第二个参数,是窗口显示在bitmap里的区域。这个是不能缩小或放大图片的,窗口的大小和bitmap的大小是一致的,
如果填10,10,50,50那就是窗口的0,0,50,50显示在位图的10,10,50,50矩形区域内,窗口起始位置是不是能指定的,只能从位置0,0开始。
获取一个像素点的值
bitmap类里getpixel函数可以获取一个像素点的color值,如果要获取窗口某一个像素点的颜色值,可以先调用drawtobitmap函数,把
窗口保存成bitmap。然后再获取。另:还有对应的函数setpixel设置一个像素的颜色值。
获取png图片显示区域,创建不规则窗口。
获取png图片区域可以用getpixel函数,获取图片里每一个像素点的颜色值,如果alpha值为0的话,那就是透明的,否则把这个点加入区域。那么要如何获取一个color对象的alpah值呢,调用toargb成员函数,这个是32位整数,刚好可以存储4个8位字节的数值:a,r,g,b。
看下示例吧,把alpha值提取出来
{
 color cor1 = color.fromargb(123,225,229,230);
 //获取color的argb值 
 int argb = cor2.toargb();
 //转换成字符数组
 byte[] bargb = bitconverter.getbytes(argb);
 //bargb[3]存储的是alpha值
 string str = string.format({0},{1},{2},{3}, bargb[0], bargb[1], bargb[2], bargb[3]);
 messagebox.show(str);
}
一个完整的示例,获取png显示区域
示例代码:       
public form1()
        {
            initializecomponent();
            //存储png非透明部分的路径
            graphicspath path = new graphicspath();
            //加载png图片
            bitmap bmp = new bitmap(d:\\image\\win.png);
            //判断每个像素的颜色值,获取图片的显示区域
            for (int y = 0; y < bmp.height; y++)
                for (int x = 0; x < bmp.width; x++)
                {
                    color cor = bmp.getpixel(x, y);
                    int argb = cor.toargb();
                    byte[] bargb = bitconverter.getbytes(argb);
                    //像素颜色值不是透明的
                    if (bargb[3] != 0)
                    {
                        //把这个像素点区域添加到路径里去
                        path.addrectangle(new rectangle(x, y, 1, 1));
                    }
                }
            //设置窗口显示区域,通过路径创建区域
            this.region = new region(path);
        }
但是这个方法有点不可靠,如果png图片里有些像素点的颜色值是半透明的,这样就得不到想要的外观结果。虽然看着png图片里有些地方好像是透明的。
解决方法就是自己来做png图片,按你自己的规则来。不要从网上找。
设置了不规则窗口,就可以把那张png图片绘制到窗口里去了,但由于半透明的问题,得先用透明画刷填充窗口,然后再绘制。
不过还有一个问题,非客户区窗口绘制,像我们之前的绘制,都是在窗口客户区里绘制的。
如果要绘制的图片和窗口对应起来的话,得从非客户区域开始绘制。这个要怎么做到呢。下一章再说吧。
更多c# gdi+编程(四)。
其它类似信息

推荐信息