抛开GDI+完美实现角度渐变,散分。
之前利用GDI+实现了线性渐变、对称渐变、圆形渐变、菱形渐变的基本效果,对于角度渐变一直没有思路。最近偶尔灵感一来,何必一定要求助GDI+呢,结果仔细分析下,其实这个的数学过程也不是很复杂,完全可以自己去实现啊。
兴起之余,干脆都不用GDI+,角度渐变都能实现,线性、对称和圆形从数学上讲还要简单些。只有这个菱形渐变涉及到的图形学知识稍微多谢,暂时还没有实现算法的自我编码。
其实一旦自己写算法,就能明白一些软件为什么有某些选项,比如渐变里PS就有反向、防色等,这个防色从代码角度来说就是误差扩散,和图像由高位变为低位时那个算法原理一致,这就叫一通百通啊。
[img=http://www.cnblogs.com/images/cnblogs_com/laviewpbt/193120/t_%e4%b8%ba%e9%a2%9d%e5%a4%96%e9%][/img]
[解决办法]
欢迎共享
[解决办法]
[解决办法]
[解决办法]
看看晚上有没有时间,有时间给大家整理一个原汁原味的版本,就是完全是按照原始算法写的版本,不做优化,然后有兴趣的可以自己优化,看你们的优化能力如何。
[解决办法]
谢谢分享........
[解决办法]
没有优化能力的再次路过
[解决办法]
很强大
[解决办法]
这就叫专业!
[解决办法]
感谢分享
[解决办法]
该回复于2010-12-16 12:58:58被版主删除
[解决办法]
仰慕中。。。
[解决办法]
观赏,NB
[解决办法]
有博客园帐号的可以到这里下载
http://files.cnblogs.com/laviewpbt/AngleGradient.rar
没有的我直接贴代码,就是新建一个窗体,直接贴代码就可以运行的。
Option Explicit
Private Type RGBQUAD '只有bibitcount为1,2,4时才有调色板
Blue As Byte '蓝色分量
Green As Byte '绿色分量
Red As Byte '红色分量
Reserved As Byte '保留值
End Type
Private Type BITMAPINFOHEADER '40 bytes
biSize As Long 'BITMAPINFOHEADER结构的大小
biWidth As Long
biHeight As Long
biPlanes As Integer '设备的为平面数,现在都是1
biBitCount As Integer '图像的颜色位图
biCompression As Long '压缩方式
biSizeImage As Long '实际的位图数据所占字节
biXPelsPerMeter As Long '目标设备的水平分辨率
biYPelsPerMeter As Long '目标设备的垂直分辨率
biClrUsed As Long '使用的颜色数
biClrImportant As Long '重要的颜色数。如果该项为0,表示所有颜色都是重要的
End Type
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal Hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFOHEADER, ByVal wUsage As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Const DIB_RGB_COLORS = 0&
Private Const BI_RGB = 0&
Private LastX As Long
Private LastY As Long
Private StartX As Long
Private StartY As Long
Private MouseDown As Boolean
Private BmpInfo As BITMAPINFOHEADER
Private m_Width As Long
Private m_Height As Long
Private PixelData() As Byte
Private Stride As Long
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = vbLeftButton Then
LastX = X
LastY = Y
StartX = X
StartY = Y
MouseDown = True
End If
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If MouseDown = True Then
Line (StartX, StartY)-(LastX, LastY)
Line (StartX, StartY)-(X, Y)
LastX = X
LastY = Y
End If
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If MouseDown = True Then
Dim ColorArray(3) As RGBQUAD
Dim PositonArrray(3) As Single
Dim t As Long
ColorArray(0).Red = 0:
ColorArray(0).Green = 0:
ColorArray(0).Blue = 255:
ColorArray(1).Red = 255:
ColorArray(1).Green = 255:
ColorArray(1).Blue = 255:
ColorArray(2).Red = 0:
ColorArray(2).Green = 255:
ColorArray(2).Blue = 255:
ColorArray(3).Red = 255:
ColorArray(3).Green = 0:
ColorArray(3).Blue = 0
PositonArrray(0) = 0 '第一个最好为0
PositonArrray(1) = 0.2
PositonArrray(2) = 0.7
PositonArrray(3) = 1 '最后一个最好为1,并且必须升序排列,且不能相等
t = GetTickCount
AngleGradient CLng(StartX), CLng(StartY), CLng(X), CLng(Y), ColorArray, PositonArrray()
Me.Caption = GetTickCount - t
MouseDown = False
End If
End Sub
Private Sub Form_Load()
Dim X As Long
m_Width = Me.ScaleWidth
m_Height = Me.ScaleHeight
Stride = m_Width * 4
LastX = -1: LastY = -1
ReDim PixelData(m_Width * m_Height * 4 - 1) As Byte
With BmpInfo
.biSize = Len(BmpInfo)
.biWidth = m_Width
.biHeight = -m_Height
.biPlanes = 1
.biBitCount = 32
.biCompression = BI_RGB
End With
Me.ScaleMode = 3
Me.DrawMode = 6 '反色笔
End Sub
Private Function AngleGradient(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, _
ColorArray() As RGBQUAD, PositionArray() As Single) As Boolean
Dim Dx1 As Long, Dx2 As Long
Dim Dy1 As Long, Dy2 As Long
Dim Speed As Long
Dim StartAngle As Double, EndAngle As Double
Dim Angle As Double
Dim DiffPosition As Double
Dim X As Long, Y As Long
Dim Z As Long
Dim Count As Long
Const Pi As Double = 3.1415926
Const HalfPi As Double = Pi / 2
Const TripplePi As Double = 1.5 * Pi
Count = UBound(ColorArray) - LBound(ColorArray)
Dx2 = X2 - X1: Dy2 = Y1 - Y2 '得到起始角度(以X1,Y1点位原点)
If Dx2 > 0 Then '
StartAngle = Atn(Dy2 / Dx2) '位于第一第四象限(Atn函数范围的值为-PI/2到PI/2)
ElseIf Dx2 < 0 Then
StartAngle = Atn(Dy2 / Dx2) + Pi '位于第二第三象限
Else
If Dy2 > 0 Then '特殊处理
StartAngle = HalfPi
Else
StartAngle = TripplePi
End If
End If
For Y = 0 To m_Height - 1
Speed = Y * Stride '
For X = 0 To m_Width - 1
Dy1 = Y1 - Y
Dx1 = X - X1
If Dx1 < 0 Then '这里的计算公式是Index=(当前角度-StartAngle)/2/pi*4096,稍微做了优化
EndAngle = Atn(Dy1 / Dx1) + Pi
ElseIf Dx1 > 0 Then
EndAngle = Atn(Dy1 / Dx1)
Else
If Dy1 > 0 Then
EndAngle = HalfPi
Else
EndAngle = TripplePi
End If
End If
Angle = EndAngle - StartAngle '计算和其实线条的角度差
If Angle < 0 Then Angle = Angle + 2 * Pi '修正下
Angle = Angle / 2 / Pi '归一化
If Angle >= PositionArray(Count) Then
PixelData(Speed + 2) = ColorArray(Count).Red
PixelData(Speed + 1) = ColorArray(Count).Green
PixelData(Speed) = ColorArray(Count).Blue
Else
For Z = 0 To Count - 1
If Angle >= PositionArray(Z) And Angle < PositionArray(Z + 1) Then '根据角度差来插值
DiffPosition = (Angle - PositionArray(Z)) / (PositionArray(Z + 1) - PositionArray(Z))
PixelData(Speed + 2) = (DiffPosition * (ColorArray(Z + 1).Red * 1& - ColorArray(Z).Red) + ColorArray(Z).Red)
PixelData(Speed + 1) = (DiffPosition * (ColorArray(Z + 1).Green * 1& - ColorArray(Z).Green) + ColorArray(Z).Green)
PixelData(Speed) = (DiffPosition * (ColorArray(Z + 1).Blue * 1& - ColorArray(Z).Blue) + ColorArray(Z).Blue)
Exit For
End If
Next
End If
Speed = Speed + 4
Next
Next
SetDIBitsToDevice Me.Hdc, 0, 0, m_Width, m_Height, 0, 0, 0, m_Height, PixelData(0), BmpInfo, DIB_RGB_COLORS
End Function
兴起之余,干脆都不用GDI+,角度渐变都能实现,线性、对称和圆形从数学上讲还要简单些。只有这个菱形渐变涉及到的图形学知识稍微多谢,暂时还没有实现算法的自我编码。
[解决办法]
该回复于2010-12-17 09:05:11被版主删除
[解决办法]
该回复于2010-12-17 09:05:11被版主删除
[解决办法]
感谢分享,不错,不错,真不错
[解决办法]
该回复于2010-12-17 09:05:10被版主删除
[解决办法]
用途是什么?
[解决办法]
感谢分享!
[解决办法]
呵呵,楼主挺牛的
[解决办法]
围观专家
[解决办法]
复用性问题,自己理解跟好。
[解决办法]
感谢分享
[解决办法]
该回复于2010-12-17 09:08:35被版主删除
[解决办法]
该回复于2010-12-17 09:10:41被版主删除
[解决办法]
该回复于2010-12-17 09:08:37被版主删除
[解决办法]
该回复于2010-12-17 09:08:36被版主删除
[解决办法]
昨天顶过了,居然又找不到了,再顶!
[解决办法]
牛人啊
[解决办法]
角度渐变是以当前点和两个取样点之间的夹角(0-360度之间)为依据进行插值的,而径向渐变则是以当前点于起点的距离和两个取样点距离之间的比值为依据进行插值的。对称渐变则是以当前点到垂直于两取样点,且经过起点的直线的距离和两取样点距离的比值为依据,且这个距离取的是正值。而线性渐变其实要比堆成渐变复杂些,还要判断距离的正负,也就是说要判断当前点和终点是否在直线的同一侧。
不过呢,这些都一些基本的集合知识,比如点到直线的距离,点在直线的那一侧啊等等,都不是很困难。
[解决办法]
该回复于2010-12-17 10:08:26被版主删除
[解决办法]
很好,谢谢楼主
[解决办法]
收藏一个
[解决办法]
这渐变,有啥用啊?谁需要这样的渐变啊?
[解决办法]
都是精品啊
[解决办法]
顶
[解决办法]
该回复于2010-12-17 13:20:30被版主删除
[解决办法]
帮顶顶!
我在IDE里花了22秒.....
[解决办法]
很好很好
[解决办法]
都是牛人啊。。。
[解决办法]
顶啊~记得学OPENGL的时候,就学了下颜色渐变就是对颜色进行插值
[解决办法]