Repository: manuelbl/QrCodeGenerator
Branch: master
Commit: d5d7336a2377
Files: 113
Total size: 1.0 MB
Directory structure:
gitextract_hpw2vdf4/
├── .config/
│ └── dotnet-tools.json
├── .github/
│ └── workflows/
│ ├── continuous-integration.yml
│ └── demos.yaml
├── .gitignore
├── Demo-ASP.NET-Core/
│ ├── Demo-ASP.NET-Core.csproj
│ ├── Demo-ASP.NET-Core.sln
│ ├── Program.cs
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── QrCodeBitmapExtensions.cs
│ ├── QrCodeController.cs
│ ├── README.md
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot/
│ ├── home.html
│ ├── styles.css
│ └── ui.js
├── Demo-ImageMagick/
│ ├── Demo-ImageMagick.csproj
│ ├── Demo-ImageMagick.sln
│ ├── Program.cs
│ ├── QrCodeImageExtensions.cs
│ └── README.md
├── Demo-ImageSharp/
│ ├── Demo-ImageSharp.csproj
│ ├── Demo-ImageSharp.sln
│ ├── Program.cs
│ ├── QrCodeBitmapExtensions.cs
│ └── README.md
├── Demo-QRCode-Variety/
│ ├── Demo-QRCode-Variety.csproj
│ ├── Demo-QRCode-Variety.sln
│ ├── Program.cs
│ └── README.md
├── Demo-SkiaSharp/
│ ├── Demo-SkiaSharp.csproj
│ ├── Demo-SkiaSharp.sln
│ ├── Program.cs
│ ├── QrCodeBitmapExtensions.cs
│ └── README.md
├── Demo-System-Drawing/
│ ├── Demo-System-Drawing.csproj
│ ├── Demo-System-Drawing.sln
│ ├── Program.cs
│ ├── QrCodeBitmapExtensions.cs
│ └── README.md
├── Demo-VCard/
│ ├── Program.cs
│ ├── VCardDemo.csproj
│ └── VCardDemo.sln
├── Demo-WinForms/
│ ├── Demo-WinForms.csproj
│ ├── Demo-WinForms.sln
│ ├── Form1.Designer.cs
│ ├── Form1.cs
│ ├── Form1.resx
│ ├── Program.cs
│ ├── QrCodeBitmapExtensions.cs
│ ├── QrCodeControl.cs
│ └── README.md
├── Demo-WinUI/
│ ├── Demo-WinUI/
│ │ ├── App.xaml
│ │ ├── App.xaml.cs
│ │ ├── Demo-WinUI.csproj
│ │ ├── MainViewModel.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── NativeMethods.txt
│ │ ├── Package.appxmanifest
│ │ ├── Properties/
│ │ │ ├── PublishProfiles/
│ │ │ │ ├── win-arm64.pubxml
│ │ │ │ ├── win-x64.pubxml
│ │ │ │ └── win-x86.pubxml
│ │ │ └── launchSettings.json
│ │ ├── QrCodeControl.xaml
│ │ ├── QrCodeControl.xaml.cs
│ │ ├── QrCodeDrawing.cs
│ │ └── app.manifest
│ ├── Demo-WinUI.sln
│ └── README.md
├── Demo-WindowsPresentationFoundation/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── AssemblyInfo.cs
│ ├── Demo-WindowsPresentationFoundation.csproj
│ ├── Demo-WindowsPresentationFoundation.sln
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── QrCodeDrawing.cs
│ ├── README.md
│ └── app.manifest
├── LICENSE
├── QrCodeGenerator/
│ ├── BitArrayExtensions.cs
│ ├── DataTooLongException.cs
│ ├── Graphics.cs
│ ├── Key.snk
│ ├── Objects.cs
│ ├── PngBuilder.cs
│ ├── QrCode.cs
│ ├── QrCodeGenerator.csproj
│ ├── QrSegment.cs
│ ├── QrSegmentAdvanced.cs
│ ├── ReedSolomonGenerator.cs
│ ├── docfx/
│ │ ├── api/
│ │ │ └── index.md
│ │ ├── docfx.json
│ │ └── index.md
│ └── docs/
│ └── README.md
├── QrCodeGenerator.sln
├── QrCodeGeneratorTest/
│ ├── BitArrayExtensionsTest.cs
│ ├── KanjiTest.cs
│ ├── PngTest.cs
│ ├── QrCodeBitmapTest.cs
│ ├── QrCodeDataProvider.cs
│ ├── QrCodeGeneratorTest.csproj
│ ├── QrCodeTest.cs
│ ├── QrCodeTestCase.cs
│ ├── QrSegmentEncodingTest.cs
│ ├── QrSegmentRegexTest.cs
│ ├── RandomData.cs
│ ├── StructuredAppendTest.cs
│ ├── SvgTest.cs
│ └── TestHelper.cs
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .config/dotnet-tools.json
================================================
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-validate": {
"version": "0.0.1-preview.304",
"commands": [
"dotnet-validate"
]
}
}
}
================================================
FILE: .github/workflows/continuous-integration.yml
================================================
name: Continuous Integration
on: [push, pull_request]
env:
Configuration: Release
ContinuousIntegrationBuild: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: true
TERM: xterm-256color
jobs:
package:
strategy:
matrix:
os: [ macos-latest, ubuntu-latest, windows-latest ]
fail-fast: false
runs-on: ${{ matrix.os }}
name: Build and run tests
steps:
- name: Checkout git repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.x
8.x
- name: Restore NuGet packages
run: dotnet restore
- name: Build solution
run: dotnet build --no-restore --verbosity normal
- name: Run tests
run: dotnet test --no-build --verbosity normal
- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: TestResults-${{ runner.os }}
path: TestResults-*.html
- name: Create and validate NuGet packages
run: |
dotnet tool restore
dotnet pack --no-build --verbosity normal
if: startsWith(matrix.os,'windows')
================================================
FILE: .github/workflows/demos.yaml
================================================
name: Demos
on: [push, pull_request]
env:
Configuration: Release
ContinuousIntegrationBuild: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_NOLOGO: true
DOTNET_SYSTEM_CONSOLE_ALLOW_ANSI_COLOR_REDIRECTION: true
TERM: xterm-256color
jobs:
build:
runs-on: windows-latest
name: Build demo projects
steps:
- name: Checkout git repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.x
8.x
- name: Create local NuGet source
run: |
mkdir ..\LocalPackages
$pkgdir = Resolve-Path ..\LocalPackages
dotnet nuget add source $pkgdir --name Local
- name: Build library package
run: |
dotnet restore
dotnet tool restore
dotnet pack --verbosity normal
- name: Install library package
run: |
$pkg = Resolve-Path QrCodeGenerator\bin\Release\Net.Codecrete.QrCodeGenerator.*.nupkg
nuget push $pkg -Source Local
- name: Build Demo-ImageSharp
run: dotnet build
working-directory: Demo-ImageSharp
- name: Build Demo-ASP.NET-Core
run: dotnet build
working-directory: Demo-ASP.NET-Core
- name: Build Demo-ImageMagick
run: dotnet build
working-directory: Demo-ImageMagick
- name: Build Demo-QRCode-Variety
run: dotnet build
working-directory: Demo-QRCode-Variety
- name: Build Demo-SkiaSharp
run: dotnet build
working-directory: Demo-SkiaSharp
- name: Build Demo-System-Drawing
run: dotnet build
working-directory: Demo-System-Drawing
- name: Build Demo-VCard
run: dotnet build
working-directory: Demo-VCard
- name: Build Demo-WindowsPresentationFoundation
run: dotnet build
working-directory: Demo-WindowsPresentationFoundation
- name: Build Demo-WinForms
run: dotnet build
working-directory: Demo-WinForms
- name: Build Demo-WinUI
run: dotnet build
working-directory: Demo-WinUI
================================================
FILE: .gitignore
================================================
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Bb]in/
[Oo]bj/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Visual Studio Code
.vscode/
# Rider
.idea/
================================================
FILE: Demo-ASP.NET-Core/Demo-ASP.NET-Core.csproj
================================================
net8.0Net.Codecrete.QrCodeGenerator.Demo
================================================
FILE: Demo-ASP.NET-Core/Demo-ASP.NET-Core.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31919.166
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-ASP.NET-Core", "Demo-ASP.NET-Core.csproj", "{8EA82CD7-A88E-4A93-94B0-FA0C7DD1C7F1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8EA82CD7-A88E-4A93-94B0-FA0C7DD1C7F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EA82CD7-A88E-4A93-94B0-FA0C7DD1C7F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EA82CD7-A88E-4A93-94B0-FA0C7DD1C7F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EA82CD7-A88E-4A93-94B0-FA0C7DD1C7F1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2902DABB-C256-46C5-AF46-35600F5F7A0E}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-ASP.NET-Core/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup();
});
}
}
================================================
FILE: Demo-ASP.NET-Core/Properties/launchSettings.json
================================================
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:25726",
"sslPort": 44337
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Demo_ASP.NET_Core": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
================================================
FILE: Demo-ASP.NET-Core/QrCodeBitmapExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using SkiaSharp;
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator
{
public static class QrCodeBitmapExtensions
{
///
/// The background color.
/// The foreground color.
public static SKBitmap ToBitmap(this QrCode qrCode, int scale, int border, SKColor foreground, SKColor background)
{
// check arguments
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Value out of range");
}
int size = qrCode.Size;
int dim = (size + border * 2) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large");
}
// create bitmap
SKBitmap bitmap = new SKBitmap(dim, dim, SKColorType.Rgb888x, SKAlphaType.Opaque);
using (SKCanvas canvas = new SKCanvas(bitmap))
{
// draw background
using (SKPaint paint = new SKPaint { Color = background })
{
canvas.DrawRect(0, 0, dim, dim, paint);
}
// draw modules
using (SKPaint paint = new SKPaint { Color = foreground })
{
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
canvas.DrawRect((x + border) * scale, (y + border) * scale, scale, scale, paint);
}
}
}
}
}
return bitmap;
}
///
/// Creates a bitmap (raster image) of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The resulting bitmap uses the pixel format .
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static SKBitmap ToBitmap(this QrCode qrCode, int scale, int border)
{
return qrCode.ToBitmap(scale, border, SKColors.Black, SKColors.White);
}
///
/// The background color.
/// The foreground color.
public static byte[] ToPng(this QrCode qrCode, int scale, int border, SKColor foreground, SKColor background)
{
using SKBitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 90);
return data.ToArray();
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static byte[] ToPng(this QrCode qrCode, int scale, int border)
{
return qrCode.ToPng(scale, border, SKColors.Black, SKColors.White);
}
///
/// The background color.
/// The foreground color.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border, SKColor foreground, SKColor background)
{
using SKBitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 90);
using FileStream stream = File.OpenWrite(filename);
data.SaveTo(stream);
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border)
{
qrCode.SaveAsPng(filename, scale, border, SKColors.Black, SKColors.White);
}
}
}
================================================
FILE: Demo-ASP.NET-Core/QrCodeController.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.AspNetCore.Mvc;
using System;
using System.Text;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
///
/// Controller for generating QR code as PNG or SVG images
///
[ApiController]
public class QrCodeController : ControllerBase
{
private static readonly QrCode.Ecc[] errorCorrectionLevels = { QrCode.Ecc.Low, QrCode.Ecc.Medium, QrCode.Ecc.Quartile, QrCode.Ecc.High };
///
/// Generates QR code as PNG image
///
/// Text to encode in QR code
/// Error correction level (0: low ... 3: high)
/// Border width in multiples of a module (QR code pixel)
/// PNG image
[HttpGet("qrcode/png")]
[ResponseCache(Duration = 2592000)]
public ActionResult GeneratePng([FromQuery(Name = "text")] string text,
[FromQuery(Name = "ecc")] int? ecc, [FromQuery(Name = "border")] int? borderWidth)
{
ecc = Math.Clamp(ecc ?? 1, 0, 3);
borderWidth = Math.Clamp(borderWidth ?? 3, 0, 999999);
var qrCode = QrCode.EncodeText(text, errorCorrectionLevels[(int)ecc]);
byte[] png = qrCode.ToPng(20, (int)borderWidth);
return new FileContentResult(png, "image/png");
}
///
/// Generates QR code as SVG image
///
/// Text to encode in QR code
/// Error correction level (0: low ... 3: high)
/// Border width in multiples of a module (QR code pixel)
/// SVG image
[HttpGet("qrcode/svg")]
[ResponseCache(Duration = 2592000)]
public ActionResult GenerateSvg([FromQuery(Name = "text")] string text,
[FromQuery(Name = "ecc")] int? ecc, [FromQuery(Name = "border")] int? borderWidth)
{
ecc = Math.Clamp(ecc ?? 1, 0, 3);
borderWidth = Math.Clamp(borderWidth ?? 3, 0, 999999);
var qrCode = QrCode.EncodeText(text, errorCorrectionLevels[(int)ecc]);
byte[] svg = Encoding.UTF8.GetBytes(qrCode.ToSvgString((int)borderWidth));
return new FileContentResult(svg, "image/svg+xml; charset=utf-8");
}
}
}
================================================
FILE: Demo-ASP.NET-Core/README.md
================================================
# Sample code for ASP.NET Core
This example program shows how to create a QR codes in an ASP.NET core application.
The [`QrCodeController`](QrCodeController.cs) class receives the QR code text, border width and error correction level as query parameters and generates the QR code, either as an SVG or PNG.
For PNG generation, the [SkiaSharp](https://github.com/mono/SkiaSharp) rasterization library is used.
================================================
FILE: Demo-ASP.NET-Core/Startup.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
var rewriter = new RewriteOptions();
rewriter.AddRewrite("^$", "home.html", skipRemainingRules: false);
app.UseRewriter(rewriter);
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
================================================
FILE: Demo-ASP.NET-Core/appsettings.Development.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
================================================
FILE: Demo-ASP.NET-Core/appsettings.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
================================================
FILE: Demo-ASP.NET-Core/wwwroot/home.html
================================================
QR Code
QR Code
================================================
FILE: Demo-ASP.NET-Core/wwwroot/styles.css
================================================
.content {
max-width: 768px;
margin-left: auto;
margin-right: auto;
padding-left: 1em;
padding-right: 1em;
background: #eee;
}
#qrcode {
width: 80%;
max-width: 400px;
margin-top: 1em;
margin-bottom: 2em;
margin-left: auto;
margin-right: auto;
display: block;
}
#text {
width: 90%;
}
.more-space {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
h1 {
letter-spacing: 0;
text-align: center;
width: 100%;
}
================================================
FILE: Demo-ASP.NET-Core/wwwroot/ui.js
================================================
(function () {
var qrCodeImage;
var textField;
var borderField;
var eccSelect;
function updateQrCode() {
var url = new URL('qrcode/svg', document.baseURI);
url.searchParams.append('text', textField.value);
url.searchParams.append('ecc', eccSelect.value);
url.searchParams.append('border', borderField.value);
qrCodeImage.src = url;
}
function init() {
textField = document.getElementById('text');
qrCodeImage = document.getElementById('qrcode');
borderField = document.getElementById('border');
eccSelect = document.getElementById('ecc');
textField.onchange = function () { updateQrCode(); }
textField.oninput = function () { updateQrCode(); }
borderField.onchange = function () { updateQrCode(); }
borderField.oninput = function () { updateQrCode(); }
eccSelect.onchange = function () { updateQrCode(); }
}
init();
})();
================================================
FILE: Demo-ImageMagick/Demo-ImageMagick.csproj
================================================
Exenet8.0Net.Codecrete.QrCodeGenerator.Demoenableenable
================================================
FILE: Demo-ImageMagick/Demo-ImageMagick.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32630.192
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-ImageMagick", "Demo-ImageMagick.csproj", "{E4F86D1E-F08C-4BFE-BC37-9BED8A411E88}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E4F86D1E-F08C-4BFE-BC37-9BED8A411E88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4F86D1E-F08C-4BFE-BC37-9BED8A411E88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4F86D1E-F08C-4BFE-BC37-9BED8A411E88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4F86D1E-F08C-4BFE-BC37-9BED8A411E88}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BC2EF2FB-30F7-431B-B92C-05E9C7B7B07B}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-ImageMagick/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2022 suxiaobu9, Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using ImageMagick;
using Net.Codecrete.QrCodeGenerator;
string text = "Hello, world!",
fileName = "hello-world-QR.png";
var qr = QrCode.EncodeText(text, QrCode.Ecc.Medium);
qr.SaveAsPng(fileName, 10, 4, MagickColors.Black, MagickColors.White);
================================================
FILE: Demo-ImageMagick/QrCodeImageExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2022 suxiaobu9, Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using ImageMagick;
using ImageMagick.Drawing;
namespace Net.Codecrete.QrCodeGenerator;
public static class QrCodeImageExtensions
{
///
/// Creates a image of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The background color.
/// The foreground color.
///
///
public static MagickImage ToImage(this QrCode qrCode, int scale, int border, MagickColor foreground, MagickColor background)
{
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), " Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), " Value out of range");
}
var size = qrCode.Size;
var dim = (uint)((size + border * 2) * scale);
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), " Scale or border too large");
}
var image = new MagickImage(background, dim, dim)
{
Format = MagickFormat.Png,
};
var drawables = new Drawables();
drawables.FillColor(foreground);
for (var x = 0; x < size; x++)
{
var pointerX = (x + border) * scale;
for (var y = 0; y < size; y++)
{
if (qrCode.GetModule(x, y))
{
var pointerY = (y + border) * scale;
drawables.Rectangle(pointerX, pointerY, pointerX + scale - 1, pointerY + scale - 1);
}
}
}
drawables.Draw(image);
return image;
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The foreground color.
/// The background color.
///
public static byte[] ToPng(this QrCode qrCode, int scale, int border, MagickColor foreground, MagickColor background)
{
using var image = qrCode.ToImage(scale, border, foreground, background);
return image.ToByteArray();
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The foreground color.
/// The background color.
public static void SaveAsPng(this QrCode qrCode, string fileName, int scale, int border, MagickColor foreground, MagickColor background)
{
using var image = qrCode.ToImage(scale, border, foreground, background);
image.Write(fileName);
}
}
================================================
FILE: Demo-ImageMagick/README.md
================================================
# Saving as PNG using Magick.NET
This example program shows how to create a QR code and save it as a PNG file using the [Magick.NET](https://github.com/dlemstra/Magick.NET) image manipulation library (based on ImageMagick).
================================================
FILE: Demo-ImageSharp/Demo-ImageSharp.csproj
================================================
Exenet8.0Net.Codecrete.QrCodeGenerator.DemoNet.Codecrete.QrCodeGenerator.Demo2.1.0Manuel Bleichenbacher, Project NayukiQR Code Generator for .NETDemo application for QR Code GenerationCopyright Manuel Bleichenbacher and Project Nayuki (MIT License)https://opensource.org/licenses/MIThttps://github.com/manuelbl/QrCodeGeneratorhttps://github.com/manuelbl/QrCodeGeneratorCodecretePreserveNewest
================================================
FILE: Demo-ImageSharp/Demo-ImageSharp.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30611.23
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo-ImageSharp", "Demo-ImageSharp.csproj", "{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94BC47F9-3AE8-471A-AC3F-CDEFA1B21089}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-ImageSharp/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
internal class Program
{
// Create a QR code and save it as a PNG.
internal static void Main()
{
HelloWorld();
QrCodeWithImage();
}
internal static void HelloWorld()
{
var text = "Hello, world!";
var filename = "hello-world-QR.png";
var qr = QrCode.EncodeText(text, QrCode.Ecc.Medium); // Create the QR code symbol
qr.SaveAsPng(filename, scale: 10, border: 4);
Console.WriteLine($"The QR code has been saved as {Path.GetFullPath(filename)}");
}
internal static void QrCodeWithImage()
{
var text = "https://github.com/manuelbl/QrCodeGenerator";
var filename = "qr-code-with-image.png";
var logoFilename = "heart.png";
const float logoWidth = 0.15f; // logo will have 15% the width of the QR code
var qr = QrCode.EncodeText(text, QrCode.Ecc.Medium);
using (var bitmap = qr.ToBitmap(scale: 10, border: 4))
using (var logo = Image.Load(logoFilename))
{
// resize logo
var w = (int)Math.Round(bitmap.Width * logoWidth);
logo.Mutate(logo => logo.Resize(w, 0));
// draw logo in center
var topLeft = new Point((bitmap.Width - logo.Width) / 2, (bitmap.Height - logo.Height) / 2);
bitmap.Mutate(img => img.DrawImage(logo, topLeft, 1));
// save as PNG
bitmap.SaveAsPng(filename);
}
Console.WriteLine($"The QR code has been saved as {Path.GetFullPath(filename)}");
}
}
}
================================================
FILE: Demo-ImageSharp/QrCodeBitmapExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator
{
public static class QrCodeBitmapExtensions
{
///
/// The background color.
/// The foreground color.
public static Image ToBitmap(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
// check arguments
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Value out of range");
}
int size = qrCode.Size;
int dim = (size + border * 2) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large");
}
// create bitmap
var image = new Image(dim, dim);
image.Mutate(img =>
{
// draw background
img.Fill(background);
// draw modules
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
img.Fill(foreground, new Rectangle((x + border) * scale, (y + border) * scale, scale, scale));
}
}
}
});
return image;
}
///
/// Creates a bitmap (raster image) of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The resulting bitmap uses the pixel format .
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static Image ToBitmap(this QrCode qrCode, int scale, int border)
{
return qrCode.ToBitmap(scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static byte[] ToPng(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
using var image = qrCode.ToBitmap(scale, border, foreground, background);
using var ms = new MemoryStream();
image.SaveAsPng(ms);
return ms.ToArray();
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static byte[] ToPng(this QrCode qrCode, int scale, int border)
{
return qrCode.ToPng(scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border, Color foreground, Color background)
{
using Image image = qrCode.ToBitmap(scale, border, foreground, background);
image.SaveAsPng(filename);
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border)
{
qrCode.SaveAsPng(filename, scale, border, Color.Black, Color.White);
}
}
}
================================================
FILE: Demo-ImageSharp/README.md
================================================
# Saving as PNG using ImageSharp
This example program shows how to create a QR code and save it as a PNG file using the [ImageSharp](https://github.com/SixLabors/ImageSharp) rasterization library.
Additionally, it demonstrates how to add an image in the center of the QR code.
The use of ImageSharp is recommended if the project already uses ImageSharp.
================================================
FILE: Demo-QRCode-Variety/Demo-QRCode-Variety.csproj
================================================
Exenet8.0Demo_Basic
================================================
FILE: Demo-QRCode-Variety/Demo-QRCode-Variety.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-QRCode-Variety", "Demo-QRCode-Variety.csproj", "{CE334406-7A4A-4455-889B-200DEBB6C08C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CE334406-7A4A-4455-889B-200DEBB6C08C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE334406-7A4A-4455-889B-200DEBB6C08C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE334406-7A4A-4455-889B-200DEBB6C08C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE334406-7A4A-4455-889B-200DEBB6C08C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB8EAC9D-6D83-4A9C-A867-300B9DD2B793}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-QRCode-Variety/Program.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
internal class Program
{
// The main application program.
internal static void Main()
{
DoBasicDemo();
DoVarietyDemo();
DoSegmentDemo();
DoMaskDemo();
DoBinaryDemo();
}
#region Demo suite
// Creates a single QR code, then writes it to an SVG file.
private static void DoBasicDemo()
{
const string text = "Hello, world!"; // User-supplied Unicode text
var errCorLvl = QrCode.Ecc.Low; // Error correction level
var qr = QrCode.EncodeText(text, errCorLvl); // Make the QR code symbol
SaveAsSvg(qr, "hello-world-QR.svg", border: 4); // Save as SVG
}
// Creates a variety of QR codes that exercise different features of the library, and writes each one to file.
private static void DoVarietyDemo()
{
// Numeric mode encoding (3.33 bits per digit)
var qr = QrCode.EncodeText("314159265358979323846264338327950288419716939937510", QrCode.Ecc.Medium);
SaveAsSvg(qr, "pi-digits-QR.svg");
// Alphanumeric mode encoding (5.5 bits per character)
qr = QrCode.EncodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", QrCode.Ecc.High);
SaveAsSvg(qr, "alphanumeric-QR.svg", 2);
// Unicode text as UTF-8
qr = QrCode.EncodeText("こんにちwa、世界! αβγδ", QrCode.Ecc.Quartile);
SaveAsSvg(qr, "unicode-QR.svg", 3);
// Moderately large QR code using longer text (from Lewis Carroll's Alice in Wonderland)
qr = QrCode.EncodeText(
"Alice was beginning to get very tired of sitting by her sister on the bank, "
+ "and of having nothing to do: once or twice she had peeped into the book her sister was reading, "
+ "but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice "
+ "'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
+ "for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
+ "daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
+ "a White Rabbit with pink eyes ran close by her.", QrCode.Ecc.High);
SaveAsSvg(qr, "alice-wonderland-QR.svg", 10);
}
// Creates QR codes with manually specified segments for better compactness.
private static void DoSegmentDemo()
{
// Illustration "silver"
const string silver0 = "THE SQUARE ROOT OF 2 IS 1.";
const string silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
var qr = QrCode.EncodeText(silver0 + silver1, QrCode.Ecc.Low);
SaveAsSvg(qr, "sqrt2-monolithic-QR.svg", 3);
var segs = new List
{
QrSegment.MakeAlphanumeric(silver0),
QrSegment.MakeNumeric(silver1)
};
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Low);
SaveAsSvg(qr, "sqrt2-segmented-QR.svg", 3);
// Illustration "golden"
const string golden0 = "Golden ratio φ = 1.";
const string golden1 =
"6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
const string golden2 = "......";
qr = QrCode.EncodeText(golden0 + golden1 + golden2, QrCode.Ecc.Low);
SaveAsSvg(qr, "phi-monolithic-QR.svg", 5);
segs = new List
{
QrSegment.MakeBytes(Encoding.UTF8.GetBytes(golden0)),
QrSegment.MakeNumeric(golden1),
QrSegment.MakeAlphanumeric(golden2)
};
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Low);
SaveAsSvg(qr, "phi-segmented-QR.svg", 5);
// Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
const string madoka = "「魔法少女まどか☆マギカ」って、 ИАИ desu κα?";
qr = QrCode.EncodeText(madoka, QrCode.Ecc.Low);
SaveAsSvg(qr, "madoka-utf8-QR.svg", 4);
segs = new List { QrSegmentAdvanced.MakeKanji(madoka) };
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Low);
SaveAsSvg(qr, "madoka-kanji-QR.svg", 4);
}
// Creates QR codes with the same size and contents but different mask patterns.
private static void DoMaskDemo()
{
// Project Nayuki URL
var segs = QrSegment.MakeSegments("https://www.nayuki.io/");
var qr = QrCode.EncodeSegments(segs, QrCode.Ecc.High);
SaveAsSvg(qr, "project-nayuki-automask-QR.svg", 6);
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.High, QrCode.MinVersion, QrCode.MaxVersion, 3); // Force mask 3
SaveAsSvg(qr, "project-nayuki-mask3-QR.svg", 6);
// Chinese text as UTF-8
segs = QrSegment.MakeSegments("維基百科(Wikipedia,聆聽i/ˌwɪkᵻˈpiːdi.ə/)是一個自由內容、公開編輯且多語言的網路百科全書協作計畫");
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Medium, QrCode.MinVersion, QrCode.MaxVersion, 0); // Force mask 0
SaveAsSvg(qr, "unicode-mask0-QR.svg");
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Medium, QrCode.MinVersion, QrCode.MaxVersion, 1); // Force mask 1
SaveAsSvg(qr, "unicode-mask1-QR.svg");
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Medium, QrCode.MinVersion, QrCode.MaxVersion, 5); // Force mask 5
SaveAsSvg(qr, "unicode-mask5-QR.svg");
qr = QrCode.EncodeSegments(segs, QrCode.Ecc.Medium, QrCode.MinVersion, QrCode.MaxVersion, 7); // Force mask 7
SaveAsSvg(qr, "unicode-mask7-QR.svg");
}
private static void DoBinaryDemo()
{
// create binary data
byte[] data = {
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00,
0x01, 0x00, 0x80, 0x01, 0x00, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x0a,
0x00, 0x01, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c,
0x01, 0x00, 0x3b
};
var qr = QrCode.EncodeBinary(data, QrCode.Ecc.Medium);
SaveAsSvg(qr, "binary.svg");
}
#endregion
private static void SaveAsSvg(QrCode qrCode, string filname, int border = 3)
{
string svg = qrCode.ToSvgString(border); // Convert to SVG XML code
File.WriteAllText(filname, svg, Encoding.UTF8); // Write image to file
}
}
}
================================================
FILE: Demo-QRCode-Variety/README.md
================================================
# Demonstration of various QR code
This example program creates a series of QR code and saves them as SVG files.
Aside from a simple standard case, the examples demonstrates the use of:
- different encodings (numeric, alpha-numeric, Unicode)
- different error correction levels
- using multiple segments
- using different masks
- encoding binary data
================================================
FILE: Demo-SkiaSharp/Demo-SkiaSharp.csproj
================================================
Exenet8.0Net.Codecrete.QrCodeGenerator.DemoNet.Codecrete.QrCodeGenerator.Demo2.1.0Manuel Bleichenbacher, Project NayukiQR Code Generator for .NETDemo application for QR Code GenerationCopyright Manuel Bleichenbacher and Project Nayuki (MIT License)https://opensource.org/licenses/MIThttps://github.com/manuelbl/QrCodeGeneratorhttps://github.com/manuelbl/QrCodeGeneratorCodecrete
================================================
FILE: Demo-SkiaSharp/Demo-SkiaSharp.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30611.23
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo-SkiaSharp", "Demo-SkiaSharp.csproj", "{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94BC47F9-3AE8-471A-AC3F-CDEFA1B21089}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-SkiaSharp/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
internal class Program
{
// Create a QR code and save it as a PNG.
internal static void Main()
{
var text = "Hello, world!";
var filename = "hello-world-QR.png";
var qr = QrCode.EncodeText(text, QrCode.Ecc.Medium); // Create the QR code symbol
qr.SaveAsPng(filename, scale: 10, border: 4);
Console.WriteLine($"The QR code has been saved as {Path.GetFullPath(filename)}");
}
}
}
================================================
FILE: Demo-SkiaSharp/QrCodeBitmapExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using SkiaSharp;
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator
{
public static class QrCodeBitmapExtensions
{
///
/// The background color.
/// The foreground color.
public static SKBitmap ToBitmap(this QrCode qrCode, int scale, int border, SKColor foreground, SKColor background)
{
// check arguments
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Value out of range");
}
int size = qrCode.Size;
int dim = (size + border * 2) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large");
}
// create bitmap
SKBitmap bitmap = new SKBitmap(dim, dim, SKColorType.Rgb888x, SKAlphaType.Opaque);
using (SKCanvas canvas = new SKCanvas(bitmap))
{
// draw background
using (SKPaint paint = new SKPaint { Color = background })
{
canvas.DrawRect(0, 0, dim, dim, paint);
}
// draw modules
using (SKPaint paint = new SKPaint { Color = foreground })
{
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
canvas.DrawRect((x + border) * scale, (y + border) * scale, scale, scale, paint);
}
}
}
}
}
return bitmap;
}
///
/// Creates a bitmap (raster image) of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The resulting bitmap uses the pixel format .
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static SKBitmap ToBitmap(this QrCode qrCode, int scale, int border)
{
return qrCode.ToBitmap(scale, border, SKColors.Black, SKColors.White);
}
///
/// The background color.
/// The foreground color.
public static byte[] ToPng(this QrCode qrCode, int scale, int border, SKColor foreground, SKColor background)
{
using SKBitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 90);
return data.ToArray();
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static byte[] ToPng(this QrCode qrCode, int scale, int border)
{
return qrCode.ToPng(scale, border, SKColors.Black, SKColors.White);
}
///
/// The background color.
/// The foreground color.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border, SKColor foreground, SKColor background)
{
using SKBitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 90);
using FileStream stream = File.OpenWrite(filename);
data.SaveTo(stream);
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border)
{
qrCode.SaveAsPng(filename, scale, border, SKColors.Black, SKColors.White);
}
}
}
================================================
FILE: Demo-SkiaSharp/README.md
================================================
# Saving as PNG using SkiaSharp
This example program shows how to create a QR code and save it as a PNG file using the [SkiaSharp](https://github.com/mono/SkiaSharp) rasterization library.
The use of SkiaSharp is recommended for multi-platform and all non-Windows projects.
================================================
FILE: Demo-System-Drawing/Demo-System-Drawing.csproj
================================================
Exenet8.0Net.Codecrete.QrCodeGenerator.DemoNet.Codecrete.QrCodeGenerator.Demo2.1.0Manuel Bleichenbacher, Project NayukiQR Code Generator for .NETDemo application for QR Code GenerationCopyright Manuel Bleichenbacher and Project Nayuki (MIT License)https://opensource.org/licenses/MIThttps://github.com/manuelbl/QrCodeGeneratorhttps://github.com/manuelbl/QrCodeGeneratorCodecrete
================================================
FILE: Demo-System-Drawing/Demo-System-Drawing.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30611.23
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo-System-Drawing", "Demo-System-Drawing.csproj", "{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBB1A4A6-D82E-4233-8FC9-9300F9576FD2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {94BC47F9-3AE8-471A-AC3F-CDEFA1B21089}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-System-Drawing/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
internal class Program
{
// Create a QR code and save it as a PNG.
internal static void Main()
{
var text = "Hello, world!";
var filename = "hello-world-QR.png";
var qr = QrCode.EncodeText(text, QrCode.Ecc.Medium); // Create the QR code symbol
qr.SaveAsPng(filename, scale: 10, border: 4);
Console.WriteLine($"The QR code has been saved as {Path.GetFullPath(filename)}");
}
}
}
================================================
FILE: Demo-System-Drawing/QrCodeBitmapExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// QrCode extension for creating bitmaps using System.Drawing classes.
///
/// In .NET 6 and later versions, this extension will only work on Windows.
///
///
public static class QrCodeBitmapExtensions
{
///
/// The background color.
/// The foreground color.
public static Bitmap ToBitmap(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
// check arguments
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Value out of range");
}
int size = qrCode.Size;
int dim = (size + border * 2) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large");
}
// create bitmap
Bitmap bitmap = new Bitmap(dim, dim, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bitmap))
{
Draw(qrCode, g, scale, border, foreground, background);
}
return bitmap;
}
///
/// Creates a bitmap (raster image) of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The resulting bitmap uses the pixel format .
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static Bitmap ToBitmap(this QrCode qrCode, int scale, int border)
{
return qrCode.ToBitmap(scale, border, Color.Black, Color.White);
}
///
/// Draws this QR code into the specified graphics context.
///
/// The QR code is drawn at offset (0, 0). Use
/// to draw it at a different position.
///
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, Draw(graphics, scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
///
/// The graphics context to draw in.
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
public static void Draw(this QrCode qrCode, Graphics graphics, float scale, float border)
{
Draw(qrCode, graphics, scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static void Draw(this QrCode qrCode, Graphics graphics, float scale, float border, Color foreground, Color background)
{
if (scale <= 0 || border < 0)
{
return;
}
int size = qrCode.Size;
float dim = (size + border * 2) * scale;
// draw background
if (background != Color.Transparent)
{
using SolidBrush brush = new SolidBrush(background);
graphics.FillRectangle(brush, 0, 0, dim, dim);
}
// draw modules
using (SolidBrush brush = new SolidBrush(foreground))
{
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
graphics.FillRectangle(brush, (x + border) * scale, (y + border) * scale, scale, scale);
}
}
}
}
}
///
/// The background color.
/// The foreground color.
public static byte[] ToPng(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
using Bitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using MemoryStream ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static byte[] ToPng(this QrCode qrCode, int scale, int border)
{
return qrCode.ToPng(scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border, Color foreground, Color background)
{
using Bitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
bitmap.Save(filename, ImageFormat.Png);
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border)
{
qrCode.SaveAsPng(filename, scale, border, Color.Black, Color.White);
}
}
}
================================================
FILE: Demo-System-Drawing/README.md
================================================
# Saving as PNG using System.Drawing
This example program shows how to create a QR code and save it as a PNG file using the *System.Drawing* classes.
With .NET 6 and later, *System.Drawing* has become a Windows only technology. While *System.Drawing* is available on macOS and Linux on earlier .NET version, its use is only recommended for Windows.
================================================
FILE: Demo-VCard/Program.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
*
* Demo creating a QR code containing a vCard.
*
*/
using MixERP.Net.VCards;
using MixERP.Net.VCards.Models;
using MixERP.Net.VCards.Serializer;
using MixERP.Net.VCards.Types;
using Net.Codecrete.QrCodeGenerator;
using System.Collections.Generic;
using System.IO;
namespace VCardDemo
{
class Program
{
static void Main()
{
var vcard = new VCard
{
Version = VCardVersion.V3,
FirstName = "Robin",
LastName = "Hood",
Organization = "Sherwood Inc.",
Addresses = new List
{
new Address {
Type = AddressType.Work,
Street = "The Major Oak",
Locality = "Sherwood Forest",
PostalCode = "NG21 9RN",
Country = "United Kingdom",
}
},
Telephones = new List
{
new Telephone {
Type = TelephoneType.Work,
Number = "+441623677321"
}
},
Emails = new List
{
new Email
{
Type = EmailType.Smtp,
EmailAddress = "robin.hood@sherwoodinc.co.uk"
}
}
};
var qrCode = QrCode.EncodeText(vcard.Serialize(), QrCode.Ecc.Medium);
File.WriteAllText("vcard-qrcode.svg", qrCode.ToSvgString(3));
}
}
}
================================================
FILE: Demo-VCard/VCardDemo.csproj
================================================
Exenet8.0
================================================
FILE: Demo-VCard/VCardDemo.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31702.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VCardDemo", "VCardDemo.csproj", "{5DE9E10C-E608-4661-AAE9-ABCF46C0F2F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5DE9E10C-E608-4661-AAE9-ABCF46C0F2F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5DE9E10C-E608-4661-AAE9-ABCF46C0F2F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5DE9E10C-E608-4661-AAE9-ABCF46C0F2F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5DE9E10C-E608-4661-AAE9-ABCF46C0F2F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7E8A810C-1062-422C-B511-9634C165EB47}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-WinForms/Demo-WinForms.csproj
================================================
WinExenet8.0-windowsNet.Codecrete.QrCodeGenerator.DemoTrue
================================================
FILE: Demo-WinForms/Demo-WinForms.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-WinForms", "Demo-WinForms.csproj", "{A3AD57D8-ED64-40DB-8EB1-F4E1B8EF18FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A3AD57D8-ED64-40DB-8EB1-F4E1B8EF18FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A3AD57D8-ED64-40DB-8EB1-F4E1B8EF18FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3AD57D8-ED64-40DB-8EB1-F4E1B8EF18FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3AD57D8-ED64-40DB-8EB1-F4E1B8EF18FD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0CCE4B82-DC41-4CAA-9643-0130009B5A28}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-WinForms/Form1.Designer.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
namespace Net.Codecrete.QrCodeGenerator.Demo
{
partial class Form1
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.qrCodeControl = new Net.Codecrete.QrCodeGenerator.QrCodeControl();
this.qrCodeText = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.errorCorrectionCombo = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.copyButton = new System.Windows.Forms.Button();
this.borderNumericUpDown = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.borderNumericUpDown)).BeginInit();
this.SuspendLayout();
//
// qrCodeControl
//
this.qrCodeControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.qrCodeControl.BinaryData = null;
this.qrCodeControl.BorderWidth = 3;
this.qrCodeControl.ErrorCorrection = 2;
this.qrCodeControl.Location = new System.Drawing.Point(32, 32);
this.qrCodeControl.Name = "qrCodeControl";
this.qrCodeControl.Size = new System.Drawing.Size(712, 344);
this.qrCodeControl.TabIndex = 0;
this.qrCodeControl.TextData = "Test";
//
// qrCodeText
//
this.qrCodeText.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.qrCodeText.Location = new System.Drawing.Point(32, 420);
this.qrCodeText.Name = "qrCodeText";
this.qrCodeText.Size = new System.Drawing.Size(712, 39);
this.qrCodeText.TabIndex = 1;
this.qrCodeText.Text = "QR code text";
this.qrCodeText.TextChanged += new System.EventHandler(this.QrCodeText_TextChanged);
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(32, 488);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(187, 32);
this.label1.TabIndex = 2;
this.label1.Text = "Error Correction:";
//
// errorCorrectionCombo
//
this.errorCorrectionCombo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.errorCorrectionCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.errorCorrectionCombo.FormattingEnabled = true;
this.errorCorrectionCombo.Items.AddRange(new object[] {
"Low",
"Medium",
"Quartile",
"High"});
this.errorCorrectionCombo.Location = new System.Drawing.Point(225, 485);
this.errorCorrectionCombo.Name = "errorCorrectionCombo";
this.errorCorrectionCombo.Size = new System.Drawing.Size(186, 40);
this.errorCorrectionCombo.TabIndex = 3;
this.errorCorrectionCombo.SelectedIndexChanged += new System.EventHandler(this.ErrorCorrectionCombo_SelectedIndexChanged);
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(496, 488);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(90, 32);
this.label2.TabIndex = 4;
this.label2.Text = "Border:";
//
// copyButton
//
this.copyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.copyButton.Location = new System.Drawing.Point(498, 568);
this.copyButton.Name = "copyButton";
this.copyButton.Size = new System.Drawing.Size(246, 46);
this.copyButton.TabIndex = 6;
this.copyButton.Text = "Copy QR Code";
this.copyButton.UseVisualStyleBackColor = true;
this.copyButton.Click += new System.EventHandler(this.CopyButton_Click);
//
// borderNumericUpDown
//
this.borderNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.borderNumericUpDown.Location = new System.Drawing.Point(592, 486);
this.borderNumericUpDown.Name = "borderNumericUpDown";
this.borderNumericUpDown.Size = new System.Drawing.Size(152, 39);
this.borderNumericUpDown.TabIndex = 7;
this.borderNumericUpDown.Value = new decimal(new int[] {
3,
0,
0,
0});
this.borderNumericUpDown.ValueChanged += new System.EventHandler(this.BorderNumericUpDown_ValueChanged);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(774, 649);
this.Controls.Add(this.borderNumericUpDown);
this.Controls.Add(this.copyButton);
this.Controls.Add(this.label2);
this.Controls.Add(this.errorCorrectionCombo);
this.Controls.Add(this.label1);
this.Controls.Add(this.qrCodeText);
this.Controls.Add(this.qrCodeControl);
this.Name = "Form1";
this.Text = "QR Code";
((System.ComponentModel.ISupportInitialize)(this.borderNumericUpDown)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private QrCodeControl qrCodeControl;
private System.Windows.Forms.TextBox qrCodeText;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox errorCorrectionCombo;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button copyButton;
private System.Windows.Forms.NumericUpDown borderNumericUpDown;
}
}
================================================
FILE: Demo-WinForms/Form1.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Windows.Forms;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
errorCorrectionCombo.SelectedIndex = 1;
qrCodeControl.TextData = qrCodeText.Text;
qrCodeControl.ErrorCorrection = errorCorrectionCombo.SelectedIndex;
qrCodeControl.BorderWidth = (int)borderNumericUpDown.Value;
}
private void QrCodeText_TextChanged(object sender, EventArgs e)
{
qrCodeControl.TextData = qrCodeText.Text;
}
private void ErrorCorrectionCombo_SelectedIndexChanged(object sender, EventArgs e)
{
qrCodeControl.ErrorCorrection = errorCorrectionCombo.SelectedIndex;
}
private void BorderNumericUpDown_ValueChanged(object sender, EventArgs e)
{
qrCodeControl.BorderWidth = (int)borderNumericUpDown.Value;
}
private void CopyButton_Click(object sender, EventArgs e)
{
qrCodeControl.CopyToClipboard();
}
}
}
================================================
FILE: Demo-WinForms/Form1.resx
================================================
text/microsoft-resx2.0System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
================================================
FILE: Demo-WinForms/Program.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Windows.Forms;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
internal static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
================================================
FILE: Demo-WinForms/QrCodeBitmapExtensions.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// QrCode extension for creating bitmaps using System.Drawing classes.
///
/// In .NET 6 and later versions, this extension will only work on Windows.
///
///
public static class QrCodeBitmapExtensions
{
///
/// The background color.
/// The foreground color.
public static Bitmap ToBitmap(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
// check arguments
if (scale <= 0)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Value out of range");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Value out of range");
}
int size = qrCode.Size;
int dim = (size + border * 2) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large");
}
// create bitmap
Bitmap bitmap = new Bitmap(dim, dim, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bitmap))
{
Draw(qrCode, g, scale, border, foreground, background);
}
return bitmap;
}
///
/// Creates a bitmap (raster image) of this QR code.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToBitmap(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// The resulting bitmap uses the pixel format .
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static Bitmap ToBitmap(this QrCode qrCode, int scale, int border)
{
return qrCode.ToBitmap(scale, border, Color.Black, Color.White);
}
///
/// Draws this QR code into the specified graphics context.
///
/// The QR code is drawn at offset (0, 0). Use
/// to draw it at a different position.
///
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, Draw(graphics, scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
///
/// The graphics context to draw in.
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
public static void Draw(this QrCode qrCode, Graphics graphics, float scale, float border)
{
Draw(qrCode, graphics, scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static void Draw(this QrCode qrCode, Graphics graphics, float scale, float border, Color foreground, Color background)
{
if (scale <= 0 || border < 0)
{
return;
}
int size = qrCode.Size;
float dim = (size + border * 2) * scale;
// draw background
if (background != Color.Transparent)
{
using SolidBrush brush = new SolidBrush(background);
graphics.FillRectangle(brush, 0, 0, dim, dim);
}
// draw modules
using (SolidBrush brush = new SolidBrush(foreground))
{
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
graphics.FillRectangle(brush, (x + border) * scale, (y + border) * scale, scale, scale);
}
}
}
}
}
///
/// The background color.
/// The foreground color.
public static byte[] ToPng(this QrCode qrCode, int scale, int border, Color foreground, Color background)
{
using Bitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
using MemoryStream ms = new MemoryStream();
bitmap.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
///
/// Creates a PNG image of this QR code and returns it as a byte array.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, ToPng(scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// The created bitmap representing this QR code.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static byte[] ToPng(this QrCode qrCode, int scale, int border)
{
return qrCode.ToPng(scale, border, Color.Black, Color.White);
}
///
/// The background color.
/// The foreground color.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border, Color foreground, Color background)
{
using Bitmap bitmap = qrCode.ToBitmap(scale, border, foreground, background);
bitmap.Save(filename, ImageFormat.Png);
}
///
/// Saves this QR code as a PNG file.
///
/// The parameter specifies the scale of the image, which is
/// equivalent to the width and height of each QR code module. Additionally, the number
/// of modules to add as a border to all four sides can be specified.
///
///
/// For example, SaveAsPng("qrcode.png", scale: 10, border: 4) means to pad the QR code with 4 white
/// border modules on all four sides, and use 10×10 pixels to represent each module.
///
///
/// If not specified, the foreground color is black (0x000000) und the background color always white (0xFFFFFF).
///
///
/// The width and height, in pixels, of each module.
/// The number of border modules to add to each of the four sides.
/// is 0 or negative, is negative
/// or the resulting image is wider than 32,768 pixels.
public static void SaveAsPng(this QrCode qrCode, string filename, int scale, int border)
{
qrCode.SaveAsPng(filename, scale, border, Color.Black, Color.White);
}
}
}
================================================
FILE: Demo-WinForms/QrCodeControl.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Custom control for displaying a QR code
///
public class QrCodeControl : Control
{
private string _textData;
private byte[] _binaryData;
private int _errorCorrection;
private int _borderWidth;
public QrCodeControl()
{
_textData = "Test";
_errorCorrection = 2;
_borderWidth = 3;
ResizeRedraw = true;
}
public string TextData
{
get
{
if (_binaryData != null)
{
return "binary data";
}
return _textData;
}
set
{
_textData = value;
_binaryData = null;
if (_textData == null)
{
_textData = "";
}
Invalidate();
}
}
public byte[] BinaryData
{
get { return _binaryData; }
set
{
_binaryData = value;
_textData = null;
if (_binaryData == null)
{
_binaryData = new byte[0];
}
Invalidate();
}
}
public int ErrorCorrection
{
get { return _errorCorrection; }
set
{
_errorCorrection = Math.Min(Math.Max(value, 0), 3);
Invalidate();
}
}
public int BorderWidth
{
get { return _borderWidth; }
set
{
_borderWidth = Math.Max(value, 0);
Invalidate();
}
}
private static readonly QrCode.Ecc[] errorCorrectionLevels = { QrCode.Ecc.Low, QrCode.Ecc.Medium, QrCode.Ecc.Quartile, QrCode.Ecc.High };
///
/// Creates the QrCode instance with the current settings.
///
///
private QrCode CreateQrCode()
{
QrCode qrCode;
var ecc = errorCorrectionLevels[_errorCorrection];
if (_binaryData != null)
{
qrCode = QrCode.EncodeBinary(_binaryData, ecc);
}
else
{
qrCode = QrCode.EncodeText(_textData, ecc);
}
return qrCode;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int size = Math.Min(Width, Height);
var graphics = e.Graphics;
var qrCode = CreateQrCode();
graphics.TranslateTransform((Width - size) / 2, (Height - size) / 2);
qrCode.Draw(graphics, scale: size / (float)(qrCode.Size + 2 * _borderWidth), border: _borderWidth,
foreground: Color.Black, background: Color.White);
}
///
/// Copy the QR code to the clipboard.
///
/// The QR code is copied as a bitmap. It uses a scaling factor of 20 to
/// prevent a blurry result from upscaling.
///
///
public void CopyToClipboard()
{
DataObject dataObject = new DataObject();
var qrCode = CreateQrCode();
dataObject.SetData(DataFormats.Bitmap, qrCode.ToBitmap(20, _borderWidth));
Clipboard.SetDataObject(dataObject);
}
}
}
================================================
FILE: Demo-WinForms/README.md
================================================
# Windows Forms example application
This example application shows how to use the QR code library in a Windows Forms application:
- `QrCodeControl` is a custom control that can be used in any `Form`.
- The control also implements copying the QR code to the clipboard.

