public void testSampleWithNoFileIdMacro()
        {
            int[]
            sampleCodes = { 4, 928, 222, 198, 0 };
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            Assert.AreEqual(-1, DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata));
        }
        public void testSampleWithBadSequenceIndexMacro()
        {
            int[]
            sampleCodes = { 3, 928, 222, 0 };
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            Assert.AreEqual(-1, DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata));
        }
        public void testSampleWithMacroTerminatorOnly()
        {
            int[] sampleCodes = { 7, 477, 928, 222, 198, 0, 922 };
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata);

            Assert.AreEqual(99998, resultMetadata.SegmentIndex);
            Assert.AreEqual("000", resultMetadata.FileId);
            Assert.IsTrue(resultMetadata.IsLastSegment);
            Assert.AreEqual(-1, resultMetadata.SegmentCount);
            Assert.IsNull(resultMetadata.OptionalData);
        }
        public void testSampleWithNumericValues()
        {
            int[] sampleCodes = { 25, 477, 928, 111, 100, 0, 252, 21, 86, 923, 2, 2, 0, 1, 0, 0, 0, 923, 5, 130, 923,
                                  6,    1, 500,  13, 0 };
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata);

            Assert.AreEqual(0, resultMetadata.SegmentIndex);
            Assert.AreEqual("000252021086", resultMetadata.FileId);
            Assert.That(resultMetadata.IsLastSegment, Is.False);

            Assert.AreEqual(180980729000000L, resultMetadata.Timestamp);
            Assert.AreEqual(30, resultMetadata.FileSize);
            Assert.AreEqual(260013, resultMetadata.Checksum);
        }
        public void testSampleWithFilename()
        {
            int[] sampleCodes = { 23,  477, 928, 111, 100,   0, 252,  21,  86, 923,   0, 815, 251, 133,  12, 148, 537, 593,
                                  599, 923,   1, 111, 102,  98, 311, 355, 522, 920, 779,  40, 628,  33, 749, 267, 506, 213,928, 465, 248,
                                  493,  72, 780, 699, 780, 493, 755,  84, 198, 628, 368, 156, 198, 809,  19, 113 };
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 3, resultMetadata);

            Assert.AreEqual(0, resultMetadata.SegmentIndex);
            Assert.AreEqual("000252021086", resultMetadata.FileId);
            Assert.That(resultMetadata.IsLastSegment, Is.False);
            Assert.AreEqual(2, resultMetadata.SegmentCount);
            Assert.That(resultMetadata.Addressee, Is.Null);
            Assert.That(resultMetadata.Sender, Is.Null);
            Assert.AreEqual("filename.txt", resultMetadata.FileName);
        }
        public void testStandardSample2()
        {
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            int[] sampleCodes = { 11,    928, 111, 103, 17, 53, 923, 1, 111, 104, 922,
                                  // we should never reach these
                                  1000, 1000, 1000 };

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata);

            Assert.AreEqual(3, resultMetadata.SegmentIndex);
            Assert.AreEqual("017053", resultMetadata.FileId);
            Assert.That(resultMetadata.IsLastSegment, Is.True);
            Assert.AreEqual(4, resultMetadata.SegmentCount);
            Assert.That(resultMetadata.Addressee, Is.Null);
            Assert.That(resultMetadata.Sender, Is.Null);

            //int[] optionalData = resultMetadata.OptionalData;
            //Assert.AreEqual(1, optionalData[0], "first element of optional array should be the first field identifier");
            //Assert.AreEqual(104, optionalData[optionalData.Length - 1], "last element of optional array should be the last codeword of the last field");
        }
        public void testStandardSample1()
        {
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            int[] sampleCodes = { 20,    928, 111, 100, 17, 53, 923, 1, 111, 104, 923, 3, 64, 416, 34, 923, 4, 258, 446, 67,
                                  // we should never reach these
                                  1000, 1000, 1000 };

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata);

            Assert.AreEqual(0, resultMetadata.SegmentIndex);
            Assert.AreEqual("017053", resultMetadata.FileId);
            Assert.That(resultMetadata.IsLastSegment, Is.False);
            Assert.AreEqual(4, resultMetadata.SegmentCount);
            Assert.AreEqual("CEN BE", resultMetadata.Sender);
            Assert.AreEqual("ISO CH", resultMetadata.Addressee);

            //int[] optionalData = resultMetadata.OptionalData;
            //Assert.AreEqual(1, optionalData[0], "first element of optional array should be the first field identifier");
            //Assert.AreEqual(67, optionalData[optionalData.Length - 1], "last element of optional array should be the last codeword of the last field");
        }
        public void testStandardSample3()
        {
            PDF417ResultMetadata resultMetadata = new PDF417ResultMetadata();

            int[] sampleCodes = { 7, 928, 111, 100, 100, 200, 300,
                                  0 }; // Final dummy ECC codeword required to avoid ArrayIndexOutOfBounds

            DecodedBitStreamParser.decodeMacroBlock(sampleCodes, 2, resultMetadata);

            Assert.AreEqual(0, resultMetadata.SegmentIndex);
            Assert.AreEqual("100200300", resultMetadata.FileId);
            Assert.False(resultMetadata.IsLastSegment);
            Assert.AreEqual(-1, resultMetadata.SegmentCount);
            Assert.IsNull(resultMetadata.Addressee);
            Assert.IsNull(resultMetadata.Sender);
            Assert.IsNull(resultMetadata.OptionalData);

            // Check that symbol containing no data except Macro is accepted (see note in Annex H.2)
            DecoderResult decoderResult = DecodedBitStreamParser.decode(sampleCodes, "0");

            Assert.AreEqual("", decoderResult.Text);
            Assert.IsNotNull(decoderResult.Other);
        }
