mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Preliminary QR code generation support, via QRCoder.
This commit is contained in:
parent
8310edc544
commit
6c5f58d73d
9 changed files with 1687 additions and 4 deletions
|
@ -10,6 +10,7 @@ using System.Media;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using PKHeX.Saves.Substructures;
|
||||
|
||||
namespace PKHeX
|
||||
{
|
||||
|
@ -1570,7 +1571,18 @@ namespace PKHeX
|
|||
PKM pkx = preparePKM();
|
||||
byte[] ekx = pkx.EncryptedBoxData;
|
||||
const string server = "http://loadcode.projectpokemon.org/b1s1.html#"; // Rehosted with permission from LC/MS -- massive thanks!
|
||||
Image qr = QR.getQRImage(ekx, pkx.Format == 6 ? server : "null/#"); // pls no use QR on non gen6 -- bad user!
|
||||
Image qr;
|
||||
switch (pkx.Format)
|
||||
{
|
||||
case 6:
|
||||
qr = QR.getQRImage(ekx, server);
|
||||
break;
|
||||
case 7:
|
||||
qr = QR7.GenerateQRCode7((PK7) pkx);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (qr == null) return;
|
||||
|
||||
|
|
6
PKHeX/Misc/QR.Designer.cs
generated
6
PKHeX/Misc/QR.Designer.cs
generated
|
@ -42,7 +42,7 @@
|
|||
this.PB_QR.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
|
||||
this.PB_QR.Location = new System.Drawing.Point(2, 1);
|
||||
this.PB_QR.Name = "PB_QR";
|
||||
this.PB_QR.Size = new System.Drawing.Size(365, 365);
|
||||
this.PB_QR.Size = new System.Drawing.Size(405, 405);
|
||||
this.PB_QR.TabIndex = 0;
|
||||
this.PB_QR.TabStop = false;
|
||||
this.PB_QR.Click += new System.EventHandler(this.PB_QR_Click);
|
||||
|
@ -50,7 +50,7 @@
|
|||
// FontLabel
|
||||
//
|
||||
this.FontLabel.AutoSize = true;
|
||||
this.FontLabel.Location = new System.Drawing.Point(348, 353);
|
||||
this.FontLabel.Location = new System.Drawing.Point(388, 393);
|
||||
this.FontLabel.Name = "FontLabel";
|
||||
this.FontLabel.Size = new System.Drawing.Size(19, 13);
|
||||
this.FontLabel.TabIndex = 1;
|
||||
|
@ -61,7 +61,7 @@
|
|||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(369, 367);
|
||||
this.ClientSize = new System.Drawing.Size(409, 407);
|
||||
this.Controls.Add(this.FontLabel);
|
||||
this.Controls.Add(this.PB_QR);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
|
|
|
@ -213,6 +213,7 @@
|
|||
<Compile Include="Saves\SaveFile.cs" />
|
||||
<Compile Include="MysteryGifts\WC6.cs" />
|
||||
<Compile Include="Saves\Substructures\MemeCrypto.cs" />
|
||||
<Compile Include="Saves\Substructures\QR7.cs" />
|
||||
<Compile Include="Saves\Substructures\ShadowInfo.cs" />
|
||||
<Compile Include="Saves\Substructures\StrategyMemo.cs" />
|
||||
<Compile Include="Settings.cs" />
|
||||
|
@ -441,6 +442,10 @@
|
|||
<Compile Include="Util\ImageUtil.cs" />
|
||||
<Compile Include="Util\NetUtil.cs" />
|
||||
<Compile Include="Util\PathUtil.cs" />
|
||||
<Compile Include="Util\QRCoder\AbstractQRCode.cs" />
|
||||
<Compile Include="Util\QRCoder\QRCode.cs" />
|
||||
<Compile Include="Util\QRCoder\QRCodeData.cs" />
|
||||
<Compile Include="Util\QRCoder\QRCodeGenerator.cs" />
|
||||
<Compile Include="Util\RandUtil.cs" />
|
||||
<Compile Include="Util\ReflectUtil.cs" />
|
||||
<Compile Include="Util\StringUtil.cs" />
|
||||
|
|
92
PKHeX/Saves/Substructures/QR7.cs
Normal file
92
PKHeX/Saves/Substructures/QR7.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using QRCoder;
|
||||
|
||||
namespace PKHeX.Saves.Substructures
|
||||
{
|
||||
public class QR7
|
||||
{
|
||||
private static bool hasGenderDifferences(int species)
|
||||
{
|
||||
var gendered = new[]
|
||||
{
|
||||
3, 12, 19, 20, 25, 26, 41, 42, 44, 45, 64, 65, 84, 85, 97, 111, 112, 118, 119, 123, 129, 130, 154, 165, 166,
|
||||
178, 185, 186, 190, 194, 195, 198, 202, 203, 207, 208, 212, 214, 215, 217, 221, 224, 229, 232, 255, 256,
|
||||
257, 267, 269, 272, 274, 275, 307, 308, 315, 316, 317, 322, 323, 332, 350, 369, 396, 397, 398, 399, 400,
|
||||
401, 402, 403, 404, 405, 407, 415, 417, 418, 419, 424, 443, 444, 445, 449, 450, 453, 454, 456, 457, 459,
|
||||
460, 461, 464, 465, 473, 521, 592, 593, 668, 678
|
||||
};
|
||||
return gendered.Contains(species);
|
||||
}
|
||||
private static byte[] GetRawQR(int species, int formnum, bool shiny, int gender)
|
||||
{
|
||||
var basedata = "FFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000000000D20200000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000".ToByteArray();
|
||||
BitConverter.GetBytes((ushort)species).CopyTo(basedata, 0x28);
|
||||
basedata[0x2A] = (byte)formnum;
|
||||
basedata[0x2C] = (byte)(shiny ? 1 : 0);
|
||||
var forme_index = PersonalTable.SM[species].FormeIndex(species, formnum);
|
||||
var raw_gender = PersonalTable.SM[forme_index].Gender;
|
||||
switch (raw_gender)
|
||||
{
|
||||
case 0:
|
||||
basedata[0x2D] = 0;
|
||||
basedata[0x2B] = 0;
|
||||
break;
|
||||
case 0xFE:
|
||||
basedata[0x2D] = 0;
|
||||
basedata[0x2B] = 1;
|
||||
break;
|
||||
case 0xFF:
|
||||
basedata[0x2D] = 0;
|
||||
basedata[0x2B] = 2;
|
||||
break;
|
||||
default:
|
||||
basedata[0x2D] = (byte)(hasGenderDifferences(species) ? 0 : 1);
|
||||
basedata[0x2B] = (byte)gender;
|
||||
break;
|
||||
}
|
||||
return basedata;
|
||||
}
|
||||
private static byte[] GenerateQRData(PK7 pk7, int box = 0, int slot = 0)
|
||||
{
|
||||
if (box > 31)
|
||||
box = 31;
|
||||
if (slot > 29)
|
||||
slot = 29;
|
||||
if (box < 0)
|
||||
box = 0;
|
||||
if (slot < 0)
|
||||
slot = 0;
|
||||
|
||||
byte[] data = new byte[0x1A2];
|
||||
BitConverter.GetBytes(0x454B4F50).CopyTo(data, 0); // POKE magic
|
||||
data[0x5] = 0xFF; // QR Type
|
||||
BitConverter.GetBytes(box).CopyTo(data, 0x8);
|
||||
BitConverter.GetBytes(slot).CopyTo(data, 0xC);
|
||||
|
||||
pk7.EncryptedPartyData.CopyTo(data, 0x30); // Copy in pokemon data
|
||||
GetRawQR(pk7.Species, pk7.AltForm, pk7.IsShiny, pk7.Gender).CopyTo(data, 0x140);
|
||||
BitConverter.GetBytes((ushort) SaveUtil.check16(data.Take(0x1A0).ToArray(), 0)).CopyTo(data, 0x1A0);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Bitmap GenerateQRCode7(PK7 pk7, int box = 0, int slot = 0)
|
||||
{
|
||||
byte[] data = GenerateQRData(pk7, box, slot);
|
||||
using (var generator = new QRCodeGenerator())
|
||||
using (var qr_data = generator.CreateQRCode(data))
|
||||
using (var qr_code = new QRCode(qr_data))
|
||||
return qr_code.GetGraphic(4);
|
||||
}
|
||||
|
||||
public static Bitmap GenerateQRCode(byte[] data, int ppm = 4)
|
||||
{
|
||||
using (var generator = new QRCodeGenerator())
|
||||
using (var qr_data = generator.CreateQRCode(data))
|
||||
using (var qr_code = new QRCode(qr_data))
|
||||
return qr_code.GetGraphic(ppm);
|
||||
}
|
||||
}
|
||||
}
|
14
PKHeX/Util/QRCoder/AbstractQRCode.cs
Normal file
14
PKHeX/Util/QRCoder/AbstractQRCode.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
// From: https://github.com/codebude/QRCoder
|
||||
namespace QRCoder
|
||||
{
|
||||
public abstract class AbstractQRCode<T>
|
||||
{
|
||||
protected QRCodeData QrCodeData { get; set; }
|
||||
|
||||
protected AbstractQRCode(QRCodeData data) {
|
||||
this.QrCodeData = data;
|
||||
}
|
||||
|
||||
public abstract T GetGraphic(int pixelsPerModule);
|
||||
}
|
||||
}
|
138
PKHeX/Util/QRCoder/QRCode.cs
Normal file
138
PKHeX/Util/QRCoder/QRCode.cs
Normal file
|
@ -0,0 +1,138 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
// From: https://github.com/codebude/QRCoder
|
||||
namespace QRCoder
|
||||
{
|
||||
using System;
|
||||
|
||||
public class QRCode : AbstractQRCode<Bitmap>, IDisposable
|
||||
{
|
||||
public QRCode(QRCodeData data) : base(data) {}
|
||||
|
||||
public override 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);
|
||||
var gfx = Graphics.FromImage(bmp);
|
||||
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(new SolidBrush(darkColor), new Rectangle(x - offset, y - offset, pixelsPerModule, pixelsPerModule));
|
||||
}
|
||||
else
|
||||
{
|
||||
gfx.FillRectangle(new SolidBrush(lightColor), 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 = 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 = drawIconFlag ? iconDestWidth * icon.Height / icon.Width : 0;
|
||||
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)
|
||||
{
|
||||
var r = new Rectangle(x-offset, y-offset, pixelsPerModule, pixelsPerModule);
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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 void Dispose()
|
||||
{
|
||||
this.QrCodeData = null;
|
||||
}
|
||||
}
|
||||
}
|
36
PKHeX/Util/QRCoder/QRCodeData.cs
Normal file
36
PKHeX/Util/QRCoder/QRCodeData.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// From: https://github.com/codebude/QRCoder
|
||||
namespace QRCoder
|
||||
{
|
||||
using System;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
1382
PKHeX/Util/QRCoder/QRCodeGenerator.cs
Normal file
1382
PKHeX/Util/QRCoder/QRCodeGenerator.cs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -28,6 +28,10 @@ PKHeX is a Windows Forms application which requires .NET Framework v4.0.
|
|||
|
||||
The executable can be built with any compiler that supports C# 6.0.
|
||||
|
||||
## Dependencies
|
||||
|
||||
PKHeX's QR code generation code is taken from [QRCoder](https://github.com/codebude/QRCoder), which is licensed under [the MIT license](https://github.com/codebude/QRCoder/blob/master/LICENSE.txt).
|
||||
|
||||
### IDE
|
||||
|
||||
PKHeX can be opened with IDEs such as [Visual Studio](https://www.visualstudio.com/) or [MonoDevelop](http://www.monodevelop.com/) by opening the .sln or .csproj file.
|
||||
|
|
Loading…
Reference in a new issue