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 ...
随机推荐
- 快速了解Hash算法
hash hashcode java 1.hash 2.hash算法 1.hash Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射pre-image)通过 ...
- vmware Harbor 复制功能试用
vmware Harbor 复制功能试用 Harbor基于策略的Docker镜像复制功能,可在不同的数据中心.不同的运行环境之间同步镜像,并提供友好的管理界面,大大简化了实际运维中的镜像管理工作. 功 ...
- 8-Images
HTML Image Tags Tag Description <img> Defines an image <map> Defines an image-map <ar ...
- Light OJ 1116
基础数学:.. #include<bits/stdc++.h> using namespace std; typedef unsigned long long ULL; int main( ...
- Day8--------------RPM包管理
nginx.tar.gz:源码,编译安装 RPM:redhat package manage,二进制 增.删.查 1.增 package------>ls|less------------> ...
- UpdatePanel1里面使用FileUpload控件
最近做项目过程中,遇到了UpdatePanel1里面放了一个FileUpload控件,结果从后台就获取不到上传的文件了,找了好久才找到原因.原因: 加了红色部分后立马获取到了.
- Confluence 6 从外部小工具中注册访问
希望从 Confluence 中删除一个小工具,你可以选择小工具边上的 URL ,然后单击删除(Delete). 如果你希望取消订阅一个应用的小工具,你需要删除整个订阅.你不能仅仅删除你订阅中的某一个 ...
- 【Web】servlet、filter和listener
一般地,servlet.filter.listener是配置到web.xml中(web.xml 的加载顺序是:context-param -> listener -> filter -&g ...
- LeetCode(3):无重复字符的最大子串
本内容是LeetCode第三道题目:无重复字符的最大子串 # -*- coding: utf-8 -*- """ Created on Sun Mar 10 20:14: ...
- cf909C 线性dp+滚动数组好题!
一开始一直以为是区间dp.. /* f下面必须有一个s 其余的s可以和任意f进行匹配 所以用线性dp来做 先预处理一下: fffssfsfs==>3 0 1 1 dp[i][j] 表示第i行缩进 ...