.net 后端生成海报

以前项目中生成海报都是前端生成(html2canvas)但由于前端生成有各种各样的限制如
图片跨域,浏览器兼容等问题。老板就想网站中生成海报用回服务端生成海报的方式。直接通过链接就可以输出海报~~~~ 那就干吧

先看下实现的效果(主要是 背景图+二维码+标题+价格)
.net 后端生成海报_第1张图片
实现的效果感觉还是可以,就是折扣这框本来要有圆角的,但是圆角的实现好像有点麻烦最终没有弄

进入实现生成海报正题

为了方式使用这里使用 IHttpHandler的方式实现,直接使用链接传入参数即可【xxx/Images/poster.ashx?id=d9577af85ce44a2ebccf0a8593ab3332&path=http://jvimg001-10003558.image.myqcloud.com/d8f155f8437c7c3953d365e72e5200c3&title=%E8%85%BE%E8%AE%AF%E8%A7%86%E9%A2%91%E8%B6%85%E7%BA%A7%E5%BD%B1%E8%A7%86VIP%E4%BC%9A%E5%91%98%E5%B9%B4%E5%8D%A1%EF%BC%88%E6%94%AF%E6%8C%81%E7%94%B5%E8%A7%86%E7%AB%AF%EF%BC%89&op=488&p=288】
演示

引用的 dll 如下
ThoughtWorks.QRCode.dll (用于生成二维码) 【下载】
代码实现

QRCodeHelper 二维码生成类,可生成中心带有logo 的二维码

  public class QRCodeHelper
        {
            /// 
            /// 生成二维码,默认边长为250px
            /// 
            /// 二维码内容
            /// 
            public static Image BuildQRCode(string content)
            {
                return BuildQRCode(content, 250, Color.White, Color.Black);
            }

            /// 
            /// 生成二维码,自定义边长
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 
            public static Image BuildQRCode(string content, int imgSize)
            {
                return BuildQRCode(content, imgSize, Color.White, Color.Black);
            }

            /// 
            /// 生成二维码
            /// 注:自定义边长以及颜色
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 二维码底色
            /// 二维码前景色
            /// 
            public static Image BuildQRCode(string content, int imgSize, Color background, Color foreground)
            {
                return BuildQRCode_Logo(content, imgSize, background, foreground, null);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:默认生成边长为250px的二维码
            /// 
            /// 二维码内容
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, Bitmap logo)
            {
                return BuildQRCode_Logo(content, 250, Color.White, Color.Black, logo);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:自定义边长
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, int imgSize, Bitmap logo)
            {
                return BuildQRCode_Logo(content, imgSize, Color.White, Color.Black, logo);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:自定义边长以及颜色
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 二维码底色
            /// 二维码前景色
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, int imgSize, Color? background = null, Color? foreground = null, Bitmap logo = null)
            {
                QRCodeEncoder encoder = new QRCodeEncoder();
                encoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;//编码方式(注意:BYTE能支持中文,ALPHA_NUMERIC扫描出来的都是数字)
                encoder.QRCodeScale = 5;//大小(值越大生成的二维码图片像素越高)
                encoder.QRCodeVersion = 0;//版本(注意:设置为0主要是防止编码的字符串太长时发生错误)
                encoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;//错误效验、错误更正(有4个等级)
                encoder.QRCodeBackgroundColor = background ?? Color.White;
                encoder.QRCodeForegroundColor = foreground ?? Color.Black;
                System.Drawing.Image image = encoder.Encode(content, System.Text.Encoding.UTF8);
                //这里+10 使得二维码留边 
                int resWidth = imgSize + 10;
                Bitmap newBit = new Bitmap(resWidth, resWidth, PixelFormat.Format32bppRgb);
                Graphics g = Graphics.FromImage(newBit);
                //设置白色背景
                g.FillRectangle(new SolidBrush(Color.White), 0, 0, (int)resWidth, (int)resWidth);
                g.DrawImage(image, 5, 5, imgSize, imgSize);
                if (logo != null)
                {
                    int logoW = 40;
                    int w = resWidth / 4;
                    int x = resWidth / 2 - w / 2;
                    int centerW = resWidth / logoW;
                    //设置白色背景
                    g.FillRectangle(new SolidBrush(Color.White), x, x, w, w);
                    Bitmap copyImage = new Bitmap(logo, w - centerW, w - centerW);
                    g.DrawImage(copyImage, x + centerW / logoW / 2, x + centerW / 2);
                    copyImage.Dispose();
                }
                g.Dispose();
                return newBit;
            }
        }

