This produces nearly optimal encodings of text into the first-level of encoding used by Aztec code. It uses a dynamic algorithm. For each prefix of the string, it determines a set of encodings that could lead to this prefix. We repeatedly add a character and generate a new set of optimal encodings until we have read through the entire input. @author Frank Yellin @author Rustam Abdullaev
Exemplo n.º 1
0
 private static void testHighLevelEncodeString(String s, int expectedReceivedBits)
 {
    BitArray bits = new HighLevelEncoder(LATIN_1.GetBytes(s)).encode();
    int receivedBitCount = bits.ToString().Replace(" ", "").Length;
    Assert.AreEqual(expectedReceivedBits, receivedBitCount, "highLevelEncode() failed for input string: " + s);
    Assert.AreEqual(s, Internal.Decoder.highLevelDecode(toBooleanArray(bits)));
 }
Exemplo n.º 2
0
      /// <summary>
      /// Encodes the given binary content as an Aztec symbol
      /// </summary>
      /// <param name="data">input data string</param>
      /// <param name="minECCPercent">minimal percentage of error check words (According to ISO/IEC 24778:2008,
      /// a minimum of 23% + 3 words is recommended)</param>
      /// <param name="userSpecifiedLayers">if non-zero, a user-specified value for the number of layers</param>
      /// <returns>
      /// Aztec symbol matrix with metadata
      /// </returns>
      public static AztecCode encode(byte[] data, int minECCPercent, int userSpecifiedLayers)
      {
         // High-level encode
         var bits = new HighLevelEncoder(data).encode();

         // stuff bits and choose symbol size
         int eccBits = bits.Size*minECCPercent/100 + 11;
         int totalSizeBits = bits.Size + eccBits;
         bool compact;
         int layers;
         int totalBitsInLayer;
         int wordSize;
         BitArray stuffedBits;

         if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS)
         {
            compact = userSpecifiedLayers < 0;
            layers = Math.Abs(userSpecifiedLayers);
            if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS))
            {
               throw new ArgumentException(
                  String.Format("Illegal value {0} for layers", userSpecifiedLayers));
            }
            totalBitsInLayer = TotalBitsInLayer(layers, compact);
            wordSize = WORD_SIZE[layers];
            int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
            stuffedBits = stuffBits(bits, wordSize);
            if (stuffedBits.Size + eccBits > usableBitsInLayers)
            {
               throw new ArgumentException("Data to large for user specified layer");
            }
            if (compact && stuffedBits.Size > wordSize*64)
            {
               // Compact format only allows 64 data words, though C4 can hold more words than that
               throw new ArgumentException("Data to large for user specified layer");
            }
         }
         else
         {
            wordSize = 0;
            stuffedBits = null;
            // We look at the possible table sizes in the order Compact1, Compact2, Compact3,
            // Compact4, Normal4,...  Normal(i) for i < 4 isn't typically used since Compact(i+1)
            // is the same size, but has more data.
            for (int i = 0;; i++)
            {
               if (i > MAX_NB_BITS)
               {
                  throw new ArgumentException("Data too large for an Aztec code");
               }
               compact = i <= 3;
               layers = compact ? i + 1 : i;
               totalBitsInLayer = TotalBitsInLayer(layers, compact);
               if (totalSizeBits > totalBitsInLayer)
               {
                  continue;
               }
               // [Re]stuff the bits if this is the first opportunity, or if the
               // wordSize has changed
               if (wordSize != WORD_SIZE[layers])
               {
                  wordSize = WORD_SIZE[layers];
                  stuffedBits = stuffBits(bits, wordSize);
               }
               if (stuffedBits == null)
               {
                  continue;
               }
               int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer%wordSize);
               if (compact && stuffedBits.Size > wordSize*64)
               {
                  // Compact format only allows 64 data words, though C4 can hold more words than that
                  continue;
               }
               if (stuffedBits.Size + eccBits <= usableBitsInLayers)
               {
                  break;
               }
            }

         }

         BitArray messageBits = generateCheckWords(stuffedBits, totalBitsInLayer, wordSize);

         // generate mode message
         int messageSizeInWords = stuffedBits.Size / wordSize;
         var modeMessage = generateModeMessage(compact, layers, messageSizeInWords);

         // allocate symbol
         var baseMatrixSize = compact ? 11 + layers*4 : 14 + layers*4; // not including alignment lines
         var alignmentMap = new int[baseMatrixSize];
         int matrixSize;
         if (compact)
         {
            // no alignment marks in compact mode, alignmentMap is a no-op
            matrixSize = baseMatrixSize;
            for (int i = 0; i < alignmentMap.Length; i++)
            {
               alignmentMap[i] = i;
            }
         }
         else
         {
            matrixSize = baseMatrixSize + 1 + 2*((baseMatrixSize/2 - 1)/15);
            int origCenter = baseMatrixSize/2;
            int center = matrixSize/2;
            for (int i = 0; i < origCenter; i++)
            {
               int newOffset = i + i/15;
               alignmentMap[origCenter - i - 1] = center - newOffset - 1;
               alignmentMap[origCenter + i] = center + newOffset + 1;
            }
         }
         var matrix = new BitMatrix(matrixSize);

         // draw data bits
         for (int i = 0, rowOffset = 0; i < layers; i++)
         {
            int rowSize = compact ? (layers - i)*4 + 9 : (layers - i)*4 + 12;
            for (int j = 0; j < rowSize; j++)
            {
               int columnOffset = j*2;
               for (int k = 0; k < 2; k++)
               {
                  if (messageBits[rowOffset + columnOffset + k])
                  {
                     matrix[alignmentMap[i*2 + k], alignmentMap[i*2 + j]] = true;
                  }
                  if (messageBits[rowOffset + rowSize*2 + columnOffset + k])
                  {
                     matrix[alignmentMap[i*2 + j], alignmentMap[baseMatrixSize - 1 - i*2 - k]] = true;
                  }
                  if (messageBits[rowOffset + rowSize*4 + columnOffset + k])
                  {
                     matrix[alignmentMap[baseMatrixSize - 1 - i*2 - k], alignmentMap[baseMatrixSize - 1 - i*2 - j]] = true;
                  }
                  if (messageBits[rowOffset + rowSize*6 + columnOffset + k])
                  {
                     matrix[alignmentMap[baseMatrixSize - 1 - i*2 - j], alignmentMap[i*2 + k]] = true;
                  }
               }
            }
            rowOffset += rowSize*8;
         }

         // draw mode message
         drawModeMessage(matrix, compact, matrixSize, modeMessage);

         // draw alignment marks
         if (compact)
         {
            drawBullsEye(matrix, matrixSize/2, 5);
         }
         else
         {
            drawBullsEye(matrix, matrixSize/2, 7);
            for (int i = 0, j = 0; i < baseMatrixSize/2 - 1; i += 15, j += 16)
            {
               for (int k = (matrixSize/2) & 1; k < matrixSize; k += 2)
               {
                  matrix[matrixSize/2 - j, k] = true;
                  matrix[matrixSize/2 + j, k] = true;
                  matrix[k, matrixSize/2 - j] = true;
                  matrix[k, matrixSize/2 + j] = true;
               }
            }
         }

         return new AztecCode
            {
               isCompact = compact,
               Size = matrixSize,
               Layers = layers,
               CodeWords = messageSizeInWords,
               Matrix = matrix
            };
      }
Exemplo n.º 3
0
        /// <summary>
        /// Encodes the given binary content as an Aztec symbol
        /// </summary>
        /// <param name="data">input data string</param>
        /// <param name="minECCPercent">minimal percentage of error check words (According to ISO/IEC 24778:2008, a minimum of 23% + 3 words is recommended)</param>
        /// <param name="userSpecifiedLayers">if non-zero, a user-specified value for the number of layers</param>
        /// <param name="encoding">character set to mark using ECI; if null, no ECI code will be inserted, and the default encoding of ISO/IEC 8859-1 will be assuming by readers.</param>
        /// <param name="disableEci">if true, don't add ECI segment, regardless if encoding ist set</param>
        /// <returns>Aztec symbol matrix with metadata</returns>
        public static AztecCode encode(byte[] data, int minECCPercent, int userSpecifiedLayers, System.Text.Encoding encoding, bool disableEci)
        {
            // High-level encode
            BitArray bits = new HighLevelEncoder(data, encoding, disableEci).encode();

            // stuff bits and choose symbol size
            int      eccBits       = bits.Size * minECCPercent / 100 + 11;
            int      totalSizeBits = bits.Size + eccBits;
            bool     compact;
            int      layers;
            int      totalBitsInLayer;
            int      wordSize;
            BitArray stuffedBits;

            if (userSpecifiedLayers != DEFAULT_AZTEC_LAYERS)
            {
                compact = userSpecifiedLayers < 0;
                layers  = Math.Abs(userSpecifiedLayers);
                if (layers > (compact ? MAX_NB_BITS_COMPACT : MAX_NB_BITS))
                {
                    throw new ArgumentException(
                              String.Format("Illegal value {0} for layers", userSpecifiedLayers));
                }
                totalBitsInLayer = TotalBitsInLayer(layers, compact);
                wordSize         = WORD_SIZE[layers];
                int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize);
                stuffedBits = stuffBits(bits, wordSize);
                if (stuffedBits.Size + eccBits > usableBitsInLayers)
                {
                    throw new ArgumentException("Data to large for user specified layer");
                }
                if (compact && stuffedBits.Size > wordSize * 64)
                {
                    // Compact format only allows 64 data words, though C4 can hold more words than that
                    throw new ArgumentException("Data to large for user specified layer");
                }
            }
            else
            {
                wordSize    = 0;
                stuffedBits = null;
                // We look at the possible table sizes in the order Compact1, Compact2, Compact3,
                // Compact4, Normal4,...  Normal(i) for i < 4 isn't typically used since Compact(i+1)
                // is the same size, but has more data.
                for (int i = 0; ; i++)
                {
                    if (i > MAX_NB_BITS)
                    {
                        throw new ArgumentException("Data too large for an Aztec code");
                    }
                    compact          = i <= 3;
                    layers           = compact ? i + 1 : i;
                    totalBitsInLayer = TotalBitsInLayer(layers, compact);
                    if (totalSizeBits > totalBitsInLayer)
                    {
                        continue;
                    }
                    // [Re]stuff the bits if this is the first opportunity, or if the
                    // wordSize has changed
                    if (stuffedBits == null || wordSize != WORD_SIZE[layers])
                    {
                        wordSize    = WORD_SIZE[layers];
                        stuffedBits = stuffBits(bits, wordSize);
                    }
                    int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize);
                    if (compact && stuffedBits.Size > wordSize * 64)
                    {
                        // Compact format only allows 64 data words, though C4 can hold more words than that
                        continue;
                    }
                    if (stuffedBits.Size + eccBits <= usableBitsInLayers)
                    {
                        break;
                    }
                }
            }

            BitArray messageBits = generateCheckWords(stuffedBits, totalBitsInLayer, wordSize);

            // generate mode message
            int messageSizeInWords = stuffedBits.Size / wordSize;
            var modeMessage        = generateModeMessage(compact, layers, messageSizeInWords);

            // allocate symbol
            int baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines
            var alignmentMap   = new int[baseMatrixSize];
            int matrixSize;

            if (compact)
            {
                // no alignment marks in compact mode, alignmentMap is a no-op
                matrixSize = baseMatrixSize;
                for (int i = 0; i < alignmentMap.Length; i++)
                {
                    alignmentMap[i] = i;
                }
            }
            else
            {
                matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
                int origCenter = baseMatrixSize / 2;
                int center     = matrixSize / 2;
                for (int i = 0; i < origCenter; i++)
                {
                    int newOffset = i + i / 15;
                    alignmentMap[origCenter - i - 1] = center - newOffset - 1;
                    alignmentMap[origCenter + i]     = center + newOffset + 1;
                }
            }
            var matrix = new BitMatrix(matrixSize);

            // draw data bits
            for (int i = 0, rowOffset = 0; i < layers; i++)
            {
                int rowSize = (layers - i) * 4 + (compact ? 9 : 12);
                for (int j = 0; j < rowSize; j++)
                {
                    int columnOffset = j * 2;
                    for (int k = 0; k < 2; k++)
                    {
                        if (messageBits[rowOffset + columnOffset + k])
                        {
                            matrix[alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 2 + columnOffset + k])
                        {
                            matrix[alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 4 + columnOffset + k])
                        {
                            matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]] = true;
                        }
                        if (messageBits[rowOffset + rowSize * 6 + columnOffset + k])
                        {
                            matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]] = true;
                        }
                    }
                }
                rowOffset += rowSize * 8;
            }

            // draw mode message
            drawModeMessage(matrix, compact, matrixSize, modeMessage);

            // draw alignment marks
            if (compact)
            {
                drawBullsEye(matrix, matrixSize / 2, 5);
            }
            else
            {
                drawBullsEye(matrix, matrixSize / 2, 7);
                for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16)
                {
                    for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2)
                    {
                        matrix[matrixSize / 2 - j, k] = true;
                        matrix[matrixSize / 2 + j, k] = true;
                        matrix[k, matrixSize / 2 - j] = true;
                        matrix[k, matrixSize / 2 + j] = true;
                    }
                }
            }

            return(new AztecCode
            {
                isCompact = compact,
                Size = matrixSize,
                Layers = layers,
                CodeWords = messageSizeInWords,
                Matrix = matrix
            });
        }
