WPF實現(xiàn)圖片按像素拉伸
WPF中的圖片組件,本身是支持不同的拉伸效果。具體如下:
- None, 不做拉伸
- Fill 完全填充(會變形)
- Uniform 等比縮放,不會變形
- UniformToFill 等比縮放,并完全填充。不會變形,但是長的部分會被裁剪
但是,如果我們要實現(xiàn)像QQ或者微信這樣子的聊天氣泡功能,直接使用圖片組件就無法滿足要求了。
我們可以觀察下微信的聊天氣泡,他的寬度和高度可以根據(jù)我們輸入的內容自動調整,并且背景圖片也不會存在變形的問題。
今天我們就用WPF來實現(xiàn)這個功能!
要實現(xiàn)不變形的拉伸功能,我們可以針對1個像素來進行拉伸,這樣拉伸出來的圖片,除了拉伸區(qū)域的像素都是一樣的,其它區(qū)域還是保留了原來的圖片的外觀。
這里主要需要用到 CroppedBitmap類,該類主要用于裁剪,可以對 BitmapImage進行裁剪。
微信聊天氣泡這種場景,它需要支持水平和垂直的方向的拉伸效果,我們可以利用 CroppedBitmap,將原始圖片裁剪成9張圖,渲染的時候,我們分別將9張圖渲染到對應的位置。拉伸的區(qū)域就是9張圖中的上面中間位置,下面中間位置,左邊中間位置,右邊中間位置以及最中間的位置。這幾張圖片,都按1個像素進行裁剪,這樣就不會出現(xiàn)拉伸的圖片了。
關鍵代碼:
//根據(jù)裁剪區(qū)域,獲取裁剪后的圖片。ImageSource指的是原始圖片 private ImageSource GetCroppedBitmap(double x, double y, double width, double height) { return new CroppedBitmap(ImageSource, new Int32Rect((int)x, (int)y, (int)width, (int)height)); } /// <summary> /// 獲取水平偏移像素值 /// </summary> /// <returns></returns> private int GetHorizontalOffset() { return (int)(HorizontalPrecent * ImageSource.Width / 100); } /// <summary> /// 獲取垂直位置的偏移像素值 /// </summary> /// <returns></returns> private int GetVerticalOffset() { return (int)(VerticalPrecent * ImageSource.Height / 100); } /// <summary> /// 獲取水平偏移像素值 /// </summary> /// <returns></returns> private int GetStretchHeight() { return (int)(RenderSize.Height - ImageSource.Height); } /// <summary> /// 獲取垂直位置的偏移像素值 /// </summary> /// <returns></returns> private int GetStretchWidth() { return (int)(RenderSize.Width - ImageSource.Width); } /// <summary> /// 水平拉伸是否可用 /// </summary> private bool IsHorizontalStretchEnabled { get { if (HorizontalPrecent > 0 && HorizontalPrecent < 100) { return true; } return false; } } /// <summary> /// 按水平方向進行裁剪的偏移量 /// </summary> public double HorizontalPrecent { get; set; } /// <summary> /// 按垂直方向進行裁剪的偏移量 /// </summary> public double VerticalPrecent { get; set; } //繪制水平+垂直拉伸的方法 protected override void OnRender(DrawingContext drawingContext) { //這個需要9張圖 //左上,左中,左下,右上,右中,右下,水平中,垂直中 var horizontalOffset = GetHorizontalOffset(); var verticalOffset = GetVerticalOffset(); var leftTop = GetCroppedBitmap(0, 0, horizontalOffset, verticalOffset); var leftBottom = GetCroppedBitmap(0, verticalOffset + 1, horizontalOffset, ImageSource.Height - verticalOffset - 1); var rightTop = GetCroppedBitmap(horizontalOffset + 1, 0, ImageSource.Width - horizontalOffset - 1, ImageSource.Height - verticalOffset - 1); var rightBottom = GetCroppedBitmap(horizontalOffset + 1, verticalOffset + 1, ImageSource.Width - horizontalOffset - 1, ImageSource.Height - verticalOffset - 1); //最中間的 var center = GetCroppedBitmap(horizontalOffset, verticalOffset, 1, 1); var leftCenter = GetCroppedBitmap(0, verticalOffset + 1, horizontalOffset, 1); var rightCenter = GetCroppedBitmap(horizontalOffset + 1, verticalOffset + 1, ImageSource.Width - horizontalOffset - 1, 1); var topCenter = GetCroppedBitmap(horizontalOffset + 1, 0, 1, verticalOffset); var bottomCenter = GetCroppedBitmap(horizontalOffset + 1, verticalOffset + 1, 1, ImageSource.Height - verticalOffset - 1); //------------------------------- 上面的邏輯是切圖,下面的邏輯是繪制 ----------------------------------- var stretchHeight = GetStretchHeight(); if (stretchHeight < 0) stretchHeight = 0; var stretchWidth = GetStretchWidth(); if (stretchWidth < 0) stretchWidth = 0; drawingContext.DrawImage(leftTop, new Rect(0, 0, horizontalOffset, verticalOffset)); drawingContext.DrawImage(rightTop, new Rect(horizontalOffset + stretchWidth, 0, ImageSource.Width - horizontalOffset - 1, ImageSource.Height - verticalOffset)); //繪制水平方向的拉伸像素 if (stretchHeight > 0) { drawingContext.DrawImage(leftCenter, new Rect(0, verticalOffset, horizontalOffset, stretchHeight)); drawingContext.DrawImage(rightCenter, new Rect(horizontalOffset + stretchWidth, verticalOffset, ImageSource.Width - horizontalOffset - 1, stretchHeight)); } //繪制垂直方向的拉伸像素 if (stretchWidth > 0) { drawingContext.DrawImage(topCenter, new Rect(horizontalOffset, 0, stretchWidth, verticalOffset)); drawingContext.DrawImage(bottomCenter, new Rect(horizontalOffset, verticalOffset + stretchHeight, stretchWidth, ImageSource.Height - verticalOffset - 1)); } //繪制中間拉伸的像素 if (stretchHeight > 0 && stretchWidth > 0) { drawingContext.DrawImage(center, new Rect(horizontalOffset, verticalOffset, stretchWidth, stretchHeight)); } drawingContext.DrawImage(leftBottom, new Rect(0, verticalOffset + stretchHeight, horizontalOffset, ImageSource.Height - verticalOffset - 1)); drawingContext.DrawImage(rightBottom, new Rect(horizontalOffset + stretchWidth, verticalOffset + stretchHeight, ImageSource.Width - horizontalOffset - 1, ImageSource.Height - verticalOffset - 1)); } //僅支持水平方向拉伸 protected override void OnRender(DrawingContext drawingContext) { var horizontalOffset = GetHorizontalOffset(); var left = GetCroppedBitmap(0, 0, horizontalOffset, ImageSource.Height); var center = GetCroppedBitmap(horizontalOffset, 0, 1, ImageSource.Height); var right = GetCroppedBitmap(horizontalOffset + 1, 0, ImageSource.Width - horizontalOffset - 1, ImageSource.Height); drawingContext.DrawImage(left, new Rect(0, 0, horizontalOffset, ImageSource.Height)); var stretchWidth = GetStretchWidth(); if (stretchWidth > 0) { drawingContext.DrawImage(center, new Rect(horizontalOffset, 0, stretchWidth, ImageSource.Height)); } else { stretchWidth = 0; } drawingContext.DrawImage(right, new Rect(horizontalOffset + stretchWidth, 0, ImageSource.Width - horizontalOffset - 1, ImageSource.Height)); } //僅支持垂直方向拉伸 protected override void OnRender(DrawingContext drawingContext) { var verticalOffset = GetVerticalOffset(); var top = GetCroppedBitmap(0, 0, ImageSource.Width, verticalOffset); var center = GetCroppedBitmap(0, verticalOffset, ImageSource.Width, 1); var bottom = GetCroppedBitmap(0, verticalOffset + 1, ImageSource.Width, ImageSource.Height - verticalOffset - 1); drawingContext.DrawImage(top, new Rect(0, 0, ImageSource.Width, verticalOffset)); var stretchHeight = GetStretchHeight(); if (stretchHeight > 0) { drawingContext.DrawImage(center, new Rect(0, verticalOffset, ImageSource.Width, stretchHeight)); } else { stretchHeight = 0; } drawingContext.DrawImage(bottom, new Rect(0, verticalOffset + stretchHeight, ImageSource.Width, ImageSource.Height - verticalOffset - 1)); } //測量布局大小,這里要記得重寫下。這個版本不支持不同尺寸的分辨率,可以通過計算縮放比來實現(xiàn) private Size MeasureCore(Size size, ImageSource imgSource) { if (imgSource == null) return size; Size naturalSize; if (IsHorizontalStretchEnabled && IsVerticalStretchEnabled) { naturalSize = new Size(size.Width, size.Height); } else if (IsHorizontalStretchEnabled) { naturalSize = new Size(size.Width, imgSource.Height); } else if (IsVerticalStretchEnabled) { naturalSize = new Size(imgSource.Width, size.Height); } else { return size; } return naturalSize; }
以上代碼就可以實現(xiàn)水平拉伸,垂直拉伸或者水平+垂直拉伸的功能了。目前的測試代碼還不支持不同分辨率的圖片,demo中的計算是使用了ImageSource的寬高。如果需要支持任意分辨率,可以按渲染的寬高和圖片的實際寬高做個比例縮放運算即可。
到此這篇關于WPF實現(xiàn)圖片按像素拉伸的文章就介紹到這了,更多相關WPF圖片按像素拉伸內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C#使用RestSharp實現(xiàn)封裝常用的http請求方法
這篇文章主要為大家詳細介紹了C#如何使用RestSharp實現(xiàn)封裝常用的http請求方法,文中的示例代碼講解詳細,感興趣的小伙伴可以了解一下2024-02-02C#/VB.NET實現(xiàn)PPT或PPTX轉換為圖像功能
由于大多數(shù)便攜式設備支持瀏覽圖片而不支持瀏覽PowerPoint 文件,所以相比較而言,圖像對于用戶而言更加友好。本文將利用C#/VB.NET實現(xiàn)PPT或PPTX轉換為圖像功能,需要的可以參考一下2022-08-08C# winfrom 模擬ftp文件管理實現(xiàn)代碼
從網(wǎng)上找到的非常好用的模擬ftp管理代碼,整理了一下,希望對需要的人有幫助2014-01-01