Skip to content

Commit 9d34982

Browse files
authored
Merge pull request #295 from NigelThorne/seethough_barcodes
Barcodes you can use backgrounds with.
2 parents 079c236 + 0853545 commit 9d34982

File tree

2 files changed

+178
-10
lines changed

2 files changed

+178
-10
lines changed

QRCoder/ArtQRCode.cs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#if NETFRAMEWORK || NETSTANDARD2_0 || NET5_0
2+
3+
using System;
4+
using System.Drawing;
5+
using System.Drawing.Drawing2D;
6+
7+
// pull request raised to extend library used.
8+
namespace QRCoder
9+
{
10+
public class ArtQRCode : AbstractQRCode, IDisposable
11+
{
12+
/// <summary>
13+
/// Constructor without params to be used in COM Objects connections
14+
/// </summary>
15+
public ArtQRCode() { }
16+
17+
public ArtQRCode(QRCodeData data) : base(data) { }
18+
19+
public Bitmap GetGraphic(int pixelsPerModule)
20+
{
21+
return this.GetGraphic(pixelsPerModule, (pixelsPerModule * 8) / 10, Color.Black, Color.White);
22+
}
23+
24+
public Bitmap GetGraphic(Bitmap backgroundImage = null)
25+
{
26+
return this.GetGraphic(10, 7, Color.Black, Color.White, backgroundImage: backgroundImage);
27+
}
28+
29+
public Bitmap GetGraphic(
30+
int pixelsPerModule,
31+
int pixelSize,
32+
Color darkColor,
33+
Color lightColor,
34+
bool drawQuietZones = false,
35+
Bitmap reticleImage = null,
36+
Bitmap backgroundImage = null)
37+
{
38+
var numModules = this.QrCodeData.ModuleMatrix.Count - (drawQuietZones ? 0 : 8);
39+
var offset = (drawQuietZones ? 0 : 4);
40+
var size = numModules * pixelsPerModule;
41+
42+
var bitmap = Resize(backgroundImage,size) ?? new Bitmap(size, size);
43+
44+
using (var graphics = Graphics.FromImage(bitmap))
45+
{
46+
using (var lightBrush = new SolidBrush(lightColor))
47+
{
48+
using (var darkBrush = new SolidBrush(darkColor))
49+
{
50+
// make background transparent if you don't have an image -- not sure this is needed
51+
if (backgroundImage == null)
52+
{
53+
using (var brush = new SolidBrush(Color.Transparent))
54+
{
55+
graphics.FillRectangle(brush, new Rectangle(0, 0, size, size));
56+
}
57+
}
58+
59+
var darkModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, darkBrush);
60+
var lightModulePixel = MakeDotPixel(pixelsPerModule, pixelSize, lightBrush);
61+
62+
for (var x = 0; x < numModules; x += 1)
63+
{
64+
for (var y = 0; y < numModules; y += 1)
65+
{
66+
var rectangleF = new Rectangle(x * pixelsPerModule, y * pixelsPerModule, pixelsPerModule, pixelsPerModule);
67+
68+
var pixelIsDark = this.QrCodeData.ModuleMatrix[offset + y][offset + x];
69+
var solidBrush = pixelIsDark ? darkBrush : lightBrush;
70+
var pixelImage = pixelIsDark ? darkModulePixel : lightModulePixel;
71+
72+
if (!IsPartOfReticle(x, y, numModules, offset))
73+
graphics.DrawImage(pixelImage, rectangleF);
74+
else if (reticleImage == null)
75+
graphics.FillRectangle(solidBrush, rectangleF);
76+
}
77+
}
78+
79+
if (reticleImage != null)
80+
{
81+
var reticleSize = 7 * pixelsPerModule;
82+
graphics.DrawImage(reticleImage, new Rectangle(0, 0, reticleSize, reticleSize));
83+
graphics.DrawImage(reticleImage, new Rectangle(size - reticleSize, 0, reticleSize, reticleSize));
84+
graphics.DrawImage(reticleImage, new Rectangle(0, size - reticleSize, reticleSize, reticleSize));
85+
}
86+
87+
graphics.Save();
88+
}
89+
}
90+
}
91+
return bitmap;
92+
}
93+
94+
/// <summary>
95+
/// If the pixelSize is bigger than the pixelsPerModule or may end up filling the Module making a traditional QR code.
96+
/// </summary>
97+
/// <param name="pixelsPerModule"></param>
98+
/// <param name="pixelSize"></param>
99+
/// <param name="brush"></param>
100+
/// <returns></returns>
101+
private Bitmap MakeDotPixel(int pixelsPerModule, int pixelSize, SolidBrush brush)
102+
{
103+
// draw a dot
104+
var bitmap = new Bitmap(pixelSize, pixelSize);
105+
using (var graphics = Graphics.FromImage(bitmap))
106+
{
107+
graphics.FillEllipse(brush, new Rectangle(0, 0, pixelSize, pixelSize));
108+
graphics.Save();
109+
}
110+
111+
var pixelWidth = Math.Min(pixelsPerModule, pixelSize);
112+
var margin = Math.Max((pixelsPerModule - pixelWidth) / 2, 0);
113+
114+
// center the dot in the module and crop to stay the right size.
115+
var cropped = new Bitmap(pixelsPerModule, pixelsPerModule);
116+
using (var graphics = Graphics.FromImage(cropped))
117+
{
118+
graphics.DrawImage(bitmap, new Rectangle(margin, margin, pixelWidth, pixelWidth),
119+
new RectangleF(((float)pixelSize - pixelWidth) / 2, ((float)pixelSize - pixelWidth) / 2, pixelWidth, pixelWidth),
120+
GraphicsUnit.Pixel);
121+
graphics.Save();
122+
}
123+
124+
return cropped;
125+
}
126+
127+
private bool IsPartOfReticle(int x, int y, int numModules, int offset)
128+
{
129+
var cornerSize = 11 - offset;
130+
return
131+
(x < cornerSize && y < cornerSize) ||
132+
(x > (numModules - cornerSize - 1) && y < cornerSize) ||
133+
(x < cornerSize && y > (numModules - cornerSize - 1));
134+
}
135+
136+
/// <summary>
137+
/// Resize to a square bitmap, but maintain the aspect ratio by padding transparently.
138+
/// </summary>
139+
///
140+
/// <param name="image"></param>
141+
/// <param name="newSize"></param>
142+
/// <returns></returns>
143+
private Bitmap Resize(Bitmap image, int newSize)
144+
{
145+
if (image == null) return null;
146+
147+
float scale = Math.Min((float)newSize / image.Width, (float)newSize / image.Height);
148+
var scaledWidth = (int)(image.Width * scale);
149+
var scaledHeight = (int)(image.Height * scale);
150+
var offsetX = (newSize - scaledWidth) / 2;
151+
var offsetY = (newSize - scaledHeight) / 2;
152+
153+
var scaledImage = new Bitmap(image, new Size(scaledWidth, scaledHeight));
154+
155+
var bm = new Bitmap(newSize, newSize);
156+
157+
using (Graphics graphics = Graphics.FromImage(bm))
158+
{
159+
using (var brush = new SolidBrush(Color.Transparent))
160+
{
161+
graphics.FillRectangle(brush, new Rectangle(0, 0, newSize, newSize));
162+
163+
graphics.InterpolationMode = InterpolationMode.High;
164+
graphics.CompositingQuality = CompositingQuality.HighQuality;
165+
graphics.SmoothingMode = SmoothingMode.AntiAlias;
166+
167+
graphics.DrawImage(scaledImage, new Rectangle(offsetX, offsetY, scaledWidth, scaledHeight));
168+
}
169+
}
170+
171+
return bm;
172+
}
173+
}
174+
}
175+
176+
#endif

QRCoder/QRCode.cs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,9 @@ public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor,
9393
{
9494
for (var y = 0; y < size + offset; y = y + pixelsPerModule)
9595
{
96-
var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
96+
var moduleBrush = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1] ? darkBrush : lightBrush;
9797

98-
if (module)
99-
{
100-
var r = new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule);
101-
gfx.FillRectangle(darkBrush, r);
102-
}
103-
else
104-
{
105-
gfx.FillRectangle(lightBrush, new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
106-
}
98+
gfx.FillRectangle(moduleBrush , new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
10799
}
108100
}
109101

0 commit comments

Comments
 (0)