@@ -0,0 +1,152 @@ | |||||
/* | |||||
* 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; | |||||
#if !PORTABLE | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#if !UNITY | |||||
using System.Drawing; | |||||
using ZXing.QrCode; | |||||
#else | |||||
using UnityEngine; | |||||
#endif | |||||
#elif NETFX_CORE | |||||
using Windows.UI.Xaml.Media.Imaging; | |||||
#else | |||||
using System.Windows.Media.Imaging; | |||||
#endif | |||||
#endif | |||||
#if MONOANDROID | |||||
using Android.Graphics; | |||||
#endif | |||||
namespace ZXing | |||||
{ | |||||
/// <summary> | |||||
/// A smart class to decode the barcode inside a bitmap object | |||||
/// </summary> | |||||
#if MONOTOUCH | |||||
public class BarcodeReader : BarcodeReaderGeneric<MonoTouch.UIKit.UIImage>, IBarcodeReader, IMultipleBarcodeReader | |||||
{ | |||||
private static readonly Func<MonoTouch.UIKit.UIImage, LuminanceSource> defaultCreateLuminanceSource = | |||||
(img) => new RGBLuminanceSource(img); | |||||
#else | |||||
#if !PORTABLE | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#if !UNITY | |||||
public class BarcodeReader : BarcodeReaderGeneric<Bitmap>, IBarcodeReader | |||||
{ | |||||
private static readonly Func<Bitmap, LuminanceSource> defaultCreateLuminanceSource = | |||||
(bitmap) => new BitmapLuminanceSource(bitmap); | |||||
#else | |||||
public class BarcodeReader : BarcodeReaderGeneric<Color32[]>, IBarcodeReader, IMultipleBarcodeReader | |||||
{ | |||||
private static readonly Func<Color32[], int, int, LuminanceSource> defaultCreateLuminanceSource = | |||||
(rawColor32, width, height) => new Color32LuminanceSource(rawColor32, width, height); | |||||
#endif | |||||
#else | |||||
public class BarcodeReader : BarcodeReaderGeneric<WriteableBitmap>, IBarcodeReader, IMultipleBarcodeReader | |||||
{ | |||||
private static readonly Func<WriteableBitmap, LuminanceSource> defaultCreateLuminanceSource = | |||||
(bitmap) => new BitmapLuminanceSource(bitmap); | |||||
#endif | |||||
#else | |||||
public class BarcodeReader : BarcodeReaderGeneric<byte[]>, IBarcodeReader, IMultipleBarcodeReader | |||||
{ | |||||
private static readonly Func<byte[], LuminanceSource> defaultCreateLuminanceSource = | |||||
(data) => null; | |||||
#endif | |||||
#endif | |||||
/// <summary> | |||||
/// Initializes a new instance of the <see cref="BarcodeReader"/> class. | |||||
/// </summary> | |||||
public BarcodeReader() | |||||
: this(new QRCodeReader(), 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, | |||||
#if MONOTOUCH | |||||
Func<MonoTouch.UIKit.UIImage, LuminanceSource> createLuminanceSource, | |||||
#elif MONOANDROID | |||||
Func<Android.Graphics.Bitmap, LuminanceSource> createLuminanceSource, | |||||
#else | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#if !UNITY | |||||
#if !PORTABLE | |||||
Func<Bitmap, LuminanceSource> createLuminanceSource, | |||||
#else | |||||
Func<byte[], LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#else | |||||
Func<Color32[], int, int, LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#else | |||||
Func<WriteableBitmap, LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#endif | |||||
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> | |||||
public BarcodeReader(Reader reader, | |||||
#if MONOTOUCH | |||||
Func<MonoTouch.UIKit.UIImage, LuminanceSource> createLuminanceSource, | |||||
#elif MONOANDROID | |||||
Func<Android.Graphics.Bitmap, LuminanceSource> createLuminanceSource, | |||||
#else | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#if !UNITY | |||||
#if !PORTABLE | |||||
Func<Bitmap, LuminanceSource> createLuminanceSource, | |||||
#else | |||||
Func<byte[], LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#else | |||||
Func<Color32[], int, int, LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#else | |||||
Func<WriteableBitmap, LuminanceSource> createLuminanceSource, | |||||
#endif | |||||
#endif | |||||
Func<LuminanceSource, Binarizer> createBinarizer, | |||||
Func<byte[], int, int, RGBLuminanceSource.BitmapFormat, LuminanceSource> createRGBLuminanceSource | |||||
) | |||||
: base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer, createRGBLuminanceSource) | |||||
{ | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,436 @@ | |||||
/* | |||||
* 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.QrCode; | |||||
namespace ZXing | |||||
{ | |||||
/// <summary> | |||||
/// A smart class to decode the barcode inside a bitmap object | |||||
/// </summary> | |||||
public class BarcodeReaderGeneric<T> : IBarcodeReaderGeneric<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 QRCodeReader()); | |||||
} | |||||
} | |||||
/// <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 QRCodeReader(), 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 QRCodeReader(); | |||||
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 QRCodeReader; | |||||
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++) | |||||
{ | |||||
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; | |||||
} | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,161 @@ | |||||
/* | |||||
* 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; | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#if !UNITY | |||||
#if !PORTABLE | |||||
using System.Drawing; | |||||
#endif | |||||
#else | |||||
using UnityEngine; | |||||
#endif | |||||
#elif NETFX_CORE | |||||
using Windows.UI.Xaml.Media.Imaging; | |||||
#else | |||||
using System.Windows.Media.Imaging; | |||||
#endif | |||||
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); | |||||
#if MONOTOUCH | |||||
/// <summary> | |||||
/// Decodes the specified barcode bitmap. | |||||
/// </summary> | |||||
/// <param name="barcodeBitmap">The barcode bitmap.</param> | |||||
/// <returns>the result data or null</returns> | |||||
Result Decode(MonoTouch.UIKit.UIImage barcodeImage); | |||||
#elif MONOANDROID | |||||
/// <summary> | |||||
/// Decodes the specified barcode bitmap. | |||||
/// </summary> | |||||
/// <param name="barcodeBitmap">The barcode bitmap.</param> | |||||
/// <returns>the result data or null</returns> | |||||
Result Decode(Android.Graphics.Bitmap barcodeImage); | |||||
#else | |||||
#if !PORTABLE | |||||
#if !(SILVERLIGHT || NETFX_CORE) | |||||
#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(Bitmap barcodeBitmap); | |||||
#else | |||||
/// <summary> | |||||
/// Decodes the specified barcode bitmap. | |||||
/// </summary> | |||||
/// <param name="rawColor32">The image as Color32 array.</param> | |||||
/// <returns>the result data or null</returns> | |||||
Result Decode(Color32[] rawColor32, int width, int height); | |||||
#endif | |||||
#else | |||||
/// <summary> | |||||
/// Decodes the specified barcode bitmap. | |||||
/// </summary> | |||||
/// <param name="barcodeBitmap">The barcode bitmap.</param> | |||||
/// <returns>the result data or null</returns> | |||||
Result Decode(WriteableBitmap barcodeBitmap); | |||||
#endif | |||||
#endif | |||||
#endif | |||||
} | |||||
} |
@@ -0,0 +1,123 @@ | |||||
/* | |||||
* 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 | |||||
} | |||||
} |
@@ -0,0 +1,314 @@ | |||||
/* | |||||
* 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)); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,128 @@ | |||||
/* | |||||
* 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> {@link CharacterSetECI} representing ECI of given value, or null if it is legal but | |||||
/// unsupported | |||||
/// </returns> | |||||
/// <throws> IllegalArgumentException if ECI value is invalid </throws> | |||||
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> {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal | |||||
/// but unsupported | |||||
/// </returns> | |||||
public static CharacterSetECI getCharacterSetECIByName(String name) | |||||
{ | |||||
return NAME_TO_ECI[name.ToUpper()]; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,370 @@ | |||||
/* | |||||
* 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> | |||||
[Serializable] | |||||
public class DecodingOptions | |||||
{ | |||||
/// <summary> | |||||
/// Gets the data container for all options | |||||
/// </summary> | |||||
[Browsable(false)] | |||||
public IDictionary<DecodeHintType, object> Hints { get; private set; } | |||||
[field: NonSerialized] | |||||
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> | |||||
/// Initializes a new instance of the <see cref="EncodingOptions"/> 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); }; | |||||
} | |||||
[Serializable] | |||||
private class ChangeNotifyDictionary<TKey, TValue>: IDictionary<TKey, TValue> | |||||
{ | |||||
private readonly IDictionary<TKey, TValue> values; | |||||
[field: NonSerialized] | |||||
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(); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,66 @@ | |||||
/* | |||||
* 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; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,243 @@ | |||||
/* | |||||
* 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; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,288 @@ | |||||
/* | |||||
* 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; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,266 @@ | |||||
/* | |||||
* 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 | |||||
{ | |||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || WINDOWS_PHONE80 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE) | |||||
private const String PLATFORM_DEFAULT_ENCODING = "UTF-8"; | |||||
#else | |||||
private static String PLATFORM_DEFAULT_ENCODING = Encoding.Default.WebName; | |||||
#endif | |||||
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; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,102 @@ | |||||
/* | |||||
* 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. | |||||
*/ | |||||
namespace ZXing | |||||
{ | |||||
#if !WindowsCE | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
public delegate void Action(); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
public delegate void Action<in T1>(T1 param1); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
public delegate void Action<in T1, in T2>(T1 param1, T2 param2); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
public delegate void Action<in T1, in T2, in T3>(T1 param1, T2 param2, T3 param3); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="T4">The type of the 4.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <param name="param4">The param4.</param> | |||||
public delegate void Action<in T1, in T2, in T3, in T4>(T1 param1, T2 param2, T3 param3, T4 param4); | |||||
#else | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
public delegate void Action(); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
public delegate void Action<T1>(T1 param1); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
public delegate void Action<T1, T2>(T1 param1, T2 param2); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
public delegate void Action<T1, T2, T3>(T1 param1, T2 param2, T3 param3); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="T4">The type of the 4.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <param name="param4">The param4.</param> | |||||
public delegate void Action<T1, T2, T3, T4>(T1 param1, T2 param2, T3 param3, T4 param4); | |||||
#endif | |||||
} |
@@ -0,0 +1,122 @@ | |||||
/* | |||||
* 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 | |||||
{ | |||||
#if !WindowsCE | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<out TResult>(); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<in T1, out TResult>(T1 param1); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<in T1, in T2, out TResult>(T1 param1, T2 param2); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 param1, T2 param2, T3 param3); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="T4">The type of the 4.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <param name="param4">The param4.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 param1, T2 param2, T3 param3, T4 param4); | |||||
#else | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<TResult>(); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<T1, TResult>(T1 param1); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<T1, T2, TResult>(T1 param1, T2 param2); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<T1, T2, T3, TResult>(T1 param1, T2 param2, T3 param3); | |||||
/// <summary> | |||||
/// for compatibility with .net 4.0 | |||||
/// </summary> | |||||
/// <typeparam name="T1">The type of the 1.</typeparam> | |||||
/// <typeparam name="T2">The type of the 2.</typeparam> | |||||
/// <typeparam name="T3">The type of the 3.</typeparam> | |||||
/// <typeparam name="T4">The type of the 4.</typeparam> | |||||
/// <typeparam name="TResult">The type of the result.</typeparam> | |||||
/// <param name="param1">The param1.</param> | |||||
/// <param name="param2">The param2.</param> | |||||
/// <param name="param3">The param3.</param> | |||||
/// <param name="param4">The param4.</param> | |||||
/// <returns></returns> | |||||
public delegate TResult Func<T1, T2, T3, T4, TResult>(T1 param1, T2 param2, T3 param3, T4 param4); | |||||
#endif | |||||
} |
@@ -0,0 +1,29 @@ | |||||
/* | |||||
* 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 System | |||||
{ | |||||
internal class TimeZoneInfo | |||||
{ | |||||
internal static TimeZoneInfo Local = null; | |||||
internal static DateTime ConvertTime(DateTime dateTime, TimeZoneInfo destinationTimeZone) | |||||
{ | |||||
// TODO: fix it for .net 2.0 | |||||
return dateTime; | |||||
} | |||||
} | |||||
} |
@@ -54,7 +54,7 @@ namespace ZXing.QrCode.Internal | |||||
try | try | ||||
{ | { | ||||
//CharacterSetECI currentCharacterSetECI = null; | |||||
CharacterSetECI currentCharacterSetECI = null; | |||||
bool fc1InEffect = false; | bool fc1InEffect = false; | ||||
Mode mode; | Mode mode; | ||||
do | do | ||||
@@ -94,14 +94,29 @@ namespace ZXing.QrCode.Internal | |||||
symbolSequence = bits.readBits(8); | symbolSequence = bits.readBits(8); | ||||
parityData = bits.readBits(8); | parityData = bits.readBits(8); | ||||
} | } | ||||
else if (mode == Mode.ECI) | |||||
{ | |||||
// Count doesn't apply to ECI | |||||
int value = parseECIValue(bits); | |||||
currentCharacterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); | |||||
if (currentCharacterSetECI == null) | |||||
{ | |||||
return null; | |||||
} | |||||
} | |||||
else | else | ||||
{ | { | ||||
// First handle Hanzi mode which does not start with character count | // First handle Hanzi mode which does not start with character count | ||||
if (mode == Mode.HANZI) | if (mode == Mode.HANZI) | ||||
{ | { | ||||
//chinese mode contains a sub set indicator right after mode indicator | //chinese mode contains a sub set indicator right after mode indicator | ||||
//int subset = bits.readBits(4); | |||||
//int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); | |||||
int subset = bits.readBits(4); | |||||
int countHanzi = bits.readBits(mode.getCharacterCountBits(version)); | |||||
if (subset == GB2312_SUBSET) | |||||
{ | |||||
if (!decodeHanziSegment(bits, result, countHanzi)) | |||||
return null; | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -118,6 +133,16 @@ namespace ZXing.QrCode.Internal | |||||
if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) | if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) | ||||
return null; | return null; | ||||
} | } | ||||
else if (mode == Mode.BYTE) | |||||
{ | |||||
if (!decodeByteSegment(bits, result, count, currentCharacterSetECI, byteSegments, hints)) | |||||
return null; | |||||
} | |||||
else if (mode == Mode.KANJI) | |||||
{ | |||||
if (!decodeKanjiSegment(bits, result, count)) | |||||
return null; | |||||
} | |||||
else | else | ||||
{ | { | ||||
return null; | return null; | ||||
@@ -145,8 +170,214 @@ namespace ZXing.QrCode.Internal | |||||
symbolSequence, parityData); | symbolSequence, parityData); | ||||
} | } | ||||
/// <summary> | |||||
/// See specification GBT 18284-2000 | |||||
/// </summary> | |||||
/// <param name="bits">The bits.</param> | |||||
/// <param name="result">The result.</param> | |||||
/// <param name="count">The count.</param> | |||||
/// <returns></returns> | |||||
private static bool decodeHanziSegment(BitSource bits, | |||||
StringBuilder result, | |||||
int count) | |||||
{ | |||||
// Don't crash trying to read more bits than we have available. | |||||
if (count * 13 > bits.available()) | |||||
{ | |||||
return false; | |||||
} | |||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs | |||||
// and decode as GB2312 afterwards | |||||
byte[] buffer = new byte[2 * count]; | |||||
int offset = 0; | |||||
while (count > 0) | |||||
{ | |||||
// Each 13 bits encodes a 2-byte character | |||||
int twoBytes = bits.readBits(13); | |||||
int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); | |||||
if (assembledTwoBytes < 0x003BF) | |||||
{ | |||||
// In the 0xA1A1 to 0xAAFE range | |||||
assembledTwoBytes += 0x0A1A1; | |||||
} | |||||
else | |||||
{ | |||||
// In the 0xB0A1 to 0xFAFE range | |||||
assembledTwoBytes += 0x0A6A1; | |||||
} | |||||
buffer[offset] = (byte)((assembledTwoBytes >> 8) & 0xFF); | |||||
buffer[offset + 1] = (byte)(assembledTwoBytes & 0xFF); | |||||
offset += 2; | |||||
count--; | |||||
} | |||||
try | |||||
{ | |||||
result.Append(Encoding.GetEncoding(StringUtils.GB2312).GetString(buffer, 0, buffer.Length)); | |||||
} | |||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) | |||||
catch (ArgumentException) | |||||
{ | |||||
try | |||||
{ | |||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8 | |||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
#endif | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
private static bool decodeKanjiSegment(BitSource bits, | |||||
StringBuilder result, | |||||
int count) | |||||
{ | |||||
// Don't crash trying to read more bits than we have available. | |||||
if (count * 13 > bits.available()) | |||||
{ | |||||
return false; | |||||
} | |||||
// Each character will require 2 bytes. Read the characters as 2-byte pairs | |||||
// and decode as Shift_JIS afterwards | |||||
byte[] buffer = new byte[2 * count]; | |||||
int offset = 0; | |||||
while (count > 0) | |||||
{ | |||||
// Each 13 bits encodes a 2-byte character | |||||
int twoBytes = bits.readBits(13); | |||||
int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); | |||||
if (assembledTwoBytes < 0x01F00) | |||||
{ | |||||
// In the 0x8140 to 0x9FFC range | |||||
assembledTwoBytes += 0x08140; | |||||
} | |||||
else | |||||
{ | |||||
// In the 0xE040 to 0xEBBF range | |||||
assembledTwoBytes += 0x0C140; | |||||
} | |||||
buffer[offset] = (byte)(assembledTwoBytes >> 8); | |||||
buffer[offset + 1] = (byte)assembledTwoBytes; | |||||
offset += 2; | |||||
count--; | |||||
} | |||||
// Shift_JIS may not be supported in some environments: | |||||
try | |||||
{ | |||||
result.Append(Encoding.GetEncoding(StringUtils.SHIFT_JIS).GetString(buffer, 0, buffer.Length)); | |||||
} | |||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) | |||||
catch (ArgumentException) | |||||
{ | |||||
try | |||||
{ | |||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8 | |||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(buffer, 0, buffer.Length)); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
#endif | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
private static bool decodeByteSegment(BitSource bits, | |||||
StringBuilder result, | |||||
int count, | |||||
CharacterSetECI currentCharacterSetECI, | |||||
IList<byte[]> byteSegments, | |||||
IDictionary<DecodeHintType, object> hints) | |||||
{ | |||||
// Don't crash trying to read more bits than we have available. | |||||
if (count << 3 > bits.available()) | |||||
{ | |||||
return false; | |||||
} | |||||
byte[] readBytes = new byte[count]; | |||||
for (int i = 0; i < count; i++) | |||||
{ | |||||
readBytes[i] = (byte)bits.readBits(8); | |||||
} | |||||
String encoding; | |||||
if (currentCharacterSetECI == null) | |||||
{ | |||||
// The spec isn't clear on this mode; see | |||||
// section 6.4.5: t does not say which encoding to assuming | |||||
// upon decoding. I have seen ISO-8859-1 used as well as | |||||
// Shift_JIS -- without anything like an ECI designator to | |||||
// give a hint. | |||||
encoding = StringUtils.guessEncoding(readBytes, hints); | |||||
} | |||||
else | |||||
{ | |||||
encoding = currentCharacterSetECI.EncodingName; | |||||
} | |||||
try | |||||
{ | |||||
result.Append(Encoding.GetEncoding(encoding).GetString(readBytes, 0, readBytes.Length)); | |||||
} | |||||
#if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || MONOANDROID || MONOTOUCH) | |||||
catch (ArgumentException) | |||||
{ | |||||
try | |||||
{ | |||||
// Silverlight only supports a limited number of character sets, trying fallback to UTF-8 | |||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length)); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
#endif | |||||
#if WindowsCE | |||||
catch (PlatformNotSupportedException) | |||||
{ | |||||
try | |||||
{ | |||||
// WindowsCE doesn't support all encodings. But it is device depended. | |||||
// So we try here the some different ones | |||||
if (encoding == "ISO-8859-1") | |||||
{ | |||||
result.Append(Encoding.GetEncoding(1252).GetString(readBytes, 0, readBytes.Length)); | |||||
} | |||||
else | |||||
{ | |||||
result.Append(Encoding.GetEncoding("UTF-8").GetString(readBytes, 0, readBytes.Length)); | |||||
} | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
#endif | |||||
catch (Exception) | |||||
{ | |||||
return false; | |||||
} | |||||
byteSegments.Add(readBytes); | |||||
return true; | |||||
} | |||||
private static char toAlphaNumericChar(int value) | private static char toAlphaNumericChar(int value) | ||||
{ | { | ||||
@@ -7,6 +7,7 @@ using System.Diagnostics; | |||||
using System.Drawing; | using System.Drawing; | ||||
using System.Text; | using System.Text; | ||||
using System.Windows.Forms; | using System.Windows.Forms; | ||||
using ZXing; | |||||
namespace Shadowsocks.View | namespace Shadowsocks.View | ||||
{ | { | ||||
@@ -143,6 +144,7 @@ namespace Shadowsocks.View | |||||
CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)), | CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), | CreateMenuItem("Show QRCode...", new EventHandler(this.QRCodeItem_Click)), | ||||
CreateMenuItem("Scan QRCode...", new EventHandler(this.ScanQRCodeItem_Click)), | |||||
CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), | CreateMenuItem("Show Logs...", new EventHandler(this.ShowLogItem_Click)), | ||||
CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)), | CreateMenuItem("About...", new EventHandler(this.AboutItem_Click)), | ||||
new MenuItem("-"), | new MenuItem("-"), | ||||
@@ -359,41 +361,32 @@ namespace Shadowsocks.View | |||||
private void ScanQRCodeItem_Click(object sender, EventArgs e) | private void ScanQRCodeItem_Click(object sender, EventArgs e) | ||||
{ | { | ||||
/* | |||||
using (Bitmap image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, | |||||
using (Bitmap image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, | |||||
Screen.PrimaryScreen.Bounds.Height)) | Screen.PrimaryScreen.Bounds.Height)) | ||||
{ | { | ||||
using (Graphics g = Graphics.FromImage(bmpScreenCapture)) | |||||
using (Graphics g = Graphics.FromImage(image)) | |||||
{ | { | ||||
g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, | g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, | ||||
Screen.PrimaryScreen.Bounds.Y, | Screen.PrimaryScreen.Bounds.Y, | ||||
0, 0, | 0, 0, | ||||
bmpScreenCapture.Size, | |||||
image.Size, | |||||
CopyPixelOperation.SourceCopy); | CopyPixelOperation.SourceCopy); | ||||
} | } | ||||
resultPoints.Clear(); | |||||
/* var reader = new BarcodeReader | |||||
var reader = new BarcodeReader | |||||
{ | { | ||||
TryHarder = true, | |||||
PossibleFormats = new List<BarcodeFormat> | PossibleFormats = new List<BarcodeFormat> | ||||
{ | |||||
{ | |||||
BarcodeFormat.QR_CODE | BarcodeFormat.QR_CODE | ||||
} | |||||
} | |||||
}; | }; | ||||
var result = reader.Decode(image); | var result = reader.Decode(image); | ||||
var result = barcodeReader.Decode(image); | |||||
var timerStart = DateTime.Now.Ticks; | |||||
var timerStop = DateTime.Now.Ticks; | |||||
if (result == null) | |||||
if (result != null) | |||||
{ | { | ||||
txtDecoderContent.Text = "No barcode recognized"; | |||||
Console.WriteLine(result.Text); | |||||
} | } | ||||
labDuration.Text = new TimeSpan(timerStop - timerStart).Milliseconds.ToString("0 ms"); | |||||
} | } | ||||
} | |||||
* */ | |||||
} | } | ||||
private void AutoStartupItem_Click(object sender, EventArgs e) { | private void AutoStartupItem_Click(object sender, EventArgs e) { | ||||
@@ -71,6 +71,8 @@ | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<Compile Include="3rd\zxing\BarcodeFormat.cs" /> | <Compile Include="3rd\zxing\BarcodeFormat.cs" /> | ||||
<Compile Include="3rd\zxing\BarcodeReader.cs" /> | |||||
<Compile Include="3rd\zxing\BarcodeReaderGeneric.cs" /> | |||||
<Compile Include="3rd\zxing\BaseLuminanceSource.cs" /> | <Compile Include="3rd\zxing\BaseLuminanceSource.cs" /> | ||||
<Compile Include="3rd\zxing\Binarizer.cs" /> | <Compile Include="3rd\zxing\Binarizer.cs" /> | ||||
<Compile Include="3rd\zxing\BinaryBitmap.cs" /> | <Compile Include="3rd\zxing\BinaryBitmap.cs" /> | ||||
@@ -78,22 +80,33 @@ | |||||
<Compile Include="3rd\zxing\common\BitArray.cs" /> | <Compile Include="3rd\zxing\common\BitArray.cs" /> | ||||
<Compile Include="3rd\zxing\common\BitMatrix.cs" /> | <Compile Include="3rd\zxing\common\BitMatrix.cs" /> | ||||
<Compile Include="3rd\zxing\common\BitSource.cs" /> | <Compile Include="3rd\zxing\common\BitSource.cs" /> | ||||
<Compile Include="3rd\zxing\common\CharacterSetECI.cs" /> | |||||
<Compile Include="3rd\zxing\common\DecoderResult.cs" /> | <Compile Include="3rd\zxing\common\DecoderResult.cs" /> | ||||
<Compile Include="3rd\zxing\common\DecodingOptions.cs" /> | |||||
<Compile Include="3rd\zxing\common\DefaultGridSampler.cs" /> | <Compile Include="3rd\zxing\common\DefaultGridSampler.cs" /> | ||||
<Compile Include="3rd\zxing\common\DetectorResult.cs" /> | <Compile Include="3rd\zxing\common\DetectorResult.cs" /> | ||||
<Compile Include="3rd\zxing\common\detector\MathUtils.cs" /> | <Compile Include="3rd\zxing\common\detector\MathUtils.cs" /> | ||||
<Compile Include="3rd\zxing\common\detector\MonochromeRectangleDetector.cs" /> | <Compile Include="3rd\zxing\common\detector\MonochromeRectangleDetector.cs" /> | ||||
<Compile Include="3rd\zxing\common\detector\WhiteRectangleDetector.cs" /> | <Compile Include="3rd\zxing\common\detector\WhiteRectangleDetector.cs" /> | ||||
<Compile Include="3rd\zxing\common\ECI.cs" /> | |||||
<Compile Include="3rd\zxing\common\EncodingOptions.cs" /> | <Compile Include="3rd\zxing\common\EncodingOptions.cs" /> | ||||
<Compile Include="3rd\zxing\common\GlobalHistogramBinarizer.cs" /> | |||||
<Compile Include="3rd\zxing\common\GridSampler.cs" /> | <Compile Include="3rd\zxing\common\GridSampler.cs" /> | ||||
<Compile Include="3rd\zxing\common\HybridBinarizer.cs" /> | |||||
<Compile Include="3rd\zxing\common\PerspectiveTransform.cs" /> | <Compile Include="3rd\zxing\common\PerspectiveTransform.cs" /> | ||||
<Compile Include="3rd\zxing\common\reedsolomon\GenericGF.cs" /> | <Compile Include="3rd\zxing\common\reedsolomon\GenericGF.cs" /> | ||||
<Compile Include="3rd\zxing\common\reedsolomon\GenericGFPoly.cs" /> | <Compile Include="3rd\zxing\common\reedsolomon\GenericGFPoly.cs" /> | ||||
<Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonDecoder.cs" /> | <Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonDecoder.cs" /> | ||||
<Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonEncoder.cs" /> | <Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonEncoder.cs" /> | ||||
<Compile Include="3rd\zxing\common\StringUtils.cs" /> | |||||
<Compile Include="3rd\zxing\DecodeHintType.cs" /> | <Compile Include="3rd\zxing\DecodeHintType.cs" /> | ||||
<Compile Include="3rd\zxing\EncodeHintType.cs" /> | <Compile Include="3rd\zxing\EncodeHintType.cs" /> | ||||
<Compile Include="3rd\zxing\IBarcodeReader.cs" /> | |||||
<Compile Include="3rd\zxing\IBarcodeReaderGeneric.cs" /> | |||||
<Compile Include="3rd\zxing\LuminanceSource.cs" /> | <Compile Include="3rd\zxing\LuminanceSource.cs" /> | ||||
<Compile Include="3rd\zxing\net2.0\Action.cs" /> | |||||
<Compile Include="3rd\zxing\net2.0\Func.cs" /> | |||||
<Compile Include="3rd\zxing\net2.0\TimeZoneInfo.cs" /> | |||||
<Compile Include="3rd\zxing\qrcode\decoder\BitMatrixParser.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\BitMatrixParser.cs" /> | ||||
<Compile Include="3rd\zxing\qrcode\decoder\DataBlock.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\DataBlock.cs" /> | ||||
<Compile Include="3rd\zxing\qrcode\decoder\DataMask.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\DataMask.cs" /> | ||||
@@ -125,6 +138,7 @@ | |||||
<Compile Include="3rd\zxing\ResultMetadataType.cs" /> | <Compile Include="3rd\zxing\ResultMetadataType.cs" /> | ||||
<Compile Include="3rd\zxing\ResultPoint.cs" /> | <Compile Include="3rd\zxing\ResultPoint.cs" /> | ||||
<Compile Include="3rd\zxing\ResultPointCallback.cs" /> | <Compile Include="3rd\zxing\ResultPointCallback.cs" /> | ||||
<Compile Include="3rd\zxing\RGBLuminanceSource.cs" /> | |||||
<Compile Include="3rd\zxing\WriterException.cs" /> | <Compile Include="3rd\zxing\WriterException.cs" /> | ||||
<Compile Include="Controller\AutoStartup.cs" /> | <Compile Include="Controller\AutoStartup.cs" /> | ||||
<Compile Include="Controller\FileManager.cs" /> | <Compile Include="Controller\FileManager.cs" /> | ||||