All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.chart.Code128ABC Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20240823
Show newest version
package com.scudata.chart;


import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.OneDimensionalCodeWriter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
 * This object renders a CODE128 code as a {@link BitMatrix}.
 *
 * @author [email protected] (Erik Barbara)
 */
public final class Code128ABC extends OneDimensionalCodeWriter {
	public static final String TYPE_AUTO = "Auto";
	public static final String TYPE_A = "A";
	public static final String TYPE_B = "B";
	public static final String TYPE_C = "C";
	private String type = TYPE_AUTO;

	
	private static final int CODE_START_A = 103;
	private static final int CODE_START_B = 104;
	private static final int CODE_START_C = 105;
	private static final int CODE_CODE_A = 101;
	private static final int CODE_CODE_B = 100;
	private static final int CODE_CODE_C = 99;
	private static final int CODE_STOP = 106;

	// Dummy characters used to specify control characters in input
	private static final char ESCAPE_FNC_1 = '\u00f1';
	private static final char ESCAPE_FNC_2 = '\u00f2';
	private static final char ESCAPE_FNC_3 = '\u00f3';
	private static final char ESCAPE_FNC_4 = '\u00f4';

	private static final int CODE_FNC_1 = 102; // Code A, Code B, Code C
	private static final int CODE_FNC_2 = 97; // Code A, Code B
	private static final int CODE_FNC_3 = 96; // Code A, Code B
	private static final int CODE_FNC_4_A = 101; // Code A
	private static final int CODE_FNC_4_B = 100; // Code B

	// Results of minimal lookahead for code C
	private enum CType {
		UNCODABLE, ONE_DIGIT, TWO_DIGITS, FNC_1
	}

	public Code128ABC(int type) {
		switch(type) {
		case Consts.TYPE_CODE128A:
			this.type = TYPE_A;
			break;
		case Consts.TYPE_CODE128B:
			this.type = TYPE_B;
			break;
		default:
			this.type = TYPE_C;
		}
	}

	@Override
	public BitMatrix encode(String contents, BarcodeFormat format, int width,
			int height, Map hints) throws WriterException {
		if (format != BarcodeFormat.CODE_128) {
			throw new IllegalArgumentException(
					"Can only encode CODE_128, but got " + format);
		}
		return super.encode(contents, format, width, height, hints);
	}

	@Override
	public boolean[] encode(String contents) {
		int length = contents.length();
		// Check length
		if (length < 1 ) {//|| length > 80
			throw new IllegalArgumentException(
					"Contents length should be between 1 and 80 characters, but got "
							+ length);
		}
		// Check content
		for (int i = 0; i < length; i++) {
			char c = contents.charAt(i);
			switch (c) {
			case ESCAPE_FNC_1:
			case ESCAPE_FNC_2:
			case ESCAPE_FNC_3:
			case ESCAPE_FNC_4:
				break;
			default:
				if (c > 127) {
					// support for FNC4 isn't implemented, no full Latin-1
					// character set available at the moment
					throw new IllegalArgumentException(
							"Bad character in input: " + c);
				}
			}
		}

		Collection patterns = new ArrayList(); // temporary
																// storage for
																// patterns
		int checkSum = 0;
		int checkWeight = 1;
		int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C)
		int position = 0; // position in contents

		while (position < length) {
			// Select code to use
			int newCodeSet = chooseCode(contents, position, codeSet, type);

			// Get the pattern index
			int patternIndex;
			if (newCodeSet == codeSet) {
				// Encode the current character
				// First handle escapes
				switch (contents.charAt(position)) {
				case ESCAPE_FNC_1:
					patternIndex = CODE_FNC_1;
					break;
				case ESCAPE_FNC_2:
					patternIndex = CODE_FNC_2;
					break;
				case ESCAPE_FNC_3:
					patternIndex = CODE_FNC_3;
					break;
				case ESCAPE_FNC_4:
					if (codeSet == CODE_CODE_A) {
						patternIndex = CODE_FNC_4_A;
					} else {
						patternIndex = CODE_FNC_4_B;
					}
					break;
				default:
					// Then handle normal characters otherwise
					switch (codeSet) {
					case CODE_CODE_A:
						patternIndex = contents.charAt(position) - ' ';
						if (patternIndex < 0) {
							// everything below a space character comes behind
							// the underscore in the code patterns table
							patternIndex += '`';
						}
						break;
					case CODE_CODE_B:
						patternIndex = contents.charAt(position) - ' ';
						break;
					default:
						// CODE_CODE_C
						patternIndex = Integer.parseInt(contents.substring(
								position, position + 2));
						position++; // Also incremented below
						break;
					}
				}
				position++;
			} else {
				// Should we change the current code?
				// Do we have a code set?
				if (codeSet == 0) {
					// No, we don't have a code set
					switch (newCodeSet) {
					case CODE_CODE_A:
						patternIndex = CODE_START_A;
						break;
					case CODE_CODE_B:
						patternIndex = CODE_START_B;
						break;
					default:
						patternIndex = CODE_START_C;
						break;
					}
				} else {
					// Yes, we have a code set
					patternIndex = newCodeSet;
				}
				codeSet = newCodeSet;
			}

			// Get the pattern
			patterns.add(CODE_PATTERNS[patternIndex]);

			// Compute checksum
			checkSum += patternIndex * checkWeight;
			if (position != 0) {
				checkWeight++;
			}
		}

