WPF實現(xiàn)圖片按像素拉伸
WPF中的圖片組件,本身是支持不同的拉伸效果。具體如下:
- None, 不做拉伸
- Fill 完全填充(會變形)
- Uniform 等比縮放,不會變形
- UniformToFill 等比縮放,并完全填充。不會變形,但是長的部分會被裁剪
但是,如果我們要實現(xiàn)像QQ或者微信這樣子的聊天氣泡功能,直接使用圖片組件就無法滿足要求了。
我們可以觀察下微信的聊天氣泡,他的寬度和高度可以根據(jù)我們輸入的內(nèi)容自動調(diào)整,并且背景圖片也不會存在變形的問題。
今天我們就用WPF來實現(xiàn)這個功能!
要實現(xiàn)不變形的拉伸功能,我們可以針對1個像素來進(jìn)行拉伸,這樣拉伸出來的圖片,除了拉伸區(qū)域的像素都是一樣的,其它區(qū)域還是保留了原來的圖片的外觀。
這里主要需要用到 CroppedBitmap類,該類主要用于裁剪,可以對 BitmapImage進(jìn)行裁剪。
微信聊天氣泡這種場景,它需要支持水平和垂直的方向的拉伸效果,我們可以利用 CroppedBitmap,將原始圖片裁剪成9張圖,渲染的時候,我們分別將9張圖渲染到對應(yīng)的位置。拉伸的區(qū)域就是9張圖中的上面中間位置,下面中間位置,左邊中間位置,右邊中間位置以及最中間的位置。這幾張圖片,都按1個像素進(jìn)行裁剪,這樣就不會出現(xiàn)拉伸的圖片了。
關(guā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>
/// 按水平方向進(jìn)行裁剪的偏移量
/// </summary>
public double HorizontalPrecent { get; set; }
/// <summary>
/// 按垂直方向進(jìn)行裁剪的偏移量
/// </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的寬高。如果需要支持任意分辨率,可以按渲染的寬高和圖片的實際寬高做個比例縮放運(yùn)算即可。
到此這篇關(guān)于WPF實現(xiàn)圖片按像素拉伸的文章就介紹到這了,更多相關(guān)WPF圖片按像素拉伸內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#使用Mutex簡單實現(xiàn)程序單實例運(yùn)行的方法
這篇文章主要介紹了C#使用Mutex簡單實現(xiàn)程序單實例運(yùn)行的方法,涉及C#實現(xiàn)單實例程序運(yùn)行的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-09-09
C#使用RestSharp實現(xiàn)封裝常用的http請求方法
這篇文章主要為大家詳細(xì)介紹了C#如何使用RestSharp實現(xiàn)封裝常用的http請求方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2024-02-02
C#/VB.NET實現(xiàn)PPT或PPTX轉(zhuǎn)換為圖像功能
由于大多數(shù)便攜式設(shè)備支持瀏覽圖片而不支持瀏覽PowerPoint 文件,所以相比較而言,圖像對于用戶而言更加友好。本文將利用C#/VB.NET實現(xiàn)PPT或PPTX轉(zhuǎn)換為圖像功能,需要的可以參考一下2022-08-08
C# winfrom 模擬ftp文件管理實現(xiàn)代碼
從網(wǎng)上找到的非常好用的模擬ftp管理代碼,整理了一下,希望對需要的人有幫助2014-01-01
使用mutex實現(xiàn)應(yīng)用程序單實例運(yùn)行代碼分享
本文主要介紹了使用Mutex實現(xiàn)應(yīng)用程序單實例運(yùn)行的方法,實現(xiàn)原理是在程序啟動時,請求一個互斥體,如果能獲取對指定互斥的訪問權(quán),就繼續(xù)運(yùn)行程序,否則就退出程序2014-01-01

