mirror of
https://github.com/abdelkader/vCardEditor
synced 2025-12-12 08:27:19 +07:00
QR Code Draft
This commit is contained in:
78
vCardEditor/Libs/QRCoder/ASCIIQRCode.cs
Normal file
78
vCardEditor/Libs/QRCoder/ASCIIQRCode.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
public class AsciiQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public AsciiQRCode() { }
|
||||
|
||||
public AsciiQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a strings that contains the resulting QR code as ASCII chars.
|
||||
/// </summary>
|
||||
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
|
||||
/// <param name="darkColorString">String for use as dark color modules. In case of string make sure whiteSpaceString has the same length.</param>
|
||||
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
|
||||
/// <param name="endOfLine">End of line separator. (Default: \n)</param>
|
||||
/// <returns></returns>
|
||||
public string GetGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true, string endOfLine = "\n")
|
||||
{
|
||||
return string.Join(endOfLine, GetLineByLineGraphic(repeatPerModule, darkColorString, whiteSpaceString, drawQuietZones));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array of strings that contains each line of the resulting QR code as ASCII chars.
|
||||
/// </summary>
|
||||
/// <param name="repeatPerModule">Number of repeated darkColorString/whiteSpaceString per module.</param>
|
||||
/// <param name="darkColorString">String for use as dark color modules. In case of string make sure whiteSpaceString has the same length.</param>
|
||||
/// <param name="whiteSpaceString">String for use as white modules (whitespace). In case of string make sure darkColorString has the same length.</param>
|
||||
/// <returns></returns>
|
||||
public string[] GetLineByLineGraphic(int repeatPerModule, string darkColorString = "██", string whiteSpaceString = " ", bool drawQuietZones = true)
|
||||
{
|
||||
var qrCode = new List<string>();
|
||||
//We need to adjust the repeatPerModule based on number of characters in darkColorString
|
||||
//(we assume whiteSpaceString has the same number of characters)
|
||||
//to keep the QR code as square as possible.
|
||||
var quietZonesModifier = (drawQuietZones ? 0 : 8);
|
||||
var quietZonesOffset = (int)(quietZonesModifier * 0.5);
|
||||
var adjustmentValueForNumberOfCharacters = darkColorString.Length / 2 != 1 ? darkColorString.Length / 2 : 0;
|
||||
var verticalNumberOfRepeats = repeatPerModule + adjustmentValueForNumberOfCharacters;
|
||||
var sideLength = (QrCodeData.ModuleMatrix.Count - quietZonesModifier) * verticalNumberOfRepeats;
|
||||
for (var y = 0; y < sideLength; y++)
|
||||
{
|
||||
var lineBuilder = new StringBuilder();
|
||||
for (var x = 0; x < QrCodeData.ModuleMatrix.Count - quietZonesModifier; x++)
|
||||
{
|
||||
var module = QrCodeData.ModuleMatrix[x + quietZonesOffset][((y + verticalNumberOfRepeats) / verticalNumberOfRepeats - 1)+quietZonesOffset];
|
||||
for (var i = 0; i < repeatPerModule; i++)
|
||||
{
|
||||
lineBuilder.Append(module ? darkColorString : whiteSpaceString);
|
||||
}
|
||||
}
|
||||
qrCode.Add(lineBuilder.ToString());
|
||||
}
|
||||
return qrCode.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class AsciiQRCodeHelper
|
||||
{
|
||||
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorString, string whiteSpaceString, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, string endOfLine = "\n", bool drawQuietZones = true)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new AsciiQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorString, whiteSpaceString, drawQuietZones, endOfLine);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
vCardEditor/Libs/QRCoder/AbstractQRCode.cs
Normal file
28
vCardEditor/Libs/QRCoder/AbstractQRCode.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace QRCoder
|
||||
{
|
||||
public abstract class AbstractQRCode
|
||||
{
|
||||
protected QRCodeData QrCodeData { get; set; }
|
||||
|
||||
protected AbstractQRCode() {
|
||||
}
|
||||
|
||||
protected AbstractQRCode(QRCodeData data) {
|
||||
this.QrCodeData = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set a QRCodeData object that will be used to generate QR code. Used in COM Objects connections
|
||||
/// </summary>
|
||||
/// <param name="data">Need a QRCodeData object generated by QRCodeGenerator.CreateQrCode()</param>
|
||||
virtual public void SetQRCodeData(QRCodeData data) {
|
||||
this.QrCodeData = data;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.QrCodeData?.Dispose();
|
||||
this.QrCodeData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
298
vCardEditor/Libs/QRCoder/ArtQRCode.cs
Normal file
298
vCardEditor/Libs/QRCoder/ArtQRCode.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0 || NET6_0_WINDOWS
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using static QRCoder.ArtQRCode;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
// pull request raised to extend library used.
|
||||
namespace QRCoder
|
||||
{
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class ArtQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public ArtQRCode() { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates new ArtQrCode object
|
||||
/// </summary>
|
||||
/// <param name="data">QRCodeData generated by the QRCodeGenerator</param>
|
||||
public ArtQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
/// <summary>
|
||||
/// Renders an art-style QR code with dots as modules. (With default settings: DarkColor=Black, LightColor=White, Background=Transparent, QuietZone=true)
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">Amount of px each dark/light module of the QR code shall take place in the final QR code image</param>
|
||||
/// <returns>QRCode graphic as bitmap</returns>
|
||||
public Bitmap GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
return this.GetGraphic(pixelsPerModule, Color.Black, Color.White, Color.Transparent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders an art-style QR code with dots as modules and a background image (With default settings: DarkColor=Black, LightColor=White, Background=Transparent, QuietZone=true)
|
||||
/// </summary>
|
||||
/// <param name="backgroundImage">A bitmap object that will be used as background picture</param>
|
||||
/// <returns>QRCode graphic as bitmap</returns>
|
||||
public Bitmap GetGraphic(Bitmap backgroundImage = null)
|
||||
{
|
||||
return this.GetGraphic(10, Color.Black, Color.White, Color.Transparent, backgroundImage: backgroundImage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renders an art-style QR code with dots as modules and various user settings
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">Amount of px each dark/light module of the QR code shall take place in the final QR code image</param>
|
||||
/// <param name="darkColor">Color of the dark modules</param>
|
||||
/// <param name="lightColor">Color of the light modules</param>
|
||||
/// <param name="backgroundColor">Color of the background</param>
|
||||
/// <param name="backgroundImage">A bitmap object that will be used as background picture</param>
|
||||
/// <param name="pixelSizeFactor">Value between 0.0 to 1.0 that defines how big the module dots are. The bigger the value, the less round the dots will be.</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="quietZoneRenderingStyle">Style of the quiet zones</param>
|
||||
/// <param name="backgroundImageStyle">Style of the background image (if set). Fill=spanning complete graphic; DataAreaOnly=Don't paint background into quietzone</param>
|
||||
/// <param name="finderPatternImage">Optional image that should be used instead of the default finder patterns</param>
|
||||
/// <returns>QRCode graphic as bitmap</returns>
|
||||
public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Color backgroundColor, Bitmap backgroundImage = null, double pixelSizeFactor = 0.8,
|
||||
bool drawQuietZones = true, QuietZoneStyle quietZoneRenderingStyle = QuietZoneStyle.Dotted,
|
||||
BackgroundImageStyle backgroundImageStyle = BackgroundImageStyle.DataAreaOnly, Bitmap finderPatternImage = null)
|
||||
{
|
||||
if (pixelSizeFactor > 1)
|
||||
throw new Exception("The parameter pixelSize must be between 0 and 1. (0-100%)");
|
||||
int pixelSize = (int)Math.Min(pixelsPerModule, Math.Floor(pixelsPerModule / pixelSizeFactor));
|
||||
|
||||
var numModules = QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8);
|
||||
var offset = (drawQuietZones ? 0 : 4);
|
||||
var size = numModules * pixelsPerModule;
|
||||
|
||||
var bitmap = new Bitmap(size, size);
|
||||
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
using (var lightBrush = new SolidBrush(lightColor))
|
||||
{
|
||||
using (var darkBrush = new SolidBrush(darkColor))
|
||||
{
|
||||
// make background transparent
|
||||
using (var brush = new SolidBrush(backgroundColor))
|
||||
graphics.FillRectangle(brush, new Rectangle(0, 0, size, size));
|
||||
//Render background if set
|
||||
if (backgroundImage != null)
|
||||
{
|
||||
if (backgroundImageStyle == BackgroundImageStyle.Fill)
|
||||
graphics.DrawImage(Resize(backgroundImage, size), 0, 0);
|
||||
else if (backgroundImageStyle == BackgroundImageStyle.DataAreaOnly)
|
||||
{
|
||||
var bgOffset = 4 - offset;
|
||||
graphics.DrawImage(Resize(backgroundImage, size - (2 * bgOffset * pixelsPerModule)), 0 + (bgOffset * pixelsPerModule), (bgOffset * pixelsPerModule));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var darkModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, darkBrush);
|
||||
var lightModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, lightBrush);
|
||||
|
||||
for (var x = 0; x < numModules; x += 1)
|
||||
{
|
||||
for (var y = 0; y < numModules; y += 1)
|
||||
{
|
||||
var rectangleF = new Rectangle(x * pixelsPerModule, y * pixelsPerModule, pixelsPerModule, pixelsPerModule);
|
||||
|
||||
var pixelIsDark = this.QrCodeData.ModuleMatrix[offset + y][offset + x];
|
||||
var solidBrush = pixelIsDark ? darkBrush : lightBrush;
|
||||
var pixelImage = pixelIsDark ? darkModulePixel : lightModulePixel;
|
||||
|
||||
if (!IsPartOfFinderPattern(x, y, numModules, offset))
|
||||
if (drawQuietZones && quietZoneRenderingStyle == QuietZoneStyle.Flat && IsPartOfQuietZone(x, y, numModules))
|
||||
graphics.FillRectangle(solidBrush, rectangleF);
|
||||
else
|
||||
graphics.DrawImage(pixelImage, rectangleF);
|
||||
else if (finderPatternImage == null)
|
||||
graphics.FillRectangle(solidBrush, rectangleF);
|
||||
}
|
||||
}
|
||||
if (finderPatternImage != null)
|
||||
{
|
||||
var finderPatternSize = 7 * pixelsPerModule;
|
||||
graphics.DrawImage(finderPatternImage, new Rectangle(0, 0, finderPatternSize, finderPatternSize));
|
||||
graphics.DrawImage(finderPatternImage, new Rectangle(size - finderPatternSize, 0, finderPatternSize, finderPatternSize));
|
||||
graphics.DrawImage(finderPatternImage, new Rectangle(0, size - finderPatternSize, finderPatternSize, finderPatternSize));
|
||||
}
|
||||
graphics.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the pixelSize is bigger than the pixelsPerModule or may end up filling the Module making a traditional QR code.
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">Pixels used per module rendered</param>
|
||||
/// <param name="pixelSize">Size of the dots</param>
|
||||
/// <param name="brush">Color of the pixels</param>
|
||||
/// <returns></returns>
|
||||
private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush)
|
||||
{
|
||||
// draw a dot
|
||||
var bitmap = new Bitmap(pixelSize, pixelSize);
|
||||
using (var graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
graphics.FillEllipse(brush, new Rectangle(0, 0, pixelSize, pixelSize));
|
||||
graphics.Save();
|
||||
}
|
||||
|
||||
var pixelWidth = Math.Min(pixelsPerModule, pixelSize);
|
||||
var margin = Math.Max((pixelsPerModule - pixelWidth) / 2, 0);
|
||||
|
||||
// center the dot in the module and crop to stay the right size.
|
||||
var cropped = new Bitmap(pixelsPerModule, pixelsPerModule);
|
||||
using (var graphics = Graphics.FromImage(cropped))
|
||||
{
|
||||
graphics.DrawImage(bitmap, new Rectangle(margin, margin, pixelWidth, pixelWidth),
|
||||
new RectangleF(((float)pixelSize - pixelWidth) / 2, ((float)pixelSize - pixelWidth) / 2, pixelWidth, pixelWidth),
|
||||
GraphicsUnit.Pixel);
|
||||
graphics.Save();
|
||||
}
|
||||
|
||||
return cropped;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given module(-position) is part of the quietzone of a QR code
|
||||
/// </summary>
|
||||
/// <param name="x">X position</param>
|
||||
/// <param name="y">Y position</param>
|
||||
/// <param name="numModules">Total number of modules per row</param>
|
||||
/// <returns>true, if position is part of quiet zone</returns>
|
||||
private bool IsPartOfQuietZone(int x, int y, int numModules)
|
||||
{
|
||||
return
|
||||
x < 4 || //left
|
||||
y < 4 || //top
|
||||
x > numModules - 5 || //right
|
||||
y > numModules - 5; //bottom
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given module(-position) is part of one of the three finder patterns of a QR code
|
||||
/// </summary>
|
||||
/// <param name="x">X position</param>
|
||||
/// <param name="y">Y position</param>
|
||||
/// <param name="numModules">Total number of modules per row</param>
|
||||
/// <param name="offset">Offset in modules (usually depending on drawQuietZones parameter)</param>
|
||||
/// <returns>true, if position is part of any finder pattern</returns>
|
||||
private bool IsPartOfFinderPattern(int x, int y, int numModules, int offset)
|
||||
{
|
||||
var cornerSize = 11 - offset;
|
||||
var outerLimitLow = (numModules - cornerSize - 1);
|
||||
var outerLimitHigh = outerLimitLow + 8;
|
||||
var invertedOffset = 4 - offset;
|
||||
return
|
||||
(x >= invertedOffset && x < cornerSize && y >= invertedOffset && y < cornerSize) || //Top-left finder pattern
|
||||
(x > outerLimitLow && x < outerLimitHigh && y >= invertedOffset && y < cornerSize) || //Top-right finder pattern
|
||||
(x >= invertedOffset && x < cornerSize && y > outerLimitLow && y < outerLimitHigh); //Bottom-left finder pattern
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resize to a square bitmap, but maintain the aspect ratio by padding transparently.
|
||||
/// </summary>
|
||||
/// <param name="image"></param>
|
||||
/// <param name="newSize"></param>
|
||||
/// <returns>Resized image as bitmap</returns>
|
||||
private Bitmap Resize(Bitmap image, int newSize)
|
||||
{
|
||||
if (image == null) return null;
|
||||
|
||||
float scale = Math.Min((float)newSize / image.Width, (float)newSize / image.Height);
|
||||
var scaledWidth = (int)(image.Width * scale);
|
||||
var scaledHeight = (int)(image.Height * scale);
|
||||
var offsetX = (newSize - scaledWidth) / 2;
|
||||
var offsetY = (newSize - scaledHeight) / 2;
|
||||
|
||||
var scaledImage = new Bitmap(image, new Size(scaledWidth, scaledHeight));
|
||||
|
||||
var bm = new Bitmap(newSize, newSize);
|
||||
|
||||
using (Graphics graphics = Graphics.FromImage(bm))
|
||||
{
|
||||
using (var brush = new SolidBrush(Color.Transparent))
|
||||
{
|
||||
graphics.FillRectangle(brush, new Rectangle(0, 0, newSize, newSize));
|
||||
|
||||
graphics.InterpolationMode = InterpolationMode.High;
|
||||
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
graphics.DrawImage(scaledImage, new Rectangle(offsetX, offsetY, scaledWidth, scaledHeight));
|
||||
}
|
||||
}
|
||||
return bm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how the quiet zones shall be rendered.
|
||||
/// </summary>
|
||||
public enum QuietZoneStyle
|
||||
{
|
||||
Dotted,
|
||||
Flat
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines how the background image (if set) shall be rendered.
|
||||
/// </summary>
|
||||
public enum BackgroundImageStyle
|
||||
{
|
||||
Fill,
|
||||
DataAreaOnly
|
||||
}
|
||||
}
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class ArtQRCodeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper function to create an ArtQRCode graphic with a single function call
|
||||
/// </summary>
|
||||
/// <param name="plainText">Text/payload to be encoded inside the QR code</param>
|
||||
/// <param name="pixelsPerModule">Amount of px each dark/light module of the QR code shall take place in the final QR code image</param>
|
||||
/// <param name="darkColor">Color of the dark modules</param>
|
||||
/// <param name="lightColor">Color of the light modules</param>
|
||||
/// <param name="backgroundColor">Color of the background</param>
|
||||
/// <param name="eccLevel">The level of error correction data</param>
|
||||
/// <param name="forceUtf8">Shall the generator be forced to work in UTF-8 mode?</param>
|
||||
/// <param name="utf8BOM">Should the byte-order-mark be used?</param>
|
||||
/// <param name="eciMode">Which ECI mode shall be used?</param>
|
||||
/// <param name="requestedVersion">Set fixed QR code target version.</param>
|
||||
/// <param name="backgroundImage">A bitmap object that will be used as background picture</param>
|
||||
/// <param name="pixelSizeFactor">Value between 0.0 to 1.0 that defines how big the module dots are. The bigger the value, the less round the dots will be.</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="quietZoneRenderingStyle">Style of the quiet zones</param>
|
||||
/// <param name="backgroundImageStyle">Style of the background image (if set). Fill=spanning complete graphic; DataAreaOnly=Don't paint background into quietzone</param>
|
||||
/// <param name="finderPatternImage">Optional image that should be used instead of the default finder patterns</param>
|
||||
/// <returns>QRCode graphic as bitmap</returns>
|
||||
public static Bitmap GetQRCode(string plainText, int pixelsPerModule, Color darkColor, Color lightColor, Color backgroundColor, ECCLevel eccLevel, bool forceUtf8 = false,
|
||||
bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, Bitmap backgroundImage = null, double pixelSizeFactor = 0.8,
|
||||
bool drawQuietZones = true, QuietZoneStyle quietZoneRenderingStyle = QuietZoneStyle.Flat,
|
||||
BackgroundImageStyle backgroundImageStyle = BackgroundImageStyle.DataAreaOnly, Bitmap finderPatternImage = null)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new ArtQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColor, lightColor, backgroundColor, backgroundImage, pixelSizeFactor, drawQuietZones, quietZoneRenderingStyle, backgroundImageStyle, finderPatternImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
vCardEditor/Libs/QRCoder/Assets/nuget-icon.png
Normal file
BIN
vCardEditor/Libs/QRCoder/Assets/nuget-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
59
vCardEditor/Libs/QRCoder/Assets/nuget-readme.md
Normal file
59
vCardEditor/Libs/QRCoder/Assets/nuget-readme.md
Normal file
@@ -0,0 +1,59 @@
|
||||
## About
|
||||
|
||||
QRCoder is a simple library, written in C#.NET, which enables you to create QR codes. It hasn't any dependencies to other libraries and is available as .NET Framework and .NET Core PCL version on NuGet.
|
||||
|
||||
***
|
||||
|
||||
## Documentation
|
||||
|
||||
👉 *Your first place to go should be our wiki. Here you can find a detailed documentation of the QRCoder and its functions.*
|
||||
* [**QRCode Wiki**](https://github.com/codebude/QRCoder/wiki)
|
||||
* [Creator's blog (english)](http://en.code-bude.net/2013/10/17/qrcoder-an-open-source-qr-code-generator-implementation-in-csharp/)
|
||||
* [Creator's blog (german)](http://code-bude.net/2013/10/17/qrcoder-eine-open-source-qr-code-implementierung-in-csharp/)
|
||||
|
||||
### Release Notes
|
||||
The release notes for the current and all past releases can be read here: [📄 Release Notes](https://github.com/codebude/QRCoder/wiki/Release-notes)
|
||||
|
||||
## Usage / Quick start
|
||||
|
||||
You only need four lines of code, to generate and view your first QR code.
|
||||
|
||||
```csharp
|
||||
using (QRCodeGenerator qrGenerator = new QRCodeGenerator())
|
||||
using (QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q))
|
||||
using (QRCode qrCode = new QRCode(qrCodeData))
|
||||
{
|
||||
Bitmap qrCodeImage = qrCode.GetGraphic(20);
|
||||
}
|
||||
```
|
||||
|
||||
### Optional parameters and overloads
|
||||
|
||||
The GetGraphics-method has some more overloads. The first two enable you to set the color of the QR code graphic. One uses Color-class-types, the other HTML hex color notation.
|
||||
|
||||
```csharp
|
||||
//Set color by using Color-class types
|
||||
Bitmap qrCodeImage = qrCode.GetGraphic(20, Color.DarkRed, Color.PaleGreen, true);
|
||||
|
||||
//Set color by using HTML hex color notation
|
||||
Bitmap qrCodeImage = qrCode.GetGraphic(20, "#000ff0", "#0ff000");
|
||||
```
|
||||
|
||||
The other overload enables you to render a logo/image in the center of the QR code.
|
||||
|
||||
```csharp
|
||||
Bitmap qrCodeImage = qrCode.GetGraphic(20, Color.Black, Color.White, (Bitmap)Bitmap.FromFile("C:\\myimage.png"));
|
||||
```
|
||||
|
||||
There are a plenty of other options. So feel free to read more on that in our wiki: [Wiki: How to use QRCoder](https://github.com/codebude/QRCoder/wiki/How-to-use-QRCoder)
|
||||
|
||||
## Help & Issues
|
||||
|
||||
If you think you have found a bug or have new ideas or feature requests, then feel free to open a new issue: https://github.com/codebude/QRCoder/issues
|
||||
|
||||
In case you have a question about using the library (and couldn't find an answer in our wiki), feel free to open a new question/discussion: https://github.com/codebude/QRCoder/discussions
|
||||
|
||||
|
||||
## Legal information and credits
|
||||
|
||||
QRCoder is a project by [Raffael Herrmann](https://raffaelherrmann.de) and was first released in 10/2013. It's licensed under the [MIT license](https://github.com/codebude/QRCoder/blob/master/LICENSE.txt).
|
||||
115
vCardEditor/Libs/QRCoder/Base64QRCode.cs
Normal file
115
vCardEditor/Libs/QRCoder/Base64QRCode.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0 || NET6_0_WINDOWS
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using static QRCoder.Base64QRCode;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class Base64QRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
private QRCode qr;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public Base64QRCode() {
|
||||
qr = new QRCode();
|
||||
}
|
||||
|
||||
public Base64QRCode(QRCodeData data) : base(data) {
|
||||
qr = new QRCode(data);
|
||||
}
|
||||
|
||||
public override void SetQRCodeData(QRCodeData data) {
|
||||
this.qr.SetQRCodeData(data);
|
||||
}
|
||||
|
||||
public string GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
return this.GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
|
||||
}
|
||||
|
||||
|
||||
public string GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
|
||||
{
|
||||
return this.GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones, imgType);
|
||||
}
|
||||
|
||||
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
|
||||
{
|
||||
var base64 = string.Empty;
|
||||
using (Bitmap bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, drawQuietZones))
|
||||
{
|
||||
base64 = BitmapToBase64(bmp, imgType);
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon, int iconSizePercent = 15, int iconBorderWidth = 6, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
|
||||
{
|
||||
var base64 = string.Empty;
|
||||
using (Bitmap bmp = qr.GetGraphic(pixelsPerModule, darkColor, lightColor, icon, iconSizePercent, iconBorderWidth, drawQuietZones))
|
||||
{
|
||||
base64 = BitmapToBase64(bmp, imgType);
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
|
||||
private string BitmapToBase64(Bitmap bmp, ImageType imgType)
|
||||
{
|
||||
var base64 = string.Empty;
|
||||
ImageFormat iFormat;
|
||||
switch (imgType) {
|
||||
case ImageType.Png:
|
||||
iFormat = ImageFormat.Png;
|
||||
break;
|
||||
case ImageType.Jpeg:
|
||||
iFormat = ImageFormat.Jpeg;
|
||||
break;
|
||||
case ImageType.Gif:
|
||||
iFormat = ImageFormat.Gif;
|
||||
break;
|
||||
default:
|
||||
iFormat = ImageFormat.Png;
|
||||
break;
|
||||
}
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
bmp.Save(memoryStream, iFormat);
|
||||
base64 = Convert.ToBase64String(memoryStream.ToArray(), Base64FormattingOptions.None);
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
public enum ImageType
|
||||
{
|
||||
Gif,
|
||||
Jpeg,
|
||||
Png
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class Base64QRCodeHelper
|
||||
{
|
||||
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true, ImageType imgType = ImageType.Png)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new Base64QRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex, drawQuietZones, imgType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
125
vCardEditor/Libs/QRCoder/BitmapByteQRCode.cs
Normal file
125
vCardEditor/Libs/QRCoder/BitmapByteQRCode.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class BitmapByteQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public BitmapByteQRCode() { }
|
||||
|
||||
public BitmapByteQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
public byte[] GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
return GetGraphic(pixelsPerModule, new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0xFF, 0xFF, 0xFF });
|
||||
}
|
||||
|
||||
public byte[] GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex)
|
||||
{
|
||||
return GetGraphic(pixelsPerModule, HexColorToByteArray(darkColorHtmlHex), HexColorToByteArray(lightColorHtmlHex));
|
||||
}
|
||||
|
||||
public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightColorRgb)
|
||||
{
|
||||
var sideLength = this.QrCodeData.ModuleMatrix.Count * pixelsPerModule;
|
||||
|
||||
var moduleDark = darkColorRgb.Reverse();
|
||||
var moduleLight = lightColorRgb.Reverse();
|
||||
|
||||
List<byte> bmp = new List<byte>();
|
||||
|
||||
//header
|
||||
bmp.AddRange(new byte[] { 0x42, 0x4D, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00 });
|
||||
|
||||
//width
|
||||
bmp.AddRange(IntTo4Byte(sideLength));
|
||||
//height
|
||||
bmp.AddRange(IntTo4Byte(sideLength));
|
||||
|
||||
//header end
|
||||
bmp.AddRange(new byte[] { 0x01, 0x00, 0x18, 0x00 });
|
||||
|
||||
//draw qr code
|
||||
for (var x = sideLength-1; x >= 0; x = x - pixelsPerModule)
|
||||
{
|
||||
for (int pm = 0; pm < pixelsPerModule; pm++)
|
||||
{
|
||||
for (var y = 0; y < sideLength; y = y + pixelsPerModule)
|
||||
{
|
||||
var module =
|
||||
this.QrCodeData.ModuleMatrix[(x + pixelsPerModule)/pixelsPerModule - 1][(y + pixelsPerModule)/pixelsPerModule - 1];
|
||||
for (int i = 0; i < pixelsPerModule; i++)
|
||||
{
|
||||
bmp.AddRange(module ? moduleDark : moduleLight);
|
||||
}
|
||||
}
|
||||
if (sideLength%4 != 0)
|
||||
{
|
||||
for (int i = 0; i < sideLength%4; i++)
|
||||
{
|
||||
bmp.Add(0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//finalize with terminator
|
||||
bmp.AddRange(new byte[] { 0x00, 0x00 });
|
||||
|
||||
return bmp.ToArray();
|
||||
}
|
||||
|
||||
private byte[] HexColorToByteArray(string colorString)
|
||||
{
|
||||
if (colorString.StartsWith("#"))
|
||||
colorString = colorString.Substring(1);
|
||||
byte[] byteColor = new byte[colorString.Length / 2];
|
||||
for (int i = 0; i < byteColor.Length; i++)
|
||||
byteColor[i] = byte.Parse(colorString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture);
|
||||
return byteColor;
|
||||
}
|
||||
|
||||
private byte[] IntTo4Byte(int inp)
|
||||
{
|
||||
byte[] bytes = new byte[2];
|
||||
unchecked
|
||||
{
|
||||
bytes[1] = (byte)(inp >> 8);
|
||||
bytes[0] = (byte)(inp);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class BitmapByteQRCodeHelper
|
||||
{
|
||||
public static byte[] GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex,
|
||||
string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false,
|
||||
EciMode eciMode = EciMode.Default, int requestedVersion = -1)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (
|
||||
var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode,
|
||||
requestedVersion))
|
||||
using (var qrCode = new BitmapByteQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex);
|
||||
}
|
||||
|
||||
public static byte[] GetQRCode(string txt, QRCodeGenerator.ECCLevel eccLevel, int size)
|
||||
{
|
||||
using (var qrGen = new QRCodeGenerator())
|
||||
using (var qrCode = qrGen.CreateQrCode(txt, eccLevel))
|
||||
using (var qrBmp = new BitmapByteQRCode(qrCode))
|
||||
return qrBmp.GetGraphic(size);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
16
vCardEditor/Libs/QRCoder/Exceptions/DataTooLongException.cs
Normal file
16
vCardEditor/Libs/QRCoder/Exceptions/DataTooLongException.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace QRCoder.Exceptions
|
||||
{
|
||||
public class DataTooLongException : Exception
|
||||
{
|
||||
public DataTooLongException(string eccLevel, string encodingMode, int maxSizeByte) : base(
|
||||
$"The given payload exceeds the maximum size of the QR code standard. The maximum size allowed for the choosen paramters (ECC level={eccLevel}, EncodingMode={encodingMode}) is {maxSizeByte} byte."
|
||||
){}
|
||||
|
||||
public DataTooLongException(string eccLevel, string encodingMode, int version, int maxSizeByte) : base(
|
||||
$"The given payload exceeds the maximum size of the QR code standard. The maximum size allowed for the choosen paramters (ECC level={eccLevel}, EncodingMode={encodingMode}, FixedVersion={version}) is {maxSizeByte} byte."
|
||||
)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
52
vCardEditor/Libs/QRCoder/Extensions/StringValueAttribute.cs
Normal file
52
vCardEditor/Libs/QRCoder/Extensions/StringValueAttribute.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace QRCoder.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to represent a string value for a value in an enum
|
||||
/// </summary>
|
||||
public class StringValueAttribute : Attribute
|
||||
{
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Holds the alue in an enum
|
||||
/// </summary>
|
||||
public string StringValue { get; protected set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Init a StringValue Attribute
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public StringValueAttribute(string value)
|
||||
{
|
||||
this.StringValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CustomExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Will get the string value for a given enum's value
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetStringValue(this Enum value)
|
||||
{
|
||||
#if NETSTANDARD1_3
|
||||
var fieldInfo = value.GetType().GetRuntimeField(value.ToString());
|
||||
#else
|
||||
var fieldInfo = value.GetType().GetField(value.ToString());
|
||||
#endif
|
||||
var attr = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
|
||||
return attr.Length > 0 ? attr[0].StringValue : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace QRCoder.Framework4._0Methods
|
||||
{
|
||||
class Stream4Methods
|
||||
{
|
||||
public static void CopyTo(System.IO.Stream input, System.IO.Stream output)
|
||||
{
|
||||
byte[] buffer = new byte[16 * 1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
output.Write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
internal static class String40Methods
|
||||
{
|
||||
/// <summary>
|
||||
/// The IsNullOrWhiteSpace method from Framework4.0
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the <paramref name="value"/> is null or white space; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsNullOrWhiteSpace(String value)
|
||||
{
|
||||
if (value == null) return true;
|
||||
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
if (!Char.IsWhiteSpace(value[i])) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string ReverseString(string str)
|
||||
{
|
||||
char[] chars = str.ToCharArray();
|
||||
char[] result = new char[chars.Length];
|
||||
for (int i = 0, j = str.Length - 1; i < str.Length; i++, j--)
|
||||
{
|
||||
result[i] = chars[j];
|
||||
}
|
||||
return new string(result);
|
||||
}
|
||||
|
||||
public static bool IsAllDigit(string str)
|
||||
{
|
||||
foreach (var c in str)
|
||||
{
|
||||
if (!char.IsDigit(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
3124
vCardEditor/Libs/QRCoder/PayloadGenerator.cs
Normal file
3124
vCardEditor/Libs/QRCoder/PayloadGenerator.cs
Normal file
File diff suppressed because it is too large
Load Diff
243
vCardEditor/Libs/QRCoder/PdfByteQRCode.cs
Normal file
243
vCardEditor/Libs/QRCoder/PdfByteQRCode.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0 || NET6_0_WINDOWS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
/* This renderer is inspired by RemusVasii: https://github.com/codebude/QRCoder/issues/223 */
|
||||
namespace QRCoder
|
||||
{
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public class PdfByteQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
private readonly byte[] pdfBinaryComment = new byte[] { 0x25, 0xe2, 0xe3, 0xcf, 0xd3 };
|
||||
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public PdfByteQRCode() { }
|
||||
|
||||
public PdfByteQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a PDF document with a black & white QR code
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
return GetGraphic(pixelsPerModule, "#000000", "#ffffff");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes hexadecimal color string #000000 and returns byte[]{ 0, 0, 0 }
|
||||
/// </summary>
|
||||
/// <param name="colorString">Color in HEX format like #ffffff</param>
|
||||
/// <returns></returns>
|
||||
private byte[] HexColorToByteArray(string colorString)
|
||||
{
|
||||
if (colorString.StartsWith("#"))
|
||||
colorString = colorString.Substring(1);
|
||||
byte[] byteColor = new byte[colorString.Length / 2];
|
||||
for (int i = 0; i < byteColor.Length; i++)
|
||||
byteColor[i] = byte.Parse(colorString.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
return byteColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a PDF document with given colors DPI and quality
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule"></param>
|
||||
/// <param name="darkColorHtmlHex"></param>
|
||||
/// <param name="lightColorHtmlHex"></param>
|
||||
/// <param name="dpi"></param>
|
||||
/// <param name="jpgQuality"></param>
|
||||
/// <returns></returns>
|
||||
public byte[] GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, int dpi = 150, long jpgQuality = 85)
|
||||
{
|
||||
byte[] jpgArray = null, pngArray = null;
|
||||
var imgSize = QrCodeData.ModuleMatrix.Count * pixelsPerModule;
|
||||
var pdfMediaSize = (imgSize * 72 / dpi).ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
//Get QR code image
|
||||
using (var qrCode = new PngByteQRCode(QrCodeData))
|
||||
{
|
||||
pngArray = qrCode.GetGraphic(pixelsPerModule, HexColorToByteArray(darkColorHtmlHex), HexColorToByteArray(lightColorHtmlHex));
|
||||
}
|
||||
|
||||
//Create image and transofrm to JPG
|
||||
using (var msPng = new MemoryStream())
|
||||
{
|
||||
msPng.Write(pngArray, 0, pngArray.Length);
|
||||
var img = System.Drawing.Image.FromStream(msPng);
|
||||
using (var msJpeg = new MemoryStream())
|
||||
{
|
||||
// Create JPEG with specified quality
|
||||
var jpgImageCodecInfo = ImageCodecInfo.GetImageEncoders().First(x => x.MimeType == "image/jpeg");
|
||||
var jpgEncoderParameters = new EncoderParameters(1) {
|
||||
Param = new EncoderParameter[]{ new EncoderParameter(Encoder.Quality, jpgQuality) }
|
||||
};
|
||||
img.Save(msJpeg, jpgImageCodecInfo, jpgEncoderParameters);
|
||||
jpgArray = msJpeg.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
//Create PDF document
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var writer = new StreamWriter(stream, System.Text.Encoding.GetEncoding("ASCII"));
|
||||
|
||||
var xrefs = new List<long>();
|
||||
|
||||
writer.Write("%PDF-1.5\r\n");
|
||||
writer.Flush();
|
||||
|
||||
stream.Write(pdfBinaryComment, 0, pdfBinaryComment.Length);
|
||||
writer.WriteLine();
|
||||
|
||||
writer.Flush();
|
||||
xrefs.Add(stream.Position);
|
||||
|
||||
writer.Write(
|
||||
xrefs.Count.ToString() + " 0 obj\r\n" +
|
||||
"<<\r\n" +
|
||||
"/Type /Catalog\r\n" +
|
||||
"/Pages 2 0 R\r\n" +
|
||||
">>\r\n" +
|
||||
"endobj\r\n"
|
||||
);
|
||||
|
||||
writer.Flush();
|
||||
xrefs.Add(stream.Position);
|
||||
|
||||
writer.Write(
|
||||
xrefs.Count.ToString() + " 0 obj\r\n" +
|
||||
"<<\r\n" +
|
||||
"/Count 1\r\n" +
|
||||
"/Kids [ <<\r\n" +
|
||||
"/Type /Page\r\n" +
|
||||
"/Parent 2 0 R\r\n" +
|
||||
"/MediaBox [0 0 " + pdfMediaSize + " " + pdfMediaSize + "]\r\n" +
|
||||
"/Resources << /ProcSet [ /PDF /ImageC ]\r\n" +
|
||||
"/XObject << /Im1 4 0 R >> >>\r\n" +
|
||||
"/Contents 3 0 R\r\n" +
|
||||
">> ]\r\n" +
|
||||
">>\r\n" +
|
||||
"endobj\r\n"
|
||||
);
|
||||
|
||||
var X = "q\r\n" +
|
||||
pdfMediaSize + " 0 0 " + pdfMediaSize + " 0 0 cm\r\n" +
|
||||
"/Im1 Do\r\n" +
|
||||
"Q";
|
||||
|
||||
writer.Flush();
|
||||
xrefs.Add(stream.Position);
|
||||
|
||||
writer.Write(
|
||||
xrefs.Count.ToString() + " 0 obj\r\n" +
|
||||
"<< /Length " + X.Length.ToString() + " >>\r\n" +
|
||||
"stream\r\n" +
|
||||
X + "endstream\r\n" +
|
||||
"endobj\r\n"
|
||||
);
|
||||
|
||||
writer.Flush();
|
||||
xrefs.Add(stream.Position);
|
||||
|
||||
writer.Write(
|
||||
xrefs.Count.ToString() + " 0 obj\r\n" +
|
||||
"<<\r\n" +
|
||||
"/Name /Im1\r\n" +
|
||||
"/Type /XObject\r\n" +
|
||||
"/Subtype /Image\r\n" +
|
||||
"/Width " + imgSize.ToString() + "/Height " + imgSize.ToString() + "/Length 5 0 R\r\n" +
|
||||
"/Filter /DCTDecode\r\n" +
|
||||
"/ColorSpace /DeviceRGB\r\n" +
|
||||
"/BitsPerComponent 8\r\n" +
|
||||
">>\r\n" +
|
||||
"stream\r\n"
|
||||
);
|
||||
writer.Flush();
|
||||
stream.Write(jpgArray, 0, jpgArray.Length);
|
||||
writer.Write(
|
||||
"\r\n" +
|
||||
"endstream\r\n" +
|
||||
"endobj\r\n"
|
||||
);
|
||||
|
||||
writer.Flush();
|
||||
xrefs.Add(stream.Position);
|
||||
|
||||
writer.Write(
|
||||
xrefs.Count.ToString() + " 0 obj\r\n" +
|
||||
jpgArray.Length.ToString() + " endobj\r\n"
|
||||
);
|
||||
|
||||
writer.Flush();
|
||||
var startxref = stream.Position;
|
||||
|
||||
writer.Write(
|
||||
"xref\r\n" +
|
||||
"0 " + (xrefs.Count + 1).ToString() + "\r\n" +
|
||||
"0000000000 65535 f\r\n"
|
||||
);
|
||||
|
||||
foreach (var refValue in xrefs)
|
||||
writer.Write(refValue.ToString("0000000000") + " 00000 n\r\n");
|
||||
|
||||
writer.Write(
|
||||
"trailer\r\n" +
|
||||
"<<\r\n" +
|
||||
"/Size " + (xrefs.Count + 1).ToString() + "\r\n" +
|
||||
"/Root 1 0 R\r\n" +
|
||||
">>\r\n" +
|
||||
"startxref\r\n" +
|
||||
startxref.ToString() + "\r\n" +
|
||||
"%%EOF"
|
||||
);
|
||||
|
||||
writer.Flush();
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class PdfByteQRCodeHelper
|
||||
{
|
||||
public static byte[] GetQRCode(string plainText, int pixelsPerModule, string darkColorHtmlHex,
|
||||
string lightColorHtmlHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false,
|
||||
EciMode eciMode = EciMode.Default, int requestedVersion = -1)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (
|
||||
var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode,
|
||||
requestedVersion))
|
||||
using (var qrCode = new PdfByteQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorHtmlHex, lightColorHtmlHex);
|
||||
}
|
||||
|
||||
public static byte[] GetQRCode(string txt, ECCLevel eccLevel, int size)
|
||||
{
|
||||
using (var qrGen = new QRCodeGenerator())
|
||||
using (var qrCode = qrGen.CreateQrCode(txt, eccLevel))
|
||||
using (var qrBmp = new PdfByteQRCode(qrCode))
|
||||
return qrBmp.GetGraphic(size);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
341
vCardEditor/Libs/QRCoder/PngByteQRCode.cs
Normal file
341
vCardEditor/Libs/QRCoder/PngByteQRCode.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
public sealed class PngByteQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public PngByteQRCode() { }
|
||||
|
||||
public PngByteQRCode(QRCodeData data) : base(data)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a black & white PNG of the QR code, using 1-bit grayscale.
|
||||
/// </summary>
|
||||
public byte[] GetGraphic(int pixelsPerModule, bool drawQuietZones = true)
|
||||
{
|
||||
using (var png = new PngBuilder())
|
||||
{
|
||||
var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
|
||||
png.WriteHeader(size, size, 1, PngBuilder.ColorType.Greyscale);
|
||||
png.WriteScanlines(this.DrawScanlines(pixelsPerModule, drawQuietZones));
|
||||
png.WriteEnd();
|
||||
return png.GetBytes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates 2-color PNG of the QR code, using 1-bit indexed color. Accepts 3-byte RGB colors for normal images and 4-byte RGBA-colors for transparent images.
|
||||
/// </summary>
|
||||
public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgba, byte[] lightColorRgba, bool drawQuietZones = true)
|
||||
{
|
||||
using (var png = new PngBuilder())
|
||||
{
|
||||
var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
|
||||
png.WriteHeader(size, size, 1, PngBuilder.ColorType.Indexed);
|
||||
png.WritePalette(darkColorRgba, lightColorRgba);
|
||||
png.WriteScanlines(this.DrawScanlines(pixelsPerModule, drawQuietZones));
|
||||
png.WriteEnd();
|
||||
return png.GetBytes();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a bitmap where each pixel is represented by a single bit, dark = 0 and light = 1.
|
||||
/// </summary>
|
||||
private byte[] DrawScanlines(int pixelsPerModule, bool drawQuietZones)
|
||||
{
|
||||
var moduleMatrix = this.QrCodeData.ModuleMatrix;
|
||||
var matrixSize = moduleMatrix.Count - (drawQuietZones ? 0 : 8);
|
||||
var quietZoneOffset = (drawQuietZones ? 0 : 4);
|
||||
var bytesPerScanline = (matrixSize * pixelsPerModule + 7) / 8 + 1; // A monochrome scanline is one byte for filter type then one bit per pixel.
|
||||
var scanlines = new byte[bytesPerScanline * matrixSize * pixelsPerModule];
|
||||
|
||||
for (var y = 0; y < matrixSize; y++)
|
||||
{
|
||||
var modules = moduleMatrix[y+quietZoneOffset];
|
||||
var scanlineOffset = y * pixelsPerModule * bytesPerScanline;
|
||||
|
||||
// Draw a scanline with the modules from the QR code.
|
||||
for (var x = 0; x < matrixSize; x++)
|
||||
{
|
||||
if (modules[x + quietZoneOffset])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var pixelIndex = x * pixelsPerModule;
|
||||
var endIndex = pixelIndex + pixelsPerModule;
|
||||
for (; pixelIndex < endIndex; pixelIndex++)
|
||||
{
|
||||
scanlines[scanlineOffset + 1 + pixelIndex / 8] |= (byte)(0x80 >> (pixelIndex % 8));
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the scanline required number of times.
|
||||
for (var copyCount = 1; copyCount < pixelsPerModule; copyCount++)
|
||||
{
|
||||
Array.Copy(scanlines, scanlineOffset, scanlines, scanlineOffset + copyCount * bytesPerScanline, bytesPerScanline);
|
||||
}
|
||||
}
|
||||
|
||||
return scanlines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the chunks that make up a PNG file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://www.w3.org/TR/2003/REC-PNG-20031110 and https://www.ietf.org/rfc/rfc1950.txt.
|
||||
/// </remarks>
|
||||
private sealed class PngBuilder : IDisposable
|
||||
{
|
||||
private static readonly byte[] PngSignature = { 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
|
||||
};
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
// Chunk types
|
||||
private static readonly byte[] IHDR = { 73, 72, 68, 82 };
|
||||
|
||||
private static readonly byte[] IDAT = { 73, 68, 65, 84 };
|
||||
|
||||
private static readonly byte[] IEND = { 73, 69, 78, 68 };
|
||||
|
||||
private static readonly byte[] PLTE = { 80, 76, 84, 69 };
|
||||
|
||||
private static readonly byte[] tRNS = { 116, 82, 78, 83 };
|
||||
// ReSharper enable InconsistentNaming
|
||||
|
||||
public enum ColorType : byte
|
||||
{
|
||||
Greyscale = 0,
|
||||
Indexed = 3
|
||||
}
|
||||
|
||||
private MemoryStream stream = new MemoryStream();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.stream?.Dispose();
|
||||
this.stream = null;
|
||||
}
|
||||
|
||||
public byte[] GetBytes()
|
||||
{
|
||||
var bytes = this.stream.ToArray();
|
||||
|
||||
// Enumerate chunks in file and insert their CRC32 checksums.
|
||||
var chunkOffset = PngSignature.Length;
|
||||
while (chunkOffset < bytes.Length)
|
||||
{
|
||||
// Read length field.
|
||||
var dataLength = (bytes[chunkOffset] << 24) | (bytes[chunkOffset + 1] << 16) | (bytes[chunkOffset + 2] << 8) | bytes[chunkOffset + 3];
|
||||
|
||||
// CRC is computed from type and data fields.
|
||||
var crc = Crc32(bytes, chunkOffset + 4, dataLength + 4);
|
||||
|
||||
// Write CRC to end of chunk.
|
||||
var crcOffset = chunkOffset + 8 + dataLength;
|
||||
bytes[crcOffset + 0] = (byte)(crc >> 24);
|
||||
bytes[crcOffset + 1] = (byte)(crc >> 16);
|
||||
bytes[crcOffset + 2] = (byte)(crc >> 8);
|
||||
bytes[crcOffset + 3] = (byte)crc;
|
||||
|
||||
// Seek to next chunk.
|
||||
chunkOffset = crcOffset + 4;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the IHDR chunk. This must be the first chunk in the file.
|
||||
/// </summary>
|
||||
public void WriteHeader(int width, int height, byte bitDepth, ColorType colorType)
|
||||
{
|
||||
this.stream.Write(PngSignature, 0, PngSignature.Length);
|
||||
this.WriteChunkStart(IHDR, 13);
|
||||
|
||||
// Size.
|
||||
this.WriteIntBigEndian((uint)width);
|
||||
this.WriteIntBigEndian((uint)height);
|
||||
|
||||
// Color.
|
||||
this.stream.WriteByte(bitDepth);
|
||||
this.stream.WriteByte((byte)colorType);
|
||||
|
||||
// Constants.
|
||||
this.stream.WriteByte(0);
|
||||
this.stream.WriteByte(0);
|
||||
this.stream.WriteByte(0);
|
||||
|
||||
this.WriteChunkEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the PLTE chunk, and also the tRNS chunk if necessary. Must come before the IDAT chunk.
|
||||
/// </summary>
|
||||
public void WritePalette(params byte[][] rgbaColors)
|
||||
{
|
||||
const int Red = 0, Green = 1, Blue = 2, Alpha = 3;
|
||||
const byte Opaque = 255;
|
||||
var hasAlpha = false;
|
||||
|
||||
this.WriteChunkStart(PLTE, 3 * rgbaColors.Length);
|
||||
foreach (var color in rgbaColors)
|
||||
{
|
||||
hasAlpha |= color.Length > Alpha && color[Alpha] < Opaque;
|
||||
this.stream.WriteByte(color[Red]);
|
||||
this.stream.WriteByte(color[Green]);
|
||||
this.stream.WriteByte(color[Blue]);
|
||||
}
|
||||
this.WriteChunkEnd();
|
||||
|
||||
if (!hasAlpha)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.WriteChunkStart(tRNS, rgbaColors.Length);
|
||||
foreach (var color in rgbaColors)
|
||||
{
|
||||
this.stream.WriteByte(color.Length > Alpha ? color[Alpha] : Opaque);
|
||||
}
|
||||
this.WriteChunkEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the IDAT chunk with the actual picture.
|
||||
/// </summary>
|
||||
public void WriteScanlines(byte[] scanlines)
|
||||
{
|
||||
using (var idatStream = new MemoryStream())
|
||||
{
|
||||
Deflate(idatStream, scanlines);
|
||||
|
||||
this.WriteChunkStart(IDAT, (int)(idatStream.Length + 6));
|
||||
|
||||
// Deflate header.
|
||||
this.stream.WriteByte(0x78); // 8 Deflate algorithm, 7 max window size
|
||||
this.stream.WriteByte(0x9C); // Check bits.
|
||||
|
||||
// Compressed data.
|
||||
idatStream.Position = 0;
|
||||
#if NET35
|
||||
idatStream.WriteTo(this.stream);
|
||||
#else
|
||||
idatStream.CopyTo(this.stream);
|
||||
#endif
|
||||
// Deflate checksum.
|
||||
var adler = Adler32(scanlines, 0, scanlines.Length);
|
||||
this.WriteIntBigEndian(adler);
|
||||
|
||||
this.WriteChunkEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the IEND chunk. This must be the last chunk in the file.
|
||||
/// </summary>
|
||||
public void WriteEnd()
|
||||
{
|
||||
this.WriteChunkStart(IEND, 0);
|
||||
this.WriteChunkEnd();
|
||||
}
|
||||
|
||||
private void WriteChunkStart(byte[] type, int length)
|
||||
{
|
||||
this.WriteIntBigEndian((uint)length);
|
||||
this.stream.Write(type, 0, 4);
|
||||
}
|
||||
|
||||
private void WriteChunkEnd()
|
||||
{
|
||||
// Reserves 4 bytes space for crc32 so GetBytes can add it later.
|
||||
this.stream.SetLength(this.stream.Length + 4);
|
||||
this.stream.Position += 4;
|
||||
}
|
||||
|
||||
private void WriteIntBigEndian(uint value)
|
||||
{
|
||||
this.stream.WriteByte((byte)(value >> 24));
|
||||
this.stream.WriteByte((byte)(value >> 16));
|
||||
this.stream.WriteByte((byte)(value >> 8));
|
||||
this.stream.WriteByte((byte)value);
|
||||
}
|
||||
|
||||
private static void Deflate(Stream output, byte[] bytes)
|
||||
{
|
||||
using (var deflateStream = new DeflateStream(output, CompressionMode.Compress, leaveOpen: true))
|
||||
{
|
||||
deflateStream.Write(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// Reference implementation from RFC 1950. Not optimized.
|
||||
private static uint Adler32(byte[] data, int index, int length)
|
||||
{
|
||||
const uint Base = 65521;
|
||||
uint s1 = 1, 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;
|
||||
}
|
||||
|
||||
// Reference implementation from REC-PNG-20031110. Not optimized.
|
||||
private static uint Crc32(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PngByteQRCodeHelper
|
||||
{
|
||||
public static byte[] GetQRCode(string plainText, int pixelsPerModule, byte[] darkColorRgba, byte[] lightColorRgba, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new PngByteQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorRgba, lightColorRgba, drawQuietZones);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static byte[] GetQRCode(string txt, QRCodeGenerator.ECCLevel eccLevel, int size, bool drawQuietZones = true)
|
||||
{
|
||||
using (var qrGen = new QRCodeGenerator())
|
||||
using (var qrCode = qrGen.CreateQrCode(txt, eccLevel))
|
||||
using (var qrPng = new PngByteQRCode(qrCode))
|
||||
return qrPng.GetGraphic(size, drawQuietZones);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
vCardEditor/Libs/QRCoder/PostscriptQRCode.cs
Normal file
161
vCardEditor/Libs/QRCoder/PostscriptQRCode.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0 || NET6_0_WINDOWS
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class PostscriptQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public PostscriptQRCode() { }
|
||||
public PostscriptQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
public string GetGraphic(int pointsPerModule, bool epsFormat = false)
|
||||
{
|
||||
var viewBox = new Size(pointsPerModule * this.QrCodeData.ModuleMatrix.Count, pointsPerModule * this.QrCodeData.ModuleMatrix.Count);
|
||||
return this.GetGraphic(viewBox, Color.Black, Color.White, true, epsFormat);
|
||||
}
|
||||
public string GetGraphic(int pointsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
var viewBox = new Size(pointsPerModule * this.QrCodeData.ModuleMatrix.Count, pointsPerModule * this.QrCodeData.ModuleMatrix.Count);
|
||||
return this.GetGraphic(viewBox, darkColor, lightColor, drawQuietZones, epsFormat);
|
||||
}
|
||||
|
||||
public string GetGraphic(int pointsPerModule, string darkColorHex, string lightColorHex, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
var viewBox = new Size(pointsPerModule * this.QrCodeData.ModuleMatrix.Count, pointsPerModule * this.QrCodeData.ModuleMatrix.Count);
|
||||
return this.GetGraphic(viewBox, darkColorHex, lightColorHex, drawQuietZones, epsFormat);
|
||||
}
|
||||
|
||||
public string GetGraphic(Size viewBox, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
return this.GetGraphic(viewBox, Color.Black, Color.White, drawQuietZones, epsFormat);
|
||||
}
|
||||
|
||||
public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
return this.GetGraphic(viewBox, ColorTranslator.FromHtml(darkColorHex), ColorTranslator.FromHtml(lightColorHex), drawQuietZones, epsFormat);
|
||||
}
|
||||
|
||||
public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
var offset = drawQuietZones ? 0 : 4;
|
||||
var drawableModulesCount = this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : offset * 2);
|
||||
var pointsPerModule = (double)Math.Min(viewBox.Width, viewBox.Height) / (double)drawableModulesCount;
|
||||
|
||||
string psFile = string.Format(psHeader, new object[] {
|
||||
DateTime.Now.ToString("s"), CleanSvgVal(viewBox.Width), CleanSvgVal(pointsPerModule),
|
||||
epsFormat ? "EPSF-3.0" : string.Empty
|
||||
});
|
||||
psFile += string.Format(psFunctions, new object[] {
|
||||
CleanSvgVal(darkColor.R /255.0), CleanSvgVal(darkColor.G /255.0), CleanSvgVal(darkColor.B /255.0),
|
||||
CleanSvgVal(lightColor.R /255.0), CleanSvgVal(lightColor.G /255.0), CleanSvgVal(lightColor.B /255.0),
|
||||
drawableModulesCount
|
||||
});
|
||||
|
||||
for (int xi = offset; xi < offset + drawableModulesCount; xi++)
|
||||
{
|
||||
if (xi > offset)
|
||||
psFile += "nl\n";
|
||||
for (int yi = offset; yi < offset + drawableModulesCount; yi++)
|
||||
{
|
||||
psFile += (this.QrCodeData.ModuleMatrix[xi][yi] ? "f " : "b ");
|
||||
}
|
||||
psFile += "\n";
|
||||
}
|
||||
return psFile + psFooter;
|
||||
}
|
||||
|
||||
private string CleanSvgVal(double input)
|
||||
{
|
||||
//Clean double values for international use/formats
|
||||
return input.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private const string psHeader = @"%!PS-Adobe-3.0 {3}
|
||||
%%Creator: QRCoder.NET
|
||||
%%Title: QRCode
|
||||
%%CreationDate: {0}
|
||||
%%DocumentData: Clean7Bit
|
||||
%%Origin: 0
|
||||
%%DocumentMedia: Default {1} {1} 0 () ()
|
||||
%%BoundingBox: 0 0 {1} {1}
|
||||
%%LanguageLevel: 2
|
||||
%%Pages: 1
|
||||
%%Page: 1 1
|
||||
%%EndComments
|
||||
%%BeginConstants
|
||||
/sz {1} def
|
||||
/sc {2} def
|
||||
%%EndConstants
|
||||
%%BeginFeature: *PageSize Default
|
||||
<< /PageSize [ sz sz ] /ImagingBBox null >> setpagedevice
|
||||
%%EndFeature
|
||||
";
|
||||
|
||||
private const string psFunctions = @"%%BeginFunctions
|
||||
/csquare {{
|
||||
newpath
|
||||
0 0 moveto
|
||||
0 1 rlineto
|
||||
1 0 rlineto
|
||||
0 -1 rlineto
|
||||
closepath
|
||||
setrgbcolor
|
||||
fill
|
||||
}} def
|
||||
/f {{
|
||||
{0} {1} {2} csquare
|
||||
1 0 translate
|
||||
}} def
|
||||
/b {{
|
||||
1 0 translate
|
||||
}} def
|
||||
/background {{
|
||||
{3} {4} {5} csquare
|
||||
}} def
|
||||
/nl {{
|
||||
-{6} -1 translate
|
||||
}} def
|
||||
%%EndFunctions
|
||||
%%BeginBody
|
||||
0 0 moveto
|
||||
gsave
|
||||
sz sz scale
|
||||
background
|
||||
grestore
|
||||
gsave
|
||||
sc sc scale
|
||||
0 {6} 1 sub translate
|
||||
";
|
||||
|
||||
private const string psFooter = @"%%EndBody
|
||||
grestore
|
||||
showpage
|
||||
%%EOF
|
||||
";
|
||||
}
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class PostscriptQRCodeHelper
|
||||
{
|
||||
public static string GetQRCode(string plainText, int pointsPerModule, string darkColorHex, string lightColorHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true, bool epsFormat = false)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new PostscriptQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pointsPerModule, darkColorHex, lightColorHex, drawQuietZones, epsFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
138
vCardEditor/Libs/QRCoder/QRCode.cs
Normal file
138
vCardEditor/Libs/QRCoder/QRCode.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
public class QRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public QRCode() { }
|
||||
|
||||
public QRCode(QRCodeData data) : base(data) {}
|
||||
|
||||
public Bitmap GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
return this.GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
|
||||
}
|
||||
|
||||
public Bitmap GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
|
||||
{
|
||||
return this.GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), drawQuietZones);
|
||||
}
|
||||
|
||||
public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true)
|
||||
{
|
||||
var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
|
||||
var offset = drawQuietZones ? 0 : 4 * pixelsPerModule;
|
||||
|
||||
var bmp = new Bitmap(size, size);
|
||||
using (var gfx = Graphics.FromImage(bmp))
|
||||
using (var lightBrush = new SolidBrush(lightColor))
|
||||
using (var darkBrush = new SolidBrush(darkColor))
|
||||
{
|
||||
for (var x = 0; x < size + offset; x = x + pixelsPerModule)
|
||||
{
|
||||
for (var y = 0; y < size + offset; y = y + pixelsPerModule)
|
||||
{
|
||||
var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
|
||||
|
||||
if (module)
|
||||
{
|
||||
gfx.FillRectangle(darkBrush, new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx.FillRectangle(lightBrush, new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gfx.Save();
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon=null, int iconSizePercent=15, int iconBorderWidth = 0, bool drawQuietZones = true, Color? iconBackgroundColor = null)
|
||||
{
|
||||
var size = (this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8)) * pixelsPerModule;
|
||||
var offset = drawQuietZones ? 0 : 4 * pixelsPerModule;
|
||||
|
||||
var bmp = new Bitmap(size, size, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
|
||||
using (var gfx = Graphics.FromImage(bmp))
|
||||
using (var lightBrush = new SolidBrush(lightColor))
|
||||
using (var darkBrush = new SolidBrush(darkColor))
|
||||
{
|
||||
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
gfx.CompositingQuality = CompositingQuality.HighQuality;
|
||||
gfx.Clear(lightColor);
|
||||
var drawIconFlag = icon != null && iconSizePercent > 0 && iconSizePercent <= 100;
|
||||
|
||||
for (var x = 0; x < size + offset; x = x + pixelsPerModule)
|
||||
{
|
||||
for (var y = 0; y < size + offset; y = y + pixelsPerModule)
|
||||
{
|
||||
var moduleBrush = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1] ? darkBrush : lightBrush;
|
||||
gfx.FillRectangle(moduleBrush , new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
|
||||
}
|
||||
}
|
||||
|
||||
if (drawIconFlag)
|
||||
{
|
||||
float iconDestWidth = iconSizePercent * bmp.Width / 100f;
|
||||
float iconDestHeight = drawIconFlag ? iconDestWidth * icon.Height / icon.Width : 0;
|
||||
float iconX = (bmp.Width - iconDestWidth) / 2;
|
||||
float iconY = (bmp.Height - iconDestHeight) / 2;
|
||||
var centerDest = new RectangleF(iconX - iconBorderWidth, iconY - iconBorderWidth, iconDestWidth + iconBorderWidth * 2, iconDestHeight + iconBorderWidth * 2);
|
||||
var iconDestRect = new RectangleF(iconX, iconY, iconDestWidth, iconDestHeight);
|
||||
var iconBgBrush = iconBackgroundColor != null ? new SolidBrush((Color)iconBackgroundColor) : lightBrush;
|
||||
//Only render icon/logo background, if iconBorderWith is set > 0
|
||||
if (iconBorderWidth > 0)
|
||||
{
|
||||
using (GraphicsPath iconPath = CreateRoundedRectanglePath(centerDest, iconBorderWidth * 2))
|
||||
{
|
||||
gfx.FillPath(iconBgBrush, iconPath);
|
||||
}
|
||||
}
|
||||
gfx.DrawImage(icon, iconDestRect, new RectangleF(0, 0, icon.Width, icon.Height), GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
gfx.Save();
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
internal GraphicsPath CreateRoundedRectanglePath(RectangleF rect, int cornerRadius)
|
||||
{
|
||||
var roundedRect = new GraphicsPath();
|
||||
roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
|
||||
roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
|
||||
roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
|
||||
roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
|
||||
roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
|
||||
roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
|
||||
roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
|
||||
roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
|
||||
roundedRect.CloseFigure();
|
||||
return roundedRect;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class QRCodeHelper
|
||||
{
|
||||
public static Bitmap GetQRCode(string plainText, int pixelsPerModule, Color darkColor, Color lightColor, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, Bitmap icon = null, int iconSizePercent = 15, int iconBorderWidth = 0, bool drawQuietZones = true)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new QRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColor, lightColor, icon, iconSizePercent, iconBorderWidth, drawQuietZones);
|
||||
}
|
||||
}
|
||||
}
|
||||
185
vCardEditor/Libs/QRCoder/QRCodeData.cs
Normal file
185
vCardEditor/Libs/QRCoder/QRCodeData.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
using QRCoder.Framework4._0Methods;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
public class QRCodeData : IDisposable
|
||||
{
|
||||
public List<BitArray> ModuleMatrix { get; set; }
|
||||
|
||||
public QRCodeData(int version)
|
||||
{
|
||||
this.Version = version;
|
||||
var size = ModulesPerSideFromVersion(version);
|
||||
this.ModuleMatrix = new List<BitArray>();
|
||||
for (var i = 0; i < size; i++)
|
||||
this.ModuleMatrix.Add(new BitArray(size));
|
||||
}
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0
|
||||
public QRCodeData(string pathToRawData, Compression compressMode) : this(File.ReadAllBytes(pathToRawData), compressMode)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
public QRCodeData(byte[] rawData, Compression compressMode)
|
||||
{
|
||||
var bytes = new List<byte>(rawData);
|
||||
|
||||
//Decompress
|
||||
if (compressMode == Compression.Deflate)
|
||||
{
|
||||
using (var input = new MemoryStream(bytes.ToArray()))
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new DeflateStream(input, CompressionMode.Decompress))
|
||||
{
|
||||
Stream4Methods.CopyTo(dstream, output);
|
||||
}
|
||||
bytes = new List<byte>(output.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compressMode == Compression.GZip)
|
||||
{
|
||||
using (var input = new MemoryStream(bytes.ToArray()))
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new GZipStream(input, CompressionMode.Decompress))
|
||||
{
|
||||
Stream4Methods.CopyTo(dstream, output);
|
||||
}
|
||||
bytes = new List<byte>(output.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes[0] != 0x51 || bytes[1] != 0x52 || bytes[2] != 0x52)
|
||||
throw new Exception("Invalid raw data file. Filetype doesn't match \"QRR\".");
|
||||
|
||||
//Set QR code version
|
||||
var sideLen = (int)bytes[4];
|
||||
bytes.RemoveRange(0, 5);
|
||||
this.Version = (sideLen - 21 - 8) / 4 + 1;
|
||||
|
||||
//Unpack
|
||||
var modules = new Queue<bool>(8 * bytes.Count);
|
||||
foreach (var b in bytes)
|
||||
{
|
||||
var bArr = new BitArray(new byte[] { b });
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
modules.Enqueue((b & (1 << i)) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
//Build module matrix
|
||||
this.ModuleMatrix = new List<BitArray>(sideLen);
|
||||
for (int y = 0; y < sideLen; y++)
|
||||
{
|
||||
this.ModuleMatrix.Add(new BitArray(sideLen));
|
||||
for (int x = 0; x < sideLen; x++)
|
||||
{
|
||||
this.ModuleMatrix[y][x] = modules.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public byte[] GetRawData(Compression compressMode)
|
||||
{
|
||||
var bytes = new List<byte>();
|
||||
|
||||
//Add header - signature ("QRR")
|
||||
bytes.AddRange(new byte[]{ 0x51, 0x52, 0x52, 0x00 });
|
||||
|
||||
//Add header - rowsize
|
||||
bytes.Add((byte)ModuleMatrix.Count);
|
||||
|
||||
//Build data queue
|
||||
var dataQueue = new Queue<int>();
|
||||
foreach (var row in ModuleMatrix)
|
||||
{
|
||||
foreach (var module in row)
|
||||
{
|
||||
dataQueue.Enqueue((bool)module ? 1 : 0);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 8 - (ModuleMatrix.Count * ModuleMatrix.Count) % 8; i++)
|
||||
{
|
||||
dataQueue.Enqueue(0);
|
||||
}
|
||||
|
||||
//Process queue
|
||||
while (dataQueue.Count > 0)
|
||||
{
|
||||
byte b = 0;
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
b += (byte)(dataQueue.Dequeue() << i);
|
||||
}
|
||||
bytes.Add(b);
|
||||
}
|
||||
var rawData = bytes.ToArray();
|
||||
|
||||
//Compress stream (optional)
|
||||
if (compressMode == Compression.Deflate)
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (var dstream = new DeflateStream(output, CompressionMode.Compress))
|
||||
{
|
||||
dstream.Write(rawData, 0, rawData.Length);
|
||||
}
|
||||
rawData = output.ToArray();
|
||||
}
|
||||
}
|
||||
else if (compressMode == Compression.GZip)
|
||||
{
|
||||
using (var output = new MemoryStream())
|
||||
{
|
||||
using (GZipStream gzipStream = new GZipStream(output, CompressionMode.Compress, true))
|
||||
{
|
||||
gzipStream.Write(rawData, 0, rawData.Length);
|
||||
}
|
||||
rawData = output.ToArray();
|
||||
}
|
||||
}
|
||||
return rawData;
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0
|
||||
public void SaveRawData(string filePath, Compression compressMode)
|
||||
{
|
||||
File.WriteAllBytes(filePath, GetRawData(compressMode));
|
||||
}
|
||||
#endif
|
||||
|
||||
public int Version { get; private set; }
|
||||
|
||||
private static int ModulesPerSideFromVersion(int version)
|
||||
{
|
||||
return 21 + (version - 1) * 4;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.ModuleMatrix = null;
|
||||
this.Version = 0;
|
||||
|
||||
}
|
||||
|
||||
public enum Compression
|
||||
{
|
||||
Uncompressed,
|
||||
Deflate,
|
||||
GZip
|
||||
}
|
||||
}
|
||||
}
|
||||
1596
vCardEditor/Libs/QRCoder/QRCodeGenerator.cs
Normal file
1596
vCardEditor/Libs/QRCoder/QRCodeGenerator.cs
Normal file
File diff suppressed because it is too large
Load Diff
397
vCardEditor/Libs/QRCoder/SvgQRCode.cs
Normal file
397
vCardEditor/Libs/QRCoder/SvgQRCode.cs
Normal file
@@ -0,0 +1,397 @@
|
||||
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0 || NET6_0_WINDOWS
|
||||
using QRCoder.Extensions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using static QRCoder.QRCodeGenerator;
|
||||
using static QRCoder.SvgQRCode;
|
||||
|
||||
namespace QRCoder
|
||||
{
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public class SvgQRCode : AbstractQRCode, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor without params to be used in COM Objects connections
|
||||
/// </summary>
|
||||
public SvgQRCode() { }
|
||||
public SvgQRCode(QRCodeData data) : base(data) { }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">The pixel size each b/w module is drawn</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(int pixelsPerModule)
|
||||
{
|
||||
var viewBox = new Size(pixelsPerModule*this.QrCodeData.ModuleMatrix.Count, pixelsPerModule * this.QrCodeData.ModuleMatrix.Count);
|
||||
return this.GetGraphic(viewBox, Color.Black, Color.White);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string with custom colors, optional quietzone and logo
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">The pixel size each b/w module is drawn</param>
|
||||
/// <param name="darkColor">Color of the dark modules</param>
|
||||
/// <param name="lightColor">Color of the light modules</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="sizingMode">Defines if width/height or viewbox should be used for size definition</param>
|
||||
/// <param name="logo">A (optional) logo to be rendered on the code (either Bitmap or SVG)</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
var offset = drawQuietZones ? 0 : 4;
|
||||
var edgeSize = this.QrCodeData.ModuleMatrix.Count * pixelsPerModule - (offset * 2 * pixelsPerModule);
|
||||
var viewBox = new Size(edgeSize, edgeSize);
|
||||
return this.GetGraphic(viewBox, darkColor, lightColor, drawQuietZones, sizingMode, logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string with custom colors (in HEX syntax), optional quietzone and logo
|
||||
/// </summary>
|
||||
/// <param name="pixelsPerModule">The pixel size each b/w module is drawn</param>
|
||||
/// <param name="darkColorHex">The color of the dark/black modules in hex (e.g. #000000) representation</param>
|
||||
/// <param name="lightColorHex">The color of the light/white modules in hex (e.g. #ffffff) representation</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="sizingMode">Defines if width/height or viewbox should be used for size definition</param>
|
||||
/// <param name="logo">A (optional) logo to be rendered on the code (either Bitmap or SVG)</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(int pixelsPerModule, string darkColorHex, string lightColorHex, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
var offset = drawQuietZones ? 0 : 4;
|
||||
var edgeSize = this.QrCodeData.ModuleMatrix.Count * pixelsPerModule - (offset * 2 * pixelsPerModule);
|
||||
var viewBox = new Size(edgeSize, edgeSize);
|
||||
return this.GetGraphic(viewBox, darkColorHex, lightColorHex, drawQuietZones, sizingMode, logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string with optional quietzone and logo
|
||||
/// </summary>
|
||||
/// <param name="viewBox">The viewbox of the QR code graphic</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="sizingMode">Defines if width/height or viewbox should be used for size definition</param>
|
||||
/// <param name="logo">A (optional) logo to be rendered on the code (either Bitmap or SVG)</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(Size viewBox, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
return this.GetGraphic(viewBox, Color.Black, Color.White, drawQuietZones, sizingMode, logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string with custom colors and optional quietzone and logo
|
||||
/// </summary>
|
||||
/// <param name="viewBox">The viewbox of the QR code graphic</param>
|
||||
/// <param name="darkColor">Color of the dark modules</param>
|
||||
/// <param name="lightColor">Color of the light modules</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="sizingMode">Defines if width/height or viewbox should be used for size definition</param>
|
||||
/// <param name="logo">A (optional) logo to be rendered on the code (either Bitmap or SVG)</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(Size viewBox, Color darkColor, Color lightColor, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
return this.GetGraphic(viewBox, ColorTranslator.ToHtml(Color.FromArgb(darkColor.ToArgb())), ColorTranslator.ToHtml(Color.FromArgb(lightColor.ToArgb())), drawQuietZones, sizingMode, logo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a QR code as SVG string with custom colors (in HEX syntax), optional quietzone and logo
|
||||
/// </summary>
|
||||
/// <param name="viewBox">The viewbox of the QR code graphic</param>
|
||||
/// <param name="darkColorHex">The color of the dark/black modules in hex (e.g. #000000) representation</param>
|
||||
/// <param name="lightColorHex">The color of the light/white modules in hex (e.g. #ffffff) representation</param>
|
||||
/// <param name="drawQuietZones">If true a white border is drawn around the whole QR Code</param>
|
||||
/// <param name="sizingMode">Defines if width/height or viewbox should be used for size definition</param>
|
||||
/// <param name="logo">A (optional) logo to be rendered on the code (either Bitmap or SVG)</param>
|
||||
/// <returns>SVG as string</returns>
|
||||
public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
int offset = drawQuietZones ? 0 : 4;
|
||||
int drawableModulesCount = this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : offset * 2);
|
||||
double pixelsPerModule = Math.Min(viewBox.Width, viewBox.Height) / (double)drawableModulesCount;
|
||||
double qrSize = drawableModulesCount * pixelsPerModule;
|
||||
string svgSizeAttributes = (sizingMode == SizingMode.WidthHeightAttribute) ? $@"width=""{viewBox.Width}"" height=""{viewBox.Height}""" : $@"viewBox=""0 0 {viewBox.Width} {viewBox.Height}""";
|
||||
ImageAttributes? logoAttr = null;
|
||||
if (logo != null)
|
||||
logoAttr = GetLogoAttributes(logo, viewBox);
|
||||
|
||||
// Merge horizontal rectangles
|
||||
int[,] matrix = new int[drawableModulesCount, drawableModulesCount];
|
||||
for (int yi = 0; yi < drawableModulesCount; yi += 1)
|
||||
{
|
||||
BitArray bitArray = this.QrCodeData.ModuleMatrix[yi+offset];
|
||||
|
||||
int x0 = -1;
|
||||
int xL = 0;
|
||||
for (int xi = 0; xi < drawableModulesCount; xi += 1)
|
||||
{
|
||||
matrix[yi, xi] = 0;
|
||||
if (bitArray[xi+offset] && (logo == null || !logo.FillLogoBackground() || !IsBlockedByLogo((xi+offset)*pixelsPerModule, (yi+offset) * pixelsPerModule, logoAttr, pixelsPerModule)))
|
||||
{
|
||||
if(x0 == -1)
|
||||
{
|
||||
x0 = xi;
|
||||
}
|
||||
xL += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(xL > 0)
|
||||
{
|
||||
matrix[yi, x0] = xL;
|
||||
x0 = -1;
|
||||
xL = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xL > 0)
|
||||
{
|
||||
matrix[yi, x0] = xL;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder svgFile = new StringBuilder($@"<svg version=""1.1"" baseProfile=""full"" shape-rendering=""crispEdges"" {svgSizeAttributes} xmlns=""http://www.w3.org/2000/svg"" xmlns:xlink=""http://www.w3.org/1999/xlink"">");
|
||||
svgFile.AppendLine($@"<rect x=""0"" y=""0"" width=""{CleanSvgVal(qrSize)}"" height=""{CleanSvgVal(qrSize)}"" fill=""{lightColorHex}"" />");
|
||||
for (int yi = 0; yi < drawableModulesCount; yi += 1)
|
||||
{
|
||||
double y = yi * pixelsPerModule;
|
||||
for (int xi = 0; xi < drawableModulesCount; xi += 1)
|
||||
{
|
||||
int xL = matrix[yi, xi];
|
||||
if(xL > 0)
|
||||
{
|
||||
// Merge vertical rectangles
|
||||
int yL = 1;
|
||||
for (int y2 = yi + 1; y2 < drawableModulesCount; y2 += 1)
|
||||
{
|
||||
if(matrix[y2, xi] == xL)
|
||||
{
|
||||
matrix[y2, xi] = 0;
|
||||
yL += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Output SVG rectangles
|
||||
double x = xi * pixelsPerModule;
|
||||
if (logo == null || !logo.FillLogoBackground() || !IsBlockedByLogo(x, y, logoAttr, pixelsPerModule))
|
||||
svgFile.AppendLine($@"<rect x=""{CleanSvgVal(x)}"" y=""{CleanSvgVal(y)}"" width=""{CleanSvgVal(xL * pixelsPerModule)}"" height=""{CleanSvgVal(yL * pixelsPerModule)}"" fill=""{darkColorHex}"" />");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Render logo, if set
|
||||
if (logo != null)
|
||||
{
|
||||
if (!logo.IsEmbedded())
|
||||
{
|
||||
svgFile.AppendLine($@"<svg width=""100%"" height=""100%"" version=""1.1"" xmlns = ""http://www.w3.org/2000/svg"">");
|
||||
svgFile.AppendLine($@"<image x=""{CleanSvgVal(logoAttr.Value.X)}"" y=""{CleanSvgVal(logoAttr.Value.Y)}"" width=""{CleanSvgVal(logoAttr.Value.Width)}"" height=""{CleanSvgVal(logoAttr.Value.Height)}"" xlink:href=""{logo.GetDataUri()}"" />");
|
||||
svgFile.AppendLine(@"</svg>");
|
||||
}
|
||||
else
|
||||
{
|
||||
var rawLogo = (string)logo.GetRawLogo();
|
||||
var svg = System.Xml.Linq.XDocument.Parse(rawLogo);
|
||||
svg.Root.SetAttributeValue("x", CleanSvgVal(logoAttr.Value.X));
|
||||
svg.Root.SetAttributeValue("y", CleanSvgVal(logoAttr.Value.Y));
|
||||
svg.Root.SetAttributeValue("width", CleanSvgVal(logoAttr.Value.Width));
|
||||
svg.Root.SetAttributeValue("height", CleanSvgVal(logoAttr.Value.Height));
|
||||
svg.Root.SetAttributeValue("shape-rendering", "geometricPrecision");
|
||||
svgFile.AppendLine(svg.ToString(System.Xml.Linq.SaveOptions.DisableFormatting).Replace("svg:", ""));
|
||||
}
|
||||
}
|
||||
|
||||
svgFile.Append(@"</svg>");
|
||||
return svgFile.ToString();
|
||||
}
|
||||
|
||||
private bool IsBlockedByLogo(double x, double y, ImageAttributes? attr, double pixelPerModule)
|
||||
{
|
||||
return x + pixelPerModule >= attr.Value.X && x <= attr.Value.X + attr.Value.Width && y + pixelPerModule >= attr.Value.Y && y <= attr.Value.Y + attr.Value.Height;
|
||||
}
|
||||
|
||||
private ImageAttributes GetLogoAttributes(SvgLogo logo, Size viewBox)
|
||||
{
|
||||
var imgWidth = logo.GetIconSizePercent() / 100d * viewBox.Width;
|
||||
var imgHeight = logo.GetIconSizePercent() / 100d * viewBox.Height;
|
||||
var imgPosX = viewBox.Width / 2d - imgWidth / 2d;
|
||||
var imgPosY = viewBox.Height / 2d - imgHeight / 2d;
|
||||
return new ImageAttributes()
|
||||
{
|
||||
Width = imgWidth,
|
||||
Height = imgHeight,
|
||||
X = imgPosX,
|
||||
Y = imgPosY
|
||||
};
|
||||
}
|
||||
|
||||
private struct ImageAttributes
|
||||
{
|
||||
public double Width;
|
||||
public double Height;
|
||||
public double X;
|
||||
public double Y;
|
||||
}
|
||||
|
||||
private string CleanSvgVal(double input)
|
||||
{
|
||||
//Clean double values for international use/formats
|
||||
//We use explicitly "G15" to avoid differences between .NET full and Core platforms
|
||||
//https://stackoverflow.com/questions/64898117/tostring-has-a-different-behavior-between-net-462-and-net-core-3-1
|
||||
return input.ToString("G15", System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mode of sizing attribution on svg root node
|
||||
/// </summary>
|
||||
public enum SizingMode
|
||||
{
|
||||
WidthHeightAttribute,
|
||||
ViewBoxAttribute
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a logo graphic that can be rendered on a SvgQRCode
|
||||
/// </summary>
|
||||
public class SvgLogo
|
||||
{
|
||||
private string _logoData;
|
||||
private MediaType _mediaType;
|
||||
private int _iconSizePercent;
|
||||
private bool _fillLogoBackground;
|
||||
private object _logoRaw;
|
||||
private bool _isEmbedded;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a logo object to be used in SvgQRCode renderer
|
||||
/// </summary>
|
||||
/// <param name="iconRasterized">Logo to be rendered as Bitmap/rasterized graphic</param>
|
||||
/// <param name="iconSizePercent">Degree of percentage coverage of the QR code by the logo</param>
|
||||
/// <param name="fillLogoBackground">If true, the background behind the logo will be cleaned</param>
|
||||
public SvgLogo(Bitmap iconRasterized, int iconSizePercent = 15, bool fillLogoBackground = true)
|
||||
{
|
||||
_iconSizePercent = iconSizePercent;
|
||||
using (var ms = new System.IO.MemoryStream())
|
||||
{
|
||||
using (var bitmap = new Bitmap(iconRasterized))
|
||||
{
|
||||
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
|
||||
_logoData = Convert.ToBase64String(ms.GetBuffer(), Base64FormattingOptions.None);
|
||||
}
|
||||
}
|
||||
_mediaType = MediaType.PNG;
|
||||
_fillLogoBackground = fillLogoBackground;
|
||||
_logoRaw = iconRasterized;
|
||||
_isEmbedded = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a logo object to be used in SvgQRCode renderer
|
||||
/// </summary>
|
||||
/// <param name="iconVectorized">Logo to be rendered as SVG/vectorized graphic/string</param>
|
||||
/// <param name="iconSizePercent">Degree of percentage coverage of the QR code by the logo</param>
|
||||
/// <param name="fillLogoBackground">If true, the background behind the logo will be cleaned</param>
|
||||
/// <param name="iconEmbedded">If true, the logo will embedded as native svg instead of embedding it as image-tag</param>
|
||||
public SvgLogo(string iconVectorized, int iconSizePercent = 15, bool fillLogoBackground = true, bool iconEmbedded = true)
|
||||
{
|
||||
_iconSizePercent = iconSizePercent;
|
||||
_logoData = Convert.ToBase64String(Encoding.UTF8.GetBytes(iconVectorized), Base64FormattingOptions.None);
|
||||
_mediaType = MediaType.SVG;
|
||||
_fillLogoBackground = fillLogoBackground;
|
||||
_logoRaw = iconVectorized;
|
||||
_isEmbedded = iconEmbedded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw logo's data
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object GetRawLogo()
|
||||
{
|
||||
return _logoRaw;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines, if the logo shall be natively embedded.
|
||||
/// true=native svg embedding, false=embedding via image-tag
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsEmbedded()
|
||||
{
|
||||
return _isEmbedded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the media type of the logo
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MediaType GetMediaType()
|
||||
{
|
||||
return _mediaType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the logo as data-uri
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetDataUri()
|
||||
{
|
||||
return $"data:{_mediaType.GetStringValue()};base64,{_logoData}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns how much of the QR code should be covered by the logo (in percent)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetIconSizePercent()
|
||||
{
|
||||
return _iconSizePercent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if the background of the logo should be cleaned (no QR modules will be rendered behind the logo)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool FillLogoBackground()
|
||||
{
|
||||
return _fillLogoBackground;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media types for SvgLogos
|
||||
/// </summary>
|
||||
public enum MediaType : int
|
||||
{
|
||||
[StringValue("image/png")]
|
||||
PNG = 0,
|
||||
[StringValue("image/svg+xml")]
|
||||
SVG = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if NET6_0_WINDOWS
|
||||
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
|
||||
#endif
|
||||
public static class SvgQRCodeHelper
|
||||
{
|
||||
public static string GetQRCode(string plainText, int pixelsPerModule, string darkColorHex, string lightColorHex, ECCLevel eccLevel, bool forceUtf8 = false, bool utf8BOM = false, EciMode eciMode = EciMode.Default, int requestedVersion = -1, bool drawQuietZones = true, SizingMode sizingMode = SizingMode.WidthHeightAttribute, SvgLogo logo = null)
|
||||
{
|
||||
using (var qrGenerator = new QRCodeGenerator())
|
||||
using (var qrCodeData = qrGenerator.CreateQrCode(plainText, eccLevel, forceUtf8, utf8BOM, eciMode, requestedVersion))
|
||||
using (var qrCode = new SvgQRCode(qrCodeData))
|
||||
return qrCode.GetGraphic(pixelsPerModule, darkColorHex, lightColorHex, drawQuietZones, sizingMode, logo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
96
vCardEditor/View/QRDialog.Designer.cs
generated
Normal file
96
vCardEditor/View/QRDialog.Designer.cs
generated
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
namespace vCardEditor.View
|
||||
{
|
||||
partial class QRDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.btnExport = new System.Windows.Forms.Button();
|
||||
this.btnClose = new System.Windows.Forms.Button();
|
||||
this.pictureBoxQRCode = new System.Windows.Forms.PictureBox();
|
||||
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBoxQRCode)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// btnExport
|
||||
//
|
||||
this.btnExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnExport.Location = new System.Drawing.Point(464, 385);
|
||||
this.btnExport.Name = "btnExport";
|
||||
this.btnExport.Size = new System.Drawing.Size(75, 28);
|
||||
this.btnExport.TabIndex = 5;
|
||||
this.btnExport.Text = "Export..";
|
||||
this.btnExport.UseVisualStyleBackColor = true;
|
||||
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
|
||||
//
|
||||
// btnClose
|
||||
//
|
||||
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnClose.Location = new System.Drawing.Point(550, 386);
|
||||
this.btnClose.Name = "btnClose";
|
||||
this.btnClose.Size = new System.Drawing.Size(75, 28);
|
||||
this.btnClose.TabIndex = 4;
|
||||
this.btnClose.Text = "Close";
|
||||
this.btnClose.UseVisualStyleBackColor = true;
|
||||
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
|
||||
//
|
||||
// pictureBoxQRCode
|
||||
//
|
||||
this.pictureBoxQRCode.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.pictureBoxQRCode.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
|
||||
this.pictureBoxQRCode.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pictureBoxQRCode.Location = new System.Drawing.Point(12, 12);
|
||||
this.pictureBoxQRCode.Name = "pictureBoxQRCode";
|
||||
this.pictureBoxQRCode.Size = new System.Drawing.Size(613, 367);
|
||||
this.pictureBoxQRCode.TabIndex = 3;
|
||||
this.pictureBoxQRCode.TabStop = false;
|
||||
//
|
||||
// QRDialog
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(640, 422);
|
||||
this.Controls.Add(this.btnExport);
|
||||
this.Controls.Add(this.btnClose);
|
||||
this.Controls.Add(this.pictureBoxQRCode);
|
||||
this.Name = "QRDialog";
|
||||
this.Text = "QR Generator";
|
||||
((System.ComponentModel.ISupportInitialize)(this.pictureBoxQRCode)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button btnExport;
|
||||
private System.Windows.Forms.Button btnClose;
|
||||
private System.Windows.Forms.PictureBox pictureBoxQRCode;
|
||||
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
|
||||
}
|
||||
}
|
||||
93
vCardEditor/View/QRDialog.cs
Normal file
93
vCardEditor/View/QRDialog.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using QRCoder;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace vCardEditor.View
|
||||
{
|
||||
public partial class QRDialog : Form
|
||||
{
|
||||
public QRDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void RenderQrCode()
|
||||
{
|
||||
|
||||
QRCodeGenerator.ECCLevel eccLevel = (QRCodeGenerator.ECCLevel)0;
|
||||
|
||||
using (QRCodeGenerator qrGenerator = new QRCodeGenerator())
|
||||
using (QRCodeData qrCodeData = qrGenerator.CreateQrCode("BEGIN:VCARD\r\nVERSION:3.0\r\nN:Chlef université;sarah;;;\r\nFN:sarah Chlef université\r\nADR;TYPE=HOME:;;sdad;;das;;\r\nEMAIL;TYPE=INTERNET:sibri02@yahoo.fr\r\nNOTE:I am proficient in Tiger-Crane Style\\,\\nand I am more than proficient in the exquisite art of the Samurai sword.\r\nNOTE:eee\r\nORG:Google\\;GMail Team\\;Spam Detection Squad\r\nTEL;TYPE=CELL;TYPE=OTHER;TYPE=VOICE:+213560348275\r\nTEL;TYPE=OTHER;TYPE=FAX:+2131122\r\nEND:VCARD\r\n", eccLevel))
|
||||
using (QRCode qrCode = new QRCode(qrCodeData))
|
||||
{
|
||||
pictureBoxQRCode.BackgroundImage = qrCode.GetGraphic(20, GetPrimaryColor(), GetBackgroundColor(), null, 1);
|
||||
|
||||
pictureBoxQRCode.Size = new System.Drawing.Size(pictureBoxQRCode.Width, pictureBoxQRCode.Height);
|
||||
//Set the SizeMode to center the image.
|
||||
pictureBoxQRCode.SizeMode = PictureBoxSizeMode.CenterImage;
|
||||
|
||||
pictureBoxQRCode.SizeMode = PictureBoxSizeMode.StretchImage;
|
||||
}
|
||||
}
|
||||
|
||||
private Color GetPrimaryColor()
|
||||
{
|
||||
return Color.Black;
|
||||
}
|
||||
|
||||
private Color GetBackgroundColor()
|
||||
{
|
||||
return Color.White;
|
||||
}
|
||||
|
||||
private void btnClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void btnExport_Click(object sender, EventArgs e)
|
||||
{
|
||||
// Displays a SaveFileDialog so the user can save the Image
|
||||
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
|
||||
saveFileDialog1.Filter = "Bitmap Image|*.bmp|PNG Image|*.png|JPeg Image|*.jpg|Gif Image|*.gif";
|
||||
saveFileDialog1.Title = "Save an Image File";
|
||||
saveFileDialog1.ShowDialog();
|
||||
|
||||
// If the file name is not an empty string open it for saving.
|
||||
if (saveFileDialog1.FileName != "")
|
||||
{
|
||||
// Saves the Image via a FileStream created by the OpenFile method.
|
||||
using (FileStream fs = (System.IO.FileStream)saveFileDialog1.OpenFile())
|
||||
{
|
||||
// Saves the Image in the appropriate ImageFormat based upon the
|
||||
// File type selected in the dialog box.
|
||||
// NOTE that the FilterIndex property is one-based.
|
||||
|
||||
ImageFormat imageFormat = null;
|
||||
switch (saveFileDialog1.FilterIndex)
|
||||
{
|
||||
case 1:
|
||||
imageFormat = ImageFormat.Bmp;
|
||||
break;
|
||||
case 2:
|
||||
imageFormat = ImageFormat.Png;
|
||||
break;
|
||||
case 3:
|
||||
imageFormat = ImageFormat.Jpeg;
|
||||
break;
|
||||
case 4:
|
||||
imageFormat = ImageFormat.Gif;
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("File extension is not supported");
|
||||
}
|
||||
|
||||
pictureBoxQRCode.BackgroundImage.Save(fs, imageFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
vCardEditor/View/QRDialog.resx
Normal file
123
vCardEditor/View/QRDialog.resx
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
@@ -66,6 +66,23 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Libs\QRCoder\AbstractQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\ArtQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\ASCIIQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\Base64QRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\BitmapByteQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\Exceptions\DataTooLongException.cs" />
|
||||
<Compile Include="Libs\QRCoder\Extensions\StringValueAttribute.cs" />
|
||||
<Compile Include="Libs\QRCoder\Framework4.0Methods\Stream4Methods.cs" />
|
||||
<Compile Include="Libs\QRCoder\Framework4.0Methods\String4Methods.cs" />
|
||||
<Compile Include="Libs\QRCoder\PayloadGenerator.cs" />
|
||||
<Compile Include="Libs\QRCoder\PdfByteQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\PngByteQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\PostscriptQRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\QRCode.cs" />
|
||||
<Compile Include="Libs\QRCoder\QRCodeData.cs" />
|
||||
<Compile Include="Libs\QRCoder\QRCodeGenerator.cs" />
|
||||
<Compile Include="Libs\QRCoder\SvgQRCode.cs" />
|
||||
<Compile Include="Model\vCardPropeties.cs" />
|
||||
<Compile Include="Model\Column.cs" />
|
||||
<Compile Include="Model\FixedList.cs" />
|
||||
@@ -187,6 +204,12 @@
|
||||
<Compile Include="View\MainForm.Designer.cs">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="View\QRDialog.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="View\QRDialog.Designer.cs">
|
||||
<DependentUpon>QRDialog.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="View\SortableBindingList.cs" />
|
||||
<Compile Include="View\StateTextBox.cs">
|
||||
<SubType>Component</SubType>
|
||||
@@ -238,7 +261,11 @@
|
||||
<EmbeddedResource Include="View\Customs\ExtraTextGroup.resx">
|
||||
<DependentUpon>ExtraTextGroup.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="View\QRDialog.resx">
|
||||
<DependentUpon>QRDialog.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="Libs\QRCoder\Assets\nuget-readme.md" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
@@ -255,6 +282,7 @@
|
||||
<Content Include="assests\Close.png" />
|
||||
<Content Include="assests\icons8-close-16.png" />
|
||||
<Content Include="assests\vCard.ico" />
|
||||
<Content Include="Libs\QRCoder\Assets\nuget-icon.png" />
|
||||
<Content Include="Releases.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user