Exemplo n.º 4
0
      /// <summary>
      /// Encodes the given binary content as an Aztec symbol
      /// </summary>
      /// <param name="data">input data string</param>
      /// <param name="minECCPercent">minimal percentange of error check words (According to ISO/IEC 24778:2008,
      /// a minimum of 23% + 3 words is recommended)</param>
      /// <returns>Aztec symbol matrix with metadata</returns>
      public static AztecCode encode(byte[] data, int minECCPercent)
      {
         // High-level encode
         var bits = new HighLevelEncoder(data).encode();

         // stuff bits and choose symbol size
         int eccBits = bits.Size * minECCPercent / 100 + 11;
         int totalSizeBits = bits.Size + eccBits;
         int layers;
         int wordSize = 0;
         int totalSymbolBits = 0;
         BitArray stuffedBits = null;
         for (layers = 1; layers < NB_BITS_COMPACT.Length; layers++)
         {
            if (NB_BITS_COMPACT[layers] >= totalSizeBits)
            {
               if (wordSize != WORD_SIZE[layers])
               {
                  wordSize = WORD_SIZE[layers];
                  stuffedBits = stuffBits(bits, wordSize);
               }
               totalSymbolBits = NB_BITS_COMPACT[layers];
               if (stuffedBits.Size + eccBits <= NB_BITS_COMPACT[layers])
               {
                  break;
               }
            }
         }
         bool compact = true;
         if (layers == NB_BITS_COMPACT.Length)
         {
            compact = false;
            for (layers = 1; layers < NB_BITS.Length; layers++)
            {
               if (NB_BITS[layers] >= totalSizeBits)
               {
                  if (wordSize != WORD_SIZE[layers])
                  {
                     wordSize = WORD_SIZE[layers];
                     stuffedBits = stuffBits(bits, wordSize);
                  }
                  totalSymbolBits = NB_BITS[layers];
                  if (stuffedBits.Size + eccBits <= NB_BITS[layers])
                  {
                     break;
                  }
               }
            }
         }
         if (layers == NB_BITS.Length)
         {
            throw new ArgumentException("Data too large for an Aztec code");
         }

         // pad the end
         int messageSizeInWords = (stuffedBits.Size + wordSize - 1) / wordSize;
         for (int i = messageSizeInWords * wordSize - stuffedBits.Size; i > 0; i--)
         {
            stuffedBits.appendBit(true);
         }

         // generate check words
         var rs = new ReedSolomonEncoder(getGF(wordSize));
         var totalSizeInFullWords = totalSymbolBits / wordSize;
         var messageWords = bitsToWords(stuffedBits, wordSize, totalSizeInFullWords);
         rs.encode(messageWords, totalSizeInFullWords - messageSizeInWords);

         // convert to bit array and pad in the beginning
         var startPad = totalSymbolBits % wordSize;
         var messageBits = new BitArray();
         messageBits.appendBits(0, startPad);
         foreach (var messageWord in messageWords)
         {
            messageBits.appendBits(messageWord, wordSize);
         }

         // generate mode message
         var modeMessage = generateModeMessage(compact, layers, messageSizeInWords);

         // allocate symbol
         var baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines
         var alignmentMap = new int[baseMatrixSize];
         int matrixSize;
         if (compact)
         {
            // no alignment marks in compact mode, alignmentMap is a no-op
            matrixSize = baseMatrixSize;
            for (int i = 0; i < alignmentMap.Length; i++)
            {
               alignmentMap[i] = i;
            }
         }
         else
         {
            matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15);
            int origCenter = baseMatrixSize / 2;
            int center = matrixSize / 2;
            for (int i = 0; i < origCenter; i++)
            {
               int newOffset = i + i / 15;
               alignmentMap[origCenter - i - 1] = center - newOffset - 1;
               alignmentMap[origCenter + i] = center + newOffset + 1;
            }
         }
         var matrix = new BitMatrix(matrixSize);

         // draw mode and data bits
         for (int i = 0, rowOffset = 0; i < layers; i++)
         {
            int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12;
            for (int j = 0; j < rowSize; j++)
            {
               int columnOffset = j * 2;
               for (int k = 0; k < 2; k++)
               {
                  if (messageBits[rowOffset + columnOffset + k])
                  {
                     matrix[alignmentMap[i * 2 + k], alignmentMap[i * 2 + j]] = true;
                  }
                  if (messageBits[rowOffset + rowSize * 2 + columnOffset + k])
                  {
                     matrix[alignmentMap[i * 2 + j], alignmentMap[baseMatrixSize - 1 - i * 2 - k]] = true;
                  }
                  if (messageBits[rowOffset + rowSize * 4 + columnOffset + k])
                  {
                     matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - k], alignmentMap[baseMatrixSize - 1 - i * 2 - j]] = true;
                  }
                  if (messageBits[rowOffset + rowSize * 6 + columnOffset + k])
                  {
                     matrix[alignmentMap[baseMatrixSize - 1 - i * 2 - j], alignmentMap[i * 2 + k]] = true;
                  }
               }
            }
            rowOffset += rowSize * 8;
         }
         drawModeMessage(matrix, compact, matrixSize, modeMessage);

         // draw alignment marks
         if (compact)
         {
            drawBullsEye(matrix, matrixSize / 2, 5);
         }
         else
         {
            drawBullsEye(matrix, matrixSize / 2, 7);
            for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16)
            {
               for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2)
               {
                  matrix[matrixSize / 2 - j, k] = true;
                  matrix[matrixSize / 2 + j, k] = true;
                  matrix[k, matrixSize / 2 - j] = true;
                  matrix[k, matrixSize / 2 + j] = true;
               }
            }
         }

         return new AztecCode
                        {
                           isCompact = compact,
                           Size = matrixSize,
                           Layers = layers,
                           CodeWords = messageSizeInWords,
                           Matrix = matrix
                        };
      }