@@ -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(); | |||
} | |||
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" /> | |||