How can I generate circular QR codes? I would like to generate a QR code that is drawn with circles instead of squares. I currently have this code:
public Bitmap GenerateQR(string text)
{
BarcodeWriter br = new BarcodeWriter();
EncodingOptions encodingOptions = new EncodingOptions()
{
Width = 300,
Height = 300,
Margin = 1,
PureBarcode = false,
};
encodingOptions.Hints.Add(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
br.Options = encodingOptions;
br.Format = BarcodeFormat.QR_CODE;
if (!string.IsNullOrWhiteSpace(text))
{
br.Renderer = new BitmapRenderer()
{
Foreground = Color.Black,
Background = Color.White,
};
return br.Write(texto);
}
}
I use C# and the Zxing library.
I need something like this:
Well, it's not a straightforward approach. But based on the @Curtis Yallop answer here.
Here is the C# equivalent implementation.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using ZXing;
using ZXing.Common;
using ZXing.QrCode.Internal;
using Encoder = ZXing.QrCode.Internal.Encoder;
class Program
{
static void Main()
{
try
{
GenerateQRCodeImage("https://www.google.com", 300, 300, "./MyQRCode.png");
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void GenerateQRCodeImage(string text, int width, int height, string filePath)
{
Dictionary<EncodeHintType, object> encodingHints = new Dictionary<EncodeHintType, object>
{
{ EncodeHintType.CHARACTER_SET, "UTF-8" }
};
QRCode code = System.Drawing.Imaging.Encoder.encode(text, ErrorCorrectionLevel.H, encodingHints);
Bitmap image = RenderQRImage(code, width, height, 4);
using (FileStream stream = new FileStream(filePath, FileMode.Create))
{
image.Save(stream, ImageFormat.Png);
}
}
private static Bitmap RenderQRImage(QRCode code, int width, int height, int quietZone)
{
Bitmap image = new Bitmap(width, height);
using (Graphics graphics = Graphics.FromImage(image))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.Clear(Color.White);
graphics.DrawImage(image, 0, 0, width, height);
ByteMatrix input = code.Matrix;
if (input == null)
{
throw new InvalidOperationException();
}
int inputWidth = input.Width;
int inputHeight = input.Height;
int qrWidth = inputWidth + (quietZone * 2);
int qrHeight = inputHeight + (quietZone * 2);
int outputWidth = Math.Max(width, qrWidth);
int outputHeight = Math.Max(height, qrHeight);
int multiple = Math.Min(outputWidth / qrWidth, outputHeight / qrHeight);
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
const int FINDER_PATTERN_SIZE = 7;
const float CIRCLE_SCALE_DOWN_FACTOR = 21f / 30f;
int circleSize = (int)(multiple * CIRCLE_SCALE_DOWN_FACTOR);
for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple)
{
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple)
{
if (input[inputX, inputY] == 1)
{
if (!(inputX <= FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE ||
inputX >= inputWidth - FINDER_PATTERN_SIZE && inputY <= FINDER_PATTERN_SIZE ||
inputX <= FINDER_PATTERN_SIZE && inputY >= inputHeight - FINDER_PATTERN_SIZE))
{
graphics.FillEllipse(Brushes.Black, outputX, outputY, circleSize, circleSize);
}
}
}
}
int circleDiameter = multiple * FINDER_PATTERN_SIZE;
DrawFinderPatternCircleStyle(graphics, leftPadding, topPadding, circleDiameter);
DrawFinderPatternCircleStyle(graphics, leftPadding + (inputWidth - FINDER_PATTERN_SIZE) * multiple, topPadding, circleDiameter);
DrawFinderPatternCircleStyle(graphics, leftPadding, topPadding + (inputHeight - FINDER_PATTERN_SIZE) * multiple, circleDiameter);
}
return image;
}
private static void DrawFinderPatternCircleStyle(Graphics graphics, int x, int y, int circleDiameter)
{
var WHITE_CIRCLE_DIAMETER = 5 * circleDiameter / 7;
var WHITE_CIRCLE_OFFSET = circleDiameter / 7;
var MIDDLE_DOT_DIAMETER = 3 * circleDiameter / 7;
var MIDDLE_DOT_OFFSET = 2 * circleDiameter / 7;
graphics.FillEllipse(Brushes.Black, x, y, circleDiameter, circleDiameter);
graphics.FillEllipse(Brushes.White, x + WHITE_CIRCLE_OFFSET, y + WHITE_CIRCLE_OFFSET, WHITE_CIRCLE_DIAMETER, WHITE_CIRCLE_DIAMETER);
graphics.FillEllipse(Brushes.Black, x + MIDDLE_DOT_OFFSET, y + MIDDLE_DOT_OFFSET, MIDDLE_DOT_DIAMETER, MIDDLE_DOT_DIAMETER);
}
}