Issue 727 contributed initial Maxicode support

git-svn-id: https://zxing.googlecode.com/svn/trunk@1949 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2011-10-04 10:12:55 +00:00
parent 468ec159b8
commit d0c59c4c16
10 changed files with 586 additions and 2 deletions

View file

@ -45,11 +45,13 @@ Kevin Xue (NetDragon Websoft Inc., China)
Lachezar Dobrev Lachezar Dobrev
Luiz Silva Luiz Silva
Luka Finžgar Luka Finžgar
Manuel Kasten
Marcelo Marcelo
Mateusz Jędrasik Mateusz Jędrasik
Matrix44 Matrix44
Matthew Schulkind (Google) Matthew Schulkind (Google)
Matt York (LifeMarks) Matt York (LifeMarks)
mike32767
Mohamad Fairol Mohamad Fairol
Morgan Courbet Morgan Courbet
Nikolaos Ftylitakis Nikolaos Ftylitakis

View file

@ -56,6 +56,9 @@ public final class BarcodeFormat {
/** ITF (Interleaved Two of Five) 1D format. */ /** ITF (Interleaved Two of Five) 1D format. */
public static final BarcodeFormat ITF = new BarcodeFormat("ITF"); public static final BarcodeFormat ITF = new BarcodeFormat("ITF");
/** MaxiCode 2D barcode format. */
public static final BarcodeFormat MAXICODE = new BarcodeFormat("MAXICODE");
/** PDF417 format. */ /** PDF417 format. */
public static final BarcodeFormat PDF_417 = new BarcodeFormat("PDF_417"); public static final BarcodeFormat PDF_417 = new BarcodeFormat("PDF_417");

View file

@ -21,6 +21,7 @@ import com.google.zxing.datamatrix.DataMatrixReader;
import com.google.zxing.oned.MultiFormatOneDReader; import com.google.zxing.oned.MultiFormatOneDReader;
import com.google.zxing.pdf417.PDF417Reader; import com.google.zxing.pdf417.PDF417Reader;
import com.google.zxing.qrcode.QRCodeReader; import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.maxicode.MaxiCodeReader;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Vector; import java.util.Vector;
@ -122,7 +123,10 @@ public final class MultiFormatReader implements Reader {
} }
if (formats.contains(BarcodeFormat.PDF_417)) { if (formats.contains(BarcodeFormat.PDF_417)) {
readers.addElement(new PDF417Reader()); readers.addElement(new PDF417Reader());
} }
if (formats.contains(BarcodeFormat.MAXICODE)) {
readers.addElement(new MaxiCodeReader());
}
// At end in "try harder" mode // At end in "try harder" mode
if (addOneDReader && tryHarder) { if (addOneDReader && tryHarder) {
readers.addElement(new MultiFormatOneDReader(hints)); readers.addElement(new MultiFormatOneDReader(hints));
@ -137,6 +141,7 @@ public final class MultiFormatReader implements Reader {
readers.addElement(new DataMatrixReader()); readers.addElement(new DataMatrixReader());
readers.addElement(new AztecReader()); readers.addElement(new AztecReader());
readers.addElement(new PDF417Reader()); readers.addElement(new PDF417Reader());
readers.addElement(new MaxiCodeReader());
if (tryHarder) { if (tryHarder) {
readers.addElement(new MultiFormatOneDReader(hints)); readers.addElement(new MultiFormatOneDReader(hints));

View file

@ -144,6 +144,59 @@ public final class BitMatrix {
return row; return row;
} }
/**
* This is useful in detecting the enclosing rectangle of a 'pure' barcode.
*
* @return {left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white
*/
public int[] getEnclosingRectangle() {
int left = width;
int top = height;
int right = -1;
int bottom = -1;
for (int y = 0; y < height; y++) {
for (int x32 = 0; x32 < rowSize; x32++) {
int theBits = bits[y * rowSize + x32];
if (theBits != 0) {
if (y < top) {
top = y;
}
if (y > bottom) {
bottom = y;
}
if (x32 * 32 < left) {
int bit = 0;
while ((theBits << (31 - bit)) == 0) {
bit++;
}
if ((x32 * 32 + bit) < left) {
left = x32 * 32 + bit;
}
}
if (x32 * 32 + 31 > right) {
int bit = 31;
while ((theBits >>> bit) == 0) {
bit--;
}
if ((x32 * 32 + bit) > right) {
right = x32 * 32 + bit;
}
}
}
}
}
int width = right - left;
int height = bottom - top;
if (width < 0 || height < 0) {
return null;
}
return new int[] {left, top, width, height};
}
/** /**
* This is useful in detecting a corner of a 'pure' barcode. * This is useful in detecting a corner of a 'pure' barcode.
* *

View file

@ -36,6 +36,7 @@ public final class GenericGF {
public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1 public static final GenericGF QR_CODE_FIELD_256 = new GenericGF(0x011D, 256); // x^8 + x^4 + x^3 + x^2 + 1
public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1 public static final GenericGF DATA_MATRIX_FIELD_256 = new GenericGF(0x012D, 256); // x^8 + x^5 + x^3 + x^2 + 1
public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256; public static final GenericGF AZTEC_DATA_8 = DATA_MATRIX_FIELD_256;
public static final GenericGF MAXICODE_FIELD_64 = AZTEC_DATA_6;
private static final int INITIALIZATION_THRESHOLD = 0; private static final int INITIALIZATION_THRESHOLD = 0;
@ -59,7 +60,7 @@ public final class GenericGF {
this.size = size; this.size = size;
if (size <= INITIALIZATION_THRESHOLD){ if (size <= INITIALIZATION_THRESHOLD){
initialize(); initialize();
} }
} }

View file

@ -0,0 +1,121 @@
/*
* Copyright 2011 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.
*/
package com.google.zxing.maxicode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Reader;
import com.google.zxing.Result;
import com.google.zxing.ResultMetadataType;
import com.google.zxing.ResultPoint;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.maxicode.decoder.Decoder;
import java.util.Hashtable;
/**
* This implementation can detect and decode a MaxiCode in an image.
*/
public final class MaxiCodeReader implements Reader {
private static final ResultPoint[] NO_POINTS = new ResultPoint[0];
private static final int MATRIX_WIDTH = 30;
private static final int MATRIX_HEIGHT = 33;
private final Decoder decoder = new Decoder();
Decoder getDecoder() {
return decoder;
}
/**
* Locates and decodes a MaxiCode in an image.
*
* @return a String representing the content encoded by the MaxiCode
* @throws NotFoundException if a MaxiCode cannot be found
* @throws FormatException if a MaxiCode cannot be decoded
* @throws ChecksumException if error correction fails
*/
public Result decode(BinaryBitmap image) throws NotFoundException, ChecksumException, FormatException {
return decode(image, null);
}
public Result decode(BinaryBitmap image, Hashtable hints)
throws NotFoundException, ChecksumException, FormatException {
DecoderResult decoderResult;
if (hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE)) {
BitMatrix bits = extractPureBits(image.getBlackMatrix());
decoderResult = decoder.decode(bits, hints);
} else {
throw NotFoundException.getNotFoundInstance();
}
ResultPoint[] points = NO_POINTS;
Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.MAXICODE);
if (decoderResult.getECLevel() != null) {
result.putMetadata(ResultMetadataType.ERROR_CORRECTION_LEVEL, decoderResult.getECLevel());
}
return result;
}
public void reset() {
// do nothing
}
/**
* This method detects a code in a "pure" image -- that is, pure monochrome image
* which contains only an unrotated, unskewed, image of a code, with some white border
* around it. This is a specialized method that works exceptionally fast in this special
* case.
*
* @see com.google.zxing.pdf417.PDF417Reader#extractPureBits(BitMatrix)
* @see com.google.zxing.datamatrix.DataMatrixReader#extractPureBits(BitMatrix)
* @see com.google.zxing.qrcode.QRCodeReader#extractPureBits(BitMatrix)
*/
private static BitMatrix extractPureBits(BitMatrix image) throws NotFoundException {
int[] enclosingRectangle = image.getEnclosingRectangle();
if (enclosingRectangle == null) {
throw NotFoundException.getNotFoundInstance();
}
int left = enclosingRectangle[0];
int top = enclosingRectangle[1];
int width = enclosingRectangle[2];
int height = enclosingRectangle[3];
// Now just read off the bits
BitMatrix bits = new BitMatrix(MATRIX_WIDTH, MATRIX_HEIGHT);
for (int y = 0; y < MATRIX_HEIGHT; y++) {
int iy = top + (y * height + height / 2) / MATRIX_HEIGHT;
for (int x = 0; x < MATRIX_WIDTH; x++) {
int ix = left + (x * width + width / 2 + (y & 0x01) * width / 2) / MATRIX_WIDTH;
if (image.get(ix, iy)) {
bits.set(x, y);
}
}
}
return bits;
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright 2011 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.
*/
package com.google.zxing.maxicode.decoder;
import com.google.zxing.FormatException;
import com.google.zxing.common.BitMatrix;
/**
* @author mike32767
* @author Manuel Kasten
*/
final class BitMatrixParser {
private static final int[][] BITNR = {
{121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2},
{123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3},
{125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817},
{283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3},
{285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820},
{287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3},
{289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823},
{291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3},
{293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826},
{409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3},
{411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829},
{413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3},
{415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832},
{417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3},
{419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835},
{481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3},
{483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838},
{485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3},
{487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841},
{489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3},
{491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844},
{559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3},
{561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847},
{563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3},
{565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850},
{567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3},
{569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853},
{727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3},
{729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856},
{731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3},
{733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859},
{735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3},
{737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862}
};
private final BitMatrix bitMatrix;
/**
* @param bitMatrix {@link BitMatrix} to parse
* @throws FormatException if height is not 33 or width is not 30
*/
BitMatrixParser(BitMatrix bitMatrix) {
this.bitMatrix = bitMatrix;
}
byte[] readCodewords() {
byte[] result = new byte[144];
int height = bitMatrix.getHeight();
int width = bitMatrix.getWidth();
for (int y = 0; y < height; y++) {
int[] bitnrRow = BITNR[y];
for (int x = 0; x < width; x++) {
int bit = bitnrRow[x];
if (bit >= 0 && bitMatrix.get(x, y)) {
result[bit / 6] |= (byte) (1 << (5 - (bit % 6)));
}
}
}
return result;
}
}

View file

@ -0,0 +1,192 @@
/*
* Copyright 2011 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.
*/
package com.google.zxing.maxicode.decoder;
import com.google.zxing.common.DecoderResult;
import java.text.DecimalFormat;
/**
* <p>MaxiCodes can encode text or structured information as bits in one of several modes,
* with multiple character sets in one code. This class decodes the bits back into text.</p>
*
* @author mike32767
* @author Manuel Kasten
*/
final class DecodedBitStreamParser {
private static final char SHIFTA = '\uFFF0';
private static final char SHIFTB = '\uFFF1';
private static final char SHIFTC = '\uFFF2';
private static final char SHIFTD = '\uFFF3';
private static final char SHIFTE = '\uFFF4';
private static final char TWOSHIFTA = '\uFFF5';
private static final char THREESHIFTA = '\uFFF6';
private static final char LATCHA = '\uFFF7';
private static final char LATCHB = '\uFFF8';
private static final char LOCK = '\uFFF9';
private static final char ECI = '\uFFFA';
private static final char NS = '\uFFFB';
private static final char PAD = '\uFFFC';
private static final char FS = '\u001C';
private static final char GS = '\u001D';
private static final char RS = '\u001E';
private static final DecimalFormat NINE_DIGITS = new DecimalFormat("000000000");
private static final DecimalFormat THREE_DIGITS = new DecimalFormat("000");
private static final String[] SETS = {
"\nABCDEFGHIJKLMNOPQRSTUVWXYZ"+ECI+FS+GS+RS+NS+' '+PAD+"\"#$%&'()*+,-./0123456789:"+SHIFTB+SHIFTC+SHIFTD+SHIFTE+LATCHB,
"`abcdefghijklmnopqrstuvwxyz"+ECI+FS+GS+RS+NS+'{'+PAD+"}~\u007F;<=>?[\\]^_ ,./:@!|"+PAD+TWOSHIFTA+THREESHIFTA+PAD+SHIFTA+SHIFTC+SHIFTD+SHIFTE+LATCHA,
"\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9\u00CA\u00CB\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4\u00D5\u00D6\u00D7\u00D8\u00D9\u00DA"+ECI+FS+GS+RS+"\u00DB\u00DC\u00DD\u00DE\u00DF\u00AA\u00AC\u00B1\u00B2\u00B3\u00B5\u00B9\u00BA\u00BC\u00BD\u00BE\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089"+LATCHA+' '+LOCK+SHIFTD+SHIFTE+LATCHB,
"\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8\u00E9\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2\u00F3\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9\u00FA"+ECI+FS+GS+RS+NS+"\u00FB\u00FC\u00FD\u00FE\u00FF\u00A1\u00A8\u00AB\u00AF\u00B0\u00B4\u00B7\u00B8\u00BB\u00BF\u008A\u008B\u008C\u008D\u008E\u008F\u0090\u0091\u0092\u0093\u0094"+LATCHA+' '+SHIFTC+LOCK+SHIFTE+LATCHB,
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A"+ECI+PAD+PAD+'\u001B'+NS+FS+GS+RS+"\u001F\u009F\u00A0\u00A2\u00A3\u00A4\u00A5\u00A6\u00A7\u00A9\u00AD\u00AE\u00B6\u0095\u0096\u0097\u0098\u0099\u009A\u009B\u009C\u009D\u009E"+LATCHA+' '+SHIFTC+SHIFTD+LOCK+LATCHB,
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\n\u000B\u000C\r\u000E\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F\u0020\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B\u003C\u003D\u003E\u003F"
};
private DecodedBitStreamParser() {
}
static DecoderResult decode(byte[] bytes, int mode) {
StringBuffer result = new StringBuffer(144);
switch (mode) {
case 2:
case 3:
String postcode;
if (mode == 2) {
int pc = getPostCode2(bytes);
DecimalFormat df = new DecimalFormat("0000000000".substring(0, getPostCode2Length(bytes)));
postcode = df.format(pc);
} else {
postcode = getPostCode3(bytes);
}
String country = THREE_DIGITS.format(getCountry(bytes));
String service = THREE_DIGITS.format(getServiceClass(bytes));
result.append(getMessage(bytes, 10, 84));
if (result.toString().startsWith("[)>"+RS+"01"+GS)) {
result.insert(9, postcode + GS + country + GS + service + GS);
} else {
result.insert(0, postcode + GS + country + GS + service + GS);
}
break;
case 4:
result.append(getMessage(bytes, 1, 93));
break;
case 5:
result.append(getMessage(bytes, 1, 77));
break;
}
return new DecoderResult(bytes, result.toString(), null, String.valueOf(mode));
}
private static int getBit(int bit, byte[] bytes) {
bit--;
return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1;
}
private static int getInt(byte[] bytes, byte[] x) {
int val = 0;
for (int i = 0; i < x.length; i++) {
val += getBit(x[i], bytes) << (x.length - i - 1);
}
return val;
}
private static int getCountry(byte[] bytes) {
return getInt(bytes, new byte[] {53, 54, 43, 44, 45, 46, 47, 48, 37, 38});
}
private static int getServiceClass(byte[] bytes) {
return getInt(bytes, new byte[] {55, 56, 57, 58, 59, 60, 49, 50, 51, 52});
}
private static int getPostCode2Length(byte[] bytes) {
return getInt(bytes, new byte[] {39, 40, 41, 42, 31, 32});
}
private static int getPostCode2(byte[] bytes) {
return getInt(bytes, new byte[] {33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19,
20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2});
}
private static String getPostCode3(byte[] bytes) {
return String.valueOf(
new char[] {
SETS[0].charAt(getInt(bytes, new byte[] {39, 40, 41, 42, 31, 32})),
SETS[0].charAt(getInt(bytes, new byte[] {33, 34, 35, 36, 25, 26})),
SETS[0].charAt(getInt(bytes, new byte[] {27, 28, 29, 30, 19, 20})),
SETS[0].charAt(getInt(bytes, new byte[] {21, 22, 23, 24, 13, 14})),
SETS[0].charAt(getInt(bytes, new byte[] {15, 16, 17, 18, 7, 8})),
SETS[0].charAt(getInt(bytes, new byte[] { 9, 10, 11, 12, 1, 2})),
}
);
}
private static String getMessage(byte[] bytes, int start, int len) {
StringBuffer sb = new StringBuffer();
int shift = -1;
int set = 0;
int lastset = 0;
for (int i = start; i < start + len; i++) {
char c = SETS[set].charAt(bytes[i]);
switch (c) {
case LATCHA:
set = 0;
shift = -1;
break;
case LATCHB:
set = 1;
shift = -1;
break;
case SHIFTA:
case SHIFTB:
case SHIFTC:
case SHIFTD:
case SHIFTE:
lastset = set;
set = c - SHIFTA;
shift = 1;
break;
case TWOSHIFTA:
lastset = set;
set = 0;
shift = 2;
break;
case THREESHIFTA:
lastset = set;
set = 0;
shift = 3;
break;
case NS:
int nsval = (bytes[++i] << 24) + (bytes[++i] << 18) + (bytes[++i] << 12) + (bytes[++i] << 6) + bytes[++i];
sb.append(NINE_DIGITS.format(nsval));
break;
case LOCK:
shift = -1;
break;
default:
sb.append(c);
}
if (shift-- == 0) {
set = lastset;
}
}
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == PAD) {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright 2011 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.
*/
package com.google.zxing.maxicode.decoder;
import com.google.zxing.ChecksumException;
import com.google.zxing.FormatException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.DecoderResult;
import com.google.zxing.common.reedsolomon.GenericGF;
import com.google.zxing.common.reedsolomon.ReedSolomonDecoder;
import com.google.zxing.common.reedsolomon.ReedSolomonException;
import java.util.Hashtable;
/**
* <p>The main class which implements MaxiCode decoding -- as opposed to locating and extracting
* the MaxiCode from an image.</p>
*
* @author Manuel Kasten
*/
public final class Decoder {
private static final int ALL = 0;
private static final int EVEN = 1;
private static final int ODD = 2;
private final ReedSolomonDecoder rsDecoder;
public Decoder() {
rsDecoder = new ReedSolomonDecoder(GenericGF.MAXICODE_FIELD_64);
}
public DecoderResult decode(BitMatrix bits) throws ChecksumException, FormatException {
return decode(bits, null);
}
public DecoderResult decode(BitMatrix bits, Hashtable hints) throws FormatException, ChecksumException {
BitMatrixParser parser = new BitMatrixParser(bits);
byte[] codewords = parser.readCodewords();
correctErrors(codewords, 0, 10, 10, ALL);
int mode = codewords[0] & 0x0F;
byte[] datawords;
switch (mode) {
case 2:
case 3:
case 4:
correctErrors(codewords, 20, 84, 40, EVEN);
correctErrors(codewords, 20, 84, 40, ODD);
datawords = new byte[94];
break;
case 5:
correctErrors(codewords, 20, 68, 56, EVEN);
correctErrors(codewords, 20, 68, 56, ODD);
datawords = new byte[78];
break;
default:
throw FormatException.getFormatInstance();
}
for (int i = 0; i < 10; i++) {
datawords[i] = codewords[i];
}
for (int i = 20; i < datawords.length + 10; i++) {
datawords[i - 10] = codewords[i];
}
return DecodedBitStreamParser.decode(datawords, mode);
}
private void correctErrors(byte[] codewordBytes,
int start,
int dataCodewords,
int ecCodewords,
int mode) throws ChecksumException {
int codewords = dataCodewords + ecCodewords;
// in EVEN or ODD mode only half the codewords
int divisor = mode == ALL ? 1 : 2;
// First read into an array of ints
int[] codewordsInts = new int[codewords / divisor];
for (int i = 0; i < codewords; i++) {
if ((mode == ALL) || (i % 2 == (mode - 1))) {
codewordsInts[i / divisor] = codewordBytes[i + start] & 0xFF;
}
}
try {
rsDecoder.decode(codewordsInts, ecCodewords / divisor);
} catch (ReedSolomonException rse) {
throw ChecksumException.getChecksumInstance();
}
// Copy back into array of bytes -- only need to worry about the bytes that were data
// We don't care about errors in the error-correction codewords
for (int i = 0; i < dataCodewords; i++) {
if ((mode == ALL) || (i % 2 == (mode - 1))) {
codewordBytes[i + start] = (byte) codewordsInts[i / divisor];
}
}
}
}

View file

@ -163,6 +163,7 @@ public final class CommandLineRunner {
vector.addElement(BarcodeFormat.AZTEC); vector.addElement(BarcodeFormat.AZTEC);
vector.addElement(BarcodeFormat.PDF_417); vector.addElement(BarcodeFormat.PDF_417);
vector.addElement(BarcodeFormat.CODABAR); vector.addElement(BarcodeFormat.CODABAR);
vector.addElement(BarcodeFormat.MAXICODE);
} }
hints.put(DecodeHintType.POSSIBLE_FORMATS, vector); hints.put(DecodeHintType.POSSIBLE_FORMATS, vector);
if (config.isTryHarder()) { if (config.isTryHarder()) {