add reader
This commit is contained in:
+89
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates barcode formats known to this package.
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
[System.Flags]
|
||||
public enum BarcodeFormat
|
||||
{
|
||||
/// <summary>Aztec 2D barcode format.</summary>
|
||||
AZTEC = 1,
|
||||
|
||||
/// <summary>CODABAR 1D format.</summary>
|
||||
CODABAR = 2,
|
||||
|
||||
/// <summary>Code 39 1D format.</summary>
|
||||
CODE_39 = 4,
|
||||
|
||||
/// <summary>Code 93 1D format.</summary>
|
||||
CODE_93 = 8,
|
||||
|
||||
/// <summary>Code 128 1D format.</summary>
|
||||
CODE_128 = 16,
|
||||
|
||||
/// <summary>Data Matrix 2D barcode format.</summary>
|
||||
DATA_MATRIX = 32,
|
||||
|
||||
/// <summary>EAN-8 1D format.</summary>
|
||||
EAN_8 = 64,
|
||||
|
||||
/// <summary>EAN-13 1D format.</summary>
|
||||
EAN_13 = 128,
|
||||
|
||||
/// <summary>ITF (Interleaved Two of Five) 1D format.</summary>
|
||||
ITF = 256,
|
||||
|
||||
/// <summary>MaxiCode 2D barcode format.</summary>
|
||||
MAXICODE = 512,
|
||||
|
||||
/// <summary>PDF417 format.</summary>
|
||||
PDF_417 = 1024,
|
||||
|
||||
/// <summary>QR Code 2D barcode format.</summary>
|
||||
QR_CODE = 2048,
|
||||
|
||||
/// <summary>RSS 14</summary>
|
||||
RSS_14 = 4096,
|
||||
|
||||
/// <summary>RSS EXPANDED</summary>
|
||||
RSS_EXPANDED = 8192,
|
||||
|
||||
/// <summary>UPC-A 1D format.</summary>
|
||||
UPC_A = 16384,
|
||||
|
||||
/// <summary>UPC-E 1D format.</summary>
|
||||
UPC_E = 32768,
|
||||
|
||||
/// <summary>UPC/EAN extension format. Not a stand-alone format.</summary>
|
||||
UPC_EAN_EXTENSION = 65536,
|
||||
|
||||
/// <summary>MSI</summary>
|
||||
MSI = 131072,
|
||||
|
||||
/// <summary>Plessey</summary>
|
||||
PLESSEY = 262144,
|
||||
|
||||
/// <summary>
|
||||
/// 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)
|
||||
/// </summary>
|
||||
All_1D = UPC_A | UPC_E | EAN_13 | EAN_8 | CODABAR | CODE_39 | CODE_93 | CODE_128 | ITF | RSS_14 | RSS_EXPANDED
|
||||
}
|
||||
}
|
||||
+206
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class for luminance sources which supports
|
||||
/// cropping and rotating based upon the luminance values.
|
||||
/// </summary>
|
||||
public abstract class BaseLuminanceSource : LuminanceSource
|
||||
{
|
||||
// the following channel weights give nearly the same
|
||||
// gray scale picture as the java version with BufferedImage.TYPE_BYTE_GRAY
|
||||
// they are used in sub classes for luminance / gray scale calculation
|
||||
protected const int RChannelWeight = 19562;
|
||||
protected const int GChannelWeight = 38550;
|
||||
protected const int BChannelWeight = 7424;
|
||||
protected const int ChannelWeight = 16;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected byte[] luminances;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
||||
/// </summary>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
protected BaseLuminanceSource(int width, int height)
|
||||
: base(width, height)
|
||||
{
|
||||
luminances = new byte[width * height];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
||||
/// </summary>
|
||||
/// <param name="luminanceArray">The luminance array.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
protected BaseLuminanceSource(byte[] luminanceArray, int width, int height)
|
||||
: base(width, height)
|
||||
{
|
||||
luminances = new byte[width * height];
|
||||
Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
||||
/// 0 (black) to 255 (white). It is preferable for implementations of this method
|
||||
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
||||
/// getMatrix() may never be called.
|
||||
/// </summary>
|
||||
/// <param name="y">The row to fetch, 0 <= y < Height.</param>
|
||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
||||
/// Always use the returned object, and ignore the .length of the array.</param>
|
||||
/// <returns>
|
||||
/// An array containing the luminance data.
|
||||
/// </returns>
|
||||
override public byte[] getRow(int y, byte[] row)
|
||||
{
|
||||
int width = Width;
|
||||
if (row == null || row.Length < width)
|
||||
{
|
||||
row = new byte[width];
|
||||
}
|
||||
for (int i = 0; i < width; i++)
|
||||
row[i] = luminances[y * width + i];
|
||||
return row;
|
||||
}
|
||||
|
||||
public override byte[] Matrix
|
||||
{
|
||||
get { return luminances; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
|
||||
/// Only callable if {@link #isRotateSupported()} is true.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A rotated version of this object.
|
||||
/// </returns>
|
||||
public override LuminanceSource rotateCounterClockwise()
|
||||
{
|
||||
var rotatedLuminances = new byte[Width * Height];
|
||||
var newWidth = Height;
|
||||
var newHeight = Width;
|
||||
var localLuminances = Matrix;
|
||||
for (var yold = 0; yold < Height; yold++)
|
||||
{
|
||||
for (var xold = 0; xold < Width; xold++)
|
||||
{
|
||||
var ynew = newHeight - xold - 1;
|
||||
var xnew = yold;
|
||||
rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold];
|
||||
}
|
||||
}
|
||||
return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TODO: not implemented yet
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A rotated version of this object.
|
||||
/// </returns>
|
||||
public override LuminanceSource rotateCounterClockwise45()
|
||||
{
|
||||
// TODO: implement a good 45 degrees rotation without lost of information
|
||||
return base.rotateCounterClockwise45();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
|
||||
public override bool RotateSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
/// original data rather than a copy. Only callable if CropSupported is true.
|
||||
/// </summary>
|
||||
/// <param name="left">The left coordinate, 0 <= left < Width.</param>
|
||||
/// <param name="top">The top coordinate, 0 <= top <= Height.</param>
|
||||
/// <param name="width">The width of the rectangle to crop.</param>
|
||||
/// <param name="height">The height of the rectangle to crop.</param>
|
||||
/// <returns>
|
||||
/// A cropped version of this object.
|
||||
/// </returns>
|
||||
public override LuminanceSource crop(int left, int top, int width, int height)
|
||||
{
|
||||
if (left + width > Width || top + height > Height)
|
||||
{
|
||||
throw new ArgumentException("Crop rectangle does not fit within image data.");
|
||||
}
|
||||
var croppedLuminances = new byte[width * height];
|
||||
var oldLuminances = Matrix;
|
||||
var oldWidth = Width;
|
||||
var oldRightBound = left + width;
|
||||
var oldBottomBound = top + height;
|
||||
for (int yold = top, ynew = 0; yold < oldBottomBound; yold++, ynew++)
|
||||
{
|
||||
for (int xold = left, xnew = 0; xold < oldRightBound; xold++, xnew++)
|
||||
{
|
||||
croppedLuminances[ynew * width + xnew] = oldLuminances[yold * oldWidth + xold];
|
||||
}
|
||||
}
|
||||
return CreateLuminanceSource(croppedLuminances, width, height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <returns> Whether this subclass supports cropping.</returns>
|
||||
public override bool CropSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <returns>Whether this subclass supports invertion.</returns>
|
||||
public override bool InversionSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should create a new luminance source with the right class type.
|
||||
/// The method is used in methods crop and rotate.
|
||||
/// </summary>
|
||||
/// <param name="newLuminances">The new luminances.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
/// <returns></returns>
|
||||
protected abstract LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height);
|
||||
}
|
||||
}
|
||||
Executable
+104
@@ -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
|
||||
{
|
||||
/// <summary> This class hierarchy provides a set of methods to convert luminance data to 1 bit data.
|
||||
/// It allows the algorithm to vary polymorphically, for example allowing a very expensive
|
||||
/// thresholding technique for servers and a fast one for mobile. It also permits the implementation
|
||||
/// to vary, e.g. a JNI version for Android and a Java fallback version for other platforms.
|
||||
///
|
||||
/// <author>dswitkin@google.com (Daniel Switkin)</author>
|
||||
/// </summary>
|
||||
public abstract class Binarizer
|
||||
{
|
||||
private readonly LuminanceSource source;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Binarizer"/> class.
|
||||
/// </summary>
|
||||
/// <param name="source">The source.</param>
|
||||
protected internal Binarizer(LuminanceSource source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentException("Source must be non-null.");
|
||||
}
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the luminance source object.
|
||||
/// </summary>
|
||||
virtual public LuminanceSource LuminanceSource
|
||||
{
|
||||
get
|
||||
{
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
/// cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
/// This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
/// For callers which only examine one row of pixels at a time, the same BitArray should be reused
|
||||
/// and passed in with each call for performance. However it is legal to keep more than one row
|
||||
/// at a time if needed.
|
||||
/// </summary>
|
||||
/// <param name="y">The row to fetch, 0 <= y < bitmap height.</param>
|
||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
||||
/// If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
/// </param>
|
||||
/// <returns> The array of bits for this row (true means black).</returns>
|
||||
public abstract BitArray getBlackRow(int y, BitArray row);
|
||||
|
||||
/// <summary> Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive
|
||||
/// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
/// may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
/// fetched using getBlackRow(), so don't mix and match between them.
|
||||
/// </summary>
|
||||
/// <returns> The 2D array of bits for the image (true means black).</returns>
|
||||
public abstract BitMatrix BlackMatrix { get; }
|
||||
|
||||
/// <summary> Creates a new object with the same type as this Binarizer implementation, but with pristine
|
||||
/// state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache
|
||||
/// of 1 bit data. See Effective Java for why we can't use Java's clone() method.
|
||||
/// </summary>
|
||||
/// <param name="source">The LuminanceSource this Binarizer will operate on.</param>
|
||||
/// <returns> A new concrete Binarizer implementation object.</returns>
|
||||
public abstract Binarizer createBinarizer(LuminanceSource source);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the luminance source object.
|
||||
/// </summary>
|
||||
public int Width
|
||||
{
|
||||
get { return source.Width; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the luminance source object.
|
||||
/// </summary>
|
||||
public int Height
|
||||
{
|
||||
get { return source.Height; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+186
@@ -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
|
||||
{
|
||||
|
||||
/// <summary> This class is the core bitmap class used by ZXing to represent 1 bit data. Reader objects
|
||||
/// accept a BinaryBitmap and attempt to decode it.
|
||||
///
|
||||
/// </summary>
|
||||
/// <author> dswitkin@google.com (Daniel Switkin)
|
||||
/// </author>
|
||||
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
|
||||
/// </author>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <returns> The width of the bitmap.
|
||||
/// </returns>
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
return binarizer.Width;
|
||||
}
|
||||
|
||||
}
|
||||
/// <returns> The height of the bitmap.
|
||||
/// </returns>
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
return binarizer.Height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> Converts one row of luminance data to 1 bit data. May actually do the conversion, or return
|
||||
/// cached data. Callers should assume this method is expensive and call it as seldom as possible.
|
||||
/// This method is intended for decoding 1D barcodes and may choose to apply sharpening.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="y">The row to fetch, 0 <= y < bitmap height.
|
||||
/// </param>
|
||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
||||
/// If used, the Binarizer will call BitArray.clear(). Always use the returned object.
|
||||
/// </param>
|
||||
/// <returns> The array of bits for this row (true means black).
|
||||
/// </returns>
|
||||
public BitArray getBlackRow(int y, BitArray row)
|
||||
{
|
||||
return binarizer.getBlackRow(y, row);
|
||||
}
|
||||
|
||||
/// <summary> Converts a 2D array of luminance data to 1 bit. As above, assume this method is expensive
|
||||
/// and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or
|
||||
/// may not apply sharpening. Therefore, a row from this matrix may not be identical to one
|
||||
/// fetched using getBlackRow(), so don't mix and match between them.
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns> The 2D array of bits for the image (true means black).
|
||||
/// </returns>
|
||||
public BitMatrix BlackMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
// The matrix is created on demand the first time it is requested, then cached. There are two
|
||||
// reasons for this:
|
||||
// 1. This work will never be done if the caller only installs 1D Reader objects, or if a
|
||||
// 1D Reader finds a barcode before the 2D Readers run.
|
||||
// 2. This work will only be done once even if the caller installs multiple 2D Readers.
|
||||
if (matrix == null)
|
||||
{
|
||||
matrix = binarizer.BlackMatrix;
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns> Whether this bitmap can be cropped.
|
||||
/// </returns>
|
||||
public bool CropSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return binarizer.LuminanceSource.CropSupported;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary> Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
/// original data rather than a copy. Only callable if isCropSupported() is true.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="left">The left coordinate, 0 <= left < getWidth().
|
||||
/// </param>
|
||||
/// <param name="top">The top coordinate, 0 <= top <= getHeight().
|
||||
/// </param>
|
||||
/// <param name="width">The width of the rectangle to crop.
|
||||
/// </param>
|
||||
/// <param name="height">The height of the rectangle to crop.
|
||||
/// </param>
|
||||
/// <returns> A cropped version of this object.
|
||||
/// </returns>
|
||||
public BinaryBitmap crop(int left, int top, int width, int height)
|
||||
{
|
||||
var newSource = binarizer.LuminanceSource.crop(left, top, width, height);
|
||||
return new BinaryBitmap(binarizer.createBinarizer(newSource));
|
||||
}
|
||||
|
||||
/// <returns> Whether this bitmap supports counter-clockwise rotation.
|
||||
/// </returns>
|
||||
public bool RotateSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return binarizer.LuminanceSource.RotateSupported;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
|
||||
/// Only callable if {@link #isRotateSupported()} is true.
|
||||
/// </summary>
|
||||
/// <returns> A rotated version of this object.
|
||||
/// </returns>
|
||||
public BinaryBitmap rotateCounterClockwise()
|
||||
{
|
||||
var newSource = binarizer.LuminanceSource.rotateCounterClockwise();
|
||||
return new BinaryBitmap(binarizer.createBinarizer(newSource));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with rotated image data by 45 degrees counterclockwise.
|
||||
/// Only callable if {@link #isRotateSupported()} is true.
|
||||
/// </summary>
|
||||
/// <returns>A rotated version of this object.</returns>
|
||||
public BinaryBitmap rotateCounterClockwise45()
|
||||
{
|
||||
LuminanceSource newSource = binarizer.LuminanceSource.rotateCounterClockwise45();
|
||||
return new BinaryBitmap(binarizer.createBinarizer(newSource));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var blackMatrix = BlackMatrix;
|
||||
return blackMatrix != null ? blackMatrix.ToString() : String.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
+242
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class.
|
||||
/// </summary>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
protected BitmapLuminanceSource(int width, int height)
|
||||
: base(width, height)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class
|
||||
/// with the image of a Bitmap instance
|
||||
/// </summary>
|
||||
/// <param name="bitmap">The bitmap.</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should create a new luminance source with the right class type.
|
||||
/// The method is used in methods crop and rotate.
|
||||
/// </summary>
|
||||
/// <param name="newLuminances">The new luminances.</param>
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
/// <returns></returns>
|
||||
protected override LuminanceSource CreateLuminanceSource(byte[] newLuminances, int width, int height)
|
||||
{
|
||||
return new BitmapLuminanceSource(width, height) { luminances = newLuminances };
|
||||
}
|
||||
}
|
||||
}
|
||||
+198
@@ -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
|
||||
{
|
||||
/// <summary> The purpose of this class hierarchy is to abstract different bitmap implementations across
|
||||
/// platforms into a standard interface for requesting greyscale luminance values. The interface
|
||||
/// only provides immutable methods; therefore crop and rotation create copies. This is to ensure
|
||||
/// that one Reader does not modify the original luminance source and leave it in an unknown state
|
||||
/// for other Readers in the chain.
|
||||
/// </summary>
|
||||
/// <author> dswitkin@google.com (Daniel Switkin)
|
||||
/// </author>
|
||||
/// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source
|
||||
/// </author>
|
||||
public abstract class LuminanceSource
|
||||
{
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
protected LuminanceSource(int width, int height)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/// <summary> Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
||||
/// 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have
|
||||
/// to bitwise and with 0xff for each value. It is preferable for implementations of this method
|
||||
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
||||
/// getMatrix() may never be called.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="y">The row to fetch, 0 <= y < Height.
|
||||
/// </param>
|
||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
||||
/// Always use the returned object, and ignore the .length of the array.
|
||||
/// </param>
|
||||
/// <returns> An array containing the luminance data.
|
||||
/// </returns>
|
||||
public abstract byte[] getRow(int y, byte[] row);
|
||||
|
||||
/// <summary> Fetches luminance data for the underlying bitmap. Values should be fetched using:
|
||||
/// int luminance = array[y * width + x] & 0xff;
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns> A row-major 2D array of luminance values. Do not use result.length as it may be
|
||||
/// larger than width * height bytes on some platforms. Do not modify the contents
|
||||
/// of the result.
|
||||
/// </returns>
|
||||
public abstract byte[] Matrix { get; }
|
||||
|
||||
/// <returns> The width of the bitmap.</returns>
|
||||
virtual public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
return width;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
width = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns> The height of the bitmap.</returns>
|
||||
virtual public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
return height;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
height = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <returns> Whether this subclass supports cropping.</returns>
|
||||
virtual public bool CropSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Returns a new object with cropped image data. Implementations may keep a reference to the
|
||||
/// original data rather than a copy. Only callable if CropSupported is true.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="left">The left coordinate, 0 <= left < Width.
|
||||
/// </param>
|
||||
/// <param name="top">The top coordinate, 0 <= top <= Height.
|
||||
/// </param>
|
||||
/// <param name="width">The width of the rectangle to crop.
|
||||
/// </param>
|
||||
/// <param name="height">The height of the rectangle to crop.
|
||||
/// </param>
|
||||
/// <returns> A cropped version of this object.
|
||||
/// </returns>
|
||||
public virtual LuminanceSource crop(int left, int top, int width, int height)
|
||||
{
|
||||
throw new NotSupportedException("This luminance source does not support cropping.");
|
||||
}
|
||||
|
||||
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
|
||||
virtual public bool RotateSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
|
||||
/// Only callable if {@link #isRotateSupported()} is true.
|
||||
/// </summary>
|
||||
/// <returns> A rotated version of this object.
|
||||
/// </returns>
|
||||
public virtual LuminanceSource rotateCounterClockwise()
|
||||
{
|
||||
throw new NotSupportedException("This luminance source does not support rotation.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new object with rotated image data by 45 degrees counterclockwise.
|
||||
/// Only callable if {@link #isRotateSupported()} is true.
|
||||
/// </summary>
|
||||
/// <returns>A rotated version of this object.</returns>
|
||||
public virtual LuminanceSource rotateCounterClockwise45()
|
||||
{
|
||||
throw new NotSupportedException("This luminance source does not support rotation by 45 degrees.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
/// <returns>Whether this subclass supports invertion.</returns>
|
||||
virtual public bool InversionSupported
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+59
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementations of this interface can decode an image of a barcode in some format into
|
||||
/// the String it encodes. For example, <see cref="ZXing.QrCode.QRCodeReader" /> can
|
||||
/// decode a QR code. The decoder may optionally receive hints from the caller which may help
|
||||
/// it decode more quickly or accurately.
|
||||
///
|
||||
/// See <see cref="MultiFormatReader" />, which attempts to determine what barcode
|
||||
/// format is present within the image as well, and then decodes it accordingly.
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
/// <author>dswitkin@google.com (Daniel Switkin)</author>
|
||||
public interface Reader
|
||||
{
|
||||
/// <summary>
|
||||
/// Locates and decodes a barcode in some format within an image.
|
||||
/// </summary>
|
||||
/// <param name="image">image of barcode to decode</param>
|
||||
/// <returns>String which the barcode encodes</returns>
|
||||
Result decode(BinaryBitmap image);
|
||||
|
||||
/// <summary> Locates and decodes a barcode in some format within an image. This method also accepts
|
||||
/// hints, each possibly associated to some data, which may help the implementation decode.
|
||||
/// </summary>
|
||||
/// <param name="image">image of barcode to decode</param>
|
||||
/// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}" /> from <see cref="DecodeHintType" />
|
||||
/// to arbitrary data. The
|
||||
/// meaning of the data depends upon the hint type. The implementation may or may not do
|
||||
/// anything with these hints.
|
||||
/// </param>
|
||||
/// <returns>String which the barcode encodes</returns>
|
||||
Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints);
|
||||
|
||||
/// <summary>
|
||||
/// Resets any internal state the implementation has after a decode, to prepare it
|
||||
/// for reuse.
|
||||
/// </summary>
|
||||
void reset();
|
||||
}
|
||||
}
|
||||
+71
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// The general exception class throw when something goes wrong during decoding of a barcode.
|
||||
/// This includes, but is not limited to, failing checksums / error correction algorithms, being
|
||||
/// unable to locate finder timing patterns, and so on.
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
[Serializable]
|
||||
public class ReaderException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the instance.
|
||||
/// </summary>
|
||||
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<String,Integer> throwers = new HashMap<String,Integer>(32);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReaderException"/> class.
|
||||
/// </summary>
|
||||
protected ReaderException()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+161
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Encapsulates the result of decoding a barcode within an image.
|
||||
/// </summary>
|
||||
public sealed class Result
|
||||
{
|
||||
/// <returns>raw text encoded by the barcode, if applicable, otherwise <code>null</code></returns>
|
||||
public String Text { get; private set; }
|
||||
|
||||
/// <returns>raw bytes encoded by the barcode, if applicable, otherwise <code>null</code></returns>
|
||||
public byte[] RawBytes { get; private set; }
|
||||
|
||||
/// <returns>
|
||||
/// points related to the barcode in the image. These are typically points
|
||||
/// identifying finder patterns or the corners of the barcode. The exact meaning is
|
||||
/// specific to the type of barcode that was decoded.
|
||||
/// </returns>
|
||||
public ResultPoint[] ResultPoints { get; private set; }
|
||||
|
||||
/// <returns>{@link BarcodeFormat} representing the format of the barcode that was decoded</returns>
|
||||
public BarcodeFormat BarcodeFormat { get; private set; }
|
||||
|
||||
/// <returns>
|
||||
/// {@link Hashtable} mapping {@link ResultMetadataType} keys to values. May be
|
||||
/// <code>null</code>. This contains optional metadata about what was detected about the barcode,
|
||||
/// like orientation.
|
||||
/// </returns>
|
||||
public IDictionary<ResultMetadataType, object> ResultMetadata { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the timestamp.
|
||||
/// </summary>
|
||||
public long Timestamp { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Result"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="rawBytes">The raw bytes.</param>
|
||||
/// <param name="resultPoints">The result points.</param>
|
||||
/// <param name="format">The format.</param>
|
||||
public Result(String text,
|
||||
byte[] rawBytes,
|
||||
ResultPoint[] resultPoints,
|
||||
BarcodeFormat format)
|
||||
: this(text, rawBytes, resultPoints, format, DateTime.Now.Ticks)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Result"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="rawBytes">The raw bytes.</param>
|
||||
/// <param name="resultPoints">The result points.</param>
|
||||
/// <param name="format">The format.</param>
|
||||
/// <param name="timestamp">The timestamp.</param>
|
||||
public Result(String text, byte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format, long timestamp)
|
||||
{
|
||||
if (text == null && rawBytes == null)
|
||||
{
|
||||
throw new ArgumentException("Text and bytes are null");
|
||||
}
|
||||
Text = text;
|
||||
RawBytes = rawBytes;
|
||||
ResultPoints = resultPoints;
|
||||
BarcodeFormat = format;
|
||||
ResultMetadata = null;
|
||||
Timestamp = timestamp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds one metadata to the result
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public void putMetadata(ResultMetadataType type, Object value)
|
||||
{
|
||||
if (ResultMetadata == null)
|
||||
{
|
||||
ResultMetadata = new Dictionary<ResultMetadataType, object>();
|
||||
}
|
||||
ResultMetadata[type] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a list of metadata to the result
|
||||
/// </summary>
|
||||
/// <param name="metadata">The metadata.</param>
|
||||
public void putAllMetadata(IDictionary<ResultMetadataType, object> metadata)
|
||||
{
|
||||
if (metadata != null)
|
||||
{
|
||||
if (ResultMetadata == null)
|
||||
{
|
||||
ResultMetadata = metadata;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var entry in metadata)
|
||||
ResultMetadata[entry.Key] = entry.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the result points.
|
||||
/// </summary>
|
||||
/// <param name="newPoints">The new points.</param>
|
||||
public void addResultPoints(ResultPoint[] newPoints)
|
||||
{
|
||||
var oldPoints = ResultPoints;
|
||||
if (oldPoints == null)
|
||||
{
|
||||
ResultPoints = newPoints;
|
||||
}
|
||||
else if (newPoints != null && newPoints.Length > 0)
|
||||
{
|
||||
var allPoints = new ResultPoint[oldPoints.Length + newPoints.Length];
|
||||
Array.Copy(oldPoints, 0, allPoints, 0, oldPoints.Length);
|
||||
Array.Copy(newPoints, 0, allPoints, oldPoints.Length, newPoints.Length);
|
||||
ResultPoints = allPoints;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String"/> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String"/> that represents this instance.
|
||||
/// </returns>
|
||||
public override String ToString()
|
||||
{
|
||||
if (Text == null)
|
||||
{
|
||||
return "[" + RawBytes.Length + " bytes]";
|
||||
}
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents some type of metadata about the result of the decoding that the decoder
|
||||
/// wishes to communicate back to the caller.
|
||||
/// </summary>
|
||||
/// <author>Sean Owen</author>
|
||||
public enum ResultMetadataType
|
||||
{
|
||||
/// <summary>
|
||||
/// Unspecified, application-specific metadata. Maps to an unspecified {@link Object}.
|
||||
/// </summary>
|
||||
OTHER,
|
||||
|
||||
/// <summary>
|
||||
/// Denotes the likely approximate orientation of the barcode in the image. This value
|
||||
/// is given as degrees rotated clockwise from the normal, upright orientation.
|
||||
/// For example a 1D barcode which was found by reading top-to-bottom would be
|
||||
/// said to have orientation "90". This key maps to an {@link Integer} whose
|
||||
/// value is in the range [0,360).
|
||||
/// </summary>
|
||||
ORIENTATION,
|
||||
|
||||
/// <summary>
|
||||
/// <p>2D barcode formats typically encode text, but allow for a sort of 'byte mode'
|
||||
/// which is sometimes used to encode binary data. While {@link Result} makes available
|
||||
/// the complete raw bytes in the barcode for these formats, it does not offer the bytes
|
||||
/// from the byte segments alone.</p>
|
||||
/// <p>This maps to a {@link java.util.List} of byte arrays corresponding to the
|
||||
/// raw bytes in the byte segments in the barcode, in order.</p>
|
||||
/// </summary>
|
||||
BYTE_SEGMENTS,
|
||||
|
||||
/// <summary>
|
||||
/// Error correction level used, if applicable. The value type depends on the
|
||||
/// format, but is typically a String.
|
||||
/// </summary>
|
||||
ERROR_CORRECTION_LEVEL,
|
||||
|
||||
/// <summary>
|
||||
/// For some periodicals, indicates the issue number as an {@link Integer}.
|
||||
/// </summary>
|
||||
ISSUE_NUMBER,
|
||||
|
||||
/// <summary>
|
||||
/// For some products, indicates the suggested retail price in the barcode as a
|
||||
/// formatted {@link String}.
|
||||
/// </summary>
|
||||
SUGGESTED_PRICE,
|
||||
|
||||
/// <summary>
|
||||
/// For some products, the possible country of manufacture as a {@link String} denoting the
|
||||
/// ISO country code. Some map to multiple possible countries, like "US/CA".
|
||||
/// </summary>
|
||||
POSSIBLE_COUNTRY,
|
||||
|
||||
/// <summary>
|
||||
/// For some products, the extension text
|
||||
/// </summary>
|
||||
UPC_EAN_EXTENSION,
|
||||
|
||||
/// <summary>
|
||||
/// If the code format supports structured append and
|
||||
/// the current scanned code is part of one then the
|
||||
/// sequence number is given with it.
|
||||
/// </summary>
|
||||
STRUCTURED_APPEND_SEQUENCE,
|
||||
|
||||
/// <summary>
|
||||
/// If the code format supports structured append and
|
||||
/// the current scanned code is part of one then the
|
||||
/// parity is given with it.
|
||||
/// </summary>
|
||||
STRUCTURED_APPEND_PARITY,
|
||||
|
||||
/// <summary>
|
||||
/// PDF417-specific metadata
|
||||
/// </summary>
|
||||
PDF417_EXTRA_METADATA,
|
||||
|
||||
/// <summary>
|
||||
/// Aztec-specific metadata
|
||||
/// </summary>
|
||||
AZTEC_EXTRA_METADATA
|
||||
}
|
||||
}
|
||||
+255
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This implementation can detect and decode QR Codes in an image.
|
||||
/// <author>Sean Owen</author>
|
||||
/// </summary>
|
||||
public class QRCodeReader : Reader
|
||||
{
|
||||
private static readonly ResultPoint[] NO_POINTS = new ResultPoint[0];
|
||||
|
||||
private readonly Decoder decoder = new Decoder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the decoder.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected Decoder getDecoder()
|
||||
{
|
||||
return decoder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates and decodes a QR code in an image.
|
||||
///
|
||||
/// <returns>a String representing the content encoded by the QR code</returns>
|
||||
/// </summary>
|
||||
public Result decode(BinaryBitmap image)
|
||||
{
|
||||
return decode(image, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Locates and decodes a barcode in some format within an image. This method also accepts
|
||||
/// hints, each possibly associated to some data, which may help the implementation decode.
|
||||
/// </summary>
|
||||
/// <param name="image">image of barcode to decode</param>
|
||||
/// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/>
|
||||
/// to arbitrary data. The
|
||||
/// meaning of the data depends upon the hint type. The implementation may or may not do
|
||||
/// anything with these hints.</param>
|
||||
/// <returns>
|
||||
/// String which the barcode encodes
|
||||
/// </returns>
|
||||
public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets any internal state the implementation has after a decode, to prepare it
|
||||
/// for reuse.
|
||||
/// </summary>
|
||||
public void reset()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method detects a code in a "pure" image -- that is, pure monochrome image
|
||||
/// which contains only an unrotated, unskewed, image of a code, with some white border
|
||||
/// around it. This is a specialized method that works exceptionally fast in this special
|
||||
/// case.
|
||||
///
|
||||
/// <seealso cref="ZXing.Datamatrix.DataMatrixReader.extractPureBits(BitMatrix)" />
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
{
|
||||
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)) {
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
<Reference Include="System.XML" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="3rd\zxing\BarcodeFormat.cs" />
|
||||
<Compile Include="3rd\zxing\BaseLuminanceSource.cs" />
|
||||
<Compile Include="3rd\zxing\Binarizer.cs" />
|
||||
<Compile Include="3rd\zxing\BinaryBitmap.cs" />
|
||||
<Compile Include="3rd\zxing\BitmapLuminanceSource.cs" />
|
||||
<Compile Include="3rd\zxing\common\BitArray.cs" />
|
||||
<Compile Include="3rd\zxing\common\BitMatrix.cs" />
|
||||
<Compile Include="3rd\zxing\common\BitSource.cs" />
|
||||
@@ -88,6 +93,7 @@
|
||||
<Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonEncoder.cs" />
|
||||
<Compile Include="3rd\zxing\DecodeHintType.cs" />
|
||||
<Compile Include="3rd\zxing\EncodeHintType.cs" />
|
||||
<Compile Include="3rd\zxing\LuminanceSource.cs" />
|
||||
<Compile Include="3rd\zxing\qrcode\decoder\BitMatrixParser.cs" />
|
||||
<Compile Include="3rd\zxing\qrcode\decoder\DataBlock.cs" />
|
||||
<Compile Include="3rd\zxing\qrcode\decoder\DataMask.cs" />
|
||||
@@ -112,6 +118,11 @@
|
||||
<Compile Include="3rd\zxing\qrcode\encoder\QRCode.cs" />
|
||||
<Compile Include="3rd\zxing\qrcode\encoder\QrCodeEncodingOptions.cs" />
|
||||
<Compile Include="3rd\SimpleJson.cs" />
|
||||
<Compile Include="3rd\zxing\qrcode\QRCodeReader.cs" />
|
||||
<Compile Include="3rd\zxing\Reader.cs" />
|
||||
<Compile Include="3rd\zxing\ReaderException.cs" />
|
||||
<Compile Include="3rd\zxing\Result.cs" />
|
||||
<Compile Include="3rd\zxing\ResultMetadataType.cs" />
|
||||
<Compile Include="3rd\zxing\ResultPoint.cs" />
|
||||
<Compile Include="3rd\zxing\ResultPointCallback.cs" />
|
||||
<Compile Include="3rd\zxing\WriterException.cs" />
|
||||
|
||||
Reference in New Issue
Block a user