首先貼出本文參考學習的文章吧。
https://www.cnblogs.com/LCHL/p/9055642.html#4206298
感謝這位懶羊羊博主的代碼和講解,我在此基礎上稍微加了一些東西,希望能使書寫效果得到更好的提升吧。建議先從羊博主的博文看起。
前文
- 本文致力於解決羊博主的2-3問題,即代碼粗細度的優化。
- 本文本着分享知識的目的寫出,希望能對一些尋找類似知識的人一些幫助,能得到各位的批評指正也是榮幸萬分。
- 因工作公司的原因,無法貼出全部代碼,我盡量在下文中對自己的思路進行詳細的講解。(要吃飯的呀)
關鍵詞
Freeze, DrawingContext
思路
1. 卡頓問題
羊博主提出使用WPF中的Freeze()方法將畫刷“凍結”。
Freezable 類提供特殊功能,以便在使用修改或復制開銷很大的對象時幫助提高應用程序性能。
筆者使用該方法后,書寫性能得到了很大提升,但是書寫點數目達到萬為單位時,出現書寫不流暢的情況,且越書寫越卡頓。筆者冥思苦想三天三夜,嘗試了很多方法都沒有得到解決。果然皇天不負有心人,終於還是讓我找到了一些改進方法。代碼如下:
ImageDrawing image = new ImageDrawing()
{
ImageSource = imageSource,
Rect = new Rect(x - t1 / 2.0, y - t1 / 2.0, t1, t1)
//t1 為當前的粗細度;x為當前的X坐標,y為當前Y坐標
};
image.Freeze();
drawingContext.DrawDrawing(image);
將DrawImage更改為DrawDrawing,書寫性能確實得到了雖然微弱但可見的提升。(自己給自己鼓掌)但是具體有多少提升,筆者並沒有做量化。(太懶了) 效果基本滿意,如果您有更好的解決方法,希望能得到您的指點。
后文,筆者在羊博主的指點下讓書寫效率又得到了數以十倍的提升,非常感謝羊兄的指導。然筆者愚鈍,力有不逮,不能向讀者說出其精髓之一二,實在抱歉。該優化方法在羊博主文章中也部分寫出,對於這方面有要求的讀者,可以學習羊博主的博客。
2. 顏色問題
羊博主博客已完美解決該問題,棒棒噠。✿✿ヽ(°▽°)ノ✿)
3. 粗細問題
- 粗細度問題可以分解為兩個問題,一個是書寫時間,一個是書寫距離。簡而言之就是書寫速度越快,筆跡越細;書寫速度越慢,筆跡越粗。(速度v = 距離s / 時間t,這個大家應該都知道)
3.1 書寫距離
書寫距離應該怎么獲得?
--- 無非就是兩個點之間的距離。
- 在InkCanvas下重寫OnDraw方法(詳見羊博主博文)
- 在OnDraw方法中帶了參數StylusPointCollection,該參數為書寫點的搜集。該參數搜集動態繪制時產生的點,一般為兩個點,即繪制一條線段時的前后兩個點,這兩個點相減就得到了兩點間的距離。
3.2 書寫時間
這個參數在Ondraw中沒有,如果想關聯該參數的話可以研究一下RawStylusInput.Timestamp,(項目組的大神把這些都搭建好了,我用就完事了)該參數可以獲取發生輸入的時間,兩點時間相減就獲得了間距的書寫時間。兩點就是兩條線段的終點,因為在繪制時是連續的線,所以后面的線的起點和前面線的終點為相同的點,這個應該很好理解。
3.3 書寫速度
通過距離除以時間得出書寫速度,自己規定一個速度閾值,在大於這個閾值時,將粗細值縮小;小於這個閾值時,將粗細度放大。該閾值就看你自己想要書寫的效果定。建議將進行加減時的值設置為定值,這樣線條變化更加平滑。
以下代碼不包含時間參數的影響,即只考慮書寫間距的影響。所以大家都能用。
部分代碼如下:
Point p1 = (Point)stylusPoints[1]; //線段的終點
Vector dis= p1 - p0; //兩點間距
if (dis.Length != 0)
{
double y= (p1.Y - p0.Y) / dis.Length; //Y軸上的單位變化量
double x= (p1.X - p0.X) / dis.Length;
double aX = p0.X;
double aY = p0.Y;
for (double j = 0; j <= dis.Length; j += 10) //分割線段,化線為點,對每個點進行處理,達到粗細平滑變化的效果
{
if (Convert.ToInt32(dis.Length) > LastDis) //前個線段的長度大於當前線段的情況,讓線條變細
{
t1 = (t1 - _sub) <= _minT ? _minT : t1 - _sub;
}
else if (t1 < _thick) //前個線段的長度大於當前線段,且小於規定的最大寬度
{
t1 = (t1 + _add) >= _thick ? _thick : t1 + _add;
}
aX+= x;
aY+= y;
ImageDrawing i = new ImageDrawing()
{
ImageSource = imageSource,
Rect = new Rect(aX - t1/ 2.0, aY - t1/ 2.0, t1, t1)
};
i.Freeze();
drawingContext.DrawDrawing(i); //繪制
}
p0 = new Point(aX, aY); //保存最后一個優化點,即終點
LastDis = Convert.ToInt32(dis.Length);
_thick= t1;
}
靜態呈現方法與之相同,只要理解了上述的方法,應該就沒什么大問題了。筆者就不在此贅述。 效果圖:
可以在最小的粗細度的時候判斷是否還是超過現在的線段長度,是的話可以讓aX 和aY 這兩個值直接等於最后的點,從而實現書寫過快時的流線間斷感。但是線段會不平滑。(圖畫的比較丑,沒有表現出間斷的優美感。。。)
效果圖:
if (_thickness == _minT)
{
aX += x * (distance.Length - j - 1);
aY += y * (distance.Length - j - 1);
break;
}
打完收工。
有疑問請留言。