Exemplo n.º 9
0
        public SummaryResults testPDF417BlackBoxCountingResults(bool assertOnFailure)
        {
            Assert.IsFalse(testResults.Count == 0);

            IDictionary <String, List <String> > imageFiles = getImageFileLists();
            int testCount = testResults.Count;

            int[] passedCounts          = new int[testCount];
            int[] misreadCounts         = new int[testCount];
            int[] tryHarderCounts       = new int[testCount];
            int[] tryHaderMisreadCounts = new int[testCount];

            foreach (KeyValuePair <String, List <String> > testImageGroup in imageFiles)
            {
                log.InfoFormat("Starting Image Group {0}", testImageGroup.Key);

                String fileBaseName = testImageGroup.Key;
                String expectedText;
                String expectedTextFile = fileBaseName + ".txt";
                if (File.Exists(expectedTextFile))
                {
                    expectedText = File.ReadAllText(expectedTextFile, UTF8);
                }
                else
                {
                    expectedTextFile = fileBaseName + ".bin";
                    Assert.IsTrue(File.Exists(expectedTextFile));
                    expectedText = File.ReadAllText(expectedTextFile, ISO88591);
                }

                for (int x = 0; x < testCount; x++)
                {
                    List <Result> results = new List <Result>();
                    foreach (var imageFile in testImageGroup.Value)
                    {
#if !SILVERLIGHT
                        var image = new Bitmap(Image.FromFile(imageFile));
#else
                        var image = new WriteableBitmap(0, 0);
                        image.SetSource(File.OpenRead(testImage));
#endif
                        var rotation     = testResults[x].Rotation;
                        var rotatedImage = rotateImage(image, rotation);
                        var source       = new BitmapLuminanceSource(rotatedImage);
                        var bitmap       = new BinaryBitmap(new HybridBinarizer(source));

                        try
                        {
                            results.AddRange(decode(bitmap, false));
                        }
                        catch (ReaderException ignored)
                        {
                            // ignore
                        }
                    }
                    results.Sort((arg0, arg1) =>
                    {
                        PDF417ResultMetadata resultMetadata      = getMeta(arg0);
                        PDF417ResultMetadata otherResultMetadata = getMeta(arg1);
                        return(resultMetadata.SegmentIndex - otherResultMetadata.SegmentIndex);
                    });
                    var    resultText = new StringBuilder();
                    String fileId     = null;
                    foreach (Result result in results)
                    {
                        PDF417ResultMetadata resultMetadata = getMeta(result);
                        Assert.NotNull(resultMetadata, "resultMetadata");
                        if (fileId == null)
                        {
                            fileId = resultMetadata.FileId;
                        }
                        Assert.AreEqual(fileId, resultMetadata.FileId, "FileId");
                        resultText.Append(result.Text);
                    }
                    Assert.AreEqual(expectedText, resultText.ToString(), "ExpectedText");
                    passedCounts[x]++;
                    tryHarderCounts[x]++;
                }
            }

            // Print the results of all tests first
            int totalFound      = 0;
            int totalMustPass   = 0;
            int totalMisread    = 0;
            int totalMaxMisread = 0;

            int numberOfTests = imageFiles.Count;
            for (int x = 0; x < testResults.Count; x++)
            {
                TestResult testResult = testResults[x];
                log.InfoFormat("Rotation {0} degrees:", (int)testResult.Rotation);
                log.InfoFormat(" {0} of {1} images passed ({2} required)", passedCounts[x], numberOfTests,
                               testResult.MustPassCount);
                int failed = numberOfTests - passedCounts[x];
                log.InfoFormat(" {0} failed due to misreads, {1} not detected", misreadCounts[x], failed - misreadCounts[x]);
                log.InfoFormat(" {0} of {1} images passed with try harder ({2} required)", tryHarderCounts[x],
                               numberOfTests, testResult.TryHarderCount);
                failed = numberOfTests - tryHarderCounts[x];
                log.InfoFormat(" {0} failed due to misreads, {1} not detected", tryHaderMisreadCounts[x], failed -
                               tryHaderMisreadCounts[x]);
                totalFound      += passedCounts[x] + tryHarderCounts[x];
                totalMustPass   += testResult.MustPassCount + testResult.TryHarderCount;
                totalMisread    += misreadCounts[x] + tryHaderMisreadCounts[x];
                totalMaxMisread += testResult.MaxMisreads + testResult.MaxTryHarderMisreads;
            }

            int totalTests = numberOfTests * testCount * 2;
            log.InfoFormat("Decoded {0} images out of {1} ({2}%, {3} required)", totalFound, totalTests, totalFound *
                           100 /
                           totalTests, totalMustPass);
            if (totalFound > totalMustPass)
            {
                log.WarnFormat("+++ Test too lax by {0} images", totalFound - totalMustPass);
            }
            else if (totalFound < totalMustPass)
            {
                log.WarnFormat("--- Test failed by {0} images", totalMustPass - totalFound);
            }

            if (totalMisread < totalMaxMisread)
            {
                log.WarnFormat("+++ Test expects too many misreads by {0} images", totalMaxMisread - totalMisread);
            }
            else if (totalMisread > totalMaxMisread)
            {
                log.WarnFormat("--- Test had too many misreads by {0} images", totalMisread - totalMaxMisread);
            }

            // Then run through again and assert if any failed
            if (assertOnFailure)
            {
                for (int x = 0; x < testCount; x++)
                {
                    TestResult testResult = testResults[x];
                    String     label      = "Rotation " + testResult.Rotation + " degrees: Too many images failed";
                    Assert.IsTrue(passedCounts[x] >= testResult.MustPassCount, label);
                    Assert.IsTrue(tryHarderCounts[x] >= testResult.TryHarderCount, "Try harder, " + label);
                    label = "Rotation " + testResult.Rotation + " degrees: Too many images misread";
                    Assert.IsTrue(misreadCounts[x] <= testResult.MaxMisreads, label);
                    Assert.IsTrue(tryHaderMisreadCounts[x] <= testResult.MaxTryHarderMisreads, "Try harder, " + label);
                }
            }
            return(new SummaryResults(totalFound, totalMustPass, totalTests));
        }
Exemplo n.º 10
0
        private static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata)
        {
            if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0])
            {
                // we must have at least two bytes left for the segment index
                return(-1);
            }
            var segmentIndexArray = new int[NUMBER_OF_SEQUENCE_CODEWORDS];

            for (var i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++)
            {
                segmentIndexArray[i] = codewords[codeIndex];
            }
            var s = decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS);

            if (s == null)
            {
                return(-1);
            }
            resultMetadata.SegmentIndex = Int32.Parse(s);

            var fileId = new StringBuilder();

            codeIndex             = textCompaction(codewords, codeIndex, fileId);
            resultMetadata.FileId = fileId.ToString();

            switch (codewords[codeIndex])
            {
            case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
                codeIndex++;
                var additionalOptionCodeWords      = new int[codewords[0] - codeIndex];
                var additionalOptionCodeWordsIndex = 0;

                var end = false;
                while ((codeIndex < codewords[0]) && !end)
                {
                    var code = codewords[codeIndex++];
                    if (code < TEXT_COMPACTION_MODE_LATCH)
                    {
                        additionalOptionCodeWords[additionalOptionCodeWordsIndex++] = code;
                    }
                    else
                    {
                        switch (code)
                        {
                        case MACRO_PDF417_TERMINATOR:
                            resultMetadata.IsLastSegment = true;
                            codeIndex++;
                            end = true;
                            break;

                        default:
                            return(-1);
                        }
                    }
                }
                resultMetadata.OptionalData = new int[additionalOptionCodeWordsIndex];
                Array.Copy(additionalOptionCodeWords, resultMetadata.OptionalData, additionalOptionCodeWordsIndex);
                break;

            case MACRO_PDF417_TERMINATOR:
                resultMetadata.IsLastSegment = true;
                codeIndex++;
                break;
            }

            return(codeIndex);
        }