		// Compute and append checksum
		checkSum %= 103;
		patterns.add(CODE_PATTERNS[checkSum]);

		// Append stop code
		patterns.add(CODE_PATTERNS[CODE_STOP]);

		// Compute code width
		int codeWidth = 0;
		for (int[] pattern : patterns) {
			for (int width : pattern) {
				codeWidth += width;
			}
		}

		// Compute result
		boolean[] result = new boolean[codeWidth];
		int pos = 0;
		for (int[] pattern : patterns) {
			pos += appendPattern(result, pos, pattern, true);
		}

		return result;
	}

	private static CType findCType(CharSequence value, int start) {
		int last = value.length();
		if (start >= last) {
			return CType.UNCODABLE;
		}
		char c = value.charAt(start);
		if (c == ESCAPE_FNC_1) {
			return CType.FNC_1;
		}
		if (c < '0' || c > '9') {
			return CType.UNCODABLE;
		}
		if (start + 1 >= last) {
			return CType.ONE_DIGIT;
		}
		c = value.charAt(start + 1);
		if (c < '0' || c > '9') {
			return CType.ONE_DIGIT;
		}
		return CType.TWO_DIGITS;
	}

	private static int chooseCode(CharSequence value, int start, int oldCode,
			String type) {
		if (type == TYPE_A) {
			return CODE_CODE_A;
		}
		if (type == TYPE_B) {
			return CODE_CODE_B;
		}
		if (type == TYPE_C) {
			return CODE_CODE_C;
		}
		CType lookahead = findCType(value, start);
		if (lookahead == CType.ONE_DIGIT) {
			return CODE_CODE_B;
		}
		if (lookahead == CType.UNCODABLE) {
			if (start < value.length()) {
				char c = value.charAt(start);
				if (c < ' ' || (oldCode == CODE_CODE_A && c < '`')) {
					// can continue in code A, encodes ASCII 0 to 95
					return CODE_CODE_A;
				}
			}
			return CODE_CODE_B; // no choice
		}
		if (oldCode == CODE_CODE_C) { // can continue in code C
			return CODE_CODE_C;
		}
		if (oldCode == CODE_CODE_B) {
			if (lookahead == CType.FNC_1) {
				return CODE_CODE_B; // can continue in code B
			}
			// Seen two consecutive digits, see what follows
			lookahead = findCType(value, start + 2);
			if (lookahead == CType.UNCODABLE || lookahead == CType.ONE_DIGIT) {
				return CODE_CODE_B; // not worth switching now
			}
			if (lookahead == CType.FNC_1) { // two digits, then FNC_1...
				lookahead = findCType(value, start + 3);
				if (lookahead == CType.TWO_DIGITS) { // then two more digits,
														// switch
					return CODE_CODE_C;
				} else {
					return CODE_CODE_B; // otherwise not worth switching
				}
			}
			// At this point, there are at least 4 consecutive digits.
			// Look ahead to choose whether to switch now or on the next round.
			int index = start + 4;
			while ((lookahead = findCType(value, index)) == CType.TWO_DIGITS) {
				index += 2;
			}
			if (lookahead == CType.ONE_DIGIT) { // odd number of digits, switch
												// later
				return CODE_CODE_B;
			}
			return CODE_CODE_C; // even number of digits, switch now
		}
		// Here oldCode == 0, which means we are choosing the initial code
		if (lookahead == CType.FNC_1) { // ignore FNC_1
			lookahead = findCType(value, start + 1);
		}
		if (lookahead == CType.TWO_DIGITS) { // at least two digits, start in
												// code C
			return CODE_CODE_C;
		}
		return CODE_CODE_B;
	}

	static final int[][] CODE_PATTERNS = {
		      {2, 1, 2, 2, 2, 2}, // 0
		      {2, 2, 2, 1, 2, 2},
		      {2, 2, 2, 2, 2, 1},
		      {1, 2, 1, 2, 2, 3},
		      {1, 2, 1, 3, 2, 2},
		      {1, 3, 1, 2, 2, 2}, // 5
		      {1, 2, 2, 2, 1, 3},
		      {1, 2, 2, 3, 1, 2},
		      {1, 3, 2, 2, 1, 2},
		      {2, 2, 1, 2, 1, 3},
		      {2, 2, 1, 3, 1, 2}, // 10
		      {2, 3, 1, 2, 1, 2},
		      {1, 1, 2, 2, 3, 2},
		      {1, 2, 2, 1, 3, 2},
		      {1, 2, 2, 2, 3, 1},
		      {1, 1, 3, 2, 2, 2}, // 15
		      {1, 2, 3, 1, 2, 2},
		      {1, 2, 3, 2, 2, 1},
		      {2, 2, 3, 2, 1, 1},
		      {2, 2, 1, 1, 3, 2},
		      {2, 2, 1, 2, 3, 1}, // 20
		      {2, 1, 3, 2, 1, 2},
		      {2, 2, 3, 1, 1, 2},
		      {3, 1, 2, 1, 3, 1},
		      {3, 1, 1, 2, 2, 2},
		      {3, 2, 1, 1, 2, 2}, // 25
		      {3, 2, 1, 2, 2, 1},
		      {3, 1, 2, 2, 1, 2},
		      {3, 2, 2, 1, 1, 2},
		      {3, 2, 2, 2, 1, 1},
		      {2, 1, 2, 1, 2, 3}, // 30
		      {2, 1, 2, 3, 2, 1},
		      {2, 3, 2, 1, 2, 1},
		      {1, 1, 1, 3, 2, 3},
		      {1, 3, 1, 1, 2, 3},
		      {1, 3, 1, 3, 2, 1}, // 35
		      {1, 1, 2, 3, 1, 3},
		      {1, 3, 2, 1, 1, 3},
		      {1, 3, 2, 3, 1, 1},
		      {2, 1, 1, 3, 1, 3},
		      {2, 3, 1, 1, 1, 3}, // 40
		      {2, 3, 1, 3, 1, 1},
		      {1, 1, 2, 1, 3, 3},
		      {1, 1, 2, 3, 3, 1},
		      {1, 3, 2, 1, 3, 1},
		      {1, 1, 3, 1, 2, 3}, // 45
		      {1, 1, 3, 3, 2, 1},
		      {1, 3, 3, 1, 2, 1},
		      {3, 1, 3, 1, 2, 1},
		      {2, 1, 1, 3, 3, 1},
		      {2, 3, 1, 1, 3, 1}, // 50
		      {2, 1, 3, 1, 1, 3},
		      {2, 1, 3, 3, 1, 1},
		      {2, 1, 3, 1, 3, 1},
		      {3, 1, 1, 1, 2, 3},
		      {3, 1, 1, 3, 2, 1}, // 55
		      {3, 3, 1, 1, 2, 1},
		      {3, 1, 2, 1, 1, 3},
		      {3, 1, 2, 3, 1, 1},
		      {3, 3, 2, 1, 1, 1},
		      {3, 1, 4, 1, 1, 1}, // 60
		      {2, 2, 1, 4, 1, 1},
		      {4, 3, 1, 1, 1, 1},
		      {1, 1, 1, 2, 2, 4},
		      {1, 1, 1, 4, 2, 2},
		      {1, 2, 1, 1, 2, 4}, // 65
		      {1, 2, 1, 4, 2, 1},
		      {1, 4, 1, 1, 2, 2},
		      {1, 4, 1, 2, 2, 1},
		      {1, 1, 2, 2, 1, 4},
		      {1, 1, 2, 4, 1, 2}, // 70
		      {1, 2, 2, 1, 1, 4},
		      {1, 2, 2, 4, 1, 1},
		      {1, 4, 2, 1, 1, 2},
		      {1, 4, 2, 2, 1, 1},
		      {2, 4, 1, 2, 1, 1}, // 75
		      {2, 2, 1, 1, 1, 4},
		      {4, 1, 3, 1, 1, 1},
		      {2, 4, 1, 1, 1, 2},
		      {1, 3, 4, 1, 1, 1},
		      {1, 1, 1, 2, 4, 2}, // 80
		      {1, 2, 1, 1, 4, 2},
		      {1, 2, 1, 2, 4, 1},
		      {1, 1, 4, 2, 1, 2},
		      {1, 2, 4, 1, 1, 2},
		      {1, 2, 4, 2, 1, 1}, // 85
		      {4, 1, 1, 2, 1, 2},
		      {4, 2, 1, 1, 1, 2},
		      {4, 2, 1, 2, 1, 1},
		      {2, 1, 2, 1, 4, 1},
		      {2, 1, 4, 1, 2, 1}, // 90
		      {4, 1, 2, 1, 2, 1},
		      {1, 1, 1, 1, 4, 3},
		      {1, 1, 1, 3, 4, 1},
		      {1, 3, 1, 1, 4, 1},
		      {1, 1, 4, 1, 1, 3}, // 95
		      {1, 1, 4, 3, 1, 1},
		      {4, 1, 1, 1, 1, 3},
		      {4, 1, 1, 3, 1, 1},
		      {1, 1, 3, 1, 4, 1},
		      {1, 1, 4, 1, 3, 1}, // 100
		      {3, 1, 1, 1, 4, 1},
		      {4, 1, 1, 1, 3, 1},
		      {2, 1, 1, 4, 1, 2},
		      {2, 1, 1, 2, 1, 4},
		      {2, 1, 1, 2, 3, 2}, // 105
		      {2, 3, 3, 1, 1, 1, 2}
		  };
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy