/* * Copyright 2010 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; namespace ZXing.OneD { /// /// This object renders a CODE128 code as a . /// /// erik.barbara@gmail.com (Erik Barbara) /// public sealed class Code128Writer : OneDimensionalCodeWriter { private const int CODE_START_B = 104; private const int CODE_START_C = 105; private const int CODE_CODE_B = 100; private const int CODE_CODE_C = 99; private const int CODE_STOP = 106; // Dummy characters used to specify control characters in input private const char ESCAPE_FNC_1 = '\u00f1'; private const char ESCAPE_FNC_2 = '\u00f2'; private const char ESCAPE_FNC_3 = '\u00f3'; private const char ESCAPE_FNC_4 = '\u00f4'; private const int CODE_FNC_1 = 102; // Code A, Code B, Code C private const int CODE_FNC_2 = 97; // Code A, Code B private const int CODE_FNC_3 = 96; // Code A, Code B private const int CODE_FNC_4_B = 100; // Code B private bool forceCodesetB; public override BitMatrix encode(String contents, BarcodeFormat format, int width, int height, IDictionary hints) { if (format != BarcodeFormat.CODE_128) { throw new ArgumentException("Can only encode CODE_128, but got " + format); } forceCodesetB = (hints != null && hints.ContainsKey(EncodeHintType.CODE128_FORCE_CODESET_B) && (bool) hints[EncodeHintType.CODE128_FORCE_CODESET_B]); return base.encode(contents, format, width, height, hints); } override public bool[] encode(String contents) { int length = contents.Length; // Check length if (length < 1 || length > 80) { throw new ArgumentException( "Contents length should be between 1 and 80 characters, but got " + length); } // Check content for (int i = 0; i < length; i++) { char c = contents[i]; if (c < ' ' || c > '~') { switch (c) { case ESCAPE_FNC_1: case ESCAPE_FNC_2: case ESCAPE_FNC_3: case ESCAPE_FNC_4: break; default: throw new ArgumentException("Bad character in input: " + c); } } } var patterns = new List(); // 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 requiredDigitCount = codeSet == CODE_CODE_C ? 2 : 4; int newCodeSet; if (isDigits(contents, position, requiredDigitCount)) { newCodeSet = forceCodesetB ? CODE_CODE_B : CODE_CODE_C; } else { newCodeSet = CODE_CODE_B; } //Get the pattern index int patternIndex; if (newCodeSet == codeSet) { // Encode the current character // First handle escapes switch (contents[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: patternIndex = CODE_FNC_4_B; // FIXME if this ever outputs Code A break; default: // Then handle normal characters otherwise if (codeSet == CODE_CODE_B) { patternIndex = contents[position] - ' '; } else { // CODE_CODE_C patternIndex = Int32.Parse(contents.Substring(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 if (newCodeSet == CODE_CODE_B) { patternIndex = CODE_START_B; } else { // CODE_CODE_C patternIndex = CODE_START_C; } } else { // Yes, we have a code set patternIndex = newCodeSet; } codeSet = newCodeSet; } // Get the pattern patterns.Add(Code128Reader.CODE_PATTERNS[patternIndex]); // Compute checksum checkSum += patternIndex * checkWeight; if (position != 0) { checkWeight++; } } // Compute and append checksum checkSum %= 103; patterns.Add(Code128Reader.CODE_PATTERNS[checkSum]); // Append stop code patterns.Add(Code128Reader.CODE_PATTERNS[CODE_STOP]); // Compute code width int codeWidth = 0; foreach (int[] pattern in patterns) { foreach (int width in pattern) { codeWidth += width; } } // Compute result var result = new bool[codeWidth]; int pos = 0; foreach (int[] pattern in patterns) { pos += appendPattern(result, pos, pattern, true); } return result; } private static bool isDigits(String value, int start, int length) { int end = start + length; int last = value.Length; for (int i = start; i < end && i < last; i++) { char c = value[i]; if (c < '0' || c > '9') { if (c != ESCAPE_FNC_1) { return false; } end++; // ignore FNC_1 } } return end <= last; // end > last if we've run out of string } } }