@@ -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 | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -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; } | |||||
} | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -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 }; | |||||
} | |||||
} | |||||
} |
@@ -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(); | |||||
} | |||||
} | |||||
} |
@@ -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(); | |||||
} | |||||
} |
@@ -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 | |||||
} | |||||
} | |||||
} |
@@ -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; | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
} | |||||
} |
@@ -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(); | 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) { | private void AutoStartupItem_Click(object sender, EventArgs e) { | ||||
AutoStartupItem.Checked = !AutoStartupItem.Checked; | AutoStartupItem.Checked = !AutoStartupItem.Checked; | ||||
if (!AutoStartup.Set(AutoStartupItem.Checked)) { | if (!AutoStartup.Set(AutoStartupItem.Checked)) { | ||||
@@ -70,6 +70,11 @@ | |||||
<Reference Include="System.XML" /> | <Reference Include="System.XML" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<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\BitArray.cs" /> | ||||
<Compile Include="3rd\zxing\common\BitMatrix.cs" /> | <Compile Include="3rd\zxing\common\BitMatrix.cs" /> | ||||
<Compile Include="3rd\zxing\common\BitSource.cs" /> | <Compile Include="3rd\zxing\common\BitSource.cs" /> | ||||
@@ -88,6 +93,7 @@ | |||||
<Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonEncoder.cs" /> | <Compile Include="3rd\zxing\common\reedsolomon\ReedSolomonEncoder.cs" /> | ||||
<Compile Include="3rd\zxing\DecodeHintType.cs" /> | <Compile Include="3rd\zxing\DecodeHintType.cs" /> | ||||
<Compile Include="3rd\zxing\EncodeHintType.cs" /> | <Compile Include="3rd\zxing\EncodeHintType.cs" /> | ||||
<Compile Include="3rd\zxing\LuminanceSource.cs" /> | |||||
<Compile Include="3rd\zxing\qrcode\decoder\BitMatrixParser.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\BitMatrixParser.cs" /> | ||||
<Compile Include="3rd\zxing\qrcode\decoder\DataBlock.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\DataBlock.cs" /> | ||||
<Compile Include="3rd\zxing\qrcode\decoder\DataMask.cs" /> | <Compile Include="3rd\zxing\qrcode\decoder\DataMask.cs" /> | ||||
@@ -112,6 +118,11 @@ | |||||
<Compile Include="3rd\zxing\qrcode\encoder\QRCode.cs" /> | <Compile Include="3rd\zxing\qrcode\encoder\QRCode.cs" /> | ||||
<Compile Include="3rd\zxing\qrcode\encoder\QrCodeEncodingOptions.cs" /> | <Compile Include="3rd\zxing\qrcode\encoder\QrCodeEncodingOptions.cs" /> | ||||
<Compile Include="3rd\SimpleJson.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\ResultPoint.cs" /> | ||||
<Compile Include="3rd\zxing\ResultPointCallback.cs" /> | <Compile Include="3rd\zxing\ResultPointCallback.cs" /> | ||||
<Compile Include="3rd\zxing\WriterException.cs" /> | <Compile Include="3rd\zxing\WriterException.cs" /> | ||||