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

【關注我的博客】

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM