content: package com.lvrenyang.qrcode;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * QRコード. <br/>
   * ■使い方 <br/>
   * (1) 誤り訂正レベル、データ等、諸パラメータを設定します。 <br/>
   * (2) make() を呼び出してQRコードを作成します。 <br/>
   * (3) getModuleCount() と isDark() で、QRコードのデータを取得します。 <br/>
   * 
   * @author Kazuhiko Arase
   */
  public class QRCode {
  
  	private static final int PAD0 = 0xEC;
  
  	private static final int PAD1 = 0x11;
  
  	private int typeNumber;
  
  	private Boolean[][] modules;
  
  	private int moduleCount;
  
  	private int errorCorrectLevel;
  
  	private List<QRData> qrDataList;
  
  	/**
  	 * コンストラクタ <br>
  	 * 型番1, 誤り訂正レベルH のQRコードのインスタンスを生成します。
  	 * 
  	 * @see ErrorCorrectLevel
  	 */
  	public QRCode() {
  		this.typeNumber = 1;
  		this.errorCorrectLevel = ErrorCorrectLevel.H;
  		this.qrDataList = new ArrayList<QRData>(1);
  	}
  
  	/**
  	 * 型番を取得する。
  	 * 
  	 * @return 型番
  	 */
  	public int getTypeNumber() {
  		return typeNumber;
  	}
  
  	/**
  	 * 型番を設定する。
  	 * 
  	 * @param typeNumber
  	 *            型番
  	 */
  	public void setTypeNumber(int typeNumber) {
  		this.typeNumber = typeNumber;
  	}
  
  	/**
  	 * 誤り訂正レベルを取得する。
  	 * 
  	 * @return 誤り訂正レベル
  	 * @see ErrorCorrectLevel
  	 */
  	public int getErrorCorrectLevel() {
  		return errorCorrectLevel;
  	}
  
  	/**
  	 * 誤り訂正レベルを設定する。
  	 * 
  	 * @param errorCorrectLevel
  	 *            誤り訂正レベル
  	 * @see ErrorCorrectLevel
  	 */
  	public void setErrorCorrectLevel(int errorCorrectLevel) {
  		this.errorCorrectLevel = errorCorrectLevel;
  	}
  
  	/**
  	 * データを追加する。
  	 * 
  	 * @param data
  	 *            データ
  	 */
  	public void addData(String data) {
  		addData(data, QRUtil.getMode(data));
  	}
  
  	/**
  	 * モードを指定してデータを追加する。
  	 * 
  	 * @param data
  	 *            データ
  	 * @param mode
  	 *            モード
  	 * @see Mode
  	 */
  	public void addData(String data, int mode) {
  
  		switch (mode) {
  
  		case Mode.MODE_NUMBER:
  			addData(new QRNumber(data));
  			break;
  
  		case Mode.MODE_ALPHA_NUM:
  			addData(new QRAlphaNum(data));
  			break;
  
  		case Mode.MODE_8BIT_BYTE:
  			addData(new QR8BitByte(data));
  			break;
  
  		case Mode.MODE_KANJI:
  			addData(new QRKanji(data));
  			break;
  
  		default:
  			throw new IllegalArgumentException("mode:" + mode);
  		}
  	}
  
  	/**
  	 * データをクリアする。 <br/>
  	 * addData で追加されたデータをクリアします。
  	 */
  	public void clearData() {
  		qrDataList.clear();
  	}
  
  	protected void addData(QRData qrData) {
  		qrDataList.add(qrData);
  	}
  
  	protected int getDataCount() {
  		return qrDataList.size();
  	}
  
  	protected QRData getData(int index) {
  		return qrDataList.get(index);
  	}
  
  	/**
  	 * 暗モジュールかどうかを取得する。
  	 * 
  	 * @param row
  	 *            行 (0 ～ モジュール数 - 1)
  	 * @param col
  	 *            列 (0 ～ モジュール数 - 1)
  	 */
  	public boolean isDark(int row, int col) {
  		if (modules[row][col] != null) {
  			return modules[row][col].booleanValue();
  		} else {
  			return false;
  		}
  	}
  
  	/**
  	 * モジュール数を取得する。
  	 */
  	public int getModuleCount() {
  		return moduleCount;
  	}
  
  	/**
  	 * QRコードを作成する。
  	 */
  	public void make() {
  		make(false, getBestMaskPattern());
  	}
  
  	/**
  	 * 在调用make之后，调用该函数获取QR码的点阵图数据。
  	 * 
  	 * @return
  	 */
  	public Boolean[][] getModules() {
  		return modules;
  	}
  
  	private int getBestMaskPattern() {
  
  		int minLostPoint = 0;
  		int pattern = 0;
  
  		for (int i = 0; i < 8; i++) {
  
  			make(true, i);
  
  			int lostPoint = QRUtil.getLostPoint(this);
  
  			if (i == 0 || minLostPoint > lostPoint) {
  				minLostPoint = lostPoint;
  				pattern = i;
  			}
  		}
  
  		return pattern;
  	}
  
  	/**
  	 * 
  	 */
  	private void make(boolean test, int maskPattern) {
  
  		// モジュール初期化
  		moduleCount = typeNumber * 4 + 17;
  		modules = new Boolean[moduleCount][moduleCount];
  
  		// 位置検出パターン及び分離パターンを設定
  		setupPositionProbePattern(0, 0);
  		setupPositionProbePattern(moduleCount - 7, 0);
  		setupPositionProbePattern(0, moduleCount - 7);
  
  		setupPositionAdjustPattern();
  		setupTimingPattern();
  
  		setupTypeInfo(test, maskPattern);
  
  		if (typeNumber >= 7) {
  			setupTypeNumber(test);
  		}
  
  		QRData[] dataArray = qrDataList.toArray(new QRData[qrDataList.size()]);
  
  		byte[] data = createData(typeNumber, errorCorrectLevel, dataArray);
  
  		mapData(data, maskPattern);
  	}
  
  	private void mapData(byte[] data, int maskPattern) {
  
  		int inc = -1;
  		int row = moduleCount - 1;
  		int bitIndex = 7;
  		int byteIndex = 0;
  
  		for (int col = moduleCount - 1; col > 0; col -= 2) {
  
  			if (col == 6)
  				col--;
  
  			while (true) {
  
  				for (int c = 0; c < 2; c++) {
  
  					if (modules[row][col - c] == null) {
  
  						boolean dark = false;
  
  						if (byteIndex < data.length) {
  							dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
  						}
  
  						boolean mask = QRUtil
  								.getMask(maskPattern, row, col - c);
  
  						if (mask) {
  							dark = !dark;
  						}
  
  						modules[row][col - c] = Boolean.valueOf(dark);
  						bitIndex--;
  
  						if (bitIndex == -1) {
  							byteIndex++;
  							bitIndex = 7;
  						}
  					}
  				}
  
  				row += inc;
  
  				if (row < 0 || moduleCount <= row) {
  					row -= inc;
  					inc = -inc;
  					break;
  				}
  			}
  		}
  
  	}
  
  	/**
  	 * 位置合わせパターンを設定
  	 */
  	private void setupPositionAdjustPattern() {
  
  		int[] pos = QRUtil.getPatternPosition(typeNumber);
  
  		for (int i = 0; i < pos.length; i++) {
  
  			for (int j = 0; j < pos.length; j++) {
  
  				int row = pos[i];
  				int col = pos[j];
  
  				if (modules[row][col] != null) {
  					continue;
  				}
  
  				for (int r = -2; r <= 2; r++) {
  
  					for (int c = -2; c <= 2; c++) {
  
  						if (r == -2 || r == 2 || c == -2 || c == 2
  								|| (r == 0 && c == 0)) {
  							modules[row + r][col + c] = Boolean.valueOf(true);
  						} else {
  							modules[row + r][col + c] = Boolean.valueOf(false);
  						}
  					}
  				}
  
  			}
  		}
  	}
  
  	/**
  	 * 位置検出パターンを設定
  	 */
  	private void setupPositionProbePattern(int row, int col) {
  
  		for (int r = -1; r <= 7; r++) {
  
  			for (int c = -1; c <= 7; c++) {
  
  				if (row + r <= -1 || moduleCount <= row + r || col + c <= -1
  						|| moduleCount <= col + c) {
  					continue;
  				}
  
  				if ((0 <= r && r <= 6 && (c == 0 || c == 6))
  						|| (0 <= c && c <= 6 && (r == 0 || r == 6))
  						|| (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
  					modules[row + r][col + c] = Boolean.valueOf(true);
  				} else {
  					modules[row + r][col + c] = Boolean.valueOf(false);
  				}
  			}
  		}
  	}
  
  	/**
  	 * タイミングパターンを設定
  	 */
  	private void setupTimingPattern() {
  		for (int r = 8; r < moduleCount - 8; r++) {
  			if (modules[r][6] != null) {
  				continue;
  			}
  			modules[r][6] = Boolean.valueOf(r % 2 == 0);
  		}
  		for (int c = 8; c < moduleCount - 8; c++) {
  			if (modules[6][c] != null) {
  				continue;
  			}
  			modules[6][c] = Boolean.valueOf(c % 2 == 0);
  		}
  	}
  
  	/**
  	 * 型番を設定
  	 */
  	private void setupTypeNumber(boolean test) {
  
  		int bits = QRUtil.getBCHTypeNumber(typeNumber);
  
  		for (int i = 0; i < 18; i++) {
  			Boolean mod = Boolean.valueOf(!test && ((bits >> i) & 1) == 1);
  			modules[i / 3][i % 3 + moduleCount - 8 - 3] = mod;
  		}
  
  		for (int i = 0; i < 18; i++) {
  			Boolean mod = Boolean.valueOf(!test && ((bits >> i) & 1) == 1);
  			modules[i % 3 + moduleCount - 8 - 3][i / 3] = mod;
  		}
  	}
  
  	/**
  	 * 形式情報を設定
  	 */
  	private void setupTypeInfo(boolean test, int maskPattern) {
  
  		int data = (errorCorrectLevel << 3) | maskPattern;
  		int bits = QRUtil.getBCHTypeInfo(data);
  
  		// 縦方向
  		for (int i = 0; i < 15; i++) {
  
  			Boolean mod = Boolean.valueOf(!test && ((bits >> i) & 1) == 1);
  
  			if (i < 6) {
  				modules[i][8] = mod;
  			} else if (i < 8) {
  				modules[i + 1][8] = mod;
  			} else {
  				modules[moduleCount - 15 + i][8] = mod;
  			}
  		}
  
  		// 横方向
  		for (int i = 0; i < 15; i++) {
  
  			Boolean mod = Boolean.valueOf(!test && ((bits >> i) & 1) == 1);
  
  			if (i < 8) {
  				modules[8][moduleCount - i - 1] = mod;
  			} else if (i < 9) {
  				modules[8][15 - i - 1 + 1] = mod;
  			} else {
  				modules[8][15 - i - 1] = mod;
  			}
  		}
  
  		// 固定
  		modules[moduleCount - 8][8] = Boolean.valueOf(!test);
  
  	}
  
  	public static byte[] createData(int typeNumber, int errorCorrectLevel,
  			QRData[] dataArray) {
  
  		RSBlock[] rsBlocks = RSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
  
  		BitBuffer buffer = new BitBuffer();
  
  		for (int i = 0; i < dataArray.length; i++) {
  			QRData data = dataArray[i];
  			buffer.put(data.getMode(), 4);
  			buffer.put(data.getLength(), data.getLengthInBits(typeNumber));
  			data.write(buffer);
  		}
  
  		// 最大データ数を計算
  		int totalDataCount = 0;
  		for (int i = 0; i < rsBlocks.length; i++) {
  			totalDataCount += rsBlocks[i].getDataCount();
  		}
  
  		if (buffer.getLengthInBits() > totalDataCount * 8) {
  			throw new IllegalArgumentException("code length overflow. ("
  					+ buffer.getLengthInBits() + ">" + totalDataCount * 8 + ")");
  		}
  
  		// 終端コード
  		if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
  			buffer.put(0, 4);
  		}
  
  		// padding
  		while (buffer.getLengthInBits() % 8 != 0) {
  			buffer.put(false);
  		}
  
  		// padding
  		while (true) {
  
  			if (buffer.getLengthInBits() >= totalDataCount * 8) {
  				break;
  			}
  			buffer.put(PAD0, 8);
  
  			if (buffer.getLengthInBits() >= totalDataCount * 8) {
  				break;
  			}
  			buffer.put(PAD1, 8);
  		}
  
  		return createBytes(buffer, rsBlocks);
  	}
  
  	private static byte[] createBytes(BitBuffer buffer, RSBlock[] rsBlocks) {
  
  		int offset = 0;
  
  		int maxDcCount = 0;
  		int maxEcCount = 0;
  
  		int[][] dcdata = new int[rsBlocks.length][];
  		int[][] ecdata = new int[rsBlocks.length][];
  
  		for (int r = 0; r < rsBlocks.length; r++) {
  
  			int dcCount = rsBlocks[r].getDataCount();
  			int ecCount = rsBlocks[r].getTotalCount() - dcCount;
  
  			maxDcCount = Math.max(maxDcCount, dcCount);
  			maxEcCount = Math.max(maxEcCount, ecCount);
  
  			dcdata[r] = new int[dcCount];
  			for (int i = 0; i < dcdata[r].length; i++) {
  				dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
  			}
  			offset += dcCount;
  
  			Polynomial rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
  			Polynomial rawPoly = new Polynomial(dcdata[r],
  					rsPoly.getLength() - 1);
  
  			Polynomial modPoly = rawPoly.mod(rsPoly);
  			ecdata[r] = new int[rsPoly.getLength() - 1];
  			for (int i = 0; i < ecdata[r].length; i++) {
  				int modIndex = i + modPoly.getLength() - ecdata[r].length;
  				ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
  			}
  
  		}
  
  		int totalCodeCount = 0;
  		for (int i = 0; i < rsBlocks.length; i++) {
  			totalCodeCount += rsBlocks[i].getTotalCount();
  		}
  
  		byte[] data = new byte[totalCodeCount];
  
  		int index = 0;
  
  		for (int i = 0; i < maxDcCount; i++) {
  			for (int r = 0; r < rsBlocks.length; r++) {
  				if (i < dcdata[r].length) {
  					data[index++] = (byte) dcdata[r][i];
  				}
  			}
  		}
  
  		for (int i = 0; i < maxEcCount; i++) {
  			for (int r = 0; r < rsBlocks.length; r++) {
  				if (i < ecdata[r].length) {
  					data[index++] = (byte) ecdata[r][i];
  				}
  			}
  		}
  
  		return data;
  
  	}
  
  	/**
  	 * 最小の型番となる QRCode を作成する。
  	 * 
  	 * @param data
  	 *            データ
  	 * @param errorCorrectLevel
  	 *            誤り訂正レベル
  	 */
  	public static QRCode getMinimumQRCode(String data, int errorCorrectLevel) {
  
  		int mode = QRUtil.getMode(data);
  
  		QRCode qr = new QRCode();
  		qr.setErrorCorrectLevel(errorCorrectLevel);
  		qr.addData(data, mode);
  
  		int length = qr.getData(0).getLength();
  
  		for (int typeNumber = 1; typeNumber <= 10; typeNumber++) {
  			if (length <= QRUtil.getMaxLength(typeNumber, mode,
  					errorCorrectLevel)) {
  				qr.setTypeNumber(typeNumber);
  				qr.make();
  				return qr;
  			}
  		}
  
  		return null;
  	}
  
  }
  