为了使用颜色丰富,需要将css 常规的进行转换

private Color ColorConvertBy16(string colorString)//16进制颜色值
        {
            int v = int.Parse(colorString, System.Globalization.NumberStyles.HexNumber);
            return Color.FromArgb(255, Convert.ToByte((v >> 16) & 255), Convert.ToByte((v >> 8) & 255), Convert.ToByte((v >> 0) & 255));
        }

下面是完成的代码实现

绘制海报的主要方法 CreatePoster ,FileCacheHelper 是封装的文件缓存类
using Jonvie.xxx 是内部封装的缓存相关的引用 (可去掉)

<%@ WebHandler Language="C#" Class="Enterprise.WebSite.App_Code.Poster" %>
using System;
using System.Web;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Web.SessionState;
using System.Net;
using ThoughtWorks.QRCode.Codec;
using Jonvie.CacheUtil;
using Jonvie.Extensions;
namespace Enterprise.WebSite.App_Code
{
    public class Poster : IHttpHandler
    {
        private readonly string fontName = "微软雅黑";
        public void ProcessRequest(HttpContext context)
        {
            string id = context.Request.QueryString["id"] ?? "";
            if (!string.IsNullOrWhiteSpace(id))
            {
                string path = context.Request.QueryString["path"] ?? "";
                string title = context.Request.QueryString["title"] ?? "";
                if (title.Length > 40)
                {
                    title = title.Substring(0, 40);
                }
                string qrcodeUrl = $"https://wx.jonvie.com/yp/plugins/RechargeClient/SureOrder?pid={id}&flag=pc";
                decimal op = 0;
                if (!string.IsNullOrWhiteSpace(context.Request.QueryString["op"]))
                {
                    op = Convert.ToDecimal(context.Request.QueryString["op"]);
                }
                decimal p = 0;
                if (!string.IsNullOrWhiteSpace(context.Request.QueryString["p"]))
                {
                    p = Convert.ToDecimal(context.Request.QueryString["p"]);
                }
                if (!string.IsNullOrWhiteSpace(path))
                    path += "?imageView2/1/w/750/h/750/q/100";
                string key = ($"{id}_{p}").MD5();
                FileCacheHelper _fileCache = new FileCacheHelper("_cache", "product-poster", new TimeSpan(5, 0, 0, 0, 0));
                byte[] poster = _fileCache.GetOrAddCacheItem<byte[]>(key, () =>
                {
                    return CreatePoster(path, title, op, p, qrcodeUrl);
                });
                context.Response.Clear();
                context.Response.ContentType = "image/jpeg";
                context.Response.BinaryWrite(poster);

            }
        }
        private byte[] CreatePoster(string path, string title, decimal op = 0, decimal p = 0, string qrcodeUrl = "")
        {
            decimal discount = 0;
            if (op > 0)
            {
                discount = Math.Floor(p / op * 100M) / 10M;
            }
            Image image = ReduceNetworkImage(path);
            int w = 750;
            int h = 1000;
            int margin = 20;
            //先绘画一个750*1000的背景
            Bitmap bitmap = new Bitmap(w, h, PixelFormat.Format32bppPArgb);
            //在背景上开始绘画   
            Graphics g = Graphics.FromImage(bitmap);
            //插入的像素位置由偏移量控制。
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            //像素偏移方式,像素在水平和垂直距离上均偏移若干个单位,以进行高速锯齿消除。
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;
            g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            //填充颜色
            g.Clear(ColorConvertBy16("fafafa"));
            //绘制头部图片,指定位置为 0, 0, 334, 334
            Image imgBack = ReduceNetworkImage(path);
            g.DrawImage(imgBack, 0, 0, 750, 750);
            AddFontWarp(g, title, 5, 760, new Font(new Font(fontName, 24), FontStyle.Regular), w);
            AddFont(g, $"原价{op}", margin, 850, new Font(new Font(fontName, 18), FontStyle.Strikeout), new SolidBrush(ColorConvertBy16("a7a7a7")));
            AddFont(g, $"¥{p}", margin, 880, new Font(new Font(fontName, 20), FontStyle.Bold), new SolidBrush(Color.Red));
            if (discount > 0)
            {
                string zkTxt = $"{discount}折";
                g.FillRectangle(new SolidBrush(ColorConvertBy16("ffdf00")), margin, 920, zkTxt.Length * 16f + 4, 28);
                AddFont(g, zkTxt, margin + 4, 920, new Font(fontName, 16), new SolidBrush(Color.Red));
            }
            AddFont(g, "微信扫一扫 立即充值>>", margin, 960, new Font(fontName, 18), new SolidBrush(ColorConvertBy16("a7a7a7")));
            g.DrawImage(QRCodeHelper.BuildQRCode(qrcodeUrl, 140), new PointF(580, 840));
            MemoryStream ms = new MemoryStream();
            //保存为Jpg类型
            bitmap.Save(ms, ImageFormat.Jpeg);
            g.Dispose();
            bitmap.Dispose();
            image.Dispose();
            return ms.ToArray();
        }
        /// 
        /// 添加矩形
        /// 
        /// 
        private void AddRectangle(Graphics g, int x, int y, int w, int h, int radius)
        {
            int cRadius = radius;
            // 要实现 圆角化的 矩形
            Rectangle rect = new Rectangle(x, y, w - cRadius, h - cRadius);
            // 指定图形路径, 有一系列 直线/曲线 组成
            System.Drawing.Drawing2D.GraphicsPath myPath = new System.Drawing.Drawing2D.GraphicsPath();
            myPath.StartFigure();
            myPath.AddArc(new Rectangle(new Point(rect.X, rect.Y), new Size(2 * cRadius, 2 * cRadius)), 180, 90);
            myPath.AddLine(new Point(rect.X + cRadius, rect.Y), new Point(rect.Right - cRadius, rect.Y));
            myPath.AddArc(new Rectangle(new Point(rect.Right - 2 * cRadius, rect.Y), new Size(2 * cRadius, 2 * cRadius)), 270, 90);
            myPath.AddLine(new Point(rect.Right, rect.Y + cRadius), new Point(rect.Right, rect.Bottom - cRadius));
            myPath.AddArc(new Rectangle(new Point(rect.Right - 2 * cRadius, rect.Bottom - 2 * cRadius), new Size(2 * cRadius, 2 * cRadius)), 0, 90);
            myPath.AddLine(new Point(rect.Right - cRadius, rect.Bottom), new Point(rect.X + cRadius, rect.Bottom));
            myPath.AddArc(new Rectangle(new Point(rect.X, rect.Bottom - 2 * cRadius), new Size(2 * cRadius, 2 * cRadius)), 90, 90);
            myPath.AddLine(new Point(rect.X, rect.Bottom - cRadius), new Point(rect.X, rect.Y + cRadius));
            myPath.CloseFigure();
            g.DrawPath(new Pen(Color.Red, 1), myPath);
        }
        //添加文字
        private void AddFont(Graphics g, string txt, int x, int y, Font font = null, SolidBrush mybrush = null)
        {
            if (mybrush == null)
                mybrush = new SolidBrush(Color.Black);
            if (font == null)
                font = new Font(fontName, 14);
            g.DrawString(txt, font, mybrush, new PointF(x, y));
        }
        //添加文字
        private void AddFont(Graphics g, string txt, int x, int y, float emSize = 14, Font font = null, SolidBrush mybrush = null)
        {
            if (mybrush == null)
                mybrush = new SolidBrush(Color.Black);
            if (font == null)
                font = new Font(fontName, emSize);
            g.DrawString(txt, font, mybrush, new PointF(x, y));
        }
        //添加文字,可换行 
        private void AddFontWarp(Graphics g, string txt, int x, int y, int emSize = 14, Font font = null, int maxw = 400)
        {
            if (font == null)
                font = new Font(fontName, emSize);
            RectangleF descRect = new RectangleF();
            descRect.Location = new Point(x, y);
            descRect.Size = new Size(maxw, ((int)g.MeasureString(txt, font, maxw, StringFormat.GenericTypographic).Height));
            g.DrawString(txt, font, Brushes.Black, descRect);
        }
        private void AddFontWarp(Graphics g, string txt, int x, int y, Font font = null, int maxw = 400)
        {
            if (font == null)
                font = new Font(fontName, 14);
            RectangleF descRect = new RectangleF();
            descRect.Location = new Point(x, y);
            descRect.Size = new Size(maxw, ((int)g.MeasureString(txt, font, maxw, StringFormat.GenericTypographic).Height));
            g.DrawString(txt, font, Brushes.Black, descRect);
        }
        //获取图片并处理成指定只存返回,宽高填写0,直接返回原尺寸
        private Image ReduceNetworkImage(string url, int toWidth = 0, int toHeight = 0)
        {
            HttpWebRequest httpwebr = (HttpWebRequest)HttpWebRequest.Create(url);
            httpwebr.Method = "GET";
            Stream s = httpwebr.GetResponse().GetResponseStream();
            Image originalImage = Image.FromStream(s);
            if (toWidth <= 0 && toHeight <= 0)
            {
                return originalImage;
            }
            else if (toWidth > 0 && toHeight > 0)
            {
                if (originalImage.Width < toWidth && originalImage.Height < toHeight)
                    return originalImage;
            }
            else if (toWidth <= 0 && toHeight > 0)
            {
                if (originalImage.Height < toHeight)
                    return originalImage;
                toWidth = originalImage.Width * toHeight / originalImage.Height;
            }
            else if (toHeight <= 0 && toWidth > 0)
            {
                if (originalImage.Width < toWidth)
                    return originalImage;
                toHeight = originalImage.Height * toWidth / originalImage.Width;
            }
            Image toBitmap = new Bitmap(toWidth, toHeight);
            using (Graphics g = Graphics.FromImage(toBitmap))
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.Clear(Color.Transparent);
                g.DrawImage(originalImage,
                            new Rectangle(0, 0, toWidth, toHeight),
                            new Rectangle(0, 0, originalImage.Width, originalImage.Height),
                            GraphicsUnit.Pixel);
                originalImage.Dispose();
                return toBitmap;
            }
        }

