Skip to content

Commit 289a0f6

Browse files
committed
Qr Code Analyzer
1 parent 0bdc517 commit 289a0f6

15 files changed

Lines changed: 782 additions & 2 deletions

QrCodeAnalyzer/App.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Application x:Class="Net.Codecrete.QrCodeGenerator.Analyzer.App"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="clr-namespace:Net.Codecrete.QrCodeGenerator.Analyzer"
5+
StartupUri="MainWindow.xaml">
6+
<Application.Resources>
7+
8+
</Application.Resources>
9+
</Application>

QrCodeAnalyzer/App.xaml.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// QR code generator library (.NET)
3+
// https://github.com/manuelbl/QrCodeGenerator
4+
//
5+
// Copyright (c) 2021 Manuel Bleichenbacher
6+
// Licensed under MIT License
7+
// https://opensource.org/licenses/MIT
8+
//
9+
10+
using System.Windows;
11+
12+
namespace Net.Codecrete.QrCodeGenerator.Analyzer
13+
{
14+
/// <summary>
15+
/// Interaction logic for AnalyzerApp.xaml
16+
/// </summary>
17+
public partial class App : Application
18+
{
19+
}
20+
}

QrCodeAnalyzer/AssemblyInfo.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// QR code generator library (.NET)
3+
// https://github.com/manuelbl/QrCodeGenerator
4+
//
5+
// Copyright (c) 2021 Manuel Bleichenbacher
6+
// Licensed under MIT License
7+
// https://opensource.org/licenses/MIT
8+
//
9+
10+
using System.Windows;
11+
12+
[assembly: ThemeInfo(
13+
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
14+
//(used if a resource is not found in the page,
15+
// or application resource dictionaries)
16+
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
17+
//(used if a resource is not found in the page,
18+
// app, or any theme specific resource dictionaries)
19+
)]

