WPF 下两种图片合成或加水印的方式(转载)
来源:http://www.cnblogs.com/lxblog/
最近项目中应用多次应用了图片合成,为了今后方便特此记下。
在WPF下有两种图片合成的方式,一种还是用原来C#提供的GDI+方式,命名空间是System.Drawing 和 System.Drawing.Imaging,另一种是WPF中新添加的API,命名空间是 System.Windows.Media 和 System.Windows.Media.Imaging 。
我们来做一个简单的例子,分别用上面的两种方式实现,功能是在一个背景图上面,画一个头像,然后在写一个签名。
首先准备一张背景图(bg.jpg)和两个头像图片(tiger.png 和 lion.png)最后的生成的图片效果如下图:


把准备的素材拷贝到项目中,其文件属性【复制到输出目录】选择【始终复制】,【生成操作】选择【内容】。
这里贴一下两种方式的主要代码,具体代码可以在文章最后点击下载。
方法一
private BitmapSource MakePicture(string bgImagePath, string headerImagePath, string signature)
{ //获取背景图
BitmapSource bgImage = new BitmapImage(new Uri(bgImagePath, UriKind.Relative));
//获取头像
BitmapSource headerImage = new BitmapImage(new Uri(headerImagePath, UriKind.Relative)); //创建一个RenderTargetBitmap 对象,将WPF中的Visual对象输出
RenderTargetBitmap composeImage = new RenderTargetBitmap(bgImage.PixelWidth, bgImage.PixelHeight, bgImage.DpiX, bgImage.DpiY, PixelFormats.Default); FormattedText signatureTxt = new FormattedText(signature,
System.Globalization.CultureInfo.CurrentCulture,
System.Windows.FlowDirection.LeftToRight,
new Typeface(System.Windows.SystemFonts.MessageFontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
,
System.Windows.Media.Brushes.White); DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(bgImage, new Rect(, , bgImage.Width, bgImage.Height)); //计算头像的位置
double x = (bgImage.Width / - headerImage.Width) / ;
double y = (bgImage.Height - headerImage.Height) / - ;
drawingContext.DrawImage(headerImage, new Rect(x, y, headerImage.Width, headerImage.Height)); //计算签名的位置
double x2 = (bgImage.Width/ - signatureTxt.Width) / ;
double y2 = y + headerImage.Height + ;
drawingContext.DrawText(signatureTxt, new System.Windows.Point(x2, y2));
drawingContext.Close();
composeImage.Render(drawingVisual); //定义一个JPG编码器
JpegBitmapEncoder bitmapEncoder = new JpegBitmapEncoder();
//加入第一帧
bitmapEncoder.Frames.Add(BitmapFrame.Create(composeImage)); //保存至文件(不会修改源文件,将修改后的图片保存至程序目录下)
string savePath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"\合成.jpg";
bitmapEncoder.Save(File.OpenWrite(Path.GetFileName(savePath)));
return composeImage;
}
方法二
private BitmapSource MakePictureGDI(string bgImagePath, string headerImagePath, string signature)
{
GDI.Image bgImage = GDI.Bitmap.FromFile(bgImagePath);
GDI.Image headerImage = GDI.Bitmap.FromFile(headerImagePath); //新建一个画板,画板的大小和底图一致
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(bgImage.Width, bgImage.Height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
//设置高质量插值法
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
//设置高质量,低速度呈现平滑程度
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//清空画布并以透明背景色填充
g.Clear(System.Drawing.Color.Transparent); //先在画板上面画底图
g.DrawImage(bgImage, new GDI.Rectangle(, , bitmap.Width, bitmap.Height)); //再在画板上画头像
int x = (bgImage.Width / - headerImage.Width) / ;
int y = (bgImage.Height - headerImage.Height) / - ;
g.DrawImage(headerImage, new GDI.Rectangle(x, y, headerImage.Width, headerImage.Height),
new GDI.Rectangle(, , headerImage.Width, headerImage.Height),
GDI.GraphicsUnit.Pixel); //在画板上写文字
using (GDI.Font f = new GDI.Font("Arial", , GDI.FontStyle.Bold))
{
using (GDI.Brush b = new GDI.SolidBrush(GDI.Color.White))
{
float fontWidth = g.MeasureString(signature, f).Width;
float x2 = (bgImage.Width / - fontWidth) / ;
float y2 = y + headerImage.Height + ;
g.DrawString(signature, f, b, x2, y2);
}
} try
{
string savePath = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase + @"\GDI+合成.jpg";
bitmap.Save(savePath, System.Drawing.Imaging.ImageFormat.Jpeg);
return ToBitmapSource(bitmap);
}
catch (System.Exception e)
{
throw e;
}
finally
{
bgImage.Dispose();
headerImage.Dispose();
g.Dispose();
}
} #region GDI+ Image 转化成 BitmapSource
[System.Runtime.InteropServices.DllImport("gdi32")]
static extern int DeleteObject(IntPtr o);
public BitmapSource ToBitmapSource(GDI.Bitmap bitmap)
{
IntPtr ip = bitmap.GetHbitmap(); BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ip, IntPtr.Zero, System.Windows.Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
DeleteObject(ip);//释放对象
return bitmapSource;
}
#endregion
WPF 下两种图片合成或加水印的方式(转载)的更多相关文章
- C# 图片的裁剪,两个图片合成一个图片
图片的裁剪,两个图片合成一个图片(这是从网上摘的) /// <summary> /// 图片裁剪,生成新图,保存在同一目录下,名字加_new,格式1.png 新图1_ne ...
- 两种图片延迟加载的方法总结jquery.scrollLoading.js与jquery.lazyload.js
估计网上能查到的最多的两种图片延迟加载方法就是jquery.scrollLoading.js与jquery.lazyload.js了,其中jquery.lazyload.js的调用方法因为有网友爆出的 ...
- Convert between cv::Mat and QImage 两种图片类转换
在使用Qt和OpenCV混合编程时,我们有时需要在两种图片类cv::Mat和QImage之间进行转换,下面的代码参考了网上这个帖子: //##### cv::Mat ---> QImage ## ...
- android环境下两种md5加密方式
在平时开发过程中,MD5加密是一个比较常用的算法,最常见的使用场景就是在帐号注册时,用户输入的密码经md5加密后,传输至服务器保存起来.虽然md5加密经常用,但是md5的加密原理我还真说不上来,对md ...
- Android两种为ViewPager+Fragment添加Tab的方式
在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为Vi ...
- 网页加水印 svg 方式
/** *网页加水印 svg 方式 * * @export * @param {*} [{ * container = document.body, * content = '请勿外传', * wid ...
- 原生js - 两种图片懒加载实现原理
目前图片懒加载的方式主要有两种: 1.利用getBoundingClientRectAPI得到当前元素与视窗的距离来判断 2.利用h5的新API IntersectionObserver 来实现 ge ...
- Linux 下操作GPIO(两种方法,驱动和mmap)(转载)
目前我所知道的在Linux下操作GPIO有两种方法: 1.编写驱动,这当然要熟悉Linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据io ...
- .net下几种常用的对称加解密
加密解密算法,太常用了,可是实在忍受不了十次八次之后还是要重头写,总是能告诉我原来的算法不好用(实际是压根不会用)的情况,不如直接写出来,再有人要直接给他看看,也顺便记录下算法,方便下新手大众. DE ...
随机推荐
- 广联达 BIM5D 云平台---《建筑信息模型标准》解读
广联达 BIM5D 云平台: 1.用户管理: https://account.glodon.com/info 2.模型使用: http://bim5d-hunan.glodon.com/api/v ...
- python3+selenium入门04-元素定位
我们在对浏览界面做操作时,比如点击按钮,搜索框输入内容.都需要把鼠标挪过去,然后再点击,或者输入内容.在selenium操作时也是一样的.需要先对元素进行定位,然后才能进行操作.可以借助浏览器的开发者 ...
- 题解-CodeForces835F Roads in the Kingdom
Problem CodeForces-835F 题意:求基环树删去环上任意一边后直径最小值,直径定义为所有点对最近距离的最大值 Solution 首先明确删去环上一点是不会影响树内直径的,所以应当先把 ...
- Alpha 冲刺 (3/10)
目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:冲刺3 团队部分 后敬甲(组长) 过去两天完成了哪些任务 文字描述 组织第一次团队编程 继续阅读小程序开发文档 接下来的 ...
- Android ADT 离线下载
网上很多的Android在IDE eclipse的开发环境教程,ADT的就安装肯定也在里面啦 ADT的安装都是一个在线安装地址: https://dl-ssl.google.com/android/e ...
- 【原创】编程基础之Ruby
ruby2.6.2 官方:https://www.ruby-lang.org/en/ 一 简介 A dynamic, open source programming language with a f ...
- 深入理解ajax
http://www.imooc.com/code/13468 基础练习 http://www.imooc.com/video/5644 !ajax! 常用 for ...
- Confluence 6 配置管理员联系页面
管理员联系页面是一个格式化的页面,这个页面能够允许 Confluence 用户在 Confluence 中向管理员发送消息(在这部分的内容,管理员是默认管理员用户组的成员). 有关用户组的解释,请参考 ...
- JavaScript利用键盘方向键(上下键)控制表格行选中
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...
- 【ftp】主动模式和被动模式
来自:http://blog.csdn.net/liuhelong12/article/details/50218311 原博主不让转载全文,不过下面这部分是原博主转载别人的,所以我拿过来应该没问题吧 ...