Exemplo n.º 11
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;

            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:
                    codeIndex = byteCompaction(code, codewords, encoding ?? (encoding = getEncoding(PDF417HighLevelEncoder.DEFAULT_ENCODING_NAME)), codeIndex, result);
                    break;

                case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
                    result.Append((char)codewords[codeIndex++]);
                    break;

                case NUMERIC_COMPACTION_MODE_LATCH:
                    codeIndex = numericCompaction(codewords, codeIndex, result);
                    break;

                case ECI_CHARSET:
                    var charsetECI = CharacterSetECI.getCharacterSetECIByValue(codewords[codeIndex++]);
                    encoding = 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);
            }

            var decoderResult = new DecoderResult(null, result.ToString(), null, ecLevel);

            decoderResult.Other = resultMetadata;
            return(decoderResult);
        }
Exemplo n.º 12
0
        internal static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata)
        {
            if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0])
            {
                // we must have at least two bytes left for the segment index
                return(-1);
            }
            var segmentIndexArray = new int[NUMBER_OF_SEQUENCE_CODEWORDS];

            for (var i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++)
            {
                segmentIndexArray[i] = codewords[codeIndex];
            }
            var s = decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS);

            if (s == null)
            {
                return(-1);
            }
            resultMetadata.SegmentIndex = Int32.Parse(s);

            var fileId = new StringBuilder();

            codeIndex             = textCompaction(codewords, codeIndex, fileId);
            resultMetadata.FileId = fileId.ToString();

            int optionalFieldsStart = -1;

            if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD)
            {
                optionalFieldsStart = codeIndex + 1;
            }

            while (codeIndex < codewords[0])
            {
                switch (codewords[codeIndex])
                {
                case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
                    codeIndex++;
                    switch (codewords[codeIndex])
                    {
                    case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME:
                        var fileName = new StringBuilder();
                        codeIndex = textCompaction(codewords, codeIndex + 1, fileName);
                        resultMetadata.FileName = fileName.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_SENDER:
                        var sender = new StringBuilder();
                        codeIndex             = textCompaction(codewords, codeIndex + 1, sender);
                        resultMetadata.Sender = sender.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE:
                        var addressee = new StringBuilder();
                        codeIndex = textCompaction(codewords, codeIndex + 1, addressee);
                        resultMetadata.Addressee = addressee.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT:
                    {
                        var segmentCount = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, segmentCount);
#if WindowsCE
                        try { resultMetadata.SegmentCount = Int32.Parse(segmentCount.ToString()); }
                        catch { }
#else
                        int intResult;
                        if (Int32.TryParse(segmentCount.ToString(), out intResult))
                        {
                            resultMetadata.SegmentCount = intResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP:
                    {
                        var timestamp = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, timestamp);
#if WindowsCE
                        try { resultMetadata.Timestamp = Int64.Parse(timestamp.ToString()); }
                        catch { }
#else
                        long longResult;
                        if (Int64.TryParse(timestamp.ToString(), out longResult))
                        {
                            resultMetadata.Timestamp = longResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM:
                    {
                        var checksum = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, checksum);
#if WindowsCE
                        try { resultMetadata.Checksum = Int32.Parse(checksum.ToString()); }
                        catch { }
#else
                        int intResult;
                        if (Int32.TryParse(checksum.ToString(), out intResult))
                        {
                            resultMetadata.Checksum = intResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE:
                    {
                        var fileSize = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, fileSize);
#if WindowsCE
                        try { resultMetadata.FileSize = Int64.Parse(fileSize.ToString()); }
                        catch { }
#else
                        long longResult;
                        if (Int64.TryParse(fileSize.ToString(), out longResult))
                        {
                            resultMetadata.FileSize = longResult;
                        }
#endif
                    }
                    break;

                    default:
                        break;
                    }
                    break;

                case MACRO_PDF417_TERMINATOR:
                    codeIndex++;
                    resultMetadata.IsLastSegment = true;
                    break;

                default:
                    break;
                }
            }

            return(codeIndex);
        }
Exemplo n.º 13
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();

            while (codeIndex < codewords[0])
            {
                switch (code)
                {
                case TEXT_COMPACTION_MODE_LATCH:
                    codeIndex = textCompaction(codewords, codeIndex, result);
                    break;

                case BYTE_COMPACTION_MODE_LATCH:
                    codeIndex = byteCompaction(code, codewords, codeIndex, result);
                    break;

                case NUMERIC_COMPACTION_MODE_LATCH:
                    codeIndex = numericCompaction(codewords, codeIndex, result);
                    break;

                case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
                    codeIndex = byteCompaction(code, codewords, codeIndex, result);
                    break;

                case BYTE_COMPACTION_MODE_LATCH_6:
                    codeIndex = byteCompaction(code, codewords, codeIndex, result);
                    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);
            }

            var decoderResult = new DecoderResult(null, result.ToString(), null, ecLevel);

            decoderResult.Other = resultMetadata;
            return(decoderResult);
        }
        internal static int decodeMacroBlock(int[] codewords, int codeIndex, PDF417ResultMetadata resultMetadata)
        {
            if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0])
            {
                // we must have at least two bytes left for the segment index
                return(-1);
            }
            var segmentIndexArray = new int[NUMBER_OF_SEQUENCE_CODEWORDS];

            for (var i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++)
            {
                segmentIndexArray[i] = codewords[codeIndex];
            }
            var segmentIndexString = decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS);

            if (segmentIndexString == null)
            {
                return(-1);
            }
            if (string.IsNullOrEmpty(segmentIndexString))
            {
                resultMetadata.SegmentIndex = 0;
            }
            else
            {
                try
                {
                    resultMetadata.SegmentIndex = Int32.Parse(segmentIndexString);
                }
                catch (Exception)
                {
                    // too large; bad input?
                    return(-1);
                }
            }

            // Decoding the fileId codewords as 0-899 numbers, each 0-filled to width 3. This follows the spec
            // (See ISO/IEC 15438:2015 Annex H.6) and preserves all info, but some generators (e.g. TEC-IT) write
            // the fileId using text compaction, so in those cases the fileId will appear mangled.
            var fileId = new StringBuilder();

            while (codeIndex < codewords[0] &&
                   codeIndex < codewords.Length &&
                   codewords[codeIndex] != MACRO_PDF417_TERMINATOR &&
                   codewords[codeIndex] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD)
            {
                fileId.Append(codewords[codeIndex].ToString("D3"));
                codeIndex++;
            }
            if (fileId.Length == 0)
            {
                // at least one fileId codeword is required (Annex H.2)
                return(-1);
            }
            resultMetadata.FileId = fileId.ToString();

            int optionalFieldsStart = -1;

            if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD)
            {
                optionalFieldsStart = codeIndex + 1;
            }

            while (codeIndex < codewords[0])
            {
                switch (codewords[codeIndex])
                {
                case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
                    codeIndex++;
                    switch (codewords[codeIndex])
                    {
                    case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME:
                        var fileName = new StringBuilder();
                        codeIndex = textCompaction(codewords, codeIndex + 1, fileName);
                        resultMetadata.FileName = fileName.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_SENDER:
                        var sender = new StringBuilder();
                        codeIndex             = textCompaction(codewords, codeIndex + 1, sender);
                        resultMetadata.Sender = sender.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE:
                        var addressee = new StringBuilder();
                        codeIndex = textCompaction(codewords, codeIndex + 1, addressee);
                        resultMetadata.Addressee = addressee.ToString();
                        break;

                    case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT:
                    {
                        var segmentCount = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, segmentCount);
#if WindowsCE
                        try { resultMetadata.SegmentCount = Int32.Parse(segmentCount.ToString()); }
                        catch { }
#else
                        int intResult;
                        if (Int32.TryParse(segmentCount.ToString(), out intResult))
                        {
                            resultMetadata.SegmentCount = intResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP:
                    {
                        var timestamp = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, timestamp);
#if WindowsCE
                        try { resultMetadata.Timestamp = Int64.Parse(timestamp.ToString()); }
                        catch { }
#else
                        long longResult;
                        if (Int64.TryParse(timestamp.ToString(), out longResult))
                        {
                            resultMetadata.Timestamp = longResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM:
                    {
                        var checksum = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, checksum);
#if WindowsCE
                        try { resultMetadata.Checksum = Int32.Parse(checksum.ToString()); }
                        catch { }
#else
                        int intResult;
                        if (Int32.TryParse(checksum.ToString(), out intResult))
                        {
                            resultMetadata.Checksum = intResult;
                        }
#endif
                    }
                    break;

                    case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE:
                    {
                        var fileSize = new StringBuilder();
                        codeIndex = numericCompaction(codewords, codeIndex + 1, fileSize);
#if WindowsCE
                        try { resultMetadata.FileSize = Int64.Parse(fileSize.ToString()); }
                        catch { }
#else
                        long longResult;
                        if (Int64.TryParse(fileSize.ToString(), out longResult))
                        {
                            resultMetadata.FileSize = longResult;
                        }
#endif
                    }
                    break;

                    default:
                        break;
                    }
                    break;

                case MACRO_PDF417_TERMINATOR:
                    codeIndex++;
                    resultMetadata.IsLastSegment = true;
                    break;

                default:
                    break;
                }
            }

            return(codeIndex);
        }