diff --git a/shadowsocks-csharp/3rd/zxing/BarcodeReader.cs b/shadowsocks-csharp/3rd/zxing/BarcodeReader.cs new file mode 100755 index 0000000..5363a4d --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BarcodeReader.cs @@ -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 +{ + /// + /// A smart class to decode the barcode inside a bitmap object + /// +#if MONOTOUCH + public class BarcodeReader : BarcodeReaderGeneric, IBarcodeReader, IMultipleBarcodeReader + { + private static readonly Func defaultCreateLuminanceSource = + (img) => new RGBLuminanceSource(img); +#else +#if !PORTABLE +#if !(SILVERLIGHT || NETFX_CORE) +#if !UNITY + public class BarcodeReader : BarcodeReaderGeneric, IBarcodeReader + { + private static readonly Func defaultCreateLuminanceSource = + (bitmap) => new BitmapLuminanceSource(bitmap); +#else + public class BarcodeReader : BarcodeReaderGeneric, IBarcodeReader, IMultipleBarcodeReader + { + private static readonly Func defaultCreateLuminanceSource = + (rawColor32, width, height) => new Color32LuminanceSource(rawColor32, width, height); +#endif +#else + public class BarcodeReader : BarcodeReaderGeneric, IBarcodeReader, IMultipleBarcodeReader + { + private static readonly Func defaultCreateLuminanceSource = + (bitmap) => new BitmapLuminanceSource(bitmap); +#endif +#else + public class BarcodeReader : BarcodeReaderGeneric, IBarcodeReader, IMultipleBarcodeReader + { + private static readonly Func defaultCreateLuminanceSource = + (data) => null; +#endif +#endif + /// + /// Initializes a new instance of the class. + /// + public BarcodeReader() + : this(new QRCodeReader(), defaultCreateLuminanceSource, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Sets the reader which should be used to find and decode the barcode. + /// If null then MultiFormatReader is used + /// Sets the function to create a luminance source object for a bitmap. + /// If null, an exception is thrown when Decode is called + /// Sets the function to create a binarizer object for a luminance source. + /// If null then HybridBinarizer is used + public BarcodeReader(Reader reader, +#if MONOTOUCH + Func createLuminanceSource, +#elif MONOANDROID + Func createLuminanceSource, +#else +#if !(SILVERLIGHT || NETFX_CORE) +#if !UNITY +#if !PORTABLE + Func createLuminanceSource, +#else + Func createLuminanceSource, +#endif +#else + Func createLuminanceSource, +#endif +#else + Func createLuminanceSource, +#endif +#endif + Func createBinarizer + ) + : base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Sets the reader which should be used to find and decode the barcode. + /// If null then MultiFormatReader is used + /// Sets the function to create a luminance source object for a bitmap. + /// If null, an exception is thrown when Decode is called + /// Sets the function to create a binarizer object for a luminance source. + /// If null then HybridBinarizer is used + public BarcodeReader(Reader reader, +#if MONOTOUCH + Func createLuminanceSource, +#elif MONOANDROID + Func createLuminanceSource, +#else +#if !(SILVERLIGHT || NETFX_CORE) +#if !UNITY +#if !PORTABLE + Func createLuminanceSource, +#else + Func createLuminanceSource, +#endif +#else + Func createLuminanceSource, +#endif +#else + Func createLuminanceSource, +#endif +#endif + Func createBinarizer, + Func createRGBLuminanceSource + ) + : base(reader, createLuminanceSource ?? defaultCreateLuminanceSource, createBinarizer, createRGBLuminanceSource) + { + } + } +} diff --git a/shadowsocks-csharp/3rd/zxing/BarcodeReaderGeneric.cs b/shadowsocks-csharp/3rd/zxing/BarcodeReaderGeneric.cs new file mode 100755 index 0000000..3ce4656 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BarcodeReaderGeneric.cs @@ -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 +{ + /// + /// A smart class to decode the barcode inside a bitmap object + /// + public class BarcodeReaderGeneric : IBarcodeReaderGeneric + { + private static readonly Func defaultCreateBinarizer = + (luminanceSource) => new HybridBinarizer(luminanceSource); + + protected static readonly Func defaultCreateRGBLuminanceSource = + (rawBytes, width, height, format) => new RGBLuminanceSource(rawBytes, width, height, format); + + private Reader reader; + private readonly Func createRGBLuminanceSource; +#if !UNITY + private readonly Func createLuminanceSource; +#else + private readonly Func createLuminanceSource; +#endif + private readonly Func createBinarizer; + private bool usePreviousState; + private DecodingOptions options; + + /// + /// Gets or sets the options. + /// + /// + /// The options. + /// + public DecodingOptions Options + { + get { return options ?? (options = new DecodingOptions()); } + set { options = value; } + } + + /// + /// Gets the reader which should be used to find and decode the barcode. + /// + /// + /// The reader. + /// + protected Reader Reader + { + get + { + return reader ?? (reader = new QRCodeReader()); + } + } + + /// + /// Gets or sets a method which is called if an important point is found + /// + /// + /// The result point callback. + /// + public event Action 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 explicitResultPointFound; + + /// + /// event is executed if a result was found via decode + /// + public event Action ResultFound; + + /// + /// Gets or sets a flag which cause a deeper look into the bitmap + /// + /// + /// true if [try harder]; otherwise, false. + /// + [Obsolete("Please use the Options.TryHarder property instead.")] + public bool TryHarder + { + get { return Options.TryHarder; } + set { Options.TryHarder = value; } + } + + /// + /// Image is a pure monochrome image of a barcode. + /// + /// + /// true if monochrome image of a barcode; otherwise, false. + /// + [Obsolete("Please use the Options.PureBarcode property instead.")] + public bool PureBarcode + { + get { return Options.PureBarcode; } + set { Options.PureBarcode = value; } + } + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + /// + /// The character set. + /// + [Obsolete("Please use the Options.CharacterSet property instead.")] + public string CharacterSet + { + get { return Options.CharacterSet; } + set { Options.CharacterSet = value; } + } + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a {@link java.util.List} of {@link BarcodeFormat}s. + /// + /// + /// The possible formats. + /// + [Obsolete("Please use the Options.PossibleFormats property instead.")] + public IList PossibleFormats + { + get { return Options.PossibleFormats; } + set { Options.PossibleFormats = value; } + } + + /// + /// Gets or sets a value indicating whether the image should be automatically rotated. + /// Rotation is supported for 90, 180 and 270 degrees + /// + /// + /// true if image should be rotated; otherwise, false. + /// + public bool AutoRotate { get; set; } + + /// + /// 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 + /// + /// + /// true if image should be inverted; otherwise, false. + /// + public bool TryInverted { get; set; } + +#if !UNITY + /// + /// Optional: Gets or sets the function to create a luminance source object for a bitmap. + /// If null a platform specific default LuminanceSource is used + /// + /// + /// The function to create a luminance source object. + /// + protected Func CreateLuminanceSource +#else + /// + /// Optional: Gets or sets the function to create a luminance source object for a bitmap. + /// If null a platform specific default LuminanceSource is used + /// + /// + /// The function to create a luminance source object. + /// + protected Func CreateLuminanceSource +#endif + { + get + { + return createLuminanceSource; + } + } + + /// + /// Optional: Gets or sets the function to create a binarizer object for a luminance source. + /// If null then HybridBinarizer is used + /// + /// + /// The function to create a binarizer object. + /// + protected Func CreateBinarizer + { + get + { + return createBinarizer ?? defaultCreateBinarizer; + } + } + + /// + /// Initializes a new instance of the class. + /// + public BarcodeReaderGeneric() + : this(new QRCodeReader(), null, defaultCreateBinarizer) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Sets the reader which should be used to find and decode the barcode. + /// If null then MultiFormatReader is used + /// Sets the function to create a luminance source object for a bitmap. + /// If null, an exception is thrown when Decode is called + /// Sets the function to create a binarizer object for a luminance source. + /// If null then HybridBinarizer is used + public BarcodeReaderGeneric(Reader reader, +#if !UNITY + Func createLuminanceSource, +#else + Func createLuminanceSource, +#endif + Func createBinarizer + ) + : this(reader, createLuminanceSource, createBinarizer, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Sets the reader which should be used to find and decode the barcode. + /// If null then MultiFormatReader is used + /// Sets the function to create a luminance source object for a bitmap. + /// If null, an exception is thrown when Decode is called + /// Sets the function to create a binarizer object for a luminance source. + /// If null then HybridBinarizer is used + /// 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. + public BarcodeReaderGeneric(Reader reader, +#if !UNITY + Func createLuminanceSource, +#else + Func createLuminanceSource, +#endif + Func createBinarizer, + Func 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 + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + public Result Decode(T barcodeBitmap) +#else + /// + /// Decodes the specified barcode bitmap. + /// + /// raw bytes of the image in RGB order + /// + /// + /// + /// the result data or null + /// + 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 + + /// + /// 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. + /// + /// The luminance source. + /// + 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 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); + } + } + + /// + /// Decodes the specified barcode bitmap. + /// + /// The image as byte[] array. + /// The width. + /// The height. + /// The format. + /// + /// the result data or null + /// + 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); + } + + } +} diff --git a/shadowsocks-csharp/3rd/zxing/IBarcodeReader.cs b/shadowsocks-csharp/3rd/zxing/IBarcodeReader.cs new file mode 100755 index 0000000..66d90ff --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/IBarcodeReader.cs @@ -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 +{ + /// + /// Interface for a smart class to decode the barcode inside a bitmap object + /// + public interface IBarcodeReader + { + /// + /// event is executed when a result point was found + /// + event Action ResultPointFound; + + /// + /// event is executed when a result was found via decode + /// + event Action ResultFound; + + /// + /// Gets or sets a flag which cause a deeper look into the bitmap + /// + /// + /// true if [try harder]; otherwise, false. + /// + [Obsolete("Please use the Options.TryHarder property instead.")] + bool TryHarder { get; set; } + + /// + /// Image is a pure monochrome image of a barcode. + /// + /// + /// true if monochrome image of a barcode; otherwise, false. + /// + [Obsolete("Please use the Options.PureBarcode property instead.")] + bool PureBarcode { get; set; } + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + /// + /// The character set. + /// + [Obsolete("Please use the Options.CharacterSet property instead.")] + string CharacterSet { get; set; } + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a {@link java.util.List} of {@link BarcodeFormat}s. + /// + /// + /// The possible formats. + /// + [Obsolete("Please use the Options.PossibleFormats property instead.")] + IList PossibleFormats { get; set; } + + /// + /// Specifies some options which influence the decoding process + /// + DecodingOptions Options { get; set; } + + /// + /// Decodes the specified barcode bitmap which is given by a generic byte array with the order RGB24. + /// + /// The image as RGB24 array. + /// The width. + /// The height. + /// The format. + /// + /// the result data or null + /// + Result Decode(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format); + + /// + /// 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. + /// + /// The luminance source. + /// + Result Decode(LuminanceSource luminanceSource); + +#if MONOTOUCH + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(MonoTouch.UIKit.UIImage barcodeImage); +#elif MONOANDROID + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(Android.Graphics.Bitmap barcodeImage); +#else +#if !PORTABLE +#if !(SILVERLIGHT || NETFX_CORE) +#if !UNITY + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(Bitmap barcodeBitmap); +#else + /// + /// Decodes the specified barcode bitmap. + /// + /// The image as Color32 array. + /// the result data or null + Result Decode(Color32[] rawColor32, int width, int height); +#endif +#else + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(WriteableBitmap barcodeBitmap); +#endif +#endif +#endif + } +} diff --git a/shadowsocks-csharp/3rd/zxing/IBarcodeReaderGeneric.cs b/shadowsocks-csharp/3rd/zxing/IBarcodeReaderGeneric.cs new file mode 100755 index 0000000..1860988 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/IBarcodeReaderGeneric.cs @@ -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 +{ + /// + /// Interface for a smart class to decode the barcode inside a bitmap object + /// + /// gives the type of the input data + public interface IBarcodeReaderGeneric + { + /// + /// event is executed when a result point was found + /// + event Action ResultPointFound; + + /// + /// event is executed when a result was found via decode + /// + event Action ResultFound; + + /// + /// Gets or sets a flag which cause a deeper look into the bitmap + /// + /// + /// true if [try harder]; otherwise, false. + /// + [Obsolete("Please use the Options.TryHarder property instead.")] + bool TryHarder { get; set; } + + /// + /// Image is a pure monochrome image of a barcode. + /// + /// + /// true if monochrome image of a barcode; otherwise, false. + /// + [Obsolete("Please use the Options.PureBarcode property instead.")] + bool PureBarcode { get; set; } + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + /// + /// The character set. + /// + [Obsolete("Please use the Options.CharacterSet property instead.")] + string CharacterSet { get; set; } + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a {@link java.util.List} of {@link BarcodeFormat}s. + /// + /// + /// The possible formats. + /// + [Obsolete("Please use the Options.PossibleFormats property instead.")] + IList PossibleFormats { get; set; } + + /// + /// Specifies some options which influence the decoding process + /// + DecodingOptions Options { get; set; } + + /// + /// Decodes the specified barcode bitmap which is given by a generic byte array. + /// + /// The barcode bitmap. + /// The width. + /// The height. + /// The format. + /// + /// the result data or null + /// + Result Decode(byte[] rawRGB, int width, int height, RGBLuminanceSource.BitmapFormat format); + + /// + /// 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. + /// + /// The luminance source. + /// + Result Decode(LuminanceSource luminanceSource); + +#if !PORTABLE +#if !UNITY + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(T barcodeBitmap); +#else + /// + /// Decodes the specified barcode bitmap. + /// + /// The barcode bitmap. + /// the result data or null + Result Decode(T rawRGB, int width, int height); +#endif +#endif + } +} diff --git a/shadowsocks-csharp/3rd/zxing/RGBLuminanceSource.cs b/shadowsocks-csharp/3rd/zxing/RGBLuminanceSource.cs new file mode 100755 index 0000000..6af439e --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/RGBLuminanceSource.cs @@ -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 +{ + /// + /// Luminance source class which support different formats of images. + /// + public partial class RGBLuminanceSource : BaseLuminanceSource + { + /// + /// enumeration of supported bitmap format which the RGBLuminanceSource can process + /// + public enum BitmapFormat + { + /// + /// format of the byte[] isn't known. RGBLuminanceSource tries to determine the best possible value + /// + Unknown, + /// + /// grayscale array, the byte array is a luminance array with 1 byte per pixel + /// + Gray8, + /// + /// 3 bytes per pixel with the channels red, green and blue + /// + RGB24, + /// + /// 4 bytes per pixel with the channels red, green and blue + /// + RGB32, + /// + /// 4 bytes per pixel with the channels alpha, red, green and blue + /// + ARGB32, + /// + /// 3 bytes per pixel with the channels blue, green and red + /// + BGR24, + /// + /// 4 bytes per pixel with the channels blue, green and red + /// + BGR32, + /// + /// 4 bytes per pixel with the channels blue, green, red and alpha + /// + BGRA32, + /// + /// 2 bytes per pixel, 5 bit red, 6 bits green and 5 bits blue + /// + RGB565, + /// + /// 4 bytes per pixel with the channels red, green, blue and alpha + /// + RGBA32, + } + + /// + /// Initializes a new instance of the class. + /// + /// The width. + /// The height. + protected RGBLuminanceSource(int width, int height) + : base(width, height) + { + } + + /// + /// Initializes a new instance of the class. + /// It supports a byte array with 3 bytes per pixel (RGB24). + /// + /// The RGB raw bytes. + /// The width. + /// The height. + public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height) + : this(rgbRawBytes, width, height, BitmapFormat.RGB24) + { + } + + /// + /// Initializes a new instance of the class. + /// It supports a byte array with 1 byte per pixel (Gray8). + /// That means the whole array consists of the luminance values (grayscale). + /// + /// The luminance array. + /// The width. + /// The height. + /// if set to true [is8 bit]. + [Obsolete("Use RGBLuminanceSource(luminanceArray, width, height, BitmapFormat.Gray8)")] + public RGBLuminanceSource(byte[] luminanceArray, int width, int height, bool is8Bit) + : this(luminanceArray, width, height, BitmapFormat.Gray8) + { + } + + /// + /// Initializes a new instance of the class. + /// It supports a byte array with 3 bytes per pixel (RGB24). + /// + /// The RGB raw bytes. + /// The width. + /// The height. + /// The bitmap format. + public RGBLuminanceSource(byte[] rgbRawBytes, int width, int height, BitmapFormat bitmapFormat) + : base(width, height) + { + CalculateLuminance(rgbRawBytes, bitmapFormat); + } + + /// + /// Should create a new luminance source with the right class type. + /// The method is used in methods crop and rotate. + /// + /// The new luminances. + /// The width. + /// The height. + /// + 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)); + } + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/common/CharacterSetECI.cs b/shadowsocks-csharp/3rd/zxing/common/CharacterSetECI.cs new file mode 100755 index 0000000..cb42eb5 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/CharacterSetECI.cs @@ -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 +{ + /// Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 + /// of ISO 18004. + /// + /// + /// Sean Owen + public sealed class CharacterSetECI : ECI + { + internal static readonly IDictionary VALUE_TO_ECI; + internal static readonly IDictionary NAME_TO_ECI; + + private readonly String encodingName; + + public String EncodingName + { + get + { + return encodingName; + } + + } + + static CharacterSetECI() + { + VALUE_TO_ECI = new Dictionary(); + NAME_TO_ECI = new Dictionary(); + // 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; + } + } + + /// character set ECI value + /// + /// {@link CharacterSetECI} representing ECI of given value, or null if it is legal but + /// unsupported + /// + /// IllegalArgumentException if ECI value is invalid + public static CharacterSetECI getCharacterSetECIByValue(int value) + { + if (value < 0 || value >= 900) + { + return null; + } + return VALUE_TO_ECI[value]; + } + + /// character set ECI encoding name + /// + /// {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal + /// but unsupported + /// + public static CharacterSetECI getCharacterSetECIByName(String name) + { + return NAME_TO_ECI[name.ToUpper()]; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/common/DecodingOptions.cs b/shadowsocks-csharp/3rd/zxing/common/DecodingOptions.cs new file mode 100755 index 0000000..9a58f9a --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/DecodingOptions.cs @@ -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 +{ + /// + /// Defines an container for encoder options + /// + [Serializable] + public class DecodingOptions + { + /// + /// Gets the data container for all options + /// + [Browsable(false)] + public IDictionary Hints { get; private set; } + + [field: NonSerialized] + public event Action ValueChanged; + + /// + /// Gets or sets a flag which cause a deeper look into the bitmap + /// + /// + /// true if [try harder]; otherwise, false. + /// + 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); + } + } + } + } + + /// + /// Image is a pure monochrome image of a barcode. + /// + /// + /// true if monochrome image of a barcode; otherwise, false. + /// + 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); + } + } + } + } + + /// + /// Specifies what character encoding to use when decoding, where applicable (type String) + /// + /// + /// The character set. + /// + 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); + } + } + } + } + + /// + /// Image is known to be of one of a few possible formats. + /// Maps to a {@link java.util.List} of {@link BarcodeFormat}s. + /// + /// + /// The possible formats. + /// + public IList PossibleFormats + { + get + { + if (Hints.ContainsKey(DecodeHintType.POSSIBLE_FORMATS)) + return (IList)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); + } + } + } + } + + /// + /// if Code39 could be detected try to use extended mode for full ASCII character set + /// + 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); + } + } + } + } + + /// + /// Don't fail if a Code39 is detected but can't be decoded in extended mode. + /// Return the raw Code39 result instead. Maps to . + /// + 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); + } + } + } + } + + /// + /// 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 . + /// + 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); + } + } + } + } + /// + /// Initializes a new instance of the class. + /// + public DecodingOptions() + { + var hints = new ChangeNotifyDictionary(); + Hints = hints; + UseCode39ExtendedMode = true; + UseCode39RelaxedExtendedMode = true; + hints.ValueChanged += (o, args) => { if (ValueChanged != null) ValueChanged(this, EventArgs.Empty); }; + } + + [Serializable] + private class ChangeNotifyDictionary: IDictionary + { + private readonly IDictionary values; + + [field: NonSerialized] + public event Action ValueChanged; + + public ChangeNotifyDictionary() + { + values = new Dictionary(); + } + + 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 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 Values + { + get { return values.Values; } + } + + public TValue this[TKey key] + { + get + { + return values[key]; + } + set + { + values[key] = value; + OnValueChanged(); + } + } + + public void Add(KeyValuePair item) + { + values.Add(item); + OnValueChanged(); + } + + public void Clear() + { + values.Clear(); + OnValueChanged(); + } + + public bool Contains(KeyValuePair item) + { + return values.Contains(item); + } + + public void CopyTo(KeyValuePair[] 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 item) + { + var result = values.Remove(item); + OnValueChanged(); + + return result; + } + + public IEnumerator> GetEnumerator() + { + return values.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return ((System.Collections.IEnumerable)values).GetEnumerator(); + } + } + } +} diff --git a/shadowsocks-csharp/3rd/zxing/common/ECI.cs b/shadowsocks-csharp/3rd/zxing/common/ECI.cs new file mode 100755 index 0000000..fa947ba --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/ECI.cs @@ -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 +{ + + /// Superclass of classes encapsulating types ECIs, according to "Extended Channel Interpretations" + /// 5.3 of ISO 18004. + /// + /// + /// Sean Owen + /// + /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source + /// + 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; + } + + /// ECI value + /// + /// {@link ECI} representing ECI of given value, or null if it is legal but unsupported + /// + /// IllegalArgumentException if ECI value is invalid + 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/common/GlobalHistogramBinarizer.cs b/shadowsocks-csharp/3rd/zxing/common/GlobalHistogramBinarizer.cs new file mode 100755 index 0000000..91f20d5 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/GlobalHistogramBinarizer.cs @@ -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 +{ + /// 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. + /// + /// dswitkin@google.com (Daniel Switkin) + /// Sean Owen + /// + 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; + + /// + /// Initializes a new instance of the class. + /// + /// The source. + public GlobalHistogramBinarizer(LuminanceSource source) + : base(source) + { + luminances = EMPTY; + buckets = new int[LUMINANCE_BUCKETS]; + } + + /// + /// Applies simple sharpening to the row data to improve performance of the 1D Readers. + /// + /// + /// + /// + 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; + } + + /// + /// Does not sharpen the data, as this call is intended to only be used by 2D Readers. + /// + 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; + } + } + + /// + /// 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. + /// + /// The LuminanceSource this Binarizer will operate on. + /// + /// A new concrete Binarizer implementation object. + /// + 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/common/HybridBinarizer.cs b/shadowsocks-csharp/3rd/zxing/common/HybridBinarizer.cs new file mode 100755 index 0000000..d818550 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/HybridBinarizer.cs @@ -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 +{ + /// 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. + /// + /// + /// dswitkin@google.com (Daniel Switkin) + /// + /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source + /// + 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); + } + + /// + /// 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. + /// + 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; + } + } + } + + /// + /// 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). + /// + /// The luminances. + /// Width of the sub. + /// Height of the sub. + /// The width. + /// The height. + /// The black points. + /// The matrix. + 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; + } + + /// + /// Applies a single threshold to an 8x8 block of pixels. + /// + /// The luminances. + /// The xoffset. + /// The yoffset. + /// The threshold. + /// The stride. + /// The matrix. + 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); + } + } + } + + /// + /// 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 + /// + /// The luminances. + /// Width of the sub. + /// Height of the sub. + /// The width. + /// The height. + /// + 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs b/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs new file mode 100755 index 0000000..55b5ec9 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs @@ -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 +{ + /// + /// Common string-related functions. + /// + /// Sean Owen + /// Alex Dupre + 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; + + /// + /// Guesses the encoding. + /// + /// bytes encoding a string, whose encoding should be guessed + /// decode hints if applicable + /// 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 + public static String guessEncoding(byte[] bytes, IDictionary 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; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/net2.0/Action.cs b/shadowsocks-csharp/3rd/zxing/net2.0/Action.cs new file mode 100755 index 0000000..88601bc --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/net2.0/Action.cs @@ -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 + /// + /// for compatibility with .net 4.0 + /// + public delegate void Action(); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The param1. + public delegate void Action(T1 param1); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The param1. + /// The param2. + public delegate void Action(T1 param1, T2 param2); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The param1. + /// The param2. + /// The param3. + public delegate void Action(T1 param1, T2 param2, T3 param3); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the 4. + /// The param1. + /// The param2. + /// The param3. + /// The param4. + public delegate void Action(T1 param1, T2 param2, T3 param3, T4 param4); +#else + /// + /// for compatibility with .net 4.0 + /// + public delegate void Action(); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The param1. + public delegate void Action(T1 param1); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The param1. + /// The param2. + public delegate void Action(T1 param1, T2 param2); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The param1. + /// The param2. + /// The param3. + public delegate void Action(T1 param1, T2 param2, T3 param3); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the 4. + /// The param1. + /// The param2. + /// The param3. + /// The param4. + public delegate void Action(T1 param1, T2 param2, T3 param3, T4 param4); +#endif +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/net2.0/Func.cs b/shadowsocks-csharp/3rd/zxing/net2.0/Func.cs new file mode 100755 index 0000000..2b2388f --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/net2.0/Func.cs @@ -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 + /// + /// for compatibility with .net 4.0 + /// + /// The type of the result. + /// + public delegate TResult Func(); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the result. + /// The param1. + /// + public delegate TResult Func(T1 param1); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the result. + /// The param1. + /// The param2. + /// + public delegate TResult Func(T1 param1, T2 param2); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the result. + /// The param1. + /// The param2. + /// The param3. + /// + public delegate TResult Func(T1 param1, T2 param2, T3 param3); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the 4. + /// The type of the result. + /// The param1. + /// The param2. + /// The param3. + /// The param4. + /// + public delegate TResult Func(T1 param1, T2 param2, T3 param3, T4 param4); +#else + /// + /// for compatibility with .net 4.0 + /// + /// The type of the result. + /// + public delegate TResult Func(); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the result. + /// The param1. + /// + public delegate TResult Func(T1 param1); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the result. + /// The param1. + /// The param2. + /// + public delegate TResult Func(T1 param1, T2 param2); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the result. + /// The param1. + /// The param2. + /// The param3. + /// + public delegate TResult Func(T1 param1, T2 param2, T3 param3); + /// + /// for compatibility with .net 4.0 + /// + /// The type of the 1. + /// The type of the 2. + /// The type of the 3. + /// The type of the 4. + /// The type of the result. + /// The param1. + /// The param2. + /// The param3. + /// The param4. + /// + public delegate TResult Func(T1 param1, T2 param2, T3 param3, T4 param4); +#endif +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/net2.0/TimeZoneInfo.cs b/shadowsocks-csharp/3rd/zxing/net2.0/TimeZoneInfo.cs new file mode 100755 index 0000000..c96f52c --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/net2.0/TimeZoneInfo.cs @@ -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; + } + } +} diff --git a/shadowsocks-csharp/3rd/zxing/qrcode/decoder/DecodedBitStreamParser.cs b/shadowsocks-csharp/3rd/zxing/qrcode/decoder/DecodedBitStreamParser.cs index cb59141..77a0b2c 100755 --- a/shadowsocks-csharp/3rd/zxing/qrcode/decoder/DecodedBitStreamParser.cs +++ b/shadowsocks-csharp/3rd/zxing/qrcode/decoder/DecodedBitStreamParser.cs @@ -54,7 +54,7 @@ namespace ZXing.QrCode.Internal try { - //CharacterSetECI currentCharacterSetECI = null; + CharacterSetECI currentCharacterSetECI = null; bool fc1InEffect = false; Mode mode; do @@ -94,14 +94,29 @@ namespace ZXing.QrCode.Internal symbolSequence = 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 { // First handle Hanzi mode which does not start with character count if (mode == Mode.HANZI) { //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 { @@ -118,6 +133,16 @@ namespace ZXing.QrCode.Internal if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) 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 { return null; @@ -145,8 +170,214 @@ namespace ZXing.QrCode.Internal symbolSequence, parityData); } + /// + /// See specification GBT 18284-2000 + /// + /// The bits. + /// The result. + /// The count. + /// + 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 byteSegments, + IDictionary 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) { diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index acd4699..a4d4356 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Drawing; using System.Text; using System.Windows.Forms; +using ZXing; namespace Shadowsocks.View { @@ -143,6 +144,7 @@ namespace Shadowsocks.View CreateMenuItem("Update PAC from GFWList", new EventHandler(this.UpdatePACFromGFWListItem_Click)), new MenuItem("-"), 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("About...", new EventHandler(this.AboutItem_Click)), new MenuItem("-"), @@ -359,41 +361,32 @@ namespace Shadowsocks.View 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)) { - using (Graphics g = Graphics.FromImage(bmpScreenCapture)) + using (Graphics g = Graphics.FromImage(image)) { g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, - bmpScreenCapture.Size, + image.Size, CopyPixelOperation.SourceCopy); } - resultPoints.Clear(); - /* var reader = new BarcodeReader + var reader = new BarcodeReader { + TryHarder = true, PossibleFormats = new List - { + { BarcodeFormat.QR_CODE - } + } }; - 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) { diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 4c33531..1d91db5 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -71,6 +71,8 @@ + + @@ -78,22 +80,33 @@ + + + + + + + + + + + @@ -125,6 +138,7 @@ +