tidy
This commit is contained in:
@@ -25,7 +25,7 @@ public class FrameHandler(INavigationContext navigationContext) :
|
|||||||
async void HandleNavigatingFrom(object? _,
|
async void HandleNavigatingFrom(object? _,
|
||||||
NavigatingCancelEventArgs args)
|
NavigatingCancelEventArgs args)
|
||||||
{
|
{
|
||||||
Dictionary<string,object> results = [];
|
Dictionary<string, object> results = [];
|
||||||
|
|
||||||
control.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
|
control.RemoveHandler(Frame.NavigatingFromEvent, HandleNavigatingFrom);
|
||||||
NavigatedFrom(sender, control, () => results);
|
NavigatedFrom(sender, control, () => results);
|
||||||
|
|||||||
@@ -34,4 +34,3 @@ public class NavigationContext(INavigationContextCollection contexts) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
|
|
||||||
public record ComponentConfiguration
|
public record ComponentConfiguration
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,6 @@ public partial class ComponentConfigurationViewModel<TConfiguration, TValue, THe
|
|||||||
TDescription description,
|
TDescription description,
|
||||||
TAction action) : base(provider, factory, mediator, publisher, subscriber, disposer)
|
TAction action) : base(provider, factory, mediator, publisher, subscriber, disposer)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Handle(Changed<TConfiguration> args,
|
public Task Handle(Changed<TConfiguration> args,
|
||||||
@@ -58,6 +57,7 @@ public partial class ComponentConfigurationViewModel<TConfiguration, TValue, TAc
|
|||||||
Value = valueDelegate.Invoke(configuration);
|
Value = valueDelegate.Invoke(configuration);
|
||||||
return base.Activated();
|
return base.Activated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Handle(Changed<TConfiguration> args,
|
public Task Handle(Changed<TConfiguration> args,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ public class ComponentHost(IServiceProvider services,
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken = default)
|
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ public class ConfigurationChangedHandler<TConfiguration, TValue>(ConfigurationVa
|
|||||||
{
|
{
|
||||||
if (configurationValue.TryUpdate(configuration, out TValue value))
|
if (configurationValue.TryUpdate(configuration, out TValue value))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record Create<TValue>(TValue Value);
|
public record Create<TValue>(TValue Value);
|
||||||
|
|
||||||
|
|||||||
@@ -144,12 +144,12 @@ public static class Test
|
|||||||
services.AddTransient(provider =>
|
services.AddTransient(provider =>
|
||||||
provider.GetRequiredKeyedService<IConfigurationDescriptor<TConfiguration>>(section).Value);
|
provider.GetRequiredKeyedService<IConfigurationDescriptor<TConfiguration>>(section).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultBuilder :
|
public class DefaultBuilder :
|
||||||
HostBuilder
|
HostBuilder
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,20 +56,26 @@ public class DictionaryStringObjectJsonConverter :
|
|||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
return reader.GetString();
|
return reader.GetString();
|
||||||
|
|
||||||
case JsonTokenType.False:
|
case JsonTokenType.False:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case JsonTokenType.True:
|
case JsonTokenType.True:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case JsonTokenType.Null:
|
case JsonTokenType.Null:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
case JsonTokenType.Number:
|
case JsonTokenType.Number:
|
||||||
if (reader.TryGetInt64(out var result))
|
if (reader.TryGetInt64(out var result))
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return reader.GetDecimal();
|
return reader.GetDecimal();
|
||||||
|
|
||||||
case JsonTokenType.StartObject:
|
case JsonTokenType.StartObject:
|
||||||
return Read(ref reader, null!, options);
|
return Read(ref reader, null!, options);
|
||||||
|
|
||||||
case JsonTokenType.StartArray:
|
case JsonTokenType.StartArray:
|
||||||
List<object?> list = [];
|
List<object?> list = [];
|
||||||
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
|
||||||
@@ -77,6 +83,7 @@ public class DictionaryStringObjectJsonConverter :
|
|||||||
list.Add(ExtractValue(ref reader, options));
|
list.Add(ExtractValue(ref reader, options));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Reactive.Disposables;
|
using System.Collections;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
|
|
||||||
public interface IComponentConfigurationViewModel
|
public interface IComponentConfigurationViewModel
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,3 @@
|
|||||||
|
|
||||||
public interface IComponentScopeCollection :
|
public interface IComponentScopeCollection :
|
||||||
IList<ComponentScopeDescriptor>;
|
IList<ComponentScopeDescriptor>;
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,3 @@ public interface IComponentScopeProvider
|
|||||||
{
|
{
|
||||||
ComponentScopeDescriptor? Get(string key);
|
ComponentScopeDescriptor? Get(string key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
|
|
||||||
public interface IContentTemplate
|
public interface IContentTemplate
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,6 @@ public interface IFactory<TParameter, TService>
|
|||||||
TService? Create(TParameter value);
|
TService? Create(TParameter value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface IFactory<TService>
|
public interface IFactory<TService>
|
||||||
{
|
{
|
||||||
TService? Create();
|
TService? Create();
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
namespace Toolkit.Foundation
|
||||||
public interface IMediator
|
|
||||||
{
|
{
|
||||||
Task<TResponse?> Handle<TRequest, TResponse>(TRequest request,
|
public interface IMediator
|
||||||
CancellationToken cancellationToken = default)
|
{
|
||||||
where TRequest : notnull;
|
Task<object?> Handle(object message, CancellationToken cancellationToken = default);
|
||||||
|
Task<TResponse?> Handle<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken = default) where TRequest : notnull;
|
||||||
Task<object?> Handle(object request, CancellationToken
|
}
|
||||||
cancellationToken = default);
|
|
||||||
}
|
}
|
||||||
@@ -4,4 +4,3 @@ public interface INavigation
|
|||||||
{
|
{
|
||||||
Type Type { get; set; }
|
Type Type { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,3 @@ public interface INavigationScope
|
|||||||
|
|
||||||
Task NavigateBackAsync(object? context, CancellationToken cancellationToken = default);
|
Task NavigateBackAsync(object? context, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,3 @@ public interface IConfirmation
|
|||||||
{
|
{
|
||||||
Task<bool> Confirm();
|
Task<bool> Confirm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public interface IPublisher
|
|||||||
object key,
|
object key,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
where TMessage : notnull;
|
where TMessage : notnull;
|
||||||
|
|
||||||
Task PublishUI<TMessage>(object key,
|
Task PublishUI<TMessage>(object key,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
where TMessage : new();
|
where TMessage : new();
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public interface IRequest<out TResponse> :
|
|
||||||
IMessage;
|
|
||||||
|
|
||||||
public interface IRequest : IRequest<Unit>;
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Extensions.Configuration.Json;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using Microsoft.Extensions.FileProviders.Physical;
|
using Microsoft.Extensions.FileProviders.Physical;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public record KeyAccelerator(VirtualKey Key,
|
public record KeyAccelerator(VirtualKey Key,
|
||||||
VirtualKey[]? Modifiers = null) :
|
VirtualKey[]? Modifiers = null);
|
||||||
IRequest;
|
|
||||||
@@ -27,7 +27,7 @@ public class Mediator(IServiceProvider provider) :
|
|||||||
public Task<object?> Handle(object message,
|
public Task<object?> Handle(object message,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (message.GetType().GetInterface(typeof(IRequest<>).Name) is Type requestType &&
|
if (message.GetType().GetInterface(message.GetType().Name) is Type requestType &&
|
||||||
requestType.GetGenericArguments().Length == 1)
|
requestType.GetGenericArguments().Length == 1)
|
||||||
{
|
{
|
||||||
Type responseType = requestType.GetGenericArguments()[0];
|
Type responseType = requestType.GetGenericArguments()[0];
|
||||||
|
|||||||
@@ -18,5 +18,3 @@ public class NavigateBackHandler(IComponentScopeProvider provider) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record NavigatingFrom(object Content) :
|
|
||||||
IRequest<IReadOnlyCollection<object>>;
|
|
||||||
|
|
||||||
public record NavigatingTo(object Content) :
|
|
||||||
IRequest<IReadOnlyCollection<object>>;
|
|
||||||
@@ -5,4 +5,3 @@ public record Navigation :
|
|||||||
{
|
{
|
||||||
public required Type Type { get; set; }
|
public required Type Type { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,4 +101,3 @@ public class NavigationScope(IPublisher publisher,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
|
|||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public partial class ObservableCollectionViewModel<TViewModel> :
|
public partial class ObservableCollectionViewModel<TViewModel> :
|
||||||
ObservableObject,
|
ObservableObject,
|
||||||
IObservableCollectionViewModel<TViewModel>,
|
IObservableCollectionViewModel<TViewModel>,
|
||||||
@@ -113,7 +114,6 @@ public partial class ObservableCollectionViewModel<TViewModel> :
|
|||||||
}
|
}
|
||||||
catch (InvalidCastException)
|
catch (InvalidCastException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this[index] = item!;
|
this[index] = item!;
|
||||||
@@ -172,7 +172,6 @@ public partial class ObservableCollectionViewModel<TViewModel> :
|
|||||||
}
|
}
|
||||||
catch (InvalidCastException)
|
catch (InvalidCastException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Add(item!);
|
Add(item!);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public partial class ObservableViewModel :
|
public partial class ObservableViewModel :
|
||||||
ObservableObject,
|
ObservableObject,
|
||||||
IObservableViewModel,
|
IObservableViewModel,
|
||||||
IInitializer,
|
IInitializer,
|
||||||
|
|||||||
@@ -66,14 +66,14 @@ public class Publisher(ISubscriptionManager subscriptionManager,
|
|||||||
null, cancellationToken);
|
null, cancellationToken);
|
||||||
|
|
||||||
public Task Publish<TMessage>(CancellationToken cancellationToken = default)
|
public Task Publish<TMessage>(CancellationToken cancellationToken = default)
|
||||||
where TMessage : new() =>
|
where TMessage : new() =>
|
||||||
Publish(new TMessage(), async args => await args(),
|
Publish(new TMessage(), async args => await args(),
|
||||||
null, cancellationToken);
|
null, cancellationToken);
|
||||||
|
|
||||||
public Task PublishUI<TMessage>(object key,
|
public Task PublishUI<TMessage>(object key,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
where TMessage : new() =>
|
where TMessage : new() =>
|
||||||
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()),
|
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()),
|
||||||
key, cancellationToken);
|
key, cancellationToken);
|
||||||
|
|
||||||
public Task PublishUI<TMessage>(TMessage message,
|
public Task PublishUI<TMessage>(TMessage message,
|
||||||
@@ -88,6 +88,7 @@ public class Publisher(ISubscriptionManager subscriptionManager,
|
|||||||
where TMessage : notnull =>
|
where TMessage : notnull =>
|
||||||
Publish(message, args => dispatcher.InvokeAsync(async () => await args()),
|
Publish(message, args => dispatcher.InvokeAsync(async () => await args()),
|
||||||
key, cancellationToken);
|
key, cancellationToken);
|
||||||
|
|
||||||
public Task PublishUI<TMessage>(CancellationToken cancellationToken = default)
|
public Task PublishUI<TMessage>(CancellationToken cancellationToken = default)
|
||||||
where TMessage : new() =>
|
where TMessage : new() =>
|
||||||
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()),
|
Publish(new TMessage(), args => dispatcher.InvokeAsync(async () => await args()),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record Remove<TValue>(TValue Value);
|
public record Remove<TValue>(TValue Value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public record Replace<TValue>(int Index, TValue Value);
|
public record Replace<TValue>(int Index, TValue Value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public record StartProcess(string Process) : IRequest;
|
public record StartProcess(string Process);
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.Reflection;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
|
||||||
|
|
||||||
public class SubscriptionManager(SubscriptionCollection subscriptions) :
|
public class SubscriptionManager(SubscriptionCollection subscriptions) :
|
||||||
ISubscriptionManager
|
ISubscriptionManager
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ public partial class ValueViewModel<TValue>(IServiceProvider provider,
|
|||||||
|
|
||||||
protected virtual void OnChanged(TValue? value)
|
protected virtual void OnChanged(TValue? value)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void OnValueChanged(TValue? value) => OnChanged(value);
|
partial void OnValueChanged(TValue? value) => OnChanged(value);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ internal static class ComparisonLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (leftOperand is IComparable leftComparableOperand &&
|
if (leftOperand is IComparable leftComparableOperand &&
|
||||||
rightOperand is IComparable rightComparableOperand)
|
rightOperand is IComparable rightComparableOperand)
|
||||||
{
|
{
|
||||||
@@ -35,6 +34,7 @@ internal static class ComparisonLogic
|
|||||||
case ComparisonConditionType.Equal:
|
case ComparisonConditionType.Equal:
|
||||||
result = Equals(leftOperand, rightOperand);
|
result = Equals(leftOperand, rightOperand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.NotEqual:
|
case ComparisonConditionType.NotEqual:
|
||||||
result = !Equals(leftOperand, rightOperand);
|
result = !Equals(leftOperand, rightOperand);
|
||||||
break;
|
break;
|
||||||
@@ -54,11 +54,9 @@ internal static class ComparisonLogic
|
|||||||
}
|
}
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (InvalidCastException)
|
catch (InvalidCastException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convertedOperand == null)
|
if (convertedOperand == null)
|
||||||
@@ -74,18 +72,23 @@ internal static class ComparisonLogic
|
|||||||
case ComparisonConditionType.Equal:
|
case ComparisonConditionType.Equal:
|
||||||
result = comparison == 0;
|
result = comparison == 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.GreaterThan:
|
case ComparisonConditionType.GreaterThan:
|
||||||
result = comparison > 0;
|
result = comparison > 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.GreaterThanOrEqual:
|
case ComparisonConditionType.GreaterThanOrEqual:
|
||||||
result = comparison >= 0;
|
result = comparison >= 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.LessThan:
|
case ComparisonConditionType.LessThan:
|
||||||
result = comparison < 0;
|
result = comparison < 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.LessThanOrEqual:
|
case ComparisonConditionType.LessThanOrEqual:
|
||||||
result = comparison <= 0;
|
result = comparison <= 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ComparisonConditionType.NotEqual:
|
case ComparisonConditionType.NotEqual:
|
||||||
result = comparison != 0;
|
result = comparison != 0;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Metadata;
|
using Avalonia.Metadata;
|
||||||
using Toolkit.UI.Avalonia;
|
|
||||||
|
|
||||||
namespace Toolkit.UI.Avalonia;
|
namespace Toolkit.UI.Avalonia;
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class NavigateAction :
|
|||||||
get => GetValue(RouteProperty);
|
get => GetValue(RouteProperty);
|
||||||
set => SetValue(RouteProperty, value);
|
set => SetValue(RouteProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Scope
|
public string Scope
|
||||||
{
|
{
|
||||||
get => GetValue(ScopeProperty);
|
get => GetValue(ScopeProperty);
|
||||||
@@ -67,7 +68,8 @@ public class NavigateAction :
|
|||||||
|
|
||||||
if (control.DataContext is IObservableViewModel observableViewModel)
|
if (control.DataContext is IObservableViewModel observableViewModel)
|
||||||
{
|
{
|
||||||
object[] parameters = [.. Parameters ?? Enumerable.Empty<object?>(), ..
|
object[] parameters = [.. Parameters ?? Enumerable.Empty<object?>(),
|
||||||
|
..
|
||||||
ParameterBindings is { Count: > 0 } ?
|
ParameterBindings is { Count: > 0 } ?
|
||||||
ParameterBindings.Select(binding => new KeyValuePair<string, object>(binding.Key, binding.Value)).ToArray() :
|
ParameterBindings.Select(binding => new KeyValuePair<string, object>(binding.Key, binding.Value)).ToArray() :
|
||||||
Enumerable.Empty<KeyValuePair<string, object>>()];
|
Enumerable.Empty<KeyValuePair<string, object>>()];
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public class ParameterBinding :
|
|||||||
get => GetValue(KeyProperty);
|
get => GetValue(KeyProperty);
|
||||||
set => SetValue(KeyProperty, value);
|
set => SetValue(KeyProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Value
|
public object Value
|
||||||
{
|
{
|
||||||
get => GetValue(ValueProperty);
|
get => GetValue(ValueProperty);
|
||||||
|
|||||||
@@ -17,21 +17,21 @@ public class BlurBehind :
|
|||||||
|
|
||||||
public static readonly ImmutableExperimentalAcrylicMaterial DefaultAcrylicMaterialDark =
|
public static readonly ImmutableExperimentalAcrylicMaterial DefaultAcrylicMaterialDark =
|
||||||
(ImmutableExperimentalAcrylicMaterial)new ExperimentalAcrylicMaterial()
|
(ImmutableExperimentalAcrylicMaterial)new ExperimentalAcrylicMaterial()
|
||||||
{
|
{
|
||||||
MaterialOpacity = 0.25,
|
MaterialOpacity = 0.25,
|
||||||
TintColor = Colors.Black,
|
TintColor = Colors.Black,
|
||||||
TintOpacity = 0.7,
|
TintOpacity = 0.7,
|
||||||
PlatformTransparencyCompensationLevel = 0
|
PlatformTransparencyCompensationLevel = 0
|
||||||
}.ToImmutable();
|
}.ToImmutable();
|
||||||
|
|
||||||
public static readonly ImmutableExperimentalAcrylicMaterial DefaultAcrylicMaterialLight =
|
public static readonly ImmutableExperimentalAcrylicMaterial DefaultAcrylicMaterialLight =
|
||||||
(ImmutableExperimentalAcrylicMaterial)new ExperimentalAcrylicMaterial()
|
(ImmutableExperimentalAcrylicMaterial)new ExperimentalAcrylicMaterial()
|
||||||
{
|
{
|
||||||
MaterialOpacity = 0.0,
|
MaterialOpacity = 0.0,
|
||||||
TintColor = Colors.White,
|
TintColor = Colors.White,
|
||||||
TintOpacity = 0.3,
|
TintOpacity = 0.3,
|
||||||
PlatformTransparencyCompensationLevel = 0
|
PlatformTransparencyCompensationLevel = 0
|
||||||
}.ToImmutable();
|
}.ToImmutable();
|
||||||
|
|
||||||
static BlurBehind()
|
static BlurBehind()
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,6 @@ public class BlurBehind :
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(ICustomDrawOperation? other) =>
|
public bool Equals(ICustomDrawOperation? other) =>
|
||||||
@@ -74,7 +73,7 @@ public class BlurBehind :
|
|||||||
|
|
||||||
public void Render(ImmediateDrawingContext context)
|
public void Render(ImmediateDrawingContext context)
|
||||||
{
|
{
|
||||||
if (context.TryGetFeature<ISkiaSharpApiLeaseFeature>() is ISkiaSharpApiLeaseFeature leaseFeature)
|
if (context.TryGetFeature<ISkiaSharpApiLeaseFeature>() is ISkiaSharpApiLeaseFeature leaseFeature)
|
||||||
{
|
{
|
||||||
using ISkiaSharpApiLease? lease = leaseFeature.Lease();
|
using ISkiaSharpApiLease? lease = leaseFeature.Lease();
|
||||||
if (lease.SkCanvas is SKCanvas canvas)
|
if (lease.SkCanvas is SKCanvas canvas)
|
||||||
@@ -105,11 +104,9 @@ public class BlurBehind :
|
|||||||
|
|
||||||
canvas.DrawRect(0, 0, (float)bounds.Width, (float)bounds.Height, blurSnapPaint);
|
canvas.DrawRect(0, 0, (float)bounds.Width, (float)bounds.Height, blurSnapPaint);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,6 @@ public class CarouselView :
|
|||||||
{
|
{
|
||||||
itemVisuals[(newIndex + i - 2 + columnCount) % columnCount].Offset =
|
itemVisuals[(newIndex + i - 2 + columnCount) % columnCount].Offset =
|
||||||
new Vector3((float)(offsets[i] - centreOffset), 0, 0);
|
new Vector3((float)(offsets[i] - centreOffset), 0, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -253,6 +252,7 @@ public class CarouselView :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCollectionChanged(object? sender,
|
private void OnCollectionChanged(object? sender,
|
||||||
NotifyCollectionChangedEventArgs args) => ArrangeItems(newIndex);
|
NotifyCollectionChangedEventArgs args) => ArrangeItems(newIndex);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Avalonia.Media.Imaging;
|
using Avalonia;
|
||||||
using Avalonia.Styling;
|
|
||||||
using Avalonia;
|
|
||||||
using SukiUI.Utilities.Background;
|
|
||||||
using Avalonia.Platform;
|
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using Avalonia.Platform;
|
||||||
|
using Avalonia.Styling;
|
||||||
|
using SukiUI.Utilities.Background;
|
||||||
|
|
||||||
namespace Toolkit.UI.Controls.Avalonia;
|
namespace Toolkit.UI.Controls.Avalonia;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
|
||||||
namespace Toolkit.UI.Controls.Avalonia;
|
namespace Toolkit.UI.Controls.Avalonia;
|
||||||
|
|
||||||
public class ScopedBatchHelper
|
public class ScopedBatchHelper
|
||||||
{
|
{
|
||||||
private DispatcherTimer? timer;
|
private DispatcherTimer? timer;
|
||||||
|
|||||||
@@ -1,127 +1,124 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding;
|
namespace Gma.QrCodeNet.Encoding;
|
||||||
|
|
||||||
internal sealed class BitList : IEnumerable<bool>
|
internal sealed class BitList : IEnumerable<bool>
|
||||||
{
|
{
|
||||||
internal BitList()
|
internal BitList()
|
||||||
{
|
{
|
||||||
Count = 0;
|
Count = 0;
|
||||||
List = new List<byte>(32);
|
List = new List<byte>(32);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal BitList(IEnumerable<byte> byteArray)
|
internal BitList(IEnumerable<byte> byteArray)
|
||||||
{
|
{
|
||||||
Count = byteArray.Count();
|
Count = byteArray.Count();
|
||||||
List = byteArray.ToList();
|
List = byteArray.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal List<byte> List { get; }
|
internal List<byte> List { get; }
|
||||||
|
|
||||||
internal int Count { get; private set; }
|
internal int Count { get; private set; }
|
||||||
|
|
||||||
internal bool this[int index]
|
internal bool this[int index]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= Count)
|
if (index < 0 || index >= Count)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index), "Index out of range");
|
throw new ArgumentOutOfRangeException(nameof(index), "Index out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
int value_Renamed = List[index >> 3] & 0xff;
|
int value_Renamed = List[index >> 3] & 0xff;
|
||||||
return ((value_Renamed >> (7 - (index & 0x7))) & 1) == 1;
|
return ((value_Renamed >> (7 - (index & 0x7))) & 1) == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<bool> GetEnumerator()
|
public IEnumerator<bool> GetEnumerator()
|
||||||
{
|
{
|
||||||
int numBytes = Count >> 3;
|
int numBytes = Count >> 3;
|
||||||
int remainder = Count & 0x7;
|
int remainder = Count & 0x7;
|
||||||
byte value;
|
byte value;
|
||||||
for (int index = 0; index < numBytes; index++)
|
for (int index = 0; index < numBytes; index++)
|
||||||
{
|
{
|
||||||
value = List[index];
|
value = List[index];
|
||||||
for (int shiftNum = 7; shiftNum >= 0; shiftNum--)
|
for (int shiftNum = 7; shiftNum >= 0; shiftNum--)
|
||||||
{
|
{
|
||||||
yield return ((value >> shiftNum) & 1) == 1;
|
yield return ((value >> shiftNum) & 1) == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remainder > 0)
|
if (remainder > 0)
|
||||||
{
|
{
|
||||||
value = List[numBytes];
|
value = List[numBytes];
|
||||||
for (int index = 0; index < remainder; index++)
|
for (int index = 0; index < remainder; index++)
|
||||||
{
|
{
|
||||||
yield return ((value >> (7 - index)) & 1) == 1;
|
yield return ((value >> (7 - index)) & 1) == 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ToBit(bool item)
|
private int ToBit(bool item)
|
||||||
{
|
{
|
||||||
return item ? 1 : 0;
|
return item ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Add(bool item)
|
internal void Add(bool item)
|
||||||
{
|
{
|
||||||
int numBitsinLastByte = Count & 0x7;
|
int numBitsinLastByte = Count & 0x7;
|
||||||
|
|
||||||
// Add one more byte to List when we have no bits in the last byte.
|
// Add one more byte to List when we have no bits in the last byte.
|
||||||
if (numBitsinLastByte == 0)
|
if (numBitsinLastByte == 0)
|
||||||
{
|
{
|
||||||
List.Add(0);
|
List.Add(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
List[Count >> 3] |= (byte)(ToBit(item) << (7 - numBitsinLastByte));
|
List[Count >> 3] |= (byte)(ToBit(item) << (7 - numBitsinLastByte));
|
||||||
Count++;
|
Count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Add(IEnumerable<bool> items)
|
internal void Add(IEnumerable<bool> items)
|
||||||
{
|
{
|
||||||
foreach (bool item in items)
|
foreach (bool item in items)
|
||||||
{
|
{
|
||||||
Add(item);
|
Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Add(int value, int bitCount)
|
internal void Add(int value, int bitCount)
|
||||||
{
|
{
|
||||||
if (bitCount is < 0 or > 32)
|
if (bitCount is < 0 or > 32)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(bitCount), $"{nameof(bitCount)} must be greater than or equal to 0");
|
throw new ArgumentOutOfRangeException(nameof(bitCount), $"{nameof(bitCount)} must be greater than or equal to 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
int numBitsLeft = bitCount;
|
int numBitsLeft = bitCount;
|
||||||
|
|
||||||
while (numBitsLeft > 0)
|
while (numBitsLeft > 0)
|
||||||
{
|
{
|
||||||
if ((Count & 0x7) == 0 && numBitsLeft >= 8)
|
if ((Count & 0x7) == 0 && numBitsLeft >= 8)
|
||||||
{
|
{
|
||||||
// Add one more byte to List.
|
// Add one more byte to List.
|
||||||
byte newByte = (byte)((value >> (numBitsLeft - 8)) & 0xFF);
|
byte newByte = (byte)((value >> (numBitsLeft - 8)) & 0xFF);
|
||||||
AppendByte(newByte);
|
AppendByte(newByte);
|
||||||
numBitsLeft -= 8;
|
numBitsLeft -= 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool bit = ((value >> (numBitsLeft - 1)) & 1) == 1;
|
bool bit = ((value >> (numBitsLeft - 1)) & 1) == 1;
|
||||||
Add(bit);
|
Add(bit);
|
||||||
numBitsLeft--;
|
numBitsLeft--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AppendByte(byte item)
|
private void AppendByte(byte item)
|
||||||
{
|
{
|
||||||
List.Add(item);
|
List.Add(item);
|
||||||
Count += 8;
|
Count += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,23 +2,23 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public abstract class BitMatrix
|
public abstract class BitMatrix
|
||||||
{
|
{
|
||||||
public abstract int Width { get; }
|
public abstract int Width { get; }
|
||||||
public abstract int Height { get; }
|
public abstract int Height { get; }
|
||||||
public abstract bool[,] InternalArray { get; }
|
public abstract bool[,] InternalArray { get; }
|
||||||
|
|
||||||
public abstract bool this[int i, int j] { get; set; }
|
public abstract bool this[int i, int j] { get; set; }
|
||||||
|
|
||||||
internal void CopyTo(TriStateMatrix target, MatrixRectangle sourceArea, MatrixPoint targetPoint, MatrixStatus mstatus)
|
internal void CopyTo(TriStateMatrix target, MatrixRectangle sourceArea, MatrixPoint targetPoint, MatrixStatus mstatus)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < sourceArea.Size.Height; j++)
|
for (int j = 0; j < sourceArea.Size.Height; j++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < sourceArea.Size.Width; i++)
|
for (int i = 0; i < sourceArea.Size.Width; i++)
|
||||||
{
|
{
|
||||||
bool value = this[sourceArea.Location.X + i, sourceArea.Location.Y + j];
|
bool value = this[sourceArea.Location.X + i, sourceArea.Location.Y + j];
|
||||||
target[targetPoint.X + i, targetPoint.Y + j, mstatus] = value;
|
target[targetPoint.X + i, targetPoint.Y + j, mstatus] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void CopyTo(TriStateMatrix target, MatrixPoint targetPoint, MatrixStatus mstatus) => CopyTo(target, new MatrixRectangle(new MatrixPoint(0, 0), new MatrixSize(Width, Height)), targetPoint, mstatus);
|
internal void CopyTo(TriStateMatrix target, MatrixPoint targetPoint, MatrixStatus mstatus) => CopyTo(target, new MatrixRectangle(new MatrixPoint(0, 0), new MatrixSize(Width, Height)), targetPoint, mstatus);
|
||||||
}
|
}
|
||||||
@@ -2,30 +2,30 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public abstract class BitMatrixBase : BitMatrix
|
public abstract class BitMatrixBase : BitMatrix
|
||||||
{
|
{
|
||||||
protected BitMatrixBase(int width, bool[,] internalArray)
|
protected BitMatrixBase(int width, bool[,] internalArray)
|
||||||
{
|
{
|
||||||
Width = width;
|
Width = width;
|
||||||
InternalArray = internalArray;
|
InternalArray = internalArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BitMatrixBase(bool[,] internalArray)
|
protected BitMatrixBase(bool[,] internalArray)
|
||||||
{
|
{
|
||||||
InternalArray = internalArray;
|
InternalArray = internalArray;
|
||||||
int width = internalArray.GetLength(0);
|
int width = internalArray.GetLength(0);
|
||||||
Width = width;
|
Width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool[,] InternalArray { get; }
|
public override bool[,] InternalArray { get; }
|
||||||
|
|
||||||
public override int Width { get; }
|
public override int Width { get; }
|
||||||
|
|
||||||
public static bool CanCreate(bool[,] internalArray)
|
public static bool CanCreate(bool[,] internalArray)
|
||||||
{
|
{
|
||||||
if (internalArray is null)
|
if (internalArray is null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return internalArray.GetLength(0) == internalArray.GetLength(1);
|
return internalArray.GetLength(0) == internalArray.GetLength(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+38
-40
@@ -1,48 +1,46 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
||||||
|
|
||||||
public static class CharCountIndicatorTable
|
public static class CharCountIndicatorTable
|
||||||
{
|
{
|
||||||
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
|
||||||
public static int[] GetCharCountIndicatorSet()
|
public static int[] GetCharCountIndicatorSet()
|
||||||
{
|
{
|
||||||
return new int[] { 8, 16, 16 };
|
return new int[] { 8, 16, 16 };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetBitCountInCharCountIndicator(int version)
|
public static int GetBitCountInCharCountIndicator(int version)
|
||||||
{
|
{
|
||||||
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
|
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
|
||||||
int versionGroup = GetVersionGroup(version);
|
int versionGroup = GetVersionGroup(version);
|
||||||
|
|
||||||
return charCountIndicatorSet[versionGroup];
|
return charCountIndicatorSet[versionGroup];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
|
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
|
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
|
||||||
private static int GetVersionGroup(int version)
|
private static int GetVersionGroup(int version)
|
||||||
{
|
{
|
||||||
if (version > 40)
|
if (version > 40)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Unexpected version: {version}.");
|
throw new InvalidOperationException($"Unexpected version: {version}.");
|
||||||
}
|
}
|
||||||
else if (version >= 27)
|
else if (version >= 27)
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
else if (version >= 10)
|
else if (version >= 10)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (version > 0)
|
else if (version > 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Unexpected version: {version}.");
|
throw new InvalidOperationException($"Unexpected version: {version}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
using Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
||||||
using Gma.QrCodeNet.Encoding.Terminate;
|
using Gma.QrCodeNet.Encoding.Terminate;
|
||||||
using Gma.QrCodeNet.Encoding.Versions;
|
using Gma.QrCodeNet.Encoding.Versions;
|
||||||
@@ -10,53 +9,53 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
|||||||
/// Which uses sub functions under several different namespaces</remarks>
|
/// Which uses sub functions under several different namespaces</remarks>
|
||||||
internal static class DataEncode
|
internal static class DataEncode
|
||||||
{
|
{
|
||||||
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
|
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
|
||||||
{
|
{
|
||||||
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
|
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
|
||||||
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
|
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
|
||||||
|
|
||||||
BitList encodeContent = encoderBase.GetDataBits(content);
|
BitList encodeContent = encoderBase.GetDataBits(content);
|
||||||
|
|
||||||
int encodeContentLength = encodeContent.Count;
|
int encodeContentLength = encodeContent.Count;
|
||||||
|
|
||||||
VersionControlStruct vcStruct =
|
VersionControlStruct vcStruct =
|
||||||
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
|
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
|
||||||
|
|
||||||
BitList dataCodewords = new();
|
BitList dataCodewords = new();
|
||||||
|
|
||||||
// Eci header
|
// Eci header
|
||||||
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
|
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
|
||||||
{
|
{
|
||||||
dataCodewords.Add(vcStruct.ECIHeader);
|
dataCodewords.Add(vcStruct.ECIHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
dataCodewords.Add(encoderBase.GetModeIndicator());
|
dataCodewords.Add(encoderBase.GetModeIndicator());
|
||||||
int numLetter = encodeContentLength >> 3;
|
int numLetter = encodeContentLength >> 3;
|
||||||
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
|
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
dataCodewords.Add(encodeContent);
|
dataCodewords.Add(encodeContent);
|
||||||
|
|
||||||
// Terminator Padding
|
// Terminator Padding
|
||||||
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
|
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
|
||||||
|
|
||||||
int dataCodewordsCount = dataCodewords.Count;
|
int dataCodewordsCount = dataCodewords.Count;
|
||||||
if ((dataCodewordsCount & 0x7) != 0)
|
if ((dataCodewordsCount & 0x7) != 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
|
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
|
||||||
}
|
}
|
||||||
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
|
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
|
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
|
||||||
}
|
}
|
||||||
|
|
||||||
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
|
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
|
||||||
return encStruct;
|
return encStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EncoderBase CreateEncoder(string encodingName)
|
private static EncoderBase CreateEncoder(string encodingName)
|
||||||
{
|
{
|
||||||
return new EightBitByteEncoder(encodingName);
|
return new EightBitByteEncoder(encodingName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,255 +1,252 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
||||||
|
|
||||||
public sealed class ECISet
|
public sealed class ECISet
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
|
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int ECIMode = 7;
|
private const int ECIMode = 7;
|
||||||
|
|
||||||
private const int ECIIndicatorNumBits = 4;
|
private const int ECIIndicatorNumBits = 4;
|
||||||
|
|
||||||
private Dictionary<string, int>? _nameToValue;
|
private Dictionary<string, int>? _nameToValue;
|
||||||
private Dictionary<int, string>? _valueToName;
|
private Dictionary<int, string>? _valueToName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize ECI Set.
|
/// Initialize ECI Set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="option">AppendOption is enum under ECISet
|
/// <param name="option">AppendOption is enum under ECISet
|
||||||
/// Use NameToValue during Encode. ValueToName during Decode</param>
|
/// Use NameToValue during Encode. ValueToName during Decode</param>
|
||||||
internal ECISet(AppendOption option)
|
internal ECISet(AppendOption option)
|
||||||
{
|
{
|
||||||
Initialize(option);
|
Initialize(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AppendOption
|
public enum AppendOption
|
||||||
{
|
{
|
||||||
NameToValue,
|
NameToValue,
|
||||||
ValueToName,
|
ValueToName,
|
||||||
Both
|
Both
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Length indicator for number of ECI codewords
|
/// Length indicator for number of ECI codewords
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
|
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
|
||||||
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
|
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
|
||||||
/// <description>Bits required for each one is:
|
/// <description>Bits required for each one is:
|
||||||
/// one = 1, two = 2, three = 3</description>
|
/// one = 1, two = 2, three = 3</description>
|
||||||
private enum ECICodewordsLength
|
private enum ECICodewordsLength
|
||||||
{
|
{
|
||||||
One = 0,
|
One = 0,
|
||||||
Two = 2,
|
Two = 2,
|
||||||
Three = 6
|
Three = 6
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
||||||
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
||||||
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
|
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
|
||||||
private static int NumOfCodewords(int eCIValue)
|
private static int NumOfCodewords(int eCIValue)
|
||||||
{
|
{
|
||||||
if (eCIValue is >= 0 and <= 127)
|
if (eCIValue is >= 0 and <= 127)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (eCIValue is > 127 and <= 16383)
|
else if (eCIValue is > 127 and <= 16383)
|
||||||
{
|
{
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
else if (eCIValue is > 16383 and <= 999999)
|
else if (eCIValue is > 16383 and <= 999999)
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
|
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
||||||
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
||||||
/// <returns>Number of bits for ECI Assignment Value</returns>
|
/// <returns>Number of bits for ECI Assignment Value</returns>
|
||||||
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
|
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
|
||||||
|
|
||||||
private void AppendECI(string name, int value, AppendOption option)
|
private void AppendECI(string name, int value, AppendOption option)
|
||||||
{
|
{
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case AppendOption.NameToValue:
|
case AppendOption.NameToValue:
|
||||||
_nameToValue?.Add(name, value);
|
_nameToValue?.Add(name, value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppendOption.ValueToName:
|
case AppendOption.ValueToName:
|
||||||
_valueToName?.Add(value, name);
|
_valueToName?.Add(value, name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppendOption.Both:
|
case AppendOption.Both:
|
||||||
_nameToValue?.Add(name, value);
|
_nameToValue?.Add(name, value);
|
||||||
_valueToName?.Add(value, name);
|
_valueToName?.Add(value, name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
|
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Initialize(AppendOption option)
|
private void Initialize(AppendOption option)
|
||||||
{
|
{
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case AppendOption.NameToValue:
|
case AppendOption.NameToValue:
|
||||||
_nameToValue = new Dictionary<string, int>();
|
_nameToValue = new Dictionary<string, int>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppendOption.ValueToName:
|
case AppendOption.ValueToName:
|
||||||
_valueToName = new Dictionary<int, string>();
|
_valueToName = new Dictionary<int, string>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AppendOption.Both:
|
case AppendOption.Both:
|
||||||
_nameToValue = new Dictionary<string, int>();
|
_nameToValue = new Dictionary<string, int>();
|
||||||
_valueToName = new Dictionary<int, string>();
|
_valueToName = new Dictionary<int, string>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
|
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
|
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
|
||||||
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
|
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
|
||||||
// ToDo. Fill up remaining missing table.
|
// ToDo. Fill up remaining missing table.
|
||||||
AppendECI("iso-8859-1", 1, option);
|
AppendECI("iso-8859-1", 1, option);
|
||||||
AppendECI("IBM437", 2, option);
|
AppendECI("IBM437", 2, option);
|
||||||
|
|
||||||
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
|
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
|
||||||
AppendECI("iso-8859-2", 4, option);
|
AppendECI("iso-8859-2", 4, option);
|
||||||
AppendECI("iso-8859-3", 5, option);
|
AppendECI("iso-8859-3", 5, option);
|
||||||
AppendECI("iso-8859-4", 6, option);
|
AppendECI("iso-8859-4", 6, option);
|
||||||
AppendECI("iso-8859-5", 7, option);
|
AppendECI("iso-8859-5", 7, option);
|
||||||
AppendECI("iso-8859-6", 8, option);
|
AppendECI("iso-8859-6", 8, option);
|
||||||
AppendECI("iso-8859-7", 9, option);
|
AppendECI("iso-8859-7", 9, option);
|
||||||
AppendECI("iso-8859-8", 10, option);
|
AppendECI("iso-8859-8", 10, option);
|
||||||
AppendECI("iso-8859-9", 11, option);
|
AppendECI("iso-8859-9", 11, option);
|
||||||
AppendECI("windows-874", 13, option);
|
AppendECI("windows-874", 13, option);
|
||||||
AppendECI("iso-8859-13", 15, option);
|
AppendECI("iso-8859-13", 15, option);
|
||||||
AppendECI("iso-8859-15", 17, option);
|
AppendECI("iso-8859-15", 17, option);
|
||||||
AppendECI("shift_jis", 20, option);
|
AppendECI("shift_jis", 20, option);
|
||||||
AppendECI("utf-8", 26, option);
|
AppendECI("utf-8", 26, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
|
||||||
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
/// <param name="eCIValue">Range: 0 ~ 999999</param>
|
||||||
/// <returns>Number of bits for ECI Header</returns>
|
/// <returns>Number of bits for ECI Header</returns>
|
||||||
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
|
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
|
||||||
|
|
||||||
internal int GetECIValueByName(string encodingName)
|
internal int GetECIValueByName(string encodingName)
|
||||||
{
|
{
|
||||||
if (_nameToValue is null)
|
if (_nameToValue is null)
|
||||||
{
|
{
|
||||||
Initialize(AppendOption.NameToValue);
|
Initialize(AppendOption.NameToValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
|
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
|
||||||
{
|
{
|
||||||
return eCIValue;
|
return eCIValue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
|
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string GetECINameByValue(int eCIValue)
|
internal string GetECINameByValue(int eCIValue)
|
||||||
{
|
{
|
||||||
if (_valueToName is null)
|
if (_valueToName is null)
|
||||||
{
|
{
|
||||||
Initialize(AppendOption.ValueToName);
|
Initialize(AppendOption.ValueToName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
|
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
|
||||||
{
|
{
|
||||||
return eCIName;
|
return eCIName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
|
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <returns>ECI table in Dictionary collection</returns>
|
/// <returns>ECI table in Dictionary collection</returns>
|
||||||
public Dictionary<string, int>? GetECITable()
|
public Dictionary<string, int>? GetECITable()
|
||||||
{
|
{
|
||||||
if (_nameToValue is null)
|
if (_nameToValue is null)
|
||||||
{
|
{
|
||||||
Initialize(AppendOption.NameToValue);
|
Initialize(AppendOption.NameToValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _nameToValue;
|
return _nameToValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsECIName(string encodingName)
|
public bool ContainsECIName(string encodingName)
|
||||||
{
|
{
|
||||||
if (_nameToValue is null)
|
if (_nameToValue is null)
|
||||||
{
|
{
|
||||||
Initialize(AppendOption.NameToValue);
|
Initialize(AppendOption.NameToValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _nameToValue!.ContainsKey(encodingName);
|
return _nameToValue!.ContainsKey(encodingName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsECIValue(int eciValue)
|
public bool ContainsECIValue(int eciValue)
|
||||||
{
|
{
|
||||||
if (_valueToName is null)
|
if (_valueToName is null)
|
||||||
{
|
{
|
||||||
Initialize(AppendOption.ValueToName);
|
Initialize(AppendOption.ValueToName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _valueToName!.ContainsKey(eciValue);
|
return _valueToName!.ContainsKey(eciValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
|
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
|
||||||
internal BitList GetECIHeader(string encodingName)
|
internal BitList GetECIHeader(string encodingName)
|
||||||
{
|
{
|
||||||
int eciValue = GetECIValueByName(encodingName);
|
int eciValue = GetECIValueByName(encodingName);
|
||||||
|
|
||||||
BitList dataBits = new()
|
BitList dataBits = new()
|
||||||
{
|
{
|
||||||
{ ECIMode, ECIIndicatorNumBits }
|
{ ECIMode, ECIIndicatorNumBits }
|
||||||
};
|
};
|
||||||
|
|
||||||
int eciAssignmentByte = NumOfCodewords(eciValue);
|
int eciAssignmentByte = NumOfCodewords(eciValue);
|
||||||
|
|
||||||
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
|
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
|
||||||
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
|
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
|
||||||
int eciAssignmentBits;
|
int eciAssignmentBits;
|
||||||
switch (eciAssignmentByte)
|
switch (eciAssignmentByte)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
// Indicator = 0. Page 24. Chapter 6.4.2.1
|
// Indicator = 0. Page 24. Chapter 6.4.2.1
|
||||||
dataBits.Add((int)ECICodewordsLength.One, 1);
|
dataBits.Add((int)ECICodewordsLength.One, 1);
|
||||||
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
|
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// Indicator = 10. Page 24. Chapter 6.4.2.1
|
// Indicator = 10. Page 24. Chapter 6.4.2.1
|
||||||
dataBits.Add((int)ECICodewordsLength.Two, 2);
|
dataBits.Add((int)ECICodewordsLength.Two, 2);
|
||||||
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
|
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
// Indicator = 110. Page 24. Chapter 6.4.2.1
|
// Indicator = 110. Page 24. Chapter 6.4.2.1
|
||||||
dataBits.Add((int)ECICodewordsLength.Three, 3);
|
dataBits.Add((int)ECICodewordsLength.Three, 3);
|
||||||
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
|
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
|
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
|
||||||
}
|
}
|
||||||
|
|
||||||
dataBits.Add(eciValue, eciAssignmentBits);
|
dataBits.Add(eciValue, eciAssignmentBits);
|
||||||
|
|
||||||
return dataBits;
|
return dataBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+51
-53
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -14,67 +12,67 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
|||||||
/// <remarks>ISO/IEC 18004:2000 Chapter 8.4.4 Page 22</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Chapter 8.4.4 Page 22</remarks>
|
||||||
internal class EightBitByteEncoder : EncoderBase
|
internal class EightBitByteEncoder : EncoderBase
|
||||||
{
|
{
|
||||||
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
|
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bitcount, Chapter 8.4.4, P.24
|
/// Bitcount, Chapter 8.4.4, P.24
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int EightBitByteBitcount = 8;
|
private const int EightBitByteBitcount = 8;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// EightBitByte encoder's encoding will change according to different region
|
/// EightBitByte encoder's encoding will change according to different region
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
|
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
|
||||||
internal EightBitByteEncoder(string encoding) : base()
|
internal EightBitByteEncoder(string encoding) : base()
|
||||||
{
|
{
|
||||||
Encoding = encoding ?? DefaultEncoding;
|
Encoding = encoding ?? DefaultEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal EightBitByteEncoder() : base()
|
internal EightBitByteEncoder() : base()
|
||||||
{
|
{
|
||||||
Encoding = DefaultEncoding;
|
Encoding = DefaultEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string Encoding { get; private set; }
|
internal string Encoding { get; private set; }
|
||||||
|
|
||||||
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
|
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
|
||||||
|
|
||||||
internal override BitList GetDataBits(string content)
|
internal override BitList GetDataBits(string content)
|
||||||
{
|
{
|
||||||
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
|
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
|
||||||
if (!eciSet.ContainsECIName(Encoding))
|
if (!eciSet.ContainsECIName(Encoding))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(
|
throw new ArgumentOutOfRangeException(
|
||||||
nameof(Encoding),
|
nameof(Encoding),
|
||||||
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
|
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] contentBytes = EncodeContent(content, Encoding);
|
byte[] contentBytes = EncodeContent(content, Encoding);
|
||||||
|
|
||||||
return GetDataBitsByByteArray(contentBytes, Encoding);
|
return GetDataBitsByByteArray(contentBytes, Encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
|
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
|
||||||
{
|
{
|
||||||
var dataBits = new BitList();
|
var dataBits = new BitList();
|
||||||
|
|
||||||
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
|
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
|
||||||
// Also include ECI header before encoding header. Which will be add with encoding header.
|
// Also include ECI header before encoding header. Which will be add with encoding header.
|
||||||
if (encodingName == "utf-8")
|
if (encodingName == "utf-8")
|
||||||
{
|
{
|
||||||
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
|
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
|
||||||
for (int index = 0; index < utf8BOM.Length; index++)
|
for (int index = 0; index < utf8BOM.Length; index++)
|
||||||
{
|
{
|
||||||
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
|
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < encodeContent.Length; index++)
|
for (int index = 0; index < encodeContent.Length; index++)
|
||||||
{
|
{
|
||||||
dataBits.Add(encodeContent[index], EightBitByteBitcount);
|
dataBits.Add(encodeContent[index], EightBitByteBitcount);
|
||||||
}
|
}
|
||||||
return dataBits;
|
return dataBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
|
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,12 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
|||||||
|
|
||||||
internal struct EncodationStruct
|
internal struct EncodationStruct
|
||||||
{
|
{
|
||||||
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
|
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
|
||||||
{
|
{
|
||||||
VersionDetail = vcStruct.VersionDetail;
|
VersionDetail = vcStruct.VersionDetail;
|
||||||
DataCodewords = dataCodewords;
|
DataCodewords = dataCodewords;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal VersionDetail VersionDetail { get; set; }
|
internal VersionDetail VersionDetail { get; set; }
|
||||||
internal BitList DataCodewords { get; set; }
|
internal BitList DataCodewords { get; set; }
|
||||||
}
|
}
|
||||||
@@ -2,45 +2,45 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
|
|||||||
|
|
||||||
public abstract class EncoderBase
|
public abstract class EncoderBase
|
||||||
{
|
{
|
||||||
internal EncoderBase()
|
internal EncoderBase()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual int GetDataLength(string content) => content.Length;
|
protected virtual int GetDataLength(string content) => content.Length;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the bit representation of input data.
|
/// Returns the bit representation of input data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal abstract BitList GetDataBits(string content);
|
internal abstract BitList GetDataBits(string content);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns bit representation of Modevalue.
|
/// Returns bit representation of Modevalue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
|
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
|
||||||
internal BitList GetModeIndicator()
|
internal BitList GetModeIndicator()
|
||||||
{
|
{
|
||||||
BitList modeIndicatorBits = new()
|
BitList modeIndicatorBits = new()
|
||||||
{
|
{
|
||||||
{ 0001 << 2, 4 }
|
{ 0001 << 2, 4 }
|
||||||
};
|
};
|
||||||
return modeIndicatorBits;
|
return modeIndicatorBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal BitList GetCharCountIndicator(int characterCount, int version)
|
internal BitList GetCharCountIndicator(int characterCount, int version)
|
||||||
{
|
{
|
||||||
BitList characterCountBits = new();
|
BitList characterCountBits = new();
|
||||||
int bitCount = GetBitCountInCharCountIndicator(version);
|
int bitCount = GetBitCountInCharCountIndicator(version);
|
||||||
characterCountBits.Add(characterCount, bitCount);
|
characterCountBits.Add(characterCount, bitCount);
|
||||||
return characterCountBits;
|
return characterCountBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the length of the Character Count Indicator,
|
/// Defines the length of the Character Count Indicator,
|
||||||
/// which varies according to the mode and the symbol version in use
|
/// which varies according to the mode and the symbol version in use
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Number of bits in Character Count Indicator.</returns>
|
/// <returns>Number of bits in Character Count Indicator.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
|
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected abstract int GetBitCountInCharCountIndicator(int version);
|
protected abstract int GetBitCountInCharCountIndicator(int version);
|
||||||
}
|
}
|
||||||
+38
-41
@@ -1,57 +1,54 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
||||||
|
|
||||||
public static class InputRecognise
|
public static class InputRecognise
|
||||||
{
|
{
|
||||||
public static RecognitionStruct Recognise(string content)
|
public static RecognitionStruct Recognise(string content)
|
||||||
{
|
{
|
||||||
string encodingName = EightBitByteRecognision(content, 0, content.Length);
|
string encodingName = EightBitByteRecognision(content, 0, content.Length);
|
||||||
return new RecognitionStruct(encodingName);
|
return new RecognitionStruct(encodingName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
|
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(content))
|
if (string.IsNullOrEmpty(content))
|
||||||
throw new ArgumentNullException(nameof(content));
|
throw new ArgumentNullException(nameof(content));
|
||||||
|
|
||||||
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
|
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
|
||||||
|
|
||||||
Dictionary<string, int>? eciSet = eciSets.GetECITable();
|
Dictionary<string, int>? eciSet = eciSets.GetECITable();
|
||||||
|
|
||||||
if(eciSet == null)
|
if (eciSet == null)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
// we will not check for utf8 encoding.
|
// we will not check for utf8 encoding.
|
||||||
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
|
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
|
||||||
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
|
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
|
||||||
|
|
||||||
int scanPos = startPos;
|
int scanPos = startPos;
|
||||||
|
|
||||||
// default encoding as priority
|
// default encoding as priority
|
||||||
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
|
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
|
||||||
if (scanPos == -1)
|
if (scanPos == -1)
|
||||||
{
|
{
|
||||||
return QRCodeConstantVariable.DefaultEncoding;
|
return QRCodeConstantVariable.DefaultEncoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (KeyValuePair<string, int> kvp in eciSet)
|
foreach (KeyValuePair<string, int> kvp in eciSet)
|
||||||
{
|
{
|
||||||
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
|
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
|
||||||
if (scanPos == -1)
|
if (scanPos == -1)
|
||||||
{
|
{
|
||||||
return kvp.Key;
|
return kvp.Key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scanPos == -1)
|
if (scanPos == -1)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("foreach Loop check give wrong result.");
|
throw new ArgumentException("foreach Loop check give wrong result.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return QRCodeConstantVariable.UTF8Encoding;
|
return QRCodeConstantVariable.UTF8Encoding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+59
-61
@@ -1,72 +1,70 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
||||||
|
|
||||||
public static class ModeEncodeCheck
|
public static class ModeEncodeCheck
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
|
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
|
||||||
/// 0x3F is '?'
|
/// 0x3F is '?'
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int QuestionMarkChar = 0x3F;
|
private const int QuestionMarkChar = 0x3F;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
|
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
|
||||||
/// it will return -1. Else it will return failed encoding position.
|
/// it will return -1. Else it will return failed encoding position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="content">Input string</param>
|
/// <param name="content">Input string</param>
|
||||||
/// <param name="encodingName">Encoding name. Check ECI table</param>
|
/// <param name="encodingName">Encoding name. Check ECI table</param>
|
||||||
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
|
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
|
||||||
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
|
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(content))
|
if (string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
throw new IndexOutOfRangeException("Input cannot be null or empty.");
|
throw new IndexOutOfRangeException("Input cannot be null or empty.");
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Text.Encoding encoding;
|
System.Text.Encoding encoding;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
encoding = System.Text.Encoding.GetEncoding(encodingName);
|
encoding = System.Text.Encoding.GetEncoding(encodingName);
|
||||||
}
|
}
|
||||||
catch (ArgumentException)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
return startingPosition;
|
return startingPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] currentChar = new char[1];
|
char[] currentChar = new char[1];
|
||||||
byte[] bytes;
|
byte[] bytes;
|
||||||
|
|
||||||
for (int index = startingPosition; index < contentLength; index++)
|
for (int index = startingPosition; index < contentLength; index++)
|
||||||
{
|
{
|
||||||
currentChar[0] = content[index];
|
currentChar[0] = content[index];
|
||||||
bytes = encoding.GetBytes(currentChar);
|
bytes = encoding.GetBytes(currentChar);
|
||||||
int length = bytes.Length;
|
int length = bytes.Length;
|
||||||
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
|
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
|
||||||
{
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
else if (length > 1)
|
else if (length > 1)
|
||||||
{
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int index = 0; index < startingPosition; index++)
|
for (int index = 0; index < startingPosition; index++)
|
||||||
{
|
{
|
||||||
currentChar[0] = content[index];
|
currentChar[0] = content[index];
|
||||||
bytes = encoding.GetBytes(currentChar);
|
bytes = encoding.GetBytes(currentChar);
|
||||||
int length = bytes.Length;
|
int length = bytes.Length;
|
||||||
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
|
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
|
||||||
{
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
else if (length > 1)
|
else if (length > 1)
|
||||||
{
|
{
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-6
@@ -2,11 +2,11 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
|
|||||||
|
|
||||||
public struct RecognitionStruct
|
public struct RecognitionStruct
|
||||||
{
|
{
|
||||||
public RecognitionStruct(string encodingName)
|
public RecognitionStruct(string encodingName)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
EncodingName = encodingName;
|
EncodingName = encodingName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EncodingName { get; private set; }
|
public string EncodingName { get; private set; }
|
||||||
}
|
}
|
||||||
@@ -2,59 +2,59 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
|||||||
|
|
||||||
internal static class BCHCalculator
|
internal static class BCHCalculator
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate int length by search for Most significant bit
|
/// Calculate int length by search for Most significant bit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="num">Input Number</param>
|
/// <param name="num">Input Number</param>
|
||||||
/// <returns>Most significant bit</returns>
|
/// <returns>Most significant bit</returns>
|
||||||
internal static int PosMSB(int num) => num == 0 ? 0 : BinarySearchPos(num, 0, 32) + 1;
|
internal static int PosMSB(int num) => num == 0 ? 0 : BinarySearchPos(num, 0, 32) + 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Search for right side bit of Most significant bit
|
/// Search for right side bit of Most significant bit
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="num">Input number</param>
|
/// <param name="num">Input number</param>
|
||||||
/// <param name="lowBoundary">Lower boundary. At start should be 0</param>
|
/// <param name="lowBoundary">Lower boundary. At start should be 0</param>
|
||||||
/// <param name="highBoundary">Higher boundary. At start should be 32</param>
|
/// <param name="highBoundary">Higher boundary. At start should be 32</param>
|
||||||
/// <returns>Most significant bit - 1</returns>
|
/// <returns>Most significant bit - 1</returns>
|
||||||
private static int BinarySearchPos(int num, int lowBoundary, int highBoundary)
|
private static int BinarySearchPos(int num, int lowBoundary, int highBoundary)
|
||||||
{
|
{
|
||||||
int mid = (lowBoundary + highBoundary) / 2;
|
int mid = (lowBoundary + highBoundary) / 2;
|
||||||
int shiftResult = num >> mid;
|
int shiftResult = num >> mid;
|
||||||
if (shiftResult == 1)
|
if (shiftResult == 1)
|
||||||
{
|
{
|
||||||
return mid;
|
return mid;
|
||||||
}
|
}
|
||||||
else if (shiftResult < 1)
|
else if (shiftResult < 1)
|
||||||
{
|
{
|
||||||
return BinarySearchPos(num, lowBoundary, mid);
|
return BinarySearchPos(num, lowBoundary, mid);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return BinarySearchPos(num, mid, highBoundary);
|
return BinarySearchPos(num, mid, highBoundary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// With input number and polynomial number. Method will calculate BCH value and return
|
/// With input number and polynomial number. Method will calculate BCH value and return
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="num">Input number</param>
|
/// <param name="num">Input number</param>
|
||||||
/// <param name="poly">Polynomial number</param>
|
/// <param name="poly">Polynomial number</param>
|
||||||
/// <returns>BCH value</returns>
|
/// <returns>BCH value</returns>
|
||||||
internal static int CalculateBCH(int num, int poly)
|
internal static int CalculateBCH(int num, int poly)
|
||||||
{
|
{
|
||||||
int polyMSB = PosMSB(poly);
|
int polyMSB = PosMSB(poly);
|
||||||
|
|
||||||
// num's length will be old length + new length - 1.
|
// num's length will be old length + new length - 1.
|
||||||
// Once divide poly number. BCH number will be one length short than Poly number's length.
|
// Once divide poly number. BCH number will be one length short than Poly number's length.
|
||||||
num <<= (polyMSB - 1);
|
num <<= (polyMSB - 1);
|
||||||
int numMSB = PosMSB(num);
|
int numMSB = PosMSB(num);
|
||||||
while (PosMSB(num) >= polyMSB)
|
while (PosMSB(num) >= polyMSB)
|
||||||
{
|
{
|
||||||
// left shift Poly number to same level as num. Then xor.
|
// left shift Poly number to same level as num. Then xor.
|
||||||
// Remove most significant bits of num.
|
// Remove most significant bits of num.
|
||||||
num ^= poly << (numMSB - polyMSB);
|
num ^= poly << (numMSB - polyMSB);
|
||||||
numMSB = PosMSB(num);
|
numMSB = PosMSB(num);
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,72 +1,70 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
||||||
|
|
||||||
/// <remarks>ISO/IEC 18004:2000 Chapter 8.7.3 Page 46</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Chapter 8.7.3 Page 46</remarks>
|
||||||
internal static class Codeword
|
internal static class Codeword
|
||||||
{
|
{
|
||||||
internal static void TryEmbedCodewords(this TriStateMatrix tsMatrix, BitList codewords)
|
internal static void TryEmbedCodewords(this TriStateMatrix tsMatrix, BitList codewords)
|
||||||
{
|
{
|
||||||
int sWidth = tsMatrix.Width;
|
int sWidth = tsMatrix.Width;
|
||||||
int codewordsSize = codewords.Count;
|
int codewordsSize = codewords.Count;
|
||||||
|
|
||||||
int bitIndex = 0;
|
int bitIndex = 0;
|
||||||
int directionUp = -1;
|
int directionUp = -1;
|
||||||
|
|
||||||
int x = sWidth - 1;
|
int x = sWidth - 1;
|
||||||
int y = sWidth - 1;
|
int y = sWidth - 1;
|
||||||
|
|
||||||
while (x > 0)
|
while (x > 0)
|
||||||
{
|
{
|
||||||
// Skip vertical timing pattern
|
// Skip vertical timing pattern
|
||||||
if (x == 6)
|
if (x == 6)
|
||||||
{
|
{
|
||||||
x -= 1;
|
x -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (y >= 0 && y < sWidth)
|
while (y >= 0 && y < sWidth)
|
||||||
{
|
{
|
||||||
for (int xOffset = 0; xOffset < 2; xOffset++)
|
for (int xOffset = 0; xOffset < 2; xOffset++)
|
||||||
{
|
{
|
||||||
int xPos = x - xOffset;
|
int xPos = x - xOffset;
|
||||||
if (tsMatrix.MStatus(xPos, y) == MatrixStatus.None)
|
if (tsMatrix.MStatus(xPos, y) == MatrixStatus.None)
|
||||||
{
|
{
|
||||||
bool bit;
|
bool bit;
|
||||||
if (bitIndex < codewordsSize)
|
if (bitIndex < codewordsSize)
|
||||||
{
|
{
|
||||||
bit = codewords[bitIndex];
|
bit = codewords[bitIndex];
|
||||||
bitIndex++;
|
bitIndex++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bit = false;
|
bit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsMatrix[xPos, y, MatrixStatus.Data] = bit;
|
tsMatrix[xPos, y, MatrixStatus.Data] = bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
y = NextY(y, directionUp);
|
y = NextY(y, directionUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
directionUp = ChangeDirection(directionUp);
|
directionUp = ChangeDirection(directionUp);
|
||||||
y = NextY(y, directionUp);
|
y = NextY(y, directionUp);
|
||||||
x -= 2;
|
x -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitIndex != codewordsSize)
|
if (bitIndex != codewordsSize)
|
||||||
{
|
{
|
||||||
throw new Exception($"Not all bits from {nameof(codewords)} consumed by matrix: {bitIndex} / {codewordsSize}.");
|
throw new Exception($"Not all bits from {nameof(codewords)} consumed by matrix: {bitIndex} / {codewordsSize}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int NextY(int y, int directionUp)
|
internal static int NextY(int y, int directionUp)
|
||||||
{
|
{
|
||||||
return y + directionUp;
|
return y + directionUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int ChangeDirection(int directionUp)
|
internal static int ChangeDirection(int directionUp)
|
||||||
{
|
{
|
||||||
return -directionUp;
|
return -directionUp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using Gma.QrCodeNet.Encoding.Masking;
|
using Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
||||||
@@ -10,105 +9,105 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
|||||||
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
|
||||||
internal static class FormatInformation
|
internal static class FormatInformation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// From Appendix C in JISX0510:2004 (p.65).
|
/// From Appendix C in JISX0510:2004 (p.65).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int FormatInfoPoly = 0x537;
|
private const int FormatInfoPoly = 0x537;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// From Appendix C in JISX0510:2004 (p.65).
|
/// From Appendix C in JISX0510:2004 (p.65).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int FormatInfoMaskPattern = 0x5412;
|
private const int FormatInfoMaskPattern = 0x5412;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Embed format information to tristatematrix.
|
/// Embed format information to tristatematrix.
|
||||||
/// Process combination of create info bits, BCH error correction bits calculation, embed towards matrix.
|
/// Process combination of create info bits, BCH error correction bits calculation, embed towards matrix.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Chapter 8.9 Page 53</remarks>
|
||||||
internal static void EmbedFormatInformation(this TriStateMatrix triMatrix, ErrorCorrectionLevel errorLevel, Pattern pattern)
|
internal static void EmbedFormatInformation(this TriStateMatrix triMatrix, ErrorCorrectionLevel errorLevel, Pattern pattern)
|
||||||
{
|
{
|
||||||
BitList formatInfo = GetFormatInfoBits(errorLevel, pattern);
|
BitList formatInfo = GetFormatInfoBits(errorLevel, pattern);
|
||||||
int width = triMatrix.Width;
|
int width = triMatrix.Width;
|
||||||
for (int index = 0; index < 15; index++)
|
for (int index = 0; index < 15; index++)
|
||||||
{
|
{
|
||||||
MatrixPoint point = PointForInfo1(index);
|
MatrixPoint point = PointForInfo1(index);
|
||||||
bool bit = formatInfo[index];
|
bool bit = formatInfo[index];
|
||||||
triMatrix[point.X, point.Y, MatrixStatus.NoMask] = bit;
|
triMatrix[point.X, point.Y, MatrixStatus.NoMask] = bit;
|
||||||
|
|
||||||
if (index < 7)
|
if (index < 7)
|
||||||
{
|
{
|
||||||
triMatrix[8, width - 1 - index, MatrixStatus.NoMask] = bit;
|
triMatrix[8, width - 1 - index, MatrixStatus.NoMask] = bit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
triMatrix[width - 8 + (index - 7), 8, MatrixStatus.NoMask] = bit;
|
triMatrix[width - 8 + (index - 7), 8, MatrixStatus.NoMask] = bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MatrixPoint PointForInfo1(int bitsIndex)
|
private static MatrixPoint PointForInfo1(int bitsIndex)
|
||||||
{
|
{
|
||||||
if (bitsIndex <= 7)
|
if (bitsIndex <= 7)
|
||||||
{
|
{
|
||||||
return bitsIndex >= 6
|
return bitsIndex >= 6
|
||||||
? new MatrixPoint(bitsIndex + 1, 8)
|
? new MatrixPoint(bitsIndex + 1, 8)
|
||||||
: new MatrixPoint(bitsIndex, 8);
|
: new MatrixPoint(bitsIndex, 8);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return bitsIndex == 8
|
return bitsIndex == 8
|
||||||
? new MatrixPoint(8, 8 - (bitsIndex - 7))
|
? new MatrixPoint(8, 8 - (bitsIndex - 7))
|
||||||
: new MatrixPoint(8, 8 - (bitsIndex - 7) - 1);
|
: new MatrixPoint(8, 8 - (bitsIndex - 7) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitList GetFormatInfoBits(ErrorCorrectionLevel errorLevel, Pattern pattern)
|
private static BitList GetFormatInfoBits(ErrorCorrectionLevel errorLevel, Pattern pattern)
|
||||||
{
|
{
|
||||||
int formatInfo = (int)pattern.MaskPatternType;
|
int formatInfo = (int)pattern.MaskPatternType;
|
||||||
|
|
||||||
// Pattern bits length = 3
|
// Pattern bits length = 3
|
||||||
formatInfo |= GetErrorCorrectionIndicatorBits(errorLevel) << 3;
|
formatInfo |= GetErrorCorrectionIndicatorBits(errorLevel) << 3;
|
||||||
|
|
||||||
int bchCode = BCHCalculator.CalculateBCH(formatInfo, FormatInfoPoly);
|
int bchCode = BCHCalculator.CalculateBCH(formatInfo, FormatInfoPoly);
|
||||||
|
|
||||||
// bchCode length = 10
|
// bchCode length = 10
|
||||||
formatInfo = (formatInfo << 10) | bchCode;
|
formatInfo = (formatInfo << 10) | bchCode;
|
||||||
|
|
||||||
// xor maskPattern
|
// xor maskPattern
|
||||||
formatInfo ^= FormatInfoMaskPattern;
|
formatInfo ^= FormatInfoMaskPattern;
|
||||||
|
|
||||||
BitList resultBits = new()
|
BitList resultBits = new()
|
||||||
{
|
{
|
||||||
{ formatInfo, 15 }
|
{ formatInfo, 15 }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (resultBits.Count != 15)
|
if (resultBits.Count != 15)
|
||||||
{
|
{
|
||||||
throw new Exception("FormatInfoBits length is not 15");
|
throw new Exception("FormatInfoBits length is not 15");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return resultBits;
|
return resultBits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// According Table 25 — Error correction level indicators
|
/// According Table 25 — Error correction level indicators
|
||||||
/// Using these bits as enum values would destroy their order which currently corresponds to error correction strength.
|
/// Using these bits as enum values would destroy their order which currently corresponds to error correction strength.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static int GetErrorCorrectionIndicatorBits(ErrorCorrectionLevel errorLevel)
|
internal static int GetErrorCorrectionIndicatorBits(ErrorCorrectionLevel errorLevel)
|
||||||
{
|
{
|
||||||
// L 01
|
// L 01
|
||||||
// M 00
|
// M 00
|
||||||
// Q 11
|
// Q 11
|
||||||
// H 10
|
// H 10
|
||||||
return errorLevel switch
|
return errorLevel switch
|
||||||
{
|
{
|
||||||
ErrorCorrectionLevel.H => 0x02,
|
ErrorCorrectionLevel.H => 0x02,
|
||||||
ErrorCorrectionLevel.L => 0x01,
|
ErrorCorrectionLevel.L => 0x01,
|
||||||
ErrorCorrectionLevel.M => 0x00,
|
ErrorCorrectionLevel.M => 0x00,
|
||||||
ErrorCorrectionLevel.Q => 0x03,
|
ErrorCorrectionLevel.Q => 0x03,
|
||||||
_ => throw new ArgumentException($"Unsupported error correction level [{errorLevel}]", nameof(errorLevel))
|
_ => throw new ArgumentException($"Unsupported error correction level [{errorLevel}]", nameof(errorLevel))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -8,63 +6,63 @@ namespace Gma.QrCodeNet.Encoding.EncodingRegion;
|
|||||||
/// <remarks>ISO/IEC 18004:2000 Chapter 8.10 Page 54</remarks>
|
/// <remarks>ISO/IEC 18004:2000 Chapter 8.10 Page 54</remarks>
|
||||||
internal static class VersionInformation
|
internal static class VersionInformation
|
||||||
{
|
{
|
||||||
private const int VIRectangleHeight = 3;
|
private const int VIRectangleHeight = 3;
|
||||||
private const int VIRectangleWidth = 6;
|
private const int VIRectangleWidth = 6;
|
||||||
|
|
||||||
private const int LengthDataBits = 6;
|
private const int LengthDataBits = 6;
|
||||||
private const int LengthECBits = 12;
|
private const int LengthECBits = 12;
|
||||||
private const int VersionBCHPoly = 0x1f25;
|
private const int VersionBCHPoly = 0x1f25;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Embed version information to Matrix
|
/// Embed version information to Matrix
|
||||||
/// Only for version greater than or equal to 7
|
/// Only for version greater than or equal to 7
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static void EmbedVersionInformation(this TriStateMatrix tsMatrix, int version)
|
internal static void EmbedVersionInformation(this TriStateMatrix tsMatrix, int version)
|
||||||
{
|
{
|
||||||
if (version < 7)
|
if (version < 7)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitList versionInfo = VersionInfoBitList(version);
|
BitList versionInfo = VersionInfoBitList(version);
|
||||||
|
|
||||||
int matrixWidth = tsMatrix.Width;
|
int matrixWidth = tsMatrix.Width;
|
||||||
|
|
||||||
// 1 cell between version info and position stencil
|
// 1 cell between version info and position stencil
|
||||||
int shiftLength = QRCodeConstantVariable.PositionStencilWidth + VIRectangleHeight + 1;
|
int shiftLength = QRCodeConstantVariable.PositionStencilWidth + VIRectangleHeight + 1;
|
||||||
|
|
||||||
// Reverse order input
|
// Reverse order input
|
||||||
int viIndex = LengthDataBits + LengthECBits - 1;
|
int viIndex = LengthDataBits + LengthECBits - 1;
|
||||||
|
|
||||||
for (int viWidth = 0; viWidth < VIRectangleWidth; viWidth++)
|
for (int viWidth = 0; viWidth < VIRectangleWidth; viWidth++)
|
||||||
{
|
{
|
||||||
for (int viHeight = 0; viHeight < VIRectangleHeight; viHeight++)
|
for (int viHeight = 0; viHeight < VIRectangleHeight; viHeight++)
|
||||||
{
|
{
|
||||||
bool bit = versionInfo[viIndex];
|
bool bit = versionInfo[viIndex];
|
||||||
viIndex--;
|
viIndex--;
|
||||||
|
|
||||||
// Bottom left
|
// Bottom left
|
||||||
tsMatrix[viWidth, (matrixWidth - shiftLength + viHeight), MatrixStatus.NoMask] = bit;
|
tsMatrix[viWidth, (matrixWidth - shiftLength + viHeight), MatrixStatus.NoMask] = bit;
|
||||||
|
|
||||||
// Top right
|
// Top right
|
||||||
tsMatrix[(matrixWidth - shiftLength + viHeight), viWidth, MatrixStatus.NoMask] = bit;
|
tsMatrix[(matrixWidth - shiftLength + viHeight), viWidth, MatrixStatus.NoMask] = bit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitList VersionInfoBitList(int version)
|
private static BitList VersionInfoBitList(int version)
|
||||||
{
|
{
|
||||||
BitList result = new()
|
BitList result = new()
|
||||||
{
|
{
|
||||||
{ version, LengthDataBits },
|
{ version, LengthDataBits },
|
||||||
{ BCHCalculator.CalculateBCH(version, VersionBCHPoly), LengthECBits }
|
{ BCHCalculator.CalculateBCH(version, VersionBCHPoly), LengthECBits }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (result.Count != (LengthECBits + LengthDataBits))
|
if (result.Count != (LengthECBits + LengthDataBits))
|
||||||
{
|
{
|
||||||
throw new Exception("Version Info creation error. Result is not 18 bits");
|
throw new Exception("Version Info creation error. Result is not 18 bits");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,84 +1,82 @@
|
|||||||
using Gma.QrCodeNet.Encoding.ReedSolomon;
|
using Gma.QrCodeNet.Encoding.ReedSolomon;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.ErrorCorrection;
|
namespace Gma.QrCodeNet.Encoding.ErrorCorrection;
|
||||||
|
|
||||||
internal static class ECGenerator
|
internal static class ECGenerator
|
||||||
{
|
{
|
||||||
internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd)
|
internal static BitList FillECCodewords(BitList dataCodewords, VersionDetail vd)
|
||||||
{
|
{
|
||||||
List<byte> dataCodewordsByte = dataCodewords.List;
|
List<byte> dataCodewordsByte = dataCodewords.List;
|
||||||
|
|
||||||
int ecBlockGroup1 = vd.ECBlockGroup1;
|
int ecBlockGroup1 = vd.ECBlockGroup1;
|
||||||
int numDataBytesGroup1 = vd.NumDataBytesGroup1;
|
int numDataBytesGroup1 = vd.NumDataBytesGroup1;
|
||||||
int numDataBytesGroup2 = vd.NumDataBytesGroup2;
|
int numDataBytesGroup2 = vd.NumDataBytesGroup2;
|
||||||
|
|
||||||
int ecBytesPerBlock = vd.NumECBytesPerBlock;
|
int ecBytesPerBlock = vd.NumECBytesPerBlock;
|
||||||
|
|
||||||
int dataBytesOffset = 0;
|
int dataBytesOffset = 0;
|
||||||
byte[][] dByteJArray = new byte[vd.NumECBlocks][];
|
byte[][] dByteJArray = new byte[vd.NumECBlocks][];
|
||||||
byte[][] ecByteJArray = new byte[vd.NumECBlocks][];
|
byte[][] ecByteJArray = new byte[vd.NumECBlocks][];
|
||||||
|
|
||||||
GaloisField256 gf256 = GaloisField256.QRCodeGaloisField;
|
GaloisField256 gf256 = GaloisField256.QRCodeGaloisField;
|
||||||
GeneratorPolynomial generator = new(gf256);
|
GeneratorPolynomial generator = new(gf256);
|
||||||
|
|
||||||
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
||||||
{
|
{
|
||||||
if (blockId < ecBlockGroup1)
|
if (blockId < ecBlockGroup1)
|
||||||
{
|
{
|
||||||
dByteJArray[blockId] = new byte[numDataBytesGroup1];
|
dByteJArray[blockId] = new byte[numDataBytesGroup1];
|
||||||
for (int index = 0; index < numDataBytesGroup1; index++)
|
for (int index = 0; index < numDataBytesGroup1; index++)
|
||||||
{
|
{
|
||||||
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
|
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
|
||||||
}
|
}
|
||||||
dataBytesOffset += numDataBytesGroup1;
|
dataBytesOffset += numDataBytesGroup1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dByteJArray[blockId] = new byte[numDataBytesGroup2];
|
dByteJArray[blockId] = new byte[numDataBytesGroup2];
|
||||||
for (int index = 0; index < numDataBytesGroup2; index++)
|
for (int index = 0; index < numDataBytesGroup2; index++)
|
||||||
{
|
{
|
||||||
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
|
dByteJArray[blockId][index] = dataCodewordsByte[dataBytesOffset + index];
|
||||||
}
|
}
|
||||||
dataBytesOffset += numDataBytesGroup2;
|
dataBytesOffset += numDataBytesGroup2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ecByteJArray[blockId] = ReedSolomonEncoder.Encode(dByteJArray[blockId], ecBytesPerBlock, generator);
|
ecByteJArray[blockId] = ReedSolomonEncoder.Encode(dByteJArray[blockId], ecBytesPerBlock, generator);
|
||||||
}
|
}
|
||||||
if (vd.NumDataBytes != dataBytesOffset)
|
if (vd.NumDataBytes != dataBytesOffset)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Data bytes do not match offset");
|
throw new ArgumentException("Data bytes do not match offset");
|
||||||
}
|
}
|
||||||
|
|
||||||
BitList codewords = new();
|
BitList codewords = new();
|
||||||
|
|
||||||
int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2;
|
int maxDataLength = ecBlockGroup1 == vd.NumECBlocks ? numDataBytesGroup1 : numDataBytesGroup2;
|
||||||
|
|
||||||
for (int dataId = 0; dataId < maxDataLength; dataId++)
|
for (int dataId = 0; dataId < maxDataLength; dataId++)
|
||||||
{
|
{
|
||||||
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
||||||
{
|
{
|
||||||
if (!(dataId == numDataBytesGroup1 && blockId < ecBlockGroup1))
|
if (!(dataId == numDataBytesGroup1 && blockId < ecBlockGroup1))
|
||||||
{
|
{
|
||||||
codewords.Add(dByteJArray[blockId][dataId], 8);
|
codewords.Add(dByteJArray[blockId][dataId], 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ecId = 0; ecId < ecBytesPerBlock; ecId++)
|
for (int ecId = 0; ecId < ecBytesPerBlock; ecId++)
|
||||||
{
|
{
|
||||||
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
for (int blockId = 0; blockId < vd.NumECBlocks; blockId++)
|
||||||
{
|
{
|
||||||
codewords.Add(ecByteJArray[blockId][ecId], 8);
|
codewords.Add(ecByteJArray[blockId][ecId], 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vd.NumTotalBytes != codewords.Count >> 3)
|
if (vd.NumTotalBytes != codewords.Count >> 3)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"Total bytes: {vd.NumTotalBytes}. Actual bits: {codewords.Count}");
|
throw new ArgumentException($"Total bytes: {vd.NumTotalBytes}. Actual bits: {codewords.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return codewords;
|
return codewords;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public enum ErrorCorrectionLevel
|
public enum ErrorCorrectionLevel
|
||||||
{
|
{
|
||||||
L,
|
L,
|
||||||
M,
|
M,
|
||||||
Q,
|
Q,
|
||||||
H
|
H
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding;
|
namespace Gma.QrCodeNet.Encoding;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -7,11 +5,11 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class InputOutOfBoundaryException : Exception
|
public class InputOutOfBoundaryException : Exception
|
||||||
{
|
{
|
||||||
public InputOutOfBoundaryException() : base()
|
public InputOutOfBoundaryException() : base()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputOutOfBoundaryException(string message) : base(message)
|
public InputOutOfBoundaryException(string message) : base(message)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,12 @@ namespace Gma.QrCodeNet.Encoding.Masking;
|
|||||||
|
|
||||||
public enum MaskPatternType
|
public enum MaskPatternType
|
||||||
{
|
{
|
||||||
Type0 = 0,
|
Type0 = 0,
|
||||||
Type1 = 1,
|
Type1 = 1,
|
||||||
Type2 = 2,
|
Type2 = 2,
|
||||||
Type3 = 3,
|
Type3 = 3,
|
||||||
Type4 = 4,
|
Type4 = 4,
|
||||||
Type5 = 5,
|
Type5 = 5,
|
||||||
Type6 = 6,
|
Type6 = 6,
|
||||||
Type7 = 7
|
Type7 = 7
|
||||||
}
|
}
|
||||||
@@ -1,44 +1,43 @@
|
|||||||
using System;
|
|
||||||
using Gma.QrCodeNet.Encoding.EncodingRegion;
|
using Gma.QrCodeNet.Encoding.EncodingRegion;
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
public static class MatrixExtensions
|
public static class MatrixExtensions
|
||||||
{
|
{
|
||||||
public static TriStateMatrix Xor(this TriStateMatrix first, Pattern second, ErrorCorrectionLevel errorLevel)
|
public static TriStateMatrix Xor(this TriStateMatrix first, Pattern second, ErrorCorrectionLevel errorLevel)
|
||||||
{
|
{
|
||||||
TriStateMatrix result = XorMatrix(first, second);
|
TriStateMatrix result = XorMatrix(first, second);
|
||||||
result.EmbedFormatInformation(errorLevel, second);
|
result.EmbedFormatInformation(errorLevel, second);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TriStateMatrix XorMatrix(TriStateMatrix first, BitMatrix second)
|
private static TriStateMatrix XorMatrix(TriStateMatrix first, BitMatrix second)
|
||||||
{
|
{
|
||||||
int width = first.Width;
|
int width = first.Width;
|
||||||
TriStateMatrix maskedMatrix = new(width);
|
TriStateMatrix maskedMatrix = new(width);
|
||||||
for (int x = 0; x < width; x++)
|
for (int x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < width; y++)
|
for (int y = 0; y < width; y++)
|
||||||
{
|
{
|
||||||
MatrixStatus states = first.MStatus(x, y);
|
MatrixStatus states = first.MStatus(x, y);
|
||||||
switch (states)
|
switch (states)
|
||||||
{
|
{
|
||||||
case MatrixStatus.NoMask:
|
case MatrixStatus.NoMask:
|
||||||
maskedMatrix[x, y, MatrixStatus.NoMask] = first[x, y];
|
maskedMatrix[x, y, MatrixStatus.NoMask] = first[x, y];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MatrixStatus.Data:
|
case MatrixStatus.Data:
|
||||||
maskedMatrix[x, y, MatrixStatus.Data] = first[x, y] ^ second[x, y];
|
maskedMatrix[x, y, MatrixStatus.Data] = first[x, y] ^ second[x, y];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"{nameof(TriStateMatrix)} has None value cell.", nameof(first));
|
throw new ArgumentException($"{nameof(TriStateMatrix)} has None value cell.", nameof(first));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return maskedMatrix;
|
return maskedMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TriStateMatrix Apply(this TriStateMatrix matrix, Pattern pattern, ErrorCorrectionLevel errorLevel) => matrix.Xor(pattern, errorLevel);
|
public static TriStateMatrix Apply(this TriStateMatrix matrix, Pattern pattern, ErrorCorrectionLevel errorLevel) => matrix.Xor(pattern, errorLevel);
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
public abstract class Pattern : BitMatrix
|
public abstract class Pattern : BitMatrix
|
||||||
{
|
{
|
||||||
public override int Width => throw new NotSupportedException();
|
public override int Width => throw new NotSupportedException();
|
||||||
public override int Height => throw new NotSupportedException();
|
public override int Height => throw new NotSupportedException();
|
||||||
|
|
||||||
public override bool[,] InternalArray => throw new NotImplementedException();
|
public override bool[,] InternalArray => throw new NotImplementedException();
|
||||||
|
|
||||||
public abstract MaskPatternType MaskPatternType { get; }
|
public abstract MaskPatternType MaskPatternType { get; }
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern0 : Pattern
|
internal class Pattern0 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type0;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type0;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => (j + i) % 2 == 0;
|
get => (j + i) % 2 == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern1 : Pattern
|
internal class Pattern1 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type1;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type1;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => j % 2 == 0;
|
get => j % 2 == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern2 : Pattern
|
internal class Pattern2 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type2;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type2;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => i % 3 == 0;
|
get => i % 3 == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern3 : Pattern
|
internal class Pattern3 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type3;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type3;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => (j + i) % 3 == 0;
|
get => (j + i) % 3 == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern4 : Pattern
|
internal class Pattern4 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type4;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type4;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => ((j / 2) + (i / 3)) % 2 == 0;
|
get => ((j / 2) + (i / 3)) % 2 == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern5 : Pattern
|
internal class Pattern5 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type5;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type5;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => (((i * j) % 2) + ((i * j) % 3)) == 0;
|
get => (((i * j) % 2) + ((i * j) % 3)) == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
using System;
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern6 : Pattern
|
internal class Pattern6 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type6;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type6;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => ((((i * j) % 2) + ((i * j) % 3)) % 2) == 0;
|
get => ((((i * j) % 2) + ((i * j) % 3)) % 2) == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class Pattern7 : Pattern
|
internal class Pattern7 : Pattern
|
||||||
{
|
{
|
||||||
public override MaskPatternType MaskPatternType => MaskPatternType.Type7;
|
public override MaskPatternType MaskPatternType => MaskPatternType.Type7;
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => (((i * j) % 3) + (((i + j) % 2) % 2)) == 0;
|
get => (((i * j) % 3) + (((i + j) % 2) % 2)) == 0;
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,28 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking;
|
namespace Gma.QrCodeNet.Encoding.Masking;
|
||||||
|
|
||||||
internal class PatternFactory
|
internal class PatternFactory
|
||||||
{
|
{
|
||||||
internal Pattern CreateByType(MaskPatternType maskPatternType)
|
internal Pattern CreateByType(MaskPatternType maskPatternType)
|
||||||
{
|
{
|
||||||
return maskPatternType switch
|
return maskPatternType switch
|
||||||
{
|
{
|
||||||
MaskPatternType.Type0 => new Pattern0(),
|
MaskPatternType.Type0 => new Pattern0(),
|
||||||
MaskPatternType.Type1 => new Pattern1(),
|
MaskPatternType.Type1 => new Pattern1(),
|
||||||
MaskPatternType.Type2 => new Pattern2(),
|
MaskPatternType.Type2 => new Pattern2(),
|
||||||
MaskPatternType.Type3 => new Pattern3(),
|
MaskPatternType.Type3 => new Pattern3(),
|
||||||
MaskPatternType.Type4 => new Pattern4(),
|
MaskPatternType.Type4 => new Pattern4(),
|
||||||
MaskPatternType.Type5 => new Pattern5(),
|
MaskPatternType.Type5 => new Pattern5(),
|
||||||
MaskPatternType.Type6 => new Pattern6(),
|
MaskPatternType.Type6 => new Pattern6(),
|
||||||
MaskPatternType.Type7 => new Pattern7(),
|
MaskPatternType.Type7 => new Pattern7(),
|
||||||
_ => throw new NotSupportedException("This should never happen.")
|
_ => throw new NotSupportedException("This should never happen.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<Pattern> AllPatterns()
|
internal IEnumerable<Pattern> AllPatterns()
|
||||||
{
|
{
|
||||||
foreach (MaskPatternType patternType in Enum.GetValues(typeof(MaskPatternType)))
|
foreach (MaskPatternType patternType in Enum.GetValues(typeof(MaskPatternType)))
|
||||||
{
|
{
|
||||||
yield return CreateByType(patternType);
|
yield return CreateByType(patternType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+27
-29
@@ -1,36 +1,34 @@
|
|||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
||||||
|
|
||||||
internal static class MatrixScoreCalculator
|
internal static class MatrixScoreCalculator
|
||||||
{
|
{
|
||||||
internal static BitMatrix GetLowestPenaltyMatrix(this TriStateMatrix matrix, ErrorCorrectionLevel errorLevel)
|
internal static BitMatrix GetLowestPenaltyMatrix(this TriStateMatrix matrix, ErrorCorrectionLevel errorLevel)
|
||||||
{
|
{
|
||||||
PatternFactory patternFactory = new();
|
PatternFactory patternFactory = new();
|
||||||
int score = int.MaxValue;
|
int score = int.MaxValue;
|
||||||
int tempScore;
|
int tempScore;
|
||||||
TriStateMatrix result = new(matrix.Width);
|
TriStateMatrix result = new(matrix.Width);
|
||||||
TriStateMatrix triMatrix;
|
TriStateMatrix triMatrix;
|
||||||
foreach (Pattern pattern in patternFactory.AllPatterns())
|
foreach (Pattern pattern in patternFactory.AllPatterns())
|
||||||
{
|
{
|
||||||
triMatrix = matrix.Apply(pattern, errorLevel);
|
triMatrix = matrix.Apply(pattern, errorLevel);
|
||||||
tempScore = triMatrix.PenaltyScore();
|
tempScore = triMatrix.PenaltyScore();
|
||||||
if (tempScore < score)
|
if (tempScore < score)
|
||||||
{
|
{
|
||||||
score = tempScore;
|
score = tempScore;
|
||||||
result = triMatrix;
|
result = triMatrix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int PenaltyScore(this BitMatrix matrix)
|
internal static int PenaltyScore(this BitMatrix matrix)
|
||||||
{
|
{
|
||||||
PenaltyFactory penaltyFactory = new();
|
PenaltyFactory penaltyFactory = new();
|
||||||
return
|
return
|
||||||
penaltyFactory
|
penaltyFactory
|
||||||
.AllRules()
|
.AllRules()
|
||||||
.Sum(penalty => penalty.PenaltyCalculate(matrix));
|
.Sum(penalty => penalty.PenaltyCalculate(matrix));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,5 +2,5 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
|
|
||||||
public abstract class Penalty
|
public abstract class Penalty
|
||||||
{
|
{
|
||||||
internal abstract int PenaltyCalculate(BitMatrix matrix);
|
internal abstract int PenaltyCalculate(BitMatrix matrix);
|
||||||
}
|
}
|
||||||
@@ -5,81 +5,81 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Penalty1 : Penalty
|
internal class Penalty1 : Penalty
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate penalty value for first rule.
|
/// Calculate penalty value for first rule.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal override int PenaltyCalculate(BitMatrix matrix)
|
internal override int PenaltyCalculate(BitMatrix matrix)
|
||||||
{
|
{
|
||||||
int penaltyValue = PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
|
int penaltyValue = PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
|
||||||
return penaltyValue;
|
return penaltyValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
|
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
|
||||||
{
|
{
|
||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
int width = matrix.Width;
|
int width = matrix.Width;
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
while (i < width)
|
while (i < width)
|
||||||
{
|
{
|
||||||
while (j < width - 4)
|
while (j < width - 4)
|
||||||
{
|
{
|
||||||
bool preBit = isHorizontal
|
bool preBit = isHorizontal
|
||||||
? matrix[j + 4, i]
|
? matrix[j + 4, i]
|
||||||
: matrix[i, j + 4];
|
: matrix[i, j + 4];
|
||||||
int numSameBitCell = 1;
|
int numSameBitCell = 1;
|
||||||
|
|
||||||
for (int x = 1; x <= 4; x++)
|
for (int x = 1; x <= 4; x++)
|
||||||
{
|
{
|
||||||
bool bit = isHorizontal
|
bool bit = isHorizontal
|
||||||
? matrix[j + 4 - x, i]
|
? matrix[j + 4 - x, i]
|
||||||
: matrix[i, j + 4 - x];
|
: matrix[i, j + 4 - x];
|
||||||
if (bit == preBit)
|
if (bit == preBit)
|
||||||
{
|
{
|
||||||
numSameBitCell++;
|
numSameBitCell++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numSameBitCell == 1)
|
if (numSameBitCell == 1)
|
||||||
{
|
{
|
||||||
j += 4;
|
j += 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int x = 5;
|
int x = 5;
|
||||||
while ((j + x) < width)
|
while ((j + x) < width)
|
||||||
{
|
{
|
||||||
bool bit = isHorizontal
|
bool bit = isHorizontal
|
||||||
? matrix[j + x, i]
|
? matrix[j + x, i]
|
||||||
: matrix[i, j + x];
|
: matrix[i, j + x];
|
||||||
if (bit == preBit)
|
if (bit == preBit)
|
||||||
{
|
{
|
||||||
numSameBitCell++;
|
numSameBitCell++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
if (numSameBitCell >= 5)
|
if (numSameBitCell >= 5)
|
||||||
{
|
{
|
||||||
penalty += (3 + (numSameBitCell - 5));
|
penalty += (3 + (numSameBitCell - 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
j += x;
|
j += x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j = 0;
|
j = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,47 +5,47 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Penalty2 : Penalty
|
internal class Penalty2 : Penalty
|
||||||
{
|
{
|
||||||
internal override int PenaltyCalculate(BitMatrix matrix)
|
internal override int PenaltyCalculate(BitMatrix matrix)
|
||||||
{
|
{
|
||||||
int width = matrix.Width;
|
int width = matrix.Width;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
|
|
||||||
while (y < (width - 1))
|
while (y < (width - 1))
|
||||||
{
|
{
|
||||||
while (x < (width - 1))
|
while (x < (width - 1))
|
||||||
{
|
{
|
||||||
bool topR = matrix[x + 1, y];
|
bool topR = matrix[x + 1, y];
|
||||||
|
|
||||||
if (topR == matrix[x + 1, y + 1]) // Bottom Right
|
if (topR == matrix[x + 1, y + 1]) // Bottom Right
|
||||||
{
|
{
|
||||||
if (topR == matrix[x, y + 1]) // Bottom Left
|
if (topR == matrix[x, y + 1]) // Bottom Left
|
||||||
{
|
{
|
||||||
if (topR == matrix[x, y]) // Top Left
|
if (topR == matrix[x, y]) // Top Left
|
||||||
{
|
{
|
||||||
penalty += 3;
|
penalty += 3;
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x += 1;
|
x += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
x += 2;
|
x += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x = 0;
|
x = 0;
|
||||||
y++;
|
y++;
|
||||||
}
|
}
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,137 +5,137 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Penalty3 : Penalty
|
internal class Penalty3 : Penalty
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate penalty value for Third rule.
|
/// Calculate penalty value for Third rule.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal override int PenaltyCalculate(BitMatrix matrix) => PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
|
internal override int PenaltyCalculate(BitMatrix matrix) => PenaltyCalculation(matrix, true) + PenaltyCalculation(matrix, false);
|
||||||
|
|
||||||
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
|
private int PenaltyCalculation(BitMatrix matrix, bool isHorizontal)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 1;
|
int j = 1;
|
||||||
int penalty = 0;
|
int penalty = 0;
|
||||||
int width = matrix.Width;
|
int width = matrix.Width;
|
||||||
bool bit;
|
bool bit;
|
||||||
while (i < width)
|
while (i < width)
|
||||||
{
|
{
|
||||||
while (j < width - 5)
|
while (j < width - 5)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + 4, i]
|
? matrix[j + 4, i]
|
||||||
: matrix[i, j + 4];
|
: matrix[i, j + 4];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j, i]
|
? matrix[j, i]
|
||||||
: matrix[i, j];
|
: matrix[i, j];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
penalty += PatternCheck(matrix, i, j, isHorizontal);
|
penalty += PatternCheck(matrix, i, j, isHorizontal);
|
||||||
j += 4;
|
j += 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
j += 4;
|
j += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int num = 4; num > 0; num--)
|
for (int num = 4; num > 0; num--)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + num, i]
|
? matrix[j + num, i]
|
||||||
: matrix[i, j + num];
|
: matrix[i, j + num];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
j += num;
|
j += num;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (num == 1)
|
if (num == 1)
|
||||||
{
|
{
|
||||||
j += 5;
|
j += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
j = 0;
|
j = 0;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return penalty;
|
return penalty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int PatternCheck(BitMatrix matrix, int i, int j, bool isHorizontal)
|
private int PatternCheck(BitMatrix matrix, int i, int j, bool isHorizontal)
|
||||||
{
|
{
|
||||||
bool bit;
|
bool bit;
|
||||||
for (int num = 3; num >= 1; num--)
|
for (int num = 3; num >= 1; num--)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + num, i]
|
? matrix[j + num, i]
|
||||||
: matrix[i, j + num];
|
: matrix[i, j + num];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for left side and right side x ( xoxxxox ).
|
// Check for left side and right side x ( xoxxxox ).
|
||||||
if ((j - 1) < 0 || (j + 1) >= matrix.Width)
|
if ((j - 1) < 0 || (j + 1) >= matrix.Width)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + 5, i]
|
? matrix[j + 5, i]
|
||||||
: matrix[i, j + 5];
|
: matrix[i, j + 5];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j - 1, i]
|
? matrix[j - 1, i]
|
||||||
: matrix[i, j - 1];
|
: matrix[i, j - 1];
|
||||||
if (!bit)
|
if (!bit)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((j - 5) >= 0)
|
if ((j - 5) >= 0)
|
||||||
{
|
{
|
||||||
for (int num = -2; num >= -5; num--)
|
for (int num = -2; num >= -5; num--)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + num, i]
|
? matrix[j + num, i]
|
||||||
: matrix[i, j + num];
|
: matrix[i, j + num];
|
||||||
if (bit)
|
if (bit)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num == -5)
|
if (num == -5)
|
||||||
{
|
{
|
||||||
return 40;
|
return 40;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((j + 9) < matrix.Width)
|
if ((j + 9) < matrix.Width)
|
||||||
{
|
{
|
||||||
for (int num = 6; num <= 9; num++)
|
for (int num = 6; num <= 9; num++)
|
||||||
{
|
{
|
||||||
bit = isHorizontal
|
bit = isHorizontal
|
||||||
? matrix[j + num, i]
|
? matrix[j + num, i]
|
||||||
: matrix[i, j + num];
|
: matrix[i, j + num];
|
||||||
if (bit)
|
if (bit)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 40;
|
return 40;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -7,30 +5,30 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Penalty4 : Penalty
|
internal class Penalty4 : Penalty
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculate penalty value for Fourth rule.
|
/// Calculate penalty value for Fourth rule.
|
||||||
/// Perform O(n) search for available x modules
|
/// Perform O(n) search for available x modules
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal override int PenaltyCalculate(BitMatrix matrix)
|
internal override int PenaltyCalculate(BitMatrix matrix)
|
||||||
{
|
{
|
||||||
int width = matrix.Width;
|
int width = matrix.Width;
|
||||||
int darkBitCount = 0;
|
int darkBitCount = 0;
|
||||||
|
|
||||||
for (int j = 0; j < width; j++)
|
for (int j = 0; j < width; j++)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < width; i++)
|
for (int i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
if (matrix[i, j])
|
if (matrix[i, j])
|
||||||
{
|
{
|
||||||
darkBitCount++;
|
darkBitCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrixCount = width * width;
|
int matrixCount = width * width;
|
||||||
|
|
||||||
double ratio = (double)darkBitCount / matrixCount;
|
double ratio = (double)darkBitCount / matrixCount;
|
||||||
|
|
||||||
return Math.Abs((int)((ratio * 100) - 50)) / 5 * 10;
|
return Math.Abs((int)((ratio * 100) - 50)) / 5 * 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -8,23 +5,23 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class PenaltyFactory
|
internal class PenaltyFactory
|
||||||
{
|
{
|
||||||
internal Penalty CreateByRule(PenaltyRules penaltyRule)
|
internal Penalty CreateByRule(PenaltyRules penaltyRule)
|
||||||
{
|
{
|
||||||
return penaltyRule switch
|
return penaltyRule switch
|
||||||
{
|
{
|
||||||
PenaltyRules.Rule01 => new Penalty1(),
|
PenaltyRules.Rule01 => new Penalty1(),
|
||||||
PenaltyRules.Rule02 => new Penalty2(),
|
PenaltyRules.Rule02 => new Penalty2(),
|
||||||
PenaltyRules.Rule03 => new Penalty3(),
|
PenaltyRules.Rule03 => new Penalty3(),
|
||||||
PenaltyRules.Rule04 => new Penalty4(),
|
PenaltyRules.Rule04 => new Penalty4(),
|
||||||
_ => throw new ArgumentException($"Unsupport penalty rule: {penaltyRule}", nameof(penaltyRule))
|
_ => throw new ArgumentException($"Unsupport penalty rule: {penaltyRule}", nameof(penaltyRule))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<Penalty> AllRules()
|
internal IEnumerable<Penalty> AllRules()
|
||||||
{
|
{
|
||||||
foreach (PenaltyRules penaltyRule in Enum.GetValues(typeof(PenaltyRules)))
|
foreach (PenaltyRules penaltyRule in Enum.GetValues(typeof(PenaltyRules)))
|
||||||
{
|
{
|
||||||
yield return CreateByRule(penaltyRule);
|
yield return CreateByRule(penaltyRule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@ namespace Gma.QrCodeNet.Encoding.Masking.Scoring;
|
|||||||
|
|
||||||
public enum PenaltyRules
|
public enum PenaltyRules
|
||||||
{
|
{
|
||||||
Rule01 = 1,
|
Rule01 = 1,
|
||||||
Rule02 = 2,
|
Rule02 = 2,
|
||||||
Rule03 = 3,
|
Rule03 = 3,
|
||||||
Rule04 = 4
|
Rule04 = 4
|
||||||
}
|
}
|
||||||
@@ -2,19 +2,19 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public struct MatrixPoint
|
public struct MatrixPoint
|
||||||
{
|
{
|
||||||
internal MatrixPoint(int x, int y)
|
internal MatrixPoint(int x, int y)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int X { get; private set; }
|
public int X { get; private set; }
|
||||||
public int Y { get; private set; }
|
public int Y { get; private set; }
|
||||||
|
|
||||||
public MatrixPoint Offset(MatrixPoint offset) => new(offset.X + X, offset.Y + Y);
|
public MatrixPoint Offset(MatrixPoint offset) => new(offset.X + X, offset.Y + Y);
|
||||||
|
|
||||||
internal MatrixPoint Offset(int offsetX, int offsetY) => Offset(new MatrixPoint(offsetX, offsetY));
|
internal MatrixPoint Offset(int offsetX, int offsetY) => Offset(new MatrixPoint(offsetX, offsetY));
|
||||||
|
|
||||||
public override string ToString() => $"Point({X};{Y})";
|
public override string ToString() => $"Point({X};{Y})";
|
||||||
}
|
}
|
||||||
@@ -1,32 +1,31 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding;
|
namespace Gma.QrCodeNet.Encoding;
|
||||||
|
|
||||||
internal struct MatrixRectangle : IEnumerable<MatrixPoint>
|
internal struct MatrixRectangle : IEnumerable<MatrixPoint>
|
||||||
{
|
{
|
||||||
internal MatrixRectangle(MatrixPoint location, MatrixSize size) :
|
internal MatrixRectangle(MatrixPoint location, MatrixSize size) :
|
||||||
this()
|
this()
|
||||||
{
|
{
|
||||||
Location = location;
|
Location = location;
|
||||||
Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MatrixPoint Location { get; private set; }
|
public MatrixPoint Location { get; private set; }
|
||||||
public MatrixSize Size { get; private set; }
|
public MatrixSize Size { get; private set; }
|
||||||
|
|
||||||
public IEnumerator<MatrixPoint> GetEnumerator()
|
public IEnumerator<MatrixPoint> GetEnumerator()
|
||||||
{
|
{
|
||||||
for (int j = Location.Y; j < Location.Y + Size.Height; j++)
|
for (int j = Location.Y; j < Location.Y + Size.Height; j++)
|
||||||
{
|
{
|
||||||
for (int i = Location.X; i < Location.X + Size.Width; i++)
|
for (int i = Location.X; i < Location.X + Size.Width; i++)
|
||||||
{
|
{
|
||||||
yield return new MatrixPoint(i, j);
|
yield return new MatrixPoint(i, j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
|
||||||
public override string ToString() => $"Rectangle({Location.X};{Location.Y}):({Size.Width} x {Size.Height})";
|
public override string ToString() => $"Rectangle({Location.X};{Location.Y}):({Size.Width} x {Size.Height})";
|
||||||
}
|
}
|
||||||
@@ -2,18 +2,18 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public struct MatrixSize
|
public struct MatrixSize
|
||||||
{
|
{
|
||||||
internal MatrixSize(int width, int height)
|
internal MatrixSize(int width, int height)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
Width = width;
|
Width = width;
|
||||||
Height = height;
|
Height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Width { get; private set; }
|
public int Width { get; private set; }
|
||||||
public int Height { get; private set; }
|
public int Height { get; private set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Size({Width};{Height})";
|
return $"Size({Width};{Height})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public enum MatrixStatus
|
public enum MatrixStatus
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
NoMask,
|
NoMask,
|
||||||
Data
|
Data
|
||||||
}
|
}
|
||||||
+7
-7
@@ -4,11 +4,11 @@ namespace Gma.QrCodeNet.Encoding.Positioning;
|
|||||||
|
|
||||||
internal static class PositioningPatternBuilder
|
internal static class PositioningPatternBuilder
|
||||||
{
|
{
|
||||||
internal static void EmbedBasicPatterns(int version, TriStateMatrix matrix)
|
internal static void EmbedBasicPatterns(int version, TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
new PositionDetectionPattern(version).ApplyTo(matrix);
|
new PositionDetectionPattern(version).ApplyTo(matrix);
|
||||||
new DarkDotAtLeftBottom(version).ApplyTo(matrix);
|
new DarkDotAtLeftBottom(version).ApplyTo(matrix);
|
||||||
new AlignmentPattern(version).ApplyTo(matrix);
|
new AlignmentPattern(version).ApplyTo(matrix);
|
||||||
new TimingPattern(version).ApplyTo(matrix);
|
new TimingPattern(version).ApplyTo(matrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+89
-93
@@ -1,105 +1,101 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
||||||
|
|
||||||
internal class AlignmentPattern : PatternStencilBase
|
internal class AlignmentPattern : PatternStencilBase
|
||||||
{
|
{
|
||||||
public AlignmentPattern(int version)
|
public AlignmentPattern(int version)
|
||||||
: base(version)
|
: base(version)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool[,] AlignmentPatternArray { get; } =
|
private static bool[,] AlignmentPatternArray { get; } =
|
||||||
new[,]
|
new[,]
|
||||||
{
|
{
|
||||||
{ X, X, X, X, X },
|
{ X, X, X, X, X },
|
||||||
{ X, O, O, O, X },
|
{ X, O, O, O, X },
|
||||||
{ X, O, X, O, X },
|
{ X, O, X, O, X },
|
||||||
{ X, O, O, O, X },
|
{ X, O, O, O, X },
|
||||||
{ X, X, X, X, X }
|
{ X, X, X, X, X }
|
||||||
};
|
};
|
||||||
|
|
||||||
public override bool[,] Stencil => AlignmentPatternArray;
|
public override bool[,] Stencil => AlignmentPatternArray;
|
||||||
|
|
||||||
// Table E.1 — Row/column coordinates of center module of Alignment Patterns
|
// Table E.1 — Row/column coordinates of center module of Alignment Patterns
|
||||||
private static byte[][] AlignmentPatternCoordinatesByVersion { get; } =
|
private static byte[][] AlignmentPatternCoordinatesByVersion { get; } =
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
Array.Empty<byte>(),
|
Array.Empty<byte>(),
|
||||||
Array.Empty<byte>(),
|
Array.Empty<byte>(),
|
||||||
new byte[] { 6, 18 },
|
new byte[] { 6, 18 },
|
||||||
new byte[] { 6, 22 },
|
new byte[] { 6, 22 },
|
||||||
new byte[] { 6, 26 },
|
new byte[] { 6, 26 },
|
||||||
new byte[] { 6, 30 },
|
new byte[] { 6, 30 },
|
||||||
new byte[] { 6, 34 },
|
new byte[] { 6, 34 },
|
||||||
new byte[] { 6, 22, 38 },
|
new byte[] { 6, 22, 38 },
|
||||||
new byte[] { 6, 24, 42 },
|
new byte[] { 6, 24, 42 },
|
||||||
new byte[] { 6, 26, 46 },
|
new byte[] { 6, 26, 46 },
|
||||||
new byte[] { 6, 28, 50 },
|
new byte[] { 6, 28, 50 },
|
||||||
new byte[] { 6, 30, 54 },
|
new byte[] { 6, 30, 54 },
|
||||||
new byte[] { 6, 32, 58 },
|
new byte[] { 6, 32, 58 },
|
||||||
new byte[] { 6, 34, 62 },
|
new byte[] { 6, 34, 62 },
|
||||||
new byte[] { 6, 26, 46, 66 },
|
new byte[] { 6, 26, 46, 66 },
|
||||||
new byte[] { 6, 26, 48, 70 },
|
new byte[] { 6, 26, 48, 70 },
|
||||||
new byte[] { 6, 26, 50, 74 },
|
new byte[] { 6, 26, 50, 74 },
|
||||||
new byte[] { 6, 30, 54, 78 },
|
new byte[] { 6, 30, 54, 78 },
|
||||||
new byte[] { 6, 30, 56, 82 },
|
new byte[] { 6, 30, 56, 82 },
|
||||||
new byte[] { 6, 30, 58, 86 },
|
new byte[] { 6, 30, 58, 86 },
|
||||||
new byte[] { 6, 34, 62, 90 },
|
new byte[] { 6, 34, 62, 90 },
|
||||||
new byte[] { 6, 28, 50, 72, 94 },
|
new byte[] { 6, 28, 50, 72, 94 },
|
||||||
new byte[] { 6, 26, 50, 74, 98 },
|
new byte[] { 6, 26, 50, 74, 98 },
|
||||||
new byte[] { 6, 30, 54, 78, 102 },
|
new byte[] { 6, 30, 54, 78, 102 },
|
||||||
new byte[] { 6, 28, 54, 80, 106 },
|
new byte[] { 6, 28, 54, 80, 106 },
|
||||||
new byte[] { 6, 32, 58, 84, 110 },
|
new byte[] { 6, 32, 58, 84, 110 },
|
||||||
new byte[] { 6, 30, 58, 86, 114 },
|
new byte[] { 6, 30, 58, 86, 114 },
|
||||||
new byte[] { 6, 34, 62, 90, 118 },
|
new byte[] { 6, 34, 62, 90, 118 },
|
||||||
new byte[] { 6, 26, 50, 74, 98, 122 },
|
new byte[] { 6, 26, 50, 74, 98, 122 },
|
||||||
new byte[] { 6, 30, 54, 78, 102, 126 },
|
new byte[] { 6, 30, 54, 78, 102, 126 },
|
||||||
new byte[] { 6, 26, 52, 78, 104, 130 },
|
new byte[] { 6, 26, 52, 78, 104, 130 },
|
||||||
new byte[] { 6, 30, 56, 82, 108, 134 },
|
new byte[] { 6, 30, 56, 82, 108, 134 },
|
||||||
new byte[] { 6, 34, 60, 86, 112, 138 },
|
new byte[] { 6, 34, 60, 86, 112, 138 },
|
||||||
new byte[] { 6, 30, 58, 86, 114, 142 },
|
new byte[] { 6, 30, 58, 86, 114, 142 },
|
||||||
new byte[] { 6, 34, 62, 90, 118, 146 },
|
new byte[] { 6, 34, 62, 90, 118, 146 },
|
||||||
new byte[] { 6, 30, 54, 78, 102, 126, 150 },
|
new byte[] { 6, 30, 54, 78, 102, 126, 150 },
|
||||||
new byte[] { 6, 24, 50, 76, 102, 128, 154 },
|
new byte[] { 6, 24, 50, 76, 102, 128, 154 },
|
||||||
new byte[] { 6, 28, 54, 80, 106, 132, 158 },
|
new byte[] { 6, 28, 54, 80, 106, 132, 158 },
|
||||||
new byte[] { 6, 32, 58, 84, 110, 136, 162 },
|
new byte[] { 6, 32, 58, 84, 110, 136, 162 },
|
||||||
new byte[] { 6, 26, 54, 82, 110, 138, 166 },
|
new byte[] { 6, 26, 54, 82, 110, 138, 166 },
|
||||||
new byte[] { 6, 30, 58, 86, 114, 142, 170 }
|
new byte[] { 6, 30, 58, 86, 114, 142, 170 }
|
||||||
};
|
};
|
||||||
|
|
||||||
public override void ApplyTo(TriStateMatrix matrix)
|
public override void ApplyTo(TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
foreach (MatrixPoint coordinatePair in GetNonColidingCoordinatePairs(matrix))
|
foreach (MatrixPoint coordinatePair in GetNonColidingCoordinatePairs(matrix))
|
||||||
{
|
{
|
||||||
CopyTo(matrix, coordinatePair, MatrixStatus.NoMask);
|
CopyTo(matrix, coordinatePair, MatrixStatus.NoMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<MatrixPoint> GetNonColidingCoordinatePairs(TriStateMatrix matrix)
|
public IEnumerable<MatrixPoint> GetNonColidingCoordinatePairs(TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
GetAllCoordinatePairs()
|
GetAllCoordinatePairs()
|
||||||
.Where(point => matrix.MStatus(point.Offset(2, 2)) == MatrixStatus.None);
|
.Where(point => matrix.MStatus(point.Offset(2, 2)) == MatrixStatus.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MatrixPoint> GetAllCoordinatePairs()
|
private IEnumerable<MatrixPoint> GetAllCoordinatePairs()
|
||||||
{
|
{
|
||||||
IEnumerable<byte> coordinates = GetPatternCoordinatesByVersion(Version);
|
IEnumerable<byte> coordinates = GetPatternCoordinatesByVersion(Version);
|
||||||
foreach (byte centerX in coordinates)
|
foreach (byte centerX in coordinates)
|
||||||
{
|
{
|
||||||
foreach (byte centerY in coordinates)
|
foreach (byte centerY in coordinates)
|
||||||
{
|
{
|
||||||
MatrixPoint location = new(centerX - 2, centerY - 2);
|
MatrixPoint location = new(centerX - 2, centerY - 2);
|
||||||
yield return location;
|
yield return location;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<byte> GetPatternCoordinatesByVersion(int version)
|
private static IEnumerable<byte> GetPatternCoordinatesByVersion(int version)
|
||||||
{
|
{
|
||||||
return AlignmentPatternCoordinatesByVersion[version];
|
return AlignmentPatternCoordinatesByVersion[version];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+8
-10
@@ -1,17 +1,15 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
||||||
|
|
||||||
internal class DarkDotAtLeftBottom : PatternStencilBase
|
internal class DarkDotAtLeftBottom : PatternStencilBase
|
||||||
{
|
{
|
||||||
public DarkDotAtLeftBottom(int version) : base(version)
|
public DarkDotAtLeftBottom(int version) : base(version)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool[,] Stencil => throw new NotImplementedException();
|
public override bool[,] Stencil => throw new NotImplementedException();
|
||||||
|
|
||||||
public override void ApplyTo(TriStateMatrix matrix)
|
public override void ApplyTo(TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
matrix[8, matrix.Width - 8, MatrixStatus.NoMask] = true;
|
matrix[8, matrix.Width - 8, MatrixStatus.NoMask] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-19
@@ -1,32 +1,30 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
||||||
|
|
||||||
internal abstract class PatternStencilBase : BitMatrix
|
internal abstract class PatternStencilBase : BitMatrix
|
||||||
{
|
{
|
||||||
protected const bool O = false;
|
protected const bool O = false;
|
||||||
protected const bool X = true;
|
protected const bool X = true;
|
||||||
|
|
||||||
internal PatternStencilBase(int version)
|
internal PatternStencilBase(int version)
|
||||||
{
|
{
|
||||||
Version = version;
|
Version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Version { get; private set; }
|
public int Version { get; private set; }
|
||||||
|
|
||||||
public abstract bool[,] Stencil { get; }
|
public abstract bool[,] Stencil { get; }
|
||||||
|
|
||||||
public override int Width => Stencil.GetLength(0);
|
public override int Width => Stencil.GetLength(0);
|
||||||
|
|
||||||
public override int Height => Stencil.GetLength(1);
|
public override int Height => Stencil.GetLength(1);
|
||||||
|
|
||||||
public override bool[,] InternalArray => throw new NotImplementedException();
|
public override bool[,] InternalArray => throw new NotImplementedException();
|
||||||
|
|
||||||
public override bool this[int i, int j]
|
public override bool this[int i, int j]
|
||||||
{
|
{
|
||||||
get => Stencil[i, j];
|
get => Stencil[i, j];
|
||||||
set => throw new NotSupportedException();
|
set => throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void ApplyTo(TriStateMatrix matrix);
|
public abstract void ApplyTo(TriStateMatrix matrix);
|
||||||
}
|
}
|
||||||
+29
-29
@@ -2,40 +2,40 @@ namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
|||||||
|
|
||||||
internal class PositionDetectionPattern : PatternStencilBase
|
internal class PositionDetectionPattern : PatternStencilBase
|
||||||
{
|
{
|
||||||
public PositionDetectionPattern(int version)
|
public PositionDetectionPattern(int version)
|
||||||
: base(version)
|
: base(version)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool[,] PositionDetection { get; } =
|
private static bool[,] PositionDetection { get; } =
|
||||||
new[,]
|
new[,]
|
||||||
{
|
{
|
||||||
{ O, O, O, O, O, O, O, O, O },
|
{ O, O, O, O, O, O, O, O, O },
|
||||||
{ O, X, X, X, X, X, X, X, O },
|
{ O, X, X, X, X, X, X, X, O },
|
||||||
{ O, X, O, O, O, O, O, X, O },
|
{ O, X, O, O, O, O, O, X, O },
|
||||||
{ O, X, O, X, X, X, O, X, O },
|
{ O, X, O, X, X, X, O, X, O },
|
||||||
{ O, X, O, X, X, X, O, X, O },
|
{ O, X, O, X, X, X, O, X, O },
|
||||||
{ O, X, O, X, X, X, O, X, O },
|
{ O, X, O, X, X, X, O, X, O },
|
||||||
{ O, X, O, O, O, O, O, X, O },
|
{ O, X, O, O, O, O, O, X, O },
|
||||||
{ O, X, X, X, X, X, X, X, O },
|
{ O, X, X, X, X, X, X, X, O },
|
||||||
{ O, O, O, O, O, O, O, O, O }
|
{ O, O, O, O, O, O, O, O, O }
|
||||||
};
|
};
|
||||||
|
|
||||||
public override bool[,] Stencil => PositionDetection;
|
public override bool[,] Stencil => PositionDetection;
|
||||||
|
|
||||||
public override void ApplyTo(TriStateMatrix matrix)
|
public override void ApplyTo(TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
MatrixSize size = GetSizeOfSquareWithSeparators();
|
MatrixSize size = GetSizeOfSquareWithSeparators();
|
||||||
|
|
||||||
MatrixPoint leftTopCorner = new(0, 0);
|
MatrixPoint leftTopCorner = new(0, 0);
|
||||||
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 1), size), leftTopCorner, MatrixStatus.NoMask);
|
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 1), size), leftTopCorner, MatrixStatus.NoMask);
|
||||||
|
|
||||||
MatrixPoint rightTopCorner = new(matrix.Width - Width + 1, 0);
|
MatrixPoint rightTopCorner = new(matrix.Width - Width + 1, 0);
|
||||||
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(0, 1), size), rightTopCorner, MatrixStatus.NoMask);
|
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(0, 1), size), rightTopCorner, MatrixStatus.NoMask);
|
||||||
|
|
||||||
MatrixPoint leftBottomCorner = new(0, matrix.Width - Width + 1);
|
MatrixPoint leftBottomCorner = new(0, matrix.Width - Width + 1);
|
||||||
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 0), size), leftBottomCorner, MatrixStatus.NoMask);
|
CopyTo(matrix, new MatrixRectangle(new MatrixPoint(1, 0), size), leftBottomCorner, MatrixStatus.NoMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatrixSize GetSizeOfSquareWithSeparators() => new(Width - 1, Height - 1);
|
private MatrixSize GetSizeOfSquareWithSeparators() => new(Width - 1, Height - 1);
|
||||||
}
|
}
|
||||||
+24
-26
@@ -1,35 +1,33 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
namespace Gma.QrCodeNet.Encoding.Positioning.Stencils;
|
||||||
|
|
||||||
internal class TimingPattern : PatternStencilBase
|
internal class TimingPattern : PatternStencilBase
|
||||||
{
|
{
|
||||||
public TimingPattern(int version)
|
public TimingPattern(int version)
|
||||||
: base(version)
|
: base(version)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool[,] Stencil => throw new NotImplementedException();
|
public override bool[,] Stencil => throw new NotImplementedException();
|
||||||
|
|
||||||
public override void ApplyTo(TriStateMatrix matrix)
|
public override void ApplyTo(TriStateMatrix matrix)
|
||||||
{
|
{
|
||||||
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
|
// -8 is for skipping position detection patterns (size 7), and two horizontal/vertical
|
||||||
// separation patterns (size 1). Thus, 8 = 7 + 1.
|
// separation patterns (size 1). Thus, 8 = 7 + 1.
|
||||||
for (int i = 8; i < matrix.Width - 8; ++i)
|
for (int i = 8; i < matrix.Width - 8; ++i)
|
||||||
{
|
{
|
||||||
bool value = (sbyte)((i + 1) % 2) == 1;
|
bool value = (sbyte)((i + 1) % 2) == 1;
|
||||||
|
|
||||||
// Horizontal line.
|
// Horizontal line.
|
||||||
if (matrix.MStatus(6, i) == MatrixStatus.None)
|
if (matrix.MStatus(6, i) == MatrixStatus.None)
|
||||||
{
|
{
|
||||||
matrix[6, i, MatrixStatus.NoMask] = value;
|
matrix[6, i, MatrixStatus.NoMask] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical line.
|
// Vertical line.
|
||||||
if (matrix.MStatus(i, 6) == MatrixStatus.None)
|
if (matrix.MStatus(i, 6) == MatrixStatus.None)
|
||||||
{
|
{
|
||||||
matrix[i, 6, MatrixStatus.NoMask] = value;
|
matrix[i, 6, MatrixStatus.NoMask] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,48 +5,48 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class QRCodeConstantVariable
|
public static class QRCodeConstantVariable
|
||||||
{
|
{
|
||||||
public const int MinVersion = 1;
|
public const int MinVersion = 1;
|
||||||
public const int MaxVersion = 40;
|
public const int MaxVersion = 40;
|
||||||
|
|
||||||
public const string DefaultEncoding = "iso-8859-1";
|
public const string DefaultEncoding = "iso-8859-1";
|
||||||
public const string UTF8Encoding = "utf-8";
|
public const string UTF8Encoding = "utf-8";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ISO/IEC 18004:2006(E) Page 45 Chapter Generating the error correction codewords
|
/// ISO/IEC 18004:2006(E) Page 45 Chapter Generating the error correction codewords
|
||||||
/// Primative Polynomial = Bin 100011101 = Dec 285
|
/// Primative Polynomial = Bin 100011101 = Dec 285
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int QRCodePrimitive = 285;
|
public const int QRCodePrimitive = 285;
|
||||||
|
|
||||||
internal const int TerminatorNPaddingBit = 0;
|
internal const int TerminatorNPaddingBit = 0;
|
||||||
|
|
||||||
internal const int TerminatorLength = 4;
|
internal const int TerminatorLength = 4;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 0xEC
|
/// 0xEC
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const int PadeCodewordsOdd = 0xec;
|
internal const int PadeCodewordsOdd = 0xec;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 0x11
|
/// 0x11
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const int PadeCodewordsEven = 0x11;
|
internal const int PadeCodewordsEven = 0x11;
|
||||||
|
|
||||||
internal const int PositionStencilWidth = 7;
|
internal const int PositionStencilWidth = 7;
|
||||||
|
|
||||||
internal static bool[] PadeOdd = new bool[]
|
internal static bool[] PadeOdd = new bool[]
|
||||||
{
|
{
|
||||||
true, true, true, false,
|
true, true, true, false,
|
||||||
true, true, false, false
|
true, true, false, false
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static bool[] PadeEven = new bool[]
|
internal static bool[] PadeEven = new bool[]
|
||||||
{
|
{
|
||||||
false, false, false, true,
|
false, false, false, true,
|
||||||
false, false, false, true
|
false, false, false, true
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// URL:http://en.wikipedia.org/wiki/Byte-order_mark
|
/// URL:http://en.wikipedia.org/wiki/Byte-order_mark
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] UTF8ByteOrderMark => new byte[] { 0xEF, 0xBB, 0xBF };
|
public static byte[] UTF8ByteOrderMark => new byte[] { 0xEF, 0xBB, 0xBF };
|
||||||
}
|
}
|
||||||
@@ -9,24 +9,24 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
internal static class QRCodeEncode
|
internal static class QRCodeEncode
|
||||||
{
|
{
|
||||||
internal static BitMatrix Encode(string content, ErrorCorrectionLevel errorLevel)
|
internal static BitMatrix Encode(string content, ErrorCorrectionLevel errorLevel)
|
||||||
{
|
{
|
||||||
EncodationStruct encodeStruct = DataEncode.Encode(content, errorLevel);
|
EncodationStruct encodeStruct = DataEncode.Encode(content, errorLevel);
|
||||||
|
|
||||||
return ProcessEncodationResult(encodeStruct, errorLevel);
|
return ProcessEncodationResult(encodeStruct, errorLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BitMatrix ProcessEncodationResult(EncodationStruct encodeStruct, ErrorCorrectionLevel errorLevel)
|
private static BitMatrix ProcessEncodationResult(EncodationStruct encodeStruct, ErrorCorrectionLevel errorLevel)
|
||||||
{
|
{
|
||||||
BitList codewords = ECGenerator.FillECCodewords(encodeStruct.DataCodewords, encodeStruct.VersionDetail);
|
BitList codewords = ECGenerator.FillECCodewords(encodeStruct.DataCodewords, encodeStruct.VersionDetail);
|
||||||
|
|
||||||
TriStateMatrix triMatrix = new(encodeStruct.VersionDetail.MatrixWidth);
|
TriStateMatrix triMatrix = new(encodeStruct.VersionDetail.MatrixWidth);
|
||||||
PositioningPatternBuilder.EmbedBasicPatterns(encodeStruct.VersionDetail.Version, triMatrix);
|
PositioningPatternBuilder.EmbedBasicPatterns(encodeStruct.VersionDetail.Version, triMatrix);
|
||||||
|
|
||||||
triMatrix.EmbedVersionInformation(encodeStruct.VersionDetail.Version);
|
triMatrix.EmbedVersionInformation(encodeStruct.VersionDetail.Version);
|
||||||
triMatrix.EmbedFormatInformation(errorLevel, new Pattern0());
|
triMatrix.EmbedFormatInformation(errorLevel, new Pattern0());
|
||||||
triMatrix.TryEmbedCodewords(codewords);
|
triMatrix.TryEmbedCodewords(codewords);
|
||||||
|
|
||||||
return triMatrix.GetLowestPenaltyMatrix(errorLevel);
|
return triMatrix.GetLowestPenaltyMatrix(errorLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,21 +8,21 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class QrCode
|
public class QrCode
|
||||||
{
|
{
|
||||||
internal QrCode(BitMatrix matrix)
|
internal QrCode(BitMatrix matrix)
|
||||||
{
|
{
|
||||||
Matrix = matrix;
|
Matrix = matrix;
|
||||||
IsContainMatrix = true;
|
IsContainMatrix = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsContainMatrix
|
public bool IsContainMatrix
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BitMatrix Matrix
|
public BitMatrix Matrix
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,38 +2,38 @@ namespace Gma.QrCodeNet.Encoding;
|
|||||||
|
|
||||||
public class QrEncoder
|
public class QrEncoder
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default QrEncoder will set ErrorCorrectionLevel as M
|
/// Default QrEncoder will set ErrorCorrectionLevel as M
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QrEncoder()
|
public QrEncoder()
|
||||||
: this(ErrorCorrectionLevel.M)
|
: this(ErrorCorrectionLevel.M)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// QrEncoder with parameter ErrorCorrectionLevel.
|
/// QrEncoder with parameter ErrorCorrectionLevel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public QrEncoder(ErrorCorrectionLevel errorCorrectionLevel)
|
public QrEncoder(ErrorCorrectionLevel errorCorrectionLevel)
|
||||||
{
|
{
|
||||||
ErrorCorrectionLevel = errorCorrectionLevel;
|
ErrorCorrectionLevel = errorCorrectionLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorCorrectionLevel ErrorCorrectionLevel { get; set; }
|
public ErrorCorrectionLevel ErrorCorrectionLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encode string content to QrCode matrix
|
/// Encode string content to QrCode matrix
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <exception cref="InputOutOfBoundaryException">
|
/// <exception cref="InputOutOfBoundaryException">
|
||||||
/// This exception for string content is null, empty or too large</exception>
|
/// This exception for string content is null, empty or too large</exception>
|
||||||
public QrCode Encode(string content)
|
public QrCode Encode(string content)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(content))
|
if (string.IsNullOrEmpty(content))
|
||||||
{
|
{
|
||||||
throw new InputOutOfBoundaryException("Input cannot be null or empty.");
|
throw new InputOutOfBoundaryException("Input cannot be null or empty.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new QrCode(QRCodeEncode.Encode(content, ErrorCorrectionLevel));
|
return new QrCode(QRCodeEncode.Encode(content, ErrorCorrectionLevel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
|
namespace Gma.QrCodeNet.Encoding.ReedSolomon;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -7,116 +5,116 @@ namespace Gma.QrCodeNet.Encoding.ReedSolomon;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class GaloisField256
|
internal sealed class GaloisField256
|
||||||
{
|
{
|
||||||
internal GaloisField256(int primitive)
|
internal GaloisField256(int primitive)
|
||||||
{
|
{
|
||||||
AntiLogTable = new int[256];
|
AntiLogTable = new int[256];
|
||||||
LogTable = new int[256];
|
LogTable = new int[256];
|
||||||
|
|
||||||
Primitive = primitive;
|
Primitive = primitive;
|
||||||
|
|
||||||
int gfx = 1;
|
int gfx = 1;
|
||||||
|
|
||||||
// Power cycle is from 0 to 254. 2^255 = 1 = 2^0
|
// Power cycle is from 0 to 254. 2^255 = 1 = 2^0
|
||||||
// Value cycle is from 1 to 255. Thus there should not have Log(0).
|
// Value cycle is from 1 to 255. Thus there should not have Log(0).
|
||||||
for (int powers = 0; powers < 256; powers++)
|
for (int powers = 0; powers < 256; powers++)
|
||||||
{
|
{
|
||||||
AntiLogTable[powers] = gfx;
|
AntiLogTable[powers] = gfx;
|
||||||
if (powers != 255)
|
if (powers != 255)
|
||||||
{
|
{
|
||||||
LogTable[gfx] = powers;
|
LogTable[gfx] = powers;
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx <<= 1; // gfx = gfx * 2 where alpha is 2.
|
gfx <<= 1; // gfx = gfx * 2 where alpha is 2.
|
||||||
|
|
||||||
if (gfx > 255)
|
if (gfx > 255)
|
||||||
{
|
{
|
||||||
gfx ^= primitive;
|
gfx ^= primitive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int[] AntiLogTable { get; }
|
private int[] AntiLogTable { get; }
|
||||||
private int[] LogTable { get; }
|
private int[] LogTable { get; }
|
||||||
|
|
||||||
internal int Primitive { get; }
|
internal int Primitive { get; }
|
||||||
|
|
||||||
internal static GaloisField256 QRCodeGaloisField => new(QRCodeConstantVariable.QRCodePrimitive);
|
internal static GaloisField256 QRCodeGaloisField => new(QRCodeConstantVariable.QRCodePrimitive);
|
||||||
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Powers of a in GF table. Where a = 2
|
/// Powers of a in GF table. Where a = 2
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal int Exponent(int powersOfa) => AntiLogTable[powersOfa];
|
internal int Exponent(int powersOfa) => AntiLogTable[powersOfa];
|
||||||
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Log (power of a) in GF table. Where a = 2
|
/// Log (power of a) in GF table. Where a = 2
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal int Log(int gfValue)
|
internal int Log(int gfValue)
|
||||||
{
|
{
|
||||||
if (gfValue == 0)
|
if (gfValue == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("GaloisField value will not be equal to 0, Log method.");
|
throw new ArgumentException("GaloisField value will not be equal to 0, Log method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return LogTable[gfValue];
|
return LogTable[gfValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int Inverse(int gfValue)
|
internal int Inverse(int gfValue)
|
||||||
{
|
{
|
||||||
if (gfValue == 0)
|
if (gfValue == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("GaloisField value will not be equal to 0, Inverse method.");
|
throw new ArgumentException("GaloisField value will not be equal to 0, Inverse method.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Exponent(255 - Log(gfValue));
|
return Exponent(255 - Log(gfValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int Addition(int gfValueA, int gfValueB) => gfValueA ^ gfValueB;
|
internal int Addition(int gfValueA, int gfValueB) => gfValueA ^ gfValueB;
|
||||||
|
|
||||||
internal int Subtraction(int gfValueA, int gfValueB) => Addition(gfValueA, gfValueB); // Subtraction is same as addition.
|
internal int Subtraction(int gfValueA, int gfValueB) => Addition(gfValueA, gfValueB); // Subtraction is same as addition.
|
||||||
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Product of two values.
|
/// Product of two values.
|
||||||
/// In other words. a multiply b
|
/// In other words. a multiply b
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal int Product(int gfValueA, int gfValueB)
|
internal int Product(int gfValueA, int gfValueB)
|
||||||
{
|
{
|
||||||
if (gfValueA == 0 || gfValueB == 0)
|
if (gfValueA == 0 || gfValueB == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (gfValueA == 1)
|
if (gfValueA == 1)
|
||||||
{
|
{
|
||||||
return gfValueB;
|
return gfValueB;
|
||||||
}
|
}
|
||||||
if (gfValueB == 1)
|
if (gfValueB == 1)
|
||||||
{
|
{
|
||||||
return gfValueA;
|
return gfValueA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Exponent((Log(gfValueA) + Log(gfValueB)) % 255);
|
return Exponent((Log(gfValueA) + Log(gfValueB)) % 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// Quotient of two values.
|
/// Quotient of two values.
|
||||||
/// In other words. a divided b
|
/// In other words. a divided b
|
||||||
/// </returns>
|
/// </returns>
|
||||||
internal int Quotient(int gfValueA, int gfValueB)
|
internal int Quotient(int gfValueA, int gfValueB)
|
||||||
{
|
{
|
||||||
if (gfValueA == 0)
|
if (gfValueA == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfValueB == 0)
|
if (gfValueB == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"{nameof(gfValueB)} cannot be zero.");
|
throw new ArgumentException($"{nameof(gfValueB)} cannot be zero.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gfValueB == 1)
|
if (gfValueB == 1)
|
||||||
{
|
{
|
||||||
return gfValueA;
|
return gfValueA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Exponent(Math.Abs(Log(gfValueA) - Log(gfValueB)) % 255);
|
return Exponent(Math.Abs(Log(gfValueA) - Log(gfValueB)) % 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user