将引用的源码变成安装包的形式引用

This commit is contained in:
akwkevin
2021-07-23 16:42:51 +08:00
parent 8cd13373a5
commit 0d369f90f4
242 changed files with 25 additions and 46376 deletions

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net472</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
<UseWPF>true</UseWPF>
</PropertyGroup>
@@ -121,20 +121,26 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dragablz" Version="0.0.3.223" />
<PackageReference Include="Fluent.Ribbon" Version="8.0.3" />
<PackageReference Include="gong-wpf-dragdrop" Version="2.3.2" />
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="MahApps.Metro" Version="2.0.0" />
<PackageReference Include="MahApps.Metro.IconPacks" Version="4.8.0" />
<PackageReference Include="MahApps.Metro.IconPacks.FontAwesome" Version="4.8.0" />
<PackageReference Include="MahApps.Metro.IconPacks.VaadinIcons" Version="4.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Util.Svg2XamlTestExtension" Version="1.2.5" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Dragablz\Dragablz\Dragablz.csproj" />
<ProjectReference Include="..\Fluent.Ribbon\Fluent.Ribbon\Fluent.Ribbon.csproj" />
<ProjectReference Include="..\gong-wpf-dragdrop\src\GongSolutions.WPF.DragDrop\GongSolutions.WPF.DragDrop.csproj" />
<ProjectReference Include="..\Util.DiagramDesigner\Util.DiagramDesigner.csproj" />
<ProjectReference Include="..\zxing.core\zxing.core\zxing.core.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="zxing.core">
<HintPath>zxing.core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

View File

@@ -1154,18 +1154,18 @@ namespace AIStudio.Wpf.ADiagram.ViewModels
List<Color> result = new List<Color>();
for (var i = 0; i < count; i++)
{
var colors = ColorGallery.GetGradient(ColorGallery.StandardThemeColors[i], 10);
for (var j = 9; j >= 0; j--)
{
result.Add(colors[j]);
}
//var colors = ColorGallery.GetGradient(ColorGallery.StandardThemeColors[i], 10);
//for (var j = 9; j >= 0; j--)
//{
// result.Add(colors[j]);
//}
}
{
var colors = ColorGallery.GetGradient(Colors.Black, 10);
for (var j = 9; j >= 0; j--)
{
result.Add(colors[j]);
}
//var colors = ColorGallery.GetGradient(Colors.Black, 10);
//for (var j = 9; j >= 0; j--)
//{
// result.Add(colors[j]);
//}
}
return result.ToArray();
}

Binary file not shown.

View File

@@ -5,34 +5,8 @@ VisualStudioVersion = 16.0.29509.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Util.DiagramDesigner", "Util.DiagramDesigner\Util.DiagramDesigner.csproj", "{3FC9F09D-83EA-4914-8980-A6B4C3352836}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluent.Ribbon", "Fluent.Ribbon\Fluent.Ribbon\Fluent.Ribbon.csproj", "{8828180F-6840-4019-B151-336FD4CF89B0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfAnimatedGif", "WpfAnimatedGif\WpfAnimatedGif.csproj", "{95DFC433-5097-4F8C-881C-FC0ED172F14E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AIStudio.Wpf.ADiagram", "AIStudio.Wpf.ADiagram\AIStudio.Wpf.ADiagram.csproj", "{9D2DCA7D-9E0C-4E6E-ACD9-2CD18C75FE34}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluent.Ribbon.Showcase", "Fluent.Ribbon\Fluent.Ribbon.Showcase\Fluent.Ribbon.Showcase.csproj", "{201885CE-BEEC-465E-B0CB-D416494DF611}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dragablz", "Dragablz\Dragablz\Dragablz.csproj", "{62608851-A3A1-467C-8FC2-4EA833BA94F7}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fluent", "Fluent", "{3DCF79F7-3E2E-4104-B294-93FD574C985B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dragablz", "Dragablz", "{3F017B57-F43A-46AC-9265-D0619CEDF935}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DragablzDemo", "Dragablz\DragablzDemo\DragablzDemo.csproj", "{CD59A633-9EFD-4B96-95DE-A3DD7E828BED}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zxing.core", "zxing.core", "{548B8B1E-71F1-439C-895D-9FA652FBEFFD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zxing.core", "zxing.core\zxing.core\zxing.core.csproj", "{112E5A66-F6AF-407B-B23E-EBD24C0084AB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WPFDemo", "zxing.core\WPFDemo\WPFDemo.csproj", "{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DragDrop", "DragDrop", "{734F752D-AADA-420D-966C-B2A1EDF220D4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GongSolutions.WPF.DragDrop", "gong-wpf-dragdrop\src\GongSolutions.WPF.DragDrop\GongSolutions.WPF.DragDrop.csproj", "{6B3EBB67-48DD-48DF-80F0-ED530D4724E2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Showcase.WPF.DragDrop", "gong-wpf-dragdrop\src\Showcase\Showcase.WPF.DragDrop.csproj", "{963E3D97-D75A-4096-81D3-1F28DB758254}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -43,60 +17,14 @@ Global
{3FC9F09D-83EA-4914-8980-A6B4C3352836}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3FC9F09D-83EA-4914-8980-A6B4C3352836}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3FC9F09D-83EA-4914-8980-A6B4C3352836}.Release|Any CPU.Build.0 = Release|Any CPU
{8828180F-6840-4019-B151-336FD4CF89B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8828180F-6840-4019-B151-336FD4CF89B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8828180F-6840-4019-B151-336FD4CF89B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8828180F-6840-4019-B151-336FD4CF89B0}.Release|Any CPU.Build.0 = Release|Any CPU
{95DFC433-5097-4F8C-881C-FC0ED172F14E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95DFC433-5097-4F8C-881C-FC0ED172F14E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95DFC433-5097-4F8C-881C-FC0ED172F14E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95DFC433-5097-4F8C-881C-FC0ED172F14E}.Release|Any CPU.Build.0 = Release|Any CPU
{9D2DCA7D-9E0C-4E6E-ACD9-2CD18C75FE34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D2DCA7D-9E0C-4E6E-ACD9-2CD18C75FE34}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D2DCA7D-9E0C-4E6E-ACD9-2CD18C75FE34}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D2DCA7D-9E0C-4E6E-ACD9-2CD18C75FE34}.Release|Any CPU.Build.0 = Release|Any CPU
{201885CE-BEEC-465E-B0CB-D416494DF611}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{201885CE-BEEC-465E-B0CB-D416494DF611}.Debug|Any CPU.Build.0 = Debug|Any CPU
{201885CE-BEEC-465E-B0CB-D416494DF611}.Release|Any CPU.ActiveCfg = Release|Any CPU
{201885CE-BEEC-465E-B0CB-D416494DF611}.Release|Any CPU.Build.0 = Release|Any CPU
{62608851-A3A1-467C-8FC2-4EA833BA94F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62608851-A3A1-467C-8FC2-4EA833BA94F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62608851-A3A1-467C-8FC2-4EA833BA94F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62608851-A3A1-467C-8FC2-4EA833BA94F7}.Release|Any CPU.Build.0 = Release|Any CPU
{CD59A633-9EFD-4B96-95DE-A3DD7E828BED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CD59A633-9EFD-4B96-95DE-A3DD7E828BED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CD59A633-9EFD-4B96-95DE-A3DD7E828BED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CD59A633-9EFD-4B96-95DE-A3DD7E828BED}.Release|Any CPU.Build.0 = Release|Any CPU
{112E5A66-F6AF-407B-B23E-EBD24C0084AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{112E5A66-F6AF-407B-B23E-EBD24C0084AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{112E5A66-F6AF-407B-B23E-EBD24C0084AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{112E5A66-F6AF-407B-B23E-EBD24C0084AB}.Release|Any CPU.Build.0 = Release|Any CPU
{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E}.Release|Any CPU.Build.0 = Release|Any CPU
{6B3EBB67-48DD-48DF-80F0-ED530D4724E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6B3EBB67-48DD-48DF-80F0-ED530D4724E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6B3EBB67-48DD-48DF-80F0-ED530D4724E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B3EBB67-48DD-48DF-80F0-ED530D4724E2}.Release|Any CPU.Build.0 = Release|Any CPU
{963E3D97-D75A-4096-81D3-1F28DB758254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{963E3D97-D75A-4096-81D3-1F28DB758254}.Debug|Any CPU.Build.0 = Debug|Any CPU
{963E3D97-D75A-4096-81D3-1F28DB758254}.Release|Any CPU.ActiveCfg = Release|Any CPU
{963E3D97-D75A-4096-81D3-1F28DB758254}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{8828180F-6840-4019-B151-336FD4CF89B0} = {3DCF79F7-3E2E-4104-B294-93FD574C985B}
{201885CE-BEEC-465E-B0CB-D416494DF611} = {3DCF79F7-3E2E-4104-B294-93FD574C985B}
{62608851-A3A1-467C-8FC2-4EA833BA94F7} = {3F017B57-F43A-46AC-9265-D0619CEDF935}
{CD59A633-9EFD-4B96-95DE-A3DD7E828BED} = {3F017B57-F43A-46AC-9265-D0619CEDF935}
{112E5A66-F6AF-407B-B23E-EBD24C0084AB} = {548B8B1E-71F1-439C-895D-9FA652FBEFFD}
{DA299EFC-BC08-4FD7-8FA0-818057D6EF8E} = {548B8B1E-71F1-439C-895D-9FA652FBEFFD}
{6B3EBB67-48DD-48DF-80F0-ED530D4724E2} = {734F752D-AADA-420D-966C-B2A1EDF220D4}
{963E3D97-D75A-4096-81D3-1F28DB758254} = {734F752D-AADA-420D-966C-B2A1EDF220D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D30FC641-F06C-4E35-AEA5-48A9B6E59CE0}
EndGlobalSection

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net462;net472</TargetFrameworks>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
<UseWPF>true</UseWPF>
</PropertyGroup>
@@ -14,10 +14,7 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfAnimatedGif\WpfAnimatedGif.csproj" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary>
/// Enumerates barcode formats known to this package.
/// </summary>
/// <author>Sean Owen</author>
[System.Flags]
public enum BarcodeFormat
{
/// <summary>Aztec 2D barcode format.</summary>
AZTEC = 1,
/// <summary>CODABAR 1D format.</summary>
CODABAR = 2,
/// <summary>Code 39 1D format.</summary>
CODE_39 = 4,
/// <summary>Code 93 1D format.</summary>
CODE_93 = 8,
/// <summary>Code 128 1D format.</summary>
CODE_128 = 16,
/// <summary>Data Matrix 2D barcode format.</summary>
DATA_MATRIX = 32,
/// <summary>EAN-8 1D format.</summary>
EAN_8 = 64,
/// <summary>EAN-13 1D format.</summary>
EAN_13 = 128,
/// <summary>ITF (Interleaved Two of Five) 1D format.</summary>
ITF = 256,
/// <summary>MaxiCode 2D barcode format.</summary>
MAXICODE = 512,
/// <summary>PDF417 format.</summary>
PDF_417 = 1024,
/// <summary>QR Code 2D barcode format.</summary>
QR_CODE = 2048,
/// <summary>RSS 14</summary>
RSS_14 = 4096,
/// <summary>RSS EXPANDED</summary>
RSS_EXPANDED = 8192,
/// <summary>UPC-A 1D format.</summary>
UPC_A = 16384,
/// <summary>UPC-E 1D format.</summary>
UPC_E = 32768,
/// <summary>UPC/EAN extension format. Not a stand-alone format.</summary>
UPC_EAN_EXTENSION = 65536,
/// <summary>MSI</summary>
MSI = 131072,
/// <summary>Plessey</summary>
PLESSEY = 262144,
/// <summary>Intelligent Mail barcode</summary>
IMB = 524288,
/// <summary>
/// UPC_A | UPC_E | EAN_13 | EAN_8 | CODABAR | CODE_39 | CODE_93 | CODE_128 | ITF | RSS_14 | RSS_EXPANDED
/// without MSI (to many false-positives) and IMB (not enough tested, and it looks more like a 2D)
/// </summary>
All_1D = UPC_A | UPC_E | EAN_13 | EAN_8 | CODABAR | CODE_39 | CODE_93 | CODE_128 | ITF | RSS_14 | RSS_EXPANDED
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Drawing;
namespace ZXing
{
/// <summary>
/// A smart class to decode the barcode inside a bitmap object
/// </summary>
public class BarcodeReader : BarcodeReader<Bitmap>, IBarcodeReader
{
private static readonly Func<Bitmap, LuminanceSource> defaultCreateLuminanceSource =
(bitmap) => new BitmapLuminanceSource(bitmap);
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
public BarcodeReader()
: this(null, defaultCreateLuminanceSource, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
public BarcodeReader(Reader reader,
Func<Bitmap, LuminanceSource> createLuminanceSource,
Func<LuminanceSource, Binarizer> createBinarizer
)
: base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
/// <param name="createRGBLuminanceSource">Sets the function to create a luminance source object for a rgb raw byte array.</param>
public BarcodeReader(Reader reader,
Func<Bitmap, LuminanceSource> createLuminanceSource,
Func<LuminanceSource, Binarizer> createBinarizer,
Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource
)
: base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer, createRGBLuminanceSource)
{
}
}
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// A smart class to decode the barcode inside a bitmap object
/// </summary>
public class BarcodeReader<T> : BarcodeReaderGeneric, IBarcodeReader<T>
{
private readonly Func<T, LuminanceSource> createLuminanceSource;
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
public BarcodeReader(Func<T, LuminanceSource> createLuminanceSource)
: this(null, createLuminanceSource, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
public BarcodeReader(Reader reader,
Func<T, LuminanceSource> createLuminanceSource,
Func<LuminanceSource, Binarizer> createBinarizer
)
: this(reader, createLuminanceSource, createBinarizer, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReader"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
/// <param name="createRGBLuminanceSource">Sets the function to create a luminance source object for a rgb raw byte array.</param>
public BarcodeReader(Reader reader,
Func<T, LuminanceSource> createLuminanceSource,
Func<LuminanceSource, Binarizer> createBinarizer,
Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource
)
: base(reader, createBinarizer, createRGBLuminanceSource)
{
this.createLuminanceSource = createLuminanceSource;
}
/// <summary>
/// Constructor for additional image formats for one BarcodeReader class
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
/// <param name="createRGBLuminanceSource">Sets the function to create a luminance source object for a rgb raw byte array.</param>
protected BarcodeReader(Reader reader,
Func<LuminanceSource, Binarizer> createBinarizer,
Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource
)
: base(reader, createBinarizer, createRGBLuminanceSource)
{
}
/// <summary>
/// Optional: Gets or sets the function to create a luminance source object for a bitmap.
/// If null a platform specific default LuminanceSource is used
/// </summary>
/// <value>
/// The function to create a luminance source object.
/// </value>
protected Func<T, LuminanceSource> CreateLuminanceSource
{
get
{
return createLuminanceSource;
}
}
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
public Result Decode(T barcodeBitmap)
{
if (CreateLuminanceSource == null)
{
throw new InvalidOperationException("You have to declare a luminance source delegate.");
}
if (barcodeBitmap == null)
throw new ArgumentNullException("barcodeBitmap");
var luminanceSource = CreateLuminanceSource(barcodeBitmap);
return Decode(luminanceSource);
}
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
public Result[] DecodeMultiple(T barcodeBitmap)
{
if (CreateLuminanceSource == null)
{
throw new InvalidOperationException("You have to declare a luminance source delegate.");
}
if (barcodeBitmap == null)
throw new ArgumentNullException("barcodeBitmap");
var luminanceSource = CreateLuminanceSource(barcodeBitmap);
return DecodeMultiple(luminanceSource);
}
}
}

View File

@@ -1,604 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Multi;
using ZXing.Multi.QrCode;
namespace ZXing
{
/// <summary>
/// A smart class to decode the barcode inside a bitmap object
/// </summary>
public class BarcodeReaderGeneric<T> : IBarcodeReaderGeneric<T>, IMultipleBarcodeReaderGeneric<T>
{
private static readonly Func<LuminanceSource, Binarizer> defaultCreateBinarizer =
(luminanceSource) => new HybridBinarizer(luminanceSource);
protected static readonly Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> defaultCreateRGBLuminanceSource =
(rawBytes, width, height, format) => new RGBLuminanceSource(rawBytes, width, height, format);
private Reader reader;
private readonly Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource;
#if !UNITY
private readonly Func<T, LuminanceSource> createLuminanceSource;
#else
private readonly Func<T, int, int, LuminanceSource> createLuminanceSource;
#endif
private readonly Func<LuminanceSource, Binarizer> createBinarizer;
private bool usePreviousState;
private DecodingOptions options;
/// <summary>
/// Gets or sets the options.
/// </summary>
/// <value>
/// The options.
/// </value>
public DecodingOptions Options
{
get { return options ?? (options = new DecodingOptions()); }
set { options = value; }
}
/// <summary>
/// Gets the reader which should be used to find and decode the barcode.
/// </summary>
/// <value>
/// The reader.
/// </value>
protected Reader Reader
{
get
{
return reader ?? (reader = new MultiFormatReader());
}
}
/// <summary>
/// Gets or sets a method which is called if an important point is found
/// </summary>
/// <value>
/// The result point callback.
/// </value>
public event Action<ResultPoint> ResultPointFound
{
add
{
if (!Options.Hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK))
{
var callback = new ResultPointCallback(OnResultPointFound);
Options.Hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK] = callback;
}
explicitResultPointFound += value;
usePreviousState = false;
}
remove
{
explicitResultPointFound -= value;
if (explicitResultPointFound == null)
Options.Hints.Remove(DecodeHintType.NEED_RESULT_POINT_CALLBACK);
usePreviousState = false;
}
}
private event Action<ResultPoint> explicitResultPointFound;
/// <summary>
/// event is executed if a result was found via decode
/// </summary>
public event Action<Result> ResultFound;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.TryHarder property instead.")]
public bool TryHarder
{
get { return Options.TryHarder; }
set { Options.TryHarder = value; }
}
/// <summary>
/// Image is a pure monochrome image of a barcode.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.PureBarcode property instead.")]
public bool PureBarcode
{
get { return Options.PureBarcode; }
set { Options.PureBarcode = value; }
}
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
[Obsolete("Please use the Options.CharacterSet property instead.")]
public string CharacterSet
{
get { return Options.CharacterSet; }
set { Options.CharacterSet = value; }
}
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
[Obsolete("Please use the Options.PossibleFormats property instead.")]
public IList<BarcodeFormat> PossibleFormats
{
get { return Options.PossibleFormats; }
set { Options.PossibleFormats = value; }
}
/// <summary>
/// Gets or sets a value indicating whether the image should be automatically rotated.
/// Rotation is supported for 90, 180 and 270 degrees
/// </summary>
/// <value>
/// <c>true</c> if image should be rotated; otherwise, <c>false</c>.
/// </value>
public bool AutoRotate { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the image should be automatically inverted
/// if no result is found in the original image.
/// ATTENTION: Please be carefully because it slows down the decoding process if it is used
/// </summary>
/// <value>
/// <c>true</c> if image should be inverted; otherwise, <c>false</c>.
/// </value>
public bool TryInverted { get; set; }
#if !UNITY
/// <summary>
/// Optional: Gets or sets the function to create a luminance source object for a bitmap.
/// If null a platform specific default LuminanceSource is used
/// </summary>
/// <value>
/// The function to create a luminance source object.
/// </value>
protected Func<T, LuminanceSource> CreateLuminanceSource
#else
/// <summary>
/// Optional: Gets or sets the function to create a luminance source object for a bitmap.
/// If null a platform specific default LuminanceSource is used
/// </summary>
/// <value>
/// The function to create a luminance source object.
/// </value>
protected Func<T, int, int, LuminanceSource> CreateLuminanceSource
#endif
{
get
{
return createLuminanceSource;
}
}
/// <summary>
/// Optional: Gets or sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used
/// </summary>
/// <value>
/// The function to create a binarizer object.
/// </value>
protected Func<LuminanceSource, Binarizer> CreateBinarizer
{
get
{
return createBinarizer ?? defaultCreateBinarizer;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReaderGeneric{T}"/> class.
/// </summary>
public BarcodeReaderGeneric()
: this(new MultiFormatReader(), null, defaultCreateBinarizer)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReaderGeneric{T}"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
public BarcodeReaderGeneric(Reader reader,
#if !UNITY
Func<T, LuminanceSource> createLuminanceSource,
#else
Func<T, int, int, LuminanceSource> createLuminanceSource,
#endif
Func<LuminanceSource, Binarizer> createBinarizer
)
: this(reader, createLuminanceSource, createBinarizer, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BarcodeReaderGeneric{T}"/> class.
/// </summary>
/// <param name="reader">Sets the reader which should be used to find and decode the barcode.
/// If null then MultiFormatReader is used</param>
/// <param name="createLuminanceSource">Sets the function to create a luminance source object for a bitmap.
/// If null, an exception is thrown when Decode is called</param>
/// <param name="createBinarizer">Sets the function to create a binarizer object for a luminance source.
/// If null then HybridBinarizer is used</param>
/// <param name="createRGBLuminanceSource">Sets the function to create a luminance source object for a rgb array.
/// If null the RGBLuminanceSource is used. The handler is only called when Decode with a byte[] array is called.</param>
public BarcodeReaderGeneric(Reader reader,
#if !UNITY
Func<T, LuminanceSource> createLuminanceSource,
#else
Func<T, int, int, LuminanceSource> createLuminanceSource,
#endif
Func<LuminanceSource, Binarizer> createBinarizer,
Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource
)
{
this.reader = reader ?? new MultiFormatReader();
this.createLuminanceSource = createLuminanceSource;
this.createBinarizer = createBinarizer ?? defaultCreateBinarizer;
this.createRGBLuminanceSource = createRGBLuminanceSource ?? defaultCreateRGBLuminanceSource;
Options.ValueChanged += (o, args) => usePreviousState = false;
usePreviousState = false;
}
#if !PORTABLE
#if !UNITY
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
public Result Decode(T barcodeBitmap)
#else
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">raw bytes of the image in RGB order</param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns>
/// the result data or null
/// </returns>
public Result Decode(T rawRGB, int width, int height)
#endif
{
if (CreateLuminanceSource == null)
{
throw new InvalidOperationException("You have to declare a luminance source delegate.");
}
#if !UNITY
if (barcodeBitmap == null)
throw new ArgumentNullException("barcodeBitmap");
#else
if (rawRGB == null)
throw new ArgumentNullException("rawRGB");
#endif
#if !UNITY
var luminanceSource = CreateLuminanceSource(barcodeBitmap);
#else
var luminanceSource = CreateLuminanceSource(rawRGB, width, height);
#endif
return Decode(luminanceSource);
}
#endif
/// <summary>
/// Tries to decode a barcode within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
virtual public Result Decode(LuminanceSource luminanceSource)
{
var result = default(Result);
var binarizer = CreateBinarizer(luminanceSource);
var binaryBitmap = new BinaryBitmap(binarizer);
var multiformatReader = Reader as MultiFormatReader;
var rotationCount = 0;
var rotationMaxCount = 1;
if (AutoRotate)
{
Options.Hints[DecodeHintType.TRY_HARDER_WITHOUT_ROTATION] = true;
rotationMaxCount = 4;
}
else
{
if (Options.Hints.ContainsKey(DecodeHintType.TRY_HARDER_WITHOUT_ROTATION))
Options.Hints.Remove(DecodeHintType.TRY_HARDER_WITHOUT_ROTATION);
}
for (; rotationCount < rotationMaxCount; rotationCount++)
{
if (usePreviousState && multiformatReader != null)
{
result = multiformatReader.decodeWithState(binaryBitmap);
}
else
{
result = Reader.decode(binaryBitmap, Options.Hints);
usePreviousState = true;
}
if (result == null)
{
if (TryInverted && luminanceSource.InversionSupported)
{
binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.invert()));
if (usePreviousState && multiformatReader != null)
{
result = multiformatReader.decodeWithState(binaryBitmap);
}
else
{
result = Reader.decode(binaryBitmap, Options.Hints);
usePreviousState = true;
}
}
}
if (result != null ||
!luminanceSource.RotateSupported ||
!AutoRotate)
break;
binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.rotateCounterClockwise()));
}
if (result != null)
{
if (result.ResultMetadata == null)
{
result.putMetadata(ResultMetadataType.ORIENTATION, rotationCount * 90);
}
else if (!result.ResultMetadata.ContainsKey(ResultMetadataType.ORIENTATION))
{
result.ResultMetadata[ResultMetadataType.ORIENTATION] = rotationCount * 90;
}
else
{
// perhaps the core decoder rotates the image already (can happen if TryHarder is specified)
result.ResultMetadata[ResultMetadataType.ORIENTATION] = ((int)(result.ResultMetadata[ResultMetadataType.ORIENTATION]) + rotationCount * 90) % 360;
}
OnResultFound(result);
}
return result;
}
#if !PORTABLE
#if !UNITY
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
public Result[] DecodeMultiple(T barcodeBitmap)
#else
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">raw bytes of the image in RGB order</param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns>
/// the result data or null
/// </returns>
public Result[] DecodeMultiple(T rawRGB, int width, int height)
#endif
{
if (CreateLuminanceSource == null)
{
throw new InvalidOperationException("You have to declare a luminance source delegate.");
}
#if !UNITY
if (barcodeBitmap == null)
throw new ArgumentNullException("barcodeBitmap");
#else
if (rawRGB == null)
throw new ArgumentNullException("rawRGB");
#endif
#if !UNITY
var luminanceSource = CreateLuminanceSource(barcodeBitmap);
#else
var luminanceSource = CreateLuminanceSource(rawRGB, width, height);
#endif
return DecodeMultiple(luminanceSource);
}
#endif
/// <summary>
/// Tries to decode barcodes within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
virtual public Result[] DecodeMultiple(LuminanceSource luminanceSource)
{
var results = default(Result[]);
var binarizer = CreateBinarizer(luminanceSource);
var binaryBitmap = new BinaryBitmap(binarizer);
var rotationCount = 0;
var rotationMaxCount = 1;
MultipleBarcodeReader multiReader = null;
if (AutoRotate)
{
Options.Hints[DecodeHintType.TRY_HARDER_WITHOUT_ROTATION] = true;
rotationMaxCount = 4;
}
var formats = Options.PossibleFormats;
if (formats != null &&
formats.Count == 1 &&
formats.Contains(BarcodeFormat.QR_CODE))
{
multiReader = new QRCodeMultiReader();
}
else
{
multiReader = new GenericMultipleBarcodeReader(Reader);
}
for (; rotationCount < rotationMaxCount; rotationCount++)
{
results = multiReader.decodeMultiple(binaryBitmap, Options.Hints);
if (results == null)
{
if (TryInverted && luminanceSource.InversionSupported)
{
binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.invert()));
results = multiReader.decodeMultiple(binaryBitmap, Options.Hints);
}
}
if (results != null ||
!luminanceSource.RotateSupported ||
!AutoRotate)
break;
binaryBitmap = new BinaryBitmap(CreateBinarizer(luminanceSource.rotateCounterClockwise()));
}
if (results != null)
{
foreach (var result in results)
{
if (result.ResultMetadata == null)
{
result.putMetadata(ResultMetadataType.ORIENTATION, rotationCount * 90);
}
else if (!result.ResultMetadata.ContainsKey(ResultMetadataType.ORIENTATION))
{
result.ResultMetadata[ResultMetadataType.ORIENTATION] = rotationCount * 90;
}
else
{
// perhaps the core decoder rotates the image already (can happen if TryHarder is specified)
result.ResultMetadata[ResultMetadataType.ORIENTATION] =
((int)(result.ResultMetadata[ResultMetadataType.ORIENTATION]) + rotationCount * 90) % 360;
}
}
OnResultsFound(results);
}
return results;
}
protected void OnResultsFound(IEnumerable<Result> results)
{
if (ResultFound != null)
{
foreach (var result in results)
{
ResultFound(result);
}
}
}
protected void OnResultFound(Result result)
{
if (ResultFound != null)
{
ResultFound(result);
}
}
protected void OnResultPointFound(ResultPoint resultPoint)
{
if (explicitResultPointFound != null)
{
explicitResultPointFound(resultPoint);
}
}
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">The image as byte[] array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
public Result Decode(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format)
{
if (rawRGB == null)
throw new ArgumentNullException("rawRGB");
var luminanceSource = createRGBLuminanceSource(rawRGB, width, height, format);
return Decode(luminanceSource);
}
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">The image as byte[] array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
public Result[] DecodeMultiple(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format)
{
if (rawRGB == null)
throw new ArgumentNullException("rawRGB");
var luminanceSource = createRGBLuminanceSource(rawRGB, width, height, format);
return DecodeMultiple(luminanceSource);
}
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
using ZXing.Rendering;
namespace ZXing
{
/// <summary>
/// A base class for specific barcode writers with specific formats of barcode images.
/// </summary>
/// <typeparam name="TOutput">The type of the output.</typeparam>
public class BarcodeWriterGeneric<TOutput> : IBarcodeWriterGeneric<TOutput>
{
private EncodingOptions options;
/// <summary>
/// Gets or sets the barcode format.
/// The value is only suitable if the MultiFormatWriter is used.
/// </summary>
public BarcodeFormat Format { get; set; }
/// <summary>
/// Gets or sets the options container for the encoding and renderer process.
/// </summary>
public EncodingOptions Options
{
get
{
return (options ?? (options = new EncodingOptions { Height = 100, Width = 100 }));
}
set
{
options = value;
}
}
/// <summary>
/// Gets or sets the writer which encodes the content to a BitMatrix.
/// If no value is set the MultiFormatWriter is used.
/// </summary>
public Writer Encoder { get; set; }
/// <summary>
/// Gets or sets the renderer which should be used to render the encoded BitMatrix.
/// </summary>
public IBarcodeRenderer<TOutput> Renderer { get; set; }
/// <summary>
/// Encodes the specified contents and returns a BitMatrix array.
/// That array has to be rendered manually or with a IBarcodeRenderer.
/// </summary>
/// <param name="contents">The contents.</param>
/// <returns></returns>
public BitMatrix Encode(string contents)
{
var encoder = Encoder ?? new MultiFormatWriter();
var currentOptions = Options;
return encoder.encode(contents, Format, currentOptions.Width, currentOptions.Height, currentOptions.Hints);
}
/// <summary>
/// Encodes the specified contents and returns a rendered instance of the barcode.
/// For rendering the instance of the property Renderer is used and has to be set before
/// calling that method.
/// </summary>
/// <param name="contents">The contents.</param>
/// <returns></returns>
public TOutput Write(string contents)
{
if (Renderer == null)
{
throw new InvalidOperationException("You have to set a renderer instance.");
}
var matrix = Encode(contents);
return Renderer.Render(matrix, Format, contents, Options);
}
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// For rendering the instance of the property Renderer is used and has to be set before
/// calling that method.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
public TOutput Write(BitMatrix matrix)
{
if (Renderer == null)
{
throw new InvalidOperationException("You have to set a renderer instance.");
}
return Renderer.Render(matrix, Format, null, Options);
}
}
}

View File

@@ -1,213 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// The base class for luminance sources which supports
/// cropping and rotating based upon the luminance values.
/// </summary>
public abstract class BaseLuminanceSource : LuminanceSource
{
// the following channel weights give nearly the same
// gray scale picture as the java version with BufferedImage.TYPE_BYTE_GRAY
// they are used in sub classes for luminance / gray scale calculation
protected const int RChannelWeight = 19562;
protected const int GChannelWeight = 38550;
protected const int BChannelWeight = 7424;
protected const int ChannelWeight = 16;
/// <summary>
///
/// </summary>
protected byte[] luminances;
/// <summary>
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected BaseLuminanceSource(int width, int height)
: base(width, height)
{
luminances = new byte[width * height];
}
/// <summary>
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
/// </summary>
/// <param name="luminanceArray">The luminance array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected BaseLuminanceSource(byte[] luminanceArray, int width, int height)
: base(width, height)
{
luminances = new byte[width * height];
Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height);
}
/// <summary>
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
/// 0 (black) to 255 (white). It is preferable for implementations of this method
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
/// getMatrix() may never be called.
/// </summary>
/// <param name="y">The row to fetch, 0 &lt;= y &lt; Height.</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// Always use the returned object, and ignore the .length of the array.</param>
/// <returns>
/// An array containing the luminance data.
/// </returns>
override public byte[] getRow(int y, byte[] row)
{
int width = Width;
if (row == null || row.Length < width)
{
row = new byte[width];
}
for (int i = 0; i < width; i++)
row[i] = luminances[y * width + i];
return row;
}
public override byte[] Matrix
{
get { return luminances; }
}
/// <summary>
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
/// Only callable if {@link #isRotateSupported()} is true.
/// </summary>
/// <returns>
/// A rotated version of this object.
/// </returns>
public override LuminanceSource rotateCounterClockwise()
{
var rotatedLuminances = new byte[Width * Height];
var newWidth = Height;
var newHeight = Width;
var localLuminances = Matrix;
for (var yold = 0; yold < Height; yold++)
{
for (var xold = 0; xold < Width; xold++)
{
var ynew = newHeight - xold - 1;
var xnew = yold;
rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold];
}
}
return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight);
}
/// <summary>
/// TODO: not implemented yet
/// </summary>
/// <returns>
/// A rotated version of this object.
/// </returns>
public override LuminanceSource rotateCounterClockwise45()
{
// TODO: implement a good 45 degrees rotation without lost of information
return base.rotateCounterClockwise45();
}
/// <summary>
/// </summary>
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
public override bool RotateSupported
{
get
{
return true;
}
}
/// <summary>
/// Returns a new object with cropped image data. Implementations may keep a reference to the
/// original data rather than a copy. Only callable if CropSupported is true.
/// </summary>
/// <param name="left">The left coordinate, 0 &lt;= left &lt; Width.</param>
/// <param name="top">The top coordinate, 0 &lt;= top &lt;= Height.</param>
/// <param name="width">The width of the rectangle to crop.</param>
/// <param name="height">The height of the rectangle to crop.</param>
/// <returns>
/// A cropped version of this object.
/// </returns>
public override LuminanceSource crop(int left, int top, int width, int height)
{
if (left + width > Width || top + height > Height)
{
throw new ArgumentException("Crop rectangle does not fit within image data.");
}
var croppedLuminances = new byte[width * height];
var oldLuminances = Matrix;
var oldWidth = Width;
var oldRightBound = left + width;
var oldBottomBound = top + height;
for (int yold = top, ynew = 0; yold < oldBottomBound; yold++, ynew++)
{
for (int xold = left, xnew = 0; xold < oldRightBound; xold++, xnew++)
{
croppedLuminances[ynew * width + xnew] = oldLuminances[yold * oldWidth + xold];
}
}
return CreateLuminanceSource(croppedLuminances, width, height);
}
/// <summary>
/// </summary>
/// <returns> Whether this subclass supports cropping.</returns>
public override bool CropSupported
{
get
{
return true;
}
}
/// <summary>
/// </summary>
/// <returns>Whether this subclass supports invertion.</returns>
public override bool InversionSupported
{
get
{
return true;
}
}
/// <summary>
/// Inverts the luminance values (newValue = 255 - oldValue)
/// </summary>
public override LuminanceSource invert()
{
return new InvertedLuminanceSource(this);
}
/// <summary>
/// Should create a new luminance source with the right class type.
/// The method is used in methods crop and rotate.
/// </summary>
/// <param name="newLuminances">The new luminances.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns></returns>
protected abstract LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height);
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing
{
/// <summary> This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
/// It allows the algorithm to vary polymorphically, for example allowing a very expensive
/// thresholding technique for servers and a fast one for mobile. It also permits the implementation
/// to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
///
/// <author>dswitkin@google.com (Daniel Switkin)</author>
/// </summary>
public abstract class Binarizer
{
private readonly LuminanceSource source;
/// <summary>
/// Initializes a new instance of the <see cref="Binarizer"/> class.
/// </summary>
/// <param name="source">The source.</param>
protected internal Binarizer(LuminanceSource source)
{
if (source == null)
{
throw new ArgumentException("Source must be non-null.");
}
this.source = source;
}
/// <summary>
/// Gets the luminance source object.
/// </summary>
virtual public LuminanceSource LuminanceSource
{
get
{
return source;
}
}
/// <summary> Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
/// cached data. Callers should assume this method is expensive and call it as seldom as possible.
/// This method is intended for decoding 1D barcodes and may choose to apply sharpening.
/// For callers which only examine one row of pixels at a time, the same BitArray should be reused
/// and passed in with each call for performance. However it is legal to keep more than one row
/// at a time if needed.
/// </summary>
/// <param name="y">The row to fetch, which must be in [0, bitmap height)</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// If used, the Binarizer will call BitArray.clear(). Always use the returned object.
/// </param>
/// <returns> The array of bits for this row (true means black).</returns>
public abstract BitArray getBlackRow(int y, BitArray row);
/// <summary> Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
/// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
/// may not apply sharpening. Therefore, a row from this matrix may not be identical to one
/// fetched using getBlackRow(), so don't mix and match between them.
/// </summary>
/// <returns> The 2D array of bits for the image (true means black).</returns>
public abstract BitMatrix BlackMatrix { get; }
/// <summary> Creates a new object with the same type as this Binarizer implementation, but with pristine
/// state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
/// of 1 bit data. See Effective Java for why we can't use Java's clone() method.
/// </summary>
/// <param name="source">The LuminanceSource this Binarizer will operate on.</param>
/// <returns> A new concrete Binarizer implementation object.</returns>
public abstract Binarizer createBinarizer(LuminanceSource source);
/// <summary>
/// Gets the width of the luminance source object.
/// </summary>
public int Width
{
get { return source.Width; }
}
/// <summary>
/// Gets the height of the luminance source object.
/// </summary>
public int Height
{
get { return source.Height; }
}
}
}

View File

@@ -1,180 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing
{
/// <summary>
/// This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
/// accept a BinaryBitmap and attempt to decode it.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed class BinaryBitmap
{
private readonly Binarizer binarizer;
private BitMatrix matrix;
public BinaryBitmap(Binarizer binarizer)
{
if (binarizer == null)
{
throw new ArgumentException("Binarizer must be non-null.");
}
this.binarizer = binarizer;
}
internal BinaryBitmap(BitMatrix matrix)
{
if (matrix == null)
{
throw new ArgumentException("matrix must be non-null.");
}
this.matrix = matrix;
}
/// <returns>
/// The width of the bitmap.
/// </returns>
public int Width
{
get
{
return binarizer.Width;
}
}
/// <returns>
/// The height of the bitmap.
/// </returns>
public int Height
{
get
{
return binarizer.Height;
}
}
/// <summary>
/// Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
/// cached data. Callers should assume this method is expensive and call it as seldom as possible.
/// This method is intended for decoding 1D barcodes and may choose to apply sharpening.
/// </summary>
/// <param name="y">The row to fetch, which must be in [0, bitmap height).</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// If used, the Binarizer will call BitArray.clear(). Always use the returned object.
/// </param>
/// <returns> The array of bits for this row (true means black).</returns>
public BitArray getBlackRow(int y, BitArray row)
{
return binarizer.getBlackRow(y, row);
}
/// <summary>
/// Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
/// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
/// may not apply sharpening. Therefore, a row from this matrix may not be identical to one
/// fetched using getBlackRow(), so don't mix and match between them.
/// </summary>
/// <returns> The 2D array of bits for the image (true means black).</returns>
public BitMatrix BlackMatrix
{
get
{
// The matrix is created on demand the first time it is requested, then cached. There are two
// reasons for this:
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
// 1D Reader finds a barcode before the 2D Readers run.
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
return matrix ?? (matrix = binarizer.BlackMatrix);
}
}
/// <returns>
/// Whether this bitmap can be cropped.
/// </returns>
public bool CropSupported
{
get
{
return binarizer.LuminanceSource.CropSupported;
}
}
/// <summary>
/// Returns a new object with cropped image data. Implementations may keep a reference to the
/// original data rather than a copy. Only callable if isCropSupported() is true.
/// </summary>
/// <param name="left">The left coordinate, which must be in [0, Width)</param>
/// <param name="top">The top coordinate, which must be in [0, Height)</param>
/// <param name="width">The width of the rectangle to crop.</param>
/// <param name="height">The height of the rectangle to crop.</param>
/// <returns> A cropped version of this object.</returns>
public BinaryBitmap crop(int left, int top, int width, int height)
{
var newSource = binarizer.LuminanceSource.crop(left, top, width, height);
return new BinaryBitmap(binarizer.createBinarizer(newSource));
}
/// <returns>
/// Whether this bitmap supports counter-clockwise rotation.
/// </returns>
public bool RotateSupported
{
get
{
return binarizer.LuminanceSource.RotateSupported;
}
}
/// <summary>
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
/// Only callable if <see cref="RotateSupported"/> is true.
/// </summary>
/// <returns>A rotated version of this object.</returns>
public BinaryBitmap rotateCounterClockwise()
{
var newSource = binarizer.LuminanceSource.rotateCounterClockwise();
return new BinaryBitmap(binarizer.createBinarizer(newSource));
}
/// <summary>
/// Returns a new object with rotated image data by 45 degrees counterclockwise.
/// Only callable if <see cref="RotateSupported"/> is true.
/// </summary>
/// <returns>A rotated version of this object.</returns>
public BinaryBitmap rotateCounterClockwise45()
{
LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise45();
return new BinaryBitmap(binarizer.createBinarizer(newSource));
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
var blackMatrix = BlackMatrix;
return blackMatrix != null ? blackMatrix.ToString() : String.Empty;
}
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing
{
/// <summary>
/// Encapsulates a type of hint that a caller may pass to a barcode reader to help it
/// more quickly or accurately decode it. It is up to implementations to decide what,
/// if anything, to do with the information that is supplied.
/// <seealso cref="Reader.decode(BinaryBitmap, IDictionary{DecodeHintType, object})" />
/// </summary>
/// <author>Sean Owen</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public enum DecodeHintType
{
/// <summary>
/// Unspecified, application-specific hint. Maps to an unspecified <see cref="System.Object" />.
/// </summary>
OTHER,
/// <summary>
/// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
/// use <see cref="bool" /> = true.
/// </summary>
PURE_BARCODE,
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a <see cref="System.Collections.ICollection" /> of <see cref="BarcodeFormat" />s.
/// </summary>
POSSIBLE_FORMATS,
/// <summary>
/// Spend more time to try to find a barcode; optimize for accuracy, not speed.
/// Doesn't matter what it maps to; use <see cref="bool" /> = true.
/// </summary>
TRY_HARDER,
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
CHARACTER_SET,
/// <summary>
/// Allowed lengths of encoded data -- reject anything else. Maps to an int[].
/// </summary>
ALLOWED_LENGTHS,
/// <summary>
/// Assume Code 39 codes employ a check digit. Maps to <see cref="bool" />.
/// </summary>
ASSUME_CODE_39_CHECK_DIGIT,
/// <summary>
/// The caller needs to be notified via callback when a possible <see cref="ResultPoint" />
/// is found. Maps to a <see cref="ResultPointCallback" />.
/// </summary>
NEED_RESULT_POINT_CALLBACK,
/// <summary>
/// Assume MSI codes employ a check digit. Maps to <see cref="bool" />.
/// </summary>
ASSUME_MSI_CHECK_DIGIT,
/// <summary>
/// if Code39 could be detected try to use extended mode for full ASCII character set
/// Maps to <see cref="bool" />.
/// </summary>
USE_CODE_39_EXTENDED_MODE,
/// <summary>
/// Don't fail if a Code39 is detected but can't be decoded in extended mode.
/// Return the raw Code39 result instead. Maps to <see cref="bool" />.
/// </summary>
RELAXED_CODE_39_EXTENDED_MODE,
/// <summary>
/// 1D readers supporting rotation with TRY_HARDER enabled.
/// But BarcodeReader class can do auto-rotating for 1D and 2D codes.
/// Enabling that option prevents 1D readers doing double rotation.
/// BarcodeReader enables that option automatically if "global" auto-rotation is enabled.
/// Maps to <see cref="bool" />.
/// </summary>
TRY_HARDER_WITHOUT_ROTATION,
/// <summary>
/// Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
/// For example this affects FNC1 handling for Code 128 (aka GS1-128). Doesn't matter what it maps to;
/// use <see cref="bool" />.
/// </summary>
ASSUME_GS1,
/// <summary>
/// If true, return the start and end digits in a Codabar barcode instead of stripping them. They
/// are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
/// to not be. Doesn't matter what it maps to; use <see cref="bool" />.
/// </summary>
RETURN_CODABAR_START_END,
/// <summary>
/// Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
/// Maps to an <see cref="Array.int" /> of the allowed extension lengths, for example [2], [5], or [2, 5].
/// If it is optional to have an extension, do not set this hint. If this is set,
/// and a UPC or EAN barcode is found but an extension is not, then no result will be returned
/// at all.
/// </summary>
ALLOWED_EAN_EXTENSIONS
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// Simply encapsulates a width and height.
/// </summary>
public sealed class Dimension
{
private readonly int width;
private readonly int height;
public Dimension(int width, int height)
{
if (width < 0 || height < 0)
{
throw new ArgumentException();
}
this.width = width;
this.height = height;
}
public int Width
{
get { return width; }
}
public int Height
{
get { return height; }
}
public override bool Equals(Object other)
{
if (other is Dimension)
{
var d = (Dimension)other;
return width == d.width && height == d.height;
}
return false;
}
public override int GetHashCode()
{
return width * 32713 + height;
}
public override String ToString()
{
return width + "x" + height;
}
}
}

View File

@@ -1,131 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary>
/// These are a set of hints that you may pass to Writers to specify their behavior.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public enum EncodeHintType
{
/// <summary>
/// Specifies the width of the barcode image
/// type: <see cref="System.Int32" />
/// </summary>
WIDTH,
/// <summary>
/// Specifies the height of the barcode image
/// type: <see cref="System.Int32" />
/// </summary>
HEIGHT,
/// <summary>
/// Don't put the content string into the output image.
/// type: <see cref="System.Boolean" />
/// </summary>
PURE_BARCODE,
/// <summary>
/// Specifies what degree of error correction to use, for example in QR Codes.
/// Type depends on the encoder. For example for QR codes it's type
/// <see cref="ZXing.QrCode.Internal.ErrorCorrectionLevel" />
/// For Aztec it is of type <see cref="System.Int32" />, representing the minimal percentage of error correction words.
/// Note: an Aztec symbol should have a minimum of 25% EC words.
/// For PDF417 it is of type <see cref="ZXing.PDF417.Internal.PDF417ErrorCorrectionLevel"/> or <see cref="System.Int32" /> (between 0 and 8),
/// </summary>
ERROR_CORRECTION,
/// <summary>
/// Specifies what character encoding to use where applicable.
/// type: <see cref="System.String" />
/// </summary>
CHARACTER_SET,
/// <summary>
/// Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
/// by format; for example it controls margin before and after the barcode horizontally for
/// most 1D formats.
/// type: <see cref="System.Int32" />
/// </summary>
MARGIN,
/// <summary>
/// Specifies whether to use compact mode for PDF417.
/// type: <see cref="System.Boolean" />
/// </summary>
PDF417_COMPACT,
/// <summary>
/// Specifies what compaction mode to use for PDF417.
/// type: <see cref="ZXing.PDF417.Internal.Compaction" />
/// </summary>
PDF417_COMPACTION,
/// <summary>
/// Specifies the minimum and maximum number of rows and columns for PDF417.
/// type: <see cref="ZXing.PDF417.Internal.Dimensions" />
/// </summary>
PDF417_DIMENSIONS,
/// <summary>
/// Don't append ECI segment.
/// That is against the specification of QR Code but some
/// readers have problems if the charset is switched from
/// ISO-8859-1 (default) to UTF-8 with the necessary ECI segment.
/// If you set the property to true you can use UTF-8 encoding
/// and the ECI segment is omitted.
/// type: <see cref="System.Boolean" />
/// </summary>
DISABLE_ECI,
/// <summary>
/// Specifies the matrix shape for Data Matrix (type <see cref="ZXing.Datamatrix.Encoder.SymbolShapeHint"/>)
/// </summary>
DATA_MATRIX_SHAPE,
/// <summary>
/// Specifies a minimum barcode size (type <see cref="ZXing.Dimension"/>). Only applicable to Data Matrix now.
/// </summary>
MIN_SIZE,
/// <summary>
/// Specifies a maximum barcode size (type <see cref="ZXing.Dimension"/>). Only applicable to Data Matrix now.
/// </summary>
MAX_SIZE,
/// <summary>
/// if true, don't switch to codeset C for numbers
/// </summary>
CODE128_FORCE_CODESET_B,
/// <summary>
/// Specifies the default encodation for Data Matrix (type <see cref="ZXing.Datamatrix.Encoder.Encodation"/>)
/// Make sure that the content fits into the encodation value, otherwise there will be an exception thrown.
/// standard value: Encodation.ASCII
/// </summary>
DATA_MATRIX_DEFAULT_ENCODATION,
/// <summary>
/// Specifies the required number of layers for an Aztec code:
/// a negative number (-1, -2, -3, -4) specifies a compact Aztec code
/// 0 indicates to use the minimum number of layers (the default)
/// a positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code
/// </summary>
AZTEC_LAYERS,
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// Thrown when a barcode was successfully detected, but some aspect of
/// the content did not conform to the barcode's format rules. This could have
/// been due to a mis-detection.
/// <author>Sean Owen</author>
/// </summary>
public sealed class FormatException : ReaderException
{
private FormatException()
{
}
private FormatException(Exception innerException)
: base(innerException)
{
}
new public static FormatException Instance
{
get { return new FormatException(); }
}
public static FormatException getInstance(Exception innerExc)
{
return new FormatException(innerExc);
}
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing
{
/// <summary>
/// Interface for a smart class to decode the barcode inside a bitmap object
/// </summary>
public interface IBarcodeReader
{
/// <summary>
/// event is executed when a result point was found
/// </summary>
event Action<ResultPoint> ResultPointFound;
/// <summary>
/// event is executed when a result was found via decode
/// </summary>
event Action<Result> ResultFound;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.TryHarder property instead.")]
bool TryHarder { get; set; }
/// <summary>
/// Image is a pure monochrome image of a barcode.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.PureBarcode property instead.")]
bool PureBarcode { get; set; }
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
[Obsolete("Please use the Options.CharacterSet property instead.")]
string CharacterSet { get; set; }
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
[Obsolete("Please use the Options.PossibleFormats property instead.")]
IList<BarcodeFormat> PossibleFormats { get; set; }
/// <summary>
/// Specifies some options which influence the decoding process
/// </summary>
DecodingOptions Options { get; set; }
/// <summary>
/// Decodes the specified barcode bitmap which is given by a generic byte array with the order RGB24.
/// </summary>
/// <param name="rawRGB">The image as RGB24 array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
Result Decode(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format);
/// <summary>
/// Tries to decode a barcode within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
Result Decode(LuminanceSource luminanceSource);
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary>
/// Interface for a smart class to decode the barcode inside a bitmap object
/// </summary>
public partial interface IBarcodeReader<T>
{
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
Result Decode(T barcodeBitmap);
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing
{
/// <summary>
/// Interface for a smart class to decode the barcode inside a bitmap object
/// </summary>
/// <typeparam name="T">gives the type of the input data</typeparam>
public interface IBarcodeReaderGeneric<T>
{
/// <summary>
/// event is executed when a result point was found
/// </summary>
event Action<ResultPoint> ResultPointFound;
/// <summary>
/// event is executed when a result was found via decode
/// </summary>
event Action<Result> ResultFound;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.TryHarder property instead.")]
bool TryHarder { get; set; }
/// <summary>
/// Image is a pure monochrome image of a barcode.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.PureBarcode property instead.")]
bool PureBarcode { get; set; }
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
[Obsolete("Please use the Options.CharacterSet property instead.")]
string CharacterSet { get; set; }
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
[Obsolete("Please use the Options.PossibleFormats property instead.")]
IList<BarcodeFormat> PossibleFormats { get; set; }
/// <summary>
/// Specifies some options which influence the decoding process
/// </summary>
DecodingOptions Options { get; set; }
/// <summary>
/// Decodes the specified barcode bitmap which is given by a generic byte array.
/// </summary>
/// <param name="rawRGB">The barcode bitmap.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
Result Decode(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format);
/// <summary>
/// Tries to decode a barcode within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
Result Decode(LuminanceSource luminanceSource);
#if !PORTABLE
#if !UNITY
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
Result Decode(T barcodeBitmap);
#else
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
Result Decode(T rawRGB, int width, int height);
#endif
#endif
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
#if MONOTOUCH
#if __UNIFIED__
using UIKit;
#else
using MonoTouch.UIKit;
#endif
#endif
namespace ZXing
{
/// <summary>
/// Interface for a smart class to encode some content into a barcode
/// </summary>
public interface IBarcodeWriter
{
/// <summary>
/// Encodes the specified contents.
/// </summary>
/// <param name="contents">The contents.</param>
/// <returns></returns>
BitMatrix Encode(string contents);
#if MONOTOUCH
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
UIImage Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
UIImage Write(BitMatrix matrix);
#endif
#if MONOANDROID
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
Android.Graphics.Bitmap Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
Android.Graphics.Bitmap Write(BitMatrix matrix);
#endif
#if UNITY
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
UnityEngine.Color32[] Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
UnityEngine.Color32[] Write(BitMatrix matrix);
#endif
#if SILVERLIGHT
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
System.Windows.Media.Imaging.WriteableBitmap Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
System.Windows.Media.Imaging.WriteableBitmap Write(BitMatrix matrix);
#endif
#if NETFX_CORE
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
Windows.UI.Xaml.Media.Imaging.WriteableBitmap Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
Windows.UI.Xaml.Media.Imaging.WriteableBitmap Write(BitMatrix matrix);
#endif
#if (NET40 || NET35 || NET20) && !UNITY
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
System.Drawing.Bitmap Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
System.Drawing.Bitmap Write(BitMatrix matrix);
#endif
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
namespace ZXing
{
#if !(WINDOWS_PHONE || WindowsCE)
/// <summary>
/// Interface for a smart class to encode some content into a barcode
/// </summary>
public interface IBarcodeWriterGeneric<out TOutput>
#else
/// <summary>
/// Interface for a smart class to encode some content into a barcode
/// </summary>
public interface IBarcodeWriterGeneric<TOutput>
#endif
{
/// <summary>
/// Encodes the specified contents.
/// </summary>
/// <param name="contents">The contents.</param>
/// <returns></returns>
BitMatrix Encode(string contents);
/// <summary>
/// Creates a visual representation of the contents
/// </summary>
/// <param name="contents">The contents.</param>
/// <returns></returns>
TOutput Write(string contents);
/// <summary>
/// Returns a rendered instance of the barcode which is given by a BitMatrix.
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns></returns>
TOutput Write(BitMatrix matrix);
}
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing
{
/// <summary>
/// Interface for a smart class to decode multiple barcodes inside a bitmap object
/// </summary>
public interface IMultipleBarcodeReader
{
/// <summary>
/// event is executed when a result point was found
/// </summary>
event Action<ResultPoint> ResultPointFound;
/// <summary>
/// event is executed when a result was found via decode
/// </summary>
event Action<Result> ResultFound;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.TryHarder property instead.")]
bool TryHarder { get; set; }
/// <summary>
/// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
/// use {@link Boolean#TRUE}.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.PureBarcode property instead.")]
bool PureBarcode { get; set; }
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
[Obsolete("Please use the Options.CharacterSet property instead.")]
string CharacterSet { get; set; }
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
[Obsolete("Please use the Options.PossibleFormats property instead.")]
IList<BarcodeFormat> PossibleFormats { get; set; }
/// <summary>
/// Specifies some options which influence the decoding process
/// </summary>
DecodingOptions Options { get; set; }
/// <summary>
/// Decodes the specified barcode bitmap which is given by a generic byte array with the order RGB24.
/// </summary>
/// <param name="rawRGB">The image as RGB24 array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
Result[] DecodeMultiple(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format);
/// <summary>
/// Tries to decode barcodes within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
Result[] DecodeMultiple(LuminanceSource luminanceSource);
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing
{
/// <summary>
/// Interface for a smart class to decode multiple barcodes inside a bitmap object
/// </summary>
public interface IMultipleBarcodeReaderGeneric<T>
{
/// <summary>
/// event is executed when a result point was found
/// </summary>
event Action<ResultPoint> ResultPointFound;
/// <summary>
/// event is executed when a result was found via decode
/// </summary>
event Action<Result> ResultFound;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.TryHarder property instead.")]
bool TryHarder { get; set; }
/// <summary>
/// Image is a pure monochrome image of a barcode. Doesn't matter what it maps to;
/// use {@link Boolean#TRUE}.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
[Obsolete("Please use the Options.PureBarcode property instead.")]
bool PureBarcode { get; set; }
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
[Obsolete("Please use the Options.CharacterSet property instead.")]
string CharacterSet { get; set; }
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
[Obsolete("Please use the Options.PossibleFormats property instead.")]
IList<BarcodeFormat> PossibleFormats { get; set; }
/// <summary>
/// Specifies some options which influence the decoding process
/// </summary>
DecodingOptions Options { get; set; }
/// <summary>
/// Decodes the specified barcode bitmap which is given by a generic byte array with the order RGB24.
/// </summary>
/// <param name="rawRGB">The barcode bitmap.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="format">The format.</param>
/// <returns>
/// the result data or null
/// </returns>
Result[] DecodeMultiple(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format);
/// <summary>
/// Tries to decode barcodes within an image which is given by a luminance source.
/// That method gives a chance to prepare a luminance source completely before calling
/// the time consuming decoding method. On the other hand there is a chance to create
/// a luminance source which is independent from external resources (like Bitmap objects)
/// and the decoding call can be made in a background thread.
/// </summary>
/// <param name="luminanceSource">The luminance source.</param>
/// <returns></returns>
Result[] DecodeMultiple(LuminanceSource luminanceSource);
#if !PORTABLE
#if !UNITY
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="barcodeBitmap">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
Result[] DecodeMultiple(T barcodeBitmap);
#else
/// <summary>
/// Decodes the specified barcode bitmap.
/// </summary>
/// <param name="rawRGB">The barcode bitmap.</param>
/// <returns>the result data or null</returns>
Result[] DecodeMultiple(T rawRGB, int width, int height);
#endif
#endif
}
}

View File

@@ -1,154 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary>
/// A wrapper implementation of {@link LuminanceSource} which inverts the luminances it returns -- black becomes
/// white and vice versa, and each value becomes (255-value).
/// </summary>
/// <author>Sean Owen</author>
public sealed class InvertedLuminanceSource : LuminanceSource
{
private readonly LuminanceSource @delegate;
private byte[] invertedMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="InvertedLuminanceSource"/> class.
/// </summary>
/// <param name="delegate">The @delegate.</param>
public InvertedLuminanceSource(LuminanceSource @delegate)
: base(@delegate.Width, @delegate.Height)
{
this.@delegate = @delegate;
}
/// <summary>
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
/// to bitwise and with 0xff for each value. It is preferable for implementations of this method
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
/// getMatrix() may never be called.
/// </summary>
/// <param name="y">The row to fetch, 0 &lt;= y &lt; Height.</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// Always use the returned object, and ignore the .length of the array.</param>
/// <returns>
/// An array containing the luminance data.
/// </returns>
override public byte[] getRow(int y, byte[] row)
{
row = @delegate.getRow(y, row);
int width = Width;
for (int i = 0; i < width; i++)
{
row[i] = (byte)(255 - (row[i] & 0xFF));
}
return row;
}
/// <summary>
/// Fetches luminance data for the underlying bitmap. Values should be fetched using:
/// int luminance = array[y * width + x] &amp; 0xff;
/// </summary>
/// <returns> A row-major 2D array of luminance values. Do not use result.length as it may be
/// larger than width * height bytes on some platforms. Do not modify the contents
/// of the result.
/// </returns>
override public byte[] Matrix
{
get
{
if (invertedMatrix == null)
{
byte[] matrix = @delegate.Matrix;
int length = Width*Height;
invertedMatrix = new byte[length];
for (int i = 0; i < length; i++)
{
invertedMatrix[i] = (byte) (255 - (matrix[i] & 0xFF));
}
}
return invertedMatrix;
}
}
/// <summary>
/// </summary>
/// <returns> Whether this subclass supports cropping.</returns>
override public bool CropSupported
{
get { return @delegate.CropSupported; }
}
/// <summary>
/// Returns a new object with cropped image data. Implementations may keep a reference to the
/// original data rather than a copy. Only callable if CropSupported is true.
/// </summary>
/// <param name="left">The left coordinate, 0 &lt;= left &lt; Width.</param>
/// <param name="top">The top coordinate, 0 &lt;= top &lt;= Height.</param>
/// <param name="width">The width of the rectangle to crop.</param>
/// <param name="height">The height of the rectangle to crop.</param>
/// <returns>
/// A cropped version of this object.
/// </returns>
override public LuminanceSource crop(int left, int top, int width, int height)
{
return new InvertedLuminanceSource(@delegate.crop(left, top, width, height));
}
/// <summary>
/// </summary>
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
override public bool RotateSupported
{
get { return @delegate.RotateSupported; }
}
/// <summary>
/// Inverts this instance.
/// </summary>
/// <returns>original delegate {@link LuminanceSource} since invert undoes itself</returns>
override public LuminanceSource invert()
{
return @delegate;
}
/// <summary>
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
/// Only callable if {@link #isRotateSupported()} is true.
/// </summary>
/// <returns>
/// A rotated version of this object.
/// </returns>
override public LuminanceSource rotateCounterClockwise()
{
return new InvertedLuminanceSource(@delegate.rotateCounterClockwise());
}
/// <summary>
/// Returns a new object with rotated image data by 45 degrees counterclockwise.
/// Only callable if {@link #isRotateSupported()} is true.
/// </summary>
/// <returns>
/// A rotated version of this object.
/// </returns>
override public LuminanceSource rotateCounterClockwise45()
{
return new InvertedLuminanceSource(@delegate.rotateCounterClockwise45());
}
}
}

View File

@@ -1,194 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing
{
/// <summary>
/// The purpose of this class hierarchy is to abstract different bitmap implementations across
/// platforms into a standard interface for requesting greyscale luminance values. The interface
/// only provides immutable methods; therefore crop and rotation create copies. This is to ensure
/// that one Reader does not modify the original luminance source and leave it in an unknown state
/// for other Readers in the chain.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public abstract class LuminanceSource
{
private int width;
private int height;
protected LuminanceSource(int width, int height)
{
this.width = width;
this.height = height;
}
/// <summary>
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
/// to bitwise and with 0xff for each value. It is preferable for implementations of this method
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
/// getMatrix() may never be called.
/// </summary>
/// <param name="y">The row to fetch, which must be in [0, bitmap height)</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// Always use the returned object, and ignore the .length of the array.
/// </param>
/// <returns> An array containing the luminance data.</returns>
public abstract byte[] getRow(int y, byte[] row);
/// <summary>
/// Fetches luminance data for the underlying bitmap. Values should be fetched using:
/// <code>int luminance = array[y * width + x] & 0xff</code>
/// </summary>
/// <returns>
/// A row-major 2D array of luminance values. Do not use result.length as it may be
/// larger than width * height bytes on some platforms. Do not modify the contents
/// of the result.
/// </returns>
public abstract byte[] Matrix { get; }
/// <returns> The width of the bitmap.</returns>
virtual public int Width
{
get
{
return width;
}
protected set
{
width = value;
}
}
/// <returns> The height of the bitmap.</returns>
virtual public int Height
{
get
{
return height;
}
protected set
{
height = value;
}
}
/// <returns> Whether this subclass supports cropping.</returns>
virtual public bool CropSupported
{
get
{
return false;
}
}
/// <summary>
/// Returns a new object with cropped image data. Implementations may keep a reference to the
/// original data rather than a copy. Only callable if CropSupported is true.
/// </summary>
/// <param name="left">The left coordinate, which must be in [0, Width)</param>
/// <param name="top">The top coordinate, which must be in [0, Height)</param>
/// <param name="width">The width of the rectangle to crop.</param>
/// <param name="height">The height of the rectangle to crop.</param>
/// <returns> A cropped version of this object.</returns>
public virtual LuminanceSource crop(int left, int top, int width, int height)
{
throw new NotSupportedException("This luminance source does not support cropping.");
}
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
virtual public bool RotateSupported
{
get
{
return false;
}
}
/// <summary>
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
/// Only callable if <see cref="RotateSupported"/> is true.
/// </summary>
/// <returns>A rotated version of this object.</returns>
public virtual LuminanceSource rotateCounterClockwise()
{
throw new NotSupportedException("This luminance source does not support rotation.");
}
/// <summary>
/// Returns a new object with rotated image data by 45 degrees counterclockwise.
/// Only callable if <see cref="RotateSupported"/> is true.
/// </summary>
/// <returns>A rotated version of this object.</returns>
public virtual LuminanceSource rotateCounterClockwise45()
{
throw new NotSupportedException("This luminance source does not support rotation by 45 degrees.");
}
/// <summary>
/// </summary>
/// <returns>Whether this subclass supports invertion.</returns>
virtual public bool InversionSupported
{
get
{
return false;
}
}
virtual public LuminanceSource invert()
{
throw new NotSupportedException("This luminance source does not support inversion.");
}
override public String ToString()
{
var row = new byte[width];
var result = new StringBuilder(height * (width + 1));
for (int y = 0; y < height; y++)
{
row = getRow(y, row);
for (int x = 0; x < width; x++)
{
int luminance = row[x] & 0xFF;
char c;
if (luminance < 0x40)
{
c = '#';
}
else if (luminance < 0x80)
{
c = '+';
}
else if (luminance < 0xC0)
{
c = '.';
}
else
{
c = ' ';
}
result.Append(c);
}
result.Append('\n');
}
return result.ToString();
}
}
}

View File

@@ -1,228 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using ZXing.Aztec;
using ZXing.Datamatrix;
using ZXing.IMB;
using ZXing.Maxicode;
using ZXing.OneD;
using ZXing.PDF417;
using ZXing.QrCode;
namespace ZXing
{
/// <summary>
/// MultiFormatReader is a convenience class and the main entry point into the library for most uses.
/// By default it attempts to decode all barcode formats that the library supports. Optionally, you
/// can provide a hints object to request different behavior, for example only decoding QR codes.
/// </summary>
/// <author>Sean Owen</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source</author>
public sealed class MultiFormatReader : Reader
{
private IDictionary<DecodeHintType, object> hints;
private IList<Reader> readers;
/// <summary> This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it
/// passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly.
/// Use setHints() followed by decodeWithState() for continuous scan applications.
///
/// </summary>
/// <param name="image">The pixel data to decode
/// </param>
/// <returns> The contents of the image
/// </returns>
/// <throws> ReaderException Any errors which occurred </throws>
public Result decode(BinaryBitmap image)
{
Hints = null;
return decodeInternal(image);
}
/// <summary> Decode an image using the hints provided. Does not honor existing state.
///
/// </summary>
/// <param name="image">The pixel data to decode
/// </param>
/// <param name="hints">The hints to use, clearing the previous state.
/// </param>
/// <returns> The contents of the image
/// </returns>
/// <throws> ReaderException Any errors which occurred </throws>
public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints)
{
Hints = hints;
return decodeInternal(image);
}
/// <summary> Decode an image using the state set up by calling setHints() previously. Continuous scan
/// clients will get a <b>large</b> speed increase by using this instead of decode().
///
/// </summary>
/// <param name="image">The pixel data to decode
/// </param>
/// <returns> The contents of the image
/// </returns>
/// <throws> ReaderException Any errors which occurred </throws>
public Result decodeWithState(BinaryBitmap image)
{
// Make sure to set up the default state so we don't crash
if (readers == null)
{
Hints = null;
}
return decodeInternal(image);
}
/// <summary> This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls
/// to decodeWithState(image) can reuse the same set of readers without reallocating memory. This
/// is important for performance in continuous scan clients.
///
/// </summary>
/// <param name="hints">The set of hints to use for subsequent calls to decode(image)
/// </param>
public IDictionary<DecodeHintType, object> Hints
{
set
{
hints = value;
var tryHarder = value != null && value.ContainsKey(DecodeHintType.TRY_HARDER);
var formats = value == null || !value.ContainsKey(DecodeHintType.POSSIBLE_FORMATS) ? null : (IList<BarcodeFormat>)value[DecodeHintType.POSSIBLE_FORMATS];
if (formats != null)
{
bool addOneDReader =
formats.Contains(BarcodeFormat.All_1D) ||
formats.Contains(BarcodeFormat.UPC_A) ||
formats.Contains(BarcodeFormat.UPC_E) ||
formats.Contains(BarcodeFormat.EAN_13) ||
formats.Contains(BarcodeFormat.EAN_8) ||
formats.Contains(BarcodeFormat.CODABAR) ||
formats.Contains(BarcodeFormat.CODE_39) ||
formats.Contains(BarcodeFormat.CODE_93) ||
formats.Contains(BarcodeFormat.CODE_128) ||
formats.Contains(BarcodeFormat.ITF) ||
formats.Contains(BarcodeFormat.RSS_14) ||
formats.Contains(BarcodeFormat.RSS_EXPANDED);
readers = new List<Reader>();
// Put 1D readers upfront in "normal" mode
if (addOneDReader && !tryHarder)
{
readers.Add(new MultiFormatOneDReader(value));
}
if (formats.Contains(BarcodeFormat.QR_CODE))
{
readers.Add(new QRCodeReader());
}
if (formats.Contains(BarcodeFormat.DATA_MATRIX))
{
readers.Add(new DataMatrixReader());
}
if (formats.Contains(BarcodeFormat.AZTEC))
{
readers.Add(new AztecReader());
}
if (formats.Contains(BarcodeFormat.PDF_417))
{
readers.Add(new PDF417Reader());
}
if (formats.Contains(BarcodeFormat.MAXICODE))
{
readers.Add(new MaxiCodeReader());
}
if (formats.Contains(BarcodeFormat.IMB))
{
readers.Add(new IMBReader());
}
// At end in "try harder" mode
if (addOneDReader && tryHarder)
{
readers.Add(new MultiFormatOneDReader(value));
}
}
if (readers == null ||
readers.Count == 0)
{
readers = readers ?? new List<Reader>();
if (!tryHarder)
{
readers.Add(new MultiFormatOneDReader(value));
}
readers.Add(new QRCodeReader());
readers.Add(new DataMatrixReader());
readers.Add(new AztecReader());
readers.Add(new PDF417Reader());
readers.Add(new MaxiCodeReader());
if (tryHarder)
{
readers.Add(new MultiFormatOneDReader(value));
}
}
}
}
public void reset()
{
if (readers != null)
{
foreach (var reader in readers)
{
reader.reset();
}
}
}
private Result decodeInternal(BinaryBitmap image)
{
if (readers != null)
{
var rpCallback = hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)
? (ResultPointCallback) hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK]
: null;
for (var index = 0; index < readers.Count; index++)
{
var reader = readers[index];
reader.reset();
var result = reader.decode(image, hints);
if (result != null)
{
// found a barcode, pushing the successful reader up front
// I assume that the same type of barcode is read multiple times
// so the reordering of the readers list should speed up the next reading
// a little bit
readers.RemoveAt(index);
readers.Insert(0, reader);
return result;
}
if (rpCallback != null)
rpCallback(null);
}
}
return null;
}
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Aztec;
using ZXing.Common;
using ZXing.Datamatrix;
using ZXing.OneD;
using ZXing.PDF417;
using ZXing.QrCode;
namespace ZXing
{
/// <summary> This is a factory class which finds the appropriate Writer subclass for the BarcodeFormat
/// requested and encodes the barcode with the supplied contents.
///
/// </summary>
/// <author> dswitkin@google.com (Daniel Switkin)
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class MultiFormatWriter : Writer
{
private static readonly IDictionary<BarcodeFormat, Func<Writer>> formatMap;
static MultiFormatWriter()
{
formatMap = new Dictionary<BarcodeFormat, Func<Writer>>
{
{BarcodeFormat.EAN_8, () => new EAN8Writer()},
{BarcodeFormat.EAN_13, () => new EAN13Writer()},
{BarcodeFormat.UPC_A, () => new UPCAWriter()},
{BarcodeFormat.QR_CODE, () => new QRCodeWriter()},
{BarcodeFormat.CODE_39, () => new Code39Writer()},
{BarcodeFormat.CODE_128, () => new Code128Writer()},
{BarcodeFormat.ITF, () => new ITFWriter()},
{BarcodeFormat.PDF_417, () => new PDF417Writer()},
{BarcodeFormat.CODABAR, () => new CodaBarWriter()},
{BarcodeFormat.MSI, () => new MSIWriter()},
{BarcodeFormat.PLESSEY, () => new PlesseyWriter()},
{BarcodeFormat.DATA_MATRIX, () => new DataMatrixWriter()},
{BarcodeFormat.AZTEC, () => new AztecWriter()},
};
}
/// <summary>
/// Gets the collection of supported writers.
/// </summary>
public static ICollection<BarcodeFormat> SupportedWriters
{
get { return formatMap.Keys; }
}
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
{
return encode(contents, format, width, height, null);
}
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, IDictionary<EncodeHintType, object> hints)
{
if (!formatMap.ContainsKey(format))
throw new ArgumentException("No encoder available for format " + format);
return formatMap[format]().encode(contents, format, width, height, hints);
}
}
}

View File

@@ -1,260 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// This object extends LuminanceSource around an array of YUV data returned from the camera driver,
/// with the option to crop to a rectangle within the full data. This can be used to exclude
/// superfluous pixels around the perimeter and speed up decoding.
/// It works for any pixel format where the Y channel is planar and appears first, including
/// YCbCr_420_SP and YCbCr_422_SP.
/// @author dswitkin@google.com (Daniel Switkin)
/// </summary>
public sealed class PlanarYUVLuminanceSource : BaseLuminanceSource
{
private const int THUMBNAIL_SCALE_FACTOR = 2;
private readonly byte[] yuvData;
private readonly int dataWidth;
private readonly int dataHeight;
private readonly int left;
private readonly int top;
/// <summary>
/// Initializes a new instance of the <see cref="PlanarYUVLuminanceSource"/> class.
/// </summary>
/// <param name="yuvData">The yuv data.</param>
/// <param name="dataWidth">Width of the data.</param>
/// <param name="dataHeight">Height of the data.</param>
/// <param name="left">The left.</param>
/// <param name="top">The top.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="reverseHoriz">if set to <c>true</c> [reverse horiz].</param>
public PlanarYUVLuminanceSource(byte[] yuvData,
int dataWidth,
int dataHeight,
int left,
int top,
int width,
int height,
bool reverseHoriz)
: base(width, height)
{
if (left + width > dataWidth || top + height > dataHeight)
{
throw new ArgumentException("Crop rectangle does not fit within image data.");
}
this.yuvData = yuvData;
this.dataWidth = dataWidth;
this.dataHeight = dataHeight;
this.left = left;
this.top = top;
if (reverseHoriz)
{
reverseHorizontal(width, height);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="PlanarYUVLuminanceSource"/> class.
/// </summary>
/// <param name="luminances">The luminances.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
private PlanarYUVLuminanceSource(byte[] luminances, int width, int height)
: base(width, height)
{
yuvData = luminances;
this.luminances = luminances;
dataWidth = width;
dataHeight = height;
left = 0;
top = 0;
}
/// <summary>
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
/// to bitwise and with 0xff for each value. It is preferable for implementations of this method
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
/// getMatrix() may never be called.
/// </summary>
/// <param name="y">The row to fetch, 0 &lt;= y &lt; Height.</param>
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
/// Always use the returned object, and ignore the .length of the array.</param>
/// <returns>
/// An array containing the luminance data.
/// </returns>
override public byte[] getRow(int y, byte[] row)
{
if (y < 0 || y >= Height)
{
throw new ArgumentException("Requested row is outside the image: " + y);
}
int width = Width;
if (row == null || row.Length < width)
{
row = new byte[width];
}
int offset = (y + top) * dataWidth + left;
Array.Copy(yuvData, offset, row, 0, width);
return row;
}
/// <summary>
///
/// </summary>
override public byte[] Matrix
{
get
{
int width = Width;
int height = Height;
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if (width == dataWidth && height == dataHeight)
{
return yuvData;
}
int area = width * height;
byte[] matrix = new byte[area];
int inputOffset = top * dataWidth + left;
// If the width matches the full width of the underlying data, perform a single copy.
if (width == dataWidth)
{
Array.Copy(yuvData, inputOffset, matrix, 0, area);
return matrix;
}
// Otherwise copy one cropped row at a time.
byte[] yuv = yuvData;
for (int y = 0; y < height; y++)
{
int outputOffset = y * width;
Array.Copy(yuv, inputOffset, matrix, outputOffset, width);
inputOffset += dataWidth;
}
return matrix;
}
}
/// <summary>
/// </summary>
/// <returns> Whether this subclass supports cropping.</returns>
override public bool CropSupported
{
get { return true; }
}
/// <summary>
/// Returns a new object with cropped image data. Implementations may keep a reference to the
/// original data rather than a copy. Only callable if CropSupported is true.
/// </summary>
/// <param name="left">The left coordinate, 0 &lt;= left &lt; Width.</param>
/// <param name="top">The top coordinate, 0 &lt;= top &lt;= Height.</param>
/// <param name="width">The width of the rectangle to crop.</param>
/// <param name="height">The height of the rectangle to crop.</param>
/// <returns>
/// A cropped version of this object.
/// </returns>
override public LuminanceSource crop(int left, int top, int width, int height)
{
return new PlanarYUVLuminanceSource(yuvData,
dataWidth,
dataHeight,
this.left + left,
this.top + top,
width,
height,
false);
}
/// <summary>
/// Renders the cropped greyscale bitmap.
/// </summary>
/// <returns></returns>
public int[] renderThumbnail()
{
int width = Width / THUMBNAIL_SCALE_FACTOR;
int height = Height / THUMBNAIL_SCALE_FACTOR;
int[] pixels = new int[width * height];
byte[] yuv = yuvData;
int inputOffset = top * dataWidth + left;
for (int y = 0; y < height; y++)
{
int outputOffset = y * width;
for (int x = 0; x < width; x++)
{
int grey = yuv[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff;
pixels[outputOffset + x] = ((0x00FF0000 << 8) | (grey * 0x00010101));
}
inputOffset += dataWidth * THUMBNAIL_SCALE_FACTOR;
}
return pixels;
}
/// <summary>
/// width of image from {@link #renderThumbnail()}
/// </summary>
public int ThumbnailWidth
{
get
{
return Width / THUMBNAIL_SCALE_FACTOR;
}
}
/// <summary>
/// height of image from {@link #renderThumbnail()}
/// </summary>
public int ThumbnailHeight
{
get
{
return Height / THUMBNAIL_SCALE_FACTOR;
}
}
private void reverseHorizontal(int width, int height)
{
byte[] yuvData = this.yuvData;
for (int y = 0, rowStart = top * dataWidth + left; y < height; y++, rowStart += dataWidth)
{
int middle = rowStart + width / 2;
for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--)
{
byte temp = yuvData[x1];
yuvData[x1] = yuvData[x2];
yuvData[x2] = temp;
}
}
}
protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
{
return new PlanarYUVLuminanceSource(newLuminances, width, height);
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
///
/// </summary>
[Obsolete("Use RGBLuminanceSource with the argument BitmapFormat.RGB565")]
public class RGB565LuminanceSource :RGBLuminanceSource
{
/// <summary>
/// Initializes a new instance of the <see cref="RGB565LuminanceSource"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected RGB565LuminanceSource(int width, int height)
: base(width, height)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RGB565LuminanceSource"/> class.
/// </summary>
/// <param name="rgb565RawData">The RGB565 raw data.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public RGB565LuminanceSource(byte[] rgb565RawData, int width, int height)
: base(rgb565RawData, width, height, BitmapFormat.RGB565)
{
}
/// <summary>
/// Should create a new luminance source with the right class type.
/// The method is used in methods crop and rotate.
/// </summary>
/// <param name="newLuminances">The new luminances.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns></returns>
protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
{
return new RGB565LuminanceSource(width, height) { luminances = newLuminances };
}
}
}

View File

@@ -1,314 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// Luminance source class which support different formats of images.
/// </summary>
public partial class RGBLuminanceSource : BaseLuminanceSource
{
/// <summary>
/// enumeration of supported bitmap format which the RGBLuminanceSource can process
/// </summary>
public enum BitmapFormat
{
/// <summary>
/// format of the byte[] isn't known. RGBLuminanceSource tries to determine the best possible value
/// </summary>
Unknown,
/// <summary>
/// grayscale array, the byte array is a luminance array with 1 byte per pixel
/// </summary>
Gray8,
/// <summary>
/// 3 bytes per pixel with the channels red, green and blue
/// </summary>
RGB24,
/// <summary>
/// 4 bytes per pixel with the channels red, green and blue
/// </summary>
RGB32,
/// <summary>
/// 4 bytes per pixel with the channels alpha, red, green and blue
/// </summary>
ARGB32,
/// <summary>
/// 3 bytes per pixel with the channels blue, green and red
/// </summary>
BGR24,
/// <summary>
/// 4 bytes per pixel with the channels blue, green and red
/// </summary>
BGR32,
/// <summary>
/// 4 bytes per pixel with the channels blue, green, red and alpha
/// </summary>
BGRA32,
/// <summary>
/// 2 bytes per pixel, 5 bit red, 6 bits green and 5 bits blue
/// </summary>
RGB565,
/// <summary>
/// 4 bytes per pixel with the channels red, green, blue and alpha
/// </summary>
RGBA32,
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBLuminanceSource"/> class.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
protected RGBLuminanceSource(int width, int height)
: base(width, height)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBLuminanceSource"/> class.
/// It supports a byte array with 3 bytes per pixel (RGB24).
/// </summary>
/// <param name="rgbRawBytes">The RGB raw bytes.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height)
: this(rgbRawBytes, width, height, BitmapFormat.RGB24)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBLuminanceSource"/> class.
/// It supports a byte array with 1 byte per pixel (Gray8).
/// That means the whole array consists of the luminance values (grayscale).
/// </summary>
/// <param name="luminanceArray">The luminance array.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="is8Bit">if set to <c>true</c> [is8 bit].</param>
[Obsolete("Use RGBLuminanceSource(luminanceArray, width, height, BitmapFormat.Gray8)")]
public RGBLuminanceSource(byte[] luminanceArray, int width, int height, bool is8Bit)
: this(luminanceArray, width, height, BitmapFormat.Gray8)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RGBLuminanceSource"/> class.
/// It supports a byte array with 3 bytes per pixel (RGB24).
/// </summary>
/// <param name="rgbRawBytes">The RGB raw bytes.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="bitmapFormat">The bitmap format.</param>
public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height, BitmapFormat bitmapFormat)
: base(width, height)
{
CalculateLuminance(rgbRawBytes, bitmapFormat);
}
/// <summary>
/// Should create a new luminance source with the right class type.
/// The method is used in methods crop and rotate.
/// </summary>
/// <param name="newLuminances">The new luminances.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns></returns>
protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
{
return new RGBLuminanceSource(width, height) { luminances = newLuminances };
}
private static BitmapFormat DetermineBitmapFormat(byte[] rgbRawBytes, int width, int height)
{
var square = width*height;
var byteperpixel = rgbRawBytes.Length/square;
switch (byteperpixel)
{
case 1:
return BitmapFormat.Gray8;
case 2:
return BitmapFormat.RGB565;
case 3:
return BitmapFormat.RGB24;
case 4:
return BitmapFormat.RGB32;
default:
throw new ArgumentException("The bitmap format could not be determined. Please specify the correct value.");
}
}
protected void CalculateLuminance(byte[] rgbRawBytes, BitmapFormat bitmapFormat)
{
if (bitmapFormat == BitmapFormat.Unknown)
{
bitmapFormat = DetermineBitmapFormat(rgbRawBytes, Width, Height);
}
switch (bitmapFormat)
{
case BitmapFormat.Gray8:
Buffer.BlockCopy(rgbRawBytes, 0, luminances, 0, rgbRawBytes.Length < luminances.Length ? rgbRawBytes.Length : luminances.Length);
break;
case BitmapFormat.RGB24:
CalculateLuminanceRGB24(rgbRawBytes);
break;
case BitmapFormat.BGR24:
CalculateLuminanceBGR24(rgbRawBytes);
break;
case BitmapFormat.RGB32:
CalculateLuminanceRGB32(rgbRawBytes);
break;
case BitmapFormat.BGR32:
CalculateLuminanceBGR32(rgbRawBytes);
break;
case BitmapFormat.RGBA32:
CalculateLuminanceRGBA32(rgbRawBytes);
break;
case BitmapFormat.ARGB32:
CalculateLuminanceARGB32(rgbRawBytes);
break;
case BitmapFormat.BGRA32:
CalculateLuminanceBGRA32(rgbRawBytes);
break;
case BitmapFormat.RGB565:
CalculateLuminanceRGB565(rgbRawBytes);
break;
default:
throw new ArgumentException("The bitmap format isn't supported.", bitmapFormat.ToString());
}
}
private void CalculateLuminanceRGB565(byte[] rgb565RawData)
{
var luminanceIndex = 0;
for (var index = 0; index < rgb565RawData.Length && luminanceIndex < luminances.Length; index += 2, luminanceIndex++)
{
var byte1 = rgb565RawData[index];
var byte2 = rgb565RawData[index + 1];
var b5 = byte1 & 0x1F;
var g5 = (((byte1 & 0xE0) >> 5) | ((byte2 & 0x03) << 3)) & 0x1F;
var r5 = (byte2 >> 2) & 0x1F;
var r8 = (r5 * 527 + 23) >> 6;
var g8 = (g5 * 527 + 23) >> 6;
var b8 = (b5 * 527 + 23) >> 6;
// cheap, not fully accurate conversion
//var pixel = (byte2 << 8) | byte1;
//b8 = (((pixel) & 0x001F) << 3);
//g8 = (((pixel) & 0x07E0) >> 2) & 0xFF;
//r8 = (((pixel) & 0xF800) >> 8);
luminances[luminanceIndex] = (byte)((RChannelWeight * r8 + GChannelWeight * g8 + BChannelWeight * b8) >> ChannelWeight);
}
}
private void CalculateLuminanceRGB24(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
int r = rgbRawBytes[rgbIndex++];
int g = rgbRawBytes[rgbIndex++];
int b = rgbRawBytes[rgbIndex++];
luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
}
}
private void CalculateLuminanceBGR24(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
int b = rgbRawBytes[rgbIndex++];
int g = rgbRawBytes[rgbIndex++];
int r = rgbRawBytes[rgbIndex++];
luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
}
}
private void CalculateLuminanceRGB32(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
int r = rgbRawBytes[rgbIndex++];
int g = rgbRawBytes[rgbIndex++];
int b = rgbRawBytes[rgbIndex++];
rgbIndex++;
luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
}
}
private void CalculateLuminanceBGR32(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
int b = rgbRawBytes[rgbIndex++];
int g = rgbRawBytes[rgbIndex++];
int r = rgbRawBytes[rgbIndex++];
rgbIndex++;
luminances[luminanceIndex] = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
}
}
private void CalculateLuminanceBGRA32(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
var b = rgbRawBytes[rgbIndex++];
var g = rgbRawBytes[rgbIndex++];
var r = rgbRawBytes[rgbIndex++];
var alpha = rgbRawBytes[rgbIndex++];
var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8));
}
}
private void CalculateLuminanceRGBA32(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
var r = rgbRawBytes[rgbIndex++];
var g = rgbRawBytes[rgbIndex++];
var b = rgbRawBytes[rgbIndex++];
var alpha = rgbRawBytes[rgbIndex++];
var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8));
}
}
private void CalculateLuminanceARGB32(byte[] rgbRawBytes)
{
for (int rgbIndex = 0, luminanceIndex = 0; rgbIndex < rgbRawBytes.Length && luminanceIndex < luminances.Length; luminanceIndex++)
{
// Calculate luminance cheaply, favoring green.
var alpha = rgbRawBytes[rgbIndex++];
var r = rgbRawBytes[rgbIndex++];
var g = rgbRawBytes[rgbIndex++];
var b = rgbRawBytes[rgbIndex++];
var luminance = (byte)((RChannelWeight * r + GChannelWeight * g + BChannelWeight * b) >> ChannelWeight);
luminances[luminanceIndex] = (byte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8));
}
}
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
namespace ZXing
{
/// <summary>
/// Implementations of this interface can decode an image of a barcode in some format into
/// the String it encodes. For example, <see cref="ZXing.QrCode.QRCodeReader" /> can
/// decode a QR code. The decoder may optionally receive hints from the caller which may help
/// it decode more quickly or accurately.
///
/// See <see cref="MultiFormatReader" />, which attempts to determine what barcode
/// format is present within the image as well, and then decodes it accordingly.
/// </summary>
/// <author>Sean Owen</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public interface Reader
{
/// <summary>
/// Locates and decodes a barcode in some format within an image.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <returns>String which the barcode encodes</returns>
Result decode(BinaryBitmap image);
/// <summary> Locates and decodes a barcode in some format within an image. This method also accepts
/// hints, each possibly associated to some data, which may help the implementation decode.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}" /> from <see cref="DecodeHintType" />
/// to arbitrary data. The
/// meaning of the data depends upon the hint type. The implementation may or may not do
/// anything with these hints.
/// </param>
/// <returns>String which the barcode encodes</returns>
Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints);
/// <summary>
/// Resets any internal state the implementation has after a decode, to prepare it
/// for reuse.
/// </summary>
void reset();
}
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// The general exception class throw when something goes wrong during decoding of a barcode.
/// This includes, but is not limited to, failing checksums / error correction algorithms, being
/// unable to locate finder timing patterns, and so on.
/// </summary>
/// <author>Sean Owen</author>
public class ReaderException : Exception
{
/// <summary>
/// Gets the instance.
/// </summary>
public static ReaderException Instance
{
get
{
return new ReaderException();
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ReaderException"/> class.
/// </summary>
protected ReaderException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ReaderException"/> class.
/// </summary>
/// <param name="innerException">The inner exception.</param>
protected ReaderException(Exception innerException)
: base(innerException.Message, innerException)
{
}
}
}

View File

@@ -1,161 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing
{
/// <summary>
/// Encapsulates the result of decoding a barcode within an image.
/// </summary>
public sealed class Result
{
/// <returns>raw text encoded by the barcode, if applicable, otherwise <code>null</code></returns>
public String Text { get; private set; }
/// <returns>raw bytes encoded by the barcode, if applicable, otherwise <code>null</code></returns>
public byte[] RawBytes { get; private set; }
/// <returns>
/// points related to the barcode in the image. These are typically points
/// identifying finder patterns or the corners of the barcode. The exact meaning is
/// specific to the type of barcode that was decoded.
/// </returns>
public ResultPoint[] ResultPoints { get; private set; }
/// <returns>{@link BarcodeFormat} representing the format of the barcode that was decoded</returns>
public BarcodeFormat BarcodeFormat { get; private set; }
/// <returns>
/// {@link Hashtable} mapping {@link ResultMetadataType} keys to values. May be
/// <code>null</code>. This contains optional metadata about what was detected about the barcode,
/// like orientation.
/// </returns>
public IDictionary<ResultMetadataType, object> ResultMetadata { get; private set; }
/// <summary>
/// Gets the timestamp.
/// </summary>
public long Timestamp { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="Result"/> class.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="rawBytes">The raw bytes.</param>
/// <param name="resultPoints">The result points.</param>
/// <param name="format">The format.</param>
public Result(String text,
byte[] rawBytes,
ResultPoint[] resultPoints,
BarcodeFormat format)
: this(text, rawBytes, resultPoints, format, DateTime.Now.Ticks)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Result"/> class.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="rawBytes">The raw bytes.</param>
/// <param name="resultPoints">The result points.</param>
/// <param name="format">The format.</param>
/// <param name="timestamp">The timestamp.</param>
public Result(String text, byte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format, long timestamp)
{
if (text == null && rawBytes == null)
{
throw new ArgumentException("Text and bytes are null");
}
Text = text;
RawBytes = rawBytes;
ResultPoints = resultPoints;
BarcodeFormat = format;
ResultMetadata = null;
Timestamp = timestamp;
}
/// <summary>
/// Adds one metadata to the result
/// </summary>
/// <param name="type">The type.</param>
/// <param name="value">The value.</param>
public void putMetadata(ResultMetadataType type, Object value)
{
if (ResultMetadata == null)
{
ResultMetadata = new Dictionary<ResultMetadataType, object>();
}
ResultMetadata[type] = value;
}
/// <summary>
/// Adds a list of metadata to the result
/// </summary>
/// <param name="metadata">The metadata.</param>
public void putAllMetadata(IDictionary<ResultMetadataType, object> metadata)
{
if (metadata != null)
{
if (ResultMetadata == null)
{
ResultMetadata = metadata;
}
else
{
foreach (var entry in metadata)
ResultMetadata[entry.Key] = entry.Value;
}
}
}
/// <summary>
/// Adds the result points.
/// </summary>
/// <param name="newPoints">The new points.</param>
public void addResultPoints(ResultPoint[] newPoints)
{
var oldPoints = ResultPoints;
if (oldPoints == null)
{
ResultPoints = newPoints;
}
else if (newPoints != null && newPoints.Length > 0)
{
var allPoints = new ResultPoint[oldPoints.Length + newPoints.Length];
Array.Copy(oldPoints, 0, allPoints, 0, oldPoints.Length);
Array.Copy(newPoints, 0, allPoints, oldPoints.Length, newPoints.Length);
ResultPoints = allPoints;
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
if (Text == null)
{
return "[" + RawBytes.Length + " bytes]";
}
return Text;
}
}
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary>
/// Represents some type of metadata about the result of the decoding that the decoder
/// wishes to communicate back to the caller.
/// </summary>
/// <author>Sean Owen</author>
public enum ResultMetadataType
{
/// <summary>
/// Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
/// </summary>
OTHER,
/// <summary>
/// Denotes the likely approximate orientation of the barcode in the image. This value
/// is given as degrees rotated clockwise from the normal, upright orientation.
/// For example a 1D barcode which was found by reading top-to-bottom would be
/// said to have orientation "90". This key maps to an {@link Integer} whose
/// value is in the range [0,360).
/// </summary>
ORIENTATION,
/// <summary>
/// <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode'
/// which is sometimes used to encode binary data. While {@link Result} makes available
/// the complete raw bytes in the barcode for these formats, it does not offer the bytes
/// from the byte segments alone.</p>
/// <p>This maps to a {@link java.util.List} of byte arrays corresponding to the
/// raw bytes in the byte segments in the barcode, in order.</p>
/// </summary>
BYTE_SEGMENTS,
/// <summary>
/// Error correction level used, if applicable. The value type depends on the
/// format, but is typically a String.
/// </summary>
ERROR_CORRECTION_LEVEL,
/// <summary>
/// For some periodicals, indicates the issue number as an {@link Integer}.
/// </summary>
ISSUE_NUMBER,
/// <summary>
/// For some products, indicates the suggested retail price in the barcode as a
/// formatted {@link String}.
/// </summary>
SUGGESTED_PRICE,
/// <summary>
/// For some products, the possible country of manufacture as a {@link String} denoting the
/// ISO country code. Some map to multiple possible countries, like "US/CA".
/// </summary>
POSSIBLE_COUNTRY,
/// <summary>
/// For some products, the extension text
/// </summary>
UPC_EAN_EXTENSION,
/// <summary>
/// If the code format supports structured append and
/// the current scanned code is part of one then the
/// sequence number is given with it.
/// </summary>
STRUCTURED_APPEND_SEQUENCE,
/// <summary>
/// If the code format supports structured append and
/// the current scanned code is part of one then the
/// parity is given with it.
/// </summary>
STRUCTURED_APPEND_PARITY,
/// <summary>
/// PDF417-specific metadata
/// </summary>
PDF417_EXTRA_METADATA,
/// <summary>
/// Aztec-specific metadata
/// </summary>
AZTEC_EXTRA_METADATA
}
}

View File

@@ -1,196 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common.Detector;
namespace ZXing
{
/// <summary>
/// Encapsulates a point of interest in an image containing a barcode. Typically, this
/// would be the location of a finder pattern or the corner of the barcode, for example.
/// </summary>
/// <author>Sean Owen</author>
public class ResultPoint
{
private readonly float x;
private readonly float y;
private readonly byte[] bytesX;
private readonly byte[] bytesY;
private String toString;
/// <summary>
/// Initializes a new instance of the <see cref="ResultPoint"/> class.
/// </summary>
public ResultPoint()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ResultPoint"/> class.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
public ResultPoint(float x, float y)
{
this.x = x;
this.y = y;
// calculate only once for GetHashCode
bytesX = BitConverter.GetBytes(x);
bytesY = BitConverter.GetBytes(y);
}
/// <summary>
/// Gets the X.
/// </summary>
virtual public float X
{
get
{
return x;
}
}
/// <summary>
/// Gets the Y.
/// </summary>
virtual public float Y
{
get
{
return y;
}
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="other">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Object other)
{
var otherPoint = other as ResultPoint;
if (otherPoint == null)
return false;
return x == otherPoint.x && y == otherPoint.y;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
return 31 * ((bytesX[0] << 24) + (bytesX[1] << 16) + (bytesX[2] << 8) + bytesX[3]) +
(bytesY[0] << 24) + (bytesY[1] << 16) + (bytesY[2] << 8) + bytesY[3];
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
if (toString == null)
{
var result = new System.Text.StringBuilder(25);
result.AppendFormat(System.Globalization.CultureInfo.CurrentUICulture, "({0}, {1})", x, y);
toString = result.ToString();
}
return toString;
}
/// <summary>
/// Orders an array of three ResultPoints in an order [A,B,C] such that AB is less than AC and
/// BC is less than AC and the angle between BC and BA is less than 180 degrees.
/// </summary>
/// <param name="patterns">array of three <see cref="ResultPoint" /> to order</param>
public static void orderBestPatterns(ResultPoint[] patterns)
{
// Find distances between pattern centers
float zeroOneDistance = distance(patterns[0], patterns[1]);
float oneTwoDistance = distance(patterns[1], patterns[2]);
float zeroTwoDistance = distance(patterns[0], patterns[2]);
ResultPoint pointA, pointB, pointC;
// Assume one closest to other two is B; A and C will just be guesses at first
if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance)
{
pointB = patterns[0];
pointA = patterns[1];
pointC = patterns[2];
}
else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance)
{
pointB = patterns[1];
pointA = patterns[0];
pointC = patterns[2];
}
else
{
pointB = patterns[2];
pointA = patterns[0];
pointC = patterns[1];
}
// Use cross product to figure out whether A and C are correct or flipped.
// This asks whether BC x BA has a positive z component, which is the arrangement
// we want for A, B, C. If it's negative, then we've got it flipped around and
// should swap A and C.
if (crossProductZ(pointA, pointB, pointC) < 0.0f)
{
ResultPoint temp = pointA;
pointA = pointC;
pointC = temp;
}
patterns[0] = pointA;
patterns[1] = pointB;
patterns[2] = pointC;
}
/// <summary>
/// calculates the distance between two points
/// </summary>
/// <param name="pattern1">first pattern</param>
/// <param name="pattern2">second pattern</param>
/// <returns>
/// distance between two points
/// </returns>
public static float distance(ResultPoint pattern1, ResultPoint pattern2)
{
return MathUtils.distance(pattern1.x, pattern1.y, pattern2.x, pattern2.y);
}
/// <summary>
/// Returns the z component of the cross product between vectors BC and BA.
/// </summary>
private static float crossProductZ(ResultPoint pointA, ResultPoint pointB, ResultPoint pointC)
{
float bX = pointB.x;
float bY = pointB.y;
return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
}
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing
{
/// <summary> Callback which is invoked when a possible result point (significant
/// point in the barcode image such as a corner) is found.
///
/// </summary>
/// <seealso cref="DecodeHintType.NEED_RESULT_POINT_CALLBACK">
/// </seealso>
public delegate void ResultPointCallback(ResultPoint point);
}

View File

@@ -1,175 +0,0 @@
//
// In order to convert some functionality to Visual C#, the Java Language Conversion Assistant
// creates "support classes" that duplicate the original functionality.
//
// Support classes replicate the functionality of the original code, but in some cases they are
// substantially different architecturally. Although every effort is made to preserve the
// original architecture of the application in the converted project, the user should be aware that
// the primary goal of these support classes is to replicate functionality, and that at times
// the architecture of the resulting solution may differ somewhat.
//
using System;
using System.Collections.Generic;
using System.Text;
namespace ZXing
{
/// <summary>
/// Contains conversion support elements such as classes, interfaces and static methods.
/// </summary>
public static class SupportClass
{
/*******************************/
/// <summary>
/// Copies an array of chars obtained from a String into a specified array of chars
/// </summary>
/// <param name="sourceString">The String to get the chars from</param>
/// <param name="sourceStart">Position of the String to start getting the chars</param>
/// <param name="sourceEnd">Position of the String to end getting the chars</param>
/// <param name="destinationArray">Array to return the chars</param>
/// <param name="destinationStart">Position of the destination array of chars to start storing the chars</param>
/// <returns>An array of chars</returns>
public static void GetCharsFromString(System.String sourceString, int sourceStart, int sourceEnd, char[] destinationArray, int destinationStart)
{
int sourceCounter = sourceStart;
int destinationCounter = destinationStart;
while (sourceCounter < sourceEnd)
{
destinationArray[destinationCounter] = (char)sourceString[sourceCounter];
sourceCounter++;
destinationCounter++;
}
}
/*******************************/
/// <summary>
/// Sets the capacity for the specified List
/// </summary>
/// <param name="vector">The List which capacity will be set</param>
/// <param name="newCapacity">The new capacity value</param>
public static void SetCapacity<T>(System.Collections.Generic.IList<T> vector, int newCapacity) where T : new()
{
while (newCapacity > vector.Count)
vector.Add(new T());
while (newCapacity < vector.Count)
vector.RemoveAt(vector.Count - 1);
}
/// <summary>
/// Converts a string-Collection to an array
/// </summary>
/// <param name="strings">The strings.</param>
/// <returns></returns>
public static String[] toStringArray(ICollection<string> strings)
{
var result = new String[strings.Count];
strings.CopyTo(result, 0);
return result;
}
/// <summary>
/// Joins all elements to one string.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="separator">The separator.</param>
/// <param name="values">The values.</param>
/// <returns></returns>
public static string Join<T>(string separator, IEnumerable<T> values)
{
var builder = new StringBuilder();
separator = separator ?? String.Empty;
if (values != null)
{
foreach (var value in values)
{
builder.Append(value);
builder.Append(separator);
}
if (builder.Length > 0)
builder.Length -= separator.Length;
}
return builder.ToString();
}
/// <summary>
/// Fills the specified array.
/// (can't use extension method because of .Net 2.0 support)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array">The array.</param>
/// <param name="value">The value.</param>
public static void Fill<T>(T[] array, T value)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = value;
}
}
/// <summary>
/// Fills the specified array.
/// (can't use extension method because of .Net 2.0 support)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array">The array.</param>
/// <param name="startIndex">The start index.</param>
/// <param name="endIndex">The end index.</param>
/// <param name="value">The value.</param>
public static void Fill<T>(T[] array, int startIndex, int endIndex, T value)
{
for (int i = startIndex; i < endIndex; i++)
{
array[i] = value;
}
}
public static string ToBinaryString(int x)
{
char[] bits = new char[32];
int i = 0;
while (x != 0)
{
bits[i++] = (x & 1) == 1 ? '1' : '0';
x >>= 1;
}
Array.Reverse(bits, 0, i);
return new string(bits);
}
public static int bitCount(int n)
{
int ret = 0;
while (n != 0)
{
n &= (n - 1);
ret++;
}
return ret;
}
/// <summary>
/// Savely gets the value of a decoding hint
/// if hints is null the default is returned
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="hints">The hints.</param>
/// <param name="hintType">Type of the hint.</param>
/// <param name="default">The @default.</param>
/// <returns></returns>
public static T GetValue<T>(IDictionary<DecodeHintType, object> hints, DecodeHintType hintType, T @default)
{
// can't use extension method because of .Net 2.0 support
if (hints == null)
return @default;
if (!hints.ContainsKey(hintType))
return @default;
return (T)hints[hintType];
}
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing
{
/// <summary> The base class for all objects which encode/generate a barcode image.
///
/// </summary>
/// <author> dswitkin@google.com (Daniel Switkin)
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public interface Writer
{
/// <summary>
/// Encode a barcode using the default settings.
/// </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <returns> The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)</returns>
BitMatrix encode(System.String contents, BarcodeFormat format, int width, int height);
/// <summary> </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <param name="hints">Additional parameters to supply to the encoder</param>
/// <returns> The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)</returns>
BitMatrix encode(String contents, BarcodeFormat format, int width, int height, IDictionary<EncodeHintType, object> hints);
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing
{
/// <summary>
/// A base class which covers the range of exceptions which may occur when encoding a barcode using
/// the Writer framework.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed class WriterException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="WriterException"/> class.
/// </summary>
public WriterException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WriterException"/> class.
/// </summary>
/// <param name="message">The message.</param>
public WriterException(String message)
:base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WriterException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="innerExc">The inner exc.</param>
public WriterException(String message, Exception innerExc)
: base(message, innerExc)
{
}
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// The class contains all information about the Aztec code which was found
/// </summary>
public class AztecDetectorResult : DetectorResult
{
/// <summary>
/// Gets a value indicating whether this Aztec code is compact.
/// </summary>
/// <value>
/// <c>true</c> if compact; otherwise, <c>false</c>.
/// </value>
public bool Compact { get; private set; }
/// <summary>
/// Gets the nb datablocks.
/// </summary>
public int NbDatablocks { get; private set; }
/// <summary>
/// Gets the nb layers.
/// </summary>
public int NbLayers { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="AztecDetectorResult"/> class.
/// </summary>
/// <param name="bits">The bits.</param>
/// <param name="points">The points.</param>
/// <param name="compact">if set to <c>true</c> [compact].</param>
/// <param name="nbDatablocks">The nb datablocks.</param>
/// <param name="nbLayers">The nb layers.</param>
public AztecDetectorResult(BitMatrix bits,
ResultPoint[] points,
bool compact,
int nbDatablocks,
int nbLayers)
: base(bits, points)
{
Compact = compact;
NbDatablocks = nbDatablocks;
NbLayers = nbLayers;
}
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Aztec.Internal;
namespace ZXing.Aztec
{
/// <summary>
/// This implementation can detect and decode Aztec codes in an image.
/// </summary>
/// <author>David Olivier</author>
public class AztecReader : Reader
{
/// <summary>
/// Locates and decodes a barcode in some format within an image.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <returns>
/// a String representing the content encoded by the Data Matrix code
/// </returns>
public Result decode(BinaryBitmap image)
{
return decode(image, null);
}
/// <summary>
/// Locates and decodes a Data Matrix code in an image.
/// </summary>
/// <param name="image">image of barcode to decode</param>
/// <param name="hints">passed as a {@link java.util.Hashtable} from {@link com.google.zxing.DecodeHintType}
/// to arbitrary data. The
/// meaning of the data depends upon the hint type. The implementation may or may not do
/// anything with these hints.</param>
/// <returns>
/// String which the barcode encodes
/// </returns>
public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints)
{
var blackmatrix = image.BlackMatrix;
if (blackmatrix == null)
return null;
Detector detector = new Detector(blackmatrix);
ResultPoint[] points = null;
DecoderResult decoderResult = null;
var detectorResult = detector.detect(false);
if (detectorResult != null)
{
points = detectorResult.Points;
decoderResult = new Decoder().decode(detectorResult);
}
if (decoderResult == null)
{
detectorResult = detector.detect(true);
if (detectorResult == null)
return null;
points = detectorResult.Points;
decoderResult = new Decoder().decode(detectorResult);
if (decoderResult == null)
return null;
}
if (hints != null &&
hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK))
{
var rpcb = (ResultPointCallback)hints[DecodeHintType.NEED_RESULT_POINT_CALLBACK];
if (rpcb != null)
{
foreach (var point in points)
{
rpcb(point);
}
}
}
var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.AZTEC);
IList<byte[]> byteSegments = decoderResult.ByteSegments;
if (byteSegments != null)
{
result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
}
var ecLevel = decoderResult.ECLevel;
if (ecLevel != null)
{
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
}
result.putMetadata(ResultMetadataType.AZTEC_EXTRA_METADATA,
new AztecResultMetadata(detectorResult.Compact, detectorResult.NbDatablocks, detectorResult.NbLayers));
return result;
}
/// <summary>
/// Resets any internal state the implementation has after a decode, to prepare it
/// for reuse.
/// </summary>
public void reset()
{
// do nothing
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Aztec
{
/// <summary>
/// Aztec result meta data.
/// </summary>
public sealed class AztecResultMetadata
{
/// <summary>
/// Gets a value indicating whether this Aztec code is compact.
/// </summary>
/// <value>
/// <c>true</c> if compact; otherwise, <c>false</c>.
/// </value>
public bool Compact { get; private set; }
/// <summary>
/// Gets the nb datablocks.
/// </summary>
public int Datablocks { get; private set; }
/// <summary>
/// Gets the nb layers.
/// </summary>
public int Layers { get; private set; }
/// <summary>
///
/// </summary>
/// <param name="compact"></param>
/// <param name="datablocks"></param>
/// <param name="layers"></param>
public AztecResultMetadata(bool compact, int datablocks, int layers)
{
Compact = compact;
Datablocks = datablocks;
Layers = layers;
}
}
}

View File

@@ -1,164 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using ZXing.Aztec.Internal;
using ZXing.Common;
namespace ZXing.Aztec
{
/// <summary>
/// Generates Aztec 2D barcodes.
/// </summary>
public sealed class AztecWriter : Writer
{
private static readonly Encoding DEFAULT_CHARSET;
static AztecWriter()
{
#if !(WindowsCE || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE)
DEFAULT_CHARSET = Encoding.GetEncoding("ISO-8859-1");
#elif WindowsCE
try
{
DEFAULT_CHARSET = Encoding.GetEncoding("ISO-8859-1");
}
catch (PlatformNotSupportedException)
{
DEFAULT_CHARSET = Encoding.GetEncoding(1252);
}
#else
// not fully correct but what else
DEFAULT_CHARSET = Encoding.GetEncoding("UTF-8");
#endif
}
/// <summary>
/// Encode a barcode using the default settings.
/// </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <returns>
/// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
/// </returns>
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
{
return encode(contents, format, width, height, null);
}
/// <summary>
/// </summary>
/// <param name="contents">The contents to encode in the barcode</param>
/// <param name="format">The barcode format to generate</param>
/// <param name="width">The preferred width in pixels</param>
/// <param name="height">The preferred height in pixels</param>
/// <param name="hints">Additional parameters to supply to the encoder</param>
/// <returns>
/// The generated barcode as a Matrix of unsigned bytes (0 == black, 255 == white)
/// </returns>
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, IDictionary<EncodeHintType, object> hints)
{
var charset = DEFAULT_CHARSET;
int eccPercent = Internal.Encoder.DEFAULT_EC_PERCENT;
int layers = Internal.Encoder.DEFAULT_AZTEC_LAYERS;
if (hints != null)
{
if (hints.ContainsKey(EncodeHintType.CHARACTER_SET))
{
object charsetname = hints[EncodeHintType.CHARACTER_SET];
if (charsetname != null)
{
charset = Encoding.GetEncoding(charsetname.ToString());
}
}
if (hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
{
object eccPercentObject = hints[EncodeHintType.ERROR_CORRECTION];
if (eccPercentObject != null)
{
eccPercent = Convert.ToInt32(eccPercentObject);
}
}
if (hints.ContainsKey(EncodeHintType.AZTEC_LAYERS))
{
object layersObject = hints[EncodeHintType.AZTEC_LAYERS];
if (layersObject != null)
{
layers = Convert.ToInt32(layersObject);
}
}
}
return encode(contents,
format,
width,
height,
charset,
eccPercent,
layers);
}
private static BitMatrix encode(String contents, BarcodeFormat format, int width, int height, Encoding charset, int eccPercent, int layers)
{
if (format != BarcodeFormat.AZTEC)
{
throw new ArgumentException("Can only encode AZTEC code, but got " + format);
}
var aztec = Internal.Encoder.encode(charset.GetBytes(contents), eccPercent, layers);
return renderResult(aztec, width, height);
}
private static BitMatrix renderResult(AztecCode code, int width, int height)
{
var input = code.Matrix;
if (input == null)
{
throw new InvalidOperationException("No input code matrix");
}
int inputWidth = input.Width;
int inputHeight = input.Height;
int outputWidth = Math.Max(width, inputWidth);
int outputHeight = Math.Max(height, inputHeight);
int multiple = Math.Min(outputWidth / inputWidth, outputHeight / inputHeight);
int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
int topPadding = (outputHeight - (inputHeight * multiple)) / 2;
var output = new BitMatrix(outputWidth, outputHeight);
for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple)
{
// Write the contents of this row of the barcode
for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple)
{
if (input[inputX, inputY])
{
output.setRegion(outputX, outputY, multiple, multiple);
}
}
}
return output;
}
}
}

View File

@@ -1,410 +0,0 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using ZXing.Common;
using ZXing.Common.ReedSolomon;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// The main class which implements Aztec Code decoding -- as opposed to locating and extracting
/// the Aztec Code from an image.
/// </summary>
/// <author>David Olivier</author>
public sealed class Decoder
{
private enum Table
{
UPPER,
LOWER,
MIXED,
DIGIT,
PUNCT,
BINARY
}
private static readonly String[] UPPER_TABLE =
{
"CTRL_PS", " ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "CTRL_LL", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
private static readonly String[] LOWER_TABLE =
{
"CTRL_PS", " ", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "CTRL_US", "CTRL_ML", "CTRL_DL", "CTRL_BS"
};
private static readonly String[] MIXED_TABLE =
{
"CTRL_PS", " ", "\x1", "\x2", "\x3", "\x4", "\x5", "\x6", "\x7", "\b", "\t", "\n",
"\xD", "\f", "\r", "\x21", "\x22", "\x23", "\x24", "\x25", "@", "\\", "^", "_",
"`", "|", "~", "\xB1", "CTRL_LL", "CTRL_UL", "CTRL_PL", "CTRL_BS"
};
private static readonly String[] PUNCT_TABLE =
{
"", "\r", "\r\n", ". ", ", ", ": ", "!", "\"", "#", "$", "%", "&", "'", "(", ")",
"*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}", "CTRL_UL"
};
private static readonly String[] DIGIT_TABLE =
{
"CTRL_PS", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ",", ".", "CTRL_UL", "CTRL_US"
};
private static readonly IDictionary<Table, String[]> codeTables = new Dictionary<Table, String[]>
{
{Table.UPPER, UPPER_TABLE},
{Table.LOWER, LOWER_TABLE},
{Table.MIXED, MIXED_TABLE},
{Table.PUNCT, PUNCT_TABLE},
{Table.DIGIT, DIGIT_TABLE},
{Table.BINARY, null}
};
private static readonly IDictionary<char, Table> codeTableMap = new Dictionary<char, Table>
{
{'U', Table.UPPER},
{'L', Table.LOWER},
{'M', Table.MIXED},
{'P', Table.PUNCT},
{'D', Table.DIGIT},
{'B', Table.BINARY}
};
private AztecDetectorResult ddata;
/// <summary>
/// Decodes the specified detector result.
/// </summary>
/// <param name="detectorResult">The detector result.</param>
/// <returns></returns>
public DecoderResult decode(AztecDetectorResult detectorResult)
{
ddata = detectorResult;
BitMatrix matrix = detectorResult.Bits;
bool[] rawbits = extractBits(matrix);
if (rawbits == null)
return null;
bool[] correctedBits = correctBits(rawbits);
if (correctedBits == null)
return null;
String result = getEncodedData(correctedBits);
if (result == null)
return null;
return new DecoderResult(null, result, null, null);
}
// This method is used for testing the high-level encoder
public static String highLevelDecode(bool[] correctedBits)
{
return getEncodedData(correctedBits);
}
/// <summary>
/// Gets the string encoded in the aztec code bits
/// </summary>
/// <param name="correctedBits">The corrected bits.</param>
/// <returns>the decoded string</returns>
private static String getEncodedData(bool[] correctedBits)
{
var endIndex = correctedBits.Length;
var latchTable = Table.UPPER; // table most recently latched to
var shiftTable = Table.UPPER; // table to use for the next read
var strTable = UPPER_TABLE;
var result = new StringBuilder(20);
var index = 0;
while (index < endIndex)
{
if (shiftTable == Table.BINARY)
{
if (endIndex - index < 5)
{
break;
}
int length = readCode(correctedBits, index, 5);
index += 5;
if (length == 0)
{
if (endIndex - index < 11)
{
break;
}
length = readCode(correctedBits, index, 11) + 31;
index += 11;
}
for (int charCount = 0; charCount < length; charCount++)
{
if (endIndex - index < 8)
{
index = endIndex; // Force outer loop to exit
break;
}
int code = readCode(correctedBits, index, 8);
result.Append((char) code);
index += 8;
}
// Go back to whatever mode we had been in
shiftTable = latchTable;
strTable = codeTables[shiftTable];
}
else
{
int size = shiftTable == Table.DIGIT ? 4 : 5;
if (endIndex - index < size)
{
break;
}
int code = readCode(correctedBits, index, size);
index += size;
String str = getCharacter(strTable, code);
if (str.StartsWith("CTRL_"))
{
// Table changes
shiftTable = getTable(str[5]);
strTable = codeTables[shiftTable];
if (str[6] == 'L')
{
latchTable = shiftTable;
}
}
else
{
result.Append(str);
// Go back to whatever mode we had been in
shiftTable = latchTable;
strTable = codeTables[shiftTable];
}
}
}
return result.ToString();
}
/// <summary>
/// gets the table corresponding to the char passed
/// </summary>
/// <param name="t">The t.</param>
/// <returns></returns>
private static Table getTable(char t)
{
if (!codeTableMap.ContainsKey(t))
return codeTableMap['U'];
return codeTableMap[t];
}
/// <summary>
/// Gets the character (or string) corresponding to the passed code in the given table
/// </summary>
/// <param name="table">the table used</param>
/// <param name="code">the code of the character</param>
/// <returns></returns>
private static String getCharacter(String[] table, int code)
{
return table[code];
}
/// <summary>
///Performs RS error correction on an array of bits.
/// </summary>
/// <param name="rawbits">The rawbits.</param>
/// <returns>the corrected array</returns>
private bool[] correctBits(bool[] rawbits)
{
GenericGF gf;
int codewordSize;
if (ddata.NbLayers <= 2)
{
codewordSize = 6;
gf = GenericGF.AZTEC_DATA_6;
}
else if (ddata.NbLayers <= 8)
{
codewordSize = 8;
gf = GenericGF.AZTEC_DATA_8;
}
else if (ddata.NbLayers <= 22)
{
codewordSize = 10;
gf = GenericGF.AZTEC_DATA_10;
}
else
{
codewordSize = 12;
gf = GenericGF.AZTEC_DATA_12;
}
int numDataCodewords = ddata.NbDatablocks;
int numCodewords = rawbits.Length/codewordSize;
if (numCodewords < numDataCodewords)
return null;
int offset = rawbits.Length % codewordSize;
int numECCodewords = numCodewords - numDataCodewords;
int[] dataWords = new int[numCodewords];
for (int i = 0; i < numCodewords; i++, offset += codewordSize)
{
dataWords[i] = readCode(rawbits, offset, codewordSize);
}
var rsDecoder = new ReedSolomonDecoder(gf);
if (!rsDecoder.decode(dataWords, numECCodewords))
return null;
// Now perform the unstuffing operation.
// First, count how many bits are going to be thrown out as stuffing
int mask = (1 << codewordSize) - 1;
int stuffedBits = 0;
for (int i = 0; i < numDataCodewords; i++)
{
int dataWord = dataWords[i];
if (dataWord == 0 || dataWord == mask)
{
return null;
}
else if (dataWord == 1 || dataWord == mask - 1)
{
stuffedBits++;
}
}
// Now, actually unpack the bits and remove the stuffing
bool[] correctedBits = new bool[numDataCodewords*codewordSize - stuffedBits];
int index = 0;
for (int i = 0; i < numDataCodewords; i++)
{
int dataWord = dataWords[i];
if (dataWord == 1 || dataWord == mask - 1)
{
// next codewordSize-1 bits are all zeros or all ones
SupportClass.Fill(correctedBits, index, index + codewordSize - 1, dataWord > 1);
index += codewordSize - 1;
}
else
{
for (int bit = codewordSize - 1; bit >= 0; --bit)
{
correctedBits[index++] = (dataWord & (1 << bit)) != 0;
}
}
}
if (index != correctedBits.Length)
return null;
return correctedBits;
}
/// <summary>
/// Gets the array of bits from an Aztec Code matrix
/// </summary>
/// <param name="matrix">The matrix.</param>
/// <returns>the array of bits</returns>
private bool[] extractBits(BitMatrix matrix)
{
bool compact = ddata.Compact;
int layers = ddata.NbLayers;
int baseMatrixSize = compact ? 11 + layers*4 : 14 + layers*4; // not including alignment lines
int[] alignmentMap = new int[baseMatrixSize];
bool[] rawbits = new bool[totalBitsInLayer(layers, compact)];
if (compact)
{
for (int i = 0; i < alignmentMap.Length; i++)
{
alignmentMap[i] = i;
}
}
else
{
int matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2 - 1)/15);
int origCenter = baseMatrixSize/2;
int center = matrixSize/2;
for (int i = 0; i < origCenter; i++)
{
int newOffset = i + i/15;
alignmentMap[origCenter - i - 1] = center - newOffset - 1;
alignmentMap[origCenter + i] = center + newOffset + 1;
}
}
for (int i = 0, rowOffset = 0; i < layers; i++)
{
int rowSize = compact ? (layers - i)*4 + 9 : (layers - i)*4 + 12;
// The top-left most point of this layer is <low, low> (not including alignment lines)
int low = i*2;
// The bottom-right most point of this layer is <high, high> (not including alignment lines)
int high = baseMatrixSize - 1 - low;
// We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows
for (int j = 0; j < rowSize; j++)
{
int columnOffset = j*2;
for (int k = 0; k < 2; k++)
{
// left column
rawbits[rowOffset + columnOffset + k] =
matrix[alignmentMap[low + k], alignmentMap[low + j]];
// bottom row
rawbits[rowOffset + 2*rowSize + columnOffset + k] =
matrix[alignmentMap[low + j], alignmentMap[high - k]];
// right column
rawbits[rowOffset + 4*rowSize + columnOffset + k] =
matrix[alignmentMap[high - k], alignmentMap[high - j]];
// top row
rawbits[rowOffset + 6*rowSize + columnOffset + k] =
matrix[alignmentMap[high - j], alignmentMap[low + k]];
}
}
rowOffset += rowSize*8;
}
return rawbits;
}
/// <summary>
/// Reads a code of given length and at given index in an array of bits
/// </summary>
/// <param name="rawbits">The rawbits.</param>
/// <param name="startIndex">The start index.</param>
/// <param name="length">The length.</param>
/// <returns></returns>
private static int readCode(bool[] rawbits, int startIndex, int length)
{
int res = 0;
for (int i = startIndex; i < startIndex + length; i++)
{
res <<= 1;
if (rawbits[i])
{
res++;
}
}
return res;
}
private static int totalBitsInLayer(int layers, bool compact)
{
return ((compact ? 88 : 112) + 16*layers)*layers;
}
}
}

View File

@@ -1,690 +0,0 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
using ZXing.Common.Detector;
using ZXing.Common.ReedSolomon;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code
/// is rotated or skewed, or partially obscured.
/// </summary>
/// <author>David Olivier</author>
public sealed class Detector
{
private readonly BitMatrix image;
private bool compact;
private int nbLayers;
private int nbDataBlocks;
private int nbCenterLayers;
private int shift;
/// <summary>
/// Initializes a new instance of the <see cref="Detector"/> class.
/// </summary>
/// <param name="image">The image.</param>
public Detector(BitMatrix image)
{
this.image = image;
}
/// <summary>
/// Detects an Aztec Code in an image.
/// </summary>
public AztecDetectorResult detect()
{
return detect(false);
}
/// <summary>
/// Detects an Aztec Code in an image.
/// </summary>
/// <param name="isMirror">if true, image is a mirror-image of original.</param>
/// <returns>
/// encapsulating results of detecting an Aztec Code
/// </returns>
public AztecDetectorResult detect(bool isMirror)
{
// 1. Get the center of the aztec matrix
var pCenter = getMatrixCenter();
if (pCenter == null)
return null;
// 2. Get the center points of the four diagonal points just outside the bull's eye
// [topRight, bottomRight, bottomLeft, topLeft]
var bullsEyeCorners = getBullsEyeCorners(pCenter);
if (bullsEyeCorners == null)
{
return null;
}
if (isMirror)
{
ResultPoint temp = bullsEyeCorners[0];
bullsEyeCorners[0] = bullsEyeCorners[2];
bullsEyeCorners[2] = temp;
}
// 3. Get the size of the matrix and other parameters from the bull's eye
if (!extractParameters(bullsEyeCorners))
{
return null;
}
// 4. Sample the grid
var bits = sampleGrid(image,
bullsEyeCorners[shift%4],
bullsEyeCorners[(shift + 1)%4],
bullsEyeCorners[(shift + 2)%4],
bullsEyeCorners[(shift + 3)%4]);
if (bits == null)
{
return null;
}
// 5. Get the corners of the matrix.
var corners = getMatrixCornerPoints(bullsEyeCorners);
if (corners == null)
{
return null;
}
return new AztecDetectorResult(bits, corners, compact, nbDataBlocks, nbLayers);
}
/// <summary>
/// Extracts the number of data layers and data blocks from the layer around the bull's eye
/// </summary>
/// <param name="bullsEyeCorners">bullEyeCornerPoints the array of bull's eye corners</param>
/// <returns></returns>
private bool extractParameters(ResultPoint[] bullsEyeCorners)
{
if (!isValid(bullsEyeCorners[0]) || !isValid(bullsEyeCorners[1]) ||
!isValid(bullsEyeCorners[2]) || !isValid(bullsEyeCorners[3]))
{
return false;
}
int length = 2 * nbCenterLayers;
// Get the bits around the bull's eye
int[] sides =
{
sampleLine(bullsEyeCorners[0], bullsEyeCorners[1], length), // Right side
sampleLine(bullsEyeCorners[1], bullsEyeCorners[2], length), // Bottom
sampleLine(bullsEyeCorners[2], bullsEyeCorners[3], length), // Left side
sampleLine(bullsEyeCorners[3], bullsEyeCorners[0], length) // Top
};
// bullsEyeCorners[shift] is the corner of the bulls'eye that has three
// orientation marks.
// sides[shift] is the row/column that goes from the corner with three
// orientation marks to the corner with two.
shift = getRotation(sides, length);
if (shift < 0)
return false;
// Flatten the parameter bits into a single 28- or 40-bit long
long parameterData = 0;
for (int i = 0; i < 4; i++)
{
int side = sides[(shift + i) % 4];
if (compact)
{
// Each side of the form ..XXXXXXX. where Xs are parameter data
parameterData <<= 7;
parameterData += (side >> 1) & 0x7F;
}
else
{
// Each side of the form ..XXXXX.XXXXX. where Xs are parameter data
parameterData <<= 10;
parameterData += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F);
}
}
// Corrects parameter data using RS. Returns just the data portion
// without the error correction.
int correctedData = getCorrectedParameterData(parameterData, compact);
if (correctedData < 0)
return false;
if (compact)
{
// 8 bits: 2 bits layers and 6 bits data blocks
nbLayers = (correctedData >> 6) + 1;
nbDataBlocks = (correctedData & 0x3F) + 1;
}
else
{
// 16 bits: 5 bits layers and 11 bits data blocks
nbLayers = (correctedData >> 11) + 1;
nbDataBlocks = (correctedData & 0x7FF) + 1;
}
return true;
}
private static readonly int[] EXPECTED_CORNER_BITS =
{
0xee0, // 07340 XXX .XX X.. ...
0x1dc, // 00734 ... XXX .XX X..
0x83b, // 04073 X.. ... XXX .XX
0x707, // 03407 .XX X.. ... XXX
};
private static int getRotation(int[] sides, int length)
{
// In a normal pattern, we expect to See
// ** .* D A
// * *
//
// . *
// .. .. C B
//
// Grab the 3 bits from each of the sides the form the locator pattern and concatenate
// into a 12-bit integer. Start with the bit at A
int cornerBits = 0;
foreach (int side in sides)
{
// XX......X where X's are orientation marks
int t = ((side >> (length - 2)) << 1) + (side & 1);
cornerBits = (cornerBits << 3) + t;
}
// Mov the bottom bit to the top, so that the three bits of the locator pattern at A are
// together. cornerBits is now:
// 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D
cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1);
// The result shift indicates which element of BullsEyeCorners[] goes into the top-left
// corner. Since the four rotation values have a Hamming distance of 8, we
// can easily tolerate two errors.
for (int shift = 0; shift < 4; shift++)
{
if (SupportClass.bitCount(cornerBits ^ EXPECTED_CORNER_BITS[shift]) <= 2)
{
return shift;
}
}
return -1;
}
/// <summary>
/// Corrects the parameter bits using Reed-Solomon algorithm
/// </summary>
/// <param name="parameterData">paremeter bits</param>
/// <param name="compact">compact true if this is a compact Aztec code</param>
/// <returns></returns>
private static int getCorrectedParameterData(long parameterData, bool compact)
{
int numCodewords;
int numDataCodewords;
if (compact)
{
numCodewords = 7;
numDataCodewords = 2;
}
else
{
numCodewords = 10;
numDataCodewords = 4;
}
int numECCodewords = numCodewords - numDataCodewords;
int[] parameterWords = new int[numCodewords];
for (int i = numCodewords - 1; i >= 0; --i)
{
parameterWords[i] = (int)parameterData & 0xF;
parameterData >>= 4;
}
var rsDecoder = new ReedSolomonDecoder(GenericGF.AZTEC_PARAM);
if (!rsDecoder.decode(parameterWords, numECCodewords))
return -1;
// Toss the error correction. Just return the data as an integer
int result = 0;
for (int i = 0; i < numDataCodewords; i++)
{
result = (result << 4) + parameterWords[i];
}
return result;
}
/// <summary>
/// Finds the corners of a bull-eye centered on the passed point
/// This returns the centers of the diagonal points just outside the bull's eye
/// Returns [topRight, bottomRight, bottomLeft, topLeft]
/// </summary>
/// <param name="pCenter">Center point</param>
/// <returns>The corners of the bull-eye</returns>
private ResultPoint[] getBullsEyeCorners(Point pCenter)
{
Point pina = pCenter;
Point pinb = pCenter;
Point pinc = pCenter;
Point pind = pCenter;
bool color = true;
for (nbCenterLayers = 1; nbCenterLayers < 9; nbCenterLayers++)
{
Point pouta = getFirstDifferent(pina, color, 1, -1);
Point poutb = getFirstDifferent(pinb, color, 1, 1);
Point poutc = getFirstDifferent(pinc, color, -1, 1);
Point poutd = getFirstDifferent(pind, color, -1, -1);
//d a
//
//c b
if (nbCenterLayers > 2)
{
float q = distance(poutd, pouta)*nbCenterLayers/(distance(pind, pina)*(nbCenterLayers + 2));
if (q < 0.75 || q > 1.25 || !isWhiteOrBlackRectangle(pouta, poutb, poutc, poutd))
{
break;
}
}
pina = pouta;
pinb = poutb;
pinc = poutc;
pind = poutd;
color = !color;
}
if (nbCenterLayers != 5 && nbCenterLayers != 7)
{
return null;
}
compact = nbCenterLayers == 5;
// Expand the square by .5 pixel in each direction so that we're on the border
// between the white square and the black square
var pinax = new ResultPoint(pina.X + 0.5f, pina.Y - 0.5f);
var pinbx = new ResultPoint(pinb.X + 0.5f, pinb.Y + 0.5f);
var pincx = new ResultPoint(pinc.X - 0.5f, pinc.Y + 0.5f);
var pindx = new ResultPoint(pind.X - 0.5f, pind.Y - 0.5f);
// Expand the square so that its corners are the centers of the points
// just outside the bull's eye.
return expandSquare(new[] {pinax, pinbx, pincx, pindx},
2*nbCenterLayers - 3,
2*nbCenterLayers);
}
/// <summary>
/// Finds a candidate center point of an Aztec code from an image
/// </summary>
/// <returns>the center point</returns>
private Point getMatrixCenter()
{
ResultPoint pointA;
ResultPoint pointB;
ResultPoint pointC;
ResultPoint pointD;
int cx;
int cy;
//Get a white rectangle that can be the border of the matrix in center bull's eye or
var whiteDetector = WhiteRectangleDetector.Create(image);
if (whiteDetector == null)
return null;
ResultPoint[] cornerPoints = whiteDetector.detect();
if (cornerPoints != null)
{
pointA = cornerPoints[0];
pointB = cornerPoints[1];
pointC = cornerPoints[2];
pointD = cornerPoints[3];
}
else
{
// This exception can be in case the initial rectangle is white
// In that case, surely in the bull's eye, we try to expand the rectangle.
cx = image.Width/2;
cy = image.Height/2;
pointA = getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
}
//Compute the center of the rectangle
cx = MathUtils.round((pointA.X + pointD.X + pointB.X + pointC.X) / 4.0f);
cy = MathUtils.round((pointA.Y + pointD.Y + pointB.Y + pointC.Y) / 4.0f);
// Redetermine the white rectangle starting from previously computed center.
// This will ensure that we end up with a white rectangle in center bull's eye
// in order to compute a more accurate center.
whiteDetector = WhiteRectangleDetector.Create(image, 15, cx, cy);
if (whiteDetector == null)
return null;
cornerPoints = whiteDetector.detect();
if (cornerPoints != null)
{
pointA = cornerPoints[0];
pointB = cornerPoints[1];
pointC = cornerPoints[2];
pointD = cornerPoints[3];
}
else
{
// This exception can be in case the initial rectangle is white
// In that case we try to expand the rectangle.
pointA = getFirstDifferent(new Point(cx + 7, cy - 7), false, 1, -1).toResultPoint();
pointB = getFirstDifferent(new Point(cx + 7, cy + 7), false, 1, 1).toResultPoint();
pointC = getFirstDifferent(new Point(cx - 7, cy + 7), false, -1, 1).toResultPoint();
pointD = getFirstDifferent(new Point(cx - 7, cy - 7), false, -1, -1).toResultPoint();
}
// Recompute the center of the rectangle
cx = MathUtils.round((pointA.X + pointD.X + pointB.X + pointC.X) / 4.0f);
cy = MathUtils.round((pointA.Y + pointD.Y + pointB.Y + pointC.Y) / 4.0f);
return new Point(cx, cy);
}
/// <summary>
/// Gets the Aztec code corners from the bull's eye corners and the parameters.
/// </summary>
/// <param name="bullsEyeCorners">the array of bull's eye corners</param>
/// <returns>the array of aztec code corners</returns>
private ResultPoint[] getMatrixCornerPoints(ResultPoint[] bullsEyeCorners)
{
return expandSquare(bullsEyeCorners, 2 * nbCenterLayers, getDimension());
}
/// <summary>
/// Creates a BitMatrix by sampling the provided image.
/// topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the
/// diagonal just outside the bull's eye.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="topLeft">The top left.</param>
/// <param name="bottomLeft">The bottom left.</param>
/// <param name="bottomRight">The bottom right.</param>
/// <param name="topRight">The top right.</param>
/// <returns></returns>
private BitMatrix sampleGrid(BitMatrix image,
ResultPoint topLeft,
ResultPoint topRight,
ResultPoint bottomRight,
ResultPoint bottomLeft)
{
GridSampler sampler = GridSampler.Instance;
int dimension = getDimension();
float low = dimension/2.0f - nbCenterLayers;
float high = dimension/2.0f + nbCenterLayers;
return sampler.sampleGrid(image,
dimension,
dimension,
low, low, // topleft
high, low, // topright
high, high, // bottomright
low, high, // bottomleft
topLeft.X, topLeft.Y,
topRight.X, topRight.Y,
bottomRight.X, bottomRight.Y,
bottomLeft.X, bottomLeft.Y);
}
/// <summary>
/// Samples a line
/// </summary>
/// <param name="p1">start point (inclusive)</param>
/// <param name="p2">end point (exclusive)</param>
/// <param name="size">number of bits</param>
/// <returns> the array of bits as an int (first bit is high-order bit of result)</returns>
private int sampleLine(ResultPoint p1, ResultPoint p2, int size)
{
int result = 0;
float d = distance(p1, p2);
float moduleSize = d / size;
float px = p1.X;
float py = p1.Y;
float dx = moduleSize * (p2.X - p1.X) / d;
float dy = moduleSize * (p2.Y - p1.Y) / d;
for (int i = 0; i < size; i++)
{
if (image[MathUtils.round(px + i * dx), MathUtils.round(py + i * dy)])
{
result |= 1 << (size - i - 1);
}
}
return result;
}
/// <summary>
/// Determines whether [is white or black rectangle] [the specified p1].
/// </summary>
/// <param name="p1">The p1.</param>
/// <param name="p2">The p2.</param>
/// <param name="p3">The p3.</param>
/// <param name="p4">The p4.</param>
/// <returns>true if the border of the rectangle passed in parameter is compound of white points only
/// or black points only</returns>
private bool isWhiteOrBlackRectangle(Point p1, Point p2, Point p3, Point p4)
{
const int corr = 3;
p1 = new Point(p1.X - corr, p1.Y + corr);
p2 = new Point(p2.X - corr, p2.Y - corr);
p3 = new Point(p3.X + corr, p3.Y - corr);
p4 = new Point(p4.X + corr, p4.Y + corr);
int cInit = getColor(p4, p1);
if (cInit == 0)
{
return false;
}
int c = getColor(p1, p2);
if (c != cInit)
{
return false;
}
c = getColor(p2, p3);
if (c != cInit)
{
return false;
}
c = getColor(p3, p4);
return c == cInit;
}
/// <summary>
/// Gets the color of a segment
/// </summary>
/// <param name="p1">The p1.</param>
/// <param name="p2">The p2.</param>
/// <returns>1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else</returns>
private int getColor(Point p1, Point p2)
{
float d = distance(p1, p2);
float dx = (p2.X - p1.X) / d;
float dy = (p2.Y - p1.Y) / d;
int error = 0;
float px = p1.X;
float py = p1.Y;
bool colorModel = image[p1.X, p1.Y];
for (int i = 0; i < d; i++)
{
px += dx;
py += dy;
if (image[MathUtils.round(px), MathUtils.round(py)] != colorModel)
{
error++;
}
}
float errRatio = error / d;
if (errRatio > 0.1f && errRatio < 0.9f)
{
return 0;
}
return (errRatio <= 0.1f) == colorModel ? 1 : -1;
}
/// <summary>
/// Gets the coordinate of the first point with a different color in the given direction
/// </summary>
/// <param name="init">The init.</param>
/// <param name="color">if set to <c>true</c> [color].</param>
/// <param name="dx">The dx.</param>
/// <param name="dy">The dy.</param>
/// <returns></returns>
private Point getFirstDifferent(Point init, bool color, int dx, int dy)
{
int x = init.X + dx;
int y = init.Y + dy;
while (isValid(x, y) && image[x, y] == color)
{
x += dx;
y += dy;
}
x -= dx;
y -= dy;
while (isValid(x, y) && image[x, y] == color)
{
x += dx;
}
x -= dx;
while (isValid(x, y) && image[x, y] == color)
{
y += dy;
}
y -= dy;
return new Point(x, y);
}
/// <summary>
/// Expand the square represented by the corner points by pushing out equally in all directions
/// </summary>
/// <param name="cornerPoints">the corners of the square, which has the bull's eye at its center</param>
/// <param name="oldSide">the original length of the side of the square in the target bit matrix</param>
/// <param name="newSide">the new length of the size of the square in the target bit matrix</param>
/// <returns>the corners of the expanded square</returns>
private static ResultPoint[] expandSquare(ResultPoint[] cornerPoints, float oldSide, float newSide)
{
float ratio = newSide/(2*oldSide);
float dx = cornerPoints[0].X - cornerPoints[2].X;
float dy = cornerPoints[0].Y - cornerPoints[2].Y;
float centerx = (cornerPoints[0].X + cornerPoints[2].X)/2.0f;
float centery = (cornerPoints[0].Y + cornerPoints[2].Y)/2.0f;
var result0 = new ResultPoint(centerx + ratio*dx, centery + ratio*dy);
var result2 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
dx = cornerPoints[1].X - cornerPoints[3].X;
dy = cornerPoints[1].Y - cornerPoints[3].Y;
centerx = (cornerPoints[1].X + cornerPoints[3].X)/2.0f;
centery = (cornerPoints[1].Y + cornerPoints[3].Y)/2.0f;
var result1 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy);
var result3 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy);
return new ResultPoint[] {result0, result1, result2, result3};
}
private bool isValid(int x, int y)
{
return x >= 0 && x < image.Width && y > 0 && y < image.Height;
}
private bool isValid(ResultPoint point)
{
int x = MathUtils.round(point.X);
int y = MathUtils.round(point.Y);
return isValid(x, y);
}
// L2 distance
private static float distance(Point a, Point b)
{
return MathUtils.distance(a.X, a.Y, b.X, b.Y);
}
private static float distance(ResultPoint a, ResultPoint b)
{
return MathUtils.distance(a.X, a.Y, b.X, b.Y);
}
private int getDimension()
{
if (compact)
{
return 4 * nbLayers + 11;
}
if (nbLayers <= 4)
{
return 4 * nbLayers + 15;
}
return 4 * nbLayers + 2 * ((nbLayers - 4) / 8 + 1) + 15;
}
internal sealed class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public ResultPoint toResultPoint()
{
return new ResultPoint(X, Y);
}
internal Point(int x, int y)
{
X = x;
Y = y;
}
public override String ToString()
{
return "<" + X + ' ' + Y + '>';
}
}
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// Aztec 2D code representation
/// </summary>
/// <author>Rustam Abdullaev</author>
public sealed class AztecCode
{
/// <summary>
/// Compact or full symbol indicator
/// </summary>
public bool isCompact { get; set; }
/// <summary>
/// Size in pixels (width and height)
/// </summary>
public int Size { get; set; }
/// <summary>
/// Number of levels
/// </summary>
public int Layers { get; set; }
/// <summary>
/// Number of data codewords
/// </summary>
public int CodeWords { get; set; }
/// <summary>
/// The symbol image
/// </summary>
public BitMatrix Matrix { get; set; }
}
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2013 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing.Aztec
{
/// <summary>
/// The class holds the available options for the <see cref="AztecWriter" />
/// </summary>
public class AztecEncodingOptions : EncodingOptions
{
/// <summary>
/// Representing the minimal percentage of error correction words.
/// Note: an Aztec symbol should have a minimum of 25% EC words.
/// </summary>
public int? ErrorCorrection
{
get
{
if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
{
return (int)Hints[EncodeHintType.ERROR_CORRECTION];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.ERROR_CORRECTION))
Hints.Remove(EncodeHintType.ERROR_CORRECTION);
}
else
{
Hints[EncodeHintType.ERROR_CORRECTION] = value;
}
}
}
/// <summary>
/// Specifies the required number of layers for an Aztec code:
/// a negative number (-1, -2, -3, -4) specifies a compact Aztec code
/// 0 indicates to use the minimum number of layers (the default)
/// a positive number (1, 2, .. 32) specifies a normal (non-compact) Aztec code
/// </summary>
public int? Layers
{
get
{
if (Hints.ContainsKey(EncodeHintType.AZTEC_LAYERS))
{
return (int)Hints[EncodeHintType.AZTEC_LAYERS];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.AZTEC_LAYERS))
Hints.Remove(EncodeHintType.AZTEC_LAYERS);
}
else
{
Hints[EncodeHintType.AZTEC_LAYERS] = value;
}
}
}
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
public sealed class BinaryShiftToken : Token
{
private readonly short binaryShiftStart;
private readonly short binaryShiftByteCount;
public BinaryShiftToken(Token previous,
int binaryShiftStart,
int binaryShiftByteCount)
: base(previous)
{
this.binaryShiftStart = (short) binaryShiftStart;
this.binaryShiftByteCount = (short) binaryShiftByteCount;
}
public override void appendTo(BitArray bitArray, byte[] text)
{
for (int i = 0; i < binaryShiftByteCount; i++)
{
if (i == 0 || (i == 31 && binaryShiftByteCount <= 62))
{
// We need a header before the first character, and before
// character 31 when the total byte code is <= 62
bitArray.appendBits(31, 5); // BINARY_SHIFT
if (binaryShiftByteCount > 62)
{
bitArray.appendBits(binaryShiftByteCount - 31, 16);
}
else if (i == 0)
{
// 1 <= binaryShiftByteCode <= 62
bitArray.appendBits(Math.Min(binaryShiftByteCount, (short) 31), 5);
}
else
{
// 32 <= binaryShiftCount <= 62 and i == 31
bitArray.appendBits(binaryShiftByteCount - 31, 5);
}
}
bitArray.appendBits(text[binaryShiftStart + i], 8);
}
}
public override String ToString()
{
return "<" + binaryShiftStart + "::" + (binaryShiftStart + binaryShiftByteCount - 1) + '>';
}
}
}

View File

@@ -1,428 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
using ZXing.Common.ReedSolomon;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// Generates Aztec 2D barcodes.
/// </summary>
/// <author>Rustam Abdullaev</author>
public static class Encoder
{
public const int DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words
public const int DEFAULT_AZTEC_LAYERS = 0;
private const int MAX_NB_BITS = 32;
private const int MAX_NB_BITS_COMPACT = 4;
private static readonly int[] WORD_SIZE = {
4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12
};
/// <summary>
/// Encodes the given binary content as an Aztec symbol
/// </summary>
/// <param name="data">input data string</param>
/// <returns>Aztec symbol matrix with metadata</returns>
public static AztecCode encode(byte[] data)
{
return encode(data, DEFAULT_EC_PERCENT, DEFAULT_AZTEC_LAYERS);
}
/// <summary>
/// Encodes the given binary content as an Aztec symbol
/// </summary>
/// <param name="data">input data string</param>
/// <param name="minECCPercent">minimal percentage of error check words (According to ISO/IEC 24778:2008,
/// a minimum of 23% + 3 words is recommended)</param>
/// <param name="userSpecifiedLayers">if non-zero, a user-specified value for the number of layers</param>
/// <returns>
/// Aztec symbol matrix with metadata
/// </returns>
public static AztecCode encode(byte[] data, int minECCPercent, int userSpecifiedLayers)
{
// High-level encode
var bits = new HighLevelEncoder(data).encode();
// stuff bits and choose symbol size
int eccBits = bits.Size*minECCPercent/100 + 11;
int totalSizeBits = bits.Size + eccBits;
bool compact;
int layers;
int totalBitsInLayer;
int wordSize;
BitArray stuffedBits;
if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS)
{
compact = userSpecifiedLayers < 0;
layers = Math.Abs(userSpecifiedLayers);
if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS))
{
throw new ArgumentException(
String.Format("Illegal value {0} for layers", userSpecifiedLayers));
}
totalBitsInLayer = TotalBitsInLayer(layers, compact);
wordSize = WORD_SIZE[layers];
int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
stuffedBits = stuffBits(bits, wordSize);
if (stuffedBits.Size + eccBits > usableBitsInLayers)
{
throw new ArgumentException("Data to large for user specified layer");
}
if (compact && stuffedBits.Size > wordSize*64)
{
// Compact format only allows 64 data words, though C4 can hold more words than that
throw new ArgumentException("Data to large for user specified layer");
}
}
else
{
wordSize = 0;
stuffedBits = null;
// We look at the possible table sizes in the order Compact1, Compact2, Compact3,
// Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1)
// is the same size, but has more data.
for (int i = 0;; i++)
{
if (i > MAX_NB_BITS)
{
throw new ArgumentException("Data too large for an Aztec code");
}
compact = i <= 3;
layers = compact ? i + 1 : i;
totalBitsInLayer = TotalBitsInLayer(layers, compact);
if (totalSizeBits > totalBitsInLayer)
{
continue;
}
// [Re]stuff the bits if this is the first opportunity, or if the
// wordSize has changed
if (wordSize != WORD_SIZE[layers])
{
wordSize = WORD_SIZE[layers];
stuffedBits = stuffBits(bits, wordSize);
}
if (stuffedBits == null)
{
continue;
}
int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
if (compact && stuffedBits.Size > wordSize*64)
{
// Compact format only allows 64 data words, though C4 can hold more words than that
continue;
}
if (stuffedBits.Size + eccBits <= usableBitsInLayers)
{
break;
}
}
}
BitArray messageBits = generateCheckWords(stuffedBits, totalBitsInLayer, wordSize);
// generate mode message
int messageSizeInWords = stuffedBits.Size / wordSize;
var modeMessage = generateModeMessage(compact, layers, messageSizeInWords);
// allocate symbol
var baseMatrixSize = compact ? 11 + layers*4 : 14 + layers*4; // not including alignment lines
var alignmentMap = new int[baseMatrixSize];
int matrixSize;
if (compact)
{
// no alignment marks in compact mode, alignmentMap is a no-op
matrixSize = baseMatrixSize;
for (int i = 0; i < alignmentMap.Length; i++)
{
alignmentMap[i] = i;
}
}
else
{
matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2 - 1)/15);
int origCenter = baseMatrixSize/2;
int center = matrixSize/2;
for (int i = 0; i < origCenter; i++)
{
int newOffset = i + i/15;
alignmentMap[origCenter - i - 1] = center - newOffset - 1;
alignmentMap[origCenter + i] = center + newOffset + 1;
}
}
var matrix = new BitMatrix(matrixSize);
// draw data bits
for (int i = 0, rowOffset = 0; i < layers; i++)
{
int rowSize = compact ? (layers - i)*4 + 9 : (layers - i)*4 + 12;
for (int j = 0; j < rowSize; j++)
{
int columnOffset = j*2;
for (int k = 0; k < 2; k++)
{
if (messageBits[rowOffset + columnOffset + k])
{
matrix[alignmentMap[i*2 + k], alignmentMap[i*2 + j]] = true;
}
if (messageBits[rowOffset + rowSize*2 + columnOffset + k])
{
matrix[alignmentMap[i*2 + j], alignmentMap[baseMatrixSize - 1 - i*2 - k]] = true;
}
if (messageBits[rowOffset + rowSize*4 + columnOffset + k])
{
matrix[alignmentMap[baseMatrixSize - 1 - i*2 - k], alignmentMap[baseMatrixSize - 1 - i*2 - j]] = true;
}
if (messageBits[rowOffset + rowSize*6 + columnOffset + k])
{
matrix[alignmentMap[baseMatrixSize - 1 - i*2 - j], alignmentMap[i*2 + k]] = true;
}
}
}
rowOffset += rowSize*8;
}
// draw mode message
drawModeMessage(matrix, compact, matrixSize, modeMessage);
// draw alignment marks
if (compact)
{
drawBullsEye(matrix, matrixSize/2, 5);
}
else
{
drawBullsEye(matrix, matrixSize/2, 7);
for (int i = 0, j = 0; i < baseMatrixSize/2 - 1; i += 15, j += 16)
{
for (int k = (matrixSize/2) & 1; k < matrixSize; k += 2)
{
matrix[matrixSize/2 - j, k] = true;
matrix[matrixSize/2 + j, k] = true;
matrix[k, matrixSize/2 - j] = true;
matrix[k, matrixSize/2 + j] = true;
}
}
}
return new AztecCode
{
isCompact = compact,
Size = matrixSize,
Layers = layers,
CodeWords = messageSizeInWords,
Matrix = matrix
};
}
private static void drawBullsEye(BitMatrix matrix, int center, int size)
{
for (var i = 0; i < size; i += 2)
{
for (var j = center - i; j <= center + i; j++)
{
matrix[j, center - i] = true;
matrix[j, center + i] = true;
matrix[center - i, j] = true;
matrix[center + i, j] = true;
}
}
matrix[center - size, center - size] = true;
matrix[center - size + 1, center - size] = true;
matrix[center - size, center - size + 1] = true;
matrix[center + size, center - size] = true;
matrix[center + size, center - size + 1] = true;
matrix[center + size, center + size - 1] = true;
}
internal static BitArray generateModeMessage(bool compact, int layers, int messageSizeInWords)
{
var modeMessage = new BitArray();
if (compact)
{
modeMessage.appendBits(layers - 1, 2);
modeMessage.appendBits(messageSizeInWords - 1, 6);
modeMessage = generateCheckWords(modeMessage, 28, 4);
}
else
{
modeMessage.appendBits(layers - 1, 5);
modeMessage.appendBits(messageSizeInWords - 1, 11);
modeMessage = generateCheckWords(modeMessage, 40, 4);
}
return modeMessage;
}
private static void drawModeMessage(BitMatrix matrix, bool compact, int matrixSize, BitArray modeMessage)
{
int center = matrixSize / 2;
if (compact)
{
for (var i = 0; i < 7; i++)
{
int offset = center - 3 + i;
if (modeMessage[i])
{
matrix[offset, center - 5] = true;
}
if (modeMessage[i + 7])
{
matrix[center + 5, offset] = true;
}
if (modeMessage[20 - i])
{
matrix[offset, center + 5] = true;
}
if (modeMessage[27 - i])
{
matrix[center - 5, offset] = true;
}
}
}
else
{
for (var i = 0; i < 10; i++)
{
int offset = center - 5 + i + i / 5;
if (modeMessage[i])
{
matrix[offset, center - 7] = true;
}
if (modeMessage[i + 10])
{
matrix[center + 7, offset] = true;
}
if (modeMessage[29 - i])
{
matrix[offset, center + 7] = true;
}
if (modeMessage[39 - i])
{
matrix[center - 7, offset] = true;
}
}
}
}
private static BitArray generateCheckWords(BitArray bitArray, int totalBits, int wordSize)
{
if (bitArray.Size % wordSize != 0)
throw new InvalidOperationException("size of bit array is not a multiple of the word size");
// bitArray is guaranteed to be a multiple of the wordSize, so no padding needed
int messageSizeInWords = bitArray.Size / wordSize;
var rs = new ReedSolomonEncoder(getGF(wordSize));
var totalWords = totalBits / wordSize;
var messageWords = bitsToWords(bitArray, wordSize, totalWords);
rs.encode(messageWords, totalWords - messageSizeInWords);
var startPad = totalBits % wordSize;
var messageBits = new BitArray();
messageBits.appendBits(0, startPad);
foreach (var messageWord in messageWords)
{
messageBits.appendBits(messageWord, wordSize);
}
return messageBits;
}
private static int[] bitsToWords(BitArray stuffedBits, int wordSize, int totalWords)
{
var message = new int[totalWords];
int i;
int n;
for (i = 0, n = stuffedBits.Size / wordSize; i < n; i++)
{
int value = 0;
for (int j = 0; j < wordSize; j++)
{
value |= stuffedBits[i * wordSize + j] ? (1 << wordSize - j - 1) : 0;
}
message[i] = value;
}
return message;
}
private static GenericGF getGF(int wordSize)
{
switch (wordSize)
{
case 4:
return GenericGF.AZTEC_PARAM;
case 6:
return GenericGF.AZTEC_DATA_6;
case 8:
return GenericGF.AZTEC_DATA_8;
case 10:
return GenericGF.AZTEC_DATA_10;
case 12:
return GenericGF.AZTEC_DATA_12;
default:
return null;
}
}
internal static BitArray stuffBits(BitArray bits, int wordSize)
{
var @out = new BitArray();
int n = bits.Size;
int mask = (1 << wordSize) - 2;
for (int i = 0; i < n; i += wordSize)
{
int word = 0;
for (int j = 0; j < wordSize; j++)
{
if (i + j >= n || bits[i + j])
{
word |= 1 << (wordSize - 1 - j);
}
}
if ((word & mask) == mask)
{
@out.appendBits(word & mask, wordSize);
i--;
}
else if ((word & mask) == 0)
{
@out.appendBits(word | 1, wordSize);
i--;
}
else
{
@out.appendBits(word, wordSize);
}
}
return @out;
}
private static int TotalBitsInLayer(int layers, bool compact)
{
return ((compact ? 88 : 112) + 16 * layers) * layers;
}
}
}

View File

@@ -1,379 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// This produces nearly optimal encodings of text into the first-level of
/// encoding used by Aztec code.
/// It uses a dynamic algorithm. For each prefix of the string, it determines
/// a set of encodings that could lead to this prefix. We repeatedly add a
/// character and generate a new set of optimal encodings until we have read
/// through the entire input.
/// @author Frank Yellin
/// @author Rustam Abdullaev
/// </summary>
public sealed class HighLevelEncoder
{
internal static String[] MODE_NAMES = {"UPPER", "LOWER", "DIGIT", "MIXED", "PUNCT"};
internal const int MODE_UPPER = 0; // 5 bits
internal const int MODE_LOWER = 1; // 5 bits
internal const int MODE_DIGIT = 2; // 4 bits
internal const int MODE_MIXED = 3; // 5 bits
internal const int MODE_PUNCT = 4; // 5 bits
// The Latch Table shows, for each pair of Modes, the optimal method for
// getting from one mode to another. In the worst possible case, this can
// be up to 14 bits. In the best possible case, we are already there!
// The high half-word of each entry gives the number of bits.
// The low half-word of each entry are the actual bits necessary to change
internal static readonly int[][] LATCH_TABLE = new int[][]
{
new[]
{
0,
(5 << 16) + 28, // UPPER -> LOWER
(5 << 16) + 30, // UPPER -> DIGIT
(5 << 16) + 29, // UPPER -> MIXED
(10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT
},
new[]
{
(9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER
0,
(5 << 16) + 30, // LOWER -> DIGIT
(5 << 16) + 29, // LOWER -> MIXED
(10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT
},
new[]
{
(4 << 16) + 14, // DIGIT -> UPPER
(9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER
0,
(9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED
(14 << 16) + (14 << 10) + (29 << 5) + 30,
// DIGIT -> UPPER -> MIXED -> PUNCT
},
new[]
{
(5 << 16) + 29, // MIXED -> UPPER
(5 << 16) + 28, // MIXED -> LOWER
(10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT
0,
(5 << 16) + 30, // MIXED -> PUNCT
},
new[]
{
(5 << 16) + 31, // PUNCT -> UPPER
(10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER
(10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT
(10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED
0,
},
};
// A reverse mapping from [mode][char] to the encoding for that character
// in that mode. An entry of 0 indicates no mapping exists.
internal static readonly int[][] CHAR_MAP = new int[5][];
// A map showing the available shift codes. (The shifts to BINARY are not shown
internal static readonly int[][] SHIFT_TABLE = new int[6][]; // mode shift codes, per table
private readonly byte[] text;
static HighLevelEncoder()
{
CHAR_MAP[0] = new int[256];
CHAR_MAP[1] = new int[256];
CHAR_MAP[2] = new int[256];
CHAR_MAP[3] = new int[256];
CHAR_MAP[4] = new int[256];
SHIFT_TABLE[0] = new int[6];
SHIFT_TABLE[1] = new int[6];
SHIFT_TABLE[2] = new int[6];
SHIFT_TABLE[3] = new int[6];
SHIFT_TABLE[4] = new int[6];
SHIFT_TABLE[5] = new int[6];
CHAR_MAP[MODE_UPPER][' '] = 1;
for (int c = 'A'; c <= 'Z'; c++)
{
CHAR_MAP[MODE_UPPER][c] = c - 'A' + 2;
}
CHAR_MAP[MODE_LOWER][' '] = 1;
for (int c = 'a'; c <= 'z'; c++)
{
CHAR_MAP[MODE_LOWER][c] = c - 'a' + 2;
}
CHAR_MAP[MODE_DIGIT][' '] = 1;
for (int c = '0'; c <= '9'; c++)
{
CHAR_MAP[MODE_DIGIT][c] = c - '0' + 2;
}
CHAR_MAP[MODE_DIGIT][','] = 12;
CHAR_MAP[MODE_DIGIT]['.'] = 13;
int[] mixedTable = {
'\0', ' ', 1, 2, 3, 4, 5, 6, 7, '\b', '\t', '\n', 11, '\f', '\r',
27, 28, 29, 30, 31, '@', '\\', '^', '_', '`', '|', '~', 127
};
for (int i = 0; i < mixedTable.Length; i++)
{
CHAR_MAP[MODE_MIXED][mixedTable[i]] = i;
}
int[] punctTable =
{
'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?',
'[', ']', '{', '}'
};
for (int i = 0; i < punctTable.Length; i++)
{
if (punctTable[i] > 0)
{
CHAR_MAP[MODE_PUNCT][punctTable[i]] = i;
}
}
foreach (int[] table in SHIFT_TABLE)
{
SupportClass.Fill(table, -1);
}
SHIFT_TABLE[MODE_UPPER][MODE_PUNCT] = 0;
SHIFT_TABLE[MODE_LOWER][MODE_PUNCT] = 0;
SHIFT_TABLE[MODE_LOWER][MODE_UPPER] = 28;
SHIFT_TABLE[MODE_MIXED][MODE_PUNCT] = 0;
SHIFT_TABLE[MODE_DIGIT][MODE_PUNCT] = 0;
SHIFT_TABLE[MODE_DIGIT][MODE_UPPER] = 15;
}
public HighLevelEncoder(byte[] text)
{
this.text = text;
}
/// <summary>
/// Convert the text represented by this High Level Encoder into a BitArray.
/// </summary>
/// <returns>text represented by this encoder encoded as a <see cref="BitArray"/></returns>
public BitArray encode()
{
ICollection<State> states = new Collection<State>();
states.Add(State.INITIAL_STATE);
for (int index = 0; index < text.Length; index++)
{
int pairCode;
// don't remove the (int) type cast, mono compiler needs it
int nextChar = (index + 1 < text.Length) ? (int)text[index + 1] : 0;
switch (text[index])
{
case (byte)'\r':
pairCode = nextChar == '\n' ? 2 : 0;
break;
case (byte)'.':
pairCode = nextChar == ' ' ? 3 : 0;
break;
case (byte)',':
pairCode = nextChar == ' ' ? 4 : 0;
break;
case (byte)':':
pairCode = nextChar == ' ' ? 5 : 0;
break;
default:
pairCode = 0;
break;
}
if (pairCode > 0)
{
// We have one of the four special PUNCT pairs. Treat them specially.
// Get a new set of states for the two new characters.
states = updateStateListForPair(states, index, pairCode);
index++;
}
else
{
// Get a new set of states for the new character.
states = updateStateListForChar(states, index);
}
}
// We are left with a set of states. Find the shortest one.
State minState = null;
foreach (var state in states)
{
if (minState == null)
{
minState = state;
}
else
{
if (state.BitCount < minState.BitCount)
{
minState = state;
}
}
}
/*
State minState = Collections.min(states, new Comparator<State>() {
@Override
public int compare(State a, State b) {
return a.getBitCount() - b.getBitCount();
}
});
*/
// Convert it to a bit array, and return.
return minState.toBitArray(text);
}
// We update a set of states for a new character by updating each state
// for the new character, merging the results, and then removing the
// non-optimal states.
private ICollection<State> updateStateListForChar(IEnumerable<State> states, int index)
{
var result = new LinkedList<State>();
foreach (State state in states)
{
updateStateForChar(state, index, result);
}
return simplifyStates(result);
}
// Return a set of states that represent the possible ways of updating this
// state for the next character. The resulting set of states are added to
// the "result" list.
private void updateStateForChar(State state, int index, ICollection<State> result)
{
char ch = (char) (text[index] & 0xFF);
bool charInCurrentTable = CHAR_MAP[state.Mode][ch] > 0;
State stateNoBinary = null;
for (int mode = 0; mode <= MODE_PUNCT; mode++)
{
int charInMode = CHAR_MAP[mode][ch];
if (charInMode > 0)
{
if (stateNoBinary == null)
{
// Only create stateNoBinary the first time it's required.
stateNoBinary = state.endBinaryShift(index);
}
// Try generating the character by latching to its mode
if (!charInCurrentTable || mode == state.Mode || mode == MODE_DIGIT)
{
// If the character is in the current table, we don't want to latch to
// any other mode except possibly digit (which uses only 4 bits). Any
// other latch would be equally successful *after* this character, and
// so wouldn't save any bits.
State latch_state = stateNoBinary.latchAndAppend(mode, charInMode);
result.Add(latch_state);
}
// Try generating the character by switching to its mode.
if (!charInCurrentTable && SHIFT_TABLE[state.Mode][mode] >= 0)
{
// It never makes sense to temporarily shift to another mode if the
// character exists in the current mode. That can never save bits.
State shift_state = stateNoBinary.shiftAndAppend(mode, charInMode);
result.Add(shift_state);
}
}
}
if (state.BinaryShiftByteCount > 0 || CHAR_MAP[state.Mode][ch] == 0)
{
// It's never worthwhile to go into binary shift mode if you're not already
// in binary shift mode, and the character exists in your current mode.
// That can never save bits over just outputting the char in the current mode.
State binaryState = state.addBinaryShiftChar(index);
result.Add(binaryState);
}
}
private static ICollection<State> updateStateListForPair(IEnumerable<State> states, int index, int pairCode)
{
var result = new LinkedList<State>();
foreach (State state in states)
{
updateStateForPair(state, index, pairCode, result);
}
return simplifyStates(result);
}
private static void updateStateForPair(State state, int index, int pairCode, ICollection<State> result)
{
State stateNoBinary = state.endBinaryShift(index);
// Possibility 1. Latch to MODE_PUNCT, and then append this code
result.Add(stateNoBinary.latchAndAppend(MODE_PUNCT, pairCode));
if (state.Mode != MODE_PUNCT)
{
// Possibility 2. Shift to MODE_PUNCT, and then append this code.
// Every state except MODE_PUNCT (handled above) can shift
result.Add(stateNoBinary.shiftAndAppend(MODE_PUNCT, pairCode));
}
if (pairCode == 3 || pairCode == 4)
{
// both characters are in DIGITS. Sometimes better to just add two digits
State digit_state = stateNoBinary
.latchAndAppend(MODE_DIGIT, 16 - pairCode) // period or comma in DIGIT
.latchAndAppend(MODE_DIGIT, 1); // space in DIGIT
result.Add(digit_state);
}
if (state.BinaryShiftByteCount > 0)
{
// It only makes sense to do the characters as binary if we're already
// in binary mode.
State binaryState = state.addBinaryShiftChar(index).addBinaryShiftChar(index + 1);
result.Add(binaryState);
}
}
private static ICollection<State> simplifyStates(IEnumerable<State> states)
{
var result = new LinkedList<State>();
var removeList = new List<State>();
foreach (State newState in states)
{
bool add = true;
removeList.Clear();
foreach (var oldState in result)
{
if (oldState.isBetterThanOrEqualTo(newState))
{
add = false;
break;
}
if (newState.isBetterThanOrEqualTo(oldState))
{
removeList.Add(oldState);
}
}
if (add)
{
result.AddLast(newState);
}
foreach (var removeItem in removeList)
{
result.Remove(removeItem);
}
}
return result;
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
public sealed class SimpleToken : Token
{
// For normal words, indicates value and bitCount
private readonly short value;
private readonly short bitCount;
public SimpleToken(Token previous, int value, int bitCount)
: base(previous)
{
this.value = (short) value;
this.bitCount = (short) bitCount;
}
public override void appendTo(BitArray bitArray, byte[] text)
{
bitArray.appendBits(value, bitCount);
}
public override String ToString()
{
int value = this.value & ((1 << bitCount) - 1);
value |= 1 << bitCount;
return '<' + SupportClass.ToBinaryString(value | (1 << bitCount)).Substring(1) + '>';
}
}
}

View File

@@ -1,197 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
/// <summary>
/// State represents all information about a sequence necessary to generate the current output.
/// Note that a state is immutable.
/// </summary>
internal sealed class State
{
public static readonly State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
// The current mode of the encoding (or the mode to which we'll return if
// we're in Binary Shift mode.
private readonly int mode;
// The list of tokens that we output. If we are in Binary Shift mode, this
// token list does *not* yet included the token for those bytes
private readonly Token token;
// If non-zero, the number of most recent bytes that should be output
// in Binary Shift mode.
private readonly int binaryShiftByteCount;
// The total number of bits generated (including Binary Shift).
private readonly int bitCount;
public State(Token token, int mode, int binaryBytes, int bitCount)
{
this.token = token;
this.mode = mode;
this.binaryShiftByteCount = binaryBytes;
this.bitCount = bitCount;
// Make sure we match the token
//int binaryShiftBitCount = (binaryShiftByteCount * 8) +
// (binaryShiftByteCount == 0 ? 0 :
// binaryShiftByteCount <= 31 ? 10 :
// binaryShiftByteCount <= 62 ? 20 : 21);
//assert this.bitCount == token.getTotalBitCount() + binaryShiftBitCount;
}
public int Mode
{
get { return mode; }
}
public Token Token
{
get { return token; }
}
public int BinaryShiftByteCount
{
get { return binaryShiftByteCount; }
}
public int BitCount
{
get { return bitCount; }
}
/// <summary>
/// Create a new state representing this state with a latch to a (not
/// necessary different) mode, and then a code.
/// </summary>
public State latchAndAppend(int mode, int value)
{
//assert binaryShiftByteCount == 0;
int bitCount = this.bitCount;
Token token = this.token;
if (mode != this.mode)
{
int latch = HighLevelEncoder.LATCH_TABLE[this.mode][mode];
token = token.add(latch & 0xFFFF, latch >> 16);
bitCount += latch >> 16;
}
int latchModeBitCount = mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
token = token.add(value, latchModeBitCount);
return new State(token, mode, 0, bitCount + latchModeBitCount);
}
/// <summary>
/// Create a new state representing this state, with a temporary shift
/// to a different mode to output a single value.
/// </summary>
public State shiftAndAppend(int mode, int value)
{
//assert binaryShiftByteCount == 0 && this.mode != mode;
Token token = this.token;
int thisModeBitCount = this.mode == HighLevelEncoder.MODE_DIGIT ? 4 : 5;
// Shifts exist only to UPPER and PUNCT, both with tokens size 5.
token = token.add(HighLevelEncoder.SHIFT_TABLE[this.mode][mode], thisModeBitCount);
token = token.add(value, 5);
return new State(token, this.mode, 0, this.bitCount + thisModeBitCount + 5);
}
/// <summary>
/// Create a new state representing this state, but an additional character
/// output in Binary Shift mode.
/// </summary>
public State addBinaryShiftChar(int index)
{
Token token = this.token;
int mode = this.mode;
int bitCount = this.bitCount;
if (this.mode == HighLevelEncoder.MODE_PUNCT || this.mode == HighLevelEncoder.MODE_DIGIT)
{
//assert binaryShiftByteCount == 0;
int latch = HighLevelEncoder.LATCH_TABLE[mode][HighLevelEncoder.MODE_UPPER];
token = token.add(latch & 0xFFFF, latch >> 16);
bitCount += latch >> 16;
mode = HighLevelEncoder.MODE_UPPER;
}
int deltaBitCount =
(binaryShiftByteCount == 0 || binaryShiftByteCount == 31) ? 18 :
(binaryShiftByteCount == 62) ? 9 : 8;
State result = new State(token, mode, binaryShiftByteCount + 1, bitCount + deltaBitCount);
if (result.binaryShiftByteCount == 2047 + 31)
{
// The string is as long as it's allowed to be. We should end it.
result = result.endBinaryShift(index + 1);
}
return result;
}
/// <summary>
/// Create the state identical to this one, but we are no longer in
/// Binary Shift mode.
/// </summary>
public State endBinaryShift(int index)
{
if (binaryShiftByteCount == 0)
{
return this;
}
Token token = this.token;
token = token.addBinaryShift(index - binaryShiftByteCount, binaryShiftByteCount);
//assert token.getTotalBitCount() == this.bitCount;
return new State(token, mode, 0, this.bitCount);
}
/// <summary>
/// Returns true if "this" state is better (or equal) to be in than "that"
/// state under all possible circumstances.
/// </summary>
public bool isBetterThanOrEqualTo(State other)
{
int mySize = this.bitCount + (HighLevelEncoder.LATCH_TABLE[this.mode][other.mode] >> 16);
if (other.binaryShiftByteCount > 0 &&
(this.binaryShiftByteCount == 0 || this.binaryShiftByteCount > other.binaryShiftByteCount))
{
mySize += 10; // Cost of entering Binary Shift mode.
}
return mySize <= other.bitCount;
}
public BitArray toBitArray(byte[] text)
{
// Reverse the tokens, so that they are in the order that they should
// be output
var symbols = new LinkedList<Token>();
for (Token token = endBinaryShift(text.Length).token; token != null; token = token.Previous)
{
symbols.AddFirst(token);
}
BitArray bitArray = new BitArray();
// Add each token to the result.
foreach (Token symbol in symbols)
{
symbol.appendTo(bitArray, text);
}
//assert bitArray.getSize() == this.bitCount;
return bitArray;
}
public override String ToString()
{
return String.Format("{0} bits={1} bytes={2}", HighLevelEncoder.MODE_NAMES[mode], bitCount, binaryShiftByteCount);
}
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2013 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
namespace ZXing.Aztec.Internal
{
public abstract class Token
{
public static Token EMPTY = new SimpleToken(null, 0, 0);
private readonly Token previous;
protected Token(Token previous)
{
this.previous = previous;
}
public Token Previous
{
get { return previous; }
}
public Token add(int value, int bitCount)
{
return new SimpleToken(this, value, bitCount);
}
public Token addBinaryShift(int start, int byteCount)
{
int bitCount = (byteCount*8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21);
return new BinaryShiftToken(this, start, byteCount);
}
public abstract void appendTo(BitArray bitArray, byte[] text);
}
}

View File

@@ -1,488 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common
{
/// <summary>
/// A simple, fast array of bits, represented compactly by an array of ints internally.
/// </summary>
/// <author>Sean Owen</author>
public sealed class BitArray
{
private int[] bits;
private int size;
public int Size
{
get
{
return size;
}
}
public int SizeInBytes
{
get
{
return (size + 7) >> 3;
}
}
public bool this[int i]
{
get
{
return (bits[i >> 5] & (1 << (i & 0x1F))) != 0;
}
set
{
if (value)
bits[i >> 5] |= 1 << (i & 0x1F);
}
}
public BitArray()
{
this.size = 0;
this.bits = new int[1];
}
public BitArray(int size)
{
if (size < 1)
{
throw new ArgumentException("size must be at least 1");
}
this.size = size;
this.bits = makeArray(size);
}
// For testing only
private BitArray(int[] bits, int size)
{
this.bits = bits;
this.size = size;
}
private void ensureCapacity(int size)
{
if (size > bits.Length << 5)
{
int[] newBits = makeArray(size);
System.Array.Copy(bits, 0, newBits, 0, bits.Length);
bits = newBits;
}
}
/// <summary> Flips bit i.
///
/// </summary>
/// <param name="i">bit to set
/// </param>
public void flip(int i)
{
bits[i >> 5] ^= 1 << (i & 0x1F);
}
private static int numberOfTrailingZeros(int num)
{
var index = (-num & num)%37;
if (index < 0)
index *= -1;
return _lookup[index];
}
private static readonly int[] _lookup =
{
32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
};
/// <summary>
/// Gets the next set.
/// </summary>
/// <param name="from">first bit to check</param>
/// <returns>index of first bit that is set, starting from the given index, or size if none are set
/// at or beyond this given index</returns>
public int getNextSet(int from)
{
if (from >= size)
{
return size;
}
int bitsOffset = from >> 5;
int currentBits = bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0)
{
if (++bitsOffset == bits.Length)
{
return size;
}
currentBits = bits[bitsOffset];
}
int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/// <summary>
/// see getNextSet(int)
/// </summary>
/// <param name="from">index to start looking for unset bit</param>
/// <returns>index of next unset bit, or <see cref="Size"/> if none are unset until the end</returns>
public int getNextUnset(int from)
{
if (from >= size)
{
return size;
}
int bitsOffset = from >> 5;
int currentBits = ~bits[bitsOffset];
// mask off lesser bits first
currentBits &= ~((1 << (from & 0x1F)) - 1);
while (currentBits == 0)
{
if (++bitsOffset == bits.Length)
{
return size;
}
currentBits = ~bits[bitsOffset];
}
int result = (bitsOffset << 5) + numberOfTrailingZeros(currentBits);
return result > size ? size : result;
}
/// <summary> Sets a block of 32 bits, starting at bit i.
///
/// </summary>
/// <param name="i">first bit to set
/// </param>
/// <param name="newBits">the new value of the next 32 bits. Note again that the least-significant bit
/// corresponds to bit i, the next-least-significant to i+1, and so on.
/// </param>
public void setBulk(int i, int newBits)
{
bits[i >> 5] = newBits;
}
/// <summary>
/// Sets a range of bits.
/// </summary>
/// <param name="start">start of range, inclusive.</param>
/// <param name="end">end of range, exclusive</param>
public void setRange(int start, int end)
{
if (end < start)
{
throw new ArgumentException();
}
if (end == start)
{
return;
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
int firstInt = start >> 5;
int lastInt = end >> 5;
for (int i = firstInt; i <= lastInt; i++)
{
int firstBit = i > firstInt ? 0 : start & 0x1F;
int lastBit = i < lastInt ? 31 : end & 0x1F;
int mask;
if (firstBit == 0 && lastBit == 31)
{
mask = -1;
}
else
{
mask = 0;
for (int j = firstBit; j <= lastBit; j++)
{
mask |= 1 << j;
}
}
bits[i] |= mask;
}
}
/// <summary> Clears all bits (sets to false).</summary>
public void clear()
{
int max = bits.Length;
for (int i = 0; i < max; i++)
{
bits[i] = 0;
}
}
/// <summary> Efficient method to check if a range of bits is set, or not set.
///
/// </summary>
/// <param name="start">start of range, inclusive.
/// </param>
/// <param name="end">end of range, exclusive
/// </param>
/// <param name="value">if true, checks that bits in range are set, otherwise checks that they are not set
/// </param>
/// <returns> true iff all bits are set or not set in range, according to value argument
/// </returns>
/// <throws> IllegalArgumentException if end is less than or equal to start </throws>
public bool isRange(int start, int end, bool value)
{
if (end < start)
{
throw new System.ArgumentException();
}
if (end == start)
{
return true; // empty range matches
}
end--; // will be easier to treat this as the last actually set bit -- inclusive
int firstInt = start >> 5;
int lastInt = end >> 5;
for (int i = firstInt; i <= lastInt; i++)
{
int firstBit = i > firstInt ? 0 : start & 0x1F;
int lastBit = i < lastInt ? 31 : end & 0x1F;
int mask;
if (firstBit == 0 && lastBit == 31)
{
mask = -1;
}
else
{
mask = 0;
for (int j = firstBit; j <= lastBit; j++)
{
mask |= 1 << j;
}
}
// Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is,
// equals the mask, or we're looking for 0s and the masked portion is not all 0s
if ((bits[i] & mask) != (value ? mask : 0))
{
return false;
}
}
return true;
}
/// <summary>
/// Appends the bit.
/// </summary>
/// <param name="bit">The bit.</param>
public void appendBit(bool bit)
{
ensureCapacity(size + 1);
if (bit)
{
bits[size >> 5] |= 1 << (size & 0x1F);
}
size++;
}
/// <returns> underlying array of ints. The first element holds the first 32 bits, and the least
/// significant bit is bit 0.
/// </returns>
public int[] Array
{
get { return bits; }
}
/// <summary>
/// Appends the least-significant bits, from value, in order from most-significant to
/// least-significant. For example, appending 6 bits from 0x000001E will append the bits
/// 0, 1, 1, 1, 1, 0 in that order.
/// </summary>
/// <param name="value"><see cref="int"/> containing bits to append</param>
/// <param name="numBits">bits from value to append</param>
public void appendBits(int value, int numBits)
{
if (numBits < 0 || numBits > 32)
{
throw new ArgumentException("Num bits must be between 0 and 32");
}
ensureCapacity(size + numBits);
for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--)
{
appendBit(((value >> (numBitsLeft - 1)) & 0x01) == 1);
}
}
public void appendBitArray(BitArray other)
{
int otherSize = other.size;
ensureCapacity(size + otherSize);
for (int i = 0; i < otherSize; i++)
{
appendBit(other[i]);
}
}
public void xor(BitArray other)
{
if (bits.Length != other.bits.Length)
{
throw new ArgumentException("Sizes don't match");
}
for (int i = 0; i < bits.Length; i++)
{
// The last byte could be incomplete (i.e. not have 8 bits in
// it) but there is no problem since 0 XOR 0 == 0.
bits[i] ^= other.bits[i];
}
}
/// <summary>
/// Toes the bytes.
/// </summary>
/// <param name="bitOffset">first bit to start writing</param>
/// <param name="array">array to write into. Bytes are written most-significant byte first. This is the opposite
/// of the internal representation, which is exposed by BitArray</param>
/// <param name="offset">position in array to start writing</param>
/// <param name="numBytes">how many bytes to write</param>
public void toBytes(int bitOffset, byte[] array, int offset, int numBytes)
{
for (int i = 0; i < numBytes; i++)
{
int theByte = 0;
for (int j = 0; j < 8; j++)
{
if (this[bitOffset])
{
theByte |= 1 << (7 - j);
}
bitOffset++;
}
array[offset + i] = (byte)theByte;
}
}
/// <summary> Reverses all bits in the array.</summary>
public void reverse()
{
var newBits = new int[bits.Length];
// reverse all int's first
var len = ((size - 1) >> 5);
var oldBitsLen = len + 1;
for (var i = 0; i < oldBitsLen; i++)
{
var x = (long)bits[i];
x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
x = ((x >> 16) & 0x0000ffffu) | ((x & 0x0000ffffu) << 16);
newBits[len - i] = (int)x;
}
// now correct the int's if the bit size isn't a multiple of 32
if (size != oldBitsLen * 32)
{
var leftOffset = oldBitsLen * 32 - size;
var mask = 1;
for (var i = 0; i < 31 - leftOffset; i++)
mask = (mask << 1) | 1;
var currentInt = (newBits[0] >> leftOffset) & mask;
for (var i = 1; i < oldBitsLen; i++)
{
var nextInt = newBits[i];
currentInt |= nextInt << (32 - leftOffset);
newBits[i - 1] = currentInt;
currentInt = (nextInt >> leftOffset) & mask;
}
newBits[oldBitsLen - 1] = currentInt;
}
bits = newBits;
}
private static int[] makeArray(int size)
{
return new int[(size + 31) >> 5];
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="o">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(Object o)
{
var other = o as BitArray;
if (other == null)
return false;
if (size != other.size)
return false;
for (var index = 0; index < size; index++)
{
if (bits[index] != other.bits[index])
return false;
}
return true;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
var hash = size;
foreach (var bit in bits)
{
hash = 31 * hash + bit.GetHashCode();
}
return hash;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
var result = new System.Text.StringBuilder(size);
for (int i = 0; i < size; i++)
{
if ((i & 0x07) == 0)
{
result.Append(' ');
}
result.Append(this[i] ? 'X' : '.');
}
return result.ToString();
}
/// <summary>
/// Erstellt ein neues Objekt, das eine Kopie der aktuellen Instanz darstellt.
/// </summary>
/// <returns>
/// Ein neues Objekt, das eine Kopie dieser Instanz darstellt.
/// </returns>
public object Clone()
{
return new BitArray((int[])bits.Clone(), size);
}
}
}

View File

@@ -1,589 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Common
{
/// <summary>
/// <p>Represents a 2D matrix of bits. In function arguments below, and throughout the common
/// module, x is the column position, and y is the row position. The ordering is always x, y.
/// The origin is at the top-left.</p>
/// <p>Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins
/// with a new int. This is done intentionally so that we can copy out a row into a BitArray very
/// efficiently.</p>
/// <p>The ordering of bits is row-major. Within each int, the least significant bits are used first,
/// meaning they represent lower x values. This is compatible with BitArray's implementation.</p>
/// </summary>
/// <author>Sean Owen</author>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
public sealed partial class BitMatrix
{
private readonly int width;
private readonly int height;
private readonly int rowSize;
private readonly int[] bits;
/// <returns> The width of the matrix
/// </returns>
public int Width
{
get { return width; }
}
/// <returns> The height of the matrix
/// </returns>
public int Height
{
get { return height; }
}
/// <summary> This method is for compatibility with older code. It's only logical to call if the matrix
/// is square, so I'm throwing if that's not the case.
///
/// </summary>
/// <returns> row/column dimension of this matrix
/// </returns>
public int Dimension
{
get
{
if (width != height)
{
throw new ArgumentException("Can't call Dimension on a non-square matrix");
}
return width;
}
}
/// <returns>
/// The rowsize of the matrix
/// </returns>
public int RowSize
{
get { return rowSize; }
}
// A helper to construct a square matrix.
public BitMatrix(int dimension)
: this(dimension, dimension)
{
}
public BitMatrix(int width, int height)
{
if (width < 1 || height < 1)
{
throw new System.ArgumentException("Both dimensions must be greater than 0");
}
this.width = width;
this.height = height;
this.rowSize = (width + 31) >> 5;
bits = new int[rowSize*height];
}
internal BitMatrix(int width, int height, int rowSize, int[] bits)
{
this.width = width;
this.height = height;
this.rowSize = rowSize;
this.bits = bits;
}
internal BitMatrix(int width, int height, int[] bits)
{
this.width = width;
this.height = height;
this.rowSize = (width + 31) >> 5;
this.bits = bits;
}
public static BitMatrix parse(String stringRepresentation, String setString, String unsetString)
{
if (stringRepresentation == null)
{
throw new ArgumentException();
}
bool[] bits = new bool[stringRepresentation.Length];
int bitsPos = 0;
int rowStartPos = 0;
int rowLength = -1;
int nRows = 0;
int pos = 0;
while (pos < stringRepresentation.Length)
{
if (stringRepresentation.Substring(pos, 1).Equals("\n") ||
stringRepresentation.Substring(pos, 1).Equals("\r"))
{
if (bitsPos > rowStartPos)
{
if (rowLength == -1)
{
rowLength = bitsPos - rowStartPos;
}
else if (bitsPos - rowStartPos != rowLength)
{
throw new ArgumentException("row lengths do not match");
}
rowStartPos = bitsPos;
nRows++;
}
pos++;
}
else if (stringRepresentation.Substring(pos, setString.Length).Equals(setString))
{
pos += setString.Length;
bits[bitsPos] = true;
bitsPos++;
}
else if (stringRepresentation.Substring(pos, unsetString.Length).Equals(unsetString))
{
pos += unsetString.Length;
bits[bitsPos] = false;
bitsPos++;
}
else
{
throw new ArgumentException("illegal character encountered: " + stringRepresentation.Substring(pos));
}
}
// no EOL at end?
if (bitsPos > rowStartPos)
{
if (rowLength == -1)
{
rowLength = bitsPos - rowStartPos;
}
else if (bitsPos - rowStartPos != rowLength)
{
throw new ArgumentException("row lengths do not match");
}
nRows++;
}
BitMatrix matrix = new BitMatrix(rowLength, nRows);
for (int i = 0; i < bitsPos; i++)
{
if (bits[i])
{
matrix[i%rowLength, i/rowLength] = true;
}
}
return matrix;
}
/// <summary> <p>Gets the requested bit, where true means black.</p>
///
/// </summary>
/// <param name="x">The horizontal component (i.e. which column)
/// </param>
/// <param name="y">The vertical component (i.e. which row)
/// </param>
/// <returns> value of given bit in matrix
/// </returns>
public bool this[int x, int y]
{
get
{
int offset = y*rowSize + (x >> 5);
return (((int) ((uint) (bits[offset]) >> (x & 0x1f))) & 1) != 0;
}
set
{
if (value)
{
int offset = y*rowSize + (x >> 5);
bits[offset] |= 1 << (x & 0x1f);
}
else
{
int offset = y*rowSize + (x/32);
bits[offset] &= ~(1 << (x & 0x1f));
}
}
}
/// <summary> <p>Flips the given bit.</p>
///
/// </summary>
/// <param name="x">The horizontal component (i.e. which column)
/// </param>
/// <param name="y">The vertical component (i.e. which row)
/// </param>
public void flip(int x, int y)
{
int offset = y*rowSize + (x >> 5);
bits[offset] ^= 1 << (x & 0x1f);
}
/// <summary>
/// Exclusive-or (XOR): Flip the bit in this {@code BitMatrix} if the corresponding
/// mask bit is set.
/// </summary>
/// <param name="mask">The mask.</param>
public void xor(BitMatrix mask)
{
if (width != mask.Width || height != mask.Height
|| rowSize != mask.RowSize)
{
throw new ArgumentException("input matrix dimensions do not match");
}
var rowArray = new BitArray(width/32 + 1);
for (int y = 0; y < height; y++)
{
int offset = y*rowSize;
int[] row = mask.getRow(y, rowArray).Array;
for (int x = 0; x < rowSize; x++)
{
bits[offset + x] ^= row[x];
}
}
}
/// <summary> Clears all bits (sets to false).</summary>
public void clear()
{
int max = bits.Length;
for (int i = 0; i < max; i++)
{
bits[i] = 0;
}
}
/// <summary> <p>Sets a square region of the bit matrix to true.</p>
///
/// </summary>
/// <param name="left">The horizontal position to begin at (inclusive)
/// </param>
/// <param name="top">The vertical position to begin at (inclusive)
/// </param>
/// <param name="width">The width of the region
/// </param>
/// <param name="height">The height of the region
/// </param>
public void setRegion(int left, int top, int width, int height)
{
if (top < 0 || left < 0)
{
throw new System.ArgumentException("Left and top must be nonnegative");
}
if (height < 1 || width < 1)
{
throw new System.ArgumentException("Height and width must be at least 1");
}
int right = left + width;
int bottom = top + height;
if (bottom > this.height || right > this.width)
{
throw new System.ArgumentException("The region must fit inside the matrix");
}
for (int y = top; y < bottom; y++)
{
int offset = y*rowSize;
for (int x = left; x < right; x++)
{
bits[offset + (x >> 5)] |= 1 << (x & 0x1f);
}
}
}
/// <summary> A fast method to retrieve one row of data from the matrix as a BitArray.
///
/// </summary>
/// <param name="y">The row to retrieve
/// </param>
/// <param name="row">An optional caller-allocated BitArray, will be allocated if null or too small
/// </param>
/// <returns> The resulting BitArray - this reference should always be used even when passing
/// your own row
/// </returns>
public BitArray getRow(int y, BitArray row)
{
if (row == null || row.Size < width)
{
row = new BitArray(width);
}
else
{
row.clear();
}
int offset = y*rowSize;
for (int x = 0; x < rowSize; x++)
{
row.setBulk(x << 5, bits[offset + x]);
}
return row;
}
/// <summary>
/// Sets the row.
/// </summary>
/// <param name="y">row to set</param>
/// <param name="row">{@link BitArray} to copy from</param>
public void setRow(int y, BitArray row)
{
Array.Copy(row.Array, 0, bits, y*rowSize, rowSize);
}
/// <summary>
/// Modifies this {@code BitMatrix} to represent the same but rotated 180 degrees
/// </summary>
public void rotate180()
{
var width = Width;
var height = Height;
var topRow = new BitArray(width);
var bottomRow = new BitArray(width);
for (int i = 0; i < (height + 1)/2; i++)
{
topRow = getRow(i, topRow);
bottomRow = getRow(height - 1 - i, bottomRow);
topRow.reverse();
bottomRow.reverse();
setRow(i, bottomRow);
setRow(height - 1 - i, topRow);
}
}
/// <summary>
/// This is useful in detecting the enclosing rectangle of a 'pure' barcode.
/// </summary>
/// <returns>{left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white</returns>
public int[] getEnclosingRectangle()
{
int left = width;
int top = height;
int right = -1;
int bottom = -1;
for (int y = 0; y < height; y++)
{
for (int x32 = 0; x32 < rowSize; x32++)
{
int theBits = bits[y*rowSize + x32];
if (theBits != 0)
{
if (y < top)
{
top = y;
}
if (y > bottom)
{
bottom = y;
}
if (x32*32 < left)
{
int bit = 0;
while ((theBits << (31 - bit)) == 0)
{
bit++;
}
if ((x32*32 + bit) < left)
{
left = x32*32 + bit;
}
}
if (x32*32 + 31 > right)
{
int bit = 31;
while (((int) ((uint) theBits >> bit)) == 0) // (theBits >>> bit)
{
bit--;
}
if ((x32*32 + bit) > right)
{
right = x32*32 + bit;
}
}
}
}
}
int widthTmp = right - left;
int heightTmp = bottom - top;
if (widthTmp < 0 || heightTmp < 0)
{
return null;
}
return new[] {left, top, widthTmp, heightTmp};
}
/// <summary>
/// This is useful in detecting a corner of a 'pure' barcode.
/// </summary>
/// <returns>{x,y} coordinate of top-left-most 1 bit, or null if it is all white</returns>
public int[] getTopLeftOnBit()
{
int bitsOffset = 0;
while (bitsOffset < bits.Length && bits[bitsOffset] == 0)
{
bitsOffset++;
}
if (bitsOffset == bits.Length)
{
return null;
}
int y = bitsOffset/rowSize;
int x = (bitsOffset%rowSize) << 5;
int theBits = bits[bitsOffset];
int bit = 0;
while ((theBits << (31 - bit)) == 0)
{
bit++;
}
x += bit;
return new[] {x, y};
}
public int[] getBottomRightOnBit()
{
int bitsOffset = bits.Length - 1;
while (bitsOffset >= 0 && bits[bitsOffset] == 0)
{
bitsOffset--;
}
if (bitsOffset < 0)
{
return null;
}
int y = bitsOffset/rowSize;
int x = (bitsOffset%rowSize) << 5;
int theBits = bits[bitsOffset];
int bit = 31;
while (((int) ((uint) theBits >> bit)) == 0) // (theBits >>> bit)
{
bit--;
}
x += bit;
return new int[] {x, y};
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
/// </summary>
/// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
if (!(obj is BitMatrix))
{
return false;
}
var other = (BitMatrix) obj;
if (width != other.width || height != other.height ||
rowSize != other.rowSize || bits.Length != other.bits.Length)
{
return false;
}
for (int i = 0; i < bits.Length; i++)
{
if (bits[i] != other.bits[i])
{
return false;
}
}
return true;
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public override int GetHashCode()
{
int hash = width;
hash = 31*hash + width;
hash = 31*hash + height;
hash = 31*hash + rowSize;
foreach (var bit in bits)
{
hash = 31*hash + bit.GetHashCode();
}
return hash;
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override String ToString()
{
return ToString("X ", " ", Environment.NewLine);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="setString">The set string.</param>
/// <param name="unsetString">The unset string.</param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public String ToString(String setString, String unsetString)
{
return ToString(setString, unsetString, Environment.NewLine);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <param name="setString">The set string.</param>
/// <param name="unsetString">The unset string.</param>
/// <param name="lineSeparator">The line separator.</param>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public String ToString(String setString, String unsetString, String lineSeparator)
{
var result = new StringBuilder(height*(width + 1));
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
result.Append(this[x, y] ? setString : unsetString);
}
result.Append(lineSeparator);
}
return result.ToString();
}
/// <summary>
/// Clones this instance.
/// </summary>
/// <returns></returns>
public object Clone()
{
return new BitMatrix(width, height, rowSize, (int[]) bits.Clone());
}
}
}

View File

@@ -1,124 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common
{
/// <summary> <p>This provides an easy abstraction to read bits at a time from a sequence of bytes, where the
/// number of bits read is not often a multiple of 8.</p>
///
/// <p>This class is thread-safe but not reentrant. Unless the caller modifies the bytes array
/// it passed in, in which case all bets are off.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class BitSource
{
private readonly byte[] bytes;
private int byteOffset;
private int bitOffset;
/// <param name="bytes">bytes from which this will read bits. Bits will be read from the first byte first.
/// Bits are read within a byte from most-significant to least-significant bit.
/// </param>
public BitSource(byte[] bytes)
{
this.bytes = bytes;
}
/// <summary>
/// index of next bit in current byte which would be read by the next call to {@link #readBits(int)}.
/// </summary>
public int BitOffset
{
get { return bitOffset; }
}
/// <summary>
/// index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}.
/// </summary>
public int ByteOffset
{
get { return byteOffset; }
}
/// <param name="numBits">number of bits to read
/// </param>
/// <returns> int representing the bits read. The bits will appear as the least-significant
/// bits of the int
/// </returns>
/// <exception cref="ArgumentException">if numBits isn't in [1,32] or more than is available</exception>
public int readBits(int numBits)
{
if (numBits < 1 || numBits > 32 || numBits > available())
{
throw new ArgumentException(numBits.ToString(), "numBits");
}
int result = 0;
// First, read remainder from current byte
if (bitOffset > 0)
{
int bitsLeft = 8 - bitOffset;
int toRead = numBits < bitsLeft ? numBits : bitsLeft;
int bitsToNotRead = bitsLeft - toRead;
int mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
result = (bytes[byteOffset] & mask) >> bitsToNotRead;
numBits -= toRead;
bitOffset += toRead;
if (bitOffset == 8)
{
bitOffset = 0;
byteOffset++;
}
}
// Next read whole bytes
if (numBits > 0)
{
while (numBits >= 8)
{
result = (result << 8) | (bytes[byteOffset] & 0xFF);
byteOffset++;
numBits -= 8;
}
// Finally read a partial byte
if (numBits > 0)
{
int bitsToNotRead = 8 - numBits;
int mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
result = (result << numBits) | ((bytes[byteOffset] & mask) >> bitsToNotRead);
bitOffset += numBits;
}
}
return result;
}
/// <returns> number of bits that can be read successfully
/// </returns>
public int available()
{
return 8 * (bytes.Length - byteOffset) - bitOffset;
}
}
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Common
{
/// <summary> Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1
/// of ISO 18004.
///
/// </summary>
/// <author>Sean Owen</author>
public sealed class CharacterSetECI : ECI
{
internal static readonly IDictionary<int, CharacterSetECI> VALUE_TO_ECI;
internal static readonly IDictionary<string, CharacterSetECI> NAME_TO_ECI;
private readonly String encodingName;
public String EncodingName
{
get
{
return encodingName;
}
}
static CharacterSetECI()
{
VALUE_TO_ECI = new Dictionary<int, CharacterSetECI>();
NAME_TO_ECI = new Dictionary<string, CharacterSetECI>();
// TODO figure out if these values are even right!
addCharacterSet(0, "CP437");
addCharacterSet(1, new[] { "ISO-8859-1", "ISO8859_1" });
addCharacterSet(2, "CP437");
addCharacterSet(3, new[] { "ISO-8859-1", "ISO8859_1" });
addCharacterSet(4, new[] { "ISO-8859-2", "ISO8859_2" });
addCharacterSet(5, new[] { "ISO-8859-3", "ISO8859_3" });
addCharacterSet(6, new[] { "ISO-8859-4", "ISO8859_4" });
addCharacterSet(7, new[] { "ISO-8859-5", "ISO8859_5" });
addCharacterSet(8, new[] { "ISO-8859-6", "ISO8859_6" });
addCharacterSet(9, new[] { "ISO-8859-7", "ISO8859_7" });
addCharacterSet(10, new[] { "ISO-8859-8", "ISO8859_8" });
addCharacterSet(11, new[] { "ISO-8859-9", "ISO8859_9" });
addCharacterSet(12, new[] { "ISO-8859-4", "ISO-8859-10", "ISO8859_10" }); // use ISO-8859-4 because ISO-8859-16 isn't supported
addCharacterSet(13, new[] { "ISO-8859-11", "ISO8859_11" });
addCharacterSet(15, new[] { "ISO-8859-13", "ISO8859_13" });
addCharacterSet(16, new[] { "ISO-8859-1", "ISO-8859-14", "ISO8859_14" }); // use ISO-8859-1 because ISO-8859-16 isn't supported
addCharacterSet(17, new[] { "ISO-8859-15", "ISO8859_15" });
addCharacterSet(18, new[] { "ISO-8859-3", "ISO-8859-16", "ISO8859_16" }); // use ISO-8859-3 because ISO-8859-16 isn't supported
addCharacterSet(20, new[] { "SJIS", "Shift_JIS" });
addCharacterSet(21, new[] { "WINDOWS-1250", "CP1250" });
addCharacterSet(22, new[] { "WINDOWS-1251", "CP1251" });
addCharacterSet(23, new[] { "WINDOWS-1252", "CP1252" });
addCharacterSet(24, new[] { "WINDOWS-1256", "CP1256" });
addCharacterSet(25, new[] { "UTF-16BE", "UNICODEBIG" });
addCharacterSet(26, new[] { "UTF-8", "UTF8" });
addCharacterSet(27, "US-ASCII");
addCharacterSet(170, "US-ASCII");
addCharacterSet(28, "BIG5");
addCharacterSet(29, new[] { "GB18030", "GB2312", "EUC_CN", "GBK" });
addCharacterSet(30, new[] { "EUC-KR", "EUC_KR" });
}
private CharacterSetECI(int value, String encodingName)
: base(value)
{
this.encodingName = encodingName;
}
private static void addCharacterSet(int value, String encodingName)
{
var eci = new CharacterSetECI(value, encodingName);
VALUE_TO_ECI[value] = eci; // can't use valueOf
NAME_TO_ECI[encodingName] = eci;
}
private static void addCharacterSet(int value, String[] encodingNames)
{
var eci = new CharacterSetECI(value, encodingNames[0]);
VALUE_TO_ECI[value] = eci; // can't use valueOf
foreach (string t in encodingNames)
{
NAME_TO_ECI[t] = eci;
}
}
/// <param name="value">character set ECI value</param>
/// <returns><see cref="CharacterSetECI"/> representing ECI of given value, or null if it is legal but unsupported</returns>
public static CharacterSetECI getCharacterSetECIByValue(int value)
{
if (value < 0 || value >= 900)
{
return null;
}
return VALUE_TO_ECI[value];
}
/// <param name="name">character set ECI encoding name</param>
/// <returns><see cref="CharacterSetECI"/> representing ECI for character encoding, or null if it is legalbut unsupported</returns>
public static CharacterSetECI getCharacterSetECIByName(String name)
{
return NAME_TO_ECI[name.ToUpper()];
}
}
}

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Common
{
/// <summary>
/// Encapsulates the result of decoding a matrix of bits. This typically
/// applies to 2D barcode formats. For now it contains the raw bytes obtained,
/// as well as a String interpretation of those bytes, if applicable.
/// <author>Sean Owen</author>
/// </summary>
public sealed class DecoderResult
{
public byte[] RawBytes { get; private set; }
public String Text { get; private set; }
public IList<byte[]> ByteSegments { get; private set; }
public String ECLevel { get; private set; }
public bool StructuredAppend
{
get { return StructuredAppendParity >= 0 && StructuredAppendSequenceNumber >= 0; }
}
public int ErrorsCorrected { get; set; }
public int StructuredAppendSequenceNumber { get; private set; }
public int Erasures { get; set; }
public int StructuredAppendParity { get; private set; }
/// <summary>
/// Miscellanseous data value for the various decoders
/// </summary>
/// <value>The other.</value>
public object Other { get; set; }
public DecoderResult(byte[] rawBytes, String text, IList<byte[]> byteSegments, String ecLevel)
: this(rawBytes, text, byteSegments, ecLevel, -1, -1)
{
}
public DecoderResult(byte[] rawBytes, String text, IList<byte[]> byteSegments, String ecLevel, int saSequence, int saParity)
{
if (rawBytes == null && text == null)
{
throw new ArgumentException();
}
RawBytes = rawBytes;
Text = text;
ByteSegments = byteSegments;
ECLevel = ecLevel;
StructuredAppendParity = saParity;
StructuredAppendSequenceNumber = saSequence;
}
}
}

View File

@@ -1,485 +0,0 @@
/*
* Copyright 2013 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace ZXing.Common
{
/// <summary>
/// Defines an container for encoder options
/// </summary>
public class DecodingOptions
{
/// <summary>
/// Gets the data container for all options
/// </summary>
public IDictionary<DecodeHintType, object> Hints { get; private set; }
public event Action<object, EventArgs> ValueChanged;
/// <summary>
/// Gets or sets a flag which cause a deeper look into the bitmap
/// </summary>
/// <value>
/// <c>true</c> if [try harder]; otherwise, <c>false</c>.
/// </value>
public bool TryHarder
{
get
{
if (Hints.ContainsKey(DecodeHintType.TRY_HARDER))
return (bool)Hints[DecodeHintType.TRY_HARDER];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.TRY_HARDER] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.TRY_HARDER))
{
Hints.Remove(DecodeHintType.TRY_HARDER);
}
}
}
}
/// <summary>
/// Image is a pure monochrome image of a barcode.
/// </summary>
/// <value>
/// <c>true</c> if monochrome image of a barcode; otherwise, <c>false</c>.
/// </value>
public bool PureBarcode
{
get
{
if (Hints.ContainsKey(DecodeHintType.PURE_BARCODE))
return (bool)Hints[DecodeHintType.PURE_BARCODE];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.PURE_BARCODE] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.PURE_BARCODE))
{
Hints.Remove(DecodeHintType.PURE_BARCODE);
}
}
}
}
/// <summary>
/// Specifies what character encoding to use when decoding, where applicable (type String)
/// </summary>
/// <value>
/// The character set.
/// </value>
public string CharacterSet
{
get
{
if (Hints.ContainsKey(DecodeHintType.CHARACTER_SET))
return (string)Hints[DecodeHintType.CHARACTER_SET];
return null;
}
set
{
if (value != null)
{
Hints[DecodeHintType.CHARACTER_SET] = value;
}
else
{
if (Hints.ContainsKey(DecodeHintType.CHARACTER_SET))
{
Hints.Remove(DecodeHintType.CHARACTER_SET);
}
}
}
}
/// <summary>
/// Image is known to be of one of a few possible formats.
/// Maps to a {@link java.util.List} of {@link BarcodeFormat}s.
/// </summary>
/// <value>
/// The possible formats.
/// </value>
public IList<BarcodeFormat> PossibleFormats
{
get
{
if (Hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS))
return (IList<BarcodeFormat>)Hints[DecodeHintType.POSSIBLE_FORMATS];
return null;
}
set
{
if (value != null)
{
Hints[DecodeHintType.POSSIBLE_FORMATS] = value;
}
else
{
if (Hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS))
{
Hints.Remove(DecodeHintType.POSSIBLE_FORMATS);
}
}
}
}
/// <summary>
/// if Code39 could be detected try to use extended mode for full ASCII character set
/// </summary>
public bool UseCode39ExtendedMode
{
get
{
if (Hints.ContainsKey(DecodeHintType.USE_CODE_39_EXTENDED_MODE))
return (bool)Hints[DecodeHintType.USE_CODE_39_EXTENDED_MODE];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.USE_CODE_39_EXTENDED_MODE] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.USE_CODE_39_EXTENDED_MODE))
{
Hints.Remove(DecodeHintType.USE_CODE_39_EXTENDED_MODE);
}
}
}
}
/// <summary>
/// Don't fail if a Code39 is detected but can't be decoded in extended mode.
/// Return the raw Code39 result instead. Maps to <see cref="bool" />.
/// </summary>
public bool UseCode39RelaxedExtendedMode
{
get
{
if (Hints.ContainsKey(DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE))
return (bool)Hints[DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE))
{
Hints.Remove(DecodeHintType.RELAXED_CODE_39_EXTENDED_MODE);
}
}
}
}
/// <summary>
/// If true, return the start and end digits in a Codabar barcode instead of stripping them. They
/// are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them
/// to not be. Doesn't matter what it maps to; use <see cref="bool" />.
/// </summary>
public bool ReturnCodabarStartEnd
{
get
{
if (Hints.ContainsKey(DecodeHintType.RETURN_CODABAR_START_END))
return (bool)Hints[DecodeHintType.RETURN_CODABAR_START_END];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.RETURN_CODABAR_START_END] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.RETURN_CODABAR_START_END))
{
Hints.Remove(DecodeHintType.RETURN_CODABAR_START_END);
}
}
}
}
/// <summary>
/// Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed.
/// For example this affects FNC1 handling for Code 128 (aka GS1-128).
/// </summary>
/// <value>
/// <c>true</c> if it should assume GS1; otherwise, <c>false</c>.
/// </value>
public bool AssumeGS1
{
get
{
if (Hints.ContainsKey(DecodeHintType.ASSUME_GS1))
return (bool)Hints[DecodeHintType.ASSUME_GS1];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.ASSUME_GS1] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.ASSUME_GS1))
{
Hints.Remove(DecodeHintType.ASSUME_GS1);
}
}
}
}
/// <summary>
/// Assume MSI codes employ a check digit. Maps to <see cref="bool" />.
/// </summary>
/// <value>
/// <c>true</c> if it should assume a MSI check digit; otherwise, <c>false</c>.
/// </value>
public bool AssumeMSICheckDigit
{
get
{
if (Hints.ContainsKey(DecodeHintType.ASSUME_MSI_CHECK_DIGIT))
return (bool)Hints[DecodeHintType.ASSUME_MSI_CHECK_DIGIT];
return false;
}
set
{
if (value)
{
Hints[DecodeHintType.ASSUME_MSI_CHECK_DIGIT] = true;
}
else
{
if (Hints.ContainsKey(DecodeHintType.ASSUME_MSI_CHECK_DIGIT))
{
Hints.Remove(DecodeHintType.ASSUME_MSI_CHECK_DIGIT);
}
}
}
}
/// <summary>
/// Allowed lengths of encoded data -- reject anything else. Maps to an int[].
/// </summary>
public int[] AllowedLengths
{
get
{
if (Hints.ContainsKey(DecodeHintType.ALLOWED_LENGTHS))
return (int[])Hints[DecodeHintType.ALLOWED_LENGTHS];
return null;
}
set
{
if (value != null && value.Length > 0)
{
Hints[DecodeHintType.ALLOWED_LENGTHS] = value;
}
else
{
if (Hints.ContainsKey(DecodeHintType.ALLOWED_LENGTHS))
{
Hints.Remove(DecodeHintType.ALLOWED_LENGTHS);
}
}
}
}
/// <summary>
/// Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this.
/// Maps to an <see cref="Array.int" /> of the allowed extension lengths, for example [2], [5], or [2, 5].
/// If it is optional to have an extension, do not set this hint. If this is set,
/// and a UPC or EAN barcode is found but an extension is not, then no result will be returned
/// at all.
/// </summary>
public int[] AllowedEANExtensions
{
get
{
if (Hints.ContainsKey(DecodeHintType.ALLOWED_EAN_EXTENSIONS))
return (int[])Hints[DecodeHintType.ALLOWED_EAN_EXTENSIONS];
return null;
}
set
{
if (value != null && value.Length > 0)
{
Hints[DecodeHintType.ALLOWED_EAN_EXTENSIONS] = value;
}
else
{
if (Hints.ContainsKey(DecodeHintType.ALLOWED_EAN_EXTENSIONS))
{
Hints.Remove(DecodeHintType.ALLOWED_EAN_EXTENSIONS);
}
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="DecodingOptions"/> class.
/// </summary>
public DecodingOptions()
{
var hints = new ChangeNotifyDictionary<DecodeHintType, object>();
Hints = hints;
UseCode39ExtendedMode = true;
UseCode39RelaxedExtendedMode = true;
hints.ValueChanged += (o, args) => { if (ValueChanged != null) ValueChanged(this, EventArgs.Empty); };
}
private class ChangeNotifyDictionary<TKey, TValue>: IDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> values;
public event Action<object, EventArgs> ValueChanged;
public ChangeNotifyDictionary()
{
values = new Dictionary<TKey, TValue>();
}
private void OnValueChanged()
{
if (ValueChanged != null)
ValueChanged(this, EventArgs.Empty);
}
public void Add(TKey key, TValue value)
{
values.Add(key, value);
OnValueChanged();
}
public bool ContainsKey(TKey key)
{
return values.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return values.Keys; }
}
public bool Remove(TKey key)
{
var result = values.Remove(key);
OnValueChanged();
return result;
}
public bool TryGetValue(TKey key, out TValue value)
{
return values.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return values.Values; }
}
public TValue this[TKey key]
{
get
{
return values[key];
}
set
{
values[key] = value;
OnValueChanged();
}
}
public void Add(KeyValuePair<TKey, TValue> item)
{
values.Add(item);
OnValueChanged();
}
public void Clear()
{
values.Clear();
OnValueChanged();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return values.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
values.CopyTo(array, arrayIndex);
}
public int Count
{
get { return values.Count; }
}
public bool IsReadOnly
{
get { return values.IsReadOnly; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
var result = values.Remove(item);
OnValueChanged();
return result;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return values.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.IEnumerable)values).GetEnumerator();
}
}
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common
{
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class DefaultGridSampler : GridSampler
{
public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY)
{
PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(
p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY,
p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY);
return sampleGrid(image, dimensionX, dimensionY, transform);
}
public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform)
{
if (dimensionX <= 0 || dimensionY <= 0)
{
return null;
}
BitMatrix bits = new BitMatrix(dimensionX, dimensionY);
float[] points = new float[dimensionX << 1];
for (int y = 0; y < dimensionY; y++)
{
int max = points.Length;
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
float iValue = (float)y + 0.5f;
for (int x = 0; x < max; x += 2)
{
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
points[x] = (float)(x >> 1) + 0.5f;
points[x + 1] = iValue;
}
transform.transformPoints(points);
// Quick check to see if points transformed to something inside the image;
// sufficient to check the endpoints
if (!checkAndNudgePoints(image, points))
return null;
try
{
for (int x = 0; x < max; x += 2)
{
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
bits[x >> 1, y] = image[(int)points[x], (int)points[x + 1]];
}
}
catch (System.IndexOutOfRangeException)
{
// This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting
// transform gets "twisted" such that it maps a straight line of points to a set of points
// whose endpoints are in bounds, but others are not. There is probably some mathematical
// way to detect this about the transformation that I don't know yet.
// This results in an ugly runtime exception despite our clever checks above -- can't have
// that. We could check each point's coordinates but that feels duplicative. We settle for
// catching and wrapping ArrayIndexOutOfBoundsException.
return null;
}
}
return bits;
}
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common
{
/// <summary> <p>Encapsulates the result of detecting a barcode in an image. This includes the raw
/// matrix of black/white pixels corresponding to the barcode, and possibly points of interest
/// in the image, like the location of finder patterns or corners of the barcode in the image.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public class DetectorResult
{
public BitMatrix Bits { get; private set; }
public ResultPoint[] Points { get; private set; }
public DetectorResult(BitMatrix bits, ResultPoint[] points)
{
Bits = bits;
Points = points;
}
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common
{
/// <summary> Superclass of classes encapsulating types ECIs, according to "Extended Channel Interpretations"
/// 5.3 of ISO 18004.
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public abstract class ECI
{
virtual public int Value
{
get
{
return value_Renamed;
}
}
//UPGRADE_NOTE: Final was removed from the declaration of 'value '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
private int value_Renamed;
internal ECI(int value_Renamed)
{
this.value_Renamed = value_Renamed;
}
/// <param name="value">ECI value
/// </param>
/// <returns> {@link ECI} representing ECI of given value, or null if it is legal but unsupported
/// </returns>
/// <throws> IllegalArgumentException if ECI value is invalid </throws>
public static ECI getECIByValue(int value_Renamed)
{
if (value_Renamed < 0 || value_Renamed > 999999)
{
throw new System.ArgumentException("Bad ECI value: " + value_Renamed);
}
if (value_Renamed < 900)
{
// Character set ECIs use 000000 - 000899
return CharacterSetECI.getCharacterSetECIByValue(value_Renamed);
}
return null;
}
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright 2012 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace ZXing.Common
{
/// <summary>
/// Defines an container for encoder options
/// </summary>
public class EncodingOptions
{
/// <summary>
/// Gets the data container for all options
/// </summary>
public IDictionary<EncodeHintType, object> Hints { get; private set; }
/// <summary>
/// Specifies the height of the barcode image
/// </summary>
public int Height
{
get
{
if (Hints.ContainsKey(EncodeHintType.HEIGHT))
{
return (int)Hints[EncodeHintType.HEIGHT];
}
return 0;
}
set
{
Hints[EncodeHintType.HEIGHT] = value;
}
}
/// <summary>
/// Specifies the width of the barcode image
/// </summary>
public int Width
{
get
{
if (Hints.ContainsKey(EncodeHintType.WIDTH))
{
return (int)Hints[EncodeHintType.WIDTH];
}
return 0;
}
set
{
Hints[EncodeHintType.WIDTH] = value;
}
}
/// <summary>
/// Don't put the content string into the output image.
/// </summary>
public bool PureBarcode
{
get
{
if (Hints.ContainsKey(EncodeHintType.PURE_BARCODE))
{
return (bool)Hints[EncodeHintType.PURE_BARCODE];
}
return false;
}
set
{
Hints[EncodeHintType.PURE_BARCODE] = value;
}
}
/// <summary>
/// Specifies margin, in pixels, to use when generating the barcode. The meaning can vary
/// by format; for example it controls margin before and after the barcode horizontally for
/// most 1D formats.
/// </summary>
public int Margin
{
get
{
if (Hints.ContainsKey(EncodeHintType.MARGIN))
{
return (int) Hints[EncodeHintType.MARGIN];
}
return 0;
}
set
{
Hints[EncodeHintType.MARGIN] = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="EncodingOptions"/> class.
/// </summary>
public EncodingOptions()
{
Hints = new Dictionary<EncodeHintType, object>();
}
}
}

View File

@@ -1,243 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common
{
/// <summary> This Binarizer implementation uses the old ZXing global histogram approach. It is suitable
/// for low-end mobile devices which don't have enough CPU or memory to use a local thresholding
/// algorithm. However, because it picks a global black point, it cannot handle difficult shadows
/// and gradients.
///
/// Faster mobile devices and all desktop applications should probably use HybridBinarizer instead.
///
/// <author>dswitkin@google.com (Daniel Switkin)</author>
/// <author>Sean Owen</author>
/// </summary>
public class GlobalHistogramBinarizer : Binarizer
{
private const int LUMINANCE_BITS = 5;
private const int LUMINANCE_SHIFT = 8 - LUMINANCE_BITS;
private const int LUMINANCE_BUCKETS = 1 << LUMINANCE_BITS;
private static readonly byte[] EMPTY = new byte[0];
private byte[] luminances;
private readonly int[] buckets;
/// <summary>
/// Initializes a new instance of the <see cref="GlobalHistogramBinarizer"/> class.
/// </summary>
/// <param name="source">The source.</param>
public GlobalHistogramBinarizer(LuminanceSource source)
: base(source)
{
luminances = EMPTY;
buckets = new int[LUMINANCE_BUCKETS];
}
/// <summary>
/// Applies simple sharpening to the row data to improve performance of the 1D Readers.
/// </summary>
/// <param name="y"></param>
/// <param name="row"></param>
/// <returns></returns>
public override BitArray getBlackRow(int y, BitArray row)
{
LuminanceSource source = LuminanceSource;
int width = source.Width;
if (row == null || row.Size < width)
{
row = new BitArray(width);
}
else
{
row.clear();
}
initArrays(width);
byte[] localLuminances = source.getRow(y, luminances);
int[] localBuckets = buckets;
for (int x = 0; x < width; x++)
{
int pixel = localLuminances[x] & 0xff;
localBuckets[pixel >> LUMINANCE_SHIFT]++;
}
int blackPoint;
if (!estimateBlackPoint(localBuckets, out blackPoint))
return null;
int left = localLuminances[0] & 0xff;
int center = localLuminances[1] & 0xff;
for (int x = 1; x < width - 1; x++)
{
int right = localLuminances[x + 1] & 0xff;
// A simple -1 4 -1 box filter with a weight of 2.
int luminance = ((center << 2) - left - right) >> 1;
row[x] = (luminance < blackPoint);
left = center;
center = right;
}
return row;
}
/// <summary>
/// Does not sharpen the data, as this call is intended to only be used by 2D Readers.
/// </summary>
override public BitMatrix BlackMatrix
{
get
{
LuminanceSource source = LuminanceSource;
byte[] localLuminances;
int width = source.Width;
int height = source.Height;
BitMatrix matrix = new BitMatrix(width, height);
// Quickly calculates the histogram by sampling four rows from the image. This proved to be
// more robust on the blackbox tests than sampling a diagonal as we used to do.
initArrays(width);
int[] localBuckets = buckets;
for (int y = 1; y < 5; y++)
{
int row = height * y / 5;
localLuminances = source.getRow(row, luminances);
int right = (width << 2) / 5;
for (int x = width / 5; x < right; x++)
{
int pixel = localLuminances[x] & 0xff;
localBuckets[pixel >> LUMINANCE_SHIFT]++;
}
}
int blackPoint;
if (!estimateBlackPoint(localBuckets, out blackPoint))
return null;
// We delay reading the entire image luminance until the black point estimation succeeds.
// Although we end up reading four rows twice, it is consistent with our motto of
// "fail quickly" which is necessary for continuous scanning.
localLuminances = source.Matrix;
for (int y = 0; y < height; y++)
{
int offset = y * width;
for (int x = 0; x < width; x++)
{
int pixel = localLuminances[offset + x] & 0xff;
matrix[x, y] = (pixel < blackPoint);
}
}
return matrix;
}
}
/// <summary>
/// Creates a new object with the same type as this Binarizer implementation, but with pristine
/// state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
/// of 1 bit data. See Effective Java for why we can't use Java's clone() method.
/// </summary>
/// <param name="source">The LuminanceSource this Binarizer will operate on.</param>
/// <returns>
/// A new concrete Binarizer implementation object.
/// </returns>
public override Binarizer createBinarizer(LuminanceSource source)
{
return new GlobalHistogramBinarizer(source);
}
private void initArrays(int luminanceSize)
{
if (luminances.Length < luminanceSize)
{
luminances = new byte[luminanceSize];
}
for (int x = 0; x < LUMINANCE_BUCKETS; x++)
{
buckets[x] = 0;
}
}
private static bool estimateBlackPoint(int[] buckets, out int blackPoint)
{
blackPoint = 0;
// Find the tallest peak in the histogram.
int numBuckets = buckets.Length;
int maxBucketCount = 0;
int firstPeak = 0;
int firstPeakSize = 0;
for (int x = 0; x < numBuckets; x++)
{
if (buckets[x] > firstPeakSize)
{
firstPeak = x;
firstPeakSize = buckets[x];
}
if (buckets[x] > maxBucketCount)
{
maxBucketCount = buckets[x];
}
}
// Find the second-tallest peak which is somewhat far from the tallest peak.
int secondPeak = 0;
int secondPeakScore = 0;
for (int x = 0; x < numBuckets; x++)
{
int distanceToBiggest = x - firstPeak;
// Encourage more distant second peaks by multiplying by square of distance.
int score = buckets[x] * distanceToBiggest * distanceToBiggest;
if (score > secondPeakScore)
{
secondPeak = x;
secondPeakScore = score;
}
}
// Make sure firstPeak corresponds to the black peak.
if (firstPeak > secondPeak)
{
int temp = firstPeak;
firstPeak = secondPeak;
secondPeak = temp;
}
// If there is too little contrast in the image to pick a meaningful black point, throw rather
// than waste time trying to decode the image, and risk false positives.
// TODO: It might be worth comparing the brightest and darkest pixels seen, rather than the
// two peaks, to determine the contrast.
if (secondPeak - firstPeak <= numBuckets >> 4)
{
return false;
}
// Find a valley between them that is low and closer to the white peak.
int bestValley = secondPeak - 1;
int bestValleyScore = -1;
for (int x = secondPeak - 1; x > firstPeak; x--)
{
int fromFirst = x - firstPeak;
int score = fromFirst*fromFirst*(secondPeak - x)*(maxBucketCount - buckets[x]);
if (score > bestValleyScore)
{
bestValley = x;
bestValleyScore = score;
}
}
blackPoint = bestValley << LUMINANCE_SHIFT;
return true;
}
}
}

View File

@@ -1,197 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common
{
/// <summary> Implementations of this class can, given locations of finder patterns for a QR code in an
/// image, sample the right points in the image to reconstruct the QR code, accounting for
/// perspective distortion. It is abstracted since it is relatively expensive and should be allowed
/// to take advantage of platform-specific optimized implementations, like Sun's Java Advanced
/// Imaging library, but which may not be available in other environments such as J2ME, and vice
/// versa.
///
/// The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)}
/// with an instance of a class which implements this interface.
/// </summary>
/// <author> Sean Owen</author>
public abstract class GridSampler
{
/// <returns> the current implementation of <see cref="GridSampler"/>
/// </returns>
public static GridSampler Instance
{
get
{
return gridSampler;
}
}
private static GridSampler gridSampler = new DefaultGridSampler();
/// <summary> Sets the implementation of <see cref="GridSampler"/> used by the library. One global
/// instance is stored, which may sound problematic. But, the implementation provided
/// ought to be appropriate for the entire platform, and all uses of this library
/// in the whole lifetime of the JVM. For instance, an Android activity can swap in
/// an implementation that takes advantage of native platform libraries.
/// </summary>
/// <param name="newGridSampler">The platform-specific object to install.</param>
public static void setGridSampler(GridSampler newGridSampler)
{
if (newGridSampler == null)
{
throw new System.ArgumentException();
}
gridSampler = newGridSampler;
}
/// <summary>
/// <p>Samples an image for a square matrix of bits of the given dimension. This is used to extract
/// the black/white modules of a 2D barcode like a QR Code found in an image. Because this barcode
/// may be rotated or perspective-distorted, the caller supplies four points in the source image
/// that define known points in the barcode, so that the image may be sampled appropriately.</p>
/// <p>The last eight "from" parameters are four X/Y coordinate pairs of locations of points in
/// the image that define some significant points in the image to be sample. For example,
/// these may be the location of finder pattern in a QR Code.</p>
/// <p>The first eight "to" parameters are four X/Y coordinate pairs measured in the destination
/// <see cref="BitMatrix"/>, from the top left, where the known points in the image given by the "from"
/// parameters map to.</p>
/// <p>These 16 parameters define the transformation needed to sample the image.</p>
/// </summary>
/// <param name="image">image to sample</param>
/// <param name="dimensionX">The dimension X.</param>
/// <param name="dimensionY">The dimension Y.</param>
/// <param name="p1ToX">The p1 preimage X.</param>
/// <param name="p1ToY">The p1 preimage Y.</param>
/// <param name="p2ToX">The p2 preimage X.</param>
/// <param name="p2ToY">The p2 preimage Y.</param>
/// <param name="p3ToX">The p3 preimage X.</param>
/// <param name="p3ToY">The p3 preimage Y.</param>
/// <param name="p4ToX">The p4 preimage X.</param>
/// <param name="p4ToY">The p4 preimage Y.</param>
/// <param name="p1FromX">The p1 image X.</param>
/// <param name="p1FromY">The p1 image Y.</param>
/// <param name="p2FromX">The p2 image X.</param>
/// <param name="p2FromY">The p2 image Y.</param>
/// <param name="p3FromX">The p3 image X.</param>
/// <param name="p3FromY">The p3 image Y.</param>
/// <param name="p4FromX">The p4 image X.</param>
/// <param name="p4FromY">The p4 image Y.</param>
/// <returns>
/// <see cref="BitMatrix"/> representing a grid of points sampled from the image within a region
/// defined by the "from" parameters
/// </returns>
/// <throws> ReaderException if image can't be sampled, for example, if the transformation defined </throws>
public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY);
public virtual BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform)
{
throw new System.NotSupportedException();
}
/// <summary> <p>Checks a set of points that have been transformed to sample points on an image against
/// the image's dimensions to see if the point are even within the image.</p>
///
/// <p>This method will actually "nudge" the endpoints back onto the image if they are found to be
/// barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder
/// patterns in an image where the QR Code runs all the way to the image border.</p>
///
/// <p>For efficiency, the method will check points from either end of the line until one is found
/// to be within the image. Because the set of points are assumed to be linear, this is valid.</p>
///
/// </summary>
/// <param name="image">image into which the points should map
/// </param>
/// <param name="points">actual points in x1,y1,...,xn,yn form
/// </param>
protected internal static bool checkAndNudgePoints(BitMatrix image, float[] points)
{
int width = image.Width;
int height = image.Height;
// Check and nudge points from start until we see some that are OK:
bool nudged = true;
for (int offset = 0; offset < points.Length && nudged; offset += 2)
{
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
int x = (int)points[offset];
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
int y = (int)points[offset + 1];
if (x < -1 || x > width || y < -1 || y > height)
{
return false;
}
nudged = false;
if (x == -1)
{
points[offset] = 0.0f;
nudged = true;
}
else if (x == width)
{
points[offset] = width - 1;
nudged = true;
}
if (y == -1)
{
points[offset + 1] = 0.0f;
nudged = true;
}
else if (y == height)
{
points[offset + 1] = height - 1;
nudged = true;
}
}
// Check and nudge points from end:
nudged = true;
for (int offset = points.Length - 2; offset >= 0 && nudged; offset -= 2)
{
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
int x = (int)points[offset];
//UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
int y = (int)points[offset + 1];
if (x < -1 || x > width || y < -1 || y > height)
{
return false;
}
nudged = false;
if (x == -1)
{
points[offset] = 0.0f;
nudged = true;
}
else if (x == width)
{
points[offset] = width - 1;
nudged = true;
}
if (y == -1)
{
points[offset + 1] = 0.0f;
nudged = true;
}
else if (y == height)
{
points[offset + 1] = height - 1;
nudged = true;
}
}
return true;
}
}
}

View File

@@ -1,288 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common
{
/// <summary> This class implements a local thresholding algorithm, which while slower than the
/// GlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for
/// high frequency images of barcodes with black data on white backgrounds. For this application,
/// it does a much better job than a global blackpoint with severe shadows and gradients.
/// However it tends to produce artifacts on lower frequency images and is therefore not
/// a good general purpose binarizer for uses outside ZXing.
///
/// This class extends GlobalHistogramBinarizer, using the older histogram approach for 1D readers,
/// and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already
/// inherently local, and only fails for horizontal gradients. We can revisit that problem later,
/// but for now it was not a win to use local blocks for 1D.
///
/// This Binarizer is the default for the unit tests and the recommended class for library users.
///
/// </summary>
/// <author> dswitkin@google.com (Daniel Switkin)
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class HybridBinarizer : GlobalHistogramBinarizer
{
override public BitMatrix BlackMatrix
{
get
{
binarizeEntireImage();
return matrix;
}
}
// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels.
// So this is the smallest dimension in each axis we can accept.
private const int BLOCK_SIZE_POWER = 3;
private const int BLOCK_SIZE = 1 << BLOCK_SIZE_POWER; // ...0100...00
private const int BLOCK_SIZE_MASK = BLOCK_SIZE - 1; // ...0011...11
private const int MINIMUM_DIMENSION = 40;
private const int MIN_DYNAMIC_RANGE = 24;
private BitMatrix matrix = null;
public HybridBinarizer(LuminanceSource source)
: base(source)
{
}
public override Binarizer createBinarizer(LuminanceSource source)
{
return new HybridBinarizer(source);
}
/// <summary>
/// Calculates the final BitMatrix once for all requests. This could be called once from the
/// constructor instead, but there are some advantages to doing it lazily, such as making
/// profiling easier, and not doing heavy lifting when callers don't expect it.
/// </summary>
private void binarizeEntireImage()
{
if (matrix == null)
{
LuminanceSource source = LuminanceSource;
int width = source.Width;
int height = source.Height;
if (width >= MINIMUM_DIMENSION && height >= MINIMUM_DIMENSION)
{
byte[] luminances = source.Matrix;
int subWidth = width >> BLOCK_SIZE_POWER;
if ((width & BLOCK_SIZE_MASK) != 0)
{
subWidth++;
}
int subHeight = height >> BLOCK_SIZE_POWER;
if ((height & BLOCK_SIZE_MASK) != 0)
{
subHeight++;
}
int[][] blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width, height);
var newMatrix = new BitMatrix(width, height);
calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints, newMatrix);
matrix = newMatrix;
}
else
{
// If the image is too small, fall back to the global histogram approach.
matrix = base.BlackMatrix;
}
}
}
/// <summary>
/// For each 8x8 block in the image, calculate the average black point using a 5x5 grid
/// of the blocks around it. Also handles the corner cases (fractional blocks are computed based
/// on the last 8 pixels in the row/column which are also used in the previous block).
/// </summary>
/// <param name="luminances">The luminances.</param>
/// <param name="subWidth">Width of the sub.</param>
/// <param name="subHeight">Height of the sub.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="blackPoints">The black points.</param>
/// <param name="matrix">The matrix.</param>
private static void calculateThresholdForBlock(byte[] luminances, int subWidth, int subHeight, int width, int height, int[][] blackPoints, BitMatrix matrix)
{
for (int y = 0; y < subHeight; y++)
{
int yoffset = y << BLOCK_SIZE_POWER;
int maxYOffset = height - BLOCK_SIZE;
if (yoffset > maxYOffset)
{
yoffset = maxYOffset;
}
for (int x = 0; x < subWidth; x++)
{
int xoffset = x << BLOCK_SIZE_POWER;
int maxXOffset = width - BLOCK_SIZE;
if (xoffset > maxXOffset)
{
xoffset = maxXOffset;
}
int left = cap(x, 2, subWidth - 3);
int top = cap(y, 2, subHeight - 3);
int sum = 0;
for (int z = -2; z <= 2; z++)
{
int[] blackRow = blackPoints[top + z];
sum += blackRow[left - 2];
sum += blackRow[left - 1];
sum += blackRow[left];
sum += blackRow[left + 1];
sum += blackRow[left + 2];
}
int average = sum / 25;
thresholdBlock(luminances, xoffset, yoffset, average, width, matrix);
}
}
}
private static int cap(int value, int min, int max)
{
return value < min ? min : value > max ? max : value;
}
/// <summary>
/// Applies a single threshold to an 8x8 block of pixels.
/// </summary>
/// <param name="luminances">The luminances.</param>
/// <param name="xoffset">The xoffset.</param>
/// <param name="yoffset">The yoffset.</param>
/// <param name="threshold">The threshold.</param>
/// <param name="stride">The stride.</param>
/// <param name="matrix">The matrix.</param>
private static void thresholdBlock(byte[] luminances, int xoffset, int yoffset, int threshold, int stride, BitMatrix matrix)
{
int offset = (yoffset * stride) + xoffset;
for (int y = 0; y < BLOCK_SIZE; y++, offset += stride)
{
for (int x = 0; x < BLOCK_SIZE; x++)
{
int pixel = luminances[offset + x] & 0xff;
// Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
matrix[xoffset + x, yoffset + y] = (pixel <= threshold);
}
}
}
/// <summary>
/// Calculates a single black point for each 8x8 block of pixels and saves it away.
/// See the following thread for a discussion of this algorithm:
/// http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0
/// </summary>
/// <param name="luminances">The luminances.</param>
/// <param name="subWidth">Width of the sub.</param>
/// <param name="subHeight">Height of the sub.</param>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns></returns>
private static int[][] calculateBlackPoints(byte[] luminances, int subWidth, int subHeight, int width, int height)
{
int[][] blackPoints = new int[subHeight][];
for (int i = 0; i < subHeight; i++)
{
blackPoints[i] = new int[subWidth];
}
for (int y = 0; y < subHeight; y++)
{
int yoffset = y << BLOCK_SIZE_POWER;
int maxYOffset = height - BLOCK_SIZE;
if (yoffset > maxYOffset)
{
yoffset = maxYOffset;
}
for (int x = 0; x < subWidth; x++)
{
int xoffset = x << BLOCK_SIZE_POWER;
int maxXOffset = width - BLOCK_SIZE;
if (xoffset > maxXOffset)
{
xoffset = maxXOffset;
}
int sum = 0;
int min = 0xFF;
int max = 0;
for (int yy = 0, offset = yoffset * width + xoffset; yy < BLOCK_SIZE; yy++, offset += width)
{
for (int xx = 0; xx < BLOCK_SIZE; xx++)
{
int pixel = luminances[offset + xx] & 0xFF;
// still looking for good contrast
sum += pixel;
if (pixel < min)
{
min = pixel;
}
if (pixel > max)
{
max = pixel;
}
}
// short-circuit min/max tests once dynamic range is met
if (max - min > MIN_DYNAMIC_RANGE)
{
// finish the rest of the rows quickly
for (yy++, offset += width; yy < BLOCK_SIZE; yy++, offset += width)
{
for (int xx = 0; xx < BLOCK_SIZE; xx++)
{
sum += luminances[offset + xx] & 0xFF;
}
}
}
}
// The default estimate is the average of the values in the block.
int average = sum >> (BLOCK_SIZE_POWER * 2);
if (max - min <= MIN_DYNAMIC_RANGE)
{
// If variation within the block is low, assume this is a block with only light or only
// dark pixels. In that case we do not want to use the average, as it would divide this
// low contrast area into black and white pixels, essentially creating data out of noise.
//
// The default assumption is that the block is light/background. Since no estimate for
// the level of dark pixels exists locally, use half the min for the block.
average = min >> 1;
if (y > 0 && x > 0)
{
// Correct the "white background" assumption for blocks that have neighbors by comparing
// the pixels in this block to the previously calculated black points. This is based on
// the fact that dark barcode symbology is always surrounded by some amount of light
// background for which reasonable black point estimates were made. The bp estimated at
// the boundaries is used for the interior.
// The (min < bp) is arbitrary but works better than other heuristics that were tried.
int averageNeighborBlackPoint = (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) +
blackPoints[y - 1][x - 1]) >> 2;
if (min < averageNeighborBlackPoint)
{
average = averageNeighborBlackPoint;
}
}
}
blackPoints[y][x] = average;
}
}
return blackPoints;
}
}
}

View File

@@ -1,159 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common
{
/// <summary> <p>This class implements a perspective transform in two dimensions. Given four source and four
/// destination points, it will compute the transformation implied between them. The code is based
/// directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class PerspectiveTransform
{
private float a11;
private float a12;
private float a13;
private float a21;
private float a22;
private float a23;
private float a31;
private float a32;
private float a33;
private PerspectiveTransform(float a11, float a21, float a31, float a12, float a22, float a32, float a13, float a23, float a33)
{
this.a11 = a11;
this.a12 = a12;
this.a13 = a13;
this.a21 = a21;
this.a22 = a22;
this.a23 = a23;
this.a31 = a31;
this.a32 = a32;
this.a33 = a33;
}
public static PerspectiveTransform quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p, float x3p, float y3p)
{
PerspectiveTransform qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
PerspectiveTransform sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
return sToQ.times(qToS);
}
public void transformPoints(float[] points)
{
int max = points.Length;
float a11 = this.a11;
float a12 = this.a12;
float a13 = this.a13;
float a21 = this.a21;
float a22 = this.a22;
float a23 = this.a23;
float a31 = this.a31;
float a32 = this.a32;
float a33 = this.a33;
for (int i = 0; i < max; i += 2)
{
float x = points[i];
float y = points[i + 1];
float denominator = a13 * x + a23 * y + a33;
points[i] = (a11 * x + a21 * y + a31) / denominator;
points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
}
}
/// <summary>Convenience method, not optimized for performance. </summary>
public void transformPoints(float[] xValues, float[] yValues)
{
int n = xValues.Length;
for (int i = 0; i < n; i++)
{
float x = xValues[i];
float y = yValues[i];
float denominator = a13 * x + a23 * y + a33;
xValues[i] = (a11 * x + a21 * y + a31) / denominator;
yValues[i] = (a12 * x + a22 * y + a32) / denominator;
}
}
public static PerspectiveTransform squareToQuadrilateral(float x0, float y0,
float x1, float y1,
float x2, float y2,
float x3, float y3)
{
float dx3 = x0 - x1 + x2 - x3;
float dy3 = y0 - y1 + y2 - y3;
if (dx3 == 0.0f && dy3 == 0.0f)
{
// Affine
return new PerspectiveTransform(x1 - x0, x2 - x1, x0,
y1 - y0, y2 - y1, y0,
0.0f, 0.0f, 1.0f);
}
else
{
float dx1 = x1 - x2;
float dx2 = x3 - x2;
float dy1 = y1 - y2;
float dy2 = y3 - y2;
float denominator = dx1*dy2 - dx2*dy1;
float a13 = (dx3*dy2 - dx2*dy3)/denominator;
float a23 = (dx1*dy3 - dx3*dy1)/denominator;
return new PerspectiveTransform(x1 - x0 + a13*x1, x3 - x0 + a23*x3, x0,
y1 - y0 + a13*y1, y3 - y0 + a23*y3, y0,
a13, a23, 1.0f);
}
}
public static PerspectiveTransform quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)
{
// Here, the adjoint serves as the inverse:
return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
}
internal PerspectiveTransform buildAdjoint()
{
// Adjoint is the transpose of the cofactor matrix:
return new PerspectiveTransform(a22 * a33 - a23 * a32,
a23 * a31 - a21 * a33,
a21 * a32 - a22 * a31,
a13 * a32 - a12 * a33,
a11 * a33 - a13 * a31,
a12 * a31 - a11 * a32,
a12 * a23 - a13 * a22,
a13 * a21 - a11 * a23,
a11 * a22 - a12 * a21);
}
internal PerspectiveTransform times(PerspectiveTransform other)
{
return new PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13,
a11 * other.a21 + a21 * other.a22 + a31 * other.a23,
a11 * other.a31 + a21 * other.a32 + a31 * other.a33,
a12 * other.a11 + a22 * other.a12 + a32 * other.a13,
a12 * other.a21 + a22 * other.a22 + a32 * other.a23,
a12 * other.a31 + a22 * other.a32 + a32 * other.a33,
a13 * other.a11 + a23 * other.a12 + a33 * other.a13,
a13 * other.a21 + a23 * other.a22 + a33 * other.a23,
a13 * other.a31 + a23 * other.a32 + a33 * other.a33);
}
}
}

View File

@@ -1,262 +0,0 @@
/*
* Copyright (C) 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace ZXing.Common
{
/// <summary>
/// Common string-related functions.
/// </summary>
/// <author>Sean Owen</author>
/// <author>Alex Dupre</author>
public static class StringUtils
{
private const String PLATFORM_DEFAULT_ENCODING = "UTF-8";
public static String SHIFT_JIS = "SJIS";
public static String GB2312 = "GB2312";
private const String EUC_JP = "EUC-JP";
private const String UTF8 = "UTF-8";
private const String ISO88591 = "ISO-8859-1";
private static readonly bool ASSUME_SHIFT_JIS =
String.Compare(SHIFT_JIS, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(EUC_JP, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0;
/// <summary>
/// Guesses the encoding.
/// </summary>
/// <param name="bytes">bytes encoding a string, whose encoding should be guessed</param>
/// <param name="hints">decode hints if applicable</param>
/// <returns>name of guessed encoding; at the moment will only guess one of:
/// {@link #SHIFT_JIS}, {@link #UTF8}, {@link #ISO88591}, or the platform
/// default encoding if none of these can possibly be correct</returns>
public static String guessEncoding(byte[] bytes, IDictionary<DecodeHintType, object> hints)
{
if (hints != null && hints.ContainsKey(DecodeHintType.CHARACTER_SET))
{
String characterSet = (String)hints[DecodeHintType.CHARACTER_SET];
if (characterSet != null)
{
return characterSet;
}
}
// For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
// which should be by far the most common encodings.
int length = bytes.Length;
bool canBeISO88591 = true;
bool canBeShiftJIS = true;
bool canBeUTF8 = true;
int utf8BytesLeft = 0;
//int utf8LowChars = 0;
int utf2BytesChars = 0;
int utf3BytesChars = 0;
int utf4BytesChars = 0;
int sjisBytesLeft = 0;
//int sjisLowChars = 0;
int sjisKatakanaChars = 0;
//int sjisDoubleBytesChars = 0;
int sjisCurKatakanaWordLength = 0;
int sjisCurDoubleBytesWordLength = 0;
int sjisMaxKatakanaWordLength = 0;
int sjisMaxDoubleBytesWordLength = 0;
//int isoLowChars = 0;
//int isoHighChars = 0;
int isoHighOther = 0;
bool utf8bom = bytes.Length > 3 &&
bytes[0] == 0xEF &&
bytes[1] == 0xBB &&
bytes[2] == 0xBF;
for (int i = 0;
i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8);
i++)
{
int value = bytes[i] & 0xFF;
// UTF-8 stuff
if (canBeUTF8)
{
if (utf8BytesLeft > 0)
{
if ((value & 0x80) == 0)
{
canBeUTF8 = false;
}
else
{
utf8BytesLeft--;
}
}
else if ((value & 0x80) != 0)
{
if ((value & 0x40) == 0)
{
canBeUTF8 = false;
}
else
{
utf8BytesLeft++;
if ((value & 0x20) == 0)
{
utf2BytesChars++;
}
else
{
utf8BytesLeft++;
if ((value & 0x10) == 0)
{
utf3BytesChars++;
}
else
{
utf8BytesLeft++;
if ((value & 0x08) == 0)
{
utf4BytesChars++;
}
else
{
canBeUTF8 = false;
}
}
}
}
} //else {
//utf8LowChars++;
//}
}
// ISO-8859-1 stuff
if (canBeISO88591)
{
if (value > 0x7F && value < 0xA0)
{
canBeISO88591 = false;
}
else if (value > 0x9F)
{
if (value < 0xC0 || value == 0xD7 || value == 0xF7)
{
isoHighOther++;
} //else {
//isoHighChars++;
//}
} //else {
//isoLowChars++;
//}
}
// Shift_JIS stuff
if (canBeShiftJIS)
{
if (sjisBytesLeft > 0)
{
if (value < 0x40 || value == 0x7F || value > 0xFC)
{
canBeShiftJIS = false;
}
else
{
sjisBytesLeft--;
}
}
else if (value == 0x80 || value == 0xA0 || value > 0xEF)
{
canBeShiftJIS = false;
}
else if (value > 0xA0 && value < 0xE0)
{
sjisKatakanaChars++;
sjisCurDoubleBytesWordLength = 0;
sjisCurKatakanaWordLength++;
if (sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength)
{
sjisMaxKatakanaWordLength = sjisCurKatakanaWordLength;
}
}
else if (value > 0x7F)
{
sjisBytesLeft++;
//sjisDoubleBytesChars++;
sjisCurKatakanaWordLength = 0;
sjisCurDoubleBytesWordLength++;
if (sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength)
{
sjisMaxDoubleBytesWordLength = sjisCurDoubleBytesWordLength;
}
}
else
{
//sjisLowChars++;
sjisCurKatakanaWordLength = 0;
sjisCurDoubleBytesWordLength = 0;
}
}
}
if (canBeUTF8 && utf8BytesLeft > 0)
{
canBeUTF8 = false;
}
if (canBeShiftJIS && sjisBytesLeft > 0)
{
canBeShiftJIS = false;
}
// Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done
if (canBeUTF8 && (utf8bom || utf2BytesChars + utf3BytesChars + utf4BytesChars > 0))
{
return UTF8;
}
// Easy -- if assuming Shift_JIS or at least 3 valid consecutive not-ascii characters (and no evidence it can't be), done
if (canBeShiftJIS && (ASSUME_SHIFT_JIS || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3))
{
return SHIFT_JIS;
}
// Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short words. The crude heuristic is:
// - If we saw
// - only two consecutive katakana chars in the whole text, or
// - at least 10% of bytes that could be "upper" not-alphanumeric Latin1,
// - then we conclude Shift_JIS, else ISO-8859-1
if (canBeISO88591 && canBeShiftJIS)
{
return (sjisMaxKatakanaWordLength == 2 && sjisKatakanaChars == 2) || isoHighOther * 10 >= length
? SHIFT_JIS : ISO88591;
}
// Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding
if (canBeISO88591)
{
return ISO88591;
}
if (canBeShiftJIS)
{
return SHIFT_JIS;
}
if (canBeUTF8)
{
return UTF8;
}
// Otherwise, we take a wild guess with platform encoding
return PLATFORM_DEFAULT_ENCODING;
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2012 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common.Detector
{
public static class MathUtils
{
/// <summary>
/// Ends up being a bit faster than {@link Math#round(float)}. This merely rounds its
/// argument to the nearest int, where x.5 rounds up to x+1. Semantics of this shortcut
/// differ slightly from {@link Math#round(float)} in that half rounds down for negative
/// values. -2.5 rounds to -3, not -2. For purposes here it makes no difference.
/// </summary>
/// <param name="d">real value to round</param>
/// <returns>nearest <c>int</c></returns>
public static int round(float d)
{
if (float.IsNaN(d))
return 0;
if (float.IsPositiveInfinity(d))
return int.MaxValue;
return (int)(d + (d < 0.0f ? -0.5f : 0.5f));
}
public static float distance(float aX, float aY, float bX, float bY)
{
float xDiff = aX - bX;
float yDiff = aY - bY;
return (float)Math.Sqrt(xDiff * xDiff + yDiff * yDiff);
}
public static float distance(int aX, int aY, int bX, int bY)
{
int xDiff = aX - bX;
int yDiff = aY - bY;
return (float)Math.Sqrt(xDiff * xDiff + yDiff * yDiff);
}
}
}

View File

@@ -1,252 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common.Detector
{
/// <summary> <p>A somewhat generic detector that looks for a barcode-like rectangular region within an image.
/// It looks within a mostly white region of an image for a region of black and white, but mostly
/// black. It returns the four corners of the region, as best it can determine.</p>
///
/// </summary>
/// <author> Sean Owen
/// </author>
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
/// </author>
public sealed class MonochromeRectangleDetector
{
private const int MAX_MODULES = 32;
private BitMatrix image;
public MonochromeRectangleDetector(BitMatrix image)
{
this.image = image;
}
/// <summary> <p>Detects a rectangular region of black and white -- mostly black -- with a region of mostly
/// white, in an image.</p>
///
/// </summary>
/// <returns> {@link ResultPoint}[] describing the corners of the rectangular region. The first and
/// last points are opposed on the diagonal, as are the second and third. The first point will be
/// the topmost point and the last, the bottommost. The second point will be leftmost and the
/// third, the rightmost
/// </returns>
public ResultPoint[] detect()
{
int height = image.Height;
int width = image.Width;
int halfHeight = height >> 1;
int halfWidth = width >> 1;
int deltaY = System.Math.Max(1, height / (MAX_MODULES << 3));
int deltaX = System.Math.Max(1, width / (MAX_MODULES << 3));
int top = 0;
int bottom = height;
int left = 0;
int right = width;
ResultPoint pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, -deltaY, top, bottom, halfWidth >> 1);
if (pointA == null)
return null;
top = (int)pointA.Y - 1;
ResultPoint pointB = findCornerFromCenter(halfWidth, -deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1);
if (pointB == null)
return null;
left = (int)pointB.X - 1;
ResultPoint pointC = findCornerFromCenter(halfWidth, deltaX, left, right, halfHeight, 0, top, bottom, halfHeight >> 1);
if (pointC == null)
return null;
right = (int)pointC.X + 1;
ResultPoint pointD = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, deltaY, top, bottom, halfWidth >> 1);
if (pointD == null)
return null;
bottom = (int)pointD.Y + 1;
// Go try to find point A again with better information -- might have been off at first.
pointA = findCornerFromCenter(halfWidth, 0, left, right, halfHeight, -deltaY, top, bottom, halfWidth >> 2);
if (pointA == null)
return null;
return new ResultPoint[] { pointA, pointB, pointC, pointD };
}
/// <summary> Attempts to locate a corner of the barcode by scanning up, down, left or right from a center
/// point which should be within the barcode.
///
/// </summary>
/// <param name="centerX">center's x component (horizontal)
/// </param>
/// <param name="deltaX">same as deltaY but change in x per step instead
/// </param>
/// <param name="left">minimum value of x
/// </param>
/// <param name="right">maximum value of x
/// </param>
/// <param name="centerY">center's y component (vertical)
/// </param>
/// <param name="deltaY">change in y per step. If scanning up this is negative; down, positive;
/// left or right, 0
/// </param>
/// <param name="top">minimum value of y to search through (meaningless when di == 0)
/// </param>
/// <param name="bottom">maximum value of y
/// </param>
/// <param name="maxWhiteRun">maximum run of white pixels that can still be considered to be within
/// the barcode
/// </param>
/// <returns> a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found
/// </returns>
private ResultPoint findCornerFromCenter(int centerX, int deltaX, int left, int right, int centerY, int deltaY, int top, int bottom, int maxWhiteRun)
{
int[] lastRange = null;
for (int y = centerY, x = centerX; y < bottom && y >= top && x < right && x >= left; y += deltaY, x += deltaX)
{
int[] range;
if (deltaX == 0)
{
// horizontal slices, up and down
range = blackWhiteRange(y, maxWhiteRun, left, right, true);
}
else
{
// vertical slices, left and right
range = blackWhiteRange(x, maxWhiteRun, top, bottom, false);
}
if (range == null)
{
if (lastRange == null)
{
return null;
}
// lastRange was found
if (deltaX == 0)
{
int lastY = y - deltaY;
if (lastRange[0] < centerX)
{
if (lastRange[1] > centerX)
{
// straddle, choose one or the other based on direction
return new ResultPoint(deltaY > 0 ? lastRange[0] : lastRange[1], lastY);
}
return new ResultPoint(lastRange[0], lastY);
}
else
{
return new ResultPoint(lastRange[1], lastY);
}
}
else
{
int lastX = x - deltaX;
if (lastRange[0] < centerY)
{
if (lastRange[1] > centerY)
{
return new ResultPoint(lastX, deltaX < 0 ? lastRange[0] : lastRange[1]);
}
return new ResultPoint(lastX, lastRange[0]);
}
else
{
return new ResultPoint(lastX, lastRange[1]);
}
}
}
lastRange = range;
}
return null;
}
/// <summary> Computes the start and end of a region of pixels, either horizontally or vertically, that could
/// be part of a Data Matrix barcode.
///
/// </summary>
/// <param name="fixedDimension">if scanning horizontally, this is the row (the fixed vertical location)
/// where we are scanning. If scanning vertically it's the column, the fixed horizontal location
/// </param>
/// <param name="maxWhiteRun">largest run of white pixels that can still be considered part of the
/// barcode region
/// </param>
/// <param name="minDim">minimum pixel location, horizontally or vertically, to consider
/// </param>
/// <param name="maxDim">maximum pixel location, horizontally or vertically, to consider
/// </param>
/// <param name="horizontal">if true, we're scanning left-right, instead of up-down
/// </param>
/// <returns> int[] with start and end of found range, or null if no such range is found
/// (e.g. only white was found)
/// </returns>
private int[] blackWhiteRange(int fixedDimension, int maxWhiteRun, int minDim, int maxDim, bool horizontal)
{
int center = (minDim + maxDim) >> 1;
// Scan left/up first
int start = center;
while (start >= minDim)
{
if (horizontal ? image[start, fixedDimension] : image[fixedDimension, start])
{
start--;
}
else
{
int whiteRunStart = start;
do
{
start--;
}
while (start >= minDim && !(horizontal ? image[start, fixedDimension] : image[fixedDimension, start]));
int whiteRunSize = whiteRunStart - start;
if (start < minDim || whiteRunSize > maxWhiteRun)
{
start = whiteRunStart;
break;
}
}
}
start++;
// Then try right/down
int end = center;
while (end < maxDim)
{
if (horizontal ? image[end, fixedDimension] : image[fixedDimension, end])
{
end++;
}
else
{
int whiteRunStart = end;
do
{
end++;
}
while (end < maxDim && !(horizontal ? image[end, fixedDimension] : image[fixedDimension, end]));
int whiteRunSize = end - whiteRunStart;
if (end >= maxDim || whiteRunSize > maxWhiteRun)
{
end = whiteRunStart;
break;
}
}
}
end--;
return end > start ? new int[] { start, end } : null;
}
}
}

View File

@@ -1,433 +0,0 @@
/*
* Copyright 2010 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common.Detector
{
/// <summary>
/// Detects a candidate barcode-like rectangular region within an image. It
/// starts around the center of the image, increases the size of the candidate
/// region until it finds a white rectangular region. By keeping track of the
/// last black points it encountered, it determines the corners of the barcode.
/// </summary>
/// <author>David Olivier</author>
public sealed class WhiteRectangleDetector
{
private const int INIT_SIZE = 10;
private const int CORR = 1;
private readonly BitMatrix image;
private readonly int height;
private readonly int width;
private readonly int leftInit;
private readonly int rightInit;
private readonly int downInit;
private readonly int upInit;
/// <summary>
/// Creates a WhiteRectangleDetector instance
/// </summary>
/// <param name="image">The image.</param>
/// <returns>null, if image is too small, otherwise a WhiteRectangleDetector instance</returns>
public static WhiteRectangleDetector Create(BitMatrix image)
{
if (image == null)
return null;
var instance = new WhiteRectangleDetector(image);
if (instance.upInit < 0 || instance.leftInit < 0 || instance.downInit >= instance.height || instance.rightInit >= instance.width)
{
return null;
}
return instance;
}
/// <summary>
/// Creates a WhiteRectangleDetector instance
/// </summary>
/// <param name="image">barcode image to find a rectangle in</param>
/// <param name="initSize">initial size of search area around center</param>
/// <param name="x">x position of search center</param>
/// <param name="y">y position of search center</param>
/// <returns>
/// null, if image is too small, otherwise a WhiteRectangleDetector instance
/// </returns>
public static WhiteRectangleDetector Create(BitMatrix image, int initSize, int x, int y)
{
var instance = new WhiteRectangleDetector(image, initSize, x, y);
if (instance.upInit < 0 || instance.leftInit < 0 || instance.downInit >= instance.height || instance.rightInit >= instance.width)
{
return null;
}
return instance;
}
/// <summary>
/// Initializes a new instance of the <see cref="WhiteRectangleDetector"/> class.
/// </summary>
/// <param name="image">The image.</param>
/// <exception cref="ArgumentException">if image is too small</exception>
internal WhiteRectangleDetector(BitMatrix image)
: this(image, INIT_SIZE, image.Width/2, image.Height/2)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="WhiteRectangleDetector"/> class.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="initSize">Size of the init.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
internal WhiteRectangleDetector(BitMatrix image, int initSize, int x, int y)
{
this.image = image;
height = image.Height;
width = image.Width;
int halfsize = initSize / 2;
leftInit = x - halfsize;
rightInit = x + halfsize;
upInit = y - halfsize;
downInit = y + halfsize;
}
/// <summary>
/// Detects a candidate barcode-like rectangular region within an image. It
/// starts around the center of the image, increases the size of the candidate
/// region until it finds a white rectangular region.
/// </summary>
/// <returns><see cref="ResultPoint" />[] describing the corners of the rectangular
/// region. The first and last points are opposed on the diagonal, as
/// are the second and third. The first point will be the topmost
/// point and the last, the bottommost. The second point will be
/// leftmost and the third, the rightmost</returns>
public ResultPoint[] detect()
{
int left = leftInit;
int right = rightInit;
int up = upInit;
int down = downInit;
bool sizeExceeded = false;
bool aBlackPointFoundOnBorder = true;
bool atLeastOneBlackPointFoundOnBorder = false;
bool atLeastOneBlackPointFoundOnRight = false;
bool atLeastOneBlackPointFoundOnBottom = false;
bool atLeastOneBlackPointFoundOnLeft = false;
bool atLeastOneBlackPointFoundOnTop = false;
while (aBlackPointFoundOnBorder)
{
aBlackPointFoundOnBorder = false;
// .....
// . |
// .....
bool rightBorderNotWhite = true;
while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < width)
{
rightBorderNotWhite = containsBlackPoint(up, down, right, false);
if (rightBorderNotWhite)
{
right++;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnRight = true;
}
else if (!atLeastOneBlackPointFoundOnRight)
{
right++;
}
}
if (right >= width)
{
sizeExceeded = true;
break;
}
// .....
// . .
// .___.
bool bottomBorderNotWhite = true;
while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < height)
{
bottomBorderNotWhite = containsBlackPoint(left, right, down, true);
if (bottomBorderNotWhite)
{
down++;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnBottom = true;
}
else if (!atLeastOneBlackPointFoundOnBottom)
{
down++;
}
}
if (down >= height)
{
sizeExceeded = true;
break;
}
// .....
// | .
// .....
bool leftBorderNotWhite = true;
while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0)
{
leftBorderNotWhite = containsBlackPoint(up, down, left, false);
if (leftBorderNotWhite)
{
left--;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnLeft = true;
}
else if (!atLeastOneBlackPointFoundOnLeft)
{
left--;
}
}
if (left < 0)
{
sizeExceeded = true;
break;
}
// .___.
// . .
// .....
bool topBorderNotWhite = true;
while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0)
{
topBorderNotWhite = containsBlackPoint(left, right, up, true);
if (topBorderNotWhite)
{
up--;
aBlackPointFoundOnBorder = true;
atLeastOneBlackPointFoundOnTop = true;
}
else if (!atLeastOneBlackPointFoundOnTop)
{
up--;
}
}
if (up < 0)
{
sizeExceeded = true;
break;
}
if (aBlackPointFoundOnBorder)
{
atLeastOneBlackPointFoundOnBorder = true;
}
}
if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder)
{
int maxSize = right - left;
ResultPoint z = null;
for (int i = 1; i < maxSize; i++)
{
z = getBlackPointOnSegment(left, down - i, left + i, down);
if (z != null)
{
break;
}
}
if (z == null)
{
return null;
}
ResultPoint t = null;
//go down right
for (int i = 1; i < maxSize; i++)
{
t = getBlackPointOnSegment(left, up + i, left + i, up);
if (t != null)
{
break;
}
}
if (t == null)
{
return null;
}
ResultPoint x = null;
//go down left
for (int i = 1; i < maxSize; i++)
{
x = getBlackPointOnSegment(right, up + i, right - i, up);
if (x != null)
{
break;
}
}
if (x == null)
{
return null;
}
ResultPoint y = null;
//go up left
for (int i = 1; i < maxSize; i++)
{
y = getBlackPointOnSegment(right, down - i, right - i, down);
if (y != null)
{
break;
}
}
if (y == null)
{
return null;
}
return centerEdges(y, z, x, t);
}
else
{
return null;
}
}
private ResultPoint getBlackPointOnSegment(float aX, float aY, float bX, float bY)
{
int dist = MathUtils.round(MathUtils.distance(aX, aY, bX, bY));
float xStep = (bX - aX) / dist;
float yStep = (bY - aY) / dist;
for (int i = 0; i < dist; i++)
{
int x = MathUtils.round(aX + i * xStep);
int y = MathUtils.round(aY + i * yStep);
if (image[x, y])
{
return new ResultPoint(x, y);
}
}
return null;
}
/// <summary>
/// recenters the points of a constant distance towards the center
/// </summary>
/// <param name="y">bottom most point</param>
/// <param name="z">left most point</param>
/// <param name="x">right most point</param>
/// <param name="t">top most point</param>
/// <returns><see cref="ResultPoint"/>[] describing the corners of the rectangular
/// region. The first and last points are opposed on the diagonal, as
/// are the second and third. The first point will be the topmost
/// point and the last, the bottommost. The second point will be
/// leftmost and the third, the rightmost</returns>
private ResultPoint[] centerEdges(ResultPoint y, ResultPoint z,
ResultPoint x, ResultPoint t)
{
//
// t t
// z x
// x OR z
// y y
//
float yi = y.X;
float yj = y.Y;
float zi = z.X;
float zj = z.Y;
float xi = x.X;
float xj = x.Y;
float ti = t.X;
float tj = t.Y;
if (yi < width / 2.0f)
{
return new[]
{
new ResultPoint(ti - CORR, tj + CORR),
new ResultPoint(zi + CORR, zj + CORR),
new ResultPoint(xi - CORR, xj - CORR),
new ResultPoint(yi + CORR, yj - CORR)
};
}
else
{
return new[]
{
new ResultPoint(ti + CORR, tj + CORR),
new ResultPoint(zi + CORR, zj - CORR),
new ResultPoint(xi - CORR, xj + CORR),
new ResultPoint(yi - CORR, yj - CORR)
};
}
}
/// <summary>
/// Determines whether a segment contains a black point
/// </summary>
/// <param name="a">min value of the scanned coordinate</param>
/// <param name="b">max value of the scanned coordinate</param>
/// <param name="fixed">value of fixed coordinate</param>
/// <param name="horizontal">set to true if scan must be horizontal, false if vertical</param>
/// <returns>
/// true if a black point has been found, else false.
/// </returns>
private bool containsBlackPoint(int a, int b, int @fixed, bool horizontal)
{
if (horizontal)
{
for (int x = a; x <= b; x++)
{
if (image[x, @fixed])
{
return true;
}
}
}
else
{
for (int y = a; y <= b; y++)
{
if (image[@fixed, y])
{
return true;
}
}
}
return false;
}
}
}

View File

@@ -1,210 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Common.ReedSolomon
{
/// <summary>
/// <p>This class contains utility methods for performing mathematical operations over
/// the Galois Fields. Operations use a given primitive polynomial in calculations.</p>
/// <p>Throughout this package, elements of the GF are represented as an {@code int}
/// for convenience and speed (but at the cost of memory).
/// </p>
/// </summary>
/// <author>Sean Owen</author>
public sealed class GenericGF
{
public static GenericGF AZTEC_DATA_12 = new GenericGF(0x1069, 4096, 1); // x^12 + x^6 + x^5 + x^3 + 1
public static GenericGF AZTEC_DATA_10 = new GenericGF(0x409, 1024, 1); // x^10 + x^3 + 1
public static GenericGF AZTEC_DATA_6 = new GenericGF(0x43, 64, 1); // x^6 + x + 1
public static GenericGF AZTEC_PARAM = new GenericGF(0x13, 16, 1); // x^4 + x + 1
public static GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
public static GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256, 1); // x^8 + x^5 + x^3 + x^2 + 1
public static GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
public static GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
private int[] expTable;
private int[] logTable;
private GenericGFPoly zero;
private GenericGFPoly one;
private readonly int size;
private readonly int primitive;
private readonly int generatorBase;
/// <summary>
/// Create a representation of GF(size) using the given primitive polynomial.
/// </summary>
/// <param name="primitive">irreducible polynomial whose coefficients are represented by
/// * the bits of an int, where the least-significant bit represents the constant
/// * coefficient</param>
/// <param name="size">the size of the field</param>
/// <param name="genBase">the factor b in the generator polynomial can be 0- or 1-based
/// * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))).
/// * In most cases it should be 1, but for QR code it is 0.</param>
public GenericGF(int primitive, int size, int genBase)
{
this.primitive = primitive;
this.size = size;
this.generatorBase = genBase;
expTable = new int[size];
logTable = new int[size];
int x = 1;
for (int i = 0; i < size; i++)
{
expTable[i] = x;
x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
if (x >= size)
{
x ^= primitive;
x &= size - 1;
}
}
for (int i = 0; i < size - 1; i++)
{
logTable[expTable[i]] = i;
}
// logTable[0] == 0 but this should never be used
zero = new GenericGFPoly(this, new int[] { 0 });
one = new GenericGFPoly(this, new int[] { 1 });
}
internal GenericGFPoly Zero
{
get
{
return zero;
}
}
internal GenericGFPoly One
{
get
{
return one;
}
}
/// <summary>
/// Builds the monomial.
/// </summary>
/// <param name="degree">The degree.</param>
/// <param name="coefficient">The coefficient.</param>
/// <returns>the monomial representing coefficient * x^degree</returns>
internal GenericGFPoly buildMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return zero;
}
int[] coefficients = new int[degree + 1];
coefficients[0] = coefficient;
return new GenericGFPoly(this, coefficients);
}
/// <summary>
/// Implements both addition and subtraction -- they are the same in GF(size).
/// </summary>
/// <returns>sum/difference of a and b</returns>
static internal int addOrSubtract(int a, int b)
{
return a ^ b;
}
/// <summary>
/// Exps the specified a.
/// </summary>
/// <returns>2 to the power of a in GF(size)</returns>
internal int exp(int a)
{
return expTable[a];
}
/// <summary>
/// Logs the specified a.
/// </summary>
/// <param name="a">A.</param>
/// <returns>base 2 log of a in GF(size)</returns>
internal int log(int a)
{
if (a == 0)
{
throw new ArgumentException();
}
return logTable[a];
}
/// <summary>
/// Inverses the specified a.
/// </summary>
/// <returns>multiplicative inverse of a</returns>
internal int inverse(int a)
{
if (a == 0)
{
throw new ArithmeticException();
}
return expTable[size - logTable[a] - 1];
}
/// <summary>
/// Multiplies the specified a with b.
/// </summary>
/// <param name="a">A.</param>
/// <param name="b">The b.</param>
/// <returns>product of a and b in GF(size)</returns>
internal int multiply(int a, int b)
{
if (a == 0 || b == 0)
{
return 0;
}
return expTable[(logTable[a] + logTable[b]) % (size - 1)];
}
/// <summary>
/// Gets the size.
/// </summary>
public int Size
{
get { return size; }
}
/// <summary>
/// Gets the generator base.
/// </summary>
public int GeneratorBase
{
get { return generatorBase; }
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
override public String ToString()
{
return "GF(0x" + primitive.ToString("X") + ',' + size + ')';
}
}
}

View File

@@ -1,331 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Common.ReedSolomon
{
/// <summary>
/// <p>Represents a polynomial whose coefficients are elements of a GF.
/// Instances of this class are immutable.</p>
/// <p>Much credit is due to William Rucklidge since portions of this code are an indirect
/// port of his C++ Reed-Solomon implementation.</p>
/// </summary>
/// <author>Sean Owen</author>
internal sealed class GenericGFPoly
{
private readonly GenericGF field;
private readonly int[] coefficients;
/// <summary>
/// Initializes a new instance of the <see cref="GenericGFPoly"/> class.
/// </summary>
/// <param name="field">the {@link GenericGF} instance representing the field to use
/// to perform computations</param>
/// <param name="coefficients">coefficients as ints representing elements of GF(size), arranged
/// from most significant (highest-power term) coefficient to least significant</param>
/// <exception cref="ArgumentException">if argument is null or empty,
/// or if leading coefficient is 0 and this is not a
/// constant polynomial (that is, it is not the monomial "0")</exception>
internal GenericGFPoly(GenericGF field, int[] coefficients)
{
if (coefficients.Length == 0)
{
throw new ArgumentException();
}
this.field = field;
int coefficientsLength = coefficients.Length;
if (coefficientsLength > 1 && coefficients[0] == 0)
{
// Leading term must be non-zero for anything except the constant polynomial "0"
int firstNonZero = 1;
while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0)
{
firstNonZero++;
}
if (firstNonZero == coefficientsLength)
{
this.coefficients = new int[]{0};
}
else
{
this.coefficients = new int[coefficientsLength - firstNonZero];
Array.Copy(coefficients,
firstNonZero,
this.coefficients,
0,
this.coefficients.Length);
}
}
else
{
this.coefficients = coefficients;
}
}
internal int[] Coefficients
{
get { return coefficients; }
}
/// <summary>
/// degree of this polynomial
/// </summary>
internal int Degree
{
get
{
return coefficients.Length - 1;
}
}
/// <summary>
/// Gets a value indicating whether this <see cref="GenericGFPoly"/> is zero.
/// </summary>
/// <value>true iff this polynomial is the monomial "0"</value>
internal bool isZero
{
get { return coefficients[0] == 0; }
}
/// <summary>
/// coefficient of x^degree term in this polynomial
/// </summary>
/// <param name="degree">The degree.</param>
/// <returns>coefficient of x^degree term in this polynomial</returns>
internal int getCoefficient(int degree)
{
return coefficients[coefficients.Length - 1 - degree];
}
/// <summary>
/// evaluation of this polynomial at a given point
/// </summary>
/// <param name="a">A.</param>
/// <returns>evaluation of this polynomial at a given point</returns>
internal int evaluateAt(int a)
{
int result = 0;
if (a == 0)
{
// Just return the x^0 coefficient
return getCoefficient(0);
}
int size = coefficients.Length;
if (a == 1)
{
// Just the sum of the coefficients
foreach (var coefficient in coefficients)
{
result = GenericGF.addOrSubtract(result, coefficient);
}
return result;
}
result = coefficients[0];
for (int i = 1; i < size; i++)
{
result = GenericGF.addOrSubtract(field.multiply(a, result), coefficients[i]);
}
return result;
}
internal GenericGFPoly addOrSubtract(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (isZero)
{
return other;
}
if (other.isZero)
{
return this;
}
int[] smallerCoefficients = this.coefficients;
int[] largerCoefficients = other.coefficients;
if (smallerCoefficients.Length > largerCoefficients.Length)
{
int[] temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
int[] sumDiff = new int[largerCoefficients.Length];
int lengthDiff = largerCoefficients.Length - smallerCoefficients.Length;
// Copy high-order terms only found in higher-degree polynomial's coefficients
Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
for (int i = lengthDiff; i < largerCoefficients.Length; i++)
{
sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
}
return new GenericGFPoly(field, sumDiff);
}
internal GenericGFPoly multiply(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (isZero || other.isZero)
{
return field.Zero;
}
int[] aCoefficients = this.coefficients;
int aLength = aCoefficients.Length;
int[] bCoefficients = other.coefficients;
int bLength = bCoefficients.Length;
int[] product = new int[aLength + bLength - 1];
for (int i = 0; i < aLength; i++)
{
int aCoeff = aCoefficients[i];
for (int j = 0; j < bLength; j++)
{
product[i + j] = GenericGF.addOrSubtract(product[i + j],
field.multiply(aCoeff, bCoefficients[j]));
}
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly multiply(int scalar)
{
if (scalar == 0)
{
return field.Zero;
}
if (scalar == 1)
{
return this;
}
int size = coefficients.Length;
int[] product = new int[size];
for (int i = 0; i < size; i++)
{
product[i] = field.multiply(coefficients[i], scalar);
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly multiplyByMonomial(int degree, int coefficient)
{
if (degree < 0)
{
throw new ArgumentException();
}
if (coefficient == 0)
{
return field.Zero;
}
int size = coefficients.Length;
int[] product = new int[size + degree];
for (int i = 0; i < size; i++)
{
product[i] = field.multiply(coefficients[i], coefficient);
}
return new GenericGFPoly(field, product);
}
internal GenericGFPoly[] divide(GenericGFPoly other)
{
if (!field.Equals(other.field))
{
throw new ArgumentException("GenericGFPolys do not have same GenericGF field");
}
if (other.isZero)
{
throw new ArgumentException("Divide by 0");
}
GenericGFPoly quotient = field.Zero;
GenericGFPoly remainder = this;
int denominatorLeadingTerm = other.getCoefficient(other.Degree);
int inverseDenominatorLeadingTerm = field.inverse(denominatorLeadingTerm);
while (remainder.Degree >= other.Degree && !remainder.isZero)
{
int degreeDifference = remainder.Degree - other.Degree;
int scale = field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
GenericGFPoly term = other.multiplyByMonomial(degreeDifference, scale);
GenericGFPoly iterationQuotient = field.buildMonomial(degreeDifference, scale);
quotient = quotient.addOrSubtract(iterationQuotient);
remainder = remainder.addOrSubtract(term);
}
return new GenericGFPoly[] { quotient, remainder };
}
public override String ToString()
{
StringBuilder result = new StringBuilder(8 * Degree);
for (int degree = Degree; degree >= 0; degree--)
{
int coefficient = getCoefficient(degree);
if (coefficient != 0)
{
if (coefficient < 0)
{
result.Append(" - ");
coefficient = -coefficient;
}
else
{
if (result.Length > 0)
{
result.Append(" + ");
}
}
if (degree == 0 || coefficient != 1)
{
int alphaPower = field.log(coefficient);
if (alphaPower == 0)
{
result.Append('1');
}
else if (alphaPower == 1)
{
result.Append('a');
}
else
{
result.Append("a^");
result.Append(alphaPower);
}
}
if (degree != 0)
{
if (degree == 1)
{
result.Append('x');
}
else
{
result.Append("x^");
result.Append(degree);
}
}
}
}
return result.ToString();
}
}
}

View File

@@ -1,227 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Common.ReedSolomon
{
/// <summary> <p>Implements Reed-Solomon decoding, as the name implies.</p>
///
/// <p>The algorithm will not be explained here, but the following references were helpful
/// in creating this implementation:</p>
///
/// <ul>
/// <li>Bruce Maggs.
/// <a href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps">
/// "Decoding Reed-Solomon Codes"</a> (see discussion of Forney's Formula)</li>
/// <li>J.I. Hall. <a href="www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf">
/// "Chapter 5. Generalized Reed-Solomon Codes"</a>
/// (see discussion of Euclidean algorithm)</li>
/// </ul>
///
/// <p>Much credit is due to William Rucklidge since portions of this code are an indirect
/// port of his C++ Reed-Solomon implementation.</p>
///
/// </summary>
/// <author>Sean Owen</author>
/// <author>William Rucklidge</author>
/// <author>sanfordsquires</author>
public sealed class ReedSolomonDecoder
{
private readonly GenericGF field;
public ReedSolomonDecoder(GenericGF field)
{
this.field = field;
}
/// <summary>
/// <p>Decodes given set of received codewords, which include both data and error-correction
/// codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place,
/// in the input.</p>
/// </summary>
/// <param name="received">data and error-correction codewords</param>
/// <param name="twoS">number of error-correction codewords available</param>
/// <returns>false: decoding fails</returns>
public bool decode(int[] received, int twoS)
{
var poly = new GenericGFPoly(field, received);
var syndromeCoefficients = new int[twoS];
var noError = true;
for (var i = 0; i < twoS; i++)
{
var eval = poly.evaluateAt(field.exp(i + field.GeneratorBase));
syndromeCoefficients[syndromeCoefficients.Length - 1 - i] = eval;
if (eval != 0)
{
noError = false;
}
}
if (noError)
{
return true;
}
var syndrome = new GenericGFPoly(field, syndromeCoefficients);
var sigmaOmega = runEuclideanAlgorithm(field.buildMonomial(twoS, 1), syndrome, twoS);
if (sigmaOmega == null)
return false;
var sigma = sigmaOmega[0];
var errorLocations = findErrorLocations(sigma);
if (errorLocations == null)
return false;
var omega = sigmaOmega[1];
var errorMagnitudes = findErrorMagnitudes(omega, errorLocations);
for (var i = 0; i < errorLocations.Length; i++)
{
var position = received.Length - 1 - field.log(errorLocations[i]);
if (position < 0)
{
// throw new ReedSolomonException("Bad error location");
return false;
}
received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
}
return true;
}
internal GenericGFPoly[] runEuclideanAlgorithm(GenericGFPoly a, GenericGFPoly b, int R)
{
// Assume a's degree is >= b's
if (a.Degree < b.Degree)
{
GenericGFPoly temp = a;
a = b;
b = temp;
}
GenericGFPoly rLast = a;
GenericGFPoly r = b;
GenericGFPoly tLast = field.Zero;
GenericGFPoly t = field.One;
// Run Euclidean algorithm until r's degree is less than R/2
while (r.Degree >= R / 2)
{
GenericGFPoly rLastLast = rLast;
GenericGFPoly tLastLast = tLast;
rLast = r;
tLast = t;
// Divide rLastLast by rLast, with quotient in q and remainder in r
if (rLast.isZero)
{
// Oops, Euclidean algorithm already terminated?
// throw new ReedSolomonException("r_{i-1} was zero");
return null;
}
r = rLastLast;
GenericGFPoly q = field.Zero;
int denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree);
int dltInverse = field.inverse(denominatorLeadingTerm);
while (r.Degree >= rLast.Degree && !r.isZero)
{
int degreeDiff = r.Degree - rLast.Degree;
int scale = field.multiply(r.getCoefficient(r.Degree), dltInverse);
q = q.addOrSubtract(field.buildMonomial(degreeDiff, scale));
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
}
t = q.multiply(tLast).addOrSubtract(tLastLast);
if (r.Degree >= rLast.Degree)
{
// throw new IllegalStateException("Division algorithm failed to reduce polynomial?");
return null;
}
}
int sigmaTildeAtZero = t.getCoefficient(0);
if (sigmaTildeAtZero == 0)
{
// throw new ReedSolomonException("sigmaTilde(0) was zero");
return null;
}
int inverse = field.inverse(sigmaTildeAtZero);
GenericGFPoly sigma = t.multiply(inverse);
GenericGFPoly omega = r.multiply(inverse);
return new GenericGFPoly[] { sigma, omega };
}
private int[] findErrorLocations(GenericGFPoly errorLocator)
{
// This is a direct application of Chien's search
int numErrors = errorLocator.Degree;
if (numErrors == 1)
{
// shortcut
return new int[] { errorLocator.getCoefficient(1) };
}
int[] result = new int[numErrors];
int e = 0;
for (int i = 1; i < field.Size && e < numErrors; i++)
{
if (errorLocator.evaluateAt(i) == 0)
{
result[e] = field.inverse(i);
e++;
}
}
if (e != numErrors)
{
// throw new ReedSolomonException("Error locator degree does not match number of roots");
return null;
}
return result;
}
private int[] findErrorMagnitudes(GenericGFPoly errorEvaluator, int[] errorLocations)
{
// This is directly applying Forney's Formula
int s = errorLocations.Length;
int[] result = new int[s];
for (int i = 0; i < s; i++)
{
int xiInverse = field.inverse(errorLocations[i]);
int denominator = 1;
for (int j = 0; j < s; j++)
{
if (i != j)
{
//denominator = field.multiply(denominator,
// GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
// Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
// Below is a funny-looking workaround from Steven Parkes
int term = field.multiply(errorLocations[j], xiInverse);
int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1;
denominator = field.multiply(denominator, termPlus1);
// removed in java version, not sure if this is right
// denominator = field.multiply(denominator, GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
}
}
result[i] = field.multiply(errorEvaluator.evaluateAt(xiInverse), field.inverse(denominator));
if (field.GeneratorBase != 0)
{
result[i] = field.multiply(result[i], xiInverse);
}
}
return result;
}
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
namespace ZXing.Common.ReedSolomon
{
/// <summary>
/// Implements Reed-Solomon encoding, as the name implies.
/// </summary>
/// <author>Sean Owen</author>
/// <author>William Rucklidge</author>
public sealed class ReedSolomonEncoder
{
private readonly GenericGF field;
private readonly IList<GenericGFPoly> cachedGenerators;
public ReedSolomonEncoder(GenericGF field)
{
this.field = field;
this.cachedGenerators = new List<GenericGFPoly>();
cachedGenerators.Add(new GenericGFPoly(field, new int[] { 1 }));
}
private GenericGFPoly buildGenerator(int degree)
{
if (degree >= cachedGenerators.Count)
{
var lastGenerator = cachedGenerators[cachedGenerators.Count - 1];
for (int d = cachedGenerators.Count; d <= degree; d++)
{
var nextGenerator = lastGenerator.multiply(new GenericGFPoly(field, new int[] { 1, field.exp(d - 1 + field.GeneratorBase) }));
cachedGenerators.Add(nextGenerator);
lastGenerator = nextGenerator;
}
}
return cachedGenerators[degree];
}
public void encode(int[] toEncode, int ecBytes)
{
if (ecBytes == 0)
{
throw new ArgumentException("No error correction bytes");
}
var dataBytes = toEncode.Length - ecBytes;
if (dataBytes <= 0)
{
throw new ArgumentException("No data bytes provided");
}
var generator = buildGenerator(ecBytes);
var infoCoefficients = new int[dataBytes];
Array.Copy(toEncode, 0, infoCoefficients, 0, dataBytes);
var info = new GenericGFPoly(field, infoCoefficients);
info = info.multiplyByMonomial(ecBytes, 1);
var remainder = info.divide(generator)[1];
var coefficients = remainder.Coefficients;
var numZeroCoefficients = ecBytes - coefficients.Length;
for (var i = 0; i < numZeroCoefficients; i++)
{
toEncode[dataBytes + i] = 0;
}
Array.Copy(coefficients, 0, toEncode, dataBytes + numZeroCoefficients, coefficients.Length);
}
}
}

View File

@@ -1,168 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Datamatrix.Internal;
namespace ZXing.Datamatrix
{
/// <summary>
/// This implementation can detect and decode Data Matrix codes in an image.
///
/// <author>bbrown@google.com (Brian Brown)</author>
/// </summary>
public sealed class DataMatrixReader : Reader
{
private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];
private readonly Decoder decoder = new Decoder();
/// <summary>
/// Locates and decodes a Data Matrix code in an image.
///
/// <returns>a String representing the content encoded by the Data Matrix code</returns>
/// <exception cref="FormatException">if a Data Matrix code cannot be decoded</exception>
/// </summary>
public Result decode(BinaryBitmap image)
{
return decode(image, null);
}
public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints)
{
DecoderResult decoderResult;
ResultPoint[] points;
if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE))
{
BitMatrix bits = extractPureBits(image.BlackMatrix);
if (bits == null)
return null;
decoderResult = decoder.decode(bits);
points = NO_POINTS;
}
else
{
DetectorResult detectorResult = new Detector(image.BlackMatrix).detect();
if (detectorResult == null)
return null;
decoderResult = decoder.decode(detectorResult.Bits);
points = detectorResult.Points;
}
if (decoderResult == null)
return null;
Result result = new Result(decoderResult.Text, decoderResult.RawBytes, points,
BarcodeFormat.DATA_MATRIX);
IList<byte[]> byteSegments = decoderResult.ByteSegments;
if (byteSegments != null)
{
result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments);
}
var ecLevel = decoderResult.ECLevel;
if (ecLevel != null)
{
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel);
}
return result;
}
public void reset()
{
// do nothing
}
/// <summary>
/// This method detects a code in a "pure" image -- that is, pure monochrome image
/// which contains only an unrotated, unskewed, image of a code, with some white border
/// around it. This is a specialized method that works exceptionally fast in this special
/// case.
///
/// <seealso cref="ZXing.QrCode.QRCodeReader.extractPureBits(BitMatrix)" />
/// </summary>
private static BitMatrix extractPureBits(BitMatrix image)
{
int[] leftTopBlack = image.getTopLeftOnBit();
int[] rightBottomBlack = image.getBottomRightOnBit();
if (leftTopBlack == null || rightBottomBlack == null)
{
return null;
}
int moduleSize;
if (!DataMatrixReader.moduleSize(leftTopBlack, image, out moduleSize))
return null;
int top = leftTopBlack[1];
int bottom = rightBottomBlack[1];
int left = leftTopBlack[0];
int right = rightBottomBlack[0];
int matrixWidth = (right - left + 1) / moduleSize;
int matrixHeight = (bottom - top + 1) / moduleSize;
if (matrixWidth <= 0 || matrixHeight <= 0)
{
return null;
}
// Push in the "border" by half the module width so that we start
// sampling in the middle of the module. Just in case the image is a
// little off, this will help recover.
int nudge = moduleSize >> 1;
top += nudge;
left += nudge;
// Now just read off the bits
BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight);
for (int y = 0; y < matrixHeight; y++)
{
int iOffset = top + y * moduleSize;
for (int x = 0; x < matrixWidth; x++)
{
if (image[left + x * moduleSize, iOffset])
{
bits[x, y] = true;
}
}
}
return bits;
}
private static bool moduleSize(int[] leftTopBlack, BitMatrix image, out int modulesize)
{
int width = image.Width;
int x = leftTopBlack[0];
int y = leftTopBlack[1];
while (x < width && image[x, y])
{
x++;
}
if (x == width)
{
modulesize = 0;
return false;
}
modulesize = x - leftTopBlack[0];
if (modulesize == 0)
{
return false;
}
return true;
}
}
}

View File

@@ -1,193 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Datamatrix.Encoder;
using ZXing.QrCode.Internal;
namespace ZXing.Datamatrix
{
/// <summary>
/// This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values.
/// </summary>
/// <author>dswitkin@google.com (Daniel Switkin)</author>
/// <author>Guillaume Le Biller Added to zxing lib.</author>
public sealed class DataMatrixWriter : Writer
{
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height)
{
return encode(contents, format, width, height, null);
}
public BitMatrix encode(String contents, BarcodeFormat format, int width, int height, IDictionary<EncodeHintType, object> hints)
{
if (String.IsNullOrEmpty(contents))
{
throw new ArgumentException("Found empty contents", contents);
}
if (format != BarcodeFormat.DATA_MATRIX)
{
throw new ArgumentException("Can only encode DATA_MATRIX, but got " + format);
}
if (width < 0 || height < 0)
{
throw new ArgumentException("Requested dimensions are too small: " + width + 'x' + height);
}
// Try to get force shape & min / max size
var shape = SymbolShapeHint.FORCE_NONE;
var defaultEncodation = Encodation.ASCII;
var minSize = new Dimension(width, height);
Dimension maxSize = null;
if (hints != null)
{
var requestedShape = hints.ContainsKey(EncodeHintType.DATA_MATRIX_SHAPE) ? (SymbolShapeHint?)hints[EncodeHintType.DATA_MATRIX_SHAPE] : null;
if (requestedShape != null)
{
shape = requestedShape.Value;
}
var requestedMinSize = hints.ContainsKey(EncodeHintType.MIN_SIZE) ? (Dimension)hints[EncodeHintType.MIN_SIZE] : null;
if (requestedMinSize != null)
{
minSize = requestedMinSize;
}
var requestedMaxSize = hints.ContainsKey(EncodeHintType.MAX_SIZE) ? (Dimension)hints[EncodeHintType.MAX_SIZE] : null;
if (requestedMaxSize != null)
{
maxSize = requestedMaxSize;
}
var requestedDefaultEncodation = hints.ContainsKey(EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION) ? (int?)hints[EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION] : (int?)null;
if (requestedDefaultEncodation != null)
{
defaultEncodation = requestedDefaultEncodation.Value;
}
}
//1. step: Data encodation
String encoded = HighLevelEncoder.encodeHighLevel(contents, shape, minSize, maxSize, defaultEncodation);
SymbolInfo symbolInfo = SymbolInfo.lookup(encoded.Length, shape, minSize, maxSize, true);
//2. step: ECC generation
String codewords = ErrorCorrection.encodeECC200(encoded, symbolInfo);
//3. step: Module placement in Matrix
var placement =
new DefaultPlacement(codewords, symbolInfo.getSymbolDataWidth(), symbolInfo.getSymbolDataHeight());
placement.place();
//4. step: low-level encoding
return encodeLowLevel(placement, symbolInfo);
}
/// <summary>
/// Encode the given symbol info to a bit matrix.
/// </summary>
/// <param name="placement">The DataMatrix placement.</param>
/// <param name="symbolInfo">The symbol info to encode.</param>
/// <returns>The bit matrix generated.</returns>
private static BitMatrix encodeLowLevel(DefaultPlacement placement, SymbolInfo symbolInfo)
{
int symbolWidth = symbolInfo.getSymbolDataWidth();
int symbolHeight = symbolInfo.getSymbolDataHeight();
var matrix = new ByteMatrix(symbolInfo.getSymbolWidth(), symbolInfo.getSymbolHeight());
int matrixY = 0;
for (int y = 0; y < symbolHeight; y++)
{
// Fill the top edge with alternate 0 / 1
int matrixX;
if ((y % symbolInfo.matrixHeight) == 0)
{
matrixX = 0;
for (int x = 0; x < symbolInfo.getSymbolWidth(); x++)
{
matrix.set(matrixX, matrixY, (x % 2) == 0);
matrixX++;
}
matrixY++;
}
matrixX = 0;
for (int x = 0; x < symbolWidth; x++)
{
// Fill the right edge with full 1
if ((x % symbolInfo.matrixWidth) == 0)
{
matrix.set(matrixX, matrixY, true);
matrixX++;
}
matrix.set(matrixX, matrixY, placement.getBit(x, y));
matrixX++;
// Fill the right edge with alternate 0 / 1
if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1)
{
matrix.set(matrixX, matrixY, (y % 2) == 0);
matrixX++;
}
}
matrixY++;
// Fill the bottom edge with full 1
if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1)
{
matrixX = 0;
for (int x = 0; x < symbolInfo.getSymbolWidth(); x++)
{
matrix.set(matrixX, matrixY, true);
matrixX++;
}
matrixY++;
}
}
return convertByteMatrixToBitMatrix(matrix);
}
/// <summary>
/// Convert the ByteMatrix to BitMatrix.
/// </summary>
/// <param name="matrix">The input matrix.</param>
/// <returns>The output matrix.</returns>
private static BitMatrix convertByteMatrixToBitMatrix(ByteMatrix matrix)
{
int matrixWidgth = matrix.Width;
int matrixHeight = matrix.Height;
var output = new BitMatrix(matrixWidgth, matrixHeight);
output.clear();
for (int i = 0; i < matrixWidgth; i++)
{
for (int j = 0; j < matrixHeight; j++)
{
// Zero is white in the bytematrix
if (matrix[i, j] == 1)
{
output[i, j] = true;
}
}
}
return output;
}
}
}

View File

@@ -1,519 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// <author>bbrown@google.com (Brian Brown)</author>
/// </summary>
sealed class BitMatrixParser
{
private readonly BitMatrix mappingBitMatrix;
private readonly BitMatrix readMappingMatrix;
private readonly Version version;
/// <summary>
/// <param name="bitMatrix"><see cref="BitMatrix" />to parse</param>
/// <exception cref="FormatException">if dimension is < 8 or >144 or not 0 mod 2</exception>
/// </summary>
internal BitMatrixParser(BitMatrix bitMatrix)
{
int dimension = bitMatrix.Height;
if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0)
{
return;
}
version = readVersion(bitMatrix);
if (version != null)
{
mappingBitMatrix = extractDataRegion(bitMatrix);
readMappingMatrix = new BitMatrix(mappingBitMatrix.Width, mappingBitMatrix.Height);
}
}
public Version Version
{
get { return version; }
}
/// <summary>
/// <p>Creates the version object based on the dimension of the original bit matrix from
/// the datamatrix code.</p>
///
/// <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p>
///
/// <param name="bitMatrix">Original <see cref="BitMatrix" />including alignment patterns</param>
/// <returns><see cref="Version" />encapsulating the Data Matrix Code's "version"</returns>
/// <exception cref="FormatException">if the dimensions of the mapping matrix are not valid</exception>
/// Data Matrix dimensions.
/// </summary>
internal static Version readVersion(BitMatrix bitMatrix)
{
int numRows = bitMatrix.Height;
int numColumns = bitMatrix.Width;
return Version.getVersionForDimensions(numRows, numColumns);
}
/// <summary>
/// <p>Reads the bits in the <see cref="BitMatrix" />representing the mapping matrix (No alignment patterns)
/// in the correct order in order to reconstitute the codewords bytes contained within the
/// Data Matrix Code.</p>
///
/// <returns>bytes encoded within the Data Matrix Code</returns>
/// <exception cref="FormatException">if the exact number of bytes expected is not read</exception>
/// </summary>
internal byte[] readCodewords()
{
byte[] result = new byte[version.getTotalCodewords()];
int resultOffset = 0;
int row = 4;
int column = 0;
int numRows = mappingBitMatrix.Height;
int numColumns = mappingBitMatrix.Width;
bool corner1Read = false;
bool corner2Read = false;
bool corner3Read = false;
bool corner4Read = false;
// Read all of the codewords
do
{
// Check the four corner cases
if ((row == numRows) && (column == 0) && !corner1Read)
{
result[resultOffset++] = (byte)readCorner1(numRows, numColumns);
row -= 2;
column += 2;
corner1Read = true;
}
else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read)
{
result[resultOffset++] = (byte)readCorner2(numRows, numColumns);
row -= 2;
column += 2;
corner2Read = true;
}
else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read)
{
result[resultOffset++] = (byte)readCorner3(numRows, numColumns);
row -= 2;
column += 2;
corner3Read = true;
}
else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read)
{
result[resultOffset++] = (byte)readCorner4(numRows, numColumns);
row -= 2;
column += 2;
corner4Read = true;
}
else
{
// Sweep upward diagonally to the right
do
{
if ((row < numRows) && (column >= 0) && !readMappingMatrix[column, row])
{
result[resultOffset++] = (byte)readUtah(row, column, numRows, numColumns);
}
row -= 2;
column += 2;
} while ((row >= 0) && (column < numColumns));
row += 1;
column += 3;
// Sweep downward diagonally to the left
do
{
if ((row >= 0) && (column < numColumns) && !readMappingMatrix[column, row])
{
result[resultOffset++] = (byte)readUtah(row, column, numRows, numColumns);
}
row += 2;
column -= 2;
} while ((row < numRows) && (column >= 0));
row += 3;
column += 1;
}
} while ((row < numRows) || (column < numColumns));
if (resultOffset != version.getTotalCodewords())
{
return null;
}
return result;
}
/// <summary>
/// <p>Reads a bit of the mapping matrix accounting for boundary wrapping.</p>
///
/// <param name="row">Row to read in the mapping matrix</param>
/// <param name="column">Column to read in the mapping matrix</param>
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>value of the given bit in the mapping matrix</returns>
/// </summary>
bool readModule(int row, int column, int numRows, int numColumns)
{
// Adjust the row and column indices based on boundary wrapping
if (row < 0)
{
row += numRows;
column += 4 - ((numRows + 4) & 0x07);
}
if (column < 0)
{
column += numColumns;
row += 4 - ((numColumns + 4) & 0x07);
}
readMappingMatrix[column, row] = true;
return mappingBitMatrix[column, row];
}
/// <summary>
/// <p>Reads the 8 bits of the standard Utah-shaped pattern.</p>
///
/// <p>See ISO 16022:2006, 5.8.1 Figure 6</p>
///
/// <param name="row">Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern</param>
/// <param name="column">Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern</param>
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>byte from the utah shape</returns>
/// </summary>
int readUtah(int row, int column, int numRows, int numColumns)
{
int currentByte = 0;
if (readModule(row - 2, column - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 2, column - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row - 1, column, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(row, column, numRows, numColumns))
{
currentByte |= 1;
}
return currentByte;
}
/// <summary>
/// <p>Reads the 8 bits of the special corner condition 1.</p>
///
/// <p>See ISO 16022:2006, Figure F.3</p>
///
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>byte from the Corner condition 1</returns>
/// </summary>
int readCorner1(int numRows, int numColumns)
{
int currentByte = 0;
if (readModule(numRows - 1, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(2, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(3, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
return currentByte;
}
/// <summary>
/// <p>Reads the 8 bits of the special corner condition 2.</p>
///
/// <p>See ISO 16022:2006, Figure F.4</p>
///
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>byte from the Corner condition 2</returns>
/// </summary>
int readCorner2(int numRows, int numColumns)
{
int currentByte = 0;
if (readModule(numRows - 3, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 2, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 4, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 3, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
return currentByte;
}
/// <summary>
/// <p>Reads the 8 bits of the special corner condition 3.</p>
///
/// <p>See ISO 16022:2006, Figure F.5</p>
///
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>byte from the Corner condition 3</returns>
/// </summary>
int readCorner3(int numRows, int numColumns)
{
int currentByte = 0;
if (readModule(numRows - 1, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 3, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 3, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
return currentByte;
}
/// <summary>
/// <p>Reads the 8 bits of the special corner condition 4.</p>
///
/// <p>See ISO 16022:2006, Figure F.6</p>
///
/// <param name="numRows">Number of rows in the mapping matrix</param>
/// <param name="numColumns">Number of columns in the mapping matrix</param>
/// <returns>byte from the Corner condition 4</returns>
/// </summary>
int readCorner4(int numRows, int numColumns)
{
int currentByte = 0;
if (readModule(numRows - 3, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 2, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(numRows - 1, 0, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 2, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(0, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(1, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(2, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
currentByte <<= 1;
if (readModule(3, numColumns - 1, numRows, numColumns))
{
currentByte |= 1;
}
return currentByte;
}
/// <summary>
/// <p>Extracts the data region from a <see cref="BitMatrix" />that contains
/// alignment patterns.</p>
///
/// <param name="bitMatrix">Original <see cref="BitMatrix" />with alignment patterns</param>
/// <returns>BitMatrix that has the alignment patterns removed</returns>
/// </summary>
BitMatrix extractDataRegion(BitMatrix bitMatrix)
{
int symbolSizeRows = version.getSymbolSizeRows();
int symbolSizeColumns = version.getSymbolSizeColumns();
if (bitMatrix.Height != symbolSizeRows)
{
throw new ArgumentException("Dimension of bitMarix must match the version size");
}
int dataRegionSizeRows = version.getDataRegionSizeRows();
int dataRegionSizeColumns = version.getDataRegionSizeColumns();
int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows;
int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns;
int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows;
int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns;
BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionColumn, sizeDataRegionRow);
for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow)
{
int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows;
for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn)
{
int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns;
for (int i = 0; i < dataRegionSizeRows; ++i)
{
int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i;
int writeRowOffset = dataRegionRowOffset + i;
for (int j = 0; j < dataRegionSizeColumns; ++j)
{
int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j;
if (bitMatrix[readColumnOffset, readRowOffset])
{
int writeColumnOffset = dataRegionColumnOffset + j;
bitMatrixWithoutAlignment[writeColumnOffset, writeRowOffset] = true;
}
}
}
}
}
return bitMatrixWithoutAlignment;
}
}
}

View File

@@ -1,133 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// <p>Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into
/// multiple blocks, each of which is a unit of data and error-correction codewords. Each
/// is represented by an instance of this class.</p>
///
/// <author>bbrown@google.com (Brian Brown)</author>
/// </summary>
internal sealed class DataBlock
{
private readonly int numDataCodewords;
private readonly byte[] codewords;
private DataBlock(int numDataCodewords, byte[] codewords)
{
this.numDataCodewords = numDataCodewords;
this.codewords = codewords;
}
/// <summary>
/// <p>When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them.
/// That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This
/// method will separate the data into original blocks.</p>
///
/// <param name="rawCodewords">bytes as read directly from the Data Matrix Code</param>
/// <param name="version">version of the Data Matrix Code</param>
/// <returns>DataBlocks containing original bytes, "de-interleaved" from representation in the</returns>
/// Data Matrix Code
/// </summary>
internal static DataBlock[] getDataBlocks(byte[] rawCodewords,
Version version)
{
// Figure out the number and size of data blocks used by this version
Version.ECBlocks ecBlocks = version.getECBlocks();
// First count the total number of data blocks
int totalBlocks = 0;
Version.ECB[] ecBlockArray = ecBlocks.ECBlocksValue;
foreach (Version.ECB ecBlock in ecBlockArray)
{
totalBlocks += ecBlock.Count;
}
// Now establish DataBlocks of the appropriate size and number of data codewords
DataBlock[] result = new DataBlock[totalBlocks];
int numResultBlocks = 0;
foreach (Version.ECB ecBlock in ecBlockArray)
{
for (int i = 0; i < ecBlock.Count; i++)
{
int numDataCodewords = ecBlock.DataCodewords;
int numBlockCodewords = ecBlocks.ECCodewords + numDataCodewords;
result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
}
}
// All blocks have the same amount of data, except that the last n
// (where n may be 0) have 1 less byte. Figure out where these start.
// TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144
int longerBlocksTotalCodewords = result[0].codewords.Length;
//int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1;
int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.ECCodewords;
int shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1;
// The last elements of result may be 1 element shorter for 144 matrix
// first fill out as many elements as all of them have minus 1
int rawCodewordsOffset = 0;
for (int i = 0; i < shorterBlocksNumDataCodewords; i++)
{
for (int j = 0; j < numResultBlocks; j++)
{
result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
}
}
// Fill out the last data block in the longer ones
bool specialVersion = version.getVersionNumber() == 24;
int numLongerBlocks = specialVersion ? 8 : numResultBlocks;
for (int j = 0; j < numLongerBlocks; j++)
{
result[j].codewords[longerBlocksNumDataCodewords - 1] = rawCodewords[rawCodewordsOffset++];
}
// Now add in error correction blocks
int max = result[0].codewords.Length;
for (int i = longerBlocksNumDataCodewords; i < max; i++)
{
for (int j = 0; j < numResultBlocks; j++)
{
int jOffset = specialVersion ? (j + 8)%numResultBlocks : j;
int iOffset = specialVersion && jOffset > 7 ? i - 1 : i;
result[jOffset].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
}
}
if (rawCodewordsOffset != rawCodewords.Length)
{
throw new ArgumentException();
}
return result;
}
internal int NumDataCodewords
{
get { return numDataCodewords; }
}
internal byte[] Codewords
{
get { return codewords; }
}
}
}

View File

@@ -1,705 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
using ZXing.Common;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes
/// in one Data Matrix Code. This class decodes the bits back into text.</p>
///
/// <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>
///
/// <author>bbrown@google.com (Brian Brown)</author>
/// <author>Sean Owen</author>
/// </summary>
internal static class DecodedBitStreamParser
{
private enum Mode
{
PAD_ENCODE, // Not really a mode
ASCII_ENCODE,
C40_ENCODE,
TEXT_ENCODE,
ANSIX12_ENCODE,
EDIFACT_ENCODE,
BASE256_ENCODE
}
/// <summary>
/// See ISO 16022:2006, Annex C Table C.1
/// The C40 Basic Character Set (*'s used for placeholders for the shift values)
/// </summary>
private static readonly char[] C40_BASIC_SET_CHARS =
{
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
private static readonly char[] C40_SHIFT2_SET_CHARS =
{
'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.',
'/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'
};
/// <summary>
/// See ISO 16022:2006, Annex C Table C.2
/// The Text Basic Character Set (*'s used for placeholders for the shift values)
/// </summary>
private static readonly char[] TEXT_BASIC_SET_CHARS =
{
'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
};
// Shift 2 for Text is the same encoding as C40
private static readonly char[] TEXT_SHIFT2_SET_CHARS = C40_SHIFT2_SET_CHARS;
private static readonly char[] TEXT_SHIFT3_SET_CHARS =
{
'`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{',
'|', '}', '~', (char) 127
};
internal static DecoderResult decode(byte[] bytes)
{
BitSource bits = new BitSource(bytes);
StringBuilder result = new StringBuilder(100);
StringBuilder resultTrailer = new StringBuilder(0);
List<byte[]> byteSegments = new List<byte[]>(1);
Mode mode = Mode.ASCII_ENCODE;
do
{
if (mode == Mode.ASCII_ENCODE)
{
if (!decodeAsciiSegment(bits, result, resultTrailer, out mode))
return null;
}
else
{
switch (mode)
{
case Mode.C40_ENCODE:
if (!decodeC40Segment(bits, result))
return null;
break;
case Mode.TEXT_ENCODE:
if (!decodeTextSegment(bits, result))
return null;
break;
case Mode.ANSIX12_ENCODE:
if (!decodeAnsiX12Segment(bits, result))
return null;
break;
case Mode.EDIFACT_ENCODE:
if (!decodeEdifactSegment(bits, result))
return null;
break;
case Mode.BASE256_ENCODE:
if (!decodeBase256Segment(bits, result, byteSegments))
return null;
break;
default:
return null;
}
mode = Mode.ASCII_ENCODE;
}
} while (mode != Mode.PAD_ENCODE && bits.available() > 0);
if (resultTrailer.Length > 0)
{
result.Append(resultTrailer.ToString());
}
return new DecoderResult(bytes, result.ToString(), byteSegments.Count == 0 ? null : byteSegments, null);
}
/// <summary>
/// See ISO 16022:2006, 5.2.3 and Annex C, Table C.2
/// </summary>
private static bool decodeAsciiSegment(BitSource bits,
StringBuilder result,
StringBuilder resultTrailer,
out Mode mode)
{
bool upperShift = false;
mode = Mode.ASCII_ENCODE;
do
{
int oneByte = bits.readBits(8);
if (oneByte == 0)
{
return false;
}
else if (oneByte <= 128)
{
// ASCII data (ASCII value + 1)
if (upperShift)
{
oneByte += 128;
//upperShift = false;
}
result.Append((char) (oneByte - 1));
mode = Mode.ASCII_ENCODE;
return true;
}
else if (oneByte == 129)
{
// Pad
mode = Mode.PAD_ENCODE;
return true;
}
else if (oneByte <= 229)
{
// 2-digit data 00-99 (Numeric Value + 130)
int value = oneByte - 130;
if (value < 10)
{
// pad with '0' for single digit values
result.Append('0');
}
result.Append(value);
}
else if (oneByte == 230)
{
// Latch to C40 encodation
mode = Mode.C40_ENCODE;
return true;
}
else if (oneByte == 231)
{
// Latch to Base 256 encodation
mode = Mode.BASE256_ENCODE;
return true;
}
else if (oneByte == 232)
{
// FNC1
result.Append((char) 29); // translate as ASCII 29
}
else if (oneByte == 233 || oneByte == 234)
{
// Structured Append, Reader Programming
// Ignore these symbols for now
//throw ReaderException.Instance;
}
else if (oneByte == 235)
{
// Upper Shift (shift to Extended ASCII)
upperShift = true;
}
else if (oneByte == 236)
{
// 05 Macro
result.Append("[)>\u001E05\u001D");
resultTrailer.Insert(0, "\u001E\u0004");
}
else if (oneByte == 237)
{
// 06 Macro
result.Append("[)>\u001E06\u001D");
resultTrailer.Insert(0, "\u001E\u0004");
}
else if (oneByte == 238)
{
// Latch to ANSI X12 encodation
mode = Mode.ANSIX12_ENCODE;
return true;
}
else if (oneByte == 239)
{
// Latch to Text encodation
mode = Mode.TEXT_ENCODE;
return true;
}
else if (oneByte == 240)
{
// Latch to EDIFACT encodation
mode = Mode.EDIFACT_ENCODE;
return true;
}
else if (oneByte == 241)
{
// ECI Character
// TODO(bbrown): I think we need to support ECI
//throw ReaderException.Instance;
// Ignore this symbol for now
}
else if (oneByte >= 242)
{
// Not to be used in ASCII encodation
// ... but work around encoders that end with 254, latch back to ASCII
if (oneByte != 254 || bits.available() != 0)
{
return false;
}
}
} while (bits.available() > 0);
mode = Mode.ASCII_ENCODE;
return true;
}
/// <summary>
/// See ISO 16022:2006, 5.2.5 and Annex C, Table C.1
/// </summary>
private static bool decodeC40Segment(BitSource bits, StringBuilder result)
{
// Three C40 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
// TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time
bool upperShift = false;
int[] cValues = new int[3];
int shift = 0;
do
{
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8)
{
return true;
}
int firstByte = bits.readBits(8);
if (firstByte == 254)
{
// Unlatch codeword
return true;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++)
{
int cValue = cValues[i];
switch (shift)
{
case 0:
if (cValue < 3)
{
shift = cValue + 1;
}
else if (cValue < C40_BASIC_SET_CHARS.Length)
{
char c40char = C40_BASIC_SET_CHARS[cValue];
if (upperShift)
{
result.Append((char) (c40char + 128));
upperShift = false;
}
else
{
result.Append(c40char);
}
}
else
{
return false;
}
break;
case 1:
if (upperShift)
{
result.Append((char) (cValue + 128));
upperShift = false;
}
else
{
result.Append((char) cValue);
}
shift = 0;
break;
case 2:
if (cValue < C40_SHIFT2_SET_CHARS.Length)
{
char c40char = C40_SHIFT2_SET_CHARS[cValue];
if (upperShift)
{
result.Append((char) (c40char + 128));
upperShift = false;
}
else
{
result.Append(c40char);
}
}
else if (cValue == 27)
{
// FNC1
result.Append((char) 29); // translate as ASCII 29
}
else if (cValue == 30)
{
// Upper Shift
upperShift = true;
}
else
{
return false;
}
shift = 0;
break;
case 3:
if (upperShift)
{
result.Append((char) (cValue + 224));
upperShift = false;
}
else
{
result.Append((char) (cValue + 96));
}
shift = 0;
break;
default:
return false;
}
}
} while (bits.available() > 0);
return true;
}
/// <summary>
/// See ISO 16022:2006, 5.2.6 and Annex C, Table C.2
/// </summary>
private static bool decodeTextSegment(BitSource bits, StringBuilder result)
{
// Three Text values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
// TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time
bool upperShift = false;
int[] cValues = new int[3];
int shift = 0;
do
{
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8)
{
return true;
}
int firstByte = bits.readBits(8);
if (firstByte == 254)
{
// Unlatch codeword
return true;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++)
{
int cValue = cValues[i];
switch (shift)
{
case 0:
if (cValue < 3)
{
shift = cValue + 1;
}
else if (cValue < TEXT_BASIC_SET_CHARS.Length)
{
char textChar = TEXT_BASIC_SET_CHARS[cValue];
if (upperShift)
{
result.Append((char) (textChar + 128));
upperShift = false;
}
else
{
result.Append(textChar);
}
}
else
{
return false;
}
break;
case 1:
if (upperShift)
{
result.Append((char) (cValue + 128));
upperShift = false;
}
else
{
result.Append((char) cValue);
}
shift = 0;
break;
case 2:
// Shift 2 for Text is the same encoding as C40
if (cValue < TEXT_SHIFT2_SET_CHARS.Length)
{
char textChar = TEXT_SHIFT2_SET_CHARS[cValue];
if (upperShift)
{
result.Append((char) (textChar + 128));
upperShift = false;
}
else
{
result.Append(textChar);
}
}
else if (cValue == 27)
{
// FNC1
result.Append((char) 29); // translate as ASCII 29
}
else if (cValue == 30)
{
// Upper Shift
upperShift = true;
}
else
{
return false;
}
shift = 0;
break;
case 3:
if (cValue < TEXT_SHIFT3_SET_CHARS.Length)
{
char textChar = TEXT_SHIFT3_SET_CHARS[cValue];
if (upperShift)
{
result.Append((char) (textChar + 128));
upperShift = false;
}
else
{
result.Append(textChar);
}
shift = 0;
}
else
{
return false;
}
break;
default:
return false;
}
}
} while (bits.available() > 0);
return true;
}
/// <summary>
/// See ISO 16022:2006, 5.2.7
/// </summary>
private static bool decodeAnsiX12Segment(BitSource bits,
StringBuilder result)
{
// Three ANSI X12 values are encoded in a 16-bit value as
// (1600 * C1) + (40 * C2) + C3 + 1
int[] cValues = new int[3];
do
{
// If there is only one byte left then it will be encoded as ASCII
if (bits.available() == 8)
{
return true;
}
int firstByte = bits.readBits(8);
if (firstByte == 254)
{
// Unlatch codeword
return true;
}
parseTwoBytes(firstByte, bits.readBits(8), cValues);
for (int i = 0; i < 3; i++)
{
int cValue = cValues[i];
if (cValue == 0)
{
// X12 segment terminator <CR>
result.Append('\r');
}
else if (cValue == 1)
{
// X12 segment separator *
result.Append('*');
}
else if (cValue == 2)
{
// X12 sub-element separator >
result.Append('>');
}
else if (cValue == 3)
{
// space
result.Append(' ');
}
else if (cValue < 14)
{
// 0 - 9
result.Append((char) (cValue + 44));
}
else if (cValue < 40)
{
// A - Z
result.Append((char) (cValue + 51));
}
else
{
return false;
}
}
} while (bits.available() > 0);
return true;
}
private static void parseTwoBytes(int firstByte, int secondByte, int[] result)
{
int fullBitValue = (firstByte << 8) + secondByte - 1;
int temp = fullBitValue/1600;
result[0] = temp;
fullBitValue -= temp*1600;
temp = fullBitValue/40;
result[1] = temp;
result[2] = fullBitValue - temp*40;
}
/// <summary>
/// See ISO 16022:2006, 5.2.8 and Annex C Table C.3
/// </summary>
private static bool decodeEdifactSegment(BitSource bits, StringBuilder result)
{
do
{
// If there is only two or less bytes left then it will be encoded as ASCII
if (bits.available() <= 16)
{
return true;
}
for (int i = 0; i < 4; i++)
{
int edifactValue = bits.readBits(6);
// Check for the unlatch character
if (edifactValue == 0x1F)
{
// 011111
// Read rest of byte, which should be 0, and stop
int bitsLeft = 8 - bits.BitOffset;
if (bitsLeft != 8)
{
bits.readBits(bitsLeft);
}
return true;
}
if ((edifactValue & 0x20) == 0)
{
// no 1 in the leading (6th) bit
edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value
}
result.Append((char) edifactValue);
}
} while (bits.available() > 0);
return true;
}
/// <summary>
/// See ISO 16022:2006, 5.2.9 and Annex B, B.2
/// </summary>
private static bool decodeBase256Segment(BitSource bits,
StringBuilder result,
IList<byte[]> byteSegments)
{
// Figure out how long the Base 256 Segment is.
int codewordPosition = 1 + bits.ByteOffset; // position is 1-indexed
int d1 = unrandomize255State(bits.readBits(8), codewordPosition++);
int count;
if (d1 == 0)
{
// Read the remainder of the symbol
count = bits.available()/8;
}
else if (d1 < 250)
{
count = d1;
}
else
{
count = 250*(d1 - 249) + unrandomize255State(bits.readBits(8), codewordPosition++);
}
// We're seeing NegativeArraySizeException errors from users.
if (count < 0)
{
return false;
}
byte[] bytes = new byte[count];
for (int i = 0; i < count; i++)
{
// Have seen this particular error in the wild, such as at
// http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2
if (bits.available() < 8)
{
return false;
}
bytes[i] = (byte) unrandomize255State(bits.readBits(8), codewordPosition++);
}
byteSegments.Add(bytes);
try
{
#if (WINDOWS_PHONE || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || WindowsCE || PORTABLE)
#if WindowsCE
result.Append(Encoding.GetEncoding(1252).GetString(bytes, 0, bytes.Length));
#else
result.Append(Encoding.GetEncoding("ISO-8859-1").GetString(bytes, 0, bytes.Length));
#endif
#else
result.Append(Encoding.GetEncoding("ISO-8859-1").GetString(bytes));
#endif
}
catch (Exception uee)
{
throw new InvalidOperationException("Platform does not support required encoding: " + uee);
}
return true;
}
/// <summary>
/// See ISO 16022:2006, Annex B, B.2
/// </summary>
private static int unrandomize255State(int randomizedBase256Codeword,
int base256CodewordPosition)
{
int pseudoRandomNumber = ((149*base256CodewordPosition)%255) + 1;
int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;
return tempVariable >= 0 ? tempVariable : tempVariable + 256;
}
}
}

View File

@@ -1,145 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using ZXing.Common;
using ZXing.Common.ReedSolomon;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// <p>The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting
/// the Data Matrix Code from an image.</p>
///
/// <author>bbrown@google.com (Brian Brown)</author>
/// </summary>
public sealed class Decoder
{
private readonly ReedSolomonDecoder rsDecoder;
/// <summary>
/// Initializes a new instance of the <see cref="Decoder"/> class.
/// </summary>
public Decoder()
{
rsDecoder = new ReedSolomonDecoder(GenericGF.DATA_MATRIX_FIELD_256);
}
/// <summary>
/// <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans.
/// "true" is taken to mean a black module.</p>
///
/// <param name="image">booleans representing white/black Data Matrix Code modules</param>
/// <returns>text and bytes encoded within the Data Matrix Code</returns>
/// <exception cref="FormatException">if the Data Matrix Code cannot be decoded</exception>
/// <exception cref="ChecksumException">if error correction fails</exception>
/// </summary>
public DecoderResult decode(bool[][] image)
{
int dimension = image.Length;
BitMatrix bits = new BitMatrix(dimension);
for (int i = 0; i < dimension; i++)
{
for (int j = 0; j < dimension; j++)
{
if (image[i][j])
{
bits[j, i] = true;
}
}
}
return decode(bits);
}
/// <summary>
/// <p>Decodes a Data Matrix Code represented as a <see cref="BitMatrix" />. A 1 or "true" is taken
/// to mean a black module.</p>
/// </summary>
/// <param name="bits">booleans representing white/black Data Matrix Code modules</param>
/// <returns>text and bytes encoded within the Data Matrix Code</returns>
public DecoderResult decode(BitMatrix bits)
{
// Construct a parser and read version, error-correction level
BitMatrixParser parser = new BitMatrixParser(bits);
if (parser.Version == null)
return null;
// Read codewords
byte[] codewords = parser.readCodewords();
if (codewords == null)
return null;
// Separate into data blocks
DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, parser.Version);
int dataBlocksCount = dataBlocks.Length;
// Count total number of data bytes
int totalBytes = 0;
foreach (var db in dataBlocks)
{
totalBytes += db.NumDataCodewords;
}
byte[] resultBytes = new byte[totalBytes];
// Error-correct and copy data blocks together into a stream of bytes
for (int j = 0; j < dataBlocksCount; j++)
{
DataBlock dataBlock = dataBlocks[j];
byte[] codewordBytes = dataBlock.Codewords;
int numDataCodewords = dataBlock.NumDataCodewords;
if (!correctErrors(codewordBytes, numDataCodewords))
return null;
for (int i = 0; i < numDataCodewords; i++)
{
// De-interlace data blocks.
resultBytes[i * dataBlocksCount + j] = codewordBytes[i];
}
}
// Decode the contents of that stream of bytes
return DecodedBitStreamParser.decode(resultBytes);
}
/// <summary>
/// <p>Given data and error-correction codewords received, possibly corrupted by errors, attempts to
/// correct the errors in-place using Reed-Solomon error correction.</p>
///
/// <param name="codewordBytes">data and error correction codewords</param>
/// <param name="numDataCodewords">number of codewords that are data bytes</param>
/// </summary>
private bool correctErrors(byte[] codewordBytes, int numDataCodewords)
{
int numCodewords = codewordBytes.Length;
// First read into an array of ints
int[] codewordsInts = new int[numCodewords];
for (int i = 0; i < numCodewords; i++)
{
codewordsInts[i] = codewordBytes[i] & 0xFF;
}
int numECCodewords = codewordBytes.Length - numDataCodewords;
if (!rsDecoder.decode(codewordsInts, numECCodewords))
return false;
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < numDataCodewords; i++)
{
codewordBytes[i] = (byte)codewordsInts[i];
}
return true;
}
}
}

View File

@@ -1,261 +0,0 @@
/*
* Copyright 2007 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// The Version object encapsulates attributes about a particular
/// size Data Matrix Code.
///
/// <author>bbrown@google.com (Brian Brown)</author>
/// </summary>
public sealed class Version
{
private static readonly Version[] VERSIONS = buildVersions();
private readonly int versionNumber;
private readonly int symbolSizeRows;
private readonly int symbolSizeColumns;
private readonly int dataRegionSizeRows;
private readonly int dataRegionSizeColumns;
private readonly ECBlocks ecBlocks;
private readonly int totalCodewords;
internal Version(int versionNumber,
int symbolSizeRows,
int symbolSizeColumns,
int dataRegionSizeRows,
int dataRegionSizeColumns,
ECBlocks ecBlocks)
{
this.versionNumber = versionNumber;
this.symbolSizeRows = symbolSizeRows;
this.symbolSizeColumns = symbolSizeColumns;
this.dataRegionSizeRows = dataRegionSizeRows;
this.dataRegionSizeColumns = dataRegionSizeColumns;
this.ecBlocks = ecBlocks;
// Calculate the total number of codewords
int total = 0;
int ecCodewords = ecBlocks.ECCodewords;
ECB[] ecbArray = ecBlocks.ECBlocksValue;
foreach (ECB ecBlock in ecbArray)
{
total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
}
this.totalCodewords = total;
}
public int getVersionNumber()
{
return versionNumber;
}
public int getSymbolSizeRows()
{
return symbolSizeRows;
}
public int getSymbolSizeColumns()
{
return symbolSizeColumns;
}
public int getDataRegionSizeRows()
{
return dataRegionSizeRows;
}
public int getDataRegionSizeColumns()
{
return dataRegionSizeColumns;
}
public int getTotalCodewords()
{
return totalCodewords;
}
internal ECBlocks getECBlocks()
{
return ecBlocks;
}
/// <summary>
/// <p>Deduces version information from Data Matrix dimensions.</p>
///
/// <param name="numRows">Number of rows in modules</param>
/// <param name="numColumns">Number of columns in modules</param>
/// <returns>Version for a Data Matrix Code of those dimensions</returns>
/// <exception cref="FormatException">if dimensions do correspond to a valid Data Matrix size</exception>
/// </summary>
public static Version getVersionForDimensions(int numRows, int numColumns)
{
if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0)
{
return null;
}
foreach (var version in VERSIONS)
{
if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns)
{
return version;
}
}
return null;
}
/// <summary>
/// <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
/// use blocks of differing sizes within one version, so, this encapsulates the parameters for
/// each set of blocks. It also holds the number of error-correction codewords per block since it
/// will be the same across all blocks within one version.</p>
/// </summary>
internal sealed class ECBlocks
{
private readonly int ecCodewords;
private readonly ECB[] _ecBlocksValue;
internal ECBlocks(int ecCodewords, ECB ecBlocks)
{
this.ecCodewords = ecCodewords;
this._ecBlocksValue = new ECB[] { ecBlocks };
}
internal ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2)
{
this.ecCodewords = ecCodewords;
this._ecBlocksValue = new ECB[] { ecBlocks1, ecBlocks2 };
}
internal int ECCodewords
{
get { return ecCodewords; }
}
internal ECB[] ECBlocksValue
{
get { return _ecBlocksValue; }
}
}
/// <summary>
/// <p>Encapsualtes the parameters for one error-correction block in one symbol version.
/// This includes the number of data codewords, and the number of times a block with these
/// parameters is used consecutively in the Data Matrix code version's format.</p>
/// </summary>
internal sealed class ECB
{
private readonly int count;
private readonly int dataCodewords;
internal ECB(int count, int dataCodewords)
{
this.count = count;
this.dataCodewords = dataCodewords;
}
internal int Count
{
get { return count; }
}
internal int DataCodewords
{
get { return dataCodewords; }
}
}
override public String ToString()
{
return versionNumber.ToString();
}
/// <summary>
/// See ISO 16022:2006 5.5.1 Table 7
/// </summary>
private static Version[] buildVersions()
{
return new Version[]
{
new Version(1, 10, 10, 8, 8,
new ECBlocks(5, new ECB(1, 3))),
new Version(2, 12, 12, 10, 10,
new ECBlocks(7, new ECB(1, 5))),
new Version(3, 14, 14, 12, 12,
new ECBlocks(10, new ECB(1, 8))),
new Version(4, 16, 16, 14, 14,
new ECBlocks(12, new ECB(1, 12))),
new Version(5, 18, 18, 16, 16,
new ECBlocks(14, new ECB(1, 18))),
new Version(6, 20, 20, 18, 18,
new ECBlocks(18, new ECB(1, 22))),
new Version(7, 22, 22, 20, 20,
new ECBlocks(20, new ECB(1, 30))),
new Version(8, 24, 24, 22, 22,
new ECBlocks(24, new ECB(1, 36))),
new Version(9, 26, 26, 24, 24,
new ECBlocks(28, new ECB(1, 44))),
new Version(10, 32, 32, 14, 14,
new ECBlocks(36, new ECB(1, 62))),
new Version(11, 36, 36, 16, 16,
new ECBlocks(42, new ECB(1, 86))),
new Version(12, 40, 40, 18, 18,
new ECBlocks(48, new ECB(1, 114))),
new Version(13, 44, 44, 20, 20,
new ECBlocks(56, new ECB(1, 144))),
new Version(14, 48, 48, 22, 22,
new ECBlocks(68, new ECB(1, 174))),
new Version(15, 52, 52, 24, 24,
new ECBlocks(42, new ECB(2, 102))),
new Version(16, 64, 64, 14, 14,
new ECBlocks(56, new ECB(2, 140))),
new Version(17, 72, 72, 16, 16,
new ECBlocks(36, new ECB(4, 92))),
new Version(18, 80, 80, 18, 18,
new ECBlocks(48, new ECB(4, 114))),
new Version(19, 88, 88, 20, 20,
new ECBlocks(56, new ECB(4, 144))),
new Version(20, 96, 96, 22, 22,
new ECBlocks(68, new ECB(4, 174))),
new Version(21, 104, 104, 24, 24,
new ECBlocks(56, new ECB(6, 136))),
new Version(22, 120, 120, 18, 18,
new ECBlocks(68, new ECB(6, 175))),
new Version(23, 132, 132, 20, 20,
new ECBlocks(62, new ECB(8, 163))),
new Version(24, 144, 144, 22, 22,
new ECBlocks(62, new ECB(8, 156), new ECB(2, 155))),
new Version(25, 8, 18, 6, 16,
new ECBlocks(7, new ECB(1, 5))),
new Version(26, 8, 32, 6, 14,
new ECBlocks(11, new ECB(1, 10))),
new Version(27, 12, 26, 10, 24,
new ECBlocks(14, new ECB(1, 16))),
new Version(28, 12, 36, 10, 16,
new ECBlocks(18, new ECB(1, 22))),
new Version(29, 16, 36, 14, 16,
new ECBlocks(24, new ECB(1, 32))),
new Version(30, 16, 48, 14, 22,
new ECBlocks(28, new ECB(1, 49)))
};
}
}
}

View File

@@ -1,487 +0,0 @@
/*
* Copyright 2008 ZXing authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using ZXing.Common;
using ZXing.Common.Detector;
namespace ZXing.Datamatrix.Internal
{
/// <summary>
/// <p>Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code
/// is rotated or skewed, or partially obscured.</p>
/// </summary>
/// <author>Sean Owen</author>
public sealed class Detector
{
private readonly BitMatrix image;
private readonly WhiteRectangleDetector rectangleDetector;
/// <summary>
/// Initializes a new instance of the <see cref="Detector"/> class.
/// </summary>
/// <param name="image">The image.</param>
public Detector(BitMatrix image)
{
this.image = image;
rectangleDetector = WhiteRectangleDetector.Create(image);
}
/// <summary>
/// <p>Detects a Data Matrix Code in an image.</p>
/// </summary>
/// <returns><see cref="DetectorResult" />encapsulating results of detecting a Data Matrix Code or null</returns>
public DetectorResult detect()
{
if (rectangleDetector == null)
// can be null, if the image is to small
return null;
ResultPoint[] cornerPoints = rectangleDetector.detect();
if (cornerPoints == null)
return null;
var pointA = cornerPoints[0];
var pointB = cornerPoints[1];
var pointC = cornerPoints[2];
var pointD = cornerPoints[3];
// Point A and D are across the diagonal from one another,
// as are B and C. Figure out which are the solid black lines
// by counting transitions
var transitions = new List<ResultPointsAndTransitions>(4);
transitions.Add(transitionsBetween(pointA, pointB));
transitions.Add(transitionsBetween(pointA, pointC));
transitions.Add(transitionsBetween(pointB, pointD));
transitions.Add(transitionsBetween(pointC, pointD));
transitions.Sort(new ResultPointsAndTransitionsComparator());
// Sort by number of transitions. First two will be the two solid sides; last two
// will be the two alternating black/white sides
var lSideOne = transitions[0];
var lSideTwo = transitions[1];
// Figure out which point is their intersection by tallying up the number of times we see the
// endpoints in the four endpoints. One will show up twice.
var pointCount = new Dictionary<ResultPoint, int>();
increment(pointCount, lSideOne.From);
increment(pointCount, lSideOne.To);
increment(pointCount, lSideTwo.From);
increment(pointCount, lSideTwo.To);
ResultPoint maybeTopLeft = null;
ResultPoint bottomLeft = null;
ResultPoint maybeBottomRight = null;
foreach (var entry in pointCount)
{
ResultPoint point = entry.Key;
int value = entry.Value;
if (value == 2)
{
bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides
}
else
{
// Otherwise it's either top left or bottom right -- just assign the two arbitrarily now
if (maybeTopLeft == null)
{
maybeTopLeft = point;
}
else
{
maybeBottomRight = point;
}
}
}
if (maybeTopLeft == null || bottomLeft == null || maybeBottomRight == null)
{
return null;
}
// Bottom left is correct but top left and bottom right might be switched
ResultPoint[] corners = { maybeTopLeft, bottomLeft, maybeBottomRight };
// Use the dot product trick to sort them out
ResultPoint.orderBestPatterns(corners);
// Now we know which is which:
ResultPoint bottomRight = corners[0];
bottomLeft = corners[1];
ResultPoint topLeft = corners[2];
// Which point didn't we find in relation to the "L" sides? that's the top right corner
ResultPoint topRight;
if (!pointCount.ContainsKey(pointA))
{
topRight = pointA;
}
else if (!pointCount.ContainsKey(pointB))
{
topRight = pointB;
}
else if (!pointCount.ContainsKey(pointC))
{
topRight = pointC;
}
else
{
topRight = pointD;
}
// Next determine the dimension by tracing along the top or right side and counting black/white
// transitions. Since we start inside a black module, we should see a number of transitions
// equal to 1 less than the code dimension. Well, actually 2 less, because we are going to
// end on a black module:
// The top right point is actually the corner of a module, which is one of the two black modules
// adjacent to the white module at the top right. Tracing to that corner from either the top left
// or bottom right should work here.
int dimensionTop = transitionsBetween(topLeft, topRight).Transitions;
int dimensionRight = transitionsBetween(bottomRight, topRight).Transitions;
if ((dimensionTop & 0x01) == 1)
{
// it can't be odd, so, round... up?
dimensionTop++;
}
dimensionTop += 2;
if ((dimensionRight & 0x01) == 1)
{
// it can't be odd, so, round... up?
dimensionRight++;
}
dimensionRight += 2;
BitMatrix bits;
ResultPoint correctedTopRight;
// Rectanguar symbols are 6x16, 6x28, 10x24, 10x32, 14x32, or 14x44. If one dimension is more
// than twice the other, it's certainly rectangular, but to cut a bit more slack we accept it as
// rectangular if the bigger side is at least 7/4 times the other:
if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop)
{
// The matrix is rectangular
correctedTopRight =
correctTopRightRectangular(bottomLeft, bottomRight, topLeft, topRight, dimensionTop, dimensionRight);
if (correctedTopRight == null)
{
correctedTopRight = topRight;
}
dimensionTop = transitionsBetween(topLeft, correctedTopRight).Transitions;
dimensionRight = transitionsBetween(bottomRight, correctedTopRight).Transitions;
if ((dimensionTop & 0x01) == 1)
{
// it can't be odd, so, round... up?
dimensionTop++;
}
if ((dimensionRight & 0x01) == 1)
{
// it can't be odd, so, round... up?
dimensionRight++;
}
bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, correctedTopRight, dimensionTop, dimensionRight);
}
else
{
// The matrix is square
int dimension = Math.Min(dimensionRight, dimensionTop);
// correct top right point to match the white module
correctedTopRight = correctTopRight(bottomLeft, bottomRight, topLeft, topRight, dimension);
if (correctedTopRight == null)
{
correctedTopRight = topRight;
}
// Redetermine the dimension using the corrected top right point
int dimensionCorrected = Math.Max(transitionsBetween(topLeft, correctedTopRight).Transitions,
transitionsBetween(bottomRight, correctedTopRight).Transitions);
dimensionCorrected++;
if ((dimensionCorrected & 0x01) == 1)
{
dimensionCorrected++;
}
bits = sampleGrid(image,
topLeft,
bottomLeft,
bottomRight,
correctedTopRight,
dimensionCorrected,
dimensionCorrected);
}
if (bits == null)
return null;
return new DetectorResult(bits, new ResultPoint[] { topLeft, bottomLeft, bottomRight, correctedTopRight });
}
/// <summary>
/// Calculates the position of the white top right module using the output of the rectangle detector
/// for a rectangular matrix
/// </summary>
private ResultPoint correctTopRightRectangular(ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint topLeft,
ResultPoint topRight,
int dimensionTop,
int dimensionRight)
{
float corr = distance(bottomLeft, bottomRight) / (float)dimensionTop;
int norm = distance(topLeft, topRight);
if (norm == 0)
return null;
float cos = (topRight.X - topLeft.X) / norm;
float sin = (topRight.Y - topLeft.Y) / norm;
ResultPoint c1 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin);
corr = distance(bottomLeft, topLeft) / (float)dimensionRight;
norm = distance(bottomRight, topRight);
if (norm == 0)
return null;
cos = (topRight.X - bottomRight.X) / norm;
sin = (topRight.Y - bottomRight.Y) / norm;
ResultPoint c2 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin);
if (!isValid(c1))
{
if (isValid(c2))
{
return c2;
}
return null;
}
if (!isValid(c2))
{
return c1;
}
int l1 = Math.Abs(dimensionTop - transitionsBetween(topLeft, c1).Transitions) +
Math.Abs(dimensionRight - transitionsBetween(bottomRight, c1).Transitions);
int l2 = Math.Abs(dimensionTop - transitionsBetween(topLeft, c2).Transitions) +
Math.Abs(dimensionRight - transitionsBetween(bottomRight, c2).Transitions);
if (l1 <= l2)
{
return c1;
}
return c2;
}
/// <summary>
/// Calculates the position of the white top right module using the output of the rectangle detector
/// for a square matrix
/// </summary>
private ResultPoint correctTopRight(ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint topLeft,
ResultPoint topRight,
int dimension)
{
float corr = distance(bottomLeft, bottomRight) / (float)dimension;
int norm = distance(topLeft, topRight);
if (norm == 0)
return null;
float cos = (topRight.X - topLeft.X) / norm;
float sin = (topRight.Y - topLeft.Y) / norm;
ResultPoint c1 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin);
corr = distance(bottomLeft, topLeft) / (float)dimension;
norm = distance(bottomRight, topRight);
if (norm == 0)
return null;
cos = (topRight.X - bottomRight.X) / norm;
sin = (topRight.Y - bottomRight.Y) / norm;
ResultPoint c2 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin);
if (!isValid(c1))
{
if (isValid(c2))
{
return c2;
}
return null;
}
if (!isValid(c2))
{
return c1;
}
int l1 = Math.Abs(transitionsBetween(topLeft, c1).Transitions -
transitionsBetween(bottomRight, c1).Transitions);
int l2 = Math.Abs(transitionsBetween(topLeft, c2).Transitions -
transitionsBetween(bottomRight, c2).Transitions);
return l1 <= l2 ? c1 : c2;
}
private bool isValid(ResultPoint p)
{
return p.X >= 0 && p.X < image.Width && p.Y > 0 && p.Y < image.Height;
}
// L2 distance
private static int distance(ResultPoint a, ResultPoint b)
{
return MathUtils.round(ResultPoint.distance(a, b));
}
/// <summary>
/// Increments the Integer associated with a key by one.
/// </summary>
private static void increment(IDictionary<ResultPoint, int> table, ResultPoint key)
{
if (table.ContainsKey(key))
{
int value = table[key];
table[key] = value + 1;
}
else
{
table[key] = 1;
}
}
private static BitMatrix sampleGrid(BitMatrix image,
ResultPoint topLeft,
ResultPoint bottomLeft,
ResultPoint bottomRight,
ResultPoint topRight,
int dimensionX,
int dimensionY)
{
GridSampler sampler = GridSampler.Instance;
return sampler.sampleGrid(image,
dimensionX,
dimensionY,
0.5f,
0.5f,
dimensionX - 0.5f,
0.5f,
dimensionX - 0.5f,
dimensionY - 0.5f,
0.5f,
dimensionY - 0.5f,
topLeft.X,
topLeft.Y,
topRight.X,
topRight.Y,
bottomRight.X,
bottomRight.Y,
bottomLeft.X,
bottomLeft.Y);
}
/// <summary>
/// Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.
/// </summary>
private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to)
{
// See QR Code Detector, sizeOfBlackWhiteBlackRun()
int fromX = (int)from.X;
int fromY = (int)from.Y;
int toX = (int)to.X;
int toY = (int)to.Y;
bool steep = Math.Abs(toY - fromY) > Math.Abs(toX - fromX);
if (steep)
{
int temp = fromX;
fromX = fromY;
fromY = temp;
temp = toX;
toX = toY;
toY = temp;
}
int dx = Math.Abs(toX - fromX);
int dy = Math.Abs(toY - fromY);
int error = -dx >> 1;
int ystep = fromY < toY ? 1 : -1;
int xstep = fromX < toX ? 1 : -1;
int transitions = 0;
bool inBlack = image[steep ? fromY : fromX, steep ? fromX : fromY];
for (int x = fromX, y = fromY; x != toX; x += xstep)
{
bool isBlack = image[steep ? y : x, steep ? x : y];
if (isBlack != inBlack)
{
transitions++;
inBlack = isBlack;
}
error += dy;
if (error > 0)
{
if (y == toY)
{
break;
}
y += ystep;
error -= dx;
}
}
return new ResultPointsAndTransitions(from, to, transitions);
}
/// <summary>
/// Simply encapsulates two points and a number of transitions between them.
/// </summary>
private sealed class ResultPointsAndTransitions
{
public ResultPoint From { get; private set; }
public ResultPoint To { get; private set; }
public int Transitions { get; private set; }
public ResultPointsAndTransitions(ResultPoint from, ResultPoint to, int transitions)
{
From = from;
To = to;
Transitions = transitions;
}
override public String ToString()
{
return From + "/" + To + '/' + Transitions;
}
}
/// <summary>
/// Orders ResultPointsAndTransitions by number of transitions, ascending.
/// </summary>
private sealed class ResultPointsAndTransitionsComparator : IComparer<ResultPointsAndTransitions>
{
public int Compare(ResultPointsAndTransitions o1, ResultPointsAndTransitions o2)
{
return o1.Transitions - o2.Transitions;
}
}
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class ASCIIEncoder : Encoder
{
public int EncodingMode
{
get { return Encodation.ASCII; }
}
public void encode(EncoderContext context)
{
//step B
int n = HighLevelEncoder.determineConsecutiveDigitCount(context.Message, context.Pos);
if (n >= 2)
{
context.writeCodeword(encodeASCIIDigits(context.Message[context.Pos],
context.Message[context.Pos + 1]));
context.Pos += 2;
}
else
{
char c = context.CurrentChar;
int newMode = HighLevelEncoder.lookAheadTest(context.Message, context.Pos, EncodingMode);
if (newMode != EncodingMode)
{
switch (newMode)
{
case Encodation.BASE256:
context.writeCodeword(HighLevelEncoder.LATCH_TO_BASE256);
context.signalEncoderChange(Encodation.BASE256);
return;
case Encodation.C40:
context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
context.signalEncoderChange(Encodation.C40);
return;
case Encodation.X12:
context.writeCodeword(HighLevelEncoder.LATCH_TO_ANSIX12);
context.signalEncoderChange(Encodation.X12);
break;
case Encodation.TEXT:
context.writeCodeword(HighLevelEncoder.LATCH_TO_TEXT);
context.signalEncoderChange(Encodation.TEXT);
break;
case Encodation.EDIFACT:
context.writeCodeword(HighLevelEncoder.LATCH_TO_EDIFACT);
context.signalEncoderChange(Encodation.EDIFACT);
break;
default:
throw new InvalidOperationException("Illegal mode: " + newMode);
}
}
else if (HighLevelEncoder.isExtendedASCII(c))
{
context.writeCodeword(HighLevelEncoder.UPPER_SHIFT);
context.writeCodeword((char)(c - 128 + 1));
context.Pos++;
}
else
{
context.writeCodeword((char)(c + 1));
context.Pos++;
}
}
}
private static char encodeASCIIDigits(char digit1, char digit2)
{
if (HighLevelEncoder.isDigit(digit1) && HighLevelEncoder.isDigit(digit2))
{
int num = (digit1 - 48) * 10 + (digit2 - 48);
return (char)(num + 130);
}
throw new ArgumentException("not digits: " + digit1 + digit2);
}
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class Base256Encoder : Encoder
{
public int EncodingMode
{
get { return Encodation.BASE256; }
}
public void encode(EncoderContext context)
{
var buffer = new StringBuilder();
buffer.Append('\u0000'); //Initialize length field
while (context.HasMoreCharacters)
{
char c = context.CurrentChar;
buffer.Append(c);
context.Pos++;
int newMode = HighLevelEncoder.lookAheadTest(context.Message, context.Pos, EncodingMode);
if (newMode != EncodingMode)
{
context.signalEncoderChange(newMode);
break;
}
}
int dataCount = buffer.Length - 1;
const int lengthFieldSize = 1;
int currentSize = context.CodewordCount + dataCount + lengthFieldSize;
context.updateSymbolInfo(currentSize);
bool mustPad = (context.SymbolInfo.dataCapacity - currentSize) > 0;
if (context.HasMoreCharacters || mustPad)
{
if (dataCount <= 249)
{
buffer[0] = (char)dataCount;
}
else if (dataCount > 249 && dataCount <= 1555)
{
buffer[0] = (char)((dataCount / 250) + 249);
buffer.Insert(1, new [] { (char)(dataCount % 250) });
}
else
{
throw new InvalidOperationException(
"Message length not in valid ranges: " + dataCount);
}
}
{
var c = buffer.Length;
for (int i = 0; i < c; i++)
{
context.writeCodeword(randomize255State(
buffer[i], context.CodewordCount + 1));
}
}
}
private static char randomize255State(char ch, int codewordPosition)
{
int pseudoRandom = ((149 * codewordPosition) % 255) + 1;
int tempVariable = ch + pseudoRandom;
if (tempVariable <= 255)
{
return (char)tempVariable;
}
return (char)(tempVariable - 256);
}
}
}

View File

@@ -1,223 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal class C40Encoder : Encoder
{
virtual public int EncodingMode
{
get { return Encodation.C40; }
}
virtual public void encode(EncoderContext context)
{
//step C
var buffer = new StringBuilder();
while (context.HasMoreCharacters)
{
char c = context.CurrentChar;
context.Pos++;
int lastCharSize = encodeChar(c, buffer);
int unwritten = (buffer.Length / 3) * 2;
int curCodewordCount = context.CodewordCount + unwritten;
context.updateSymbolInfo(curCodewordCount);
int available = context.SymbolInfo.dataCapacity - curCodewordCount;
if (!context.HasMoreCharacters)
{
//Avoid having a single C40 value in the last triplet
var removed = new StringBuilder();
if ((buffer.Length % 3) == 2)
{
if (available < 2 || available > 2)
{
lastCharSize = backtrackOneCharacter(context, buffer, removed,
lastCharSize);
}
}
while ((buffer.Length % 3) == 1
&& ((lastCharSize <= 3 && available != 1) || lastCharSize > 3))
{
lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize);
}
break;
}
int count = buffer.Length;
if ((count % 3) == 0)
{
int newMode = HighLevelEncoder.lookAheadTest(context.Message, context.Pos, EncodingMode);
if (newMode != EncodingMode)
{
context.signalEncoderChange(newMode);
break;
}
}
}
handleEOD(context, buffer);
}
private int backtrackOneCharacter(EncoderContext context,
StringBuilder buffer, StringBuilder removed, int lastCharSize)
{
int count = buffer.Length;
buffer.Remove(count - lastCharSize, lastCharSize);
context.Pos--;
char c = context.CurrentChar;
lastCharSize = encodeChar(c, removed);
context.resetSymbolInfo(); //Deal with possible reduction in symbol size
return lastCharSize;
}
internal static void writeNextTriplet(EncoderContext context, StringBuilder buffer)
{
context.writeCodewords(encodeToCodewords(buffer, 0));
buffer.Remove(0, 3);
}
/// <summary>
/// Handle "end of data" situations
/// </summary>
/// <param name="context">the encoder context</param>
/// <param name="buffer">the buffer with the remaining encoded characters</param>
virtual protected void handleEOD(EncoderContext context, StringBuilder buffer)
{
int unwritten = (buffer.Length / 3) * 2;
int rest = buffer.Length % 3;
int curCodewordCount = context.CodewordCount + unwritten;
context.updateSymbolInfo(curCodewordCount);
int available = context.SymbolInfo.dataCapacity - curCodewordCount;
if (rest == 2)
{
buffer.Append('\u0000'); //Shift 1
while (buffer.Length >= 3)
{
writeNextTriplet(context, buffer);
}
if (context.HasMoreCharacters)
{
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
}
}
else if (available == 1 && rest == 1)
{
while (buffer.Length >= 3)
{
writeNextTriplet(context, buffer);
}
if (context.HasMoreCharacters)
{
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
}
// else no unlatch
context.Pos--;
}
else if (rest == 0)
{
while (buffer.Length >= 3)
{
writeNextTriplet(context, buffer);
}
if (available > 0 || context.HasMoreCharacters)
{
context.writeCodeword(HighLevelEncoder.C40_UNLATCH);
}
}
else
{
throw new InvalidOperationException("Unexpected case. Please report!");
}
context.signalEncoderChange(Encodation.ASCII);
}
virtual protected int encodeChar(char c, StringBuilder sb)
{
if (c == ' ')
{
sb.Append('\u0003');
return 1;
}
if (c >= '0' && c <= '9')
{
sb.Append((char)(c - 48 + 4));
return 1;
}
if (c >= 'A' && c <= 'Z')
{
sb.Append((char)(c - 65 + 14));
return 1;
}
if (c >= '\u0000' && c <= '\u001f')
{
sb.Append('\u0000'); //Shift 1 Set
sb.Append(c);
return 2;
}
if (c >= '!' && c <= '/')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 33));
return 2;
}
if (c >= ':' && c <= '@')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 58 + 15));
return 2;
}
if (c >= '[' && c <= '_')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 91 + 22));
return 2;
}
if (c >= '\u0060' && c <= '\u007f')
{
sb.Append('\u0002'); //Shift 3 Set
sb.Append((char)(c - 96));
return 2;
}
if (c >= '\u0080')
{
sb.Append("\u0001\u001e"); //Shift 2, Upper Shift
int len = 2;
len += encodeChar((char)(c - 128), sb);
return len;
}
throw new InvalidOperationException("Illegal character: " + c);
}
private static String encodeToCodewords(StringBuilder sb, int startPos)
{
char c1 = sb[startPos];
char c2 = sb[startPos + 1];
char c3 = sb[startPos + 2];
int v = (1600 * c1) + (40 * c2) + c3 + 1;
char cw1 = (char)(v / 256);
char cw2 = (char)(v % 256);
return new String(new char[] { cw1, cw2 });
}
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Datamatrix.Encoder
{
internal sealed class DataMatrixSymbolInfo144 : SymbolInfo
{
public DataMatrixSymbolInfo144()
: base(false, 1558, 620, 22, 22, 36, -1, 62)
{
}
public override int getInterleavedBlockCount()
{
return 10;
}
public override int getDataLengthForInterleavedBlock(int index)
{
return (index <= 8) ? 156 : 155;
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* Copyright 2013 ZXing.Net authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using ZXing.Common;
using ZXing.Datamatrix.Encoder;
namespace ZXing.Datamatrix
{
/// <summary>
/// The class holds the available options for the DatamatrixWriter
/// </summary>
public class DatamatrixEncodingOptions : EncodingOptions
{
/// <summary>
/// Specifies the matrix shape for Data Matrix
/// </summary>
public SymbolShapeHint? SymbolShape
{
get
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_SHAPE))
{
return (SymbolShapeHint)Hints[EncodeHintType.DATA_MATRIX_SHAPE];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_SHAPE))
Hints.Remove(EncodeHintType.DATA_MATRIX_SHAPE);
}
else
{
Hints[EncodeHintType.DATA_MATRIX_SHAPE] = value;
}
}
}
/// <summary>
/// Specifies a minimum barcode size
/// </summary>
public Dimension MinSize
{
get
{
if (Hints.ContainsKey(EncodeHintType.MIN_SIZE))
{
return (Dimension)Hints[EncodeHintType.MIN_SIZE];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.MIN_SIZE))
Hints.Remove(EncodeHintType.MIN_SIZE);
}
else
{
Hints[EncodeHintType.MIN_SIZE] = value;
}
}
}
/// <summary>
/// Specifies a maximum barcode size
/// </summary>
public Dimension MaxSize
{
get
{
if (Hints.ContainsKey(EncodeHintType.MAX_SIZE))
{
return (Dimension)Hints[EncodeHintType.MAX_SIZE];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.MAX_SIZE))
Hints.Remove(EncodeHintType.MAX_SIZE);
}
else
{
Hints[EncodeHintType.MAX_SIZE] = value;
}
}
}
/// <summary>
/// Specifies the default encodation
/// Make sure that the content fits into the encodation value, otherwise there will be an exception thrown.
/// standard value: Encodation.ASCII
/// </summary>
public int? DefaultEncodation
{
get
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION))
{
return (int)Hints[EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION];
}
return null;
}
set
{
if (value == null)
{
if (Hints.ContainsKey(EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION))
Hints.Remove(EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION);
}
else
{
Hints[EncodeHintType.DATA_MATRIX_DEFAULT_ENCODATION] = value;
}
}
}
}
}

View File

@@ -1,222 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E).
/// </summary>
public class DefaultPlacement
{
private readonly String codewords;
private readonly int numrows;
private readonly int numcols;
private readonly byte[] bits;
/// <summary>
/// Main constructor
/// </summary>
/// <param name="codewords">the codewords to place</param>
/// <param name="numcols">the number of columns</param>
/// <param name="numrows">the number of rows</param>
public DefaultPlacement(String codewords, int numcols, int numrows)
{
this.codewords = codewords;
this.numcols = numcols;
this.numrows = numrows;
this.bits = new byte[numcols * numrows];
SupportClass.Fill(this.bits, (byte)2); //Initialize with "not set" value
}
public int Numrows
{
get { return numrows; }
}
public int Numcols
{
get { return numcols; }
}
public byte[] Bits
{
get { return bits; }
}
public bool getBit(int col, int row)
{
return bits[row * numcols + col] == 1;
}
public void setBit(int col, int row, bool bit)
{
bits[row * numcols + col] = bit ? (byte)1 : (byte)0;
}
public bool hasBit(int col, int row)
{
return bits[row * numcols + col] < 2;
}
public void place()
{
int pos = 0;
int row = 4;
int col = 0;
do
{
/* repeatedly first check for one of the special corner cases, then... */
if ((row == numrows) && (col == 0))
{
corner1(pos++);
}
if ((row == numrows - 2) && (col == 0) && ((numcols % 4) != 0))
{
corner2(pos++);
}
if ((row == numrows - 2) && (col == 0) && (numcols % 8 == 4))
{
corner3(pos++);
}
if ((row == numrows + 4) && (col == 2) && ((numcols % 8) == 0))
{
corner4(pos++);
}
/* sweep upward diagonally, inserting successive characters... */
do
{
if ((row < numrows) && (col >= 0) && !hasBit(col, row))
{
utah(row, col, pos++);
}
row -= 2;
col += 2;
} while (row >= 0 && (col < numcols));
row++;
col += 3;
/* and then sweep downward diagonally, inserting successive characters, ... */
do
{
if ((row >= 0) && (col < numcols) && !hasBit(col, row))
{
utah(row, col, pos++);
}
row += 2;
col -= 2;
} while ((row < numrows) && (col >= 0));
row += 3;
col++;
/* ...until the entire array is scanned */
} while ((row < numrows) || (col < numcols));
/* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */
if (!hasBit(numcols - 1, numrows - 1))
{
setBit(numcols - 1, numrows - 1, true);
setBit(numcols - 2, numrows - 2, true);
}
}
private void module(int row, int col, int pos, int bit)
{
if (row < 0)
{
row += numrows;
col += 4 - ((numrows + 4) % 8);
}
if (col < 0)
{
col += numcols;
row += 4 - ((numcols + 4) % 8);
}
// Note the conversion:
int v = codewords[pos];
v &= 1 << (8 - bit);
setBit(col, row, v != 0);
}
/// <summary>
/// Places the 8 bits of a utah-shaped symbol character in ECC200.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="col">The col.</param>
/// <param name="pos">character position</param>
private void utah(int row, int col, int pos)
{
module(row - 2, col - 2, pos, 1);
module(row - 2, col - 1, pos, 2);
module(row - 1, col - 2, pos, 3);
module(row - 1, col - 1, pos, 4);
module(row - 1, col, pos, 5);
module(row, col - 2, pos, 6);
module(row, col - 1, pos, 7);
module(row, col, pos, 8);
}
private void corner1(int pos)
{
module(numrows - 1, 0, pos, 1);
module(numrows - 1, 1, pos, 2);
module(numrows - 1, 2, pos, 3);
module(0, numcols - 2, pos, 4);
module(0, numcols - 1, pos, 5);
module(1, numcols - 1, pos, 6);
module(2, numcols - 1, pos, 7);
module(3, numcols - 1, pos, 8);
}
private void corner2(int pos)
{
module(numrows - 3, 0, pos, 1);
module(numrows - 2, 0, pos, 2);
module(numrows - 1, 0, pos, 3);
module(0, numcols - 4, pos, 4);
module(0, numcols - 3, pos, 5);
module(0, numcols - 2, pos, 6);
module(0, numcols - 1, pos, 7);
module(1, numcols - 1, pos, 8);
}
private void corner3(int pos)
{
module(numrows - 3, 0, pos, 1);
module(numrows - 2, 0, pos, 2);
module(numrows - 1, 0, pos, 3);
module(0, numcols - 2, pos, 4);
module(0, numcols - 1, pos, 5);
module(1, numcols - 1, pos, 6);
module(2, numcols - 1, pos, 7);
module(3, numcols - 1, pos, 8);
}
private void corner4(int pos)
{
module(numrows - 1, 0, pos, 1);
module(numrows - 1, numcols - 1, pos, 2);
module(0, numcols - 3, pos, 3);
module(0, numcols - 2, pos, 4);
module(0, numcols - 1, pos, 5);
module(1, numcols - 3, pos, 6);
module(1, numcols - 2, pos, 7);
module(1, numcols - 1, pos, 8);
}
}
}

View File

@@ -1,165 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class EdifactEncoder : Encoder
{
public int EncodingMode
{
get { return Encodation.EDIFACT; }
}
public void encode(EncoderContext context)
{
//step F
var buffer = new StringBuilder();
while (context.HasMoreCharacters)
{
char c = context.CurrentChar;
encodeChar(c, buffer);
context.Pos++;
int count = buffer.Length;
if (count >= 4)
{
context.writeCodewords(encodeToCodewords(buffer, 0));
buffer.Remove(0, 4);
int newMode = HighLevelEncoder.lookAheadTest(context.Message, context.Pos, EncodingMode);
if (newMode != EncodingMode)
{
context.signalEncoderChange(Encodation.ASCII);
break;
}
}
}
buffer.Append((char)31); //Unlatch
handleEOD(context, buffer);
}
/// <summary>
/// Handle "end of data" situations
/// </summary>
/// <param name="context">the encoder context</param>
/// <param name="buffer">the buffer with the remaining encoded characters</param>
private static void handleEOD(EncoderContext context, StringBuilder buffer)
{
try
{
int count = buffer.Length;
if (count == 0)
{
return; //Already finished
}
if (count == 1)
{
//Only an unlatch at the end
context.updateSymbolInfo();
int available = context.SymbolInfo.dataCapacity - context.CodewordCount;
int remaining = context.RemainingCharacters;
if (remaining == 0 && available <= 2)
{
return; //No unlatch
}
}
if (count > 4)
{
throw new InvalidOperationException("Count must not exceed 4");
}
int restChars = count - 1;
String encoded = encodeToCodewords(buffer, 0);
bool endOfSymbolReached = !context.HasMoreCharacters;
bool restInAscii = endOfSymbolReached && restChars <= 2;
if (restChars <= 2)
{
context.updateSymbolInfo(context.CodewordCount + restChars);
int available = context.SymbolInfo.dataCapacity - context.CodewordCount;
if (available >= 3)
{
restInAscii = false;
context.updateSymbolInfo(context.CodewordCount + encoded.Length);
//available = context.symbolInfo.dataCapacity - context.getCodewordCount();
}
}
if (restInAscii)
{
context.resetSymbolInfo();
context.Pos -= restChars;
}
else
{
context.writeCodewords(encoded);
}
}
finally
{
context.signalEncoderChange(Encodation.ASCII);
}
}
private static void encodeChar(char c, StringBuilder sb)
{
if (c >= ' ' && c <= '?')
{
sb.Append(c);
}
else if (c >= '@' && c <= '^')
{
sb.Append((char)(c - 64));
}
else
{
HighLevelEncoder.illegalCharacter(c);
}
}
private static String encodeToCodewords(StringBuilder sb, int startPos)
{
int len = sb.Length - startPos;
if (len == 0)
{
throw new InvalidOperationException("StringBuilder must not be empty");
}
char c1 = sb[startPos];
char c2 = len >= 2 ? sb[startPos + 1] : (char)0;
char c3 = len >= 3 ? sb[startPos + 2] : (char)0;
char c4 = len >= 4 ? sb[startPos + 3] : (char)0;
int v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4;
char cw1 = (char)((v >> 16) & 255);
char cw2 = (char)((v >> 8) & 255);
char cw3 = (char)(v & 255);
var res = new StringBuilder(3);
res.Append(cw1);
if (len >= 2)
{
res.Append(cw2);
}
if (len >= 3)
{
res.Append(cw3);
}
return res.ToString();
}
}
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// Enumeration for encodation types
/// </summary>
public sealed class Encodation
{
public const int ASCII = 0;
public const int C40 = 1;
public const int TEXT = 2;
public const int X12 = 3;
public const int EDIFACT = 4;
public const int BASE256 = 5;
}
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Datamatrix.Encoder
{
internal interface Encoder
{
int EncodingMode { get; }
void encode(EncoderContext context);
}
}

View File

@@ -1,186 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class EncoderContext
{
private readonly String msg;
private SymbolShapeHint shape;
private Dimension minSize;
private Dimension maxSize;
private readonly StringBuilder codewords;
private int pos;
private int newEncoding;
private SymbolInfo symbolInfo;
private int skipAtEnd;
private static readonly Encoding encoding;
static EncoderContext()
{
#if !(WindowsCE || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE)
encoding = Encoding.GetEncoding("ISO-8859-1");
#elif WindowsCE
try
{
encoding = Encoding.GetEncoding("ISO-8859-1");
}
catch (PlatformNotSupportedException)
{
encoding = Encoding.GetEncoding(1252);
}
#else
// not fully correct but what else
encoding = Encoding.GetEncoding("UTF-8");
#endif
}
public EncoderContext(String msg)
{
//From this point on Strings are not Unicode anymore!
var msgBinary = encoding.GetBytes(msg);
var sb = new StringBuilder(msgBinary.Length);
var c = msgBinary.Length;
for (int i = 0; i < c; i++)
{
// TODO: does it works in .Net the same way?
var ch = (char)(msgBinary[i] & 0xff);
if (ch == '?' && msg[i] != '?')
{
throw new ArgumentException("Message contains characters outside " + encoding.WebName + " encoding.");
}
sb.Append(ch);
}
this.msg = sb.ToString(); //Not Unicode here!
shape = SymbolShapeHint.FORCE_NONE;
this.codewords = new StringBuilder(msg.Length);
newEncoding = -1;
}
public void setSymbolShape(SymbolShapeHint shape)
{
this.shape = shape;
}
public void setSizeConstraints(Dimension minSize, Dimension maxSize)
{
this.minSize = minSize;
this.maxSize = maxSize;
}
public void setSkipAtEnd(int count)
{
this.skipAtEnd = count;
}
public char CurrentChar
{
get { return msg[pos]; }
}
public char Current
{
get { return msg[pos]; }
}
public void writeCodewords(String codewords)
{
this.codewords.Append(codewords);
}
public void writeCodeword(char codeword)
{
this.codewords.Append(codeword);
}
public int CodewordCount
{
get { return this.codewords.Length; }
}
public void signalEncoderChange(int encoding)
{
this.newEncoding = encoding;
}
public void resetEncoderSignal()
{
this.newEncoding = -1;
}
public bool HasMoreCharacters
{
get { return pos < TotalMessageCharCount; }
}
private int TotalMessageCharCount
{
get { return msg.Length - skipAtEnd; }
}
public int RemainingCharacters
{
get { return TotalMessageCharCount - pos; }
}
public void updateSymbolInfo()
{
updateSymbolInfo(CodewordCount);
}
public void updateSymbolInfo(int len)
{
if (this.symbolInfo == null || len > this.symbolInfo.dataCapacity)
{
this.symbolInfo = SymbolInfo.lookup(len, shape, minSize, maxSize, true);
}
}
public void resetSymbolInfo()
{
this.symbolInfo = null;
}
public int Pos
{
get { return pos; }
set { pos = value; }
}
public StringBuilder Codewords
{
get { return codewords; }
}
public SymbolInfo SymbolInfo
{
get { return symbolInfo; }
}
public int NewEncoding
{
get { return newEncoding; }
}
public String Message
{
get { return msg; }
}
}
}

View File

@@ -1,283 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// Error Correction Code for ECC200.
/// </summary>
public static class ErrorCorrection
{
/// <summary>
/// Lookup table which factors to use for which number of error correction codewords.
/// See FACTORS.
/// </summary>
private static readonly int[] FACTOR_SETS
= { 5, 7, 10, 11, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 62, 68 };
/// <summary>
/// Precomputed polynomial factors for ECC 200.
/// </summary>
private static readonly int[][] FACTORS = {
new[] {228, 48, 15, 111, 62},
new[] {23, 68, 144, 134, 240, 92, 254},
new[] {28, 24, 185, 166, 223, 248, 116, 255, 110, 61},
new[] {175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120},
new[] {41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242},
new[] {156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185}
,
new[]
{
83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254,
225,
48, 90, 188
},
new[]
{
15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79,
108,
82, 27, 174, 186, 172
},
new[]
{
52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21
, 5
, 172,
254, 124, 12, 181, 184, 96, 50, 193
},
new[]
{
211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34,
249,
121,
17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255
},
new[]
{
245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220,
251, 80, 182,
229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59
,
25,
225, 98, 81, 112
},
new[]
{
77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133,
242
, 8,
175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57,
54,
101,
248, 202, 69, 50, 150, 177, 226, 5, 9, 5
},
new[]
{
245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205,
188,
237, 87,
191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100
,
66, 138,
186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253
,
225, 19
},
new[]
{
175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192
,
215, 235,
150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117,
203,
29, 232,
144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127,
67,
247, 28,
155, 43, 203, 107, 233, 53, 143, 46
},
new[]
{
242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143,
108,
196, 37,
185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175,
64
, 114, 71,
161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163
,
31,
176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204
},
new[]
{
220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36
,
73, 127,
213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15,
160,
227, 236,
66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231,
136,
223, 239,
181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153,
132, 63,
96, 103, 82, 186
}
};
private const int MODULO_VALUE = 0x12D;
private static readonly int[] LOG;
private static readonly int[] ALOG;
static ErrorCorrection()
{
//Create log and antilog table
LOG = new int[256];
ALOG = new int[255];
int p = 1;
for (int i = 0; i < 255; i++)
{
ALOG[i] = p;
LOG[p] = i;
p <<= 1;
if (p >= 256)
{
p ^= MODULO_VALUE;
}
}
}
/// <summary>
/// Creates the ECC200 error correction for an encoded message.
/// </summary>
/// <param name="codewords">The codewords.</param>
/// <param name="symbolInfo">information about the symbol to be encoded</param>
/// <returns>the codewords with interleaved error correction.</returns>
public static String encodeECC200(String codewords, SymbolInfo symbolInfo)
{
if (codewords.Length != symbolInfo.dataCapacity)
{
throw new ArgumentException(
"The number of codewords does not match the selected symbol");
}
var sb = new StringBuilder(symbolInfo.dataCapacity + symbolInfo.errorCodewords);
sb.Append(codewords);
int blockCount = symbolInfo.getInterleavedBlockCount();
if (blockCount == 1)
{
String ecc = createECCBlock(codewords, symbolInfo.errorCodewords);
sb.Append(ecc);
}
else
{
sb.Length = sb.Capacity;
int[] dataSizes = new int[blockCount];
int[] errorSizes = new int[blockCount];
int[] startPos = new int[blockCount];
for (int i = 0; i < blockCount; i++)
{
dataSizes[i] = symbolInfo.getDataLengthForInterleavedBlock(i + 1);
errorSizes[i] = symbolInfo.getErrorLengthForInterleavedBlock(i + 1);
startPos[i] = 0;
if (i > 0)
{
startPos[i] = startPos[i - 1] + dataSizes[i];
}
}
for (int block = 0; block < blockCount; block++)
{
var temp = new StringBuilder(dataSizes[block]);
for (int d = block; d < symbolInfo.dataCapacity; d += blockCount)
{
temp.Append(codewords[d]);
}
String ecc = createECCBlock(temp.ToString(), errorSizes[block]);
int pos = 0;
for (int e = block; e < errorSizes[block] * blockCount; e += blockCount)
{
sb[symbolInfo.dataCapacity + e] = ecc[pos++];
}
}
}
return sb.ToString();
}
private static String createECCBlock(String codewords, int numECWords)
{
return createECCBlock(codewords, 0, codewords.Length, numECWords);
}
private static String createECCBlock(String codewords, int start, int len, int numECWords)
{
int table = -1;
for (int i = 0; i < FACTOR_SETS.Length; i++)
{
if (FACTOR_SETS[i] == numECWords)
{
table = i;
break;
}
}
if (table < 0)
{
throw new ArgumentException(
"Illegal number of error correction codewords specified: " + numECWords);
}
int[] poly = FACTORS[table];
char[] ecc = new char[numECWords];
for (int i = 0; i < numECWords; i++)
{
ecc[i] = (char)0;
}
for (int i = start; i < start + len; i++)
{
int m = ecc[numECWords - 1] ^ codewords[i];
for (int k = numECWords - 1; k > 0; k--)
{
if (m != 0 && poly[k] != 0)
{
ecc[k] = (char)(ecc[k - 1] ^ ALOG[(LOG[m] + LOG[poly[k]]) % 255]);
}
else
{
ecc[k] = ecc[k - 1];
}
}
if (m != 0 && poly[0] != 0)
{
ecc[0] = (char)ALOG[(LOG[m] + LOG[poly[0]]) % 255];
}
else
{
ecc[0] = (char)0;
}
}
char[] eccReversed = new char[numECWords];
for (int i = 0; i < numECWords; i++)
{
eccReversed[i] = ecc[numECWords - i - 1];
}
return new String(eccReversed);
}
}
}

View File

@@ -1,537 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in
/// annex S.
/// </summary>
internal static class HighLevelEncoder
{
/// <summary>
/// Padding character
/// </summary>
public const char PAD = (char)129;
/// <summary>
/// mode latch to C40 encodation mode
/// </summary>
public const char LATCH_TO_C40 = (char)230;
/// <summary>
/// mode latch to Base 256 encodation mode
/// </summary>
public const char LATCH_TO_BASE256 = (char)231;
/// <summary>
/// FNC1 Codeword
/// </summary>
public const char FNC1 = (char)232;
/// <summary>
/// Structured Append Codeword
/// </summary>
public const char STRUCTURED_APPEND = (char)233;
/// <summary>
/// Reader Programming
/// </summary>
public const char READER_PROGRAMMING = (char)234;
/// <summary>
/// Upper Shift
/// </summary>
public const char UPPER_SHIFT = (char)235;
/// <summary>
/// 05 Macro
/// </summary>
public const char MACRO_05 = (char)236;
/// <summary>
/// 06 Macro
/// </summary>
public const char MACRO_06 = (char)237;
/// <summary>
/// mode latch to ANSI X.12 encodation mode
/// </summary>
public const char LATCH_TO_ANSIX12 = (char)238;
/// <summary>
/// mode latch to Text encodation mode
/// </summary>
public const char LATCH_TO_TEXT = (char)239;
/// <summary>
/// mode latch to EDIFACT encodation mode
/// </summary>
public const char LATCH_TO_EDIFACT = (char)240;
/// <summary>
/// ECI character (Extended Channel Interpretation)
/// </summary>
public const char ECI = (char)241;
/// <summary>
/// Unlatch from C40 encodation
/// </summary>
public const char C40_UNLATCH = (char)254;
/// <summary>
/// Unlatch from X12 encodation
/// </summary>
public const char X12_UNLATCH = (char)254;
/// <summary>
/// 05 Macro header
/// </summary>
public const String MACRO_05_HEADER = "[)>\u001E05\u001D";
/// <summary>
/// 06 Macro header
/// </summary>
public const String MACRO_06_HEADER = "[)>\u001E06\u001D";
/// <summary>
/// Macro trailer
/// </summary>
public const String MACRO_TRAILER = "\u001E\u0004";
/*
/// <summary>
/// Converts the message to a byte array using the default encoding (cp437) as defined by the
/// specification
/// </summary>
/// <param name="msg">the message</param>
/// <returns>the byte array of the message</returns>
public static byte[] getBytesForMessage(String msg)
{
return Encoding.GetEncoding("CP437").GetBytes(msg); //See 4.4.3 and annex B of ISO/IEC 15438:2001(E)
}
*/
private static char randomize253State(char ch, int codewordPosition)
{
int pseudoRandom = ((149 * codewordPosition) % 253) + 1;
int tempVariable = ch + pseudoRandom;
return tempVariable <= 254 ? (char)tempVariable : (char)(tempVariable - 254);
}
/// <summary>
/// Performs message encoding of a DataMatrix message using the algorithm described in annex P
/// of ISO/IEC 16022:2000(E).
/// </summary>
/// <param name="msg">the message</param>
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
public static String encodeHighLevel(String msg)
{
return encodeHighLevel(msg, SymbolShapeHint.FORCE_NONE, null, null, Encodation.ASCII);
}
/// <summary>
/// Performs message encoding of a DataMatrix message using the algorithm described in annex P
/// of ISO/IEC 16022:2000(E).
/// </summary>
/// <param name="msg">the message</param>
/// <param name="shape">requested shape. May be {@code SymbolShapeHint.FORCE_NONE},{@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}.</param>
/// <param name="minSize">the minimum symbol size constraint or null for no constraint</param>
/// <param name="maxSize">the maximum symbol size constraint or null for no constraint</param>
/// <returns>the encoded message (the char values range from 0 to 255)</returns>
public static String encodeHighLevel(String msg,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
int defaultEncodation)
{
//the codewords 0..255 are encoded as Unicode characters
Encoder[] encoders =
{
new ASCIIEncoder(), new C40Encoder(), new TextEncoder(),
new X12Encoder(), new EdifactEncoder(), new Base256Encoder()
};
var context = new EncoderContext(msg);
context.setSymbolShape(shape);
context.setSizeConstraints(minSize, maxSize);
if (msg.StartsWith(MACRO_05_HEADER) && msg.EndsWith(MACRO_TRAILER))
{
context.writeCodeword(MACRO_05);
context.setSkipAtEnd(2);
context.Pos += MACRO_05_HEADER.Length;
}
else if (msg.StartsWith(MACRO_06_HEADER) && msg.EndsWith(MACRO_TRAILER))
{
context.writeCodeword(MACRO_06);
context.setSkipAtEnd(2);
context.Pos += MACRO_06_HEADER.Length;
}
int encodingMode = defaultEncodation; //Default mode
switch (encodingMode)
{
case Encodation.BASE256:
context.writeCodeword(HighLevelEncoder.LATCH_TO_BASE256);
break;
case Encodation.C40:
context.writeCodeword(HighLevelEncoder.LATCH_TO_C40);
break;
case Encodation.X12:
context.writeCodeword(HighLevelEncoder.LATCH_TO_ANSIX12);
break;
case Encodation.TEXT:
context.writeCodeword(HighLevelEncoder.LATCH_TO_TEXT);
break;
case Encodation.EDIFACT:
context.writeCodeword(HighLevelEncoder.LATCH_TO_EDIFACT);
break;
case Encodation.ASCII:
break;
default:
throw new InvalidOperationException("Illegal mode: " + encodingMode);
}
while (context.HasMoreCharacters)
{
encoders[encodingMode].encode(context);
if (context.NewEncoding >= 0)
{
encodingMode = context.NewEncoding;
context.resetEncoderSignal();
}
}
int len = context.Codewords.Length;
context.updateSymbolInfo();
int capacity = context.SymbolInfo.dataCapacity;
if (len < capacity)
{
if (encodingMode != Encodation.ASCII && encodingMode != Encodation.BASE256)
{
context.writeCodeword('\u00fe'); //Unlatch (254)
}
}
//Padding
StringBuilder codewords = context.Codewords;
if (codewords.Length < capacity)
{
codewords.Append(PAD);
}
while (codewords.Length < capacity)
{
codewords.Append(randomize253State(PAD, codewords.Length + 1));
}
return context.Codewords.ToString();
}
internal static int lookAheadTest(String msg, int startpos, int currentMode)
{
if (startpos >= msg.Length)
{
return currentMode;
}
float[] charCounts;
//step J
if (currentMode == Encodation.ASCII)
{
charCounts = new [] { 0, 1, 1, 1, 1, 1.25f };
}
else
{
charCounts = new [] { 1, 2, 2, 2, 2, 2.25f };
charCounts[currentMode] = 0;
}
int charsProcessed = 0;
while (true)
{
//step K
if ((startpos + charsProcessed) == msg.Length)
{
var min = Int32.MaxValue;
var mins = new byte[6];
var intCharCounts = new int[6];
min = findMinimums(charCounts, intCharCounts, min, mins);
var minCount = getMinimumCount(mins);
if (intCharCounts[Encodation.ASCII] == min)
{
return Encodation.ASCII;
}
if (minCount == 1 && mins[Encodation.BASE256] > 0)
{
return Encodation.BASE256;
}
if (minCount == 1 && mins[Encodation.EDIFACT] > 0)
{
return Encodation.EDIFACT;
}
if (minCount == 1 && mins[Encodation.TEXT] > 0)
{
return Encodation.TEXT;
}
if (minCount == 1 && mins[Encodation.X12] > 0)
{
return Encodation.X12;
}
return Encodation.C40;
}
char c = msg[startpos + charsProcessed];
charsProcessed++;
//step L
if (isDigit(c))
{
charCounts[Encodation.ASCII] += 0.5f;
}
else if (isExtendedASCII(c))
{
charCounts[Encodation.ASCII] = (int)Math.Ceiling(charCounts[Encodation.ASCII]);
charCounts[Encodation.ASCII] += 2;
}
else
{
charCounts[Encodation.ASCII] = (int)Math.Ceiling(charCounts[Encodation.ASCII]);
charCounts[Encodation.ASCII]++;
}
//step M
if (isNativeC40(c))
{
charCounts[Encodation.C40] += 2.0f / 3.0f;
}
else if (isExtendedASCII(c))
{
charCounts[Encodation.C40] += 8.0f / 3.0f;
}
else
{
charCounts[Encodation.C40] += 4.0f / 3.0f;
}
//step N
if (isNativeText(c))
{
charCounts[Encodation.TEXT] += 2.0f / 3.0f;
}
else if (isExtendedASCII(c))
{
charCounts[Encodation.TEXT] += 8.0f / 3.0f;
}
else
{
charCounts[Encodation.TEXT] += 4.0f / 3.0f;
}
//step O
if (isNativeX12(c))
{
charCounts[Encodation.X12] += 2.0f / 3.0f;
}
else if (isExtendedASCII(c))
{
charCounts[Encodation.X12] += 13.0f / 3.0f;
}
else
{
charCounts[Encodation.X12] += 10.0f / 3.0f;
}
//step P
if (isNativeEDIFACT(c))
{
charCounts[Encodation.EDIFACT] += 3.0f / 4.0f;
}
else if (isExtendedASCII(c))
{
charCounts[Encodation.EDIFACT] += 17.0f / 4.0f;
}
else
{
charCounts[Encodation.EDIFACT] += 13.0f / 4.0f;
}
// step Q
if (isSpecialB256(c))
{
charCounts[Encodation.BASE256] += 4;
}
else
{
charCounts[Encodation.BASE256]++;
}
//step R
if (charsProcessed >= 4)
{
var intCharCounts = new int[6];
var mins = new byte[6];
findMinimums(charCounts, intCharCounts, Int32.MaxValue, mins);
int minCount = getMinimumCount(mins);
if (intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.BASE256]
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.C40]
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.TEXT]
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.X12]
&& intCharCounts[Encodation.ASCII] < intCharCounts[Encodation.EDIFACT])
{
return Encodation.ASCII;
}
if (intCharCounts[Encodation.BASE256] < intCharCounts[Encodation.ASCII]
|| (mins[Encodation.C40] + mins[Encodation.TEXT] + mins[Encodation.X12] + mins[Encodation.EDIFACT]) == 0)
{
return Encodation.BASE256;
}
if (minCount == 1 && mins[Encodation.EDIFACT] > 0)
{
return Encodation.EDIFACT;
}
if (minCount == 1 && mins[Encodation.TEXT] > 0)
{
return Encodation.TEXT;
}
if (minCount == 1 && mins[Encodation.X12] > 0)
{
return Encodation.X12;
}
if (intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.ASCII]
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.BASE256]
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.EDIFACT]
&& intCharCounts[Encodation.C40] + 1 < intCharCounts[Encodation.TEXT])
{
if (intCharCounts[Encodation.C40] < intCharCounts[Encodation.X12])
{
return Encodation.C40;
}
if (intCharCounts[Encodation.C40] == intCharCounts[Encodation.X12])
{
int p = startpos + charsProcessed + 1;
while (p < msg.Length)
{
char tc = msg[p];
if (isX12TermSep(tc))
{
return Encodation.X12;
}
if (!isNativeX12(tc))
{
break;
}
p++;
}
return Encodation.C40;
}
}
}
}
}
private static int findMinimums(float[] charCounts, int[] intCharCounts, int min, byte[] mins)
{
SupportClass.Fill(mins, (byte)0);
for (int i = 0; i < 6; i++)
{
intCharCounts[i] = (int)Math.Ceiling(charCounts[i]);
int current = intCharCounts[i];
if (min > current)
{
min = current;
SupportClass.Fill(mins, (byte)0);
}
if (min == current)
{
mins[i]++;
}
}
return min;
}
private static int getMinimumCount(byte[] mins)
{
int minCount = 0;
for (int i = 0; i < 6; i++)
{
minCount += mins[i];
}
return minCount;
}
internal static bool isDigit(char ch)
{
return ch >= '0' && ch <= '9';
}
internal static bool isExtendedASCII(char ch)
{
return ch >= 128 && ch <= 255;
}
internal static bool isNativeC40(char ch)
{
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
}
internal static bool isNativeText(char ch)
{
return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
}
internal static bool isNativeX12(char ch)
{
return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
}
internal static bool isX12TermSep(char ch)
{
return (ch == '\r') //CR
|| (ch == '*')
|| (ch == '>');
}
internal static bool isNativeEDIFACT(char ch)
{
return ch >= ' ' && ch <= '^';
}
internal static bool isSpecialB256(char ch)
{
return false; //TODO NOT IMPLEMENTED YET!!!
}
/// <summary>
/// Determines the number of consecutive characters that are encodable using numeric compaction.
/// </summary>
/// <param name="msg">the message</param>
/// <param name="startpos">the start position within the message</param>
/// <returns>the requested character count</returns>
public static int determineConsecutiveDigitCount(String msg, int startpos)
{
int count = 0;
int len = msg.Length;
int idx = startpos;
if (idx < len)
{
char ch = msg[idx];
while (isDigit(ch) && idx < len)
{
count++;
idx++;
if (idx < len)
{
ch = msg[idx];
}
}
}
return count;
}
internal static void illegalCharacter(char c)
{
throw new ArgumentException(String.Format("Illegal character: {0} (0x{1:X})", c, (int)c));
}
}
}

View File

@@ -1,258 +0,0 @@
/*
* Copyright 2006 Jeremias Maerki
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// Symbol info table for DataMatrix.
/// </summary>
public class SymbolInfo
{
internal static readonly SymbolInfo[] PROD_SYMBOLS = {
new SymbolInfo(false, 3, 5, 8, 8, 1),
new SymbolInfo(false, 5, 7, 10, 10, 1),
/*rect*/new SymbolInfo(true, 5, 7, 16, 6, 1),
new SymbolInfo(false, 8, 10, 12, 12, 1),
/*rect*/new SymbolInfo(true, 10, 11, 14, 6, 2),
new SymbolInfo(false, 12, 12, 14, 14, 1),
/*rect*/new SymbolInfo(true, 16, 14, 24, 10, 1),
new SymbolInfo(false, 18, 14, 16, 16, 1),
new SymbolInfo(false, 22, 18, 18, 18, 1),
/*rect*/new SymbolInfo(true, 22, 18, 16, 10, 2),
new SymbolInfo(false, 30, 20, 20, 20, 1),
/*rect*/new SymbolInfo(true, 32, 24, 16, 14, 2),
new SymbolInfo(false, 36, 24, 22, 22, 1),
new SymbolInfo(false, 44, 28, 24, 24, 1),
/*rect*/new SymbolInfo(true, 49, 28, 22, 14, 2),
new SymbolInfo(false, 62, 36, 14, 14, 4),
new SymbolInfo(false, 86, 42, 16, 16, 4),
new SymbolInfo(false, 114, 48, 18, 18, 4),
new SymbolInfo(false, 144, 56, 20, 20, 4),
new SymbolInfo(false, 174, 68, 22, 22, 4),
new SymbolInfo(false, 204, 84, 24, 24, 4, 102, 42),
new SymbolInfo(false, 280, 112, 14, 14, 16, 140, 56),
new SymbolInfo(false, 368, 144, 16, 16, 16, 92, 36),
new SymbolInfo(false, 456, 192, 18, 18, 16, 114, 48),
new SymbolInfo(false, 576, 224, 20, 20, 16, 144, 56),
new SymbolInfo(false, 696, 272, 22, 22, 16, 174, 68),
new SymbolInfo(false, 816, 336, 24, 24, 16, 136, 56),
new SymbolInfo(false, 1050, 408, 18, 18, 36, 175, 68),
new SymbolInfo(false, 1304, 496, 20, 20, 36, 163, 62),
new DataMatrixSymbolInfo144(),
};
private static SymbolInfo[] symbols = PROD_SYMBOLS;
/**
* Overrides the symbol info set used by this class. Used for testing purposes.
*
* @param override the symbol info set to use
*/
public static void overrideSymbolSet(SymbolInfo[] @override)
{
symbols = @override;
}
private readonly bool rectangular;
internal readonly int dataCapacity;
internal readonly int errorCodewords;
public readonly int matrixWidth;
public readonly int matrixHeight;
private readonly int dataRegions;
private readonly int rsBlockData;
private readonly int rsBlockError;
public SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords,
int matrixWidth, int matrixHeight, int dataRegions)
: this(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions,
dataCapacity, errorCodewords)
{
}
internal SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords,
int matrixWidth, int matrixHeight, int dataRegions,
int rsBlockData, int rsBlockError)
{
this.rectangular = rectangular;
this.dataCapacity = dataCapacity;
this.errorCodewords = errorCodewords;
this.matrixWidth = matrixWidth;
this.matrixHeight = matrixHeight;
this.dataRegions = dataRegions;
this.rsBlockData = rsBlockData;
this.rsBlockError = rsBlockError;
}
public static SymbolInfo lookup(int dataCodewords)
{
return lookup(dataCodewords, SymbolShapeHint.FORCE_NONE, true);
}
public static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape)
{
return lookup(dataCodewords, shape, true);
}
public static SymbolInfo lookup(int dataCodewords, bool allowRectangular, bool fail)
{
SymbolShapeHint shape = allowRectangular
? SymbolShapeHint.FORCE_NONE : SymbolShapeHint.FORCE_SQUARE;
return lookup(dataCodewords, shape, fail);
}
private static SymbolInfo lookup(int dataCodewords, SymbolShapeHint shape, bool fail)
{
return lookup(dataCodewords, shape, null, null, fail);
}
public static SymbolInfo lookup(int dataCodewords,
SymbolShapeHint shape,
Dimension minSize,
Dimension maxSize,
bool fail)
{
foreach (SymbolInfo symbol in symbols)
{
if (shape == SymbolShapeHint.FORCE_SQUARE && symbol.rectangular)
{
continue;
}
if (shape == SymbolShapeHint.FORCE_RECTANGLE && !symbol.rectangular)
{
continue;
}
if (minSize != null
&& (symbol.getSymbolWidth() < minSize.Width
|| symbol.getSymbolHeight() < minSize.Height))
{
continue;
}
if (maxSize != null
&& (symbol.getSymbolWidth() > maxSize.Width
|| symbol.getSymbolHeight() > maxSize.Height))
{
continue;
}
if (dataCodewords <= symbol.dataCapacity)
{
return symbol;
}
}
if (fail)
{
throw new ArgumentException(
"Can't find a symbol arrangement that matches the message. Data codewords: "
+ dataCodewords);
}
return null;
}
int getHorizontalDataRegions()
{
switch (dataRegions)
{
case 1:
return 1;
case 2:
return 2;
case 4:
return 2;
case 16:
return 4;
case 36:
return 6;
default:
throw new InvalidOperationException("Cannot handle this number of data regions");
}
}
int getVerticalDataRegions()
{
switch (dataRegions)
{
case 1:
return 1;
case 2:
return 1;
case 4:
return 2;
case 16:
return 4;
case 36:
return 6;
default:
throw new InvalidOperationException("Cannot handle this number of data regions");
}
}
public int getSymbolDataWidth()
{
return getHorizontalDataRegions() * matrixWidth;
}
public int getSymbolDataHeight()
{
return getVerticalDataRegions() * matrixHeight;
}
public int getSymbolWidth()
{
return getSymbolDataWidth() + (getHorizontalDataRegions() * 2);
}
public int getSymbolHeight()
{
return getSymbolDataHeight() + (getVerticalDataRegions() * 2);
}
public int getCodewordCount()
{
return dataCapacity + errorCodewords;
}
virtual public int getInterleavedBlockCount()
{
return dataCapacity / rsBlockData;
}
virtual public int getDataLengthForInterleavedBlock(int index)
{
return rsBlockData;
}
public int getErrorLengthForInterleavedBlock(int index)
{
return rsBlockError;
}
public override String ToString()
{
var sb = new StringBuilder();
sb.Append(rectangular ? "Rectangular Symbol:" : "Square Symbol:");
sb.Append(" data region ").Append(matrixWidth).Append('x').Append(matrixHeight);
sb.Append(", symbol size ").Append(getSymbolWidth()).Append('x').Append(getSymbolHeight());
sb.Append(", symbol data size ").Append(getSymbolDataWidth()).Append('x').Append(getSymbolDataHeight());
sb.Append(", codewords ").Append(dataCapacity).Append('+').Append(errorCodewords);
return sb.ToString();
}
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace ZXing.Datamatrix.Encoder
{
/// <summary>
/// Enumeration for DataMatrix symbol shape hint. It can be used to force square or rectangular
/// symbols.
/// </summary>
public enum SymbolShapeHint
{
FORCE_NONE,
FORCE_SQUARE,
FORCE_RECTANGLE,
}
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class TextEncoder : C40Encoder
{
override public int EncodingMode
{
get { return Encodation.TEXT; }
}
override protected int encodeChar(char c, StringBuilder sb)
{
if (c == ' ')
{
sb.Append('\u0003');
return 1;
}
if (c >= '0' && c <= '9')
{
sb.Append((char)(c - 48 + 4));
return 1;
}
if (c >= 'a' && c <= 'z')
{
sb.Append((char)(c - 97 + 14));
return 1;
}
if (c >= '\u0000' && c <= '\u001f')
{
sb.Append('\u0000'); //Shift 1 Set
sb.Append(c);
return 2;
}
if (c >= '!' && c <= '/')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 33));
return 2;
}
if (c >= ':' && c <= '@')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 58 + 15));
return 2;
}
if (c >= '[' && c <= '_')
{
sb.Append('\u0001'); //Shift 2 Set
sb.Append((char)(c - 91 + 22));
return 2;
}
if (c == '\u0060')
{
sb.Append('\u0002'); //Shift 3 Set
sb.Append((char)(c - 96));
return 2;
}
if (c >= 'A' && c <= 'Z')
{
sb.Append('\u0002'); //Shift 3 Set
sb.Append((char)(c - 65 + 1));
return 2;
}
if (c >= '{' && c <= '\u007f')
{
sb.Append('\u0002'); //Shift 3 Set
sb.Append((char)(c - 123 + 27));
return 2;
}
if (c >= '\u0080')
{
sb.Append("\u0001\u001e"); //Shift 2, Upper Shift
int len = 2;
len += encodeChar((char)(c - 128), sb);
return len;
}
HighLevelEncoder.illegalCharacter(c);
return -1;
}
}
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright 2006-2007 Jeremias Maerki.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Text;
namespace ZXing.Datamatrix.Encoder
{
internal sealed class X12Encoder : C40Encoder
{
public override int EncodingMode
{
get { return Encodation.X12; }
}
public override void encode(EncoderContext context)
{
//step C
var buffer = new StringBuilder();
int currentMode = EncodingMode;
while (context.HasMoreCharacters)
{
char c = context.CurrentChar;
context.Pos++;
encodeChar(c, buffer);
int count = buffer.Length;
if ((count%3) == 0)
{
writeNextTriplet(context, buffer);
int newMode = HighLevelEncoder.lookAheadTest(context.Message, context.Pos, currentMode);
if (newMode != currentMode)
{
context.signalEncoderChange(newMode);
break;
}
}
}
handleEOD(context, buffer);
}
protected override int encodeChar(char c, StringBuilder sb)
{
if (c == '\r')
{
sb.Append('\u0000');
}
else if (c == '*')
{
sb.Append('\u0001');
}
else if (c == '>')
{
sb.Append('\u0002');
}
else if (c == ' ')
{
sb.Append('\u0003');
}
else if (c >= '0' && c <= '9')
{
sb.Append((char) (c - 48 + 4));
}
else if (c >= 'A' && c <= 'Z')
{
sb.Append((char) (c - 65 + 14));
}
else
{
HighLevelEncoder.illegalCharacter(c);
}
return 1;
}
protected override void handleEOD(EncoderContext context, StringBuilder buffer)
{
context.updateSymbolInfo();
int available = context.SymbolInfo.dataCapacity - context.CodewordCount;
int count = buffer.Length;
context.Pos -= count;
if (context.RemainingCharacters > 1 || available > 1 ||
context.RemainingCharacters != available)
context.writeCodeword(HighLevelEncoder.X12_UNLATCH);
if (context.NewEncoding < 0)
context.signalEncoderChange(Encodation.ASCII);
}
}
}

Some files were not shown because too many files have changed in this diff Show More