diff --git a/shadowsocks-csharp/3rd/zxing/BarcodeFormat.cs b/shadowsocks-csharp/3rd/zxing/BarcodeFormat.cs new file mode 100755 index 00000000..e20f6535 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BarcodeFormat.cs @@ -0,0 +1,89 @@ +/* +* Copyright 2007 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +namespace ZXing +{ + /// + /// Enumerates barcode formats known to this package. + /// + /// Sean Owen + [System.Flags] + public enum BarcodeFormat + { + /// Aztec 2D barcode format. + AZTEC = 1, + + /// CODABAR 1D format. + CODABAR = 2, + + /// Code 39 1D format. + CODE_39 = 4, + + /// Code 93 1D format. + CODE_93 = 8, + + /// Code 128 1D format. + CODE_128 = 16, + + /// Data Matrix 2D barcode format. + DATA_MATRIX = 32, + + /// EAN-8 1D format. + EAN_8 = 64, + + /// EAN-13 1D format. + EAN_13 = 128, + + /// ITF (Interleaved Two of Five) 1D format. + ITF = 256, + + /// MaxiCode 2D barcode format. + MAXICODE = 512, + + /// PDF417 format. + PDF_417 = 1024, + + /// QR Code 2D barcode format. + QR_CODE = 2048, + + /// RSS 14 + RSS_14 = 4096, + + /// RSS EXPANDED + RSS_EXPANDED = 8192, + + /// UPC-A 1D format. + UPC_A = 16384, + + /// UPC-E 1D format. + UPC_E = 32768, + + /// UPC/EAN extension format. Not a stand-alone format. + UPC_EAN_EXTENSION = 65536, + + /// MSI + MSI = 131072, + + /// Plessey + PLESSEY = 262144, + + /// + /// UPC_A | UPC_E | EAN_13 | EAN_8 | CODABAR | CODE_39 | CODE_93 | CODE_128 | ITF | RSS_14 | RSS_EXPANDED + /// without MSI (to many false-positives) + /// + All_1D = UPC_A | UPC_E | EAN_13 | EAN_8 | CODABAR | CODE_39 | CODE_93 | CODE_128 | ITF | RSS_14 | RSS_EXPANDED + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/BaseLuminanceSource.cs b/shadowsocks-csharp/3rd/zxing/BaseLuminanceSource.cs new file mode 100755 index 00000000..c91d81db --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BaseLuminanceSource.cs @@ -0,0 +1,206 @@ +/* +* 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 +{ + /// + /// The base class for luminance sources which supports + /// cropping and rotating based upon the luminance values. + /// + public abstract class BaseLuminanceSource : LuminanceSource + { + // the following channel weights give nearly the same + // gray scale picture as the java version with BufferedImage.TYPE_BYTE_GRAY + // they are used in sub classes for luminance / gray scale calculation + protected const int RChannelWeight = 19562; + protected const int GChannelWeight = 38550; + protected const int BChannelWeight = 7424; + protected const int ChannelWeight = 16; + + /// + /// + /// + protected byte[] luminances; + + /// + /// Initializes a new instance of the class. + /// + /// The width. + /// The height. + protected BaseLuminanceSource(int width, int height) + : base(width, height) + { + luminances = new byte[width * height]; + } + + /// + /// Initializes a new instance of the class. + /// + /// The luminance array. + /// The width. + /// The height. + protected BaseLuminanceSource(byte[] luminanceArray, int width, int height) + : base(width, height) + { + luminances = new byte[width * height]; + Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height); + } + + /// + /// Fetches one row of luminance data from the underlying platform's bitmap. Values range from + /// 0 (black) to 255 (white). It is preferable for implementations of this method + /// to only fetch this row rather than the whole image, since no 2D Readers may be installed and + /// getMatrix() may never be called. + /// + /// The row to fetch, 0 <= y < Height. + /// An optional preallocated array. If null or too small, it will be ignored. + /// Always use the returned object, and ignore the .length of the array. + /// + /// An array containing the luminance data. + /// + override public byte[] getRow(int y, byte[] row) + { + int width = Width; + if (row == null || row.Length < width) + { + row = new byte[width]; + } + for (int i = 0; i < width; i++) + row[i] = luminances[y * width + i]; + return row; + } + + public override byte[] Matrix + { + get { return luminances; } + } + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if {@link #isRotateSupported()} is true. + /// + /// + /// A rotated version of this object. + /// + public override LuminanceSource rotateCounterClockwise() + { + var rotatedLuminances = new byte[Width * Height]; + var newWidth = Height; + var newHeight = Width; + var localLuminances = Matrix; + for (var yold = 0; yold < Height; yold++) + { + for (var xold = 0; xold < Width; xold++) + { + var ynew = newHeight - xold - 1; + var xnew = yold; + rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold]; + } + } + return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight); + } + + /// + /// TODO: not implemented yet + /// + /// + /// A rotated version of this object. + /// + public override LuminanceSource rotateCounterClockwise45() + { + // TODO: implement a good 45 degrees rotation without lost of information + return base.rotateCounterClockwise45(); + } + + /// + /// + /// Whether this subclass supports counter-clockwise rotation. + public override bool RotateSupported + { + get + { + return true; + } + } + + /// + /// Returns a new object with cropped image data. Implementations may keep a reference to the + /// original data rather than a copy. Only callable if CropSupported is true. + /// + /// The left coordinate, 0 <= left < Width. + /// The top coordinate, 0 <= top <= Height. + /// The width of the rectangle to crop. + /// The height of the rectangle to crop. + /// + /// A cropped version of this object. + /// + public override LuminanceSource crop(int left, int top, int width, int height) + { + if (left + width > Width || top + height > Height) + { + throw new ArgumentException("Crop rectangle does not fit within image data."); + } + var croppedLuminances = new byte[width * height]; + var oldLuminances = Matrix; + var oldWidth = Width; + var oldRightBound = left + width; + var oldBottomBound = top + height; + for (int yold = top, ynew = 0; yold < oldBottomBound; yold++, ynew++) + { + for (int xold = left, xnew = 0; xold < oldRightBound; xold++, xnew++) + { + croppedLuminances[ynew * width + xnew] = oldLuminances[yold * oldWidth + xold]; + } + } + return CreateLuminanceSource(croppedLuminances, width, height); + } + + /// + /// + /// Whether this subclass supports cropping. + public override bool CropSupported + { + get + { + return true; + } + } + + /// + /// + /// Whether this subclass supports invertion. + public override bool InversionSupported + { + get + { + return true; + } + } + + + /// + /// 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 abstract LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height); + } +} diff --git a/shadowsocks-csharp/3rd/zxing/Binarizer.cs b/shadowsocks-csharp/3rd/zxing/Binarizer.cs new file mode 100755 index 00000000..213ec66a --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Binarizer.cs @@ -0,0 +1,104 @@ +/* +* Copyright 2009 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; + +using ZXing.Common; + +namespace ZXing +{ + /// This class hierarchy provides a set of methods to convert luminance data to 1 bit data. + /// It allows the algorithm to vary polymorphically, for example allowing a very expensive + /// thresholding technique for servers and a fast one for mobile. It also permits the implementation + /// to vary, e.g. a JNI version for Android and a Java fallback version for other platforms. + /// + /// dswitkin@google.com (Daniel Switkin) + /// + public abstract class Binarizer + { + private readonly LuminanceSource source; + + /// + /// Initializes a new instance of the class. + /// + /// The source. + protected internal Binarizer(LuminanceSource source) + { + if (source == null) + { + throw new ArgumentException("Source must be non-null."); + } + this.source = source; + } + + /// + /// Gets the luminance source object. + /// + virtual public LuminanceSource LuminanceSource + { + get + { + return source; + } + } + + /// Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + /// cached data. Callers should assume this method is expensive and call it as seldom as possible. + /// This method is intended for decoding 1D barcodes and may choose to apply sharpening. + /// For callers which only examine one row of pixels at a time, the same BitArray should be reused + /// and passed in with each call for performance. However it is legal to keep more than one row + /// at a time if needed. + /// + /// The row to fetch, 0 <= y < bitmap height. + /// An optional preallocated array. If null or too small, it will be ignored. + /// If used, the Binarizer will call BitArray.clear(). Always use the returned object. + /// + /// The array of bits for this row (true means black). + public abstract BitArray getBlackRow(int y, BitArray row); + + /// Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive + /// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or + /// may not apply sharpening. Therefore, a row from this matrix may not be identical to one + /// fetched using getBlackRow(), so don't mix and match between them. + /// + /// The 2D array of bits for the image (true means black). + public abstract BitMatrix BlackMatrix { get; } + + /// 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 abstract Binarizer createBinarizer(LuminanceSource source); + + /// + /// Gets the width of the luminance source object. + /// + public int Width + { + get { return source.Width; } + } + + /// + /// Gets the height of the luminance source object. + /// + public int Height + { + get { return source.Height; } + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/BinaryBitmap.cs b/shadowsocks-csharp/3rd/zxing/BinaryBitmap.cs new file mode 100755 index 00000000..fea1b266 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BinaryBitmap.cs @@ -0,0 +1,186 @@ +/* +* Copyright 2009 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using ZXing.Common; + +namespace ZXing +{ + + /// This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects + /// accept a BinaryBitmap and attempt to decode it. + /// + /// + /// dswitkin@google.com (Daniel Switkin) + /// + /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source + /// + + public sealed class BinaryBitmap + { + private Binarizer binarizer; + private BitMatrix matrix; + + public BinaryBitmap(Binarizer binarizer) + { + if (binarizer == null) + { + throw new ArgumentException("Binarizer must be non-null."); + } + this.binarizer = binarizer; + } + + /// The width of the bitmap. + /// + public int Width + { + get + { + return binarizer.Width; + } + + } + /// The height of the bitmap. + /// + public int Height + { + get + { + return binarizer.Height; + } + + } + + /// Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + /// cached data. Callers should assume this method is expensive and call it as seldom as possible. + /// This method is intended for decoding 1D barcodes and may choose to apply sharpening. + /// + /// + /// The row to fetch, 0 <= y < bitmap height. + /// + /// An optional preallocated array. If null or too small, it will be ignored. + /// If used, the Binarizer will call BitArray.clear(). Always use the returned object. + /// + /// The array of bits for this row (true means black). + /// + public BitArray getBlackRow(int y, BitArray row) + { + return binarizer.getBlackRow(y, row); + } + + /// Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive + /// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or + /// may not apply sharpening. Therefore, a row from this matrix may not be identical to one + /// fetched using getBlackRow(), so don't mix and match between them. + /// + /// + /// The 2D array of bits for the image (true means black). + /// + public BitMatrix BlackMatrix + { + get + { + // The matrix is created on demand the first time it is requested, then cached. There are two + // reasons for this: + // 1. This work will never be done if the caller only installs 1D Reader objects, or if a + // 1D Reader finds a barcode before the 2D Readers run. + // 2. This work will only be done once even if the caller installs multiple 2D Readers. + if (matrix == null) + { + matrix = binarizer.BlackMatrix; + } + return matrix; + } + } + + /// Whether this bitmap can be cropped. + /// + public bool CropSupported + { + get + { + return binarizer.LuminanceSource.CropSupported; + } + + } + + /// Returns a new object with cropped image data. Implementations may keep a reference to the + /// original data rather than a copy. Only callable if isCropSupported() is true. + /// + /// + /// The left coordinate, 0 <= left < getWidth(). + /// + /// The top coordinate, 0 <= top <= getHeight(). + /// + /// The width of the rectangle to crop. + /// + /// The height of the rectangle to crop. + /// + /// A cropped version of this object. + /// + public BinaryBitmap crop(int left, int top, int width, int height) + { + var newSource = binarizer.LuminanceSource.crop(left, top, width, height); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + + /// Whether this bitmap supports counter-clockwise rotation. + /// + public bool RotateSupported + { + get + { + return binarizer.LuminanceSource.RotateSupported; + } + + } + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if {@link #isRotateSupported()} is true. + /// + /// A rotated version of this object. + /// + public BinaryBitmap rotateCounterClockwise() + { + var newSource = binarizer.LuminanceSource.rotateCounterClockwise(); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + + /// + /// Returns a new object with rotated image data by 45 degrees counterclockwise. + /// Only callable if {@link #isRotateSupported()} is true. + /// + /// A rotated version of this object. + public BinaryBitmap rotateCounterClockwise45() + { + LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise45(); + return new BinaryBitmap(binarizer.createBinarizer(newSource)); + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override string ToString() + { + var blackMatrix = BlackMatrix; + return blackMatrix != null ? blackMatrix.ToString() : String.Empty; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/BitmapLuminanceSource.cs b/shadowsocks-csharp/3rd/zxing/BitmapLuminanceSource.cs new file mode 100755 index 00000000..8c61f531 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/BitmapLuminanceSource.cs @@ -0,0 +1,242 @@ +/* +* Copyright 2012 ZXing.Net authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Drawing.Imaging; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace ZXing +{ + public partial class BitmapLuminanceSource : BaseLuminanceSource + { + /// + /// Initializes a new instance of the class. + /// + /// The width. + /// The height. + protected BitmapLuminanceSource(int width, int height) + : base(width, height) + { + } + + /// + /// Initializes a new instance of the class + /// with the image of a Bitmap instance + /// + /// The bitmap. + public BitmapLuminanceSource(Bitmap bitmap) + : base(bitmap.Width, bitmap.Height) + { + var height = bitmap.Height; + var width = bitmap.Width; + + // In order to measure pure decoding speed, we convert the entire image to a greyscale array + // The underlying raster of image consists of bytes with the luminance values +#if WindowsCE + var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); +#else + var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); +#endif + try + { + var stride = Math.Abs(data.Stride); + var pixelWidth = stride/width; + + if (pixelWidth > 4) + { + // old slow way for unsupported bit depth + Color c; + for (int y = 0; y < height; y++) + { + int offset = y*width; + for (int x = 0; x < width; x++) + { + c = bitmap.GetPixel(x, y); + luminances[offset + x] = (byte)((RChannelWeight * c.R + GChannelWeight * c.G + BChannelWeight * c.B) >> ChannelWeight); + } + } + } + else + { + var strideStep = data.Stride; + var buffer = new byte[stride]; + var ptrInBitmap = data.Scan0; + +#if !WindowsCE + // prepare palette for 1 and 8 bit indexed bitmaps + var luminancePalette = new byte[bitmap.Palette.Entries.Length]; + for (var index = 0; index < bitmap.Palette.Entries.Length; index++) + { + var color = bitmap.Palette.Entries[index]; + luminancePalette[index] = (byte) ((RChannelWeight*color.R + + GChannelWeight*color.G + + BChannelWeight*color.B) >> ChannelWeight); + } + if (bitmap.PixelFormat == PixelFormat.Format32bppArgb || + bitmap.PixelFormat == PixelFormat.Format32bppPArgb) + { + pixelWidth = 40; + } + if ((int)bitmap.PixelFormat == 8207 || + (bitmap.Flags & (int)ImageFlags.ColorSpaceCmyk) == (int)ImageFlags.ColorSpaceCmyk) + { + pixelWidth = 41; + } +#endif + + for (int y = 0; y < height; y++) + { + // copy a scanline not the whole bitmap because of memory usage + Marshal.Copy(ptrInBitmap, buffer, 0, stride); +#if NET40 + ptrInBitmap = IntPtr.Add(ptrInBitmap, strideStep); +#else + ptrInBitmap = new IntPtr(ptrInBitmap.ToInt64() + strideStep); +#endif + var offset = y*width; + switch (pixelWidth) + { +#if !WindowsCE + case 0: + for (int x = 0; x*8 < width; x++) + { + for (int subX = 0; subX < 8 && 8*x + subX < width; subX++) + { + var index = (buffer[x] >> (7 - subX)) & 1; + luminances[offset + 8*x + subX] = luminancePalette[index]; + } + } + break; + case 1: + for (int x = 0; x < width; x++) + { + luminances[offset + x] = luminancePalette[buffer[x]]; + } + break; +#endif + case 2: + // should be RGB565 or RGB555, assume RGB565 + { + var maxIndex = 2*width; + for (int index = 0; index < maxIndex; index += 2) + { + var byte1 = buffer[index]; + var byte2 = buffer[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; + + luminances[offset] = (byte)((RChannelWeight * r8 + GChannelWeight * g8 + BChannelWeight * b8) >> ChannelWeight); + offset++; + } + } + break; + case 3: + { + var maxIndex = width*3; + for (int x = 0; x < maxIndex; x += 3) + { + var luminance = (byte) ((BChannelWeight*buffer[x] + + GChannelWeight*buffer[x + 1] + + RChannelWeight*buffer[x + 2]) >> ChannelWeight); + luminances[offset] = luminance; + offset++; + } + } + break; + case 4: + // 4 bytes without alpha channel value + { + var maxIndex = 4*width; + for (int x = 0; x < maxIndex; x += 4) + { + var luminance = (byte) ((BChannelWeight*buffer[x] + + GChannelWeight*buffer[x + 1] + + RChannelWeight*buffer[x + 2]) >> ChannelWeight); + + luminances[offset] = luminance; + offset++; + } + } + break; + case 40: + // with alpha channel; some barcodes are completely black if you + // only look at the r, g and b channel but the alpha channel controls + // the view + { + var maxIndex = 4*width; + for (int x = 0; x < maxIndex; x += 4) + { + var luminance = (byte) ((BChannelWeight*buffer[x] + + GChannelWeight*buffer[x + 1] + + RChannelWeight*buffer[x + 2]) >> ChannelWeight); + + // calculating the resulting luminance based upon a white background + // var alpha = buffer[x * pixelWidth + 3] / 255.0; + // luminance = (byte)(luminance * alpha + 255 * (1 - alpha)); + var alpha = buffer[x + 3]; + luminance = (byte) (((luminance*alpha) >> 8) + (255*(255 - alpha) >> 8) + 1); + luminances[offset] = luminance; + offset++; + } + } + break; + case 41: + // CMYK color space + { + var maxIndex = 4 * width; + for (int x = 0; x < maxIndex; x += 4) + { + var luminance = (byte) (255 - ((BChannelWeight*buffer[x] + + GChannelWeight*buffer[x + 1] + + RChannelWeight*buffer[x + 2]) >> ChannelWeight)); + // Ignore value of k at the moment + luminances[offset] = luminance; + offset++; + } + } + break; + default: + throw new NotSupportedException(); + } + } + } + } + finally + { + bitmap.UnlockBits(data); + } + } + + /// + /// 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 BitmapLuminanceSource(width, height) { luminances = newLuminances }; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/LuminanceSource.cs b/shadowsocks-csharp/3rd/zxing/LuminanceSource.cs new file mode 100755 index 00000000..371a27c7 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/LuminanceSource.cs @@ -0,0 +1,198 @@ +/* +* Copyright 2009 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Text; + +namespace ZXing +{ + /// The purpose of this class hierarchy is to abstract different bitmap implementations across + /// platforms into a standard interface for requesting greyscale luminance values. The interface + /// only provides immutable methods; therefore crop and rotation create copies. This is to ensure + /// that one Reader does not modify the original luminance source and leave it in an unknown state + /// for other Readers in the chain. + /// + /// dswitkin@google.com (Daniel Switkin) + /// + /// www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source + /// + public abstract class LuminanceSource + { + private int width; + private int height; + + protected LuminanceSource(int width, int height) + { + this.width = width; + this.height = height; + } + + /// Fetches one row of luminance data from the underlying platform's bitmap. Values range from + /// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have + /// to bitwise and with 0xff for each value. It is preferable for implementations of this method + /// to only fetch this row rather than the whole image, since no 2D Readers may be installed and + /// getMatrix() may never be called. + /// + /// + /// The row to fetch, 0 <= y < Height. + /// + /// An optional preallocated array. If null or too small, it will be ignored. + /// Always use the returned object, and ignore the .length of the array. + /// + /// An array containing the luminance data. + /// + public abstract byte[] getRow(int y, byte[] row); + + /// Fetches luminance data for the underlying bitmap. Values should be fetched using: + /// int luminance = array[y * width + x] & 0xff; + /// + /// + /// A row-major 2D array of luminance values. Do not use result.length as it may be + /// larger than width * height bytes on some platforms. Do not modify the contents + /// of the result. + /// + public abstract byte[] Matrix { get; } + + /// The width of the bitmap. + virtual public int Width + { + get + { + return width; + } + protected set + { + width = value; + } + } + + /// The height of the bitmap. + virtual public int Height + { + get + { + return height; + } + protected set + { + height = value; + } + } + + /// Whether this subclass supports cropping. + virtual public bool CropSupported + { + get + { + return false; + } + } + + /// Returns a new object with cropped image data. Implementations may keep a reference to the + /// original data rather than a copy. Only callable if CropSupported is true. + /// + /// + /// The left coordinate, 0 <= left < Width. + /// + /// The top coordinate, 0 <= top <= Height. + /// + /// The width of the rectangle to crop. + /// + /// The height of the rectangle to crop. + /// + /// A cropped version of this object. + /// + public virtual LuminanceSource crop(int left, int top, int width, int height) + { + throw new NotSupportedException("This luminance source does not support cropping."); + } + + /// Whether this subclass supports counter-clockwise rotation. + virtual public bool RotateSupported + { + get + { + return false; + } + } + + /// + /// Returns a new object with rotated image data by 90 degrees counterclockwise. + /// Only callable if {@link #isRotateSupported()} is true. + /// + /// A rotated version of this object. + /// + public virtual LuminanceSource rotateCounterClockwise() + { + throw new NotSupportedException("This luminance source does not support rotation."); + } + + /// + /// Returns a new object with rotated image data by 45 degrees counterclockwise. + /// Only callable if {@link #isRotateSupported()} is true. + /// + /// A rotated version of this object. + public virtual LuminanceSource rotateCounterClockwise45() + { + throw new NotSupportedException("This luminance source does not support rotation by 45 degrees."); + } + + /// + /// + /// Whether this subclass supports invertion. + virtual public bool InversionSupported + { + get + { + return false; + } + } + + override public String ToString() + { + var row = new byte[width]; + var result = new StringBuilder(height * (width + 1)); + for (int y = 0; y < height; y++) + { + row = getRow(y, row); + for (int x = 0; x < width; x++) + { + int luminance = row[x] & 0xFF; + char c; + if (luminance < 0x40) + { + c = '#'; + } + else if (luminance < 0x80) + { + c = '+'; + } + else if (luminance < 0xC0) + { + c = '.'; + } + else + { + c = ' '; + } + result.Append(c); + } + result.Append('\n'); + } + return result.ToString(); + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/Reader.cs b/shadowsocks-csharp/3rd/zxing/Reader.cs new file mode 100755 index 00000000..b96267af --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Reader.cs @@ -0,0 +1,59 @@ +/* +* Copyright 2007 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System.Collections.Generic; + +namespace ZXing +{ + /// + /// Implementations of this interface can decode an image of a barcode in some format into + /// the String it encodes. For example, can + /// decode a QR code. The decoder may optionally receive hints from the caller which may help + /// it decode more quickly or accurately. + /// + /// See , which attempts to determine what barcode + /// format is present within the image as well, and then decodes it accordingly. + /// + /// Sean Owen + /// dswitkin@google.com (Daniel Switkin) + public interface Reader + { + /// + /// Locates and decodes a barcode in some format within an image. + /// + /// image of barcode to decode + /// String which the barcode encodes + Result decode(BinaryBitmap image); + + /// Locates and decodes a barcode in some format within an image. This method also accepts + /// hints, each possibly associated to some data, which may help the implementation decode. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// + /// String which the barcode encodes + Result decode(BinaryBitmap image, IDictionary hints); + + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + void reset(); + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/ReaderException.cs b/shadowsocks-csharp/3rd/zxing/ReaderException.cs new file mode 100755 index 00000000..90936b5c --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/ReaderException.cs @@ -0,0 +1,71 @@ +/* +* Copyright 2007 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; + +namespace ZXing +{ + /// + /// The general exception class throw when something goes wrong during decoding of a barcode. + /// This includes, but is not limited to, failing checksums / error correction algorithms, being + /// unable to locate finder timing patterns, and so on. + /// + /// Sean Owen + [Serializable] + public class ReaderException : Exception + { + /// + /// Gets the instance. + /// + public static ReaderException Instance + { + get + { + return instance; + } + + } + + // TODO: Currently we throw up to 400 ReaderExceptions while scanning a single 240x240 image before + // rejecting it. This involves a lot of overhead and memory allocation, and affects both performance + // and latency on continuous scan clients. In the future, we should change all the decoders not to + // throw exceptions for routine events, like not finding a barcode on a given row. Instead, we + // should return error codes back to the callers, and simply delete this class. In the mean time, I + // have altered this class to be as lightweight as possible, by ignoring the exception string, and + // by disabling the generation of stack traces, which is especially time consuming. These are just + // temporary measures, pending the big cleanup. + + //UPGRADE_NOTE: Final was removed from the declaration of 'instance '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'" + private static readonly ReaderException instance = new ReaderException(); + + // EXCEPTION TRACKING SUPPORT + // Identifies who is throwing exceptions and how often. To use: + // + // 1. Uncomment these lines and the code below which uses them. + // 2. Uncomment the two corresponding lines in j2se/CommandLineRunner.decode() + // 3. Change core to build as Java 1.5 temporarily + // private static int exceptionCount = 0; + // private static Map throwers = new HashMap(32); + + /// + /// Initializes a new instance of the class. + /// + protected ReaderException() + { + // do nothing + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/Result.cs b/shadowsocks-csharp/3rd/zxing/Result.cs new file mode 100755 index 00000000..3aa6f5b8 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/Result.cs @@ -0,0 +1,161 @@ +/* +* Copyright 2007 ZXing authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +using System; +using System.Collections.Generic; + +namespace ZXing +{ + /// + /// Encapsulates the result of decoding a barcode within an image. + /// + public sealed class Result + { + /// raw text encoded by the barcode, if applicable, otherwise null + public String Text { get; private set; } + + /// raw bytes encoded by the barcode, if applicable, otherwise null + public byte[] RawBytes { get; private set; } + + /// + /// points related to the barcode in the image. These are typically points + /// identifying finder patterns or the corners of the barcode. The exact meaning is + /// specific to the type of barcode that was decoded. + /// + public ResultPoint[] ResultPoints { get; private set; } + + /// {@link BarcodeFormat} representing the format of the barcode that was decoded + public BarcodeFormat BarcodeFormat { get; private set; } + + /// + /// {@link Hashtable} mapping {@link ResultMetadataType} keys to values. May be + /// null. This contains optional metadata about what was detected about the barcode, + /// like orientation. + /// + public IDictionary ResultMetadata { get; private set; } + + /// + /// Gets the timestamp. + /// + public long Timestamp { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The text. + /// The raw bytes. + /// The result points. + /// The format. + public Result(String text, + byte[] rawBytes, + ResultPoint[] resultPoints, + BarcodeFormat format) + : this(text, rawBytes, resultPoints, format, DateTime.Now.Ticks) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The text. + /// The raw bytes. + /// The result points. + /// The format. + /// The timestamp. + public Result(String text, byte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format, long timestamp) + { + if (text == null && rawBytes == null) + { + throw new ArgumentException("Text and bytes are null"); + } + Text = text; + RawBytes = rawBytes; + ResultPoints = resultPoints; + BarcodeFormat = format; + ResultMetadata = null; + Timestamp = timestamp; + } + + /// + /// Adds one metadata to the result + /// + /// The type. + /// The value. + public void putMetadata(ResultMetadataType type, Object value) + { + if (ResultMetadata == null) + { + ResultMetadata = new Dictionary(); + } + ResultMetadata[type] = value; + } + + /// + /// Adds a list of metadata to the result + /// + /// The metadata. + public void putAllMetadata(IDictionary metadata) + { + if (metadata != null) + { + if (ResultMetadata == null) + { + ResultMetadata = metadata; + } + else + { + foreach (var entry in metadata) + ResultMetadata[entry.Key] = entry.Value; + } + } + } + + /// + /// Adds the result points. + /// + /// The new points. + public void addResultPoints(ResultPoint[] newPoints) + { + var oldPoints = ResultPoints; + if (oldPoints == null) + { + ResultPoints = newPoints; + } + else if (newPoints != null && newPoints.Length > 0) + { + var allPoints = new ResultPoint[oldPoints.Length + newPoints.Length]; + Array.Copy(oldPoints, 0, allPoints, 0, oldPoints.Length); + Array.Copy(newPoints, 0, allPoints, oldPoints.Length, newPoints.Length); + ResultPoints = allPoints; + } + } + + /// + /// Returns a that represents this instance. + /// + /// + /// A that represents this instance. + /// + public override String ToString() + { + if (Text == null) + { + return "[" + RawBytes.Length + " bytes]"; + } + return Text; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/ResultMetadataType.cs b/shadowsocks-csharp/3rd/zxing/ResultMetadataType.cs new file mode 100755 index 00000000..360357c8 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/ResultMetadataType.cs @@ -0,0 +1,102 @@ +/* + * Copyright 2008 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace ZXing +{ + /// + /// Represents some type of metadata about the result of the decoding that the decoder + /// wishes to communicate back to the caller. + /// + /// Sean Owen + public enum ResultMetadataType + { + /// + /// Unspecified, application-specific metadata. Maps to an unspecified {@link Object}. + /// + OTHER, + + /// + /// Denotes the likely approximate orientation of the barcode in the image. This value + /// is given as degrees rotated clockwise from the normal, upright orientation. + /// For example a 1D barcode which was found by reading top-to-bottom would be + /// said to have orientation "90". This key maps to an {@link Integer} whose + /// value is in the range [0,360). + /// + ORIENTATION, + + /// + ///

2D barcode formats typically encode text, but allow for a sort of 'byte mode' + /// which is sometimes used to encode binary data. While {@link Result} makes available + /// the complete raw bytes in the barcode for these formats, it does not offer the bytes + /// from the byte segments alone.

+ ///

This maps to a {@link java.util.List} of byte arrays corresponding to the + /// raw bytes in the byte segments in the barcode, in order.

+ ///
+ BYTE_SEGMENTS, + + /// + /// Error correction level used, if applicable. The value type depends on the + /// format, but is typically a String. + /// + ERROR_CORRECTION_LEVEL, + + /// + /// For some periodicals, indicates the issue number as an {@link Integer}. + /// + ISSUE_NUMBER, + + /// + /// For some products, indicates the suggested retail price in the barcode as a + /// formatted {@link String}. + /// + SUGGESTED_PRICE, + + /// + /// For some products, the possible country of manufacture as a {@link String} denoting the + /// ISO country code. Some map to multiple possible countries, like "US/CA". + /// + POSSIBLE_COUNTRY, + + /// + /// For some products, the extension text + /// + UPC_EAN_EXTENSION, + + /// + /// If the code format supports structured append and + /// the current scanned code is part of one then the + /// sequence number is given with it. + /// + STRUCTURED_APPEND_SEQUENCE, + + /// + /// If the code format supports structured append and + /// the current scanned code is part of one then the + /// parity is given with it. + /// + STRUCTURED_APPEND_PARITY, + + /// + /// PDF417-specific metadata + /// + PDF417_EXTRA_METADATA, + + /// + /// Aztec-specific metadata + /// + AZTEC_EXTRA_METADATA + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/3rd/zxing/qrcode/QRCodeReader.cs b/shadowsocks-csharp/3rd/zxing/qrcode/QRCodeReader.cs new file mode 100755 index 00000000..d4fcc770 --- /dev/null +++ b/shadowsocks-csharp/3rd/zxing/qrcode/QRCodeReader.cs @@ -0,0 +1,255 @@ +/* + * Copyright 2007 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; + +using ZXing.Common; +using ZXing.QrCode.Internal; + +namespace ZXing.QrCode +{ + /// + /// This implementation can detect and decode QR Codes in an image. + /// Sean Owen + /// + public class QRCodeReader : Reader + { + private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0]; + + private readonly Decoder decoder = new Decoder(); + + /// + /// Gets the decoder. + /// + /// + protected Decoder getDecoder() + { + return decoder; + } + + /// + /// Locates and decodes a QR code in an image. + /// + /// a String representing the content encoded by the QR code + /// + public Result decode(BinaryBitmap image) + { + return decode(image, null); + } + + /// + /// Locates and decodes a barcode in some format within an image. This method also accepts + /// hints, each possibly associated to some data, which may help the implementation decode. + /// + /// image of barcode to decode + /// passed as a from + /// to arbitrary data. The + /// meaning of the data depends upon the hint type. The implementation may or may not do + /// anything with these hints. + /// + /// String which the barcode encodes + /// + public Result decode(BinaryBitmap image, IDictionary hints) + { + DecoderResult decoderResult; + ResultPoint[] points; + if (image == null || image.BlackMatrix == null) + { + // something is wrong with the image + return null; + } + if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) + { + var bits = extractPureBits(image.BlackMatrix); + if (bits == null) + return null; + decoderResult = decoder.decode(bits, hints); + points = NO_POINTS; + } + else + { + var detectorResult = new Detector(image.BlackMatrix).detect(hints); + if (detectorResult == null) + return null; + decoderResult = decoder.decode(detectorResult.Bits, hints); + points = detectorResult.Points; + } + if (decoderResult == null) + return null; + + // If the code was mirrored: swap the bottom-left and the top-right points. + var data = decoderResult.Other as QRCodeDecoderMetaData; + if (data != null) + { + data.applyMirroredCorrection(points); + } + + var result = new Result(decoderResult.Text, decoderResult.RawBytes, points, BarcodeFormat.QR_CODE); + var byteSegments = decoderResult.ByteSegments; + if (byteSegments != null) + { + result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, byteSegments); + } + var ecLevel = decoderResult.ECLevel; + if (ecLevel != null) + { + result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, ecLevel); + } + if (decoderResult.StructuredAppend) + { + result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_SEQUENCE, decoderResult.StructuredAppendSequenceNumber); + result.putMetadata(ResultMetadataType.STRUCTURED_APPEND_PARITY, decoderResult.StructuredAppendParity); + } + return result; + } + + /// + /// Resets any internal state the implementation has after a decode, to prepare it + /// for reuse. + /// + public void reset() + { + // do nothing + } + + /// + /// This method detects a code in a "pure" image -- that is, pure monochrome image + /// which contains only an unrotated, unskewed, image of a code, with some white border + /// around it. This is a specialized method that works exceptionally fast in this special + /// case. + /// + /// + /// + private static BitMatrix extractPureBits(BitMatrix image) + { + int[] leftTopBlack = image.getTopLeftOnBit(); + int[] rightBottomBlack = image.getBottomRightOnBit(); + if (leftTopBlack == null || rightBottomBlack == null) + { + return null; + } + + float moduleSize; + if (!QRCodeReader.moduleSize(leftTopBlack, image, out moduleSize)) + return null; + + int top = leftTopBlack[1]; + int bottom = rightBottomBlack[1]; + int left = leftTopBlack[0]; + int right = rightBottomBlack[0]; + + // Sanity check! + if (left >= right || top >= bottom) + { + return null; + } + + if (bottom - top != right - left) + { + // Special case, where bottom-right module wasn't black so we found something else in the last row + // Assume it's a square, so use height as the width + right = left + (bottom - top); + } + + int matrixWidth = (int)Math.Round((right - left + 1) / moduleSize); + int matrixHeight = (int)Math.Round((bottom - top + 1) / moduleSize); + if (matrixWidth <= 0 || matrixHeight <= 0) + { + return null; + } + if (matrixHeight != matrixWidth) + { + // Only possibly decode square regions + return null; + } + + // Push in the "border" by half the module width so that we start + // sampling in the middle of the module. Just in case the image is a + // little off, this will help recover. + int nudge = (int)(moduleSize / 2.0f); + top += nudge; + left += nudge; + + // But careful that this does not sample off the edge + int nudgedTooFarRight = left + (int)((matrixWidth - 1) * moduleSize) - (right - 1); + if (nudgedTooFarRight > 0) + { + if (nudgedTooFarRight > nudge) + { + // Neither way fits; abort + return null; + } + left -= nudgedTooFarRight; + } + int nudgedTooFarDown = top + (int)((matrixHeight - 1) * moduleSize) - (bottom - 1); + if (nudgedTooFarDown > 0) + { + if (nudgedTooFarDown > nudge) + { + // Neither way fits; abort + return null; + } + top -= nudgedTooFarDown; + } + + // Now just read off the bits + BitMatrix bits = new BitMatrix(matrixWidth, matrixHeight); + for (int y = 0; y < matrixHeight; y++) + { + int iOffset = top + (int)(y * moduleSize); + for (int x = 0; x < matrixWidth; x++) + { + if (image[left + (int)(x * moduleSize), iOffset]) + { + bits[x, y] = true; + } + } + } + return bits; + } + + private static bool moduleSize(int[] leftTopBlack, BitMatrix image, out float msize) + { + int height = image.Height; + int width = image.Width; + int x = leftTopBlack[0]; + int y = leftTopBlack[1]; + bool inBlack = true; + int transitions = 0; + while (x < width && y < height) + { + if (inBlack != image[x, y]) + { + if (++transitions == 5) + { + break; + } + inBlack = !inBlack; + } + x++; + y++; + } + if (x == width || y == height) + { + msize = 0.0f; + return false; + } + msize = (x - leftTopBlack[0]) / 7.0f; + return true; + } + } +} \ No newline at end of file diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 3d875f3e..acd46995 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -357,6 +357,45 @@ namespace Shadowsocks.View qrCodeForm.Show(); } + private void ScanQRCodeItem_Click(object sender, EventArgs e) + { + /* + using (Bitmap image = new Bitmap(Screen.PrimaryScreen.Bounds.Width, + Screen.PrimaryScreen.Bounds.Height)) + { + using (Graphics g = Graphics.FromImage(bmpScreenCapture)) + { + g.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, + Screen.PrimaryScreen.Bounds.Y, + 0, 0, + bmpScreenCapture.Size, + CopyPixelOperation.SourceCopy); + } + resultPoints.Clear(); + /* var reader = new BarcodeReader + { + 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) + { + txtDecoderContent.Text = "No barcode recognized"; + } + labDuration.Text = new TimeSpan(timerStop - timerStart).Milliseconds.ToString("0 ms"); + + } + } + * */ + } + private void AutoStartupItem_Click(object sender, EventArgs e) { AutoStartupItem.Checked = !AutoStartupItem.Checked; if (!AutoStartup.Set(AutoStartupItem.Checked)) { diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 89cb782c..4c335313 100755 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -70,6 +70,11 @@ + + + + + @@ -88,6 +93,7 @@ + @@ -112,6 +118,11 @@ + + + + +