Skip to content

Commit 378a5fa

Browse files
committed
Improved logo and background handling
1 parent 0c3bc02 commit 378a5fa

File tree

1 file changed

+49
-7
lines changed

1 file changed

+49
-7
lines changed

QRCoder/SvgQRCode.cs

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex
5454
double pixelsPerModule = Math.Min(viewBox.Width, viewBox.Height) / (double)drawableModulesCount;
5555
double qrSize = drawableModulesCount * pixelsPerModule;
5656
string svgSizeAttributes = (sizingMode == SizingMode.WidthHeightAttribute) ? $@"width=""{viewBox.Width}"" height=""{viewBox.Height}""" : $@"viewBox=""0 0 {viewBox.Width} {viewBox.Height}""";
57+
ImageAttributes? logoAttr = null;
58+
if (logo != null)
59+
logoAttr = GetLogoAttributes(logo, viewBox);
5760

5861
// Merge horizontal rectangles
5962
int[,] matrix = new int[drawableModulesCount, drawableModulesCount];
@@ -66,7 +69,7 @@ public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex
6669
for (int xi = 0; xi < drawableModulesCount; xi += 1)
6770
{
6871
matrix[yi, xi] = 0;
69-
if (bitArray[xi+offset])
72+
if (bitArray[xi+offset] && !IsBlockedByLogo((xi+offset)*pixelsPerModule, (yi+offset) * pixelsPerModule, logoAttr, pixelsPerModule))
7073
{
7174
if(x0 == -1)
7275
{
@@ -91,7 +94,7 @@ public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex
9194
}
9295
}
9396

94-
StringBuilder svgFile = new StringBuilder($@"<svg version=""1.1"" baseProfile=""full"" shape-rendering=""crispEdges"" {svgSizeAttributes} xmlns=""http://www.w3.org/2000/svg"">");
97+
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"">");
9598
svgFile.AppendLine($@"<rect x=""0"" y=""0"" width=""{CleanSvgVal(qrSize)}"" height=""{CleanSvgVal(qrSize)}"" fill=""{lightColorHex}"" />");
9699
for (int yi = 0; yi < drawableModulesCount; yi += 1)
97100
{
@@ -118,23 +121,55 @@ public string GetGraphic(Size viewBox, string darkColorHex, string lightColorHex
118121

119122
// Output SVG rectangles
120123
double x = xi * pixelsPerModule;
121-
svgFile.AppendLine($@"<rect x=""{CleanSvgVal(x)}"" y=""{CleanSvgVal(y)}"" width=""{CleanSvgVal(xL * pixelsPerModule)}"" height=""{CleanSvgVal(yL * pixelsPerModule)}"" fill=""{darkColorHex}"" />");
124+
if (!IsBlockedByLogo(x, y, logoAttr, pixelsPerModule))
125+
svgFile.AppendLine($@"<rect x=""{CleanSvgVal(x)}"" y=""{CleanSvgVal(y)}"" width=""{CleanSvgVal(xL * pixelsPerModule)}"" height=""{CleanSvgVal(yL * pixelsPerModule)}"" fill=""{darkColorHex}"" />");
126+
122127
}
123128
}
124129
}
125130

126131
//Render logo, if set
127132
if (logo != null)
128-
{
133+
{
129134
svgFile.AppendLine($@"<svg width=""100%"" height=""100%"" version=""1.1"" xmlns = ""http://www.w3.org/2000/svg"">");
130-
svgFile.AppendLine($@"<image x=""{50 - (logo.GetIconSizePercent() / 2)}%"" y=""{50 - (logo.GetIconSizePercent() / 2)}%"" width=""{logo.GetIconSizePercent()}%"" height=""{logo.GetIconSizePercent()}%"" href=""{logo.GetDataUri()}"" />");
135+
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()}"" />");
131136
svgFile.AppendLine(@"</svg>");
132137
}
133138

134139
svgFile.Append(@"</svg>");
135140
return svgFile.ToString();
136141
}
137142

143+
private bool IsBlockedByLogo(double x, double y, ImageAttributes? attr, double pixelPerModule)
144+
{
145+
if (attr == null)
146+
return false;
147+
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;
148+
}
149+
150+
private ImageAttributes GetLogoAttributes(SvgLogo logo, Size viewBox)
151+
{
152+
var imgWidth = logo.GetIconSizePercent() / 100d * viewBox.Width;
153+
var imgHeight = logo.GetIconSizePercent() / 100d * viewBox.Height;
154+
var imgPosX = viewBox.Width / 2d - imgWidth / 2d;
155+
var imgPosY = viewBox.Height / 2d - imgHeight / 2d;
156+
return new ImageAttributes()
157+
{
158+
Width = imgWidth,
159+
Height = imgHeight,
160+
X = imgPosX,
161+
Y = imgPosY
162+
};
163+
}
164+
165+
private struct ImageAttributes
166+
{
167+
public double Width;
168+
public double Height;
169+
public double X;
170+
public double Y;
171+
}
172+
138173
private string CleanSvgVal(double input)
139174
{
140175
//Clean double values for international use/formats
@@ -152,13 +187,14 @@ public class SvgLogo
152187
private string _logoData;
153188
private string _mediaType;
154189
private int _iconSizePercent;
190+
private bool _fillLogoBackground;
155191

156192
/// <summary>
157193
/// Create a logo object to be used in SvgQRCode renderer
158194
/// </summary>
159195
/// <param name="iconRasterized">Logo to be rendered as Bitmap/rasterized graphic</param>
160196
/// <param name="iconSizePercent">Degree of percentage coverage of the QR code by the logo</param>
161-
public SvgLogo(Bitmap iconRasterized, int iconSizePercent = 15)
197+
public SvgLogo(Bitmap iconRasterized, int iconSizePercent = 15, bool fillLogoBackground = true)
162198
{
163199
_iconSizePercent = iconSizePercent;
164200
using (var ms = new System.IO.MemoryStream())
@@ -170,18 +206,20 @@ public SvgLogo(Bitmap iconRasterized, int iconSizePercent = 15)
170206
}
171207
}
172208
_mediaType = "image/png";
209+
_fillLogoBackground = fillLogoBackground;
173210
}
174211

175212
/// <summary>
176213
/// Create a logo object to be used in SvgQRCode renderer
177214
/// </summary>
178215
/// <param name="iconVectorized">Logo to be rendered as SVG/vectorized graphic/string</param>
179216
/// <param name="iconSizePercent">Degree of percentage coverage of the QR code by the logo</param>
180-
public SvgLogo(string iconVectorized, int iconSizePercent = 15)
217+
public SvgLogo(string iconVectorized, int iconSizePercent = 15, bool fillLogoBackground = true)
181218
{
182219
_iconSizePercent = iconSizePercent;
183220
_logoData = Convert.ToBase64String(Encoding.UTF8.GetBytes(iconVectorized), Base64FormattingOptions.None);
184221
_mediaType = "image/svg+xml";
222+
_fillLogoBackground = fillLogoBackground;
185223
}
186224

187225
public string GetDataUri()
@@ -193,6 +231,10 @@ public int GetIconSizePercent()
193231
{
194232
return _iconSizePercent;
195233
}
234+
public bool FillLogoBackground()
235+
{
236+
return _fillLogoBackground;
237+
}
196238
}
197239
}
198240

0 commit comments

Comments
 (0)