        private Color ColorConvertBy16(string colorString)//16进制颜色值
        {
            int v = int.Parse(colorString, System.Globalization.NumberStyles.HexNumber);
            return Color.FromArgb(255, Convert.ToByte((v >> 16) & 255), Convert.ToByte((v >> 8) & 255), Convert.ToByte((v >> 0) & 255));
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }


        private Point getPoint(int i, int w, int h)
        {
            Random r = new Random(i + DateTime.Now.Millisecond);
            int x = r.Next(-3 * w, 3 * w);
            int y = r.Next(-3 * h, 3 * h);
            return new Point(x, y);
        }

        private Color getFontColor(int seed)
        {
            Random r = new Random(seed + DateTime.Now.Millisecond);
            int i = r.Next(0, 9);
            Color[] color = new Color[]{
            Color.Violet,
            Color.YellowGreen,
            Color.Red,
            Color.RoyalBlue,
            Color.Purple,
            Color.SeaGreen,
            Color.SlateGray,
            Color.SteelBlue,
            Color.Teal,
            Color.YellowGreen
            };
            return color[i];
        }
        public class QRCodeHelper
        {
            /// 
            /// 生成二维码,默认边长为250px
            /// 
            /// 二维码内容
            /// 
            public static Image BuildQRCode(string content)
            {
                return BuildQRCode(content, 250, Color.White, Color.Black);
            }

