├── .dockerignore ├── .gitignore ├── ConfigTool ├── .keep └── Release.zip ├── Images ├── .keep ├── ARITHMETIC_G.gif ├── ARITHMETIC_N.gif ├── ARITHMETIC_ZH_G.gif ├── ARITHMETIC_ZH_N.gif ├── CHINESE_G.gif ├── CHINESE_N.gif ├── Config.png ├── DEFAULT_G.gif ├── DEFAULT_N.gif ├── Font_Actionj.gif ├── Font_Epilog.gif ├── Font_Fresnel.gif ├── Font_Headache.gif ├── Font_Kaiti.gif ├── Font_Lexo.gif ├── Font_Prefix.gif ├── Font_Progbot.gif ├── Font_Ransom.gif ├── Font_Robot.gif ├── Font_Scandal.gif ├── NUMBER_G.gif ├── NUMBER_N.gif ├── NUMBER_ZH_CN.gif ├── NUMBER_ZH_CN_G.gif ├── NUMBER_ZH_HK_G.gif ├── NUMBER_ZH_HK_N.gif ├── WORD_G.gif ├── WORD_LOWER_G.gif ├── WORD_LOWER_N.gif ├── WORD_N.gif ├── WORD_NUMBER_LOWER_G.gif ├── WORD_NUMBER_LOWER_N.gif ├── WORD_NUMBER_UPPER_G.gif ├── WORD_NUMBER_UPPER_N.gif ├── WORD_UPPER_G.gif ├── WORD_UPPER_N.gif ├── bold.gif ├── font_demo.png └── normal.gif ├── LICENSE ├── Lazy.Captcha.Core ├── CaptchaBuilder.cs ├── CaptchaData.cs ├── CaptchaHelper.cs ├── CaptchaOptions.cs ├── CaptchaService.cs ├── CaptchaServiceBuilder.cs ├── CaptchaServiceCollectionExtensions.cs ├── CaptchaType.cs ├── DefaultCaptcha.cs ├── DefaultColors.cs ├── DefaultFontFamilys.cs ├── EvaluationEngine.cs ├── Generator │ ├── Code │ │ ├── Characters.cs │ │ ├── DefaultCaptchaCodeGenerator.cs │ │ ├── ExpressionEvaluator.cs │ │ └── ICaptchaCodeGenerator.cs │ ├── Extensions │ │ ├── ByteExtensions.cs │ │ └── CaptchaTypeExtensions.cs │ └── Image │ │ ├── DefaultCaptchaImageGenerator.cs │ │ ├── Gif │ │ ├── AnimatedGifEncoder.cs │ │ ├── LZWEncoder.cs │ │ └── NeuQuant.cs │ │ ├── ICaptchaImageGenerator.cs │ │ ├── ICaptchaImageGeneratorBuilder.cs │ │ ├── Models │ │ ├── BubbleGraphicDescription.cs │ │ ├── InterferenceLineGraphicDescription.cs │ │ └── TextGraphicDescription.cs │ │ └── Option │ │ ├── CaptchaImageGeneratorOption.cs │ │ └── DefaultCaptchaImageOptionBuilder.cs ├── ICaptcha.cs ├── ICaptchaBuilder.cs ├── Lazy.Captcha.Core.csproj ├── Storage │ ├── Caches │ │ ├── CacheEntity.cs │ │ └── MemoryCache.cs │ ├── DefaultStorage.cs │ ├── IStorage.cs │ └── MemeoryStorage.cs └── fonts │ ├── actionj.ttf │ ├── epilog.ttf │ ├── fresnel.ttf │ ├── headache.ttf │ ├── kaiti.ttf │ ├── lexo.ttf │ ├── prefix.ttf │ ├── progbot.ttf │ ├── ransom.ttf │ ├── robot.ttf │ └── scandal.ttf ├── Lazy.Captcha.xUnit ├── Demo.cs ├── EvaluationEngineTest.cs ├── GlobalUsing.cs ├── Lazy.Captcha.xUnit.csproj └── inputs │ └── fb.jpg ├── LazyCaptcha.sln ├── README.md ├── README_V1.md ├── Sample.MvcFramework ├── App_Start │ ├── BundleConfig.cs │ ├── FilterConfig.cs │ ├── RouteConfig.cs │ └── WebApiConfig.cs ├── Areas │ └── HelpPage │ │ ├── ApiDescriptionExtensions.cs │ │ ├── App_Start │ │ └── HelpPageConfig.cs │ │ ├── Controllers │ │ └── HelpController.cs │ │ ├── HelpPage.css │ │ ├── HelpPageAreaRegistration.cs │ │ ├── HelpPageConfigurationExtensions.cs │ │ ├── ModelDescriptions │ │ ├── CollectionModelDescription.cs │ │ ├── ComplexTypeModelDescription.cs │ │ ├── DictionaryModelDescription.cs │ │ ├── EnumTypeModelDescription.cs │ │ ├── EnumValueDescription.cs │ │ ├── IModelDocumentationProvider.cs │ │ ├── KeyValuePairModelDescription.cs │ │ ├── ModelDescription.cs │ │ ├── ModelDescriptionGenerator.cs │ │ ├── ModelNameAttribute.cs │ │ ├── ModelNameHelper.cs │ │ ├── ParameterAnnotation.cs │ │ ├── ParameterDescription.cs │ │ └── SimpleTypeModelDescription.cs │ │ ├── Models │ │ └── HelpPageApiModel.cs │ │ ├── SampleGeneration │ │ ├── HelpPageSampleGenerator.cs │ │ ├── HelpPageSampleKey.cs │ │ ├── ImageSample.cs │ │ ├── InvalidSample.cs │ │ ├── ObjectGenerator.cs │ │ ├── SampleDirection.cs │ │ └── TextSample.cs │ │ ├── Views │ │ ├── Help │ │ │ ├── Api.cshtml │ │ │ ├── DisplayTemplates │ │ │ │ ├── ApiGroup.cshtml │ │ │ │ ├── CollectionModelDescription.cshtml │ │ │ │ ├── ComplexTypeModelDescription.cshtml │ │ │ │ ├── DictionaryModelDescription.cshtml │ │ │ │ ├── EnumTypeModelDescription.cshtml │ │ │ │ ├── HelpPageApiModel.cshtml │ │ │ │ ├── ImageSample.cshtml │ │ │ │ ├── InvalidSample.cshtml │ │ │ │ ├── KeyValuePairModelDescription.cshtml │ │ │ │ ├── ModelDescriptionLink.cshtml │ │ │ │ ├── Parameters.cshtml │ │ │ │ ├── Samples.cshtml │ │ │ │ ├── SimpleTypeModelDescription.cshtml │ │ │ │ └── TextSample.cshtml │ │ │ ├── Index.cshtml │ │ │ └── ResourceModel.cshtml │ │ ├── Shared │ │ │ └── _Layout.cshtml │ │ ├── Web.config │ │ └── _ViewStart.cshtml │ │ └── XmlDocumentationProvider.cs ├── Content │ ├── Site.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.min.css.map │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ └── bootstrap.min.css.map ├── Controllers │ ├── CaptchaController.cs │ └── HomeController.cs ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Sample.MvcFramework.csproj ├── Scripts │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-3.4.1.intellisense.js │ ├── jquery-3.4.1.js │ ├── jquery-3.4.1.min.js │ ├── jquery-3.4.1.min.map │ ├── jquery-3.4.1.slim.js │ ├── jquery-3.4.1.slim.min.js │ ├── jquery-3.4.1.slim.min.map │ └── modernizr-2.8.3.js ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 └── packages.config ├── Sample.NetCore ├── Controllers │ └── CaptchaController.cs ├── CustomFonts │ ├── BunnyeggsRegular-8M5aZ.ttf │ ├── KgHappy-wWZZ.ttf │ └── WhoaSaucePersonalUseBold-mLmV5.ttf ├── Dockerfile ├── Program.cs ├── Properties │ └── launchSettings.json ├── RandomCaptcha.cs ├── ResourceFontFamilysFinder.cs ├── Sample.NetCore.csproj ├── appsettings.Development.json ├── appsettings.json └── wwwroot │ ├── index.css │ ├── index.html │ ├── index.js │ ├── loading.gif │ ├── loading.png │ └── vue.min.js ├── Sample.Winfrom ├── App.config ├── Helpers │ ├── UIHelper.cs │ └── UnitHelper.cs ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Models │ ├── CaptchaImageGeneratorOptionJsonModel.cs │ ├── CaptchaOptionsJsonModel.cs │ ├── CaptchaOptionsWrapper.cs │ ├── CaptchaTypeOption.cs │ ├── FontFamilyOption.cs │ └── Option.cs ├── OptionProviders │ ├── CaptchaTypeOptionProvider.cs │ └── FontFamilyOptionProvider.cs ├── PerformanceTest.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── DataSources │ │ ├── Sample.Winfrom.Models.CaptchaTypeOption.datasource │ │ └── Sample.Winfrom.Models.FontFamilyOption.datasource │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Sample.Winfrom.csproj └── templates │ ├── highlight │ ├── jquery.highlight.css │ ├── jquery.highlight.js │ └── jquery.min.js │ ├── scripts │ └── demo.js │ └── tpl.html └── 字体裁剪 ├── kaiti.ttf ├── kaiti_output.ttf ├── words.txt └── 裁剪命令.txt /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /ConfigTool/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/ConfigTool/.keep -------------------------------------------------------------------------------- /ConfigTool/Release.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/ConfigTool/Release.zip -------------------------------------------------------------------------------- /Images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/.keep -------------------------------------------------------------------------------- /Images/ARITHMETIC_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/ARITHMETIC_G.gif -------------------------------------------------------------------------------- /Images/ARITHMETIC_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/ARITHMETIC_N.gif -------------------------------------------------------------------------------- /Images/ARITHMETIC_ZH_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/ARITHMETIC_ZH_G.gif -------------------------------------------------------------------------------- /Images/ARITHMETIC_ZH_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/ARITHMETIC_ZH_N.gif -------------------------------------------------------------------------------- /Images/CHINESE_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/CHINESE_G.gif -------------------------------------------------------------------------------- /Images/CHINESE_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/CHINESE_N.gif -------------------------------------------------------------------------------- /Images/Config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Config.png -------------------------------------------------------------------------------- /Images/DEFAULT_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/DEFAULT_G.gif -------------------------------------------------------------------------------- /Images/DEFAULT_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/DEFAULT_N.gif -------------------------------------------------------------------------------- /Images/Font_Actionj.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Actionj.gif -------------------------------------------------------------------------------- /Images/Font_Epilog.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Epilog.gif -------------------------------------------------------------------------------- /Images/Font_Fresnel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Fresnel.gif -------------------------------------------------------------------------------- /Images/Font_Headache.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Headache.gif -------------------------------------------------------------------------------- /Images/Font_Kaiti.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Kaiti.gif -------------------------------------------------------------------------------- /Images/Font_Lexo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Lexo.gif -------------------------------------------------------------------------------- /Images/Font_Prefix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Prefix.gif -------------------------------------------------------------------------------- /Images/Font_Progbot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Progbot.gif -------------------------------------------------------------------------------- /Images/Font_Ransom.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Ransom.gif -------------------------------------------------------------------------------- /Images/Font_Robot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Robot.gif -------------------------------------------------------------------------------- /Images/Font_Scandal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/Font_Scandal.gif -------------------------------------------------------------------------------- /Images/NUMBER_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_G.gif -------------------------------------------------------------------------------- /Images/NUMBER_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_N.gif -------------------------------------------------------------------------------- /Images/NUMBER_ZH_CN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_ZH_CN.gif -------------------------------------------------------------------------------- /Images/NUMBER_ZH_CN_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_ZH_CN_G.gif -------------------------------------------------------------------------------- /Images/NUMBER_ZH_HK_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_ZH_HK_G.gif -------------------------------------------------------------------------------- /Images/NUMBER_ZH_HK_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/NUMBER_ZH_HK_N.gif -------------------------------------------------------------------------------- /Images/WORD_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_G.gif -------------------------------------------------------------------------------- /Images/WORD_LOWER_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_LOWER_G.gif -------------------------------------------------------------------------------- /Images/WORD_LOWER_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_LOWER_N.gif -------------------------------------------------------------------------------- /Images/WORD_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_N.gif -------------------------------------------------------------------------------- /Images/WORD_NUMBER_LOWER_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_NUMBER_LOWER_G.gif -------------------------------------------------------------------------------- /Images/WORD_NUMBER_LOWER_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_NUMBER_LOWER_N.gif -------------------------------------------------------------------------------- /Images/WORD_NUMBER_UPPER_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_NUMBER_UPPER_G.gif -------------------------------------------------------------------------------- /Images/WORD_NUMBER_UPPER_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_NUMBER_UPPER_N.gif -------------------------------------------------------------------------------- /Images/WORD_UPPER_G.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_UPPER_G.gif -------------------------------------------------------------------------------- /Images/WORD_UPPER_N.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/WORD_UPPER_N.gif -------------------------------------------------------------------------------- /Images/bold.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/bold.gif -------------------------------------------------------------------------------- /Images/font_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/font_demo.png -------------------------------------------------------------------------------- /Images/normal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Images/normal.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 pojianbing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core 9 | { 10 | internal class CaptchaBuilder : ICaptchaBuilder 11 | { 12 | public CaptchaBuilder(IServiceCollection services) 13 | { 14 | Services = services; 15 | } 16 | public IServiceCollection Services { get; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Lazy.Captcha.Core 8 | { 9 | public class CaptchaData 10 | { 11 | public CaptchaData(string id, string code, byte[] bytes) 12 | { 13 | Id = id; 14 | Code = code; 15 | Bytes = bytes; 16 | } 17 | 18 | public string Id { get; set; } 19 | public string Code { get; set; } 20 | public byte[] Bytes { get; set; } 21 | public string Base64 => Convert.ToBase64String(Bytes); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaHelper.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator.Code; 2 | using Lazy.Captcha.Core.Generator.Image; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Lazy.Captcha.Core 8 | { 9 | /// 10 | /// 验证码帮助类 11 | /// 12 | public class CaptchaHelper 13 | { 14 | private static CaptchaService CaptchaService; 15 | 16 | public static void Initialization(CaptchaService captchaService) 17 | { 18 | CaptchaService = captchaService; 19 | } 20 | 21 | /// 22 | /// 生成验证码 23 | /// 24 | /// 验证码id 25 | /// 缓存时间,未设定则使用配置时间 26 | /// 27 | public static CaptchaData Generate(string captchaId, int? expirySeconds = null) 28 | { 29 | return CaptchaService.Generate(captchaId, expirySeconds); 30 | } 31 | 32 | /// 33 | /// 校验 34 | /// 35 | /// 验证码id 36 | /// 用户输入的验证码 37 | /// 校验成功时是否移除缓存(用于多次验证) 38 | /// 39 | public static bool Validate(string captchaId, string code, bool removeIfSuccess = true) 40 | { 41 | return CaptchaService.Validate(captchaId, code, removeIfSuccess); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaOptions.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Lazy.Captcha.Core.Generator.Code; 3 | using Lazy.Captcha.Core.Generator.Image; 4 | using Lazy.Captcha.Core.Generator.Image.Option; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Lazy.Captcha.Core 12 | { 13 | public class CaptchaOptions 14 | { 15 | private const int DEFAULT_CODE_LENGTH = 4; 16 | private CaptchaType _captchaType = CaptchaType.DEFAULT; 17 | 18 | /// 19 | /// 验证码类型 20 | /// 21 | public CaptchaType CaptchaType 22 | { 23 | get { return _captchaType; } 24 | set 25 | { 26 | if (value.IsArithmetic()) 27 | { 28 | if (this.CodeLength == DEFAULT_CODE_LENGTH) 29 | { 30 | this.CodeLength = 2; 31 | } 32 | } 33 | 34 | if (value.ContainsChinese()) 35 | { 36 | this.ImageOption.FontFamily = DefaultFontFamilys.Instance.Kaiti; 37 | } 38 | 39 | _captchaType = value; 40 | } 41 | } 42 | 43 | /// 44 | /// 验证码长度 当CaptchaType为ARITHMETIC, ARITHMETIC_ZH时, 长度代表乘数个数 45 | /// 46 | public int CodeLength { get; set; } = DEFAULT_CODE_LENGTH; 47 | 48 | /// 49 | /// 过期时长 50 | /// 51 | public int ExpirySeconds { get; set; } = 60; 52 | 53 | /// 54 | /// code比较是否忽略大小写 55 | /// 56 | public bool IgnoreCase { get; set; } = true; 57 | 58 | /// 59 | /// 存储键前缀 60 | /// 61 | public string StoreageKeyPrefix { get; set; } 62 | 63 | /// 64 | /// 图片选项 65 | /// 66 | public CaptchaImageGeneratorOption ImageOption { get; set; } = new CaptchaImageGeneratorOption(); 67 | } 68 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaService.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator.Code; 2 | using Lazy.Captcha.Core.Generator.Image; 3 | using Lazy.Captcha.Core.Storage; 4 | using Microsoft.Extensions.Caching.Memory; 5 | using Microsoft.Extensions.Options; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace Lazy.Captcha.Core 11 | { 12 | public class CaptchaService 13 | { 14 | private CaptchaOptions CaptchaOptions; 15 | private IStorage Storage; 16 | 17 | /// 18 | /// 构造函数 19 | /// 20 | /// 21 | public CaptchaService(CaptchaOptions captchaOptions, IStorage storage) 22 | { 23 | CaptchaOptions = captchaOptions; 24 | Storage = storage; 25 | } 26 | 27 | /// 28 | /// 生成验证码 29 | /// 30 | /// 验证码id 31 | /// 缓存时间,未设定则使用配置时间 32 | /// 33 | public CaptchaData Generate(string captchaId, int? expirySeconds = null) 34 | { 35 | var _captchaCodeGenerator = new DefaultCaptchaCodeGenerator(CaptchaOptions.CaptchaType); 36 | var _captchaImageGenerator = new DefaultCaptchaImageGenerator(); 37 | 38 | var (renderText, code) = _captchaCodeGenerator.Generate(CaptchaOptions.CodeLength); 39 | var image = _captchaImageGenerator.Generate(renderText, CaptchaOptions.ImageOption); 40 | expirySeconds = expirySeconds.HasValue ? expirySeconds.Value : CaptchaOptions.ExpirySeconds; 41 | Storage.Set(captchaId, code, DateTime.Now.AddSeconds(expirySeconds.Value).ToUniversalTime()); 42 | 43 | return new CaptchaData(captchaId, code, image); 44 | } 45 | 46 | /// 47 | /// 校验 48 | /// 49 | /// 验证码id 50 | /// 用户输入的验证码 51 | /// 校验成功时是否移除缓存(用于多次验证) 52 | /// 53 | public bool Validate(string captchaId, string code, bool removeIfSuccess = true) 54 | { 55 | var val = Storage.Get(captchaId); 56 | var comparisonType = CaptchaOptions.IgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture; 57 | var success = !string.IsNullOrWhiteSpace(code) && 58 | !string.IsNullOrWhiteSpace(val) && 59 | string.Equals(val, code, comparisonType); 60 | 61 | if (!success || (success && removeIfSuccess)) 62 | { 63 | Storage.Remove(captchaId); 64 | } 65 | 66 | return success; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Linq; 6 | using Lazy.Captcha.Core; 7 | using Lazy.Captcha.Core.Storage; 8 | using Lazy.Captcha.Core.Storeage; 9 | using Microsoft.Extensions.Configuration; 10 | using Microsoft.Extensions.DependencyInjection.Extensions; 11 | using SkiaSharp; 12 | 13 | namespace Microsoft.Extensions.DependencyInjection 14 | { 15 | public static class CaptchaServiceCollectionExtensions 16 | { 17 | public static IServiceCollection AddCaptcha(this IServiceCollection services) 18 | { 19 | return AddCaptcha(services, null); 20 | } 21 | 22 | public static IServiceCollection AddCaptcha(this IServiceCollection services, Action optionsAction) 23 | { 24 | var factory = services.FirstOrDefault(p => p.ServiceType == typeof(IConfiguration)); 25 | IConfiguration configuration = (IConfiguration)factory.ImplementationFactory(null); 26 | return AddCaptcha(services, configuration, optionsAction); 27 | } 28 | 29 | public static IServiceCollection AddCaptcha(this IServiceCollection services, IConfiguration configuration, Action optionsAction = null) 30 | { 31 | services.Configure(configuration?.GetSection("CaptchaOptions")); 32 | services.PostConfigure(options => 33 | { 34 | var fontFamily = configuration?.GetSection("CaptchaOptions:ImageOption:FontFamily")?.Value; 35 | if (!string.IsNullOrWhiteSpace(fontFamily)) 36 | { 37 | options.ImageOption.FontFamily = DefaultFontFamilys.Instance.GetFontFamily(fontFamily); 38 | } 39 | 40 | var backgroundColor = configuration?.GetSection("CaptchaOptions:ImageOption:BackgroundColor")?.Value; 41 | if (!string.IsNullOrWhiteSpace(backgroundColor)) 42 | { 43 | if (SKColor.TryParse(backgroundColor, out var color)) 44 | { 45 | options.ImageOption.BackgroundColor = color; 46 | } 47 | } 48 | 49 | var foregroudColors = configuration?.GetSection("CaptchaOptions:ImageOption:ForegroundColors")?.Value; 50 | if (!string.IsNullOrWhiteSpace(foregroudColors)) 51 | { 52 | var colors = foregroudColors.Split(',').ToList().Where(e => !string.IsNullOrEmpty(e)); 53 | foreach (var item in colors) 54 | { 55 | if (SKColor.TryParse(item, out var color)) 56 | { 57 | if (options.ImageOption.ForegroundColors == null) 58 | { 59 | options.ImageOption.ForegroundColors = new List(); 60 | } 61 | options.ImageOption.ForegroundColors.Add(color); 62 | } 63 | } 64 | } 65 | if (options.ImageOption.ForegroundColors == null || options.ImageOption.ForegroundColors.Count() == 0) 66 | { 67 | options.ImageOption.ForegroundColors = DefaultColors.Instance.Colors; 68 | } 69 | }); 70 | if (optionsAction != null) services.PostConfigure(optionsAction); 71 | 72 | services.AddScoped(); 73 | services.AddScoped(); 74 | services.AddDistributedMemoryCache(); 75 | 76 | return services; 77 | } 78 | 79 | [Obsolete("请直接使用 AddCaptcha 方法,已更改为默认注册内存缓存", false)] 80 | public static IServiceCollection AddMemoryCacheCaptcha(this IServiceCollection services, IConfiguration configuration, Action optionsAction = null) 81 | { 82 | return services.AddCaptcha(configuration, optionsAction); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/CaptchaType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Lazy.Captcha.Core.Generator 8 | { 9 | public enum CaptchaType 10 | { 11 | /// 12 | /// 默认(英文字符大小写,数字混合) 13 | /// 14 | DEFAULT=0, 15 | 16 | /// 17 | /// 中文 18 | /// 19 | CHINESE=1, 20 | 21 | /// 22 | /// 数字 23 | /// 24 | NUMBER=2, 25 | 26 | /// 27 | /// 中文数字小写 28 | /// 29 | NUMBER_ZH_CN=3, 30 | 31 | /// 32 | /// 中文数字大写 33 | /// 34 | NUMBER_ZH_HK=4, 35 | 36 | /// 37 | /// 英文字符大小写混合 38 | /// 39 | WORD=5, 40 | 41 | /// 42 | /// 英文字符小写 43 | /// 44 | WORD_LOWER=6, 45 | 46 | /// 47 | /// 英文字符大写 48 | /// 49 | WORD_UPPER=7, 50 | 51 | /// 52 | /// 英文小写,数字混合 53 | /// 54 | WORD_NUMBER_LOWER=8, 55 | 56 | /// 57 | /// 英文大写,数字混合 58 | /// 59 | WORD_NUMBER_UPPER=9, 60 | 61 | /// 62 | /// 数字计算 63 | /// 64 | ARITHMETIC=10, 65 | 66 | /// 67 | /// 数字计算,中文 68 | /// 69 | ARITHMETIC_ZH=11 70 | } 71 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/DefaultCaptcha.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/DefaultCaptcha.cs -------------------------------------------------------------------------------- /Lazy.Captcha.Core/DefaultColors.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core 9 | { 10 | public class DefaultColors 11 | { 12 | public static DefaultColors Instance = new DefaultColors(); 13 | 14 | public List Colors = new List 15 | { 16 | SKColor.Parse("#0087ff"), 17 | SKColor.Parse("#339933"), 18 | SKColor.Parse("#ff6666"), 19 | SKColor.Parse("#ff9900"), 20 | SKColor.Parse("#996600"), 21 | SKColor.Parse("#996699"), 22 | SKColor.Parse("#339999"), 23 | SKColor.Parse("#6666ff"), 24 | SKColor.Parse("#0066cc"), 25 | SKColor.Parse("#cc3333"), 26 | SKColor.Parse("#0099cc"), 27 | SKColor.Parse("#003366"), 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/DefaultFontFamilys.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using SkiaSharp; 6 | 7 | namespace Lazy.Captcha.Core 8 | { 9 | public class DefaultFontFamilys 10 | { 11 | public static DefaultFontFamilys Instance = new DefaultFontFamilys(); 12 | private static List _fontFamilies = null; 13 | private static Dictionary FamilyNameMapper = new Dictionary 14 | { 15 | { "actionj", "Action Jackson" }, 16 | { "epilog", "Epilog" }, 17 | { "fresnel", "Fresnel" }, 18 | { "headache", "Tom's Headache" }, 19 | { "lexo", "Lexographer" }, 20 | { "prefix", "Prefix" }, 21 | { "progbot", "PROG.BOT" }, 22 | { "ransom", "Ransom" }, 23 | { "robot", "Robot Teacher" }, 24 | { "scandal", "Potassium Scandal" }, 25 | { "kaiti", "FZKai-Z03" } 26 | }; 27 | 28 | static DefaultFontFamilys() 29 | { 30 | if (_fontFamilies == null) 31 | { 32 | var assembly = Assembly.GetExecutingAssembly(); 33 | var names = assembly.GetManifestResourceNames(); 34 | _fontFamilies = new List(); 35 | 36 | if (names?.Length > 0 == true) 37 | { 38 | foreach (var name in names) 39 | { 40 | _fontFamilies.Add(SKTypeface.FromStream(assembly.GetManifestResourceStream(name))); 41 | } 42 | } 43 | else 44 | { 45 | throw new Exception($"绘制验证码字体文件加载失败"); 46 | } 47 | } 48 | } 49 | 50 | /// 51 | /// 获取字体 52 | /// 53 | public SKTypeface GetFontFamily(string name) 54 | { 55 | var realName = "Epilog"; 56 | var normalizeName = name.ToLowerInvariant(); 57 | if (FamilyNameMapper.ContainsKey(normalizeName)) 58 | { 59 | // 默认字体 60 | realName = FamilyNameMapper[normalizeName]; 61 | } 62 | // 改用StartsWith, 某些环境下: Prefix取到的值为Prefix Endangered, Ransom取到的值为Ransom CutUpLetters 63 | return _fontFamilies.First(f => f.FamilyName.StartsWith(realName)); 64 | } 65 | 66 | /// 67 | /// ACTIONJ 68 | /// 69 | public SKTypeface Actionj 70 | { 71 | get 72 | { 73 | return GetFontFamily("Actionj"); 74 | } 75 | } 76 | 77 | /// 78 | /// Epilog 79 | /// 80 | public SKTypeface Epilog 81 | { 82 | get 83 | { 84 | return GetFontFamily("Epilog"); 85 | } 86 | } 87 | 88 | /// 89 | /// Fresnel 90 | /// 91 | public SKTypeface Fresnel 92 | { 93 | get 94 | { 95 | return GetFontFamily("Fresnel"); 96 | } 97 | } 98 | 99 | /// 100 | /// headache 101 | /// 102 | public SKTypeface Headache 103 | { 104 | get 105 | { 106 | return GetFontFamily("Headache"); 107 | } 108 | } 109 | 110 | /// 111 | /// Lexo 112 | /// 113 | public SKTypeface Lexo 114 | { 115 | get 116 | { 117 | return GetFontFamily("Lexo"); 118 | } 119 | } 120 | 121 | /// 122 | /// Prefix 123 | /// 124 | public SKTypeface Prefix 125 | { 126 | get 127 | { 128 | return GetFontFamily("Prefix"); 129 | } 130 | } 131 | 132 | /// 133 | /// Progbot 134 | /// 135 | public SKTypeface Progbot 136 | { 137 | get 138 | { 139 | return GetFontFamily("Progbot"); 140 | } 141 | } 142 | 143 | /// 144 | /// Ransom 145 | /// 146 | public SKTypeface Ransom 147 | { 148 | get 149 | { 150 | return GetFontFamily("Ransom"); 151 | } 152 | } 153 | 154 | /// 155 | /// Robot 156 | /// 157 | public SKTypeface Robot 158 | { 159 | get 160 | { 161 | return GetFontFamily("Robot"); 162 | } 163 | } 164 | 165 | /// 166 | /// Scandal 167 | /// 168 | public SKTypeface Scandal 169 | { 170 | get 171 | { 172 | return GetFontFamily("Scandal"); 173 | } 174 | } 175 | 176 | /// 177 | /// 楷体 178 | /// 179 | public SKTypeface Kaiti 180 | { 181 | get 182 | { 183 | return GetFontFamily("Kaiti"); 184 | } 185 | } 186 | } 187 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/EvaluationEngine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Lazy.Captcha.Core 8 | { 9 | public class EvaluationEngine 10 | { 11 | /// 12 | /// 操作符级别映射 13 | /// 14 | private Dictionary OperatorLevelMaps = new Dictionary 15 | { 16 | { '(', 1 }, 17 | { ')', 1 }, 18 | { '+', 2 }, 19 | { '-', 2 }, 20 | { 'x', 3 }, 21 | { '*', 3 }, 22 | { '÷', 3 }, 23 | { '/', 3 }, 24 | { '^', 4 }, 25 | { '√', 4 }, 26 | { '%', 4 } 27 | }; 28 | 29 | /// 30 | /// 是否数字 31 | /// 32 | /// 33 | /// 34 | private bool IsNumber(string str) 35 | { 36 | return double.TryParse(str, out var _); 37 | } 38 | 39 | /// 40 | /// 是否数字 41 | /// 42 | /// 43 | /// 44 | private bool IsNumber(char c) 45 | { 46 | var charCode = (int)c; 47 | return charCode >= 48 && charCode <= 57; 48 | } 49 | 50 | /// 51 | /// 转为逆波兰 52 | /// 53 | /// 54 | /// 55 | private List ConvertToRPN(string exp) 56 | { 57 | var output = new List(); 58 | var index = 0; 59 | var operatorStack = new Stack(); 60 | 61 | while (index < exp.Count()) 62 | { 63 | var currentIndex = index; 64 | var prevIndex = index - 1; 65 | var prev = prevIndex < 0 ? "" : exp[prevIndex] + ""; 66 | var current = exp[currentIndex]; 67 | var isNegativeSign = current == '-' && currentIndex == 0; 68 | 69 | if (OperatorLevelMaps.ContainsKey(current) && !isNegativeSign) 70 | { 71 | if (current == '(') 72 | { 73 | operatorStack.Push(current); 74 | } 75 | else if (current == ')') 76 | { 77 | while (operatorStack.Peek() != '(') 78 | { 79 | output.Add(operatorStack.Pop().ToString()); 80 | } 81 | operatorStack.Pop(); // )弹出 82 | } 83 | else 84 | { 85 | while (operatorStack.Count != 0 && operatorStack.Peek() != '(' && OperatorLevelMaps[current] <= OperatorLevelMaps[operatorStack.Peek()]) 86 | { 87 | output.Add(operatorStack.Pop().ToString()); 88 | } 89 | operatorStack.Push(current); 90 | } 91 | 92 | index++; 93 | } 94 | else 95 | { 96 | if (isNegativeSign) index++; 97 | // 扫描连续数字: -1.23 98 | while (index < exp.Count() && (IsNumber(exp[index]) || exp[index] == '.') && exp[index] != ' ') 99 | { 100 | index++; 101 | } 102 | output.Add(exp.Substring(currentIndex, index - currentIndex)); 103 | } 104 | } 105 | 106 | while (operatorStack.Count != 0) output.Add(operatorStack.Pop().ToString()); 107 | 108 | return output; 109 | } 110 | 111 | /// 112 | /// 根据运算符计算 113 | /// 114 | /// 115 | /// 116 | /// 117 | /// 118 | /// 119 | private double Cacl(double v1, double v2, string op) 120 | { 121 | switch (op) 122 | { 123 | case "+": 124 | return v1 + v2; 125 | case "-": 126 | return v1 - v2; 127 | case "x": 128 | case "*": 129 | return v1 * v2; 130 | case "÷": 131 | case "/": 132 | return v1 / v2; 133 | case "^": 134 | return Math.Pow(v1, v2); 135 | } 136 | 137 | throw new Exception("未知操作符"); 138 | } 139 | 140 | /// 141 | /// 根据逆波兰计算 142 | /// 143 | /// 144 | /// 145 | private double CalcRPN(List rpn) 146 | { 147 | var stack = new Stack(); 148 | 149 | for (var i = 0; i < rpn.Count; i++) 150 | { 151 | var item = rpn[i]; 152 | 153 | if (IsNumber(item)) 154 | { 155 | stack.Push(item); 156 | } 157 | else 158 | { 159 | if (item == "√") 160 | { 161 | var v = stack.Pop(); 162 | stack.Push((Math.Sqrt((double)v)).ToString()); 163 | } 164 | else if (item == "%") 165 | { 166 | stack.Push((PopDouble() / 100.0d).ToString()); 167 | } 168 | else 169 | { 170 | var v1 = PopDouble(); 171 | var v2 = PopDouble(); 172 | var v = Cacl(v2, v1, item); 173 | stack.Push(v.ToString()); 174 | } 175 | } 176 | 177 | double PopDouble() 178 | { 179 | var v = (string)stack.Pop(); 180 | return double.Parse(v); 181 | } 182 | } 183 | 184 | return double.Parse((string)stack.Pop()); 185 | } 186 | 187 | /// 188 | /// 计算 189 | /// 190 | /// 191 | /// 192 | public double Evaluate(string exp) 193 | { 194 | exp = exp.Replace(" ", ""); 195 | var rpn = ConvertToRPN(exp); 196 | return CalcRPN(rpn); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Code/Characters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Lazy.Captcha.Core.Generator.Code 8 | { 9 | public class Characters 10 | { 11 | /// 12 | /// 小写英文字符 13 | /// 14 | public static List WORD_LOWER = new List { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; 15 | 16 | /// 17 | /// 大写英文字符 18 | /// 19 | public static List WORD_UPPER = new List { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; 20 | 21 | /// 22 | /// 中文 23 | /// 24 | public static List CHINESE = new List { '的', '一', '国', '在', '人', '了', '有', '中', '是', '年', '和', '大', '业', '不', '为', '发', '会', '工', '经', '上', '地', '市', '要', '个', '产', '这', '出', '行', '作', '生', '家', '以', '成', '到', '日', '民', '来', '我', '部', '对', '进', '多', '全', '建', '他', '公', '开', '们', '场', '展', '时', '理', '新', '方', '主', '企', '资', '实', '学', '报', '制', '政', '济', '用', '同', '于', '法', '高', '长', '现', '本', '月', '定', '化', '加', '动', '合', '品', '重', '关', '机', '分', '力', '自', '外', '者', '区', '能', '设', '后', '就', '等', '体', '下', '万', '元', '社', '过', '前', '面', '农', '也', '得', '与', '说', '之', '员', '而', '务', '利', '电', '文', '事', '可', '种', '总', '改', '三', '各', '好', '金', '第', '司', '其', '从', '平', '代', '当', '天', '水', '省', '提', '商', '十', '管', '内', '小', '技', '位', '目', '起', '海', '所', '立', '已', '通', '入', '量', '子', '问', '度', '北', '保', '心', '还', '科', '委', '都', '术', '使', '明', '着', '次', '将', '增', '基', '名', '向', '门', '应', '里', '美', '由', '规', '今', '题', '记', '点', '计', '去', '强', '两', '些', '表', '系', '办', '教', '正', '条', '最', '达', '特', '革', '收', '二', '期', '并', '程', '厂', '如', '道', '际', '及', '西', '口', '京', '华', '任', '调', '性', '导', '组', '东', '路', '活', '广', '意', '比', '投', '决', '交', '统', '党', '南', '安', '此', '领', '结', '营', '项', '情', '解', '议', '义', '山', '先', '车', '然', '价', '放', '世', '间', '因', '共', '院', '步', '物', '界', '集', '把', '持', '无', '但', '城', '相', '书', '村', '求', '治', '取', '原', '处', '府', '研', '质', '信', '四', '运', '县', '军', '件', '育', '局', '干', '队', '团', '又', '造', '形', '级', '标', '联', '专', '少', '费', '效', '据', '手', '施', '权', '江', '近', '深', '更', '认', '果', '格', '几', '看', '没', '职', '服', '台', '式', '益', '想', '数', '单', '样', '只', '被', '亿', '老', '受', '优', '常', '销', '志', '战', '流', '很', '接', '乡', '头', '给', '至', '难', '观', '指', '创', '证', '织', '论', '别', '五', '协', '变', '风', '批', '见', '究', '支', '那', '查', '张', '精', '每', '林', '转', '划', '准', '做', '需', '传', '争', '税', '构', '具', '百', '或', '才', '积', '势', '举', '必', '型', '易', '视', '快', '李', '参', '回', '引', '镇', '首', '推', '思', '完', '消', '值', '该', '走', '装', '众', '责', '备', '州', '供', '包', '副', '极', '整', '确', '知', '贸', '己', '环', '话', '反', '身', '选', '亚', '么', '带', '采', '王', '策', '真', '女', '谈', '严', '斯', '况', '色', '打', '德', '告', '仅', '它', '气', '料', '神', '率', '识', '劳', '境', '源', '青', '护', '列', '兴', '许', '户', '马', '港', '则', '节', '款', '拉', '直', '案', '股', '光', '较', '河', '花', '根', '布', '线', '土', '克', '再', '群', '医', '清', '速', '律', '她', '族', '历', '非', '感', '占', '续', '师', '何', '影', '功', '负', '验', '望', '财', '类', '货', '约', '艺', '售', '连', '纪', '按', '讯', '史', '示', '象', '养', '获', '石', '食', '抓', '富', '模', '始', '住', '赛', '客', '越', '闻', '央', '席', '坚' }; 25 | 26 | /// 27 | /// 数字 28 | /// 29 | public static List NUMBER = new List { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; 30 | 31 | /// 32 | /// 中文数字小写 33 | /// 34 | public static List NUMBER_ZH_CN = new List { '零', '一', '二', '三', '四', '五', '六', '七', '八', '九' }; 35 | 36 | /// 37 | /// 中文数字大写 38 | /// 39 | public static List NUMBER_ZH_HK = new List { '零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' }; 40 | 41 | /// 42 | /// 英文字母大小写,数字混合 43 | /// 44 | public static List DEFAULT 45 | { 46 | get 47 | { 48 | var letters = new List(); 49 | letters.AddRange(NUMBER); 50 | letters.AddRange(WORD_LOWER); 51 | letters.AddRange(WORD_UPPER); 52 | return letters; 53 | } 54 | } 55 | 56 | /// 57 | /// 英文字母大小写混合 58 | /// 59 | public static List WORD 60 | { 61 | get 62 | { 63 | var letters = new List(); 64 | letters.AddRange(WORD_LOWER); 65 | letters.AddRange(WORD_UPPER); 66 | return letters; 67 | } 68 | } 69 | 70 | /// 71 | /// 英文字母小写,数字混合 72 | /// 73 | public static List WORD_NUMBER_LOWER 74 | { 75 | get 76 | { 77 | var letters = new List(); 78 | letters.AddRange(NUMBER); 79 | letters.AddRange(WORD_LOWER); 80 | return letters; 81 | } 82 | } 83 | 84 | /// 85 | /// 英文字母大写,数字混合 86 | /// 87 | public static List WORD_NUMBER_UPPER 88 | { 89 | get 90 | { 91 | var letters = new List(); 92 | letters.AddRange(NUMBER); 93 | letters.AddRange(WORD_UPPER); 94 | return letters; 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Code/ICaptchaCodeGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Lazy.Captcha.Core.Generator.Code 8 | { 9 | public interface ICaptchaCodeGenerator 10 | { 11 | (string renderText, string code) Generate(int length); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Extensions/ByteExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core 9 | { 10 | public static class ByteExtensions 11 | { 12 | public static Stream ToStream(this byte[] bytes) 13 | { 14 | return new MemoryStream(bytes); 15 | } 16 | 17 | public static string ToBase64(this byte[] bytes) 18 | { 19 | return Convert.ToBase64String(bytes); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Extensions/CaptchaTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator.Code; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core.Generator 9 | { 10 | public static class CaptchaTypeExtensions 11 | { 12 | public static bool ContainsChinese(this CaptchaType captchaType) 13 | { 14 | return captchaType == CaptchaType.ARITHMETIC_ZH || 15 | captchaType == CaptchaType.NUMBER_ZH_CN || 16 | captchaType == CaptchaType.NUMBER_ZH_HK || 17 | captchaType == CaptchaType.CHINESE; 18 | } 19 | 20 | public static bool IsArithmetic(this CaptchaType captchaType) 21 | { 22 | return captchaType == CaptchaType.ARITHMETIC || captchaType == CaptchaType.ARITHMETIC_ZH; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/ICaptchaImageGenerator.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator.Image.Option; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core.Generator.Image 9 | { 10 | /// 11 | /// 验证码生成器 12 | /// 13 | public interface ICaptchaImageGenerator 14 | { 15 | byte[] Generate(string text, CaptchaImageGeneratorOption option); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/ICaptchaImageGeneratorBuilder.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Lazy.Captcha.Core.Generator.Image.Option; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Lazy.Captcha.Core.Generator.Image 10 | { 11 | public interface ICaptchaImageOptionBuilder 12 | { 13 | CaptchaImageGeneratorOption Build(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/Models/BubbleGraphicDescription.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Text; 6 | 7 | namespace Lazy.Captcha.Core.Generator.Image.Models 8 | { 9 | public class BubbleGraphicDescription 10 | { 11 | public float Cx { get; set; } 12 | public float Cy { get; set; } 13 | public float Radius { get; set; } 14 | public SKColor Color { get; set; } 15 | public float Thickness { get; set; } 16 | public float BlendPercentage { get; set; } = 1; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/Models/InterferenceLineGraphicDescription.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Lazy.Captcha.Core.Generator.Image.Models 7 | { 8 | public class InterferenceLineGraphicDescription 9 | { 10 | public SKColor Color { get; set; } 11 | public SKPoint Start { get; set; } 12 | public SKPoint Ctrl1 { get; set; } 13 | public SKPoint Ctrl2 { get; set; } 14 | public SKPoint End { get; set; } 15 | public float BlendPercentage { get; set; } = 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/Models/TextGraphicDescription.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Text; 6 | 7 | namespace Lazy.Captcha.Core.Generator.Image.Models 8 | { 9 | public class TextGraphicDescription 10 | { 11 | public string Text { get; set; } 12 | public SKTypeface Font { get; set; } 13 | public SKColor Color { get; set; } 14 | public PointF Location { get; set; } 15 | public float FontSize { get; set; } 16 | public float BlendPercentage { get; set; } = 1; 17 | public bool TextBold { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/Option/CaptchaImageGeneratorOption.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core.Generator.Image.Option 9 | { 10 | public class CaptchaImageGeneratorOption 11 | { 12 | /// 13 | /// 是否启用动画 14 | /// 15 | public bool Animation { get; set; } = false; 16 | /// 17 | /// 背景色 18 | /// 19 | public SKColor BackgroundColor { get; set; } = SKColors.White; 20 | /// 21 | /// 前景色 22 | /// 23 | public List ForegroundColors { get; set; } 24 | /// 25 | /// FontFamily 26 | /// 27 | public SKTypeface FontFamily { get; set;}= DefaultFontFamilys.Instance.Kaiti; 28 | /// 29 | /// 字体大小 30 | /// 31 | public float FontSize { get; set; } = 28; 32 | 33 | /// 34 | /// 验证码的宽 35 | /// 36 | public int Width { get; set; } = 130; 37 | /// 38 | /// 验证码高 39 | /// 40 | public int Height { get; set; } = 48; 41 | /// 42 | /// 气泡最小半径 43 | /// 44 | public int BubbleMinRadius { get; set; } = 3; 45 | /// 46 | /// 气泡最小半径 47 | /// 48 | public int BubbleMaxRadius { get; set; } = 8; 49 | /// 50 | /// 气泡数量 51 | /// 52 | public int BubbleCount { get; set; } = 3; 53 | /// 54 | /// 气泡边沿厚度 55 | /// 56 | public float BubbleThickness { get; set; } = 1; 57 | /// 58 | /// 干扰线数量 59 | /// 60 | public int InterferenceLineCount { get; set; } = 1; 61 | /// 62 | /// 每帧延迟,Animation=true时有效 63 | /// 64 | public int FrameDelay { get; set; } = 300; 65 | /// 66 | /// 图片质量(仅对静态验证有效) 67 | /// 68 | public int Quality { get; set; } = 100; 69 | /// 70 | /// 文本粗体 71 | /// 72 | public bool TextBold { get; set; } = false; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Generator/Image/Option/DefaultCaptchaImageOptionBuilder.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Lazy.Captcha.Core.Generator.Code; 3 | using SkiaSharp; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Lazy.Captcha.Core.Generator.Image.Option 11 | { 12 | public class DefaultCaptchaImageOptionBuilder : ICaptchaImageOptionBuilder 13 | { 14 | private CaptchaImageGeneratorOption _option = new CaptchaImageGeneratorOption(); 15 | 16 | public static DefaultCaptchaImageOptionBuilder Create() 17 | { 18 | return new DefaultCaptchaImageOptionBuilder(); 19 | } 20 | 21 | /// 22 | /// 背景色 23 | /// 24 | /// 25 | /// 26 | public DefaultCaptchaImageOptionBuilder CaptchaType(SKColor backgroundColor) 27 | { 28 | this._option.BackgroundColor = backgroundColor; 29 | return this; 30 | } 31 | 32 | /// 33 | /// 字体 34 | /// 35 | /// 36 | /// 37 | public DefaultCaptchaImageOptionBuilder FontFamily(SKTypeface fontFamily) 38 | { 39 | this._option.FontFamily = fontFamily; 40 | return this; 41 | } 42 | 43 | /// 44 | /// 字体大小 45 | /// 46 | /// 47 | /// 48 | public DefaultCaptchaImageOptionBuilder FontFamily(float fontSize) 49 | { 50 | this._option.FontSize = fontSize; 51 | return this; 52 | } 53 | 54 | /// 55 | /// 验证码的宽高 56 | /// 57 | /// 58 | /// 59 | /// 60 | public DefaultCaptchaImageOptionBuilder Size(int width, int height) 61 | { 62 | this._option.Width = width; 63 | this._option.Height = height; 64 | return this; 65 | } 66 | 67 | /// 68 | /// 气泡数量 69 | /// 70 | /// 71 | /// 72 | public DefaultCaptchaImageOptionBuilder BubbleCount(int bubbleCount) 73 | { 74 | this._option.BubbleCount = bubbleCount; 75 | return this; 76 | } 77 | 78 | /// 79 | /// 气泡边沿厚度 80 | /// 81 | /// 82 | /// 83 | public DefaultCaptchaImageOptionBuilder BubbleCount(float bubbleThickness) 84 | { 85 | this._option.BubbleThickness = bubbleThickness; 86 | return this; 87 | } 88 | 89 | /// 90 | /// 干扰线数量 91 | /// 92 | /// 93 | /// 94 | public DefaultCaptchaImageOptionBuilder InterferenceLineCount(int interferenceLineCount) 95 | { 96 | this._option.InterferenceLineCount = interferenceLineCount; 97 | return this; 98 | } 99 | 100 | 101 | public CaptchaImageGeneratorOption Build() 102 | { 103 | return this._option; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/ICaptcha.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Lazy.Captcha.Core 8 | { 9 | public interface ICaptcha 10 | { 11 | /// 12 | /// 生成验证码 13 | /// 14 | /// 验证码id 15 | /// 缓存时间,未设定则使用配置时间 16 | /// 17 | CaptchaData Generate(string captchaId, int? expirySeconds = null); 18 | 19 | /// 20 | /// 校验 21 | /// 22 | /// 验证码id 23 | /// 用户输入的验证码 24 | /// 校验成功时是否移除缓存(用于多次验证) 25 | /// 26 | bool Validate(string captchaId, string code, bool removeIfSuccess = true); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/ICaptchaBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Lazy.Captcha.Core 9 | { 10 | public interface ICaptchaBuilder 11 | { 12 | IServiceCollection Services { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Lazy.Captcha.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 仿EasyCaptcha和SimpleCaptcha,基于.Net Standard 2.0的图形验证码模块。版本2.0.0起绘图由ImageSharp调整为SkiaSharp。文档地址: https://gitee.com/pojianbing/lazy-captcha 6 | https://gitee.com/pojianbing/lazy-captcha 7 | https://gitee.com/pojianbing/lazy-captcha 8 | git 9 | true 10 | snupkg 11 | 2.0.4 12 | 2.0.4 13 | captcha 验证码 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Storage/Caches/CacheEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Lazy.Captcha.Core.Storage.Caches 6 | { 7 | /// 8 | /// 缓存实体 9 | /// 10 | public class CacheEntity 11 | { 12 | /// 13 | /// 键 14 | /// 15 | public string Key { get; set; } 16 | /// 17 | /// 值 18 | /// 19 | public string Value { get; set; } 20 | /// 21 | /// 过期时间 22 | /// 23 | public DateTimeOffset AbsoluteExpiration { get; set; } 24 | 25 | /// 26 | /// 是否过期 27 | /// 28 | public bool IsExpired 29 | { 30 | get 31 | { 32 | DateTimeOffset now = DateTime.Now.ToUniversalTime(); 33 | return AbsoluteExpiration.Subtract(now).TotalMilliseconds < 0; 34 | } 35 | } 36 | 37 | /// 38 | /// 缓存数据 39 | /// 40 | /// 缓存键 41 | /// 值 42 | public CacheEntity(string key, string value) 43 | { 44 | this.Key = key; 45 | this.Value = value; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Storage/Caches/MemoryCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Timers; 8 | 9 | namespace Lazy.Captcha.Core.Storage.Caches 10 | { 11 | public class MemoryCache 12 | { 13 | private Timer CacheCheckTimer; 14 | private ConcurrentDictionary Cache = new ConcurrentDictionary(); 15 | public static MemoryCache Default = new MemoryCache(60); 16 | 17 | public MemoryCache(int checkCacheIntervalInSecs) 18 | { 19 | CacheCheckTimer = new Timer(); 20 | CacheCheckTimer.Interval = checkCacheIntervalInSecs * 1000; 21 | CacheCheckTimer.Elapsed += CacheCheckTimer_Elapsed; 22 | CacheCheckTimer.Start(); 23 | } 24 | 25 | public string Get(string key) 26 | { 27 | if (Cache.TryGetValue(key, out var data)) 28 | { 29 | if (data.IsExpired) 30 | { 31 | Cache.TryRemove(key, out var _); 32 | return null; 33 | } 34 | return data.Value; 35 | } 36 | return null; 37 | } 38 | 39 | public void Remove(string key) 40 | { 41 | Cache.TryRemove(key, out var _); 42 | } 43 | 44 | public void Set(string key, string value, DateTimeOffset absoluteExpiration) 45 | { 46 | var data = new CacheEntity(key, value); 47 | data.AbsoluteExpiration = absoluteExpiration; 48 | 49 | Cache.TryRemove(key, out _); 50 | Cache.TryAdd(key, data); 51 | } 52 | 53 | /// 54 | /// 过期检测 55 | /// 56 | /// 57 | /// 58 | /// 59 | private void CacheCheckTimer_Elapsed(object sender, ElapsedEventArgs e) 60 | { 61 | Task.Run(() => 62 | { 63 | try 64 | { 65 | foreach (string cacheKey in Cache.Keys) 66 | { 67 | if (Cache.TryGetValue(cacheKey, out var data)) 68 | { 69 | if (data.IsExpired) 70 | { 71 | Cache.TryRemove(cacheKey, out var _); 72 | } 73 | } 74 | } 75 | } 76 | catch (Exception ex) 77 | { 78 | Console.WriteLine(ex.ToString()); 79 | } 80 | }); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Storage/DefaultStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Lazy.Captcha.Core.Storage; 3 | using Microsoft.Extensions.Caching.Distributed; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace Lazy.Captcha.Core.Storeage 7 | { 8 | public class DefaultStorage : IStorage 9 | { 10 | private readonly IDistributedCache _cache; 11 | private readonly IOptionsMonitor _options; 12 | 13 | public DefaultStorage(IOptionsMonitor options, IDistributedCache cache) 14 | { 15 | _options = options; 16 | _cache = cache; 17 | } 18 | 19 | private string WrapKey(string key) 20 | { 21 | return $"{this._options.CurrentValue.StoreageKeyPrefix}{key}"; 22 | } 23 | 24 | public string Get(string key) 25 | { 26 | return _cache.GetString(WrapKey(key)); 27 | } 28 | 29 | public void Remove(string key) 30 | { 31 | _cache.Remove(WrapKey(key)); 32 | } 33 | 34 | public void Set(string key, string value, DateTimeOffset absoluteExpiration) 35 | { 36 | _cache.SetString(WrapKey(key), value, new DistributedCacheEntryOptions 37 | { 38 | AbsoluteExpiration = absoluteExpiration 39 | }); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Storage/IStorage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Lazy.Captcha.Core.Storage 4 | { 5 | public interface IStorage 6 | { 7 | void Set(string key, string value, DateTimeOffset absoluteExpiration); 8 | 9 | string Get(string key); 10 | 11 | void Remove(string key); 12 | } 13 | } -------------------------------------------------------------------------------- /Lazy.Captcha.Core/Storage/MemeoryStorage.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Storage.Caches; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Lazy.Captcha.Core.Storage 7 | { 8 | public class MemeoryStorage : IStorage 9 | { 10 | private MemoryCache Cache; 11 | public string StoreageKeyPrefix { get; set; } = string.Empty; 12 | 13 | public MemeoryStorage() 14 | { 15 | Cache = MemoryCache.Default; 16 | } 17 | 18 | private string WrapKey(string key) 19 | { 20 | return $"{StoreageKeyPrefix}{key}"; 21 | } 22 | 23 | public string Get(string key) 24 | { 25 | return Cache.Get(WrapKey(key)); 26 | } 27 | 28 | public void Remove(string key) 29 | { 30 | Cache.Remove(WrapKey(key)); 31 | } 32 | 33 | public void Set(string key, string value, DateTimeOffset absoluteExpiration) 34 | { 35 | Cache.Set(WrapKey(key), value, absoluteExpiration); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/actionj.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/actionj.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/epilog.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/epilog.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/fresnel.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/fresnel.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/headache.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/headache.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/kaiti.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/kaiti.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/lexo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/lexo.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/prefix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/prefix.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/progbot.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/progbot.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/ransom.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/ransom.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/robot.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/robot.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.Core/fonts/scandal.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.Core/fonts/scandal.ttf -------------------------------------------------------------------------------- /Lazy.Captcha.xUnit/Demo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.xUnit/Demo.cs -------------------------------------------------------------------------------- /Lazy.Captcha.xUnit/EvaluationEngineTest.cs: -------------------------------------------------------------------------------- 1 |  2 | using Lazy.Captcha.Core; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Lazy.Captcha.xUnit 10 | { 11 | public class EvaluationEngineTest 12 | { 13 | private EvaluationEngine engine = new EvaluationEngine(); 14 | 15 | [Fact] 16 | public void Test1() 17 | { 18 | var result = engine.Evaluate("1 + 1"); 19 | Assert.Equal(2, result); 20 | } 21 | 22 | [Fact] 23 | public void Test2() 24 | { 25 | var result = engine.Evaluate("3 + 8"); 26 | Assert.Equal(11, result); 27 | } 28 | 29 | [Fact] 30 | public void Test3() 31 | { 32 | var result = engine.Evaluate("11 + 5"); 33 | Assert.Equal(16, result); 34 | } 35 | 36 | [Fact] 37 | public void Test4() 38 | { 39 | var result = engine.Evaluate("11 - 5"); 40 | Assert.Equal(6, result); 41 | } 42 | 43 | [Fact] 44 | public void Test5() 45 | { 46 | var result = engine.Evaluate("7 - 9"); 47 | Assert.Equal(-2, result); 48 | } 49 | 50 | [Fact] 51 | public void Test6() 52 | { 53 | var result = engine.Evaluate("0-0"); 54 | Assert.Equal(0, result); 55 | } 56 | 57 | [Fact] 58 | public void Test7() 59 | { 60 | var result = engine.Evaluate("5*0"); 61 | Assert.Equal(0, result); 62 | } 63 | 64 | [Fact] 65 | public void Test8() 66 | { 67 | var result = engine.Evaluate("5*3"); 68 | Assert.Equal(15, result); 69 | } 70 | 71 | [Fact] 72 | public void Test9() 73 | { 74 | var result = engine.Evaluate("5*10"); 75 | Assert.Equal(50, result); 76 | } 77 | 78 | [Fact] 79 | public void Test10() 80 | { 81 | var result = engine.Evaluate("8x2"); 82 | Assert.Equal(16, result); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Lazy.Captcha.xUnit/GlobalUsing.cs: -------------------------------------------------------------------------------- 1 | global using System; 2 | global using System.Collections.Generic; 3 | global using System.Linq; 4 | global using System.Text; 5 | global using System.Threading.Tasks; 6 | global using Xunit; -------------------------------------------------------------------------------- /Lazy.Captcha.xUnit/Lazy.Captcha.xUnit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Always 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lazy.Captcha.xUnit/inputs/fb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Lazy.Captcha.xUnit/inputs/fb.jpg -------------------------------------------------------------------------------- /LazyCaptcha.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lazy.Captcha.Core", "Lazy.Captcha.Core\Lazy.Captcha.Core.csproj", "{B640C86B-87E3-4CBE-94A9-2CA3AC704A08}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lazy.Captcha.xUnit", "Lazy.Captcha.xUnit\Lazy.Captcha.xUnit.csproj", "{4E63EE78-CE03-4D89-BF86-7AF2247082F2}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{5FB114D8-1F49-4BAC-87FF-0E26494C6B6C}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.Winfrom", "Sample.Winfrom\Sample.Winfrom.csproj", "{88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.NetCore", "Sample.NetCore\Sample.NetCore.csproj", "{94C05019-52D1-4064-9807-10D465C3B5A3}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample.MvcFramework", "Sample.MvcFramework\Sample.MvcFramework.csproj", "{F172A3CE-0295-40FC-B739-694EFE9A41C8}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {B640C86B-87E3-4CBE-94A9-2CA3AC704A08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {B640C86B-87E3-4CBE-94A9-2CA3AC704A08}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {B640C86B-87E3-4CBE-94A9-2CA3AC704A08}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {B640C86B-87E3-4CBE-94A9-2CA3AC704A08}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {4E63EE78-CE03-4D89-BF86-7AF2247082F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {4E63EE78-CE03-4D89-BF86-7AF2247082F2}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {4E63EE78-CE03-4D89-BF86-7AF2247082F2}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {4E63EE78-CE03-4D89-BF86-7AF2247082F2}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {94C05019-52D1-4064-9807-10D465C3B5A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {94C05019-52D1-4064-9807-10D465C3B5A3}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {94C05019-52D1-4064-9807-10D465C3B5A3}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {94C05019-52D1-4064-9807-10D465C3B5A3}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {F172A3CE-0295-40FC-B739-694EFE9A41C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {F172A3CE-0295-40FC-B739-694EFE9A41C8}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {F172A3CE-0295-40FC-B739-694EFE9A41C8}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {F172A3CE-0295-40FC-B739-694EFE9A41C8}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(NestedProjects) = preSolution 49 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C} = {5FB114D8-1F49-4BAC-87FF-0E26494C6B6C} 50 | {94C05019-52D1-4064-9807-10D465C3B5A3} = {5FB114D8-1F49-4BAC-87FF-0E26494C6B6C} 51 | {F172A3CE-0295-40FC-B739-694EFE9A41C8} = {5FB114D8-1F49-4BAC-87FF-0E26494C6B6C} 52 | EndGlobalSection 53 | GlobalSection(ExtensibilityGlobals) = postSolution 54 | SolutionGuid = {E4457E8D-D3CA-4EA5-88B3-52CB2405BA1E} 55 | EndGlobalSection 56 | EndGlobal 57 | -------------------------------------------------------------------------------- /Sample.MvcFramework/App_Start/BundleConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Optimization; 3 | 4 | namespace Sample.MvcFramework 5 | { 6 | public class BundleConfig 7 | { 8 | // 有关捆绑的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkId=301862 9 | public static void RegisterBundles(BundleCollection bundles) 10 | { 11 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include( 12 | "~/Scripts/jquery-{version}.js")); 13 | 14 | // 使用要用于开发和学习的 Modernizr 的开发版本。然后,当你做好 15 | // 生产准备就绪,请使用 https://modernizr.com 上的生成工具仅选择所需的测试。 16 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include( 17 | "~/Scripts/modernizr-*")); 18 | 19 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include( 20 | "~/Scripts/bootstrap.js")); 21 | 22 | bundles.Add(new StyleBundle("~/Content/css").Include( 23 | "~/Content/bootstrap.css", 24 | "~/Content/site.css")); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sample.MvcFramework/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace Sample.MvcFramework 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sample.MvcFramework/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace Sample.MvcFramework 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sample.MvcFramework/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace Sample.MvcFramework 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | // Web API 配置和服务 13 | 14 | // Web API 路由 15 | config.MapHttpAttributeRoutes(); 16 | 17 | config.Routes.MapHttpRoute( 18 | name: "DefaultApi", 19 | routeTemplate: "api/{controller}/{id}", 20 | defaults: new { id = RouteParameter.Optional } 21 | ); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ApiDescriptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Web; 4 | using System.Web.Http.Description; 5 | 6 | namespace Sample.MvcFramework.Areas.HelpPage 7 | { 8 | public static class ApiDescriptionExtensions 9 | { 10 | /// 11 | /// Generates an URI-friendly ID for the . E.g. "Get-Values-id_name" instead of "GetValues/{id}?name={name}" 12 | /// 13 | /// The . 14 | /// The ID as a string. 15 | public static string GetFriendlyId(this ApiDescription description) 16 | { 17 | string path = description.RelativePath; 18 | string[] urlParts = path.Split('?'); 19 | string localPath = urlParts[0]; 20 | string queryKeyString = null; 21 | if (urlParts.Length > 1) 22 | { 23 | string query = urlParts[1]; 24 | string[] queryKeys = HttpUtility.ParseQueryString(query).AllKeys; 25 | queryKeyString = String.Join("_", queryKeys); 26 | } 27 | 28 | StringBuilder friendlyPath = new StringBuilder(); 29 | friendlyPath.AppendFormat("{0}-{1}", 30 | description.HttpMethod.Method, 31 | localPath.Replace("/", "-").Replace("{", String.Empty).Replace("}", String.Empty)); 32 | if (queryKeyString != null) 33 | { 34 | friendlyPath.AppendFormat("_{0}", queryKeyString.Replace('.', '-')); 35 | } 36 | return friendlyPath.ToString(); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/App_Start/HelpPageConfig.cs: -------------------------------------------------------------------------------- 1 | // Uncomment the following to provide samples for PageResult. Must also add the Microsoft.AspNet.WebApi.OData 2 | // package to your project. 3 | ////#define Handle_PageResultOfT 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.Diagnostics; 9 | using System.Diagnostics.CodeAnalysis; 10 | using System.Linq; 11 | using System.Net.Http.Headers; 12 | using System.Reflection; 13 | using System.Web; 14 | using System.Web.Http; 15 | #if Handle_PageResultOfT 16 | using System.Web.Http.OData; 17 | #endif 18 | 19 | namespace Sample.MvcFramework.Areas.HelpPage 20 | { 21 | /// 22 | /// Use this class to customize the Help Page. 23 | /// For example you can set a custom to supply the documentation 24 | /// or you can provide the samples for the requests/responses. 25 | /// 26 | public static class HelpPageConfig 27 | { 28 | [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", 29 | MessageId = "Sample.MvcFramework.Areas.HelpPage.TextSample.#ctor(System.String)", 30 | Justification = "End users may choose to merge this string with existing localized resources.")] 31 | [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", 32 | MessageId = "bsonspec", 33 | Justification = "Part of a URI.")] 34 | public static void Register(HttpConfiguration config) 35 | { 36 | //// Uncomment the following to use the documentation from XML documentation file. 37 | //config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml"))); 38 | 39 | //// Uncomment the following to use "sample string" as the sample for all actions that have string as the body parameter or return type. 40 | //// Also, the string arrays will be used for IEnumerable. The sample objects will be serialized into different media type 41 | //// formats by the available formatters. 42 | //config.SetSampleObjects(new Dictionary 43 | //{ 44 | // {typeof(string), "sample string"}, 45 | // {typeof(IEnumerable), new string[]{"sample 1", "sample 2"}} 46 | //}); 47 | 48 | // Extend the following to provide factories for types not handled automatically (those lacking parameterless 49 | // constructors) or for which you prefer to use non-default property values. Line below provides a fallback 50 | // since automatic handling will fail and GeneratePageResult handles only a single type. 51 | #if Handle_PageResultOfT 52 | config.GetHelpPageSampleGenerator().SampleObjectFactories.Add(GeneratePageResult); 53 | #endif 54 | 55 | // Extend the following to use a preset object directly as the sample for all actions that support a media 56 | // type, regardless of the body parameter or return type. The lines below avoid display of binary content. 57 | // The BsonMediaTypeFormatter (if available) is not used to serialize the TextSample object. 58 | config.SetSampleForMediaType( 59 | new TextSample("Binary JSON content. See http://bsonspec.org for details."), 60 | new MediaTypeHeaderValue("application/bson")); 61 | 62 | //// Uncomment the following to use "[0]=foo&[1]=bar" directly as the sample for all actions that support form URL encoded format 63 | //// and have IEnumerable as the body parameter or return type. 64 | //config.SetSampleForType("[0]=foo&[1]=bar", new MediaTypeHeaderValue("application/x-www-form-urlencoded"), typeof(IEnumerable)); 65 | 66 | //// Uncomment the following to use "1234" directly as the request sample for media type "text/plain" on the controller named "Values" 67 | //// and action named "Put". 68 | //config.SetSampleRequest("1234", new MediaTypeHeaderValue("text/plain"), "Values", "Put"); 69 | 70 | //// Uncomment the following to use the image on "../images/aspNetHome.png" directly as the response sample for media type "image/png" 71 | //// on the controller named "Values" and action named "Get" with parameter "id". 72 | //config.SetSampleResponse(new ImageSample("../images/aspNetHome.png"), new MediaTypeHeaderValue("image/png"), "Values", "Get", "id"); 73 | 74 | //// Uncomment the following to correct the sample request when the action expects an HttpRequestMessage with ObjectContent. 75 | //// The sample will be generated as if the controller named "Values" and action named "Get" were having string as the body parameter. 76 | //config.SetActualRequestType(typeof(string), "Values", "Get"); 77 | 78 | //// Uncomment the following to correct the sample response when the action returns an HttpResponseMessage with ObjectContent. 79 | //// The sample will be generated as if the controller named "Values" and action named "Post" were returning a string. 80 | //config.SetActualResponseType(typeof(string), "Values", "Post"); 81 | } 82 | 83 | #if Handle_PageResultOfT 84 | private static object GeneratePageResult(HelpPageSampleGenerator sampleGenerator, Type type) 85 | { 86 | if (type.IsGenericType) 87 | { 88 | Type openGenericType = type.GetGenericTypeDefinition(); 89 | if (openGenericType == typeof(PageResult<>)) 90 | { 91 | // Get the T in PageResult 92 | Type[] typeParameters = type.GetGenericArguments(); 93 | Debug.Assert(typeParameters.Length == 1); 94 | 95 | // Create an enumeration to pass as the first parameter to the PageResult constuctor 96 | Type itemsType = typeof(List<>).MakeGenericType(typeParameters); 97 | object items = sampleGenerator.GetSampleObject(itemsType); 98 | 99 | // Fill in the other information needed to invoke the PageResult constuctor 100 | Type[] parameterTypes = new Type[] { itemsType, typeof(Uri), typeof(long?), }; 101 | object[] parameters = new object[] { items, null, (long)ObjectGenerator.DefaultCollectionSize, }; 102 | 103 | // Call PageResult(IEnumerable items, Uri nextPageLink, long? count) constructor 104 | ConstructorInfo constructor = type.GetConstructor(parameterTypes); 105 | return constructor.Invoke(parameters); 106 | } 107 | } 108 | 109 | return null; 110 | } 111 | #endif 112 | } 113 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Controllers/HelpController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Web.Http; 3 | using System.Web.Mvc; 4 | using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions; 5 | using Sample.MvcFramework.Areas.HelpPage.Models; 6 | 7 | namespace Sample.MvcFramework.Areas.HelpPage.Controllers 8 | { 9 | /// 10 | /// The controller that will handle requests for the help page. 11 | /// 12 | public class HelpController : Controller 13 | { 14 | private const string ErrorViewName = "Error"; 15 | 16 | public HelpController() 17 | : this(GlobalConfiguration.Configuration) 18 | { 19 | } 20 | 21 | public HelpController(HttpConfiguration config) 22 | { 23 | Configuration = config; 24 | } 25 | 26 | public HttpConfiguration Configuration { get; private set; } 27 | 28 | public ActionResult Index() 29 | { 30 | ViewBag.DocumentationProvider = Configuration.Services.GetDocumentationProvider(); 31 | return View(Configuration.Services.GetApiExplorer().ApiDescriptions); 32 | } 33 | 34 | public ActionResult Api(string apiId) 35 | { 36 | if (!String.IsNullOrEmpty(apiId)) 37 | { 38 | HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId); 39 | if (apiModel != null) 40 | { 41 | return View(apiModel); 42 | } 43 | } 44 | 45 | return View(ErrorViewName); 46 | } 47 | 48 | public ActionResult ResourceModel(string modelName) 49 | { 50 | if (!String.IsNullOrEmpty(modelName)) 51 | { 52 | ModelDescriptionGenerator modelDescriptionGenerator = Configuration.GetModelDescriptionGenerator(); 53 | ModelDescription modelDescription; 54 | if (modelDescriptionGenerator.GeneratedModels.TryGetValue(modelName, out modelDescription)) 55 | { 56 | return View(modelDescription); 57 | } 58 | } 59 | 60 | return View(ErrorViewName); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/HelpPage.css: -------------------------------------------------------------------------------- 1 | .help-page h1, 2 | .help-page .h1, 3 | .help-page h2, 4 | .help-page .h2, 5 | .help-page h3, 6 | .help-page .h3, 7 | #body.help-page, 8 | .help-page-table th, 9 | .help-page-table pre, 10 | .help-page-table p { 11 | font-family: "Segoe UI Light", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif; 12 | } 13 | 14 | .help-page pre.wrapped { 15 | white-space: -moz-pre-wrap; 16 | white-space: -pre-wrap; 17 | white-space: -o-pre-wrap; 18 | white-space: pre-wrap; 19 | } 20 | 21 | .help-page .warning-message-container { 22 | margin-top: 20px; 23 | padding: 0 10px; 24 | color: #525252; 25 | background: #EFDCA9; 26 | border: 1px solid #CCCCCC; 27 | } 28 | 29 | .help-page-table { 30 | width: 100%; 31 | border-collapse: collapse; 32 | text-align: left; 33 | margin: 0px 0px 20px 0px; 34 | border-top: 1px solid #D4D4D4; 35 | } 36 | 37 | .help-page-table th { 38 | text-align: left; 39 | font-weight: bold; 40 | border-bottom: 1px solid #D4D4D4; 41 | padding: 5px 6px 5px 6px; 42 | } 43 | 44 | .help-page-table td { 45 | border-bottom: 1px solid #D4D4D4; 46 | padding: 10px 8px 10px 8px; 47 | vertical-align: top; 48 | } 49 | 50 | .help-page-table pre, 51 | .help-page-table p { 52 | margin: 0px; 53 | padding: 0px; 54 | font-family: inherit; 55 | font-size: 100%; 56 | } 57 | 58 | .help-page-table tbody tr:hover td { 59 | background-color: #F3F3F3; 60 | } 61 | 62 | .help-page a:hover { 63 | background-color: transparent; 64 | } 65 | 66 | .help-page .sample-header { 67 | border: 2px solid #D4D4D4; 68 | background: #00497E; 69 | color: #FFFFFF; 70 | padding: 8px 15px; 71 | border-bottom: none; 72 | display: inline-block; 73 | margin: 10px 0px 0px 0px; 74 | } 75 | 76 | .help-page .sample-content { 77 | display: block; 78 | border-width: 0; 79 | padding: 15px 20px; 80 | background: #FFFFFF; 81 | border: 2px solid #D4D4D4; 82 | margin: 0px 0px 10px 0px; 83 | } 84 | 85 | .help-page .api-name { 86 | width: 40%; 87 | } 88 | 89 | .help-page .api-documentation { 90 | width: 60%; 91 | } 92 | 93 | .help-page .parameter-name { 94 | width: 20%; 95 | } 96 | 97 | .help-page .parameter-documentation { 98 | width: 40%; 99 | } 100 | 101 | .help-page .parameter-type { 102 | width: 20%; 103 | } 104 | 105 | .help-page .parameter-annotations { 106 | width: 20%; 107 | } 108 | 109 | .help-page h1, 110 | .help-page .h1 { 111 | font-size: 36px; 112 | line-height: normal; 113 | } 114 | 115 | .help-page h2, 116 | .help-page .h2 { 117 | font-size: 24px; 118 | } 119 | 120 | .help-page h3, 121 | .help-page .h3 { 122 | font-size: 20px; 123 | } 124 | 125 | #body.help-page { 126 | font-size: 14px; 127 | line-height: 143%; 128 | color: #333; 129 | } 130 | 131 | .help-page a { 132 | color: #0000EE; 133 | text-decoration: none; 134 | } 135 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/HelpPageAreaRegistration.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Http; 2 | using System.Web.Mvc; 3 | 4 | namespace Sample.MvcFramework.Areas.HelpPage 5 | { 6 | public class HelpPageAreaRegistration : AreaRegistration 7 | { 8 | public override string AreaName 9 | { 10 | get 11 | { 12 | return "HelpPage"; 13 | } 14 | } 15 | 16 | public override void RegisterArea(AreaRegistrationContext context) 17 | { 18 | context.MapRoute( 19 | "HelpPage_Default", 20 | "Help/{action}/{apiId}", 21 | new { controller = "Help", action = "Index", apiId = UrlParameter.Optional }); 22 | 23 | HelpPageConfig.Register(GlobalConfiguration.Configuration); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/CollectionModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class CollectionModelDescription : ModelDescription 4 | { 5 | public ModelDescription ElementDescription { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ComplexTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 4 | { 5 | public class ComplexTypeModelDescription : ModelDescription 6 | { 7 | public ComplexTypeModelDescription() 8 | { 9 | Properties = new Collection(); 10 | } 11 | 12 | public Collection Properties { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/DictionaryModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class DictionaryModelDescription : KeyValuePairModelDescription 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/EnumTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 5 | { 6 | public class EnumTypeModelDescription : ModelDescription 7 | { 8 | public EnumTypeModelDescription() 9 | { 10 | Values = new Collection(); 11 | } 12 | 13 | public Collection Values { get; private set; } 14 | } 15 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/EnumValueDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class EnumValueDescription 4 | { 5 | public string Documentation { get; set; } 6 | 7 | public string Name { get; set; } 8 | 9 | public string Value { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/IModelDocumentationProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 5 | { 6 | public interface IModelDocumentationProvider 7 | { 8 | string GetDocumentation(MemberInfo member); 9 | 10 | string GetDocumentation(Type type); 11 | } 12 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/KeyValuePairModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class KeyValuePairModelDescription : ModelDescription 4 | { 5 | public ModelDescription KeyModelDescription { get; set; } 6 | 7 | public ModelDescription ValueModelDescription { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ModelDescription.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 4 | { 5 | /// 6 | /// Describes a type model. 7 | /// 8 | public abstract class ModelDescription 9 | { 10 | public string Documentation { get; set; } 11 | 12 | public Type ModelType { get; set; } 13 | 14 | public string Name { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ModelNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 4 | { 5 | /// 6 | /// Use this attribute to change the name of the generated for a type. 7 | /// 8 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = false, Inherited = false)] 9 | public sealed class ModelNameAttribute : Attribute 10 | { 11 | public ModelNameAttribute(string name) 12 | { 13 | Name = name; 14 | } 15 | 16 | public string Name { get; private set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ModelNameHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 7 | { 8 | internal static class ModelNameHelper 9 | { 10 | // Modify this to provide custom model name mapping. 11 | public static string GetModelName(Type type) 12 | { 13 | ModelNameAttribute modelNameAttribute = type.GetCustomAttribute(); 14 | if (modelNameAttribute != null && !String.IsNullOrEmpty(modelNameAttribute.Name)) 15 | { 16 | return modelNameAttribute.Name; 17 | } 18 | 19 | string modelName = type.Name; 20 | if (type.IsGenericType) 21 | { 22 | // Format the generic type name to something like: GenericOfAgurment1AndArgument2 23 | Type genericType = type.GetGenericTypeDefinition(); 24 | Type[] genericArguments = type.GetGenericArguments(); 25 | string genericTypeName = genericType.Name; 26 | 27 | // Trim the generic parameter counts from the name 28 | genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`')); 29 | string[] argumentTypeNames = genericArguments.Select(t => GetModelName(t)).ToArray(); 30 | modelName = String.Format(CultureInfo.InvariantCulture, "{0}Of{1}", genericTypeName, String.Join("And", argumentTypeNames)); 31 | } 32 | 33 | return modelName; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ParameterAnnotation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 4 | { 5 | public class ParameterAnnotation 6 | { 7 | public Attribute AnnotationAttribute { get; set; } 8 | 9 | public string Documentation { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/ParameterDescription.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | 4 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 5 | { 6 | public class ParameterDescription 7 | { 8 | public ParameterDescription() 9 | { 10 | Annotations = new Collection(); 11 | } 12 | 13 | public Collection Annotations { get; private set; } 14 | 15 | public string Documentation { get; set; } 16 | 17 | public string Name { get; set; } 18 | 19 | public ModelDescription TypeDescription { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/ModelDescriptions/SimpleTypeModelDescription.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | { 3 | public class SimpleTypeModelDescription : ModelDescription 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Models/HelpPageApiModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using System.Net.Http.Headers; 4 | using System.Web.Http.Description; 5 | using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions; 6 | 7 | namespace Sample.MvcFramework.Areas.HelpPage.Models 8 | { 9 | /// 10 | /// The model that represents an API displayed on the help page. 11 | /// 12 | public class HelpPageApiModel 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | public HelpPageApiModel() 18 | { 19 | UriParameters = new Collection(); 20 | SampleRequests = new Dictionary(); 21 | SampleResponses = new Dictionary(); 22 | ErrorMessages = new Collection(); 23 | } 24 | 25 | /// 26 | /// Gets or sets the that describes the API. 27 | /// 28 | public ApiDescription ApiDescription { get; set; } 29 | 30 | /// 31 | /// Gets or sets the collection that describes the URI parameters for the API. 32 | /// 33 | public Collection UriParameters { get; private set; } 34 | 35 | /// 36 | /// Gets or sets the documentation for the request. 37 | /// 38 | public string RequestDocumentation { get; set; } 39 | 40 | /// 41 | /// Gets or sets the that describes the request body. 42 | /// 43 | public ModelDescription RequestModelDescription { get; set; } 44 | 45 | /// 46 | /// Gets the request body parameter descriptions. 47 | /// 48 | public IList RequestBodyParameters 49 | { 50 | get 51 | { 52 | return GetParameterDescriptions(RequestModelDescription); 53 | } 54 | } 55 | 56 | /// 57 | /// Gets or sets the that describes the resource. 58 | /// 59 | public ModelDescription ResourceDescription { get; set; } 60 | 61 | /// 62 | /// Gets the resource property descriptions. 63 | /// 64 | public IList ResourceProperties 65 | { 66 | get 67 | { 68 | return GetParameterDescriptions(ResourceDescription); 69 | } 70 | } 71 | 72 | /// 73 | /// Gets the sample requests associated with the API. 74 | /// 75 | public IDictionary SampleRequests { get; private set; } 76 | 77 | /// 78 | /// Gets the sample responses associated with the API. 79 | /// 80 | public IDictionary SampleResponses { get; private set; } 81 | 82 | /// 83 | /// Gets the error messages associated with this model. 84 | /// 85 | public Collection ErrorMessages { get; private set; } 86 | 87 | private static IList GetParameterDescriptions(ModelDescription modelDescription) 88 | { 89 | ComplexTypeModelDescription complexTypeModelDescription = modelDescription as ComplexTypeModelDescription; 90 | if (complexTypeModelDescription != null) 91 | { 92 | return complexTypeModelDescription.Properties; 93 | } 94 | 95 | CollectionModelDescription collectionModelDescription = modelDescription as CollectionModelDescription; 96 | if (collectionModelDescription != null) 97 | { 98 | complexTypeModelDescription = collectionModelDescription.ElementDescription as ComplexTypeModelDescription; 99 | if (complexTypeModelDescription != null) 100 | { 101 | return complexTypeModelDescription.Properties; 102 | } 103 | } 104 | 105 | return null; 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/SampleGeneration/ImageSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents an image sample on the help page. There's a display template named ImageSample associated with this class. 7 | /// 8 | public class ImageSample 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The URL of an image. 14 | public ImageSample(string src) 15 | { 16 | if (src == null) 17 | { 18 | throw new ArgumentNullException("src"); 19 | } 20 | Src = src; 21 | } 22 | 23 | public string Src { get; private set; } 24 | 25 | public override bool Equals(object obj) 26 | { 27 | ImageSample other = obj as ImageSample; 28 | return other != null && Src == other.Src; 29 | } 30 | 31 | public override int GetHashCode() 32 | { 33 | return Src.GetHashCode(); 34 | } 35 | 36 | public override string ToString() 37 | { 38 | return Src; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/SampleGeneration/InvalidSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents an invalid sample on the help page. There's a display template named InvalidSample associated with this class. 7 | /// 8 | public class InvalidSample 9 | { 10 | public InvalidSample(string errorMessage) 11 | { 12 | if (errorMessage == null) 13 | { 14 | throw new ArgumentNullException("errorMessage"); 15 | } 16 | ErrorMessage = errorMessage; 17 | } 18 | 19 | public string ErrorMessage { get; private set; } 20 | 21 | public override bool Equals(object obj) 22 | { 23 | InvalidSample other = obj as InvalidSample; 24 | return other != null && ErrorMessage == other.ErrorMessage; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | return ErrorMessage.GetHashCode(); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return ErrorMessage; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/SampleGeneration/SampleDirection.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.MvcFramework.Areas.HelpPage 2 | { 3 | /// 4 | /// Indicates whether the sample is used for request or response 5 | /// 6 | public enum SampleDirection 7 | { 8 | Request = 0, 9 | Response 10 | } 11 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/SampleGeneration/TextSample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.MvcFramework.Areas.HelpPage 4 | { 5 | /// 6 | /// This represents a preformatted text sample on the help page. There's a display template named TextSample associated with this class. 7 | /// 8 | public class TextSample 9 | { 10 | public TextSample(string text) 11 | { 12 | if (text == null) 13 | { 14 | throw new ArgumentNullException("text"); 15 | } 16 | Text = text; 17 | } 18 | 19 | public string Text { get; private set; } 20 | 21 | public override bool Equals(object obj) 22 | { 23 | TextSample other = obj as TextSample; 24 | return other != null && Text == other.Text; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | return Text.GetHashCode(); 30 | } 31 | 32 | public override string ToString() 33 | { 34 | return Text; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/Api.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using Sample.MvcFramework.Areas.HelpPage.Models 3 | @model HelpPageApiModel 4 | 5 | @{ 6 | var description = Model.ApiDescription; 7 | ViewBag.Title = description.HttpMethod.Method + " " + description.RelativePath; 8 | } 9 | 10 | 11 |
12 | 19 |
20 | @Html.DisplayForModel() 21 |
22 |
23 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/ApiGroup.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Controllers 3 | @using System.Web.Http.Description 4 | @using Sample.MvcFramework.Areas.HelpPage 5 | @using Sample.MvcFramework.Areas.HelpPage.Models 6 | @model IGrouping 7 | 8 | @{ 9 | var controllerDocumentation = ViewBag.DocumentationProvider != null ? 10 | ViewBag.DocumentationProvider.GetDocumentation(Model.Key) : 11 | null; 12 | } 13 | 14 |

@Model.Key.ControllerName

15 | @if (!String.IsNullOrEmpty(controllerDocumentation)) 16 | { 17 |

@controllerDocumentation

18 | } 19 | 20 | 21 | 22 | 23 | 24 | @foreach (var api in Model) 25 | { 26 | 27 | 28 | 38 | 39 | } 40 | 41 |
APIDescription
@api.HttpMethod.Method @api.RelativePath 29 | @if (api.Documentation != null) 30 | { 31 |

@api.Documentation

32 | } 33 | else 34 | { 35 |

No documentation available.

36 | } 37 |
-------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/CollectionModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model CollectionModelDescription 3 | @if (Model.ElementDescription is ComplexTypeModelDescription) 4 | { 5 | @Html.DisplayFor(m => m.ElementDescription) 6 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/ComplexTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model ComplexTypeModelDescription 3 | @Html.DisplayFor(m => m.Properties, "Parameters") -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/DictionaryModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model DictionaryModelDescription 3 | Dictionary of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] 4 | and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/EnumTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model EnumTypeModelDescription 3 | 4 |

Possible enumeration values:

5 | 6 | 7 | 8 | 9 | 10 | 11 | @foreach (EnumValueDescription value in Model.Values) 12 | { 13 | 14 | 15 | 18 | 21 | 22 | } 23 | 24 |
NameValueDescription
@value.Name 16 |

@value.Value

17 |
19 |

@value.Documentation

20 |
-------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/HelpPageApiModel.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Description 3 | @using Sample.MvcFramework.Areas.HelpPage.Models 4 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 5 | @model HelpPageApiModel 6 | 7 | @{ 8 | ApiDescription description = Model.ApiDescription; 9 | } 10 |

@description.HttpMethod.Method @description.RelativePath

11 |
12 |

@description.Documentation

13 | 14 |

Request Information

15 | 16 |

URI Parameters

17 | @Html.DisplayFor(m => m.UriParameters, "Parameters") 18 | 19 |

Body Parameters

20 | 21 |

@Model.RequestDocumentation

22 | 23 | @if (Model.RequestModelDescription != null) 24 | { 25 | @Html.DisplayFor(m => m.RequestModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.RequestModelDescription }) 26 | if (Model.RequestBodyParameters != null) 27 | { 28 | @Html.DisplayFor(m => m.RequestBodyParameters, "Parameters") 29 | } 30 | } 31 | else 32 | { 33 |

None.

34 | } 35 | 36 | @if (Model.SampleRequests.Count > 0) 37 | { 38 |

Request Formats

39 | @Html.DisplayFor(m => m.SampleRequests, "Samples") 40 | } 41 | 42 |

Response Information

43 | 44 |

Resource Description

45 | 46 |

@description.ResponseDescription.Documentation

47 | 48 | @if (Model.ResourceDescription != null) 49 | { 50 | @Html.DisplayFor(m => m.ResourceDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ResourceDescription }) 51 | if (Model.ResourceProperties != null) 52 | { 53 | @Html.DisplayFor(m => m.ResourceProperties, "Parameters") 54 | } 55 | } 56 | else 57 | { 58 |

None.

59 | } 60 | 61 | @if (Model.SampleResponses.Count > 0) 62 | { 63 |

Response Formats

64 | @Html.DisplayFor(m => m.SampleResponses, "Samples") 65 | } 66 | 67 |
-------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/ImageSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage 2 | @model ImageSample 3 | 4 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/InvalidSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage 2 | @model InvalidSample 3 | 4 | @if (HttpContext.Current.IsDebuggingEnabled) 5 | { 6 |
7 |

@Model.ErrorMessage

8 |
9 | } 10 | else 11 | { 12 |

Sample not available.

13 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/KeyValuePairModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model KeyValuePairModelDescription 3 | Pair of @Html.DisplayFor(m => Model.KeyModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.KeyModelDescription }) [key] 4 | and @Html.DisplayFor(m => Model.ValueModelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = Model.ValueModelDescription }) [value] -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/ModelDescriptionLink.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model Type 3 | @{ 4 | ModelDescription modelDescription = ViewBag.modelDescription; 5 | if (modelDescription is ComplexTypeModelDescription || modelDescription is EnumTypeModelDescription) 6 | { 7 | if (Model == typeof(Object)) 8 | { 9 | @:Object 10 | } 11 | else 12 | { 13 | @Html.ActionLink(modelDescription.Name, "ResourceModel", "Help", new { modelName = modelDescription.Name }, null) 14 | } 15 | } 16 | else if (modelDescription is CollectionModelDescription) 17 | { 18 | var collectionDescription = modelDescription as CollectionModelDescription; 19 | var elementDescription = collectionDescription.ElementDescription; 20 | @:Collection of @Html.DisplayFor(m => elementDescription.ModelType, "ModelDescriptionLink", new { modelDescription = elementDescription }) 21 | } 22 | else 23 | { 24 | @Html.DisplayFor(m => modelDescription) 25 | } 26 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/Parameters.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Collections.Generic 2 | @using System.Collections.ObjectModel 3 | @using System.Web.Http.Description 4 | @using System.Threading 5 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 6 | @model IList 7 | 8 | @if (Model.Count > 0) 9 | { 10 | 11 | 12 | 13 | 14 | 15 | @foreach (ParameterDescription parameter in Model) 16 | { 17 | ModelDescription modelDescription = parameter.TypeDescription; 18 | 19 | 20 | 23 | 26 | 39 | 40 | } 41 | 42 |
NameDescriptionTypeAdditional information
@parameter.Name 21 |

@parameter.Documentation

22 |
24 | @Html.DisplayFor(m => modelDescription.ModelType, "ModelDescriptionLink", new { modelDescription = modelDescription }) 25 | 27 | @if (parameter.Annotations.Count > 0) 28 | { 29 | foreach (var annotation in parameter.Annotations) 30 | { 31 |

@annotation.Documentation

32 | } 33 | } 34 | else 35 | { 36 |

None.

37 | } 38 |
43 | } 44 | else 45 | { 46 |

None.

47 | } 48 | 49 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/Samples.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Net.Http.Headers 2 | @model Dictionary 3 | 4 | @{ 5 | // Group the samples into a single tab if they are the same. 6 | Dictionary samples = Model.GroupBy(pair => pair.Value).ToDictionary( 7 | pair => String.Join(", ", pair.Select(m => m.Key.ToString()).ToArray()), 8 | pair => pair.Key); 9 | var mediaTypes = samples.Keys; 10 | } 11 |
12 | @foreach (var mediaType in mediaTypes) 13 | { 14 |

@mediaType

15 |
16 | Sample: 17 | @{ 18 | var sample = samples[mediaType]; 19 | if (sample == null) 20 | { 21 |

Sample not available.

22 | } 23 | else 24 | { 25 | @Html.DisplayFor(s => sample); 26 | } 27 | } 28 |
29 | } 30 |
-------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/SimpleTypeModelDescription.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 2 | @model SimpleTypeModelDescription 3 | @Model.Documentation -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/DisplayTemplates/TextSample.cshtml: -------------------------------------------------------------------------------- 1 | @using Sample.MvcFramework.Areas.HelpPage 2 | @model TextSample 3 | 4 |
5 | @Model.Text
6 | 
-------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using System.Web.Http.Controllers 3 | @using System.Web.Http.Description 4 | @using System.Collections.ObjectModel 5 | @using Sample.MvcFramework.Areas.HelpPage.Models 6 | @model Collection 7 | 8 | @{ 9 | ViewBag.Title = "ASP.NET Web API Help Page"; 10 | 11 | // Group APIs by controller 12 | ILookup apiGroups = Model.ToLookup(api => api.ActionDescriptor.ControllerDescriptor); 13 | } 14 | 15 | 16 |
17 |
18 |
19 |

@ViewBag.Title

20 |
21 |
22 |
23 |
24 | 32 |
33 | @foreach (var group in apiGroups) 34 | { 35 | @Html.DisplayFor(m => group, "ApiGroup") 36 | } 37 |
38 |
39 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Help/ResourceModel.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Web.Http 2 | @using Sample.MvcFramework.Areas.HelpPage.ModelDescriptions 3 | @model ModelDescription 4 | 5 | 6 |
7 | 14 |

@Model.Name

15 |

@Model.Documentation

16 |
17 | @Html.DisplayFor(m => Model) 18 |
19 |
20 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @ViewBag.Title 7 | @RenderSection("scripts", required: false) 8 | 9 | 10 | @RenderBody() 11 | 12 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Areas/HelpPage/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | // Change the Layout path below to blend the look and feel of the help page with your existing web pages 3 | Layout = "~/Views/Shared/_Layout.cshtml"; 4 | } -------------------------------------------------------------------------------- /Sample.MvcFramework/Content/Site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Set padding to keep content from hitting the edges */ 7 | .body-content { 8 | padding-left: 15px; 9 | padding-right: 15px; 10 | } 11 | 12 | /* Set width on the form input elements since they're 100% wide by default */ 13 | input, 14 | select, 15 | textarea { 16 | max-width: 280px; 17 | } 18 | 19 | .navbar-inverse .navbar-toggle:hover, 20 | .navbar-inverse .navbar-toggle:focus { 21 | background-color: #777; 22 | border-color: #fff 23 | } 24 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Controllers/CaptchaController.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Web; 7 | using System.Web.Mvc; 8 | 9 | namespace Sample.MvcFramework.Controllers 10 | { 11 | public class CaptchaController : Controller 12 | { 13 | [HttpGet] 14 | public ActionResult Index() 15 | { 16 | var id = Guid.NewGuid().ToString("N"); 17 | var captchaData = CaptchaHelper.Generate(id); 18 | var output = new CaptchaResponse 19 | { 20 | Id = id, 21 | Base64 = captchaData.Base64 22 | }; 23 | return Json(output, JsonRequestBehavior.AllowGet); 24 | 25 | } 26 | 27 | /// 28 | /// 演示时使用HttpGet传参方便,这里仅做返回处理 29 | /// 30 | [HttpGet()] 31 | public bool Validate(string id, string code) 32 | { 33 | return CaptchaHelper.Validate(id, code); 34 | } 35 | } 36 | 37 | public class CaptchaResponse 38 | { 39 | public string Id { get; set; } 40 | public string Base64 { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | 7 | namespace Sample.MvcFramework.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | public ActionResult Index() 12 | { 13 | ViewBag.Title = "Home Page"; 14 | 15 | return View(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Sample.MvcFramework.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core; 2 | using Lazy.Captcha.Core.Generator; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Web; 7 | using System.Web.Http; 8 | using System.Web.Mvc; 9 | using System.Web.Optimization; 10 | using System.Web.Routing; 11 | 12 | namespace Sample.MvcFramework 13 | { 14 | public class WebApiApplication : System.Web.HttpApplication 15 | { 16 | protected void Application_Start() 17 | { 18 | AreaRegistration.RegisterAllAreas(); 19 | GlobalConfiguration.Configure(WebApiConfig.Register); 20 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 21 | RouteConfig.RegisterRoutes(RouteTable.Routes); 22 | BundleConfig.RegisterBundles(BundleTable.Bundles); 23 | CaptchaConfig(); 24 | } 25 | 26 | private void CaptchaConfig() 27 | { 28 | var captchaService = CaptchaServiceBuilder 29 | .New() 30 | .Width(98) 31 | .Height(35) 32 | .FontSize(20) 33 | .CaptchaType(CaptchaType.ARITHMETIC) 34 | .FontFamily(DefaultFontFamilys.Instance.Ransom) 35 | .InterferenceLineCount(3) 36 | .Animation(false) 37 | .Build(); 38 | CaptchaHelper.Initialization(captchaService); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的常规信息是通过以下项进行控制的 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Sample.MvcFramework")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Sample.MvcFramework")] 13 | [assembly: AssemblyCopyright("版权所有(C) 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 将使此程序集中的类型 18 | // 对 COM 组件不可见。如果需要 19 | // COM,在该类型上将 ComVisible 属性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于 typelib 的 ID 23 | [assembly: Guid("93a908a8-010d-4f6e-8d78-e1c7082bb5d2")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 内部版本号 30 | // 修订号 31 | // 32 | // 你可以指定所有值,也可以让修订版本和内部版本号采用默认值, 33 | // 方法是按如下所示使用 "*": 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | 
2 |

ASP.NET

3 |

ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS, and JavaScript.

4 |

Learn more »

5 |
6 |
7 |
8 |

Getting started

9 |

ASP.NET Web API is a framework that makes it easy to build HTTP services that reach 10 | a broad range of clients, including browsers and mobile devices. ASP.NET Web API 11 | is an ideal platform for building RESTful applications on the .NET Framework.

12 |

Learn more »

13 |
14 |
15 |

Get more libraries

16 |

NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.

17 |

Learn more »

18 |
19 |
20 |

Web Hosting

21 |

You can easily find a web hosting company that offers the right mix of features and price for your applications.

22 |

Learn more »

23 |
24 |
25 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 错误 7 | 8 | 9 |
10 |

错误。

11 |

处理你的请求时出错。

12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | @ViewBag.Title - 我的 ASP.NET 应用程序 8 | @Styles.Render("~/Content/css") 9 | @Scripts.Render("~/bundles/modernizr") 10 | 11 | 12 | 30 |
31 | @RenderBody() 32 |
33 |
34 |

© @DateTime.Now.Year - 我的 ASP.NET 应用程序

35 |
36 |
37 | 38 | @Scripts.Render("~/bundles/jquery") 39 | @Scripts.Render("~/bundles/bootstrap") 40 | @RenderSection("scripts", required: false) 41 | 42 | 43 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } 4 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Sample.MvcFramework/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Sample.MvcFramework/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.MvcFramework/favicon.ico -------------------------------------------------------------------------------- /Sample.MvcFramework/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.MvcFramework/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /Sample.MvcFramework/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.MvcFramework/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /Sample.MvcFramework/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.MvcFramework/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /Sample.MvcFramework/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.MvcFramework/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /Sample.MvcFramework/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Sample.NetCore/Controllers/CaptchaController.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/Controllers/CaptchaController.cs -------------------------------------------------------------------------------- /Sample.NetCore/CustomFonts/BunnyeggsRegular-8M5aZ.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/CustomFonts/BunnyeggsRegular-8M5aZ.ttf -------------------------------------------------------------------------------- /Sample.NetCore/CustomFonts/KgHappy-wWZZ.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/CustomFonts/KgHappy-wWZZ.ttf -------------------------------------------------------------------------------- /Sample.NetCore/CustomFonts/WhoaSaucePersonalUseBold-mLmV5.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/CustomFonts/WhoaSaucePersonalUseBold-mLmV5.ttf -------------------------------------------------------------------------------- /Sample.NetCore/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM registry.cn-hangzhou.aliyuncs.com/newbe36524/aspnet:6.0 AS base 4 | WORKDIR /app 5 | EXPOSE 80 6 | EXPOSE 443 7 | 8 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build 9 | WORKDIR /src 10 | COPY ["Sample.NetCore/Sample.NetCore.csproj", "Sample.NetCore/"] 11 | COPY ["Lazy.Captcha.Core/Lazy.Captcha.Core.csproj", "Lazy.Captcha.Core/"] 12 | RUN dotnet restore "Sample.NetCore/Sample.NetCore.csproj" 13 | COPY . . 14 | WORKDIR "/src/Sample.NetCore" 15 | RUN dotnet build "Sample.NetCore.csproj" -c Release -o /app/build 16 | 17 | FROM build AS publish 18 | RUN dotnet publish "Sample.NetCore.csproj" -c Release -o /app/publish /p:UseAppHost=false 19 | 20 | FROM base AS final 21 | WORKDIR /app 22 | COPY --from=publish /app/publish . 23 | 24 | #修改apt-get源,加速apt下载 25 | RUN sed -i s@/deb.debian.org/@/mirrors.163.com/@g /etc/apt/sources.list 26 | RUN cat /etc/apt/sources.list 27 | #安装fontconfig 28 | RUN apt-get clean 29 | RUN apt-get update && apt-get install -y fontconfig 30 | 31 | ENTRYPOINT ["dotnet", "Sample.NetCore.dll"] -------------------------------------------------------------------------------- /Sample.NetCore/Program.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/Program.cs -------------------------------------------------------------------------------- /Sample.NetCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Sample.NetCore": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "index.html", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "https://localhost:7220;http://localhost:5220" 12 | }, 13 | "IIS Express": { 14 | "commandName": "IISExpress", 15 | "launchBrowser": true, 16 | "launchUrl": "index.html", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "Docker": { 22 | "commandName": "Docker", 23 | "launchBrowser": true, 24 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/index.html", 25 | "publishAllPorts": true, 26 | "useSSL": true 27 | } 28 | }, 29 | "$schema": "https://json.schemastore.org/launchsettings.json", 30 | "iisSettings": { 31 | "windowsAuthentication": false, 32 | "anonymousAuthentication": true, 33 | "iisExpress": { 34 | "applicationUrl": "http://localhost:48460", 35 | "sslPort": 44372 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Sample.NetCore/RandomCaptcha.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Lazy.Captcha.Core.Storage; 3 | using Lazy.Captcha.Core; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace Sample.NetCore 7 | { 8 | /// 9 | /// 随机验证码 10 | /// 11 | public class RandomCaptcha : DefaultCaptcha 12 | { 13 | private static readonly Random random = new(); 14 | private static readonly CaptchaType[] captchaTypes = Enum.GetValues(); 15 | 16 | public RandomCaptcha(IOptionsSnapshot options, IStorage storage) : base(options, storage) 17 | { 18 | } 19 | 20 | /// 21 | /// 更新选项 22 | /// 23 | /// 24 | protected override void ChangeOptions(CaptchaOptions options) 25 | { 26 | // 随机验证码类型 27 | options.CaptchaType = captchaTypes[random.Next(0, captchaTypes.Length)]; 28 | 29 | // 当是算数运算时,CodeLength是指运算数个数 30 | if (options.CaptchaType.IsArithmetic()) 31 | { 32 | options.CodeLength = 2; 33 | } 34 | else 35 | { 36 | options.CodeLength = 4; 37 | } 38 | 39 | // 如果包含中文时,使用kaiti字体,否则文字乱码 40 | if (options.CaptchaType.ContainsChinese()) 41 | { 42 | options.ImageOption.FontFamily = DefaultFontFamilys.Instance.Kaiti; 43 | options.ImageOption.FontSize = 24; 44 | } 45 | else 46 | { 47 | options.ImageOption.FontFamily = DefaultFontFamilys.Instance.Actionj; 48 | } 49 | 50 | // 动静随机 51 | options.ImageOption.Animation = random.Next(2) == 0; 52 | 53 | // 干扰线随机 54 | options.ImageOption.InterferenceLineCount = random.Next(1, 4); 55 | 56 | // 气泡随机 57 | options.ImageOption.BubbleCount = random.Next(1, 4); 58 | 59 | // 其他选项... 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sample.NetCore/ResourceFontFamilysFinder.cs: -------------------------------------------------------------------------------- 1 | using SkiaSharp; 2 | using System.Reflection; 3 | 4 | namespace Sample.NetCore 5 | { 6 | public class ResourceFontFamilysFinder 7 | { 8 | private static Lazy> _fontFamilies = new Lazy>(() => 9 | { 10 | var fontFamilies = new List(); 11 | var assembly = Assembly.GetExecutingAssembly(); 12 | var names = assembly.GetManifestResourceNames(); 13 | 14 | if (names?.Length > 0 == true) 15 | { 16 | foreach (var name in names) 17 | { 18 | if (!name.EndsWith("ttf")) continue; 19 | fontFamilies.Add(SKTypeface.FromStream(assembly.GetManifestResourceStream(name))); 20 | } 21 | } 22 | 23 | return fontFamilies; 24 | }); 25 | 26 | 27 | public static SKTypeface Find(string name) 28 | { 29 | return _fontFamilies.Value.First(e => e.FamilyName == name); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sample.NetCore/Sample.NetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8f38fd12-0eb2-4a15-992a-68e26293d7f5 8 | Linux 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Sample.NetCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Sample.NetCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "RedisCache": "localhost,password=Aa123456." 4 | }, 5 | "CaptchaOptions": { 6 | "CaptchaType": 10, 7 | "CodeLength": 2, 8 | "ExpirySeconds": 60, 9 | "IgnoreCase": true, 10 | "StoreageKeyPrefix": "", 11 | "ImageOption": { 12 | "Animation": false, 13 | "BackgroundColor": null, 14 | "ForegroundColors": null, 15 | "FontFamily": "Actionj", 16 | "FontSize": 26.0, 17 | "Width": 98, 18 | "Height": 35, 19 | "BubbleMinRadius": 3, 20 | "BubbleMaxRadius": 8, 21 | "BubbleCount": 0, 22 | "BubbleThickness": 1.0, 23 | "InterferenceLineCount": 0, 24 | "FrameDelay": 300, 25 | "Quality": 100, 26 | "TextBold": true 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Sample.NetCore/wwwroot/index.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: black; 3 | } 4 | 5 | .grid { 6 | height: 800px; 7 | width: 1280px; 8 | margin: auto; 9 | /* 设置容器布局为grid布局 */ 10 | display: grid; 11 | /* 指定每一行的宽度 每个宽度中间用空格隔开 */ 12 | grid-template-rows: repeat(13, 7.69%); 13 | /* 指定每一列的宽度 每个宽度中间用空格隔开 */ 14 | grid-template-columns: repeat(12, 8.33%); 15 | margin-top:20px; 16 | } 17 | 18 | .grid .cell { 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | color: white; 24 | font-size: 10px; 25 | border: 1px solid #202020; 26 | word-break: break-word; 27 | } 28 | 29 | .grid .cell img{ 30 | border-radius: 1px; 31 | } 32 | 33 | .unsupport{ 34 | color: #8f8f8f; 35 | } 36 | 37 | .tip { 38 | color: #8f8f8f; 39 | width: 1280px; 40 | margin: auto; 41 | margin-top: 30px; 42 | font-size: 12px; 43 | font-weight: bold; 44 | } -------------------------------------------------------------------------------- /Sample.NetCore/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 | 13 |
14 | 粗体 15 |
16 | 17 |
18 | 19 |
类型/字体
20 |
{{font}}
21 | 22 | 30 | 31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Sample.NetCore/wwwroot/index.js: -------------------------------------------------------------------------------- 1 | Vue.component('lazy-img', { 2 | template: "", 3 | props: { 4 | src: { 5 | type: String, 6 | required: false, 7 | default: () => { 8 | return this.url; 9 | } 10 | }, 11 | }, 12 | data() { 13 | return { 14 | url: 'loading.gif' 15 | } 16 | }, 17 | watch: { 18 | src: { 19 | immediate: true, 20 | handler() { 21 | this.url = 'loading.gif' 22 | var newImg = new Image() 23 | newImg.src = this.src 24 | newImg.onerror = () => { 25 | newImg.src = this.url 26 | } 27 | newImg.onload = () => { 28 | this.url = newImg.src 29 | } 30 | } 31 | } 32 | }, 33 | mounted() { 34 | 35 | } 36 | }) 37 | 38 | 39 | new Vue({ 40 | el: '#app', 41 | data() { 42 | return { 43 | types: [ 44 | 'DEFAULT', 'CHINESE', 'NUMBER', 'NUMBER_ZH_CN', 'NUMBER_ZH_HK', 'WORD', 'WORD_LOWER', 45 | 'WORD_UPPER', 'WORD_NUMBER_LOWER', 'WORD_NUMBER_UPPER', 'ARITHMETIC', 'ARITHMETIC_ZH' 46 | ], 47 | fonts: ['Actionj', 'Fresnel', 'Kaiti', 'Prefix', 'Ransom', 'Scandal', 'Epilog', 'Headache', 'Lexo', 'Progbot', 'Robot'], 48 | groupCaptchas: [], 49 | textBold: true 50 | } 51 | }, 52 | mounted() { 53 | this.generate() 54 | }, 55 | methods: { 56 | handleChange() { 57 | this.generate() 58 | }, 59 | generate() { 60 | let id = 0 61 | 62 | this.groupCaptchas = [] 63 | for (let i = 0; i < this.types.length; i++) { 64 | let typeCaptchas = { 65 | type: this.types[i], 66 | captchas: [] 67 | } 68 | for (let j = 0; j < this.fonts.length; j++) { 69 | let isSupport = this.isSupport(this.types[i], this.fonts[j]) 70 | typeCaptchas.captchas.push({ 71 | type: this.types[i], 72 | font: this.fonts[j], 73 | url: `captcha/dynamic?id=${++id}&type=${this.types[i]}&font=${this.fonts[j]}&textBold=${this.textBold}&t=${new Date}`, 74 | isSupport: isSupport 75 | }) 76 | } 77 | this.groupCaptchas.push(typeCaptchas) 78 | } 79 | }, 80 | isSupport(type, font) { 81 | //类型为中文,仅支持Kaiti 82 | if ((type === 'CHINESE' || type === 'NUMBER_ZH_CN' || type === 'NUMBER_ZH_HK' || type === 'ARITHMETIC_ZH') && font !== 'Kaiti') return false 83 | // 其他个例 84 | if (type === 'ARITHMETIC' && font === 'Fresnel') return false 85 | if (type === 'ARITHMETIC' && font === 'Ransom') return false 86 | if (type === 'ARITHMETIC' && font === 'Progbot') return false 87 | 88 | return true 89 | } 90 | }, 91 | }) -------------------------------------------------------------------------------- /Sample.NetCore/wwwroot/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/wwwroot/loading.gif -------------------------------------------------------------------------------- /Sample.NetCore/wwwroot/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/Sample.NetCore/wwwroot/loading.png -------------------------------------------------------------------------------- /Sample.Winfrom/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Sample.Winfrom/Helpers/UIHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | 8 | namespace Sample.Winfrom.Helpers 9 | { 10 | public class UIHelper 11 | { 12 | /// 13 | /// Invoke 14 | /// 15 | /// 16 | /// 17 | public static void Invoke(Control control, Action action) 18 | { 19 | Action del = delegate () 20 | { 21 | action(); 22 | }; 23 | control.Invoke(del); 24 | } 25 | 26 | /// 27 | /// 显示对话框 28 | /// 29 | /// 30 | /// 31 | public static void ShowMessageBox(Control control, string message) 32 | { 33 | Invoke(control, () => 34 | { 35 | Clipboard.SetDataObject(message); 36 | MessageBox.Show(control, message); 37 | }); 38 | } 39 | 40 | /// 41 | /// 显示对话框 42 | /// 43 | /// 44 | /// 45 | /// 46 | /// 47 | public static DialogResult ShowMessageBox(Control control, string message, MessageBoxButtons messageBoxButtons) 48 | { 49 | DialogResult reslt = DialogResult.None; 50 | UIHelper.Invoke(control, () => 51 | { 52 | Clipboard.SetDataObject(message); 53 | reslt = MessageBox.Show(control, "确认", message, messageBoxButtons); 54 | }); 55 | return reslt; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Sample.Winfrom/Helpers/UnitHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Sample.Winfrom.Helpers 8 | { 9 | internal class UnitHelper 10 | { 11 | public static String FormatFileSize(long fileSize) 12 | { 13 | if (fileSize < 0) 14 | { 15 | throw new ArgumentOutOfRangeException("fileSize"); 16 | } 17 | else if (fileSize >= 1024 * 1024 * 1024) 18 | { 19 | return string.Format("{0:########0.00} GB", ((Double)fileSize) / (1024 * 1024 * 1024)); 20 | } 21 | else if (fileSize >= 1024 * 1024) 22 | { 23 | return string.Format("{0:####0.00} MB", ((Double)fileSize) / (1024 * 1024)); 24 | } 25 | else if (fileSize >= 1024) 26 | { 27 | return string.Format("{0:####0.00} KB", ((Double)fileSize) / 1024); 28 | } 29 | else 30 | { 31 | return string.Format("{0} bytes", fileSize); 32 | } 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sample.Winfrom/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | 17, 17 125 | 126 | 127 | 270, 17 128 | 129 | 130 | 270, 17 131 | 132 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/CaptchaImageGeneratorOptionJsonModel.cs: -------------------------------------------------------------------------------- 1 |  2 | using Lazy.Captcha.Core; 3 | using SkiaSharp; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Sample.Winfrom.Models 11 | { 12 | public class CaptchaImageGeneratorOptionJsonModel 13 | { 14 | /// 15 | /// 是否启用动画 16 | /// 17 | public bool Animation { get; set; } 18 | /// 19 | /// 背景色 20 | /// 21 | public string BackgroundColor { get; set; } 22 | /// 23 | /// 前景色 24 | /// 25 | public string ForegroundColors { get; set; } 26 | /// 27 | /// FontFamily 28 | /// 29 | public string FontFamily { get; set; } 30 | /// 31 | /// 字体大小 32 | /// 33 | public float FontSize { get; set; } 34 | 35 | /// 36 | /// 验证码的宽 37 | /// 38 | public int Width { get; set; } 39 | /// 40 | /// 验证码高 41 | /// 42 | public int Height { get; set; } 43 | /// 44 | /// 气泡最小半径 45 | /// 46 | public int BubbleMinRadius { get; set; } 47 | /// 48 | /// 气泡最小半径 49 | /// 50 | public int BubbleMaxRadius { get; set; } 51 | /// 52 | /// 气泡数量 53 | /// 54 | public int BubbleCount { get; set; } 55 | /// 56 | /// 气泡边沿厚度 57 | /// 58 | public float BubbleThickness { get; set; } 59 | /// 60 | /// 干扰线数量 61 | /// 62 | public int InterferenceLineCount { get; set; } 63 | /// 64 | /// 每帧延迟,Animation=true时有效 65 | /// 66 | public int FrameDelay { get; set; } 67 | /// 68 | /// 图片质量(影响生成图片的大小) 69 | /// 70 | public int Quality { get; set; } = 100; 71 | /// 72 | /// 文本粗体 73 | /// 74 | public bool TextBold { get; set; } = false; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/CaptchaOptionsJsonModel.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator.Image.Option; 2 | using Lazy.Captcha.Core.Generator; 3 | using Lazy.Captcha.Core; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Sample.Winfrom.Models 11 | { 12 | public class CaptchaOptionsJsonModel 13 | { 14 | /// 15 | /// 验证码类型 16 | /// 17 | public int CaptchaType { get; set; } 18 | 19 | /// 20 | /// 验证码长度 当CaptchaType为ARITHMETIC, ARITHMETIC_ZH时, 长度代表乘数个数 21 | /// 22 | public int CodeLength { get; set; } 23 | 24 | /// 25 | /// 过期时长 26 | /// 27 | public int ExpirySeconds { get; set; } 28 | 29 | /// 30 | /// code比较是否忽略大小写 31 | /// 32 | public bool IgnoreCase { get; set; } 33 | 34 | /// 35 | /// 存储键前缀 36 | /// 37 | public string StoreageKeyPrefix { get; set; } 38 | 39 | /// 40 | /// 图片选项 41 | /// 42 | public CaptchaImageGeneratorOptionJsonModel ImageOption { get; set; } = new CaptchaImageGeneratorOptionJsonModel(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/CaptchaOptionsWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Sample.Winfrom.Models 8 | { 9 | public class CaptchaOptionsWrapper 10 | { 11 | public CaptchaOptionsJsonModel CaptchaOptions { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/CaptchaTypeOption.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | 3 | namespace Sample.Winfrom.Models 4 | { 5 | public class CaptchaTypeOption : Option 6 | { 7 | public CaptchaTypeOption(string text, CaptchaType value) 8 | { 9 | Text = text; 10 | Value = value; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/FontFamilyOption.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using SkiaSharp; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Sample.Winfrom.Models 10 | { 11 | public class FontFamilyOption : Option 12 | { 13 | public FontFamilyOption(string text, SKTypeface value) 14 | { 15 | Text = text; 16 | Value = value; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sample.Winfrom/Models/Option.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.Winfrom.Models 2 | { 3 | /// 4 | /// 选项 5 | /// 6 | /// 7 | public class Option 8 | { 9 | /// 10 | /// 选项文本 11 | /// 12 | public string Text { get; set; } 13 | /// 14 | /// 选项值 15 | /// 16 | public T Value { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sample.Winfrom/OptionProviders/CaptchaTypeOptionProvider.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Sample.Winfrom.Models; 3 | using System.Collections.Generic; 4 | 5 | namespace Sample.Winfrom.OptionProviders 6 | { 7 | public class CaptchaTypeOptionProvider 8 | { 9 | public static List Provide() 10 | { 11 | return new List 12 | { 13 | new CaptchaTypeOption("默认", CaptchaType.DEFAULT), 14 | new CaptchaTypeOption("中文汉字", CaptchaType.CHINESE), 15 | new CaptchaTypeOption("数字", CaptchaType.NUMBER), 16 | new CaptchaTypeOption("中文数字(小写)", CaptchaType.NUMBER_ZH_CN), 17 | new CaptchaTypeOption("中文数字(大写)", CaptchaType.NUMBER_ZH_HK), 18 | new CaptchaTypeOption("字母大小写", CaptchaType.WORD), 19 | new CaptchaTypeOption("字母小写", CaptchaType.WORD_LOWER), 20 | new CaptchaTypeOption("字母大写", CaptchaType.WORD_UPPER), 21 | new CaptchaTypeOption("字母数字小写", CaptchaType.WORD_NUMBER_LOWER), 22 | new CaptchaTypeOption("字母数字大写", CaptchaType.WORD_NUMBER_UPPER), 23 | new CaptchaTypeOption("阿拉伯数字运算", CaptchaType.ARITHMETIC), 24 | new CaptchaTypeOption("中文数字运算", CaptchaType.ARITHMETIC_ZH), 25 | }; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sample.Winfrom/OptionProviders/FontFamilyOptionProvider.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core; 2 | using Sample.Winfrom.Models; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Sample.Winfrom.OptionProviders 10 | { 11 | public class FontFamilyOptionProvider 12 | { 13 | public static List Provide() 14 | { 15 | return new List 16 | { 17 | new FontFamilyOption("Actionj", DefaultFontFamilys.Instance.Actionj), 18 | new FontFamilyOption("Kaiti", DefaultFontFamilys.Instance.Kaiti), 19 | new FontFamilyOption("Fresnel", DefaultFontFamilys.Instance.Fresnel), 20 | new FontFamilyOption("Prefix", DefaultFontFamilys.Instance.Prefix), 21 | new FontFamilyOption("Ransom", DefaultFontFamilys.Instance.Ransom), 22 | new FontFamilyOption("Scandal", DefaultFontFamilys.Instance.Scandal), 23 | new FontFamilyOption("Epilog", DefaultFontFamilys.Instance.Epilog), 24 | new FontFamilyOption("Headache", DefaultFontFamilys.Instance.Headache), 25 | new FontFamilyOption("Lexo", DefaultFontFamilys.Instance.Lexo), 26 | new FontFamilyOption("Progbot", DefaultFontFamilys.Instance.Progbot), 27 | new FontFamilyOption("Robot", DefaultFontFamilys.Instance.Robot), 28 | }; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sample.Winfrom/PerformanceTest.cs: -------------------------------------------------------------------------------- 1 | using Lazy.Captcha.Core.Generator; 2 | using Lazy.Captcha.Core; 3 | using Microsoft.Extensions.Options; 4 | using Sample.Winfrom.Models; 5 | using Sample.Winfrom.OptionProviders; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using System.Diagnostics; 12 | using System.Net.Sockets; 13 | 14 | namespace Sample.Winfrom 15 | { 16 | public class PerformanceTest 17 | { 18 | private CaptchaOptionsJsonModel options; 19 | private int loopCount; 20 | 21 | public event Action Progress; 22 | public event Action Complete; 23 | 24 | public PerformanceTest(CaptchaOptionsJsonModel options, int loopCount) 25 | { 26 | this.options = options; 27 | this.loopCount = loopCount; 28 | } 29 | 30 | public void Start() 31 | { 32 | var taskFactory = new TaskFactory(); 33 | taskFactory.StartNew(() => 34 | { 35 | var stopwatch = new Stopwatch(); 36 | stopwatch.Start(); 37 | 38 | long size = 0; 39 | 40 | for (var i = 0; i < loopCount; i++) 41 | { 42 | var fontFamily = FontFamilyOptionProvider.Provide().First(e => e.Text == options.ImageOption.FontFamily).Value; 43 | var service = CaptchaServiceBuilder 44 | .New() 45 | .CodeLength(options.CodeLength) 46 | .CaptchaType((CaptchaType)options.CaptchaType) 47 | .FontFamily(fontFamily) 48 | .FontSize(options.ImageOption.FontSize) 49 | .BubbleCount(options.ImageOption.BubbleCount) 50 | .BubbleThickness(options.ImageOption.BubbleThickness) 51 | .BubbleMinRadius(options.ImageOption.BubbleMinRadius) 52 | .BubbleMaxRadius(options.ImageOption.BubbleMaxRadius) 53 | .InterferenceLineCount(options.ImageOption.InterferenceLineCount) 54 | .Animation(options.ImageOption.Animation) 55 | .FrameDelay(options.ImageOption.FrameDelay) 56 | .Width(options.ImageOption.Width) 57 | .Height(options.ImageOption.Height) 58 | .Quality(options.ImageOption.Quality) 59 | .Build(); 60 | var captchaData = service.Generate(Guid.NewGuid().ToString()); 61 | if (Progress != null) Progress((int)((i + 1.0) / loopCount * 100.0)); 62 | 63 | size += captchaData.Bytes.Count(); 64 | } 65 | if (Complete != null) Complete(loopCount, stopwatch.ElapsedMilliseconds, size); 66 | 67 | }, TaskCreationOptions.LongRunning); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Sample.Winfrom/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace Sample.Winfrom 8 | { 9 | internal static class Program 10 | { 11 | /// 12 | /// 应用程序的主入口点。 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new MainForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("Sample.Winfrom")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Sample.Winfrom")] 13 | [assembly: AssemblyCopyright("Copyright © 2022")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("88d16fe4-b614-46f6-bd0a-daeeb2fcc88c")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 33 | //通过使用 "*",如下所示: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/DataSources/Sample.Winfrom.Models.CaptchaTypeOption.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | Sample.Winfrom.Models.CaptchaTypeOption, Sample.Winfrom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/DataSources/Sample.Winfrom.Models.FontFamilyOption.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | Sample.Winfrom.Models.FontFamilyOption, Sample.Winfrom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Sample.Winfrom.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sample.Winfrom.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Sample.Winfrom.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sample.Winfrom/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample.Winfrom/Sample.Winfrom.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {88D16FE4-B614-46F6-BD0A-DAEEB2FCC88C} 8 | WinExe 9 | Sample.Winfrom 10 | Sample.Winfrom 11 | v4.6.2 12 | 512 13 | true 14 | 15 | PackageReference 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Form 55 | 56 | 57 | MainForm.cs 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | MainForm.cs 72 | 73 | 74 | ResXFileCodeGenerator 75 | Resources.Designer.cs 76 | Designer 77 | 78 | 79 | True 80 | Resources.resx 81 | True 82 | 83 | 84 | 85 | 86 | SettingsSingleFileGenerator 87 | Settings.Designer.cs 88 | 89 | 90 | True 91 | Settings.settings 92 | True 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | {B640C86B-87E3-4CBE-94A9-2CA3AC704A08} 101 | Lazy.Captcha.Core 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | PreserveNewest 110 | 111 | 112 | PreserveNewest 113 | 114 | 115 | PreserveNewest 116 | 117 | 118 | PreserveNewest 119 | 120 | 121 | PreserveNewest 122 | 123 | 124 | 125 | 126 | 13.0.2 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /Sample.Winfrom/templates/highlight/jquery.highlight.css: -------------------------------------------------------------------------------- 1 | div.highlight { 2 | background:#FFFFFF; 3 | border:1px solid #E0E0E0; 4 | font-family:"Courier New",Courier,monospace; 5 | overflow: hidden; 6 | border-radius: 4px 4px 4px 4px; 7 | margin: 0 0 1.5em; 8 | } 9 | div.highlight pre{ 10 | width: 100%; 11 | overflow: auto; 12 | padding:0; 13 | margin:0; 14 | font-size:13px; 15 | clear: both; 16 | border-radius: 0; 17 | border: none; 18 | } 19 | 20 | /* tabs */ 21 | div.highlight ul.tabs { 22 | overflow: hidden; 23 | padding: 5px 0 5px 0; 24 | margin: 0; 25 | list-style: none; 26 | border-bottom: 1px solid #E0E0E0; 27 | width: 100%; 28 | position: relative; 29 | } 30 | div.highlight ul.tabs li { 31 | padding: 0; 32 | margin: 0 5px; 33 | float: left; 34 | background: none; 35 | border-bottom: 1px dashed #CCC; 36 | line-height:1.0em; 37 | color: #CCC; 38 | cursor: pointer; 39 | } 40 | div.highlight ul.tabs li.active { 41 | border-bottom: none; 42 | cursor: default; 43 | } 44 | 45 | /* pre */ 46 | div.highlight pre.code ol { 47 | margin: 0; 48 | padding:0 0 0 45px; 49 | background:#e7e5dc; 50 | } 51 | div.highlight pre.code ul { 52 | margin: 0; 53 | padding:0; 54 | } 55 | div.highlight pre.code ol li, 56 | div.highlight pre.code ul li { 57 | padding:0 0 0 5px; 58 | border-left:3px solid #CCC; 59 | background:#F8F8F8; 60 | } 61 | div.highlight pre.code ul li { 62 | border-left:none; 63 | } 64 | div.highlight pre.code ol li.even, 65 | div.highlight pre.code ul li.even { 66 | background-color:#FFFFFF; 67 | } 68 | div.highlight pre.source { 69 | display: none; 70 | padding:0 0 0 5px; 71 | } 72 | 73 | /* highligting */ 74 | pre.code .str { 75 | color: #0d0; 76 | } 77 | pre.code .var { 78 | color: #d00; 79 | } 80 | 81 | pre.code .kwd, 82 | pre.code .kwd span { 83 | color: #070; 84 | } 85 | pre.code .com, 86 | pre.code .com span { 87 | color:#008; 88 | font-style: italic; 89 | font-weight: normal; 90 | } 91 | pre.code .typ { 92 | color: #606; 93 | } 94 | pre.code .lit { 95 | color: #066; 96 | } 97 | pre.code .pun { 98 | color: #660; } 99 | pre.code .pln { 100 | color: #000; 101 | } 102 | pre.code .tag { 103 | color: #008; 104 | font-weight: bold; 105 | } 106 | pre.code .atn { 107 | color: #606; 108 | } 109 | pre.code .atv { 110 | color: #080; 111 | } 112 | pre.code .dec { 113 | color: #606; 114 | } 115 | pre.code .fnc, 116 | pre.code .fnc span { 117 | color: #00b; 118 | } 119 | 120 | /* css */ 121 | .css pre.code .kwd, 122 | .css pre.code .kwd span { 123 | color: #008; 124 | font-weight: bold; 125 | } 126 | /* php */ 127 | .php pre.code .str, 128 | .php pre.code .str span { 129 | color: #0d0; 130 | } 131 | .php pre.code .var, 132 | .php pre.code .var span { 133 | color: #b00; 134 | }; 135 | .php pre.code .com, 136 | .php pre.code .com span { 137 | color:#008; 138 | font-style: italic; 139 | font-weight: normal; 140 | } 141 | -------------------------------------------------------------------------------- /Sample.Winfrom/templates/scripts/demo.js: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /Sample.Winfrom/templates/tpl.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | SyntaxHighlighter Build Test Page 6 | 7 | 28 | 29 | 30 | 35 | 36 | 37 |
38 | {{data}}
39 |     
40 | 41 | 42 | -------------------------------------------------------------------------------- /字体裁剪/kaiti.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/字体裁剪/kaiti.ttf -------------------------------------------------------------------------------- /字体裁剪/kaiti_output.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pojianbing/LazyCaptcha/69ed3e5eab82e87b7399fc2ad43cf48b1e64bf5e/字体裁剪/kaiti_output.ttf -------------------------------------------------------------------------------- /字体裁剪/words.txt: -------------------------------------------------------------------------------- 1 | 的一国在人了有中是年和大业不为发会工经上地市要个产这出行作生家以成到日民来我部对进多全建他公开们场展时理新方主企资实学报制政济用同于法高长现本月定化加动合品重关机分力自外者区能设后就等体下万元社过前面农也得与说之员而务利电文事可种总改三各好金第司其从平代当天水省提商十管内小技位目起海所立已通入量子问度北保心还科委都术使明着次将增基名向门应里美由规今题记点计去强两些表系办教正条最达特革收二期并程厂如道际及西口京华任调性导组东路活广意比投决交统党南安此领结营项情解议义山先车然价放世间因共院步物界集把持无但城相书村求治取原处府研质信四运县军件育局干队团又造形级标联专少费效据手施权江近深更认果格几看没职服台式益想数单样只被亿老受优常销志战流很接乡头给至难观指创证织论别五协变风批见究支那查张精每林转划准做需传争税构具百或才积势举必型易视快李参回引镇首推思完消值该走装众责备州供包副极整确知贸己环话反身选亚么带采王策真女谈严斯况色打德告仅它气料神率识劳境源青护列兴许户马港则节款拉直案股光较河花根布线土克再群医清速律她族历非感占续师何影功负验望财类货约艺售连纪按讯史示象养获石食抓富模始住赛客越闻央席坚零一二三四五六七八九零壹贰叁肆伍陆柒捌玖abcdefghkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZABCDEFGHJKMNPQRSTUVWXYZ0123456789+-x/?=加减乘除 -------------------------------------------------------------------------------- /字体裁剪/裁剪命令.txt: -------------------------------------------------------------------------------- 1 | fonttools subset "kaiti.ttf" --text-file="words.txt" --output-file="kaiti_output.ttf" --------------------------------------------------------------------------------