public ResultNode(Mode mode, int fromPosition, int charsetEncoderIndex, int characterLength, MinimalEncoder encoder, ResultList resultList) { this.mode = mode; this.fromPosition = fromPosition; this.charsetEncoderIndex = charsetEncoderIndex; this.characterLength = characterLength; this.encoder = encoder; this.resultList = resultList; }
public Edge(Mode mode, int fromPosition, int charsetEncoderIndex, int characterLength, Edge previous, Version version, MinimalEncoder encoder) { this.mode = mode; this.fromPosition = fromPosition; this.charsetEncoderIndex = mode == Mode.BYTE || previous == null ? charsetEncoderIndex : previous.charsetEncoderIndex; // inherit the encoding if not of type BYTE this.characterLength = characterLength; this.previous = previous; int size = previous != null ? previous.cachedTotalSize : 0; bool needECI = mode == Mode.BYTE && (previous == null && this.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1 (previous != null && this.charsetEncoderIndex != previous.charsetEncoderIndex); if (previous == null || mode != previous.mode || needECI) { size += 4 + mode.getCharacterCountBits(version); } switch (mode.Name) { case Mode.Names.KANJI: size += 13; break; case Mode.Names.ALPHANUMERIC: size += characterLength == 1 ? 6 : 11; break; case Mode.Names.NUMERIC: size += characterLength == 1 ? 4 : characterLength == 2 ? 7 : 10; break; case Mode.Names.BYTE: size += 8 * encoder.encoders[charsetEncoderIndex].GetBytes(encoder.stringToEncode.Substring(fromPosition, characterLength)).Length; if (needECI) { size += 4 + 8; // the ECI assignment numbers for ISO-8859-x, UTF-8 and UTF-16 are all 8 bit long } break; } cachedTotalSize = size; }
public ResultList(Version version, Edge solution, MinimalEncoder encoder) { this.encoder = encoder; this.version = version; var length = 0; var current = solution; var containsECI = false; while (current != null) { length += current.characterLength; Edge previous = current.previous; bool needECI = current.mode == Mode.BYTE && (previous == null && current.charsetEncoderIndex != 0) || // at the beginning and charset is not ISO-8859-1 (previous != null && current.charsetEncoderIndex != previous.charsetEncoderIndex); if (needECI) { containsECI = true; } if (previous == null || previous.mode != current.mode || needECI) { list.Insert(0, new ResultNode(current.mode, current.fromPosition, current.charsetEncoderIndex, length, encoder, this)); length = 0; } if (needECI) { list.Insert(0, new ResultNode(Mode.ECI, current.fromPosition, current.charsetEncoderIndex, 0, encoder, this)); } current = previous; } // prepend FNC1 if needed. If the bits contain an ECI then the FNC1 must be preceeded by an ECI. // If there is no ECI at the beginning then we put an ECI to the default charset (ISO-8859-1) if (encoder.isGS1) { var first = list[0]; if (first != null && first.mode != Mode.ECI && containsECI) { // prepend a default character set ECI list.Insert(0, new ResultNode(Mode.ECI, 0, 0, 0, encoder, this)); } first = list[0]; // prepend or insert a FNC1_FIRST_POSITION after the ECI (if any) var node = new ResultNode(Mode.FNC1_FIRST_POSITION, 0, 0, 0, encoder, this); if (first == null || first.mode != Mode.ECI) { list.Insert(0, node); } else { list.Insert(1, node); } } // set version to smallest version into which the bits fit. int versionNumber = version.VersionNumber; int lowerLimit; int upperLimit; switch (getVersionSize(version)) { case VersionSize.SMALL: lowerLimit = 1; upperLimit = 9; break; case VersionSize.MEDIUM: lowerLimit = 10; upperLimit = 26; break; case VersionSize.LARGE: default: lowerLimit = 27; upperLimit = 40; break; } int size = getSize(version); // increase version if needed while (versionNumber < upperLimit && !Encoder.willFit(size, Version.getVersionForNumber(versionNumber), encoder.ecLevel)) { versionNumber++; } // shrink version if possible while (versionNumber > lowerLimit && Encoder.willFit(size, Version.getVersionForNumber(versionNumber - 1), encoder.ecLevel)) { versionNumber--; } this.version = Version.getVersionForNumber(versionNumber); }
/// <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); 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; 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); }