如何在ASP.Net中实现自定义音频Capcha [英] How to implement Custom Audio Capcha in ASP.Net

查看:129
本文介绍了如何在ASP.Net中实现自定义音频Capcha的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们使用C#.Net创建了一个自定义Capcha生成器.现在,我们需要升级Capcha,使其包含音频功能(Listen Capcha).我们的主要限制是我们不能使用任何第三方组件(Dll)

We have created a Custom Capcha generator using C#.Net. Now we have requirement to upgrade our Capcha to include audio feature(Listen Capcha). Our major constraint is that we cannot use any third party components(Dlls)

请指导我实现此类功能.

Please guide me to implement such functionality.

谢谢.

推荐答案

我过去做过类似的事情.需要将背噪(乐器音乐)与串联的字母/字符合并在一起.除了使用中的录音外,我们还从不同的声音中产生了声音.所有这些增加了能够从语音中提取验证码文本的智能代码"的复杂性.由于明显的原因,我还不得不将最终的WAVE转换为MP3(使用lame_enc.dll).要解释您的操作方式并不容易,所以我提供了工作所需的第一个草稿版本,因为它使用了第三方DLL,所以省去了MP3代码.

I made something like this in the past. There was a need for back noise (instrumental music) merged with the concatenated letters/characters. In addition recordings in use we generated from different voices. All these increased the complexity for "smart code" able to extract the captcha text from voice. I had also to transform the final WAVE to MP3 (using lame_enc.dll) for obvious reasons. It's not so easy to explain you how to do it, so I include the very first draft version needed for the job, leaving out the MP3 code as it uses a third party DLL.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Reflection;

