C#自定义画刷原理解析

windows系统中的画板工具,有好几种画刷,C#中并没有直接对应可使用的类,只能自己研究。

1.画刷原理

根据本人对PS的相关功能细心分析,发现各种画刷其实就是一幅图片的移位重叠显示。通常这幅画刷图是半透明的,只有其中一些区域有颜色。

上图中的画刷,把间隔设大之后可以明显看到原图的模样。

这是基于位移的画刷,另外有基于时间的,比如喷枪工具。

2.代码实现

1).  直线算法

为什么要直线算法?因为我们移动鼠标,触发MouseMove事件,记录鼠标前一坐标点与当前点,如果两点是是相邻的,当然不需要再做多余的算法,当如果两点是不相邻的,我们就需要计算两点之间所有的点。否则无法有效地进行固定间隔绘制画刷图。

/// <summary>
/// 顺序获取两点间直线上的所有点
/// </summary>
/// <param name="pStart">开始点</param>
/// <param name="pEnd">结束点</param>
/// <returns>两点间直线上的所有点</returns>
private List<Point> getPoint2Point(Point pStart, Point pEnd)
        {
            List<Point> linePoint = new List<Point>();
            if (pStart.X == pEnd.X && pStart.Y == pEnd.Y)
            {
                linePoint.Add(pStart);
                return linePoint;
            }
            DDALine(pStart.X, pStart.Y, pEnd.X, pEnd.Y, ref  linePoint);
            return linePoint;
        }
        //DDA直线画法
        private void DDALine(int x0, int y0, int x1, int y1, ref List<Point> ptl) 
        {  
            int dx,dy,eps1,k;  
            float x,y,xIncre,yIncre;  
            dx=x1-x0;  
            dy=y1-y0;  
            x=x0;  
            y=y0;  
            if(Math.Abs(dx)>Math.Abs(dy))  
            eps1=Math.Abs(dx);  
            else  
            eps1=Math.Abs(dy);  
            xIncre=(float)dx/(float)eps1;  
            yIncre=(float)dy/(float)eps1;  
            for(k=0;k<=eps1;k++)  
            {
                ptl.Add( new Point((int)(x + 0.5), (int)(y + 0.5)) );  
                x+=xIncre;  
                y+=yIncre;  
            }  
        } 

2).鼠标事件

分别为鼠标按下、移动、放开事件

bool bIsDraw = false; //主图画线
Point startPoint_Draw = new Point();//划线点变量
List<Point> pts = new List<Point>();//画点保存
private void pictureBox_main_MouseMove(object sender, MouseEventArgs e)
 {
            PictureBox pb = sender as PictureBox;
            ssl_point.Text = e.Location.ToString();
            pb.Refresh();
            if (bIsDraw)
            {
                Point p = limitPoint(e.Location, pictureBox_main.ClientSize);
                if (p == startPoint_Draw) return;
                Graphics gs = Graphics.FromImage(pb.Image);
                if (pictureBox_main.Image != null  )
                {
                     List<Point> pl =  getPoint2Point(startPoint_Draw,  p);
                     pl.RemoveAt(0);
                     pts.AddRange(pl);
                     if (pts.Count >= peninv)
                     {
                         for (int i = penmod; i < pts.Count; i += peninv)
                         {
                             gs.DrawImage(blushbmp_curr, pts[i].X - pensize , pts[i].Y - pensize  , pensize*2, pensize*2);
                         }
                         penmod = pts.Count % peninv;
                         pts.RemoveRange(0, pts.Count - penmod);
                     } 
                }
                gs.Dispose();
                startPoint_Draw = p;
            }
        }
        private void pictureBox_main_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == System.Windows.Forms.MouseButtons.Left)
            if (bIsDraw == false)
            {
                startPoint_Draw = e.Location;
                pts.Clear();
                pts.Add(startPoint_Draw);
                bIsDraw = true;
            }
        }
        private void pictureBox_main_MouseUp(object sender, MouseEventArgs e)
        {
            if (bIsDraw == true)
            {
                bIsDraw = false;
                if (pictureBox_main.Image != null   )
                {
                     pts.Clear();
                }
                pictureBox_main.Refresh();   
            }
        }

如果根据位移方向加上图片的角度旋转效果,应该会更加接近PS的效果。

3.效果

我使用的画刷图就是来源于本文上图的PS画刷。

图中5条画刷线分别使用间隔1,10,20,40,80。使用不同的原图,就能得到各种各样的画刷。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#纹理画刷TextureBrush用法实例

    本文实例讲述了C#纹理画刷TextureBrush用法.分享给大家供大家参考.具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Text; using System.Windows.Forms; namespac

  • C#线性渐变画刷LinearGradientBrush用法实例

    本文实例讲述了C#线性渐变画刷LinearGradientBrush用法.分享给大家供大家参考.具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D;

  • C#模式画刷HatchBrush用法实例

    本文实例讲述了C#模式画刷HatchBrush用法.分享给大家供大家参考.具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace

  • C#从画刷创建画笔的方法

    本文实例讲述了C#从画刷创建画笔的方法.分享给大家供大家参考.具体实现方法如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace Wi

  • C#自定义画刷原理解析

    windows系统中的画板工具,有好几种画刷,C#中并没有直接对应可使用的类,只能自己研究. 1.画刷原理 根据本人对PS的相关功能细心分析,发现各种画刷其实就是一幅图片的移位重叠显示.通常这幅画刷图是半透明的,只有其中一些区域有颜色. 上图中的画刷,把间隔设大之后可以明显看到原图的模样. 这是基于位移的画刷,另外有基于时间的,比如喷枪工具. 2.代码实现 1).  直线算法 为什么要直线算法?因为我们移动鼠标,触发MouseMove事件,记录鼠标前一坐标点与当前点,如果两点是是相邻的,当然不需

  • Java8 自定义CompletableFuture的原理解析

    目录 Java8 自定义CompletableFuture原理 CompleteFuture简单使用 下面简单介绍用法 Java8 自定义CompletableFuture原理 Future 接口 的局限性有很多,其中一个就是需要主动的去询问是否完成,如果等子线程的任务完成以后,通知我,那岂不是更好? public class FutureInAction3 { public static void main(String[] args) { Future<String> future = i

  • Python CategoricalDtype自定义排序实现原理解析

    CategoricalDtype自定义排序 当我们的透视表生成完毕后,有很多情况下需要我们对某列或某行值进行排序.排序有很多种方法.例如sort_index及sort_values函数也可以对数据进行排序,这里就不多说了. 对于数值和字母的排序很容易,但是对于中文的排序就有点麻烦了.默认情况下是按照utf-8的编码来进行排序的但是即使如此也很难满足我们对汉字排序的要求.所以通过CategoricalDtye可以把数据类型转成Category类型 然后通过指定参数列表的顺序来自定义那个元素先那个元

  • python 上下文管理器及自定义原理解析

    这篇文章主要介绍了python 上下文管理器原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上. Python 提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式. 上下文管理器是Python2.5之后才出现的概念.上下文管理器规定了某个对象的使用范围,当进入或者离开了使

  • 这一次搞懂Spring自定义标签以及注解解析原理说明

    前言 在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如何解析的.同时我们常用的注解如:@Service.@Component.@Controller标注的类也是需要在xml中配置<context:component-scan>才能自动注入到IOC容器中,所以本篇也会重点分析注解解析原理. 正文 自定义标签解析原理 在上一篇分析默认标签解析时看到过这个类DefaultBeanDefinit

  • Spring注解@RestControllerAdvice原理解析

    这篇文章主要介绍了Spring注解@RestControllerAdvice原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 前段时间部门搭建新系统,需要出异常后统一接口的返回格式,于是用到了Spring的注解@RestControllerAdvice.现在把此注解的用法总结一下. 用法 首先定义返回对象ResponseDto package com.staff.points.common; import lombok.Data;

  • Java JDBC导致的反序列化攻击原理解析

    这篇文章主要介绍了Java JDBC导致的反序列化攻击原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景 上周BlackHat Europe 2019的议题<New Exploit Technique In Java Deserialization Attack>中提到了一个通过注入JDBC URL实现反序列化攻击的场景,简单分析一下. 分析 首先,当java应用使用MySQL Connector/J(官方的JDBC驱动,本文基于其

  • python通过opencv实现图片裁剪原理解析

    这篇文章主要介绍了python通过opencv实现图片裁剪原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 图像裁剪的基本概念 : 图像裁剪是指将图像中我们想要的研究区以外的区域去除,经常是按照行政区划或研究区域的边界对图像进行裁剪.例如,一张500×400的图像,我们只想要中间的250×200的区域,就可以使用图像裁剪将四周的区域去除. 在实际开发工作中,我们经常需要对图像进行分幅裁剪,按照ERDAS实际图像分幅裁剪的过程,可以将图像分

  • 微信小程序button标签open-type属性原理解析

    这篇文章主要介绍了微信小程序button标签open-type属性原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 open-type (微信开放能力):合法值中的其中之一: getUserInfo说明:引导用户授权 而获取用户信息,可以从bindgetuserinfo回调中获取到用户信息 而按钮的bindgetuserinfo属性 说明:用户点击该按钮时,会返回获取到的用户信息,回调的detail数据与wx.getUserInfo返回的

  • JavaScript对象原型链原理解析

    这篇文章主要介绍了JavaScript对象原型链原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一个js对象,除了自己设置的属性外,还会自动生成proto.class.extensible属性,其中,proto属性指向对象的原型. 对象的属性也有writable.enumerable.configurable.value和get/set的配置方法. 对象的创建方式有三种: 一.使用字面量直接创建. 二.基于原型链创建. 分析上图,要点如

随机推荐