C#二维码生成与解码(二)

 本文内容在《C#二维码生成与解码》的基础上增加了纠错级别和Logo图标加入,增加了二维码的功能。关于透明度在这里没有单独显现,因为在颜色里面就已经包含,颜色值由8位8进制构成,最前面的两位就是控制透明度的,后面的6位分为对应红绿蓝的值。

【窗体效果图】

【程序源代码】

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ZXing;
using ZXing.QrCode.Internal;
using System.IO;

namespace ErWeiMa
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            cbocorrection.SelectedIndex = 1;
        }

        /// <summary>获取标志图像路径</summary>
        private void btnLogo_Click(object sender, EventArgs e)
        {
            var dlg = new OpenFileDialog()
            {
                Filter = "图片文件|*.png;*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.tif;*.tiff|所有文件|*.*",
                Multiselect = false
            };
            if (dlg.ShowDialog() ==DialogResult.OK)
                this.txtLogoFile.Text = dlg.FileName;
        }

        /// <summary>生成二维码图片</summary>
        private void btnGen_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(this.txtMessage.Text))
            {
                MessageBox.Show("编码用的内容字符串不能为空。", "操作错误",MessageBoxButtons.OK,MessageBoxIcon.Error);
                return;
            }

            this.imgQrcode.Image = null;

            try
            {
                // 纠错级别
                var errCorrLvl = ErrorCorrectionLevel.M;
                var corrRatio = 0.15;
                switch (this.cbocorrection.SelectedIndex)
                {
                    case 0: errCorrLvl = ErrorCorrectionLevel.L; corrRatio = 0.07; break;
                    case 1: errCorrLvl = ErrorCorrectionLevel.M; corrRatio = 0.15; break;
                    case 2: errCorrLvl = ErrorCorrectionLevel.Q; corrRatio = 0.25; break;
                    case 3: errCorrLvl = ErrorCorrectionLevel.H; corrRatio = 0.30; break;
                }

                int Qsize = Int32.Parse(textBox1.Text);
                if(Qsize==0)
                    Qsize=(int)this.imgQrcode.Width;
                // 生成 QR Code 位图
                var hints = new Dictionary<EncodeHintType, object>();
                hints.Add(EncodeHintType.CHARACTER_SET, "UTF-8");
                hints.Add(EncodeHintType.ERROR_CORRECTION, errCorrLvl);
                var matrix = new MultiFormatWriter().encode(this.txtMessage.Text, BarcodeFormat.QR_CODE,Qsize ,Qsize, hints);
                var bitmap = new Bitmap(matrix.Width, matrix.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                var deepColor = ColorTranslator.FromHtml("0xff000000");
                var lightColor = ColorTranslator.FromHtml("0xffffffff");
                if (!String.IsNullOrWhiteSpace(this.txtDeepColor.Text))
                    deepColor = ColorTranslator.FromHtml("0x" + this.txtDeepColor.Text.TrimStart('#'));
                if (!String.IsNullOrWhiteSpace(this.txtLightColor.Text))
                    lightColor = ColorTranslator.FromHtml("0x" + this.txtLightColor.Text.TrimStart('#'));
                for (int x = 0; x < matrix.Width; x++)
                    for (int y = 0; y < matrix.Height; y++)
                        bitmap.SetPixel(x, y, matrix[x, y] ? deepColor : lightColor);

                // 添加标志
                if (!String.IsNullOrWhiteSpace(this.txtLogoFile.Text))
                {
                    if (File.Exists(this.txtLogoFile.Text))
                    {
                        var logo = new Bitmap(this.txtLogoFile.Text);
                        var ratio = (double)(logo.Width * logo.Height) / (double)(bitmap.Width * bitmap.Height);
                        if (ratio > corrRatio * 0.6)    // 标志图片大小最大只能占到最大容错面积的60%以保证图片高可读性
                        {
                            MessageBox.Show(String.Format("在当前指定的纠错级别下,标志图片大小最大只能占到二维码图片面积的 {0:P1}。", corrRatio * 0.6), "操作错误",MessageBoxButtons.OK,MessageBoxIcon.Error);
                            return;
                        }

                        CreateQRCodeBitmapWithPortrait(bitmap, logo);
                    }
                    else
                    {
                        var dlgResult = MessageBox.Show("指定的标志图片文件不存在!\r\n是否忽略标志图片继续生成?", "警告",MessageBoxButtons.YesNo,MessageBoxIcon.Warning);
                        if (dlgResult == DialogResult.OK) return;
                    }
                }
                this.imgQrcode.Image = bitmap;
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("生成二维码图片时出错。\r\n错误类型:{0}\r\n错误信息:{1}", ex.GetType(), ex.Message), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        /// <summary>在二维码位图上绘制标志。</summary>
        private void CreateQRCodeBitmapWithPortrait(Bitmap qrCode, Bitmap logo)
        {
            Graphics g = Graphics.FromImage(qrCode);
            int qsize = Int32.Parse(textBox1.Text);
            // 设置头像要显示的位置,即居中显示
            int rectX = (qsize- logo.Width) / 2;
            int rectY = (qsize - logo.Height) / 2;
            g.DrawImage(logo, rectX, rectY);

            g.Dispose();
        }

        /// <summary>保存二维码图片 </summary>
        private void btnSave_Click(object sender, EventArgs e)
        {
            Image img = imgQrcode.Image;
            if (img != null)
            {
                SaveFileDialog sFD = new SaveFileDialog();
                sFD.Filter = "*.png|*.png";
                if (sFD.ShowDialog() == DialogResult.OK)
                {
                    Bitmap bmap = new Bitmap(img, img.Width, img.Height);
                    bmap.Save(sFD.FileName);
                    MessageBox.Show("保存成功!");
                }
            }
            else
            {
                MessageBox.Show("您还没有生成二维码!");
            }
        }

        private void btnRead_Click(object sender, EventArgs e)
        {
            var dlg = new OpenFileDialog()
            {
                Filter = "图片文件|*.png;*.bmp;*.dib;*.jpg;*.jpeg;*.jpe;*.jfif;*.tif;*.tiff|所有文件|*.*",
                Multiselect = false
            };
            if (dlg.ShowDialog() ==DialogResult.OK)
            {
                // 采用先将图片文件内容读入字节数组然后再通过该数组创建图像实例是为了读取图片后图片文件不再会被文件访问锁锁定
                byte[] bytes = null;
                using (var stream = File.Open(dlg.FileName, FileMode.Open))
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    var fileInfo = new FileInfo(dlg.FileName);
                    bytes = reader.ReadBytes(unchecked((int)fileInfo.Length));
                    reader.Close();
                }

                try
                {
                    MemoryStream ms = new MemoryStream(bytes);
                    imgQrcode.Image = new Bitmap(ms);
                }
                catch (Exception ex)
                {
                    this.imgQrcode = null;
                    MessageBox.Show(String.Format("读取图片信息时出错,可能图片是不认识的图像格式。\r\n错误类型:{0}\r\n错误信息:{1}", ex.GetType(), ex.Message), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void btnAnalysis_Click(object sender, EventArgs e)
        {
            var image = imgQrcode.Image;
            if (image == null)
            {
                MessageBox.Show("二维码图片空白,还没读取二维码图片。", "操作错误", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return;
            }

            this.txtMessage.Text = String.Empty;
            this.lblQ.Text = "(空)";

            Bitmap bitmap;           
            bitmap = new Bitmap(image);

            try
            {
                LuminanceSource source = new BitmapLuminanceSource(bitmap);
                /* 
                 * 在二值化方面,GlobalHistogramBinarizer 提供了比较基础的二值化方法,而 HybridBinarizer 则算是高级的算法,建议要机器性能比较好才使用。
                 * HybridBinarizer 在识别对比度比较低的图片就是比 GlobalHistogramBinarizer 要差;
                 * HybridBinarizer 在光照均匀的情况下,效果比 GlobalHistogramBinarizer 优。
                 */
                // var binarizer = new ZXing.Common.HybridBinarizer(luminance);
                var binarizer = new ZXing.Common.GlobalHistogramBinarizer(source);
                var binBitmap = new BinaryBitmap(binarizer);
                var hints = new Dictionary<DecodeHintType, object>();
                hints.Add(DecodeHintType.CHARACTER_SET, "UTF-8");
                var result = new MultiFormatReader().decode(binBitmap, hints);
                if (result == null)
                {
                    MessageBox.Show("无法正确解析图片。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                this.txtMessage.Text = result.Text;
                this.lblQ.Text = result.BarcodeFormat.ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("解析图片时出错。\r\n错误类型:{0}\r\n错误信息:{1}", ex.GetType(), ex.Message), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

【引用dll文件】
http://pan.baidu.com/s/1ntNr79v

【关注我的博客】

 

 

 

 

 

 

 

posted @ 2014-07-08 19:00  徐航  阅读(8488)  评论(3编辑  收藏  举报