Skip to content

Commit

Permalink
Refactor QR Dialog (#101)
Browse files Browse the repository at this point in the history
* Refactor QR portion
* Use UIUtil.ShowDialogAndDestroy
* Renamed caption of the form and set a minimal size

Co-authored-by: dannoe <github@dannoe.de>
  • Loading branch information
robinvanpoppel and dannoe committed Apr 11, 2020
1 parent 2bcd3af commit 0617625
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 392 deletions.
1 change: 0 additions & 1 deletion KeeTrayTOTP/KeeTrayTOTP.csproj
Expand Up @@ -103,7 +103,6 @@
<Compile Include="ShowQR.Designer.cs">
<DependentUpon>ShowQR.cs</DependentUpon>
</Compile>
<Compile Include="Libraries\QRCoder\Stream4Methods.cs" />
<Compile Include="TrayTOTP_CustomColumn.cs" />
<Compile Include="TrayTOTP_Extensions.cs" />
<Compile Include="FormHelp.cs">
Expand Down
129 changes: 20 additions & 109 deletions KeeTrayTOTP/Libraries/QRCoder/QRCode.cs
Expand Up @@ -22,145 +22,56 @@
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

using System.Drawing;
using System.Drawing.Drawing2D;

namespace QRCoder
{
using System;
using System.Drawing;

public sealed class QRCode : IDisposable
{
public QRCodeData QrCodeData { get; private set; }

public void Dispose()
{
this.QrCodeData = null;
}
/// <summary>
/// Constructor without params to be used in COM Objects connections
/// </summary>
public QRCode() { }
private QRCodeData QrCodeData;
private static readonly SolidBrush darkBrush = new SolidBrush(Color.Black);
private static readonly SolidBrush lightBrush = new SolidBrush(Color.White);

public QRCode(QRCodeData data)
{
this.QrCodeData = 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)
public Bitmap GetGraphic(int pixelsPerModule, 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);
var gfx = Graphics.FromImage(bmp);
for (var x = 0; x < size + offset; x = x + pixelsPerModule)
using (var gfx = Graphics.FromImage(bmp))
{
for (var y = 0; y < size + offset; y = y + pixelsPerModule)
for (var x = 0; x < size + offset; x += pixelsPerModule)
{
var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
var rect = new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule);
var brush = module ? new SolidBrush(darkColor) : new SolidBrush(lightColor);
gfx.FillRectangle(brush, rect);
}
}

gfx.Save();
return bmp;
}

public Bitmap GetGraphic(int pixelsPerModule, Color darkColor, Color lightColor, Bitmap icon = null, int iconSizePercent = 15, int iconBorderWidth = 6, 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, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

var gfx = Graphics.FromImage(bmp);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.CompositingQuality = CompositingQuality.HighQuality;
gfx.Clear(lightColor);

var drawIconFlag = icon != null && iconSizePercent > 0 && iconSizePercent <= 100;

GraphicsPath iconPath = null;
float iconDestWidth = 0, iconDestHeight = 0, iconX = 0, iconY = 0;

if (drawIconFlag)
{
iconDestWidth = iconSizePercent * bmp.Width / 100f;
iconDestHeight = iconDestWidth * icon.Height / icon.Width;
iconX = (bmp.Width - iconDestWidth) / 2;
iconY = (bmp.Height - iconDestHeight) / 2;

var centerDest = new RectangleF(iconX - iconBorderWidth, iconY - iconBorderWidth, iconDestWidth + iconBorderWidth * 2, iconDestHeight + iconBorderWidth * 2);
iconPath = this.CreateRoundedRectanglePath(centerDest, iconBorderWidth * 2);
}

var lightBrush = new SolidBrush(lightColor);
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)
for (var y = 0; y < size + offset; y += pixelsPerModule)
{
var r = new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule);
var module = this.QrCodeData.ModuleMatrix[(y + pixelsPerModule) / pixelsPerModule - 1][(x + pixelsPerModule) / pixelsPerModule - 1];
var rect = new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule);
var brush = module ? darkBrush : lightBrush;

if (drawIconFlag)
{
var region = new Region(r);
region.Exclude(iconPath);
gfx.FillRegion(darkBrush, region);
}
else
{
gfx.FillRectangle(darkBrush, r);
}
}
else
{
gfx.FillRectangle(lightBrush, new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
gfx.FillRectangle(brush, rect);
}
}
}

if (drawIconFlag)
{
var iconDestRect = new RectangleF(iconX, iconY, iconDestWidth, iconDestHeight);
gfx.DrawImage(icon, iconDestRect, new RectangleF(0, 0, icon.Width, icon.Height), GraphicsUnit.Pixel);
gfx.Save();
}

gfx.Save();
return bmp;
}

internal GraphicsPath CreateRoundedRectanglePath(RectangleF rect, int cornerRadius)
public void Dispose()
{
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;
if (this.QrCodeData != null)
{
QrCodeData.Dispose();
}

this.QrCodeData = null;
}
}
}
142 changes: 2 additions & 140 deletions KeeTrayTOTP/Libraries/QRCoder/QRCodeData.cs
Expand Up @@ -25,17 +25,14 @@

using System.Collections;
using System.Collections.Generic;
using QRCoder.Framework4._0Methods;

namespace QRCoder
{
using System;
using System.IO;
using System.IO.Compression;

public class QRCodeData : IDisposable
public sealed class QRCodeData : IDisposable
{
public List<BitArray> ModuleMatrix { get; set; }
public List<BitArray> ModuleMatrix { get; private set; }

public QRCodeData(int version)
{
Expand All @@ -47,134 +44,6 @@ public QRCodeData(int version)
this.ModuleMatrix.Add(new BitArray(size));
}
}
public QRCodeData(byte[] rawData, Compression compressMode)
{
var bytes = new List<byte>(rawData);

//Decompress
if (compressMode.Equals(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.Equals(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>();
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>();
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.Equals(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.Equals(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;
}

public int Version { get; private set; }

Expand All @@ -188,12 +57,5 @@ public void Dispose()
this.ModuleMatrix = null;
this.Version = 0;
}

public enum Compression
{
Uncompressed,
Deflate,
GZip
}
}
}

0 comments on commit 0617625

Please sign in to comment.