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),
                                                   50,
                                                   System.Windows.Media.Brushes.White);

            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawImage(bgImage, new Rect(0, 0, bgImage.Width, bgImage.Height));

            //计算头像的位置
            double x = (bgImage.Width / 2 - headerImage.Width) / 2;
            double y = (bgImage.Height - headerImage.Height) / 2 - 100;
            drawingContext.DrawImage(headerImage, new Rect(x, y, headerImage.Width, headerImage.Height));

            //计算签名的位置
            double x2 = (bgImage.Width/2 - signatureTxt.Width) / 2;
            double y2 = y + headerImage.Height + 20;
            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(0, 0, bitmap.Width, bitmap.Height));

            //再在画板上画头像
            int x = (bgImage.Width / 2 - headerImage.Width) / 2;
            int y = (bgImage.Height - headerImage.Height) / 2 - 100;
            g.DrawImage(headerImage, new GDI.Rectangle(x, y, headerImage.Width, headerImage.Height),
                                     new GDI.Rectangle(0, 0, headerImage.Width, headerImage.Height),
                                     GDI.GraphicsUnit.Pixel);

            //在画板上写文字
            using (GDI.Font f = new GDI.Font("Arial", 20, GDI.FontStyle.Bold))
            {
                using (GDI.Brush b = new GDI.SolidBrush(GDI.Color.White))
                {
                    float fontWidth = g.MeasureString(signature, f).Width;
                    float x2 = (bgImage.Width / 2 - fontWidth) / 2;
                    float y2 = y + headerImage.Height + 20;
                    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

原文地址:https://www.cnblogs.com/144823836yj/p/8569553.html

时间: 2024-10-13 04:43:41

WPF 下两种图片合成或加水印的方式(转载)的相关文章

android环境下两种md5加密方式

在平时开发过程中,MD5加密是一个比较常用的算法,最常见的使用场景就是在帐号注册时,用户输入的密码经md5加密后,传输至服务器保存起来.虽然md5加密经常用,但是md5的加密原理我还真说不上来,对md5的认知目前仅仅停留在会使用的水平,想搞清楚还是要花点时间的,这是md5加密算法的相关介绍.本文主要介绍android平台下两种md5加密方式,分别为基于java语言的md5加密及ndk环境下基于c语言的md5加密. 下面代码为基于java语言的md5加密: public String getMD5

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

在使用Qt和OpenCV混合编程时,我们有时需要在两种图片类cv::Mat和QImage之间进行转换,下面的代码参考了网上这个帖子: //##### cv::Mat ---> QImage ##### // Shallow copy QImage mat2qimage_ref(cv::Mat &m, QImage::Format format) { return QImage(m.data, m.cols, m.rows, m.step, format); } // Deep copy QI

flink on yarn模式下两种提交job方式

flink on yarn模式下两种提交job方式 https://juejin.im/post/5bf8dd7a51882507e94b8b15 https://www.cnblogs.com/asker009/p/11327533.html https://ci.apache.org/projects/flink/flink-docs-release-1.9/ops/deployment/yarn_setup.html#flink-yarn-session 原文地址:https://www.

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

在Android开发中ViewPager的使用是非常广泛的,而它不仅仅能够实现简单的开始引导页,还可以结合Fragment并添加Tab作为选项卡或为显示大批量页面实现强大的顺畅滑动 下面介绍两种为ViewPager+Fragment添加Tab的方式: 第一种: 在MainActivity布局中定义一个ViewPager 在MainActivity中声明ViewPager并实现它的Adapter继承自FragmentPagerAdapter 首先需要通过重写有参的构造方法来获取FragmentMa

iOS:图片上传时两种图片压缩方式的比较

上传图片不全面的想法:把图片保存到本地,然后把图片的路径上传到服务器,最后又由服务器把路径返回,这种方式不具有扩展性,如果用户换了手机,那么新手机的沙盒中就没有服务器返回的图片路径了,此时就无法获取之前已经上传了的头像了,在项目中明显的不可行. 上传图片的正确方式:上传头像到服务器一般是将图片NSData上传到服务器,服务器返回一个图片NSString地址,之后再将NSString的路径转为url并通过url请求去更新用户头像(用户头像此时更新的便是NSString) 代码为: AFHTTPRe

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

目前我所知道的在Linux下操作GPIO有两种方法: 1.编写驱动,这当然要熟悉Linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据ioctl命令进行GPIO寄存器的读写,并把结果回送到应用层.这里提供一点程序片断供大家参考: int  init_module(void){ printk(KERN_ALERT "ioctl load.\r\n"); register_chrdev(254,"ioreg"

Linux下两种删除过期文件的方法详述

一.概述 在实际的C软件开发项目中,不同的软件会在不同的目录中生成文件,由于磁盘的存储空间有限,开发人员不得不考虑对目录下的过期文件进行删除.一般说来,有两种删除过期文件的方法,一种是在C程序中实现,一种是利用crontab实现.本文对这两种方法的具体实现进行详细的介绍. 为了便于说明,本文中的过期文件的后缀为.c,存放在/home/zhou/zhouzx/Test目录下,过期时间为1天. 二.在C程序中实现过期文件删除 在该方法中,我们要考虑的主要问题为: (1)要删除过期多久的文件?文件存放

微信平台下两种消息处理流程

简单的微信公共账号的开发貌似很简单.相当于汇总了我们所有程序的入口. 但是微信的消息处理模式主要有两种,今天我们主要看看一下其间的区别. 1 编辑模式下的消息处理模式 步骤一:用户使用微信客户端像公众号发送消息. 二:根据公众号运营者配置的规则进行处理 三:将处理结构返回给微信客户端,通过公众号呈现给用户. 2开发模式下的处理流程 步骤一:用户使用微信客户端向公众号发送消息. 二:通过HTTP POST 消息 三:接受处理消息 四:返回处理结果 五:将处理结果返回,通过公众号呈现给用户 两者的却

两种简单实现菜单高亮显示的JS类(转载)

两种简单实现菜单高亮显示的JS类 近期在写一个博客管理后台的前端,涉及在同一页面两种高亮显示当前菜单的需求.记得当年写静态页时,为了实现高亮都是在每个页面加不同的样式,呵.高亮显示我觉得对于web前端来说,是比较常用到的效果,正好此次又要用到,特地整理出我所写的两种高亮类. 其实思路很简单,第一种方法是通过遍历链接组的href值,通过indexOf判断href值是否被包含在浏览器当前url值中.此方法有一定局限,比如对于iframe内的菜单是不能这样判断的; 第二种方法适用范围更广一样,实现思路