================================================
FILE: Demo-WinUI/Demo-WinUI/App.xaml
================================================
================================================
FILE: Demo-WinUI/Demo-WinUI/App.xaml.cs
================================================
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2022 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System;
using System.Runtime.InteropServices;
using Windows.Graphics;
using WinRT.Interop;
using Windows.Win32;
using Windows.Win32.Foundation;
namespace Net.Codecrete.QrCodeGenerator.Demo;
///
/// QR Code application.
///
public partial class App : Application
{
///
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
///
public App()
{
InitializeComponent();
}
///
/// Invoked when the application is launched.
///
/// Details about the launch request and process.
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
m_window = new MainWindow
{
Title = "QR Code"
};
// Set initial windows size.
Resize(500, 600);
m_window.Activate();
}
private Window m_window;
private void Resize(int x, int y)
{
var scalingFactor = GetDpiScalingFactor();
GetAppWindow().Resize(new SizeInt32((int)(x * scalingFactor), (int)(y * scalingFactor)));
}
private AppWindow GetAppWindow()
{
IntPtr hWnd = WindowNative.GetWindowHandle(m_window);
WindowId wndId = Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(wndId);
}
private double GetDpiScalingFactor()
{
IntPtr hWnd = WindowNative.GetWindowHandle(m_window);
var dpi = PInvoke.GetDpiForWindow((HWND)hWnd);
return (float)dpi / 96;
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/Demo-WinUI.csproj
================================================
WinExenet8.0-windows10.0.19041.010.0.17763.0Net.Codecrete.QrCodeGenerator.Demoapp.manifestx86;x64;ARM64win-x86;win-x64;win-arm64win-$(Platform).pubxmltruetrueQrCodeWinUIDemoFalseTrueFalseTrueNever0allruntime; build; native; contentfiles; analyzers; buildtransitiveMSBuild:Compiletrue
================================================
FILE: Demo-WinUI/Demo-WinUI/MainViewModel.cs
================================================
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2022 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Threading.Tasks;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage.Streams;
namespace Net.Codecrete.QrCodeGenerator.Demo;
///
/// View model for MainWindow
///
public partial class MainViewModel : ObservableObject
{
///
/// QR code text
///
[ObservableProperty]
string text = "Hello, world!";
///
/// QR code error correction level
///
[ObservableProperty]
QrCode.Ecc errorCorrection = QrCode.Ecc.Medium;
///
/// Width of border around QR code (in QR code pixels)
///
[ObservableProperty]
int borderWidth = 3;
private readonly Tuple[] errorCorrectionLevels_ =
{
new Tuple("Low", QrCode.Ecc.Low),
new Tuple("Medium", QrCode.Ecc.Medium),
new Tuple("Quartile", QrCode.Ecc.Quartile),
new Tuple("High", QrCode.Ecc.High)
};
///
/// List of error correction levels
///
public Tuple[] ErrorCorrectionLevels => errorCorrectionLevels_;
///
/// Copy the QR code to the clipboard (as a PNG image).
///
///
[RelayCommand]
async Task CopyToClipboard()
{
var qrCode = QrCode.EncodeText(Text, ErrorCorrection);
// Don't close stream; it won't work anymore
var stream = new InMemoryRandomAccessStream();
await QrCodeDrawing.WriteAsPng(stream, qrCode, 20, BorderWidth);
var dataPackage = new DataPackage();
dataPackage.SetBitmap(RandomAccessStreamReference.CreateFromStream(stream));
Clipboard.SetContent(dataPackage);
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/MainWindow.xaml
================================================
Error Correction:Border Width:
================================================
FILE: Demo-WinUI/Demo-WinUI/MainWindow.xaml.cs
================================================
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2022 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.UI.Xaml;
namespace Net.Codecrete.QrCodeGenerator.Demo;
///
/// Main window
///
public sealed partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
RootElement.Loaded += RootElement_Loaded;
}
public MainViewModel ViewModel { get; } = new MainViewModel();
private void RootElement_Loaded(object sender, RoutedEventArgs e)
{
// The combo box needs help to set the initial value
ErrorCorrectionCombo.SelectedValue = ViewModel.ErrorCorrection;
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/NativeMethods.txt
================================================
GetDpiForWindow
================================================
FILE: Demo-WinUI/Demo-WinUI/Package.appxmanifest
================================================
Qr Code GeneratorManuelAssets\StoreLogo.png
================================================
FILE: Demo-WinUI/Demo-WinUI/Properties/PublishProfiles/win-arm64.pubxml
================================================
FileSystemARM64win-arm64bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\trueFalseFalseTrue
================================================
FILE: Demo-WinUI/Demo-WinUI/Properties/PublishProfiles/win-x64.pubxml
================================================
FileSystemx64win-x64bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\trueFalseFalseTrue
================================================
FILE: Demo-WinUI/Demo-WinUI/Properties/PublishProfiles/win-x86.pubxml
================================================
FileSystemx86win-x86bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\trueFalseFalseTrue
================================================
FILE: Demo-WinUI/Demo-WinUI/Properties/launchSettings.json
================================================
{
"profiles": {
"Demo-WinUI (Package)": {
"commandName": "MsixPackage"
},
"Demo-WinUI (Unpackaged)": {
"commandName": "Project"
}
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/QrCodeControl.xaml
================================================
================================================
FILE: Demo-WinUI/Demo-WinUI/QrCodeControl.xaml.cs
================================================
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2022 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.Graphics.Canvas.UI.Xaml;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Numerics;
using Windows.Foundation;
using Windows.UI;
namespace Net.Codecrete.QrCodeGenerator.Demo;
///
/// Control for displaying a QR code.
///
public sealed partial class QrCodeControl : UserControl
{
public QrCodeControl()
{
InitializeComponent();
}
///
/// Text contained in QR code.
///
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
nameof(Text),
typeof(string),
typeof(QrCodeControl),
new PropertyMetadata("", (d, args) => { (d as QrCodeControl).qrCodeCanvas.Invalidate(); })
);
///
/// Width of border around QR code (in QR pixels)
///
public int BorderWidth
{
get { return (int)GetValue(BorderWidthProperty); }
set { SetValue(BorderWidthProperty, value); }
}
public static readonly DependencyProperty BorderWidthProperty = DependencyProperty.Register(
nameof(BorderWidth),
typeof(int),
typeof(QrCodeControl),
new PropertyMetadata(3, (d, args) => { (d as QrCodeControl).qrCodeCanvas.Invalidate(); })
);
///
/// Error correction level
///
public QrCode.Ecc ErrorCorrection
{
get { return (QrCode.Ecc)GetValue(ErrorCorrectionProperty); }
set { SetValue(ErrorCorrectionProperty, value); }
}
public static readonly DependencyProperty ErrorCorrectionProperty = DependencyProperty.Register(
nameof(ErrorCorrection),
typeof(QrCode.Ecc),
typeof(QrCodeControl),
new PropertyMetadata(QrCode.Ecc.Medium, (d, args) => { (d as QrCodeControl).qrCodeCanvas.Invalidate(); })
);
///
/// QR code background color
///
public Color QrCodeBackgroundColor
{
get { return (Color)GetValue(QrCodeBackgroundColorProperty); }
set { SetValue(QrCodeBackgroundColorProperty, value); }
}
public static readonly DependencyProperty QrCodeBackgroundColorProperty = DependencyProperty.Register(
nameof(QrCodeBackgroundColor),
typeof(Color),
typeof(QrCodeControl),
new PropertyMetadata(Colors.White, (d, args) => { (d as QrCodeControl).qrCodeCanvas.Invalidate(); })
);
///
/// QR code pixel color
///
public Color QrCodePixelColor
{
get { return (Color)GetValue(QrCodePixelColorProperty); }
set { SetValue(QrCodePixelColorProperty, value); }
}
public static readonly DependencyProperty QrCodePixelColorProperty = DependencyProperty.Register(
nameof(QrCodePixelColor),
typeof(Color),
typeof(QrCodeControl),
new PropertyMetadata(Colors.Black, (d, args) => { (d as QrCodeControl).qrCodeCanvas.Invalidate(); })
);
protected override Size ArrangeOverride(Size finalSize)
{
var dim = Math.Min(finalSize.Width, finalSize.Height);
qrCodeCanvas.Arrange(new Rect(new Point((finalSize.Width - dim) / 2, (finalSize.Height - dim) / 2), new Size(dim, dim)));
return finalSize;
}
protected override Size MeasureOverride(Size availableSize)
{
var dim = Math.Min(availableSize.Width, availableSize.Height);
if (double.IsPositiveInfinity(dim))
dim = 3000;
return new Size(dim, dim);
}
private void QrCode_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
var code = QrCode.EncodeText(Text, ErrorCorrection);
var scale = (float)(sender.ActualWidth / (code.Size + 2 * BorderWidth));
args.DrawingSession.Transform = Matrix3x2.CreateScale(scale, scale);
QrCodeDrawing.Draw(code, args.DrawingSession, BorderWidth, QrCodePixelColor, QrCodeBackgroundColor);
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/QrCodeDrawing.cs
================================================
//
// Swiss QR Bill Generator for .NET
// Copyright (c) 2022 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using Microsoft.Graphics.Canvas;
using Microsoft.UI;
using System;
using System.Numerics;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage.Streams;
using Windows.UI;
namespace Net.Codecrete.QrCodeGenerator.Demo;
public class QrCodeDrawing
{
///
/// Draws the QR code in the specified drawing context.
///
/// The QR code is drawn with the top left corner of the border at (0, 0).
/// Each module (QR code pixel) will be drawn with 1 unit wide and tall.
/// If a different position or size is desired, the drawing context's transformation
/// matrix can be setup accordingly.
///
///
/// The QR code.
/// The drawing session.
///
///
///
public static void Draw(QrCode qrCode, CanvasDrawingSession drawingSession, int borderWidth, Color foreground, Color? background)
{
int size = qrCode.Size;
// draw the background
if (background != null)
{
drawingSession.FillRectangle(new Rect(0, 0, size + 2 * borderWidth, size + 2 * borderWidth), (Color)background);
}
// draw the modules
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
var rect = new Rect(x + borderWidth, y + borderWidth, 1, 1);
drawingSession.FillRectangle(rect, foreground);
}
}
}
}
///
/// Writes a PNG for the specified QR code.
///
/// To achieve a crisp bitmap without any anti-aliasing, the bitmap is sized such
/// that each QR code module is multiple pixels tall and wide.
/// The resulting size depends on the QR code size;
/// it is (qr-code-size + 2 * border-width) pixels tall and wide.
///
///
/// The stream to write to
/// The QR code.
/// The size of each module (QR code pixel), in pixels
/// The width of the border around the QR code, in multiples of a single module (QR code pixel).
public static Task WriteAsPng(IRandomAccessStream stream, QrCode qrCode, int moduleSize, int borderWidth = 3)
{
return WriteAsPng(stream, qrCode, moduleSize, borderWidth, Colors.Black, Colors.White);
}
///
/// The forground color.
/// The background color.
/// PNG image
public static async Task WriteAsPng(IRandomAccessStream stream, QrCode qrCode, int moduleSize, int borderWidth, Color foreground, Color background)
{
// create offscreen bitmap
int size = moduleSize * (qrCode.Size + 2 * borderWidth);
var device = CanvasDevice.GetSharedDevice();
var offscreen = new CanvasRenderTarget(device, size, size, 96);
using (CanvasDrawingSession ds = offscreen.CreateDrawingSession())
{
// draw QR code
ds.Clear(background);
ds.Transform = Matrix3x2.CreateScale(moduleSize, moduleSize);
Draw(qrCode, ds, borderWidth, foreground, null);
}
// create PNG image
await offscreen.SaveAsync(stream, CanvasBitmapFileFormat.Png);
}
}
================================================
FILE: Demo-WinUI/Demo-WinUI/app.manifest
================================================
true/PMPerMonitorV2, PerMonitor
================================================
FILE: Demo-WinUI/Demo-WinUI.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33122.133
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-WinUI", "Demo-WinUI\Demo-WinUI.csproj", "{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|ARM64.Build.0 = Debug|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|ARM64.Deploy.0 = Debug|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x64.ActiveCfg = Debug|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x64.Build.0 = Debug|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x64.Deploy.0 = Debug|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x86.ActiveCfg = Debug|x86
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x86.Build.0 = Debug|x86
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Debug|x86.Deploy.0 = Debug|x86
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|ARM64.ActiveCfg = Release|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|ARM64.Build.0 = Release|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|ARM64.Deploy.0 = Release|ARM64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x64.ActiveCfg = Release|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x64.Build.0 = Release|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x64.Deploy.0 = Release|x64
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x86.ActiveCfg = Release|x86
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x86.Build.0 = Release|x86
{28CEBE86-06C4-42B3-BEC9-8A8C40D2C83A}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8B01C7CA-A20C-4B84-815A-3F3519AACB3A}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-WinUI/README.md
================================================
# WinUI 3 example application
This example application shows how to use the QR code library in a WinUI 3 application:
- [`QrCodeControl`](Demo-WinUI/QrCodeControl.xaml.cs) is a user control for displaying a QR code.
- [`QrCodeDrawing`](Demo-WinUI/QrCodeDrawing.cs) is a class for drawing a QR code to [Win2D](https://github.com/microsoft/Win2D) `CanvasDrawingSession` (resolution independent) or to a PNG file.
- Copying a QR code to the clipboard is also shown.

================================================
FILE: Demo-WindowsPresentationFoundation/App.xaml
================================================
================================================
FILE: Demo-WindowsPresentationFoundation/App.xaml.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System.Windows;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
}
}
================================================
FILE: Demo-WindowsPresentationFoundation/AssemblyInfo.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
================================================
FILE: Demo-WindowsPresentationFoundation/Demo-WindowsPresentationFoundation.csproj
================================================
WinExenet8.0-windowsNet.Codecrete.QrCodeGenerator.Demoenabletrueapp.manifest
================================================
FILE: Demo-WindowsPresentationFoundation/Demo-WindowsPresentationFoundation.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo-WindowsPresentationFoundation", "Demo-WindowsPresentationFoundation.csproj", "{6E8E5080-AF6E-4B4F-89A8-098B0BE6A912}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6E8E5080-AF6E-4B4F-89A8-098B0BE6A912}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E8E5080-AF6E-4B4F-89A8-098B0BE6A912}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E8E5080-AF6E-4B4F-89A8-098B0BE6A912}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E8E5080-AF6E-4B4F-89A8-098B0BE6A912}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {36CE72FB-2954-40CC-B7E3-D3C496C61DF5}
EndGlobalSection
EndGlobal
================================================
FILE: Demo-WindowsPresentationFoundation/MainWindow.xaml
================================================
================================================
FILE: Demo-WindowsPresentationFoundation/MainWindow.xaml.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System;
using System.Windows;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
private string _text = "QR code text";
private int _borderWidth = 3;
private QrCode.Ecc _errorCorrection = QrCode.Ecc.Medium;
private readonly Tuple[] _errorCorrectionLevels =
{
new Tuple("Low", QrCode.Ecc.Low),
new Tuple("Medium", QrCode.Ecc.Medium),
new Tuple("Quartile", QrCode.Ecc.Quartile),
new Tuple("High", QrCode.Ecc.High)
};
public MainWindow()
{
InitializeComponent();
UpdateQrCode();
}
public int BorderWidth
{
get { return _borderWidth; }
set
{
_borderWidth = value;
UpdateQrCode();
}
}
public string Text
{
get { return _text; }
set
{
_text = value;
UpdateQrCode();
}
}
public Tuple[] ErrorCorrectionLevels
{
get { return _errorCorrectionLevels; }
}
public QrCode.Ecc ErrorCorrection
{
get { return _errorCorrection; }
set
{
_errorCorrection = value;
UpdateQrCode();
}
}
private void UpdateQrCode()
{
var qrCode = QrCode.EncodeText(_text, ErrorCorrection);
QrCodeImage.Source = QrCodeDrawing.CreateDrawing(qrCode, 192, BorderWidth);
}
private void CopyButton_Click(object sender, RoutedEventArgs e)
{
// put the QR code on the clipboard as a bitmap
var qrCode = QrCode.EncodeText(_text, ErrorCorrection);
var bitmap = QrCodeDrawing.CreateBitmapImage(qrCode, 20, BorderWidth);
var dataObject = new DataObject();
dataObject.SetData(DataFormats.Bitmap, bitmap);
Clipboard.SetDataObject(dataObject);
}
}
}
================================================
FILE: Demo-WindowsPresentationFoundation/QrCodeDrawing.cs
================================================
//
// QR code generator library (.NET)
// https://github.com/manuelbl/QrCodeGenerator
//
// Copyright (c) 2021 Manuel Bleichenbacher
// Licensed under MIT License
// https://opensource.org/licenses/MIT
//
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace Net.Codecrete.QrCodeGenerator.Demo
{
public class QrCodeDrawing
{
///
/// Create a resolution independent drawing for the specified QR code.
///
/// The drawing can be used as an image's source, or for printing.
///
///
/// The QR code.
/// The width and height of the resulting drawing, including the border (in dip).
/// The width of the border, in multiples of a single module (QR code pixel)
/// The device independent drawing.
public static DrawingImage CreateDrawing(QrCode qrCode, double size, int borderWidth = 3)
{
return CreateDrawing(qrCode, size, borderWidth, Colors.Black, Colors.White);
}
///
///
///
/// The device independent drawing.
public static DrawingImage CreateDrawing(QrCode qrCode, double size, int borderWidth, Color foreground, Color? background)
{
var group = new DrawingGroup();
using (var drawingContext = group.Open())
{
var backgroundBrush = background != null ? new SolidColorBrush((Color)background) : null;
var foregroundBrush = new SolidColorBrush(foreground);
double scale = size / (qrCode.Size + 2 * borderWidth);
drawingContext.PushTransform(new ScaleTransform(scale, scale));
Draw(qrCode, drawingContext, borderWidth, foregroundBrush, backgroundBrush);
drawingContext.Pop();
}
var image = new DrawingImage(group);
image.Freeze();
return image;
}
///
/// Draws the QR code in the specified drawing context.
///
/// The QR code is drawn with the top left corner of the border at (0, 0).
/// Each module (QR code pixel) will be drawn with 1 unit wide and tall.
/// If a different position or size is desired, the drawing context's transformation
/// matrix can be setup accordingly.
///
///
/// The QR code.
/// The drawing context.
///
///
///
public static void Draw(QrCode qrCode, DrawingContext drawingContext, int borderWidth, Brush foreground, Brush? background)
{
int size = qrCode.Size;
// draw the background
if (background != null)
{
drawingContext.DrawRectangle(background, null, new Rect(0, 0, size + 2 * borderWidth, size + 2 * borderWidth));
}
// draw the modules
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
if (qrCode.GetModule(x, y))
{
var rect = new Rect(x + borderWidth, y + borderWidth, 1, 1);
drawingContext.DrawRectangle(foreground, null, rect);
}
}
}
}
///
/// Create a bitmap for the specified QR code.
///
/// To achieve a crisp bitmap without any anti-aliasing, the bitmap is sized such
/// that each QR code module is multiple pixels tall and wide.
/// The resulting size depends on the QR code size;
/// it is (qr-code-size + 2 * border-width) pixels tall and wide.
///
///
/// The QR code.
/// The size of each module (QR code pixel), in pixels
/// The width of the border around the QR code, in multiples of a single module (QR code pixel).
/// The bitmap.
public static BitmapSource CreateBitmapImage(QrCode qrCode, int moduleSize, int borderWidth = 3)
{
return CreateBitmapImage(qrCode, moduleSize, borderWidth, Colors.Black, Colors.White);
}
///
/// The forground color.
/// The background color.
/// The bitmap.
public static BitmapSource CreateBitmapImage(QrCode qrCode, int moduleSize, int borderWidth, Color foreground, Color background)
{
var drawingVisual = new AliasedDrawingVisual();
int size = qrCode.Size + 2 * borderWidth;
using (var drawingContext = drawingVisual.RenderOpen())
{
var foregroundBrush = new SolidColorBrush(foreground);
var backgroundBrush = new SolidColorBrush(background);
drawingContext.PushTransform(new ScaleTransform(moduleSize, moduleSize));
drawingContext.DrawRectangle(backgroundBrush, null, new Rect(0, 0, size, size));
Draw(qrCode, drawingContext, borderWidth, foregroundBrush, null);
}
var bitmap = new RenderTargetBitmap(size * moduleSize, size * moduleSize, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(drawingVisual);
return bitmap;
}
///
/// Drawing visual using aliased edge mode.
///
/// This subclass is needed because the VisualEdgeMode property is protected
/// and doesn't work for DrawingVisual.
///
///
class AliasedDrawingVisual : DrawingVisual
{
public AliasedDrawingVisual()
{
VisualEdgeMode = EdgeMode.Aliased;
}
}
}
}
================================================
FILE: Demo-WindowsPresentationFoundation/README.md
================================================
# Windows Presentation Foundation (WPF) example application
This example application shows how to use the QR code library in a WPF application:
- `QrCodeDrawing` is a class for either creating a resolution independent `DrawingVisual` or a bitmap. Both can be displayed in an `Image` control
- The control also implements copying the QR code to the clipboard.

================================================
FILE: Demo-WindowsPresentationFoundation/app.manifest
================================================
PerMonitorV2,PerMonitortrue
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Manuel Bleichenbacher
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: QrCodeGenerator/BitArrayExtensions.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Extension methods for the class.
///
public static class BitArrayExtensions
{
///
/// Appends the specified number bits of the specified value to this bit array.
///
/// The least significant bits of the specified value are added. They are appended in reverse order,
/// from the most significant to the least significant one, i.e. bits 0 to len-1
/// are appended in the order len-1, len-2 ... 1, 0.
///
///
/// Requires 0 ≤ len ≤ 31, and 0 ≤ val < 2len.
///
///
/// The BitArray instance that this method extends.
/// The value to append.
/// The number of low-order bits in the value to append.
/// Value or number of bits is out of range.
public static void AppendBits(this BitArray bitArray, uint val, int len)
{
if (len < 0 || len > 31)
{
throw new ArgumentOutOfRangeException(nameof(len), "'len' out of range");
}
if (val >> len != 0)
{
throw new ArgumentOutOfRangeException(nameof(val), "'val' out of range");
}
var bitLength = bitArray.Length;
bitArray.Length = bitLength + len;
var mask = 1U << (len - 1);
for (var i = bitLength; i < bitLength + len; i++) // Append bit by bit
{
if ((val & mask) != 0)
{
bitArray.Set(i, true);
}
mask >>= 1;
}
}
///
/// Appends the content of the specified bit array to the end of this array.
///
/// The BitArray instance that this method extends.
/// The bit array to append
/// If bitArray is null.
public static void AppendData(this BitArray bitArray, BitArray otherArray)
{
Objects.RequireNonNull(otherArray);
var bitLength = bitArray.Length;
bitArray.Length = bitLength + otherArray.Length;
for (var i = 0; i < otherArray.Length; i++, bitLength++) // Append bit by bit
{
if (otherArray[i])
{
bitArray.Set(bitLength, true);
}
}
}
///
/// Extracts the specified number of bits at the specified index in this bit array.
///
/// The bit at index becomes the most significant bit of the result,
/// The bit at index + - 1 becomes the least significant bit.
///
///
/// Requires 0 ≤ len ≤ 31, 0 ≤ index, and index + len ≤ bit array length.
///
///
/// The BitArray instance that this method extends.
/// The index of the first bit to extract.
/// The number of bits to extract.
/// The extracted bits as an unsigned integer.
/// Index or length is out of range.
public static uint ExtractBits(this BitArray bitArray, int index, int len)
{
if (len < 0 || len > 31)
{
throw new ArgumentOutOfRangeException(nameof(len), "'len' out of range");
}
if (index < 0 || index + len > bitArray.Length)
{
throw new ArgumentOutOfRangeException(nameof(index), "'index' out of range");
}
uint result = 0;
for (var i = 0; i < len; i++)
{
result <<= 1;
if (bitArray.Get(index + i))
{
result |= 1;
}
}
return result;
}
}
}
================================================
FILE: QrCodeGenerator/DataTooLongException.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// The exception that is thrown when the supplied data does not fit in the QR code.
///
///
/// Ways to handle this exception include:
///
///
Decrease the error correction level (if it was greater than )
///
Increase the maxVersion argument (if it was less than ).
/// This advice applies to the advanced factory functions
/// and
/// only.
/// Other factory functions automatically try all versions up to .
///
Split the text into several segments and encode them using different encoding modes
/// (see .)
///
Make the text or binary data shorter.
///
Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
///
Reject the data and notify the caller/user.
///
///
///
///
///
///
public class DataTooLongException : ArgumentException
{
///
/// Initializes a new instance of the class.
///
/// The message that describes the error.
public DataTooLongException(string message)
: base(message)
{ }
}
}
================================================
FILE: QrCodeGenerator/Graphics.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Globalization;
using System.Text;
namespace Net.Codecrete.QrCodeGenerator
{
internal class Graphics
{
internal Graphics(int size, bool[,] modules)
{
_size = size;
_modules = modules;
}
private readonly int _size;
// The modules of this QR code (false = light, true = dark).
// Immutable after constructor finishes.
private readonly bool[,] _modules;
internal string ToSvgString(int border, string foreground, string background)
{
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Border must be non-negative");
}
var dim = _size + border * 2;
var sb = new StringBuilder()
.Append("\n")
.Append("\n")
.Append($"\n")
.ToString();
}
internal string ToGraphicsPath(int border)
{
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), "Border must be non-negative");
}
// Work on copy as it is destructive
var modules = CopyModules();
var path = new StringBuilder();
CreatePath(path, modules, border);
return path.ToString();
}
internal byte[] ToBmpBitmap(int border, int scale, int foreground, int background)
{
if (scale < 1)
{
throw new ArgumentOutOfRangeException(nameof(scale), scale, "Scale must be greater than 0.");
}
if (border < 0)
{
throw new ArgumentOutOfRangeException(nameof(border), border, "Border must be non-negative.");
}
var dim = (_size + 2 * border) * scale;
if (dim > short.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(scale), "Scale or border too large.");
}
// NOTE: Works for Size > 0
// Modules to bytes
// x >> 3 == x / 8
var bytesToWrite = ((dim - 1) >> 3) + 1;
// NOTE: Align to 4 bytes
// This is a Bitmap requirement
// (size + (align - 1)) & ~(align - 1)
var aligned = (bytesToWrite + 3) & ~3;
var fileSize = 62 + dim * aligned;
var buf = new byte[fileSize];
// NOTE: BMP file header
buf[0] = (byte)'B';
buf[1] = (byte)'M';
buf[2] = (byte)fileSize;
buf[3] = (byte)(fileSize >> 8);
buf[4] = (byte)(fileSize >> 16);
buf[5] = (byte)(fileSize >> 24);
// NOTE: Offset to bitmap data
buf[10] = 62;
// NOTE: BMP info header
buf[14] = 40;
// NOTE: Image width
buf[18] = (byte)dim;
buf[19] = (byte)(dim >> 8);
buf[20] = (byte)(dim >> 16);
buf[21] = (byte)(dim >> 24);
// NOTE: Image height
buf[22] = buf[18];
buf[23] = buf[19];
buf[24] = buf[20];
buf[25] = buf[21];
// NOTE: Number of color planes (usually 1)
// Must be non-zero
buf[26] = 1;
// NOTE: Number of bits per pixel (1 bpp)
buf[28] = 1;
// NOTE: Horizontal resolution (pixels/meter)
// 3780 ppm (96 dpi)
buf[38] = 196;
buf[39] = 14;
// NOTE: Vertical resolution (pixels/meter)
// 3780 ppm (96 dpi)
buf[42] = buf[38];
buf[43] = buf[39];
// NOTE: Color table
// Alpha isn't useful here
// Foreground - Dark
buf[54] = (byte)foreground; // blue
buf[55] = (byte)(foreground >> 8); // green
buf[56] = (byte)(foreground >> 16); // red
// Background - Light
buf[58] = (byte)background; // blue
buf[59] = (byte)(background >> 8); // green
buf[60] = (byte)(background >> 16); // red
var scaledBorder = border * scale;
int i;
int y;
byte px;
if (border > 0)
{
var scaledSize = _size * scale;
for (i = 0; i < aligned; ++i)
{
px = 255;
if (i == bytesToWrite - 1)
{
px = (byte)(255 << ((bytesToWrite << 3) - dim));
}
else if (i >= bytesToWrite)
{
px = 0;
}
for (y = 0; y < scaledBorder; ++y)
{
buf[62 + i + y * aligned] = px;
buf[62 + i + (y + scaledSize + scaledBorder) * aligned] = px;
}
}
}
for (y = 0; y < _size; ++y)
{
int j;
var yOffset = y * scale + scaledBorder;
for (i = 0; i < aligned; ++i)
{
px = 0;
for (j = 0; j < 8; ++j)
{
var x = ((i << 3) + j) / scale;
if (x >= dim)
{
continue;
}
if (x < border || x >= _size + border)
{
px |= (byte)(1 << (7 - j));
continue;
}
px |= (byte)(_modules[(_size - y - 1), x - border] ? 0 : 1 << (7 - j));
}
buf[62 + i + yOffset * aligned] = px;
}
// NOTE: Copy rows when scaling
for (i = 1; i <= scale - 1; ++i)
{
for (j = 0; j < aligned; ++j)
{
buf[62 + j + (yOffset + i) * aligned] = buf[62 + j + yOffset * aligned];
}
}
}
return buf;
}
// Append a SVG/XAML path for the QR code to the provided string builder
private static void CreatePath(StringBuilder path, bool[,] modules, int border)
{
// Simple algorithm to reduce the number of rectangles for drawing the QR code
// and reduce SVG/XAML size.
var size = modules.GetLength(0);
for (var y = 0; y < size; y++)
{
for (var x = 0; x < size; x++)
{
if (modules[y, x])
{
DrawLargestRectangle(path, modules, x, y, border);
}
}
}
}
// Find, draw and clear largest rectangle with (x, y) as the top left corner
private static void DrawLargestRectangle(StringBuilder path, bool[,] modules, int x, int y, int border)
{
var size = modules.GetLength(0);
var bestW = 1;
var bestH = 1;
var maxArea = 1;
var xLimit = size;
var iy = y;
while (iy < size && modules[iy, x])
{
var w = 0;
while (x + w < xLimit && modules[iy, x + w])
{
w++;
}
var area = w * (iy - y + 1);
if (area > maxArea)
{
maxArea = area;
bestW = w;
bestH = iy - y + 1;
}
xLimit = x + w;
iy++;
}
// append path command
if (x != 0 || y != 0)
{
path.Append(' ');
}
// Different locales use different minus signs.
FormattableString pathElement = $"M{x + border},{y + border}h{bestW}v{bestH}h{-bestW}z";
path.Append(pathElement.ToString(CultureInfo.InvariantCulture));
// clear processed modules
ClearRectangle(modules, x, y, bestW, bestH);
}
// Clear a rectangle of modules
private static void ClearRectangle(bool[,] modules, int x, int y, int width, int height)
{
for (var iy = y; iy < y + height; iy++)
{
for (var ix = x; ix < x + width; ix++)
{
modules[iy, ix] = false;
}
}
}
// Create a copy of the modules (in row-major order)
private bool[,] CopyModules()
{
var modules = new bool[_size, _size];
for (var y = 0; y < _size; y++)
{
for (var x = 0; x < _size; x++)
{
modules[y, x] = _modules[y, x];
}
}
return modules;
}
}
}
================================================
FILE: QrCodeGenerator/Objects.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Helper functions to check for valid arguments.
///
internal static class Objects
{
///
/// Ensures that the specified argument is not null.
///
/// Throws a exception if the argument is null.
///
///
/// The type of the argument.
/// The argument to check.
/// Argument passed to function.
/// The specified argument is null.
internal static T RequireNonNull(T arg)
{
if (arg == null)
{
throw new ArgumentNullException();
}
return arg;
}
}
}
================================================
FILE: QrCodeGenerator/PngBuilder.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
*
*/
using System;
using System.IO;
using System.IO.Compression;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Creates a PNG file from a given QR code.
///
internal sealed class PngBuilder
{
private static readonly byte[] Signature = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
private static readonly uint[] CrcTable =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
private static readonly byte[] IHDR = { 73, 72, 68, 82 };
private static readonly byte[] PLTE = { 80, 76, 84, 69 };
private static readonly byte[] IDAT = { 73, 68, 65, 84 };
private static readonly byte[] IEND = { 73, 69, 78, 68 };
///
/// Creates a PNG image for the given QR code.
///
/// The PNG image uses indexed colors, 1 bit per pixel and a palette with entries for the foreground and background colors.
///
///
/// The QR code.
/// The border width, as a factor of the module (QR code pixel) size.
/// The width and height, in pixels, of each module.
/// The foreground color (dark modules), in RGB value (little endian).
/// The background color (light modules), in RGB value (little endian).
/// A PNG image, as a byte array.
///
internal static byte[] ToImage(QrCode qrCode, int scale, int border, int foreground, int background)
{
var imageSize = (qrCode.Size + border * 2) * scale;
var builder = new PngBuilder();
builder.WriteHeader(imageSize, imageSize, 1, 3);
builder.WritePalette(new int[] { background, foreground });
builder.WriteData(CreateBitmap(qrCode, border, scale));
builder.WriteEnd();
return builder.GetBytes();
}
///
/// Creates an uncompressed 1-bit per pixel bitmap of the QR code.
///
/// The QR code
/// The border
/// The scale
/// Bitmap, as a byte array
private static byte[] CreateBitmap(QrCode qrCode, int border, int scale)
{
var size = qrCode.Size;
var imageSize = (size + border * 2) * scale;
var bytesPerLine = (imageSize + 7) / 8 + 1; // additional byte at the start for filter type
var data = new byte[bytesPerLine * imageSize];
for (var y = 0; y < size; y++)
{
var offset = (border + y) * scale * bytesPerLine;
for (var x = 0; x < size; x++)
{
if (!qrCode.GetModule(x, y))
continue;
var pos = (border + x) * scale;
var end = pos + scale;
// set pixels for module ('scale' times)
for (; pos < end; pos++)
{
var index = offset + pos / 8 + 1;
data[index] |= (byte)(0x80U >> (pos % 8));
}
}
// replicate line 'scale' times
for (var i = 1; i < scale; i++)
Array.Copy(data, offset, data, offset + i * bytesPerLine, bytesPerLine);
}
return data;
}
private readonly MemoryStream stream = new MemoryStream();
///
/// Returns the resulting PNG bytes.
///
/// PNG file, as a byte array.
private byte[] GetBytes()
{
var bytes = stream.ToArray();
SetCRC(bytes);
return bytes;
}
///
/// Writes the PNG header (IHDR chunk).
///
/// The image width.
/// The image height.
/// The bits per pixel.
/// The color type (see PNG specification).
private void WriteHeader(int width, int height, byte bitDepth, byte colorType)
{
stream.Write(Signature, 0, Signature.Length);
WriteChunkStart(IHDR, 13);
WriteIntBigEndian((uint)width);
WriteIntBigEndian((uint)height);
stream.WriteByte(bitDepth);
stream.WriteByte(colorType);
stream.WriteByte(0);
stream.WriteByte(0);
stream.WriteByte(0);
WriteChunkEnd();
}
///
/// Writes the palette (PLTE chunk).
///
/// The color palettes as an array of RGB values.
private void WritePalette(int[] palette)
{
WriteChunkStart(PLTE, palette.Length * 3);
foreach (var color in palette)
{
stream.WriteByte((byte)((color >> 16) & 0xFF));
stream.WriteByte((byte)((color >> 8) & 0xFF));
stream.WriteByte((byte)(color & 0xFF));
}
WriteChunkEnd();
}
///
/// Writes the pixel data (IDAT chunk).
///
/// The pixel data.
private void WriteData(byte[] data)
{
var compressedData = Deflate(data);
WriteChunkStart(IDAT, compressedData.Length + 6);
stream.WriteByte(0x78);
stream.WriteByte(0x9C);
stream.Write(compressedData, 0, compressedData.Length);
var adler = CalcAdler32(data, 0, data.Length);
WriteIntBigEndian(adler);
WriteChunkEnd();
}
///
/// Writes the end chunk (IEND).
///
private void WriteEnd()
{
WriteChunkStart(IEND, 0);
WriteChunkEnd();
}
private static void SetCRC(byte[] bytes)
{
var chunkOffset = Signature.Length;
while (chunkOffset < bytes.Length)
{
// calculate CRC
var dataLength = (bytes[chunkOffset] << 24) | (bytes[chunkOffset + 1] << 16) | (bytes[chunkOffset + 2] << 8) | bytes[chunkOffset + 3];
var crc = CalcCrc32(bytes, chunkOffset + 4, dataLength + 4);
var crcOffset = chunkOffset + 8 + dataLength;
// set CRC
bytes[crcOffset + 0] = (byte)(crc >> 24);
bytes[crcOffset + 1] = (byte)(crc >> 16);
bytes[crcOffset + 2] = (byte)(crc >> 8);
bytes[crcOffset + 3] = (byte)crc;
chunkOffset = crcOffset + 4;
}
}
private void WriteChunkStart(byte[] type, int length)
{
WriteIntBigEndian((uint)length);
stream.Write(type, 0, 4);
}
private void WriteChunkEnd()
{
stream.SetLength(stream.Length + 4);
stream.Position += 4;
}
private void WriteIntBigEndian(uint value)
{
stream.WriteByte((byte)(value >> 24));
stream.WriteByte((byte)(value >> 16));
stream.WriteByte((byte)(value >> 8));
stream.WriteByte((byte)value);
}
private static byte[] Deflate(byte[] data)
{
var output = new MemoryStream();
using (var deflater = new DeflateStream(output, CompressionLevel.Optimal))
{
deflater.Write(data, 0, data.Length);
}
return output.ToArray();
}
private static uint CalcAdler32(byte[] data, int index, int length)
{
const uint Base = 65521;
uint s1 = 1;
uint s2 = 0;
var end = index + length;
for (var n = index; n < end; n++)
{
s1 = (s1 + data[n]) % Base;
s2 = (s2 + s1) % Base;
}
return (s2 << 16) + s1;
}
private static uint CalcCrc32(byte[] data, int index, int length)
{
var c = 0xffffffff;
var end = index + length;
for (var n = index; n < end; n++)
c = CrcTable[(c ^ data[n]) & 0xff] ^ (c >> 8);
return c ^ 0xffffffff;
}
}
}
================================================
FILE: QrCodeGenerator/QrCode.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Represents a QR code containing text or binary data.
///
/// Instances of this class represent an immutable square grid of dark and light pixels
/// (called modules by the QR code specification).
/// Static factory methods are provided to create QR codes from text or binary data.
/// Some of the methods provide detailed control about the encoding parameters such a QR
/// code size (called version by the standard), error correction level and mask.
///
///
/// QR codes are a type of two-dimensional barcodes, invented by Denso Wave and
/// described in the ISO/IEC 18004 standard.
///
///
/// This class covers the QR Code Model 2 specification, supporting all versions (sizes)
/// from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
///
///
///
/// To create a QR code instance:
///
///
///
High level: Take the payload data and call
/// or .
///
Mid level: Custom-make a list of instances and call
///
///
Low level: Custom-make an array of data codeword bytes (including segment headers and
/// final padding, excluding error correction codewords), supply the appropriate version number,
/// and call the .
///
///
///
public class QrCode
{
#region Static factory functions (high level)
///
/// Creates a QR code representing the specified text using the specified error correction level.
///
/// As a conservative upper bound, this function is guaranteed to succeed for strings with up to 738
/// Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
/// QR code version (size) is automatically chosen. The resulting ECC level will be higher than the one
/// specified if it can be achieved without increasing the size (version).
///
///
/// The text to be encoded. The full range of Unicode characters may be used.
/// The minimum error correction level to use.
/// The created QR code instance representing the specified text.
/// or is null.
/// The text is too long to fit in the largest QR code size (version)
/// at the specified error correction level.
public static QrCode EncodeText(string text, Ecc ecl)
{
Objects.RequireNonNull(text);
Objects.RequireNonNull(ecl);
var segments = QrSegment.MakeSegments(text);
return EncodeSegments(segments, ecl);
}
///
/// Creates a series of QR codes representing the specified text.
///
/// The result will consist of the minimal number of QR codes needed
/// to encode the text with the given error correction level and version (size of QR code).
/// If multiple QR codes are required, Structured Append data is included to link the QR codes.
///
///
/// Each QR code might use multiple segments with different encoding modes
/// to maximize the amount of text that can be stored in each QR code.
///
///
/// Each QR code will contain a valid string as it is ensured that splitting only occurs
/// at character boundaries and not in the middle of a multi-byte encoding of a character.
/// This increases compatibility with QR code scanners that incorrectly assume that each
/// individual QR code in the series contains a valid UTF-8 string.
///
///
/// The text to be encoded. The full range of Unicode characters may be used.
/// The minimum error correction level to use.
/// The version (size of QR code) to use. Default is 29.
/// Whether error correction level should be upgraded if possible. Default is false.
/// A list of QR codes representing the specified text.
/// or is null.
/// The text is too long to fit the maximum of 16 QR codes with the given parameters.
public static List EncodeTextInMultipleCodes(string text, Ecc ecl, int version = 29, bool boostEcl = true)
{
Objects.RequireNonNull(text);
Objects.RequireNonNull(ecl);
// Test if text fits in a single QR code
try {
var segments = QrSegmentAdvanced.MakeSegmentsOptimally(text, ecl, version, version);
var qrCode = EncodeSegments(segments, ecl, minVersion: version, maxVersion: version, boostEcl: boostEcl);
return new List { qrCode };
} catch (DataTooLongException)
{
// Continue with multiple QR codes
}
return QrSegmentAdvanced.MakeSegmentsForMultipleCodes(text, ecl, version)
.Select(segmentList => EncodeSegments(segmentList, ecl, minVersion: version, maxVersion: version, boostEcl: boostEcl))
.ToList();
}
///
/// Creates a QR code representing the specified binary data using the specified error correction level.
///
/// This function encodes the data in the binary segment mode. The maximum number of
/// bytes allowed is 2953. The smallest possible QR code version is automatically chosen.
/// The resulting ECC level will be higher than the one specified if it can be achieved without increasing the size (version).
///
///
/// The binary data to encode.
/// The minimum error correction level to use.
/// The created QR code representing the specified data.
/// or is null.
/// The specified data is too long to fit in the largest QR code size (version)
/// at the specified error correction level.
public static QrCode EncodeBinary(byte[] data, Ecc ecl)
{
Objects.RequireNonNull(data);
Objects.RequireNonNull(ecl);
var seg = QrSegment.MakeBytes(data);
return EncodeSegments(new List { seg }, ecl);
}
#endregion
#region Static factory functions (mid level)
///
/// Creates a QR code representing the specified segments with the specified encoding parameters.
///
/// The smallest possible QR code version (size) is used. The range of versions can be
/// restricted by the and parameters.
///
///
/// If is true, the resulting ECC level will be higher than the
/// one specified if it can be achieved without increasing the size (version).
///
///
/// The QR code mask is usually automatically chosen. It can be explicitly set with the
/// parameter by using a value between 0 to 7 (inclusive). -1 is for automatic mode (which may be slow).
///
///
/// This function allows the user to create a custom sequence of segments that switches
/// between modes (such as alphanumeric and byte) to encode text in less space and gives full control over all
/// encoding parameters.
///
///
///
/// This is a mid-level API; the high-level APIs are
/// and .
///
/// The segments to encode.
/// The minimal or fixed error correction level to use .
/// The minimum version (size) of the QR code (between 1 and 40).
/// The maximum version (size) of the QR code (between 1 and 40).
/// The mask number to use (between 0 and 7), or -1 for automatic mask selection.
/// If true the ECC level wil be increased if it can be achieved without increasing the size (version).
/// The created QR code representing the segments.
/// , any list element, or is null.
/// 1 ≤ minVersion ≤ maxVersion ≤ 40
/// or -1 ≤ mask ≤ 7 is violated.
/// The segments are too long to fit in the largest QR code size (version)
/// at the specified error correction level.
public static QrCode EncodeSegments(List segments, Ecc ecl, int minVersion = MinVersion, int maxVersion = MaxVersion, int mask = -1, bool boostEcl = true)
{
Objects.RequireNonNull(segments);
Objects.RequireNonNull(ecl);
if (minVersion < MinVersion || minVersion > maxVersion)
{
throw new ArgumentOutOfRangeException(nameof(minVersion), "Invalid value");
}
if (maxVersion > MaxVersion)
{
throw new ArgumentOutOfRangeException(nameof(maxVersion), "Invalid value");
}
if (mask < -1 || mask > 7)
{
throw new ArgumentOutOfRangeException(nameof(mask), "Invalid value");
}
// Find the minimal version number to use
int version, dataUsedBits;
for (version = minVersion; ; version++)
{
var numDataBits = GetNumDataCodewords(version, ecl) * 8; // Number of data bits available
dataUsedBits = QrSegment.GetTotalBits(segments, version);
if (dataUsedBits != -1 && dataUsedBits <= numDataBits)
{
break; // This version number is found to be suitable
}
if (version < maxVersion)
{
continue;
}
// All versions in the range could not fit the given data
var msg = "Segment too long";
if (dataUsedBits != -1)
{
msg = $"Data length = {dataUsedBits} bits, Max capacity = {numDataBits} bits";
}
throw new DataTooLongException(msg);
}
Debug.Assert(dataUsedBits != -1);
// Increase the error correction level while the data still fits in the current version number
foreach (var newEcl in Ecc.AllValues)
{ // From low to high
if (boostEcl && dataUsedBits <= GetNumDataCodewords(version, newEcl) * 8)
{
ecl = newEcl;
}
}
// Concatenate all segments to create the data bit string
var ba = new BitArray(0);
foreach (var seg in segments)
{
ba.AppendBits(seg.EncodingMode.ModeBits, 4);
ba.AppendBits((uint)seg.NumChars, seg.EncodingMode.NumCharCountBits(version));
ba.AppendData(seg.GetData());
}
Debug.Assert(ba.Length == dataUsedBits);
// Add terminator and pad up to a byte if applicable
var dataCapacityBits = GetNumDataCodewords(version, ecl) * 8;
Debug.Assert(ba.Length <= dataCapacityBits);
ba.AppendBits(0, Math.Min(4, dataCapacityBits - ba.Length));
ba.AppendBits(0, (8 - ba.Length % 8) % 8);
Debug.Assert(ba.Length % 8 == 0);
// Pad with alternating bytes until data capacity is reached
for (uint padByte = 0xEC; ba.Length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
{
ba.AppendBits(padByte, 8);
}
// Pack bits into bytes in big endian
var dataCodewords = new byte[ba.Length / 8];
for (var i = 0; i < ba.Length; i++)
{
if (ba.Get(i))
{
dataCodewords[i >> 3] |= (byte)(1 << (7 - (i & 7)));
}
}
// Create the QR code object
return new QrCode(version, ecl, dataCodewords, mask);
}
#endregion
#region Public immutable properties
///
/// The version (size) of this QR code (between 1 for the smallest and 40 for the biggest).
///
/// The QR code version (size).
public int Version { get; }
///
/// The width and height of this QR code, in modules (pixels).
/// The size is a value between 21 and 177.
/// This is equal to version × 4 + 17.
///
/// The QR code size.
public int Size { get; }
///
/// The error correction level used for this QR code.
///
/// The error correction level.
public Ecc ErrorCorrectionLevel { get; }
///
/// The index of the mask pattern used fort this QR code (between 0 and 7).
///
/// Even if a QR code is created with automatic mask selection (mask = 1),
/// this property returns the effective mask used.
///
///
/// The mask pattern index.
public int Mask { get; }
#endregion
#region Private grids of modules/pixels, with dimensions of size * size
// The modules of this QR code (false = light, true = dark).
// Immutable after constructor finishes. Accessed through GetModule().
private readonly bool[,] _modules;
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
private readonly bool[,] _isFunction;
#endregion
#region Constructor (low level)
///
/// Constructs a QR code with the specified version number,
/// error correction level, data codeword bytes, and mask number.
///
///
/// This is a low-level API that most users should not use directly. A mid-level
/// API is the function.
///
/// The version (size) to use (between 1 to 40).
/// The error correction level to use.
/// The bytes representing segments to encode (without ECC).
/// The mask pattern to use (either -1 for automatic selection, or a value from 0 to 7 for fixed choice).
/// or is null.
/// The version or mask value is out of range,
/// or the data has an invalid length for the specified version and error correction level.
public QrCode(int version, Ecc ecl, byte[] dataCodewords, int mask = -1)
{
// Check arguments and initialize fields
if (version < MinVersion || version > MaxVersion)
{
throw new ArgumentOutOfRangeException(nameof(version), "Version value out of range");
}
if (mask < -1 || mask > 7)
{
throw new ArgumentOutOfRangeException(nameof(mask), "Mask value out of range");
}
Version = version;
Size = version * 4 + 17;
Objects.RequireNonNull(ecl);
ErrorCorrectionLevel = ecl;
Objects.RequireNonNull(dataCodewords);
_modules = new bool[Size, Size]; // Initially all light
_isFunction = new bool[Size, Size];
// Compute ECC, draw modules, do masking
DrawFunctionPatterns();
var allCodewords = AddEccAndInterleave(dataCodewords);
DrawCodewords(allCodewords);
// Do masking
if (mask == -1)
{
// Automatically choose best mask
var minPenalty = int.MaxValue;
for (uint i = 0; i < 8; i++)
{
ApplyMask(i);
DrawFormatBits(i);
var penalty = GetPenaltyScore();
if (penalty < minPenalty)
{
mask = (int)i;
minPenalty = penalty;
}
ApplyMask(i); // Undoes the mask due to XOR
}
}
Debug.Assert(0 <= mask && mask <= 7);
Mask = mask;
ApplyMask((uint)mask); // Apply the final choice of mask
DrawFormatBits((uint)mask); // Overwrite old format bits
_isFunction = null;
}
#endregion
#region Public methods
///
/// Gets the color of the module (pixel) at the specified coordinates.
///
/// The top left corner has the coordinates (x=0, y=0). x-coordinates extend from left to right,
/// y-coordinates extend from top to bottom.
///
///
/// If coordinates outside the bounds of this QR code are specified, light (false) is returned.
///
///
/// The x coordinate.
/// The y coordinate.
/// The color of the specified module: true for dark modules and false
/// for light modules (or if the coordinates are outside the bounds).
public bool GetModule(int x, int y)
{
return 0 <= x && x < Size && 0 <= y && y < Size && _modules[y, x];
}
///
/// Creates an SVG image of this QR code.
///
/// The images uses Unix newlines (\n), regardless of the platform.
///
///
/// The border width, as a factor of the module (QR code pixel) size
/// The SVG image as a string.
public string ToSvgString(int border)
{
return ToSvgString(border, "#000000", "#ffffff");
}
///
/// Creates an SVG image of this QR code.
///
/// The images uses Unix newlines (\n), regardless of the platform.
///
///
/// Colors are specified using CSS color data type. Examples of valid values are
/// "#339966", "fuchsia", "rgba(137, 23, 89, 0.3)".
///
///
/// The border width, as a factor of the module (QR code pixel) size
/// The foreground color.
/// The background color.
public string ToSvgString(int border, string foreground, string background)
{
return AsGraphics().ToSvgString(border, foreground, background);
}
///
/// Creates a graphics path of this QR code valid in SVG or XAML.
///
/// The graphics path uses a coordinate system where each module is 1 unit wide and tall,
/// and the top left module is offset vertically and horizontally by border units.
///
///
/// Note that a border width other than 0 only make sense if the bounding box of the QR code
/// is explicitly set by the graphics using this path. If the bounding box of this path is
/// automatically derived, at least the right and bottom border will be missing.
///
///
/// The path will look like this: M3,3h7v1h-7z M12,3h1v4h-1z ... M70,71h1v1h-1z. It
/// is valid for SVG (<path d="M3,3h..." />) and for XAML
/// (<Path Data="M3,3h..." />). For programmatic geometry creation in WPF see
/// Geometry.Parse(String).
///
///
/// The border width, as a factor of the module (QR code pixel) size
/// The graphics path
/// Thrown if border is negative
public string ToGraphicsPath(int border = 0)
{
return AsGraphics().ToGraphicsPath(border);
}
///
/// Creates a bitmap in the BMP format.
///
/// The bitmap uses 1 bit per pixel and a color table with 2 entries.
///
///
/// Color values can be created with .
///
///
/// The border width, as a factor of the module (QR code pixel) size.
/// The width and height, in pixels, of each module.
/// The foreground color (dark modules), in RGB value (little endian).
/// The background color (light modules), in RGB value (little endian).
/// Bitmap data
/// Thrown if is negative,
/// is less than 1 or the resulting image is wider than 32,768 pixels.
public byte[] ToBmpBitmap(int border, int scale, int foreground, int background)
{
return AsGraphics().ToBmpBitmap(border, scale, foreground, background);
}
///
/// Creates bitmap in the BMP format data using black for dark modules and white for light modules.
///
/// The bitmap uses 1 bit per pixel and a color table with 2 entries.
///
///
/// The border width, as a factor of the module (QR code pixel) size.
/// The width and height, in pixels, of each module.
/// Bitmap data
/// Thrown if is negative,
/// is less than 1 or the resulting image is wider than 32,768 pixels.
public byte[] ToBmpBitmap(int border = 0, int scale = 1)
{
return ToBmpBitmap(border, scale, 0x000000, 0xffffff);
}
///
/// Creates bitmap in the PNG format data using specified foreground and background colors for dark and light modules.
///
/// The border width, as a factor of the module (QR code pixel) size.
/// The width and height, in pixels, of each module.
/// The foreground color (dark modules), in RGB value (little endian).
/// The background color (light modules), in RGB value (little endian).
/// Bitmap data
public byte[] ToPngBitmap(int border, int scale, int foreground, int background)
{
return PngBuilder.ToImage(this, scale, border, foreground, background);
}
///
/// Creates bitmap in the PNG format data using black for dark modules and white for light modules.
///
/// The border width, as a factor of the module (QR code pixel) size.
/// The width and height, in pixels, of each module.
/// Bitmap data
public byte[] ToPngBitmap(int border = 0, int scale = 1)
{
return PngBuilder.ToImage(this, scale, border, 0x000000, 0xffffff);
}
///
/// Creates an RGB color value in little endian format.
///
/// Red component.
/// Green component.
/// Blue component.
/// RGB color value
public int RgbColor(byte red, byte green, byte blue)
{
return (red << 16) | (green << 8) | blue;
}
#endregion
#region Private helper methods for constructor: Drawing function modules
// Reads this object's version field, and draws and marks all function modules.
private void DrawFunctionPatterns()
{
// Draw horizontal and vertical timing patterns
for (var i = 0; i < Size; i++)
{
SetFunctionModule(6, i, i % 2 == 0);
SetFunctionModule(i, 6, i % 2 == 0);
}
// Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
DrawFinderPattern(3, 3);
DrawFinderPattern(Size - 4, 3);
DrawFinderPattern(3, Size - 4);
// Draw numerous alignment patterns
var alignPatPos = GetAlignmentPatternPositions();
var numAlign = alignPatPos.Length;
for (var i = 0; i < numAlign; i++)
{
for (var j = 0; j < numAlign; j++)
{
// Don't draw on the three finder corners
if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
{
DrawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
}
}
}
// Draw configuration data
DrawFormatBits(0); // Dummy mask value; overwritten later in the constructor
DrawVersion();
}
// Draws two copies of the format bits (with its own error correction code)
// based on the given mask and this object's error correction level field.
private void DrawFormatBits(uint mask)
{
// Calculate error correction code and pack bits
var data = (ErrorCorrectionLevel.FormatBits << 3) | mask; // errCorrLvl is uint2, mask is uint3
var rem = data;
for (var i = 0; i < 10; i++)
{
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
}
var bits = ((data << 10) | rem) ^ 0x5412; // uint15
Debug.Assert(bits >> 15 == 0);
// Draw first copy
for (var i = 0; i <= 5; i++)
{
SetFunctionModule(8, i, GetBit(bits, i));
}
SetFunctionModule(8, 7, GetBit(bits, 6));
SetFunctionModule(8, 8, GetBit(bits, 7));
SetFunctionModule(7, 8, GetBit(bits, 8));
for (var i = 9; i < 15; i++)
{
SetFunctionModule(14 - i, 8, GetBit(bits, i));
}
// Draw second copy
for (var i = 0; i < 8; i++)
{
SetFunctionModule(Size - 1 - i, 8, GetBit(bits, i));
}
for (var i = 8; i < 15; i++)
{
SetFunctionModule(8, Size - 15 + i, GetBit(bits, i));
}
SetFunctionModule(8, Size - 8, true); // Always dark
}
// Draws two copies of the version bits (with its own error correction code),
// based on this object's version field, iff 7 <= version <= 40.
private void DrawVersion()
{
if (Version < 7)
{
return;
}
// Calculate error correction code and pack bits
var rem = (uint)Version; // version is uint6, in the range [7, 40]
for (var i = 0; i < 12; i++)
{
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
}
var bits = ((uint)Version << 12) | rem; // uint18
Debug.Assert(bits >> 18 == 0);
// Draw two copies
for (var i = 0; i < 18; i++)
{
var bit = GetBit(bits, i);
var a = Size - 11 + i % 3;
var b = i / 3;
SetFunctionModule(a, b, bit);
SetFunctionModule(b, a, bit);
}
}
// Draws a 9*9 finder pattern including the border separator,
// with the center module at (x, y). Modules can be out of bounds.
private void DrawFinderPattern(int x, int y)
{
for (var dy = -4; dy <= 4; dy++)
{
for (var dx = -4; dx <= 4; dx++)
{
var dist = Math.Max(Math.Abs(dx), Math.Abs(dy)); // Chebyshev/infinity norm
int xx = x + dx, yy = y + dy;
if (0 <= xx && xx < Size && 0 <= yy && yy < Size)
{
SetFunctionModule(xx, yy, dist != 2 && dist != 4);
}
}
}
}
// Draws a 5*5 alignment pattern, with the center module
// at (x, y). All modules must be in bounds.
private void DrawAlignmentPattern(int x, int y)
{
for (var dy = -2; dy <= 2; dy++)
{
for (var dx = -2; dx <= 2; dx++)
{
SetFunctionModule(x + dx, y + dy, Math.Max(Math.Abs(dx), Math.Abs(dy)) != 1);
}
}
}
// Sets the color of a module and marks it as a function module.
// Only used by the constructor. Coordinates must be in bounds.
private void SetFunctionModule(int x, int y, bool isDark)
{
_modules[y, x] = isDark;
_isFunction[y, x] = true;
}
private Graphics AsGraphics()
{
return new Graphics(Size, _modules);
}
#endregion
#region Private helper methods for constructor: Codewords and masking
// Returns a new byte string representing the given data with the appropriate error correction
// codewords appended to it, based on this object's version and error correction level.
private byte[] AddEccAndInterleave(byte[] data)
{
Objects.RequireNonNull(data);
if (data.Length != GetNumDataCodewords(Version, ErrorCorrectionLevel))
{
throw new ArgumentOutOfRangeException(nameof(data), "Length of data does not match version and ecl");
}
// Calculate parameter numbers
int numBlocks = NumErrorCorrectionBlocks[ErrorCorrectionLevel.Ordinal, Version];
int blockEccLen = EccCodewordsPerBlock[ErrorCorrectionLevel.Ordinal, Version];
var rawCodewords = GetNumRawDataModules(Version) / 8;
var numShortBlocks = numBlocks - rawCodewords % numBlocks;
var shortBlockLen = rawCodewords / numBlocks;
// Split data into blocks and append ECC to each block
var blocks = new byte[numBlocks][];
var rsDiv = new ReedSolomonGenerator(blockEccLen);
for (int i = 0, k = 0; i < numBlocks; i++)
{
var dat = CopyOfRange(data, k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
k += dat.Length;
var block = CopyOf(dat, shortBlockLen + 1);
var ecc = rsDiv.GetRemainder(dat);
Array.Copy(ecc, 0, block, block.Length - blockEccLen, ecc.Length);
blocks[i] = block;
}
// Interleave (not concatenate) the bytes from every block into a single sequence
var result = new byte[rawCodewords];
for (int i = 0, k = 0; i < blocks[0].Length; i++)
{
for (var j = 0; j < blocks.Length; j++)
{
// Skip the padding byte in short blocks
if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
{
result[k] = blocks[j][i];
k++;
}
}
}
return result;
}
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
// data area of this QR code. Function modules need to be marked off before this is called.
private void DrawCodewords(byte[] data)
{
Objects.RequireNonNull(data);
if (data.Length != GetNumRawDataModules(Version) / 8)
{
throw new ArgumentOutOfRangeException(nameof(data), "data length does not match version");
}
var i = 0; // Bit index into the data
// Do the funny zigzag scan
for (var right = Size - 1; right >= 1; right -= 2)
{
// Index of right column in each column pair
if (right == 6)
{
right = 5;
}
for (var vert = 0; vert < Size; vert++)
{
// Vertical counter
for (var j = 0; j < 2; j++)
{
var x = right - j; // Actual x coordinate
var upward = ((right + 1) & 2) == 0;
var y = upward ? Size - 1 - vert : vert; // Actual y coordinate
if (!_isFunction[y, + x] && i < data.Length * 8)
{
_modules[y, x] = GetBit(data[(uint)i >> 3], 7 - (i & 7));
i++;
}
// If this QR code has any remainder bits (0 to 7), they were assigned as
// 0/false/light by the constructor and are left unchanged by this method
}
}
}
Debug.Assert(i == data.Length * 8);
}
// XORs the codeword modules in this QR code with the given mask pattern.
// The function modules must be marked and the codeword bits must be drawn
// before masking. Due to the arithmetic of XOR, calling applyMask() with
// the same mask value a second time will undo the mask. A final well-formed
// QR code needs exactly one (not zero, two, etc.) mask applied.
private void ApplyMask(uint mask)
{
if (mask < 0 || mask > 7)
{
throw new ArgumentOutOfRangeException(nameof(mask), "Mask value out of range");
}
for (var y = 0; y < Size; y++)
{
for (var x = 0; x < Size; x++)
{
var invert = false;
switch (mask)
{
case 0: invert = (x + y) % 2 == 0; break;
case 1: invert = y % 2 == 0; break;
case 2: invert = x % 3 == 0; break;
case 3: invert = (x + y) % 3 == 0; break;
case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
}
_modules[y, x] ^= invert && !_isFunction[y, x];
}
}
}
// Calculates and returns the penalty score based on state of this QR code's current modules.
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
private int GetPenaltyScore()
{
var result = 0;
// Adjacent modules in row having same color, and finder-like patterns
for (var y = 0; y < Size; y++)
{
var runColor = false;
var runX = 0;
var finderPenalty = new FinderPenalty(Size);
for (var x = 0; x < Size; x++)
{
if (_modules[y, x] == runColor)
{
runX++;
if (runX == 5)
{
result += PenaltyN1;
}
else if (runX > 5)
{
result++;
}
}
else
{
finderPenalty.AddHistory(runX);
if (!runColor)
{
result += finderPenalty.CountPatterns() * PenaltyN3;
}
runColor = _modules[y, x];
runX = 1;
}
}
result += finderPenalty.TerminateAndCount(runColor, runX) * PenaltyN3;
}
// Adjacent modules in column having same color, and finder-like patterns
for (var x = 0; x < Size; x++)
{
var runColor = false;
var runY = 0;
var finderPenalty = new FinderPenalty(Size);
for (var y = 0; y < Size; y++)
{
if (_modules[y, x] == runColor)
{
runY++;
if (runY == 5)
{
result += PenaltyN1;
}
else if (runY > 5)
{
result++;
}
}
else
{
finderPenalty.AddHistory(runY);
if (!runColor)
{
result += finderPenalty.CountPatterns() * PenaltyN3;
}
runColor = _modules[y, x];
runY = 1;
}
}
result += finderPenalty.TerminateAndCount(runColor, runY) * PenaltyN3;
}
// 2*2 blocks of modules having same color
for (var y = 0; y < Size - 1; y++)
{
for (var x = 0; x < Size - 1; x++)
{
var color = _modules[y, x];
if (color == _modules[y, x + 1] &&
color == _modules[y + 1, x] &&
color == _modules[y + 1, x + 1])
{
result += PenaltyN2;
}
}
}
// Balance of dark and light modules
var dark = 0;
for (var y = 0; y < Size; y++)
{
for (var x = 0; x < Size; x++)
{
if (_modules[y, x])
{
dark++;
}
}
}
var total = Size * Size; // Note that size is odd, so dark/total != 1/2
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
var k = (Math.Abs(dark * 20 - total * 10) + total - 1) / total - 1;
result += k * PenaltyN4;
Debug.Assert(0 <= result && result <= 2568888); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
return result;
}
#endregion
#region Private helper functions
// Returns an ascending list of positions of alignment patterns for this version number.
// Each position is in the range [0,177), and are used on both the x and y axes.
// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
private int[] GetAlignmentPatternPositions()
{
if (Version == 1)
{
return Array.Empty();
}
else
{
var numAlign = Version / 7 + 2;
var step = (Version * 8 + numAlign * 3 + 5) / (numAlign * 4 - 4) * 2;
var result = new int[numAlign];
result[0] = 6;
for (int i = result.Length - 1, pos = Size - 7; i >= 1; i--, pos -= step)
{
result[i] = pos;
}
return result;
}
}
///
/// Returns the number of data bits that can be stored in a QR code of the given version.
///
/// The returned number is after all function modules are excluded. This includes remainder bits,
/// so it might not be a multiple of 8. The result is in the range [208, 29648].
///
///
private static int GetNumRawDataModules(int ver)
{
if (ver < MinVersion || ver > MaxVersion)
{
throw new ArgumentOutOfRangeException(nameof(ver), "Version number out of range");
}
var size = ver * 4 + 17;
var result = size * size; // Number of modules in the whole QR code square
result -= 8 * 8 * 3; // Subtract the three finders with separators
result -= 15 * 2 + 1; // Subtract the format information and dark module
result -= (size - 16) * 2; // Subtract the timing patterns (excluding finders)
// The five lines above are equivalent to: int result = (16 * ver + 128) * ver + 64;
if (ver >= 2)
{
var numAlign = ver / 7 + 2;
result -= (numAlign - 1) * (numAlign - 1) * 25; // Subtract alignment patterns not overlapping with timing patterns
result -= (numAlign - 2) * 2 * 20; // Subtract alignment patterns that overlap with timing patterns
// The two lines above are equivalent to: result -= (25 * numAlign - 10) * numAlign - 55;
if (ver >= 7)
{
result -= 6 * 3 * 2; // Subtract version information
}
}
Debug.Assert(208 <= result && result <= 29648);
return result;
}
///
/// Returns the number of 8-bit data codewords contained in a QR code of the given version number and error correction level.
///
/// The result is the net data capacity, without error correction data, and after discarding remainder bits.
///
///
/// The version number.
/// The error correction level.
/// The number of codewords.
public static int GetNumDataCodewords(int ver, Ecc ecl)
{
return GetNumRawDataModules(ver) / 8
- EccCodewordsPerBlock[ecl.Ordinal, ver]
* NumErrorCorrectionBlocks[ecl.Ordinal, ver];
}
// Helper class for getPenaltyScore().
// Internal the run history is organized in reverse order
// (compared to Nayuki's code) to avoid the copying when
// adding to the history.
private struct FinderPenalty
{
private readonly short[] _runHistory;
private readonly int _size;
public FinderPenalty(int size)
{
_size = size;
_runHistory = new short[7];
}
// Can only be called immediately after a light run is added, and
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
internal int CountPatterns()
{
int n = _runHistory[1];
Debug.Assert(n <= _size * 3);
var core = n > 0 && _runHistory[2] == n && _runHistory[3] == n * 3 && _runHistory[4] == n && _runHistory[5] == n;
return (core && _runHistory[0] >= n * 4 && _runHistory[6] >= n ? 1 : 0)
+ (core && _runHistory[6] >= n * 4 && _runHistory[0] >= n ? 1 : 0);
}
// Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
internal int TerminateAndCount(bool currentRunColor, int currentRunLength)
{
if (currentRunColor)
{
// Terminate dark run
AddHistory(currentRunLength);
currentRunLength = 0;
}
currentRunLength += _size; // Add light border to final run
AddHistory(currentRunLength);
return CountPatterns();
}
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
internal void AddHistory(int currentRunLength)
{
if (_runHistory[0] == 0)
currentRunLength += _size; // Add light border to initial run
Array.Copy(_runHistory, 0, _runHistory, 1, 6);
_runHistory[0] = (short) currentRunLength;
}
}
private static byte[] CopyOfRange(byte[] original, int from, int to)
{
var result = new byte[to - from];
Array.Copy(original, from, result, 0, to - from);
return result;
}
private static byte[] CopyOf(byte[] original, int newLength)
{
var result = new byte[newLength];
Array.Copy(original, result, Math.Min(original.Length, newLength));
return result;
}
// Returns true iff the i'th bit of x is set to 1.
private static bool GetBit(uint x, int i)
{
return ((x >> i) & 1) != 0;
}
#endregion
#region Constants and tables
///
/// The minimum version (size) supported in the QR Code Model 2 standard – namely 1.
///
/// The minimum version.
public const int MinVersion = 1;
///
/// The maximum version (size) supported in the QR Code Model 2 standard – namely 40.
///
/// The maximum version.
public const int MaxVersion = 40;
// For use in getPenaltyScore(), when evaluating which mask is best.
private const int PenaltyN1 = 3;
private const int PenaltyN2 = 3;
private const int PenaltyN3 = 40;
private const int PenaltyN4 = 10;
private static readonly byte[,] EccCodewordsPerBlock = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
// 0, 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 Error correction level { 255, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }, // Low
{ 255, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }, // Low
{ 255, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 }, // Medium
{ 255, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }, // Quartile
{ 255, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 } // High
};
private static readonly byte[,] NumErrorCorrectionBlocks = {
// Version: (note that index 0 is for padding, and is set to an illegal value)
// 0, 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 Error correction level
{ 255, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25 }, // Low
{ 255, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49 }, // Medium
{ 255, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68 }, // Quartile
{ 255, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81 } // High
};
#endregion
#region Public helper enumeration
///
/// Error correction level in QR code symbol.
///
public sealed class Ecc
{
///
/// Low error correction level. The QR code can tolerate about 7% erroneous codewords.
///
/// Low error correction level.
public static readonly Ecc Low = new Ecc(0, 1);
///
/// Medium error correction level. The QR code can tolerate about 15% erroneous codewords.
///
/// Medium error correction level.
public static readonly Ecc Medium = new Ecc(1, 0);
///
/// Quartile error correction level. The QR code can tolerate about 25% erroneous codewords.
///
/// Quartile error correction level.
public static readonly Ecc Quartile = new Ecc(2, 3);
///
/// High error correction level. The QR code can tolerate about 30% erroneous codewords.
///
/// High error correction level.
public static readonly Ecc High = new Ecc(3, 2);
internal static readonly Ecc[] AllValues = { Low, Medium, Quartile, High };
///
/// Ordinal number of error correction level (in the range 0 to 3).
///
///
/// Higher number represent a higher amount of error tolerance.
///
/// Ordinal number.
public int Ordinal { get; }
// In the range 0 to 3 (unsigned 2-bit integer).
internal uint FormatBits { get; }
// Constructor.
private Ecc(int ordinal, uint fb)
{
Ordinal = ordinal;
FormatBits = fb;
}
}
#endregion
}
}
================================================
FILE: QrCodeGenerator/QrCodeGenerator.csproj
================================================
netstandard2.0;net6.0trueNet.Codecrete.QrCodeGeneratorNet.Codecrete.QrCodeGenerator2.1.0Manuel Bleichenbacher, Project NayukiQR Code Generator for .NETQR Code Generator for .NET – simple, compact and with many examples.
Core features:
- Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
- Output formats: Raw modules/pixels of the QR symbol, SVG, XAML path, PNG and BMP files. For other raster bitmap formats, see project home page.
- Encodes numeric and special-alphanumeric text in less space than general text
- Open source code under the permissive MIT License
- Built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.).
- Example code for WinForms, WPF, ASP.NET, ImageSharp, SkiaSharp and many more
Manual parameters:
- You can specify the minimum and maximum version number allowed, and the library will automatically choose the smallest version in the range that fits the data.
- You can specify the mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one.
- You can specify an error correction level, or optionally allow the library to boost it if it doesn't increase the version number.
- You can create a list of data segments manually and add ECI segments.
Optional advanced features:
- Long text can be split into multiple linked QR codes (aka Structured Append)
- Encodes Japanese Unicode text in Kanji mode to save a lot of space compared to UTF-8 bytes
- Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general/kanji parts
Copyright (c) Manuel Bleichenbacher and Project Nayuki (MIT License)https://github.com/manuelbl/QrCodeGeneratorhttps://github.com/manuelbl/QrCodeGeneratorREADME.mdlogo.pngqr code, qrcode, kanji, qrcode generator, svgNew in releases 2.1.x:
- PNG support
- Structured append / Linked QR mode
CodecretetrueKey.snk1.6.0.02.0.1.0MITTruetrue2.1.02.0.0Truetruetrueembeddedtruetrue
================================================
FILE: QrCodeGenerator/QrSegment.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Represents a segment of character/binary/control data in a QR code symbol.
///
///
///
/// The easiest way to deal with QR code segments is to call
/// or , and not
/// to use instances of this class directly. The mid-level way is to take the payload
/// data and call a static factory function such as .
/// The low-level way is to custom-make the bit array and call the
/// constructor with appropriate values.
///
///
/// This segment class imposes no length restrictions, but QR codes have restrictions.
/// Even in the most favorable conditions, a QR code can only hold 7089 characters of data.
/// Any segment longer than this is meaningless for the purpose of generating QR codes.
///
///
/// This class can represent kanji mode segments, but provides no help in encoding them
/// - see for full kanji support.
///
///
/// Instances of this class are immutable.
///
///
public class QrSegment
{
#region Static factory functions (mid level)
///
/// Creates a segment representing the specified binary data
/// encoded in byte mode. All input byte arrays are acceptable.
///
/// Any text string can be converted to UTF-8 bytes (using Encoding.UTF8.GetBytes(str))
/// and encoded as a byte mode segment.
///
///
/// The binary data to encode.
/// The created segment containing the specified data.
/// data is null.
public static QrSegment MakeBytes(byte[] data)
{
Objects.RequireNonNull(data);
var ba = new BitArray(0);
foreach (var b in data)
{
ba.AppendBits(b, 8);
}
return new QrSegment(Mode.Byte, data.Length, ba);
}
///
/// Creates a segment representing the specified binary data
/// encoded in byte mode. All input byte arrays are acceptable.
///
/// Any text string can be converted to UTF-8 bytes (using Encoding.UTF8.GetBytes(str))
/// and encoded as a byte mode segment.
///
///
/// The binary data to encode.
/// The created segment containing the specified data.
/// data is null.
public static QrSegment MakeBytes(ArraySegment data)
{
Objects.RequireNonNull(data);
var ba = new BitArray(0);
foreach (var b in data)
{
ba.AppendBits(b, 8);
}
return new QrSegment(Mode.Byte, data.Count, ba);
}
///
/// Creates a segment representing the specified string of decimal digits.
/// The segment is encoded in numeric mode.
///
/// The text to encode, consisting of digits from 0 to 9 only.
/// The created segment containing the text.
/// digits is null.
/// digits contains non-digit characters
public static QrSegment MakeNumeric(string digits)
{
Objects.RequireNonNull(digits);
if (!IsNumeric(digits))
{
throw new ArgumentOutOfRangeException(nameof(digits), "String contains non-numeric characters");
}
var ba = new BitArray(0);
for (var i = 0; i < digits.Length;)
{
// Consume up to 3 digits per iteration
var n = Math.Min(digits.Length - i, 3);
ba.AppendBits(uint.Parse(digits.Substring(i, n)), n * 3 + 1);
i += n;
}
return new QrSegment(Mode.Numeric, digits.Length, ba);
}
///
/// Creates a segment representing the specified text string.
/// The segment is encoded in alphanumeric mode.
///
/// Allowed characters are: 0 to 9, A to Z (uppercase only), space,
/// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
///
///
/// The text to encode, consisting of allowed characters only.
/// The created segment containing the text.
/// text is null.
/// text contains non-encodable characters.
public static QrSegment MakeAlphanumeric(string text)
{
Objects.RequireNonNull(text);
if (!IsAlphanumeric(text))
{
throw new ArgumentOutOfRangeException(nameof(text), "String contains unencodable characters in alphanumeric mode");
}
var ba = new BitArray(0);
int i;
for (i = 0; i <= text.Length - 2; i += 2)
{
// Process groups of 2
var temp = (uint)AlphanumericCharset.IndexOf(text[i]) * 45;
temp += (uint)AlphanumericCharset.IndexOf(text[i + 1]);
ba.AppendBits(temp, 11);
}
if (i < text.Length) // 1 character remaining
{
ba.AppendBits((uint)AlphanumericCharset.IndexOf(text[i]), 6);
}
return new QrSegment(Mode.Alphanumeric, text.Length, ba);
}
///
/// Creates a segment for the structured append header.
///
/// The parity value.
/// The position of the code within the sequence of codes (1 based).
/// The total number of codes in the sequence of codes.
/// The created segment containing the specified header.
/// data is null.
internal static QrSegment MakeStructuredAppend(byte parity, int position, int total)
{
var bitArray = new BitArray(0);
bitArray.AppendBits((uint)position - 1, 4);
bitArray.AppendBits((uint)total - 1, 4);
bitArray.AppendBits(parity, 8);
return new QrSegment(Mode.StructuredAppend, 0, bitArray);
}
///
/// Creates a list of zero or more segments representing the specified text string.
///
/// The text may contain the full range of Unicode characters.
///
///
/// The result may consist of multiple segments with various encoding modes in order to minimize the length of the bit stream.
///
///
/// The text to be encoded.
/// The created mutable list of segments representing the specified text.
/// text is null.
///
/// The current implementation does not create multiple segments.
///
public static List MakeSegments(string text)
{
Objects.RequireNonNull(text);
// Select the most efficient segment encoding automatically
var result = new List();
if (text == "")
{
// Leave result empty
}
else if (IsNumeric(text))
{
result.Add(MakeNumeric(text));
}
else if (IsAlphanumeric(text))
{
result.Add(MakeAlphanumeric(text));
}
else
{
result.Add(MakeBytes(Encoding.UTF8.GetBytes(text)));
}
return result;
}
///
/// Creates a segment representing an Extended Channel Interpretation
/// (ECI) designator with the specified assignment value.
///
/// The ECI assignment number (see the AIM ECI specification).
/// The created segment containing the data.
/// assignValis outside the range [0, 106).
public static QrSegment MakeEci(int assignVal)
{
var ba = new BitArray(0);
if (assignVal < 0)
{
throw new ArgumentOutOfRangeException(nameof(assignVal), "ECI assignment value out of range");
}
if (assignVal < 1 << 7)
{
ba.AppendBits((uint)assignVal, 8);
}
else if (assignVal < 1 << 14)
{
ba.AppendBits(2, 2);
ba.AppendBits((uint)assignVal, 14);
}
else if (assignVal < 1_000_000)
{
ba.AppendBits(6, 3);
ba.AppendBits((uint)assignVal, 21);
}
else
{
throw new ArgumentOutOfRangeException(nameof(assignVal), "ECI assignment value out of range");
}
return new QrSegment(Mode.Eci, 0, ba);
}
///
/// Tests whether the specified string can be encoded as a segment in numeric mode.
///
/// A string is encodable iff each character is in the range "0" to "9".
///
///
/// the string to test for encodability (not null)
/// true iff each character is in the range "0" to "9".
/// if the string is null
///
public static bool IsNumeric(string text)
{
return NumericRegex.IsMatch(text);
}
///
/// Tests whether the specified string can be encoded as a segment in alphanumeric mode.
///
/// A string is encodable iff each character is in the range "0" to "9", "A" to "Z" (uppercase only),
/// space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
///
///
/// the string to test for encodability (not null)
/// true iff each character is in the alphanumeric mode character set.
/// if the string is null
///
public static bool IsAlphanumeric(string text)
{
return AlphanumericRegex.IsMatch(text);
}
#endregion
#region Instance fields
/// The encoding mode of this segment.
/// Encoding mode.
public Mode EncodingMode { get; }
///
/// The length of this segment's unencoded data.
///
/// Measured in characters for numeric/alphanumeric/kanji mode,
/// bytes for byte mode, and 0 for ECI mode.
///
///
/// Different from the data's bit length.
///
///
/// Length of the segment's unencoded data.
public int NumChars { get; }
// The data bits of this segment. Not null. Accessed through GetData().
private readonly BitArray _data;
#endregion
#region Constructor (low level)
///
/// Initializes a QR code segment with the specified attributes and data.
///
/// The character count must agree with the mode and the bit array length,
/// but the constraint isn't checked. The specified bit array is cloned.
///
///
/// The segment mode used to encode this segment.
/// The data length in characters or bytes (depending on the segment mode).
/// The data bits.
/// or is null.
/// is negative.
public QrSegment(Mode mode, int numChars, BitArray data)
{
EncodingMode = Objects.RequireNonNull(mode);
Objects.RequireNonNull(data);
if (numChars < 0)
{
throw new ArgumentOutOfRangeException(nameof(numChars), "Invalid value");
}
NumChars = numChars;
_data = (BitArray)data.Clone(); // Make defensive copy
}
#endregion
#region Methods
///
/// Returns a copy of this segment's data bits.
///
/// A copy of the data bits.
public BitArray GetData()
{
return (BitArray)_data.Clone(); // Make defensive copy
}
///
/// Returns the text represented by this segment.
///
/// This method will fail if the segment contains binary data that
/// cannot be converted to text.
///
///
/// The text.
public string GetText()
{
var result = new StringBuilder();
AppendText(result);
return result.ToString();
}
///
/// Returns the joined text represented by the provided segments.
///
/// List of segments
///
public static string GetJoinedText(List segments)
{
var result = new StringBuilder();
foreach (var segment in segments)
{
segment.AppendText(result);
}
return result.ToString();
}
///
/// Returns the joined text represented by the provided segments.
///
/// List of list of segments
///
public static string GetJoinedText(List> segments)
{
var result = new StringBuilder();
foreach (var segmentList in segments)
{
foreach (var segment in segmentList)
{
segment.AppendText(result);
}
}
return result.ToString();
}
private void AppendText(StringBuilder builder)
{
if (EncodingMode == Mode.Numeric)
{
for (int offset = 0; offset < NumChars; offset += 3)
{
var n = Math.Min(NumChars - offset, 3);
var bitIndex = offset / 3 * 10;
if (n == 3)
{
var value = _data.ExtractBits(bitIndex, 10);
builder.Append((char)('0' + value / 100));
builder.Append((char)('0' + value / 10 % 10));
builder.Append((char)('0' + value % 10));
}
else if (n == 2)
{
var value = _data.ExtractBits(bitIndex, 7);
builder.Append((char)('0' + value / 10));
builder.Append((char)('0' + value % 10));
}
else if (n == 1)
{
var value = _data.ExtractBits(bitIndex, 4);
builder.Append((char)('0' + value));
}
}
}
else if (EncodingMode == Mode.Alphanumeric)
{
for (int offset = 0; offset < NumChars; offset += 2)
{
var n = Math.Min(NumChars - offset, 2);
var bitIndex = offset / 2 * 11;
if (n == 2)
{
var value = (int)_data.ExtractBits(bitIndex, 11);
builder.Append(AlphanumericCharset[value / 45]);
builder.Append(AlphanumericCharset[value % 45]);
}
else
{
var value = (int)_data.ExtractBits(bitIndex, 6);
builder.Append(AlphanumericCharset[value]);
}
}
}
else if (EncodingMode == Mode.Byte)
{
var bytes = new byte[NumChars];
for (int i = 0; i < NumChars; i++)
{
bytes[i] = (byte)_data.ExtractBits(i * 8, 8);
}
builder.Append(Encoding.UTF8.GetString(bytes));
}
}
///
/// Calculates the number of bits needed to encode the given segments.
///
/// Returns a non-negative number if successful. Otherwise returns -1 if a segment has too
/// many characters to fit its length field, or the total bits exceeds int.MaxValue.
///
///
/// The segements.
/// The version number.
/// The number of bits, or -1.
internal static int GetTotalBits(List segments, int version)
{
Objects.RequireNonNull(segments);
long result = 0;
foreach (var seg in segments)
{
Objects.RequireNonNull(seg);
var ccBits = seg.EncodingMode.NumCharCountBits(version);
if (seg.NumChars >= 1 << ccBits)
{
return -1; // The segment's length doesn't fit the field's bit width
}
result += 4L + ccBits + seg._data.Length;
if (result > int.MaxValue)
{
return -1; // The sum will overflow an int type
}
}
return (int)result;
}
///
/// Calculates the total number of bits required to encode a data segment in a QR code.
///
/// The number of characters in the data segment to be encoded. For byte mode, it is the number of bytes.
/// The encoding mode used for the data segment.
/// The QR code version.
/// The total number of bits required to encode the segment, including the mode indicator, character count
/// indicator, and data bits. Returns -1 if the number of characters exceeds the maximum allowed for the
/// specified mode and version.
/// Thrown if the specified mode is not supported for this calculation.
internal static int GetTotalBits(int numChars, Mode mode, int version)
{
var ccBits = mode.NumCharCountBits(version);
if (numChars >= 1 << ccBits)
{
return -1; // The segment's length doesn't fit the field's bit width
}
int dataBits = 0;
if (mode == Mode.Numeric)
{
dataBits = numChars / 3 * 10 + (numChars % 3 == 0 ? 0 : (numChars % 3 * 3 + 1));
}
else if (mode == Mode.Alphanumeric)
{
dataBits = numChars / 2 * 11 + (numChars % 2 == 0 ? 0 : 6);
}
else if (mode == Mode.Byte)
{
dataBits = numChars * 8;
}
else if (mode == Mode.Kanji)
{
dataBits = numChars * 13;
}
else
{
throw new ArgumentOutOfRangeException(nameof(mode), "Unsupported mode for this calculation");
}
return 4 + ccBits + dataBits;
}
#endregion
#region Constants
// Describes precisely all strings that are encodable in numeric mode.
private static readonly Regex NumericRegex = new Regex("^[0-9]*$", RegexOptions.Compiled);
// Describes precisely all strings that are encodable in alphanumeric mode.
private static readonly Regex AlphanumericRegex = new Regex("^[A-Z0-9 $%*+./:-]*$", RegexOptions.Compiled);
// The set of all legal characters in alphanumeric mode, where
// each character value maps to the index in the string.
internal const string AlphanumericCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
#endregion
#region Public helper enumeration
///
/// Segment encoding mode.
///
/// Describes how text or binary data is encoded into bits.
///
///
public sealed class Mode
{
///
/// Numeric encoding mode.
///
/// Numeric encoding mode.
public static readonly Mode Numeric = new Mode(0x1, 10, 12, 14);
///
/// Alphanumeric encoding mode.
///
/// Alphanumeric encoding mode.
public static readonly Mode Alphanumeric = new Mode(0x2, 9, 11, 13);
///
/// Byte encoding mode.
///
/// Byte encoding mode.
public static readonly Mode Byte = new Mode(0x4, 8, 16, 16);
///
/// Kanji encoding mode.
///
/// Kanji encoding mode.
public static readonly Mode Kanji = new Mode(0x8, 8, 10, 12);
///
/// ECI encoding mode.
///
/// ECI encoding mode.
public static readonly Mode Eci = new Mode(0x7, 0, 0, 0);
///
/// Structured append encoding mode.
///
/// Structured append encoding mode.
public static readonly Mode StructuredAppend = new Mode(0x3, 0, 0, 0);
///
/// Mode indicator value.
///
/// 4 bit value in the QR segment header indicating the encoding mode.
///
///
/// Mode indicator value
internal uint ModeBits { get; }
///
/// Array of character count bit length.
///
/// Number of bits for character count in QR segment header.
/// The three array values apply to versions 0 to 9, 10 to 26 and 27 to 40
/// respectively. All array values are in the range [0, 16].
///
///
/// Array of character count bit length
private int[] NumBitsCharCount { get; }
///
/// Returns the bit length of the character count in the QR segment header
/// for the specified QR code version. The result is in the range [0, 16].
///
/// the QR code version (between 1 and 40)
///
internal int NumCharCountBits(int ver)
{
Debug.Assert(QrCode.MinVersion <= ver && ver <= QrCode.MaxVersion);
return NumBitsCharCount[(ver + 7) / 17];
}
// private constructor to initializes the constants
private Mode(uint modeBits, params int[] numBitsCharCount)
{
ModeBits = modeBits;
NumBitsCharCount = numBitsCharCount;
}
}
#endregion
}
}
================================================
FILE: QrCodeGenerator/QrSegmentAdvanced.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using static Net.Codecrete.QrCodeGenerator.QrSegment;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Advanced methods for encoding QR codes using Kanji mode or using multiple segments with different encodings.
///
///
///
public static class QrSegmentAdvanced
{
#region Optimal list of segments encoder
///
/// Creates a list of zero or more segments to represent the specified text string.
/// The resulting list optimally minimizes the total encoded bit length, subjected to the constraints
/// of the specified error correction level, minimum and maximum version number.
///
/// This function potentially uses all four text encoding modes: numeric, alphanumeric, byte (UTF-8),
/// and Kanji. It is a more sophisticated but slower replacement for .
///
///
/// The text to be encoded can contain the full set of Unicode characters (code points).
///
///
/// The text to be encoded.
/// The error correction level to use.
/// The minimum version (size) of the QR code (between 1 and 40).
/// The maximum version (size) of the QR code (between 1 and 40).
/// The created mutable list of segments encoding the specified text with a minimal bit length.
/// or is null.
/// 1 ≤ minVersion ≤ maxVersion ≤ 40 is violated.
/// The text is too long to fit into the QR code with the given encoding parameters.
public static List MakeSegmentsOptimally(string text, QrCode.Ecc ecl, int minVersion = QrCode.MinVersion, int maxVersion = QrCode.MaxVersion)
{
// Check arguments
Objects.RequireNonNull(text);
Objects.RequireNonNull(ecl);
if (minVersion < QrCode.MinVersion || minVersion > maxVersion)
{
throw new ArgumentOutOfRangeException(nameof(minVersion), "Invalid value");
}
if (maxVersion > QrCode.MaxVersion)
{
throw new ArgumentOutOfRangeException(nameof(maxVersion), "Invalid value");
}
List segments = null;
var codePoints = ToCodePoints(text);
int dataCapacityBits = 0;
int dataUsedBits = 0;
// Iterate through version numbers, and make tentative segments
for (var version = minVersion; version <= maxVersion; version += 1)
{
if (version == minVersion || version == 10 || version == 27)
segments = MakeSegmentsOptimally(codePoints, version);
Debug.Assert(segments != null);
// Check if the segments fit
dataCapacityBits = QrCode.GetNumDataCodewords(version, ecl) * 8;
dataUsedBits = GetTotalBits(segments, version);
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
return segments; // This version number is found to be suitable
}
// All versions in the range could not fit the given text
var msg = "Segment too long";
if (dataUsedBits != -1)
msg = $"Data length = {dataUsedBits} bits, Max capacity = {dataCapacityBits} bits";
throw new DataTooLongException(msg);
}
// Returns a new list of segments that is optimal for the given text at the given version number.
private static List MakeSegmentsOptimally(IReadOnlyList codePoints, int version)
{
if (codePoints.Count == 0)
return new List();
var charModes = ComputeCharacterModes(codePoints, version);
return SplitIntoSegments(codePoints, charModes);
}
///
/// Measures the length of the segments optimal for the given version number.
///
/// The text, as an array of codepoints.
/// The version.
/// The length, in bits.
private static int MeasureSegmentsOptimally(IReadOnlyList codePoints, int version)
{
if (codePoints.Count == 0)
return 0;
var charModes = ComputeCharacterModes(codePoints, version);
return MeasureSegments(codePoints, charModes, version);
}
// Returns a new array representing the optimal mode per code point based on the given text and version.
private static Mode[] ComputeCharacterModes(IReadOnlyList codePoints, int version)
{
if (codePoints.Count == 0)
{
throw new ArgumentOutOfRangeException(nameof(codePoints));
}
Mode[] modeTypes = { Mode.Byte, Mode.Alphanumeric, Mode.Numeric, Mode.Kanji }; // Do not modify
var numModes = modeTypes.Length;
// Segment header sizes, measured in 1/6 bits
var headCosts = new int[numModes];
for (var i = 0; i < numModes; i++)
{
headCosts[i] = (4 + modeTypes[i].NumCharCountBits(version)) * 6;
}
// charModes[i][j] represents the mode to encode the code point at
// index i such that the final segment ends in modeTypes[j] and the
// total number of bits is minimized over all possible choices
var charModes = new Mode[codePoints.Count, numModes];
// At the beginning of each iteration of the loop below,
// prevCosts[j] is the exact minimum number of 1/6 bits needed to
// encode the entire string prefix of length i, and end in modeTypes[j]
var prevCosts = (int[])headCosts.Clone();
// Calculate costs using dynamic programming
for (var i = 0; i < codePoints.Count; i++)
{
var c = codePoints[i];
var curCosts = new int[numModes];
{
// Always extend a byte mode segment
curCosts[0] = prevCosts[0] + CountUtf8Bytes(c) * 8 * 6;
charModes[i, 0] = modeTypes[0];
}
// Extend a segment if possible
if (AlphanumericCharset.Contains((char)c))
{
// Is alphanumeric
curCosts[1] = prevCosts[1] + 33; // 5.5 bits per alphanumeric char
charModes[i, 1] = modeTypes[1];
}
if ('0' <= c && c <= '9')
{
// Is numeric
curCosts[2] = prevCosts[2] + 20; // 3.33 bits per digit
charModes[i, 2] = modeTypes[2];
}
if (IsKanji(c))
{
curCosts[3] = prevCosts[3] + 78; // 13 bits per Shift JIS char
charModes[i, 3] = modeTypes[3];
}
// Start new segment at the end to switch modes
for (var j = 0; j < numModes; j++)
{
// To mode
for (var k = 0; k < numModes; k++)
{
// From mode
var newCost = (curCosts[k] + 5) / 6 * 6 + headCosts[j];
if (charModes[i, k] == null || charModes[i, j] != null && newCost >= curCosts[j])
continue;
curCosts[j] = newCost;
charModes[i, j] = modeTypes[k];
}
}
prevCosts = curCosts;
}
// Find optimal ending mode
Mode curMode = null;
for (int i = 0, minCost = 0; i < numModes; i++)
{
if (curMode != null && prevCosts[i] >= minCost) continue;
minCost = prevCosts[i];
curMode = modeTypes[i];
}
// Get optimal mode for each code point by tracing backwards
var result = new Mode[codePoints.Count];
for (var i = result.Length - 1; i >= 0; i--)
{
for (var j = 0; j < numModes; j++)
{
if (modeTypes[j] != curMode) continue;
curMode = charModes[i, j];
result[i] = curMode;
break;
}
}
return result;
}
// Returns a new list of segments based on the given text and modes, such that
// consecutive code points in the same mode are put into the same segment.
private static List SplitIntoSegments(IReadOnlyList codePoints, IReadOnlyList charModes)
{
if (codePoints.Count == 0)
throw new ArgumentOutOfRangeException(nameof(codePoints));
var result = new List();
GroupConsecutiveModes(charModes, (startIndex, endIndex, mode) =>
{
var s = FromCodePoints(codePoints, startIndex, endIndex - startIndex);
if (mode == Mode.Byte)
{
result.Add(MakeBytes(Encoding.UTF8.GetBytes(s)));
}
else if (mode == Mode.Numeric)
{
result.Add(MakeNumeric(s));
}
else if (mode == Mode.Alphanumeric)
{
result.Add(MakeAlphanumeric(s));
}
else if (mode == Mode.Kanji)
{
result.Add(MakeKanji(s));
}
else
{
Debug.Assert(false);
}
});
return result;
}
// Measures the length of segments based on the given text and modes, such that
// consecutive code points in the same mode are put into the same segment.
private static int MeasureSegments(IReadOnlyList codePoints, IReadOnlyList charModes, int version)
{
if (codePoints.Count == 0)
throw new ArgumentOutOfRangeException(nameof(codePoints));
var result = 0;
GroupConsecutiveModes(charModes, (startIndex, endIndex, mode) =>
{
int numChars;
if (mode == Mode.Byte)
{
numChars = 0;
for (int i = startIndex; i < endIndex; i += 1)
{
numChars += CountUtf8Bytes(codePoints[i]);
}
}
else
{
numChars = endIndex - startIndex;
}
result += GetTotalBits(numChars, mode, version);
});
return result;
}
private static string FromCodePoints(IReadOnlyList codepoints, int startIndex, int count)
{
var useBigEndian = !BitConverter.IsLittleEndian;
Encoding utf32 = new UTF32Encoding(useBigEndian, false, true);
var octets = new byte[count * 4];
for (int i = startIndex, j = 0; i < startIndex + count; i++, j += 4)
{
var bytes = BitConverter.GetBytes(codepoints[i]);
octets[j] = bytes[0];
octets[j + 1] = bytes[1];
octets[j + 2] = bytes[2];
octets[j + 3] = bytes[3];
}
return utf32.GetString(octets);
}
// Returns a new array of Unicode code points (effectively
// UTF-32 / UCS-4) representing the given UTF-16 string.
private static int[] ToCodePoints(string s)
{
var useBigEndian = !BitConverter.IsLittleEndian;
Encoding utf32 = new UTF32Encoding(useBigEndian, false, true);
var octets = utf32.GetBytes(s);
var result = new int[octets.Length / 4];
for (int i = 0, j = 0; i < octets.Length; i += 4, j++)
{
result[j] = BitConverter.ToInt32(octets, i);
}
return result;
}
// Returns the number of UTF-8 bytes needed to encode the given Unicode code point.
private static int CountUtf8Bytes(int cp)
{
if (cp < 0) throw new ArgumentOutOfRangeException(nameof(cp), "Invalid code point");
if (cp < 0x80) return 1;
if (cp < 0x800) return 2;
if (cp < 0x10000) return 3;
if (cp < 0x110000) return 4;
throw new ArgumentOutOfRangeException(nameof(cp), "Invalid code point");
}
#endregion
#region Kanji mode segment encoder
///
/// Creates a segment encoding the specified text in Kanji mode.
///
/// Broadly speaking, the set of encodable characters are Kanji used in Japan,
/// Hiragana, Katakana, East Asian punctuation, full-width ASCII, Greek, and Cyrillic.
/// Examples of non-encodable characters include ordinary ASCII, half-width Katakana,
/// more extensive Chinese Hanzi.
///
///
/// The text to encoding, containing only characters allowed by the Kanji encoding.
/// The created segment representing the specified text.
/// is null.
/// contains non-encodable characters.
///
public static QrSegment MakeKanji(string text)
{
Objects.RequireNonNull(text);
var ba = new BitArray(0);
foreach (var val in text.Select(t => UnicodeToQrKanji[t]))
{
if (val == 0xffff)
{
throw new ArgumentOutOfRangeException(nameof(text), "String contains non-kanji-mode characters");
}
ba.AppendBits(val, 13);
}
return new QrSegment(Mode.Kanji, text.Length, ba);
}
///
/// Tests whether the specified string can be encoded as a segment in Kanji mode.
///
/// Broadly speaking, the set of encodable characters are Kanji used in Japan,
/// Hiragana, Katakana, East Asian punctuation, full-width ASCII, Greek, and Cyrillic.
/// Examples of non-encodable characters include ordinary ASCII, half-width Katakana,
/// more extensive Chinese Hanzi.
///
///
/// The text to test for encodability.
/// true iff each character is in the Kanji mode character set.
/// is null.
public static bool IsEncodableAsKanji(string text)
{
Objects.RequireNonNull(text);
return text.All(t => IsKanji(t));
}
private static bool IsKanji(int c)
{
return c < UnicodeToQrKanji.Length && UnicodeToQrKanji[c] != 0xffff;
}
// Data derived from ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/SHIFTJIS.TXT
private const string PackedQrKanjiToUnicode =
"MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZA" +
"ALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA///////////////////" +
"//////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h" +
"/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBN" +
"ME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////" +
"////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDh" +
"MOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+" +
"A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQm" +
"BCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQ" +
"JRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"/////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32t" +
"fe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYg" +
"ZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2" +
"cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5" +
"////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLs" +
"bTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CE" +
"lFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKg" +
"dZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/" +
"U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6" +
"UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo" +
"//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6r" +
"XydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOn" +
"ZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtk" +
"mANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiV" +
"nfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/X" +
"YB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6luf" +
"hQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/S" +
"ge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZ" +
"WXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJac" +
"l5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066" +
"TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bb" +
"fL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6" +
"ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333P" +
"fZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7e" +
"gM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bj" +
"WMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0" +
"gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oC" +
"iuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhY" +
"WVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLr" +
"W8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/D" +
"fQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGro" +
"XmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/" +
"l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16c" +
"YBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7" +
"WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851s" +
"Tk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04H" +
"YWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5f" +
"UbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+K" +
"gACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHM" +
"W+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3v" +
"lzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV////////////////////////////////////////////////////////////////////////////////////////" +
"/////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/l" +
"UBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGT" +
"UZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQ" +
"Uw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////" +
"VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaP" +
"VqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4" +
"WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrj" +
"Wtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yr" +
"XLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/" +
"XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQ" +
"YClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FY" +
"YVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KU" +
"Ytdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTH" +
"ZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2Zo" +
"Zl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGge" +
"aEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammy" +
"aa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7" +
"awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzX" +
"bMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7J" +
"brdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3Aw" +
"cD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKy" +
"csNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTy" +
"dPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYw" +
"djt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7" +
"d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXog" +
"eh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuc" +
"e5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G" +
"////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5a" +
"fnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAh" +
"gCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHC" +
"gbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMv" +
"gyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UY" +
"hSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs" +
"//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZ" +
"iF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9" +
"ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tf" +
"i2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3b" +
"jcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485" +
"j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEy" +
"kTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNW" +
"k7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYu" +
"li+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJem" +
"l6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnY" +
"mdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uD" +
"m5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1k" +
"nVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+" +
"n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////" +
"/////////////////////////////////////////////w==";
private static readonly ushort[] UnicodeToQrKanji = new ushort[1 << 16];
static QrSegmentAdvanced()
{
// Unpack the Shift JIS table into a more computation-friendly form
for (var i = 0; i < UnicodeToQrKanji.Length; i++)
UnicodeToQrKanji[i] = 0xffff;
var bytes = Convert.FromBase64String(PackedQrKanjiToUnicode);
for (var i = 0; i < bytes.Length; i += 2)
{
var c = (bytes[i] << 8) | bytes[i + 1];
if (c == 0xFFFF)
continue;
Debug.Assert(UnicodeToQrKanji[c] == 0xffff);
UnicodeToQrKanji[c] = (ushort)(i / 2);
}
}
#endregion
#region Structured Append
///
/// Creates the segments for multiple QR codes for the specified text.
///
/// The result will consist of the minimal number of QR codes needed
/// to encode the text with the given error correction level and version (size of QR code).
/// If multiple QR codes are required, Structured Append data is included to link the QR codes.
///
///
/// Each QR code might use multiple segments with different encoding modes
/// to maximize the amount of text that can be stored in each QR code.
///
///
/// The outer list represents the series of QR codes to be created.
/// The inner lists contains the QR segments for each QR code.
///
///
/// Each QR code will contain a valid string as it is ensured that splitting only occurs
/// at character boundaries and not in the middle of a multi-byte encoding of a character.
/// This increases compatibility with QR code scanners that incorrectly assume that each
/// individual QR code in the series contains a valid UTF-8 string.
///
///
/// The text to be encoded. The full range of Unicode characters may be used.
/// The minimum error correction level to use.
/// The version (size of QR code) to use. Default is 29.
/// A list of list of QR segments representing the specified text.
public static List> MakeSegmentsForMultipleCodes(string text, QrCode.Ecc ecl, int version = 29)
{
// Check arguments
Objects.RequireNonNull(text);
Objects.RequireNonNull(ecl);
if (version < QrCode.MinVersion || version > QrCode.MaxVersion)
{
throw new ArgumentOutOfRangeException(nameof(version), "Invalid value");
}
var qrCodesSegments = SplitTextIntoMultipleCodes(text, ecl, version);
var parity = CalculateParity(text);
// add structured append segment
for (int i = 0; i < qrCodesSegments.Count; i += 1)
{
qrCodesSegments[i].Insert(0, MakeStructuredAppend(parity, i + 1, qrCodesSegments.Count));
}
return qrCodesSegments;
}
private static List> SplitTextIntoMultipleCodes(string text, QrCode.Ecc ecl, int version)
{
var codePoints = ToCodePoints(text);
var dataCapacityBits = QrCode.GetNumDataCodewords(version, ecl) * 8 - 20; // 20 bits for the structured append
var result = new List>();
// repeatedly find the longest text that fits into a QR code of the given version and ecl
int startIndex = 0;
while (startIndex < codePoints.Length)
{
if (result.Count >= 16)
{
throw new DataTooLongException("The text is too long to fit into 16 QR codes");
}
// binary search for longest text
var low = startIndex;
var high = codePoints.Length;
while (low < high)
{
var mid = (low + high + 1) / 2;
var requiredBits = MeasureSegmentsOptimally(new ArraySegment(codePoints, startIndex, mid - startIndex), version);
if (requiredBits <= dataCapacityBits)
{
low = mid;
}
else
{
high = mid - 1;
}
}
if (high == startIndex)
{
// even a version 1 QR code should be sufficient to fit the structured append header plus one character
throw new InvalidOperationException("QR code splitting: should not reach");
}
Debug.Assert(high == codePoints.Length
|| MeasureSegmentsOptimally(new ArraySegment(codePoints, startIndex, high - startIndex + 1), version) > dataCapacityBits);
result.Add(MakeSegmentsOptimally(new ArraySegment(codePoints, startIndex, high - startIndex), version));
startIndex = high;
}
return result;
}
private static byte CalculateParity(string text)
{
var data = Encoding.UTF8.GetBytes(text);
byte parity = 0;
foreach (var value in data)
{
parity ^= (byte)(value >> 8);
}
return parity;
}
#endregion
#region Helpers
///
/// Groups consecutive segment modes with the same value and calls the action.
///
/// List of segement modes
/// Action to call for each group
private static void GroupConsecutiveModes(IReadOnlyList elements, Action action)
{
var startIndex = 0;
var lastValue = elements[0];
var index = 0;
while (true)
{
if (index == elements.Count || elements[index] != lastValue)
{
action(startIndex, index, lastValue);
if (index == elements.Count)
break;
startIndex = index;
lastValue = elements[index];
}
index += 1;
}
}
#endregion
}
}
================================================
FILE: QrCodeGenerator/ReedSolomonGenerator.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Diagnostics;
namespace Net.Codecrete.QrCodeGenerator
{
///
/// Computes the Reed-Solomon error correction codewords for a sequence of data codewords at a given degree.
///
/// Instances are immutable, and the state only depends on the degree.
/// This class is useful because all data blocks in a QR code share the same the divisor polynomial.
///
///
internal class ReedSolomonGenerator
{
#region Fields
// Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
// is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
private readonly byte[] _coefficients;
#endregion
#region Constructors
///
/// Initializes a new Reed-Solomon ECC generator for the specified degree.
///
///
/// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm.
///
/// The divisor polynomial degree (between 1 and 255).
/// degree < 1 or degree > 255
internal ReedSolomonGenerator(int degree)
{
if (degree < 1 || degree > 255)
{
throw new ArgumentOutOfRangeException(nameof(degree), "Degree out of range");
}
// Start with the monomial x^0
_coefficients = new byte[degree];
_coefficients[degree - 1] = 1;
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// drop the highest term, and store the rest of the coefficients in order of descending powers.
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
uint root = 1;
for (var i = 0; i < degree; i++)
{
// Multiply the current product by (x - r^i)
for (var j = 0; j < _coefficients.Length; j++)
{
_coefficients[j] = Multiply(_coefficients[j], root);
if (j + 1 < _coefficients.Length)
{
_coefficients[j] ^= _coefficients[j + 1];
}
}
root = Multiply(root, 0x02);
}
}
#endregion
#region Methods
///
/// Computes the Reed-Solomon error correction codewords for the specified
/// sequence of data codewords.
///
/// This method does not alter this object's state (as it is immutable).
///
///
/// The sequence of data codewords.
/// The Reed-Solomon error correction codewords, as a byte array.
/// If data is null.
internal byte[] GetRemainder(byte[] data)
{
Objects.RequireNonNull(data);
// Compute the remainder by performing polynomial division
var result = new byte[_coefficients.Length];
foreach (var b in data)
{
var factor = (uint)(b ^ result[0]);
Array.Copy(result, 1, result, 0, result.Length - 1);
result[result.Length - 1] = 0;
for (var i = 0; i < result.Length; i++)
{
result[i] ^= Multiply(_coefficients[i], factor);
}
}
return result;
}
#endregion
#region Static functions
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
private static byte Multiply(uint x, uint y)
{
Debug.Assert(x >> 8 == 0 && y >> 8 == 0);
// Russian peasant multiplication
uint z = 0;
for (var i = 7; i >= 0; i--)
{
z = (z << 1) ^ ((z >> 7) * 0x11D);
z ^= ((y >> i) & 1) * x;
}
Debug.Assert(z >> 8 == 0);
return (byte)z;
}
#endregion
}
}
================================================
FILE: QrCodeGenerator/docfx/api/index.md
================================================
# QR Code Generator for .NET
Open-source library for generating QR codes from text strings and byte arrays.
## .NET API Documention
* [QrCode](xref:Net.Codecrete.QrCodeGenerator.QrCode): Creates and represents QR codes
* [QrSegment](xref:Net.Codecrete.QrCodeGenerator.QrSegment): Represents a segment of character/binary/control data in a QR code symbol
* [QrSegmentAdvanced](xref:Net.Codecrete.QrCodeGenerator.QrSegmentAdvanced): Advanced methods for encoding QR codes using Kanji mode or using multiple segments with different encodings.
* [All types and classes](xref:Net.Codecrete.QrCodeGenerator)
Additional information on [GitHub project page](https://github.com/manuelbl/QrCodeGenerator)
## Features
Core features:
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output formats: Raw modules/pixels of the QR symbol, SVG, XAML path, PNG and BMP files. For other raster bitmap formats, see project home page.
* Encodes numeric and special alphanumeric text in less space than general text
* Open source code under the permissive *MIT License*
* Built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.).
* Available as a [NuGet package](https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/) (named *Net.Codecrete.QrCodeGenerator*)
* Example code for WinForms, WPF, ASP.NET, ImageSharp, SkiaSharp and many more
Manual parameters:
* You can specify the minimum and maximum *version number* allowed, and the library will automatically choose the smallest version in the range that fits the data.
* You can specify the *mask pattern* manually, otherwise library will automatically evaluate all 8 masks and select the optimal one.
* You can specify an *error correction level*, or optionally allow the library to boost it if it doesn't increase the version number.
* You can create a list of *data segments* manually and add *ECI segments*.
Optional advanced features:
* Long text can be split into multiple linked QR codes (aka Structured Append)
* Encodes Japanese Unicode text in *Kanji mode* to save a lot of space compared to UTF-8 bytes
* Computes *optimal segment mode* switching for text with mixed numeric/alphanumeric/general/kanji parts
## Examples
Simple operation:
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class SimpleOperation
{
static void Main()
{
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.Medium);
string svg = qr.ToSvgString(4);
File.WriteAllText("hello-world-qr.svg", svg, Encoding.UTF8);
}
}
}
Manual operation:
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class ManualOperation
{
static void Main()
{
var segments = QrCode.MakeSegments("3141592653589793238462643383");
var qr = QrCode.EncodeSegments(segments, QrCode.Ecc.High, 5, 5, 2, false);
for (int y = 0; y < qr.Size; y++)
{
for (int x = 0; x < qr.Size; x++)
{
... paint qr.GetModule(x,y) ...
}
}
}
}
}
## Requirements
QR Code Generator for .NET requires a .NET implementation compatible with .NET Standard 2.0 or higher, i.e. any of:
- .NET Core 2.0 or higher
- .NET Framework 4.6.1 or higher
- Mono 5.4 or higher
- Universal Windows Platform 10.0.16299 or higher
- Xamarin
### Raster Images / Bitmaps
Starting with .NET 6, *System.Drawing* is only supported on Windows operating system and thus cannot be used for multi-platform libraries like this one. Therefore, `ToBitmap()` has been removed.
Two raster bitmap formats are supported with the need for additional libraries:
- *PNG*: See [`QrCode.ToPngBitmap()`](xref:Net.Codecrete.QrCodeGenerator.QrCode.ToPngBitmap(System.Int32,System.Int32))
- *BMP*: See [`QrCode.ToBmpBitmap()`](xref:Net.Codecrete.QrCodeGenerator.QrCode.ToBmpBitmap(System.Int32,System.Int32))
These methods are limited, e.g. with regards to the size of the generated image.
For more advanced and more efficient ways to generate different raster image formats:
- Select one of the imaging libraries below
- Add the NuGet dependencies to your project
- Copy the appropriate `QrCodeBitmapExtensions.cs` file to your project
| Library | Recommendation | NuGet dependencies | Extension file |
| ------- | -------------- | ------------------ | -------------- |
| **System.Drawing** | For Windows only projects | `System.Drawing.Common` | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-SkiaSharp/QrCodeBitmapExtensions.cs) |
| **SkiaSharp** | For macOS, Linux, iOS, Android and multi-platform projects | `SkiaSharp` and `SkiaSharp.NativeAssets.Linux` (for Linux only) | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-SkiaSharp/QrCodeBitmapExtensions.cs) |
| **ImageSharp** | Alternative for multi-platform projects. Might require a commercial license. | `SixLabors.ImageSharp.Drawing` | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/QrCodeBitmapExtensions.cs) |
Using these extension methods, generating PNG images is straight-forward:
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class PngImage
{
static void Main()
{
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.Medium);
qr.SaveAsPng("hello-world-qr.png", 10, 3);
}
}
}
================================================
FILE: QrCodeGenerator/docfx/docfx.json
================================================
{
"metadata": [
{
"src": [
{
"files": [
"**.csproj"
],
"src": ".."
}
],
"dest": "../obj/docfx/api",
"disableGitFeatures": false,
"disableDefaultFilter": false
}
],
"build": {
"content": [
{
"files": [
"api/**.yml"
],
"src": "../obj/docfx"
},
{
"files": [
"index.md",
"api/index.md"
]
}
],
"resource": [
],
"overwrite": [
{
"files": [
"apidoc/**.md"
],
"exclude": [
"obj/**",
"bin/**"
]
}
],
"dest": "../bin/_site",
"globalMetadataFiles": [],
"fileMetadataFiles": [],
"template": [
"default",
"modern"
],
"postProcessors": [],
"markdownEngineName": "markdig",
"noLangKeyword": false,
"keepFileLink": false,
"cleanupCacheHistory": false,
"disableGitFeatures": false
}
}
================================================
FILE: QrCodeGenerator/docfx/index.md
================================================
# QR Code Generator for .NET
[.NET Reference Documentation](api/index.md)
================================================
FILE: QrCodeGenerator/docs/README.md
================================================
# QR Code Generator for .NET
Open-source library for generating QR codes from text strings and byte arrays.
The library is built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.) including .NET 6 on all platforms.
It is mostly a translation of project Nayuki's Java version of the QR code generator. The project provides implementations for
many more programming languages, and the [Project Nayuki web site](https://www.nayuki.io/page/qr-code-generator-library) has additional information about the implementation.
## Features
Core features:
* Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard
* Output formats: Raw modules/pixels of the QR symbol, SVG, XAML path, PNG and BMP files. For other raster bitmap formats, see [below](#raster-images--bitmaps).
* Encodes numeric and special-alphanumeric text in less space than general text
* Open source code under the permissive *MIT License*
* Built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.).
* Available as a [NuGet package](https://www.nuget.org/packages/Net.Codecrete.QrCodeGenerator/) (named *Net.Codecrete.QrCodeGenerator*)
* Example code for WinForms, WPF, ASP.NET, ImageSharp, SkiaSharp and many more
Manual parameters:
* You can specify the minimum and maximum *version number* allowed, and the library will automatically choose the smallest version in the range that fits the data.
* You can specify the *mask pattern* manually, otherwise library will automatically evaluate all 8 masks and select the optimal one.
* You can specify an *error correction level*, or optionally allow the library to boost it if it doesn't increase the size (version).
* You can create a list of *data segments* manually and add *ECI segments*.
Optional advanced features:
* Long text can be split into multiple linked QR codes (aka Structured Append)
* Encodes Japanese Unicode text in *Kanji mode* to save space compared to UTF-8 bytes
* Computes *optimal segment mode* switching for text with mixed numeric/alphanumeric/general/kanji parts
## Getting started
1. Create a new Visual Studio project for .NET Core 3.1 (or higher) (*File > New > Project...* / *Visual C# > .NET Core > Console App (.NET Core)*)
2. Add the library via NuGet:
Either via *Project > Manage NuGet Packages...* / *Browse* / search for *qrcodegenerator* / *Install*
Or by running a command in the Package Manager Console
```
Install-Package Net.Codecrete.QrCodeGenerator -Version 2.0.7
```
3. Add the code from the example below
4. Run it
## API Documention
See [API Documentation](https://codecrete.net/QrCodeGenerator/api/index.html)
## Examples
**Simple operation**
```cslang
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class SimpleOperation
{
static void Main()
{
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.Medium);
string svg = qr.ToSvgString(4);
File.WriteAllText("hello-world-qr.svg", svg, Encoding.UTF8);
}
}
}
```
**Manual operation**
```cslang
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class ManualOperation
{
static void Main()
{
var segments = QrSegment.MakeSegments("3141592653589793238462643383");
var qr = QrCode.EncodeSegments(segments, QrCode.Ecc.High, 5, 5, 2, false);
for (int y = 0; y < qr.Size; y++)
{
for (int x = 0; x < qr.Size; x++)
{
... paint qr.GetModule(x,y) ...
}
}
}
}
}
```
## Requirements
QR Code Generator for .NET requires a .NET implementation compatible with .NET Standard 2.0 or higher, i.e. any of:
- .NET Core 2.0 or higher
- .NET Framework 4.6.1 or higher
- Mono 5.4 or higher
- Universal Windows Platform 10.0.16299 or higher
- Xamarin
### Raster Images / Bitmaps
Starting with .NET 6, *System.Drawing* is only supported on Windows operating system and thus cannot be used for multi-platform libraries like this one. Therefore, `ToBitmap()` has been removed.
Two raster bitmap formats are supported with the need for additional libraries:
- *PNG*: See `QrCode.ToPngBitmap()`
- *BMP*: See `QrCode.ToBmpBitmap()`
These methods are limited, e.g. with regards to the size of the generated image.
For more advanced and more efficient ways to generate different raster image formats:
- Select one of the imaging libraries below
- Add the NuGet dependencies to your project
- Copy the appropriate `QrCodeBitmapExtensions.cs` file to your project
| Imaging library | Recommendation | NuGet dependencies | Extension file |
| ------- | -------------- | ------------------ | -------------- |
| **System.Drawing** | For Windows only projects | `System.Drawing.Common` | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-System-Drawing/QrCodeBitmapExtensions.cs) |
| **SkiaSharp** | For macOS, Linux, iOS, Android and multi-platform projects | `SkiaSharp` and `SkiaSharp.NativeAssets.Linux` (for Linux only) | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-SkiaSharp/QrCodeBitmapExtensions.cs) |
| **ImageSharp** | Alternative for multi-platform projects. Might require a commercial license. | `SixLabors.ImageSharp.Drawing` | [QrCodeBitmapExtensions.cs](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-ImageSharp/QrCodeBitmapExtensions.cs) |
Using these extension methods, generating PNG images is straight-forward:
```cslang
using Net.Codecrete.QrCodeGenerator;
namespace Examples
{
class PngImage
{
static void Main()
{
var qr = QrCode.EncodeText("Hello, world!", QrCode.Ecc.Medium);
qr.SaveAsPng("hello-world-qr.png", 10, 3);
}
}
}
```
## Examples
Several example projects demonstrate how to generate QR code with different frameworks and libraries:
- [Demo-QRCode-Variety](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-QRCode-Variety): Demonstrates how QR codes with different encodings, error correction and masks can be generated. All QR codes are saved as SVG files.
- [Demo-WinUI](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-WinUI): Demonstrates how QR codes can be used in WinUI 3 applications and/or using [Win2D](https://github.com/microsoft/Win2D) (incl. copying to the clipboard).
- [Demo-WindowsPresentationFoundation](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-WindowsPresentationFoundation): Demonstrates how QR codes can be used in WPF applications (incl. copying to the clipboard).
- [Demo-WinForms](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-WinForms): Demonstrates how QR codes can be used in Windows Forms applications (incl. copying to the clipboard).
- [Demo-ASP.NET-Core](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-ASP.NET-Core): Demonstrates how to create QR codes in a web application implemented using ASP.NET Core.
- [Demo-VCard](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-VCard): Demonstrates how contact data (similar to business cards) can be saved in a QR Code using the VCard standard.
- [Demo-System-Drawing](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-System-Drawing): Demonstrates how a QR code can be saved a PNG file, using the *System.Drawing* classes, which have become a Windows only technology starting with .NET 6.
- [Demo-SkiaSharp](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-SkiaSharp): Demonstrates how a QR code can be saved a PNG file, using the SkiaSharp multi-platform raster image library.
- [Demo-ImageSharp](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-ImageSharp): Demonstrates how a QR code can be saved a PNG file, using the ImageSharp raster image library. Additionally, a QR code with an image in the center is created.
- [Demo-ImageMagick](https://github.com/manuelbl/QrCodeGenerator/blob/v2.1.0/Demo-ImageMagick): Demonstrates how a QR code can be saved a PNG file, using the Magick.NET image manipulation library (based on ImageMagick).
================================================
FILE: QrCodeGenerator.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31424.327
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QrCodeGenerator", "QrCodeGenerator\QrCodeGenerator.csproj", "{36B0822E-28D7-43C7-BAF7-AF578E31E978}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QrCodeGeneratorTest", "QrCodeGeneratorTest\QrCodeGeneratorTest.csproj", "{81307EE7-7915-4D2D-8F71-495F239FD266}"
ProjectSection(ProjectDependencies) = postProject
{36B0822E-28D7-43C7-BAF7-AF578E31E978} = {36B0822E-28D7-43C7-BAF7-AF578E31E978}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{36B0822E-28D7-43C7-BAF7-AF578E31E978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{36B0822E-28D7-43C7-BAF7-AF578E31E978}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36B0822E-28D7-43C7-BAF7-AF578E31E978}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36B0822E-28D7-43C7-BAF7-AF578E31E978}.Release|Any CPU.Build.0 = Release|Any CPU
{81307EE7-7915-4D2D-8F71-495F239FD266}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81307EE7-7915-4D2D-8F71-495F239FD266}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81307EE7-7915-4D2D-8F71-495F239FD266}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81307EE7-7915-4D2D-8F71-495F239FD266}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {256EFBB5-C259-4422-BE66-29B9FF4BF92F}
EndGlobalSection
EndGlobal
================================================
FILE: QrCodeGeneratorTest/BitArrayExtensionsTest.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using System.Collections;
using Xunit;
namespace Net.Codecrete.QrCodeGenerator.Test
{
public class BitArrayExtensionsTest
{
[Fact]
public void AppendInt1()
{
var ba = new BitArray(0);
ba.AppendBits(18, 6);
Assert.Equal(6, ba.Length);
Assert.False(ba[0]);
Assert.True(ba[1]);
Assert.False(ba[2]);
Assert.False(ba[3]);
Assert.True(ba[4]);
Assert.False(ba[5]);
}
[Fact]
public void AppendInt2()
{
var ba = new BitArray(0);
ba.AppendBits(18, 6);
ba.AppendBits(3, 2);
Assert.Equal(8, ba.Length);
Assert.False(ba[0]);
Assert.True(ba[1]);
Assert.False(ba[2]);
Assert.False(ba[3]);
Assert.True(ba[4]);
Assert.False(ba[5]);
Assert.True(ba[6]);
Assert.True(ba[7]);
}
[Fact]
public void AppendExtraBits()
{
var ba = new BitArray(0);
Assert.Throws(() =>
{
ba.AppendBits(128, 4);
});
}
[Fact]
public void ExtractBits()
{
var ba = new BitArray(0);
ba.AppendBits(18, 6);
ba.AppendBits(0b11001010, 8);
Assert.Equal(18u, ba.ExtractBits(0, 6));
Assert.Equal(0b11001010u, ba.ExtractBits(6, 8));
}
}
}
================================================
FILE: QrCodeGeneratorTest/KanjiTest.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System.Collections.Generic;
using Xunit;
// ReSharper disable StringLiteralTypo
namespace Net.Codecrete.QrCodeGenerator.Test
{
public class KanjiTest
{
private const string KanjiSample
= "委マツニオ男喜でろつ絶選にッ自君エ碁4配堪イルネコ禁2京果ユウタカ著書ンぴは役村ン政経購税き視思61近退ほぜ。投むでみ書権し輔組キ黒壁えちをあ刊中申内イヌ著太記ヲ庁宿ホマ湯連マクラ相就づ藤業トリカ場止ラマエニ現露ラ情伝ま登厘架れち。任ムオホ除85郊ツ執父たはんゅ喜離レクセサ社暖せげ磨育こぽずぎ聞来ンは事聞煙や無杯すやべぽ信93幕もいび及町いば事階齢利江ず。"
+ "陸スシネク賢軽ワマ産闘人めせ視豊ネワマキ庭朝療へ終胸ずでリぐ価交こる覧夜でわみを氷性聞年よとク。朝定掲ぞぴえる縄策ヌキウク主力まひ本生ウヒア鎖検ヘ同階リぞ美字ツイキニ問企表カクツ助1台づレぼえ。事箕ケテ内上べが訃長す容批ヨ多帯ヌムフハ社早オイ球選アヘ話交じぞぽ上国78覚は根辺むげたょ室也も。"
+ "数ヨフヱイ血結質ッろ護外すうだご古犠リ自陽カアタ幅交数ぼもそき請件ろ問拉著フヒミ陰天61債ン。竹ごつべク市成キヤウ検新スセヒヲ花期的もぴは嶋信ヱマサワ局記来イヲナネ比引フタニハ津適よいうり長熊う割監ッそ投出リラツル誇載距ふかすん論紅ょごくむ井5消宗征訟おなス。油ヤレワ減力テミ機46残ツケ遺鳥そ前名ニ作38草あぶづだ見遠ヘ覧程ラり転由教おとへ当潟とみ味購域施活ぜどだ。"
+ "駆投ねづ女日べリりが離口にわ神新え続竹ワハ時円とりば権読け質打ノセ記囲ラヨヒソ暮交だ族時加せげ。山テカ牧於ちぶん社47開低きねぽぶ眼明んドっ東検キ連可劇はよしぶ意田ソ信道ユヌネル経自い日花ぴラに。休ク況術ハヤ感要ヨ禁社ぴくざな賠表台里レヱ属自ホヱ民活え因物ぴぽド形型会ロモヱセ法本談ル関49打ツノ速新ぎき堀冬密浦絶どぞつ。"
+ "追ろ役陸モヘセ担妊ぱゅン島47自ミリシホ子載科ぐばのド返物ナ月営わを屋界ヒクエム取強あるゆ売増ロムネ鶏交応更ょ。認投か者木ッ変甲テケツマ類読けっイり鋼巻ス観市徴ンぎる金谷ゆけ当披トソロ薬身とを勢米ハ件確ー実市浮絵レ。職ウト基交と止士高こてゆべ集団制ラクイ観経回スミネカ治6聖うぜ頑機ずお国20覧歌ヌレ故携ムネナシ選文ヲレ西納30図ねリず行格ぜお電医丸族の。"
+ "県梨フアヨ長気チ手過フエ本患イやぼ回劇ぶ表神サヘヌ聞変モチ導産埼もすけん付必ッ罪真え号情6長ドンたじ雄員将格真復ほるおと。答モ闘貨午マソカチ革覇ヱキチマ農多ルメタ宮門ルメユ中作ツキテ主書タカモサ事崎ぞルぼ犯柴海図ほち義暴よッろン阪制エ景修級ぐル。変ム注止まどけふ境趣んかラ内経むがる面28湯ぱはげど元使ナ屋俸どだび会表連トスなり年埋たれゃ。"
+ "資むぎ方退キソセ逃於ケイヲカ域元まど月経快美りか再入ソエヨム播大マス勝星むま芸投フサル男記クかふば詰当ソ患京へ駆食えぞ知属ヱレアユ市秋ょ。7速コ覧広ヤミチケ接済なクろ件2段ト折67的了だぞじ伸属ぴっ秋頭イナタフ聞践周は上並あ一6便苦レざ外喰杜椿榎び。応めにえン稿業タキリ盗16水春めわ雑成めす国含ウレハラ最完レ面立更東稿ハクヌ添起チタヨテ営尾ら。"
+ "済メヌ集取ネツホユ人9芋ヒツコワ春34能メレタツ朝源ぞ名校げイ太化テソタ近慎ナ口20夜け会報あルトお量問保ぎ場上っ浪足まだゅト育更ラホテカ太健象延ゆル。展つゃた後幸ちぞわぼ金質レ未曲ネマ勝投の若著遅ごぽ時顔セカ報高夫コユエラ応迎飯りばまで愛児ケ息9債核築がち。応文ドッ記強ユノヌエ初検なしよぱ長止表へよ今工テメ相取載ミ青1書にあひ略稿ぶごよ的会報じぐ挑政手一基づ。"
+ "覧ツハ女子み絡康89嘉塁塾嶋4分4約タニウ政提タヌル王朝よきはべ運案ヒホ男週めーお開培イわ北事巡流む。服勢ラメリユ邦大め地若ゅ構神ヒカロ疑育サ済供しりろべ告惑合コヤリナ代井てじぜゆ沖立験ヲモスロ加知ネ競30嘉塁塾嶋90女れフわず勝脱せでに植出党尾滋ず。写ねけを値碁ヌロ計新そへう最男イ筑地ー作提ツムハウ暮工ざ転阜終ふてお抑売買エ題要じレ王護い手乗学カクリソ発府めだごラ変実三以て。"
+ "世なべるそ名走スレヤ変週トウ残予ハサヌカ払者じのドル分定リば米61与アエユ来熱成かのら終参しつド日備てな要勤奇そむ磐価ヌ問者チ治本ンむくい限前サトスハ郎禁ヘマ自朝せ主並局行承ね。全キロヲ芸来はてし見9所謙レ撤住ワ約子情農スニ手個いよゆぴ事断ニ遊83常左県煙8東金締ばねぞ。友府ょ盤養虚ぽ昇球つはー繰申チオ境著ごふょ派広だ戦事すめ無問きこどぱ毎保37火ヱト韓端侍勃卑ぼン。";
[Fact]
public void IsKanjiEncodable()
{
Assert.True(QrSegmentAdvanced.IsEncodableAsKanji(KanjiSample));
}
}
}
================================================
FILE: QrCodeGeneratorTest/PngTest.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
*
*/
using System.IO;
using System.Threading.Tasks;
using VerifyTests;
using VerifyXunit;
using Xunit;
using static Net.Codecrete.QrCodeGenerator.QrCode;
namespace Net.Codecrete.QrCodeGenerator.Test
{
public class PngTest
{
static PngTest()
{
VerifyImageMagick.Initialize();
VerifyImageMagick.RegisterComparers(threshold: 0.005);
}
private const string CodeText1 = "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.";
private const string CodeText2 = "The quick brown fox";
protected readonly VerifySettings Settings = new VerifySettings();
public PngTest()
{
Settings.UseDirectory("ReferenceFiles");
}
[Fact]
public Task PngImage()
{
var qrCode = EncodeText(CodeText1, Ecc.Medium);
var pngData = qrCode.ToPngBitmap(5, 3);
using (var stream = new MemoryStream(pngData))
{
return Verifier.Verify(stream, "png", Settings);
}
}
[Fact]
public Task ColorPngImage()
{
var qrCode = EncodeText(CodeText2, Ecc.Medium);
var pngData = qrCode.ToPngBitmap(3, 7, 0x171c80, 0xccbc9b);
using (var stream = new MemoryStream(pngData))
{
return Verifier.Verify(stream, "png", Settings);
}
}
}
}
================================================
FILE: QrCodeGeneratorTest/QrCodeBitmapTest.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System;
using Xunit;
using static Net.Codecrete.QrCodeGenerator.QrCode;
namespace Net.Codecrete.QrCodeGenerator.Test
{
public class QrCodeBitmapTest
{
private static Ecc EccFromOrdinal(int val)
{
Ecc ecc;
switch (val) {
case 0:
ecc = Ecc.Low;
break;
case 1:
ecc = Ecc.Medium;
break;
case 2:
ecc = Ecc.Quartile;
break;
case 3:
ecc = Ecc.High;
break;
default:
throw new ArgumentOutOfRangeException(nameof(val), val, string.Empty);
}
return ecc;
}
[Theory]
[InlineData("https://some-weird-test-site.site?whatever=test&test=123&qrcodes=true", 1, 0, 1,
"Qk1mAQAAAAAAAD4AAAAoAAAAJQAAACUAAAABAAEAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wABNbl4gAAAAH2YIHtIAAAARZKOUbgAAABF18iIsAAAAEULZ/AQAAAAfZzqZwAAAAABYtBVaAAAAP8KPrdoAAAAHVwj8EAAAADmh5vWmAAAANCnMkWYAAAAR+1mSzgAAAAtnd3kiAAAABPpnc5YAAAAiXY2DBgAAABv8FrGaAAAAHiVuNCYAAAAAywgdMgAAADQcKpM+AAAAOrRjotoAAAAVXNn/YAAAACSHPJaSAAAALhO2q4YAAAAxmIcBzgAAABsKCF5gAAAAN9hmn3IAAAA4MVQolgAAAArPWKDKAAAAHQXyPAwAAAA/wOSb/gAAAABVVVUAAAAAH0JTdXwAAAARRH2pRAAAABFccYFEAAAAEX0A8UQAAAAfaGzFfAAAAABEwzkAAAAAA==")]
[InlineData("https://some-weird-test-site.site?whatever=test&test=123&qrcodes=true", 2, 3, 1,
"Qk22AQAAAAAAAD4AAAAoAAAALwAAAC8AAAABAAEAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wD///////4AAP///////gAA///////+AADgO6v/YF4AAO+lxCohTgAA6L2ATReuAADouUKYTT4AAOigXCdAXgAA77/XlU5OAADgP97Ayo4AAP/iVozOrgAA5zlqO0D+AAD4+wMZZW4AAPilMcmmbgAA4c22rPiOAAD1l98/df4AAPnKd3lDfgAA8Z0JkavOAAD8dAKZIK4AAOGKaI1l3gAA6mgrWDluAADyLHIZrm4AAOt5c5RwLgAA6jxX4lfOAADsRaV5aW4AAOy55Z0tbgAA9XL2RLCOAAD5M02aHV4AAPPi/21fTgAA/rYvuSHuAADhczd3qq4AAPcUukk33gAA7UCOCQ1eAADgHCpZLO4AAPVGm7CyTgAA9qZa7lS+AAD//LTZL/4AAOAqqqqoDgAA76jKfwvuAADopX0Q+i4AAOi25Ci6LgAA6K8FphouAADvv3xO2+4AAOA6ZIx4DgAA///////+AAD///////4AAP///////gAA")]
[InlineData("https://some-weird-test-site.site?whatever=test&test=123&qrcodes=true", 2, 3, 4,
"Qk3eEQAAAAAAAD4AAAAoAAAAvAAAALwAAAABAAEAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wD///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D/8AAAAP/w//Dw8P//////D/AAAA8P////8AAAAP/w//Dw8P//////D/AAAA8P////8AAAAP/w//Dw8P//////D/AAAA8P////8AAAAP/w//Dw8P//////D/AAAA8P////8P//8PAPD/8ADwAA8PDwAPAADw8A////8P//8PAPD/8ADwAA8PDwAPAADw8A////8P//8PAPD/8ADwAA8PDwAPAADw8A////8P//8PAPD/8ADwAA8PDwAPAADw8A////8PAA8P//D/AAAAAPAP8PAA8P//Dw////8PAA8P//D/AAAAAPAP8PAA8P//Dw////8PAA8P//D/AAAAAPAP8PAA8P//Dw////8PAA8P//D/AAAAAPAP8PAA8P//Dw////8PAA8P/wDw8AAPDwD/AADwD/DwD/////8PAA8P/wDw8AAPDwD/AADwD/DwD/////8PAA8P/wDw8AAPDwD/AADwD/DwD/////8PAA8P/wDw8AAPDwD/AADwD/DwD/////8PAA8PAAAA8P/wAA8A//DwAAAA8P////8PAA8PAAAA8P/wAA8A//DwAAAA8P////8PAA8PAAAA8P/wAA8A//DwAAAA8P////8PAA8PAAAA8P/wAA8A//DwAAAA8P////8P//8P////8PD//wDw8PDwD/8A8A////8P//8P////8PD//wDw8PDwD/8A8A////8P//8P////8PD//wDw8PDwD/8A8A////8P//8P////8PD//wDw8PDwD/8A8A////8AAAAP////8P//D/AAAA/wDw8PAA////8AAAAP////8P//D/AAAA/wDw8PAA////8AAAAP////8P//D/AAAA/wDw8PAA////8AAAAP////8P//D/AAAA/wDw8PAA//////////AA8A8PD/DwAP8A/wD/8PDw//////////AA8A8PD/DwAP8A/wD/8PDw//////////AA8A8PD/DwAP8A/wD/8PDw//////////AA8A8PD/DwAP8A/wD/8PDw////8A//AP/wDw/w8PAA//D/DwAAAP//////8A//AP/wDw/w8PAA//D/DwAAAP//////8A//AP/wDw/w8PAA//D/DwAAAP//////8A//AP/wDw/w8PAA//D/DwAAAP////////AA///w/wAAAP8AD/APD/APDw/w//////AA///w/wAAAP8AD/APD/APDw/w//////AA///w/wAAAP8AD/APD/APDw/w//////AA///w/wAAAP8AD/APD/APDw/w//////AA8PAPDwD/AA//APAP8PAP8A/w//////AA8PAPDwD/AA//APAP8PAP8A/w//////AA8PAPDwD/AA//APAP8PAP8A/w//////AA8PAPDwD/AA//APAP8PAP8A/w////8AAP/wD/D/D/D/Dw8P8A///wAPAA////8AAP/wD/D/D/D/Dw8P8A///wAPAA////8AAP/wD/D/D/D/Dw8P8A///wAPAA////8AAP/wD/D/D/D/Dw8P8A///wAPAA/////w8P8A8P//8P//8A////D/8PD////////w8P8A8P//8P//8A////D/8PD////////w8P8A8P//8P//8A////D/8PD////////w8P8A8P//8P//8A////D/8PD/////////AP/wDw8A//D/8P//APDwAA/w////////AP/wDw8A//D/8P//APDwAA/w////////AP/wDw8A//D/8P//APDwAA/w////////AP/wDw8A//D/8P//APDwAA/w///////wAP8A//DwAA8A/wDwAP8PDw//8A/////wAP8A//DwAA8A/wDwAP8PDw//8A/////wAP8A//DwAA8A/wDwAP8PDw//8A/////wAP8A//DwAA8A/wDwAP8PDw//8A//////8AD/8PAAAAAPDwD/APAPAAAPDw//////8AD/8PAAAAAPDwD/APAPAAAPDw//////8AD/8PAAAAAPDwD/APAPAAAPDw//////8AD/8PAAAAAPDwD/APAPAAAPDw////8AAP8ADw8A/w8ADwAP8PD/APD/8P////8AAP8ADw8A/w8ADwAP8PD/APD/8P////8AAP8ADw8A/w8ADwAP8PD/APD/8P////8AAP8ADw8A/w8ADwAP8PD/APD/8P////8PDwD/DwAADw8P8PD/AAAP/wDw/w////8PDwD/DwAADw8P8PD/AAAP/wDw/w////8PDwD/DwAADw8P8PD/AAAP/wDw/w////8PDwD/DwAADw8P8PD/AAAP/wDw/w/////wDwAPD/AA//APAAD/AP8PD/8A/w/////wDwAPD/AA//APAAD/AP8PD/8A/w/////wDwAPD/AA//APAAD/AP8PD/8A/w/////wDwAPD/AA//APAAD/AP8PD/8A/w////8PD/D//wDw//AP/wDw8AD/8AAADw////8PD/D//wDw//AP/wDw8AD/8AAADw////8PD/D//wDw//AP/wDw8AD/8AAADw////8PD/D//wDw//AP/wDw8AD/8AAADw////8PDwAP//AA8PD///8ADwDw8P//8A////8PDwAP//AA8PD///8ADwDw8P//8A////8PDwAP//AA8PD///8ADwDw8P//8A////8PDwAP//AA8PD///8ADwDw8P//8A////8P8ADwAPD/DwDw8P//APD/DwDw/w////8P8ADwAPD/DwDw8P//APD/DwDw/w////8P8ADwAPD/DwDw8P//APD/DwDw/w////8P8ADwAPD/DwDw8P//APD/DwDw/w////8P8A8P/wD//wDw/wD/8PAPD/Dw/w////8P8A8P/wD//wDw/wD/8PAPD/Dw/w////8P8A8P/wD//wDw/wD/8PAPD/Dw/w////8P8A8P/wD//wDw/wD/8PAPD/Dw/w/////w8PD/8A8P//D/APAA8A8P8AAPAA/////w8PD/8A8P//D/APAA8A8P8AAPAA/////w8PD/8A8P//D/APAA8A8P8AAPAA/////w8PD/8A8P//D/APAA8A8P8AAPAA//////APAP8A/w8A/w/wD/DwAA//Dw8P//////APAP8A/w8A/w/wD/DwAA//Dw8P//////APAP8A/w8A/w/wD/DwAA//Dw8P//////APAP8A/w8A/w/wD/DwAA//Dw8P/////wD///AA8P////8P8P8PDw///w8A/////wD///AA8P////8P8P8PDw///w8A/////wD///AA8P////8P8P8PDw///w8A/////wD///AA8P////8P8P8PDw///w8A///////w8P8P8ADw///w//APAPAAD//w///////w8P8P8ADw///w//APAPAAD//w///////w8P8P8ADw///w//APAPAAD//w///////w8P8P8ADw///w//APAPAAD//w////8AAPD/8A/wD/D/8P/w//8PDw8PDw////8AAPD/8A/wD/D/8P/w//8PDw8PDw////8AAPD/8A/wD/D/8P/w//8PDw8PDw////8AAPD/8A/wD/D/8P/w//8PDw8PDw/////w//AA8PAPD/8PAPAPAPAP8P//8P/////w//AA8PAPD/8PAPAPAPAP8P//8P/////w//AA8PAPD/8PAPAPAPAP8P//8P/////w//AA8PAPD/8PAPAPAPAP8P//8P////8P8PDwAAAPAA//AAAPAPAAD/Dw8P////8P8PDwAAAPAA//AAAPAPAAD/Dw8P////8P8PDwAAAPAA//AAAPAPAAD/Dw8P////8P8PDwAAAPAA//AAAPAPAAD/Dw8P////8AAAAA//AADw8PAPD/APAPD/AP/w////8AAAAA//AADw8PAPD/APAPD/AP/w////8AAAAA//AADw8PAPD/APAPD/AP/w////8AAAAA//AADw8PAPD/APAPD/AP/w/////w8PDwAP8PAP8P/w/wAA8P8A8A8A/////w8PDwAP8PAP8P/w/wAA8P8A8A8A/////w8PDwAP8PAP8P/w/wAA8P8A8A8A/////w8PDwAP8PAP8P/w/wAA8P8A8A8A/////w/w8PAP8A8P8PD/8P/wDw8PAPD//////w/w8PAP8A8P8PD/8P/wDw8PAPD//////w/w8PAP8A8P8PD/8P/wDw8PAPD//////w/w8PAP8A8P8PD/8P/wDw8PAPD/////////////APD/DwD/D/APAPD/////////////////APD/DwD/D/APAPD/////////////////APD/DwD/D/APAPD/////////////////APD/DwD/D/APAPD/////////8AAAAPDw8PDw8PDw8PDw8PDwAAAA////8AAAAPDw8PDw8PDw8PDw8PDwAAAA////8AAAAPDw8PDw8PDw8PDw8PDwAAAA////8AAAAPDw8PDw8PDw8PDw8PDwAAAA////8P//8PDwAP8A8PAP////AADw///w////8P//8PDwAP8A8PAP////AADw///w////8P//8PDwAP8A8PAP////AADw///w////8P//8PDwAP8A8PAP////AADw///w////8PAA8PAPDw///w8ADwAA///w8ADw////8PAA8PAPDw///w8ADwAA///w8ADw////8PAA8PAPDw///w8ADwAA///w8ADw////8PAA8PAPDw///w8ADwAA///w8ADw////8PAA8P8P8P/wDwAA8PAA8P/w8ADw////8PAA8P8P8P/wDwAA8PAA8P/w8ADw////8PAA8P8P8P/wDwAA8PAA8P/w8ADw////8PAA8P8P8P/wDwAA8PAA8P/w8ADw////8PAA8PD//wAADw/w8A/wAA/w8ADw////8PAA8PD//wAADw/w8A/wAA/w8ADw////8PAA8PD//wAADw/w8A/wAA/w8ADw////8PAA8PD//wAADw/w8A/wAA/w8ADw////8P//8P///w///wAPAP/w/w/w///w////8P//8P///w///wAPAP/w/w/w///w////8P//8P///w///wAPAP/w/w/w///w////8P//8P///w///wAPAP/w/w/w///w////8AAAAP/w8A/wDwDwAP8AD//wAAAA////8AAAAP/w8A/wDwDwAP8AD//wAAAA////8AAAAP/w8A/wDwDwAP8AD//wAAAA////8AAAAP/w8A/wDwDwAP8AD//wAAAA//////////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////D///////////////////////////////A=")]
[InlineData("https://some-weird-test-site.site?whatever=test&test=123&qrcodes=true", 3, 2, 2,
"Qk3eBgAAAAAAAD4AAAAoAAAAagAAAGoAAAABAAEAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wD/////////////////wAAA/////////////////8AAAP/////////////////AAAD/////////////////wAAA8AA8wAzz8//PwA//A/////AAPMAM8/P/z8AP/wP////z/z/wADMwAzPAwPA/////8/8/8AAzMAMzwMDwP/////MDMM/zAAzAwwD/AP/////zAzDP8wAMwMMA/wD/////8wMzw8wzMAAw8P8wM/////MDM8PMMzAAMPD/MDP////zAzw8w88APPwPMADD////8wM8PMPPADz8DzAAw/////P/PDD/wz8D/MDz8P/////z/zww/8M/A/zA8/D/////8AAzDAwPMzw8w/Mww/////AAMwwMDzM8PMPzMMP///////AMP/8/D/zPA/AD///////wDD//Pw/8zwPwA/////A/PPP8MwA88z/wA//////wPzzz/DMAPPM/8AP//////A/AzDzwwA/DDDzPM/////wPwMw88MAPwww8zzP////8/D//PMMD8Dz/DM/P/////Pw//zzDA/A8/wzPz/////DM/zz88/88wPAzAAP////wzP88/PP/PMDwMwAD/////D8Pw8/zAwAMMMMzA/////w/D8PP8wMADDDDMwP////8MM8z8Dz8zAMDzwwP/////DDPM/A8/MwDA88MD/////PAPwDDMzzw8A/zwz/////zwD8AwzM88PAP88M//////8PzwAPwP/AMwMMPz//////D88AD8D/wDMDDD8//////zzMMAzzADMw8/PD//////88zDAM8wAzMPPzw//////PM/wDzDz/PADwMMMP////zzP8A8w8/zwA8DDDD//////wwAM88M8MPMwMP8//////8MADPPDPDDzMDD/P////zwPwzD/zww/wD/8zD////88D8Mw/88MP8A//Mw/////MDA/zDAMPz8Pz/wDP////zAwP8wwDD8/D8/8Az//////zMD8MPAzP//PzP///////8zA/DDwMz//z8z//////z8AM8MPAADzPPMAPD////8/ADPDDwAA8zzzADw/////Az8zDPPz8MPMwD8A/////wM/Mwzz8/DDzMA/AP////8PMzMD8wMwADMPMwA/////DzMzA/MDMAAzDzMAP////8A/ADPAM/AA8zw/AP/////APwAzwDPwAPM8PwD/////8wAwDADwAAzw/AAP//////MAMAwA8AAM8PwAD/////8MPDDMzMwAwDw/w///////DDwwzMzMAMA8P8P//////zADPzDw/Mz8wPP/zP////8wAz8w8PzM/MDz/8z/////z/wwD/8DAP8DDAzPP////8/8MA//AwD/AwwMzz/////MMAAAMD/P8D8MM8w/////zDAAADA/z/A/DDPMP/////w/P//Aw/MP8AzAPz/////8Pz//wMPzD/AMwD8/////P/P8MM///MMPw8AP/////z/z/DDP//zDD8PAD//////APM/zzDAz/Mz8Dww/////wDzP88wwM/zM/A8MP////wPzD/AwPzAAzAPwA/////8D8w/wMD8wAMwD8AP/////8AwAAA8Mz/DPw/w8P/////AMAAAPDM/wz8P8PD////8DM88D8z8DDAw8PMM/////AzPPA/M/AwwMPDzDP/////DPwPP88P/wADw/Mz/////wz8Dz/PD/8AA8PzM/////PAD8PMPz8wDDD/AA/////zwA/DzD8/MAww/wAP///////DPA/PzMAw/PwMz///////wzwPz8zAMPz8DM//////DwA8PwAADMMAPDP//////w8APD8AAAzDADwz////////8ADP8D8MDMwD//////////AAz/A/DAzMA///////8AAzMzMzMzMzMzMAA/////AAMzMzMzMzMzMzAAP////z/zzz/MM/M/PDPz/z////8/888/zDPzPzwz8/8/////MDM8/DMwAw8PD/MDP////zAzPPwzMAMPDw/zAz////8wM8PwD8M8/MwM8wM/////MDPD8A/DPPzMDPMDP////zAzzwzDMAPMwwwzAz////8wM88MwzADzMMMMwM/////P/PwP8wPwAwDADP/P////z/z8D/MD8AMAwAz/z////8AA/DAM//zw/wPMAA/////AAPwwDP/88P8DzAAP/////////////////////wAAA/////////////////8AAAP/////////////////AAAD/////////////////wAAA")]
[InlineData("https://some-weird-test-site.site?whatever=test&test=123&qrcodes=true", 1, 1, 16,
"Qk0+wwAAAAAAAD4AAAAoAAAAcAIAAHACAAABAAEAAAAAAAAAAADEDgAAxA4AAAAAAAAAAAAAAAAAAP///wD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP//AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAP////8AAP//AAD/////AAD///////8AAAAA//8AAP//////////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAA/////wAA//8AAP////8AAP///////wAAAAD//wAA//////////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAP////8AAP//AAD/////AAD///////8AAAAA//8AAP//////////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAA/////wAA//8AAP////8AAP///////wAAAAD//wAA//////////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAP////8AAP//AAD/////AAD///////8AAAAA//8AAP//////////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAA/////wAA//8AAP////8AAP///////wAAAAD//wAA//////////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAP////8AAP//AAD/////AAD///////8AAAAA//8AAP//////////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAA/////wAA//8AAP////8AAP///////wAAAAD//wAA//////////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAP////8AAP//AAD/////AAD///////8AAAAA//8AAP//////////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAA/////wAA//8AAP////8AAP///////wAAAAD//wAA//////////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAD/////AAD//wAA/////wAA////////AAAAAP//AAD//////////wAAAAAAAP//AAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA/////////////wAA/////wAAAAD/////AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA//////////8AAP////8AAP//AAAAAP//////////AAD/////////////AAD/////AAAAAP////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAD//////////wAA/////wAA//8AAAAA//////////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA/////////////wAA/////wAAAAD/////AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA//////////8AAP////8AAP//AAAAAP//////////AAD/////////////AAD/////AAAAAP////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAD//////////wAA/////wAA//8AAAAA//////////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA/////////////wAA/////wAAAAD/////AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA//////////8AAP////8AAP//AAAAAP//////////AAD/////////////AAD/////AAAAAP////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAD//////////wAA/////wAA//8AAAAA//////////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA/////////////wAA/////wAAAAD/////AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA//////////8AAP////8AAP//AAAAAP//////////AAD/////////////AAD/////AAAAAP////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAD//////////wAA/////wAA//8AAAAA//////////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA/////////////wAA/////wAAAAD/////AAAAAAAAAAAAAP//AAAAAAAAAAAAAAAA//////////8AAP////8AAP//AAAAAP//////////AAD/////////////AAD/////AAAAAP////8AAAAAAAAAAAAA//8AAAAAAAAAAAAAAAD//////////wAA/////wAA//8AAAAA//////////8AAP////////////8AAP////8AAAAA/////wAAAAAAAAAAAAD//wAAAAAAAAAAAAAAAP//////////AAD/////AAD//wAAAAD//////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD/////AAAAAP//AAAAAP//AAD//wAAAAAAAP///////wAAAAD//wAA//8AAAAAAAD/////AAD///////////////8AAP//AAAAAAAA//8AAP////8AAAAA//8AAAAA//8AAP//AAAAAAAA////////AAAAAP//AAD//wAAAAAAAP////8AAP///////////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD/////AAAAAP//AAAAAP//AAD//wAAAAAAAP///////wAAAAD//wAA//8AAAAAAAD/////AAD///////////////8AAP//AAAAAAAA//8AAP////8AAAAA//8AAAAA//8AAP//AAAAAAAA////////AAAAAP//AAD//wAAAAAAAP////8AAP///////////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD/////AAAAAP//AAAAAP//AAD//wAAAAAAAP///////wAAAAD//wAA//8AAAAAAAD/////AAD///////////////8AAP//AAAAAAAA//8AAP////8AAAAA//8AAAAA//8AAP//AAAAAAAA////////AAAAAP//AAD//wAAAAAAAP////8AAP///////////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD/////AAAAAP//AAAAAP//AAD//wAAAAAAAP///////wAAAAD//wAA//8AAAAAAAD/////AAD///////////////8AAP//AAAAAAAA//8AAP////8AAAAA//8AAAAA//8AAP//AAAAAAAA////////AAAAAP//AAD//wAAAAAAAP////8AAP///////////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD/////AAAAAP//AAAAAP//AAD//wAAAAAAAP///////wAAAAD//wAA//8AAAAAAAD/////AAD///////////////8AAP//AAAAAAAA//8AAP////8AAAAA//8AAAAA//8AAP//AAAAAAAA////////AAAAAP//AAD//wAAAAAAAP////8AAP///////////////wAA//8AAAAAAAD//wAA/////wAAAAD//wAAAAD//wAA//8AAAAAAAD///////8AAAAA//8AAP//AAAAAAAA/////wAA////////////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP///////wAA//8AAP////////////8AAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAP////8AAP///////wAA//8AAAAAAAD//wAA////////AAD//wAA/////////////wAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA/////wAA////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP///////wAA//8AAP////////////8AAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAP////8AAP///////wAA//8AAAAAAAD//wAA////////AAD//wAA/////////////wAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA/////wAA////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP///////wAA//8AAP////////////8AAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAP////8AAP///////wAA//8AAAAAAAD//wAA////////AAD//wAA/////////////wAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA/////wAA////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP///////wAA//8AAP////////////8AAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAP////8AAP///////wAA//8AAAAAAAD//wAA////////AAD//wAA/////////////wAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA/////wAA////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP///////wAA//8AAP////////////8AAAAA//8AAAAAAAD//wAAAAAAAP//AAAAAAAA//8AAP////8AAP///////wAA//8AAAAAAAD//wAA////////AAD//wAA/////////////wAAAAD//wAAAAAAAP//AAAAAAAA//8AAAAAAAD//wAA/////wAA////////AAD//wAAAAAAAP//AAD///////8AAP//AAD/////////////AAAAAP//AAAAAAAA//8AAAAAAAD//wAAAAAAAP//AAD/////AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAAAAP//AAD/////AAD/////AAAAAP//////////////////AAAAAAAAAAAAAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAAAA//8AAP////8AAP////8AAAAA//////////////////8AAAAAAAAAAAAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAAAAP//AAD/////AAD/////AAAAAP//////////////////AAAAAAAAAAAAAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAAAA//8AAP////8AAP////8AAAAA//////////////////8AAAAAAAAAAAAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAAAAP//AAD/////AAD/////AAAAAP//////////////////AAAAAAAAAAAAAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAAAA//8AAP////8AAP////8AAAAA//////////////////8AAAAAAAAAAAAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAAAAP//AAD/////AAD/////AAAAAP//////////////////AAAAAAAAAAAAAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAAAA//8AAP////8AAP////8AAAAA//////////////////8AAAAAAAAAAAAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAAAAP//AAD/////AAD/////AAAAAP//////////////////AAAAAAAAAAAAAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAAAA//8AAP////8AAP////8AAAAA//////////////////8AAAAAAAAAAAAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAAAAD//wAA/////wAA/////wAAAAD//////////////////wAAAAAAAAAAAAAAAAAA//8AAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAD/////////////AAD/////AAAAAP///////wAAAAD///////8AAP//AAD//wAAAAD/////AAAAAP///////wAAAAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA////////AAAAAP///////wAA//8AAP//AAAAAP////8AAAAA////////AAAAAAAAAAAAAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAD/////////////AAD/////AAAAAP///////wAAAAD///////8AAP//AAD//wAAAAD/////AAAAAP///////wAAAAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA////////AAAAAP///////wAA//8AAP//AAAAAP////8AAAAA////////AAAAAAAAAAAAAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAD/////////////AAD/////AAAAAP///////wAAAAD///////8AAP//AAD//wAAAAD/////AAAAAP///////wAAAAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA////////AAAAAP///////wAA//8AAP//AAAAAP////8AAAAA////////AAAAAAAAAAAAAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAD/////////////AAD/////AAAAAP///////wAAAAD///////8AAP//AAD//wAAAAD/////AAAAAP///////wAAAAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA////////AAAAAP///////wAA//8AAP//AAAAAP////8AAAAA////////AAAAAAAAAAAAAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAD/////////////AAD/////AAAAAP///////wAAAAD///////8AAP//AAD//wAAAAD/////AAAAAP///////wAAAAAAAAAAAAD///////8AAP////////////8AAP////8AAAAA////////AAAAAP///////wAA//8AAP//AAAAAP////8AAAAA////////AAAAAAAAAAAAAP///////wAA/////////////wAA/////wAAAAD///////8AAAAA////////AAD//wAA//8AAAAA/////wAAAAD///////8AAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA//////////8AAAAAAAAAAAAAAAAAAP//AAD/////AAAAAAAA//8AAP////8AAP//AAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD/////AAD//////////wAAAAAAAAAAAAAAAAAA//8AAP////8AAAAAAAD//wAA/////wAA//8AAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP////8AAP//////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA//////////8AAAAAAAAAAAAAAAAAAP//AAD/////AAAAAAAA//8AAP////8AAP//AAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD/////AAD//////////wAAAAAAAAAAAAAAAAAA//8AAP////8AAAAAAAD//wAA/////wAA//8AAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP////8AAP//////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA//////////8AAAAAAAAAAAAAAAAAAP//AAD/////AAAAAAAA//8AAP////8AAP//AAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD/////AAD//////////wAAAAAAAAAAAAAAAAAA//8AAP////8AAAAAAAD//wAA/////wAA//8AAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP////8AAP//////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA//////////8AAAAAAAAAAAAAAAAAAP//AAD/////AAAAAAAA//8AAP////8AAP//AAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD/////AAD//////////wAAAAAAAAAAAAAAAAAA//8AAP////8AAAAAAAD//wAA/////wAA//8AAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP////8AAP//////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA//////////8AAAAAAAAAAAAAAAAAAP//AAD/////AAAAAAAA//8AAP////8AAP//AAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD/////AAD//////////wAAAAAAAAAAAAAAAAAA//8AAP////8AAAAAAAD//wAA/////wAA//8AAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP////8AAP//////////AAAAAAAAAAAAAAAAAAD//wAA/////wAAAAAAAP//AAD/////AAD//wAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD///////////////////////////////8AAAAAAAAAAP//AAD//wAAAAAAAP////////////8AAP//AAD/////AAD///////8AAP////8AAP///////////////////////////////wAAAAAAAAAA//8AAP//AAAAAAAA/////////////wAA//8AAP////8AAP///////wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD///////////////////////////////8AAAAAAAAAAP//AAD//wAAAAAAAP////////////8AAP//AAD/////AAD///////8AAP////8AAP///////////////////////////////wAAAAAAAAAA//8AAP//AAAAAAAA/////////////wAA//8AAP////8AAP///////wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD///////////////////////////////8AAAAAAAAAAP//AAD//wAAAAAAAP////////////8AAP//AAD/////AAD///////8AAP////8AAP///////////////////////////////wAAAAAAAAAA//8AAP//AAAAAAAA/////////////wAA//8AAP////8AAP///////wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD///////////////////////////////8AAAAAAAAAAP//AAD//wAAAAAAAP////////////8AAP//AAD/////AAD///////8AAP////8AAP///////////////////////////////wAAAAAAAAAA//8AAP//AAAAAAAA/////////////wAA//8AAP////8AAP///////wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD///////////////////////////////8AAAAAAAAAAP//AAD//wAAAAAAAP////////////8AAP//AAD/////AAD///////8AAP////8AAP///////////////////////////////wAAAAAAAAAA//8AAP//AAAAAAAA/////////////wAA//8AAP////8AAP///////wAA/////wAA////////////////////////////////AAAAAAAAAAD//wAA//8AAAAAAAD/////////////AAD//wAA/////wAA////////AAD/////AAD//////////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////AAAAAAAA////////AAD//wAA//8AAP///////wAAAAAAAAAA//8AAAAAAAD///////////////8AAAAAAAAAAAAA//8AAAAAAAD///////8AAAAAAAD///////8AAP//AAD//wAA////////AAAAAAAAAAD//wAAAAAAAP///////////////wAAAAAAAAAAAAD//wAAAAAAAP///////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////AAAAAAAA////////AAD//wAA//8AAP///////wAAAAAAAAAA//8AAAAAAAD///////////////8AAAAAAAAAAAAA//8AAAAAAAD///////8AAAAAAAD///////8AAP//AAD//wAA////////AAAAAAAAAAD//wAAAAAAAP///////////////wAAAAAAAAAAAAD//wAAAAAAAP///////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////AAAAAAAA////////AAD//wAA//8AAP///////wAAAAAAAAAA//8AAAAAAAD///////////////8AAAAAAAAAAAAA//8AAAAAAAD///////8AAAAAAAD///////8AAP//AAD//wAA////////AAAAAAAAAAD//wAAAAAAAP///////////////wAAAAAAAAAAAAD//wAAAAAAAP///////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////AAAAAAAA////////AAD//wAA//8AAP///////wAAAAAAAAAA//8AAAAAAAD///////////////8AAAAAAAAAAAAA//8AAAAAAAD///////8AAAAAAAD///////8AAP//AAD//wAA////////AAAAAAAAAAD//wAAAAAAAP///////////////wAAAAAAAAAAAAD//wAAAAAAAP///////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////AAAAAAAA////////AAD//wAA//8AAP///////wAAAAAAAAAA//8AAAAAAAD///////////////8AAAAAAAAAAAAA//8AAAAAAAD///////8AAAAAAAD///////8AAP//AAD//wAA////////AAAAAAAAAAD//wAAAAAAAP///////////////wAAAAAAAAAAAAD//wAAAAAAAP///////wAAAAAAAP///////wAA//8AAP//AAD///////8AAAAAAAAAAP//AAAAAAAA////////////////AAAAAAAAAAAAAP//AAAAAAAA////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP////////////////////8AAAAA/////wAA//8AAAAAAAAAAP//////////AAAAAP////8AAP//////////AAD//wAA/////wAA//8AAAAA/////////////////////wAAAAD/////AAD//wAAAAAAAAAA//////////8AAAAA/////wAA//////////8AAP//AAD/////AAD//wAAAAD/////////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP////////////////////8AAAAA/////wAA//8AAAAAAAAAAP//////////AAAAAP////8AAP//////////AAD//wAA/////wAA//8AAAAA/////////////////////wAAAAD/////AAD//wAAAAAAAAAA//////////8AAAAA/////wAA//////////8AAP//AAD/////AAD//wAAAAD/////////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP////////////////////8AAAAA/////wAA//8AAAAAAAAAAP//////////AAAAAP////8AAP//////////AAD//wAA/////wAA//8AAAAA/////////////////////wAAAAD/////AAD//wAAAAAAAAAA//////////8AAAAA/////wAA//////////8AAP//AAD/////AAD//wAAAAD/////////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP////////////////////8AAAAA/////wAA//8AAAAAAAAAAP//////////AAAAAP////8AAP//////////AAD//wAA/////wAA//8AAAAA/////////////////////wAAAAD/////AAD//wAAAAAAAAAA//////////8AAAAA/////wAA//////////8AAP//AAD/////AAD//wAAAAD/////////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP////////////////////8AAAAA/////wAA//8AAAAAAAAAAP//////////AAAAAP////8AAP//////////AAD//wAA/////wAA//8AAAAA/////////////////////wAAAAD/////AAD//wAAAAAAAAAA//////////8AAAAA/////wAA//////////8AAP//AAD/////AAD//wAAAAD/////////////////////AAAAAP////8AAP//AAAAAAAAAAD//////////wAAAAD/////AAD//////////wAA//8AAP////8AAP//AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA//////////////////8AAP//AAAAAAAAAAD//wAA//8AAAAA////////AAAAAP////8AAAAA//8AAAAA//8AAAAAAAD//wAA/////wAAAAD//////////////////wAA//8AAAAAAAAAAP//AAD//wAAAAD///////8AAAAA/////wAAAAD//wAAAAD//wAAAAAAAP//AAD/////AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA//////////////////8AAP//AAAAAAAAAAD//wAA//8AAAAA////////AAAAAP////8AAAAA//8AAAAA//8AAAAAAAD//wAA/////wAAAAD//////////////////wAA//8AAAAAAAAAAP//AAD//wAAAAD///////8AAAAA/////wAAAAD//wAAAAD//wAAAAAAAP//AAD/////AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA//////////////////8AAP//AAAAAAAAAAD//wAA//8AAAAA////////AAAAAP////8AAAAA//8AAAAA//8AAAAAAAD//wAA/////wAAAAD//////////////////wAA//8AAAAAAAAAAP//AAD//wAAAAD///////8AAAAA/////wAAAAD//wAAAAD//wAAAAAAAP//AAD/////AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA//////////////////8AAP//AAAAAAAAAAD//wAA//8AAAAA////////AAAAAP////8AAAAA//8AAAAA//8AAAAAAAD//wAA/////wAAAAD//////////////////wAA//8AAAAAAAAAAP//AAD//wAAAAD///////8AAAAA/////wAAAAD//wAAAAD//wAAAAAAAP//AAD/////AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA//////////////////8AAP//AAAAAAAAAAD//wAA//8AAAAA////////AAAAAP////8AAAAA//8AAAAA//8AAAAAAAD//wAA/////wAAAAD//////////////////wAA//8AAAAAAAAAAP//AAD//wAAAAD///////8AAAAA/////wAAAAD//wAAAAD//wAAAAAAAP//AAD/////AAAAAP//////////////////AAD//wAAAAAAAAAA//8AAP//AAAAAP///////wAAAAD/////AAAAAP//AAAAAP//AAAAAAAA//8AAP////8AAAAA/////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAD//wAAAAAAAP///////////////wAA/////wAA//8AAP////8AAAAA/////wAAAAD//wAAAAD//wAA/////wAAAAD///////////////8AAP//AAAAAAAA////////////////AAD/////AAD//wAA/////wAAAAD/////AAAAAP//AAAAAP//AAD/////AAAAAP///////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAD//wAAAAAAAP///////////////wAA/////wAA//8AAP////8AAAAA/////wAAAAD//wAAAAD//wAA/////wAAAAD///////////////8AAP//AAAAAAAA////////////////AAD/////AAD//wAA/////wAAAAD/////AAAAAP//AAAAAP//AAD/////AAAAAP///////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAD//wAAAAAAAP///////////////wAA/////wAA//8AAP////8AAAAA/////wAAAAD//wAAAAD//wAA/////wAAAAD///////////////8AAP//AAAAAAAA////////////////AAD/////AAD//wAA/////wAAAAD/////AAAAAP//AAAAAP//AAD/////AAAAAP///////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAD//wAAAAAAAP///////////////wAA/////wAA//8AAP////8AAAAA/////wAAAAD//wAAAAD//wAA/////wAAAAD///////////////8AAP//AAAAAAAA////////////////AAD/////AAD//wAA/////wAAAAD/////AAAAAP//AAAAAP//AAD/////AAAAAP///////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAD//wAAAAAAAP///////////////wAA/////wAA//8AAP////8AAAAA/////wAAAAD//wAAAAD//wAA/////wAAAAD///////////////8AAP//AAAAAAAA////////////////AAD/////AAD//wAA/////wAAAAD/////AAAAAP//AAAAAP//AAD/////AAAAAP///////////////wAA//8AAAAAAAD///////////////8AAP////8AAP//AAD/////AAAAAP////8AAAAA//8AAAAA//8AAP////8AAAAA////////////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAA//8AAP////8AAP////8AAAAA////////AAD///////8AAP///////wAA//////////8AAAAA//8AAAAA//8AAAAAAAD//////////wAAAAD//wAA/////wAA/////wAAAAD///////8AAP///////wAA////////AAD//////////wAAAAD//wAAAAD//wAAAAAAAP//////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAA//8AAP////8AAP////8AAAAA////////AAD///////8AAP///////wAA//////////8AAAAA//8AAAAA//8AAAAAAAD//////////wAAAAD//wAA/////wAA/////wAAAAD///////8AAP///////wAA////////AAD//////////wAAAAD//wAAAAD//wAAAAAAAP//////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAA//8AAP////8AAP////8AAAAA////////AAD///////8AAP///////wAA//////////8AAAAA//8AAAAA//8AAAAAAAD//////////wAAAAD//wAA/////wAA/////wAAAAD///////8AAP///////wAA////////AAD//////////wAAAAD//wAAAAD//wAAAAAAAP//////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAA//8AAP////8AAP////8AAAAA////////AAD///////8AAP///////wAA//////////8AAAAA//8AAAAA//8AAAAAAAD//////////wAAAAD//wAA/////wAA/////wAAAAD///////8AAP///////wAA////////AAD//////////wAAAAD//wAAAAD//wAAAAAAAP//////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAA//8AAP////8AAP////8AAAAA////////AAD///////8AAP///////wAA//////////8AAAAA//8AAAAA//8AAAAAAAD//////////wAAAAD//wAA/////wAA/////wAAAAD///////8AAP///////wAA////////AAD//////////wAAAAD//wAAAAD//wAAAAAAAP//////////AAAAAP//AAD/////AAD/////AAAAAP///////wAA////////AAD///////8AAP//////////AAAAAP//AAAAAP//AAAAAAAA//////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA/////////////wAAAAAAAP//AAAAAP////////////8AAP//AAAAAP////8AAAAA////////AAD///////8AAAAA////////AAAAAP//AAD/////////////AAAAAAAA//8AAAAA/////////////wAA//8AAAAA/////wAAAAD///////8AAP///////wAAAAD///////8AAAAA//8AAP////////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA/////////////wAAAAAAAP//AAAAAP////////////8AAP//AAAAAP////8AAAAA////////AAD///////8AAAAA////////AAAAAP//AAD/////////////AAAAAAAA//8AAAAA/////////////wAA//8AAAAA/////wAAAAD///////8AAP///////wAAAAD///////8AAAAA//8AAP////////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA/////////////wAAAAAAAP//AAAAAP////////////8AAP//AAAAAP////8AAAAA////////AAD///////8AAAAA////////AAAAAP//AAD/////////////AAAAAAAA//8AAAAA/////////////wAA//8AAAAA/////wAAAAD///////8AAP///////wAAAAD///////8AAAAA//8AAP////////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA/////////////wAAAAAAAP//AAAAAP////////////8AAP//AAAAAP////8AAAAA////////AAD///////8AAAAA////////AAAAAP//AAD/////////////AAAAAAAA//8AAAAA/////////////wAA//8AAAAA/////wAAAAD///////8AAP///////wAAAAD///////8AAAAA//8AAP////////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA/////////////wAAAAAAAP//AAAAAP////////////8AAP//AAAAAP////8AAAAA////////AAD///////8AAAAA////////AAAAAP//AAD/////////////AAAAAAAA//8AAAAA/////////////wAA//8AAAAA/////wAAAAD///////8AAP///////wAAAAD///////8AAAAA//8AAP////////////8AAAAAAAD//wAAAAD/////////////AAD//wAAAAD/////AAAAAP///////wAA////////AAAAAP///////wAAAAD//wAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD///////////////8AAAAAAAD//wAAAAD//wAA////////AAD/////AAAAAAAA/////wAA/////wAAAAAAAAAAAAD/////AAAAAAAAAAAAAP///////////////wAAAAAAAP//AAAAAP//AAD///////8AAP////8AAAAAAAD/////AAD/////AAAAAAAAAAAAAP////8AAAAAAAAAAAAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD///////////////8AAAAAAAD//wAAAAD//wAA////////AAD/////AAAAAAAA/////wAA/////wAAAAAAAAAAAAD/////AAAAAAAAAAAAAP///////////////wAAAAAAAP//AAAAAP//AAD///////8AAP////8AAAAAAAD/////AAD/////AAAAAAAAAAAAAP////8AAAAAAAAAAAAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD///////////////8AAAAAAAD//wAAAAD//wAA////////AAD/////AAAAAAAA/////wAA/////wAAAAAAAAAAAAD/////AAAAAAAAAAAAAP///////////////wAAAAAAAP//AAAAAP//AAD///////8AAP////8AAAAAAAD/////AAD/////AAAAAAAAAAAAAP////8AAAAAAAAAAAAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD///////////////8AAAAAAAD//wAAAAD//wAA////////AAD/////AAAAAAAA/////wAA/////wAAAAAAAAAAAAD/////AAAAAAAAAAAAAP///////////////wAAAAAAAP//AAAAAP//AAD///////8AAP////8AAAAAAAD/////AAD/////AAAAAAAAAAAAAP////8AAAAAAAAAAAAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD///////////////8AAAAAAAD//wAAAAD//wAA////////AAD/////AAAAAAAA/////wAA/////wAAAAAAAAAAAAD/////AAAAAAAAAAAAAP///////////////wAAAAAAAP//AAAAAP//AAD///////8AAP////8AAAAAAAD/////AAD/////AAAAAAAAAAAAAP////8AAAAAAAAAAAAA////////////////AAAAAAAA//8AAAAA//8AAP///////wAA/////wAAAAAAAP////8AAP////8AAAAAAAAAAAAA/////wAAAAAAAAAAAAD/////////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP////8AAP////////////////////8AAAAAAAAAAAAA//8AAP////8AAP//AAD/////AAAAAAAA/////wAAAAD/////AAD//////////wAA/////wAA/////////////////////wAAAAAAAAAAAAD//wAA/////wAA//8AAP////8AAAAAAAD/////AAAAAP////8AAP//////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP////8AAP////////////////////8AAAAAAAAAAAAA//8AAP////8AAP//AAD/////AAAAAAAA/////wAAAAD/////AAD//////////wAA/////wAA/////////////////////wAAAAAAAAAAAAD//wAA/////wAA//8AAP////8AAAAAAAD/////AAAAAP////8AAP//////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP////8AAP////////////////////8AAAAAAAAAAAAA//8AAP////8AAP//AAD/////AAAAAAAA/////wAAAAD/////AAD//////////wAA/////wAA/////////////////////wAAAAAAAAAAAAD//wAA/////wAA//8AAP////8AAAAAAAD/////AAAAAP////8AAP//////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP////8AAP////////////////////8AAAAAAAAAAAAA//8AAP////8AAP//AAD/////AAAAAAAA/////wAAAAD/////AAD//////////wAA/////wAA/////////////////////wAAAAAAAAAAAAD//wAA/////wAA//8AAP////8AAAAAAAD/////AAAAAP////8AAP//////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP////8AAP////////////////////8AAAAAAAAAAAAA//8AAP////8AAP//AAD/////AAAAAAAA/////wAAAAD/////AAD//////////wAA/////wAA/////////////////////wAAAAAAAAAAAAD//wAA/////wAA//8AAP////8AAAAAAAD/////AAAAAP////8AAP//////////AAD/////AAD/////////////////////AAAAAAAAAAAAAP//AAD/////AAD//wAA/////wAAAAAAAP////8AAAAA/////wAA//////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAA//////////8AAAAAAAD//wAAAAD//wAA//8AAP////8AAP///////wAAAAAAAP////8AAP//AAAAAAAAAAD//wAAAAD/////////////AAD//////////wAAAAAAAP//AAAAAP//AAD//wAA/////wAA////////AAAAAAAA/////wAA//8AAAAAAAAAAP//AAAAAP////////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAA//////////8AAAAAAAD//wAAAAD//wAA//8AAP////8AAP///////wAAAAAAAP////8AAP//AAAAAAAAAAD//wAAAAD/////////////AAD//////////wAAAAAAAP//AAAAAP//AAD//wAA/////wAA////////AAAAAAAA/////wAA//8AAAAAAAAAAP//AAAAAP////////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAA//////////8AAAAAAAD//wAAAAD//wAA//8AAP////8AAP///////wAAAAAAAP////8AAP//AAAAAAAAAAD//wAAAAD/////////////AAD//////////wAAAAAAAP//AAAAAP//AAD//wAA/////wAA////////AAAAAAAA/////wAA//8AAAAAAAAAAP//AAAAAP////////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAA//////////8AAAAAAAD//wAAAAD//wAA//8AAP////8AAP///////wAAAAAAAP////8AAP//AAAAAAAAAAD//wAAAAD/////////////AAD//////////wAAAAAAAP//AAAAAP//AAD//wAA/////wAA////////AAAAAAAA/////wAA//8AAAAAAAAAAP//AAAAAP////////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAA//////////8AAAAAAAD//wAAAAD//wAA//8AAP////8AAP///////wAAAAAAAP////8AAP//AAAAAAAAAAD//wAAAAD/////////////AAD//////////wAAAAAAAP//AAAAAP//AAD//wAA/////wAA////////AAAAAAAA/////wAA//8AAAAAAAAAAP//AAAAAP////////////8AAP//////////AAAAAAAA//8AAAAA//8AAP//AAD/////AAD///////8AAAAAAAD/////AAD//wAAAAAAAAAA//8AAAAA/////////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP//////////AAAAAAAAAAAAAAAA/////wAAAAD//wAA/////wAAAAAAAAAA//8AAAAAAAAAAAAAAAD///////8AAP//AAAAAP////8AAAAA//////////8AAAAAAAAAAAAAAAD/////AAAAAP//AAD/////AAAAAAAAAAD//wAAAAAAAAAAAAAAAP///////wAA//8AAAAA/////wAAAAD//////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP//////////AAAAAAAAAAAAAAAA/////wAAAAD//wAA/////wAAAAAAAAAA//8AAAAAAAAAAAAAAAD///////8AAP//AAAAAP////8AAAAA//////////8AAAAAAAAAAAAAAAD/////AAAAAP//AAD/////AAAAAAAAAAD//wAAAAAAAAAAAAAAAP///////wAA//8AAAAA/////wAAAAD//////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP//////////AAAAAAAAAAAAAAAA/////wAAAAD//wAA/////wAAAAAAAAAA//8AAAAAAAAAAAAAAAD///////8AAP//AAAAAP////8AAAAA//////////8AAAAAAAAAAAAAAAD/////AAAAAP//AAD/////AAAAAAAAAAD//wAAAAAAAAAAAAAAAP///////wAA//8AAAAA/////wAAAAD//////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP//////////AAAAAAAAAAAAAAAA/////wAAAAD//wAA/////wAAAAAAAAAA//8AAAAAAAAAAAAAAAD///////8AAP//AAAAAP////8AAAAA//////////8AAAAAAAAAAAAAAAD/////AAAAAP//AAD/////AAAAAAAAAAD//wAAAAAAAAAAAAAAAP///////wAA//8AAAAA/////wAAAAD//////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP//////////AAAAAAAAAAAAAAAA/////wAAAAD//wAA/////wAAAAAAAAAA//8AAAAAAAAAAAAAAAD///////8AAP//AAAAAP////8AAAAA//////////8AAAAAAAAAAAAAAAD/////AAAAAP//AAD/////AAAAAAAAAAD//wAAAAAAAAAAAAAAAP///////wAA//8AAAAA/////wAAAAD//////////wAAAAAAAAAAAAAAAP////8AAAAA//8AAP////8AAAAAAAAAAP//AAAAAAAAAAAAAAAA////////AAD//wAAAAD/////AAAAAP///////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP//////////////////////////AAD//wAAAAAAAAAAAAD///////8AAAAAAAAAAP//AAD//wAA//8AAP//AAAAAP//AAAAAP////8AAAAA//////////////////////////8AAP//AAAAAAAAAAAAAP///////wAAAAAAAAAA//8AAP//AAD//wAA//8AAAAA//8AAAAA/////wAAAAD//////////////////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP//////////////////////////AAD//wAAAAAAAAAAAAD///////8AAAAAAAAAAP//AAD//wAA//8AAP//AAAAAP//AAAAAP////8AAAAA//////////////////////////8AAP//AAAAAAAAAAAAAP///////wAAAAAAAAAA//8AAP//AAD//wAA//8AAAAA//8AAAAA/////wAAAAD//////////////////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP//////////////////////////AAD//wAAAAAAAAAAAAD///////8AAAAAAAAAAP//AAD//wAA//8AAP//AAAAAP//AAAAAP////8AAAAA//////////////////////////8AAP//AAAAAAAAAAAAAP///////wAAAAAAAAAA//8AAP//AAD//wAA//8AAAAA//8AAAAA/////wAAAAD//////////////////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP//////////////////////////AAD//wAAAAAAAAAAAAD///////8AAAAAAAAAAP//AAD//wAA//8AAP//AAAAAP//AAAAAP////8AAAAA//////////////////////////8AAP//AAAAAAAAAAAAAP///////wAAAAAAAAAA//8AAP//AAD//wAA//8AAAAA//8AAAAA/////wAAAAD//////////////////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP//////////////////////////AAD//wAAAAAAAAAAAAD///////8AAAAAAAAAAP//AAD//wAA//8AAP//AAAAAP//AAAAAP////8AAAAA//////////////////////////8AAP//AAAAAAAAAAAAAP///////wAAAAAAAAAA//8AAP//AAD//wAA//8AAAAA//8AAAAA/////wAAAAD//////////////////////////wAA//8AAAAAAAAAAAAA////////AAAAAAAAAAD//wAA//8AAP//AAD//wAAAAD//wAAAAD/////AAAAAP////////////////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////////////wAA//8AAP//AAD/////AAD//wAAAAAAAP////8AAAAAAAD///////8AAP//AAAAAAAA//8AAP////8AAP////8AAP//////////////////AAD//wAA//8AAP////8AAP//AAAAAAAA/////wAAAAAAAP///////wAA//8AAAAAAAD//wAA/////wAA/////wAA//////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////////////wAA//8AAP//AAD/////AAD//wAAAAAAAP////8AAAAAAAD///////8AAP//AAAAAAAA//8AAP////8AAP////8AAP//////////////////AAD//wAA//8AAP////8AAP//AAAAAAAA/////wAAAAAAAP///////wAA//8AAAAAAAD//wAA/////wAA/////wAA//////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////////////wAA//8AAP//AAD/////AAD//wAAAAAAAP////8AAAAAAAD///////8AAP//AAAAAAAA//8AAP////8AAP////8AAP//////////////////AAD//wAA//8AAP////8AAP//AAAAAAAA/////wAAAAAAAP///////wAA//8AAAAAAAD//wAA/////wAA/////wAA//////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////////////wAA//8AAP//AAD/////AAD//wAAAAAAAP////8AAAAAAAD///////8AAP//AAAAAAAA//8AAP////8AAP////8AAP//////////////////AAD//wAA//8AAP////8AAP//AAAAAAAA/////wAAAAAAAP///////wAA//8AAAAAAAD//wAA/////wAA/////wAA//////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////////////wAA//8AAP//AAD/////AAD//wAAAAAAAP////8AAAAAAAD///////8AAP//AAAAAAAA//8AAP////8AAP////8AAP//////////////////AAD//wAA//8AAP////8AAP//AAAAAAAA/////wAAAAAAAP///////wAA//8AAAAAAAD//wAA/////wAA/////wAA//////////////////8AAP//AAD//wAA/////wAA//8AAAAAAAD/////AAAAAAAA////////AAD//wAAAAAAAP//AAD/////AAD/////AAD//////////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA////////AAD//wAA//8AAP//AAD//wAA////////AAAAAP////8AAP////8AAAAA////////////////////////AAD/////AAAAAAAAAAD///////8AAP//AAD//wAA//8AAP//AAD///////8AAAAA/////wAA/////wAAAAD///////////////////////8AAP////8AAAAAAAAAAP///////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA////////AAD//wAA//8AAP//AAD//wAA////////AAAAAP////8AAP////8AAAAA////////////////////////AAD/////AAAAAAAAAAD///////8AAP//AAD//wAA//8AAP//AAD///////8AAAAA/////wAA/////wAAAAD///////////////////////8AAP////8AAAAAAAAAAP///////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA////////AAD//wAA//8AAP//AAD//wAA////////AAAAAP////8AAP////8AAAAA////////////////////////AAD/////AAAAAAAAAAD///////8AAP//AAD//wAA//8AAP//AAD///////8AAAAA/////wAA/////wAAAAD///////////////////////8AAP////8AAAAAAAAAAP///////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA////////AAD//wAA//8AAP//AAD//wAA////////AAAAAP////8AAP////8AAAAA////////////////////////AAD/////AAAAAAAAAAD///////8AAP//AAD//wAA//8AAP//AAD///////8AAAAA/////wAA/////wAAAAD///////////////////////8AAP////8AAAAAAAAAAP///////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA////////AAD//wAA//8AAP//AAD//wAA////////AAAAAP////8AAP////8AAAAA////////////////////////AAD/////AAAAAAAAAAD///////8AAP//AAD//wAA//8AAP//AAD///////8AAAAA/////wAA/////wAAAAD///////////////////////8AAP////8AAAAAAAAAAP///////wAA//8AAP//AAD//wAA//8AAP///////wAAAAD/////AAD/////AAAAAP///////////////////////wAA/////wAAAAAAAAAA//////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAAAAD//wAAAAD//wAAAAAAAAAA////////AAAAAP//////////AAAAAP//AAAAAP//AAD/////AAD//wAAAAD//wAAAAD/////////////AAAAAP//AAAAAP//AAAAAAAAAAD///////8AAAAA//////////8AAAAA//8AAAAA//8AAP////8AAP//AAAAAP//AAAAAP////////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAAAAD//wAAAAD//wAAAAAAAAAA////////AAAAAP//////////AAAAAP//AAAAAP//AAD/////AAD//wAAAAD//wAAAAD/////////////AAAAAP//AAAAAP//AAAAAAAAAAD///////8AAAAA//////////8AAAAA//8AAAAA//8AAP////8AAP//AAAAAP//AAAAAP////////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAAAAD//wAAAAD//wAAAAAAAAAA////////AAAAAP//////////AAAAAP//AAAAAP//AAD/////AAD//wAAAAD//wAAAAD/////////////AAAAAP//AAAAAP//AAAAAAAAAAD///////8AAAAA//////////8AAAAA//8AAAAA//8AAP////8AAP//AAAAAP//AAAAAP////////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAAAAD//wAAAAD//wAAAAAAAAAA////////AAAAAP//////////AAAAAP//AAAAAP//AAD/////AAD//wAAAAD//wAAAAD/////////////AAAAAP//AAAAAP//AAAAAAAAAAD///////8AAAAA//////////8AAAAA//8AAAAA//8AAP////8AAP//AAAAAP//AAAAAP////////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAAAAD//wAAAAD//wAAAAAAAAAA////////AAAAAP//////////AAAAAP//AAAAAP//AAD/////AAD//wAAAAD//wAAAAD/////////////AAAAAP//AAAAAP//AAAAAAAAAAD///////8AAAAA//////////8AAAAA//8AAAAA//8AAP////8AAP//AAAAAP//AAAAAP////////////8AAAAA//8AAAAA//8AAAAAAAAAAP///////wAAAAD//////////wAAAAD//wAAAAD//wAA/////wAA//8AAAAA//8AAAAA/////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA////////////////AAD///////8AAAAAAAAAAP//AAAAAP///////wAA/////wAA/////wAA//8AAP//AAD//wAA////////AAAAAAAAAAD///////////////8AAP///////wAAAAAAAAAA//8AAAAA////////AAD/////AAD/////AAD//wAA//8AAP//AAD///////8AAAAAAAAAAP///////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA////////////////AAD///////8AAAAAAAAAAP//AAAAAP///////wAA/////wAA/////wAA//8AAP//AAD//wAA////////AAAAAAAAAAD///////////////8AAP///////wAAAAAAAAAA//8AAAAA////////AAD/////AAD/////AAD//wAA//8AAP//AAD///////8AAAAAAAAAAP///////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA////////////////AAD///////8AAAAAAAAAAP//AAAAAP///////wAA/////wAA/////wAA//8AAP//AAD//wAA////////AAAAAAAAAAD///////////////8AAP///////wAAAAAAAAAA//8AAAAA////////AAD/////AAD/////AAD//wAA//8AAP//AAD///////8AAAAAAAAAAP///////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA////////////////AAD///////8AAAAAAAAAAP//AAAAAP///////wAA/////wAA/////wAA//8AAP//AAD//wAA////////AAAAAAAAAAD///////////////8AAP///////wAAAAAAAAAA//8AAAAA////////AAD/////AAD/////AAD//wAA//8AAP//AAD///////8AAAAAAAAAAP///////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA////////////////AAD///////8AAAAAAAAAAP//AAAAAP///////wAA/////wAA/////wAA//8AAP//AAD//wAA////////AAAAAAAAAAD///////////////8AAP///////wAAAAAAAAAA//8AAAAA////////AAD/////AAD/////AAD//wAA//8AAP//AAD///////8AAAAAAAAAAP///////////////wAA////////AAAAAAAAAAD//wAAAAD///////8AAP////8AAP////8AAP//AAD//wAA//8AAP///////wAAAAAAAAAA//////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA/////////////////////wAAAAAAAP////8AAAAA/////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP///////wAAAAD/////////////////////AAAAAAAA/////wAAAAD/////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA////////AAAAAP////////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA/////////////////////wAAAAAAAP////8AAAAA/////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP///////wAAAAD/////////////////////AAAAAAAA/////wAAAAD/////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA////////AAAAAP////////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA/////////////////////wAAAAAAAP////8AAAAA/////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP///////wAAAAD/////////////////////AAAAAAAA/////wAAAAD/////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA////////AAAAAP////////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA/////////////////////wAAAAAAAP////8AAAAA/////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP///////wAAAAD/////////////////////AAAAAAAA/////wAAAAD/////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA////////AAAAAP////////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA/////////////////////wAAAAAAAP////8AAAAA/////wAAAAAAAP//AAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP///////wAAAAD/////////////////////AAAAAAAA/////wAAAAD/////AAAAAAAA//8AAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA////////AAAAAP////////////////////8AAAAAAAD/////AAAAAP////8AAAAAAAD//wAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD///////8AAAAA////////////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD///////8AAP////8AAP////8AAAAAAAAAAP//AAD//wAAAAAAAAAAAAD//wAAAAAAAAAA//8AAP//////////AAAAAP////8AAAAAAAAAAP///////wAA/////wAA/////wAAAAAAAAAA//8AAP//AAAAAAAAAAAAAP//AAAAAAAAAAD//wAA//////////8AAAAA/////wAAAAAAAAAA////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD///////8AAP////8AAP////8AAAAAAAAAAP//AAD//wAAAAAAAAAAAAD//wAAAAAAAAAA//8AAP//////////AAAAAP////8AAAAAAAAAAP///////wAA/////wAA/////wAAAAAAAAAA//8AAP//AAAAAAAAAAAAAP//AAAAAAAAAAD//wAA//////////8AAAAA/////wAAAAAAAAAA////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD///////8AAP////8AAP////8AAAAAAAAAAP//AAD//wAAAAAAAAAAAAD//wAAAAAAAAAA//8AAP//////////AAAAAP////8AAAAAAAAAAP///////wAA/////wAA/////wAAAAAAAAAA//8AAP//AAAAAAAAAAAAAP//AAAAAAAAAAD//wAA//////////8AAAAA/////wAAAAAAAAAA////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD///////8AAP////8AAP////8AAAAAAAAAAP//AAD//wAAAAAAAAAAAAD//wAAAAAAAAAA//8AAP//////////AAAAAP////8AAAAAAAAAAP///////wAA/////wAA/////wAAAAAAAAAA//8AAP//AAAAAAAAAAAAAP//AAAAAAAAAAD//wAA//////////8AAAAA/////wAAAAAAAAAA////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD///////8AAP////8AAP////8AAAAAAAAAAP//AAD//wAAAAAAAAAAAAD//wAAAAAAAAAA//8AAP//////////AAAAAP////8AAAAAAAAAAP///////wAA/////wAA/////wAAAAAAAAAA//8AAP//AAAAAAAAAAAAAP//AAAAAAAAAAD//wAA//////////8AAAAA/////wAAAAAAAAAA////////AAD/////AAD/////AAAAAAAAAAD//wAA//8AAAAAAAAAAAAA//8AAAAAAAAAAP//AAD//////////wAAAAD/////AAAAAAAAAAD/////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD///////////////8AAP////////////8AAP////8AAAAAAAAAAP////8AAAAA/////wAA//8AAAAA/////////////wAA////////AAAAAP///////////////wAA/////////////wAA/////wAAAAAAAAAA/////wAAAAD/////AAD//wAAAAD/////////////AAD///////8AAAAA////////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD///////////////8AAP////////////8AAP////8AAAAAAAAAAP////8AAAAA/////wAA//8AAAAA/////////////wAA////////AAAAAP///////////////wAA/////////////wAA/////wAAAAAAAAAA/////wAAAAD/////AAD//wAAAAD/////////////AAD///////8AAAAA////////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD///////////////8AAP////////////8AAP////8AAAAAAAAAAP////8AAAAA/////wAA//8AAAAA/////////////wAA////////AAAAAP///////////////wAA/////////////wAA/////wAAAAAAAAAA/////wAAAAD/////AAD//wAAAAD/////////////AAD///////8AAAAA////////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD///////////////8AAP////////////8AAP////8AAAAAAAAAAP////8AAAAA/////wAA//8AAAAA/////////////wAA////////AAAAAP///////////////wAA/////////////wAA/////wAAAAAAAAAA/////wAAAAD/////AAD//wAAAAD/////////////AAD///////8AAAAA////////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD///////////////8AAP////////////8AAP////8AAAAAAAAAAP////8AAAAA/////wAA//8AAAAA/////////////wAA////////AAAAAP///////////////wAA/////////////wAA/////wAAAAAAAAAA/////wAAAAD/////AAD//wAAAAD/////////////AAD///////8AAAAA////////////////AAD/////////////AAD/////AAAAAAAAAAD/////AAAAAP////8AAP//AAAAAP////////////8AAP///////wAAAAD//////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////////////AAAAAAAAAAAAAP////8AAAAAAAD//wAA//8AAP//AAD//wAAAAAAAAAA//8AAP//AAAAAAAA//8AAAAA//8AAP////////////////////8AAAAAAAAAAAAA/////wAAAAAAAP//AAD//wAA//8AAP//AAAAAAAAAAD//wAA//8AAAAAAAD//wAAAAD//wAA/////////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////////////AAAAAAAAAAAAAP////8AAAAAAAD//wAA//8AAP//AAD//wAAAAAAAAAA//8AAP//AAAAAAAA//8AAAAA//8AAP////////////////////8AAAAAAAAAAAAA/////wAAAAAAAP//AAD//wAA//8AAP//AAAAAAAAAAD//wAA//8AAAAAAAD//wAAAAD//wAA/////////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////////////AAAAAAAAAAAAAP////8AAAAAAAD//wAA//8AAP//AAD//wAAAAAAAAAA//8AAP//AAAAAAAA//8AAAAA//8AAP////////////////////8AAAAAAAAAAAAA/////wAAAAAAAP//AAD//wAA//8AAP//AAAAAAAAAAD//wAA//8AAAAAAAD//wAAAAD//wAA/////////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////////////AAAAAAAAAAAAAP////8AAAAAAAD//wAA//8AAP//AAD//wAAAAAAAAAA//8AAP//AAAAAAAA//8AAAAA//8AAP////////////////////8AAAAAAAAAAAAA/////wAAAAAAAP//AAD//wAA//8AAP//AAAAAAAAAAD//wAA//8AAAAAAAD//wAAAAD//wAA/////////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////////////AAAAAAAAAAAAAP////8AAAAAAAD//wAA//8AAP//AAD//wAAAAAAAAAA//8AAP//AAAAAAAA//8AAAAA//8AAP////////////////////8AAAAAAAAAAAAA/////wAAAAAAAP//AAD//wAA//8AAP//AAAAAAAAAAD//wAA//8AAAAAAAD//wAAAAD//wAA/////////////////////wAAAAAAAAAAAAD/////AAAAAAAA//8AAP//AAD//wAA//8AAAAAAAAAAP//AAD//wAAAAAAAP//AAAAAP//AAD/////////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAAAA//8AAP//AAD/////AAAAAP//////////AAD//wAA/////wAAAAAAAP//AAD//wAAAAAAAAAAAAD/////AAAAAP//AAD//////////wAAAAD//wAA//8AAP////8AAAAA//////////8AAP//AAD/////AAAAAAAA//8AAP//AAAAAAAAAAAAAP////8AAAAA//8AAP//////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAAAA//8AAP//AAD/////AAAAAP//////////AAD//wAA/////wAAAAAAAP//AAD//wAAAAAAAAAAAAD/////AAAAAP//AAD//////////wAAAAD//wAA//8AAP////8AAAAA//////////8AAP//AAD/////AAAAAAAA//8AAP//AAAAAAAAAAAAAP////8AAAAA//8AAP//////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAAAA//8AAP//AAD/////AAAAAP//////////AAD//wAA/////wAAAAAAAP//AAD//wAAAAAAAAAAAAD/////AAAAAP//AAD//////////wAAAAD//wAA//8AAP////8AAAAA//////////8AAP//AAD/////AAAAAAAA//8AAP//AAAAAAAAAAAAAP////8AAAAA//8AAP//////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAAAA//8AAP//AAD/////AAAAAP//////////AAD//wAA/////wAAAAAAAP//AAD//wAAAAAAAAAAAAD/////AAAAAP//AAD//////////wAAAAD//wAA//8AAP////8AAAAA//////////8AAP//AAD/////AAAAAAAA//8AAP//AAAAAAAAAAAAAP////8AAAAA//8AAP//////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAAAA//8AAP//AAD/////AAAAAP//////////AAD//wAA/////wAAAAAAAP//AAD//wAAAAAAAAAAAAD/////AAAAAP//AAD//////////wAAAAD//wAA//8AAP////8AAAAA//////////8AAP//AAD/////AAAAAAAA//8AAP//AAAAAAAAAAAAAP////8AAAAA//8AAP//////////AAAAAP//AAD//wAA/////wAAAAD//////////wAA//8AAP////8AAAAAAAD//wAA//8AAAAAAAAAAAAA/////wAAAAD//wAA//////////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP///////wAA////////AAD//wAAAAAAAAAAAAD//wAA/////////////wAAAAD//wAAAAAAAP//////////AAAAAAAAAAAAAAAA/////wAA////////AAD///////8AAP//AAAAAAAAAAAAAP//AAD/////////////AAAAAP//AAAAAAAA//////////8AAAAAAAAAAAAAAAD/////AAD///////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP///////wAA////////AAD//wAAAAAAAAAAAAD//wAA/////////////wAAAAD//wAAAAAAAP//////////AAAAAAAAAAAAAAAA/////wAA////////AAD///////8AAP//AAAAAAAAAAAAAP//AAD/////////////AAAAAP//AAAAAAAA//////////8AAAAAAAAAAAAAAAD/////AAD///////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP///////wAA////////AAD//wAAAAAAAAAAAAD//wAA/////////////wAAAAD//wAAAAAAAP//////////AAAAAAAAAAAAAAAA/////wAA////////AAD///////8AAP//AAAAAAAAAAAAAP//AAD/////////////AAAAAP//AAAAAAAA//////////8AAAAAAAAAAAAAAAD/////AAD///////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP///////wAA////////AAD//wAAAAAAAAAAAAD//wAA/////////////wAAAAD//wAAAAAAAP//////////AAAAAAAAAAAAAAAA/////wAA////////AAD///////8AAP//AAAAAAAAAAAAAP//AAD/////////////AAAAAP//AAAAAAAA//////////8AAAAAAAAAAAAAAAD/////AAD///////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP///////wAA////////AAD//wAAAAAAAAAAAAD//wAA/////////////wAAAAD//wAAAAAAAP//////////AAAAAAAAAAAAAAAA/////wAA////////AAD///////8AAP//AAAAAAAAAAAAAP//AAD/////////////AAAAAP//AAAAAAAA//////////8AAAAAAAAAAAAAAAD/////AAD///////8AAP///////wAA//8AAAAAAAAAAAAA//8AAP////////////8AAAAA//8AAAAAAAD//////////wAAAAAAAAAAAAAAAP////8AAP////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA/////////////////////////////////////////////////////wAAAAAAAAAAAAAAAP///////wAAAAD//wAAAAD//wAAAAD/////AAD/////////////////////////////////////////////////////AAAAAAAAAAAAAAAA////////AAAAAP//AAAAAP//AAAAAP////8AAP////////////////////////////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA/////////////////////////////////////////////////////wAAAAAAAAAAAAAAAP///////wAAAAD//wAAAAD//wAAAAD/////AAD/////////////////////////////////////////////////////AAAAAAAAAAAAAAAA////////AAAAAP//AAAAAP//AAAAAP////8AAP////////////////////////////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA/////////////////////////////////////////////////////wAAAAAAAAAAAAAAAP///////wAAAAD//wAAAAD//wAAAAD/////AAD/////////////////////////////////////////////////////AAAAAAAAAAAAAAAA////////AAAAAP//AAAAAP//AAAAAP////8AAP////////////////////////////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA/////////////////////////////////////////////////////wAAAAAAAAAAAAAAAP///////wAAAAD//wAAAAD//wAAAAD/////AAD/////////////////////////////////////////////////////AAAAAAAAAAAAAAAA////////AAAAAP//AAAAAP//AAAAAP////8AAP////////////////////////////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA/////////////////////////////////////////////////////wAAAAAAAAAAAAAAAP///////wAAAAD//wAAAAD//wAAAAD/////AAD/////////////////////////////////////////////////////AAAAAAAAAAAAAAAA////////AAAAAP//AAAAAP//AAAAAP////8AAP////////////////////////////////////////////////////8AAAAAAAAAAAAAAAD///////8AAAAA//8AAAAA//8AAAAA/////wAA////////////////////////////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//wAA//8AAP//AAAAAAAAAAAAAAAAAAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA//8AAAAAAAAAAP//AAAAAP//AAD//wAAAAD/////AAD///////8AAP//AAD//wAA/////////////wAA////////AAD/////////////AAD//wAAAAAAAAAA//8AAAAA//8AAP//AAAAAP////8AAP///////wAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA//8AAAAAAAAAAP//AAAAAP//AAD//wAAAAD/////AAD///////8AAP//AAD//wAA/////////////wAA////////AAD/////////////AAD//wAAAAAAAAAA//8AAAAA//8AAP//AAAAAP////8AAP///////wAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA//8AAAAAAAAAAP//AAAAAP//AAD//wAAAAD/////AAD///////8AAP//AAD//wAA/////////////wAA////////AAD/////////////AAD//wAAAAAAAAAA//8AAAAA//8AAP//AAAAAP////8AAP///////wAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA//8AAAAAAAAAAP//AAAAAP//AAD//wAAAAD/////AAD///////8AAP//AAD//wAA/////////////wAA////////AAD/////////////AAD//wAAAAAAAAAA//8AAAAA//8AAP//AAAAAP////8AAP///////wAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA//8AAAAAAAAAAP//AAAAAP//AAD//wAAAAD/////AAD///////8AAP//AAD//wAA/////////////wAA////////AAD/////////////AAD//wAAAAAAAAAA//8AAAAA//8AAP//AAAAAP////8AAP///////wAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP//AAAAAAAAAAD//wAAAAD//wAA//8AAAAA/////wAA////////AAD//wAA//8AAP////////////8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAP//AAAAAAAA/////////////wAA/////wAA//8AAP//AAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAA//8AAAAAAAD/////////////AAD/////AAD//wAA//8AAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAP//AAAAAAAA/////////////wAA/////wAA//8AAP//AAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAA//8AAAAAAAD/////////////AAD/////AAD//wAA//8AAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAP//AAAAAAAA/////////////wAA/////wAA//8AAP//AAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAA//8AAAAAAAD/////////////AAD/////AAD//wAA//8AAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAP//AAAAAAAA/////////////wAA/////wAA//8AAP//AAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAA//8AAAAAAAD/////////////AAD/////AAD//wAA//8AAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAAAAAAAP//AAAAAAAA/////////////wAA/////wAA//8AAP//AAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAAAAAAA//8AAAAAAAD/////////////AAD/////AAD//wAA//8AAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAAAAAAD//wAAAAAAAP////////////8AAP////8AAP//AAD//wAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAD///////8AAAAAAAD///////8AAAAAAAD/////AAAAAAAAAAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAP///////wAAAAAAAP///////wAAAAAAAP////8AAAAAAAAAAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAD///////8AAAAAAAD///////8AAAAAAAD/////AAAAAAAAAAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAP///////wAAAAAAAP///////wAAAAAAAP////8AAAAAAAAAAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAD///////8AAAAAAAD///////8AAAAAAAD/////AAAAAAAAAAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAP///////wAAAAAAAP///////wAAAAAAAP////8AAAAAAAAAAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAD///////8AAAAAAAD///////8AAAAAAAD/////AAAAAAAAAAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAP///////wAAAAAAAP///////wAAAAAAAP////8AAAAAAAAAAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP//AAD///////8AAAAAAAD///////8AAAAAAAD/////AAAAAAAAAAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA//8AAP///////wAAAAAAAP///////wAAAAAAAP////8AAAAAAAAAAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD//wAA////////AAAAAAAA////////AAAAAAAA/////wAAAAAAAAAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA/////////////wAA//8AAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD/////////////AAD//wAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA/////////////wAA//8AAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD/////////////AAD//wAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA/////////////wAA//8AAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD/////////////AAD//wAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA/////////////wAA//8AAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD/////////////AAD//wAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA//8AAAAAAAD//wAA/////////////wAA//8AAAAAAAAAAAAAAAAAAAAA//////////8AAAAAAAD//wAA//8AAAAAAAD//wAA////////AAD//wAAAAAAAP//AAD/////////////AAD//wAAAAAAAAAAAAAAAAAAAAD//////////wAAAAAAAP//AAD//wAAAAAAAP//AAD///////8AAP//AAAAAAAA//8AAP////////////8AAP//AAAAAAAAAAAAAAAAAAAAAP//////////AAAAAAAA//8AAP//AAAAAAAA//8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAD/////////////AAD/////AAD//wAAAAAAAAAA/////wAA/////wAAAAD/////AAAAAAAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP////8AAP//AAAAAAAAAAD/////AAD/////AAAAAP////8AAAAAAAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAD/////////////AAD/////AAD//wAAAAAAAAAA/////wAA/////wAAAAD/////AAAAAAAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP////8AAP//AAAAAAAAAAD/////AAD/////AAAAAP////8AAAAAAAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAD/////////////AAD/////AAD//wAAAAAAAAAA/////wAA/////wAAAAD/////AAAAAAAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP////8AAP//AAAAAAAAAAD/////AAD/////AAAAAP////8AAAAAAAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAD/////////////AAD/////AAD//wAAAAAAAAAA/////wAA/////wAAAAD/////AAAAAAAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP////8AAP//AAAAAAAAAAD/////AAD/////AAAAAP////8AAAAAAAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAD/////////////AAD/////AAD//wAAAAAAAAAA/////wAA/////wAAAAD/////AAAAAAAA//8AAP//AAD/////////////AAD///////8AAP////////////8AAP////8AAP//AAAAAAAAAAD/////AAD/////AAAAAP////8AAAAAAAD//wAA//8AAP////////////8AAP///////wAA/////////////wAA/////wAA//8AAAAAAAAAAP////8AAP////8AAAAA/////wAAAAAAAP//AAD//wAA/////////////wAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAA/////wAAAAAAAAAA/////wAAAAD///////8AAAAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAAAAD//wAAAAD/////AAAAAAAAAAD/////AAAAAP///////wAAAAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAA/////wAAAAAAAAAA/////wAAAAD///////8AAAAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAAAAD//wAAAAD/////AAAAAAAAAAD/////AAAAAP///////wAAAAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAA/////wAAAAAAAAAA/////wAAAAD///////8AAAAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAAAAD//wAAAAD/////AAAAAAAAAAD/////AAAAAP///////wAAAAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAA/////wAAAAAAAAAA/////wAAAAD///////8AAAAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAAAAD//wAAAAD/////AAAAAAAAAAD/////AAAAAP///////wAAAAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD///////8AAAAAAAAAAAAAAAAAAP//AAAAAAAA//8AAAAA/////wAAAAAAAAAA/////wAAAAD///////8AAAAA//8AAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAA//8AAAAAAAD//wAAAAD/////AAAAAAAAAAD/////AAAAAP///////wAAAAD//wAAAAAAAAAAAAAAAAAA////////AAAAAAAAAAAAAAAAAAD//wAAAAAAAP//AAAAAP////8AAAAAAAAAAP////8AAAAA////////AAAAAP//AAAAAAAAAAAAAAAAAAD/////////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAD///////////////////////////////////////////////////////////////////////////////////////////////////////8AAP///////////////////////////////////////////////////////////////////////////////////////////////////////wAA////////////////////////////////////////////////////////////////////////////////////////////////////////AAA=")]
public void ToMonochromeBitmap_CreatesValidBitmap(
string stubText,
int stubEccOrdinal,
int stubBorder,
int stubScale,
string expectedBitmapBase64)
{
var stubEcc = EccFromOrdinal(stubEccOrdinal);
var qrCode = QrCode.EncodeText(stubText, stubEcc);
var actualBitmap = qrCode.ToBmpBitmap(stubBorder, stubScale);
var actualBase64 = Convert.ToBase64String(actualBitmap);
Assert.Equal(expectedBitmapBase64, actualBase64);
}
}
}
================================================
FILE: QrCodeGeneratorTest/QrCodeDataProvider.cs
================================================
/*
* QR code generator library (.NET)
*
* Copyright (c) Manuel Bleichenbacher (MIT License)
* https://github.com/manuelbl/QrCodeGenerator
* Copyright (c) Project Nayuki (MIT License)
* https://www.nayuki.io/page/qr-code-generator-library
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
using System.Collections;
using System.Collections.Generic;
using static Net.Codecrete.QrCodeGenerator.QrCode;
namespace Net.Codecrete.QrCodeGenerator.Test
{
public class QrCodeDataProvider : IEnumerable