namespace suryakiran
{
    internal static partial class Extensions
    {
        internal static byte[] AudioCaptcha(this string text)
        {
            String en = "abcdefghijkoprstvx0123456789", Location = string.Concat(System.Web.HttpContext.Current.Request.ServerVariables["APPL_PHYSICAL_PATH"].ToString(), @"\bin\wav\");
            Int32 dataLength = 0, length = 0, sampleRate = 0, plus = 37500, p = 0;
            Int16 bitsPerSample = 0, channels = 0;
            Byte[] music, wav;
            Random r = new Random();
            p = r.Next(1, 4000000);
            p += (p % 150) + 44;
            Byte[] rb = new Byte[9 * plus];
        // read music
        using (FileStream fs = new FileStream(String.Format(Location + @"z{0}.wav", (r.Next() % 12) + 1), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            wav = new Byte[44];
            fs.Read(wav, 0, 44);
            fs.Position = (long)p;
            fs.Read(rb, 0, rb.Length);
        }
        // make music
        using (MemoryStream ms = new MemoryStream())
        {
            channels = BitConverter.ToInt16(wav, 22); sampleRate = BitConverter.ToInt32(wav, 24); bitsPerSample = BitConverter.ToInt16(wav, 34);
            length = rb.Length; dataLength = rb.Length;
            ms.Write(new Byte[44], 0, 44); ms.Write(rb, 0, rb.Length);
            ms.Position = 0;
            using (BinaryWriter bw = new BinaryWriter(ms))
            {
                bw.Write(new char[4] { 'R', 'I', 'F', 'F' }); bw.Write(length);
                bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
                bw.Write((Int32)16); bw.Write((Int16)1);
                bw.Write(channels); bw.Write(sampleRate);
                bw.Write((Int32)(sampleRate * ((bitsPerSample * channels) / 8)));
                bw.Write((Int16)((bitsPerSample * channels) / 8));
                bw.Write(bitsPerSample); bw.Write(new char[4] { 'd', 'a', 't', 'a' }); bw.Write(dataLength);
                music = ms.ToArray();
                p = 0;
            }
        }

        using (MemoryStream final = new MemoryStream())
        {
            final.Write(music, 0, 44);
            // make voice
            using (MemoryStream msvoice = new MemoryStream())
            {
                msvoice.Write(new Byte[plus / 2], 0, plus / 2);
                length += plus; dataLength += plus / 2; p += plus / 2;
                for (var i = 0; i < text.Length; i++)
                {
                    String fn = String.Format(Location + @"{0}\{1}.wav", (r.Next() % 3), en.Substring(en.IndexOf(text.Substring(i, 1)), 1)).Replace("?", "qm");
                    wav = File.ReadAllBytes(fn);
                    Int32 size = BitConverter.ToInt32(wav, 4);
                    {
                        msvoice.Write(new Byte[plus / 2], 0, plus / 2);
                        length += plus; dataLength += plus / 2; p += plus / 2;
                    }
                    msvoice.Write(wav, 44, wav.Length - 44);
                    length += size; dataLength += size - 36;
                }
                msvoice.Position = 0;
                MemoryStream msmusic = new MemoryStream();
                msmusic.Write(music, 0, music.Length);
                msmusic.Position = 44;
                //merge;
                while (final.Length < msmusic.Length)
                    final.WriteByte((byte)(msvoice.ReadByte() - msmusic.ReadByte()));
                return final.ToArray();
            }
        }
    }

    internal static Byte[] VisualCaptcha(this String source)
    {
        try
        {
            Random r = new Random();
            Int32 w = 250, h = 75;
            String family = "Arial Rounded MT Bold";
            using (var bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb))
            {
                Int32 m = 0, nm = 0;
                Color tc;
                using (var g = Graphics.FromImage(bmp))
                {
                    g.TextRenderingHint = TextRenderingHint.AntiAlias;
                    g.SmoothingMode = SmoothingMode.HighQuality;
                    g.Clear(Color.White);
                    SizeF size;
                    m = r.Next() % 9 + 1;
                    nm = r.Next() % 3;
                    tc = Color.FromArgb(255, 255, 255);
                    size = g.MeasureString(source, new Font(family, h * 1.2f, FontStyle.Bold), new SizeF(w * 1F, h * 1F));
                    using (var brush = new LinearGradientBrush(new Rectangle(0, 0, w, h), Color.Black, Color.Black, 45, false))
                    {
                        ColorBlend blend = new ColorBlend(6);
                        for (var i = 0; i < 6; i++) { blend.Positions[i] = i * (1 / 5F); blend.Colors[i] = r.RandomColor(255, 64, 128); }
                        brush.InterpolationColors = blend;

                        for (int wave = 0; wave < 2; wave++)
                        {
                            Int32 min = (15 + wave * 20);
                            PointF[] pt = new PointF[] { new PointF(16f, (float)r.Next(min, min + 10)), new PointF(240f, (float)r.Next(min + 10, min + 20)) };
                            List<PointF> PointList = new List<PointF>();
                            float curDist = 0, distance = 0;
                            for (int i = 0; i < pt.Length - 1; i++)
                            {
                                PointF ptA = pt[i], ptB = pt[i + 1];
                                float deltaX = ptB.X - ptA.X, deltaY = ptB.Y - ptA.Y;
                                curDist = 0;
                                distance = (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
                                while (curDist < distance)
                                {
                                    curDist++;
                                    float offsetX = (float)((double)curDist / (double)distance * (double)deltaX);
                                    float offsetY = (float)((double)curDist / (double)distance * (double)deltaY);
                                    PointList.Add(new PointF(ptA.X + offsetX, ptA.Y + offsetY));
                                }
                            }
                            for (int i = 0; i < PointList.Count - 24; i = i + 24)
                            {
                                float x1 = PointList[i].X, y1 = PointList[i].Y, x2 = PointList[i + 24].X, y2 = PointList[i + 24].Y;
                                float angle = (float)((Math.Atan2(y2 - y1, x2 - x1) * 180 / 3.14159265));
                                g.TranslateTransform(x1, y1);
                                g.RotateTransform(angle);
                                Int32 pm = r.Next() % 2 + 1;
                                Point[] p1 = new Point[] { new Point(0, 0), new Point(3, -3 * pm), new Point(6, -4 * pm), new Point(9, -3 * pm), new Point(12, 0), new Point(15, 3 * pm), new Point(18, 4 * pm), new Point(21, 3 * pm), new Point(24, 0) };
                                using (var path = new GraphicsPath()) g.DrawLines(new Pen(brush, 2f), p1);
                                g.RotateTransform(-angle);
                                g.TranslateTransform(-x1, -y1);
                            }
                        }
                        using (var path = new GraphicsPath())
                        {
                            PointF[] points = new PointF[] { };
                            if (m == 1 || m == 2 || m == 3) // star trek inverse
                            {
                                path.AddString(source, new FontFamily(family), 1, h * 0.75F, new PointF((w - size.Width) / 2F, (h * 0.9F - size.Height) / 2F), StringFormat.GenericTypographic);
                                points = new PointF[] { new PointF(0, 0), new PointF(w, 0), new PointF(w * 0.2F, h), new PointF(w * 0.8F, h) };
                            }
                            else if (m == 4 || m == 5) // star trek
                            {
                                path.AddString(source, new FontFamily(family), 1, h * 0.75F, new PointF((w - size.Width) / 2F, (h * 1.2F - size.Height) / 2F + 2F), StringFormat.GenericTypographic);
                                points = new PointF[] { new PointF(w * 0.2F, 0), new PointF(w * 0.8F, 0), new PointF(0, h), new PointF(w, h) };
                            }
                            else if (m == 6 || m == 7) // grow from left
                            {
                                path.AddString(source, new FontFamily(family), 1, h * 0.75F, new PointF((w * 1.15F - size.Width) / 2F, (h - size.Height) / 2F), StringFormat.GenericTypographic);
                                points = new PointF[] { new PointF(0, h * 0.25F), new PointF(w, 0), new PointF(0, h * 0.75F), new PointF(w, h) };
                            }
                            else if (m == 8 || m == 9) // grow from right
                            {
                                path.AddString(source, new FontFamily(family), 1, h * 0.75F, new PointF((w * 0.85F - size.Width) / 2F, (h - size.Height) / 2F), StringFormat.GenericTypographic);
                                points = new PointF[] { new PointF(w * 0.1F, 0), new PointF(w * 0.9F, h * 0.25F), new PointF(w * 0.1F, h), new PointF(w * 0.9F, h * 0.75F) };
                            }
                            path.Warp(points, new RectangleF(0, 0, w, h));
                            g.FillPath(Brushes.White, path);
                            g.DrawPath(new Pen(brush, 2F), path);
                        }
                    }
                }
                using (var thumb = new Bitmap(128, 40, PixelFormat.Format32bppArgb))
                {
                    using (var g = Graphics.FromImage(thumb))
                    {
                        g.CompositingQuality = CompositingQuality.HighQuality;
                        g.SmoothingMode = SmoothingMode.HighQuality;
                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                        Rectangle tr = new Rectangle(0, 0, thumb.Width, thumb.Height);
                        g.DrawImage(bmp, tr);
                        g.DrawRectangle(new Pen(Brushes.White), new Rectangle(0, 0, 127, 39));
                    }
                    using (var ms = new MemoryStream())
                    {
                        ((Image)thumb).Save(ms, ImageFormat.Png);
                        return ms.ToArray();
                    }
                }
            }
        }
        catch { return null; }
    }

    private static Color RandomColor(this Random rnd, Int32 alpha, Int32 min, Int32 max)
    {
        return Color.FromArgb(alpha, rnd.Next(min, max), rnd.Next(min, max), rnd.Next(min, max));
    }
}

}

对于视觉和音频生成,代码均独立于验证码生成(源文本).WAVE格式的每个字母音频文件约为30KB,但每个音乐文件至少为8MB,这为我提供了广泛的随机起始位置(避免-频繁-重复的模式).您可以将代码编译为dll,也可以将其(修改后)放置在文件后面的代码中.

For both visual and audio generation the code is independent from the captcha generation (source text). Each letter audio file in WAVE format was about 30KB but each music file was at least 8MB, giving me a wide range for random starting positions (avoiding - frequently - repeated patterns). You can compile the code as a dll or place it (modified) in a code behind file.

这篇关于如何在ASP.Net中实现自定义音频Capcha的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