QrCodeAnalyzer/MainWindow.xaml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<Window x:Class="Net.Codecrete.QrCodeGenerator.Analyzer.MainWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:local="clr-namespace:Net.Codecrete.QrCodeGenerator.Analyzer"
7+
mc:Ignorable="d"
8+
Title="QR Code" Height="400" Width="600"
9+
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
10+
<Grid Margin="20,16,20,16">
11+
<Grid.ColumnDefinitions>
12+
<ColumnDefinition Width="1*"/>
13+
<ColumnDefinition Width="Auto"/>
14+
</Grid.ColumnDefinitions>
15+
<Grid.RowDefinitions>
16+
<RowDefinition Height="1*"/>
17+
<RowDefinition Height="Auto"/>
18+
</Grid.RowDefinitions>
19+
<Image Source="{Binding Path=QrCodeImage}" Grid.Row="0" Grid.Column="0" Margin="0,0,0,16"
20+
RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased"/>
21+
<Grid Grid.Row="0" Grid.Column="1">
22+
<Grid.ColumnDefinitions>
23+
<ColumnDefinition Width="Auto"/>
24+
<ColumnDefinition Width="Auto"/>
25+
</Grid.ColumnDefinitions>
26+
<Grid.RowDefinitions>
27+
<RowDefinition Height="Auto"/>
28+
<RowDefinition Height="Auto"/>
29+
<RowDefinition Height="Auto"/>
30+
<RowDefinition Height="Auto"/>
31+
<RowDefinition Height="Auto"/>
32+
<RowDefinition Height="Auto"/>
33+
<RowDefinition Height="Auto"/>
34+
</Grid.RowDefinitions>
35+
<Label Content="Horz. Streaks:" Grid.Row="0" Grid.Column="0" Background="Transparent" Cursor="Hand" Tag="HorizontalStreaks"
36+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
37+
<Label Content="{Binding Path=PenaltyDetails.HorizontalStreaks}" Grid.Row="0" Grid.Column="1" Background="Transparent" Cursor="Hand" Tag="HorizontalStreaks"
38+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
39+
<Label Content="Vert. Streaks:" Grid.Row="1" Grid.Column="0" Background="Transparent" Cursor="Hand" Tag="VerticalStreaks"
40+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
41+
<Label Content="{Binding Path=PenaltyDetails.VerticalStreaks}" Grid.Row="1" Grid.Column="1" Background="Transparent" Cursor="Hand" Tag="VerticalStreaks"
42+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
43+
<Label Content="Boxes:" Grid.Row="2" Grid.Column="0" Background="Transparent" Cursor="Hand" Tag="Blocks"
44+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
45+
<Label Content="{Binding Path=PenaltyDetails.Blocks}" Grid.Row="2" Grid.Column="1" Background="Transparent" Cursor="Hand" Tag="Blocks"
46+
PreviewMouseLeftButtonDown="HighlightLabel_MouseDown" PreviewMouseLeftButtonUp="HighlightLabel_MouseUp"/>
47+
<Label Content="Horz. Finder:" Grid.Row="3" Grid.Column="0" />
48+
<Label Content="{Binding Path=PenaltyDetails.HorizontalFinderPatterns}" Grid.Row="3" Grid.Column="1" />
49+
<Label Content="Vert. Finder:" Grid.Row="4" Grid.Column="0" />
50+
<Label Content="{Binding Path=PenaltyDetails.VerticalFinderPatterns}" Grid.Row="4" Grid.Column="1" />
51+
<Label Content="Balance:" Grid.Row="5" Grid.Column="0"/>
52+
<Label Content="{Binding Path=PenaltyDetails.ColorBalance}" Grid.Row="5" Grid.Column="1" />
53+
<Label Content="Total:" Grid.Row="6" Grid.Column="0"/>
54+
<Label Content="{Binding Path=PenaltyDetails.Total}" Grid.Row="6" Grid.Column="1" />
55+
</Grid>
56+
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2">
57+
<TextBox x:Name="QrCodeTextBox" Text="{Binding Path=Text, UpdateSourceTrigger=PropertyChanged}"
58+
Padding="5,3" Margin="0,6"/>
59+
<WrapPanel>
60+
<Label Content="Error Correction:" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0,5,12,5"/>
61+
<ComboBox x:Name="ErrorCorrectionCombo" HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Margin="0,6,24,6"
62+
ItemsSource="{Binding Path=ErrorCorrectionLevels, Mode=OneTime}" DisplayMemberPath="Item1" SelectedValuePath="Item2" SelectedValue="{Binding Path=ErrorCorrection}"/>
63+
<Label Content="Border Width:" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0,5,12,5"/>
64+
<TextBox x:Name="BorderWidthTextBox" Text="{Binding Path=BorderWidth, UpdateSourceTrigger=PropertyChanged}"
65+
HorizontalAlignment="Left" VerticalAlignment="Center" Width="60" Margin="0,6" Padding="5,3"/>
66+
</WrapPanel>
67+
<WrapPanel>
68+
<Label Content="Data Mask:" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0,5,12,5"/>
69+
<ComboBox x:Name="DataMaskCombo" HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Margin="0,6,24,6"
70+
ItemsSource="{Binding Path=DataMasks, Mode=OneTime}" DisplayMemberPath="Item1" SelectedValuePath="Item2" SelectedValue="{Binding Path=DataMaskPattern}"/>
71+
<Label Content="Selected Data Mask:" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0,5,12,5"/>
72+
<Label Content="{Binding Path=SelectedDataMaskPattern, Mode=OneWay}" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="0,5,12,5"/>
73+
</WrapPanel>
74+
<Button x:Name="CopyButton" Content="Copy QR Code" Grid.Row="3" Margin="0,6,0,0"
75+
VerticalAlignment="Center" HorizontalAlignment="Right" Padding="10,3" Click="CopyButton_Click"/>
76+
</StackPanel>
77+
</Grid>
78+
</Window>

