2015-02-25 04:10:47 +00:00
using System ;
using System.Drawing ;
2016-11-17 03:04:34 +00:00
using System.Linq ;
using System.Text ;
using System.Text.RegularExpressions ;
2016-06-20 04:22:43 +00:00
using System.Web ;
2015-02-25 04:10:47 +00:00
using System.Windows.Forms ;
2017-01-08 07:54:09 +00:00
using PKHeX.Core ;
2017-01-12 01:55:42 +00:00
using QRCoder ;
2015-02-25 04:10:47 +00:00
2017-01-08 07:54:09 +00:00
namespace PKHeX.WinForms
2015-02-25 04:10:47 +00:00
{
public partial class QR : Form
{
2016-11-29 07:02:25 +00:00
private readonly PKM pkm ;
private readonly Image icon ;
private Image qr ;
2016-11-17 03:47:41 +00:00
2017-06-18 01:37:19 +00:00
private readonly string [ ] Lines ;
2016-11-29 07:02:25 +00:00
private string extraText ;
2016-11-17 03:47:41 +00:00
2017-06-18 01:37:19 +00:00
public QR ( Image qr , Image icon , PKM pk , params string [ ] lines )
2015-02-26 07:12:38 +00:00
{
InitializeComponent ( ) ;
2016-11-17 03:47:41 +00:00
pkm = pk ;
// Layer on Text
const int stretch = 50 ;
Height + = stretch ;
2016-11-29 07:02:25 +00:00
if ( pkm ! = null & & pkm . Format = = 7 )
2016-11-17 03:47:41 +00:00
Height + = 40 ;
this . qr = qr ;
this . icon = icon ;
2017-06-18 01:37:19 +00:00
Lines = lines ;
2016-11-17 03:47:41 +00:00
if ( pkm ! = null & & pkm . Format = = 7 )
2017-06-18 01:37:19 +00:00
UpdateBoxSlotCopies ( null , null ) ;
2016-11-17 03:47:41 +00:00
else
RefreshImage ( ) ;
}
2016-11-29 07:02:25 +00:00
private void RefreshImage ( )
2016-11-17 03:47:41 +00:00
{
2017-06-18 01:37:19 +00:00
Font font = ! Main . Unicode ? FontLabel . Font : FontUtil . GetPKXFont ( ( float ) 8.25 ) ;
2015-02-26 07:12:38 +00:00
Image preview = new Bitmap ( 45 , 45 ) ;
using ( Graphics gfx = Graphics . FromImage ( preview ) )
{
gfx . FillRectangle ( new SolidBrush ( Color . White ) , 0 , 0 , preview . Width , preview . Height ) ;
2016-11-17 03:47:41 +00:00
gfx . DrawImage ( icon , preview . Width / 2 - icon . Width / 2 , preview . Height / 2 - icon . Height / 2 ) ;
2015-02-26 07:12:38 +00:00
}
2015-03-14 02:59:51 +00:00
// Layer on Preview Image
2017-01-12 01:55:42 +00:00
Image pic = ImageUtil . LayerImage ( qr , preview , qr . Width / 2 - preview . Width / 2 , qr . Height / 2 - preview . Height / 2 , 1 ) ;
2016-11-17 03:47:41 +00:00
2015-03-14 02:59:51 +00:00
Image newpic = new Bitmap ( PB_QR . Width , PB_QR . Height ) ;
2016-03-12 02:40:08 +00:00
using ( Graphics g = Graphics . FromImage ( newpic ) )
{
g . FillRectangle ( new SolidBrush ( Color . White ) , 0 , 0 , newpic . Width , newpic . Height ) ;
g . DrawImage ( pic , 0 , 0 ) ;
2015-02-26 04:19:43 +00:00
2017-06-18 01:37:19 +00:00
g . DrawString ( GetLine ( 0 ) , font , Brushes . Black , new PointF ( 18 , qr . Height - 5 ) ) ;
g . DrawString ( GetLine ( 1 ) , font , Brushes . Black , new PointF ( 18 , qr . Height + 8 ) ) ;
g . DrawString ( GetLine ( 2 ) . Replace ( Environment . NewLine , "/" ) . Replace ( "//" , " " ) . Replace ( ":/" , ": " ) , font , Brushes . Black , new PointF ( 18 , qr . Height + 20 ) ) ;
g . DrawString ( GetLine ( 3 ) + extraText , font , Brushes . Black , new PointF ( 18 , qr . Height + 32 ) ) ;
2016-03-12 02:40:08 +00:00
}
2015-03-14 02:59:51 +00:00
PB_QR . BackgroundImage = newpic ;
2015-02-25 04:10:47 +00:00
}
2016-11-17 03:47:41 +00:00
2017-06-18 01:37:19 +00:00
private string GetLine ( int line ) = > Lines . Length < = line ? string . Empty : Lines [ line ] ;
2015-02-25 04:42:05 +00:00
private void PB_QR_Click ( object sender , EventArgs e )
{
2017-01-08 07:54:09 +00:00
if ( DialogResult . Yes ! = WinFormsUtil . Prompt ( MessageBoxButtons . YesNo , "Copy QR Image to Clipboard?" ) ) return ;
2015-02-25 04:42:05 +00:00
try { Clipboard . SetImage ( PB_QR . BackgroundImage ) ; }
2017-01-08 07:54:09 +00:00
catch { WinFormsUtil . Alert ( "Failed to set Image to Clipboard" ) ; }
2015-02-25 04:42:05 +00:00
}
2016-06-20 04:22:43 +00:00
// QR Utility
2017-06-18 01:37:19 +00:00
private const string QR6PathBad = "null/#" ; // prefix to prevent URL from loading
private const string QR6Path = @"http://lunarcookies.github.io/b1s1.html#" ;
2017-08-13 07:21:42 +00:00
private const string DecodeAPI = "http://api.qrserver.com/v1/read-qr-code/?fileurl=" ;
private const int QRSize = 365 ;
private static readonly string EncodeAPI = $"http://chart.apis.google.com/chart?chs={QRSize}x{QRSize}&cht=qr&chl=" ;
2017-03-11 04:35:18 +00:00
2017-07-03 04:27:22 +00:00
internal static byte [ ] GetQRData ( string address )
2016-06-20 04:22:43 +00:00
{
// Fetch data from QR code...
2017-08-13 07:21:42 +00:00
try { if ( address . Length < 4 | | ! address . StartsWith ( "http" ) ) { WinFormsUtil . Alert ( "Clipboard text is not a valid URL:" , address ) ; return null ; } }
2017-01-08 07:54:09 +00:00
catch { WinFormsUtil . Alert ( "Clipboard text is not a valid URL:" , address ) ; return null ; }
2017-08-13 07:21:42 +00:00
string webURL = DecodeAPI + HttpUtility . UrlEncode ( address ) ;
string data ;
2016-06-20 04:22:43 +00:00
try
{
2017-08-13 07:21:42 +00:00
data = NetUtil . GetStringFromURL ( webURL ) ;
2017-01-08 07:54:09 +00:00
if ( data . Contains ( "could not find" ) ) { WinFormsUtil . Alert ( "Reader could not find QR data in the image." ) ; return null ; }
if ( data . Contains ( "filetype not supported" ) ) { WinFormsUtil . Alert ( "Input URL is not valid. Double check that it is an image (jpg/png)." , address ) ; return null ; }
2016-06-20 04:22:43 +00:00
}
2017-01-08 07:54:09 +00:00
catch { WinFormsUtil . Alert ( "Unable to connect to the internet to decode QR code." ) ; return null ; }
2017-08-13 07:21:42 +00:00
// Quickly convert the json response to a data string
try { return DecodeQRJson ( data ) ; }
catch ( Exception e ) { WinFormsUtil . Alert ( "QR string to Data failed." , e . Message ) ; return null ; }
}
private static byte [ ] DecodeQRJson ( string data )
{
const string cap = "\",\"error\":null}]}]" ;
const string intro = "[{\"type\":\"qrcode\",\"symbol\":[{\"seq\":0,\"data\":\"" ;
const string qrcode = "nQR-Code:" ;
if ( ! data . StartsWith ( intro ) )
throw new FormatException ( ) ;
string pkstr = data . Substring ( intro . Length ) ;
if ( pkstr . Contains ( qrcode ) ) // Remove multiple QR codes in same image
pkstr = pkstr . Substring ( 0 , pkstr . IndexOf ( qrcode , StringComparison . Ordinal ) ) ;
pkstr = pkstr . Substring ( 0 , pkstr . IndexOf ( cap , StringComparison . Ordinal ) ) ; // Trim outro
if ( ! pkstr . StartsWith ( "http" ) & & ! pkstr . StartsWith ( QR6PathBad ) ) // G7
{
string fstr = Regex . Unescape ( pkstr ) ;
byte [ ] raw = Encoding . Unicode . GetBytes ( fstr ) ;
// Remove 00 interstitials and retrieve from offset 0x30, take PK7 Stored Size (always)
return raw . ToList ( ) . Where ( ( c , i ) = > i % 2 = = 0 ) . Skip ( 0x30 ) . Take ( 0xE8 ) . ToArray ( ) ;
}
// All except G7
pkstr = pkstr . Substring ( pkstr . IndexOf ( "#" , StringComparison . Ordinal ) + 1 ) ; // Trim URL
pkstr = pkstr . Replace ( "\\" , "" ) ; // Rectify response
return Convert . FromBase64String ( pkstr ) ;
2016-06-20 04:22:43 +00:00
}
2017-08-13 07:21:42 +00:00
2017-06-18 01:37:19 +00:00
internal static Image GetQRImage ( byte [ ] data , string server )
2016-06-20 04:22:43 +00:00
{
string qrdata = Convert . ToBase64String ( data ) ;
string message = server + qrdata ;
2017-08-13 07:21:42 +00:00
string webURL = EncodeAPI + HttpUtility . UrlEncode ( message ) ;
2016-06-20 04:22:43 +00:00
try
{
2017-06-18 01:37:19 +00:00
return NetUtil . GetImageFromURL ( webURL ) ;
2016-06-20 04:22:43 +00:00
}
catch
{
2017-01-08 07:54:09 +00:00
if ( DialogResult . Yes ! = WinFormsUtil . Prompt ( MessageBoxButtons . YesNo , "Unable to connect to the internet to receive QR code." , "Copy QR URL to Clipboard?" ) )
2016-06-20 04:22:43 +00:00
return null ;
try { Clipboard . SetText ( webURL ) ; }
2017-01-08 07:54:09 +00:00
catch { WinFormsUtil . Alert ( "Failed to set text to Clipboard" ) ; }
2016-06-20 04:22:43 +00:00
}
return null ;
}
2016-11-17 03:47:41 +00:00
2017-06-18 01:37:19 +00:00
private void UpdateBoxSlotCopies ( object sender , EventArgs e )
2016-11-17 03:47:41 +00:00
{
if ( pkm = = null | | pkm . Format ! = 7 )
throw new ArgumentException ( "Can't update QR7 if pkm isn't a PK7!" ) ;
var box = ( int ) NUD_Box . Value - 1 ;
var slot = ( int ) NUD_Slot . Value - 1 ;
var copies = ( int ) NUD_Copies . Value ;
2017-01-12 01:55:42 +00:00
var new_qr = GenerateQRCode7 ( ( PK7 ) pkm , box , slot , copies ) ;
2016-11-17 03:47:41 +00:00
qr = new_qr ;
2016-11-29 07:02:25 +00:00
SuspendLayout ( ) ;
extraText = $" (Box {box+1}, Slot {slot+1}, {copies} cop{(copies > 1 ? " ies " : " y ")})" ;
2016-11-17 03:47:41 +00:00
RefreshImage ( ) ;
2016-11-29 07:02:25 +00:00
ResumeLayout ( ) ;
2016-11-17 03:47:41 +00:00
}
2017-01-12 01:55:42 +00:00
// QR7 Utility
public static Image GenerateQRCode7 ( PK7 pk7 , int box = 0 , int slot = 0 , int num_copies = 1 )
{
byte [ ] data = QR7 . GenerateQRData ( pk7 , box , slot , num_copies ) ;
2017-08-13 07:21:42 +00:00
return GenerateQRCode ( data , ppm : 4 ) ;
2017-01-12 01:55:42 +00:00
}
2017-08-13 07:21:42 +00:00
private static Image GenerateQRCode ( byte [ ] data , int ppm = 4 )
2017-01-12 01:55:42 +00:00
{
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 ) ;
}
2017-03-11 04:35:18 +00:00
2017-06-18 01:37:19 +00:00
public static string GetQRServer ( int format )
2017-03-11 04:35:18 +00:00
{
switch ( format )
{
case 6 :
return QR6Path ;
default :
2017-06-18 01:37:19 +00:00
return QR6PathBad ;
2017-03-11 04:35:18 +00:00
}
}
2015-02-25 04:10:47 +00:00
}
2017-05-15 20:07:07 +00:00
}