            /// 
            /// 生成二维码,自定义边长
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 
            public static Image BuildQRCode(string content, int imgSize)
            {
                return BuildQRCode(content, imgSize, Color.White, Color.Black);
            }

            /// 
            /// 生成二维码
            /// 注:自定义边长以及颜色
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 二维码底色
            /// 二维码前景色
            /// 
            public static Image BuildQRCode(string content, int imgSize, Color background, Color foreground)
            {
                return BuildQRCode_Logo(content, imgSize, background, foreground, null);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:默认生成边长为250px的二维码
            /// 
            /// 二维码内容
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, Bitmap logo)
            {
                return BuildQRCode_Logo(content, 250, Color.White, Color.Black, logo);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:自定义边长
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, int imgSize, Bitmap logo)
            {
                return BuildQRCode_Logo(content, imgSize, Color.White, Color.Black, logo);
            }

            /// 
            /// 生成二维码并添加Logo
            /// 注:自定义边长以及颜色
            /// 
            /// 二维码内容
            /// 二维码边长px
            /// 二维码底色
            /// 二维码前景色
            /// logo图片
            /// 
            public static Image BuildQRCode_Logo(string content, int imgSize, Color? background = null, Color? foreground = null, Bitmap logo = null)
            {
                QRCodeEncoder encoder = new QRCodeEncoder();
                encoder.QRCodeEncodeMode = QRCodeEncoder.ENCODE_MODE.BYTE;//编码方式(注意:BYTE能支持中文,ALPHA_NUMERIC扫描出来的都是数字)
                encoder.QRCodeScale = 5;//大小(值越大生成的二维码图片像素越高)
                encoder.QRCodeVersion = 0;//版本(注意:设置为0主要是防止编码的字符串太长时发生错误)
                encoder.QRCodeErrorCorrect = QRCodeEncoder.ERROR_CORRECTION.H;//错误效验、错误更正(有4个等级)
                encoder.QRCodeBackgroundColor = background ?? Color.White;
                encoder.QRCodeForegroundColor = foreground ?? Color.Black;
                System.Drawing.Image image = encoder.Encode(content, System.Text.Encoding.UTF8);
                //这里+10 使得二维码留边 
                int resWidth = imgSize + 10;
                Bitmap newBit = new Bitmap(resWidth, resWidth, PixelFormat.Format32bppRgb);
                Graphics g = Graphics.FromImage(newBit);
                //设置白色背景
                g.FillRectangle(new SolidBrush(Color.White), 0, 0, (int)resWidth, (int)resWidth);
                g.DrawImage(image, 5, 5, imgSize, imgSize);
                if (logo != null)
                {
                    int logoW = 40;
                    int w = resWidth / 4;
                    int x = resWidth / 2 - w / 2;
                    int centerW = resWidth / logoW;
                    //设置白色背景
                    g.FillRectangle(new SolidBrush(Color.White), x, x, w, w);
                    Bitmap copyImage = new Bitmap(logo, w - centerW, w - centerW);
                    g.DrawImage(copyImage, x + centerW / logoW / 2, x + centerW / 2);
                    copyImage.Dispose();
                }
                g.Dispose();
                return newBit;
            }
        }

    }
}

你可能感兴趣的:(.net)