QrCodeAnalyzer/MainWindow.xaml.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// QR code generator library (.NET)
3+
// https://github.com/manuelbl/QrCodeGenerator
4+
//
5+
// Copyright (c) 2021 Manuel Bleichenbacher
6+
// Licensed under MIT License
7+
// https://opensource.org/licenses/MIT
8+
//
9+
10+
using System;
11+
using System.Windows;
12+
using System.Windows.Input;
13+
14+
namespace Net.Codecrete.QrCodeGenerator.Analyzer;
15+
16+
/// <summary>
17+
/// Interaction logic for MainWindow.xaml
18+
/// </summary>
19+
public partial class MainWindow : Window
20+
{
21+
private readonly MainWindowViewModel _viewModel = new MainWindowViewModel();
22+
23+
public MainWindow()
24+
{
25+
InitializeComponent();
26+
DataContext = _viewModel;
27+
}
28+
29+
private void CopyButton_Click(object sender, RoutedEventArgs e)
30+
{
31+
var bitmap = _viewModel.CreateClipboardBitmap();
32+
var dataObject = new DataObject();
33+
dataObject.SetData(DataFormats.Bitmap, bitmap);
34+
Clipboard.SetDataObject(dataObject);
35+
}
36+
37+
private void HighlightLabel_MouseDown(object sender, MouseButtonEventArgs e)
38+
{
39+
if (sender is FrameworkElement fe
40+
&& fe.Tag is string tag
41+
&& Enum.TryParse(tag, out HighlightKind kind))
42+
{
43+
fe.CaptureMouse();
44+
_viewModel.Highlight = kind;
45+
}
46+
}
47+
48+
private void HighlightLabel_MouseUp(object sender, MouseButtonEventArgs e)
49+
{
50+
if (sender is FrameworkElement fe)
51+
{
52+
fe.ReleaseMouseCapture();
53+
}
54+
_viewModel.Highlight = HighlightKind.None;
55+
}
56+
}
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//
2+
// QR code generator library (.NET)
3+
// https://github.com/manuelbl/QrCodeGenerator
4+
//
5+
// Copyright (c) 2021 Manuel Bleichenbacher
6+
// Licensed under MIT License
7+
// https://opensource.org/licenses/MIT
8+
//
9+
10+
using System;
11+
using System.ComponentModel;
12+
using System.Runtime.CompilerServices;
13+
using System.Windows.Media;
14+
using System.Windows.Media.Imaging;
15+
16+
namespace Net.Codecrete.QrCodeGenerator.Analyzer;
17+
18+
public enum HighlightKind { None, Blocks, HorizontalStreaks, VerticalStreaks }
19+
20+
public sealed class MainWindowViewModel : INotifyPropertyChanged
21+
{
22+
private readonly QrCodeBuilder.DebugInfo _debugInfo = new QrCodeBuilder.DebugInfo();
23+
24+
private string _text = "QR code text";
25+
private int _borderWidth = 4;
26+
private QrCode.Ecc _errorCorrection = QrCode.Ecc.Medium;
27+
private int _dataMaskPattern = -1;
28+
private QrCodeBuilder.PenaltyInfo _penaltyDetails;
29+
private ImageSource? _qrCodeImage;
30+
private int _selectedDataMaskPattern = -1;
31+
private QrCode? _currentQrCode;
32+
private HighlightKind _highlight = HighlightKind.None;
33+
34+
public MainWindowViewModel()
35+
{
36+
QrCodeBuilder.DebugAccess = _debugInfo;
37+
ErrorCorrectionLevels =
38+
[
39+
new Tuple<string, QrCode.Ecc>("Low", QrCode.Ecc.Low),
40+
new Tuple<string, QrCode.Ecc>("Medium", QrCode.Ecc.Medium),
41+
new Tuple<string, QrCode.Ecc>("Quartile", QrCode.Ecc.Quartile),
42+
new Tuple<string, QrCode.Ecc>("High", QrCode.Ecc.High)
43+
];
44+
DataMasks =
45+
[
46+
new Tuple<string, int>("Auto", -1),
47+
new Tuple<string, int>("Mask 0", 0),
48+
new Tuple<string, int>("Mask 1", 1),
49+
new Tuple<string, int>("Mask 2", 2),
50+
new Tuple<string, int>("Mask 3", 3),
51+
new Tuple<string, int>("Mask 4", 4),
52+
new Tuple<string, int>("Mask 5", 5),
53+
new Tuple<string, int>("Mask 6", 6),
54+
new Tuple<string, int>("Mask 7", 7)
55+
];
56+
UpdateQrCode();
57+
}
58+
59+
public event PropertyChangedEventHandler? PropertyChanged;
60+
61+
public string Text
62+
{
63+
get => _text;
64+
set
65+
{
66+
if (_text == value) return;
67+
_text = value;
68+
UpdateQrCode();
69+
OnPropertyChanged();
70+
}
71+
}
72+
73+
public int BorderWidth
74+
{
75+
get => _borderWidth;
76+
set
77+
{
78+
if (_borderWidth == value) return;
79+
_borderWidth = value;
80+
UpdateQrCode();
81+
OnPropertyChanged();
82+
}
83+
}
84+
85+
public Tuple<string, QrCode.Ecc>[] ErrorCorrectionLevels { get; }
86+
87+
public Tuple<string, int>[] DataMasks { get; }
88+
89+
public QrCode.Ecc ErrorCorrection
90+
{
91+
get => _errorCorrection;
92+
set
93+
{
94+
if (_errorCorrection == value) return;
95+
_errorCorrection = value;
96+
UpdateQrCode();
97+
OnPropertyChanged();
98+
}
99+
}
100+
101+
public int DataMaskPattern
102+
{
103+
get => _dataMaskPattern;
104+
set
105+
{
106+
if (_dataMaskPattern == value) return;
107+
_dataMaskPattern = Math.Clamp(value, -1, 7);
108+
UpdateQrCode();
109+
OnPropertyChanged();
110+
}
111+
}
112+
113+
public int SelectedDataMaskPattern
114+
{
115+
get => _selectedDataMaskPattern;
116+
private set
117+
{
118+
if (_selectedDataMaskPattern == value) return;
119+
_selectedDataMaskPattern = value;
120+
OnPropertyChanged();
121+
}
122+
}
123+
124+
public QrCodeBuilder.PenaltyInfo PenaltyDetails
125+
{
126+
get => _penaltyDetails;
127+
private set
128+
{
129+
_penaltyDetails = value;
130+
OnPropertyChanged();
131+
}
132+
}
133+
134+
public ImageSource? QrCodeImage
135+
{
136+
get => _qrCodeImage;
137+
private set
138+
{
139+
_qrCodeImage = value;
140+
OnPropertyChanged();
141+
}
142+
}
143+
144+
public HighlightKind Highlight
145+
{
146+
get => _highlight;
147+
set
148+
{
149+
if (_highlight == value) return;
150+
_highlight = value;
151+
RenderQrCodeImage();
152+
OnPropertyChanged();
153+
}
154+
}
155+
156+
public BitmapSource CreateClipboardBitmap()
157+
{
158+
var qrCode = QrCode.EncodeText(_text, _errorCorrection);
159+
return QrCodeDrawing.CreateBitmapImage(qrCode, 20, _borderWidth);
160+
}
161+
162+
private void UpdateQrCode()
163+
{
164+
_debugInfo.ForcedDataMask = _dataMaskPattern;
165+
var qrCode = QrCode.EncodeText(_text, _errorCorrection);
166+
_currentQrCode = qrCode;
167+
SelectedDataMaskPattern = qrCode.Mask;
168+
PenaltyDetails = _debugInfo.Penalties[qrCode.Mask];
169+
RenderQrCodeImage();
170+
}
171+
172+
private void RenderQrCodeImage()
173+
{
174+
if (_currentQrCode == null) return;
175+
var highlights = _highlight switch
176+
{
177+
HighlightKind.Blocks => Penalty.GetBlocks(_currentQrCode),
178+
HighlightKind.HorizontalStreaks => Penalty.GetHorizontalStreaks(_currentQrCode),
179+
HighlightKind.VerticalStreaks => Penalty.GetVerticalStreaks(_currentQrCode),
180+
_ => null
181+
};
182+
QrCodeImage = QrCodeDrawing.CreateDrawing(_currentQrCode, 192, _borderWidth, highlights);
183+
}
184+
185+
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
186+
{
187+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
188+
}
189+
}

0 commit comments

Comments
 (0)