public bool AppendECI(int value) { encodeCurrentBytesIfAny(); CharacterSetECI characterSetECI = CharacterSetECI.getCharacterSetECIByValue(value); if (characterSetECI == null) { return(false); //throw FormatException.getFormatInstance(new RuntimeException("Unsupported ECI value " + value)); } currentCharset = CharacterSetECI.getEncoding(characterSetECI); return(true); }
private static bool decodeByteSegment(BitSource bits, StringBuilder result, int count, CharacterSetECI currentCharacterSetECI, IList <byte[]> byteSegments, IDictionary <DecodeHintType, object> hints) { // Don't crash trying to read more bits than we have available. if (count << 3 > bits.available()) { return(false); } byte[] readBytes = new byte[count]; for (int i = 0; i < count; i++) { readBytes[i] = (byte)bits.readBits(8); } Encoding encoding; if (currentCharacterSetECI == null) { // The spec isn't clear on this mode; see // section 6.4.5: t does not say which encoding to assuming // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. encoding = StringUtils.guessCharset(readBytes, hints); } else { encoding = CharacterSetECI.getEncoding(currentCharacterSetECI.EncodingName); } if (encoding == null) { encoding = StringUtils.PLATFORM_DEFAULT_ENCODING_T; } result.Append(encoding.GetString(readBytes, 0, readBytes.Length)); byteSegments.Add(readBytes); return(true); }
/// <summary> /// Gets the string encoded in the aztec code bits /// </summary> /// <param name="correctedBits">The corrected bits.</param> /// <returns>the decoded string</returns> private static String getEncodedData(bool[] correctedBits) { var endIndex = correctedBits.Length; var latchTable = Table.UPPER; // table most recently latched to var shiftTable = Table.UPPER; // table to use for the next read var strTable = UPPER_TABLE; var index = 0; // Final decoded string result // (correctedBits-5) / 4 is an upper bound on the size (all-digit result) var result = new StringBuilder((correctedBits.Length - 5) / 4); // Intermediary buffer of decoded bytes, which is decoded into a string and flushed // when character encoding changes (ECI) or input ends. using (var decodedBytes = new System.IO.MemoryStream()) { var encoding = DEFAULT_ENCODING; while (index < endIndex) { if (shiftTable == Table.BINARY) { if (endIndex - index < 5) { break; } int length = readCode(correctedBits, index, 5); index += 5; if (length == 0) { if (endIndex - index < 11) { break; } length = readCode(correctedBits, index, 11) + 31; index += 11; } for (int charCount = 0; charCount < length; charCount++) { if (endIndex - index < 8) { index = endIndex; // Force outer loop to exit break; } int code = readCode(correctedBits, index, 8); decodedBytes.WriteByte((byte)code); index += 8; } // Go back to whatever mode we had been in shiftTable = latchTable; strTable = codeTables[shiftTable]; } else { int size = shiftTable == Table.DIGIT ? 4 : 5; if (endIndex - index < size) { break; } int code = readCode(correctedBits, index, size); index += size; String str = getCharacter(strTable, code); if ("FLG(n)".Equals(str)) { if (endIndex - index < 3) { break; } int n = readCode(correctedBits, index, 3); index += 3; // flush bytes, FLG changes state if (decodedBytes.Length > 0) { var byteArray = decodedBytes.ToArray(); result.Append(encoding.GetString(byteArray, 0, byteArray.Length)); decodedBytes.SetLength(0); } switch (n) { case 0: result.Append((char)29); // translate FNC1 as ASCII 29 break; case 7: throw new FormatException("FLG(7) is reserved and illegal"); default: // ECI is decimal integer encoded as 1-6 codes in DIGIT mode int eci = 0; if (endIndex - index < 4 * n) { break; } while (n-- > 0) { int nextDigit = readCode(correctedBits, index, 4); index += 4; if (nextDigit < 2 || nextDigit > 11) { throw new FormatException("Not a decimal digit"); } eci = eci * 10 + (nextDigit - 2); } CharacterSetECI charsetECI = CharacterSetECI.getCharacterSetECIByValue(eci); encoding = CharacterSetECI.getEncoding(charsetECI); if (encoding == null) { throw new FormatException("Encoding for ECI " + eci + " can't be resolved"); } break; } // Go back to whatever mode we had been in shiftTable = latchTable; strTable = codeTables[shiftTable]; } else if (str.StartsWith("CTRL_")) { // Table changes // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. // That's including when that mode is a shift. // Our test case dlusbs.png for issue #642 exercises that. latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S shiftTable = getTable(str[5]); strTable = codeTables[shiftTable]; if (str[6] == 'L') { latchTable = shiftTable; } } else { // Though stored as a table of strings for convenience, codes actually represent 1 or 2 *bytes*. #if (PORTABLE || NETSTANDARD1_0 || NETSTANDARD1_1 || WINDOWS_PHONE || NETFX_CORE || SILVERLIGHT) var b = StringUtils.PLATFORM_DEFAULT_ENCODING_T.GetBytes(str); #else var b = Encoding.ASCII.GetBytes(str); #endif decodedBytes.Write(b, 0, b.Length); // Go back to whatever mode we had been in shiftTable = latchTable; strTable = codeTables[shiftTable]; } } } if (decodedBytes.Length > 0) { var byteArray = decodedBytes.ToArray(); result.Append(encoding.GetString(byteArray, 0, byteArray.Length)); } } return(result.ToString()); }
internal static DecoderResult decode(int[] codewords, String ecLevel) { var result = new StringBuilder(codewords.Length * 2); // Get compaction mode int codeIndex = 1; int code = codewords[codeIndex++]; var resultMetadata = new PDF417ResultMetadata(); Encoding encoding = null; bool resultIsBinary = false; while (codeIndex <= codewords[0]) { switch (code) { case TEXT_COMPACTION_MODE_LATCH: codeIndex = textCompaction(codewords, codeIndex, result); break; case BYTE_COMPACTION_MODE_LATCH: case BYTE_COMPACTION_MODE_LATCH_6: resultIsBinary = true; codeIndex = byteCompaction(code, codewords, encoding ?? (encoding = CharacterSetECI.getEncoding(PDF417HighLevelEncoder.DEFAULT_ENCODING_NAME)), codeIndex, result); break; case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: if (encoding == null) { encoding = CharacterSetECI.getEncoding(PDF417HighLevelEncoder.DEFAULT_ENCODING_NAME); } result.Append(encoding.GetString(new [] { (byte)codewords[codeIndex++] }, 0, 1)); break; case NUMERIC_COMPACTION_MODE_LATCH: codeIndex = numericCompaction(codewords, codeIndex, result); break; case ECI_CHARSET: var charsetECI = CharacterSetECI.getCharacterSetECIByValue(codewords[codeIndex++]); encoding = CharacterSetECI.getEncoding(charsetECI.EncodingName); break; case ECI_GENERAL_PURPOSE: // Can't do anything with generic ECI; skip its 2 characters codeIndex += 2; break; case ECI_USER_DEFINED: // Can't do anything with user ECI; skip its 1 character codeIndex++; break; case BEGIN_MACRO_PDF417_CONTROL_BLOCK: codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata); break; case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: case MACRO_PDF417_TERMINATOR: // Should not see these outside a macro block return(null); default: // Default to text compaction. During testing numerous barcodes // appeared to be missing the starting mode. In these cases defaulting // to text compaction seems to work. codeIndex--; codeIndex = textCompaction(codewords, codeIndex, result); break; } if (codeIndex < 0) { return(null); } if (codeIndex < codewords.Length) { code = codewords[codeIndex++]; } else { return(null); } } if (result.Length == 0) { return(null); } // Add Raw data if Binary data is present. byte[] rawData = null; if (resultIsBinary) { rawData = Encoding.GetEncoding(PDF417HighLevelEncoder.DEFAULT_ENCODING_NAME).GetBytes(result.ToString()); } var decoderResult = new DecoderResult(rawData, result.ToString(), null, ecLevel); decoderResult.Other = resultMetadata; return(decoderResult); }
/// <summary> /// Encodes the specified content. /// </summary> /// <param name="content">The content.</param> /// <param name="ecLevel">The ec level.</param> /// <param name="hints">The hints.</param> /// <returns></returns> public static QRCode encode(String content, ErrorCorrectionLevel ecLevel, IDictionary <EncodeHintType, object> hints) { Version version; BitArray headerAndDataBits; Mode mode; var hasGS1FormatHint = hints != null && hints.ContainsKey(EncodeHintType.GS1_FORMAT) && hints[EncodeHintType.GS1_FORMAT] != null && Convert.ToBoolean(hints[EncodeHintType.GS1_FORMAT].ToString()); var hasCompactionHint = hints != null && hints.ContainsKey(EncodeHintType.QR_COMPACT) && hints[EncodeHintType.QR_COMPACT] != null && Convert.ToBoolean(hints[EncodeHintType.QR_COMPACT].ToString()); // Determine what character encoding has been specified by the caller, if any bool hasEncodingHint = hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET); #if !SILVERLIGHT || WINDOWS_PHONE var encoding = DEFAULT_BYTE_MODE_ENCODING; var encodingName = hasEncodingHint ? (String)hints[EncodeHintType.CHARACTER_SET] : null; if (encodingName != null) { var eci = CharacterSetECI.getCharacterSetECIByName(encodingName); if (eci == null) { throw new WriterException(string.Format("Encoding {0} isn't supported", encodingName)); } encoding = CharacterSetECI.getEncoding(eci); if (encoding == null) { throw new WriterException(string.Format("Encoding {0} isn't supported", encodingName)); } } var generateECI = hasEncodingHint || !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box var encoding = StringUtils.PLATFORM_DEFAULT_ENCODING_T; // caller of the method can only control if the ECI segment should be written // character set is fixed to UTF-8; but some scanners doesn't like the ECI segment var generateECI = hasEncodingHint; #endif if (hasCompactionHint) { mode = Mode.BYTE; var priorityEncoding = encoding.Equals(DEFAULT_BYTE_MODE_ENCODING) ? null : encoding; var rn = MinimalEncoder.encode(content, null, priorityEncoding, hasGS1FormatHint, ecLevel); headerAndDataBits = new BitArray(); rn.getBits(headerAndDataBits); version = rn.getVersion(); } else { // Pick an encoding mode appropriate for the content. Note that this will not attempt to use // multiple modes / segments even if that were more efficient. mode = chooseMode(content, encoding); // This will store the header information, like mode and // length, as well as "header" segments like an ECI segment. var headerBits = new BitArray(); // Append ECI segment if applicable if (mode == Mode.BYTE && generateECI) { var eci = CharacterSetECI.getCharacterSetECI(encoding); if (eci != null) { var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && hints[EncodeHintType.DISABLE_ECI] != null && Convert.ToBoolean(hints[EncodeHintType.DISABLE_ECI].ToString())); if (!eciIsExplicitDisabled) { appendECI(eci, headerBits); } } } // Append the FNC1 mode header for GS1 formatted data if applicable if (hasGS1FormatHint) { // GS1 formatted codes are prefixed with a FNC1 in first position mode header appendModeInfo(Mode.FNC1_FIRST_POSITION, headerBits); } // (With ECI in place,) Write the mode marker appendModeInfo(mode, headerBits); // Collect data within the main segment, separately, to count its size if needed. Don't add it to // main payload yet. var dataBits = new BitArray(); appendBytes(content, mode, dataBits, encoding); if (hints != null && hints.ContainsKey(EncodeHintType.QR_VERSION)) { int versionNumber = Int32.Parse(hints[EncodeHintType.QR_VERSION].ToString()); version = Version.getVersionForNumber(versionNumber); int bitsNeeded = calculateBitsNeeded(mode, headerBits, dataBits, version); if (!willFit(bitsNeeded, version, ecLevel)) { throw new WriterException("Data too big for requested version"); } } else { version = recommendVersion(ecLevel, mode, headerBits, dataBits); } headerAndDataBits = new BitArray(); headerAndDataBits.appendBitArray(headerBits); // Find "length" of main segment and write it var numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length; appendLengthInfo(numLetters, version, mode, headerAndDataBits); // Put data together into the overall payload headerAndDataBits.appendBitArray(dataBits); } var ecBlocks = version.getECBlocksForLevel(ecLevel); var numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords; // Terminate the bits properly. terminateBits(numDataBytes, headerAndDataBits); // Interleave data bits with error correction code. var finalBits = interleaveWithECBytes(headerAndDataBits, version.TotalCodewords, numDataBytes, ecBlocks.NumBlocks); var qrCode = new QRCode { ECLevel = ecLevel, Mode = mode, Version = version }; // Choose the mask pattern and set to "qrCode". var dimension = version.DimensionForVersion; var matrix = new ByteMatrix(dimension, dimension); // Enable manual selection of the pattern to be used via hint var maskPattern = -1; if (hints != null && hints.ContainsKey(EncodeHintType.QR_MASK_PATTERN)) { var hintMaskPattern = Int32.Parse(hints[EncodeHintType.QR_MASK_PATTERN].ToString()); maskPattern = QRCode.isValidMaskPattern(hintMaskPattern) ? hintMaskPattern : -1; } if (maskPattern == -1) { maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix); } qrCode.MaskPattern = maskPattern; // Build the matrix and set it to "qrCode". MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix); qrCode.Matrix = matrix; return(qrCode); }