来源: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 下两种图片合成或加水印的方式(转载)的更多相关文章

  1. C# 图片的裁剪,两个图片合成一个图片

    图片的裁剪,两个图片合成一个图片(这是从网上摘的) /// <summary>         /// 图片裁剪,生成新图,保存在同一目录下,名字加_new,格式1.png  新图1_ne ...

  2. 两种图片延迟加载的方法总结jquery.scrollLoading.js与jquery.lazyload.js

    估计网上能查到的最多的两种图片延迟加载方法就是jquery.scrollLoading.js与jquery.lazyload.js了,其中jquery.lazyload.js的调用方法因为有网友爆出的 ...

  3. Convert between cv::Mat and QImage 两种图片类转换

    在使用Qt和OpenCV混合编程时,我们有时需要在两种图片类cv::Mat和QImage之间进行转换,下面的代码参考了网上这个帖子: //##### cv::Mat ---> QImage ## ...

  4. android环境下两种md5加密方式

    在平时开发过程中,MD5加密是一个比较常用的算法,最常见的使用场景就是在帐号注册时,用户输入的密码经md5加密后,传输至服务器保存起来.虽然md5加密经常用,但是md5的加密原理我还真说不上来,对md ...

  5. Android两种为ViewPager+Fragment添加Tab的方式

    在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为Vi ...

  6. 网页加水印 svg 方式

    /** *网页加水印 svg 方式 * * @export * @param {*} [{ * container = document.body, * content = '请勿外传', * wid ...

  7. 原生js - 两种图片懒加载实现原理

    目前图片懒加载的方式主要有两种: 1.利用getBoundingClientRectAPI得到当前元素与视窗的距离来判断 2.利用h5的新API IntersectionObserver 来实现 ge ...

  8. Linux 下操作GPIO(两种方法,驱动和mmap)(转载)

    目前我所知道的在Linux下操作GPIO有两种方法: 1.编写驱动,这当然要熟悉Linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据io ...

  9. .net下几种常用的对称加解密

    加密解密算法,太常用了,可是实在忍受不了十次八次之后还是要重头写,总是能告诉我原来的算法不好用(实际是压根不会用)的情况,不如直接写出来,再有人要直接给他看看,也顺便记录下算法,方便下新手大众. DE ...

随机推荐

  1. CAN总线芯片SN65HVD230QD介绍

    CAN总线硬件电路如上,采用芯片为SN65HVD230QD,从TI获得的芯片手册,可知该芯片参数为: 3.3V供电 低电流为370uA典型值

  2. Delphi 实现自动更新

    Delphi 通用程序自动更新升级:http://www.delphitop.com/html/wangluo/2968.html https://www.cnblogs.com/hnxxcxg/p/ ...

  3. 广联达 BIM5D 云平台---《建筑信息模型标准》解读

    广联达 BIM5D 云平台: 1.用户管理:  https://account.glodon.com/info 2.模型使用:  http://bim5d-hunan.glodon.com/api/v ...

  4. awk入门【转】

    awk其实不仅仅是工具软件,还是一种编程语言.不过,本文只介绍它的命令行用法,对于大多数场合,应该足够用了. 一.基本用法 awk的基本用法就是下面的形式. # 格式 $ awk 动作 文件名 # 示 ...

  5. python 彩色日志配置

    import os import logging import logging.config as log_conf import datetime import coloredlogs log_di ...

  6. Git学习笔记07-删除文件

    在Git中,删除也是一种修改.先新建一个文件,添加并提交.然后删除下看看. 一般删除直接从工作区把文件删了,或者使用rm命令 ​ 这是使用git status查看状态,会告诉我们删了哪个文件 ​ 这个 ...

  7. 设计模式C++学习笔记之十九(State状态模式)

      19.1.解释 概念:允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类. main(),客户 CLiftState,电梯状态抽象类 CCloseingState,电梯门关闭 ...

  8. UDP可靠传输那些事

    有空来论坛走走,发现讨论udp可靠传输又热了起来,有人认为udp高效率,有人认为udp丢包重传机制容易控制,还有朋友搞极限测试,当然也有人推销自己的东西,这里写一点我个人的看法. udp可靠传输其实非 ...

  9. linux系统设置静态IP,DHCP网络服务,DNS

    一.设置静态IP及DHCP网络服务 kk@yuanqiangfei:~$ cat /etc/network/interfaces # This file describes the network i ...

  10. html常用标签表单和表格等及css的简单入门

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...