Example #1
0
            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);
        }
Example #3
0
        /// <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());
        }
Example #4
0
        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);
        }
Example #5
0
        /// <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);
        }